Index: source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp =================================================================== --- source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -1571,6 +1571,9 @@ line_table->AppendLineEntryToSequence( sequence.get(), prev_addr + prev_length, prev_line, 0, prev_source_idx, false, false, false, false, true); + + line_table->InsertSequence(sequence.release()); + sequence.reset(line_table->CreateLineSequenceContainer()); } if (ShouldAddLine(match_line, lno, length)) { Index: unittests/SymbolFile/PDB/CMakeLists.txt =================================================================== --- unittests/SymbolFile/PDB/CMakeLists.txt +++ unittests/SymbolFile/PDB/CMakeLists.txt @@ -17,6 +17,10 @@ set(test_inputs test-pdb.exe test-pdb.pdb + test-pdb-function-level-linking.exe + test-pdb-function-level-linking.pdb + test-pdb-splitted-function.exe + test-pdb-splitted-function.pdb test-pdb-types.exe test-pdb-types.pdb) Index: unittests/SymbolFile/PDB/Inputs/test-pdb-function-level-linking.cpp =================================================================== --- /dev/null +++ unittests/SymbolFile/PDB/Inputs/test-pdb-function-level-linking.cpp @@ -0,0 +1,17 @@ +// Compile with "cl /c /ZI /sdl /EHsc /MTd /permissive- +// test-pdb-function-level-linking.cpp" +// Link with "link /debug:full test-pdb-function-level-linking.obj" + +#include +#include + +std::string foo() +{ + return "Hello!"; +} + +int main() +{ + auto x = foo(); + return 0; +} Index: unittests/SymbolFile/PDB/Inputs/test-pdb-splitted-function.cpp =================================================================== --- /dev/null +++ unittests/SymbolFile/PDB/Inputs/test-pdb-splitted-function.cpp @@ -0,0 +1,27 @@ +// Compile with "cl /c /Zi /GL /O2 /EHsc /MTd test-pdb-splitted-function.cpp" +// Link with "link /debug:full /LTCG /GENPROFILE +// test-pdb-splitted-function.obj" +// Run several times +// Link with "link /debug:full /LTCG /USEPROFILE +// test-pdb-splitted-function.obj" + +#include +#include + +int main() +{ + auto b = false; + for (auto i = 1; i <= 1024; i++) + { + if (b) + { + std::cout << "Unreachable code" << std::endl; + auto x = std::sin(i); + return x; + } + + b = (i % 2 + (i - 1) % 2) != 1; + } + + return 0; +} Index: unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp =================================================================== --- unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp +++ unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp @@ -56,6 +56,10 @@ SymbolFilePDB::Initialize(); m_pdb_test_exe = GetInputFilePath("test-pdb.exe"); + m_function_level_linking_test_exe = + GetInputFilePath("test-pdb-function-level-linking.exe"); + m_splitted_function_test_exe = + GetInputFilePath("test-pdb-splitted-function.exe"); m_types_test_exe = GetInputFilePath("test-pdb-types.exe"); } @@ -73,6 +77,8 @@ protected: std::string m_pdb_test_exe; + std::string m_function_level_linking_test_exe; + std::string m_splitted_function_test_exe; std::string m_types_test_exe; bool FileSpecMatchesAsBaseOrFull(const FileSpec &left, @@ -354,6 +360,56 @@ VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090); } +void TestLineTableConsistency(llvm::StringRef exe_path, llvm::StringRef source_name) +{ + // All line entries of compile unit's line table must be consistent + // even if compiled sources are not continuous in the binary file. + FileSpec fspec(exe_path, false); + ArchSpec aspec("i686-pc-windows"); + lldb::ModuleSP module = std::make_shared(fspec, aspec); + SymbolVendor *plugin = module->GetSymbolVendor(); + SymbolFile *symfile = plugin->GetSymbolFile(); + FileSpec source_file(source_name, false); + uint32_t scope = lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry; + SymbolContextList sc_list; + uint32_t count = + symfile->ResolveSymbolContext(source_file, 0, true, scope, sc_list); + EXPECT_EQ(1u, count); + + SymbolContext sc; + EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc)); + + LineTable *lt = sc.comp_unit->GetLineTable(); + EXPECT_NE(nullptr, lt); + + count = lt->GetSize(); + EXPECT_LT(0u, count); + + LineEntry le; + EXPECT_TRUE(lt->GetLineEntryAtIndex(0, le)); + for (int i = 1; i < count; i++) + { + lldb::addr_t curr_end = + le.range.GetBaseAddress().GetFileAddress() + le.range.GetByteSize(); + + EXPECT_TRUE(lt->GetLineEntryAtIndex(i, le)); + + EXPECT_LE(curr_end, le.range.GetBaseAddress().GetFileAddress()); + } +} + +TEST_F(SymbolFilePDBTests, TestFunctionLevelLinking) { + TestLineTableConsistency( + m_function_level_linking_test_exe, + "test-pdb-function-level-linking.cpp"); +} + +TEST_F(SymbolFilePDBTests, TestSplittedFunction) { + TestLineTableConsistency( + m_splitted_function_test_exe, + "test-pdb-splitted-function.cpp"); +} + TEST_F(SymbolFilePDBTests, TestSimpleClassTypes) { FileSpec fspec(m_types_test_exe.c_str(), false); ArchSpec aspec("i686-pc-windows");