Index: include/lldb/Core/FileSpecList.h =================================================================== --- include/lldb/Core/FileSpecList.h +++ include/lldb/Core/FileSpecList.h @@ -48,6 +48,9 @@ //------------------------------------------------------------------ FileSpecList(const FileSpecList &rhs); + /// Initialize this object from a vector of FileSpecs + FileSpecList(std::vector &&rhs) : m_files(std::move(rhs)) {} + //------------------------------------------------------------------ /// Destructor. //------------------------------------------------------------------ @@ -64,7 +67,11 @@ /// @return /// A const reference to this object. //------------------------------------------------------------------ - const FileSpecList &operator=(const FileSpecList &rhs); + FileSpecList &operator=(const FileSpecList &rhs) = default; + + /// Move-assignment operator. + FileSpecList &operator=(FileSpecList &&rhs) = default; + //------------------------------------------------------------------ /// Append a FileSpec object to the list. Index: lit/SymbolFile/Breakpad/Inputs/line-table.syms =================================================================== --- /dev/null +++ lit/SymbolFile/Breakpad/Inputs/line-table.syms @@ -0,0 +1,9 @@ +MODULE Linux x86_64 761550E08086333960A9074A9CE2895C0 a.out +INFO CODE_ID E05015768680393360A9074A9CE2895C +FILE 0 /tmp/a.c +FILE 2 /tmp/c.c +FUNC b0 10 0 func +b0 1 1 0 +b1 1 2 0 +b2 1 2 2 +b4 1 3 2 Index: lit/SymbolFile/Breakpad/line-table.test =================================================================== --- /dev/null +++ lit/SymbolFile/Breakpad/line-table.test @@ -0,0 +1,23 @@ +# RUN: yaml2obj %S/Inputs/basic-elf.yaml > %T/line-table.out +# RUN: %lldb %T/line-table.out -o "target symbols add -s line-table.out %S/Inputs/line-table.syms" \ +# RUN: -s %s | FileCheck %s + +image dump line-table line-table.out +# CHECK-LABEL: Line table for {{.*}}line-table.out +# CHECK-NEXT: 0x00000000004000b0: /tmp/a.c:1 +# CHECK-NEXT: 0x00000000004000b1: /tmp/a.c:2 +# CHECK-NEXT: 0x00000000004000b2: /tmp/c.c:2 +# CHECK-NEXT: 0x00000000004000b3: +# CHECK-EMPTY: +# CHECK-NEXT: 0x00000000004000b4: /tmp/c.c:3 +# CHECK-NEXT: 0x00000000004000b5: + +image lookup -a 0x4000b2 -v +# CHECK-LABEL: image lookup -a 0x4000b2 -v +# CHECK: Summary: line-table.out`func + 2 + +breakpoint set -f c.c -l 2 +# CHECK-LABEL: breakpoint set -f c.c -l 2 +# CHECK: Breakpoint 1: where = line-table.out`func + 2, address = 0x00000000004000b2 + +exit Index: source/Core/FileSpecList.cpp =================================================================== --- source/Core/FileSpecList.cpp +++ source/Core/FileSpecList.cpp @@ -25,15 +25,6 @@ FileSpecList::~FileSpecList() = default; -//------------------------------------------------------------------ -// Assignment operator -//------------------------------------------------------------------ -const FileSpecList &FileSpecList::operator=(const FileSpecList &rhs) { - if (this != &rhs) - m_files = rhs.m_files; - return *this; -} - //------------------------------------------------------------------ // Append the "file_spec" to the end of the file spec list. //------------------------------------------------------------------ Index: source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h =================================================================== --- source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h +++ source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h @@ -43,7 +43,7 @@ uint32_t CalculateAbilities() override; - void InitializeObject() override {} + void InitializeObject() override; //------------------------------------------------------------------ // Compile Unit function calls @@ -67,9 +67,7 @@ } bool ParseCompileUnitSupportFiles(const SymbolContext &sc, - FileSpecList &support_files) override { - return false; - } + FileSpecList &support_files) override; bool ParseImportedModules(const SymbolContext &sc, @@ -98,10 +96,16 @@ } bool CompleteType(CompilerType &compiler_type) override { return false; } + uint32_t ResolveSymbolContext(const Address &so_addr, lldb::SymbolContextItem resolve_scope, SymbolContext &sc) override; + uint32_t ResolveSymbolContext(const FileSpec &file_spec, uint32_t line, + bool check_inlines, + lldb::SymbolContextItem resolve_scope, + SymbolContextList &sc_list) override; + size_t GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask, TypeList &type_list) override { return 0; @@ -141,6 +145,7 @@ uint32_t GetPluginVersion() override { return 1; } private: + lldb::CompUnitSP m_comp_unit_sp; }; } // namespace breakpad Index: source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp =================================================================== --- source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp +++ source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp @@ -13,7 +13,10 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/TypeMap.h" #include "lldb/Utility/Log.h" #include "llvm/ADT/StringExtras.h" @@ -103,17 +106,23 @@ if (m_obj_file->GetPluginName() != ObjectFileBreakpad::GetPluginNameStatic()) return 0; - return CompileUnits | Functions; + return CompileUnits | Functions | LineTables; } -uint32_t SymbolFileBreakpad::GetNumCompileUnits() { - // TODO - return 0; +void SymbolFileBreakpad::InitializeObject() { + m_comp_unit_sp = std::make_shared( + m_obj_file->GetModule(), /*user_data*/ nullptr, + m_obj_file->GetModule()->GetObjectFile()->GetFileSpec(), + /*uid*/ 0, eLanguageTypeUnknown, /*is_optimized*/ eLazyBoolNo); } +uint32_t SymbolFileBreakpad::GetNumCompileUnits() { return 1; } + CompUnitSP SymbolFileBreakpad::ParseCompileUnitAtIndex(uint32_t index) { - // TODO - return nullptr; + assert(index == 0); + m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex( + 0, m_comp_unit_sp); + return m_comp_unit_sp; } size_t SymbolFileBreakpad::ParseCompileUnitFunctions(const SymbolContext &sc) { @@ -122,16 +131,131 @@ } bool SymbolFileBreakpad::ParseCompileUnitLineTable(const SymbolContext &sc) { - // TODO - return 0; + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS); + addr_t base = m_obj_file->GetModule() + ->GetObjectFile() + ->GetBaseAddress() + .GetFileAddress(); + if (base == LLDB_INVALID_ADDRESS) { + LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping " + "symtab population."); + return false; + } + auto line_table_up = llvm::make_unique(sc.comp_unit); + std::unique_ptr line_seq_up( + line_table_up->CreateLineSequenceContainer()); + llvm::Optional next_addr; + auto finish_sequence = [&]() { + line_table_up->AppendLineEntryToSequence( + line_seq_up.get(), *next_addr, /*line*/ 0, /*column*/ 0, + /*file_idx*/ 0, /*is_start_of_statement*/ false, + /*is_start_of_basic_block*/ false, /*is_prologue_end*/ false, + /*is_epilogue_begin*/ false, /*is_terminal_entry*/ true); + line_table_up->InsertSequence(line_seq_up.get()); + line_seq_up->Clear(); + }; + for (llvm::StringRef line: lines(*m_obj_file, Token::Func)) { + llvm::StringRef token_str; + std::tie(token_str, line) = getToken(line); + if (toToken(token_str) == Token::Func) + continue; + + // address size line filenum + addr_t address; + if (!to_integer(token_str, address, 16)) + continue; + address += base; + std::tie(token_str, line) = getToken(line); + addr_t size; + if (!to_integer(token_str, size, 16)) + continue; + std::tie(token_str, line) = getToken(line); + uint32_t linenum; + if (!to_integer(token_str, linenum, 10)) + continue; + std::tie(token_str, line) = getToken(line); + uint32_t filenum; + if (!to_integer(token_str, filenum, 10)) + continue; + ++filenum; // LLDB file IDs are 1-based + + if (next_addr && *next_addr != address) { + // Discontiguous entries. Finish off the previous sequence and reset. + finish_sequence(); + } + line_table_up->AppendLineEntryToSequence( + line_seq_up.get(), address, /*line*/ linenum, /*column*/ 0, + /*file_idx*/ filenum, /*is_start_of_statement*/ true, + /*is_start_of_basic_block*/ false, /*is_prologue_end*/ false, + /*is_epilogue_begin*/ false, /*is_terminal_entry*/ false); + next_addr = address + size; + } + if (next_addr) + finish_sequence(); + sc.comp_unit->SetLineTable(line_table_up.release()); + return true; +} + +bool SymbolFileBreakpad::ParseCompileUnitSupportFiles( + const SymbolContext &sc, FileSpecList &support_files) { + assert(sc.comp_unit == m_comp_unit_sp.get()); + std::vector files; + for (llvm::StringRef line: lines(*m_obj_file, Token::File)) { + // FILE number name + + // skip FILE + line = getToken(line).second; + + llvm::StringRef token; + std::tie(token, line) = getToken(line); + uint32_t number; + if (!to_integer(token, number, 10)) + continue; + ++number; // LLDB file IDs are 1-based + + llvm::StringRef name = line.trim(); + if (number >= files.size()) + files.resize(number+1); + files[number] = FileSpec(name); + } + support_files = FileSpecList(std::move(files)); + return true; } uint32_t SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr, SymbolContextItem resolve_scope, SymbolContext &sc) { - // TODO - return 0; + if (!(resolve_scope & (eSymbolContextCompUnit | eSymbolContextLineEntry))) + return 0; + sc.comp_unit = m_comp_unit_sp.get(); + SymbolContextItem result = eSymbolContextCompUnit; + if (resolve_scope & eSymbolContextLineEntry) { + if (sc.comp_unit->GetLineTable()->FindLineEntryByAddress(so_addr, + sc.line_entry)) { + result |= eSymbolContextLineEntry; + } + } + + return result; +} + +uint32_t SymbolFileBreakpad::ResolveSymbolContext(const FileSpec &file_spec, uint32_t line, + bool check_inlines, + lldb::SymbolContextItem resolve_scope, + SymbolContextList &sc_list) { + const uint32_t old_size = sc_list.GetSize(); + if (resolve_scope & eSymbolContextCompUnit) { + FileSpecList support_files = m_comp_unit_sp->GetSupportFiles(); + const bool full_match(file_spec.GetDirectory()); + if (FileSpec::Equal(file_spec, *m_comp_unit_sp, full_match) || + (check_inlines && support_files.FindFileIndex(1, file_spec, true))) { + SymbolContext sc(m_obj_file->GetModule()); + sc.comp_unit = m_comp_unit_sp.get(); + sc_list.Append(sc); + } + } + return sc_list.GetSize() - old_size; } uint32_t SymbolFileBreakpad::FindFunctions(