Improve DWARFDebugFrame::parse to also handle __eh_frame.
authorPete Cooper <peter_cooper@apple.com>
Fri, 18 Dec 2015 18:51:08 +0000 (18:51 +0000)
committerPete Cooper <peter_cooper@apple.com>
Fri, 18 Dec 2015 18:51:08 +0000 (18:51 +0000)
LLVM MC has single methods which can handle the output of EH frame and DWARF CIE's and FDE's.

This code improves DWARFDebugFrame::parse to do the same for parsing.

This also allows llvm-objdump to support the --dwarf=frames option which objdump supports.  This
option dumps the .eh_frame section using the new code in DWARFDebugFrame::parse.

http://reviews.llvm.org/D15535

Reviewed by Rafael Espindola.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@256008 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/DebugInfo/DIContext.h
include/llvm/DebugInfo/DWARF/DWARFContext.h
include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
include/llvm/DebugInfo/PDB/PDBContext.h
lib/DebugInfo/DWARF/DWARFContext.cpp
lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
lib/DebugInfo/PDB/PDBContext.cpp
test/tools/llvm-objdump/eh_frame-arm64.test
tools/llvm-objdump/MachODump.cpp
tools/llvm-objdump/llvm-objdump.cpp
tools/llvm-objdump/llvm-objdump.h

index 6659a97..769c45d 100644 (file)
@@ -140,7 +140,8 @@ public:
   DIContext(DIContextKind K) : Kind(K) {}
   virtual ~DIContext() {}
 
-  virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All) = 0;
+  virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All,
+                    bool DumpEH = false) = 0;
 
   virtual DILineInfo getLineInfoForAddress(uint64_t Address,
       DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
index ce253a0..71d5f25 100644 (file)
@@ -48,6 +48,7 @@ class DWARFContext : public DIContext {
   std::unique_ptr<DWARFDebugAranges> Aranges;
   std::unique_ptr<DWARFDebugLine> Line;
   std::unique_ptr<DWARFDebugFrame> DebugFrame;
+  std::unique_ptr<DWARFDebugFrame> EHFrame;
   std::unique_ptr<DWARFDebugMacro> Macro;
 
   DWARFUnitSection<DWARFCompileUnit> DWOCUs;
@@ -81,7 +82,8 @@ public:
     return DICtx->getKind() == CK_DWARF;
   }
 
-  void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All) override;
+  void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All,
+            bool DumpEH = false) override;
 
   typedef DWARFUnitSection<DWARFCompileUnit>::iterator_range cu_iterator_range;
   typedef DWARFUnitSection<DWARFTypeUnit>::iterator_range tu_iterator_range;
@@ -168,6 +170,9 @@ public:
   /// Get a pointer to the parsed frame information object.
   const DWARFDebugFrame *getDebugFrame();
 
+  /// Get a pointer to the parsed eh frame information object.
+  const DWARFDebugFrame *getEHFrame();
+
   /// Get a pointer to the parsed DebugMacro object.
   const DWARFDebugMacro *getDebugMacro();
 
@@ -191,6 +196,7 @@ public:
   virtual const DWARFSection &getLocSection() = 0;
   virtual StringRef getARangeSection() = 0;
   virtual StringRef getDebugFrameSection() = 0;
+  virtual StringRef getEHFrameSection() = 0;
   virtual const DWARFSection &getLineSection() = 0;
   virtual StringRef getStringSection() = 0;
   virtual StringRef getRangeSection() = 0;
