1 //===-- PythonDataObjectsTests.cpp ------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "gtest/gtest.h" 11 12 #include "llvm/ADT/STLExtras.h" 13 #include "llvm/Config/config.h" 14 #include "llvm/Support/FileSystem.h" 15 #include "llvm/Support/Path.h" 16 17 #include "lldb/Core/Address.h" 18 #include "lldb/Core/ArchSpec.h" 19 #include "lldb/Core/Module.h" 20 #include "lldb/Core/ModuleSpec.h" 21 #include "lldb/Host/FileSpec.h" 22 #include "lldb/Host/HostInfo.h" 23 #include "lldb/Symbol/CompileUnit.h" 24 #include "lldb/Symbol/LineTable.h" 25 #include "lldb/Symbol/SymbolVendor.h" 26 27 #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" 28 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" 29 #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h" 30 31 #if defined(_MSC_VER) 32 #include <objbase.h> 33 #endif 34 35 extern const char *TestMainArgv0; 36 37 using namespace lldb_private; 38 39 class SymbolFilePDBTests : public testing::Test 40 { 41 public: 42 void 43 SetUp() override 44 { 45 #if defined(_MSC_VER) 46 ::CoInitializeEx(nullptr, COINIT_MULTITHREADED); 47 #endif 48 49 HostInfoBase::Initialize(); 50 ObjectFilePECOFF::Initialize(); 51 SymbolFileDWARF::Initialize(); 52 SymbolFilePDB::Initialize(); 53 54 llvm::StringRef exe_folder = llvm::sys::path::parent_path(TestMainArgv0); 55 llvm::SmallString<128> inputs_folder = exe_folder; 56 llvm::sys::path::append(inputs_folder, "Inputs"); 57 58 m_pdb_test_exe = inputs_folder; 59 m_dwarf_test_exe = inputs_folder; 60 llvm::sys::path::append(m_pdb_test_exe, "test-pdb.exe"); 61 llvm::sys::path::append(m_dwarf_test_exe, "test-dwarf.exe"); 62 } 63 64 void 65 TearDown() override 66 { 67 #if defined(_MSC_VER) 68 ::CoUninitialize(); 69 #endif 70 SymbolFilePDB::Terminate(); 71 SymbolFileDWARF::Terminate(); 72 ObjectFilePECOFF::Terminate(); 73 } 74 75 protected: 76 llvm::SmallString<128> m_pdb_test_exe; 77 llvm::SmallString<128> m_dwarf_test_exe; 78 79 bool 80 FileSpecMatchesAsBaseOrFull(const FileSpec &left, const FileSpec &right) const 81 { 82 // If the filenames don't match, the paths can't be equal 83 if (!left.FileEquals(right)) 84 return false; 85 // If BOTH have a directory, also compare the directories. 86 if (left.GetDirectory() && right.GetDirectory()) 87 return left.DirectoryEquals(right); 88 89 // If one has a directory but not the other, they match. 90 return true; 91 } 92 93 void 94 VerifyLineEntry(lldb::ModuleSP module, const SymbolContext &sc, const FileSpec &spec, LineTable <, uint32_t line, 95 lldb::addr_t addr) 96 { 97 LineEntry entry; 98 Address address; 99 EXPECT_TRUE(module->ResolveFileAddress(addr, address)); 100 101 EXPECT_TRUE(lt.FindLineEntryByAddress(address, entry)); 102 EXPECT_EQ(line, entry.line); 103 EXPECT_EQ(address, entry.range.GetBaseAddress()); 104 105 EXPECT_TRUE(FileSpecMatchesAsBaseOrFull(spec, entry.file)); 106 } 107 108 bool 109 ContainsCompileUnit(const SymbolContextList &sc_list, const FileSpec &spec) const 110 { 111 for (size_t i = 0; i < sc_list.GetSize(); ++i) 112 { 113 const SymbolContext &sc = sc_list[i]; 114 if (FileSpecMatchesAsBaseOrFull(*sc.comp_unit, spec)) 115 return true; 116 } 117 return false; 118 } 119 }; 120 121 #if defined(HAVE_DIA_SDK) 122 #define REQUIRES_DIA_SDK(TestName) TestName 123 #else 124 #define REQUIRES_DIA_SDK(TestName) DISABLED_##TestName 125 #endif 126 127 TEST_F(SymbolFilePDBTests, TestAbilitiesForDWARF) 128 { 129 // Test that when we have Dwarf debug info, SymbolFileDWARF is used. 130 FileSpec fspec(m_dwarf_test_exe.c_str(), false); 131 ArchSpec aspec("i686-pc-windows"); 132 lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); 133 134 SymbolVendor *plugin = module->GetSymbolVendor(); 135 EXPECT_NE(nullptr, plugin); 136 SymbolFile *symfile = plugin->GetSymbolFile(); 137 EXPECT_NE(nullptr, symfile); 138 EXPECT_EQ(symfile->GetPluginName(), SymbolFileDWARF::GetPluginNameStatic()); 139 140 uint32_t expected_abilities = SymbolFile::kAllAbilities; 141 EXPECT_EQ(expected_abilities, symfile->CalculateAbilities()); 142 } 143 144 TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestAbilitiesForPDB)) 145 { 146 // Test that when we have PDB debug info, SymbolFilePDB is used. 147 FileSpec fspec(m_pdb_test_exe.c_str(), false); 148 ArchSpec aspec("i686-pc-windows"); 149 lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); 150 151 SymbolVendor *plugin = module->GetSymbolVendor(); 152 EXPECT_NE(nullptr, plugin); 153 SymbolFile *symfile = plugin->GetSymbolFile(); 154 EXPECT_NE(nullptr, symfile); 155 EXPECT_EQ(symfile->GetPluginName(), SymbolFilePDB::GetPluginNameStatic()); 156 157 uint32_t expected_abilities = SymbolFile::CompileUnits | SymbolFile::LineTables; 158 EXPECT_EQ(expected_abilities, symfile->CalculateAbilities()); 159 } 160 161 TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestResolveSymbolContextBasename)) 162 { 163 // Test that attempting to call ResolveSymbolContext with only a basename finds all full paths 164 // with the same basename 165 FileSpec fspec(m_pdb_test_exe.c_str(), false); 166 ArchSpec aspec("i686-pc-windows"); 167 lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); 168 169 SymbolVendor *plugin = module->GetSymbolVendor(); 170 EXPECT_NE(nullptr, plugin); 171 SymbolFile *symfile = plugin->GetSymbolFile(); 172 173 FileSpec header_spec("test-pdb.cpp", false); 174 SymbolContextList sc_list; 175 uint32_t result_count = symfile->ResolveSymbolContext(header_spec, 0, false, lldb::eSymbolContextCompUnit, sc_list); 176 EXPECT_EQ(1u, result_count); 177 EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec)); 178 } 179 180 TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestResolveSymbolContextFullPath)) 181 { 182 // Test that attempting to call ResolveSymbolContext with a full path only finds the one source 183 // file that matches the full path. 184 FileSpec fspec(m_pdb_test_exe.c_str(), false); 185 ArchSpec aspec("i686-pc-windows"); 186 lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); 187 188 SymbolVendor *plugin = module->GetSymbolVendor(); 189 EXPECT_NE(nullptr, plugin); 190 SymbolFile *symfile = plugin->GetSymbolFile(); 191 192 FileSpec header_spec(R"spec(D:\src\llvm\tools\lldb\unittests\SymbolFile\PDB\Inputs\test-pdb.cpp)spec", false); 193 SymbolContextList sc_list; 194 uint32_t result_count = symfile->ResolveSymbolContext(header_spec, 0, false, lldb::eSymbolContextCompUnit, sc_list); 195 EXPECT_GE(1u, result_count); 196 EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec)); 197 } 198 199 TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestLookupOfHeaderFileWithInlines)) 200 { 201 // Test that when looking up a header file via ResolveSymbolContext (i.e. a file that was not by itself 202 // compiled, but only contributes to the combined code of other source files), a SymbolContext is returned 203 // for each compiland which has line contributions from the requested header. 204 FileSpec fspec(m_pdb_test_exe.c_str(), false); 205 ArchSpec aspec("i686-pc-windows"); 206 lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); 207 208 SymbolVendor *plugin = module->GetSymbolVendor(); 209 EXPECT_NE(nullptr, plugin); 210 SymbolFile *symfile = plugin->GetSymbolFile(); 211 212 FileSpec header_specs[] = {FileSpec("test-pdb.h", false), FileSpec("test-pdb-nested.h", false)}; 213 FileSpec main_cpp_spec("test-pdb.cpp", false); 214 FileSpec alt_cpp_spec("test-pdb-alt.cpp", false); 215 for (const auto &hspec : header_specs) 216 { 217 SymbolContextList sc_list; 218 uint32_t result_count = symfile->ResolveSymbolContext(hspec, 0, true, lldb::eSymbolContextCompUnit, sc_list); 219 EXPECT_EQ(2u, result_count); 220 EXPECT_TRUE(ContainsCompileUnit(sc_list, main_cpp_spec)); 221 EXPECT_TRUE(ContainsCompileUnit(sc_list, alt_cpp_spec)); 222 } 223 } 224 225 TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestLookupOfHeaderFileWithNoInlines)) 226 { 227 // Test that when looking up a header file via ResolveSymbolContext (i.e. a file that was not by itself 228 // compiled, but only contributes to the combined code of other source files), that if check_inlines 229 // is false, no SymbolContexts are returned. 230 FileSpec fspec(m_pdb_test_exe.c_str(), false); 231 ArchSpec aspec("i686-pc-windows"); 232 lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); 233 234 SymbolVendor *plugin = module->GetSymbolVendor(); 235 EXPECT_NE(nullptr, plugin); 236 SymbolFile *symfile = plugin->GetSymbolFile(); 237 238 FileSpec header_specs[] = {FileSpec("test-pdb.h", false), FileSpec("test-pdb-nested.h", false)}; 239 for (const auto &hspec : header_specs) 240 { 241 SymbolContextList sc_list; 242 uint32_t result_count = symfile->ResolveSymbolContext(hspec, 0, false, lldb::eSymbolContextCompUnit, sc_list); 243 EXPECT_EQ(0u, result_count); 244 } 245 } 246 247 TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestLineTablesMatchAll)) 248 { 249 // Test that when calling ResolveSymbolContext with a line number of 0, all line entries from 250 // the specified files are returned. 251 FileSpec fspec(m_pdb_test_exe.c_str(), false); 252 ArchSpec aspec("i686-pc-windows"); 253 lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); 254 255 SymbolVendor *plugin = module->GetSymbolVendor(); 256 SymbolFile *symfile = plugin->GetSymbolFile(); 257 258 FileSpec source_file("test-pdb.cpp", false); 259 FileSpec header1("test-pdb.h", false); 260 FileSpec header2("test-pdb-nested.h", false); 261 uint32_t cus = symfile->GetNumCompileUnits(); 262 EXPECT_EQ(2u, cus); 263 264 SymbolContextList sc_list; 265 uint32_t scope = lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry; 266 267 uint32_t count = symfile->ResolveSymbolContext(source_file, 0, true, scope, sc_list); 268 EXPECT_EQ(1u, count); 269 SymbolContext sc; 270 EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc)); 271 272 LineTable *lt = sc.comp_unit->GetLineTable(); 273 EXPECT_NE(nullptr, lt); 274 count = lt->GetSize(); 275 // We expect one extra entry for termination (per function) 276 EXPECT_EQ(16u, count); 277 278 VerifyLineEntry(module, sc, source_file, *lt, 7, 0x401040); 279 VerifyLineEntry(module, sc, source_file, *lt, 8, 0x401043); 280 VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045); 281 282 VerifyLineEntry(module, sc, source_file, *lt, 13, 0x401050); 283 VerifyLineEntry(module, sc, source_file, *lt, 14, 0x401054); 284 VerifyLineEntry(module, sc, source_file, *lt, 15, 0x401070); 285 286 VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090); 287 VerifyLineEntry(module, sc, header1, *lt, 10, 0x401093); 288 VerifyLineEntry(module, sc, header1, *lt, 11, 0x4010a2); 289 290 VerifyLineEntry(module, sc, header2, *lt, 5, 0x401080); 291 VerifyLineEntry(module, sc, header2, *lt, 6, 0x401083); 292 VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089); 293 } 294 295 TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestLineTablesMatchSpecific)) 296 { 297 // Test that when calling ResolveSymbolContext with a specific line number, only line entries 298 // which match the requested line are returned. 299 FileSpec fspec(m_pdb_test_exe.c_str(), false); 300 ArchSpec aspec("i686-pc-windows"); 301 lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); 302 303 SymbolVendor *plugin = module->GetSymbolVendor(); 304 SymbolFile *symfile = plugin->GetSymbolFile(); 305 306 FileSpec source_file("test-pdb.cpp", false); 307 FileSpec header1("test-pdb.h", false); 308 FileSpec header2("test-pdb-nested.h", false); 309 uint32_t cus = symfile->GetNumCompileUnits(); 310 EXPECT_EQ(2u, cus); 311 312 SymbolContextList sc_list; 313 uint32_t scope = lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry; 314 315 // First test with line 7, and verify that only line 7 entries are added. 316 uint32_t count = symfile->ResolveSymbolContext(source_file, 7, true, scope, sc_list); 317 EXPECT_EQ(1u, count); 318 SymbolContext sc; 319 EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc)); 320 321 LineTable *lt = sc.comp_unit->GetLineTable(); 322 EXPECT_NE(nullptr, lt); 323 count = lt->GetSize(); 324 // We expect one extra entry for termination 325 EXPECT_EQ(3u, count); 326 327 VerifyLineEntry(module, sc, source_file, *lt, 7, 0x401040); 328 VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089); 329 330 sc_list.Clear(); 331 // Then test with line 9, and verify that only line 9 entries are added. 332 count = symfile->ResolveSymbolContext(source_file, 9, true, scope, sc_list); 333 EXPECT_EQ(1u, count); 334 EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc)); 335 336 lt = sc.comp_unit->GetLineTable(); 337 EXPECT_NE(nullptr, lt); 338 count = lt->GetSize(); 339 // We expect one extra entry for termination 340 EXPECT_EQ(3u, count); 341 342 VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045); 343 VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090); 344 } 345