341 lines · cpp
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-exception7//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 R"(33--- !COFF34OptionalHeader: 35 AddressOfEntryPoint: 036 ImageBase: 1677721637 SectionAlignment: 409638 FileAlignment: 51239 MajorOperatingSystemVersion: 640 MinorOperatingSystemVersion: 041 MajorImageVersion: 042 MinorImageVersion: 043 MajorSubsystemVersion: 644 MinorSubsystemVersion: 045 Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI46 DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ]47 SizeOfStackReserve: 104857648 SizeOfStackCommit: 409649 SizeOfHeapReserve: 104857650 SizeOfHeapCommit: 409651 ExportTable: 52 RelativeVirtualAddress: 053 Size: 054 ImportTable: 55 RelativeVirtualAddress: 056 Size: 057 ResourceTable: 58 RelativeVirtualAddress: 059 Size: 060 ExceptionTable: 61 RelativeVirtualAddress: 1228862 Size: 6063 CertificateTable: 64 RelativeVirtualAddress: 065 Size: 066 BaseRelocationTable: 67 RelativeVirtualAddress: 068 Size: 069 Debug: 70 RelativeVirtualAddress: 071 Size: 072 Architecture: 73 RelativeVirtualAddress: 074 Size: 075 GlobalPtr: 76 RelativeVirtualAddress: 077 Size: 078 TlsTable: 79 RelativeVirtualAddress: 080 Size: 081 LoadConfigTable: 82 RelativeVirtualAddress: 083 Size: 084 BoundImport: 85 RelativeVirtualAddress: 086 Size: 087 IAT: 88 RelativeVirtualAddress: 089 Size: 090 DelayImportDescriptor: 91 RelativeVirtualAddress: 092 Size: 093 ClrRuntimeHeader: 94 RelativeVirtualAddress: 095 Size: 096header: 97 Machine: IMAGE_FILE_MACHINE_AMD6498 Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ]99sections: 100 - Name: .text101 Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]102 VirtualAddress: 4096103 VirtualSize: 4096104 - Name: .rdata105 Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]106 VirtualAddress: 8192107 VirtualSize: 68108 SectionData: 010C06000C3208F006E00470036002302105020005540D0000100000001100000020000019400E352F74670028646600213465001A3315015E000EF00CE00AD008C00650109 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 register113# 0C 32 UOP_AllocSmall(2) 3 * 8 + 8 bytes, offset in prolog is 0xC114# 08 F0 UOP_PushNonVol(0) R15(0xF), offset in prolog is 8115# 06 E0 UOP_PushNonVol(0) R14(0xE), offset in prolog is 6116# 04 70 UOP_PushNonVol(0) RDI(7), offset in prolog is 4117# 03 60 UOP_PushNonVol(0) RSI(6), offset in prolog is 3118# 02 30 UOP_PushNonVol(0) RBX(3), offset in prolog is 2119# Corresponding prolog:120# 00 push rbx121# 02 push rsi122# 03 push rdi123# 04 push r14124# 06 push r15125# 08 sub rsp, 20h126 127# Unwind info at 0x2010:128# 21 05 02 00 Has chained info, prolog size = 5, unwind codes size is 2 words, no frame register129# 05 54 0D 00 UOP_SaveNonVol(4) RBP(5) to RSP + 0xD * 8, offset in prolog is 5130# Chained runtime function:131# 00 10 00 00 Start address is 0x1000132# 00 11 00 00 End address is 0x1100133# 00 20 00 00 Unwind info RVA is 0x2000134# Corresponding prolog:135# 00 mov [rsp+68h], rbp136 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 * 16139# 2F 74 67 00 UOP_SaveNonVol(4) RDI(7) to RSP + 0x67 * 8, offset in prolog is 0x2F140# 28 64 66 00 UOP_SaveNonVol(4) RSI(6) to RSP + 0x66 * 8, offset in prolog is 0x28141# 21 34 65 00 UOP_SaveNonVol(4) RBX(3) to RSP + 0x65 * 8, offset in prolog is 0x21142# 1A 33 UOP_SetFPReg(3), offset in prolog is 0x1A143# 15 01 5E 00 UOP_AllocLarge(1) 0x5E * 8 bytes, offset in prolog is 0x15144# 0E F0 UOP_PushNonVol(0) R15(0xF), offset in prolog is 0xE145# 0C E0 UOP_PushNonVol(0) R14(0xE), offset in prolog is 0xC146# 0A D0 UOP_PushNonVol(0) R13(0xD), offset in prolog is 0xA147# 08 C0 UOP_PushNonVol(0) R12(0xC), offset in prolog is 8148# 06 50 UOP_PushNonVol(0) RBP(5), offset in prolog is 6149# Corresponding prolog:150# 00 mov [rsp+8], rcx151# 05 push rbp152# 06 push r12153# 08 push r13154# 0A push r14155# 0C push r15156# 0E sub rsp, 2F0h157# 15 lea rbp, [rsp+30h]158# 1A mov [rbp+2F8h], rbx159# 21 mov [rbp+300h], rsi160# 28 mov [rbp+308h], rdi161 162 - Name: .pdata163 Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]164 VirtualAddress: 12288165 VirtualSize: 60166 SectionData: 000000000000000000000000000000000000000000000000001000000011000000200000001100000012000010200000001200000013000024200000167 168# 00 00 00 00169# 00 00 00 00 Test correct processing of empty runtime functions at begin170# 00 00 00 00171 172# 00 00 00 00173# 00 00 00 00 Test correct processing of empty runtime functions at begin174# 00 00 00 00175 176# 00 10 00 00 Start address is 0x1000177# 00 11 00 00 End address is 0x1100178# 00 20 00 00 Unwind info RVA is 0x2000179 180# 00 11 00 00 Start address is 0x1100181# 00 12 00 00 End address is 0x1200182# 10 20 00 00 Unwind info RVA is 0x2010183 184# 00 12 00 00 Start address is 0x1200185# 00 13 00 00 End address is 0x1300186# 24 20 00 00 Unwind info RVA is 0x2024187 188symbols: []189...190)");191 if (!ExpectedFile)192 return ExpectedFile.takeError();193 194 ModuleSP module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());195 ObjectFile *object_file = module_sp->GetObjectFile();196 if (!object_file)197 return llvm::createStringError("object file is null");198 199 std::unique_ptr<CallFrameInfo> cfi = object_file->CreateCallFrameInfo();200 if (!cfi)201 return llvm::createStringError("call frame info is null");202 203 SectionList *sect_list = object_file->GetSectionList();204 if (!sect_list)205 return llvm::createStringError("section list is null");206 207 std::unique_ptr<UnwindPlan> plan_up =208 cfi->GetUnwindPlan(Address(file_addr, sect_list));209 if (!plan_up)210 return llvm::createStringError("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(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(lldb_rsp_x86_64, 8);224 row.SetRegisterLocationToIsCFAPlusOffset(lldb_rsp_x86_64, 0, true);225 row.SetRegisterLocationToAtCFAPlusOffset(lldb_rip_x86_64, -8, true);226 EXPECT_EQ(*plan.GetRowAtIndex(0), row);227 228 row.SetOffset(2);229 row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x10);230 row.SetRegisterLocationToAtCFAPlusOffset(lldb_rbx_x86_64, -0x10, true);231 EXPECT_EQ(*plan.GetRowAtIndex(1), row);232 233 row.SetOffset(3);234 row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x18);235 row.SetRegisterLocationToAtCFAPlusOffset(lldb_rsi_x86_64, -0x18, true);236 EXPECT_EQ(*plan.GetRowAtIndex(2), row);237 238 row.SetOffset(4);239 row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x20);240 row.SetRegisterLocationToAtCFAPlusOffset(lldb_rdi_x86_64, -0x20, true);241 EXPECT_EQ(*plan.GetRowAtIndex(3), row);242 243 row.SetOffset(6);244 row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x28);245 row.SetRegisterLocationToAtCFAPlusOffset(lldb_r14_x86_64, -0x28, true);246 EXPECT_EQ(*plan.GetRowAtIndex(4), row);247 248 row.SetOffset(8);249 row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x30);250 row.SetRegisterLocationToAtCFAPlusOffset(lldb_r15_x86_64, -0x30, true);251 EXPECT_EQ(*plan.GetRowAtIndex(5), row);252 253 row.SetOffset(0xC);254 row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 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(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(lldb_rsp_x86_64, 0x50);268 row.SetRegisterLocationToIsCFAPlusOffset(lldb_rsp_x86_64, 0, true);269 row.SetRegisterLocationToAtCFAPlusOffset(lldb_rip_x86_64, -8, true);270 row.SetRegisterLocationToAtCFAPlusOffset(lldb_rbx_x86_64, -0x10, true);271 row.SetRegisterLocationToAtCFAPlusOffset(lldb_rsi_x86_64, -0x18, true);272 row.SetRegisterLocationToAtCFAPlusOffset(lldb_rdi_x86_64, -0x20, true);273 row.SetRegisterLocationToAtCFAPlusOffset(lldb_r14_x86_64, -0x28, true);274 row.SetRegisterLocationToAtCFAPlusOffset(lldb_r15_x86_64, -0x30, true);275 EXPECT_EQ(*plan.GetRowAtIndex(0), row);276 277 row.SetOffset(5);278 row.SetRegisterLocationToAtCFAPlusOffset(lldb_rbp_x86_64, 0x18, 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(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(lldb_rsp_x86_64, 8);292 row.SetRegisterLocationToIsCFAPlusOffset(lldb_rsp_x86_64, 0, true);293 row.SetRegisterLocationToAtCFAPlusOffset(lldb_rip_x86_64, -8, true);294 EXPECT_EQ(*plan.GetRowAtIndex(0), row);295 296 row.SetOffset(6);297 row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x10);298 row.SetRegisterLocationToAtCFAPlusOffset(lldb_rbp_x86_64, -0x10, true);299 EXPECT_EQ(*plan.GetRowAtIndex(1), row);300 301 row.SetOffset(8);302 row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x18);303 row.SetRegisterLocationToAtCFAPlusOffset(lldb_r12_x86_64, -0x18, true);304 EXPECT_EQ(*plan.GetRowAtIndex(2), row);305 306 row.SetOffset(0xA);307 row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x20);308 row.SetRegisterLocationToAtCFAPlusOffset(lldb_r13_x86_64, -0x20, true);309 EXPECT_EQ(*plan.GetRowAtIndex(3), row);310 311 row.SetOffset(0xC);312 row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x28);313 row.SetRegisterLocationToAtCFAPlusOffset(lldb_r14_x86_64, -0x28, true);314 EXPECT_EQ(*plan.GetRowAtIndex(4), row);315 316 row.SetOffset(0xE);317 row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x30);318 row.SetRegisterLocationToAtCFAPlusOffset(lldb_r15_x86_64, -0x30, true);319 EXPECT_EQ(*plan.GetRowAtIndex(5), row);320 321 row.SetOffset(0x15);322 row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x320);323 EXPECT_EQ(*plan.GetRowAtIndex(6), row);324 325 row.SetOffset(0x1A);326 row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rbp_x86_64, 0x2F0);327 EXPECT_EQ(*plan.GetRowAtIndex(7), row);328 329 row.SetOffset(0x21);330 row.SetRegisterLocationToAtCFAPlusOffset(lldb_rbx_x86_64, 8, true);331 EXPECT_EQ(*plan.GetRowAtIndex(8), row);332 333 row.SetOffset(0x28);334 row.SetRegisterLocationToAtCFAPlusOffset(lldb_rsi_x86_64, 0x10, true);335 EXPECT_EQ(*plan.GetRowAtIndex(9), row);336 337 row.SetOffset(0x2F);338 row.SetRegisterLocationToAtCFAPlusOffset(lldb_rdi_x86_64, 0x18, true);339 EXPECT_EQ(*plan.GetRowAtIndex(10), row);340}341