@@ -242,6 +248,7 @@ class DWARFContextInMemory : public DWARFContext {
   DWARFSection LocSection;
   StringRef ARangeSection;
   StringRef DebugFrameSection;
+  StringRef EHFrameSection;
   DWARFSection LineSection;
   StringRef StringSection;
   StringRef RangeSection;
@@ -281,6 +288,7 @@ public:
   const DWARFSection &getLocSection() override { return LocSection; }
   StringRef getARangeSection() override { return ARangeSection; }
   StringRef getDebugFrameSection() override { return DebugFrameSection; }
+  StringRef getEHFrameSection() override { return EHFrameSection; }
   const DWARFSection &getLineSection() override { return LineSection; }
   StringRef getStringSection() override { return StringSection; }
   StringRef getRangeSection() override { return RangeSection; }
index be925cb..cd76c90 100644 (file)
@@ -19,11 +19,13 @@ namespace llvm {
 
 class FrameEntry;
 
-/// \brief A parsed .debug_frame section
+/// \brief A parsed .debug_frame or .eh_frame section
 ///
 class DWARFDebugFrame {
+  // True if this is parsing an eh_frame section.
+  bool IsEH;
 public:
-  DWARFDebugFrame();
+  DWARFDebugFrame(bool IsEH);
   ~DWARFDebugFrame();
 
   /// \brief Dump the section data into the given stream.
index 9404a59..2034e3b 100644 (file)
@@ -38,7 +38,8 @@ public:
     return DICtx->getKind() == CK_PDB;
   }
 
-  void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All) override;
+  void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All,
+            bool DumpEH = false) override;
 
   DILineInfo getLineInfoForAddress(
       uint64_t Address,
index a4195b7..6aa4675 100644 (file)
@@ -72,7 +72,7 @@ static void dumpAccelSection(raw_ostream &OS, StringRef Name,
   Accel.dump(OS);
 }
 
-void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
+void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH) {
   if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) {
     OS << ".debug_abbrev contents:\n";
     getDebugAbbrev()->dump(OS);
@@ -125,6 +125,10 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
   if (DumpType == DIDT_All || DumpType == DIDT_Frames) {
     OS << "\n.debug_frame contents:\n";
     getDebugFrame()->dump(OS);
+    if (DumpEH) {
+      OS << "\n.eh_frame contents:\n";
+      getEHFrame()->dump(OS);
+    }
   }
 
   if (DumpType == DIDT_All || DumpType == DIDT_Macro) {
@@ -355,7 +359,18 @@ const DWARFDebugFrame *DWARFContext::getDebugFrame() {
   // http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html
   DataExtractor debugFrameData(getDebugFrameSection(), isLittleEndian(),
                                getAddressSize());
-  DebugFrame.reset(new DWARFDebugFrame());
+  DebugFrame.reset(new DWARFDebugFrame(false /* IsEH */));
+  DebugFrame->parse(debugFrameData);
+  return DebugFrame.get();
+}
+
+const DWARFDebugFrame *DWARFContext::getEHFrame() {
+  if (EHFrame)
+    return EHFrame.get();
+
+  DataExtractor debugFrameData(getEHFrameSection(), isLittleEndian(),
+                               getAddressSize());
+  DebugFrame.reset(new DWARFDebugFrame(true /* IsEH */));
   DebugFrame->parse(debugFrameData);
   return DebugFrame.get();
 }
@@ -641,6 +656,7 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj,
             .Case("debug_line", &LineSection.Data)
             .Case("debug_aranges", &ARangeSection)
             .Case("debug_frame", &DebugFrameSection)
+            .Case("eh_frame", &EHFrameSection)
             .Case("debug_str", &StringSection)
             .Case("debug_ranges", &RangeSection)
             .Case("debug_macinfo", &MacinfoSection)
index 1aa31be..eff4870 100644 (file)
@@ -10,6 +10,7 @@
 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/DataTypes.h"
@@ -191,19 +192,31 @@ public:
   CIE(uint64_t Offset, uint64_t Length, uint8_t Version,
       SmallString<8> Augmentation, uint8_t AddressSize,
       uint8_t SegmentDescriptorSize, uint64_t CodeAlignmentFactor,
-      int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister)
+      int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister,
+      SmallString<8> AugmentationData, Optional<uint32_t> FDEPointerEncoding,
+      Optional<uint32_t> LSDAPointerEncoding)
       : FrameEntry(FK_CIE, Offset, Length), Version(Version),
         Augmentation(std::move(Augmentation)),
         AddressSize(AddressSize),
         SegmentDescriptorSize(SegmentDescriptorSize),
         CodeAlignmentFactor(CodeAlignmentFactor),
         DataAlignmentFactor(DataAlignmentFactor),
-        ReturnAddressRegister(ReturnAddressRegister) {}
+        ReturnAddressRegister(ReturnAddressRegister),
+        AugmentationData(AugmentationData),
+        FDEPointerEncoding(FDEPointerEncoding),
+        LSDAPointerEncoding(LSDAPointerEncoding) { }
 
   ~CIE() override {}
 
+  StringRef getAugmentationString() const { return Augmentation; }
   uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; }
   int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; }
