Skip to content

Commit 2201164

Browse files
authored
[llvm] Win x64 Unwind V2 2/n: Support dumping UOP_Epilog (#110338)
Adds support to objdump and readobj for reading the `UOP_Epilog` entries of Windows x64 unwind v2. `UOP_Epilog` has a weird format: The first `UOP_Epilog` in the unwind data is the "header": * The least-significant bit of `OpInfo` is the "At End" flag, which signifies that there is an epilog at the very end of the associated function. * `CodeOffset` is the length each epilog described by the current unwind information (all epilogs have the same length). Any subsequent `UOP_Epilog` represents another epilog for the current function, where `OpInfo` and `CodeOffset` are combined to a 12-bit value which is the offset of the beginning of the epilog from the end of the current function. If the offset is 0, then this entry is actually padding and can be ignored.
1 parent 1515caf commit 2201164

File tree

6 files changed

+273
-31
lines changed

6 files changed

+273
-31
lines changed

llvm/include/llvm/Support/Win64EH.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ union UnwindCode {
124124
uint8_t getOpInfo() const {
125125
return (u.UnwindOpAndOpInfo >> 4) & 0x0F;
126126
}
127+
/// Gets the offset for an UOP_Epilog unwind code.
128+
uint32_t getEpilogOffset() const {
129+
assert(getUnwindOp() == UOP_Epilog);
130+
return (getOpInfo() << 8) | static_cast<uint32_t>(u.CodeOffset);
131+
}
127132
};
128133

129134
enum {
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# RUN: yaml2obj %s -o %t.exe
2+
# RUN: llvm-objdump --unwind-info %t.exe | FileCheck %s
3+
4+
# CHECK-LABEL: Unwind info:
5+
# CHECK-EMPTY:
6+
# CHECK-NEXT: Function Table:
7+
# CHECK-NEXT: Start Address: 0x1010
8+
# CHECK-NEXT: End Address: 0x1017
9+
# CHECK-NEXT: Unwind Info Address: 0x2000
10+
# CHECK-NEXT: Version: 2
11+
# CHECK-NEXT: Flags: 0
12+
# CHECK-NEXT: Size of prolog: 4
13+
# CHECK-NEXT: Number of Codes: 3
14+
# CHECK-NEXT: No frame pointer used
15+
# CHECK-NEXT: Unwind Codes:
16+
# CHECK-NEXT: 0x01: UOP_Epilog atend=yes, length=0x1
17+
# CHECK-NEXT: 0x0b: UOP_Epilog offset=0xB
18+
# CHECK-NEXT: 0x04: UOP_AllocSmall 72
19+
# CHECK-EMPTY:
20+
# CHECK-NEXT: Function Table:
21+
# CHECK-NEXT: Start Address: 0x1020
22+
# CHECK-NEXT: End Address: 0x105c
23+
# CHECK-NEXT: Unwind Info Address: 0x200c
24+
# CHECK-NEXT: Version: 1
25+
# CHECK-NEXT: Flags: 3 UNW_ExceptionHandler UNW_TerminateHandler
26+
# CHECK-NEXT: Size of prolog: 4
27+
# CHECK-NEXT: Number of Codes: 1
28+
# CHECK-NEXT: No frame pointer used
29+
# CHECK-NEXT: Unwind Codes:
30+
# CHECK-NEXT: 0x04: UOP_AllocSmall 56
31+
32+
--- !COFF
33+
OptionalHeader:
34+
AddressOfEntryPoint: 4128
35+
ImageBase: 5368709120
36+
SectionAlignment: 4096
37+
FileAlignment: 512
38+
MajorOperatingSystemVersion: 6
39+
MinorOperatingSystemVersion: 0
40+
MajorImageVersion: 0
41+
MinorImageVersion: 0
42+
MajorSubsystemVersion: 6
43+
MinorSubsystemVersion: 0
44+
Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
45+
DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE ]
46+
SizeOfStackReserve: 1048576
47+
SizeOfStackCommit: 4096
48+
SizeOfHeapReserve: 1048576
49+
SizeOfHeapCommit: 4096
50+
ExportTable:
51+
RelativeVirtualAddress: 0
52+
Size: 0
53+
ImportTable:
54+
RelativeVirtualAddress: 0
55+
Size: 0
56+
ResourceTable:
57+
RelativeVirtualAddress: 0
58+
Size: 0
59+
ExceptionTable:
60+
RelativeVirtualAddress: 12288
61+
Size: 24
62+
CertificateTable:
63+
RelativeVirtualAddress: 0
64+
Size: 0
65+
BaseRelocationTable:
66+
RelativeVirtualAddress: 0
67+
Size: 0
68+
Debug:
69+
RelativeVirtualAddress: 0
70+
Size: 0
71+
Architecture:
72+
RelativeVirtualAddress: 0
73+
Size: 0
74+
GlobalPtr:
75+
RelativeVirtualAddress: 0
76+
Size: 0
77+
TlsTable:
78+
RelativeVirtualAddress: 0
79+
Size: 0
80+
LoadConfigTable:
81+
RelativeVirtualAddress: 0
82+
Size: 0
83+
BoundImport:
84+
RelativeVirtualAddress: 0
85+
Size: 0
86+
IAT:
87+
RelativeVirtualAddress: 0
88+
Size: 0
89+
DelayImportDescriptor:
90+
RelativeVirtualAddress: 0
91+
Size: 0
92+
ClrRuntimeHeader:
93+
RelativeVirtualAddress: 0
94+
Size: 0
95+
header:
96+
Machine: IMAGE_FILE_MACHINE_AMD64
97+
Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ]
98+
sections:
99+
- Name: .text
100+
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
101+
VirtualAddress: 4096
102+
VirtualSize: 8
103+
SectionData: 00000000
104+
- Name: .xdata
105+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
106+
VirtualAddress: 8192
107+
VirtualSize: 40
108+
SectionData: 0204030001160B0604820000190401000462000070100000FFFF010804051E0009330000
109+
- Name: .pdata
110+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
111+
VirtualAddress: 12288
112+
VirtualSize: 24
113+
SectionData: 101000001710000000200000201000005C1000000C200000
114+
symbols:
115+
- Name: .text
116+
Value: 0
117+
SectionNumber: 1
118+
SimpleType: IMAGE_SYM_TYPE_NULL
119+
ComplexType: IMAGE_SYM_DTYPE_NULL
120+
StorageClass: IMAGE_SYM_CLASS_STATIC
121+
- Name: .xdata
122+
Value: 0
123+
SectionNumber: 2
124+
SimpleType: IMAGE_SYM_TYPE_NULL
125+
ComplexType: IMAGE_SYM_DTYPE_NULL
126+
StorageClass: IMAGE_SYM_CLASS_STATIC
127+
- Name: .pdata
128+
Value: 0
129+
SectionNumber: 3
130+
SimpleType: IMAGE_SYM_TYPE_NULL
131+
ComplexType: IMAGE_SYM_DTYPE_NULL
132+
StorageClass: IMAGE_SYM_CLASS_STATIC
133+
- Name: other
134+
Value: 0
135+
SectionNumber: 1
136+
SimpleType: IMAGE_SYM_TYPE_NULL
137+
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
138+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
139+
- Name: _ZN4RAIID2Ev
140+
Value: 16
141+
SectionNumber: 1
142+
SimpleType: IMAGE_SYM_TYPE_NULL
143+
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
144+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
145+
- Name: entry
146+
Value: 32
147+
SectionNumber: 1
148+
SimpleType: IMAGE_SYM_TYPE_NULL
149+
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
150+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
151+
- Name: _ZN4RAIID1Ev
152+
Value: 16
153+
SectionNumber: 1
154+
SimpleType: IMAGE_SYM_TYPE_NULL
155+
ComplexType: IMAGE_SYM_DTYPE_NULL
156+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
157+
- Name: _Unwind_Resume
158+
Value: 96
159+
SectionNumber: 1
160+
SimpleType: IMAGE_SYM_TYPE_NULL
161+
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
162+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
163+
- Name: __gxx_personality_seh0
164+
Value: 112
165+
SectionNumber: 1
166+
SimpleType: IMAGE_SYM_TYPE_NULL
167+
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
168+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
169+
- Name: GCC_except_table2
170+
Value: 20
171+
SectionNumber: 2
172+
SimpleType: IMAGE_SYM_TYPE_NULL
173+
ComplexType: IMAGE_SYM_DTYPE_NULL
174+
StorageClass: IMAGE_SYM_CLASS_STATIC
175+
...

llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-image.yaml

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,47 @@
11
# RUN: yaml2obj %s -o %t.exe
22
# RUN: llvm-readobj --unwind %t.exe | FileCheck %s
33

4-
# CHECK: RuntimeFunction {
5-
# CHECK: StartAddress: entry (0x140001020)
6-
# CHECK-NEXT: EndAddress: (0x14000105C)
7-
# CHECK-NEXT: UnwindInfoAddress: (0x140002008)
8-
# CHECK-NEXT: UnwindInfo {
9-
# CHECK-NEXT: Version: 1
10-
# CHECK-NEXT: Flags [ (0x3)
11-
# CHECK-NEXT: ExceptionHandler (0x1)
12-
# CHECK-NEXT: TerminateHandler (0x2)
13-
# CHECK-NEXT: ]
14-
# CHECK-NEXT: PrologSize: 4
15-
# CHECK-NEXT: FrameRegister: -
16-
# CHECK-NEXT: FrameOffset: -
17-
# CHECK-NEXT: UnwindCodeCount: 1
18-
# CHECK-NEXT: UnwindCodes [
19-
# CHECK-NEXT: 0x04: ALLOC_SMALL size=56
20-
# CHECK-NEXT: ]
21-
# CHECK-NEXT: Handler: __gxx_personality_seh0 (0x140001070)
4+
# CHECK-LABEL: UnwindInformation [
5+
# CHECK-NEXT: RuntimeFunction {
6+
# CHECK-NEXT: StartAddress: _ZN4RAIID2Ev (0x140001010)
7+
# CHECK-NEXT: EndAddress: (0x140001017)
8+
# CHECK-NEXT: UnwindInfoAddress: .xdata (0x140002000)
9+
# CHECK-NEXT: UnwindInfo {
10+
# CHECK-NEXT: Version: 2
11+
# CHECK-NEXT: Flags [ (0x0)
12+
# CHECK-NEXT: ]
13+
# CHECK-NEXT: PrologSize: 4
14+
# CHECK-NEXT: FrameRegister: -
15+
# CHECK-NEXT: FrameOffset: -
16+
# CHECK-NEXT: UnwindCodeCount: 3
17+
# CHECK-NEXT: UnwindCodes [
18+
# CHECK-NEXT: 0x01: EPILOG atend=yes, length=0x1
19+
# CHECK-NEXT: 0x0B: EPILOG offset=0xB
20+
# CHECK-NEXT: 0x04: ALLOC_SMALL size=72
21+
# CHECK-NEXT: ]
22+
# CHECK-NEXT: }
2223
# CHECK-NEXT: }
23-
# CHECK-NEXT: }
24+
# CHECK-NEXT: RuntimeFunction {
25+
# CHECK-NEXT: StartAddress: entry (0x140001020)
26+
# CHECK-NEXT: EndAddress: (0x14000105C)
27+
# CHECK-NEXT: UnwindInfoAddress: (0x14000200C)
28+
# CHECK-NEXT: UnwindInfo {
29+
# CHECK-NEXT: Version: 1
30+
# CHECK-NEXT: Flags [ (0x3)
31+
# CHECK-NEXT: ExceptionHandler (0x1)
32+
# CHECK-NEXT: TerminateHandler (0x2)
33+
# CHECK-NEXT: ]
34+
# CHECK-NEXT: PrologSize: 4
35+
# CHECK-NEXT: FrameRegister: -
36+
# CHECK-NEXT: FrameOffset: -
37+
# CHECK-NEXT: UnwindCodeCount: 1
38+
# CHECK-NEXT: UnwindCodes [
39+
# CHECK-NEXT: 0x04: ALLOC_SMALL size=56
40+
# CHECK-NEXT: ]
41+
# CHECK-NEXT: Handler: __gxx_personality_seh0 (0x140001070)
42+
# CHECK-NEXT: }
43+
# CHECK-NEXT: }
44+
# CHECK-NEXT: ]
2445

