Home | History | Annotate | Download | only in DebugInfo
      1 //===-- DWARFDebugFrame.h - Parsing of .debug_frame -------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "DWARFDebugFrame.h"
     11 #include "llvm/ADT/SmallString.h"
     12 #include "llvm/Support/DataTypes.h"
     13 #include "llvm/Support/ErrorHandling.h"
     14 #include "llvm/Support/Dwarf.h"
     15 #include "llvm/Support/Format.h"
     16 #include "llvm/Support/raw_ostream.h"
     17 #include <string>
     18 #include <vector>
     19 
     20 using namespace llvm;
     21 using namespace dwarf;
     22 
     23 
     24 /// \brief Abstract frame entry defining the common interface concrete
     25 /// entries implement.
     26 class llvm::FrameEntry {
     27 public:
     28   enum FrameKind {FK_CIE, FK_FDE};
     29   FrameEntry(FrameKind K, DataExtractor D, uint64_t Offset, uint64_t Length)
     30     : Kind(K), Data(D), Offset(Offset), Length(Length) {}
     31 
     32   virtual ~FrameEntry() {
     33   }
     34 
     35   FrameKind getKind() const { return Kind; }
     36   virtual uint64_t getOffset() const { return Offset; }
     37 
     38   /// \brief Parse and store a sequence of CFI instructions from our data
     39   /// stream, starting at *Offset and ending at EndOffset. If everything
     40   /// goes well, *Offset should be equal to EndOffset when this method
     41   /// returns. Otherwise, an error occurred.
     42   virtual void parseInstructions(uint32_t *Offset, uint32_t EndOffset);
     43 
     44   /// \brief Dump the entry header to the given output stream.
     45   virtual void dumpHeader(raw_ostream &OS) const = 0;
     46 
     47   /// \brief Dump the entry's instructions to the given output stream.
     48   virtual void dumpInstructions(raw_ostream &OS) const;
     49 
     50 protected:
     51   const FrameKind Kind;
     52 
     53   /// \brief The data stream holding the section from which the entry was
     54   /// parsed.
     55   DataExtractor Data;
     56 
     57   /// \brief Offset of this entry in the section.
     58   uint64_t Offset;
     59 
     60   /// \brief Entry length as specified in DWARF.
     61   uint64_t Length;
     62 
     63   /// An entry may contain CFI instructions. An instruction consists of an
     64   /// opcode and an optional sequence of operands.
     65   typedef std::vector<uint64_t> Operands;
     66   struct Instruction {
     67     Instruction(uint8_t Opcode)
     68       : Opcode(Opcode)
     69     {}
     70 
     71     uint8_t Opcode;
     72     Operands Ops;
     73   };
     74 
     75   std::vector<Instruction> Instructions;
     76 
     77   /// Convenience methods to add a new instruction with the given opcode and
     78   /// operands to the Instructions vector.
     79   void addInstruction(uint8_t Opcode) {
     80     Instructions.push_back(Instruction(Opcode));
     81   }
     82 
     83   void addInstruction(uint8_t Opcode, uint64_t Operand1) {
     84     Instructions.push_back(Instruction(Opcode));
     85     Instructions.back().Ops.push_back(Operand1);
     86   }
     87 
     88   void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) {
     89     Instructions.push_back(Instruction(Opcode));
     90     Instructions.back().Ops.push_back(Operand1);
     91     Instructions.back().Ops.push_back(Operand2);
     92   }
     93 };
     94 
     95 
     96 // See DWARF standard v3, section 7.23
     97 const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
     98 const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f;
     99 
    100 
    101 void FrameEntry::parseInstructions(uint32_t *Offset, uint32_t EndOffset) {
    102   while (*Offset < EndOffset) {
    103     uint8_t Opcode = Data.getU8(Offset);
    104     // Some instructions have a primary opcode encoded in the top bits.
    105     uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK;
    106 
    107     if (Primary) {
    108       // If it's a primary opcode, the first operand is encoded in the bottom
    109       // bits of the opcode itself.
    110       uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK;
    111       switch (Primary) {
    112         default: llvm_unreachable("Impossible primary CFI opcode");
    113         case DW_CFA_advance_loc:
    114         case DW_CFA_restore:
    115           addInstruction(Primary, Op1);
    116           break;
    117         case DW_CFA_offset:
    118           addInstruction(Primary, Op1, Data.getULEB128(Offset));
    119           break;
    120       }
    121     } else {
    122       // Extended opcode - its value is Opcode itself.
    123       switch (Opcode) {
    124         default: llvm_unreachable("Invalid extended CFI opcode");
    125         case DW_CFA_nop:
    126         case DW_CFA_remember_state:
    127         case DW_CFA_restore_state:
    128           // No operands
    129           addInstruction(Opcode);
    130           break;
    131         case DW_CFA_set_loc:
    132           // Operands: Address
    133           addInstruction(Opcode, Data.getAddress(Offset));
    134           break;
    135         case DW_CFA_advance_loc1:
    136           // Operands: 1-byte delta
    137           addInstruction(Opcode, Data.getU8(Offset));
    138           break;
    139         case DW_CFA_advance_loc2:
    140           // Operands: 2-byte delta
    141           addInstruction(Opcode, Data.getU16(Offset));
    142           break;
    143         case DW_CFA_advance_loc4:
    144           // Operands: 4-byte delta
    145           addInstruction(Opcode, Data.getU32(Offset));
    146           break;
    147         case DW_CFA_restore_extended:
    148         case DW_CFA_undefined:
    149         case DW_CFA_same_value:
    150         case DW_CFA_def_cfa_register:
    151         case DW_CFA_def_cfa_offset:
    152           // Operands: ULEB128
    153           addInstruction(Opcode, Data.getULEB128(Offset));
    154           break;
    155         case DW_CFA_def_cfa_offset_sf:
    156           // Operands: SLEB128
    157           addInstruction(Opcode, Data.getSLEB128(Offset));
    158           break;
    159         case DW_CFA_offset_extended:
    160         case DW_CFA_register:
    161         case DW_CFA_def_cfa:
    162         case DW_CFA_val_offset:
    163           // Operands: ULEB128, ULEB128
    164           addInstruction(Opcode, Data.getULEB128(Offset),
    165                                  Data.getULEB128(Offset));
    166           break;
    167         case DW_CFA_offset_extended_sf:
    168         case DW_CFA_def_cfa_sf:
    169         case DW_CFA_val_offset_sf:
    170           // Operands: ULEB128, SLEB128
    171           addInstruction(Opcode, Data.getULEB128(Offset),
    172                                  Data.getSLEB128(Offset));
    173           break;
    174         case DW_CFA_def_cfa_expression:
    175         case DW_CFA_expression:
    176         case DW_CFA_val_expression:
    177           // TODO: implement this
    178           report_fatal_error("Values with expressions not implemented yet!");
    179       }
    180     }
    181   }
    182 }
    183 
    184 
    185 void FrameEntry::dumpInstructions(raw_ostream &OS) const {
    186   // TODO: at the moment only instruction names are dumped. Expand this to
    187   // dump operands as well.
    188   for (std::vector<Instruction>::const_iterator I = Instructions.begin(),
    189                                                 E = Instructions.end();
    190        I != E; ++I) {
    191     uint8_t Opcode = I->Opcode;
    192     if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK)
    193       Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK;
    194     OS << "  " << CallFrameString(Opcode) << ":\n";
    195   }
    196 }
    197 
    198 
    199 namespace {
    200 /// \brief DWARF Common Information Entry (CIE)
    201 class CIE : public FrameEntry {
    202 public:
    203   // CIEs (and FDEs) are simply container classes, so the only sensible way to
    204   // create them is by providing the full parsed contents in the constructor.
    205   CIE(DataExtractor D, uint64_t Offset, uint64_t Length, uint8_t Version,
    206       SmallString<8> Augmentation, uint64_t CodeAlignmentFactor,
    207       int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister)
    208    : FrameEntry(FK_CIE, D, Offset, Length), Version(Version),
    209      Augmentation(Augmentation), CodeAlignmentFactor(CodeAlignmentFactor),
    210      DataAlignmentFactor(DataAlignmentFactor),
    211      ReturnAddressRegister(ReturnAddressRegister) {}
    212 
    213   ~CIE() {
    214   }
    215 
    216   void dumpHeader(raw_ostream &OS) const {
    217     OS << format("%08x %08x %08x CIE",
    218                  (uint32_t)Offset, (uint32_t)Length, DW_CIE_ID)
    219        << "\n";
    220     OS << format("  Version:               %d\n", Version);
    221     OS << "  Augmentation:          \"" << Augmentation << "\"\n";
    222     OS << format("  Code alignment factor: %u\n",
    223                  (uint32_t)CodeAlignmentFactor);
    224     OS << format("  Data alignment factor: %d\n",
    225                  (int32_t)DataAlignmentFactor);
    226     OS << format("  Return address column: %d\n",
    227                  (int32_t)ReturnAddressRegister);
    228     OS << "\n";
    229   }
    230 
    231   static bool classof(const FrameEntry *FE) {
    232     return FE->getKind() == FK_CIE;
    233   }
    234 
    235 private:
    236   /// The following fields are defined in section 6.4.1 of the DWARF standard v3
    237   uint8_t Version;
    238   SmallString<8> Augmentation;
    239   uint64_t CodeAlignmentFactor;
    240   int64_t DataAlignmentFactor;
    241   uint64_t ReturnAddressRegister;
    242 };
    243 
    244 
    245 /// \brief DWARF Frame Description Entry (FDE)
    246 class FDE : public FrameEntry {
    247 public:
    248   // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with
    249   // an offset to the CIE (provided by parsing the FDE header). The CIE itself
    250   // is obtained lazily once it's actually required.
    251   FDE(DataExtractor D, uint64_t Offset, uint64_t Length,
    252       int64_t LinkedCIEOffset, uint64_t InitialLocation, uint64_t AddressRange)
    253    : FrameEntry(FK_FDE, D, Offset, Length), LinkedCIEOffset(LinkedCIEOffset),
    254      InitialLocation(InitialLocation), AddressRange(AddressRange),
    255      LinkedCIE(NULL) {}
    256 
    257   ~FDE() {
    258   }
    259 
    260   void dumpHeader(raw_ostream &OS) const {
    261     OS << format("%08x %08x %08x FDE ",
    262                  (uint32_t)Offset, (uint32_t)Length, (int32_t)LinkedCIEOffset);
    263     OS << format("cie=%08x pc=%08x...%08x\n",
    264                  (int32_t)LinkedCIEOffset,
    265                  (uint32_t)InitialLocation,
    266                  (uint32_t)InitialLocation + (uint32_t)AddressRange);
    267     if (LinkedCIE) {
    268       OS << format("%p\n", LinkedCIE);
    269     }
    270   }
    271 
    272   static bool classof(const FrameEntry *FE) {
    273     return FE->getKind() == FK_FDE;
    274   }
    275 private:
    276 
    277   /// The following fields are defined in section 6.4.1 of the DWARF standard v3
    278   uint64_t LinkedCIEOffset;
    279   uint64_t InitialLocation;
    280   uint64_t AddressRange;
    281   CIE *LinkedCIE;
    282 };
    283 } // end anonymous namespace
    284 
    285 
    286 DWARFDebugFrame::DWARFDebugFrame() {
    287 }
    288 
    289 
    290 DWARFDebugFrame::~DWARFDebugFrame() {
    291   for (EntryVector::iterator I = Entries.begin(), E = Entries.end();
    292        I != E; ++I) {
    293     delete *I;
    294   }
    295 }
    296 
    297 
    298 static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
    299                                               uint32_t Offset, int Length) {
    300   errs() << "DUMP: ";
    301   for (int i = 0; i < Length; ++i) {
    302     uint8_t c = Data.getU8(&Offset);
    303     errs().write_hex(c); errs() << " ";
    304   }
    305   errs() << "\n";
    306 }
    307 
    308 
    309 void DWARFDebugFrame::parse(DataExtractor Data) {
    310   uint32_t Offset = 0;
    311 
    312   while (Data.isValidOffset(Offset)) {
    313     uint32_t StartOffset = Offset;
    314 
    315     bool IsDWARF64 = false;
    316     uint64_t Length = Data.getU32(&Offset);
    317     uint64_t Id;
    318 
    319     if (Length == UINT32_MAX) {
    320       // DWARF-64 is distinguished by the first 32 bits of the initial length
    321       // field being 0xffffffff. Then, the next 64 bits are the actual entry
    322       // length.
    323       IsDWARF64 = true;
    324       Length = Data.getU64(&Offset);
    325     }
    326 
    327     // At this point, Offset points to the next field after Length.
    328     // Length is the structure size excluding itself. Compute an offset one
    329     // past the end of the structure (needed to know how many instructions to
    330     // read).
    331     // TODO: For honest DWARF64 support, DataExtractor will have to treat
    332     //       offset_ptr as uint64_t*
    333     uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length);
    334 
    335     // The Id field's size depends on the DWARF format
    336     Id = Data.getUnsigned(&Offset, IsDWARF64 ? 8 : 4);
    337     bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID);
    338 
    339     FrameEntry *Entry = 0;
    340     if (IsCIE) {
    341       // Note: this is specifically DWARFv3 CIE header structure. It was
    342       // changed in DWARFv4. We currently don't support reading DWARFv4
    343       // here because LLVM itself does not emit it (and LLDB doesn't
    344       // support it either).
    345       uint8_t Version = Data.getU8(&Offset);
    346       const char *Augmentation = Data.getCStr(&Offset);
    347       uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
    348       int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
    349       uint64_t ReturnAddressRegister = Data.getULEB128(&Offset);
    350 
    351       Entry = new CIE(Data, StartOffset, Length, Version,
    352                       StringRef(Augmentation), CodeAlignmentFactor,
    353                       DataAlignmentFactor, ReturnAddressRegister);
    354     } else {
    355       // FDE
    356       uint64_t CIEPointer = Id;
    357       uint64_t InitialLocation = Data.getAddress(&Offset);
    358       uint64_t AddressRange = Data.getAddress(&Offset);
    359 
    360       Entry = new FDE(Data, StartOffset, Length, CIEPointer,
    361                       InitialLocation, AddressRange);
    362     }
    363 
    364     assert(Entry && "Expected Entry to be populated with CIE or FDE");
    365     Entry->parseInstructions(&Offset, EndStructureOffset);
    366 
    367     if (Offset == EndStructureOffset) {
    368       // Entry instrucitons parsed successfully.
    369       Entries.push_back(Entry);
    370     } else {
    371       std::string Str;
    372       raw_string_ostream OS(Str);
    373       OS << format("Parsing entry instructions at %lx failed",
    374                    Entry->getOffset());
    375       report_fatal_error(Str);
    376     }
    377   }
    378 }
    379 
    380 
    381 void DWARFDebugFrame::dump(raw_ostream &OS) const {
    382   OS << "\n";
    383   for (EntryVector::const_iterator I = Entries.begin(), E = Entries.end();
    384        I != E; ++I) {
    385     FrameEntry *Entry = *I;
    386     Entry->dumpHeader(OS);
    387     Entry->dumpInstructions(OS);
    388     OS << "\n";
    389   }
    390 }
    391 
    392