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