From af39708c2d48beedc6721fe25676789cc6719f7b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Martin=20Storsj=C3=B6?= Date: Mon, 25 Nov 2019 15:26:13 +0200 Subject: [PATCH] [llvm-readobj] Fix/improve printing WinEH unwind info for linked PE images ARMWinEHPrinter was already designed to handle linked PE images (since d2941b43f40d), but resolving symbols didn't consistently take the image base into account (as linked images seldom have a symbol table, except for in MinGW setups). Win64EHDumper wasn't really designed to handle linked images (it would crash if executed on such a file), but a few concepts (getSymbol, taking a virtual address instead of a relocation, and getSectionContaining for finding the section containing a certain virtual address) can be borrowed from ARMWinEHPrinter. Adjust ARMWinEHPrinter to print the address of the exception handler routine as a VA instead of an RVA, consistently with other addresses in the same printout, and make Win64EHDumper print addresses similarly for image cases. Differential Revision: https://reviews.llvm.org/D71303 --- llvm/test/tools/llvm-readobj/COFF/lit.local.cfg | 1 + .../llvm-readobj/COFF/unwind-arm64-image.yaml | 180 +++++++++++++++++++++ .../llvm-readobj/COFF/unwind-x86_64-image.yaml | 168 +++++++++++++++++++ llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp | 8 +- llvm/tools/llvm-readobj/Win64EHDumper.cpp | 54 ++++++- 5 files changed, 405 insertions(+), 6 deletions(-) create mode 100644 llvm/test/tools/llvm-readobj/COFF/lit.local.cfg create mode 100644 llvm/test/tools/llvm-readobj/COFF/unwind-arm64-image.yaml create mode 100644 llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-image.yaml diff --git a/llvm/test/tools/llvm-readobj/COFF/lit.local.cfg b/llvm/test/tools/llvm-readobj/COFF/lit.local.cfg new file mode 100644 index 0000000..38f3353 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/COFF/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes.add('.yaml') diff --git a/llvm/test/tools/llvm-readobj/COFF/unwind-arm64-image.yaml b/llvm/test/tools/llvm-readobj/COFF/unwind-arm64-image.yaml new file mode 100644 index 0000000..67305ee --- /dev/null +++ b/llvm/test/tools/llvm-readobj/COFF/unwind-arm64-image.yaml @@ -0,0 +1,180 @@ +# RUN: yaml2obj %s > %t.exe +# RUN: llvm-readobj --unwind %t.exe | FileCheck %s + +# CHECK: RuntimeFunction { +# CHECK: Function: entry (0x140001014) +# CHECK-NEXT: ExceptionRecord: 0x140002018 +# CHECK-NEXT: ExceptionData { +# CHECK-NEXT: FunctionLength: 92 +# CHECK-NEXT: Version: 0 +# CHECK-NEXT: ExceptionData: Yes +# CHECK-NEXT: EpiloguePacked: No +# CHECK-NEXT: EpilogueScopes: 1 +# CHECK-NEXT: ByteCodeLength: 8 +# CHECK-NEXT: Prologue [ +# CHECK-NEXT: 0xd2c4 ; str x30, [sp, #32] +# CHECK-NEXT: 0x03 ; sub sp, #48 +# CHECK-NEXT: 0xe4 ; end +# CHECK-NEXT: ] +# CHECK-NEXT: EpilogueScopes [ +# CHECK-NEXT: EpilogueScope { +# CHECK-NEXT: StartOffset: 11 +# CHECK-NEXT: EpilogueStartIndex: 4 +# CHECK-NEXT: Opcodes [ +# CHECK-NEXT: 0xd2c4 ; ldr x30, [sp, #32] +# CHECK-NEXT: 0x03 ; add sp, #48 +# CHECK-NEXT: 0xe4 ; end +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: ExceptionHandler [ +# CHECK-NEXT: Routine: __gxx_personality_seh0 (0x140001074) +# CHECK-NEXT: Parameter: 0x801FFFF +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: } + +--- !COFF +OptionalHeader: + AddressOfEntryPoint: 4116 + ImageBase: 5368709120 + SectionAlignment: 4096 + FileAlignment: 512 + MajorOperatingSystemVersion: 6 + MinorOperatingSystemVersion: 0 + MajorImageVersion: 0 + MinorImageVersion: 0 + MajorSubsystemVersion: 6 + MinorSubsystemVersion: 0 + Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI + DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE ] + SizeOfStackReserve: 1048576 + SizeOfStackCommit: 4096 + SizeOfHeapReserve: 1048576 + SizeOfHeapCommit: 4096 + ExportTable: + RelativeVirtualAddress: 0 + Size: 0 + ImportTable: + RelativeVirtualAddress: 0 + Size: 0 + ResourceTable: + RelativeVirtualAddress: 0 + Size: 0 + ExceptionTable: + RelativeVirtualAddress: 12288 + Size: 40 + CertificateTable: + RelativeVirtualAddress: 0 + Size: 0 + BaseRelocationTable: + RelativeVirtualAddress: 0 + Size: 0 + Debug: + RelativeVirtualAddress: 0 + Size: 0 + Architecture: + RelativeVirtualAddress: 0 + Size: 0 + GlobalPtr: + RelativeVirtualAddress: 0 + Size: 0 + TlsTable: + RelativeVirtualAddress: 0 + Size: 0 + LoadConfigTable: + RelativeVirtualAddress: 0 + Size: 0 + BoundImport: + RelativeVirtualAddress: 0 + Size: 0 + IAT: + RelativeVirtualAddress: 0 + Size: 0 + DelayImportDescriptor: + RelativeVirtualAddress: 0 + Size: 0 + ClrRuntimeHeader: + RelativeVirtualAddress: 0 + Size: 0 +header: + Machine: IMAGE_FILE_MACHINE_ARM64 + Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + VirtualAddress: 4096 + VirtualSize: 120 + SectionData: C0035FD6FF4300D1E00700F9FF430091C0035FD6FFC300D1FE1300F90800009008C10191E80300F9F6FFFF9701000014E07F0091080000900811009100013FD6FE1340F9FFC30091C0035FD6E00B00F9E10F00B9E07F0091080000900811009100013FD6E00B40F9E80340F900013FD6C0035FD6C0035FD6 + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 8192 + VirtualSize: 80 + SectionData: 0100400800000000E4E3E3E3040040080200800001E401E4170050100B000001D2C403E4D2C403E474100000FFFF010810083800184400000100400800000000E4E3E3E30100400800000000E4E3E3E3 + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 12288 + VirtualSize: 40 + SectionData: 0010000000200000041000000C200000141000001820000070100000382000007410000044200000 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .xdata + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: other + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: _ZN4RAIID2Ev + Value: 4 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: entry + Value: 20 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: _Unwind_Resume + Value: 112 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: _ZN4RAIID1Ev + Value: 4 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __gxx_personality_seh0 + Value: 116 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: GCC_except_table2 + Value: 44 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC +... diff --git a/llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-image.yaml b/llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-image.yaml new file mode 100644 index 0000000..c62ef24 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-image.yaml @@ -0,0 +1,168 @@ +# RUN: yaml2obj %s > %t.exe +# RUN: llvm-readobj --unwind %t.exe | FileCheck %s + +# CHECK: RuntimeFunction { +# CHECK: StartAddress: entry (0x140001020) +# CHECK-NEXT: EndAddress: (0x14000105C) +# CHECK-NEXT: UnwindInfoAddress: (0x140002008) +# CHECK-NEXT: UnwindInfo { +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Flags [ (0x3) +# CHECK-NEXT: ExceptionHandler (0x1) +# CHECK-NEXT: TerminateHandler (0x2) +# CHECK-NEXT: ] +# CHECK-NEXT: PrologSize: 4 +# CHECK-NEXT: FrameRegister: - +# CHECK-NEXT: FrameOffset: - +# CHECK-NEXT: UnwindCodeCount: 1 +# CHECK-NEXT: UnwindCodes [ +# CHECK-NEXT: 0x04: ALLOC_SMALL size=56 +# CHECK-NEXT: ] +# CHECK-NEXT: Handler: __gxx_personality_seh0 (0x140001070) +# CHECK-NEXT: } +# CHECK-NEXT: } + +--- !COFF +OptionalHeader: + AddressOfEntryPoint: 4128 + ImageBase: 5368709120 + SectionAlignment: 4096 + FileAlignment: 512 + MajorOperatingSystemVersion: 6 + MinorOperatingSystemVersion: 0 + MajorImageVersion: 0 + MinorImageVersion: 0 + MajorSubsystemVersion: 6 + MinorSubsystemVersion: 0 + Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI + DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE ] + SizeOfStackReserve: 1048576 + SizeOfStackCommit: 4096 + SizeOfHeapReserve: 1048576 + SizeOfHeapCommit: 4096 + ExportTable: + RelativeVirtualAddress: 0 + Size: 0 + ImportTable: + RelativeVirtualAddress: 0 + Size: 0 + ResourceTable: + RelativeVirtualAddress: 0 + Size: 0 + ExceptionTable: + RelativeVirtualAddress: 12288 + Size: 24 + CertificateTable: + RelativeVirtualAddress: 0 + Size: 0 + BaseRelocationTable: + RelativeVirtualAddress: 0 + Size: 0 + Debug: + RelativeVirtualAddress: 0 + Size: 0 + Architecture: + RelativeVirtualAddress: 0 + Size: 0 + GlobalPtr: + RelativeVirtualAddress: 0 + Size: 0 + TlsTable: + RelativeVirtualAddress: 0 + Size: 0 + LoadConfigTable: + RelativeVirtualAddress: 0 + Size: 0 + BoundImport: + RelativeVirtualAddress: 0 + Size: 0 + IAT: + RelativeVirtualAddress: 0 + Size: 0 + DelayImportDescriptor: + RelativeVirtualAddress: 0 + Size: 0 + ClrRuntimeHeader: + RelativeVirtualAddress: 0 + Size: 0 +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + VirtualAddress: 4096 + VirtualSize: 113 + SectionData: C3662E0F1F8400000000000F1F4400005048890C2458C3660F1F8400000000004883EC38E8D7FFFFFFE900000000488D4C2430E8D8FFFFFF904883C438C3488944242889542424488D4C2430E8BFFFFFFF488B4C2428E805000000CC0F1F4000C3662E0F1F8400000000000F1F440000C3 + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 8192 + VirtualSize: 32 + SectionData: 0101010001020000190401000462000070100000FFFF010804051E0009330000 + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 12288 + VirtualSize: 24 + SectionData: 101000001710000000200000201000005C10000008200000 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .xdata + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: other + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: _ZN4RAIID2Ev + Value: 16 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: entry + Value: 32 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: _ZN4RAIID1Ev + Value: 16 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: _Unwind_Resume + Value: 96 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __gxx_personality_seh0 + Value: 112 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: GCC_except_table2 + Value: 20 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC +... diff --git a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp index 3e026f5..8f365c5 100644 --- a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -884,7 +884,7 @@ bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, } if (XData.X()) { - const uint32_t Address = XData.ExceptionHandlerRVA(); + const uint64_t Address = COFF.getImageBase() + XData.ExceptionHandlerRVA(); const uint32_t Parameter = XData.ExceptionHandlerParameter(); const size_t HandlerOffset = HeaderWords(XData) + (XData.E() ? 0 : XData.EpilogueCount()) @@ -896,7 +896,8 @@ bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, Symbol = getSymbol(COFF, Address, /*FunctionOnly=*/true); if (!Symbol) { ListScope EHS(SW, "ExceptionHandler"); - SW.printString("Routine", "(null)"); + SW.printHex("Routine", Address); + SW.printHex("Parameter", Parameter); return true; } @@ -925,7 +926,8 @@ bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF, ErrorOr Function = getRelocatedSymbol(COFF, Section, Offset); if (!Function) - Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true); + Function = getSymbol(COFF, COFF.getImageBase() + RF.BeginAddress, + /*FunctionOnly=*/true); ErrorOr XDataRecord = getRelocatedSymbol(COFF, Section, Offset + 4); if (!XDataRecord) diff --git a/llvm/tools/llvm-readobj/Win64EHDumper.cpp b/llvm/tools/llvm-readobj/Win64EHDumper.cpp index fa268ce..380baae 100644 --- a/llvm/tools/llvm-readobj/Win64EHDumper.cpp +++ b/llvm/tools/llvm-readobj/Win64EHDumper.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Win64EHDumper.h" +#include "Error.h" #include "llvm-readobj.h" #include "llvm/Object/COFF.h" #include "llvm/Support/ErrorHandling.h" @@ -111,6 +112,20 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { } } +static std::error_code getSymbol(const COFFObjectFile &COFF, uint64_t VA, + object::SymbolRef &Sym) { + for (const auto &Symbol : COFF.symbols()) { + Expected Address = Symbol.getAddress(); + if (!Address) + return errorToErrorCode(Address.takeError()); + if (*Address == VA) { + Sym = Symbol; + return readobj_error::success; + } + } + return readobj_error::unknown_symbol; +} + static std::string formatSymbol(const Dumper::Context &Ctx, const coff_section *Section, uint64_t Offset, uint32_t Displacement) { @@ -131,9 +146,22 @@ static std::string formatSymbol(const Dumper::Context &Ctx, // TODO: Actually report errors helpfully. consumeError(Name.takeError()); } + } else if (!getSymbol(Ctx.COFF, Ctx.COFF.getImageBase() + Displacement, + Symbol)) { + Expected Name = Symbol.getName(); + if (Name) { + OS << *Name; + OS << format(" (0x%" PRIX64 ")", Ctx.COFF.getImageBase() + Displacement); + return OS.str(); + } else { + consumeError(Name.takeError()); + } } - OS << format(" (0x%" PRIX64 ")", Offset); + if (Displacement > 0) + OS << format("(0x%" PRIX64 ")", Ctx.COFF.getImageBase() + Displacement); + else + OS << format("(0x%" PRIX64 ")", Offset); return OS.str(); } @@ -159,6 +187,18 @@ static std::error_code resolveRelocation(const Dumper::Context &Ctx, return std::error_code(); } +static const object::coff_section * +getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { + for (const auto &Section : COFF.sections()) { + uint64_t Address = Section.getAddress(); + uint64_t Size = Section.getSize(); + + if (VA >= Address && (VA - Address) <= Size) + return COFF.getCOFFSection(Section); + } + return nullptr; +} + namespace llvm { namespace Win64EH { void Dumper::printRuntimeFunctionEntry(const Context &Ctx, @@ -284,9 +324,18 @@ void Dumper::printRuntimeFunction(const Context &Ctx, DictScope RFS(SW, "RuntimeFunction"); printRuntimeFunctionEntry(Ctx, Section, SectionOffset, RF); - const coff_section *XData; + const coff_section *XData = nullptr; uint64_t Offset; resolveRelocation(Ctx, Section, SectionOffset + 8, XData, Offset); + Offset = Offset + RF.UnwindInfoOffset; + + if (!XData) { + uint64_t Address = Ctx.COFF.getImageBase() + RF.UnwindInfoOffset; + XData = getSectionContaining(Ctx.COFF, Address); + if (!XData) + return; + Offset = RF.UnwindInfoOffset - XData->VirtualAddress; + } ArrayRef Contents; if (Error E = Ctx.COFF.getSectionContents(XData, Contents)) @@ -295,7 +344,6 @@ void Dumper::printRuntimeFunction(const Context &Ctx, if (Contents.empty()) return; - Offset = Offset + RF.UnwindInfoOffset; if (Offset > Contents.size()) return; -- 2.7.4