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

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: Rebase on master. 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
« no previous file with comments | « src/crankshaft/lithium.cc ('k') | src/eh-frame.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 : public AllStatic {
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 kCodeAlignmentFactor;
55 static const int kDataAlignmentFactor;
56
57 static const int kFdeVersionSize = 1;
58 static const int kFdeEncodingSpecifiersSize = 3;
59
60 static const int kEhFrameHdrVersion = 1;
61 static const int kEhFrameHdrSize = 20;
62 };
63
64 class EhFrameWriter {
65 public:
66 explicit EhFrameWriter(Zone* zone);
67
68 // The empty frame is a hack to trigger fp-based unwinding in Linux perf
69 // compiled with libunwind support when processing DWARF-based call graphs.
70 //
71 // It is effectively a valid eh_frame_hdr with an empty look up table.
72 //
73 static void WriteEmptyEhFrame(std::ostream& stream); // NOLINT
74
75 // Write the CIE and FDE header. Call it before any other method.
76 void Initialize();
77
78 void AdvanceLocation(int pc_offset);
79
80 // The <base_address> is the one to which all <offset>s in SaveRegisterToStack
81 // directives are relative. It is given by <base_register> + <base_offset>.
82 //
83 // The <base_offset> must be positive or 0.
84 //
85 void SetBaseAddressRegister(Register base_register);
86 void SetBaseAddressOffset(int base_offset);
87 void IncreaseBaseAddressOffset(int base_delta) {
88 SetBaseAddressOffset(base_offset_ + base_delta);
89 }
90 void SetBaseAddressRegisterAndOffset(Register base_register, int base_offset);
91
92 // Register saved at location <base_address> + <offset>.
93 // The <offset> must be a multiple of EhFrameConstants::kDataAlignment.
94 void RecordRegisterSavedToStack(Register name, int offset) {
95 RecordRegisterSavedToStack(RegisterToDwarfCode(name), offset);
96 }
97
98 // The register has not been modified from the previous frame.
99 void RecordRegisterNotModified(Register name);
100
101 // The register follows the rule defined in the CIE.
102 void RecordRegisterFollowsInitialRule(Register name);
103
104 void Finish(int code_size);
105
106 // Remember to call Finish() before GetEhFrame().
107 //
108 // The EhFrameWriter instance owns the buffer pointed by
109 // CodeDesc::unwinding_info, and must outlive any use of the CodeDesc.
110 //
111 void GetEhFrame(CodeDesc* desc);
112
113 int last_pc_offset() const { return last_pc_offset_; }
114 Register base_register() const { return base_register_; }
115 int base_offset() const { return base_offset_; }
26 116
27 private: 117 private:
28 uint8_t version_; 118 enum class InternalState { kUndefined, kInitialized, kFinalized };
29 uint8_t eh_frame_ptr_encoding_; 119
30 uint8_t lut_size_encoding_; 120 static const uint32_t kInt32Placeholder = 0xdeadc0de;
31 uint8_t lut_entries_encoding_; 121
32 int32_t offset_to_eh_frame_; 122 void WriteSLeb128(int32_t value);
33 uint32_t lut_entries_number_; 123 void WriteULeb128(uint32_t value);
34 int32_t offset_to_procedure_; 124
35 int32_t offset_to_fde_; 125 void WriteByte(byte value) { eh_frame_buffer_.push_back(value); }
36 }; 126 void WriteOpcode(EhFrameConstants::DwarfOpcodes opcode) {
127 WriteByte(static_cast<byte>(opcode));
128 }
129 void WriteBytes(const byte* start, int size) {
130 eh_frame_buffer_.insert(eh_frame_buffer_.end(), start, start + size);
131 }
132 void WriteInt16(uint16_t value) {
133 WriteBytes(reinterpret_cast<const byte*>(&value), sizeof(value));
134 }
135 void WriteInt32(uint32_t value) {
136 WriteBytes(reinterpret_cast<const byte*>(&value), sizeof(value));
137 }
138 void PatchInt32(int base_offset, uint32_t value) {
139 DCHECK_EQ(ReadUnalignedUInt32(eh_frame_buffer_.data() + base_offset),
140 kInt32Placeholder);
141 DCHECK_LT(base_offset + kInt32Size, eh_frame_offset());
142 WriteUnalignedUInt32(eh_frame_buffer_.data() + base_offset, value);
143 }
144
145 // Write the common information entry, which includes encoding specifiers,
146 // alignment factors, the return address (pseudo) register code and the
147 // directives to construct the initial state of the unwinding table.
148 void WriteCie();
149
150 // Write the header of the function data entry, containing a pointer to the
151 // correspondent CIE and the position and size of the associated routine.
152 void WriteFdeHeader();
153
154 // Write the contents of the .eh_frame_hdr section, including encoding
155 // specifiers and the routine => FDE lookup table.
156 void WriteEhFrameHdr(int code_size);
157
158 // Write nops until the size reaches a multiple of 8 bytes.
159 void WritePaddingToAlignedSize(int unpadded_size);
160
161 // Internal version that directly accepts a DWARF register code, needed for
162 // handling pseudo-registers on some platforms.
163 void RecordRegisterSavedToStack(int register_code, int offset);
164
165 int GetProcedureAddressOffset() const {
166 return fde_offset() + EhFrameConstants::kProcedureAddressOffsetInFde;
167 }
168
169 int GetProcedureSizeOffset() const {
170 return fde_offset() + EhFrameConstants::kProcedureSizeOffsetInFde;
171 }
172
173 int eh_frame_offset() const {
174 return static_cast<int>(eh_frame_buffer_.size());
175 }
176
177 int fde_offset() const { return cie_size_; }
178
179 // Platform specific functions implemented in eh-frame-<arch>.cc
180
181 static int RegisterToDwarfCode(Register name);
182
183 // Write directives to build the initial state in the CIE.
184 void WriteInitialStateInCie();
185
186 // Write the return address (pseudo) register code.
187 void WriteReturnAddressRegisterCode();
188
189 int cie_size_;
190 int last_pc_offset_;
191 InternalState writer_state_;
192 Register base_register_;
193 int base_offset_;
194 ZoneVector<byte> eh_frame_buffer_;
195
196 DISALLOW_COPY_AND_ASSIGN(EhFrameWriter);
197 };
198
199 class EhFrameIterator {
200 public:
201 EhFrameIterator(const byte* start, const byte* end)
202 : start_(start), next_(start), end_(end) {
203 DCHECK_LE(start, end);
204 }
205
206 void SkipCie() {
207 DCHECK_EQ(next_, start_);
208 next_ += ReadUnalignedUInt32(next_) + kInt32Size;
209 }
210
211 void SkipToFdeDirectives() {
212 SkipCie();
213 // Skip the FDE header.
214 Skip(kDirectivesOffsetInFde);
215 }
216
217 void Skip(int how_many) {
218 DCHECK_GE(how_many, 0);
219 next_ += how_many;
220 DCHECK_LE(next_, end_);
221 }
222
223 uint32_t GetNextUInt32() { return GetNextValue<uint32_t>(); }
224 uint16_t GetNextUInt16() { return GetNextValue<uint16_t>(); }
225 byte GetNextByte() { return GetNextValue<byte>(); }
226 EhFrameConstants::DwarfOpcodes GetNextOpcode() {
227 return static_cast<EhFrameConstants::DwarfOpcodes>(GetNextByte());
228 }
229
230 uint32_t GetNextULeb128();
231 int32_t GetNextSLeb128();
232
233 bool Done() const {
234 DCHECK_LE(next_, end_);
235 return next_ == end_;
236 }
237
238 int GetCurrentOffset() const {
239 DCHECK_GE(next_, start_);
240 return static_cast<int>(next_ - start_);
241 }
242
243 int GetBufferSize() { return static_cast<int>(end_ - start_); }
244
245 const void* current_address() const {
246 return reinterpret_cast<const void*>(next_);
247 }
248
249 private:
250 static const int kDirectivesOffsetInFde = 4 * kInt32Size + 1;
251
252 static uint32_t DecodeULeb128(const byte* encoded, int* encoded_size);
253 static int32_t DecodeSLeb128(const byte* encoded, int* encoded_size);
254
255 template <typename T>
256 T GetNextValue() {
257 T result;
258 DCHECK_LE(next_ + sizeof(result), end_);
259 result = ReadUnalignedValue<T>(next_);
260 next_ += sizeof(result);
261 return result;
262 }
263
264 const byte* start_;
265 const byte* next_;
266 const byte* end_;
267 };
268
269 #ifdef ENABLE_DISASSEMBLER
270
271 class EhFrameDisassembler final {
272 public:
273 EhFrameDisassembler(const byte* start, const byte* end)
274 : start_(start), end_(end) {
275 DCHECK_LT(start, end);
276 }
277
278 void DisassembleToStream(std::ostream& stream); // NOLINT
279
280 private:
281 static void DumpDwarfDirectives(std::ostream& stream, // NOLINT
282 const byte* start, const byte* end);
283
284 static const char* DwarfRegisterCodeToString(int code);
285
286 const byte* start_;
287 const byte* end_;
288
289 DISALLOW_COPY_AND_ASSIGN(EhFrameDisassembler);
290 };
291
292 #endif
37 293
38 } // namespace internal 294 } // namespace internal
39 } // namespace v8 295 } // namespace v8
40 296
41 #endif 297 #endif
OLDNEW
« no previous file with comments | « src/crankshaft/lithium.cc ('k') | src/eh-frame.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698