+  Optional<uint32_t> getFDEPointerEncoding() const {
+    return FDEPointerEncoding;
+  }
+  Optional<uint32_t> getLSDAPointerEncoding() const {
+    return LSDAPointerEncoding;
+  }
 
   void dumpHeader(raw_ostream &OS) const override {
     OS << format("%08x %08x %08x CIE",
@@ -223,6 +236,8 @@ public:
                  (int32_t)DataAlignmentFactor);
     OS << format("  Return address column: %d\n",
                  (int32_t)ReturnAddressRegister);
+    if (!AugmentationData.empty())
+      OS << "  Augmentation data:     " << AugmentationData << "\n";
     OS << "\n";
   }
 
@@ -239,6 +254,11 @@ private:
   uint64_t CodeAlignmentFactor;
   int64_t DataAlignmentFactor;
   uint64_t ReturnAddressRegister;
+
+  // The following are used when the CIE represents an EH frame entry.
+  SmallString<8> AugmentationData;
+  Optional<uint32_t> FDEPointerEncoding;
+  Optional<uint32_t> LSDAPointerEncoding;
 };
 
 
@@ -423,7 +443,7 @@ void FrameEntry::dumpInstructions(raw_ostream &OS) const {
   }
 }
 
-DWARFDebugFrame::DWARFDebugFrame() {
+DWARFDebugFrame::DWARFDebugFrame(bool IsEH) : IsEH(IsEH) {
 }
 
 DWARFDebugFrame::~DWARFDebugFrame() {
@@ -439,6 +459,39 @@ static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
   errs() << "\n";
 }
 
+static unsigned getSizeForEncoding(const DataExtractor &Data,
+                                   unsigned symbolEncoding) {
+  unsigned format = symbolEncoding & 0x0f;
+  switch (format) {
+    default: llvm_unreachable("Unknown Encoding");
+    case dwarf::DW_EH_PE_absptr:
+    case dwarf::DW_EH_PE_signed:
+      return Data.getAddressSize();
+    case dwarf::DW_EH_PE_udata2:
+    case dwarf::DW_EH_PE_sdata2:
+      return 2;
+    case dwarf::DW_EH_PE_udata4:
+    case dwarf::DW_EH_PE_sdata4:
+      return 4;
+    case dwarf::DW_EH_PE_udata8:
+    case dwarf::DW_EH_PE_sdata8:
+      return 8;
+  }
+}
+
+static uint64_t readPointer(const DataExtractor &Data, uint32_t &Offset,
+                            unsigned Encoding) {
+  switch (getSizeForEncoding(Data, Encoding)) {
+    case 2:
+      return Data.getU16(&Offset);
+    case 4:
+      return Data.getU32(&Offset);
+    case 8:
+      return Data.getU64(&Offset);
+    default:
+      llvm_unreachable("Illegal data size");
+  }
+}
 
 void DWARFDebugFrame::parse(DataExtractor Data) {
   uint32_t Offset = 0;
@@ -447,6 +500,14 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
   while (Data.isValidOffset(Offset)) {
     uint32_t StartOffset = Offset;
 
+    auto ReportError = [StartOffset](const char *ErrorMsg) {
+      std::string Str;
+      raw_string_ostream OS(Str);
+      OS << format(ErrorMsg, StartOffset);
+      OS.flush();
+      report_fatal_error(Str);
+    };
+
     bool IsDWARF64 = false;
     uint64_t Length = Data.getU32(&Offset);
     uint64_t Id;
@@ -465,47 +526,136 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
     // read).
     // TODO: For honest DWARF64 support, DataExtractor will have to treat
     //       offset_ptr as uint64_t*
+    uint32_t StartStructureOffset = Offset;
     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);
+    Id = Data.getUnsigned(&Offset, (IsDWARF64 && !IsEH) ? 8 : 4);
+    bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) ||
+                  Id == DW_CIE_ID ||
+                  (IsEH && !Id));
 
     if (IsCIE) {
       uint8_t Version = Data.getU8(&Offset);
       const char *Augmentation = Data.getCStr(&Offset);
-      uint8_t AddressSize = Version < 4 ? Data.getAddressSize() : Data.getU8(&Offset);
+      StringRef AugmentationString(Augmentation ? Augmentation : "");
+      uint8_t AddressSize = Version < 4 ? Data.getAddressSize() :
+                                          Data.getU8(&Offset);
       Data.setAddressSize(AddressSize);
       uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset);
       uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
       int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
       uint64_t ReturnAddressRegister = Data.getULEB128(&Offset);
 
