labath created this revision. labath added reviewers: clayborg, zturner, lemo, markmentovai.
This patch teaches SymbolFileBreakpad to parse the line information in breakpad files and present it to lldb. The trickiest question here was what kind of "compile units" to present to lldb, as there really isn't enough information in breakpad files to correctly reconstruct those. The two options I considered were: - have the entire file be one compile unit - have one compile unit for each FILE record The drawbacks of the first approach are that the compile unit created this way will be huge, and there isn't a good way to name it (I decided to name it after the object file). The second approach will create mostly correct compile units for cpp files, but it will still be wrong for headers. However, the biggest drawback here seemed to be the fact that this can cause a compile unit to change mid-function (for example when a function from another file is inlined or another file is #included into a function). While I don't know of any specific thing that would break in this case, it does sound like a thing that we should avoid. So, in the end, I chose the first approach, because it results in simpler code, and having one compile unit doesn't seem so bad, particularly as the second approach wouldn't result in correct compile units either. https://reviews.llvm.org/D56595 Files: include/lldb/Core/FileSpecList.h lit/SymbolFile/Breakpad/Inputs/line-table.syms lit/SymbolFile/Breakpad/line-table.test source/Core/FileSpecList.cpp source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
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<CompileUnit>( + 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<LineTable>(sc.comp_unit); + std::unique_ptr<LineSequence> line_seq_up( + line_table_up->CreateLineSequenceContainer()); + llvm::Optional<addr_t> 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<FileSpec> 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( 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: 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: 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: 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<FileSpec> &&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.
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits