Print the eh_frame section in MachoDump.
authorPete Cooper <peter_cooper@apple.com>
Mon, 14 Dec 2015 21:39:27 +0000 (21:39 +0000)
committerPete Cooper <peter_cooper@apple.com>
Mon, 14 Dec 2015 21:39:27 +0000 (21:39 +0000)
This is the start of work to dump the contents of the eh_frame section.

It currently emits CIE entries.  FDE entries will come later.

It also needs improved error checking which will follow soon.

http://reviews.llvm.org/D15502

Reviewed by Kevin Enderby and Lang Hames.

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

test/tools/llvm-objdump/Inputs/eh_frame.macho-arm64 [new file with mode: 0644]
test/tools/llvm-objdump/eh_frame-arm64.test [new file with mode: 0644]
tools/llvm-objdump/MachODump.cpp

diff --git a/test/tools/llvm-objdump/Inputs/eh_frame.macho-arm64 b/test/tools/llvm-objdump/Inputs/eh_frame.macho-arm64
new file mode 100644 (file)
index 0000000..1c54132
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/eh_frame.macho-arm64 differ
diff --git a/test/tools/llvm-objdump/eh_frame-arm64.test b/test/tools/llvm-objdump/eh_frame-arm64.test
new file mode 100644 (file)
index 0000000..dbc6bcf
--- /dev/null
@@ -0,0 +1,18 @@
+# RUN: llvm-objdump -unwind-info %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:   e4 ff ff ff ff ff ff ff 20 00 00 00 00 00 00 00 00 48 0e 10 9e 01 9d 02 00 00 00 00 
index c883514..a3356c7 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "llvm-objdump.h"
 #include "llvm-c/Disassembler.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/Triple.h"
@@ -6750,6 +6751,184 @@ 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 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);
+
+
+  //===----------------------------------
+  // Entry header
+  //===----------------------------------
+
+  for (const char *Pos = Contents.data(), *End = Contents.end(); Pos != End; ) {
+
+    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);
+              switch (getSizeForEncoding(is64Bit, *PersonalityEncoding)) {
+                case 2:
+                  Personality = readNext<uint16_t>(Pos);
+                  break;
+                case 4:
+                  Personality = readNext<uint32_t>(Pos);
+                  break;
+                case 8:
+                  Personality = readNext<uint64_t>(Pos);
+                  break;
+                default:
+                  llvm_unreachable("Illegal data size");
+              }
+              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;
+      continue;
+    }
+    // This is an FDE.
+    outs() << "FDE:\n";
+    outs() << "  Length: " << Length << "\n";
+    outs() << "  ";
+    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()) {
@@ -6771,7 +6950,7 @@ void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) {
     else if (SectName == "__unwind_info")
       printMachOUnwindInfoSection(Obj, Symbols, Section);
     else if (SectName == "__eh_frame")
-      outs() << "llvm-objdump: warning: unhandled __eh_frame section\n";
+      printMachOEHFrameSection(Obj, Symbols, Section);
   }
 }