1 //===-- TestPECallFrameInfo.cpp -------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #include "gtest/gtest.h"
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"
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"
22 using namespace lldb_private
;
25 class PECallFrameInfoTest
: public testing::Test
{
26 SubsystemRAII
<FileSystem
, ObjectFilePECOFF
> subsystems
;
29 void GetUnwindPlan(addr_t file_addr
, UnwindPlan
&plan
) const;
32 void PECallFrameInfoTest::GetUnwindPlan(addr_t file_addr
, UnwindPlan
&plan
) const {
33 llvm::Expected
<TestFile
> ExpectedFile
= TestFile::fromYaml(
37 AddressOfEntryPoint: 0
39 SectionAlignment: 4096
41 MajorOperatingSystemVersion: 6
42 MinorOperatingSystemVersion: 0
45 MajorSubsystemVersion: 6
46 MinorSubsystemVersion: 0
47 Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
48 DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ]
49 SizeOfStackReserve: 1048576
50 SizeOfStackCommit: 4096
51 SizeOfHeapReserve: 1048576
52 SizeOfHeapCommit: 4096
54 RelativeVirtualAddress: 0
57 RelativeVirtualAddress: 0
60 RelativeVirtualAddress: 0
63 RelativeVirtualAddress: 12288
66 RelativeVirtualAddress: 0
69 RelativeVirtualAddress: 0
72 RelativeVirtualAddress: 0
75 RelativeVirtualAddress: 0
78 RelativeVirtualAddress: 0
81 RelativeVirtualAddress: 0
84 RelativeVirtualAddress: 0
87 RelativeVirtualAddress: 0
90 RelativeVirtualAddress: 0
92 DelayImportDescriptor:
93 RelativeVirtualAddress: 0
96 RelativeVirtualAddress: 0
99 Machine: IMAGE_FILE_MACHINE_AMD64
100 Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ]
103 Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
107 Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
110 SectionData: 010C06000C3208F006E00470036002302105020005540D0000100000001100000020000019400E352F74670028646600213465001A3315015E000EF00CE00AD008C00650
113 # Unwind info at 0x2000:
114 # 01 0C 06 00 No chained info, prolog size = 0xC, unwind codes size is 6 words, no frame register
115 # 0C 32 UOP_AllocSmall(2) 3 * 8 + 8 bytes, offset in prolog is 0xC
116 # 08 F0 UOP_PushNonVol(0) R15(0xF), offset in prolog is 8
117 # 06 E0 UOP_PushNonVol(0) R14(0xE), offset in prolog is 6
118 # 04 70 UOP_PushNonVol(0) RDI(7), offset in prolog is 4
119 # 03 60 UOP_PushNonVol(0) RSI(6), offset in prolog is 3
120 # 02 30 UOP_PushNonVol(0) RBX(3), offset in prolog is 2
121 # Corresponding prolog:
129 # Unwind info at 0x2010:
130 # 21 05 02 00 Has chained info, prolog size = 5, unwind codes size is 2 words, no frame register
131 # 05 54 0D 00 UOP_SaveNonVol(4) RBP(5) to RSP + 0xD * 8, offset in prolog is 5
132 # Chained runtime function:
133 # 00 10 00 00 Start address is 0x1000
134 # 00 11 00 00 End address is 0x1100
135 # 00 20 00 00 Unwind info RVA is 0x2000
136 # Corresponding prolog:
137 # 00 mov [rsp+68h], rbp
139 # Unwind info at 0x2024:
140 # 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
141 # 2F 74 67 00 UOP_SaveNonVol(4) RDI(7) to RSP + 0x67 * 8, offset in prolog is 0x2F
142 # 28 64 66 00 UOP_SaveNonVol(4) RSI(6) to RSP + 0x66 * 8, offset in prolog is 0x28
143 # 21 34 65 00 UOP_SaveNonVol(4) RBX(3) to RSP + 0x65 * 8, offset in prolog is 0x21
144 # 1A 33 UOP_SetFPReg(3), offset in prolog is 0x1A
145 # 15 01 5E 00 UOP_AllocLarge(1) 0x5E * 8 bytes, offset in prolog is 0x15
146 # 0E F0 UOP_PushNonVol(0) R15(0xF), offset in prolog is 0xE
147 # 0C E0 UOP_PushNonVol(0) R14(0xE), offset in prolog is 0xC
148 # 0A D0 UOP_PushNonVol(0) R13(0xD), offset in prolog is 0xA
149 # 08 C0 UOP_PushNonVol(0) R12(0xC), offset in prolog is 8
150 # 06 50 UOP_PushNonVol(0) RBP(5), offset in prolog is 6
151 # Corresponding prolog:
152 # 00 mov [rsp+8], rcx
159 # 15 lea rbp, [rsp+30h]
160 # 1A mov [rbp+2F8h], rbx
161 # 21 mov [rbp+300h], rsi
162 # 28 mov [rbp+308h], rdi
165 Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
166 VirtualAddress: 12288
168 SectionData: 000000000000000000000000000000000000000000000000001000000011000000200000001100000012000010200000001200000013000024200000
171 # 00 00 00 00 Test correct processing of empty runtime functions at begin
175 # 00 00 00 00 Test correct processing of empty runtime functions at begin
178 # 00 10 00 00 Start address is 0x1000
179 # 00 11 00 00 End address is 0x1100
180 # 00 20 00 00 Unwind info RVA is 0x2000
182 # 00 11 00 00 Start address is 0x1100
183 # 00 12 00 00 End address is 0x1200
184 # 10 20 00 00 Unwind info RVA is 0x2010
186 # 00 12 00 00 Start address is 0x1200
187 # 00 13 00 00 End address is 0x1300
188 # 24 20 00 00 Unwind info RVA is 0x2024
193 ASSERT_THAT_EXPECTED(ExpectedFile
, llvm::Succeeded());
195 ModuleSP module_sp
= std::make_shared
<Module
>(ExpectedFile
->moduleSpec());
196 ObjectFile
*object_file
= module_sp
->GetObjectFile();
197 ASSERT_NE(object_file
, nullptr);
199 std::unique_ptr
<CallFrameInfo
> cfi
= object_file
->CreateCallFrameInfo();
200 ASSERT_NE(cfi
.get(), nullptr);
202 SectionList
*sect_list
= object_file
->GetSectionList();
203 ASSERT_NE(sect_list
, nullptr);
205 EXPECT_TRUE(cfi
->GetUnwindPlan(Address(file_addr
, sect_list
), plan
));
208 TEST_F(PECallFrameInfoTest
, Basic_eh
) {
209 UnwindPlan
plan(eRegisterKindLLDB
);
210 GetUnwindPlan(0x1001080, plan
);
211 EXPECT_EQ(plan
.GetRowCount(), 7);
215 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64
, 8);
216 row
.SetRegisterLocationToIsCFAPlusOffset(lldb_rsp_x86_64
, 0, true);
217 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_rip_x86_64
, -8, true);
218 EXPECT_EQ(*plan
.GetRowAtIndex(0), row
);
221 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64
, 0x10);
222 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_rbx_x86_64
, -0x10, true);
223 EXPECT_EQ(*plan
.GetRowAtIndex(1), row
);
226 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64
, 0x18);
227 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_rsi_x86_64
, -0x18, true);
228 EXPECT_EQ(*plan
.GetRowAtIndex(2), row
);
231 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64
, 0x20);
232 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_rdi_x86_64
, -0x20, true);
233 EXPECT_EQ(*plan
.GetRowAtIndex(3), row
);
236 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64
, 0x28);
237 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_r14_x86_64
, -0x28, true);
238 EXPECT_EQ(*plan
.GetRowAtIndex(4), row
);
241 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64
, 0x30);
242 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_r15_x86_64
, -0x30, true);
243 EXPECT_EQ(*plan
.GetRowAtIndex(5), row
);
246 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64
, 0x50);
247 EXPECT_EQ(*plan
.GetRowAtIndex(6), row
);
250 TEST_F(PECallFrameInfoTest
, Chained_eh
) {
251 UnwindPlan
plan(eRegisterKindLLDB
);
252 GetUnwindPlan(0x1001180, plan
);
253 EXPECT_EQ(plan
.GetRowCount(), 2);
257 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64
, 0x50);
258 row
.SetRegisterLocationToIsCFAPlusOffset(lldb_rsp_x86_64
, 0, true);
259 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_rip_x86_64
, -8, true);
260 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_rbx_x86_64
, -0x10, true);
261 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_rsi_x86_64
, -0x18, true);
262 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_rdi_x86_64
, -0x20, true);
263 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_r14_x86_64
, -0x28, true);
264 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_r15_x86_64
, -0x30, true);
265 EXPECT_EQ(*plan
.GetRowAtIndex(0), row
);
268 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_rbp_x86_64
, 0x18, true);
269 EXPECT_EQ(*plan
.GetRowAtIndex(1), row
);
272 TEST_F(PECallFrameInfoTest
, Frame_reg_eh
) {
273 UnwindPlan
plan(eRegisterKindLLDB
);
274 GetUnwindPlan(0x1001280, plan
);
275 EXPECT_EQ(plan
.GetRowCount(), 11);
279 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64
, 8);
280 row
.SetRegisterLocationToIsCFAPlusOffset(lldb_rsp_x86_64
, 0, true);
281 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_rip_x86_64
, -8, true);
282 EXPECT_EQ(*plan
.GetRowAtIndex(0), row
);
285 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64
, 0x10);
286 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_rbp_x86_64
, -0x10, true);
287 EXPECT_EQ(*plan
.GetRowAtIndex(1), row
);
290 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64
, 0x18);
291 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_r12_x86_64
, -0x18, true);
292 EXPECT_EQ(*plan
.GetRowAtIndex(2), row
);
295 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64
, 0x20);
296 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_r13_x86_64
, -0x20, true);
297 EXPECT_EQ(*plan
.GetRowAtIndex(3), row
);
300 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64
, 0x28);
301 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_r14_x86_64
, -0x28, true);
302 EXPECT_EQ(*plan
.GetRowAtIndex(4), row
);
305 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64
, 0x30);
306 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_r15_x86_64
, -0x30, true);
307 EXPECT_EQ(*plan
.GetRowAtIndex(5), row
);
310 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64
, 0x320);
311 EXPECT_EQ(*plan
.GetRowAtIndex(6), row
);
314 row
.GetCFAValue().SetIsRegisterPlusOffset(lldb_rbp_x86_64
, 0x2F0);
315 EXPECT_EQ(*plan
.GetRowAtIndex(7), row
);
318 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_rbx_x86_64
, 8, true);
319 EXPECT_EQ(*plan
.GetRowAtIndex(8), row
);
322 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_rsi_x86_64
, 0x10, true);
323 EXPECT_EQ(*plan
.GetRowAtIndex(9), row
);
326 row
.SetRegisterLocationToAtCFAPlusOffset(lldb_rdi_x86_64
, 0x18, true);
327 EXPECT_EQ(*plan
.GetRowAtIndex(10), row
);