+      // Parse the augmentation data for EH CIEs
+      StringRef AugmentationData;
+      Optional<uint32_t> FDEPointerEncoding;
+      Optional<uint32_t> LSDAPointerEncoding;
+      if (IsEH) {
+        Optional<uint32_t> PersonalityEncoding;
+        Optional<uint64_t> Personality;
+
+        uint64_t AugmentationLength = 0;
+        uint32_t StartAugmentationOffset = 0;
+        uint32_t EndAugmentationOffset = 0;
+
+        // Walk the augmentation string to get all the augmentation data.
+        for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {
+          switch (AugmentationString[i]) {
+            default:
+              ReportError("Unknown augmentation character in entry at %lx");
+            case 'L':
+              if (LSDAPointerEncoding)
+                ReportError("Duplicate LSDA encoding in entry at %lx");
+              LSDAPointerEncoding = Data.getU8(&Offset);
+              break;
+            case 'P': {
+              if (Personality)
+                ReportError("Duplicate personality in entry at %lx");
+              PersonalityEncoding = Data.getU8(&Offset);
+              Personality = readPointer(Data, Offset, *PersonalityEncoding);
+              break;
+            }
+            case 'R':
+              if (FDEPointerEncoding)
+                ReportError("Duplicate FDE encoding in entry at %lx");
+              FDEPointerEncoding = Data.getU8(&Offset);
+              break;
+            case 'z':
+              if (i)
+                ReportError("'z' must be the first character at %lx");
+              // Parse the augmentation length first.  We only parse it if
+              // the string contains a 'z'.
+              AugmentationLength = Data.getULEB128(&Offset);
+              StartAugmentationOffset = Offset;
+              EndAugmentationOffset =
+                Offset + static_cast<uint32_t>(AugmentationLength);
+          }
+        }
+
+        if (Offset != EndAugmentationOffset)
+          ReportError("Parsing augmentation data at %lx failed");
+
+        AugmentationData = Data.getData().slice(StartAugmentationOffset,
+                                                EndAugmentationOffset);
+      }
+
       auto Cie = make_unique<CIE>(StartOffset, Length, Version,
                                   StringRef(Augmentation), AddressSize,
                                   SegmentDescriptorSize, CodeAlignmentFactor,
-                                  DataAlignmentFactor, ReturnAddressRegister);
+                                  DataAlignmentFactor, ReturnAddressRegister,
+                                  AugmentationData, FDEPointerEncoding,
+                                  LSDAPointerEncoding);
       CIEs[StartOffset] = Cie.get();
       Entries.emplace_back(std::move(Cie));
     } else {
       // FDE
       uint64_t CIEPointer = Id;
-      uint64_t InitialLocation = Data.getAddress(&Offset);
-      uint64_t AddressRange = Data.getAddress(&Offset);
+      uint64_t InitialLocation = 0;
+      uint64_t AddressRange = 0;
+      CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer];
+
+      if (IsEH) {
+        // The address size is encoded in the CIE we reference.
+        if (!Cie)
+          ReportError("Parsing FDE data at %lx failed due to missing CIE");
+
+        Optional<uint32_t> FDEPointerEncoding = Cie->getFDEPointerEncoding();
+        if (!FDEPointerEncoding)
+          ReportError("Parsing at %lx failed due to missing pointer encoding");
+
+        InitialLocation = readPointer(Data, Offset, *FDEPointerEncoding);
+        AddressRange = readPointer(Data, Offset, *FDEPointerEncoding);
+        StringRef AugmentationString = Cie->getAugmentationString();
+        if (!AugmentationString.empty()) {
+          // Parse the augmentation length and data for this FDE.
+          uint64_t AugmentationLength = Data.getULEB128(&Offset);
+
+          uint32_t EndAugmentationOffset =
+            Offset + static_cast<uint32_t>(AugmentationLength);
+
+          // Decode the LSDA if the CIE augmentation string said we should.
+          uint64_t LSDA = 0;
+          if (Optional<uint32_t> Encoding = Cie->getLSDAPointerEncoding())
+            LSDA = readPointer(Data, Offset, *Encoding);
+
+          if (Offset != EndAugmentationOffset)
+            ReportError("Parsing augmentation data at %lx failed");
+        }
+      } else {
+        InitialLocation = Data.getAddress(&Offset);
+        AddressRange = Data.getAddress(&Offset);
+      }
 
       Entries.emplace_back(new FDE(StartOffset, Length, CIEPointer,
                                    InitialLocation, AddressRange,
-                                   CIEs[CIEPointer]));
+                                   Cie));
     }
 
     Entries.back()->parseInstructions(Data, &Offset, EndStructureOffset);
 
