Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: src/eh-frame.h

Issue 2023503002: Reland Implement .eh_frame writer and disassembler. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@eh-frame-base
Patch Set: LUT => lookup table (for clarity). Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef V8_EH_FRAME_H_ 5 #ifndef V8_EH_FRAME_H_
6 #define V8_EH_FRAME_H_ 6 #define V8_EH_FRAME_H_
7 7
8 #include <cstdint> 8 #include "src/macro-assembler.h"
9 9
10 namespace v8 { 10 namespace v8 {
11 namespace internal { 11 namespace internal {
12 12
13 class Code; 13 class EhFrameConstants final {
14 14 public:
15 class EhFrameHdr final { 15 enum class DwarfOpcodes : byte {
16 public: 16 kNop = 0x00,
17 static const int kRecordSize = 20; 17 kAdvanceLoc1 = 0x02,
18 static const int kCIESize; 18 kAdvanceLoc2 = 0x03,
19 19 kAdvanceLoc4 = 0x04,
20 explicit EhFrameHdr(Code* code); 20 kSameValue = 0x08,
21 21 kDefCfa = 0x0c,
22 int32_t offset_to_eh_frame() const { return offset_to_eh_frame_; } 22 kDefCfaRegister = 0x0d,
23 uint32_t lut_entries_number() const { return lut_entries_number_; } 23 kDefCfaOffset = 0x0e,
24 int32_t offset_to_procedure() const { return offset_to_procedure_; } 24 kOffsetExtendedSf = 0x11,
25 int32_t offset_to_fde() const { return offset_to_fde_; } 25 };
26
27 enum DwarfEncodingSpecifiers : byte {
28 kUData4 = 0x03,
29 kSData4 = 0x0b,
30 kPcRel = 0x10,
31 kDataRel = 0x30,
32 kOmit = 0xff,
33 };
34
35 static const int kLocationTag = 1;
36 static const int kLocationMask = 0x3f;
37 static const int kLocationMaskSize = 6;
38
39 static const int kSavedRegisterTag = 2;
40 static const int kSavedRegisterMask = 0x3f;
41 static const int kSavedRegisterMaskSize = 6;
42
43 static const int kFollowInitialRuleTag = 3;
44 static const int kFollowInitialRuleMask = 0x3f;
45 static const int kFollowInitialRuleMaskSize = 6;
46
47 static const int kProcedureAddressOffsetInFde = 2 * kInt32Size;
48 static const int kProcedureSizeOffsetInFde = 3 * kInt32Size;
49
50 static const int kInitialStateOffsetInCIE = 19;
51 static const int kEhFrameTerminatorSize = 4;
52
53 // Defined in eh-writer-<arch>.cc
54 static const int kDataAlignmentFactor;
55
56 static const int kFdeVersionSize = 1;
57 static const int kFdeEncodingSpecifiersSize = 3;
58
59 static const int kEhFrameHdrVersion = 1;
60 static const int kEhFrameHdrSize = 20;
61 };
62
63 class EhFrameWriter {
64 public:
65 explicit EhFrameWriter(Zone* zone);
66
67 // The dummy frame is a hack to trigger fp-based unwinding in Linux perf
rmcilroy 2016/07/08 09:20:32 /s/dummy/empty
Stefano Sanfilippo 2016/07/08 09:32:13 Done.
68 // compiled with libunwind support when collecting DWARF-based call graphs.
69 //
70 // It is effectively a valid eh_frame_hdr with an empty look up table.
71 //
72 static void WriteEmptyEhFrame(std::ostream& stream); // NOLINT
73
74 // Write the CIE and FDE header. Call it before any other method.
75 void Initialize();
76
77 void AdvanceLocation(int pc_offset);
78
79 // The <base_address> is the one to which all <offset>s in SaveRegisterToStack
80 // directives are relative. It is given by <base_register> + <base_offset>.
81 void SetBaseAddressRegister(Register base_register);
82 void SetBaseAddressOffset(int base_offset);
83 void IncreaseBaseAddressOffset(int base_delta) {
84 SetBaseAddressOffset(base_offset_ + base_delta);
85 }
86 void SetBaseAddressRegisterAndOffset(Register base_register, int base_offset);
87
88 // Register saved at location <base_address> + <offset>
89 void RecordRegisterSavedToStack(Register name, int offset) {
90 RecordRegisterSavedToStack(RegisterToDwarfCode(name), offset);
91 }
92
93 // The register has not been modified from the previous frame.
94 void RecordRegisterNotModified(Register name);
95
96 // The register follows the rule defined in the CIE.
97 void RecordRegisterFollowsInitialRule(Register name);
98
99 void Finish(int code_size);
100
101 // Remember to call Finish() before GetEhFrame().
102 //
103 // The EhFrameWriter instance owns the buffer pointed by
104 // CodeDesc::unwinding_info, and must outlive any use of the CodeDesc.
105 void GetEhFrame(CodeDesc* desc);
106
107 int last_pc_offset() const { return last_pc_offset_; }
108 Register base_register() const { return base_register_; }
109 int base_offset() const { return base_offset_; }
26 110
27 private: 111 private:
28 uint8_t version_; 112 enum class InternalState { kUndefined, kInitialized, kFinalized };
29 uint8_t eh_frame_ptr_encoding_; 113
30 uint8_t lut_size_encoding_; 114 static const uint32_t kInt32Placeholder = 0xdeadc0de;
31 uint8_t lut_entries_encoding_; 115
32 int32_t offset_to_eh_frame_; 116 void WriteSLEB128(int32_t value);
33 uint32_t lut_entries_number_; 117 void WriteULEB128(uint32_t value);
34 int32_t offset_to_procedure_; 118
35 int32_t offset_to_fde_; 119 void WriteByte(byte value) { eh_frame_buffer_.push_back(value); }
36 }; 120 void WriteOpcode(EhFrameConstants::DwarfOpcodes opcode) {
121 WriteByte(static_cast<byte>(opcode));
122 }
123 void WriteBytes(const byte* start, int size) {
124 eh_frame_buffer_.insert(eh_frame_buffer_.end(), start, start + size);
125 }
126 void WriteInt16(uint16_t value) {
127 WriteBytes(reinterpret_cast<const byte*>(&value), sizeof(value));
128 }
129 void WriteInt32(uint32_t value) {
130 WriteBytes(reinterpret_cast<const byte*>(&value), sizeof(value));
131 }
132 void PatchInt32(int base_offset, uint32_t value) {
133 DCHECK_EQ(ReadUnalignedUInt32(eh_frame_buffer_.data() + base_offset),
134 kInt32Placeholder);
135 DCHECK_LT(base_offset + kInt32Size, eh_frame_offset());
136 WriteUnalignedUInt32(eh_frame_buffer_.data() + base_offset, value);
137 }
138
139 // Write the common information entry, which includes encoding specifiers,
140 // alignment factors, the return address (pseudo) register code and the
141 // directives to construct the initial state of the unwinding table.
142 void WriteCIE();
143
144 // Write the header of the function data entry, containing a pointer to the
145 // correspondent CIE and the position and size of the associated routine.
146 void WriteFDEHeader();
147
148 // Write the contents of the .eh_frame_hdr section, including encoder
149 // specifiers and the routine => FDE lookup table.
150 void WriteEhFrameHdr(int code_size);
151
152 // Write nops to the buffer until the size reaches a multiple of 8 bytes.
153 void WritePaddingTo8ByteAlignment();
154
155 // Internal version that directly accepts a DWARF register code, needed for
156 // handling pseudo-registers on some platforms.
157 void RecordRegisterSavedToStack(int register_code, int offset);
158
159 int GetProcedureAddressOffset() const {
160 return fde_offset() + EhFrameConstants::kProcedureAddressOffsetInFde;
161 }
162
163 int GetProcedureSizeOffset() const {
164 return fde_offset() + EhFrameConstants::kProcedureSizeOffsetInFde;
165 }
166
167 int eh_frame_offset() const {
168 return static_cast<int>(eh_frame_buffer_.size());
169 }
170
171 int fde_offset() const { return cie_size_; }
172
173 // Platform specific functions implemented in eh-frame-<arch>.cc
174
175 static int RegisterToDwarfCode(Register name);
176
177 // Write directives to build the initial state in the CIE.
178 void WriteInitialStateInCIE();
179
180 // Write the return address (pseudo) register code.
181 void WriteReturnAddressRegisterCode();
182
183 int cie_size_;
184 int last_pc_offset_;
185 InternalState writer_state_;
186 Register base_register_;
187 int base_offset_;
188 ZoneVector<byte> eh_frame_buffer_;
189 };
190
191 class EhFrameIterator {
192 public:
193 EhFrameIterator(const byte* start, const byte* end)
194 : start_(start), next_(start), end_(end) {
195 DCHECK_LE(start, end);
196 }
197
198 void SkipCIE() {
199 DCHECK_EQ(next_, start_);
200 next_ += ReadUnalignedUInt32(next_) + kInt32Size;
201 }
202
203 void SkipToFDEDirectives() {
204 SkipCIE();
205 // Skip the FDE header.
206 Skip(kDirectivesOffsetInFDE);
207 }
208
209 void Skip(int how_many) {
210 DCHECK_GE(how_many, 0);
211 next_ += how_many;
212 DCHECK_LE(next_, end_);
213 }
214
215 uint32_t GetNextUInt32() { return GetNextValue<uint32_t>(); }
216 uint16_t GetNextUInt16() { return GetNextValue<uint16_t>(); }
217 byte GetNextByte() { return GetNextValue<byte>(); }
218 EhFrameConstants::DwarfOpcodes GetNextOpcode() {
219 return static_cast<EhFrameConstants::DwarfOpcodes>(GetNextByte());
220 }
221
222 uint32_t GetNextULEB128();
223 int32_t GetNextSLEB128();
224
225 bool Done() const {
226 DCHECK_LE(next_, end_);
227 return next_ == end_;
228 }
229
230 int GetCurrentOffset() const {
231 DCHECK_GE(next_, start_);
232 return static_cast<int>(next_ - start_);
233 }
234
235 int GetBufferSize() { return static_cast<int>(end_ - start_); }
236
237 const void* current_address() const {
238 return reinterpret_cast<const void*>(next_);
239 }
240
241 private:
242 static const int kDirectivesOffsetInFDE = 4 * kInt32Size + 1;
243
244 static uint32_t DecodeULEB128(const byte* encoded, int* encoded_size);
245 static int32_t DecodeSLEB128(const byte* encoded, int* encoded_size);
246
247 template <typename T>
248 T GetNextValue() {
249 T result;
250 DCHECK_LE(next_ + sizeof(result), end_);
251 result = ReadUnalignedValue<T>(next_);
252 next_ += sizeof(result);
253 return result;
254 }
255
256 const byte* start_;
257 const byte* next_;
258 const byte* end_;
259 };
260
261 #ifdef ENABLE_DISASSEMBLER
262
263 class EhFrameDisassembler final {
264 public:
265 EhFrameDisassembler(const byte* start, const byte* end)
266 : start_(start), end_(end) {
267 DCHECK_LT(start, end);
268 }
269
270 void DisassembleToStream(std::ostream& stream); // NOLINT
271
272 private:
273 static void DumpDWARFDirectives(std::ostream& stream, // NOLINT
274 const byte* start, const byte* end);
275
276 static const char* DwarfRegisterCodeToString(int code);
277
278 const byte* start_;
279 const byte* end_;
280 };
281
282 #endif
37 283
38 } // namespace internal 284 } // namespace internal
39 } // namespace v8 285 } // namespace v8
40 286
41 #endif 287 #endif
OLDNEW
« no previous file with comments | « src/crankshaft/lithium.cc ('k') | src/eh-frame.cc » ('j') | src/eh-frame.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698