2546
--- !COFF
2647
OptionalHeader:
@@ -92,18 +113,18 @@ sections:
92113
- Name: .text
93114
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
94115
VirtualAddress: 4096
95-
VirtualSize: 113
96-
SectionData: C3662E0F1F8400000000000F1F4400005048890C2458C3660F1F8400000000004883EC38E8D7FFFFFFE900000000488D4C2430E8D8FFFFFF904883C438C3488944242889542424488D4C2430E8BFFFFFFF488B4C2428E805000000CC0F1F4000C3662E0F1F8400000000000F1F440000C3
97-
- Name: .rdata
116+
VirtualSize: 8
117+
SectionData: 00000000
118+
- Name: .xdata
98119
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
99120
VirtualAddress: 8192
100-
VirtualSize: 32
101-
SectionData: 0101010001020000190401000462000070100000FFFF010804051E0009330000
121+
VirtualSize: 40
122+
SectionData: 0204030001160B0604820000190401000462000070100000FFFF010804051E0009330000
102123
- Name: .pdata
103124
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
104125
VirtualAddress: 12288
105126
VirtualSize: 24
106-
SectionData: 101000001710000000200000201000005C10000008200000
127+
SectionData: 101000001710000000200000201000005C1000000C200000
107128
symbols:
108129
- Name: .text
109130
Value: 0

