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