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
3 // found in the LICENSE file.
4
5 #include "src/diagnostics/eh-frame.h"
6
7 #include <iomanip>
8 #include <ostream>
9
10 #include "src/codegen/code-desc.h"
11
12 #if !defined(V8_TARGET_ARCH_X64) && !defined(V8_TARGET_ARCH_ARM) && \
13 !defined(V8_TARGET_ARCH_ARM64) && !defined(V8_TARGET_ARCH_S390X) && \
14 !defined(V8_TARGET_ARCH_PPC64)
15
16 // Placeholders for unsupported architectures.
17
18 namespace v8 {
19 namespace internal {
20
21 const int EhFrameConstants::kCodeAlignmentFactor = 1;
22 const int EhFrameConstants::kDataAlignmentFactor = 1;
23
WriteReturnAddressRegisterCode()24 void EhFrameWriter::WriteReturnAddressRegisterCode() { UNIMPLEMENTED(); }
25
WriteInitialStateInCie()26 void EhFrameWriter::WriteInitialStateInCie() { UNIMPLEMENTED(); }
27
RegisterToDwarfCode(Register)28 int EhFrameWriter::RegisterToDwarfCode(Register) {
29 UNIMPLEMENTED();
30 return -1;
31 }
32
33 #ifdef ENABLE_DISASSEMBLER
34
DwarfRegisterCodeToString(int)35 const char* EhFrameDisassembler::DwarfRegisterCodeToString(int) {
36 UNIMPLEMENTED();
37 return nullptr;
38 }
39
40 #endif
41
42 } // namespace internal
43 } // namespace v8
44
45 #endif
46
47 namespace v8 {
48 namespace internal {
49
50 STATIC_CONST_MEMBER_DEFINITION const int
51 EhFrameConstants::kEhFrameTerminatorSize;
52 STATIC_CONST_MEMBER_DEFINITION const int EhFrameConstants::kEhFrameHdrVersion;
53 STATIC_CONST_MEMBER_DEFINITION const int EhFrameConstants::kEhFrameHdrSize;
54
55 STATIC_CONST_MEMBER_DEFINITION const uint32_t EhFrameWriter::kInt32Placeholder;
56
57 // static
WriteEmptyEhFrame(std::ostream & stream)58 void EhFrameWriter::WriteEmptyEhFrame(std::ostream& stream) { // NOLINT
59 stream.put(EhFrameConstants::kEhFrameHdrVersion);
60
61 // .eh_frame pointer encoding specifier.
62 stream.put(EhFrameConstants::kSData4 | EhFrameConstants::kPcRel);
63
64 // Lookup table size encoding.
65 stream.put(EhFrameConstants::kUData4);
66
67 // Lookup table entries encoding.
68 stream.put(EhFrameConstants::kSData4 | EhFrameConstants::kDataRel);
69
70 // Dummy pointers and 0 entries in the lookup table.
71 char dummy_data[EhFrameConstants::kEhFrameHdrSize - 4] = {0};
72 stream.write(&dummy_data[0], sizeof(dummy_data));
73 }
74
EhFrameWriter(Zone * zone)75 EhFrameWriter::EhFrameWriter(Zone* zone)
76 : cie_size_(0),
77 last_pc_offset_(0),
78 writer_state_(InternalState::kUndefined),
79 base_register_(no_reg),
80 base_offset_(0),
81 eh_frame_buffer_(zone) {}
82
Initialize()83 void EhFrameWriter::Initialize() {
84 DCHECK_EQ(writer_state_, InternalState::kUndefined);
85 eh_frame_buffer_.reserve(128);
86 writer_state_ = InternalState::kInitialized;
87 WriteCie();
88 WriteFdeHeader();
89 }
90
WriteCie()91 void EhFrameWriter::WriteCie() {
92 static const int kCIEIdentifier = 0;
93 static const int kCIEVersion = 3;
94 static const int kAugmentationDataSize = 2;
95 static const byte kAugmentationString[] = {'z', 'L', 'R', 0};
96
97 // Placeholder for the size of the CIE.
98 int size_offset = eh_frame_offset();
99 WriteInt32(kInt32Placeholder);
100
101 // CIE identifier and version.
102 int record_start_offset = eh_frame_offset();
103 WriteInt32(kCIEIdentifier);
104 WriteByte(kCIEVersion);
105
106 // Augmentation data contents descriptor: LSDA and FDE encoding.
107 WriteBytes(&kAugmentationString[0], sizeof(kAugmentationString));
108
109 // Alignment factors.
110 WriteSLeb128(EhFrameConstants::kCodeAlignmentFactor);
111 WriteSLeb128(EhFrameConstants::kDataAlignmentFactor);
112
113 WriteReturnAddressRegisterCode();
114
115 // Augmentation data.
116 WriteULeb128(kAugmentationDataSize);
117 // No language-specific data area (LSDA).
118 WriteByte(EhFrameConstants::kOmit);
119 // FDE pointers encoding.
120 WriteByte(EhFrameConstants::kSData4 | EhFrameConstants::kPcRel);
121
122 // Write directives to build the initial state of the unwinding table.
123 DCHECK_EQ(eh_frame_offset() - size_offset,
124 EhFrameConstants::kInitialStateOffsetInCie);
125 WriteInitialStateInCie();
126
127 WritePaddingToAlignedSize(eh_frame_offset() - record_start_offset);
128
129 int record_end_offset = eh_frame_offset();
130 int encoded_cie_size = record_end_offset - record_start_offset;
131 cie_size_ = record_end_offset - size_offset;
132
133 // Patch the size of the CIE now that we know it.
134 PatchInt32(size_offset, encoded_cie_size);
135 }
136
WriteFdeHeader()137 void EhFrameWriter::WriteFdeHeader() {
138 DCHECK_NE(cie_size_, 0);
139
140 // Placeholder for size of the FDE. Will be filled in Finish().
141 DCHECK_EQ(eh_frame_offset(), fde_offset());
142 WriteInt32(kInt32Placeholder);
143
144 // Backwards offset to the CIE.
145 WriteInt32(cie_size_ + kInt32Size);
146
147 // Placeholder for pointer to procedure. Will be filled in Finish().
148 DCHECK_EQ(eh_frame_offset(), GetProcedureAddressOffset());
149 WriteInt32(kInt32Placeholder);
150
151 // Placeholder for size of the procedure. Will be filled in Finish().
152 DCHECK_EQ(eh_frame_offset(), GetProcedureSizeOffset());
153 WriteInt32(kInt32Placeholder);
154
155 // No augmentation data.
156 WriteByte(0);
157 }
158
WriteEhFrameHdr(int code_size)159 void EhFrameWriter::WriteEhFrameHdr(int code_size) {
160 DCHECK_EQ(writer_state_, InternalState::kInitialized);
161
162 //
163 // In order to calculate offsets in the .eh_frame_hdr, we must know the layout
164 // of the DSO generated by perf inject, which is assumed to be the following:
165 //
166 // | ... | |
167 // +---------------+ <-- (F) --- | Larger offsets in file
168 // | | ^ |
169 // | Instructions | | .text v
170 // | | v
171 // +---------------+ <-- (E) ---
172 // |///////////////|
173 // |////Padding////|
174 // |///////////////|
175 // +---------------+ <-- (D) ---
176 // | | ^
177 // | CIE | |
178 // | | |
179 // +---------------+ <-- (C) |
180 // | | | .eh_frame
181 // | FDE | |
182 // | | |
183 // +---------------+ |
184 // | terminator | v
185 // +---------------+ <-- (B) ---
186 // | version | ^
187 // +---------------+ |
188 // | encoding | |
189 // | specifiers | |
190 // +---------------+ <---(A) | .eh_frame_hdr
191 // | offset to | |
192 // | .eh_frame | |
193 // +---------------+ |
194 // | ... | ...
195 //
196 // (F) is aligned to a 16-byte boundary.
197 // (D) is aligned to a 8-byte boundary.
198 // (B) is aligned to a 4-byte boundary.
199 // (C), (E) and (A) have no alignment requirements.
200 //
201 // The distance between (A) and (B) is 4 bytes.
202 //
203 // The size of the FDE is required to be a multiple of the pointer size, which
204 // means that (B) will be naturally aligned to a 4-byte boundary on all the
205 // architectures we support.
206 //
207 // Because (E) has no alignment requirements, there is padding between (E) and
208 // (D). (F) is aligned at a 16-byte boundary, thus to a 8-byte one as well.
209 //
210
211 int eh_frame_size = eh_frame_offset();
212
213 WriteByte(EhFrameConstants::kEhFrameHdrVersion);
214
215 // .eh_frame pointer encoding specifier.
216 WriteByte(EhFrameConstants::kSData4 | EhFrameConstants::kPcRel);
217 // Lookup table size encoding specifier.
218 WriteByte(EhFrameConstants::kUData4);
219 // Lookup table entries encoding specifier.
220 WriteByte(EhFrameConstants::kSData4 | EhFrameConstants::kDataRel);
221
222 // Pointer to .eh_frame, relative to this offset (A -> D in the diagram).
223 WriteInt32(-(eh_frame_size + EhFrameConstants::kFdeVersionSize +
224 EhFrameConstants::kFdeEncodingSpecifiersSize));
225
226 // Number of entries in the LUT, one for the only routine.
227 WriteInt32(1);
228
229 // Pointer to the start of the routine, relative to the beginning of the
230 // .eh_frame_hdr (B -> F in the diagram).
231 WriteInt32(-(RoundUp(code_size, 8) + eh_frame_size));
232
233 // Pointer to the start of the associated FDE, relative to the start of the
234 // .eh_frame_hdr (B -> C in the diagram).
235 WriteInt32(-(eh_frame_size - cie_size_));
236
237 DCHECK_EQ(eh_frame_offset() - eh_frame_size,
238 EhFrameConstants::kEhFrameHdrSize);
239 }
240
WritePaddingToAlignedSize(int unpadded_size)241 void EhFrameWriter::WritePaddingToAlignedSize(int unpadded_size) {
242 DCHECK_EQ(writer_state_, InternalState::kInitialized);
243 DCHECK_GE(unpadded_size, 0);
244
245 int padding_size = RoundUp(unpadded_size, kSystemPointerSize) - unpadded_size;
246
247 byte nop = static_cast<byte>(EhFrameConstants::DwarfOpcodes::kNop);
248 static const byte kPadding[] = {nop, nop, nop, nop, nop, nop, nop, nop};
249 DCHECK_LE(padding_size, static_cast<int>(sizeof(kPadding)));
250 WriteBytes(&kPadding[0], padding_size);
251 }
252
AdvanceLocation(int pc_offset)253 void EhFrameWriter::AdvanceLocation(int pc_offset) {
254 DCHECK_EQ(writer_state_, InternalState::kInitialized);
255 DCHECK_GE(pc_offset, last_pc_offset_);
256 uint32_t delta = pc_offset - last_pc_offset_;
257
258 DCHECK_EQ(delta % EhFrameConstants::kCodeAlignmentFactor, 0u);
259 uint32_t factored_delta = delta / EhFrameConstants::kCodeAlignmentFactor;
260
261 if (factored_delta <= EhFrameConstants::kLocationMask) {
262 WriteByte((EhFrameConstants::kLocationTag
263 << EhFrameConstants::kLocationMaskSize) |
264 (factored_delta & EhFrameConstants::kLocationMask));
265 } else if (factored_delta <= kMaxUInt8) {
266 WriteOpcode(EhFrameConstants::DwarfOpcodes::kAdvanceLoc1);
267 WriteByte(factored_delta);
268 } else if (factored_delta <= kMaxUInt16) {
269 WriteOpcode(EhFrameConstants::DwarfOpcodes::kAdvanceLoc2);
270 WriteInt16(factored_delta);
271 } else {
272 WriteOpcode(EhFrameConstants::DwarfOpcodes::kAdvanceLoc4);
273 WriteInt32(factored_delta);
274 }
275
276 last_pc_offset_ = pc_offset;
277 }
278
SetBaseAddressOffset(int base_offset)279 void EhFrameWriter::SetBaseAddressOffset(int base_offset) {
280 DCHECK_EQ(writer_state_, InternalState::kInitialized);
281 DCHECK_GE(base_offset, 0);
282 WriteOpcode(EhFrameConstants::DwarfOpcodes::kDefCfaOffset);
283 WriteULeb128(base_offset);
284 base_offset_ = base_offset;
285 }
286
SetBaseAddressRegister(Register base_register)287 void EhFrameWriter::SetBaseAddressRegister(Register base_register) {
288 DCHECK_EQ(writer_state_, InternalState::kInitialized);
289 int code = RegisterToDwarfCode(base_register);
290 WriteOpcode(EhFrameConstants::DwarfOpcodes::kDefCfaRegister);
291 WriteULeb128(code);
292 base_register_ = base_register;
293 }
294
SetBaseAddressRegisterAndOffset(Register base_register,int base_offset)295 void EhFrameWriter::SetBaseAddressRegisterAndOffset(Register base_register,
296 int base_offset) {
297 DCHECK_EQ(writer_state_, InternalState::kInitialized);
298 DCHECK_GE(base_offset, 0);
299 int code = RegisterToDwarfCode(base_register);
300 WriteOpcode(EhFrameConstants::DwarfOpcodes::kDefCfa);
301 WriteULeb128(code);
302 WriteULeb128(base_offset);
303 base_offset_ = base_offset;
304 base_register_ = base_register;
305 }
306
RecordRegisterSavedToStack(int dwarf_register_code,int offset)307 void EhFrameWriter::RecordRegisterSavedToStack(int dwarf_register_code,
308 int offset) {
309 DCHECK_EQ(writer_state_, InternalState::kInitialized);
310 DCHECK_EQ(offset % EhFrameConstants::kDataAlignmentFactor, 0);
311 int factored_offset = offset / EhFrameConstants::kDataAlignmentFactor;
312 if (factored_offset >= 0) {
313 DCHECK_LE(dwarf_register_code, EhFrameConstants::kSavedRegisterMask);
314 WriteByte((EhFrameConstants::kSavedRegisterTag
315 << EhFrameConstants::kSavedRegisterMaskSize) |
316 (dwarf_register_code & EhFrameConstants::kSavedRegisterMask));
317 WriteULeb128(factored_offset);
318 } else {
319 WriteOpcode(EhFrameConstants::DwarfOpcodes::kOffsetExtendedSf);
320 WriteULeb128(dwarf_register_code);
321 WriteSLeb128(factored_offset);
322 }
323 }
324
RecordRegisterNotModified(Register name)325 void EhFrameWriter::RecordRegisterNotModified(Register name) {
326 RecordRegisterNotModified(RegisterToDwarfCode(name));
327 }
328
RecordRegisterNotModified(int dwarf_register_code)329 void EhFrameWriter::RecordRegisterNotModified(int dwarf_register_code) {
330 DCHECK_EQ(writer_state_, InternalState::kInitialized);
331 WriteOpcode(EhFrameConstants::DwarfOpcodes::kSameValue);
332 WriteULeb128(dwarf_register_code);
333 }
334
RecordRegisterFollowsInitialRule(Register name)335 void EhFrameWriter::RecordRegisterFollowsInitialRule(Register name) {
336 RecordRegisterFollowsInitialRule(RegisterToDwarfCode(name));
337 }
338
RecordRegisterFollowsInitialRule(int dwarf_register_code)339 void EhFrameWriter::RecordRegisterFollowsInitialRule(int dwarf_register_code) {
340 DCHECK_EQ(writer_state_, InternalState::kInitialized);
341 if (dwarf_register_code <= EhFrameConstants::kFollowInitialRuleMask) {
342 WriteByte((EhFrameConstants::kFollowInitialRuleTag
343 << EhFrameConstants::kFollowInitialRuleMaskSize) |
344 (dwarf_register_code & EhFrameConstants::kFollowInitialRuleMask));
345 } else {
346 WriteOpcode(EhFrameConstants::DwarfOpcodes::kRestoreExtended);
347 WriteULeb128(dwarf_register_code);
348 }
349 }
350
Finish(int code_size)351 void EhFrameWriter::Finish(int code_size) {
352 DCHECK_EQ(writer_state_, InternalState::kInitialized);
353 DCHECK_GE(eh_frame_offset(), cie_size_);
354
355 DCHECK_GE(eh_frame_offset(), fde_offset() + kInt32Size);
356 WritePaddingToAlignedSize(eh_frame_offset() - fde_offset() - kInt32Size);
357
358 // Write the size of the FDE now that we know it.
359 // The encoded size does not include the size field itself.
360 int encoded_fde_size = eh_frame_offset() - fde_offset() - kInt32Size;
361 PatchInt32(fde_offset(), encoded_fde_size);
362
363 // Write size and offset to procedure.
364 PatchInt32(GetProcedureAddressOffset(),
365 -(RoundUp(code_size, 8) + GetProcedureAddressOffset()));
366 PatchInt32(GetProcedureSizeOffset(), code_size);
367
368 // Terminate the .eh_frame.
369 static const byte kTerminator[EhFrameConstants::kEhFrameTerminatorSize] = {0};
370 WriteBytes(&kTerminator[0], EhFrameConstants::kEhFrameTerminatorSize);
371
372 WriteEhFrameHdr(code_size);
373
374 writer_state_ = InternalState::kFinalized;
375 }
376
GetEhFrame(CodeDesc * desc)377 void EhFrameWriter::GetEhFrame(CodeDesc* desc) {
378 DCHECK_EQ(writer_state_, InternalState::kFinalized);
379 desc->unwinding_info_size = static_cast<int>(eh_frame_buffer_.size());
380 desc->unwinding_info = eh_frame_buffer_.data();
381 }
382
WriteULeb128(uint32_t value)383 void EhFrameWriter::WriteULeb128(uint32_t value) {
384 do {
385 byte chunk = value & 0x7F;
386 value >>= 7;
387 if (value != 0) chunk |= 0x80;
388 WriteByte(chunk);
389 } while (value != 0);
390 }
391
WriteSLeb128(int32_t value)392 void EhFrameWriter::WriteSLeb128(int32_t value) {
393 static const int kSignBitMask = 0x40;
394 bool done;
395 do {
396 byte chunk = value & 0x7F;
397 value >>= 7;
398 done = ((value == 0) && ((chunk & kSignBitMask) == 0)) ||
399 ((value == -1) && ((chunk & kSignBitMask) != 0));
400 if (!done) chunk |= 0x80;
401 WriteByte(chunk);
402 } while (!done);
403 }
404
GetNextULeb128()405 uint32_t EhFrameIterator::GetNextULeb128() {
406 int size = 0;
407 uint32_t result = DecodeULeb128(next_, &size);
408 DCHECK_LE(next_ + size, end_);
409 next_ += size;
410 return result;
411 }
412
GetNextSLeb128()413 int32_t EhFrameIterator::GetNextSLeb128() {
414 int size = 0;
415 int32_t result = DecodeSLeb128(next_, &size);
416 DCHECK_LE(next_ + size, end_);
417 next_ += size;
418 return result;
419 }
420
421 // static
DecodeULeb128(const byte * encoded,int * encoded_size)422 uint32_t EhFrameIterator::DecodeULeb128(const byte* encoded,
423 int* encoded_size) {
424 const byte* current = encoded;
425 uint32_t result = 0;
426 int shift = 0;
427
428 do {
429 DCHECK_LT(shift, 8 * static_cast<int>(sizeof(result)));
430 result |= (*current & 0x7F) << shift;
431 shift += 7;
432 } while (*current++ >= 128);
433
434 DCHECK_NOT_NULL(encoded_size);
435 *encoded_size = static_cast<int>(current - encoded);
436
437 return result;
438 }
439
440 // static
DecodeSLeb128(const byte * encoded,int * encoded_size)441 int32_t EhFrameIterator::DecodeSLeb128(const byte* encoded, int* encoded_size) {
442 static const byte kSignBitMask = 0x40;
443
444 const byte* current = encoded;
445 int32_t result = 0;
446 int shift = 0;
447 byte chunk;
448
449 do {
450 chunk = *current++;
451 DCHECK_LT(shift, 8 * static_cast<int>(sizeof(result)));
452 result |= (chunk & 0x7F) << shift;
453 shift += 7;
454 } while (chunk >= 128);
455
456 // Sign extend the result if the last chunk has the sign bit set.
457 if (chunk & kSignBitMask) result |= (~0ull) << shift;
458
459 DCHECK_NOT_NULL(encoded_size);
460 *encoded_size = static_cast<int>(current - encoded);
461
462 return result;
463 }
464
465 #ifdef ENABLE_DISASSEMBLER
466
467 namespace {
468
469 class StreamModifiersScope final {
470 public:
StreamModifiersScope(std::ostream * stream)471 explicit StreamModifiersScope(std::ostream* stream)
472 : stream_(stream), flags_(stream->flags()) {}
~StreamModifiersScope()473 ~StreamModifiersScope() { stream_->flags(flags_); }
474
475 private:
476 std::ostream* stream_;
477 std::ios::fmtflags flags_;
478 };
479
480 } // namespace
481
482 // static
DumpDwarfDirectives(std::ostream & stream,const byte * start,const byte * end)483 void EhFrameDisassembler::DumpDwarfDirectives(std::ostream& stream, // NOLINT
484 const byte* start,
485 const byte* end) {
486 StreamModifiersScope modifiers_scope(&stream);
487
488 EhFrameIterator eh_frame_iterator(start, end);
489 uint32_t offset_in_procedure = 0;
490
491 while (!eh_frame_iterator.Done()) {
492 stream << eh_frame_iterator.current_address() << " ";
493
494 byte bytecode = eh_frame_iterator.GetNextByte();
495
496 if (((bytecode >> EhFrameConstants::kLocationMaskSize) & 0xFF) ==
497 EhFrameConstants::kLocationTag) {
498 int value = (bytecode & EhFrameConstants::kLocationMask) *
499 EhFrameConstants::kCodeAlignmentFactor;
500 offset_in_procedure += value;
501 stream << "| pc_offset=" << offset_in_procedure << " (delta=" << value
502 << ")\n";
503 continue;
504 }
505
506 if (((bytecode >> EhFrameConstants::kSavedRegisterMaskSize) & 0xFF) ==
507 EhFrameConstants::kSavedRegisterTag) {
508 int32_t decoded_offset = eh_frame_iterator.GetNextULeb128();
509 stream << "| "
510 << DwarfRegisterCodeToString(bytecode &
511 EhFrameConstants::kLocationMask)
512 << " saved at base" << std::showpos
513 << decoded_offset * EhFrameConstants::kDataAlignmentFactor
514 << std::noshowpos << '\n';
515 continue;
516 }
517
518 if (((bytecode >> EhFrameConstants::kFollowInitialRuleMaskSize) & 0xFF) ==
519 EhFrameConstants::kFollowInitialRuleTag) {
520 stream << "| "
521 << DwarfRegisterCodeToString(bytecode &
522 EhFrameConstants::kLocationMask)
523 << " follows rule in CIE\n";
524 continue;
525 }
526
527 switch (static_cast<EhFrameConstants::DwarfOpcodes>(bytecode)) {
528 case EhFrameConstants::DwarfOpcodes::kOffsetExtendedSf: {
529 stream << "| "
530 << DwarfRegisterCodeToString(eh_frame_iterator.GetNextULeb128());
531 int32_t decoded_offset = eh_frame_iterator.GetNextSLeb128();
532 stream << " saved at base" << std::showpos
533 << decoded_offset * EhFrameConstants::kDataAlignmentFactor
534 << std::noshowpos << '\n';
535 break;
536 }
537 case EhFrameConstants::DwarfOpcodes::kAdvanceLoc1: {
538 int value = eh_frame_iterator.GetNextByte() *
539 EhFrameConstants::kCodeAlignmentFactor;
540 offset_in_procedure += value;
541 stream << "| pc_offset=" << offset_in_procedure << " (delta=" << value
542 << ")\n";
543 break;
544 }
545 case EhFrameConstants::DwarfOpcodes::kAdvanceLoc2: {
546 int value = eh_frame_iterator.GetNextUInt16() *
547 EhFrameConstants::kCodeAlignmentFactor;
548 offset_in_procedure += value;
549 stream << "| pc_offset=" << offset_in_procedure << " (delta=" << value
550 << ")\n";
551 break;
552 }
553 case EhFrameConstants::DwarfOpcodes::kAdvanceLoc4: {
554 int value = eh_frame_iterator.GetNextUInt32() *
555 EhFrameConstants::kCodeAlignmentFactor;
556 offset_in_procedure += value;
557 stream << "| pc_offset=" << offset_in_procedure << " (delta=" << value
558 << ")\n";
559 break;
560 }
561 case EhFrameConstants::DwarfOpcodes::kDefCfa: {
562 uint32_t base_register = eh_frame_iterator.GetNextULeb128();
563 uint32_t base_offset = eh_frame_iterator.GetNextULeb128();
564 stream << "| base_register=" << DwarfRegisterCodeToString(base_register)
565 << ", base_offset=" << base_offset << '\n';
566 break;
567 }
568 case EhFrameConstants::DwarfOpcodes::kDefCfaOffset: {
569 stream << "| base_offset=" << eh_frame_iterator.GetNextULeb128()
570 << '\n';
571 break;
572 }
573 case EhFrameConstants::DwarfOpcodes::kDefCfaRegister: {
574 stream << "| base_register="
575 << DwarfRegisterCodeToString(eh_frame_iterator.GetNextULeb128())
576 << '\n';
577 break;
578 }
579 case EhFrameConstants::DwarfOpcodes::kSameValue: {
580 stream << "| "
581 << DwarfRegisterCodeToString(eh_frame_iterator.GetNextULeb128())
582 << " not modified from previous frame\n";
583 break;
584 }
585 case EhFrameConstants::DwarfOpcodes::kNop:
586 stream << "| nop\n";
587 break;
588 default:
589 UNREACHABLE();
590 return;
591 }
592 }
593 }
594
DisassembleToStream(std::ostream & stream)595 void EhFrameDisassembler::DisassembleToStream(std::ostream& stream) { // NOLINT
596 // The encoded CIE size does not include the size field itself.
597 const int cie_size =
598 base::ReadUnalignedValue<uint32_t>(reinterpret_cast<Address>(start_)) +
599 kInt32Size;
600 const int fde_offset = cie_size;
601
602 const byte* cie_directives_start =
603 start_ + EhFrameConstants::kInitialStateOffsetInCie;
604 const byte* cie_directives_end = start_ + cie_size;
605 DCHECK_LE(cie_directives_start, cie_directives_end);
606
607 stream << reinterpret_cast<const void*>(start_) << " .eh_frame: CIE\n";
608 DumpDwarfDirectives(stream, cie_directives_start, cie_directives_end);
609
610 Address procedure_offset_address =
611 reinterpret_cast<Address>(start_) + fde_offset +
612 EhFrameConstants::kProcedureAddressOffsetInFde;
613 int32_t procedure_offset =
614 base::ReadUnalignedValue<int32_t>(procedure_offset_address);
615
616 Address procedure_size_address = reinterpret_cast<Address>(start_) +
617 fde_offset +
618 EhFrameConstants::kProcedureSizeOffsetInFde;
619 uint32_t procedure_size =
620 base::ReadUnalignedValue<uint32_t>(procedure_size_address);
621
622 const byte* fde_start = start_ + fde_offset;
623 stream << reinterpret_cast<const void*>(fde_start) << " .eh_frame: FDE\n"
624 << reinterpret_cast<const void*>(procedure_offset_address)
625 << " | procedure_offset=" << procedure_offset << '\n'
626 << reinterpret_cast<const void*>(procedure_size_address)
627 << " | procedure_size=" << procedure_size << '\n';
628
629 const int fde_directives_offset = fde_offset + 4 * kInt32Size + 1;
630
631 const byte* fde_directives_start = start_ + fde_directives_offset;
632 const byte* fde_directives_end = end_ - EhFrameConstants::kEhFrameHdrSize -
633 EhFrameConstants::kEhFrameTerminatorSize;
634 DCHECK_LE(fde_directives_start, fde_directives_end);
635
636 DumpDwarfDirectives(stream, fde_directives_start, fde_directives_end);
637
638 const byte* fde_terminator_start = fde_directives_end;
639 stream << reinterpret_cast<const void*>(fde_terminator_start)
640 << " .eh_frame: terminator\n";
641
642 const byte* eh_frame_hdr_start =
643 fde_terminator_start + EhFrameConstants::kEhFrameTerminatorSize;
644 stream << reinterpret_cast<const void*>(eh_frame_hdr_start)
645 << " .eh_frame_hdr\n";
646 }
647
648 #endif
649
650 } // namespace internal
651 } // namespace v8
652