Improve DWARFDebugFrame::parse to also handle __eh_frame.

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.

llvm-svn: 256008
diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp
index defd2d4..e68a143 100644
--- a/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/llvm/tools/llvm-objdump/MachODump.cpp
@@ -1210,6 +1210,12 @@
     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 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 @@
       printMachOCompactUnwindSection(Obj, Symbols, Section);
     else if (SectName == "__unwind_info")
       printMachOUnwindInfoSection(Obj, Symbols, Section);
-    else if (SectName == "__eh_frame")
-      printMachOEHFrameSection(Obj, Symbols, Section);
   }
 }