15ffd83dbSDimitry Andric //===-- SymbolFileBreakpad.cpp --------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h" 100b57cec5SDimitry Andric #include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h" 110b57cec5SDimitry Andric #include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h" 120b57cec5SDimitry Andric #include "lldb/Core/Module.h" 130b57cec5SDimitry Andric #include "lldb/Core/PluginManager.h" 140b57cec5SDimitry Andric #include "lldb/Core/Section.h" 150b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h" 160b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h" 170b57cec5SDimitry Andric #include "lldb/Symbol/ObjectFile.h" 180b57cec5SDimitry Andric #include "lldb/Symbol/SymbolVendor.h" 190b57cec5SDimitry Andric #include "lldb/Symbol/TypeMap.h" 2081ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h" 210b57cec5SDimitry Andric #include "lldb/Utility/Log.h" 220b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h" 230b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 24bdd1243dSDimitry Andric #include <optional> 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace lldb; 270b57cec5SDimitry Andric using namespace lldb_private; 280b57cec5SDimitry Andric using namespace lldb_private::breakpad; 290b57cec5SDimitry Andric 305ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(SymbolFileBreakpad) 315ffd83dbSDimitry Andric 32480093f4SDimitry Andric char SymbolFileBreakpad::ID; 33480093f4SDimitry Andric 340b57cec5SDimitry Andric class SymbolFileBreakpad::LineIterator { 350b57cec5SDimitry Andric public: 360b57cec5SDimitry Andric // begin iterator for sections of given type 370b57cec5SDimitry Andric LineIterator(ObjectFile &obj, Record::Kind section_type) 380b57cec5SDimitry Andric : m_obj(&obj), m_section_type(toString(section_type)), 390b57cec5SDimitry Andric m_next_section_idx(0), m_next_line(llvm::StringRef::npos) { 400b57cec5SDimitry Andric ++*this; 410b57cec5SDimitry Andric } 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric // An iterator starting at the position given by the bookmark. 440b57cec5SDimitry Andric LineIterator(ObjectFile &obj, Record::Kind section_type, Bookmark bookmark); 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric // end iterator 470b57cec5SDimitry Andric explicit LineIterator(ObjectFile &obj) 480b57cec5SDimitry Andric : m_obj(&obj), 490b57cec5SDimitry Andric m_next_section_idx(m_obj->GetSectionList()->GetNumSections(0)), 500b57cec5SDimitry Andric m_current_line(llvm::StringRef::npos), 510b57cec5SDimitry Andric m_next_line(llvm::StringRef::npos) {} 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric friend bool operator!=(const LineIterator &lhs, const LineIterator &rhs) { 540b57cec5SDimitry Andric assert(lhs.m_obj == rhs.m_obj); 550b57cec5SDimitry Andric if (lhs.m_next_section_idx != rhs.m_next_section_idx) 560b57cec5SDimitry Andric return true; 570b57cec5SDimitry Andric if (lhs.m_current_line != rhs.m_current_line) 580b57cec5SDimitry Andric return true; 590b57cec5SDimitry Andric assert(lhs.m_next_line == rhs.m_next_line); 600b57cec5SDimitry Andric return false; 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric const LineIterator &operator++(); 640b57cec5SDimitry Andric llvm::StringRef operator*() const { 650b57cec5SDimitry Andric return m_section_text.slice(m_current_line, m_next_line); 660b57cec5SDimitry Andric } 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric Bookmark GetBookmark() const { 690b57cec5SDimitry Andric return Bookmark{m_next_section_idx, m_current_line}; 700b57cec5SDimitry Andric } 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric private: 730b57cec5SDimitry Andric ObjectFile *m_obj; 740b57cec5SDimitry Andric ConstString m_section_type; 750b57cec5SDimitry Andric uint32_t m_next_section_idx; 760b57cec5SDimitry Andric llvm::StringRef m_section_text; 770b57cec5SDimitry Andric size_t m_current_line; 780b57cec5SDimitry Andric size_t m_next_line; 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric void FindNextLine() { 810b57cec5SDimitry Andric m_next_line = m_section_text.find('\n', m_current_line); 820b57cec5SDimitry Andric if (m_next_line != llvm::StringRef::npos) { 830b57cec5SDimitry Andric ++m_next_line; 840b57cec5SDimitry Andric if (m_next_line >= m_section_text.size()) 850b57cec5SDimitry Andric m_next_line = llvm::StringRef::npos; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric }; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric SymbolFileBreakpad::LineIterator::LineIterator(ObjectFile &obj, 910b57cec5SDimitry Andric Record::Kind section_type, 920b57cec5SDimitry Andric Bookmark bookmark) 930b57cec5SDimitry Andric : m_obj(&obj), m_section_type(toString(section_type)), 940b57cec5SDimitry Andric m_next_section_idx(bookmark.section), m_current_line(bookmark.offset) { 950b57cec5SDimitry Andric Section § = 960b57cec5SDimitry Andric *obj.GetSectionList()->GetSectionAtIndex(m_next_section_idx - 1); 970b57cec5SDimitry Andric assert(sect.GetName() == m_section_type); 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric DataExtractor data; 1000b57cec5SDimitry Andric obj.ReadSectionData(§, data); 1010b57cec5SDimitry Andric m_section_text = toStringRef(data.GetData()); 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric assert(m_current_line < m_section_text.size()); 1040b57cec5SDimitry Andric FindNextLine(); 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric const SymbolFileBreakpad::LineIterator & 1080b57cec5SDimitry Andric SymbolFileBreakpad::LineIterator::operator++() { 1090b57cec5SDimitry Andric const SectionList &list = *m_obj->GetSectionList(); 1100b57cec5SDimitry Andric size_t num_sections = list.GetNumSections(0); 1110b57cec5SDimitry Andric while (m_next_line != llvm::StringRef::npos || 1120b57cec5SDimitry Andric m_next_section_idx < num_sections) { 1130b57cec5SDimitry Andric if (m_next_line != llvm::StringRef::npos) { 1140b57cec5SDimitry Andric m_current_line = m_next_line; 1150b57cec5SDimitry Andric FindNextLine(); 1160b57cec5SDimitry Andric return *this; 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric Section § = *list.GetSectionAtIndex(m_next_section_idx++); 1200b57cec5SDimitry Andric if (sect.GetName() != m_section_type) 1210b57cec5SDimitry Andric continue; 1220b57cec5SDimitry Andric DataExtractor data; 1230b57cec5SDimitry Andric m_obj->ReadSectionData(§, data); 1240b57cec5SDimitry Andric m_section_text = toStringRef(data.GetData()); 1250b57cec5SDimitry Andric m_next_line = 0; 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric // We've reached the end. 1280b57cec5SDimitry Andric m_current_line = m_next_line; 1290b57cec5SDimitry Andric return *this; 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric llvm::iterator_range<SymbolFileBreakpad::LineIterator> 1330b57cec5SDimitry Andric SymbolFileBreakpad::lines(Record::Kind section_type) { 1349dba64beSDimitry Andric return llvm::make_range(LineIterator(*m_objfile_sp, section_type), 1359dba64beSDimitry Andric LineIterator(*m_objfile_sp)); 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric namespace { 1390b57cec5SDimitry Andric // A helper class for constructing the list of support files for a given compile 1400b57cec5SDimitry Andric // unit. 1410b57cec5SDimitry Andric class SupportFileMap { 1420b57cec5SDimitry Andric public: 1430b57cec5SDimitry Andric // Given a breakpad file ID, return a file ID to be used in the support files 1440b57cec5SDimitry Andric // for this compile unit. 1450b57cec5SDimitry Andric size_t operator[](size_t file) { 1460b57cec5SDimitry Andric return m_map.try_emplace(file, m_map.size() + 1).first->second; 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric // Construct a FileSpecList containing only the support files relevant for 1500b57cec5SDimitry Andric // this compile unit (in the correct order). 1510b57cec5SDimitry Andric FileSpecList translate(const FileSpec &cu_spec, 1520b57cec5SDimitry Andric llvm::ArrayRef<FileSpec> all_files); 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric private: 1550b57cec5SDimitry Andric llvm::DenseMap<size_t, size_t> m_map; 1560b57cec5SDimitry Andric }; 1570b57cec5SDimitry Andric } // namespace 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric FileSpecList SupportFileMap::translate(const FileSpec &cu_spec, 1600b57cec5SDimitry Andric llvm::ArrayRef<FileSpec> all_files) { 1610b57cec5SDimitry Andric std::vector<FileSpec> result; 1620b57cec5SDimitry Andric result.resize(m_map.size() + 1); 1630b57cec5SDimitry Andric result[0] = cu_spec; 1640b57cec5SDimitry Andric for (const auto &KV : m_map) { 1650b57cec5SDimitry Andric if (KV.first < all_files.size()) 1660b57cec5SDimitry Andric result[KV.second] = all_files[KV.first]; 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric return FileSpecList(std::move(result)); 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric void SymbolFileBreakpad::Initialize() { 1720b57cec5SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(), 1730b57cec5SDimitry Andric GetPluginDescriptionStatic(), CreateInstance, 1740b57cec5SDimitry Andric DebuggerInitialize); 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric void SymbolFileBreakpad::Terminate() { 1780b57cec5SDimitry Andric PluginManager::UnregisterPlugin(CreateInstance); 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric uint32_t SymbolFileBreakpad::CalculateAbilities() { 1829dba64beSDimitry Andric if (!m_objfile_sp || !llvm::isa<ObjectFileBreakpad>(*m_objfile_sp)) 1830b57cec5SDimitry Andric return 0; 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric return CompileUnits | Functions | LineTables; 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric 1889dba64beSDimitry Andric uint32_t SymbolFileBreakpad::CalculateNumCompileUnits() { 1890b57cec5SDimitry Andric ParseCUData(); 1900b57cec5SDimitry Andric return m_cu_data->GetSize(); 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric CompUnitSP SymbolFileBreakpad::ParseCompileUnitAtIndex(uint32_t index) { 1940b57cec5SDimitry Andric if (index >= m_cu_data->GetSize()) 1950b57cec5SDimitry Andric return nullptr; 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric CompUnitData &data = m_cu_data->GetEntryRef(index).data; 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric ParseFileRecords(); 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric FileSpec spec; 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric // The FileSpec of the compile unit will be the file corresponding to the 2040b57cec5SDimitry Andric // first LINE record. 2059dba64beSDimitry Andric LineIterator It(*m_objfile_sp, Record::Func, data.bookmark), 2069dba64beSDimitry Andric End(*m_objfile_sp); 2070b57cec5SDimitry Andric assert(Record::classify(*It) == Record::Func); 2080b57cec5SDimitry Andric ++It; // Skip FUNC record. 209349cc55cSDimitry Andric // Skip INLINE records. 210349cc55cSDimitry Andric while (It != End && Record::classify(*It) == Record::Inline) 211349cc55cSDimitry Andric ++It; 212349cc55cSDimitry Andric 2130b57cec5SDimitry Andric if (It != End) { 2140b57cec5SDimitry Andric auto record = LineRecord::parse(*It); 2150b57cec5SDimitry Andric if (record && record->FileNum < m_files->size()) 2160b57cec5SDimitry Andric spec = (*m_files)[record->FileNum]; 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric 2197a6dacacSDimitry Andric auto cu_sp = std::make_shared<CompileUnit>( 2207a6dacacSDimitry Andric m_objfile_sp->GetModule(), 2217a6dacacSDimitry Andric /*user_data*/ nullptr, std::make_shared<SupportFile>(spec), index, 2220b57cec5SDimitry Andric eLanguageTypeUnknown, 2230b57cec5SDimitry Andric /*is_optimized*/ eLazyBoolNo); 2240b57cec5SDimitry Andric 2259dba64beSDimitry Andric SetCompileUnitAtIndex(index, cu_sp); 2260b57cec5SDimitry Andric return cu_sp; 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric 229349cc55cSDimitry Andric FunctionSP SymbolFileBreakpad::GetOrCreateFunction(CompileUnit &comp_unit) { 230349cc55cSDimitry Andric user_id_t id = comp_unit.GetID(); 231349cc55cSDimitry Andric if (FunctionSP func_sp = comp_unit.FindFunctionByUID(id)) 232349cc55cSDimitry Andric return func_sp; 233349cc55cSDimitry Andric 23481ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Symbols); 235349cc55cSDimitry Andric FunctionSP func_sp; 236349cc55cSDimitry Andric addr_t base = GetBaseFileAddress(); 237349cc55cSDimitry Andric if (base == LLDB_INVALID_ADDRESS) { 238349cc55cSDimitry Andric LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping " 239349cc55cSDimitry Andric "symtab population."); 240349cc55cSDimitry Andric return func_sp; 241349cc55cSDimitry Andric } 242349cc55cSDimitry Andric 243349cc55cSDimitry Andric const SectionList *list = comp_unit.GetModule()->GetSectionList(); 244349cc55cSDimitry Andric CompUnitData &data = m_cu_data->GetEntryRef(id).data; 245349cc55cSDimitry Andric LineIterator It(*m_objfile_sp, Record::Func, data.bookmark); 246349cc55cSDimitry Andric assert(Record::classify(*It) == Record::Func); 247349cc55cSDimitry Andric 248349cc55cSDimitry Andric if (auto record = FuncRecord::parse(*It)) { 249349cc55cSDimitry Andric Mangled func_name; 25006c3fb27SDimitry Andric func_name.SetValue(ConstString(record->Name)); 251349cc55cSDimitry Andric addr_t address = record->Address + base; 252349cc55cSDimitry Andric SectionSP section_sp = list->FindSectionContainingFileAddress(address); 253349cc55cSDimitry Andric if (section_sp) { 254349cc55cSDimitry Andric AddressRange func_range( 255349cc55cSDimitry Andric section_sp, address - section_sp->GetFileAddress(), record->Size); 256349cc55cSDimitry Andric // Use the CU's id because every CU has only one function inside. 257349cc55cSDimitry Andric func_sp = std::make_shared<Function>(&comp_unit, id, 0, func_name, 258349cc55cSDimitry Andric nullptr, func_range); 259349cc55cSDimitry Andric comp_unit.AddFunction(func_sp); 260349cc55cSDimitry Andric } 261349cc55cSDimitry Andric } 262349cc55cSDimitry Andric return func_sp; 263349cc55cSDimitry Andric } 264349cc55cSDimitry Andric 2650b57cec5SDimitry Andric size_t SymbolFileBreakpad::ParseFunctions(CompileUnit &comp_unit) { 266349cc55cSDimitry Andric std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); 267349cc55cSDimitry Andric return GetOrCreateFunction(comp_unit) ? 1 : 0; 2680b57cec5SDimitry Andric } 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric bool SymbolFileBreakpad::ParseLineTable(CompileUnit &comp_unit) { 2719dba64beSDimitry Andric std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); 2720b57cec5SDimitry Andric CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data; 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric if (!data.line_table_up) 2750b57cec5SDimitry Andric ParseLineTableAndSupportFiles(comp_unit, data); 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric comp_unit.SetLineTable(data.line_table_up.release()); 2780b57cec5SDimitry Andric return true; 2790b57cec5SDimitry Andric } 2800b57cec5SDimitry Andric 2810b57cec5SDimitry Andric bool SymbolFileBreakpad::ParseSupportFiles(CompileUnit &comp_unit, 2821db9f3b2SDimitry Andric SupportFileList &support_files) { 2839dba64beSDimitry Andric std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); 2840b57cec5SDimitry Andric CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data; 2850b57cec5SDimitry Andric if (!data.support_files) 2860b57cec5SDimitry Andric ParseLineTableAndSupportFiles(comp_unit, data); 2870b57cec5SDimitry Andric 2881db9f3b2SDimitry Andric for (auto &fs : *data.support_files) 2891db9f3b2SDimitry Andric support_files.Append(fs); 2900b57cec5SDimitry Andric return true; 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric 293349cc55cSDimitry Andric size_t SymbolFileBreakpad::ParseBlocksRecursive(Function &func) { 294349cc55cSDimitry Andric std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); 295349cc55cSDimitry Andric CompileUnit *comp_unit = func.GetCompileUnit(); 296349cc55cSDimitry Andric lldbassert(comp_unit); 297349cc55cSDimitry Andric ParseInlineOriginRecords(); 298349cc55cSDimitry Andric // A vector of current each level's parent block. For example, when parsing 299349cc55cSDimitry Andric // "INLINE 0 ...", the current level is 0 and its parent block is the 300bdd1243dSDimitry Andric // function block at index 0. 301349cc55cSDimitry Andric std::vector<Block *> blocks; 302349cc55cSDimitry Andric Block &block = func.GetBlock(false); 303349cc55cSDimitry Andric block.AddRange(Block::Range(0, func.GetAddressRange().GetByteSize())); 304349cc55cSDimitry Andric blocks.push_back(&block); 305349cc55cSDimitry Andric 306349cc55cSDimitry Andric size_t blocks_added = 0; 307349cc55cSDimitry Andric addr_t func_base = func.GetAddressRange().GetBaseAddress().GetOffset(); 308349cc55cSDimitry Andric CompUnitData &data = m_cu_data->GetEntryRef(comp_unit->GetID()).data; 309349cc55cSDimitry Andric LineIterator It(*m_objfile_sp, Record::Func, data.bookmark), 310349cc55cSDimitry Andric End(*m_objfile_sp); 311349cc55cSDimitry Andric ++It; // Skip the FUNC record. 312349cc55cSDimitry Andric size_t last_added_nest_level = 0; 313349cc55cSDimitry Andric while (It != End && Record::classify(*It) == Record::Inline) { 314349cc55cSDimitry Andric if (auto record = InlineRecord::parse(*It)) { 315349cc55cSDimitry Andric if (record->InlineNestLevel == 0 || 316349cc55cSDimitry Andric record->InlineNestLevel <= last_added_nest_level + 1) { 317349cc55cSDimitry Andric last_added_nest_level = record->InlineNestLevel; 318349cc55cSDimitry Andric BlockSP block_sp = std::make_shared<Block>(It.GetBookmark().offset); 319349cc55cSDimitry Andric FileSpec callsite_file; 320349cc55cSDimitry Andric if (record->CallSiteFileNum < m_files->size()) 321349cc55cSDimitry Andric callsite_file = (*m_files)[record->CallSiteFileNum]; 322349cc55cSDimitry Andric llvm::StringRef name; 323349cc55cSDimitry Andric if (record->OriginNum < m_inline_origins->size()) 324349cc55cSDimitry Andric name = (*m_inline_origins)[record->OriginNum]; 325349cc55cSDimitry Andric 326349cc55cSDimitry Andric Declaration callsite(callsite_file, record->CallSiteLineNum); 327349cc55cSDimitry Andric block_sp->SetInlinedFunctionInfo(name.str().c_str(), 328349cc55cSDimitry Andric /*mangled=*/nullptr, 329349cc55cSDimitry Andric /*decl_ptr=*/nullptr, &callsite); 330349cc55cSDimitry Andric for (const auto &range : record->Ranges) { 331349cc55cSDimitry Andric block_sp->AddRange( 332349cc55cSDimitry Andric Block::Range(range.first - func_base, range.second)); 333349cc55cSDimitry Andric } 334349cc55cSDimitry Andric block_sp->FinalizeRanges(); 335349cc55cSDimitry Andric 336349cc55cSDimitry Andric blocks[record->InlineNestLevel]->AddChild(block_sp); 337349cc55cSDimitry Andric if (record->InlineNestLevel + 1 >= blocks.size()) { 338349cc55cSDimitry Andric blocks.resize(blocks.size() + 1); 339349cc55cSDimitry Andric } 340349cc55cSDimitry Andric blocks[record->InlineNestLevel + 1] = block_sp.get(); 341349cc55cSDimitry Andric ++blocks_added; 342349cc55cSDimitry Andric } 343349cc55cSDimitry Andric } 344349cc55cSDimitry Andric ++It; 345349cc55cSDimitry Andric } 346349cc55cSDimitry Andric return blocks_added; 347349cc55cSDimitry Andric } 348349cc55cSDimitry Andric 349349cc55cSDimitry Andric void SymbolFileBreakpad::ParseInlineOriginRecords() { 350349cc55cSDimitry Andric if (m_inline_origins) 351349cc55cSDimitry Andric return; 352349cc55cSDimitry Andric m_inline_origins.emplace(); 353349cc55cSDimitry Andric 35481ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Symbols); 355349cc55cSDimitry Andric for (llvm::StringRef line : lines(Record::InlineOrigin)) { 356349cc55cSDimitry Andric auto record = InlineOriginRecord::parse(line); 357349cc55cSDimitry Andric if (!record) { 358349cc55cSDimitry Andric LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line); 359349cc55cSDimitry Andric continue; 360349cc55cSDimitry Andric } 361349cc55cSDimitry Andric 362349cc55cSDimitry Andric if (record->Number >= m_inline_origins->size()) 363349cc55cSDimitry Andric m_inline_origins->resize(record->Number + 1); 364349cc55cSDimitry Andric (*m_inline_origins)[record->Number] = record->Name; 365349cc55cSDimitry Andric } 366349cc55cSDimitry Andric } 367349cc55cSDimitry Andric 3680b57cec5SDimitry Andric uint32_t 3690b57cec5SDimitry Andric SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr, 3700b57cec5SDimitry Andric SymbolContextItem resolve_scope, 3710b57cec5SDimitry Andric SymbolContext &sc) { 3729dba64beSDimitry Andric std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); 373349cc55cSDimitry Andric if (!(resolve_scope & (eSymbolContextCompUnit | eSymbolContextLineEntry | 374349cc55cSDimitry Andric eSymbolContextFunction | eSymbolContextBlock))) 3750b57cec5SDimitry Andric return 0; 3760b57cec5SDimitry Andric 3770b57cec5SDimitry Andric ParseCUData(); 3780b57cec5SDimitry Andric uint32_t idx = 3790b57cec5SDimitry Andric m_cu_data->FindEntryIndexThatContains(so_addr.GetFileAddress()); 3800b57cec5SDimitry Andric if (idx == UINT32_MAX) 3810b57cec5SDimitry Andric return 0; 3820b57cec5SDimitry Andric 3839dba64beSDimitry Andric sc.comp_unit = GetCompileUnitAtIndex(idx).get(); 3840b57cec5SDimitry Andric SymbolContextItem result = eSymbolContextCompUnit; 3850b57cec5SDimitry Andric if (resolve_scope & eSymbolContextLineEntry) { 3860b57cec5SDimitry Andric if (sc.comp_unit->GetLineTable()->FindLineEntryByAddress(so_addr, 3870b57cec5SDimitry Andric sc.line_entry)) { 3880b57cec5SDimitry Andric result |= eSymbolContextLineEntry; 3890b57cec5SDimitry Andric } 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric 392349cc55cSDimitry Andric if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) { 393349cc55cSDimitry Andric FunctionSP func_sp = GetOrCreateFunction(*sc.comp_unit); 394349cc55cSDimitry Andric if (func_sp) { 395349cc55cSDimitry Andric sc.function = func_sp.get(); 396349cc55cSDimitry Andric result |= eSymbolContextFunction; 397349cc55cSDimitry Andric if (resolve_scope & eSymbolContextBlock) { 398349cc55cSDimitry Andric Block &block = func_sp->GetBlock(true); 399349cc55cSDimitry Andric sc.block = block.FindInnermostBlockByOffset( 400349cc55cSDimitry Andric so_addr.GetFileAddress() - 401349cc55cSDimitry Andric sc.function->GetAddressRange().GetBaseAddress().GetFileAddress()); 402349cc55cSDimitry Andric if (sc.block) 403349cc55cSDimitry Andric result |= eSymbolContextBlock; 404349cc55cSDimitry Andric } 405349cc55cSDimitry Andric } 406349cc55cSDimitry Andric } 407349cc55cSDimitry Andric 4080b57cec5SDimitry Andric return result; 4090b57cec5SDimitry Andric } 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric uint32_t SymbolFileBreakpad::ResolveSymbolContext( 412fe6060f1SDimitry Andric const SourceLocationSpec &src_location_spec, 4130b57cec5SDimitry Andric lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) { 4149dba64beSDimitry Andric std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); 4150b57cec5SDimitry Andric if (!(resolve_scope & eSymbolContextCompUnit)) 4160b57cec5SDimitry Andric return 0; 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric uint32_t old_size = sc_list.GetSize(); 4190b57cec5SDimitry Andric for (size_t i = 0, size = GetNumCompileUnits(); i < size; ++i) { 4209dba64beSDimitry Andric CompileUnit &cu = *GetCompileUnitAtIndex(i); 421fe6060f1SDimitry Andric cu.ResolveSymbolContext(src_location_spec, resolve_scope, sc_list); 4220b57cec5SDimitry Andric } 4230b57cec5SDimitry Andric return sc_list.GetSize() - old_size; 4240b57cec5SDimitry Andric } 4250b57cec5SDimitry Andric 4269dba64beSDimitry Andric void SymbolFileBreakpad::FindFunctions( 427bdd1243dSDimitry Andric const Module::LookupInfo &lookup_info, 428bdd1243dSDimitry Andric const CompilerDeclContext &parent_decl_ctx, bool include_inlines, 4290b57cec5SDimitry Andric SymbolContextList &sc_list) { 430349cc55cSDimitry Andric std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); 431349cc55cSDimitry Andric // TODO: Implement this with supported FunctionNameType. 432349cc55cSDimitry Andric 433bdd1243dSDimitry Andric ConstString name = lookup_info.GetLookupName(); 434349cc55cSDimitry Andric for (uint32_t i = 0; i < GetNumCompileUnits(); ++i) { 435349cc55cSDimitry Andric CompUnitSP cu_sp = GetCompileUnitAtIndex(i); 436349cc55cSDimitry Andric FunctionSP func_sp = GetOrCreateFunction(*cu_sp); 437349cc55cSDimitry Andric if (func_sp && name == func_sp->GetNameNoArguments()) { 438349cc55cSDimitry Andric SymbolContext sc; 439349cc55cSDimitry Andric sc.comp_unit = cu_sp.get(); 440349cc55cSDimitry Andric sc.function = func_sp.get(); 441349cc55cSDimitry Andric sc.module_sp = func_sp->CalculateSymbolContextModule(); 442349cc55cSDimitry Andric sc_list.Append(sc); 443349cc55cSDimitry Andric } 444349cc55cSDimitry Andric } 4450b57cec5SDimitry Andric } 4460b57cec5SDimitry Andric 4479dba64beSDimitry Andric void SymbolFileBreakpad::FindFunctions(const RegularExpression ®ex, 4489dba64beSDimitry Andric bool include_inlines, 4490b57cec5SDimitry Andric SymbolContextList &sc_list) { 4500b57cec5SDimitry Andric // TODO 4510b57cec5SDimitry Andric } 4520b57cec5SDimitry Andric 4530b57cec5SDimitry Andric void SymbolFileBreakpad::AddSymbols(Symtab &symtab) { 45481ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Symbols); 4559dba64beSDimitry Andric Module &module = *m_objfile_sp->GetModule(); 4560b57cec5SDimitry Andric addr_t base = GetBaseFileAddress(); 4570b57cec5SDimitry Andric if (base == LLDB_INVALID_ADDRESS) { 4580b57cec5SDimitry Andric LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping " 4590b57cec5SDimitry Andric "symtab population."); 4600b57cec5SDimitry Andric return; 4610b57cec5SDimitry Andric } 4620b57cec5SDimitry Andric 4630b57cec5SDimitry Andric const SectionList &list = *module.GetSectionList(); 464e8d8bef9SDimitry Andric llvm::DenseSet<addr_t> found_symbol_addresses; 465e8d8bef9SDimitry Andric std::vector<Symbol> symbols; 466bdd1243dSDimitry Andric auto add_symbol = [&](addr_t address, std::optional<addr_t> size, 4670b57cec5SDimitry Andric llvm::StringRef name) { 4680b57cec5SDimitry Andric address += base; 4690b57cec5SDimitry Andric SectionSP section_sp = list.FindSectionContainingFileAddress(address); 4700b57cec5SDimitry Andric if (!section_sp) { 4710b57cec5SDimitry Andric LLDB_LOG(log, 4720b57cec5SDimitry Andric "Ignoring symbol {0}, whose address ({1}) is outside of the " 4730b57cec5SDimitry Andric "object file. Mismatched symbol file?", 4740b57cec5SDimitry Andric name, address); 4750b57cec5SDimitry Andric return; 4760b57cec5SDimitry Andric } 477e8d8bef9SDimitry Andric // Keep track of what addresses were already added so far and only add 478e8d8bef9SDimitry Andric // the symbol with the first address. 479e8d8bef9SDimitry Andric if (!found_symbol_addresses.insert(address).second) 480e8d8bef9SDimitry Andric return; 481e8d8bef9SDimitry Andric symbols.emplace_back( 482e8d8bef9SDimitry Andric /*symID*/ 0, Mangled(name), eSymbolTypeCode, 4839dba64beSDimitry Andric /*is_global*/ true, /*is_debug*/ false, 4840b57cec5SDimitry Andric /*is_trampoline*/ false, /*is_artificial*/ false, 4850b57cec5SDimitry Andric AddressRange(section_sp, address - section_sp->GetFileAddress(), 48681ad6265SDimitry Andric size.value_or(0)), 48781ad6265SDimitry Andric size.has_value(), /*contains_linker_annotations*/ false, /*flags*/ 0); 4880b57cec5SDimitry Andric }; 4890b57cec5SDimitry Andric 4900b57cec5SDimitry Andric for (llvm::StringRef line : lines(Record::Public)) { 4910b57cec5SDimitry Andric if (auto record = PublicRecord::parse(line)) 492bdd1243dSDimitry Andric add_symbol(record->Address, std::nullopt, record->Name); 4930b57cec5SDimitry Andric else 4940b57cec5SDimitry Andric LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line); 4950b57cec5SDimitry Andric } 4960b57cec5SDimitry Andric 497e8d8bef9SDimitry Andric for (Symbol &symbol : symbols) 498e8d8bef9SDimitry Andric symtab.AddSymbol(std::move(symbol)); 4994824e7fdSDimitry Andric symtab.Finalize(); 5000b57cec5SDimitry Andric } 5010b57cec5SDimitry Andric 5029dba64beSDimitry Andric llvm::Expected<lldb::addr_t> 5039dba64beSDimitry Andric SymbolFileBreakpad::GetParameterStackSize(Symbol &symbol) { 5049dba64beSDimitry Andric ParseUnwindData(); 5059dba64beSDimitry Andric if (auto *entry = m_unwind_data->win.FindEntryThatContains( 5069dba64beSDimitry Andric symbol.GetAddress().GetFileAddress())) { 5079dba64beSDimitry Andric auto record = StackWinRecord::parse( 5089dba64beSDimitry Andric *LineIterator(*m_objfile_sp, Record::StackWin, entry->data)); 50981ad6265SDimitry Andric assert(record); 5109dba64beSDimitry Andric return record->ParameterSize; 5119dba64beSDimitry Andric } 5129dba64beSDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 5139dba64beSDimitry Andric "Parameter size unknown."); 5149dba64beSDimitry Andric } 5159dba64beSDimitry Andric 516bdd1243dSDimitry Andric static std::optional<std::pair<llvm::StringRef, llvm::StringRef>> 5170b57cec5SDimitry Andric GetRule(llvm::StringRef &unwind_rules) { 5180b57cec5SDimitry Andric // Unwind rules are of the form 5190b57cec5SDimitry Andric // register1: expression1 register2: expression2 ... 5200b57cec5SDimitry Andric // We assume none of the tokens in expression<n> end with a colon. 5210b57cec5SDimitry Andric 5220b57cec5SDimitry Andric llvm::StringRef lhs, rest; 5230b57cec5SDimitry Andric std::tie(lhs, rest) = getToken(unwind_rules); 5240b57cec5SDimitry Andric if (!lhs.consume_back(":")) 525bdd1243dSDimitry Andric return std::nullopt; 5260b57cec5SDimitry Andric 5270b57cec5SDimitry Andric // Seek forward to the next register: expression pair 5280b57cec5SDimitry Andric llvm::StringRef::size_type pos = rest.find(": "); 5290b57cec5SDimitry Andric if (pos == llvm::StringRef::npos) { 5300b57cec5SDimitry Andric // No pair found, this means the rest of the string is a single expression. 5310b57cec5SDimitry Andric unwind_rules = llvm::StringRef(); 5320b57cec5SDimitry Andric return std::make_pair(lhs, rest); 5330b57cec5SDimitry Andric } 5340b57cec5SDimitry Andric 5350b57cec5SDimitry Andric // Go back one token to find the end of the current rule. 5360b57cec5SDimitry Andric pos = rest.rfind(' ', pos); 5370b57cec5SDimitry Andric if (pos == llvm::StringRef::npos) 538bdd1243dSDimitry Andric return std::nullopt; 5390b57cec5SDimitry Andric 5400b57cec5SDimitry Andric llvm::StringRef rhs = rest.take_front(pos); 5410b57cec5SDimitry Andric unwind_rules = rest.drop_front(pos); 5420b57cec5SDimitry Andric return std::make_pair(lhs, rhs); 5430b57cec5SDimitry Andric } 5440b57cec5SDimitry Andric 5450b57cec5SDimitry Andric static const RegisterInfo * 5465ffd83dbSDimitry Andric ResolveRegister(const llvm::Triple &triple, 5475ffd83dbSDimitry Andric const SymbolFile::RegisterInfoResolver &resolver, 5480b57cec5SDimitry Andric llvm::StringRef name) { 5495ffd83dbSDimitry Andric if (triple.isX86() || triple.isMIPS()) { 5505ffd83dbSDimitry Andric // X86 and MIPS registers have '$' in front of their register names. Arm and 5515ffd83dbSDimitry Andric // AArch64 don't. 5525ffd83dbSDimitry Andric if (!name.consume_front("$")) 5530b57cec5SDimitry Andric return nullptr; 5540b57cec5SDimitry Andric } 5555ffd83dbSDimitry Andric return resolver.ResolveName(name); 5565ffd83dbSDimitry Andric } 5570b57cec5SDimitry Andric 5580b57cec5SDimitry Andric static const RegisterInfo * 5595ffd83dbSDimitry Andric ResolveRegisterOrRA(const llvm::Triple &triple, 5605ffd83dbSDimitry Andric const SymbolFile::RegisterInfoResolver &resolver, 5610b57cec5SDimitry Andric llvm::StringRef name) { 5620b57cec5SDimitry Andric if (name == ".ra") 5630b57cec5SDimitry Andric return resolver.ResolveNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); 5645ffd83dbSDimitry Andric return ResolveRegister(triple, resolver, name); 5650b57cec5SDimitry Andric } 5660b57cec5SDimitry Andric 5679dba64beSDimitry Andric llvm::ArrayRef<uint8_t> SymbolFileBreakpad::SaveAsDWARF(postfix::Node &node) { 5689dba64beSDimitry Andric ArchSpec arch = m_objfile_sp->GetArchitecture(); 5699dba64beSDimitry Andric StreamString dwarf(Stream::eBinary, arch.GetAddressByteSize(), 5709dba64beSDimitry Andric arch.GetByteOrder()); 5719dba64beSDimitry Andric ToDWARF(node, dwarf); 5729dba64beSDimitry Andric uint8_t *saved = m_allocator.Allocate<uint8_t>(dwarf.GetSize()); 5739dba64beSDimitry Andric std::memcpy(saved, dwarf.GetData(), dwarf.GetSize()); 5749dba64beSDimitry Andric return {saved, dwarf.GetSize()}; 5759dba64beSDimitry Andric } 5769dba64beSDimitry Andric 5779dba64beSDimitry Andric bool SymbolFileBreakpad::ParseCFIUnwindRow(llvm::StringRef unwind_rules, 5780b57cec5SDimitry Andric const RegisterInfoResolver &resolver, 5790b57cec5SDimitry Andric UnwindPlan::Row &row) { 58081ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Symbols); 5810b57cec5SDimitry Andric 5820b57cec5SDimitry Andric llvm::BumpPtrAllocator node_alloc; 5835ffd83dbSDimitry Andric llvm::Triple triple = m_objfile_sp->GetArchitecture().GetTriple(); 5840b57cec5SDimitry Andric while (auto rule = GetRule(unwind_rules)) { 5850b57cec5SDimitry Andric node_alloc.Reset(); 5860b57cec5SDimitry Andric llvm::StringRef lhs = rule->first; 5879dba64beSDimitry Andric postfix::Node *rhs = postfix::ParseOneExpression(rule->second, node_alloc); 5880b57cec5SDimitry Andric if (!rhs) { 5890b57cec5SDimitry Andric LLDB_LOG(log, "Could not parse `{0}` as unwind rhs.", rule->second); 5900b57cec5SDimitry Andric return false; 5910b57cec5SDimitry Andric } 5920b57cec5SDimitry Andric 5930b57cec5SDimitry Andric bool success = postfix::ResolveSymbols( 5940b57cec5SDimitry Andric rhs, [&](postfix::SymbolNode &symbol) -> postfix::Node * { 5950b57cec5SDimitry Andric llvm::StringRef name = symbol.GetName(); 5960b57cec5SDimitry Andric if (name == ".cfa" && lhs != ".cfa") 5970b57cec5SDimitry Andric return postfix::MakeNode<postfix::InitialValueNode>(node_alloc); 5980b57cec5SDimitry Andric 5995ffd83dbSDimitry Andric if (const RegisterInfo *info = 6005ffd83dbSDimitry Andric ResolveRegister(triple, resolver, name)) { 6010b57cec5SDimitry Andric return postfix::MakeNode<postfix::RegisterNode>( 6020b57cec5SDimitry Andric node_alloc, info->kinds[eRegisterKindLLDB]); 6030b57cec5SDimitry Andric } 6040b57cec5SDimitry Andric return nullptr; 6050b57cec5SDimitry Andric }); 6060b57cec5SDimitry Andric 6070b57cec5SDimitry Andric if (!success) { 6080b57cec5SDimitry Andric LLDB_LOG(log, "Resolving symbols in `{0}` failed.", rule->second); 6090b57cec5SDimitry Andric return false; 6100b57cec5SDimitry Andric } 6110b57cec5SDimitry Andric 6129dba64beSDimitry Andric llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*rhs); 6130b57cec5SDimitry Andric if (lhs == ".cfa") { 6149dba64beSDimitry Andric row.GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size()); 6155ffd83dbSDimitry Andric } else if (const RegisterInfo *info = 6165ffd83dbSDimitry Andric ResolveRegisterOrRA(triple, resolver, lhs)) { 6170b57cec5SDimitry Andric UnwindPlan::Row::RegisterLocation loc; 6189dba64beSDimitry Andric loc.SetIsDWARFExpression(saved.data(), saved.size()); 6190b57cec5SDimitry Andric row.SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc); 6200b57cec5SDimitry Andric } else 6210b57cec5SDimitry Andric LLDB_LOG(log, "Invalid register `{0}` in unwind rule.", lhs); 6220b57cec5SDimitry Andric } 6230b57cec5SDimitry Andric if (unwind_rules.empty()) 6240b57cec5SDimitry Andric return true; 6250b57cec5SDimitry Andric 6260b57cec5SDimitry Andric LLDB_LOG(log, "Could not parse `{0}` as an unwind rule.", unwind_rules); 6270b57cec5SDimitry Andric return false; 6280b57cec5SDimitry Andric } 6290b57cec5SDimitry Andric 6300b57cec5SDimitry Andric UnwindPlanSP 6310b57cec5SDimitry Andric SymbolFileBreakpad::GetUnwindPlan(const Address &address, 6320b57cec5SDimitry Andric const RegisterInfoResolver &resolver) { 6330b57cec5SDimitry Andric ParseUnwindData(); 6349dba64beSDimitry Andric if (auto *entry = 6359dba64beSDimitry Andric m_unwind_data->cfi.FindEntryThatContains(address.GetFileAddress())) 6369dba64beSDimitry Andric return ParseCFIUnwindPlan(entry->data, resolver); 6379dba64beSDimitry Andric if (auto *entry = 6389dba64beSDimitry Andric m_unwind_data->win.FindEntryThatContains(address.GetFileAddress())) 6399dba64beSDimitry Andric return ParseWinUnwindPlan(entry->data, resolver); 6400b57cec5SDimitry Andric return nullptr; 6419dba64beSDimitry Andric } 6420b57cec5SDimitry Andric 6439dba64beSDimitry Andric UnwindPlanSP 6449dba64beSDimitry Andric SymbolFileBreakpad::ParseCFIUnwindPlan(const Bookmark &bookmark, 6459dba64beSDimitry Andric const RegisterInfoResolver &resolver) { 6460b57cec5SDimitry Andric addr_t base = GetBaseFileAddress(); 6470b57cec5SDimitry Andric if (base == LLDB_INVALID_ADDRESS) 6480b57cec5SDimitry Andric return nullptr; 6490b57cec5SDimitry Andric 6509dba64beSDimitry Andric LineIterator It(*m_objfile_sp, Record::StackCFI, bookmark), 6519dba64beSDimitry Andric End(*m_objfile_sp); 652bdd1243dSDimitry Andric std::optional<StackCFIRecord> init_record = StackCFIRecord::parse(*It); 65381ad6265SDimitry Andric assert(init_record && init_record->Size && 6549dba64beSDimitry Andric "Record already parsed successfully in ParseUnwindData!"); 6550b57cec5SDimitry Andric 6560b57cec5SDimitry Andric auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB); 6570b57cec5SDimitry Andric plan_sp->SetSourceName("breakpad STACK CFI"); 6580b57cec5SDimitry Andric plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 6599dba64beSDimitry Andric plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); 6600b57cec5SDimitry Andric plan_sp->SetSourcedFromCompiler(eLazyBoolYes); 6610b57cec5SDimitry Andric plan_sp->SetPlanValidAddressRange( 6620b57cec5SDimitry Andric AddressRange(base + init_record->Address, *init_record->Size, 6639dba64beSDimitry Andric m_objfile_sp->GetModule()->GetSectionList())); 6640b57cec5SDimitry Andric 6650b57cec5SDimitry Andric auto row_sp = std::make_shared<UnwindPlan::Row>(); 6660b57cec5SDimitry Andric row_sp->SetOffset(0); 6679dba64beSDimitry Andric if (!ParseCFIUnwindRow(init_record->UnwindRules, resolver, *row_sp)) 6680b57cec5SDimitry Andric return nullptr; 6690b57cec5SDimitry Andric plan_sp->AppendRow(row_sp); 6700b57cec5SDimitry Andric for (++It; It != End; ++It) { 671bdd1243dSDimitry Andric std::optional<StackCFIRecord> record = StackCFIRecord::parse(*It); 67281ad6265SDimitry Andric if (!record) 6730b57cec5SDimitry Andric return nullptr; 67481ad6265SDimitry Andric if (record->Size) 6750b57cec5SDimitry Andric break; 6760b57cec5SDimitry Andric 6770b57cec5SDimitry Andric row_sp = std::make_shared<UnwindPlan::Row>(*row_sp); 6780b57cec5SDimitry Andric row_sp->SetOffset(record->Address - init_record->Address); 6799dba64beSDimitry Andric if (!ParseCFIUnwindRow(record->UnwindRules, resolver, *row_sp)) 6800b57cec5SDimitry Andric return nullptr; 6810b57cec5SDimitry Andric plan_sp->AppendRow(row_sp); 6820b57cec5SDimitry Andric } 6830b57cec5SDimitry Andric return plan_sp; 6840b57cec5SDimitry Andric } 6850b57cec5SDimitry Andric 6869dba64beSDimitry Andric UnwindPlanSP 6879dba64beSDimitry Andric SymbolFileBreakpad::ParseWinUnwindPlan(const Bookmark &bookmark, 6889dba64beSDimitry Andric const RegisterInfoResolver &resolver) { 68981ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Symbols); 6909dba64beSDimitry Andric addr_t base = GetBaseFileAddress(); 6919dba64beSDimitry Andric if (base == LLDB_INVALID_ADDRESS) 6929dba64beSDimitry Andric return nullptr; 6939dba64beSDimitry Andric 6949dba64beSDimitry Andric LineIterator It(*m_objfile_sp, Record::StackWin, bookmark); 695bdd1243dSDimitry Andric std::optional<StackWinRecord> record = StackWinRecord::parse(*It); 69681ad6265SDimitry Andric assert(record && "Record already parsed successfully in ParseUnwindData!"); 6979dba64beSDimitry Andric 6989dba64beSDimitry Andric auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB); 6999dba64beSDimitry Andric plan_sp->SetSourceName("breakpad STACK WIN"); 7009dba64beSDimitry Andric plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 7019dba64beSDimitry Andric plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); 7029dba64beSDimitry Andric plan_sp->SetSourcedFromCompiler(eLazyBoolYes); 7039dba64beSDimitry Andric plan_sp->SetPlanValidAddressRange( 7049dba64beSDimitry Andric AddressRange(base + record->RVA, record->CodeSize, 7059dba64beSDimitry Andric m_objfile_sp->GetModule()->GetSectionList())); 7069dba64beSDimitry Andric 7079dba64beSDimitry Andric auto row_sp = std::make_shared<UnwindPlan::Row>(); 7089dba64beSDimitry Andric row_sp->SetOffset(0); 7099dba64beSDimitry Andric 7109dba64beSDimitry Andric llvm::BumpPtrAllocator node_alloc; 7119dba64beSDimitry Andric std::vector<std::pair<llvm::StringRef, postfix::Node *>> program = 7129dba64beSDimitry Andric postfix::ParseFPOProgram(record->ProgramString, node_alloc); 7139dba64beSDimitry Andric 7149dba64beSDimitry Andric if (program.empty()) { 7159dba64beSDimitry Andric LLDB_LOG(log, "Invalid unwind rule: {0}.", record->ProgramString); 7169dba64beSDimitry Andric return nullptr; 7179dba64beSDimitry Andric } 7189dba64beSDimitry Andric auto it = program.begin(); 7195ffd83dbSDimitry Andric llvm::Triple triple = m_objfile_sp->GetArchitecture().GetTriple(); 7209dba64beSDimitry Andric const auto &symbol_resolver = 7219dba64beSDimitry Andric [&](postfix::SymbolNode &symbol) -> postfix::Node * { 7229dba64beSDimitry Andric llvm::StringRef name = symbol.GetName(); 7239dba64beSDimitry Andric for (const auto &rule : llvm::make_range(program.begin(), it)) { 7249dba64beSDimitry Andric if (rule.first == name) 7259dba64beSDimitry Andric return rule.second; 7269dba64beSDimitry Andric } 7275ffd83dbSDimitry Andric if (const RegisterInfo *info = ResolveRegister(triple, resolver, name)) 7289dba64beSDimitry Andric return postfix::MakeNode<postfix::RegisterNode>( 7299dba64beSDimitry Andric node_alloc, info->kinds[eRegisterKindLLDB]); 7309dba64beSDimitry Andric return nullptr; 7319dba64beSDimitry Andric }; 7329dba64beSDimitry Andric 7339dba64beSDimitry Andric // We assume the first value will be the CFA. It is usually called T0, but 7349dba64beSDimitry Andric // clang will use T1, if it needs to realign the stack. 7359dba64beSDimitry Andric auto *symbol = llvm::dyn_cast<postfix::SymbolNode>(it->second); 7369dba64beSDimitry Andric if (symbol && symbol->GetName() == ".raSearch") { 7379dba64beSDimitry Andric row_sp->GetCFAValue().SetRaSearch(record->LocalSize + 7389dba64beSDimitry Andric record->SavedRegisterSize); 7399dba64beSDimitry Andric } else { 7409dba64beSDimitry Andric if (!postfix::ResolveSymbols(it->second, symbol_resolver)) { 7419dba64beSDimitry Andric LLDB_LOG(log, "Resolving symbols in `{0}` failed.", 7429dba64beSDimitry Andric record->ProgramString); 7439dba64beSDimitry Andric return nullptr; 7449dba64beSDimitry Andric } 7459dba64beSDimitry Andric llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*it->second); 7469dba64beSDimitry Andric row_sp->GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size()); 7479dba64beSDimitry Andric } 7489dba64beSDimitry Andric 7499dba64beSDimitry Andric // Replace the node value with InitialValueNode, so that subsequent 7509dba64beSDimitry Andric // expressions refer to the CFA value instead of recomputing the whole 7519dba64beSDimitry Andric // expression. 7529dba64beSDimitry Andric it->second = postfix::MakeNode<postfix::InitialValueNode>(node_alloc); 7539dba64beSDimitry Andric 7549dba64beSDimitry Andric 7559dba64beSDimitry Andric // Now process the rest of the assignments. 7569dba64beSDimitry Andric for (++it; it != program.end(); ++it) { 7575ffd83dbSDimitry Andric const RegisterInfo *info = ResolveRegister(triple, resolver, it->first); 7589dba64beSDimitry Andric // It is not an error if the resolution fails because the program may 7599dba64beSDimitry Andric // contain temporary variables. 7609dba64beSDimitry Andric if (!info) 7619dba64beSDimitry Andric continue; 7629dba64beSDimitry Andric if (!postfix::ResolveSymbols(it->second, symbol_resolver)) { 7639dba64beSDimitry Andric LLDB_LOG(log, "Resolving symbols in `{0}` failed.", 7649dba64beSDimitry Andric record->ProgramString); 7659dba64beSDimitry Andric return nullptr; 7669dba64beSDimitry Andric } 7679dba64beSDimitry Andric 7689dba64beSDimitry Andric llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*it->second); 7699dba64beSDimitry Andric UnwindPlan::Row::RegisterLocation loc; 7709dba64beSDimitry Andric loc.SetIsDWARFExpression(saved.data(), saved.size()); 7719dba64beSDimitry Andric row_sp->SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc); 7729dba64beSDimitry Andric } 7739dba64beSDimitry Andric 7749dba64beSDimitry Andric plan_sp->AppendRow(row_sp); 7759dba64beSDimitry Andric return plan_sp; 7760b57cec5SDimitry Andric } 7770b57cec5SDimitry Andric 7780b57cec5SDimitry Andric addr_t SymbolFileBreakpad::GetBaseFileAddress() { 7799dba64beSDimitry Andric return m_objfile_sp->GetModule() 7800b57cec5SDimitry Andric ->GetObjectFile() 7810b57cec5SDimitry Andric ->GetBaseAddress() 7820b57cec5SDimitry Andric .GetFileAddress(); 7830b57cec5SDimitry Andric } 7840b57cec5SDimitry Andric 7850b57cec5SDimitry Andric // Parse out all the FILE records from the breakpad file. These will be needed 7860b57cec5SDimitry Andric // when constructing the support file lists for individual compile units. 7870b57cec5SDimitry Andric void SymbolFileBreakpad::ParseFileRecords() { 7880b57cec5SDimitry Andric if (m_files) 7890b57cec5SDimitry Andric return; 7900b57cec5SDimitry Andric m_files.emplace(); 7910b57cec5SDimitry Andric 79281ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Symbols); 7930b57cec5SDimitry Andric for (llvm::StringRef line : lines(Record::File)) { 7940b57cec5SDimitry Andric auto record = FileRecord::parse(line); 7950b57cec5SDimitry Andric if (!record) { 7960b57cec5SDimitry Andric LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line); 7970b57cec5SDimitry Andric continue; 7980b57cec5SDimitry Andric } 7990b57cec5SDimitry Andric 8000b57cec5SDimitry Andric if (record->Number >= m_files->size()) 8010b57cec5SDimitry Andric m_files->resize(record->Number + 1); 8020b57cec5SDimitry Andric FileSpec::Style style = FileSpec::GuessPathStyle(record->Name) 80381ad6265SDimitry Andric .value_or(FileSpec::Style::native); 8040b57cec5SDimitry Andric (*m_files)[record->Number] = FileSpec(record->Name, style); 8050b57cec5SDimitry Andric } 8060b57cec5SDimitry Andric } 8070b57cec5SDimitry Andric 8080b57cec5SDimitry Andric void SymbolFileBreakpad::ParseCUData() { 8090b57cec5SDimitry Andric if (m_cu_data) 8100b57cec5SDimitry Andric return; 8110b57cec5SDimitry Andric 8120b57cec5SDimitry Andric m_cu_data.emplace(); 81381ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Symbols); 8140b57cec5SDimitry Andric addr_t base = GetBaseFileAddress(); 8150b57cec5SDimitry Andric if (base == LLDB_INVALID_ADDRESS) { 8160b57cec5SDimitry Andric LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address " 8170b57cec5SDimitry Andric "of object file."); 8180b57cec5SDimitry Andric } 8190b57cec5SDimitry Andric 8200b57cec5SDimitry Andric // We shall create one compile unit for each FUNC record. So, count the number 8210b57cec5SDimitry Andric // of FUNC records, and store them in m_cu_data, together with their ranges. 8229dba64beSDimitry Andric for (LineIterator It(*m_objfile_sp, Record::Func), End(*m_objfile_sp); 8239dba64beSDimitry Andric It != End; ++It) { 8240b57cec5SDimitry Andric if (auto record = FuncRecord::parse(*It)) { 8250b57cec5SDimitry Andric m_cu_data->Append(CompUnitMap::Entry(base + record->Address, record->Size, 8260b57cec5SDimitry Andric CompUnitData(It.GetBookmark()))); 8270b57cec5SDimitry Andric } else 8280b57cec5SDimitry Andric LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It); 8290b57cec5SDimitry Andric } 8300b57cec5SDimitry Andric m_cu_data->Sort(); 8310b57cec5SDimitry Andric } 8320b57cec5SDimitry Andric 8330b57cec5SDimitry Andric // Construct the list of support files and line table entries for the given 8340b57cec5SDimitry Andric // compile unit. 8350b57cec5SDimitry Andric void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu, 8360b57cec5SDimitry Andric CompUnitData &data) { 8370b57cec5SDimitry Andric addr_t base = GetBaseFileAddress(); 8380b57cec5SDimitry Andric assert(base != LLDB_INVALID_ADDRESS && 8390b57cec5SDimitry Andric "How did we create compile units without a base address?"); 8400b57cec5SDimitry Andric 8410b57cec5SDimitry Andric SupportFileMap map; 8425ffd83dbSDimitry Andric std::vector<std::unique_ptr<LineSequence>> sequences; 8435ffd83dbSDimitry Andric std::unique_ptr<LineSequence> line_seq_up = 8445ffd83dbSDimitry Andric LineTable::CreateLineSequenceContainer(); 845bdd1243dSDimitry Andric std::optional<addr_t> next_addr; 8460b57cec5SDimitry Andric auto finish_sequence = [&]() { 8475ffd83dbSDimitry Andric LineTable::AppendLineEntryToSequence( 848fe6060f1SDimitry Andric line_seq_up.get(), *next_addr, /*line=*/0, /*column=*/0, 849fe6060f1SDimitry Andric /*file_idx=*/0, /*is_start_of_statement=*/false, 850fe6060f1SDimitry Andric /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false, 851fe6060f1SDimitry Andric /*is_epilogue_begin=*/false, /*is_terminal_entry=*/true); 8525ffd83dbSDimitry Andric sequences.push_back(std::move(line_seq_up)); 8535ffd83dbSDimitry Andric line_seq_up = LineTable::CreateLineSequenceContainer(); 8540b57cec5SDimitry Andric }; 8550b57cec5SDimitry Andric 8569dba64beSDimitry Andric LineIterator It(*m_objfile_sp, Record::Func, data.bookmark), 8579dba64beSDimitry Andric End(*m_objfile_sp); 8580b57cec5SDimitry Andric assert(Record::classify(*It) == Record::Func); 8590b57cec5SDimitry Andric for (++It; It != End; ++It) { 860349cc55cSDimitry Andric // Skip INLINE records 861349cc55cSDimitry Andric if (Record::classify(*It) == Record::Inline) 862349cc55cSDimitry Andric continue; 863349cc55cSDimitry Andric 8640b57cec5SDimitry Andric auto record = LineRecord::parse(*It); 8650b57cec5SDimitry Andric if (!record) 8660b57cec5SDimitry Andric break; 8670b57cec5SDimitry Andric 8680b57cec5SDimitry Andric record->Address += base; 8690b57cec5SDimitry Andric 8700b57cec5SDimitry Andric if (next_addr && *next_addr != record->Address) { 8710b57cec5SDimitry Andric // Discontiguous entries. Finish off the previous sequence and reset. 8720b57cec5SDimitry Andric finish_sequence(); 8730b57cec5SDimitry Andric } 8745ffd83dbSDimitry Andric LineTable::AppendLineEntryToSequence( 875fe6060f1SDimitry Andric line_seq_up.get(), record->Address, record->LineNum, /*column=*/0, 876fe6060f1SDimitry Andric map[record->FileNum], /*is_start_of_statement=*/true, 877fe6060f1SDimitry Andric /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false, 878fe6060f1SDimitry Andric /*is_epilogue_begin=*/false, /*is_terminal_entry=*/false); 8790b57cec5SDimitry Andric next_addr = record->Address + record->Size; 8800b57cec5SDimitry Andric } 8810b57cec5SDimitry Andric if (next_addr) 8820b57cec5SDimitry Andric finish_sequence(); 8835ffd83dbSDimitry Andric data.line_table_up = std::make_unique<LineTable>(&cu, std::move(sequences)); 884480093f4SDimitry Andric data.support_files = map.translate(cu.GetPrimaryFile(), *m_files); 8850b57cec5SDimitry Andric } 8860b57cec5SDimitry Andric 8870b57cec5SDimitry Andric void SymbolFileBreakpad::ParseUnwindData() { 8880b57cec5SDimitry Andric if (m_unwind_data) 8890b57cec5SDimitry Andric return; 8900b57cec5SDimitry Andric m_unwind_data.emplace(); 8919dba64beSDimitry Andric 89281ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Symbols); 8930b57cec5SDimitry Andric addr_t base = GetBaseFileAddress(); 8940b57cec5SDimitry Andric if (base == LLDB_INVALID_ADDRESS) { 8950b57cec5SDimitry Andric LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address " 8960b57cec5SDimitry Andric "of object file."); 8970b57cec5SDimitry Andric } 8980b57cec5SDimitry Andric 8999dba64beSDimitry Andric for (LineIterator It(*m_objfile_sp, Record::StackCFI), End(*m_objfile_sp); 9000b57cec5SDimitry Andric It != End; ++It) { 9010b57cec5SDimitry Andric if (auto record = StackCFIRecord::parse(*It)) { 9020b57cec5SDimitry Andric if (record->Size) 9039dba64beSDimitry Andric m_unwind_data->cfi.Append(UnwindMap::Entry( 9040b57cec5SDimitry Andric base + record->Address, *record->Size, It.GetBookmark())); 9050b57cec5SDimitry Andric } else 9060b57cec5SDimitry Andric LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It); 9070b57cec5SDimitry Andric } 9089dba64beSDimitry Andric m_unwind_data->cfi.Sort(); 9099dba64beSDimitry Andric 9109dba64beSDimitry Andric for (LineIterator It(*m_objfile_sp, Record::StackWin), End(*m_objfile_sp); 9119dba64beSDimitry Andric It != End; ++It) { 9129dba64beSDimitry Andric if (auto record = StackWinRecord::parse(*It)) { 9139dba64beSDimitry Andric m_unwind_data->win.Append(UnwindMap::Entry( 9149dba64beSDimitry Andric base + record->RVA, record->CodeSize, It.GetBookmark())); 9159dba64beSDimitry Andric } else 9169dba64beSDimitry Andric LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It); 9179dba64beSDimitry Andric } 9189dba64beSDimitry Andric m_unwind_data->win.Sort(); 9190b57cec5SDimitry Andric } 920349cc55cSDimitry Andric 921*0fca6ea1SDimitry Andric uint64_t SymbolFileBreakpad::GetDebugInfoSize(bool load_all_debug_info) { 922349cc55cSDimitry Andric // Breakpad files are all debug info. 923349cc55cSDimitry Andric return m_objfile_sp->GetByteSize(); 924349cc55cSDimitry Andric } 925