-    if (Offset != EndStructureOffset) {
-      std::string Str;
-      raw_string_ostream OS(Str);
-      OS << format("Parsing entry instructions at %lx failed", StartOffset);
-      report_fatal_error(Str);
-    }
+    if (Offset != EndStructureOffset)
+      ReportError("Parsing entry instructions at %lx failed");
   }
 }
 
index ca2ae66..561a91e 100644 (file)
@@ -28,7 +28,8 @@ PDBContext::PDBContext(const COFFObjectFile &Object,
     Session->setLoadAddress(ImageBase.get());
 }
 
-void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType) {}
+void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType,
+                      bool DumpEH) {}
 
 DILineInfo PDBContext::getLineInfoForAddress(uint64_t Address,
                                              DILineInfoSpecifier Specifier) {
index f25e035..adfd4cc 100644 (file)
@@ -1,23 +1,23 @@
-# RUN: llvm-objdump -unwind-info %p/Inputs/eh_frame.macho-arm64 2>/dev/null | FileCheck %s
+# RUN: llvm-objdump -dwarf=frames %p/Inputs/eh_frame.macho-arm64 2>/dev/null | FileCheck %s
 
-# CHECK: Contents of __eh_frame section:
-# CHECK: CIE:
-# CHECK:   Length: 16
-# CHECK:   CIE ID: 0
-# CHECK:   Version: 1
-# CHECK:   Augmentation String: zR
-# CHECK:   Code Alignment Factor: 1
-# CHECK:   Data Alignment Factor: -8
-# CHECK:   Return Address Register: 30
-# CHECK:   Augmentation Data Length: 1
-# CHECK:   FDE Address Pointer Encoding: 16
-# CHECK:   Instructions:
-# CHECK:   0c 1f 00 
-# CHECK: FDE:
-# CHECK:   Length: 32
-# CHECK:   CIE Offset: 0
-# CHECK:   PC Begin: ffffffffffffffe4
-# CHECK:   PC Range: 0000000000000020
-# CHECK:   Augmentation Data Length: 0
-# CHECK:   Instructions:
-# CHECK:   48 0e 10 9e 01 9d 02 00 00 00 00
+# CHECK: .eh_frame contents:
+
+# CHECK: 00000000 00000010 ffffffff CIE
+# CHECK:   Version:               1
+# CHECK:   Augmentation:          "zR"
+# CHECK:   Code alignment factor: 1
+# CHECK:   Data alignment factor: -8
+# CHECK:   Return address column: 30
+# CHECK:   Augmentation data:
+
+# CHECK:   DW_CFA_def_cfa: reg31 +0
+
+# CHECK: 00000014 00000020 00000018 FDE cie=00000018 pc=ffffffe4...00000004
+# CHECK:   DW_CFA_advance_loc: 8
+# CHECK:   DW_CFA_def_cfa_offset: +16
+# CHECK:   DW_CFA_offset: reg30 -8
+# CHECK:   DW_CFA_offset: reg29 -16
+# CHECK:   DW_CFA_nop:
+# CHECK:   DW_CFA_nop:
+# CHECK:   DW_CFA_nop:
+# CHECK:   DW_CFA_nop:
index defd2d4..e68a143 100644 (file)
@@ -1210,6 +1210,12 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF,
     printLazyBindTable(MachOOF);
   if (WeakBind)
     printWeakBindTable(MachOOF);
+
+  if (DwarfDumpType != DIDT_Null) {
+    std::unique_ptr<DIContext> DICtx(new DWARFContextInMemory(*MachOOF));
+    // Dump the complete DWARF structure.
+    DICtx->dump(outs(), DwarfDumpType, true /* DumpEH */);
+  }
 }
 
 // printUnknownCPUType() helps print_fat_headers for unknown CPU's.
@@ -6748,262 +6754,6 @@ static void printMachOUnwindInfoSection(const MachOObjectFile *Obj,
   }
 }
 
