diff --git a/llvm/test/tools/llvm-readobj/COFF/arm64-packed-symbol-name.yaml b/llvm/test/tools/llvm-readobj/COFF/arm64-packed-symbol-name.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/COFF/arm64-packed-symbol-name.yaml @@ -0,0 +1,59 @@ +# Check that we resolve the function name properly + +# RUN: yaml2obj %s -o %t.obj +# RUN: llvm-readobj --unwind %t.obj | FileCheck %s + +# CHECK: Function: entry (0x140001000) + +--- !COFF +OptionalHeader: + AddressOfEntryPoint: 4096 + 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 +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: 20 + SectionData: FD7BBFA9FD0300911F2003D5FD7BC1A8C0035FD6 + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 8192 + VirtualSize: 8 + SectionData: '001000001500E000' +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: entry + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/llvm/test/tools/llvm-readobj/COFF/arm64-unwind-reference.yaml b/llvm/test/tools/llvm-readobj/COFF/arm64-unwind-reference.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/COFF/arm64-unwind-reference.yaml @@ -0,0 +1,196 @@ +# Test reading an ExceptionRecord which is referenced in different ways: +# - Relocation against base of .xdata record, immediate offset in .pdata +# (what LLVM produces) +# - Relocation against symbol in .xdata, no immediate offset in .pdata +# (what MSVC produces) +# - Combination of the two above (unlikely to occur in the wild, but for +# testing the consistency of the code) + +# RUN: yaml2obj %s -o %t.obj +# RUN: llvm-readobj --unwind %t.obj | FileCheck %s + +# CHECK: UnwindInformation [ +# CHECK-NEXT: RuntimeFunction { +# CHECK-NEXT: Function: func (0x0) +# CHECK-NEXT: ExceptionRecord: .xdata (0x0) +# CHECK-NEXT: ExceptionData { +# CHECK-NEXT: FunctionLength: 4 +# CHECK-NEXT: Version: 0 +# CHECK-NEXT: ExceptionData: No +# CHECK-NEXT: EpiloguePacked: No +# CHECK-NEXT: EpilogueScopes: 0 +# CHECK-NEXT: ByteCodeLength: 4 +# CHECK-NEXT: Prologue [ +# CHECK-NEXT: 0xd400 ; str x19, [sp, #-8]! +# CHECK-NEXT: 0xe4 ; end +# CHECK-NEXT: ] +# CHECK-NEXT: EpilogueScopes [ +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: RuntimeFunction { +# CHECK-NEXT: Function: func2 (0x4) +# CHECK-NEXT: ExceptionRecord: .xdata +0x8 (0x8) +# CHECK-NEXT: ExceptionData { +# CHECK-NEXT: FunctionLength: 4 +# CHECK-NEXT: Version: 0 +# CHECK-NEXT: ExceptionData: No +# CHECK-NEXT: EpiloguePacked: No +# CHECK-NEXT: EpilogueScopes: 0 +# CHECK-NEXT: ByteCodeLength: 4 +# CHECK-NEXT: Prologue [ +# CHECK-NEXT: 0xdc01 ; str d8, [sp, #8] +# CHECK-NEXT: 0xe4 ; end +# CHECK-NEXT: ] +# CHECK-NEXT: EpilogueScopes [ +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: RuntimeFunction { +# CHECK-NEXT: Function: func3 (0x8) +# CHECK-NEXT: ExceptionRecord: func3_xdata (0x10) +# CHECK-NEXT: ExceptionData { +# CHECK-NEXT: FunctionLength: 4 +# CHECK-NEXT: Version: 0 +# CHECK-NEXT: ExceptionData: No +# CHECK-NEXT: EpiloguePacked: No +# CHECK-NEXT: EpilogueScopes: 0 +# CHECK-NEXT: ByteCodeLength: 4 +# CHECK-NEXT: Prologue [ +# CHECK-NEXT: 0xe1 ; mov fp, sp +# CHECK-NEXT: 0xe4 ; end +# CHECK-NEXT: ] +# CHECK-NEXT: EpilogueScopes [ +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: RuntimeFunction { +# CHECK-NEXT: Function: func4 (0xC) +# CHECK-NEXT: ExceptionRecord: func3_xdata +0x8 (0x18) +# CHECK-NEXT: ExceptionData { +# CHECK-NEXT: FunctionLength: 4 +# CHECK-NEXT: Version: 0 +# CHECK-NEXT: ExceptionData: No +# CHECK-NEXT: EpiloguePacked: No +# CHECK-NEXT: EpilogueScopes: 0 +# CHECK-NEXT: ByteCodeLength: 4 +# CHECK-NEXT: Prologue [ +# CHECK-NEXT: 0x81 ; stp x29, x30, [sp, #-16]! +# CHECK-NEXT: 0xe4 ; end +# CHECK-NEXT: ] +# CHECK-NEXT: EpilogueScopes [ +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: ] + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_ARM64 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: F38F1FF8E80700FDFD030091FD7BBFA9 + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 01000008D400E4E301000008DC01E4E301000008E1E4E3E30100000881E4E3E3 + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0000000000000000000000000800000000000000000000000000000008000000' + Relocations: + - VirtualAddress: 0 + SymbolName: func + Type: IMAGE_REL_ARM64_ADDR32NB + - VirtualAddress: 4 + SymbolName: .xdata + Type: IMAGE_REL_ARM64_ADDR32NB + - VirtualAddress: 8 + SymbolName: func2 + Type: IMAGE_REL_ARM64_ADDR32NB + - VirtualAddress: 12 + SymbolName: .xdata + Type: IMAGE_REL_ARM64_ADDR32NB + - VirtualAddress: 16 + SymbolName: func3 + Type: IMAGE_REL_ARM64_ADDR32NB + - VirtualAddress: 20 + SymbolName: func3_xdata + Type: IMAGE_REL_ARM64_ADDR32NB + - VirtualAddress: 24 + SymbolName: func4 + Type: IMAGE_REL_ARM64_ADDR32NB + - VirtualAddress: 28 + SymbolName: func3_xdata + Type: IMAGE_REL_ARM64_ADDR32NB +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 16 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 2581817939 + Number: 1 + - Name: .xdata + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 32 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3086971960 + Number: 2 + - Name: .pdata + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 32 + NumberOfRelocations: 8 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 3 + - Name: func + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: func2 + Value: 4 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: func3 + Value: 8 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: func4 + Value: 12 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: func3_xdata + Value: 16 + 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.h b/llvm/tools/llvm-readobj/ARMWinEHPrinter.h --- a/llvm/tools/llvm-readobj/ARMWinEHPrinter.h +++ b/llvm/tools/llvm-readobj/ARMWinEHPrinter.h @@ -146,6 +146,13 @@ getRelocatedSymbol(const object::COFFObjectFile &COFF, const object::SectionRef &Section, uint64_t Offset); + ErrorOr + getSymbolForLocation(const object::COFFObjectFile &COFF, + const object::SectionRef &Section, + uint64_t OffsetInSection, uint64_t ImmediateOffset, + uint64_t &SymbolAddress, uint64_t &SymbolOffset, + bool FunctionOnly = false); + bool dumpXDataRecord(const object::COFFObjectFile &COFF, const object::SectionRef &Section, uint64_t FunctionAddress, uint64_t VA); diff --git a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp --- a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -238,6 +238,41 @@ return inconvertibleErrorCode(); } +ErrorOr Decoder::getSymbolForLocation( + const COFFObjectFile &COFF, const SectionRef &Section, + uint64_t OffsetInSection, uint64_t ImmediateOffset, uint64_t &SymbolAddress, + uint64_t &SymbolOffset, bool FunctionOnly) { + // Try to locate a relocation that points at the offset in the section + ErrorOr SymOrErr = + getRelocatedSymbol(COFF, Section, OffsetInSection); + if (SymOrErr) { + // We found a relocation symbol; the immediate offset needs to be added + // to the symbol address. + SymbolOffset = ImmediateOffset; + + Expected AddressOrErr = SymOrErr->getAddress(); + if (!AddressOrErr) { + std::string Buf; + llvm::raw_string_ostream OS(Buf); + logAllUnhandledErrors(AddressOrErr.takeError(), OS); + OS.flush(); + report_fatal_error(Buf); + } + // We apply SymbolOffset here directly. We return it separately to allow + // the caller to print it as an offset on the symbol name. + SymbolAddress = *AddressOrErr + SymbolOffset; + } else { + // No matching relocation found; operating on a linked image. Try to + // find a descriptive symbol if possible. The immediate offset contains + // the image relative address, and we shouldn't add any offset to the + // symbol. + SymbolAddress = COFF.getImageBase() + ImmediateOffset; + SymbolOffset = 0; + SymOrErr = getSymbol(COFF, SymbolAddress, FunctionOnly); + } + return SymOrErr; +} + bool Decoder::opcode_0xxxxxxx(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { uint8_t Imm = OC[Offset] & 0x7f; @@ -919,16 +954,16 @@ } if (XData.X()) { - 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()) - + XData.CodeWords(); - - ErrorOr Symbol = getRelocatedSymbol( - COFF, Section, Offset + HandlerOffset * sizeof(uint32_t)); - if (!Symbol) - Symbol = getSymbol(COFF, Address, /*FunctionOnly=*/true); + const size_t HandlerOffset = HeaderWords(XData) + + (XData.E() ? 0 : XData.EpilogueCount()) + + XData.CodeWords(); + + uint64_t Address, SymbolOffset; + ErrorOr Symbol = getSymbolForLocation( + COFF, Section, Offset + HandlerOffset * sizeof(uint32_t), + XData.ExceptionHandlerRVA(), Address, SymbolOffset, + /*FunctionOnly=*/true); if (!Symbol) { ListScope EHS(SW, "ExceptionHandler"); SW.printHex("Routine", Address); @@ -946,7 +981,7 @@ } ListScope EHS(SW, "ExceptionHandler"); - SW.printString("Routine", formatSymbol(*Name, Address)); + SW.printString("Routine", formatSymbol(*Name, Address, SymbolOffset)); SW.printHex("Parameter", Parameter); } @@ -959,14 +994,15 @@ assert(RF.Flag() == RuntimeFunctionFlag::RFF_Unpacked && "packed entry cannot be treated as an unpacked entry"); - ErrorOr Function = getRelocatedSymbol(COFF, Section, Offset); - if (!Function) - Function = getSymbol(COFF, COFF.getImageBase() + RF.BeginAddress, - /*FunctionOnly=*/true); + uint64_t FunctionAddress, FunctionOffset; + ErrorOr Function = getSymbolForLocation( + COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset, + /*FunctionOnly=*/true); - ErrorOr XDataRecord = getRelocatedSymbol(COFF, Section, Offset + 4); - if (!XDataRecord) - XDataRecord = getSymbol(COFF, RF.ExceptionInformationRVA()); + uint64_t XDataAddress, XDataOffset; + ErrorOr XDataRecord = getSymbolForLocation( + COFF, Section, Offset + 4, RF.ExceptionInformationRVA(), XDataAddress, + XDataOffset); if (!RF.BeginAddress && !Function) return false; @@ -974,7 +1010,6 @@ return false; StringRef FunctionName; - uint64_t FunctionAddress; if (Function) { Expected FunctionNameOrErr = Function->getName(); if (!FunctionNameOrErr) { @@ -985,20 +1020,10 @@ report_fatal_error(Buf); } FunctionName = *FunctionNameOrErr; - Expected FunctionAddressOrErr = Function->getAddress(); - if (!FunctionAddressOrErr) { - std::string Buf; - llvm::raw_string_ostream OS(Buf); - logAllUnhandledErrors(FunctionAddressOrErr.takeError(), OS); - OS.flush(); - report_fatal_error(Buf); - } - FunctionAddress = *FunctionAddressOrErr; - } else { - FunctionAddress = COFF.getImageBase() + RF.BeginAddress; } - SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); + SW.printString("Function", + formatSymbol(FunctionName, FunctionAddress, FunctionOffset)); if (XDataRecord) { Expected Name = XDataRecord->getName(); @@ -1010,17 +1035,8 @@ report_fatal_error(Buf); } - Expected AddressOrErr = XDataRecord->getAddress(); - if (!AddressOrErr) { - std::string Buf; - llvm::raw_string_ostream OS(Buf); - logAllUnhandledErrors(AddressOrErr.takeError(), OS); - OS.flush(); - report_fatal_error(Buf); - } - uint64_t Address = *AddressOrErr; - - SW.printString("ExceptionRecord", formatSymbol(*Name, Address)); + SW.printString("ExceptionRecord", + formatSymbol(*Name, XDataAddress, XDataOffset)); Expected SIOrErr = XDataRecord->getSection(); if (!SIOrErr) { @@ -1030,18 +1046,15 @@ } section_iterator SI = *SIOrErr; - // FIXME: Do we need to add an offset from the relocation? - return dumpXDataRecord(COFF, *SI, FunctionAddress, - RF.ExceptionInformationRVA()); + return dumpXDataRecord(COFF, *SI, FunctionAddress, XDataAddress); } else { - uint64_t Address = COFF.getImageBase() + RF.ExceptionInformationRVA(); - SW.printString("ExceptionRecord", formatSymbol("", Address)); + SW.printString("ExceptionRecord", formatSymbol("", XDataAddress)); - ErrorOr Section = getSectionContaining(COFF, Address); + ErrorOr Section = getSectionContaining(COFF, XDataAddress); if (!Section) return false; - return dumpXDataRecord(COFF, *Section, FunctionAddress, Address); + return dumpXDataRecord(COFF, *Section, FunctionAddress, XDataAddress); } } @@ -1052,12 +1065,12 @@ RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) && "unpacked entry cannot be treated as a packed entry"); - ErrorOr Function = getRelocatedSymbol(COFF, Section, Offset); - if (!Function) - Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true); + uint64_t FunctionAddress, FunctionOffset; + ErrorOr Function = getSymbolForLocation( + COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset, + /*FunctionOnly=*/true); StringRef FunctionName; - uint64_t FunctionAddress; if (Function) { Expected FunctionNameOrErr = Function->getName(); if (!FunctionNameOrErr) { @@ -1068,20 +1081,10 @@ report_fatal_error(Buf); } FunctionName = *FunctionNameOrErr; - Expected FunctionAddressOrErr = Function->getAddress(); - if (!FunctionAddressOrErr) { - std::string Buf; - llvm::raw_string_ostream OS(Buf); - logAllUnhandledErrors(FunctionAddressOrErr.takeError(), OS); - OS.flush(); - report_fatal_error(Buf); - } - FunctionAddress = *FunctionAddressOrErr; - } else { - FunctionAddress = COFF.getPE32Header()->ImageBase + RF.BeginAddress; } - SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); + SW.printString("Function", + formatSymbol(FunctionName, FunctionAddress, FunctionOffset)); if (!isAArch64) SW.printBoolean("Fragment", RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment); @@ -1104,12 +1107,12 @@ RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) && "unpacked entry cannot be treated as a packed entry"); - ErrorOr Function = getRelocatedSymbol(COFF, Section, Offset); - if (!Function) - Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true); + uint64_t FunctionAddress, FunctionOffset; + ErrorOr Function = getSymbolForLocation( + COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset, + /*FunctionOnly=*/true); StringRef FunctionName; - uint64_t FunctionAddress; if (Function) { Expected FunctionNameOrErr = Function->getName(); if (!FunctionNameOrErr) { @@ -1120,20 +1123,10 @@ report_fatal_error(Buf); } FunctionName = *FunctionNameOrErr; - Expected FunctionAddressOrErr = Function->getAddress(); - if (!FunctionAddressOrErr) { - std::string Buf; - llvm::raw_string_ostream OS(Buf); - logAllUnhandledErrors(FunctionAddressOrErr.takeError(), OS); - OS.flush(); - report_fatal_error(Buf); - } - FunctionAddress = *FunctionAddressOrErr; - } else { - FunctionAddress = COFF.getPE32PlusHeader()->ImageBase + RF.BeginAddress; } - SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); + SW.printString("Function", + formatSymbol(FunctionName, FunctionAddress, FunctionOffset)); SW.printBoolean("Fragment", RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment); SW.printNumber("FunctionLength", RF.FunctionLength());