|
|
@@ -0,0 +1,344 @@ |
|
|
//===-- PythonDataObjectsTests.cpp ------------------------------*- C++ -*-===// |
|
|
// |
|
|
// The LLVM Compiler Infrastructure |
|
|
// |
|
|
// This file is distributed under the University of Illinois Open Source |
|
|
// License. See LICENSE.TXT for details. |
|
|
// |
|
|
//===----------------------------------------------------------------------===// |
|
|
|
|
|
#include "gtest/gtest.h" |
|
|
|
|
|
#include "llvm/ADT/STLExtras.h" |
|
|
#include "llvm/Config/config.h" |
|
|
#include "llvm/Support/FileSystem.h" |
|
|
#include "llvm/Support/Path.h" |
|
|
|
|
|
#include "lldb/Core/Address.h" |
|
|
#include "lldb/Core/ArchSpec.h" |
|
|
#include "lldb/Core/Module.h" |
|
|
#include "lldb/Core/ModuleSpec.h" |
|
|
#include "lldb/Host/FileSpec.h" |
|
|
#include "lldb/Host/HostInfo.h" |
|
|
#include "lldb/Symbol/CompileUnit.h" |
|
|
#include "lldb/Symbol/LineTable.h" |
|
|
#include "lldb/Symbol/SymbolVendor.h" |
|
|
|
|
|
#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" |
|
|
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" |
|
|
#include "Plugins/SymbolFile/PDB/SymbolFilePDB.h" |
|
|
|
|
|
#if defined(_MSC_VER) |
|
|
#include <objbase.h> |
|
|
#endif |
|
|
|
|
|
extern const char *TestMainArgv0; |
|
|
|
|
|
using namespace lldb_private; |
|
|
|
|
|
class SymbolFilePDBTests : public testing::Test |
|
|
{ |
|
|
public: |
|
|
void |
|
|
SetUp() override |
|
|
{ |
|
|
#if defined(_MSC_VER) |
|
|
::CoInitializeEx(nullptr, COINIT_MULTITHREADED); |
|
|
#endif |
|
|
|
|
|
HostInfoBase::Initialize(); |
|
|
ObjectFilePECOFF::Initialize(); |
|
|
SymbolFileDWARF::Initialize(); |
|
|
SymbolFilePDB::Initialize(); |
|
|
|
|
|
llvm::StringRef exe_folder = llvm::sys::path::parent_path(TestMainArgv0); |
|
|
llvm::SmallString<128> inputs_folder = exe_folder; |
|
|
llvm::sys::path::append(inputs_folder, "Inputs"); |
|
|
|
|
|
m_pdb_test_exe = inputs_folder; |
|
|
m_dwarf_test_exe = inputs_folder; |
|
|
llvm::sys::path::append(m_pdb_test_exe, "test-pdb.exe"); |
|
|
llvm::sys::path::append(m_dwarf_test_exe, "test-dwarf.exe"); |
|
|
} |
|
|
|
|
|
void |
|
|
TearDown() override |
|
|
{ |
|
|
#if defined(_MSC_VER) |
|
|
::CoUninitialize(); |
|
|
#endif |
|
|
SymbolFilePDB::Terminate(); |
|
|
SymbolFileDWARF::Terminate(); |
|
|
ObjectFilePECOFF::Terminate(); |
|
|
} |
|
|
|
|
|
protected: |
|
|
llvm::SmallString<128> m_pdb_test_exe; |
|
|
llvm::SmallString<128> m_dwarf_test_exe; |
|
|
|
|
|
bool |
|
|
FileSpecMatchesAsBaseOrFull(const FileSpec &left, const FileSpec &right) const |
|
|
{ |
|
|
// If the filenames don't match, the paths can't be equal |
|
|
if (!left.FileEquals(right)) |
|
|
return false; |
|
|
// If BOTH have a directory, also compare the directories. |
|
|
if (left.GetDirectory() && right.GetDirectory()) |
|
|
return left.DirectoryEquals(right); |
|
|
|
|
|
// If one has a directory but not the other, they match. |
|
|
return true; |
|
|
} |
|
|
|
|
|
void |
|
|
VerifyLineEntry(lldb::ModuleSP module, const SymbolContext &sc, const FileSpec &spec, LineTable <, uint32_t line, |
|
|
lldb::addr_t addr) |
|
|
{ |
|
|
LineEntry entry; |
|
|
Address address; |
|
|
EXPECT_TRUE(module->ResolveFileAddress(addr, address)); |
|
|
|
|
|
EXPECT_TRUE(lt.FindLineEntryByAddress(address, entry)); |
|
|
EXPECT_EQ(line, entry.line); |
|
|
EXPECT_EQ(address, entry.range.GetBaseAddress()); |
|
|
|
|
|
EXPECT_TRUE(FileSpecMatchesAsBaseOrFull(spec, entry.file)); |
|
|
} |
|
|
|
|
|
bool |
|
|
ContainsCompileUnit(const SymbolContextList &sc_list, const FileSpec &spec) const |
|
|
{ |
|
|
for (int i = 0; i < sc_list.GetSize(); ++i) |
|
|
{ |
|
|
const SymbolContext &sc = sc_list[i]; |
|
|
if (FileSpecMatchesAsBaseOrFull(*sc.comp_unit, spec)) |
|
|
return true; |
|
|
} |
|
|
return false; |
|
|
} |
|
|
}; |
|
|
|
|
|
#if defined(HAVE_DIA_SDK) |
|
|
#define REQUIRES_DIA_SDK(TestName) TestName |
|
|
#else |
|
|
#define REQUIRES_DIA_SDK(TestName) DISABLED_##TestName |
|
|
#endif |
|
|
|
|
|
TEST_F(SymbolFilePDBTests, TestAbilitiesForDWARF) |
|
|
{ |
|
|
// Test that when we have Dwarf debug info, SymbolFileDWARF is used. |
|
|
FileSpec fspec(m_dwarf_test_exe.c_str(), false); |
|
|
ArchSpec aspec("i686-pc-windows"); |
|
|
lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); |
|
|
|
|
|
SymbolVendor *plugin = module->GetSymbolVendor(); |
|
|
EXPECT_NE(nullptr, plugin); |
|
|
SymbolFile *symfile = plugin->GetSymbolFile(); |
|
|
EXPECT_NE(nullptr, symfile); |
|
|
EXPECT_EQ(symfile->GetPluginName(), SymbolFileDWARF::GetPluginNameStatic()); |
|
|
|
|
|
uint32_t expected_abilities = SymbolFile::kAllAbilities; |
|
|
EXPECT_EQ(expected_abilities, symfile->CalculateAbilities()); |
|
|
} |
|
|
|
|
|
TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestAbilitiesForPDB)) |
|
|
{ |
|
|
// Test that when we have PDB debug info, SymbolFilePDB is used. |
|
|
FileSpec fspec(m_pdb_test_exe.c_str(), false); |
|
|
ArchSpec aspec("i686-pc-windows"); |
|
|
lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); |
|
|
|
|
|
SymbolVendor *plugin = module->GetSymbolVendor(); |
|
|
EXPECT_NE(nullptr, plugin); |
|
|
SymbolFile *symfile = plugin->GetSymbolFile(); |
|
|
EXPECT_NE(nullptr, symfile); |
|
|
EXPECT_EQ(symfile->GetPluginName(), SymbolFilePDB::GetPluginNameStatic()); |
|
|
|
|
|
uint32_t expected_abilities = SymbolFile::CompileUnits | SymbolFile::LineTables; |
|
|
EXPECT_EQ(expected_abilities, symfile->CalculateAbilities()); |
|
|
} |
|
|
|
|
|
TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestResolveSymbolContextBasename)) |
|
|
{ |
|
|
// Test that attempting to call ResolveSymbolContext with only a basename finds all full paths |
|
|
// with the same basename |
|
|
FileSpec fspec(m_pdb_test_exe.c_str(), false); |
|
|
ArchSpec aspec("i686-pc-windows"); |
|
|
lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); |
|
|
|
|
|
SymbolVendor *plugin = module->GetSymbolVendor(); |
|
|
EXPECT_NE(nullptr, plugin); |
|
|
SymbolFile *symfile = plugin->GetSymbolFile(); |
|
|
|
|
|
FileSpec header_spec("test-pdb.cpp", false); |
|
|
SymbolContextList sc_list; |
|
|
uint32_t result_count = symfile->ResolveSymbolContext(header_spec, 0, false, lldb::eSymbolContextCompUnit, sc_list); |
|
|
EXPECT_EQ(1, result_count); |
|
|
EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec)); |
|
|
} |
|
|
|
|
|
TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestResolveSymbolContextFullPath)) |
|
|
{ |
|
|
// Test that attempting to call ResolveSymbolContext with a full path only finds the one source |
|
|
// file that matches the full path. |
|
|
FileSpec fspec(m_pdb_test_exe.c_str(), false); |
|
|
ArchSpec aspec("i686-pc-windows"); |
|
|
lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); |
|
|
|
|
|
SymbolVendor *plugin = module->GetSymbolVendor(); |
|
|
EXPECT_NE(nullptr, plugin); |
|
|
SymbolFile *symfile = plugin->GetSymbolFile(); |
|
|
|
|
|
FileSpec header_spec(R"spec(D:\src\llvm\tools\lldb\unittests\SymbolFile\PDB\Inputs\test-pdb.cpp)spec", false); |
|
|
SymbolContextList sc_list; |
|
|
uint32_t result_count = symfile->ResolveSymbolContext(header_spec, 0, false, lldb::eSymbolContextCompUnit, sc_list); |
|
|
EXPECT_GE(1, result_count); |
|
|
EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec)); |
|
|
} |
|
|
|
|
|
TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestLookupOfHeaderFileWithInlines)) |
|
|
{ |
|
|
// Test that when looking up a header file via ResolveSymbolContext (i.e. a file that was not by itself |
|
|
// compiled, but only contributes to the combined code of other source files), a SymbolContext is returned |
|
|
// for each compiland which has line contributions from the requested header. |
|
|
FileSpec fspec(m_pdb_test_exe.c_str(), false); |
|
|
ArchSpec aspec("i686-pc-windows"); |
|
|
lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); |
|
|
|
|
|
SymbolVendor *plugin = module->GetSymbolVendor(); |
|
|
EXPECT_NE(nullptr, plugin); |
|
|
SymbolFile *symfile = plugin->GetSymbolFile(); |
|
|
|
|
|
FileSpec header_specs[] = {FileSpec("test-pdb.h", false), FileSpec("test-pdb-nested.h", false)}; |
|
|
FileSpec main_cpp_spec("test-pdb.cpp", false); |
|
|
FileSpec alt_cpp_spec("test-pdb-alt.cpp", false); |
|
|
for (const auto &hspec : header_specs) |
|
|
{ |
|
|
SymbolContextList sc_list; |
|
|
uint32_t result_count = symfile->ResolveSymbolContext(hspec, 0, true, lldb::eSymbolContextCompUnit, sc_list); |
|
|
EXPECT_EQ(2, result_count); |
|
|
EXPECT_TRUE(ContainsCompileUnit(sc_list, main_cpp_spec)); |
|
|
EXPECT_TRUE(ContainsCompileUnit(sc_list, alt_cpp_spec)); |
|
|
} |
|
|
} |
|
|
|
|
|
TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestLookupOfHeaderFileWithNoInlines)) |
|
|
{ |
|
|
// Test that when looking up a header file via ResolveSymbolContext (i.e. a file that was not by itself |
|
|
// compiled, but only contributes to the combined code of other source files), that if check_inlines |
|
|
// is false, no SymbolContexts are returned. |
|
|
FileSpec fspec(m_pdb_test_exe.c_str(), false); |
|
|
ArchSpec aspec("i686-pc-windows"); |
|
|
lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); |
|
|
|
|
|
SymbolVendor *plugin = module->GetSymbolVendor(); |
|
|
EXPECT_NE(nullptr, plugin); |
|
|
SymbolFile *symfile = plugin->GetSymbolFile(); |
|
|
|
|
|
FileSpec header_specs[] = {FileSpec("test-pdb.h", false), FileSpec("test-pdb-nested.h", false)}; |
|
|
for (const auto &hspec : header_specs) |
|
|
{ |
|
|
SymbolContextList sc_list; |
|
|
uint32_t result_count = symfile->ResolveSymbolContext(hspec, 0, false, lldb::eSymbolContextCompUnit, sc_list); |
|
|
EXPECT_EQ(0, result_count); |
|
|
} |
|
|
} |
|
|
|
|
|
TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestLineTablesMatchAll)) |
|
|
{ |
|
|
// Test that when calling ResolveSymbolContext with a line number of 0, all line entries from |
|
|
// the specified files are returned. |
|
|
FileSpec fspec(m_pdb_test_exe.c_str(), false); |
|
|
ArchSpec aspec("i686-pc-windows"); |
|
|
lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); |
|
|
|
|
|
SymbolVendor *plugin = module->GetSymbolVendor(); |
|
|
SymbolFile *symfile = plugin->GetSymbolFile(); |
|
|
|
|
|
FileSpec source_file("test-pdb.cpp", false); |
|
|
FileSpec header1("test-pdb.h", false); |
|
|
FileSpec header2("test-pdb-nested.h", false); |
|
|
uint32_t cus = symfile->GetNumCompileUnits(); |
|
|
EXPECT_EQ(2, cus); |
|
|
|
|
|
SymbolContextList sc_list; |
|
|
uint32_t scope = lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry; |
|
|
|
|
|
uint32_t count = symfile->ResolveSymbolContext(source_file, 0, true, scope, sc_list); |
|
|
EXPECT_EQ(1, count); |
|
|
SymbolContext sc; |
|
|
EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc)); |
|
|
|
|
|
LineTable *lt = sc.comp_unit->GetLineTable(); |
|
|
EXPECT_NE(nullptr, lt); |
|
|
count = lt->GetSize(); |
|
|
// We expect one extra entry for termination (per function) |
|
|
EXPECT_EQ(16, count); |
|
|
|
|
|
VerifyLineEntry(module, sc, source_file, *lt, 7, 0x401040); |
|
|
VerifyLineEntry(module, sc, source_file, *lt, 8, 0x401043); |
|
|
VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045); |
|
|
|
|
|
VerifyLineEntry(module, sc, source_file, *lt, 13, 0x401050); |
|
|
VerifyLineEntry(module, sc, source_file, *lt, 14, 0x401054); |
|
|
VerifyLineEntry(module, sc, source_file, *lt, 15, 0x401070); |
|
|
|
|
|
VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090); |
|
|
VerifyLineEntry(module, sc, header1, *lt, 10, 0x401093); |
|
|
VerifyLineEntry(module, sc, header1, *lt, 11, 0x4010a2); |
|
|
|
|
|
VerifyLineEntry(module, sc, header2, *lt, 5, 0x401080); |
|
|
VerifyLineEntry(module, sc, header2, *lt, 6, 0x401083); |
|
|
VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089); |
|
|
} |
|
|
|
|
|
TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestLineTablesMatchSpecific)) |
|
|
{ |
|
|
// Test that when calling ResolveSymbolContext with a specific line number, only line entries |
|
|
// which match the requested line are returned. |
|
|
FileSpec fspec(m_pdb_test_exe.c_str(), false); |
|
|
ArchSpec aspec("i686-pc-windows"); |
|
|
lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); |
|
|
|
|
|
SymbolVendor *plugin = module->GetSymbolVendor(); |
|
|
SymbolFile *symfile = plugin->GetSymbolFile(); |
|
|
|
|
|
FileSpec source_file("test-pdb.cpp", false); |
|
|
FileSpec header1("test-pdb.h", false); |
|
|
FileSpec header2("test-pdb-nested.h", false); |
|
|
uint32_t cus = symfile->GetNumCompileUnits(); |
|
|
EXPECT_EQ(2, cus); |
|
|
|
|
|
SymbolContextList sc_list; |
|
|
uint32_t scope = lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry; |
|
|
|
|
|
// First test with line 7, and verify that only line 7 entries are added. |
|
|
uint32_t count = symfile->ResolveSymbolContext(source_file, 7, true, scope, sc_list); |
|
|
EXPECT_EQ(1, count); |
|
|
SymbolContext sc; |
|
|
EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc)); |
|
|
|
|
|
LineTable *lt = sc.comp_unit->GetLineTable(); |
|
|
EXPECT_NE(nullptr, lt); |
|
|
count = lt->GetSize(); |
|
|
// We expect one extra entry for termination |
|
|
EXPECT_EQ(3, count); |
|
|
|
|
|
VerifyLineEntry(module, sc, source_file, *lt, 7, 0x401040); |
|
|
VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089); |
|
|
|
|
|
sc_list.Clear(); |
|
|
// Then test with line 9, and verify that only line 9 entries are added. |
|
|
count = symfile->ResolveSymbolContext(source_file, 9, true, scope, sc_list); |
|
|
EXPECT_EQ(1, count); |
|
|
EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc)); |
|
|
|
|
|
lt = sc.comp_unit->GetLineTable(); |
|
|
EXPECT_NE(nullptr, lt); |
|
|
count = lt->GetSize(); |
|
|
// We expect one extra entry for termination |
|
|
EXPECT_EQ(3, count); |
|
|
|
|
|
VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045); |
|
|
VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090); |
|
|
} |