-static unsigned getSizeForEncoding(bool is64Bit,
-                                   unsigned symbolEncoding) {
-  unsigned format = symbolEncoding & 0x0f;
-  switch (format) {
-    default: llvm_unreachable("Unknown Encoding");
-    case dwarf::DW_EH_PE_absptr:
-    case dwarf::DW_EH_PE_signed:
-      return is64Bit ? 8 : 4;
-    case dwarf::DW_EH_PE_udata2:
-    case dwarf::DW_EH_PE_sdata2:
-      return 2;
-    case dwarf::DW_EH_PE_udata4:
-    case dwarf::DW_EH_PE_sdata4:
-      return 4;
-    case dwarf::DW_EH_PE_udata8:
-    case dwarf::DW_EH_PE_sdata8:
-      return 8;
-  }
-}
-
-static uint64_t readPointer(const char *&Pos, bool is64Bit, unsigned Encoding) {
-  switch (getSizeForEncoding(is64Bit, Encoding)) {
-    case 2:
-      return readNext<uint16_t>(Pos);
-      break;
-    case 4:
-      return readNext<uint32_t>(Pos);
-      break;
-    case 8:
-      return readNext<uint64_t>(Pos);
-      break;
-    default:
-      llvm_unreachable("Illegal data size");
-  }
-}
-
-static void printMachOEHFrameSection(const MachOObjectFile *Obj,
-                                     std::map<uint64_t, SymbolRef> &Symbols,
-                                     const SectionRef &EHFrame) {
-  if (!Obj->isLittleEndian()) {
-    outs() << "warning: cannot handle big endian __eh_frame section\n";
-    return;
-  }
-
-  bool is64Bit = Obj->is64Bit();
-
-  outs() << "Contents of __eh_frame section:\n";
-
-  StringRef Contents;
-  EHFrame.getContents(Contents);
-
-  /// A few fields of the CIE are used when decoding the FDE's.  This struct
-  /// will cache those fields we need so that we don't have to decode it
-  /// repeatedly for each FDE that references it.
-  struct DecodedCIE {
-    Optional<uint32_t> FDEPointerEncoding;
-    Optional<uint32_t> LSDAPointerEncoding;
-    bool hasAugmentationLength;
-  };
-
-  // Map from the start offset of the CIE to the cached data for that CIE.
-  DenseMap<uint64_t, DecodedCIE> CachedCIEs;
-
-  for (const char *Pos = Contents.data(), *End = Contents.end(); Pos != End; ) {
-
-    const char *EntryStartPos = Pos;
-
-    uint64_t Length = readNext<uint32_t>(Pos);
-    if (Length == 0xffffffff)
-      Length = readNext<uint64_t>(Pos);
-
-    // Save the Pos so that we can check the length we encoded against what we
-    // end up decoding.
-    const char *PosAfterLength = Pos;
-    const char *EntryEndPos = PosAfterLength + Length;
-
-    assert(EntryEndPos <= End &&
-           "__eh_frame entry length exceeds section size");
-
-    uint32_t ID = readNext<uint32_t>(Pos);
-    if (ID == 0) {
-      // This is a CIE.
-
-      uint32_t Version = readNext<uint8_t>(Pos);
-
-      // Parse a null terminated augmentation string
-      SmallString<8> AugmentationString;
-      for (uint8_t Char = readNext<uint8_t>(Pos); Char;
-           Char = readNext<uint8_t>(Pos))
-        AugmentationString.push_back(Char);
-
-      // Optionally parse the EH data if the augmentation string says it's there.
-      Optional<uint64_t> EHData;
-      if (StringRef(AugmentationString).count("eh"))
-        EHData = is64Bit ? readNext<uint64_t>(Pos) : readNext<uint32_t>(Pos);
-
-      unsigned ULEBByteCount;
-      uint64_t CodeAlignmentFactor = decodeULEB128((const uint8_t *)Pos,
-                                                   &ULEBByteCount);
-      Pos += ULEBByteCount;
-
-      int64_t DataAlignmentFactor = decodeSLEB128((const uint8_t *)Pos,
-                                                   &ULEBByteCount);
-      Pos += ULEBByteCount;
-
-      uint32_t ReturnAddressRegister = readNext<uint8_t>(Pos);
-
-      Optional<uint64_t> AugmentationLength;
-      Optional<uint32_t> LSDAPointerEncoding;
-      Optional<uint32_t> PersonalityEncoding;
-      Optional<uint64_t> Personality;
-      Optional<uint32_t> FDEPointerEncoding;
-      if (!AugmentationString.empty() && AugmentationString.front() == 'z') {
-        AugmentationLength = decodeULEB128((const uint8_t *)Pos,
-                                           &ULEBByteCount);
-        Pos += ULEBByteCount;
-
-        // Walk the augmentation string to get all the augmentation data.
-        for (unsigned i = 1, e = AugmentationString.size(); i != e; ++i) {
-          char Char = AugmentationString[i];
-          switch (Char) {
-            case 'e':
-              assert((i + 1) != e && AugmentationString[i + 1] == 'h' &&
-                     "Expected 'eh' in augmentation string");
-              break;
-            case 'L':
-              assert(!LSDAPointerEncoding && "Duplicate LSDA encoding");
-              LSDAPointerEncoding = readNext<uint8_t>(Pos);
-              break;
-            case 'P': {
-              assert(!Personality && "Duplicate personality");
-              PersonalityEncoding = readNext<uint8_t>(Pos);
-              Personality = readPointer(Pos, is64Bit, *PersonalityEncoding);
-              break;
-            }
-            case 'R':
-              assert(!FDEPointerEncoding && "Duplicate FDE encoding");
-              FDEPointerEncoding = readNext<uint8_t>(Pos);
-              break;
-            case 'z':
-              llvm_unreachable("'z' must be first in the augmentation string");
-          }
-        }
-      }
-
-      outs() << "CIE:\n";
-      outs() << "  Length: " << Length << "\n";
-      outs() << "  CIE ID: " << ID << "\n";
-      outs() << "  Version: " << Version << "\n";
-      outs() << "  Augmentation String: " << AugmentationString << "\n";
-      if (EHData)
-        outs() << "  EHData: " << *EHData << "\n";
-      outs() << "  Code Alignment Factor: " << CodeAlignmentFactor << "\n";
-      outs() << "  Data Alignment Factor: " << DataAlignmentFactor << "\n";
-      outs() << "  Return Address Register: " << ReturnAddressRegister << "\n";
-      if (AugmentationLength) {
-        outs() << "  Augmentation Data Length: " << *AugmentationLength << "\n";
-        if (LSDAPointerEncoding) {
-          outs() << "  FDE LSDA Pointer Encoding: "
-                 << *LSDAPointerEncoding << "\n";
-        }
-        if (Personality) {
-          outs() << "  Personality Encoding: " << *PersonalityEncoding << "\n";
-          outs() << "  Personality: " << *Personality << "\n";
-        }
-        if (FDEPointerEncoding) {
-          outs() << "  FDE Address Pointer Encoding: "
-                 << *FDEPointerEncoding << "\n";
-        }
-      }
-      // FIXME: Handle instructions.
-      // For now just emit some bytes
-      outs() << "  Instructions:\n  ";
-      dumpBytes(makeArrayRef((const uint8_t*)Pos, (const uint8_t*)EntryEndPos),
-                outs());
-      outs() << "\n";
-      Pos = EntryEndPos;
-
-      // Cache this entry.
-      uint64_t Offset = EntryStartPos - Contents.data();
-      CachedCIEs[Offset] = { FDEPointerEncoding, LSDAPointerEncoding,
-                             AugmentationLength.hasValue() };
-      continue;
-    }
-
-    // This is an FDE.
-    // The CIE pointer for an FDE is the same location as the ID which we
-    // already read.
-    uint32_t CIEPointer = ID;
-
-    const char *CIEStart = PosAfterLength - CIEPointer;
-    assert(CIEStart >= Contents.data() &&
-           "FDE points to CIE before the __eh_frame start");
-
-    uint64_t CIEOffset = CIEStart - Contents.data();
-    auto CIEIt = CachedCIEs.find(CIEOffset);
-    if (CIEIt == CachedCIEs.end())
-      llvm_unreachable("Couldn't find CIE at offset in to __eh_frame section");
-
-    const DecodedCIE &CIE = CIEIt->getSecond();
-    assert(CIE.FDEPointerEncoding &&
-           "FDE references CIE which did not set pointer encoding");
-
-    uint64_t PCPointerSize = getSizeForEncoding(is64Bit,
-                                                *CIE.FDEPointerEncoding);
-
-    uint64_t PCBegin = readPointer(Pos, is64Bit, *CIE.FDEPointerEncoding);
-    uint64_t PCRange = readPointer(Pos, is64Bit, *CIE.FDEPointerEncoding);
-
-    Optional<uint64_t> AugmentationLength;
-    uint32_t LSDAPointerSize;
-    Optional<uint64_t> LSDAPointer;
-    if (CIE.hasAugmentationLength) {
-      unsigned ULEBByteCount;
-      AugmentationLength = decodeULEB128((const uint8_t *)Pos,
-                                         &ULEBByteCount);
-      Pos += ULEBByteCount;
-
-      // Decode the LSDA if the CIE augmentation string said we should.
-      if (CIE.LSDAPointerEncoding) {
-        LSDAPointerSize = getSizeForEncoding(is64Bit, *CIE.LSDAPointerEncoding);
-        LSDAPointer = readPointer(Pos, is64Bit, *CIE.LSDAPointerEncoding);
-      }
-    }
-
-    outs() << "FDE:\n";
-    outs() << "  Length: " << Length << "\n";
-    outs() << "  CIE Offset: " << CIEOffset << "\n";
-
-    if (PCPointerSize == 8) {
-      outs() << format("  PC Begin: %016" PRIx64, PCBegin) << "\n";
-      outs() << format("  PC Range: %016" PRIx64, PCRange) << "\n";
-    } else {
-      outs() << format("  PC Begin: %08" PRIx64, PCBegin) << "\n";
-      outs() << format("  PC Range: %08" PRIx64, PCRange) << "\n";
-    }
-    if (AugmentationLength) {
-      outs() << "  Augmentation Data Length: " << *AugmentationLength << "\n";
-      if (LSDAPointer) {
-        if (LSDAPointerSize == 8)
-          outs() << format("  LSDA Pointer: %016\n" PRIx64, *LSDAPointer);
-        else
-          outs() << format("  LSDA Pointer: %08\n" PRIx64, *LSDAPointer);
-      }
-    }
-
-    // FIXME: Handle instructions.
-    // For now just emit some bytes
-    outs() << "  Instructions:\n  ";
-    dumpBytes(makeArrayRef((const uint8_t*)Pos, (const uint8_t*)EntryEndPos),
-              outs());
-    outs() << "\n";
-    Pos = EntryEndPos;
-  }
-}
-
 void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) {
   std::map<uint64_t, SymbolRef> Symbols;
   for (const SymbolRef &SymRef : Obj->symbols()) {
@@ -7024,8 +6774,6 @@ void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) {
       printMachOCompactUnwindSection(Obj, Symbols, Section);
     else if (SectName == "__unwind_info")
       printMachOUnwindInfoSection(Obj, Symbols, Section);
-    else if (SectName == "__eh_frame")
-      printMachOEHFrameSection(Obj, Symbols, Section);
   }
 }
 
