Skip to content

[llvm] Win x64 Unwind V2 2/n: Support dumping UOP_Epilog #110338

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions llvm/include/llvm/Support/Win64EH.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint32_t>(u.CodeOffset);
}
};

enum {
Expand Down
175 changes: 175 additions & 0 deletions llvm/test/tools/llvm-objdump/COFF/win64-unwindv2.yaml
Original file line number Diff line number Diff line change
@@ -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
...
71 changes: 46 additions & 25 deletions llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-image.yaml
Original file line number Diff line number Diff line change
@@ -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:
Expand Down Expand Up @@ -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
Expand Down
24 changes: 21 additions & 3 deletions llvm/tools/llvm-objdump/COFFDump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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<UnwindCode> UCs) {
static void printUnwindCode(ArrayRef<UnwindCode> UCs, bool &SeenFirstEpilog) {
assert(UCs.size() >= getNumUsedSlots(UCs[0]));
outs() << format(" 0x%02x: ", unsigned(UCs[0].u.CodeOffset))
<< getUnwindCodeTypeName(UCs[0].getUnwindOp());
Expand Down Expand Up @@ -301,11 +301,29 @@ static void printUnwindCode(ArrayRef<UnwindCode> 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<UnwindCode> UCs) {
bool SeenFirstEpilog = false;
for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) {
unsigned UsedSlots = getNumUsedSlots(*I);
if (UsedSlots > UCs.size()) {
Expand All @@ -316,7 +334,7 @@ static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
<< " remaining in buffer";
return ;
}
printUnwindCode(ArrayRef(I, E));
printUnwindCode(ArrayRef(I, E), SeenFirstEpilog);
I += UsedSlots;
}
}
Expand Down
Loading
Loading