diff --git a/llvm/include/llvm/Support/Win64EH.h b/llvm/include/llvm/Support/Win64EH.h index cf54f49286830..8a9be15373917 100644 --- a/llvm/include/llvm/Support/Win64EH.h +++ b/llvm/include/llvm/Support/Win64EH.h @@ -124,6 +124,11 @@ union UnwindCode { uint8_t getOpInfo() const { return (u.UnwindOpAndOpInfo >> 4) & 0x0F; } + /// Gets the offset for an UOP_Epilog unwind code. + uint32_t getEpilogOffset() const { + assert(getUnwindOp() == UOP_Epilog); + return (getOpInfo() << 8) | static_cast(u.CodeOffset); + } }; enum { diff --git a/llvm/test/tools/llvm-objdump/COFF/win64-unwindv2.yaml b/llvm/test/tools/llvm-objdump/COFF/win64-unwindv2.yaml new file mode 100644 index 0000000000000..20abcb959120d --- /dev/null +++ b/llvm/test/tools/llvm-objdump/COFF/win64-unwindv2.yaml @@ -0,0 +1,175 @@ +# RUN: yaml2obj %s -o %t.exe +# RUN: llvm-objdump --unwind-info %t.exe | FileCheck %s + +# CHECK-LABEL: Unwind info: +# CHECK-EMPTY: +# CHECK-NEXT: Function Table: +# CHECK-NEXT: Start Address: 0x1010 +# CHECK-NEXT: End Address: 0x1017 +# CHECK-NEXT: Unwind Info Address: 0x2000 +# CHECK-NEXT: Version: 2 +# CHECK-NEXT: Flags: 0 +# CHECK-NEXT: Size of prolog: 4 +# CHECK-NEXT: Number of Codes: 3 +# CHECK-NEXT: No frame pointer used +# CHECK-NEXT: Unwind Codes: +# CHECK-NEXT: 0x01: UOP_Epilog atend=yes, length=0x1 +# CHECK-NEXT: 0x0b: UOP_Epilog offset=0xB +# CHECK-NEXT: 0x04: UOP_AllocSmall 72 +# CHECK-EMPTY: +# CHECK-NEXT: Function Table: +# CHECK-NEXT: Start Address: 0x1020 +# CHECK-NEXT: End Address: 0x105c +# CHECK-NEXT: Unwind Info Address: 0x200c +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Flags: 3 UNW_ExceptionHandler UNW_TerminateHandler +# CHECK-NEXT: Size of prolog: 4 +# CHECK-NEXT: Number of Codes: 1 +# CHECK-NEXT: No frame pointer used +# CHECK-NEXT: Unwind Codes: +# CHECK-NEXT: 0x04: UOP_AllocSmall 56 + +--- !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: 8 + SectionData: 00000000 + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 8192 + VirtualSize: 40 + SectionData: 0204030001160B0604820000190401000462000070100000FFFF010804051E0009330000 + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 12288 + VirtualSize: 24 + SectionData: 101000001710000000200000201000005C1000000C200000 +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/test/tools/llvm-readobj/COFF/unwind-x86_64-image.yaml b/llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-image.yaml index 5780cf7a0467b..b9d6822a77f4a 100644 --- a/llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-image.yaml +++ b/llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-image.yaml @@ -1,26 +1,47 @@ # RUN: yaml2obj %s -o %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-LABEL: UnwindInformation [ +# CHECK-NEXT: RuntimeFunction { +# CHECK-NEXT: StartAddress: _ZN4RAIID2Ev (0x140001010) +# CHECK-NEXT: EndAddress: (0x140001017) +# CHECK-NEXT: UnwindInfoAddress: .xdata (0x140002000) +# CHECK-NEXT: UnwindInfo { +# CHECK-NEXT: Version: 2 +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: PrologSize: 4 +# CHECK-NEXT: FrameRegister: - +# CHECK-NEXT: FrameOffset: - +# CHECK-NEXT: UnwindCodeCount: 3 +# CHECK-NEXT: UnwindCodes [ +# CHECK-NEXT: 0x01: EPILOG atend=yes, length=0x1 +# CHECK-NEXT: 0x0B: EPILOG offset=0xB +# CHECK-NEXT: 0x04: ALLOC_SMALL size=72 +# CHECK-NEXT: ] +# CHECK-NEXT: } # CHECK-NEXT: } -# CHECK-NEXT: } +# CHECK-NEXT: RuntimeFunction { +# CHECK-NEXT: StartAddress: entry (0x140001020) +# CHECK-NEXT: EndAddress: (0x14000105C) +# CHECK-NEXT: UnwindInfoAddress: (0x14000200C) +# 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: } +# CHECK-NEXT: ] --- !COFF OptionalHeader: @@ -92,18 +113,18 @@ sections: - Name: .text Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] VirtualAddress: 4096 - VirtualSize: 113 - SectionData: C3662E0F1F8400000000000F1F4400005048890C2458C3660F1F8400000000004883EC38E8D7FFFFFFE900000000488D4C2430E8D8FFFFFF904883C438C3488944242889542424488D4C2430E8BFFFFFFF488B4C2428E805000000CC0F1F4000C3662E0F1F8400000000000F1F440000C3 - - Name: .rdata + VirtualSize: 8 + SectionData: 00000000 + - Name: .xdata Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] VirtualAddress: 8192 - VirtualSize: 32 - SectionData: 0101010001020000190401000462000070100000FFFF010804051E0009330000 + VirtualSize: 40 + SectionData: 0204030001160B0604820000190401000462000070100000FFFF010804051E0009330000 - Name: .pdata Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] VirtualAddress: 12288 VirtualSize: 24 - SectionData: 101000001710000000200000201000005C10000008200000 + SectionData: 101000001710000000200000201000005C1000000C200000 symbols: - Name: .text Value: 0 diff --git a/llvm/tools/llvm-objdump/COFFDump.cpp b/llvm/tools/llvm-objdump/COFFDump.cpp index 71697fa01e627..b22c9a4127fc3 100644 --- a/llvm/tools/llvm-objdump/COFFDump.cpp +++ b/llvm/tools/llvm-objdump/COFFDump.cpp @@ -240,10 +240,10 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { case UOP_AllocSmall: case UOP_SetFPReg: case UOP_PushMachFrame: + case UOP_Epilog: return 1; case UOP_SaveNonVol: case UOP_SaveXMM128: - case UOP_Epilog: return 2; case UOP_SaveNonVolBig: case UOP_SaveXMM128Big: @@ -257,7 +257,7 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { // Prints one unwind code. Because an unwind code can occupy up to 3 slots in // the unwind codes array, this function requires that the correct number of // slots is provided. -static void printUnwindCode(ArrayRef UCs) { +static void printUnwindCode(ArrayRef UCs, bool &SeenFirstEpilog) { assert(UCs.size() >= getNumUsedSlots(UCs[0])); outs() << format(" 0x%02x: ", unsigned(UCs[0].u.CodeOffset)) << getUnwindCodeTypeName(UCs[0].getUnwindOp()); @@ -301,11 +301,29 @@ static void printUnwindCode(ArrayRef UCs) { outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w") << " error code"; break; + + case UOP_Epilog: + if (SeenFirstEpilog) { + uint32_t Offset = UCs[0].getEpilogOffset(); + if (Offset == 0) { + outs() << " padding"; + } else { + outs() << " offset=" << format("0x%X", Offset); + } + } else { + SeenFirstEpilog = true; + bool AtEnd = (UCs[0].getOpInfo() & 0x1) != 0; + uint32_t Length = UCs[0].u.CodeOffset; + outs() << " atend=" << (AtEnd ? "yes" : "no") + << ", length=" << format("0x%X", Length); + } + break; } outs() << "\n"; } static void printAllUnwindCodes(ArrayRef UCs) { + bool SeenFirstEpilog = false; for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) { unsigned UsedSlots = getNumUsedSlots(*I); if (UsedSlots > UCs.size()) { @@ -316,7 +334,7 @@ static void printAllUnwindCodes(ArrayRef UCs) { << " remaining in buffer"; return ; } - printUnwindCode(ArrayRef(I, E)); + printUnwindCode(ArrayRef(I, E), SeenFirstEpilog); I += UsedSlots; } } diff --git a/llvm/tools/llvm-readobj/Win64EHDumper.cpp b/llvm/tools/llvm-readobj/Win64EHDumper.cpp index e4bd772191514..e17a035f1d371 100644 --- a/llvm/tools/llvm-readobj/Win64EHDumper.cpp +++ b/llvm/tools/llvm-readobj/Win64EHDumper.cpp @@ -65,6 +65,8 @@ static StringRef getUnwindCodeTypeName(uint8_t Code) { case UOP_SaveXMM128: return "SAVE_XMM128"; case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR"; case UOP_PushMachFrame: return "PUSH_MACHFRAME"; + case UOP_Epilog: + return "EPILOG"; } } @@ -99,6 +101,7 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { case UOP_AllocSmall: case UOP_SetFPReg: case UOP_PushMachFrame: + case UOP_Epilog: return 1; case UOP_SaveNonVol: case UOP_SaveXMM128: @@ -254,7 +257,8 @@ void Dumper::printRuntimeFunctionEntry(const Context &Ctx, // Prints one unwind code. Because an unwind code can occupy up to 3 slots in // the unwind codes array, this function requires that the correct number of // slots is provided. -void Dumper::printUnwindCode(const UnwindInfo& UI, ArrayRef UC) { +void Dumper::printUnwindCode(const UnwindInfo &UI, ArrayRef UC, + bool &SeenFirstEpilog) { assert(UC.size() >= getNumUsedSlots(UC[0])); SW.startLine() << format("0x%02X: ", unsigned(UC[0].u.CodeOffset)) @@ -306,6 +310,23 @@ void Dumper::printUnwindCode(const UnwindInfo& UI, ArrayRef UC) { case UOP_PushMachFrame: OS << " errcode=" << (UC[0].getOpInfo() == 0 ? "no" : "yes"); break; + + case UOP_Epilog: + if (SeenFirstEpilog) { + uint32_t Offset = UC[0].getEpilogOffset(); + if (Offset == 0) { + OS << " padding"; + } else { + OS << " offset=" << format("0x%X", Offset); + } + } else { + SeenFirstEpilog = true; + bool AtEnd = (UC[0].getOpInfo() & 0x1) != 0; + uint32_t Length = UC[0].u.CodeOffset; + OS << " atend=" << (AtEnd ? "yes" : "no") + << ", length=" << format("0x%X", Length); + } + break; } OS << "\n"; @@ -330,6 +351,7 @@ void Dumper::printUnwindInfo(const Context &Ctx, const coff_section *Section, { ListScope UCS(SW, "UnwindCodes"); ArrayRef UC(&UI.UnwindCodes[0], UI.NumCodes); + bool SeenFirstEpilog = false; for (const UnwindCode *UCI = UC.begin(), *UCE = UC.end(); UCI < UCE; ++UCI) { unsigned UsedSlots = getNumUsedSlots(*UCI); if (UsedSlots > UC.size()) { @@ -337,7 +359,7 @@ void Dumper::printUnwindInfo(const Context &Ctx, const coff_section *Section, return; } - printUnwindCode(UI, ArrayRef(UCI, UCE)); + printUnwindCode(UI, ArrayRef(UCI, UCE), SeenFirstEpilog); UCI = UCI + UsedSlots - 1; } } diff --git a/llvm/tools/llvm-readobj/Win64EHDumper.h b/llvm/tools/llvm-readobj/Win64EHDumper.h index 97458c916bec6..a23d30be7a113 100644 --- a/llvm/tools/llvm-readobj/Win64EHDumper.h +++ b/llvm/tools/llvm-readobj/Win64EHDumper.h @@ -44,7 +44,8 @@ class Dumper { const object::coff_section *Section, uint64_t SectionOffset, const RuntimeFunction &RF); - void printUnwindCode(const UnwindInfo& UI, ArrayRef UC); + void printUnwindCode(const UnwindInfo &UI, ArrayRef UC, + bool &SeenFirstEpilog); void printUnwindInfo(const Context &Ctx, const object::coff_section *Section, off_t Offset, const UnwindInfo &UI); void printRuntimeFunction(const Context &Ctx,