llvm/tools/llvm-objdump/COFFDump.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,10 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
240240
case UOP_AllocSmall:
241241
case UOP_SetFPReg:
242242
case UOP_PushMachFrame:
243+
case UOP_Epilog:
243244
return 1;
244245
case UOP_SaveNonVol:
245246
case UOP_SaveXMM128:
246-
case UOP_Epilog:
247247
return 2;
248248
case UOP_SaveNonVolBig:
249249
case UOP_SaveXMM128Big:
@@ -257,7 +257,7 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
257257
// Prints one unwind code. Because an unwind code can occupy up to 3 slots in
258258
// the unwind codes array, this function requires that the correct number of
259259
// slots is provided.
260-
static void printUnwindCode(ArrayRef<UnwindCode> UCs) {
260+
static void printUnwindCode(ArrayRef<UnwindCode> UCs, bool &SeenFirstEpilog) {
261261
assert(UCs.size() >= getNumUsedSlots(UCs[0]));
262262
outs() << format(" 0x%02x: ", unsigned(UCs[0].u.CodeOffset))
263263
<< getUnwindCodeTypeName(UCs[0].getUnwindOp());
@@ -301,11 +301,29 @@ static void printUnwindCode(ArrayRef<UnwindCode> UCs) {
301301
outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w")
302302
<< " error code";
303303
break;
304+
305+
case UOP_Epilog:
306+
if (SeenFirstEpilog) {
307+
uint32_t Offset = UCs[0].getEpilogOffset();
308+
if (Offset == 0) {
309+
outs() << " padding";
310+
} else {
311+
outs() << " offset=" << format("0x%X", Offset);
312+
}
313+
} else {
314+
SeenFirstEpilog = true;
315+
bool AtEnd = (UCs[0].getOpInfo() & 0x1) != 0;
316+
uint32_t Length = UCs[0].u.CodeOffset;
317+
outs() << " atend=" << (AtEnd ? "yes" : "no")
318+
<< ", length=" << format("0x%X", Length);
319+
}
320+
break;
304321
}
305322
outs() << "\n";
306323
}
307324

308325
static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
326+
bool SeenFirstEpilog = false;
309327
for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) {
310328
unsigned UsedSlots = getNumUsedSlots(*I);
311329
if (UsedSlots > UCs.size()) {
@@ -316,7 +334,7 @@ static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
316334
<< " remaining in buffer";
317335
return ;
318336
}
319-
printUnwindCode(ArrayRef(I, E));
337+
printUnwindCode(ArrayRef(I, E), SeenFirstEpilog);
320338
I += UsedSlots;
321339
}
322340
}

0 commit comments

Comments
 (0)