Skip to content

Commit 1e0a70f

Browse files
committed
[llvm] Win x64 Unwind V2 2/n: Support dumping UOP_Epilog
1 parent 916e6ad commit 1e0a70f

File tree

5 files changed

+268
-29
lines changed

5 files changed

+268
-29
lines changed
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: 113
103+
SectionData: C3662E0F1F8400000000000F1F4400005048890C2458C3660F1F8400000000004883EC38E8D7FFFFFFE900000000488D4C2430E8D8FFFFFF904883C438C3488944242889542424488D4C2430E8BFFFFFFF488B4C2428E805000000CC0F1F4000C3662E0F1F8400000000000F1F440000C3
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: 44 additions & 23 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:
@@ -94,16 +115,16 @@ sections:
94115
VirtualAddress: 4096
95116
VirtualSize: 113
96117
SectionData: C3662E0F1F8400000000000F1F4400005048890C2458C3660F1F8400000000004883EC38E8D7FFFFFFE900000000488D4C2430E8D8FFFFFF904883C438C3488944242889542424488D4C2430E8BFFFFFFF488B4C2428E805000000CC0F1F4000C3662E0F1F8400000000000F1F440000C3
97-
- Name: .rdata
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: 22 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,30 @@ 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].getOpInfo() << 8) |
308+
static_cast<uint32_t>(UCs[0].u.CodeOffset);
309+
if (Offset == 0) {
310+
outs() << " padding";
311+
} else {
312+
outs() << " offset=" << format("0x%X", Offset);
313+
}
314+
} else {
315+
SeenFirstEpilog = true;
316+
bool AtEnd = (UCs[0].getOpInfo() & 0x1) != 0;
317+
uint32_t Length = UCs[0].u.CodeOffset;
318+
outs() << " atend=" << (AtEnd ? "yes" : "no")
319+
<< ", length=" << format("0x%X", Length);
320+
}
321+
break;
304322
}
305323
outs() << "\n";
306324
}
307325

308326
static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
327+
bool SeenFirstEpilog = false;
309328
for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) {
310329
unsigned UsedSlots = getNumUsedSlots(*I);
311330
if (UsedSlots > UCs.size()) {
@@ -316,7 +335,7 @@ static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
316335
<< " remaining in buffer";
317336
return ;
318337
}
319-
printUnwindCode(ArrayRef(I, E));
338+
printUnwindCode(ArrayRef(I, E), SeenFirstEpilog);
320339
I += UsedSlots;
321340
}
322341
}

llvm/tools/llvm-readobj/Win64EHDumper.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ static StringRef getUnwindCodeTypeName(uint8_t Code) {
6565
case UOP_SaveXMM128: return "SAVE_XMM128";
6666
case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR";
6767
case UOP_PushMachFrame: return "PUSH_MACHFRAME";
68+
case UOP_Epilog:
69+
return "EPILOG";
6870
}
6971
}
7072

@@ -99,6 +101,7 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
99101
case UOP_AllocSmall:
100102
case UOP_SetFPReg:
101103
case UOP_PushMachFrame:
104+
case UOP_Epilog:
102105
return 1;
103106
case UOP_SaveNonVol:
104107
case UOP_SaveXMM128:
@@ -254,7 +257,8 @@ void Dumper::printRuntimeFunctionEntry(const Context &Ctx,
254257
// Prints one unwind code. Because an unwind code can occupy up to 3 slots in
255258
// the unwind codes array, this function requires that the correct number of
256259
// slots is provided.
257-
void Dumper::printUnwindCode(const UnwindInfo& UI, ArrayRef<UnwindCode> UC) {
260+
void Dumper::printUnwindCode(const UnwindInfo &UI, ArrayRef<UnwindCode> UC,
261+
bool &SeenFirstEpilog) {
258262
assert(UC.size() >= getNumUsedSlots(UC[0]));
259263

260264
SW.startLine() << format("0x%02X: ", unsigned(UC[0].u.CodeOffset))
@@ -306,6 +310,24 @@ void Dumper::printUnwindCode(const UnwindInfo& UI, ArrayRef<UnwindCode> UC) {
306310
case UOP_PushMachFrame:
307311
OS << " errcode=" << (UC[0].getOpInfo() == 0 ? "no" : "yes");
308312
break;
313+
314+
case UOP_Epilog:
315+
if (SeenFirstEpilog) {
316+
uint32_t Offset =
317+
(UC[0].getOpInfo() << 8) | static_cast<uint32_t>(UC[0].u.CodeOffset);
318+
if (Offset == 0) {
319+
OS << " padding";
320+
} else {
321+
OS << " offset=" << format("0x%X", Offset);
322+
}
323+
} else {
324+
SeenFirstEpilog = true;
325+
bool AtEnd = (UC[0].getOpInfo() & 0x1) != 0;
326+
uint32_t Length = UC[0].u.CodeOffset;
327+
OS << " atend=" << (AtEnd ? "yes" : "no")
328+
<< ", length=" << format("0x%X", Length);
329+
}
330+
break;
309331
}
310332

311333
OS << "\n";
@@ -330,14 +352,15 @@ void Dumper::printUnwindInfo(const Context &Ctx, const coff_section *Section,
330352
{
331353
ListScope UCS(SW, "UnwindCodes");
332354
ArrayRef<UnwindCode> UC(&UI.UnwindCodes[0], UI.NumCodes);
355+
bool SeenFirstEpilog = false;
333356
for (const UnwindCode *UCI = UC.begin(), *UCE = UC.end(); UCI < UCE; ++UCI) {
334357
unsigned UsedSlots = getNumUsedSlots(*UCI);
335358
if (UsedSlots > UC.size()) {
336359
errs() << "corrupt unwind data";
337360
return;
338361
}
339362

340-
printUnwindCode(UI, ArrayRef(UCI, UCE));
363+
printUnwindCode(UI, ArrayRef(UCI, UCE), SeenFirstEpilog);
341364
UCI = UCI + UsedSlots - 1;
342365
}
343366
}

0 commit comments

Comments
 (0)