Index: lib/DebugInfo/DWARFDebugFrame.cpp =================================================================== --- lib/DebugInfo/DWARFDebugFrame.cpp +++ lib/DebugInfo/DWARFDebugFrame.cpp @@ -14,6 +14,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include #include #include @@ -47,6 +48,15 @@ /// \brief Dump the entry's instructions to the given output stream. virtual void dumpInstructions(raw_ostream &OS) const; + /// \brief Return the unsigned code alignment factor. + virtual uint64_t getCodeAlignmentFactor() const = 0; + + /// \brief Return the signed data alignment factor. + virtual int64_t getDataAlignmentFactor() const = 0; + + /// \brief Return address of the first instruction described by the frame. + virtual uint64_t getInitialLocation() const = 0; + protected: const FrameKind Kind; @@ -68,6 +78,18 @@ : Opcode(Opcode) {} + uint64_t getUnsignedOperand(int index) const { + return Ops.at(index); + } + + int64_t getSignedOperand(int index) const { + return (int64_t)Ops.at(index); + } + + int32_t getRegisterOperand(int index) const { + return (int32_t)Ops.at(index); + } + uint8_t Opcode; Operands Ops; }; @@ -90,6 +112,14 @@ Instructions.back().Ops.push_back(Operand1); Instructions.back().Ops.push_back(Operand2); } + + /// Convenience method for printing register names + void printRegister(raw_ostream &OS, int dwarfRegNum) const { + // TODO: It would be nice to convert from dwarf register numbers + // to actual target register names. + OS << "r" << dwarfRegNum; + } + }; @@ -120,6 +150,7 @@ } } else { // Extended opcode - its value is Opcode itself. + uint64_t Op1; switch (Opcode) { default: llvm_unreachable("Invalid extended CFI opcode"); case DW_CFA_nop: @@ -161,15 +192,15 @@ case DW_CFA_def_cfa: case DW_CFA_val_offset: // Operands: ULEB128, ULEB128 - addInstruction(Opcode, Data.getULEB128(Offset), - Data.getULEB128(Offset)); + Op1 = Data.getULEB128(Offset); // ensure order of evaluation + addInstruction(Opcode, Op1, Data.getULEB128(Offset)); break; case DW_CFA_offset_extended_sf: case DW_CFA_def_cfa_sf: case DW_CFA_val_offset_sf: // Operands: ULEB128, SLEB128 - addInstruction(Opcode, Data.getULEB128(Offset), - Data.getSLEB128(Offset)); + Op1 = Data.getULEB128(Offset); // ensure order of evaluation + addInstruction(Opcode, Op1, Data.getSLEB128(Offset)); break; case DW_CFA_def_cfa_expression: case DW_CFA_expression: @@ -183,16 +214,90 @@ void FrameEntry::dumpInstructions(raw_ostream &OS) const { - // TODO: at the moment only instruction names are dumped. Expand this to - // dump operands as well. + uint64_t Location = getInitialLocation(); + uint64_t CodeAlignmentFactor = getCodeAlignmentFactor(); + int64_t DataAlignmentFactor = getDataAlignmentFactor(); for (std::vector::const_iterator I = Instructions.begin(), E = Instructions.end(); I != E; ++I) { uint8_t Opcode = I->Opcode; if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK) Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK; - OS << " " << CallFrameString(Opcode) << ":\n"; + OS << " " << CallFrameString(Opcode) << ": "; + switch (Opcode) { + default: llvm_unreachable("Invalid extended CFI opcode"); + case DW_CFA_nop: + case DW_CFA_remember_state: + case DW_CFA_restore_state: + // No operands + break; + case DW_CFA_set_loc: + Location = I->getUnsignedOperand(0); + // TODO: Need better support for printing 64-bit addresses + OS << format ("0x%8.8" PRIx64, Location); + break; + case DW_CFA_advance_loc: + case DW_CFA_advance_loc1: + case DW_CFA_advance_loc2: + case DW_CFA_advance_loc4: + Location += I->getUnsignedOperand(0) * CodeAlignmentFactor; + // TODO: Need better support for printing 64-bit addresses + OS << format("%" PRIu64 " to 0x%8.8" PRIx64, + I->getUnsignedOperand(0) * CodeAlignmentFactor, Location); + break; + case DW_CFA_def_cfa_offset: + OS << I->getUnsignedOperand(0); + break; + case DW_CFA_def_cfa_offset_sf: + OS << I->getSignedOperand(0) * DataAlignmentFactor; + break; + case DW_CFA_def_cfa: + printRegister(OS, I->getRegisterOperand(0)); + OS << format(", %" PRIu64, I->getUnsignedOperand(1)); + break; + case DW_CFA_def_cfa_sf: + case DW_CFA_val_offset_sf: + printRegister(OS, I->getRegisterOperand(0)); + OS << format(", %" PRId64, + I->getSignedOperand(1) * DataAlignmentFactor); + break; + case DW_CFA_offset: + case DW_CFA_offset_extended: + printRegister(OS, I->getRegisterOperand(0)); + OS << format(" at cfa%+" PRId64, + I->getUnsignedOperand(1) * DataAlignmentFactor); + break; + case DW_CFA_offset_extended_sf: + printRegister(OS, I->getRegisterOperand(0)); + OS << format(" at cfa%+" PRId64, + I->getSignedOperand(1) * DataAlignmentFactor); + break; + case DW_CFA_val_offset: + printRegister(OS, I->getRegisterOperand(0)); + OS << format(",%" PRId64, + I->getUnsignedOperand(1) * DataAlignmentFactor); + break; + case DW_CFA_def_cfa_register: + case DW_CFA_restore: + case DW_CFA_restore_extended: + case DW_CFA_same_value: + case DW_CFA_undefined: + printRegister(OS, I->getRegisterOperand(0)); + break; + case DW_CFA_register: + printRegister(OS, I->getRegisterOperand(0)); + OS << ","; + printRegister(OS, I->getRegisterOperand(1)); + break; + case DW_CFA_def_cfa_expression: + case DW_CFA_expression: + case DW_CFA_val_expression: + // TODO: Not yet implemented in parseInstruction() + break; + } + OS << "\n"; } + } @@ -228,6 +333,18 @@ OS << "\n"; } + uint64_t getCodeAlignmentFactor() const{ + return CodeAlignmentFactor; + } + + int64_t getDataAlignmentFactor() const { + return DataAlignmentFactor; + } + + uint64_t getInitialLocation() const { + return 0; // A CIE does not really have a location + } + static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_CIE; } @@ -245,9 +362,9 @@ /// \brief DWARF Frame Description Entry (FDE) class FDE : public FrameEntry { public: - // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with - // an offset to the CIE (provided by parsing the FDE header). The CIE itself - // is obtained lazily once it's actually required. + // Each FDE has a CIE it's "linked to". Our FDE is constructed with + // an offset to the CIE (provided by parsing the FDE header). The CIE + // is linked to after the FDE has been parsed. FDE(DataExtractor D, uint64_t Offset, uint64_t Length, int64_t LinkedCIEOffset, uint64_t InitialLocation, uint64_t AddressRange) : FrameEntry(FK_FDE, D, Offset, Length), LinkedCIEOffset(LinkedCIEOffset), @@ -264,14 +381,36 @@ (int32_t)LinkedCIEOffset, (uint32_t)InitialLocation, (uint32_t)InitialLocation + (uint32_t)AddressRange); - if (LinkedCIE) { - OS << format("%p\n", LinkedCIE); - } } static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_FDE; } + + void setLinkedCIE(CIE* Cie) { + LinkedCIE = Cie; + } + + uint64_t getLinkedCIEOffset() const { + return LinkedCIEOffset; + } + + uint64_t getCodeAlignmentFactor() const { + if (LinkedCIE) + return LinkedCIE->getCodeAlignmentFactor(); + return 0; + } + + int64_t getDataAlignmentFactor() const { + if (LinkedCIE) + return LinkedCIE->getDataAlignmentFactor(); + return 0; + } + + uint64_t getInitialLocation() const { + return InitialLocation; + } + private: /// The following fields are defined in section 6.4.1 of the DWARF standard v3 @@ -308,6 +447,7 @@ void DWARFDebugFrame::parse(DataExtractor Data) { uint32_t Offset = 0; + std::map CieMap; while (Data.isValidOffset(Offset)) { uint32_t StartOffset = Offset; @@ -351,6 +491,7 @@ Entry = new CIE(Data, StartOffset, Length, Version, StringRef(Augmentation), CodeAlignmentFactor, DataAlignmentFactor, ReturnAddressRegister); + CieMap[StartOffset] = (CIE*)Entry; } else { // FDE uint64_t CIEPointer = Id; @@ -375,6 +516,19 @@ report_fatal_error(Str); } } + + // Fixup the FDE to CIE links + for (EntryVector::const_iterator I = Entries.begin(), E = Entries.end(); + I != E; ++I) { + FrameEntry* Entry = *I; + if(Entry->getKind() == FrameEntry::FK_FDE) { + FDE* Fde = (FDE*)Entry; + uint64_t CieOffset = Fde->getLinkedCIEOffset(); + std::map::iterator CI = CieMap.find(CieOffset); + if (CI != CieMap.end()) + Fde->setLinkedCIE(CI->second); + } + } } Index: test/DebugInfo/dwarfdump-debug-frame-simple.test =================================================================== --- test/DebugInfo/dwarfdump-debug-frame-simple.test +++ test/DebugInfo/dwarfdump-debug-frame-simple.test @@ -6,22 +6,22 @@ ; FRAMES: 00000000 00000010 ffffffff CIE ; FRAMES: Version: 1 -; FRAMES: DW_CFA_def_cfa -; FRAMES-NEXT: DW_CFA_offset +; FRAMES: DW_CFA_def_cfa: r4, 4 +; FRAMES-NEXT: DW_CFA_offset: r8 at cfa-4 ; FRAMES-NEXT: DW_CFA_nop ; FRAMES-NEXT: DW_CFA_nop ; FRAMES: 00000014 00000010 00000000 FDE cie=00000000 pc=00000000...00000022 -; FRAMES: DW_CFA_advance_loc -; FRAMES-NEXT: DW_CFA_def_cfa_offset +; FRAMES: DW_CFA_advance_loc: 3 to 0x00000003 +; FRAMES-NEXT: DW_CFA_def_cfa_offset: 12 ; FRAMES-NEXT: DW_CFA_nop ; FRAMES: 00000028 00000014 00000000 FDE cie=00000000 pc=00000030...00000080 -; FRAMES: DW_CFA_advance_loc -; FRAMES-NEXT: DW_CFA_def_cfa_offset -; FRAMES-NEXT: DW_CFA_offset -; FRAMES-NEXT: DW_CFA_advance_loc -; FRAMES-NEXT: DW_CFA_def_cfa_register +; FRAMES: DW_CFA_advance_loc: 1 to 0x00000031 +; FRAMES-NEXT: DW_CFA_def_cfa_offset: 8 +; FRAMES-NEXT: DW_CFA_offset: r5 at cfa-8 +; FRAMES-NEXT: DW_CFA_advance_loc: 2 to 0x00000033 +; FRAMES-NEXT: DW_CFA_def_cfa_register: r5 ; FRAMES-NOT: CIE ; FRAMES-NOT: FDE