1//===-- TestPECallFrameInfo.cpp -------------------------------------------===//
2//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#include "gtest/gtest.h"
11
12#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
13#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
14#include "TestingSupport/SubsystemRAII.h"
15#include "TestingSupport/TestUtilities.h"
16
17#include "lldb/Core/Module.h"
18#include "lldb/Symbol/CallFrameInfo.h"
19#include "lldb/Symbol/UnwindPlan.h"
20#include "llvm/Testing/Support/Error.h"
21
22using namespace lldb_private;
23using namespace lldb;
24
25class PECallFrameInfoTest : public testing::Test {
26 SubsystemRAII<FileSystem, ObjectFilePECOFF> subsystems;
27};
28
29static llvm::Expected<std::unique_ptr<UnwindPlan>>
30GetUnwindPlan(addr_t file_addr) {
31 llvm::Expected<TestFile> ExpectedFile = TestFile::fromYaml(
32 Yaml: R"(
33--- !COFF
34OptionalHeader:
35 AddressOfEntryPoint: 0
36 ImageBase: 16777216
37 SectionAlignment: 4096
38 FileAlignment: 512
39 MajorOperatingSystemVersion: 6
40 MinorOperatingSystemVersion: 0
41 MajorImageVersion: 0
42 MinorImageVersion: 0
43 MajorSubsystemVersion: 6
44 MinorSubsystemVersion: 0
45 Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
46 DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ]
47 SizeOfStackReserve: 1048576
48 SizeOfStackCommit: 4096
49 SizeOfHeapReserve: 1048576
50 SizeOfHeapCommit: 4096
51 ExportTable:
52 RelativeVirtualAddress: 0
53 Size: 0
54 ImportTable:
55 RelativeVirtualAddress: 0
56 Size: 0
57 ResourceTable:
58 RelativeVirtualAddress: 0
59 Size: 0
60 ExceptionTable:
61 RelativeVirtualAddress: 12288
62 Size: 60
63 CertificateTable:
64 RelativeVirtualAddress: 0
65 Size: 0
66 BaseRelocationTable:
67 RelativeVirtualAddress: 0
68 Size: 0
69 Debug:
70 RelativeVirtualAddress: 0
71 Size: 0
72 Architecture:
73 RelativeVirtualAddress: 0
74 Size: 0
75 GlobalPtr:
76 RelativeVirtualAddress: 0
77 Size: 0
78 TlsTable:
79 RelativeVirtualAddress: 0
80 Size: 0
81 LoadConfigTable:
82 RelativeVirtualAddress: 0
83 Size: 0
84 BoundImport:
85 RelativeVirtualAddress: 0
86 Size: 0
87 IAT:
88 RelativeVirtualAddress: 0
89 Size: 0
90 DelayImportDescriptor:
91 RelativeVirtualAddress: 0
92 Size: 0
93 ClrRuntimeHeader:
94 RelativeVirtualAddress: 0
95 Size: 0
96header:
97 Machine: IMAGE_FILE_MACHINE_AMD64
98 Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ]
99sections:
100 - Name: .text
101 Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
102 VirtualAddress: 4096
103 VirtualSize: 4096
104 - Name: .rdata
105 Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
106 VirtualAddress: 8192
107 VirtualSize: 68
108 SectionData: 010C06000C3208F006E00470036002302105020005540D0000100000001100000020000019400E352F74670028646600213465001A3315015E000EF00CE00AD008C00650
109
110
111# Unwind info at 0x2000:
112# 01 0C 06 00 No chained info, prolog size = 0xC, unwind codes size is 6 words, no frame register
113# 0C 32 UOP_AllocSmall(2) 3 * 8 + 8 bytes, offset in prolog is 0xC
114# 08 F0 UOP_PushNonVol(0) R15(0xF), offset in prolog is 8
115# 06 E0 UOP_PushNonVol(0) R14(0xE), offset in prolog is 6
116# 04 70 UOP_PushNonVol(0) RDI(7), offset in prolog is 4
117# 03 60 UOP_PushNonVol(0) RSI(6), offset in prolog is 3
118# 02 30 UOP_PushNonVol(0) RBX(3), offset in prolog is 2
119# Corresponding prolog:
120# 00 push rbx
121# 02 push rsi
122# 03 push rdi
123# 04 push r14
124# 06 push r15
125# 08 sub rsp, 20h
126
127# Unwind info at 0x2010:
128# 21 05 02 00 Has chained info, prolog size = 5, unwind codes size is 2 words, no frame register
129# 05 54 0D 00 UOP_SaveNonVol(4) RBP(5) to RSP + 0xD * 8, offset in prolog is 5
130# Chained runtime function:
131# 00 10 00 00 Start address is 0x1000
132# 00 11 00 00 End address is 0x1100
133# 00 20 00 00 Unwind info RVA is 0x2000
134# Corresponding prolog:
135# 00 mov [rsp+68h], rbp
136
137# Unwind info at 0x2024:
138# 19 40 0E 35 No chained info, prolog size = 0x40, unwind codes size is 0xE words, frame register is RBP, frame register offset is RSP + 3 * 16
139# 2F 74 67 00 UOP_SaveNonVol(4) RDI(7) to RSP + 0x67 * 8, offset in prolog is 0x2F
140# 28 64 66 00 UOP_SaveNonVol(4) RSI(6) to RSP + 0x66 * 8, offset in prolog is 0x28
141# 21 34 65 00 UOP_SaveNonVol(4) RBX(3) to RSP + 0x65 * 8, offset in prolog is 0x21
142# 1A 33 UOP_SetFPReg(3), offset in prolog is 0x1A
143# 15 01 5E 00 UOP_AllocLarge(1) 0x5E * 8 bytes, offset in prolog is 0x15
144# 0E F0 UOP_PushNonVol(0) R15(0xF), offset in prolog is 0xE
145# 0C E0 UOP_PushNonVol(0) R14(0xE), offset in prolog is 0xC
146# 0A D0 UOP_PushNonVol(0) R13(0xD), offset in prolog is 0xA
147# 08 C0 UOP_PushNonVol(0) R12(0xC), offset in prolog is 8
148# 06 50 UOP_PushNonVol(0) RBP(5), offset in prolog is 6
149# Corresponding prolog:
150# 00 mov [rsp+8], rcx
151# 05 push rbp
152# 06 push r12
153# 08 push r13
154# 0A push r14
155# 0C push r15
156# 0E sub rsp, 2F0h
157# 15 lea rbp, [rsp+30h]
158# 1A mov [rbp+2F8h], rbx
159# 21 mov [rbp+300h], rsi
160# 28 mov [rbp+308h], rdi
161
162 - Name: .pdata
163 Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
164 VirtualAddress: 12288
165 VirtualSize: 60
166 SectionData: 000000000000000000000000000000000000000000000000001000000011000000200000001100000012000010200000001200000013000024200000
167
168# 00 00 00 00
169# 00 00 00 00 Test correct processing of empty runtime functions at begin
170# 00 00 00 00
171
172# 00 00 00 00
173# 00 00 00 00 Test correct processing of empty runtime functions at begin
174# 00 00 00 00
175
176# 00 10 00 00 Start address is 0x1000
177# 00 11 00 00 End address is 0x1100
178# 00 20 00 00 Unwind info RVA is 0x2000
179
180# 00 11 00 00 Start address is 0x1100
181# 00 12 00 00 End address is 0x1200
182# 10 20 00 00 Unwind info RVA is 0x2010
183
184# 00 12 00 00 Start address is 0x1200
185# 00 13 00 00 End address is 0x1300
186# 24 20 00 00 Unwind info RVA is 0x2024
187
188symbols: []
189...
190)");
191 if (!ExpectedFile)
192 return ExpectedFile.takeError();
193
194 ModuleSP module_sp = std::make_shared<Module>(args: ExpectedFile->moduleSpec());
195 ObjectFile *object_file = module_sp->GetObjectFile();
196 if (!object_file)
197 return llvm::createStringError(Fmt: "object file is null");
198
199 std::unique_ptr<CallFrameInfo> cfi = object_file->CreateCallFrameInfo();
200 if (!cfi)
201 return llvm::createStringError(Fmt: "call frame info is null");
202
203 SectionList *sect_list = object_file->GetSectionList();
204 if (!sect_list)
205 return llvm::createStringError(Fmt: "section list is null");
206
207 std::unique_ptr<UnwindPlan> plan_up =
208 cfi->GetUnwindPlan(addr: Address(file_addr, sect_list));
209 if (!plan_up)
210 return llvm::createStringError(Fmt: "unwind plan is null");
211 return plan_up;
212}
213
214TEST_F(PECallFrameInfoTest, Basic_eh) {
215 llvm::Expected<std::unique_ptr<UnwindPlan>> expected_plan =
216 GetUnwindPlan(file_addr: 0x1001080);
217 ASSERT_THAT_EXPECTED(expected_plan, llvm::Succeeded());
218 UnwindPlan &plan = **expected_plan;
219 EXPECT_EQ(plan.GetRowCount(), 7);
220
221 UnwindPlan::Row row;
222 row.SetOffset(0);
223 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rsp_x86_64, offset: 8);
224 row.SetRegisterLocationToIsCFAPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0, can_replace: true);
225 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_rip_x86_64, offset: -8, can_replace: true);
226 EXPECT_EQ(*plan.GetRowAtIndex(0), row);
227
228 row.SetOffset(2);
229 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0x10);
230 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_rbx_x86_64, offset: -0x10, can_replace: true);
231 EXPECT_EQ(*plan.GetRowAtIndex(1), row);
232
233 row.SetOffset(3);
234 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0x18);
235 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_rsi_x86_64, offset: -0x18, can_replace: true);
236 EXPECT_EQ(*plan.GetRowAtIndex(2), row);
237
238 row.SetOffset(4);
239 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0x20);
240 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_rdi_x86_64, offset: -0x20, can_replace: true);
241 EXPECT_EQ(*plan.GetRowAtIndex(3), row);
242
243 row.SetOffset(6);
244 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0x28);
245 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_r14_x86_64, offset: -0x28, can_replace: true);
246 EXPECT_EQ(*plan.GetRowAtIndex(4), row);
247
248 row.SetOffset(8);
249 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0x30);
250 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_r15_x86_64, offset: -0x30, can_replace: true);
251 EXPECT_EQ(*plan.GetRowAtIndex(5), row);
252
253 row.SetOffset(0xC);
254 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0x50);
255 EXPECT_EQ(*plan.GetRowAtIndex(6), row);
256}
257
258TEST_F(PECallFrameInfoTest, Chained_eh) {
259 llvm::Expected<std::unique_ptr<UnwindPlan>> expected_plan =
260 GetUnwindPlan(file_addr: 0x1001180);
261 ASSERT_THAT_EXPECTED(expected_plan, llvm::Succeeded());
262 UnwindPlan &plan = **expected_plan;
263 EXPECT_EQ(plan.GetRowCount(), 2);
264
265 UnwindPlan::Row row;
266 row.SetOffset(0);
267 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0x50);
268 row.SetRegisterLocationToIsCFAPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0, can_replace: true);
269 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_rip_x86_64, offset: -8, can_replace: true);
270 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_rbx_x86_64, offset: -0x10, can_replace: true);
271 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_rsi_x86_64, offset: -0x18, can_replace: true);
272 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_rdi_x86_64, offset: -0x20, can_replace: true);
273 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_r14_x86_64, offset: -0x28, can_replace: true);
274 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_r15_x86_64, offset: -0x30, can_replace: true);
275 EXPECT_EQ(*plan.GetRowAtIndex(0), row);
276
277 row.SetOffset(5);
278 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_rbp_x86_64, offset: 0x18, can_replace: true);
279 EXPECT_EQ(*plan.GetRowAtIndex(1), row);
280}
281
282TEST_F(PECallFrameInfoTest, Frame_reg_eh) {
283 llvm::Expected<std::unique_ptr<UnwindPlan>> expected_plan =
284 GetUnwindPlan(file_addr: 0x1001280);
285 ASSERT_THAT_EXPECTED(expected_plan, llvm::Succeeded());
286 UnwindPlan &plan = **expected_plan;
287 EXPECT_EQ(plan.GetRowCount(), 11);
288
289 UnwindPlan::Row row;
290 row.SetOffset(0);
291 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rsp_x86_64, offset: 8);
292 row.SetRegisterLocationToIsCFAPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0, can_replace: true);
293 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_rip_x86_64, offset: -8, can_replace: true);
294 EXPECT_EQ(*plan.GetRowAtIndex(0), row);
295
296 row.SetOffset(6);
297 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0x10);
298 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_rbp_x86_64, offset: -0x10, can_replace: true);
299 EXPECT_EQ(*plan.GetRowAtIndex(1), row);
300
301 row.SetOffset(8);
302 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0x18);
303 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_r12_x86_64, offset: -0x18, can_replace: true);
304 EXPECT_EQ(*plan.GetRowAtIndex(2), row);
305
306 row.SetOffset(0xA);
307 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0x20);
308 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_r13_x86_64, offset: -0x20, can_replace: true);
309 EXPECT_EQ(*plan.GetRowAtIndex(3), row);
310
311 row.SetOffset(0xC);
312 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0x28);
313 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_r14_x86_64, offset: -0x28, can_replace: true);
314 EXPECT_EQ(*plan.GetRowAtIndex(4), row);
315
316 row.SetOffset(0xE);
317 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0x30);
318 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_r15_x86_64, offset: -0x30, can_replace: true);
319 EXPECT_EQ(*plan.GetRowAtIndex(5), row);
320
321 row.SetOffset(0x15);
322 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rsp_x86_64, offset: 0x320);
323 EXPECT_EQ(*plan.GetRowAtIndex(6), row);
324
325 row.SetOffset(0x1A);
326 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: lldb_rbp_x86_64, offset: 0x2F0);
327 EXPECT_EQ(*plan.GetRowAtIndex(7), row);
328
329 row.SetOffset(0x21);
330 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_rbx_x86_64, offset: 8, can_replace: true);
331 EXPECT_EQ(*plan.GetRowAtIndex(8), row);
332
333 row.SetOffset(0x28);
334 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_rsi_x86_64, offset: 0x10, can_replace: true);
335 EXPECT_EQ(*plan.GetRowAtIndex(9), row);
336
337 row.SetOffset(0x2F);
338 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: lldb_rdi_x86_64, offset: 0x18, can_replace: true);
339 EXPECT_EQ(*plan.GetRowAtIndex(10), row);
340}
341

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of lldb/unittests/ObjectFile/PECOFF/TestPECallFrameInfo.cpp