labath created this revision. labath added reviewers: clayborg, zturner, lemo, markmentovai, amccarth. Herald added a subscriber: mgorny.
This commit adds the glue code necessary to integrate the SymbolFileBreakpad into the plugin system. Most of the methods are stubbed out. The only method implemented method is AddSymbols, which parses the PUBLIC "section" of the breakpad "object file", and fills out the Module's symtab. To enable testing this, I've made two additional changes: - dump Symtab from the SymbolVendor class. The symtab was already being dumped as a part of the object file dump, but that happened before symbol vendor kicked in, so it did not reflect any symbols added there. - add ability to explicitly specify the external symbol file in lldb-test (so that the object file could be linked with the breakpad symbol file). To make things simpler, I've changed lldb-test from consuming multiple inputs (and dumping their symbols) to having it just process a single file per invocation. This was not a problem since everyone was using it that way already. https://reviews.llvm.org/D56173 Files: lit/SymbolFile/Breakpad/Inputs/symtab.syms lit/SymbolFile/Breakpad/lit.local.cfg lit/SymbolFile/Breakpad/symtab.yaml source/API/SystemInitializerFull.cpp source/Plugins/SymbolFile/Breakpad/CMakeLists.txt source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h source/Plugins/SymbolFile/CMakeLists.txt source/Symbol/SymbolVendor.cpp tools/lldb-test/SystemInitializerTest.cpp tools/lldb-test/lldb-test.cpp
Index: tools/lldb-test/lldb-test.cpp =================================================================== --- tools/lldb-test/lldb-test.cpp +++ tools/lldb-test/lldb-test.cpp @@ -100,10 +100,14 @@ } // namespace object namespace symbols { -static cl::list<std::string> InputFilenames(cl::Positional, - cl::desc("<input files>"), - cl::OneOrMore, - cl::sub(SymbolsSubcommand)); +static cl::opt<std::string> InputFile(cl::Positional, cl::desc("<input file>"), + cl::Required, cl::sub(SymbolsSubcommand)); + +static cl::opt<std::string> + SymbolPath("symbol-file", + cl::desc("The file from which to fetch symbol information."), + cl::value_desc("file"), cl::sub(SymbolsSubcommand)); + enum class FindType { None, Function, @@ -694,28 +698,24 @@ } auto Action = *ActionOr; - int HadErrors = 0; - for (const auto &File : InputFilenames) { - outs() << "Module: " << File << "\n"; - ModuleSpec Spec{FileSpec(File)}; - Spec.GetSymbolFileSpec().SetFile(File, FileSpec::Style::native); - - auto ModulePtr = std::make_shared<lldb_private::Module>(Spec); - SymbolVendor *Vendor = ModulePtr->GetSymbolVendor(); - if (!Vendor) { - WithColor::error() << "Module has no symbol vendor.\n"; - HadErrors = 1; - continue; - } + outs() << "Module: " << InputFile << "\n"; + ModuleSpec Spec{FileSpec(InputFile)}; + StringRef Symbols = SymbolPath.empty() ? InputFile : SymbolPath; + Spec.GetSymbolFileSpec().SetFile(Symbols, FileSpec::Style::native); - if (Error E = Action(*ModulePtr)) { - WithColor::error() << toString(std::move(E)) << "\n"; - HadErrors = 1; - } + auto ModulePtr = std::make_shared<lldb_private::Module>(Spec); + SymbolVendor *Vendor = ModulePtr->GetSymbolVendor(); + if (!Vendor) { + WithColor::error() << "Module has no symbol vendor.\n"; + return 1; + } - outs().flush(); + if (Error E = Action(*ModulePtr)) { + WithColor::error() << toString(std::move(E)) << "\n"; + return 1; } - return HadErrors; + + return 0; } static void dumpSectionList(LinePrinter &Printer, const SectionList &List, bool is_subsection) { Index: tools/lldb-test/SystemInitializerTest.cpp =================================================================== --- tools/lldb-test/SystemInitializerTest.cpp +++ tools/lldb-test/SystemInitializerTest.cpp @@ -70,6 +70,7 @@ #include "Plugins/Process/gdb-remote/ProcessGDBRemote.h" #include "Plugins/Process/minidump/ProcessMinidump.h" #include "Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h" +#include "Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h" #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h" @@ -176,6 +177,7 @@ MainThreadCheckerRuntime::Initialize(); SymbolVendorELF::Initialize(); + breakpad::SymbolFileBreakpad::Initialize(); SymbolFileDWARF::Initialize(); SymbolFilePDB::Initialize(); SymbolFileSymtab::Initialize(); @@ -274,6 +276,7 @@ UndefinedBehaviorSanitizerRuntime::Terminate(); MainThreadCheckerRuntime::Terminate(); SymbolVendorELF::Terminate(); + breakpad::SymbolFileBreakpad::Terminate(); SymbolFileDWARF::Terminate(); SymbolFilePDB::Terminate(); SymbolFileSymtab::Terminate(); Index: source/Symbol/SymbolVendor.cpp =================================================================== --- source/Symbol/SymbolVendor.cpp +++ source/Symbol/SymbolVendor.cpp @@ -384,6 +384,7 @@ s->Indent(); s->PutCString("SymbolVendor"); if (m_sym_file_ap.get()) { + *s << " " << m_sym_file_ap->GetPluginName(); ObjectFile *objfile = m_sym_file_ap->GetObjectFile(); if (objfile) { const FileSpec &objfile_file_spec = objfile->GetFileSpec(); @@ -408,6 +409,9 @@ (*cu_pos)->Dump(s, show_context); } + if (Symtab *symtab = GetSymtab()) + symtab->Dump(s, nullptr, eSortOrderNone); + s->IndentLess(); } } Index: source/Plugins/SymbolFile/CMakeLists.txt =================================================================== --- source/Plugins/SymbolFile/CMakeLists.txt +++ source/Plugins/SymbolFile/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(Breakpad) add_subdirectory(DWARF) add_subdirectory(Symtab) add_subdirectory(NativePDB) Index: source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h =================================================================== --- /dev/null +++ source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h @@ -0,0 +1,149 @@ +//===-- SymbolFileBreakpad.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SYMBOLFILE_BREAKPAD_SYMBOLFILEBREAKPAD_H +#define LLDB_PLUGINS_SYMBOLFILE_BREAKPAD_SYMBOLFILEBREAKPAD_H + +#include "lldb/Symbol/SymbolFile.h" + +namespace lldb_private { + +namespace breakpad { + +class SymbolFileBreakpad : public SymbolFile { +public: + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + static void Terminate(); + static void DebuggerInitialize(Debugger &debugger) {} + static ConstString GetPluginNameStatic(); + + static const char *GetPluginDescriptionStatic() { + return "Breakpad debug symbol file reader."; + } + + static SymbolFile *CreateInstance(ObjectFile *obj_file) { + return new SymbolFileBreakpad(obj_file); + } + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + SymbolFileBreakpad(ObjectFile *object_file) : SymbolFile(object_file) {} + + ~SymbolFileBreakpad() override {} + + uint32_t CalculateAbilities() override; + + void InitializeObject() override {} + + //------------------------------------------------------------------ + // Compile Unit function calls + //------------------------------------------------------------------ + + uint32_t GetNumCompileUnits() override; + + lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override; + + lldb::LanguageType + ParseCompileUnitLanguage(const SymbolContext &sc) override { + return lldb::eLanguageTypeUnknown; + } + + size_t ParseCompileUnitFunctions(const SymbolContext &sc) override; + + bool ParseCompileUnitLineTable(const SymbolContext &sc) override; + + bool ParseCompileUnitDebugMacros(const SymbolContext &sc) override { + return false; + } + + bool ParseCompileUnitSupportFiles(const SymbolContext &sc, + FileSpecList &support_files) override { + return false; + } + + bool + ParseImportedModules(const SymbolContext &sc, + std::vector<ConstString> &imported_modules) override { + return false; + } + + size_t ParseFunctionBlocks(const SymbolContext &sc) override { return 0; } + + uint32_t FindGlobalVariables(const ConstString &name, + const CompilerDeclContext *parent_decl_ctx, + uint32_t max_matches, + VariableList &variables) override { + return 0; + } + + size_t ParseTypes(const SymbolContext &sc) override { return 0; } + size_t ParseVariablesForContext(const SymbolContext &sc) override { + return 0; + } + Type *ResolveTypeUID(lldb::user_id_t type_uid) override { return nullptr; } + llvm::Optional<ArrayInfo> GetDynamicArrayInfoForUID( + lldb::user_id_t type_uid, + const lldb_private::ExecutionContext *exe_ctx) override { + return llvm::None; + } + + bool CompleteType(CompilerType &compiler_type) override { return false; } + uint32_t ResolveSymbolContext(const Address &so_addr, + lldb::SymbolContextItem resolve_scope, + SymbolContext &sc) override; + + size_t GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask, + TypeList &type_list) override { + return 0; + } + + uint32_t FindFunctions(const ConstString &name, + const CompilerDeclContext *parent_decl_ctx, + lldb::FunctionNameType name_type_mask, + bool include_inlines, bool append, + SymbolContextList &sc_list) override; + + uint32_t FindFunctions(const RegularExpression ®ex, bool include_inlines, + bool append, SymbolContextList &sc_list) override; + + uint32_t FindTypes(const SymbolContext &sc, const ConstString &name, + const CompilerDeclContext *parent_decl_ctx, bool append, + uint32_t max_matches, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, + TypeMap &types) override; + + size_t FindTypes(const std::vector<CompilerContext> &context, bool append, + TypeMap &types) override; + + TypeSystem *GetTypeSystemForLanguage(lldb::LanguageType language) override { + return nullptr; + } + + CompilerDeclContext + FindNamespace(const SymbolContext &sc, const ConstString &name, + const CompilerDeclContext *parent_decl_ctx) override { + return CompilerDeclContext(); + } + + void AddSymbols(Symtab &symtab) override; + + ConstString GetPluginName() override { return GetPluginNameStatic(); } + uint32_t GetPluginVersion() override { return 1; } + +private: +}; + +} // namespace breakpad +} // namespace lldb_private + +#endif Index: source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp =================================================================== --- /dev/null +++ source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp @@ -0,0 +1,221 @@ +//===-- SymbolFileBreakpad.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h" +#include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/TypeMap.h" +#include "lldb/Utility/Log.h" +#include "llvm/ADT/StringExtras.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::breakpad; + +namespace { +class LineIterator { +public: + // begin iterator for sections of given type + LineIterator(ObjectFile &obj, ConstString section_type) + : m_obj(&obj), m_section_type(section_type), m_next_section_idx(0) { + ++*this; + } + + // end iterator + explicit LineIterator(ObjectFile &obj) + : m_obj(&obj), + m_next_section_idx(m_obj->GetSectionList()->GetNumSections(0)) {} + + friend bool operator!=(const LineIterator &lhs, const LineIterator &rhs) { + assert(lhs.m_obj == rhs.m_obj); + if (lhs.m_next_section_idx != rhs.m_next_section_idx) + return true; + if (lhs.m_next_text.data() != rhs.m_next_text.data()) + return true; + assert(lhs.m_current_text == rhs.m_current_text); + assert(rhs.m_next_text == rhs.m_next_text); + return false; + } + + const LineIterator &operator++(); + llvm::StringRef operator*() const { return m_current_text; } + +private: + ObjectFile *m_obj; + ConstString m_section_type; + uint32_t m_next_section_idx; + llvm::StringRef m_current_text; + llvm::StringRef m_next_text; +}; +} // namespace + +const LineIterator &LineIterator::operator++() { + const SectionList &list = *m_obj->GetSectionList(); + size_t num_sections = list.GetNumSections(0); + while (m_next_text.empty() && m_next_section_idx < num_sections) { + Section § = *list.GetSectionAtIndex(m_next_section_idx++); + if (sect.GetName() != m_section_type) + continue; + DataExtractor data; + m_obj->ReadSectionData(§, data); + m_next_text = + llvm::StringRef(reinterpret_cast<const char *>(data.GetDataStart()), + data.GetByteSize()); + } + std::tie(m_current_text, m_next_text) = m_next_text.split('\n'); + return *this; +} + +static llvm::iterator_range<LineIterator> lines(ObjectFile &obj, + ConstString section_type) { + return llvm::make_range(LineIterator(obj, section_type), LineIterator(obj)); +} + +void SymbolFileBreakpad::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + DebuggerInitialize); +} + +void SymbolFileBreakpad::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ConstString SymbolFileBreakpad::GetPluginNameStatic() { + static ConstString g_name("breakpad"); + return g_name; +} + +uint32_t SymbolFileBreakpad::CalculateAbilities() { + if (!m_obj_file) + return 0; + if (m_obj_file->GetPluginName() != ObjectFileBreakpad::GetPluginNameStatic()) + return 0; + + return CompileUnits | Functions; +} + +uint32_t SymbolFileBreakpad::GetNumCompileUnits() { + // TODO + return 0; +} + +CompUnitSP SymbolFileBreakpad::ParseCompileUnitAtIndex(uint32_t index) { + // TODO + return nullptr; +} + +size_t SymbolFileBreakpad::ParseCompileUnitFunctions(const SymbolContext &sc) { + // TODO + return 0; +} + +bool SymbolFileBreakpad::ParseCompileUnitLineTable(const SymbolContext &sc) { + // TODO + return 0; +} + +uint32_t +SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr, + SymbolContextItem resolve_scope, + SymbolContext &sc) { + // TODO + return 0; +} + +uint32_t SymbolFileBreakpad::FindFunctions( + const ConstString &name, const CompilerDeclContext *parent_decl_ctx, + FunctionNameType name_type_mask, bool include_inlines, bool append, + SymbolContextList &sc_list) { + // TODO + if (!append) + sc_list.Clear(); + return sc_list.GetSize(); +} + +uint32_t SymbolFileBreakpad::FindFunctions(const RegularExpression ®ex, + bool include_inlines, bool append, + SymbolContextList &sc_list) { + // TODO + if (!append) + sc_list.Clear(); + return sc_list.GetSize(); +} + +uint32_t SymbolFileBreakpad::FindTypes( + const SymbolContext &sc, const ConstString &name, + const CompilerDeclContext *parent_decl_ctx, bool append, + uint32_t max_matches, llvm::DenseSet<SymbolFile *> &searched_symbol_files, + TypeMap &types) { + if (!append) + types.Clear(); + return types.GetSize(); +} + +size_t +SymbolFileBreakpad::FindTypes(const std::vector<CompilerContext> &context, + bool append, TypeMap &types) { + if (!append) + types.Clear(); + return types.GetSize(); +} + +void SymbolFileBreakpad::AddSymbols(Symtab &symtab) { + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS); + Module &module = *m_obj_file->GetModule(); + addr_t base = module.GetObjectFile()->GetBaseAddress().GetFileAddress(); + if (base == LLDB_INVALID_ADDRESS) + return; + + const SectionList &list = *module.GetSectionList(); + for (llvm::StringRef line : lines(*m_obj_file, ConstString("PUBLIC"))) { + // PUBLIC [m] address param_size name + // skip PUBLIC keyword + line = getToken(line).second; + llvm::StringRef token; + std::tie(token, line) = getToken(line); + if (token == "m") + std::tie(token, line) = getToken(line); + + addr_t address; + if (!to_integer(token, address, 16)) + continue; + address += base; + + // skip param_size + line = getToken(line).second; + + llvm::StringRef name = line.trim(); + + SectionSP section_sp = list.FindSectionContainingFileAddress(address); + if (!section_sp) { + LLDB_LOG(log, + "Ignoring symbol {0}, whose address ({1}) is outside of the " + "object file. Mismatched symbol file?", + name, address); + continue; + } + + symtab.AddSymbol(Symbol( + /*symID*/ 0, Mangled(name, /*is_mangled*/ false), eSymbolTypeCode, + /*is_global*/ true, /*is_debug*/ false, /*is_trampoline*/ false, + /*is_artificial*/ false, + AddressRange(section_sp, address - section_sp->GetFileAddress(), 0), + /*size_is_valid*/ 0, /*contains_linker_annotations*/ false, + /*flags*/ 0)); + } + + // TODO: Process FUNC records as well. + + symtab.CalculateSymbolSizes(); +} Index: source/Plugins/SymbolFile/Breakpad/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/SymbolFile/Breakpad/CMakeLists.txt @@ -0,0 +1,12 @@ +add_lldb_library(lldbPluginSymbolFileBreakpad PLUGIN + SymbolFileBreakpad.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbUtility + lldbPluginObjectFileBreakpad + LINK_COMPONENTS + Support + ) Index: source/API/SystemInitializerFull.cpp =================================================================== --- source/API/SystemInitializerFull.cpp +++ source/API/SystemInitializerFull.cpp @@ -83,6 +83,7 @@ #include "Plugins/Process/mach-core/ProcessMachCore.h" #include "Plugins/Process/minidump/ProcessMinidump.h" #include "Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h" +#include "Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h" #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h" @@ -343,6 +344,7 @@ MainThreadCheckerRuntime::Initialize(); SymbolVendorELF::Initialize(); + breakpad::SymbolFileBreakpad::Initialize(); SymbolFileDWARF::Initialize(); SymbolFilePDB::Initialize(); SymbolFileSymtab::Initialize(); @@ -471,6 +473,7 @@ UndefinedBehaviorSanitizerRuntime::Terminate(); MainThreadCheckerRuntime::Terminate(); SymbolVendorELF::Terminate(); + breakpad::SymbolFileBreakpad::Terminate(); SymbolFileDWARF::Terminate(); SymbolFilePDB::Terminate(); SymbolFileSymtab::Terminate(); Index: lit/SymbolFile/Breakpad/symtab.yaml =================================================================== --- /dev/null +++ lit/SymbolFile/Breakpad/symtab.yaml @@ -0,0 +1,42 @@ +# RUN: yaml2obj %s > %t +# RUN: lldb-test symbols %t -symbol-file %S/Inputs/symtab.syms | FileCheck %s + +# CHECK: SymbolVendor breakpad ({{.*}}symtab.syms) +# CHECK: num_symbols = 3: +# CHECK: Index UserID DSX Type File Address/Value Load Address Size Flags Name +# CHECK: [ 0] 0 X Code 0x00000000004000b0 0x0000000000000010 0x00000000 f1 +# CHECK: [ 1] 0 X Code 0x00000000004000c0 0x0000000000000010 0x00000000 f2 +# CHECK: [ 2] 0 X Code 0x00000000004000d0 0x0000000000000022 0x00000000 _start + + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 + Entry: 0x00000000004000D0 +Sections: + - Name: .text1 + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x0000000000400000 + AddressAlign: 0x0000000000001000 + Size: 0xb0 + - Name: .text2 + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x00000000004000B0 + AddressAlign: 0x0000000000000010 + Size: 0x42 +Symbols: +DynamicSymbols: +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_X, PF_R ] + VAddr: 0x400000 + Align: 0x1000 + Sections: + - Section: .text1 + - Section: .text2 +... Index: lit/SymbolFile/Breakpad/lit.local.cfg =================================================================== --- /dev/null +++ lit/SymbolFile/Breakpad/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes.add('.yaml') Index: lit/SymbolFile/Breakpad/Inputs/symtab.syms =================================================================== --- /dev/null +++ lit/SymbolFile/Breakpad/Inputs/symtab.syms @@ -0,0 +1,7 @@ +MODULE Linux x86_64 761550E08086333960A9074A9CE2895C0 a.out +INFO CODE_ID E05015768680393360A9074A9CE2895C +FILE 0 /tmp/a.c +PUBLIC b0 0 f1 +PUBLIC c0 0 f2 +PUBLIC d0 0 _start +PUBLIC ff 0 _out_of_range_ignored
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits