From 832d1103af38a870d0baf9b59194e9a6f482647d Mon Sep 17 00:00:00 2001 From: Pete Cooper Date: Mon, 14 Dec 2015 21:39:27 +0000 Subject: [PATCH 1/1] Print the eh_frame section in MachoDump. 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 --- .../llvm-objdump/Inputs/eh_frame.macho-arm64 | Bin 0 -> 888 bytes test/tools/llvm-objdump/eh_frame-arm64.test | 18 ++ tools/llvm-objdump/MachODump.cpp | 181 +++++++++++++++++- 3 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 test/tools/llvm-objdump/Inputs/eh_frame.macho-arm64 create mode 100644 test/tools/llvm-objdump/eh_frame-arm64.test 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 index 0000000000000000000000000000000000000000..1c5413230d7aa512792735533eb7d939fd9ce037 GIT binary patch literal 888 zcmb7CK}!Nr5S~r5BHKJgLD&)mT>`61m!Ly|2M;11qRT^cO<{ExT~YGl(PKf^I@_?KcH)WAh7!8?JTW!YGCG@?>*;pX7;^&etac~41#fpb210FI3e1A5B064f5K2s zEUtltd;vMT)&nZ#+dUtNm{P^F^J2(;(UO$)SaO6ARED* z*|eQVe?ql(m@`7pZFr@!uR6_cy;)HzcN)FV2(bk7($^R$>zVoorR+#~8J)SgGq&iy3>0spc||M6iG zqZ<@m!x?Xh28BugX*7P$u0fVc$W9? zz@!#KnW=l@jz`tAV}?Eco|q@M7~nDAfhRVBcx!1!%xvxgO&(l~cVt4z623jdxz3aw x@=w;7LonRs3ixV7kJAXn1M)h4n{o=T5|8QPu/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 diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index c8835145611..a3356c785d6 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -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 &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(Pos); + if (Length == 0xffffffff) + Length = readNext(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(Pos); + if (ID == 0) { + // This is a CIE. + + uint32_t Version = readNext(Pos); + + // Parse a null terminated augmentation string + SmallString<8> AugmentationString; + for (uint8_t Char = readNext(Pos); Char; + Char = readNext(Pos)) + AugmentationString.push_back(Char); + + // Optionally parse the EH data if the augmentation string says it's there. + Optional EHData; + if (StringRef(AugmentationString).count("eh")) + EHData = is64Bit ? readNext(Pos) : readNext(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(Pos); + + Optional AugmentationLength; + Optional LSDAPointerEncoding; + Optional PersonalityEncoding; + Optional Personality; + Optional 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(Pos); + break; + case 'P': { + assert(!Personality && "Duplicate personality"); + PersonalityEncoding = readNext(Pos); + switch (getSizeForEncoding(is64Bit, *PersonalityEncoding)) { + case 2: + Personality = readNext(Pos); + break; + case 4: + Personality = readNext(Pos); + break; + case 8: + Personality = readNext(Pos); + break; + default: + llvm_unreachable("Illegal data size"); + } + break; + } + case 'R': + assert(!FDEPointerEncoding && "Duplicate FDE encoding"); + FDEPointerEncoding = readNext(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 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); } } -- 2.34.1