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