From 2d6ab4db1cefe78251a21cb1f3727be3cb2039d8 Mon Sep 17 00:00:00 2001 From: Pete Cooper Date: Mon, 14 Dec 2015 21:49:49 +0000 Subject: [PATCH] Start implementing FDE dumping when printing the eh_frame. This code adds some simple decoding of the FDE's in an eh_frame. There's still more to be done in terms of error handling and verification. Also, we need to be able to decode the CFI's. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@255550 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tools/llvm-objdump/eh_frame-arm64.test | 7 +- tools/llvm-objdump/MachODump.cpp | 112 +++++++++++++++++++- 2 files changed, 113 insertions(+), 6 deletions(-) diff --git a/test/tools/llvm-objdump/eh_frame-arm64.test b/test/tools/llvm-objdump/eh_frame-arm64.test index dbc6bcfcf91..f25e035a266 100644 --- a/test/tools/llvm-objdump/eh_frame-arm64.test +++ b/test/tools/llvm-objdump/eh_frame-arm64.test @@ -15,4 +15,9 @@ # 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 +# 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 diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index a3356c785d6..2fd0751dd8c 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -6786,13 +6786,22 @@ static void printMachOEHFrameSection(const MachOObjectFile *Obj, 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 FDEPointerEncoding; + Optional LSDAPointerEncoding; + bool hasAugmentationLength; + }; - //===---------------------------------- - // Entry header - //===---------------------------------- + // Map from the start offset of the CIE to the cached data for that CIE. + DenseMap CachedCIEs; for (const char *Pos = Contents.data(), *End = Contents.end(); Pos != End; ) { + const char *EntryStartPos = Pos; + uint64_t Length = readNext(Pos); if (Length == 0xffffffff) Length = readNext(Pos); @@ -6915,17 +6924,110 @@ static void printMachOEHFrameSection(const MachOObjectFile *Obj, 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; + uint64_t PCRange; + switch (PCPointerSize) { + case 2: + PCBegin = readNext(Pos); + PCRange = readNext(Pos); + break; + case 4: + PCBegin = readNext(Pos); + PCRange = readNext(Pos); + break; + case 8: + PCBegin = readNext(Pos); + PCRange = readNext(Pos); + break; + default: + llvm_unreachable("Illegal data size"); + } + + Optional AugmentationLength; + uint32_t LSDAPointerSize; + Optional 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); + switch (LSDAPointerSize) { + case 2: + LSDAPointer = readNext(Pos); + break; + case 4: + LSDAPointer = readNext(Pos); + break; + case 8: + LSDAPointer = readNext(Pos); + break; + default: + llvm_unreachable("Illegal data size"); + } + } + } + outs() << "FDE:\n"; outs() << " Length: " << Length << "\n"; - outs() << " "; + 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; - } } -- 2.34.1