index d46ea38..970fc61 100644 (file)
@@ -22,6 +22,7 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/CodeGen/FaultMaps.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDisassembler.h"
@@ -176,6 +177,11 @@ cl::opt<bool>
 cl::opt<bool> PrintFaultMaps("fault-map-section",
                              cl::desc("Display contents of faultmap section"));
 
+cl::opt<DIDumpType> llvm::DwarfDumpType(
+    "dwarf", cl::init(DIDT_Null), cl::desc("Dump of dwarf debug sections:"),
+    cl::values(clEnumValN(DIDT_Frames, "frames", ".debug_frame"),
+               clEnumValEnd));
+
 static StringRef ToolName;
 
 namespace {
@@ -1572,6 +1578,11 @@ static void DumpObject(const ObjectFile *o) {
     printRawClangAST(o);
   if (PrintFaultMaps)
     printFaultMaps(o);
+  if (DwarfDumpType != DIDT_Null) {
+    std::unique_ptr<DIContext> DICtx(new DWARFContextInMemory(*o));
+    // Dump the complete DWARF structure.
+    DICtx->dump(outs(), DwarfDumpType, true /* DumpEH */);
+  }
 }
 
 /// @brief Dump each object file in \a a;
@@ -1664,7 +1675,8 @@ int main(int argc, char **argv) {
       && !(DylibId && MachOOpt)
       && !(ObjcMetaData && MachOOpt)
       && !(FilterSections.size() != 0 && MachOOpt)
-      && !PrintFaultMaps) {
+      && !PrintFaultMaps
+      && DwarfDumpType == DIDT_Null) {
     cl::PrintHelpMessage();
     return 2;
   }
index f74ed01..7303c3a 100644 (file)
@@ -10,6 +10,7 @@
 #define LLVM_TOOLS_LLVM_OBJDUMP_LLVM_OBJDUMP_H
 
 #include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/DIContext.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/DataTypes.h"
 
@@ -53,6 +54,7 @@ extern cl::opt<bool> SectionContents;
 extern cl::opt<bool> SymbolTable;
 extern cl::opt<bool> UnwindInfo;
 extern cl::opt<bool> PrintImmHex;
+extern cl::opt<DIDumpType> DwarfDumpType;
 
 // Various helper functions.
 void error(std::error_code ec);