From 60bdc5b16e2fc17be184b515a00c2e2a2eb40b89 Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Tue, 5 Feb 2013 23:30:58 +0000 Subject: Initial support for DWARF CFI parsing and dumping in LLVM git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@174463 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/DebugInfo/DWARFDebugFrame.cpp | 195 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 lib/DebugInfo/DWARFDebugFrame.cpp (limited to 'lib/DebugInfo/DWARFDebugFrame.cpp') diff --git a/lib/DebugInfo/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARFDebugFrame.cpp new file mode 100644 index 0000000..0b78cce --- /dev/null +++ b/lib/DebugInfo/DWARFDebugFrame.cpp @@ -0,0 +1,195 @@ +//===-- DWARFDebugFrame.h - Parsing of .debug_frame -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugFrame.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/Format.h" + +using namespace llvm; +using namespace dwarf; + + +class llvm::FrameEntry { +public: + enum FrameKind {FK_CIE, FK_FDE}; + FrameEntry(FrameKind K, DataExtractor D, uint64_t Offset, uint64_t Length) + : Kind(K), Data(D), Offset(Offset), Length(Length) + {} + + FrameKind getKind() const { return Kind; } + + virtual void dumpHeader(raw_ostream &OS) const = 0; +protected: + const FrameKind Kind; + DataExtractor Data; + uint64_t Offset; + uint64_t Length; +}; + + +class CIE : public FrameEntry { +public: + // CIEs (and FDEs) are simply container classes, so the only sensible way to + // create them is by providing the full parsed contents in the constructor. + CIE(DataExtractor D, uint64_t Offset, uint64_t Length, uint8_t Version, + SmallString<8> Augmentation, uint64_t CodeAlignmentFactor, + int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister) + : FrameEntry(FK_CIE, D, Offset, Length), Version(Version), + Augmentation(Augmentation), CodeAlignmentFactor(CodeAlignmentFactor), + DataAlignmentFactor(DataAlignmentFactor), + ReturnAddressRegister(ReturnAddressRegister) + {} + + void dumpHeader(raw_ostream &OS) const { + OS << format("%08x %08x %08x CIE", Offset, Length, DW_CIE_ID) << "\n"; + OS << format(" Version: %d\n", Version); + OS << " Augmentation: \"" << Augmentation << "\"\n"; + OS << format(" Code alignment factor: %u\n", CodeAlignmentFactor); + OS << format(" Data alignment factor: %d\n", DataAlignmentFactor); + OS << format(" Return address column: %d\n", ReturnAddressRegister); + OS << "\n"; + } + + static bool classof(const FrameEntry *FE) { + return FE->getKind() == FK_CIE; + } +private: + uint8_t Version; + SmallString<8> Augmentation; + uint64_t CodeAlignmentFactor; + int64_t DataAlignmentFactor; + uint64_t ReturnAddressRegister; +}; + + +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. + 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), + InitialLocation(InitialLocation), AddressRange(AddressRange), + LinkedCIE(NULL) + {} + + void dumpHeader(raw_ostream &OS) const { + OS << format("%08x %08x %08x FDE ", Offset, Length, LinkedCIEOffset); + OS << format("cie=%08x pc=%08x...%08x\n", + LinkedCIEOffset, InitialLocation, + InitialLocation + AddressRange); + OS << "\n"; + } + + static bool classof(const FrameEntry *FE) { + return FE->getKind() == FK_FDE; + } +private: + uint64_t LinkedCIEOffset; + uint64_t InitialLocation; + uint64_t AddressRange; + CIE *LinkedCIE; +}; + + +DWARFDebugFrame::DWARFDebugFrame() +{ +} + + +DWARFDebugFrame::~DWARFDebugFrame() +{ + for (EntryVector::iterator I = Entries.begin(), E = Entries.end(); + I != E; ++I) { + delete *I; + } +} + + +static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data, + uint32_t Offset, int Length) { + errs() << "DUMP: "; + for (int i = 0; i < Length; ++i) { + uint8_t c = Data.getU8(&Offset); + errs().write_hex(c); errs() << " "; + } + errs() << "\n"; +} + + +void DWARFDebugFrame::parse(DataExtractor Data) { + uint32_t Offset = 0; + + while (Data.isValidOffset(Offset)) { + uint32_t StartOffset = Offset; + + bool IsDWARF64 = false; + uint64_t Length = Data.getU32(&Offset); + uint64_t Id; + + if (Length == UINT32_MAX) { + // DWARF-64 is distinguished by the first 32 bits of the initial length + // field being 0xffffffff. Then, the next 64 bits are the actual entry + // length. + IsDWARF64 = true; + Length = Data.getU64(&Offset); + } + + // At this point, Offset points to the next field after Length. + // Length is the structure size excluding itself. Compute an offset one + // past the end of the structure (needed to know how many instructions to + // read). + // TODO: For honest DWARF64 support, DataExtractor will have to treat + // offset_ptr as uint64_t* + uint32_t EndStructureOffset = Offset + static_cast(Length); + + // The Id field's size depends on the DWARF format + Id = Data.getUnsigned(&Offset, IsDWARF64 ? 8 : 4); + bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID); + + if (IsCIE) { + // Note: this is specifically DWARFv3 CIE header structure. It was + // changed in DWARFv4. + uint8_t Version = Data.getU8(&Offset); + const char *Augmentation = Data.getCStr(&Offset); + uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset); + int64_t DataAlignmentFactor = Data.getSLEB128(&Offset); + uint64_t ReturnAddressRegister = Data.getULEB128(&Offset); + + CIE *NewCIE = new CIE(Data, StartOffset, Length, Version, + StringRef(Augmentation), CodeAlignmentFactor, + DataAlignmentFactor, ReturnAddressRegister); + Entries.push_back(NewCIE); + } else { + // FDE + uint64_t CIEPointer = Id; + uint64_t InitialLocation = Data.getAddress(&Offset); + uint64_t AddressRange = Data.getAddress(&Offset); + + FDE *NewFDE = new FDE(Data, StartOffset, Length, CIEPointer, + InitialLocation, AddressRange); + Entries.push_back(NewFDE); + } + + Offset = EndStructureOffset; + } +} + + +void DWARFDebugFrame::dump(raw_ostream &OS) const { + OS << "\n"; + for (EntryVector::const_iterator I = Entries.begin(), E = Entries.end(); + I != E; ++I) { + (*I)->dumpHeader(OS); + } +} + -- cgit v1.1 From ba42625074aa7f4f1324a5d6666bd0e302b57f2b Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Wed, 6 Feb 2013 00:20:38 +0000 Subject: Fix some formatting & add comments, following Eric's review git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@174473 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/DebugInfo/DWARFDebugFrame.cpp | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'lib/DebugInfo/DWARFDebugFrame.cpp') diff --git a/lib/DebugInfo/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARFDebugFrame.cpp index 0b78cce..76fdb79 100644 --- a/lib/DebugInfo/DWARFDebugFrame.cpp +++ b/lib/DebugInfo/DWARFDebugFrame.cpp @@ -21,16 +21,23 @@ class llvm::FrameEntry { public: enum FrameKind {FK_CIE, FK_FDE}; FrameEntry(FrameKind K, DataExtractor D, uint64_t Offset, uint64_t Length) - : Kind(K), Data(D), Offset(Offset), Length(Length) - {} + : Kind(K), Data(D), Offset(Offset), Length(Length) {} FrameKind getKind() const { return Kind; } virtual void dumpHeader(raw_ostream &OS) const = 0; + protected: const FrameKind Kind; + + /// \brief The data stream holding the section from which the entry was + /// parsed. DataExtractor Data; + + /// \brief Offset of this entry in the section. uint64_t Offset; + + /// \brief Entry length as specified in DWARF. uint64_t Length; }; @@ -45,8 +52,7 @@ public: : FrameEntry(FK_CIE, D, Offset, Length), Version(Version), Augmentation(Augmentation), CodeAlignmentFactor(CodeAlignmentFactor), DataAlignmentFactor(DataAlignmentFactor), - ReturnAddressRegister(ReturnAddressRegister) - {} + ReturnAddressRegister(ReturnAddressRegister) {} void dumpHeader(raw_ostream &OS) const { OS << format("%08x %08x %08x CIE", Offset, Length, DW_CIE_ID) << "\n"; @@ -61,7 +67,9 @@ public: static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_CIE; } + private: + /// The following fields are defined in section 6.4.1 of the DWARF standard v3 uint8_t Version; SmallString<8> Augmentation; uint64_t CodeAlignmentFactor; @@ -75,12 +83,11 @@ 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. - FDE(DataExtractor D, uint64_t Offset, uint64_t Length, int64_t LinkedCIEOffset, - uint64_t InitialLocation, uint64_t AddressRange) + 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), InitialLocation(InitialLocation), AddressRange(AddressRange), - LinkedCIE(NULL) - {} + LinkedCIE(NULL) {} void dumpHeader(raw_ostream &OS) const { OS << format("%08x %08x %08x FDE ", Offset, Length, LinkedCIEOffset); @@ -94,6 +101,8 @@ public: return FE->getKind() == FK_FDE; } private: + + /// The following fields are defined in section 6.4.1 of the DWARF standard v3 uint64_t LinkedCIEOffset; uint64_t InitialLocation; uint64_t AddressRange; @@ -101,13 +110,11 @@ private: }; -DWARFDebugFrame::DWARFDebugFrame() -{ +DWARFDebugFrame::DWARFDebugFrame() { } -DWARFDebugFrame::~DWARFDebugFrame() -{ +DWARFDebugFrame::~DWARFDebugFrame() { for (EntryVector::iterator I = Entries.begin(), E = Entries.end(); I != E; ++I) { delete *I; -- cgit v1.1 From 8a0329e6ffc290fb177fd058a64b4cf81d4b620a Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Wed, 6 Feb 2013 03:08:02 +0000 Subject: Add virtual desctructor to FrameEntry to avoid error on delete-non-virtual-dtor git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@174483 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/DebugInfo/DWARFDebugFrame.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'lib/DebugInfo/DWARFDebugFrame.cpp') diff --git a/lib/DebugInfo/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARFDebugFrame.cpp index 76fdb79..ec55716 100644 --- a/lib/DebugInfo/DWARFDebugFrame.cpp +++ b/lib/DebugInfo/DWARFDebugFrame.cpp @@ -23,6 +23,9 @@ public: FrameEntry(FrameKind K, DataExtractor D, uint64_t Offset, uint64_t Length) : Kind(K), Data(D), Offset(Offset), Length(Length) {} + virtual ~FrameEntry() { + } + FrameKind getKind() const { return Kind; } virtual void dumpHeader(raw_ostream &OS) const = 0; @@ -54,6 +57,9 @@ public: DataAlignmentFactor(DataAlignmentFactor), ReturnAddressRegister(ReturnAddressRegister) {} + ~CIE() { + } + void dumpHeader(raw_ostream &OS) const { OS << format("%08x %08x %08x CIE", Offset, Length, DW_CIE_ID) << "\n"; OS << format(" Version: %d\n", Version); @@ -89,6 +95,9 @@ public: InitialLocation(InitialLocation), AddressRange(AddressRange), LinkedCIE(NULL) {} + ~FDE() { + } + void dumpHeader(raw_ostream &OS) const { OS << format("%08x %08x %08x FDE ", Offset, Length, LinkedCIEOffset); OS << format("cie=%08x pc=%08x...%08x\n", -- cgit v1.1 From b2ac7c09b17efadea2a9f90f45801d9d2ee687aa Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Wed, 6 Feb 2013 05:37:46 +0000 Subject: Failing builds because a private class member is not being used after initialization is one of the reasons I consider -werror to be shoddy. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@174485 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/DebugInfo/DWARFDebugFrame.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib/DebugInfo/DWARFDebugFrame.cpp') diff --git a/lib/DebugInfo/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARFDebugFrame.cpp index ec55716..974cecc 100644 --- a/lib/DebugInfo/DWARFDebugFrame.cpp +++ b/lib/DebugInfo/DWARFDebugFrame.cpp @@ -104,6 +104,9 @@ public: LinkedCIEOffset, InitialLocation, InitialLocation + AddressRange); OS << "\n"; + if (LinkedCIE) { + OS << format("%p\n", LinkedCIE); + } } static bool classof(const FrameEntry *FE) { -- cgit v1.1 From 2e402d5b5f2fce8bfe29509cc771b9919946003b Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Wed, 6 Feb 2013 16:20:31 +0000 Subject: Add some comments to new frame entries git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@174515 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/DebugInfo/DWARFDebugFrame.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/DebugInfo/DWARFDebugFrame.cpp') diff --git a/lib/DebugInfo/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARFDebugFrame.cpp index 974cecc..62e4856 100644 --- a/lib/DebugInfo/DWARFDebugFrame.cpp +++ b/lib/DebugInfo/DWARFDebugFrame.cpp @@ -17,6 +17,8 @@ using namespace llvm; using namespace dwarf; +/// \brief Abstract frame entry defining the common interface concrete +/// entries implement. class llvm::FrameEntry { public: enum FrameKind {FK_CIE, FK_FDE}; @@ -45,6 +47,7 @@ protected: }; +/// \brief DWARF Common Information Entry (CIE) class CIE : public FrameEntry { public: // CIEs (and FDEs) are simply container classes, so the only sensible way to @@ -84,6 +87,7 @@ private: }; +/// \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 -- cgit v1.1 From 90e01ac0ea5bdc6dd6bccd9c59c3acb04e339666 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Thu, 7 Feb 2013 02:02:27 +0000 Subject: DWARFDebugFrame.cpp: Fix formatting on i686 hosts. FIXME: Are they really truncated to i32 from i64 unconditionally? git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@174574 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/DebugInfo/DWARFDebugFrame.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'lib/DebugInfo/DWARFDebugFrame.cpp') diff --git a/lib/DebugInfo/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARFDebugFrame.cpp index 62e4856..6781da6 100644 --- a/lib/DebugInfo/DWARFDebugFrame.cpp +++ b/lib/DebugInfo/DWARFDebugFrame.cpp @@ -64,7 +64,9 @@ public: } void dumpHeader(raw_ostream &OS) const { - OS << format("%08x %08x %08x CIE", Offset, Length, DW_CIE_ID) << "\n"; + OS << format("%08x %08x %08x CIE", + (uint32_t)Offset, (uint32_t)Length, DW_CIE_ID) + << "\n"; OS << format(" Version: %d\n", Version); OS << " Augmentation: \"" << Augmentation << "\"\n"; OS << format(" Code alignment factor: %u\n", CodeAlignmentFactor); @@ -103,9 +105,10 @@ public: } void dumpHeader(raw_ostream &OS) const { - OS << format("%08x %08x %08x FDE ", Offset, Length, LinkedCIEOffset); + OS << format("%08x %08x %08x FDE ", + (uint32_t)Offset, (uint32_t)Length, LinkedCIEOffset); OS << format("cie=%08x pc=%08x...%08x\n", - LinkedCIEOffset, InitialLocation, + (uint32_t)LinkedCIEOffset, (uint32_t)InitialLocation, InitialLocation + AddressRange); OS << "\n"; if (LinkedCIE) { -- cgit v1.1 From 8ff0631967c64d51b193b862aa0a6f1e8eb06f78 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Thu, 7 Feb 2013 10:57:42 +0000 Subject: FDE::dumpHeader(): Forgot to fix one more formatting. It affected bigendian hosts. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@174602 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/DebugInfo/DWARFDebugFrame.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib/DebugInfo/DWARFDebugFrame.cpp') diff --git a/lib/DebugInfo/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARFDebugFrame.cpp index 6781da6..b70a285 100644 --- a/lib/DebugInfo/DWARFDebugFrame.cpp +++ b/lib/DebugInfo/DWARFDebugFrame.cpp @@ -108,8 +108,9 @@ public: OS << format("%08x %08x %08x FDE ", (uint32_t)Offset, (uint32_t)Length, LinkedCIEOffset); OS << format("cie=%08x pc=%08x...%08x\n", - (uint32_t)LinkedCIEOffset, (uint32_t)InitialLocation, - InitialLocation + AddressRange); + (uint32_t)LinkedCIEOffset, + (uint32_t)InitialLocation, + (uint32_t)InitialLocation + (uint32_t)AddressRange); OS << "\n"; if (LinkedCIE) { OS << format("%p\n", LinkedCIE); -- cgit v1.1 From d9a8d43ed3e7c6c32f52ab5d0f627f7b1cdb6aac Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Thu, 7 Feb 2013 14:54:42 +0000 Subject: FDE::dumpHeader(): Forgot to fix one more formatting, ... take two! Excuse me, I could not test it locally. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@174614 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/DebugInfo/DWARFDebugFrame.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/DebugInfo/DWARFDebugFrame.cpp') diff --git a/lib/DebugInfo/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARFDebugFrame.cpp index b70a285..244ff4c 100644 --- a/lib/DebugInfo/DWARFDebugFrame.cpp +++ b/lib/DebugInfo/DWARFDebugFrame.cpp @@ -106,9 +106,9 @@ public: void dumpHeader(raw_ostream &OS) const { OS << format("%08x %08x %08x FDE ", - (uint32_t)Offset, (uint32_t)Length, LinkedCIEOffset); + (uint32_t)Offset, (uint32_t)Length, (int32_t)LinkedCIEOffset); OS << format("cie=%08x pc=%08x...%08x\n", - (uint32_t)LinkedCIEOffset, + (int32_t)LinkedCIEOffset, (uint32_t)InitialLocation, (uint32_t)InitialLocation + (uint32_t)AddressRange); OS << "\n"; -- cgit v1.1 From 0b821eff4c9c8d3b7ac872691bc453337ad3d03a Mon Sep 17 00:00:00 2001 From: David Tweed Date: Fri, 8 Feb 2013 16:35:10 +0000 Subject: The patch to fix some issues in r174543 fixed the lines failing the test, but missed a couple of lines which weren't being explicitly looked at and were printing incorrect results. These values clearly must lie within 32 bits, so the casts are definitely safe. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@174717 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/DebugInfo/DWARFDebugFrame.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib/DebugInfo/DWARFDebugFrame.cpp') diff --git a/lib/DebugInfo/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARFDebugFrame.cpp index 244ff4c..9da304d31 100644 --- a/lib/DebugInfo/DWARFDebugFrame.cpp +++ b/lib/DebugInfo/DWARFDebugFrame.cpp @@ -69,9 +69,9 @@ public: << "\n"; OS << format(" Version: %d\n", Version); OS << " Augmentation: \"" << Augmentation << "\"\n"; - OS << format(" Code alignment factor: %u\n", CodeAlignmentFactor); - OS << format(" Data alignment factor: %d\n", DataAlignmentFactor); - OS << format(" Return address column: %d\n", ReturnAddressRegister); + OS << format(" Code alignment factor: %u\n", (uint32_t)CodeAlignmentFactor); + OS << format(" Data alignment factor: %d\n", (int32_t)DataAlignmentFactor); + OS << format(" Return address column: %d\n", (int32_t)ReturnAddressRegister); OS << "\n"; } -- cgit v1.1 From 74b3c8da4800c7e8ba8f019879db29738ecc5f74 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Fri, 15 Feb 2013 12:30:38 +0000 Subject: Make helpers static. Add missing include so LLVMInitializeObjCARCOpts gets C linkage. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@175264 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/DebugInfo/DWARFDebugFrame.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/DebugInfo/DWARFDebugFrame.cpp') diff --git a/lib/DebugInfo/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARFDebugFrame.cpp index 9da304d31..69e3a3a 100644 --- a/lib/DebugInfo/DWARFDebugFrame.cpp +++ b/lib/DebugInfo/DWARFDebugFrame.cpp @@ -46,7 +46,7 @@ protected: uint64_t Length; }; - +namespace { /// \brief DWARF Common Information Entry (CIE) class CIE : public FrameEntry { public: @@ -128,6 +128,7 @@ private: uint64_t AddressRange; CIE *LinkedCIE; }; +} // end anonymous namespace DWARFDebugFrame::DWARFDebugFrame() { -- cgit v1.1 From 7bf3d6a0438485df61c438f26cfbaef2f8d8a3c4 Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Thu, 21 Feb 2013 22:53:19 +0000 Subject: Previously, parsing capability of the .debug_frame section was added to lib/DebugInfo, with dumping in llvm-dwarfdump. This patch adds initial ability to parse and dump CFA instructions contained in entries. To keep it manageable, the patch omits some more advanced capabilities (accounted in TODOs): * Parsing of instructions with BLOCK arguments (expression lists) * Dumping of actual instruction arguments (currently only names are dumped). This is quite tricky since the dumper has to effectively "interpret" the instructions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@175820 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/DebugInfo/DWARFDebugFrame.cpp | 176 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 170 insertions(+), 6 deletions(-) (limited to 'lib/DebugInfo/DWARFDebugFrame.cpp') diff --git a/lib/DebugInfo/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARFDebugFrame.cpp index 69e3a3a..951c7a0 100644 --- a/lib/DebugInfo/DWARFDebugFrame.cpp +++ b/lib/DebugInfo/DWARFDebugFrame.cpp @@ -10,8 +10,12 @@ #include "DWARFDebugFrame.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include +#include using namespace llvm; using namespace dwarf; @@ -29,9 +33,21 @@ public: } FrameKind getKind() const { return Kind; } + virtual uint64_t getOffset() const { return Offset; } + /// \brief Parse and store a sequence of CFI instructions from our data + /// stream, starting at Offset and ending at EndOffset. If everything + /// goes well, Offset should be equal to EndOffset when this method + /// returns. Otherwise, an error occurred. + /// TODO: Improve error reporting... + virtual void parseInstructions(uint32_t &Offset, uint32_t EndOffset); + + /// \brief Dump the entry header to the given output stream. virtual void dumpHeader(raw_ostream &OS) const = 0; + /// \brief Dump the entry's instructions to the given output stream. + virtual void dumpInstructions(raw_ostream &OS) const; + protected: const FrameKind Kind; @@ -44,8 +60,143 @@ protected: /// \brief Entry length as specified in DWARF. uint64_t Length; + + /// An entry may contain CFI instructions. An instruction consists of an + /// opcode and an optional sequence of operands. + typedef std::vector Operands; + struct Instruction { + Instruction(uint8_t Opcode) + : Opcode(Opcode) + {} + + uint8_t Opcode; + Operands Ops; + }; + + std::vector Instructions; + + /// Convenience methods to add a new instruction with the given opcode and + /// operands to the Instructions vector. + void addInstruction(uint8_t Opcode) { + Instructions.push_back(Instruction(Opcode)); + } + + void addInstruction(uint8_t Opcode, uint64_t Operand1) { + Instructions.push_back(Instruction(Opcode)); + Instructions.back().Ops.push_back(Operand1); + } + + void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) { + Instructions.push_back(Instruction(Opcode)); + Instructions.back().Ops.push_back(Operand1); + Instructions.back().Ops.push_back(Operand2); + } }; + +// See DWARF standard v3, section 7.23 +const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0; +const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f; + + +void FrameEntry::parseInstructions(uint32_t &Offset, uint32_t EndOffset) { + while (Offset < EndOffset) { + uint8_t Opcode = Data.getU8(&Offset); + // Some instructions have a primary opcode encoded in the top bits. + uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK; + + if (Primary) { + // If it's a primary opcode, the first operand is encoded in the bottom + // bits of the opcode itself. + uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK; + switch (Primary) { + default: llvm_unreachable("Impossible primary CFI opcode"); + case DW_CFA_advance_loc: + case DW_CFA_restore: + addInstruction(Primary, Op1); + break; + case DW_CFA_offset: + addInstruction(Primary, Op1, Data.getULEB128(&Offset)); + break; + } + } else { + // Extended opcode - its value is Opcode itself. + 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 + addInstruction(Opcode); + break; + case DW_CFA_set_loc: + // Operands: Address + addInstruction(Opcode, Data.getAddress(&Offset)); + break; + case DW_CFA_advance_loc1: + // Operands: 1-byte delta + addInstruction(Opcode, Data.getU8(&Offset)); + break; + case DW_CFA_advance_loc2: + // Operands: 2-byte delta + addInstruction(Opcode, Data.getU16(&Offset)); + break; + case DW_CFA_advance_loc4: + // Operands: 4-byte delta + addInstruction(Opcode, Data.getU32(&Offset)); + break; + case DW_CFA_restore_extended: + case DW_CFA_undefined: + case DW_CFA_same_value: + case DW_CFA_def_cfa_register: + case DW_CFA_def_cfa_offset: + // Operands: ULEB128 + addInstruction(Opcode, Data.getULEB128(&Offset)); + break; + case DW_CFA_def_cfa_offset_sf: + // Operands: SLEB128 + addInstruction(Opcode, Data.getSLEB128(&Offset)); + break; + case DW_CFA_offset_extended: + case DW_CFA_register: + case DW_CFA_def_cfa: + case DW_CFA_val_offset: + // Operands: ULEB128, ULEB128 + addInstruction(Opcode, Data.getULEB128(&Offset), + 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)); + break; + case DW_CFA_def_cfa_expression: + case DW_CFA_expression: + case DW_CFA_val_expression: + // TODO: implement this + report_fatal_error("Values with expressions not implemented yet!"); + } + } + } +} + + +void FrameEntry::dumpInstructions(raw_ostream &OS) const { + // TODO: at the moment only instruction names are dumped. Expand this to + // dump operands as well. + 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"; + } +} + + namespace { /// \brief DWARF Common Information Entry (CIE) class CIE : public FrameEntry { @@ -69,9 +220,12 @@ public: << "\n"; OS << format(" Version: %d\n", Version); OS << " Augmentation: \"" << Augmentation << "\"\n"; - OS << format(" Code alignment factor: %u\n", (uint32_t)CodeAlignmentFactor); - OS << format(" Data alignment factor: %d\n", (int32_t)DataAlignmentFactor); - OS << format(" Return address column: %d\n", (int32_t)ReturnAddressRegister); + OS << format(" Code alignment factor: %u\n", + (uint32_t)CodeAlignmentFactor); + OS << format(" Data alignment factor: %d\n", + (int32_t)DataAlignmentFactor); + OS << format(" Return address column: %d\n", + (int32_t)ReturnAddressRegister); OS << "\n"; } @@ -111,7 +265,6 @@ public: (int32_t)LinkedCIEOffset, (uint32_t)InitialLocation, (uint32_t)InitialLocation + (uint32_t)AddressRange); - OS << "\n"; if (LinkedCIE) { OS << format("%p\n", LinkedCIE); } @@ -208,7 +361,15 @@ void DWARFDebugFrame::parse(DataExtractor Data) { Entries.push_back(NewFDE); } - Offset = EndStructureOffset; + Entries.back()->parseInstructions(Offset, EndStructureOffset); + + if (Offset != EndStructureOffset) { + std::string Str; + raw_string_ostream OS(Str); + OS << format("Parsing entry instructions at %lx failed", + Entries.back()->getOffset()); + report_fatal_error(Str); + } } } @@ -217,7 +378,10 @@ void DWARFDebugFrame::dump(raw_ostream &OS) const { OS << "\n"; for (EntryVector::const_iterator I = Entries.begin(), E = Entries.end(); I != E; ++I) { - (*I)->dumpHeader(OS); + FrameEntry *Entry = *I; + Entry->dumpHeader(OS); + Entry->dumpInstructions(OS); + OS << "\n"; } } -- cgit v1.1 From 46e0d1d58c9c1f288cbf943e4c930efd1a2968af Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Fri, 22 Feb 2013 00:50:48 +0000 Subject: Code cleanup: pass Offset by pointer to parseInstruction to more explicitly convey that it's a INOUT argument. Also, if parsing of entry instructions fails, don't push the entry. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@175847 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/DebugInfo/DWARFDebugFrame.cpp | 62 +++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 29 deletions(-) (limited to 'lib/DebugInfo/DWARFDebugFrame.cpp') diff --git a/lib/DebugInfo/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARFDebugFrame.cpp index 951c7a0..3efe6a1 100644 --- a/lib/DebugInfo/DWARFDebugFrame.cpp +++ b/lib/DebugInfo/DWARFDebugFrame.cpp @@ -36,11 +36,10 @@ public: virtual uint64_t getOffset() const { return Offset; } /// \brief Parse and store a sequence of CFI instructions from our data - /// stream, starting at Offset and ending at EndOffset. If everything - /// goes well, Offset should be equal to EndOffset when this method + /// stream, starting at *Offset and ending at EndOffset. If everything + /// goes well, *Offset should be equal to EndOffset when this method /// returns. Otherwise, an error occurred. - /// TODO: Improve error reporting... - virtual void parseInstructions(uint32_t &Offset, uint32_t EndOffset); + virtual void parseInstructions(uint32_t *Offset, uint32_t EndOffset); /// \brief Dump the entry header to the given output stream. virtual void dumpHeader(raw_ostream &OS) const = 0; @@ -99,9 +98,9 @@ const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0; const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f; -void FrameEntry::parseInstructions(uint32_t &Offset, uint32_t EndOffset) { - while (Offset < EndOffset) { - uint8_t Opcode = Data.getU8(&Offset); +void FrameEntry::parseInstructions(uint32_t *Offset, uint32_t EndOffset) { + while (*Offset < EndOffset) { + uint8_t Opcode = Data.getU8(Offset); // Some instructions have a primary opcode encoded in the top bits. uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK; @@ -116,7 +115,7 @@ void FrameEntry::parseInstructions(uint32_t &Offset, uint32_t EndOffset) { addInstruction(Primary, Op1); break; case DW_CFA_offset: - addInstruction(Primary, Op1, Data.getULEB128(&Offset)); + addInstruction(Primary, Op1, Data.getULEB128(Offset)); break; } } else { @@ -131,19 +130,19 @@ void FrameEntry::parseInstructions(uint32_t &Offset, uint32_t EndOffset) { break; case DW_CFA_set_loc: // Operands: Address - addInstruction(Opcode, Data.getAddress(&Offset)); + addInstruction(Opcode, Data.getAddress(Offset)); break; case DW_CFA_advance_loc1: // Operands: 1-byte delta - addInstruction(Opcode, Data.getU8(&Offset)); + addInstruction(Opcode, Data.getU8(Offset)); break; case DW_CFA_advance_loc2: // Operands: 2-byte delta - addInstruction(Opcode, Data.getU16(&Offset)); + addInstruction(Opcode, Data.getU16(Offset)); break; case DW_CFA_advance_loc4: // Operands: 4-byte delta - addInstruction(Opcode, Data.getU32(&Offset)); + addInstruction(Opcode, Data.getU32(Offset)); break; case DW_CFA_restore_extended: case DW_CFA_undefined: @@ -151,26 +150,26 @@ void FrameEntry::parseInstructions(uint32_t &Offset, uint32_t EndOffset) { case DW_CFA_def_cfa_register: case DW_CFA_def_cfa_offset: // Operands: ULEB128 - addInstruction(Opcode, Data.getULEB128(&Offset)); + addInstruction(Opcode, Data.getULEB128(Offset)); break; case DW_CFA_def_cfa_offset_sf: // Operands: SLEB128 - addInstruction(Opcode, Data.getSLEB128(&Offset)); + addInstruction(Opcode, Data.getSLEB128(Offset)); break; case DW_CFA_offset_extended: case DW_CFA_register: case DW_CFA_def_cfa: case DW_CFA_val_offset: // Operands: ULEB128, ULEB128 - addInstruction(Opcode, Data.getULEB128(&Offset), - Data.getULEB128(&Offset)); + addInstruction(Opcode, Data.getULEB128(Offset), + 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)); + addInstruction(Opcode, Data.getULEB128(Offset), + Data.getSLEB128(Offset)); break; case DW_CFA_def_cfa_expression: case DW_CFA_expression: @@ -337,37 +336,42 @@ void DWARFDebugFrame::parse(DataExtractor Data) { Id = Data.getUnsigned(&Offset, IsDWARF64 ? 8 : 4); bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID); + FrameEntry *Entry = 0; if (IsCIE) { // Note: this is specifically DWARFv3 CIE header structure. It was - // changed in DWARFv4. + // changed in DWARFv4. We currently don't support reading DWARFv4 + // here because LLVM itself does not emit it (and LLDB doesn't + // support it either). uint8_t Version = Data.getU8(&Offset); const char *Augmentation = Data.getCStr(&Offset); uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset); int64_t DataAlignmentFactor = Data.getSLEB128(&Offset); uint64_t ReturnAddressRegister = Data.getULEB128(&Offset); - CIE *NewCIE = new CIE(Data, StartOffset, Length, Version, - StringRef(Augmentation), CodeAlignmentFactor, - DataAlignmentFactor, ReturnAddressRegister); - Entries.push_back(NewCIE); + Entry = new CIE(Data, StartOffset, Length, Version, + StringRef(Augmentation), CodeAlignmentFactor, + DataAlignmentFactor, ReturnAddressRegister); } else { // FDE uint64_t CIEPointer = Id; uint64_t InitialLocation = Data.getAddress(&Offset); uint64_t AddressRange = Data.getAddress(&Offset); - FDE *NewFDE = new FDE(Data, StartOffset, Length, CIEPointer, - InitialLocation, AddressRange); - Entries.push_back(NewFDE); + Entry = new FDE(Data, StartOffset, Length, CIEPointer, + InitialLocation, AddressRange); } - Entries.back()->parseInstructions(Offset, EndStructureOffset); + assert(Entry && "Expected Entry to be populated with CIE or FDE"); + Entry->parseInstructions(&Offset, EndStructureOffset); - if (Offset != EndStructureOffset) { + if (Offset == EndStructureOffset) { + // Entry instrucitons parsed successfully. + Entries.push_back(Entry); + } else { std::string Str; raw_string_ostream OS(Str); OS << format("Parsing entry instructions at %lx failed", - Entries.back()->getOffset()); + Entry->getOffset()); report_fatal_error(Str); } } -- cgit v1.1