Index: lit/SymbolFile/PDB/Inputs/FunctionLevelLinkingTest.h =================================================================== --- /dev/null +++ lit/SymbolFile/PDB/Inputs/FunctionLevelLinkingTest.h @@ -0,0 +1,12 @@ +#ifndef FUNCTION_LEVEL_LINKING_TEST_H +#define FUNCTION_LEVEL_LINKING_TEST_H + +int bar() { + return 0; +} + +int baz() { + return 0; +} + +#endif Index: lit/SymbolFile/PDB/Inputs/FunctionLevelLinkingTest.cpp =================================================================== --- /dev/null +++ lit/SymbolFile/PDB/Inputs/FunctionLevelLinkingTest.cpp @@ -0,0 +1,9 @@ +#include "FunctionLevelLinkingTest.h" + +int foo() { + return 0; +} + +int main() { + return foo() + bar() + baz(); +} Index: lit/SymbolFile/PDB/Inputs/FunctionLevelLinkingTest.ord =================================================================== --- /dev/null +++ lit/SymbolFile/PDB/Inputs/FunctionLevelLinkingTest.ord @@ -0,0 +1,4 @@ +?foo@@YAHXZ +?bar@@YAHXZ +main +?baz@@YAHXZ Index: lit/SymbolFile/PDB/function-level-linking.test =================================================================== --- /dev/null +++ lit/SymbolFile/PDB/function-level-linking.test @@ -0,0 +1,4 @@ +REQUIRES: windows, lld +RUN: clang-cl /c /Zi /Gy %S/Inputs/FunctionLevelLinkingTest.cpp /o %t.obj +RUN: lld-link /debug:full /nodefaultlib /entry:main /order:@%S/Inputs/FunctionLevelLinkingTest.ord %t.obj /out:%t.exe +RUN: lldb-test symbols -verify %t.exe 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: tools/lldb-test/lldb-test.cpp =================================================================== --- tools/lldb-test/lldb-test.cpp +++ tools/lldb-test/lldb-test.cpp @@ -21,6 +21,8 @@ #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ClangASTImporter.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/TypeList.h" #include "lldb/Symbol/VariableList.h" @@ -143,6 +145,9 @@ return Result; } +static cl::opt Verify("verify", cl::desc("Verify symbol information."), + cl::sub(SymbolsSubcommand)); + static Expected getDeclContext(SymbolVendor &Vendor); static Error findFunctions(lldb_private::Module &Module); @@ -150,6 +155,7 @@ static Error findTypes(lldb_private::Module &Module); static Error findVariables(lldb_private::Module &Module); static Error dumpModule(lldb_private::Module &Module); +static Error verify(lldb_private::Module &Module); static int dumpSymbols(Debugger &Dbg); } @@ -412,7 +418,75 @@ return Error::success(); } +Error opts::symbols::verify(lldb_private::Module &Module) { + SymbolVendor *plugin = Module.GetSymbolVendor(); + if (!plugin) + return make_error("Can't get a symbol vendor.", + inconvertibleErrorCode()); + + SymbolFile *symfile = plugin->GetSymbolFile(); + if (!symfile) + return make_error("Can't get a symbol file.", + inconvertibleErrorCode()); + + uint32_t comp_units_count = symfile->GetNumCompileUnits(); + + outs() << "Found " << comp_units_count << " compile units.\n"; + + for (uint32_t i = 0; i < comp_units_count; i++) { + lldb::CompUnitSP comp_unit = symfile->ParseCompileUnitAtIndex(i); + if (!comp_unit) + return make_error("Can't get a compile unit.", + inconvertibleErrorCode()); + + outs() << "Processing '" << comp_unit->GetFilename().AsCString() << + "' compile unit.\n"; + + LineTable *lt = comp_unit->GetLineTable(); + if (!lt) + return make_error( + "Can't get a line table of a compile unit.", + inconvertibleErrorCode()); + + uint32_t count = lt->GetSize(); + + outs() << "The line table contains " << count << " entries.\n"; + + if (count == 0) + continue; + + LineEntry le; + if (!lt->GetLineEntryAtIndex(0, le)) + return make_error( + "Can't get a line entry of a compile unit", + inconvertibleErrorCode()); + + for (uint32_t i = 1; i < count; i++) { + lldb::addr_t curr_end = + le.range.GetBaseAddress().GetFileAddress() + le.range.GetByteSize(); + + if (!lt->GetLineEntryAtIndex(i, le)) + return make_error( + "Can't get a line entry of a compile unit", + inconvertibleErrorCode()); + + if (curr_end > le.range.GetBaseAddress().GetFileAddress()) + return make_error( + "Line table of a compile unit is inconsistent", + inconvertibleErrorCode()); + } + } + + outs() << "The symbol information is verified.\n"; + + return Error::success(); +} + int opts::symbols::dumpSymbols(Debugger &Dbg) { + if (Verify && Find != FindType::None) { + WithColor::error() << "Cannot both search and verify symbol information.\n"; + return 1; + } if (Find != FindType::None && Regex && !Context.empty()) { WithColor::error() << "Cannot search using both regular expressions and context.\n"; @@ -435,23 +509,26 @@ } Error (*Action)(lldb_private::Module &); - switch (Find) { - case FindType::Function: - Action = findFunctions; - break; - case FindType::Namespace: - Action = findNamespaces; - break; - case FindType::Type: - Action = findTypes; - break; - case FindType::Variable: - Action = findVariables; - break; - case FindType::None: - Action = dumpModule; - break; - } + if (!Verify) { + switch (Find) { + case FindType::Function: + Action = findFunctions; + break; + case FindType::Namespace: + Action = findNamespaces; + break; + case FindType::Type: + Action = findTypes; + break; + case FindType::Variable: + Action = findVariables; + break; + case FindType::None: + Action = dumpModule; + break; + } + } else + Action = verify; int HadErrors = 0; for (const auto &File : InputFilenames) {