1 //===-- TestDWARFCallFrameInfo.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/ELF/ObjectFileELF.h" 13 #include "Plugins/Process/Utility/RegisterContext_x86.h" 14 #include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h" 15 #include "TestingSupport/SubsystemRAII.h" 16 #include "TestingSupport/TestUtilities.h" 17 18 #include "lldb/Core/Module.h" 19 #include "lldb/Core/ModuleSpec.h" 20 #include "lldb/Core/Section.h" 21 #include "lldb/Host/FileSystem.h" 22 #include "lldb/Host/HostInfo.h" 23 #include "lldb/Symbol/DWARFCallFrameInfo.h" 24 #include "lldb/Utility/StreamString.h" 25 #include "llvm/Testing/Support/Error.h" 26 27 #include "llvm/Support/FileUtilities.h" 28 #include "llvm/Support/Path.h" 29 #include "llvm/Support/Program.h" 30 #include "llvm/Support/raw_ostream.h" 31 32 using namespace lldb_private; 33 using namespace lldb; 34 35 class DWARFCallFrameInfoTest : public testing::Test { 36 SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab> 37 subsystems; 38 39 protected: 40 void TestBasic(DWARFCallFrameInfo::Type type, llvm::StringRef symbol); 41 }; 42 43 namespace lldb_private { 44 static std::ostream &operator<<(std::ostream &OS, const UnwindPlan::Row &row) { 45 StreamString SS; 46 row.Dump(SS, nullptr, nullptr, 0); 47 return OS << SS.GetData(); 48 } 49 } // namespace lldb_private 50 51 static UnwindPlan::Row GetExpectedRow0() { 52 UnwindPlan::Row row; 53 row.SetOffset(0); 54 row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rsp_x86_64, 8); 55 row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false); 56 return row; 57 } 58 59 static UnwindPlan::Row GetExpectedRow1() { 60 UnwindPlan::Row row; 61 row.SetOffset(1); 62 row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rsp_x86_64, 16); 63 row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false); 64 row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rbp_x86_64, -16, false); 65 return row; 66 } 67 68 static UnwindPlan::Row GetExpectedRow2() { 69 UnwindPlan::Row row; 70 row.SetOffset(4); 71 row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rbp_x86_64, 16); 72 row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false); 73 row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rbp_x86_64, -16, false); 74 return row; 75 } 76 77 void DWARFCallFrameInfoTest::TestBasic(DWARFCallFrameInfo::Type type, 78 llvm::StringRef symbol) { 79 auto ExpectedFile = TestFile::fromYaml(R"( 80 --- !ELF 81 FileHeader: 82 Class: ELFCLASS64 83 Data: ELFDATA2LSB 84 Type: ET_DYN 85 Machine: EM_X86_64 86 Entry: 0x0000000000000260 87 Sections: 88 - Name: .text 89 Type: SHT_PROGBITS 90 Flags: [ SHF_ALLOC, SHF_EXECINSTR ] 91 Address: 0x0000000000000260 92 AddressAlign: 0x0000000000000010 93 Content: 554889E5897DFC8B45FC5DC30F1F4000554889E5897DFC8B45FC5DC30F1F4000554889E5897DFC8B45FC5DC3 94 #0000000000000260 <eh_frame>: 95 # 260: 55 push %rbp 96 # 261: 48 89 e5 mov %rsp,%rbp 97 # 264: 89 7d fc mov %edi,-0x4(%rbp) 98 # 267: 8b 45 fc mov -0x4(%rbp),%eax 99 # 26a: 5d pop %rbp 100 # 26b: c3 retq 101 # 26c: 0f 1f 40 00 nopl 0x0(%rax) 102 # 103 #0000000000000270 <debug_frame3>: 104 # 270: 55 push %rbp 105 # 271: 48 89 e5 mov %rsp,%rbp 106 # 274: 89 7d fc mov %edi,-0x4(%rbp) 107 # 277: 8b 45 fc mov -0x4(%rbp),%eax 108 # 27a: 5d pop %rbp 109 # 27b: c3 retq 110 # 27c: 0f 1f 40 00 nopl 0x0(%rax) 111 # 112 #0000000000000280 <debug_frame4>: 113 # 280: 55 push %rbp 114 # 281: 48 89 e5 mov %rsp,%rbp 115 # 284: 89 7d fc mov %edi,-0x4(%rbp) 116 # 287: 8b 45 fc mov -0x4(%rbp),%eax 117 # 28a: 5d pop %rbp 118 # 28b: c3 retq 119 - Name: .eh_frame 120 Type: SHT_X86_64_UNWIND 121 Flags: [ SHF_ALLOC ] 122 Address: 0x0000000000000290 123 AddressAlign: 0x0000000000000008 124 Content: 1400000000000000017A5200017810011B0C0708900100001C0000001C000000B0FFFFFF0C00000000410E108602430D0600000000000000 125 #00000000 0000000000000014 00000000 CIE 126 # Version: 1 127 # Augmentation: "zR" 128 # Code alignment factor: 1 129 # Data alignment factor: -8 130 # Return address column: 16 131 # Augmentation data: 1b 132 # 133 # DW_CFA_def_cfa: r7 (rsp) ofs 8 134 # DW_CFA_offset: r16 (rip) at cfa-8 135 # DW_CFA_nop 136 # DW_CFA_nop 137 # 138 #00000018 000000000000001c 0000001c FDE cie=00000000 pc=ffffffffffffffd0..ffffffffffffffdc 139 # DW_CFA_advance_loc: 1 to ffffffffffffffd1 140 # DW_CFA_def_cfa_offset: 16 141 # DW_CFA_offset: r6 (rbp) at cfa-16 142 # DW_CFA_advance_loc: 3 to ffffffffffffffd4 143 # DW_CFA_def_cfa_register: r6 (rbp) 144 # DW_CFA_nop 145 # DW_CFA_nop 146 # DW_CFA_nop 147 # DW_CFA_nop 148 # DW_CFA_nop 149 # DW_CFA_nop 150 # DW_CFA_nop 151 - Name: .debug_frame 152 Type: SHT_PROGBITS 153 AddressAlign: 0x0000000000000008 154 Content: 14000000FFFFFFFF03000178100C070890010000000000001C0000000000000070020000000000000C00000000000000410E108602430D0614000000FFFFFFFF040008000178100C07089001000000001C0000003800000080020000000000000C00000000000000410E108602430D06 155 #00000000 0000000000000014 ffffffff CIE 156 # Version: 3 157 # Augmentation: "" 158 # Code alignment factor: 1 159 # Data alignment factor: -8 160 # Return address column: 16 161 # 162 # DW_CFA_def_cfa: r7 (rsp) ofs 8 163 # DW_CFA_offset: r16 (rip) at cfa-8 164 # DW_CFA_nop 165 # DW_CFA_nop 166 # DW_CFA_nop 167 # DW_CFA_nop 168 # DW_CFA_nop 169 # DW_CFA_nop 170 # 171 #00000018 000000000000001c 00000000 FDE cie=00000000 pc=0000000000000270..000000000000027c 172 # DW_CFA_advance_loc: 1 to 0000000000000271 173 # DW_CFA_def_cfa_offset: 16 174 # DW_CFA_offset: r6 (rbp) at cfa-16 175 # DW_CFA_advance_loc: 3 to 0000000000000274 176 # DW_CFA_def_cfa_register: r6 (rbp) 177 # 178 #00000038 0000000000000014 ffffffff CIE 179 # Version: 4 180 # Augmentation: "" 181 # Pointer Size: 8 182 # Segment Size: 0 183 # Code alignment factor: 1 184 # Data alignment factor: -8 185 # Return address column: 16 186 # 187 # DW_CFA_def_cfa: r7 (rsp) ofs 8 188 # DW_CFA_offset: r16 (rip) at cfa-8 189 # DW_CFA_nop 190 # DW_CFA_nop 191 # DW_CFA_nop 192 # DW_CFA_nop 193 # 194 #00000050 000000000000001c 00000038 FDE cie=00000038 pc=0000000000000280..000000000000028c 195 # DW_CFA_advance_loc: 1 to 0000000000000281 196 # DW_CFA_def_cfa_offset: 16 197 # DW_CFA_offset: r6 (rbp) at cfa-16 198 # DW_CFA_advance_loc: 3 to 0000000000000284 199 # DW_CFA_def_cfa_register: r6 (rbp) 200 Symbols: 201 - Name: eh_frame 202 Type: STT_FUNC 203 Section: .text 204 Value: 0x0000000000000260 205 Size: 0x000000000000000C 206 Binding: STB_GLOBAL 207 - Name: debug_frame3 208 Type: STT_FUNC 209 Section: .text 210 Value: 0x0000000000000270 211 Size: 0x000000000000000C 212 Binding: STB_GLOBAL 213 - Name: debug_frame4 214 Type: STT_FUNC 215 Section: .text 216 Value: 0x0000000000000280 217 Size: 0x000000000000000C 218 Binding: STB_GLOBAL 219 ... 220 )"); 221 ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded()); 222 223 auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec()); 224 SectionList *list = module_sp->GetSectionList(); 225 ASSERT_NE(nullptr, list); 226 227 auto section_sp = list->FindSectionByType(type == DWARFCallFrameInfo::EH 228 ? eSectionTypeEHFrame 229 : eSectionTypeDWARFDebugFrame, 230 false); 231 ASSERT_NE(nullptr, section_sp); 232 233 DWARFCallFrameInfo cfi(*module_sp->GetObjectFile(), section_sp, type); 234 235 const Symbol *sym = module_sp->FindFirstSymbolWithNameAndType( 236 ConstString(symbol), eSymbolTypeAny); 237 ASSERT_NE(nullptr, sym); 238 239 UnwindPlan plan(eRegisterKindGeneric); 240 ASSERT_TRUE(cfi.GetUnwindPlan(sym->GetAddress(), plan)); 241 ASSERT_EQ(3, plan.GetRowCount()); 242 EXPECT_EQ(GetExpectedRow0(), *plan.GetRowAtIndex(0)); 243 EXPECT_EQ(GetExpectedRow1(), *plan.GetRowAtIndex(1)); 244 EXPECT_EQ(GetExpectedRow2(), *plan.GetRowAtIndex(2)); 245 } 246 247 TEST_F(DWARFCallFrameInfoTest, Basic_dwarf3) { 248 TestBasic(DWARFCallFrameInfo::DWARF, "debug_frame3"); 249 } 250 251 TEST_F(DWARFCallFrameInfoTest, Basic_dwarf4) { 252 TestBasic(DWARFCallFrameInfo::DWARF, "debug_frame4"); 253 } 254 255 TEST_F(DWARFCallFrameInfoTest, Basic_eh) { 256 TestBasic(DWARFCallFrameInfo::EH, "eh_frame"); 257 } 258