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

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

Issue 2023503002: Reland Implement .eh_frame writer and disassembler. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@eh-frame-base
Patch Set: if => ifdef 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 #include "src/eh-frame.h" 5 #include "src/eh-frame.h"
6 #include "src/objects-inl.h" 6
7 #include "src/objects.h" 7 #include <iomanip>
8 #include <ostream>
9
10 #if V8_TARGET_ARCH_X64
11 #include "src/x64/eh-frame-x64.h"
12 #elif V8_TARGET_ARCH_ARM
13 #include "src/arm/eh-frame-arm.h"
14 #elif V8_TARGET_ARCH_ARM64
15 #include "src/arm64/eh-frame-arm64.h"
16 #else
17
18 // Dummy placeholders
8 19
9 namespace v8 { 20 namespace v8 {
10 namespace internal { 21 namespace internal {
11 22
12 static const int DW_EH_PE_pcrel = 0x10; 23 static const Register kInitialBaseRegister = {Register::kCode_no_reg};
13 static const int DW_EH_PE_datarel = 0x30; 24 static const int kInitialBaseOffset = 0;
14 static const int DW_EH_PE_udata4 = 0x03; 25 static const int kDataAlignmentFactor = 1;
15 static const int DW_EH_PE_sdata4 = 0x0b; 26 static const byte kCIE[8] = {0};
16 27 #if ENABLE_DISASSEMBLER
17 const int EhFrameHdr::kCIESize = 0; 28 static const int kInitialStateOffsetInCIE = 0;
18 29 #endif
19 static const int kVersionSize = 1; 30
20 static const int kEncodingSpecifiersSize = 3; 31 const char* DwarfRegisterCodeToString(int) {
32 UNIMPLEMENTED();
33 return nullptr;
34 }
35
36 int RegisterToDwarfCode(Register) {
37 UNIMPLEMENTED();
38 return -1;
39 }
40
41 } // namespace internal
42 } // namespace v8
43
44 #endif
45
46 namespace v8 {
47 namespace internal {
48
49 STATIC_CONST_MEMBER_DEFINITION const uint32_t EhFrameWriter::kInt32Placeholder;
50
51 STATIC_CONST_MEMBER_DEFINITION const int EhFrameWriter::kCIESize = sizeof(kCIE);
52 static_assert(EhFrameWriter::kCIESize % kPointerSize == 0,
53 "CIE size must be a multiple of pointer size");
54
55 STATIC_CONST_MEMBER_DEFINITION const int EhFrameWriter::kFDEOffset = kCIESize;
56 STATIC_CONST_MEMBER_DEFINITION const int
57 EhFrameWriter::kProcedureAddressOffset = kFDEOffset + 2 * kInt32Size;
rmcilroy 2016/06/30 15:23:10 I think it would be better if these were relative
Stefano Sanfilippo 2016/07/04 18:21:14 Done.
58 STATIC_CONST_MEMBER_DEFINITION const int EhFrameWriter::kProcedureSizeOffset =
59 kFDEOffset + 3 * kInt32Size;
60 #ifdef ENABLE_DISASSEMBLER
61 STATIC_CONST_MEMBER_DEFINITION const int EhFrameWriter::kFDEDirectivesOffset =
rmcilroy 2016/06/30 15:23:10 This is only used in DisassembleToStream, just def
Stefano Sanfilippo 2016/07/04 18:21:14 Done.
62 kFDEOffset + 4 * kInt32Size + 1;
63 #endif
64
65 const char* DwarfRegisterCodeToString(int code);
66 int RegisterToDwarfCode(Register name);
rmcilroy 2016/06/30 15:23:10 these should be methods in EhFrameWriter
Stefano Sanfilippo 2016/07/04 18:21:14 Done.
67
68 EhFrameWriter::EhFrameWriter()
69 : last_pc_offset_(0),
70 #if DEBUG
71 eh_frame_finalised_(false),
72 #endif
73 base_register_(kInitialBaseRegister),
74 base_offset_(kInitialBaseOffset) {
75 WriteBytes(&kCIE[0], sizeof(kCIE));
76 WriteFDEHeader();
77 }
78
79 void EhFrameWriter::WriteFDEHeader() {
80 DCHECK_EQ(eh_frame_offset(), kFDEOffset);
81 WriteInt32(kInt32Placeholder); // Placeholder for size of the FDE
82 WriteInt32(kCIESize + kInt32Size); // Backwards offset to the CIE
83 DCHECK_EQ(eh_frame_offset(), kProcedureAddressOffset);
84 WriteInt32(kInt32Placeholder); // Placeholder for pointer to procedure
85 DCHECK_EQ(eh_frame_offset(), kProcedureSizeOffset);
86 WriteInt32(kInt32Placeholder); // Placeholder for size of the procedure
87 WriteByte(0); // No augmentation data
88 }
89
90 void EhFrameWriter::AdvanceLocation(int pc_offset) {
91 DCHECK_GE(pc_offset, last_pc_offset_);
92 uint32_t delta = pc_offset - last_pc_offset_;
93
94 if (delta <= kLocationMask) {
95 WriteByte((kLocationTag << kLocationMaskSize) | (delta & kLocationMask));
96 } else if (delta <= kMaxUInt8) {
97 WriteByte(kAdvanceLoc1);
98 WriteByte(delta);
99 } else if (delta <= kMaxUInt16) {
100 WriteByte(kAdvanceLoc2);
101 WriteInt16(delta);
102 } else {
103 WriteByte(kAdvanceLoc4);
104 WriteInt32(delta);
105 }
106
107 last_pc_offset_ = pc_offset;
108 }
109
110 void EhFrameWriter::DefineBaseAddressOffset(int base_offset) {
111 DCHECK_GE(base_offset, 0);
112 WriteByte(kDefCFAOffset);
113 WriteULEB128(base_offset);
114 base_offset_ = base_offset;
115 }
116
117 void EhFrameWriter::DefineBaseAddressRegister(Register name) {
118 int code = RegisterToDwarfCode(name);
119 WriteByte(kDefCFARegister);
120 WriteULEB128(code);
121 base_register_ = name;
122 }
123
124 void EhFrameWriter::DefineBaseAddressRegisterOffset(Register name,
125 int base_offset) {
126 int code = RegisterToDwarfCode(name);
127 WriteByte(kDefCFA);
128 WriteULEB128(code);
129 WriteULEB128(base_offset);
130 base_offset_ = base_offset;
131 base_register_ = name;
132 }
133
134 void EhFrameWriter::SaveRegisterToStack(Register name, int offset) {
135 int code = RegisterToDwarfCode(name);
136 DCHECK_GE(code, 0);
137 DCHECK_LE(code, kSavedRegisterMask);
138 DCHECK_EQ(offset % kDataAlignmentFactor, 0);
139 WriteByte((kSavedRegisterTag << kSavedRegisterMaskSize) |
140 (code & kSavedRegisterMask));
141 WriteULEB128(offset / std::abs(kDataAlignmentFactor));
142 }
143
144 void EhFrameWriter::RegisterIsValid(Register name) {
145 int code = RegisterToDwarfCode(name);
146 DCHECK_GE(code, 0);
147 WriteByte(kSameValue);
148 WriteULEB128(code);
149 }
150
151 void EhFrameWriter::Finish(int code_size) {
152 DCHECK_GE(eh_frame_buffer_.length(), kCIESize);
153
rmcilroy 2016/06/30 15:23:10 DCHECK(!eh_frame_finalized_)
Stefano Sanfilippo 2016/07/04 18:21:14 Done.
154 // Add padding
155 int unpadded_fde_size = eh_frame_buffer_.length() - kCIESize;
156 int padded_fde_size = RoundUp(unpadded_fde_size, 8);
157 int fde_padding_size = padded_fde_size - unpadded_fde_size;
158
159 static const byte kFDEPadding[] = {kNop, kNop, kNop, kNop,
160 kNop, kNop, kNop, kNop};
161 DCHECK_LT(fde_padding_size, static_cast<int>(sizeof(kFDEPadding)));
162 WriteBytes(&kFDEPadding[0], fde_padding_size);
163
164 // Write the size of the FDE now that we know it.
165 PatchInt32(kFDEOffset, padded_fde_size);
166
167 // Write the size and offset to procedure.
168 PatchInt32(kProcedureAddressOffset,
169 -(RoundUp(code_size, 8) + kProcedureAddressOffset));
170 PatchInt32(kProcedureSizeOffset, code_size);
171
172 // Terminate the .eh_frame.
173 static const byte kEhFrameTerminator[kEhFrameTerminatorSize] = {0};
174 WriteBytes(&kEhFrameTerminator[0], kEhFrameTerminatorSize);
175
176 // Write .eh_frame_hdr
177 EhFrameHdr eh_frame_hdr(code_size, eh_frame_offset());
178 WriteBytes(reinterpret_cast<const byte*>(&eh_frame_hdr),
179 EhFrameHdr::kRecordSize);
180
181 #if DEBUG
182 eh_frame_finalised_ = true;
183 #endif
184 }
185
186 void EhFrameWriter::GetEhFrame(CodeDesc* desc) {
187 DCHECK(eh_frame_finalised_);
188 desc->unwinding_info_size = eh_frame_buffer_.length();
189 desc->unwinding_info = eh_frame_buffer_.begin();
190 }
191
192 void EhFrameWriter::WriteULEB128(uint32_t value) {
193 do {
194 byte chunk = value & 0x7f;
195 value >>= 7;
196 if (value != 0) chunk |= 0x80;
197 eh_frame_buffer_.Add(chunk);
198 } while (value != 0);
199 }
200
201 #ifdef ENABLE_DISASSEMBLER
202
203 namespace {
204
205 uint32_t DecodeULEB128(const byte* encoded, int* encoded_size) {
206 const byte* cur = encoded;
207 uint32_t decoded_value = 0;
208
209 do {
210 decoded_value <<= 7;
211 decoded_value += static_cast<uint32_t>(static_cast<unsigned>(*cur & 0x7f));
212 } while (*cur++ >= 0x80);
213
214 *encoded_size = static_cast<int>(cur - encoded);
215 return decoded_value;
216 }
217
218 class StreamModifiersScope final {
219 public:
220 explicit StreamModifiersScope(std::ostream* stream)
221 : stream_(stream), flags_(stream->flags()) {}
222 ~StreamModifiersScope() { stream_->flags(flags_); }
223
224 private:
225 std::ostream* stream_;
226 std::ios::fmtflags flags_;
227 };
228
229 } // namespace
230
231 // static
232 void EhFrameWriter::DumpDWARFDirectives(std::ostream& stream, // NOLINT
233 const byte* begin, const byte* end) {
234 StreamModifiersScope modifiers_scope(&stream);
235
236 const byte* cur = begin;
237 uint32_t offset_in_procedure = 0;
238
239 while (cur != end) {
240 stream << reinterpret_cast<const void*>(cur) << " ";
241
242 if (((*cur >> kLocationMaskSize) & 0xff) == kLocationTag) {
243 int value = *cur & kLocationMask;
244 cur += sizeof(byte);
245 offset_in_procedure += value;
246 stream << "| pc_offset=" << std::dec << offset_in_procedure
247 << " (delta=0x" << std::hex << value << ")\n";
248 continue;
249 }
250
251 if (((*cur >> kSavedRegisterMaskSize) & 0xff) == kSavedRegisterTag) {
252 stream << "| " << DwarfRegisterCodeToString(*cur & kLocationMask);
253 cur += sizeof(byte);
254 int decoded_size = 0;
255 int decoded_offset = static_cast<int>(DecodeULEB128(cur, &decoded_size));
256 cur += decoded_size;
257 stream << " saved at base" << std::showpos << std::dec
258 << decoded_offset * kDataAlignmentFactor << '\n';
259 continue;
260 }
261
262 uint8_t bytecode = *cur;
263 cur += sizeof(byte);
264
265 switch (bytecode) {
266 case kAdvanceLoc1: {
267 unsigned value = *reinterpret_cast<const uint8_t*>(cur);
268 cur += sizeof(uint8_t);
269 offset_in_procedure += value;
270 stream << "| pc_offset=" << std::dec << offset_in_procedure
271 << " (delta=0x" << std::hex << value << ")\n";
272 break;
273 }
274 case kAdvanceLoc2: {
275 uint16_t value = ReadUnalignedUInt16(cur);
276 cur += sizeof(uint16_t);
277 offset_in_procedure += value;
278 stream << "| pc_offset=" << std::dec << offset_in_procedure
279 << " (delta=0x" << std::hex << value << ")\n";
280 break;
281 }
282 case kAdvanceLoc4: {
283 uint32_t value = ReadUnalignedUInt32(cur);
284 offset_in_procedure += value;
285 cur += sizeof(uint32_t);
286 stream << "| pc_offset=" << std::dec << offset_in_procedure
287 << " (delta=0x" << std::hex << value << ")\n";
288 break;
289 }
290 case kDefCFA: {
291 int decoded_size = 0;
292 int base_register = DecodeULEB128(cur, &decoded_size);
293 cur += decoded_size;
294 int base_offset = DecodeULEB128(cur, &decoded_size);
295 cur += decoded_size;
296 stream << "| base_register=" << DwarfRegisterCodeToString(base_register)
297 << ", base_offset=0x" << std::hex << base_offset << '\n';
298 break;
299 }
300 case kDefCFAOffset: {
301 int decoded_size = 0;
302 stream << "| base_offset=0x" << std::hex
303 << DecodeULEB128(cur, &decoded_size) << '\n';
304 cur += decoded_size;
305 break;
306 }
307 case kDefCFARegister: {
308 int decoded_size = 0;
309 stream << "| base_register="
310 << DwarfRegisterCodeToString(DecodeULEB128(cur, &decoded_size))
311 << '\n';
312 cur += decoded_size;
313 break;
314 }
315 case kSameValue: {
316 int decoded_size = 0;
317 stream << "| "
318 << DwarfRegisterCodeToString(DecodeULEB128(cur, &decoded_size))
319 << " to initial value\n";
320 cur += decoded_size;
321 break;
322 }
323 case kNop:
324 stream << "| nop\n";
325 break;
326 default:
327 UNREACHABLE();
328 return;
329 }
330 }
331 }
332
333 // static
334 void EhFrameWriter::DisassembleToStream(std::ostream& stream, // NOLINT
335 const byte* start, const byte* end) {
336 const byte* cie_directives_start = start + kInitialStateOffsetInCIE;
337 const byte* cie_directives_end = start + kCIESize;
338 DCHECK_LE(cie_directives_start, cie_directives_end);
339
340 stream << reinterpret_cast<const void*>(start) << " .eh_frame: CIE\n";
341 DumpDWARFDirectives(stream, cie_directives_start, cie_directives_end);
342
343 const byte* procedure_offset_address = start + kProcedureAddressOffset;
344 int32_t procedure_offset =
345 ReadUnalignedValue<int32_t>(procedure_offset_address);
346
347 const byte* procedure_size_address = start + kProcedureSizeOffset;
348 uint32_t procedure_size = ReadUnalignedUInt32(procedure_size_address);
349
350 const byte* fde_start = start + kCIESize;
351 stream << reinterpret_cast<const void*>(fde_start) << " .eh_frame: FDE\n"
352 << reinterpret_cast<const void*>(procedure_offset_address)
353 << " | procedure offset=" << procedure_offset << '\n'
354 << reinterpret_cast<const void*>(procedure_size_address)
355 << " | procedure size=" << procedure_size << '\n';
356
357 const byte* fde_directives_start = start + kFDEDirectivesOffset;
358 const byte* fde_directives_end =
359 end - EhFrameHdr::kRecordSize - kEhFrameTerminatorSize;
360 DCHECK_LE(fde_directives_start, fde_directives_end);
361
362 DumpDWARFDirectives(stream, fde_directives_start, fde_directives_end);
363
364 const byte* fde_terminator_start = fde_directives_end;
365 stream << reinterpret_cast<const void*>(fde_terminator_start)
366 << " .eh_frame: terminator\n";
367
368 const byte* eh_frame_hdr_start =
369 fde_terminator_start + kEhFrameTerminatorSize;
370 stream << reinterpret_cast<const void*>(eh_frame_hdr_start)
371 << " .eh_frame_hdr: placeholder\n";
372 }
373
374 #endif
21 375
22 // 376 //
23 // In order to calculate offsets in the .eh_frame_hdr, we must know the layout 377 // In order to calculate offsets in the .eh_frame_hdr, we must know the layout
24 // of the DSO generated by perf inject, which is assumed to be the following: 378 // of the DSO generated by perf inject, which is assumed to be the following:
25 // 379 //
26 // | ... | | 380 // | ... | |
27 // +---------------+ <-- (F) --- | Larger offsets in file 381 // +---------------+ <-- (F) --- | Larger offsets in file
28 // | | ^ | 382 // | | ^ |
29 // | Instructions | | .text v 383 // | Instructions | | .text v
30 // | | v 384 // | | v
(...skipping 13 matching lines...) Expand all
44 // | version | ^ 398 // | version | ^
45 // +---------------+ | 399 // +---------------+ |
46 // | encoding | | 400 // | encoding | |
47 // | specifiers | | 401 // | specifiers | |
48 // +---------------+ <---(A) | .eh_frame_hdr 402 // +---------------+ <---(A) | .eh_frame_hdr
49 // | offset to | | 403 // | offset to | |
50 // | .eh_frame | | 404 // | .eh_frame | |
51 // +---------------+ | 405 // +---------------+ |
52 // | ... | ... 406 // | ... | ...
53 // 407 //
54 // (F) is aligned at a 16-byte boundary. 408 // (F) is aligned to a 16-byte boundary.
55 // (D) is aligned at a 8-byte boundary. 409 // (D) is aligned to a 8-byte boundary.
56 // (B) is aligned at a 4-byte boundary. 410 // (B) is aligned to a 4-byte boundary.
57 // (E), (C) and (A) have no alignment requirements. 411 // (C) is aligned to an addressing unit size boundary.
412 // (E) and (A) have no alignment requirements.
58 // 413 //
59 // The distance between (A) and (B) is 4 bytes. 414 // The distance between (A) and (B) is 4 bytes.
60 // 415 //
61 // The size of the .eh_frame is required to be a multiple of the pointer size, 416 // The size of the FDE is required to be a multiple of the pointer size, which
62 // which means that (B) will be naturally aligned to a 4-byte boundary on all 417 // means that (B) will be naturally aligned to a 4-byte boundary on all the
63 // the architectures we support. 418 // architectures we support.
64 // 419 //
65 // Because (E) has no alignment requirements, there is padding between (E) and 420 // Because (E) has no alignment requirements, there is padding between (E) and
66 // (D). (F) is aligned at a 16-byte boundary, thus to a 8-byte one as well. 421 // (D). (F) is aligned at a 16-byte boundary, thus to a 8-byte one as well.
67 // 422 //
68 EhFrameHdr::EhFrameHdr(Code* code) { 423 EhFrameHdr::EhFrameHdr(int code_size, int eh_frame_size) {
69 int code_size = code->is_crankshafted() ? code->safepoint_table_offset() 424 version_ = kEhFrameHdrVersion;
70 : code->instruction_size();
71 version_ = 1;
72 eh_frame_ptr_encoding_ = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
73 lut_size_encoding_ = DW_EH_PE_udata4;
74 lut_entries_encoding_ = DW_EH_PE_sdata4 | DW_EH_PE_datarel;
75 425
76 // .eh_frame pointer and LUT 426 eh_frame_ptr_encoding_ = kSData4 | kPcRel;
77 if (code->has_unwinding_info()) { 427 lut_size_encoding_ = kUData4;
78 DCHECK_GE(code->unwinding_info_size(), EhFrameHdr::kRecordSize); 428 lut_entries_encoding_ = kSData4 | kDataRel;
79 int eh_frame_size = code->unwinding_info_size() - EhFrameHdr::kRecordSize;
80 429
81 offset_to_eh_frame_ = 430 offset_to_eh_frame_ = -(eh_frame_size + kFDEVersionSize +
82 -(eh_frame_size + kVersionSize + kEncodingSpecifiersSize); // A -> D 431 kFDEEncodingSpecifiersSize); // A -> D
83 lut_entries_number_ = 1; 432 lut_entries_number_ = 1;
84 offset_to_procedure_ = -(RoundUp(code_size, 8) + eh_frame_size); // B -> F 433 offset_to_procedure_ = -(RoundUp(code_size, 8) + eh_frame_size); // B -> F
85 offset_to_fde_ = -(eh_frame_size - kCIESize); // B -> C 434 offset_to_fde_ = -(eh_frame_size - EhFrameWriter::kCIESize); // B -> C
86 } else { 435 }
87 // Create a dummy table 436
88 offset_to_eh_frame_ = 0; 437 // static
89 lut_entries_number_ = 0; 438 EhFrameHdr EhFrameHdr::MakeDummy() {
90 offset_to_procedure_ = 0; 439 EhFrameHdr dummy_frame;
91 offset_to_fde_ = 0; 440 dummy_frame.version_ = kEhFrameHdrVersion;
92 } 441 dummy_frame.eh_frame_ptr_encoding_ = kSData4 | kPcRel;
442 dummy_frame.lut_size_encoding_ = kUData4;
443 dummy_frame.lut_entries_encoding_ = kSData4 | kDataRel;
444 dummy_frame.offset_to_eh_frame_ = 0;
445 dummy_frame.lut_entries_number_ = 0;
446 dummy_frame.offset_to_procedure_ = 0;
447 dummy_frame.offset_to_fde_ = 0;
448 return dummy_frame;
93 } 449 }
94 450
95 } // namespace internal 451 } // namespace internal
96 } // namespace v8 452 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698