diff options
Diffstat (limited to 'source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp')
-rw-r--r-- | source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp | 257 |
1 files changed, 185 insertions, 72 deletions
diff --git a/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp b/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp index d4258274a38c..f84cf0c5368d 100644 --- a/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp +++ b/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp @@ -15,7 +15,6 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/PostfixExpression.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/TypeMap.h" #include "lldb/Utility/Log.h" @@ -126,8 +125,8 @@ SymbolFileBreakpad::LineIterator::operator++() { llvm::iterator_range<SymbolFileBreakpad::LineIterator> SymbolFileBreakpad::lines(Record::Kind section_type) { - return llvm::make_range(LineIterator(*m_obj_file, section_type), - LineIterator(*m_obj_file)); + return llvm::make_range(LineIterator(*m_objfile_sp, section_type), + LineIterator(*m_objfile_sp)); } namespace { @@ -179,15 +178,13 @@ ConstString SymbolFileBreakpad::GetPluginNameStatic() { } uint32_t SymbolFileBreakpad::CalculateAbilities() { - if (!m_obj_file) - return 0; - if (m_obj_file->GetPluginName() != ObjectFileBreakpad::GetPluginNameStatic()) + if (!m_objfile_sp || !llvm::isa<ObjectFileBreakpad>(*m_objfile_sp)) return 0; return CompileUnits | Functions | LineTables; } -uint32_t SymbolFileBreakpad::GetNumCompileUnits() { +uint32_t SymbolFileBreakpad::CalculateNumCompileUnits() { ParseCUData(); return m_cu_data->GetSize(); } @@ -204,7 +201,8 @@ CompUnitSP SymbolFileBreakpad::ParseCompileUnitAtIndex(uint32_t index) { // The FileSpec of the compile unit will be the file corresponding to the // first LINE record. - LineIterator It(*m_obj_file, Record::Func, data.bookmark), End(*m_obj_file); + LineIterator It(*m_objfile_sp, Record::Func, data.bookmark), + End(*m_objfile_sp); assert(Record::classify(*It) == Record::Func); ++It; // Skip FUNC record. if (It != End) { @@ -213,12 +211,12 @@ CompUnitSP SymbolFileBreakpad::ParseCompileUnitAtIndex(uint32_t index) { spec = (*m_files)[record->FileNum]; } - auto cu_sp = std::make_shared<CompileUnit>(m_obj_file->GetModule(), + auto cu_sp = std::make_shared<CompileUnit>(m_objfile_sp->GetModule(), /*user_data*/ nullptr, spec, index, eLanguageTypeUnknown, /*is_optimized*/ eLazyBoolNo); - GetSymbolVendor().SetCompileUnitAtIndex(index, cu_sp); + SetCompileUnitAtIndex(index, cu_sp); return cu_sp; } @@ -228,6 +226,7 @@ size_t SymbolFileBreakpad::ParseFunctions(CompileUnit &comp_unit) { } bool SymbolFileBreakpad::ParseLineTable(CompileUnit &comp_unit) { + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data; if (!data.line_table_up) @@ -239,6 +238,7 @@ bool SymbolFileBreakpad::ParseLineTable(CompileUnit &comp_unit) { bool SymbolFileBreakpad::ParseSupportFiles(CompileUnit &comp_unit, FileSpecList &support_files) { + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data; if (!data.support_files) ParseLineTableAndSupportFiles(comp_unit, data); @@ -251,6 +251,7 @@ uint32_t SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr, SymbolContextItem resolve_scope, SymbolContext &sc) { + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); if (!(resolve_scope & (eSymbolContextCompUnit | eSymbolContextLineEntry))) return 0; @@ -260,7 +261,7 @@ SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr, if (idx == UINT32_MAX) return 0; - sc.comp_unit = GetSymbolVendor().GetCompileUnitAtIndex(idx).get(); + sc.comp_unit = GetCompileUnitAtIndex(idx).get(); SymbolContextItem result = eSymbolContextCompUnit; if (resolve_scope & eSymbolContextLineEntry) { if (sc.comp_unit->GetLineTable()->FindLineEntryByAddress(so_addr, @@ -275,57 +276,43 @@ SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr, uint32_t SymbolFileBreakpad::ResolveSymbolContext( const FileSpec &file_spec, uint32_t line, bool check_inlines, lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) { + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); if (!(resolve_scope & eSymbolContextCompUnit)) return 0; uint32_t old_size = sc_list.GetSize(); for (size_t i = 0, size = GetNumCompileUnits(); i < size; ++i) { - CompileUnit &cu = *GetSymbolVendor().GetCompileUnitAtIndex(i); + CompileUnit &cu = *GetCompileUnitAtIndex(i); cu.ResolveSymbolContext(file_spec, line, check_inlines, /*exact*/ false, resolve_scope, sc_list); } return sc_list.GetSize() - old_size; } -uint32_t SymbolFileBreakpad::FindFunctions( +void SymbolFileBreakpad::FindFunctions( ConstString name, const CompilerDeclContext *parent_decl_ctx, - FunctionNameType name_type_mask, bool include_inlines, bool append, + FunctionNameType name_type_mask, bool include_inlines, 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) { +void SymbolFileBreakpad::FindFunctions(const RegularExpression ®ex, + bool include_inlines, + SymbolContextList &sc_list) { // TODO - if (!append) - sc_list.Clear(); - return sc_list.GetSize(); } -uint32_t SymbolFileBreakpad::FindTypes( +void SymbolFileBreakpad::FindTypes( 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(); -} + uint32_t max_matches, llvm::DenseSet<SymbolFile *> &searched_symbol_files, + TypeMap &types) {} -size_t -SymbolFileBreakpad::FindTypes(const std::vector<CompilerContext> &context, - bool append, TypeMap &types) { - if (!append) - types.Clear(); - return types.GetSize(); -} +void SymbolFileBreakpad::FindTypes(llvm::ArrayRef<CompilerContext> pattern, + LanguageSet languages, TypeMap &types) {} void SymbolFileBreakpad::AddSymbols(Symtab &symtab) { Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS); - Module &module = *m_obj_file->GetModule(); + Module &module = *m_objfile_sp->GetModule(); addr_t base = GetBaseFileAddress(); if (base == LLDB_INVALID_ADDRESS) { LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping " @@ -347,8 +334,8 @@ void SymbolFileBreakpad::AddSymbols(Symtab &symtab) { return; } symbols.try_emplace( - address, /*symID*/ 0, Mangled(name, /*is_mangled*/ false), - eSymbolTypeCode, /*is_global*/ true, /*is_debug*/ false, + address, /*symID*/ 0, Mangled(name), eSymbolTypeCode, + /*is_global*/ true, /*is_debug*/ false, /*is_trampoline*/ false, /*is_artificial*/ false, AddressRange(section_sp, address - section_sp->GetFileAddress(), size.getValueOr(0)), @@ -372,6 +359,20 @@ void SymbolFileBreakpad::AddSymbols(Symtab &symtab) { symtab.CalculateSymbolSizes(); } +llvm::Expected<lldb::addr_t> +SymbolFileBreakpad::GetParameterStackSize(Symbol &symbol) { + ParseUnwindData(); + if (auto *entry = m_unwind_data->win.FindEntryThatContains( + symbol.GetAddress().GetFileAddress())) { + auto record = StackWinRecord::parse( + *LineIterator(*m_objfile_sp, Record::StackWin, entry->data)); + assert(record.hasValue()); + return record->ParameterSize; + } + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Parameter size unknown."); +} + static llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>> GetRule(llvm::StringRef &unwind_rules) { // Unwind rules are of the form @@ -418,7 +419,17 @@ ResolveRegisterOrRA(const SymbolFile::RegisterInfoResolver &resolver, return ResolveRegister(resolver, name); } -bool SymbolFileBreakpad::ParseUnwindRow(llvm::StringRef unwind_rules, +llvm::ArrayRef<uint8_t> SymbolFileBreakpad::SaveAsDWARF(postfix::Node &node) { + ArchSpec arch = m_objfile_sp->GetArchitecture(); + StreamString dwarf(Stream::eBinary, arch.GetAddressByteSize(), + arch.GetByteOrder()); + ToDWARF(node, dwarf); + uint8_t *saved = m_allocator.Allocate<uint8_t>(dwarf.GetSize()); + std::memcpy(saved, dwarf.GetData(), dwarf.GetSize()); + return {saved, dwarf.GetSize()}; +} + +bool SymbolFileBreakpad::ParseCFIUnwindRow(llvm::StringRef unwind_rules, const RegisterInfoResolver &resolver, UnwindPlan::Row &row) { Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS); @@ -427,7 +438,7 @@ bool SymbolFileBreakpad::ParseUnwindRow(llvm::StringRef unwind_rules, while (auto rule = GetRule(unwind_rules)) { node_alloc.Reset(); llvm::StringRef lhs = rule->first; - postfix::Node *rhs = postfix::Parse(rule->second, node_alloc); + postfix::Node *rhs = postfix::ParseOneExpression(rule->second, node_alloc); if (!rhs) { LLDB_LOG(log, "Could not parse `{0}` as unwind rhs.", rule->second); return false; @@ -451,18 +462,12 @@ bool SymbolFileBreakpad::ParseUnwindRow(llvm::StringRef unwind_rules, return false; } - ArchSpec arch = m_obj_file->GetArchitecture(); - StreamString dwarf(Stream::eBinary, arch.GetAddressByteSize(), - arch.GetByteOrder()); - ToDWARF(*rhs, dwarf); - uint8_t *saved = m_allocator.Allocate<uint8_t>(dwarf.GetSize()); - std::memcpy(saved, dwarf.GetData(), dwarf.GetSize()); - + llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*rhs); if (lhs == ".cfa") { - row.GetCFAValue().SetIsDWARFExpression(saved, dwarf.GetSize()); + row.GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size()); } else if (const RegisterInfo *info = ResolveRegisterOrRA(resolver, lhs)) { UnwindPlan::Row::RegisterLocation loc; - loc.SetIsDWARFExpression(saved, dwarf.GetSize()); + loc.SetIsDWARFExpression(saved.data(), saved.size()); row.SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc); } else LLDB_LOG(log, "Invalid register `{0}` in unwind rule.", lhs); @@ -478,31 +483,40 @@ UnwindPlanSP SymbolFileBreakpad::GetUnwindPlan(const Address &address, const RegisterInfoResolver &resolver) { ParseUnwindData(); - const UnwindMap::Entry *entry = - m_unwind_data->FindEntryThatContains(address.GetFileAddress()); - if (!entry) - return nullptr; + if (auto *entry = + m_unwind_data->cfi.FindEntryThatContains(address.GetFileAddress())) + return ParseCFIUnwindPlan(entry->data, resolver); + if (auto *entry = + m_unwind_data->win.FindEntryThatContains(address.GetFileAddress())) + return ParseWinUnwindPlan(entry->data, resolver); + return nullptr; +} +UnwindPlanSP +SymbolFileBreakpad::ParseCFIUnwindPlan(const Bookmark &bookmark, + const RegisterInfoResolver &resolver) { addr_t base = GetBaseFileAddress(); if (base == LLDB_INVALID_ADDRESS) return nullptr; - LineIterator It(*m_obj_file, Record::StackCFI, entry->data), End(*m_obj_file); + LineIterator It(*m_objfile_sp, Record::StackCFI, bookmark), + End(*m_objfile_sp); llvm::Optional<StackCFIRecord> init_record = StackCFIRecord::parse(*It); - assert(init_record.hasValue()); - assert(init_record->Size.hasValue()); + assert(init_record.hasValue() && init_record->Size.hasValue() && + "Record already parsed successfully in ParseUnwindData!"); auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB); plan_sp->SetSourceName("breakpad STACK CFI"); plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); plan_sp->SetSourcedFromCompiler(eLazyBoolYes); plan_sp->SetPlanValidAddressRange( AddressRange(base + init_record->Address, *init_record->Size, - m_obj_file->GetModule()->GetSectionList())); + m_objfile_sp->GetModule()->GetSectionList())); auto row_sp = std::make_shared<UnwindPlan::Row>(); row_sp->SetOffset(0); - if (!ParseUnwindRow(init_record->UnwindRules, resolver, *row_sp)) + if (!ParseCFIUnwindRow(init_record->UnwindRules, resolver, *row_sp)) return nullptr; plan_sp->AppendRow(row_sp); for (++It; It != End; ++It) { @@ -514,19 +528,107 @@ SymbolFileBreakpad::GetUnwindPlan(const Address &address, row_sp = std::make_shared<UnwindPlan::Row>(*row_sp); row_sp->SetOffset(record->Address - init_record->Address); - if (!ParseUnwindRow(record->UnwindRules, resolver, *row_sp)) + if (!ParseCFIUnwindRow(record->UnwindRules, resolver, *row_sp)) return nullptr; plan_sp->AppendRow(row_sp); } return plan_sp; } -SymbolVendor &SymbolFileBreakpad::GetSymbolVendor() { - return *m_obj_file->GetModule()->GetSymbolVendor(); +UnwindPlanSP +SymbolFileBreakpad::ParseWinUnwindPlan(const Bookmark &bookmark, + const RegisterInfoResolver &resolver) { + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS); + addr_t base = GetBaseFileAddress(); + if (base == LLDB_INVALID_ADDRESS) + return nullptr; + + LineIterator It(*m_objfile_sp, Record::StackWin, bookmark); + llvm::Optional<StackWinRecord> record = StackWinRecord::parse(*It); + assert(record.hasValue() && + "Record already parsed successfully in ParseUnwindData!"); + + auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB); + plan_sp->SetSourceName("breakpad STACK WIN"); + plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); + plan_sp->SetSourcedFromCompiler(eLazyBoolYes); + plan_sp->SetPlanValidAddressRange( + AddressRange(base + record->RVA, record->CodeSize, + m_objfile_sp->GetModule()->GetSectionList())); + + auto row_sp = std::make_shared<UnwindPlan::Row>(); + row_sp->SetOffset(0); + + llvm::BumpPtrAllocator node_alloc; + std::vector<std::pair<llvm::StringRef, postfix::Node *>> program = + postfix::ParseFPOProgram(record->ProgramString, node_alloc); + + if (program.empty()) { + LLDB_LOG(log, "Invalid unwind rule: {0}.", record->ProgramString); + return nullptr; + } + auto it = program.begin(); + const auto &symbol_resolver = + [&](postfix::SymbolNode &symbol) -> postfix::Node * { + llvm::StringRef name = symbol.GetName(); + for (const auto &rule : llvm::make_range(program.begin(), it)) { + if (rule.first == name) + return rule.second; + } + if (const RegisterInfo *info = ResolveRegister(resolver, name)) + return postfix::MakeNode<postfix::RegisterNode>( + node_alloc, info->kinds[eRegisterKindLLDB]); + return nullptr; + }; + + // We assume the first value will be the CFA. It is usually called T0, but + // clang will use T1, if it needs to realign the stack. + auto *symbol = llvm::dyn_cast<postfix::SymbolNode>(it->second); + if (symbol && symbol->GetName() == ".raSearch") { + row_sp->GetCFAValue().SetRaSearch(record->LocalSize + + record->SavedRegisterSize); + } else { + if (!postfix::ResolveSymbols(it->second, symbol_resolver)) { + LLDB_LOG(log, "Resolving symbols in `{0}` failed.", + record->ProgramString); + return nullptr; + } + llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*it->second); + row_sp->GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size()); + } + + // Replace the node value with InitialValueNode, so that subsequent + // expressions refer to the CFA value instead of recomputing the whole + // expression. + it->second = postfix::MakeNode<postfix::InitialValueNode>(node_alloc); + + + // Now process the rest of the assignments. + for (++it; it != program.end(); ++it) { + const RegisterInfo *info = ResolveRegister(resolver, it->first); + // It is not an error if the resolution fails because the program may + // contain temporary variables. + if (!info) + continue; + if (!postfix::ResolveSymbols(it->second, symbol_resolver)) { + LLDB_LOG(log, "Resolving symbols in `{0}` failed.", + record->ProgramString); + return nullptr; + } + + llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*it->second); + UnwindPlan::Row::RegisterLocation loc; + loc.SetIsDWARFExpression(saved.data(), saved.size()); + row_sp->SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc); + } + + plan_sp->AppendRow(row_sp); + return plan_sp; } addr_t SymbolFileBreakpad::GetBaseFileAddress() { - return m_obj_file->GetModule() + return m_objfile_sp->GetModule() ->GetObjectFile() ->GetBaseAddress() .GetFileAddress(); @@ -569,8 +671,8 @@ void SymbolFileBreakpad::ParseCUData() { // We shall create one compile unit for each FUNC record. So, count the number // of FUNC records, and store them in m_cu_data, together with their ranges. - for (LineIterator It(*m_obj_file, Record::Func), End(*m_obj_file); It != End; - ++It) { + for (LineIterator It(*m_objfile_sp, Record::Func), End(*m_objfile_sp); + It != End; ++It) { if (auto record = FuncRecord::parse(*It)) { m_cu_data->Append(CompUnitMap::Entry(base + record->Address, record->Size, CompUnitData(It.GetBookmark()))); @@ -589,7 +691,7 @@ void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu, "How did we create compile units without a base address?"); SupportFileMap map; - data.line_table_up = llvm::make_unique<LineTable>(&cu); + data.line_table_up = std::make_unique<LineTable>(&cu); std::unique_ptr<LineSequence> line_seq_up( data.line_table_up->CreateLineSequenceContainer()); llvm::Optional<addr_t> next_addr; @@ -603,7 +705,8 @@ void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu, line_seq_up->Clear(); }; - LineIterator It(*m_obj_file, Record::Func, data.bookmark), End(*m_obj_file); + LineIterator It(*m_objfile_sp, Record::Func, data.bookmark), + End(*m_objfile_sp); assert(Record::classify(*It) == Record::Func); for (++It; It != End; ++It) { auto record = LineRecord::parse(*It); @@ -631,8 +734,8 @@ void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu, void SymbolFileBreakpad::ParseUnwindData() { if (m_unwind_data) return; - m_unwind_data.emplace(); + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS); addr_t base = GetBaseFileAddress(); if (base == LLDB_INVALID_ADDRESS) { @@ -640,14 +743,24 @@ void SymbolFileBreakpad::ParseUnwindData() { "of object file."); } - for (LineIterator It(*m_obj_file, Record::StackCFI), End(*m_obj_file); + for (LineIterator It(*m_objfile_sp, Record::StackCFI), End(*m_objfile_sp); It != End; ++It) { if (auto record = StackCFIRecord::parse(*It)) { if (record->Size) - m_unwind_data->Append(UnwindMap::Entry( + m_unwind_data->cfi.Append(UnwindMap::Entry( base + record->Address, *record->Size, It.GetBookmark())); } else LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It); } - m_unwind_data->Sort(); + m_unwind_data->cfi.Sort(); + + for (LineIterator It(*m_objfile_sp, Record::StackWin), End(*m_objfile_sp); + It != End; ++It) { + if (auto record = StackWinRecord::parse(*It)) { + m_unwind_data->win.Append(UnwindMap::Entry( + base + record->RVA, record->CodeSize, It.GetBookmark())); + } else + LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It); + } + m_unwind_data->win.Sort(); } |