[llvm] r174463 - Initial support for DWARF CFI parsing and dumping in LLVM

Eli Bendersky eliben at google.com
Tue Feb 5 15:30:58 PST 2013


Author: eliben
Date: Tue Feb  5 17:30:58 2013
New Revision: 174463

URL: http://llvm.org/viewvc/llvm-project?rev=174463&view=rev
Log:
Initial support for DWARF CFI parsing and dumping in LLVM

Added:
    llvm/trunk/lib/DebugInfo/DWARFDebugFrame.cpp
    llvm/trunk/lib/DebugInfo/DWARFDebugFrame.h
Modified:
    llvm/trunk/include/llvm/DebugInfo/DIContext.h
    llvm/trunk/include/llvm/Support/Dwarf.h
    llvm/trunk/lib/DebugInfo/DWARFContext.cpp
    llvm/trunk/lib/DebugInfo/DWARFContext.h
    llvm/trunk/tools/llvm-dwarfdump/llvm-dwarfdump.cpp

Modified: llvm/trunk/include/llvm/DebugInfo/DIContext.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DIContext.h?rev=174463&r1=174462&r2=174463&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DIContext.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DIContext.h Tue Feb  5 17:30:58 2013
@@ -101,6 +101,7 @@ enum DIDumpType {
   DIDT_Abbrev,
   DIDT_AbbrevDwo,
   DIDT_Aranges,
+  DIDT_Frames,
   DIDT_Info,
   DIDT_InfoDwo,
   DIDT_Line,

Modified: llvm/trunk/include/llvm/Support/Dwarf.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Dwarf.h?rev=174463&r1=174462&r2=174463&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/Dwarf.h (original)
+++ llvm/trunk/include/llvm/Support/Dwarf.h Tue Feb  5 17:30:58 2013
@@ -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,
 

Modified: llvm/trunk/lib/DebugInfo/DWARFContext.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARFContext.cpp?rev=174463&r1=174462&r2=174463&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARFContext.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARFContext.cpp Tue Feb  5 17:30:58 2013
@@ -31,6 +31,11 @@ void DWARFContext::dump(raw_ostream &OS,
       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::g
   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::getInlining
 }
 
 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::DWARFContextInMemo
       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") {

Modified: llvm/trunk/lib/DebugInfo/DWARFContext.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARFContext.h?rev=174463&r1=174462&r2=174463&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARFContext.h (original)
+++ llvm/trunk/lib/DebugInfo/DWARFContext.h Tue Feb  5 17:30:58 2013
@@ -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 @@ public:
   /// 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 @@ public:
       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 @@ private:
 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 DWAR
 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; }

Added: llvm/trunk/lib/DebugInfo/DWARFDebugFrame.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARFDebugFrame.cpp?rev=174463&view=auto
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARFDebugFrame.cpp (added)
+++ llvm/trunk/lib/DebugInfo/DWARFDebugFrame.cpp Tue Feb  5 17:30:58 2013
@@ -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);
+  }
+}
+

Added: llvm/trunk/lib/DebugInfo/DWARFDebugFrame.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARFDebugFrame.h?rev=174463&view=auto
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARFDebugFrame.h (added)
+++ llvm/trunk/lib/DebugInfo/DWARFDebugFrame.h Tue Feb  5 17:30:58 2013
@@ -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 
+

Modified: llvm/trunk/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-dwarfdump/llvm-dwarfdump.cpp?rev=174463&r1=174462&r2=174463&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-dwarfdump/llvm-dwarfdump.cpp (original)
+++ llvm/trunk/tools/llvm-dwarfdump/llvm-dwarfdump.cpp Tue Feb  5 17:30:58 2013
@@ -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"),





More information about the llvm-commits mailing list