xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 &sect =
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(&sect, 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 &sect = *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(&sect, 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 &regex,
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