Skip to content
Browse files

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
  • Loading branch information...
1 parent 5e215f9 commit 60bdc5b16e2fc17be184b515a00c2e2a2eb40b89 @eliben eliben committed Feb 5, 2013
View
1 include/llvm/DebugInfo/DIContext.h
@@ -101,6 +101,7 @@ enum DIDumpType {
DIDT_Abbrev,
DIDT_AbbrevDwo,
DIDT_Aranges,
+ DIDT_Frames,
DIDT_Info,
DIDT_InfoDwo,
DIDT_Line,
View
13 include/llvm/Support/Dwarf.h
@@ -16,6 +16,9 @@
#ifndef LLVM_SUPPORT_DWARF_H
#define LLVM_SUPPORT_DWARF_H
+#include "llvm/Support/DataTypes.h"
+
+
namespace llvm {
//===----------------------------------------------------------------------===//
@@ -53,10 +56,16 @@ enum llvm_dwarf_constants {
DW_TAG_user_base = 0x1000, // Recommended base for user tags.
- DW_CIE_VERSION = 1, // Common frame information version.
- DW_CIE_ID = 0xffffffff // Common frame information mark.
+ DW_CIE_VERSION = 1 // Common frame information version.
};
+
+// Special ID values that distinguish a CIE from a FDE in DWARF CFI.
+// Not inside an enum because a 64-bit value is needed.
+const uint32_t DW_CIE_ID = UINT32_MAX;
+const uint64_t DW64_CIE_ID = UINT64_MAX;
+
+
enum dwarf_constants {
DWARF_VERSION = 2,
View
30 lib/DebugInfo/DWARFContext.cpp
@@ -31,6 +31,11 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
getCompileUnitAtIndex(i)->dump(OS);
}
+ if (DumpType == DIDT_All || DumpType == DIDT_Frames) {
+ OS << "\n.debug_frame contents:\n";
+ getDebugFrame()->dump(OS);
+ }
+
uint32_t offset = 0;
if (DumpType == DIDT_All || DumpType == DIDT_Aranges) {
OS << "\n.debug_aranges contents:\n";
@@ -152,6 +157,26 @@ const DWARFDebugAranges *DWARFContext::getDebugAranges() {
return Aranges.get();
}
+const DWARFDebugFrame *DWARFContext::getDebugFrame() {
+ if (DebugFrame)
+ return DebugFrame.get();
+
+ // There's a "bug" in the DWARFv3 standard with respect to the target address
+ // size within debug frame sections. While DWARF is supposed to be independent
+ // of its container, FDEs have fields with size being "target address size",
+ // which isn't specified in DWARF in general. It's only specified for CUs, but
+ // .eh_frame can appear without a .debug_info section. Follow the example of
+ // other tools (libdwarf) and extract this from the container (ObjectFile
+ // provides this information). This problem is fixed in DWARFv4
+ // See this dwarf-discuss discussion for more details:
+ // http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html
+ DataExtractor debugFrameData(getDebugFrameSection(), isLittleEndian(),
+ getAddressSize());
+ DebugFrame.reset(new DWARFDebugFrame());
+ DebugFrame->parse(debugFrameData);
+ return DebugFrame.get();
+}
+
const DWARFLineTable *
DWARFContext::getLineTableForCompileUnit(DWARFCompileUnit *cu) {
if (!Line)
@@ -440,7 +465,8 @@ DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address,
}
DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) :
- IsLittleEndian(Obj->isLittleEndian()) {
+ IsLittleEndian(Obj->isLittleEndian()),
+ AddressSize(Obj->getBytesInAddress()) {
error_code ec;
for (object::section_iterator i = Obj->begin_sections(),
e = Obj->end_sections();
@@ -459,6 +485,8 @@ DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) :
LineSection = data;
else if (name == "debug_aranges")
ARangeSection = data;
+ else if (name == "debug_frame")
+ DebugFrameSection = data;
else if (name == "debug_str")
StringSection = data;
else if (name == "debug_ranges") {
View
11 lib/DebugInfo/DWARFContext.h
@@ -12,6 +12,7 @@
#include "DWARFCompileUnit.h"
#include "DWARFDebugAranges.h"
+#include "DWARFDebugFrame.h"
#include "DWARFDebugLine.h"
#include "DWARFDebugRangeList.h"
#include "llvm/ADT/OwningPtr.h"
@@ -29,6 +30,7 @@ class DWARFContext : public DIContext {
OwningPtr<DWARFDebugAbbrev> Abbrev;
OwningPtr<DWARFDebugAranges> Aranges;
OwningPtr<DWARFDebugLine> Line;
+ OwningPtr<DWARFDebugFrame> DebugFrame;
SmallVector<DWARFCompileUnit, 1> DWOCUs;
OwningPtr<DWARFDebugAbbrev> AbbrevDWO;
@@ -84,6 +86,9 @@ class DWARFContext : public DIContext {
/// Get a pointer to the parsed DebugAranges object.
const DWARFDebugAranges *getDebugAranges();
+ /// Get a pointer to the parsed frame information object.
+ const DWARFDebugFrame *getDebugFrame();
+
/// Get a pointer to a parsed line table corresponding to a compile unit.
const DWARFDebugLine::LineTable *
getLineTableForCompileUnit(DWARFCompileUnit *cu);
@@ -96,11 +101,13 @@ class DWARFContext : public DIContext {
DILineInfoSpecifier Specifier = DILineInfoSpecifier());
virtual bool isLittleEndian() const = 0;
+ virtual uint8_t getAddressSize() const = 0;
virtual const RelocAddrMap &infoRelocMap() const = 0;
virtual const RelocAddrMap &lineRelocMap() const = 0;
virtual StringRef getInfoSection() = 0;
virtual StringRef getAbbrevSection() = 0;
virtual StringRef getARangeSection() = 0;
+ virtual StringRef getDebugFrameSection() = 0;
virtual StringRef getLineSection() = 0;
virtual StringRef getStringSection() = 0;
virtual StringRef getRangeSection() = 0;
@@ -132,11 +139,13 @@ class DWARFContext : public DIContext {
class DWARFContextInMemory : public DWARFContext {
virtual void anchor();
bool IsLittleEndian;
+ uint8_t AddressSize;
RelocAddrMap InfoRelocMap;
RelocAddrMap LineRelocMap;
StringRef InfoSection;
StringRef AbbrevSection;
StringRef ARangeSection;
+ StringRef DebugFrameSection;
StringRef LineSection;
StringRef StringSection;
StringRef RangeSection;
@@ -153,11 +162,13 @@ class DWARFContextInMemory : public DWARFContext {
public:
DWARFContextInMemory(object::ObjectFile *);
virtual bool isLittleEndian() const { return IsLittleEndian; }
+ virtual uint8_t getAddressSize() const { return AddressSize; }
virtual const RelocAddrMap &infoRelocMap() const { return InfoRelocMap; }
virtual const RelocAddrMap &lineRelocMap() const { return LineRelocMap; }
virtual StringRef getInfoSection() { return InfoSection; }
virtual StringRef getAbbrevSection() { return AbbrevSection; }
virtual StringRef getARangeSection() { return ARangeSection; }
+ virtual StringRef getDebugFrameSection() { return DebugFrameSection; }
virtual StringRef getLineSection() { return LineSection; }
virtual StringRef getStringSection() { return StringSection; }
virtual StringRef getRangeSection() { return RangeSection; }
View
195 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<uint32_t>(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);
+ }
+}
+
View
46 lib/DebugInfo/DWARFDebugFrame.h
@@ -0,0 +1,46 @@
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARFDEBUGFRAME_H
+#define LLVM_DEBUGINFO_DWARFDEBUGFRAME_H
+
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <vector>
+
+
+namespace llvm {
+
+class FrameEntry;
+
+
+/// \brief A parsed .debug_frame section
+///
+class DWARFDebugFrame {
+public:
+ DWARFDebugFrame();
+ ~DWARFDebugFrame();
+
+ /// \brief Dump the section data into the given stream.
+ void dump(raw_ostream &OS) const;
+
+ /// \brief Parse the section from raw data.
+ /// data is assumed to be pointing to the beginning of the section.
+ void parse(DataExtractor Data);
+
+private:
+ typedef std::vector<FrameEntry *> EntryVector;
+ EntryVector Entries;
+};
+
+
+} // namespace llvm
+
+#endif
+
View
1 tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -63,6 +63,7 @@ DumpType("debug-dump", cl::init(DIDT_All),
clEnumValN(DIDT_Info, "info", ".debug_info"),
clEnumValN(DIDT_InfoDwo, "info.dwo", ".debug_info.dwo"),
clEnumValN(DIDT_Line, "line", ".debug_line"),
+ clEnumValN(DIDT_Frames, "frames", ".debug_frame"),
clEnumValN(DIDT_Ranges, "ranges", ".debug_ranges"),
clEnumValN(DIDT_Str, "str", ".debug_str"),
clEnumValN(DIDT_StrDwo, "str.dwo", ".debug_str.dwo"),

0 comments on commit 60bdc5b

Please sign in to comment.
Something went wrong with that request. Please try again.