xref: /src/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1cfca06d7SDimitry Andric //===-- SymbolFileBreakpad.cpp --------------------------------------------===//
294994d37SDimitry Andric //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
694994d37SDimitry Andric //
794994d37SDimitry Andric //===----------------------------------------------------------------------===//
894994d37SDimitry Andric 
994994d37SDimitry Andric #include "Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h"
105f29bb8aSDimitry Andric #include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"
1194994d37SDimitry Andric #include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h"
1294994d37SDimitry Andric #include "lldb/Core/Module.h"
1394994d37SDimitry Andric #include "lldb/Core/PluginManager.h"
1494994d37SDimitry Andric #include "lldb/Core/Section.h"
1594994d37SDimitry Andric #include "lldb/Host/FileSystem.h"
165f29bb8aSDimitry Andric #include "lldb/Symbol/CompileUnit.h"
1794994d37SDimitry Andric #include "lldb/Symbol/ObjectFile.h"
185f29bb8aSDimitry Andric #include "lldb/Symbol/SymbolVendor.h"
1994994d37SDimitry Andric #include "lldb/Symbol/TypeMap.h"
20145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
2194994d37SDimitry Andric #include "lldb/Utility/Log.h"
225f29bb8aSDimitry Andric #include "lldb/Utility/StreamString.h"
2394994d37SDimitry Andric #include "llvm/ADT/StringExtras.h"
24e3b55780SDimitry Andric #include <optional>
2594994d37SDimitry Andric 
2694994d37SDimitry Andric using namespace lldb;
2794994d37SDimitry Andric using namespace lldb_private;
2894994d37SDimitry Andric using namespace lldb_private::breakpad;
2994994d37SDimitry Andric 
30cfca06d7SDimitry Andric LLDB_PLUGIN_DEFINE(SymbolFileBreakpad)
31cfca06d7SDimitry Andric 
32706b4fc4SDimitry Andric char SymbolFileBreakpad::ID;
33706b4fc4SDimitry Andric 
345f29bb8aSDimitry Andric class SymbolFileBreakpad::LineIterator {
3594994d37SDimitry Andric public:
3694994d37SDimitry Andric   // begin iterator for sections of given type
LineIterator(ObjectFile & obj,Record::Kind section_type)375f29bb8aSDimitry Andric   LineIterator(ObjectFile &obj, Record::Kind section_type)
385f29bb8aSDimitry Andric       : m_obj(&obj), m_section_type(toString(section_type)),
395f29bb8aSDimitry Andric         m_next_section_idx(0), m_next_line(llvm::StringRef::npos) {
4094994d37SDimitry Andric     ++*this;
4194994d37SDimitry Andric   }
4294994d37SDimitry Andric 
435f29bb8aSDimitry Andric   // An iterator starting at the position given by the bookmark.
445f29bb8aSDimitry Andric   LineIterator(ObjectFile &obj, Record::Kind section_type, Bookmark bookmark);
455f29bb8aSDimitry Andric 
4694994d37SDimitry Andric   // end iterator
LineIterator(ObjectFile & obj)4794994d37SDimitry Andric   explicit LineIterator(ObjectFile &obj)
4894994d37SDimitry Andric       : m_obj(&obj),
495f29bb8aSDimitry Andric         m_next_section_idx(m_obj->GetSectionList()->GetNumSections(0)),
505f29bb8aSDimitry Andric         m_current_line(llvm::StringRef::npos),
515f29bb8aSDimitry Andric         m_next_line(llvm::StringRef::npos) {}
5294994d37SDimitry Andric 
operator !=(const LineIterator & lhs,const LineIterator & rhs)5394994d37SDimitry Andric   friend bool operator!=(const LineIterator &lhs, const LineIterator &rhs) {
5494994d37SDimitry Andric     assert(lhs.m_obj == rhs.m_obj);
5594994d37SDimitry Andric     if (lhs.m_next_section_idx != rhs.m_next_section_idx)
5694994d37SDimitry Andric       return true;
575f29bb8aSDimitry Andric     if (lhs.m_current_line != rhs.m_current_line)
5894994d37SDimitry Andric       return true;
595f29bb8aSDimitry Andric     assert(lhs.m_next_line == rhs.m_next_line);
6094994d37SDimitry Andric     return false;
6194994d37SDimitry Andric   }
6294994d37SDimitry Andric 
6394994d37SDimitry Andric   const LineIterator &operator++();
operator *() const645f29bb8aSDimitry Andric   llvm::StringRef operator*() const {
655f29bb8aSDimitry Andric     return m_section_text.slice(m_current_line, m_next_line);
665f29bb8aSDimitry Andric   }
675f29bb8aSDimitry Andric 
GetBookmark() const685f29bb8aSDimitry Andric   Bookmark GetBookmark() const {
695f29bb8aSDimitry Andric     return Bookmark{m_next_section_idx, m_current_line};
705f29bb8aSDimitry Andric   }
7194994d37SDimitry Andric 
7294994d37SDimitry Andric private:
7394994d37SDimitry Andric   ObjectFile *m_obj;
7494994d37SDimitry Andric   ConstString m_section_type;
7594994d37SDimitry Andric   uint32_t m_next_section_idx;
765f29bb8aSDimitry Andric   llvm::StringRef m_section_text;
775f29bb8aSDimitry Andric   size_t m_current_line;
785f29bb8aSDimitry Andric   size_t m_next_line;
7994994d37SDimitry Andric 
FindNextLine()805f29bb8aSDimitry Andric   void FindNextLine() {
815f29bb8aSDimitry Andric     m_next_line = m_section_text.find('\n', m_current_line);
825f29bb8aSDimitry Andric     if (m_next_line != llvm::StringRef::npos) {
835f29bb8aSDimitry Andric       ++m_next_line;
845f29bb8aSDimitry Andric       if (m_next_line >= m_section_text.size())
855f29bb8aSDimitry Andric         m_next_line = llvm::StringRef::npos;
865f29bb8aSDimitry Andric     }
875f29bb8aSDimitry Andric   }
885f29bb8aSDimitry Andric };
895f29bb8aSDimitry Andric 
LineIterator(ObjectFile & obj,Record::Kind section_type,Bookmark bookmark)905f29bb8aSDimitry Andric SymbolFileBreakpad::LineIterator::LineIterator(ObjectFile &obj,
915f29bb8aSDimitry Andric                                                Record::Kind section_type,
925f29bb8aSDimitry Andric                                                Bookmark bookmark)
935f29bb8aSDimitry Andric     : m_obj(&obj), m_section_type(toString(section_type)),
945f29bb8aSDimitry Andric       m_next_section_idx(bookmark.section), m_current_line(bookmark.offset) {
955f29bb8aSDimitry Andric   Section &sect =
965f29bb8aSDimitry Andric       *obj.GetSectionList()->GetSectionAtIndex(m_next_section_idx - 1);
975f29bb8aSDimitry Andric   assert(sect.GetName() == m_section_type);
985f29bb8aSDimitry Andric 
995f29bb8aSDimitry Andric   DataExtractor data;
1005f29bb8aSDimitry Andric   obj.ReadSectionData(&sect, data);
1015f29bb8aSDimitry Andric   m_section_text = toStringRef(data.GetData());
1025f29bb8aSDimitry Andric 
1035f29bb8aSDimitry Andric   assert(m_current_line < m_section_text.size());
1045f29bb8aSDimitry Andric   FindNextLine();
1055f29bb8aSDimitry Andric }
1065f29bb8aSDimitry Andric 
1075f29bb8aSDimitry Andric const SymbolFileBreakpad::LineIterator &
operator ++()1085f29bb8aSDimitry Andric SymbolFileBreakpad::LineIterator::operator++() {
10994994d37SDimitry Andric   const SectionList &list = *m_obj->GetSectionList();
11094994d37SDimitry Andric   size_t num_sections = list.GetNumSections(0);
1115f29bb8aSDimitry Andric   while (m_next_line != llvm::StringRef::npos ||
1125f29bb8aSDimitry Andric          m_next_section_idx < num_sections) {
1135f29bb8aSDimitry Andric     if (m_next_line != llvm::StringRef::npos) {
1145f29bb8aSDimitry Andric       m_current_line = m_next_line;
1155f29bb8aSDimitry Andric       FindNextLine();
1165f29bb8aSDimitry Andric       return *this;
1175f29bb8aSDimitry Andric     }
1185f29bb8aSDimitry Andric 
11994994d37SDimitry Andric     Section &sect = *list.GetSectionAtIndex(m_next_section_idx++);
12094994d37SDimitry Andric     if (sect.GetName() != m_section_type)
12194994d37SDimitry Andric       continue;
12294994d37SDimitry Andric     DataExtractor data;
12394994d37SDimitry Andric     m_obj->ReadSectionData(&sect, data);
1245f29bb8aSDimitry Andric     m_section_text = toStringRef(data.GetData());
1255f29bb8aSDimitry Andric     m_next_line = 0;
12694994d37SDimitry Andric   }
1275f29bb8aSDimitry Andric   // We've reached the end.
1285f29bb8aSDimitry Andric   m_current_line = m_next_line;
12994994d37SDimitry Andric   return *this;
13094994d37SDimitry Andric }
13194994d37SDimitry Andric 
1325f29bb8aSDimitry Andric llvm::iterator_range<SymbolFileBreakpad::LineIterator>
lines(Record::Kind section_type)1335f29bb8aSDimitry Andric SymbolFileBreakpad::lines(Record::Kind section_type) {
134ead24645SDimitry Andric   return llvm::make_range(LineIterator(*m_objfile_sp, section_type),
135ead24645SDimitry Andric                           LineIterator(*m_objfile_sp));
1365f29bb8aSDimitry Andric }
1375f29bb8aSDimitry Andric 
1385f29bb8aSDimitry Andric namespace {
1395f29bb8aSDimitry Andric // A helper class for constructing the list of support files for a given compile
1405f29bb8aSDimitry Andric // unit.
1415f29bb8aSDimitry Andric class SupportFileMap {
1425f29bb8aSDimitry Andric public:
1435f29bb8aSDimitry Andric   // Given a breakpad file ID, return a file ID to be used in the support files
1445f29bb8aSDimitry Andric   // for this compile unit.
operator [](size_t file)1455f29bb8aSDimitry Andric   size_t operator[](size_t file) {
1465f29bb8aSDimitry Andric     return m_map.try_emplace(file, m_map.size() + 1).first->second;
1475f29bb8aSDimitry Andric   }
1485f29bb8aSDimitry Andric 
1495f29bb8aSDimitry Andric   // Construct a FileSpecList containing only the support files relevant for
1505f29bb8aSDimitry Andric   // this compile unit (in the correct order).
1515f29bb8aSDimitry Andric   FileSpecList translate(const FileSpec &cu_spec,
1525f29bb8aSDimitry Andric                          llvm::ArrayRef<FileSpec> all_files);
1535f29bb8aSDimitry Andric 
1545f29bb8aSDimitry Andric private:
1555f29bb8aSDimitry Andric   llvm::DenseMap<size_t, size_t> m_map;
1565f29bb8aSDimitry Andric };
1575f29bb8aSDimitry Andric } // namespace
1585f29bb8aSDimitry Andric 
translate(const FileSpec & cu_spec,llvm::ArrayRef<FileSpec> all_files)1595f29bb8aSDimitry Andric FileSpecList SupportFileMap::translate(const FileSpec &cu_spec,
1605f29bb8aSDimitry Andric                                        llvm::ArrayRef<FileSpec> all_files) {
1615f29bb8aSDimitry Andric   std::vector<FileSpec> result;
1625f29bb8aSDimitry Andric   result.resize(m_map.size() + 1);
1635f29bb8aSDimitry Andric   result[0] = cu_spec;
1645f29bb8aSDimitry Andric   for (const auto &KV : m_map) {
1655f29bb8aSDimitry Andric     if (KV.first < all_files.size())
1665f29bb8aSDimitry Andric       result[KV.second] = all_files[KV.first];
1675f29bb8aSDimitry Andric   }
1685f29bb8aSDimitry Andric   return FileSpecList(std::move(result));
16994994d37SDimitry Andric }
17094994d37SDimitry Andric 
Initialize()17194994d37SDimitry Andric void SymbolFileBreakpad::Initialize() {
17294994d37SDimitry Andric   PluginManager::RegisterPlugin(GetPluginNameStatic(),
17394994d37SDimitry Andric                                 GetPluginDescriptionStatic(), CreateInstance,
17494994d37SDimitry Andric                                 DebuggerInitialize);
17594994d37SDimitry Andric }
17694994d37SDimitry Andric 
Terminate()17794994d37SDimitry Andric void SymbolFileBreakpad::Terminate() {
17894994d37SDimitry Andric   PluginManager::UnregisterPlugin(CreateInstance);
17994994d37SDimitry Andric }
18094994d37SDimitry Andric 
CalculateAbilities()18194994d37SDimitry Andric uint32_t SymbolFileBreakpad::CalculateAbilities() {
182ead24645SDimitry Andric   if (!m_objfile_sp || !llvm::isa<ObjectFileBreakpad>(*m_objfile_sp))
18394994d37SDimitry Andric     return 0;
18494994d37SDimitry Andric 
1855f29bb8aSDimitry Andric   return CompileUnits | Functions | LineTables;
18694994d37SDimitry Andric }
18794994d37SDimitry Andric 
CalculateNumCompileUnits()188ead24645SDimitry Andric uint32_t SymbolFileBreakpad::CalculateNumCompileUnits() {
1895f29bb8aSDimitry Andric   ParseCUData();
1905f29bb8aSDimitry Andric   return m_cu_data->GetSize();
19194994d37SDimitry Andric }
19294994d37SDimitry Andric 
ParseCompileUnitAtIndex(uint32_t index)19394994d37SDimitry Andric CompUnitSP SymbolFileBreakpad::ParseCompileUnitAtIndex(uint32_t index) {
1945f29bb8aSDimitry Andric   if (index >= m_cu_data->GetSize())
19594994d37SDimitry Andric     return nullptr;
1965f29bb8aSDimitry Andric 
1975f29bb8aSDimitry Andric   CompUnitData &data = m_cu_data->GetEntryRef(index).data;
1985f29bb8aSDimitry Andric 
1995f29bb8aSDimitry Andric   ParseFileRecords();
2005f29bb8aSDimitry Andric 
2015f29bb8aSDimitry Andric   FileSpec spec;
2025f29bb8aSDimitry Andric 
2035f29bb8aSDimitry Andric   // The FileSpec of the compile unit will be the file corresponding to the
2045f29bb8aSDimitry Andric   // first LINE record.
205ead24645SDimitry Andric   LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),
206ead24645SDimitry Andric       End(*m_objfile_sp);
2075f29bb8aSDimitry Andric   assert(Record::classify(*It) == Record::Func);
2085f29bb8aSDimitry Andric   ++It; // Skip FUNC record.
209c0981da4SDimitry Andric   // Skip INLINE records.
210c0981da4SDimitry Andric   while (It != End && Record::classify(*It) == Record::Inline)
211c0981da4SDimitry Andric     ++It;
212c0981da4SDimitry Andric 
2135f29bb8aSDimitry Andric   if (It != End) {
2145f29bb8aSDimitry Andric     auto record = LineRecord::parse(*It);
2155f29bb8aSDimitry Andric     if (record && record->FileNum < m_files->size())
2165f29bb8aSDimitry Andric       spec = (*m_files)[record->FileNum];
2175f29bb8aSDimitry Andric   }
2185f29bb8aSDimitry Andric 
2194df029ccSDimitry Andric   auto cu_sp = std::make_shared<CompileUnit>(
2204df029ccSDimitry Andric       m_objfile_sp->GetModule(),
2214df029ccSDimitry Andric       /*user_data*/ nullptr, std::make_shared<SupportFile>(spec), index,
2225f29bb8aSDimitry Andric       eLanguageTypeUnknown,
2235f29bb8aSDimitry Andric       /*is_optimized*/ eLazyBoolNo);
2245f29bb8aSDimitry Andric 
225ead24645SDimitry Andric   SetCompileUnitAtIndex(index, cu_sp);
2265f29bb8aSDimitry Andric   return cu_sp;
22794994d37SDimitry Andric }
22894994d37SDimitry Andric 
GetOrCreateFunction(CompileUnit & comp_unit)229c0981da4SDimitry Andric FunctionSP SymbolFileBreakpad::GetOrCreateFunction(CompileUnit &comp_unit) {
230c0981da4SDimitry Andric   user_id_t id = comp_unit.GetID();
231c0981da4SDimitry Andric   if (FunctionSP func_sp = comp_unit.FindFunctionByUID(id))
232c0981da4SDimitry Andric     return func_sp;
233c0981da4SDimitry Andric 
234145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Symbols);
235c0981da4SDimitry Andric   FunctionSP func_sp;
236c0981da4SDimitry Andric   addr_t base = GetBaseFileAddress();
237c0981da4SDimitry Andric   if (base == LLDB_INVALID_ADDRESS) {
238c0981da4SDimitry Andric     LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping "
239c0981da4SDimitry Andric                   "symtab population.");
240c0981da4SDimitry Andric     return func_sp;
241c0981da4SDimitry Andric   }
242c0981da4SDimitry Andric 
243c0981da4SDimitry Andric   const SectionList *list = comp_unit.GetModule()->GetSectionList();
244c0981da4SDimitry Andric   CompUnitData &data = m_cu_data->GetEntryRef(id).data;
245c0981da4SDimitry Andric   LineIterator It(*m_objfile_sp, Record::Func, data.bookmark);
246c0981da4SDimitry Andric   assert(Record::classify(*It) == Record::Func);
247c0981da4SDimitry Andric 
248c0981da4SDimitry Andric   if (auto record = FuncRecord::parse(*It)) {
249c0981da4SDimitry Andric     Mangled func_name;
2507fa27ce4SDimitry Andric     func_name.SetValue(ConstString(record->Name));
251c0981da4SDimitry Andric     addr_t address = record->Address + base;
252c0981da4SDimitry Andric     SectionSP section_sp = list->FindSectionContainingFileAddress(address);
253c0981da4SDimitry Andric     if (section_sp) {
254c0981da4SDimitry Andric       AddressRange func_range(
255c0981da4SDimitry Andric           section_sp, address - section_sp->GetFileAddress(), record->Size);
256c0981da4SDimitry Andric       // Use the CU's id because every CU has only one function inside.
257c0981da4SDimitry Andric       func_sp = std::make_shared<Function>(&comp_unit, id, 0, func_name,
258c0981da4SDimitry Andric                                            nullptr, func_range);
259c0981da4SDimitry Andric       comp_unit.AddFunction(func_sp);
260c0981da4SDimitry Andric     }
261c0981da4SDimitry Andric   }
262c0981da4SDimitry Andric   return func_sp;
263c0981da4SDimitry Andric }
264c0981da4SDimitry Andric 
ParseFunctions(CompileUnit & comp_unit)26594994d37SDimitry Andric size_t SymbolFileBreakpad::ParseFunctions(CompileUnit &comp_unit) {
266c0981da4SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
267c0981da4SDimitry Andric   return GetOrCreateFunction(comp_unit) ? 1 : 0;
26894994d37SDimitry Andric }
26994994d37SDimitry Andric 
ParseLineTable(CompileUnit & comp_unit)27094994d37SDimitry Andric bool SymbolFileBreakpad::ParseLineTable(CompileUnit &comp_unit) {
271ead24645SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
2725f29bb8aSDimitry Andric   CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data;
2735f29bb8aSDimitry Andric 
2745f29bb8aSDimitry Andric   if (!data.line_table_up)
2755f29bb8aSDimitry Andric     ParseLineTableAndSupportFiles(comp_unit, data);
2765f29bb8aSDimitry Andric 
2775f29bb8aSDimitry Andric   comp_unit.SetLineTable(data.line_table_up.release());
2785f29bb8aSDimitry Andric   return true;
2795f29bb8aSDimitry Andric }
2805f29bb8aSDimitry Andric 
ParseSupportFiles(CompileUnit & comp_unit,SupportFileList & support_files)2815f29bb8aSDimitry Andric bool SymbolFileBreakpad::ParseSupportFiles(CompileUnit &comp_unit,
282aca2e42cSDimitry Andric                                            SupportFileList &support_files) {
283ead24645SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
2845f29bb8aSDimitry Andric   CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data;
2855f29bb8aSDimitry Andric   if (!data.support_files)
2865f29bb8aSDimitry Andric     ParseLineTableAndSupportFiles(comp_unit, data);
2875f29bb8aSDimitry Andric 
288aca2e42cSDimitry Andric   for (auto &fs : *data.support_files)
289aca2e42cSDimitry Andric     support_files.Append(fs);
2905f29bb8aSDimitry Andric   return true;
29194994d37SDimitry Andric }
29294994d37SDimitry Andric 
ParseBlocksRecursive(Function & func)293c0981da4SDimitry Andric size_t SymbolFileBreakpad::ParseBlocksRecursive(Function &func) {
294c0981da4SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
295c0981da4SDimitry Andric   CompileUnit *comp_unit = func.GetCompileUnit();
296c0981da4SDimitry Andric   lldbassert(comp_unit);
297c0981da4SDimitry Andric   ParseInlineOriginRecords();
298c0981da4SDimitry Andric   // A vector of current each level's parent block. For example, when parsing
299c0981da4SDimitry Andric   // "INLINE 0 ...", the current level is 0 and its parent block is the
300e3b55780SDimitry Andric   // function block at index 0.
301c0981da4SDimitry Andric   std::vector<Block *> blocks;
302c0981da4SDimitry Andric   Block &block = func.GetBlock(false);
303c0981da4SDimitry Andric   block.AddRange(Block::Range(0, func.GetAddressRange().GetByteSize()));
304c0981da4SDimitry Andric   blocks.push_back(&block);
305c0981da4SDimitry Andric 
306c0981da4SDimitry Andric   size_t blocks_added = 0;
307c0981da4SDimitry Andric   addr_t func_base = func.GetAddressRange().GetBaseAddress().GetOffset();
308c0981da4SDimitry Andric   CompUnitData &data = m_cu_data->GetEntryRef(comp_unit->GetID()).data;
309c0981da4SDimitry Andric   LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),
310c0981da4SDimitry Andric       End(*m_objfile_sp);
311c0981da4SDimitry Andric   ++It; // Skip the FUNC record.
312c0981da4SDimitry Andric   size_t last_added_nest_level = 0;
313c0981da4SDimitry Andric   while (It != End && Record::classify(*It) == Record::Inline) {
314c0981da4SDimitry Andric     if (auto record = InlineRecord::parse(*It)) {
315c0981da4SDimitry Andric       if (record->InlineNestLevel == 0 ||
316c0981da4SDimitry Andric           record->InlineNestLevel <= last_added_nest_level + 1) {
317c0981da4SDimitry Andric         last_added_nest_level = record->InlineNestLevel;
318c0981da4SDimitry Andric         BlockSP block_sp = std::make_shared<Block>(It.GetBookmark().offset);
319c0981da4SDimitry Andric         FileSpec callsite_file;
320c0981da4SDimitry Andric         if (record->CallSiteFileNum < m_files->size())
321c0981da4SDimitry Andric           callsite_file = (*m_files)[record->CallSiteFileNum];
322c0981da4SDimitry Andric         llvm::StringRef name;
323c0981da4SDimitry Andric         if (record->OriginNum < m_inline_origins->size())
324c0981da4SDimitry Andric           name = (*m_inline_origins)[record->OriginNum];
325c0981da4SDimitry Andric 
326c0981da4SDimitry Andric         Declaration callsite(callsite_file, record->CallSiteLineNum);
327c0981da4SDimitry Andric         block_sp->SetInlinedFunctionInfo(name.str().c_str(),
328c0981da4SDimitry Andric                                          /*mangled=*/nullptr,
329c0981da4SDimitry Andric                                          /*decl_ptr=*/nullptr, &callsite);
330c0981da4SDimitry Andric         for (const auto &range : record->Ranges) {
331c0981da4SDimitry Andric           block_sp->AddRange(
332c0981da4SDimitry Andric               Block::Range(range.first - func_base, range.second));
333c0981da4SDimitry Andric         }
334c0981da4SDimitry Andric         block_sp->FinalizeRanges();
335c0981da4SDimitry Andric 
336c0981da4SDimitry Andric         blocks[record->InlineNestLevel]->AddChild(block_sp);
337c0981da4SDimitry Andric         if (record->InlineNestLevel + 1 >= blocks.size()) {
338c0981da4SDimitry Andric           blocks.resize(blocks.size() + 1);
339c0981da4SDimitry Andric         }
340c0981da4SDimitry Andric         blocks[record->InlineNestLevel + 1] = block_sp.get();
341c0981da4SDimitry Andric         ++blocks_added;
342c0981da4SDimitry Andric       }
343c0981da4SDimitry Andric     }
344c0981da4SDimitry Andric     ++It;
345c0981da4SDimitry Andric   }
346c0981da4SDimitry Andric   return blocks_added;
347c0981da4SDimitry Andric }
348c0981da4SDimitry Andric 
ParseInlineOriginRecords()349c0981da4SDimitry Andric void SymbolFileBreakpad::ParseInlineOriginRecords() {
350c0981da4SDimitry Andric   if (m_inline_origins)
351c0981da4SDimitry Andric     return;
352c0981da4SDimitry Andric   m_inline_origins.emplace();
353c0981da4SDimitry Andric 
354145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Symbols);
355c0981da4SDimitry Andric   for (llvm::StringRef line : lines(Record::InlineOrigin)) {
356c0981da4SDimitry Andric     auto record = InlineOriginRecord::parse(line);
357c0981da4SDimitry Andric     if (!record) {
358c0981da4SDimitry Andric       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
359c0981da4SDimitry Andric       continue;
360c0981da4SDimitry Andric     }
361c0981da4SDimitry Andric 
362c0981da4SDimitry Andric     if (record->Number >= m_inline_origins->size())
363c0981da4SDimitry Andric       m_inline_origins->resize(record->Number + 1);
364c0981da4SDimitry Andric     (*m_inline_origins)[record->Number] = record->Name;
365c0981da4SDimitry Andric   }
366c0981da4SDimitry Andric }
367c0981da4SDimitry Andric 
36894994d37SDimitry Andric uint32_t
ResolveSymbolContext(const Address & so_addr,SymbolContextItem resolve_scope,SymbolContext & sc)36994994d37SDimitry Andric SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr,
37094994d37SDimitry Andric                                          SymbolContextItem resolve_scope,
37194994d37SDimitry Andric                                          SymbolContext &sc) {
372ead24645SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
373c0981da4SDimitry Andric   if (!(resolve_scope & (eSymbolContextCompUnit | eSymbolContextLineEntry |
374c0981da4SDimitry Andric                          eSymbolContextFunction | eSymbolContextBlock)))
37594994d37SDimitry Andric     return 0;
3765f29bb8aSDimitry Andric 
3775f29bb8aSDimitry Andric   ParseCUData();
3785f29bb8aSDimitry Andric   uint32_t idx =
3795f29bb8aSDimitry Andric       m_cu_data->FindEntryIndexThatContains(so_addr.GetFileAddress());
3805f29bb8aSDimitry Andric   if (idx == UINT32_MAX)
3815f29bb8aSDimitry Andric     return 0;
3825f29bb8aSDimitry Andric 
383ead24645SDimitry Andric   sc.comp_unit = GetCompileUnitAtIndex(idx).get();
3845f29bb8aSDimitry Andric   SymbolContextItem result = eSymbolContextCompUnit;
3855f29bb8aSDimitry Andric   if (resolve_scope & eSymbolContextLineEntry) {
3865f29bb8aSDimitry Andric     if (sc.comp_unit->GetLineTable()->FindLineEntryByAddress(so_addr,
3875f29bb8aSDimitry Andric                                                              sc.line_entry)) {
3885f29bb8aSDimitry Andric       result |= eSymbolContextLineEntry;
3895f29bb8aSDimitry Andric     }
3905f29bb8aSDimitry Andric   }
3915f29bb8aSDimitry Andric 
392c0981da4SDimitry Andric   if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) {
393c0981da4SDimitry Andric     FunctionSP func_sp = GetOrCreateFunction(*sc.comp_unit);
394c0981da4SDimitry Andric     if (func_sp) {
395c0981da4SDimitry Andric       sc.function = func_sp.get();
396c0981da4SDimitry Andric       result |= eSymbolContextFunction;
397c0981da4SDimitry Andric       if (resolve_scope & eSymbolContextBlock) {
398c0981da4SDimitry Andric         Block &block = func_sp->GetBlock(true);
399c0981da4SDimitry Andric         sc.block = block.FindInnermostBlockByOffset(
400c0981da4SDimitry Andric             so_addr.GetFileAddress() -
401c0981da4SDimitry Andric             sc.function->GetAddressRange().GetBaseAddress().GetFileAddress());
402c0981da4SDimitry Andric         if (sc.block)
403c0981da4SDimitry Andric           result |= eSymbolContextBlock;
404c0981da4SDimitry Andric       }
405c0981da4SDimitry Andric     }
406c0981da4SDimitry Andric   }
407c0981da4SDimitry Andric 
4085f29bb8aSDimitry Andric   return result;
4095f29bb8aSDimitry Andric }
4105f29bb8aSDimitry Andric 
ResolveSymbolContext(const SourceLocationSpec & src_location_spec,lldb::SymbolContextItem resolve_scope,SymbolContextList & sc_list)4115f29bb8aSDimitry Andric uint32_t SymbolFileBreakpad::ResolveSymbolContext(
412344a3780SDimitry Andric     const SourceLocationSpec &src_location_spec,
4135f29bb8aSDimitry Andric     lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
414ead24645SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
4155f29bb8aSDimitry Andric   if (!(resolve_scope & eSymbolContextCompUnit))
4165f29bb8aSDimitry Andric     return 0;
4175f29bb8aSDimitry Andric 
4185f29bb8aSDimitry Andric   uint32_t old_size = sc_list.GetSize();
4195f29bb8aSDimitry Andric   for (size_t i = 0, size = GetNumCompileUnits(); i < size; ++i) {
420ead24645SDimitry Andric     CompileUnit &cu = *GetCompileUnitAtIndex(i);
421344a3780SDimitry Andric     cu.ResolveSymbolContext(src_location_spec, resolve_scope, sc_list);
4225f29bb8aSDimitry Andric   }
4235f29bb8aSDimitry Andric   return sc_list.GetSize() - old_size;
42494994d37SDimitry Andric }
42594994d37SDimitry Andric 
FindFunctions(const Module::LookupInfo & lookup_info,const CompilerDeclContext & parent_decl_ctx,bool include_inlines,SymbolContextList & sc_list)426ead24645SDimitry Andric void SymbolFileBreakpad::FindFunctions(
427e3b55780SDimitry Andric     const Module::LookupInfo &lookup_info,
428e3b55780SDimitry Andric     const CompilerDeclContext &parent_decl_ctx, bool include_inlines,
42994994d37SDimitry Andric     SymbolContextList &sc_list) {
430c0981da4SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
431c0981da4SDimitry Andric   // TODO: Implement this with supported FunctionNameType.
432c0981da4SDimitry Andric 
433e3b55780SDimitry Andric   ConstString name = lookup_info.GetLookupName();
434c0981da4SDimitry Andric   for (uint32_t i = 0; i < GetNumCompileUnits(); ++i) {
435c0981da4SDimitry Andric     CompUnitSP cu_sp = GetCompileUnitAtIndex(i);
436c0981da4SDimitry Andric     FunctionSP func_sp = GetOrCreateFunction(*cu_sp);
437c0981da4SDimitry Andric     if (func_sp && name == func_sp->GetNameNoArguments()) {
438c0981da4SDimitry Andric       SymbolContext sc;
439c0981da4SDimitry Andric       sc.comp_unit = cu_sp.get();
440c0981da4SDimitry Andric       sc.function = func_sp.get();
441c0981da4SDimitry Andric       sc.module_sp = func_sp->CalculateSymbolContextModule();
442c0981da4SDimitry Andric       sc_list.Append(sc);
443c0981da4SDimitry Andric     }
444c0981da4SDimitry Andric   }
44594994d37SDimitry Andric }
44694994d37SDimitry Andric 
FindFunctions(const RegularExpression & regex,bool include_inlines,SymbolContextList & sc_list)447ead24645SDimitry Andric void SymbolFileBreakpad::FindFunctions(const RegularExpression &regex,
448ead24645SDimitry Andric                                        bool include_inlines,
44994994d37SDimitry Andric                                        SymbolContextList &sc_list) {
45094994d37SDimitry Andric   // TODO
45194994d37SDimitry Andric }
45294994d37SDimitry Andric 
AddSymbols(Symtab & symtab)45394994d37SDimitry Andric void SymbolFileBreakpad::AddSymbols(Symtab &symtab) {
454145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Symbols);
455ead24645SDimitry Andric   Module &module = *m_objfile_sp->GetModule();
4565f29bb8aSDimitry Andric   addr_t base = GetBaseFileAddress();
45794994d37SDimitry Andric   if (base == LLDB_INVALID_ADDRESS) {
45894994d37SDimitry Andric     LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping "
45994994d37SDimitry Andric                   "symtab population.");
46094994d37SDimitry Andric     return;
46194994d37SDimitry Andric   }
46294994d37SDimitry Andric 
46394994d37SDimitry Andric   const SectionList &list = *module.GetSectionList();
464b60736ecSDimitry Andric   llvm::DenseSet<addr_t> found_symbol_addresses;
465b60736ecSDimitry Andric   std::vector<Symbol> symbols;
466e3b55780SDimitry Andric   auto add_symbol = [&](addr_t address, std::optional<addr_t> size,
4675f29bb8aSDimitry Andric                         llvm::StringRef name) {
46894994d37SDimitry Andric     address += base;
46994994d37SDimitry Andric     SectionSP section_sp = list.FindSectionContainingFileAddress(address);
47094994d37SDimitry Andric     if (!section_sp) {
47194994d37SDimitry Andric       LLDB_LOG(log,
47294994d37SDimitry Andric                "Ignoring symbol {0}, whose address ({1}) is outside of the "
47394994d37SDimitry Andric                "object file. Mismatched symbol file?",
47494994d37SDimitry Andric                name, address);
4755f29bb8aSDimitry Andric       return;
4765f29bb8aSDimitry Andric     }
477b60736ecSDimitry Andric     // Keep track of what addresses were already added so far and only add
478b60736ecSDimitry Andric     // the symbol with the first address.
479b60736ecSDimitry Andric     if (!found_symbol_addresses.insert(address).second)
480b60736ecSDimitry Andric       return;
481b60736ecSDimitry Andric     symbols.emplace_back(
482b60736ecSDimitry Andric         /*symID*/ 0, Mangled(name), eSymbolTypeCode,
483ead24645SDimitry Andric         /*is_global*/ true, /*is_debug*/ false,
4845f29bb8aSDimitry Andric         /*is_trampoline*/ false, /*is_artificial*/ false,
4855f29bb8aSDimitry Andric         AddressRange(section_sp, address - section_sp->GetFileAddress(),
486145449b1SDimitry Andric                      size.value_or(0)),
487145449b1SDimitry Andric         size.has_value(), /*contains_linker_annotations*/ false, /*flags*/ 0);
4885f29bb8aSDimitry Andric   };
4895f29bb8aSDimitry Andric 
4905f29bb8aSDimitry Andric   for (llvm::StringRef line : lines(Record::Public)) {
4915f29bb8aSDimitry Andric     if (auto record = PublicRecord::parse(line))
492e3b55780SDimitry Andric       add_symbol(record->Address, std::nullopt, record->Name);
4935f29bb8aSDimitry Andric     else
4945f29bb8aSDimitry Andric       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
4955f29bb8aSDimitry Andric   }
4965f29bb8aSDimitry Andric 
497b60736ecSDimitry Andric   for (Symbol &symbol : symbols)
498b60736ecSDimitry Andric     symtab.AddSymbol(std::move(symbol));
499f65dcba8SDimitry Andric   symtab.Finalize();
5005f29bb8aSDimitry Andric }
5015f29bb8aSDimitry Andric 
502ead24645SDimitry Andric llvm::Expected<lldb::addr_t>
GetParameterStackSize(Symbol & symbol)503ead24645SDimitry Andric SymbolFileBreakpad::GetParameterStackSize(Symbol &symbol) {
504ead24645SDimitry Andric   ParseUnwindData();
505ead24645SDimitry Andric   if (auto *entry = m_unwind_data->win.FindEntryThatContains(
506ead24645SDimitry Andric           symbol.GetAddress().GetFileAddress())) {
507ead24645SDimitry Andric     auto record = StackWinRecord::parse(
508ead24645SDimitry Andric         *LineIterator(*m_objfile_sp, Record::StackWin, entry->data));
509145449b1SDimitry Andric     assert(record);
510ead24645SDimitry Andric     return record->ParameterSize;
511ead24645SDimitry Andric   }
512ead24645SDimitry Andric   return llvm::createStringError(llvm::inconvertibleErrorCode(),
513ead24645SDimitry Andric                                  "Parameter size unknown.");
514ead24645SDimitry Andric }
515ead24645SDimitry Andric 
516e3b55780SDimitry Andric static std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
GetRule(llvm::StringRef & unwind_rules)5175f29bb8aSDimitry Andric GetRule(llvm::StringRef &unwind_rules) {
5185f29bb8aSDimitry Andric   // Unwind rules are of the form
5195f29bb8aSDimitry Andric   //   register1: expression1 register2: expression2 ...
5205f29bb8aSDimitry Andric   // We assume none of the tokens in expression<n> end with a colon.
5215f29bb8aSDimitry Andric 
5225f29bb8aSDimitry Andric   llvm::StringRef lhs, rest;
5235f29bb8aSDimitry Andric   std::tie(lhs, rest) = getToken(unwind_rules);
5245f29bb8aSDimitry Andric   if (!lhs.consume_back(":"))
525e3b55780SDimitry Andric     return std::nullopt;
5265f29bb8aSDimitry Andric 
5275f29bb8aSDimitry Andric   // Seek forward to the next register: expression pair
5285f29bb8aSDimitry Andric   llvm::StringRef::size_type pos = rest.find(": ");
5295f29bb8aSDimitry Andric   if (pos == llvm::StringRef::npos) {
5305f29bb8aSDimitry Andric     // No pair found, this means the rest of the string is a single expression.
5315f29bb8aSDimitry Andric     unwind_rules = llvm::StringRef();
5325f29bb8aSDimitry Andric     return std::make_pair(lhs, rest);
5335f29bb8aSDimitry Andric   }
5345f29bb8aSDimitry Andric 
5355f29bb8aSDimitry Andric   // Go back one token to find the end of the current rule.
5365f29bb8aSDimitry Andric   pos = rest.rfind(' ', pos);
5375f29bb8aSDimitry Andric   if (pos == llvm::StringRef::npos)
538e3b55780SDimitry Andric     return std::nullopt;
5395f29bb8aSDimitry Andric 
5405f29bb8aSDimitry Andric   llvm::StringRef rhs = rest.take_front(pos);
5415f29bb8aSDimitry Andric   unwind_rules = rest.drop_front(pos);
5425f29bb8aSDimitry Andric   return std::make_pair(lhs, rhs);
5435f29bb8aSDimitry Andric }
5445f29bb8aSDimitry Andric 
5455f29bb8aSDimitry Andric static const RegisterInfo *
ResolveRegister(const llvm::Triple & triple,const SymbolFile::RegisterInfoResolver & resolver,llvm::StringRef name)546cfca06d7SDimitry Andric ResolveRegister(const llvm::Triple &triple,
547cfca06d7SDimitry Andric                 const SymbolFile::RegisterInfoResolver &resolver,
5485f29bb8aSDimitry Andric                 llvm::StringRef name) {
549cfca06d7SDimitry Andric   if (triple.isX86() || triple.isMIPS()) {
550cfca06d7SDimitry Andric     // X86 and MIPS registers have '$' in front of their register names. Arm and
551cfca06d7SDimitry Andric     // AArch64 don't.
552cfca06d7SDimitry Andric     if (!name.consume_front("$"))
5535f29bb8aSDimitry Andric       return nullptr;
5545f29bb8aSDimitry Andric   }
555cfca06d7SDimitry Andric   return resolver.ResolveName(name);
556cfca06d7SDimitry Andric }
5575f29bb8aSDimitry Andric 
5585f29bb8aSDimitry Andric static const RegisterInfo *
ResolveRegisterOrRA(const llvm::Triple & triple,const SymbolFile::RegisterInfoResolver & resolver,llvm::StringRef name)559cfca06d7SDimitry Andric ResolveRegisterOrRA(const llvm::Triple &triple,
560cfca06d7SDimitry Andric                     const SymbolFile::RegisterInfoResolver &resolver,
5615f29bb8aSDimitry Andric                     llvm::StringRef name) {
5625f29bb8aSDimitry Andric   if (name == ".ra")
5635f29bb8aSDimitry Andric     return resolver.ResolveNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
564cfca06d7SDimitry Andric   return ResolveRegister(triple, resolver, name);
5655f29bb8aSDimitry Andric }
5665f29bb8aSDimitry Andric 
SaveAsDWARF(postfix::Node & node)567ead24645SDimitry Andric llvm::ArrayRef<uint8_t> SymbolFileBreakpad::SaveAsDWARF(postfix::Node &node) {
568ead24645SDimitry Andric   ArchSpec arch = m_objfile_sp->GetArchitecture();
569ead24645SDimitry Andric   StreamString dwarf(Stream::eBinary, arch.GetAddressByteSize(),
570ead24645SDimitry Andric                      arch.GetByteOrder());
571ead24645SDimitry Andric   ToDWARF(node, dwarf);
572ead24645SDimitry Andric   uint8_t *saved = m_allocator.Allocate<uint8_t>(dwarf.GetSize());
573ead24645SDimitry Andric   std::memcpy(saved, dwarf.GetData(), dwarf.GetSize());
574ead24645SDimitry Andric   return {saved, dwarf.GetSize()};
575ead24645SDimitry Andric }
576ead24645SDimitry Andric 
ParseCFIUnwindRow(llvm::StringRef unwind_rules,const RegisterInfoResolver & resolver,UnwindPlan::Row & row)577ead24645SDimitry Andric bool SymbolFileBreakpad::ParseCFIUnwindRow(llvm::StringRef unwind_rules,
5785f29bb8aSDimitry Andric                                         const RegisterInfoResolver &resolver,
5795f29bb8aSDimitry Andric                                         UnwindPlan::Row &row) {
580145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Symbols);
5815f29bb8aSDimitry Andric 
5825f29bb8aSDimitry Andric   llvm::BumpPtrAllocator node_alloc;
583cfca06d7SDimitry Andric   llvm::Triple triple = m_objfile_sp->GetArchitecture().GetTriple();
5845f29bb8aSDimitry Andric   while (auto rule = GetRule(unwind_rules)) {
5855f29bb8aSDimitry Andric     node_alloc.Reset();
5865f29bb8aSDimitry Andric     llvm::StringRef lhs = rule->first;
587ead24645SDimitry Andric     postfix::Node *rhs = postfix::ParseOneExpression(rule->second, node_alloc);
5885f29bb8aSDimitry Andric     if (!rhs) {
5895f29bb8aSDimitry Andric       LLDB_LOG(log, "Could not parse `{0}` as unwind rhs.", rule->second);
5905f29bb8aSDimitry Andric       return false;
5915f29bb8aSDimitry Andric     }
5925f29bb8aSDimitry Andric 
5935f29bb8aSDimitry Andric     bool success = postfix::ResolveSymbols(
5945f29bb8aSDimitry Andric         rhs, [&](postfix::SymbolNode &symbol) -> postfix::Node * {
5955f29bb8aSDimitry Andric           llvm::StringRef name = symbol.GetName();
5965f29bb8aSDimitry Andric           if (name == ".cfa" && lhs != ".cfa")
5975f29bb8aSDimitry Andric             return postfix::MakeNode<postfix::InitialValueNode>(node_alloc);
5985f29bb8aSDimitry Andric 
599cfca06d7SDimitry Andric           if (const RegisterInfo *info =
600cfca06d7SDimitry Andric                   ResolveRegister(triple, resolver, name)) {
6015f29bb8aSDimitry Andric             return postfix::MakeNode<postfix::RegisterNode>(
6025f29bb8aSDimitry Andric                 node_alloc, info->kinds[eRegisterKindLLDB]);
6035f29bb8aSDimitry Andric           }
6045f29bb8aSDimitry Andric           return nullptr;
6055f29bb8aSDimitry Andric         });
6065f29bb8aSDimitry Andric 
6075f29bb8aSDimitry Andric     if (!success) {
6085f29bb8aSDimitry Andric       LLDB_LOG(log, "Resolving symbols in `{0}` failed.", rule->second);
6095f29bb8aSDimitry Andric       return false;
6105f29bb8aSDimitry Andric     }
6115f29bb8aSDimitry Andric 
612ead24645SDimitry Andric     llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*rhs);
6135f29bb8aSDimitry Andric     if (lhs == ".cfa") {
614ead24645SDimitry Andric       row.GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size());
615cfca06d7SDimitry Andric     } else if (const RegisterInfo *info =
616cfca06d7SDimitry Andric                    ResolveRegisterOrRA(triple, resolver, lhs)) {
6175f29bb8aSDimitry Andric       UnwindPlan::Row::RegisterLocation loc;
618ead24645SDimitry Andric       loc.SetIsDWARFExpression(saved.data(), saved.size());
6195f29bb8aSDimitry Andric       row.SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc);
6205f29bb8aSDimitry Andric     } else
6215f29bb8aSDimitry Andric       LLDB_LOG(log, "Invalid register `{0}` in unwind rule.", lhs);
6225f29bb8aSDimitry Andric   }
6235f29bb8aSDimitry Andric   if (unwind_rules.empty())
6245f29bb8aSDimitry Andric     return true;
6255f29bb8aSDimitry Andric 
6265f29bb8aSDimitry Andric   LLDB_LOG(log, "Could not parse `{0}` as an unwind rule.", unwind_rules);
6275f29bb8aSDimitry Andric   return false;
6285f29bb8aSDimitry Andric }
6295f29bb8aSDimitry Andric 
6305f29bb8aSDimitry Andric UnwindPlanSP
GetUnwindPlan(const Address & address,const RegisterInfoResolver & resolver)6315f29bb8aSDimitry Andric SymbolFileBreakpad::GetUnwindPlan(const Address &address,
6325f29bb8aSDimitry Andric                                   const RegisterInfoResolver &resolver) {
6335f29bb8aSDimitry Andric   ParseUnwindData();
634ead24645SDimitry Andric   if (auto *entry =
635ead24645SDimitry Andric           m_unwind_data->cfi.FindEntryThatContains(address.GetFileAddress()))
636ead24645SDimitry Andric     return ParseCFIUnwindPlan(entry->data, resolver);
637ead24645SDimitry Andric   if (auto *entry =
638ead24645SDimitry Andric           m_unwind_data->win.FindEntryThatContains(address.GetFileAddress()))
639ead24645SDimitry Andric     return ParseWinUnwindPlan(entry->data, resolver);
6405f29bb8aSDimitry Andric   return nullptr;
641ead24645SDimitry Andric }
6425f29bb8aSDimitry Andric 
643ead24645SDimitry Andric UnwindPlanSP
ParseCFIUnwindPlan(const Bookmark & bookmark,const RegisterInfoResolver & resolver)644ead24645SDimitry Andric SymbolFileBreakpad::ParseCFIUnwindPlan(const Bookmark &bookmark,
645ead24645SDimitry Andric                                        const RegisterInfoResolver &resolver) {
6465f29bb8aSDimitry Andric   addr_t base = GetBaseFileAddress();
6475f29bb8aSDimitry Andric   if (base == LLDB_INVALID_ADDRESS)
6485f29bb8aSDimitry Andric     return nullptr;
6495f29bb8aSDimitry Andric 
650ead24645SDimitry Andric   LineIterator It(*m_objfile_sp, Record::StackCFI, bookmark),
651ead24645SDimitry Andric       End(*m_objfile_sp);
652e3b55780SDimitry Andric   std::optional<StackCFIRecord> init_record = StackCFIRecord::parse(*It);
653145449b1SDimitry Andric   assert(init_record && init_record->Size &&
654ead24645SDimitry Andric          "Record already parsed successfully in ParseUnwindData!");
6555f29bb8aSDimitry Andric 
6565f29bb8aSDimitry Andric   auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB);
6575f29bb8aSDimitry Andric   plan_sp->SetSourceName("breakpad STACK CFI");
6585f29bb8aSDimitry Andric   plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
659ead24645SDimitry Andric   plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);
6605f29bb8aSDimitry Andric   plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
6615f29bb8aSDimitry Andric   plan_sp->SetPlanValidAddressRange(
6625f29bb8aSDimitry Andric       AddressRange(base + init_record->Address, *init_record->Size,
663ead24645SDimitry Andric                    m_objfile_sp->GetModule()->GetSectionList()));
6645f29bb8aSDimitry Andric 
6655f29bb8aSDimitry Andric   auto row_sp = std::make_shared<UnwindPlan::Row>();
6665f29bb8aSDimitry Andric   row_sp->SetOffset(0);
667ead24645SDimitry Andric   if (!ParseCFIUnwindRow(init_record->UnwindRules, resolver, *row_sp))
6685f29bb8aSDimitry Andric     return nullptr;
6695f29bb8aSDimitry Andric   plan_sp->AppendRow(row_sp);
6705f29bb8aSDimitry Andric   for (++It; It != End; ++It) {
671e3b55780SDimitry Andric     std::optional<StackCFIRecord> record = StackCFIRecord::parse(*It);
672145449b1SDimitry Andric     if (!record)
6735f29bb8aSDimitry Andric       return nullptr;
674145449b1SDimitry Andric     if (record->Size)
6755f29bb8aSDimitry Andric       break;
6765f29bb8aSDimitry Andric 
6775f29bb8aSDimitry Andric     row_sp = std::make_shared<UnwindPlan::Row>(*row_sp);
6785f29bb8aSDimitry Andric     row_sp->SetOffset(record->Address - init_record->Address);
679ead24645SDimitry Andric     if (!ParseCFIUnwindRow(record->UnwindRules, resolver, *row_sp))
6805f29bb8aSDimitry Andric       return nullptr;
6815f29bb8aSDimitry Andric     plan_sp->AppendRow(row_sp);
6825f29bb8aSDimitry Andric   }
6835f29bb8aSDimitry Andric   return plan_sp;
6845f29bb8aSDimitry Andric }
6855f29bb8aSDimitry Andric 
686ead24645SDimitry Andric UnwindPlanSP
ParseWinUnwindPlan(const Bookmark & bookmark,const RegisterInfoResolver & resolver)687ead24645SDimitry Andric SymbolFileBreakpad::ParseWinUnwindPlan(const Bookmark &bookmark,
688ead24645SDimitry Andric                                        const RegisterInfoResolver &resolver) {
689145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Symbols);
690ead24645SDimitry Andric   addr_t base = GetBaseFileAddress();
691ead24645SDimitry Andric   if (base == LLDB_INVALID_ADDRESS)
692ead24645SDimitry Andric     return nullptr;
693ead24645SDimitry Andric 
694ead24645SDimitry Andric   LineIterator It(*m_objfile_sp, Record::StackWin, bookmark);
695e3b55780SDimitry Andric   std::optional<StackWinRecord> record = StackWinRecord::parse(*It);
696145449b1SDimitry Andric   assert(record && "Record already parsed successfully in ParseUnwindData!");
697ead24645SDimitry Andric 
698ead24645SDimitry Andric   auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB);
699ead24645SDimitry Andric   plan_sp->SetSourceName("breakpad STACK WIN");
700ead24645SDimitry Andric   plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
701ead24645SDimitry Andric   plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);
702ead24645SDimitry Andric   plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
703ead24645SDimitry Andric   plan_sp->SetPlanValidAddressRange(
704ead24645SDimitry Andric       AddressRange(base + record->RVA, record->CodeSize,
705ead24645SDimitry Andric                    m_objfile_sp->GetModule()->GetSectionList()));
706ead24645SDimitry Andric 
707ead24645SDimitry Andric   auto row_sp = std::make_shared<UnwindPlan::Row>();
708ead24645SDimitry Andric   row_sp->SetOffset(0);
709ead24645SDimitry Andric 
710ead24645SDimitry Andric   llvm::BumpPtrAllocator node_alloc;
711ead24645SDimitry Andric   std::vector<std::pair<llvm::StringRef, postfix::Node *>> program =
712ead24645SDimitry Andric       postfix::ParseFPOProgram(record->ProgramString, node_alloc);
713ead24645SDimitry Andric 
714ead24645SDimitry Andric   if (program.empty()) {
715ead24645SDimitry Andric     LLDB_LOG(log, "Invalid unwind rule: {0}.", record->ProgramString);
716ead24645SDimitry Andric     return nullptr;
717ead24645SDimitry Andric   }
718ead24645SDimitry Andric   auto it = program.begin();
719cfca06d7SDimitry Andric   llvm::Triple triple = m_objfile_sp->GetArchitecture().GetTriple();
720ead24645SDimitry Andric   const auto &symbol_resolver =
721ead24645SDimitry Andric       [&](postfix::SymbolNode &symbol) -> postfix::Node * {
722ead24645SDimitry Andric     llvm::StringRef name = symbol.GetName();
723ead24645SDimitry Andric     for (const auto &rule : llvm::make_range(program.begin(), it)) {
724ead24645SDimitry Andric       if (rule.first == name)
725ead24645SDimitry Andric         return rule.second;
726ead24645SDimitry Andric     }
727cfca06d7SDimitry Andric     if (const RegisterInfo *info = ResolveRegister(triple, resolver, name))
728ead24645SDimitry Andric       return postfix::MakeNode<postfix::RegisterNode>(
729ead24645SDimitry Andric           node_alloc, info->kinds[eRegisterKindLLDB]);
730ead24645SDimitry Andric     return nullptr;
731ead24645SDimitry Andric   };
732ead24645SDimitry Andric 
733ead24645SDimitry Andric   // We assume the first value will be the CFA. It is usually called T0, but
734ead24645SDimitry Andric   // clang will use T1, if it needs to realign the stack.
735ead24645SDimitry Andric   auto *symbol = llvm::dyn_cast<postfix::SymbolNode>(it->second);
736ead24645SDimitry Andric   if (symbol && symbol->GetName() == ".raSearch") {
737ead24645SDimitry Andric     row_sp->GetCFAValue().SetRaSearch(record->LocalSize +
738ead24645SDimitry Andric                                       record->SavedRegisterSize);
739ead24645SDimitry Andric   } else {
740ead24645SDimitry Andric     if (!postfix::ResolveSymbols(it->second, symbol_resolver)) {
741ead24645SDimitry Andric       LLDB_LOG(log, "Resolving symbols in `{0}` failed.",
742ead24645SDimitry Andric                record->ProgramString);
743ead24645SDimitry Andric       return nullptr;
744ead24645SDimitry Andric     }
745ead24645SDimitry Andric     llvm::ArrayRef<uint8_t> saved  = SaveAsDWARF(*it->second);
746ead24645SDimitry Andric     row_sp->GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size());
747ead24645SDimitry Andric   }
748ead24645SDimitry Andric 
749ead24645SDimitry Andric   // Replace the node value with InitialValueNode, so that subsequent
750ead24645SDimitry Andric   // expressions refer to the CFA value instead of recomputing the whole
751ead24645SDimitry Andric   // expression.
752ead24645SDimitry Andric   it->second = postfix::MakeNode<postfix::InitialValueNode>(node_alloc);
753ead24645SDimitry Andric 
754ead24645SDimitry Andric 
755ead24645SDimitry Andric   // Now process the rest of the assignments.
756ead24645SDimitry Andric   for (++it; it != program.end(); ++it) {
757cfca06d7SDimitry Andric     const RegisterInfo *info = ResolveRegister(triple, resolver, it->first);
758ead24645SDimitry Andric     // It is not an error if the resolution fails because the program may
759ead24645SDimitry Andric     // contain temporary variables.
760ead24645SDimitry Andric     if (!info)
761ead24645SDimitry Andric       continue;
762ead24645SDimitry Andric     if (!postfix::ResolveSymbols(it->second, symbol_resolver)) {
763ead24645SDimitry Andric       LLDB_LOG(log, "Resolving symbols in `{0}` failed.",
764ead24645SDimitry Andric                record->ProgramString);
765ead24645SDimitry Andric       return nullptr;
766ead24645SDimitry Andric     }
767ead24645SDimitry Andric 
768ead24645SDimitry Andric     llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*it->second);
769ead24645SDimitry Andric     UnwindPlan::Row::RegisterLocation loc;
770ead24645SDimitry Andric     loc.SetIsDWARFExpression(saved.data(), saved.size());
771ead24645SDimitry Andric     row_sp->SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc);
772ead24645SDimitry Andric   }
773ead24645SDimitry Andric 
774ead24645SDimitry Andric   plan_sp->AppendRow(row_sp);
775ead24645SDimitry Andric   return plan_sp;
7765f29bb8aSDimitry Andric }
7775f29bb8aSDimitry Andric 
GetBaseFileAddress()7785f29bb8aSDimitry Andric addr_t SymbolFileBreakpad::GetBaseFileAddress() {
779ead24645SDimitry Andric   return m_objfile_sp->GetModule()
7805f29bb8aSDimitry Andric       ->GetObjectFile()
7815f29bb8aSDimitry Andric       ->GetBaseAddress()
7825f29bb8aSDimitry Andric       .GetFileAddress();
7835f29bb8aSDimitry Andric }
7845f29bb8aSDimitry Andric 
7855f29bb8aSDimitry Andric // Parse out all the FILE records from the breakpad file. These will be needed
7865f29bb8aSDimitry Andric // when constructing the support file lists for individual compile units.
ParseFileRecords()7875f29bb8aSDimitry Andric void SymbolFileBreakpad::ParseFileRecords() {
7885f29bb8aSDimitry Andric   if (m_files)
7895f29bb8aSDimitry Andric     return;
7905f29bb8aSDimitry Andric   m_files.emplace();
7915f29bb8aSDimitry Andric 
792145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Symbols);
7935f29bb8aSDimitry Andric   for (llvm::StringRef line : lines(Record::File)) {
7945f29bb8aSDimitry Andric     auto record = FileRecord::parse(line);
7955f29bb8aSDimitry Andric     if (!record) {
7965f29bb8aSDimitry Andric       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
79794994d37SDimitry Andric       continue;
79894994d37SDimitry Andric     }
79994994d37SDimitry Andric 
8005f29bb8aSDimitry Andric     if (record->Number >= m_files->size())
8015f29bb8aSDimitry Andric       m_files->resize(record->Number + 1);
8025f29bb8aSDimitry Andric     FileSpec::Style style = FileSpec::GuessPathStyle(record->Name)
803145449b1SDimitry Andric                                 .value_or(FileSpec::Style::native);
8045f29bb8aSDimitry Andric     (*m_files)[record->Number] = FileSpec(record->Name, style);
8055f29bb8aSDimitry Andric   }
80694994d37SDimitry Andric }
80794994d37SDimitry Andric 
ParseCUData()8085f29bb8aSDimitry Andric void SymbolFileBreakpad::ParseCUData() {
8095f29bb8aSDimitry Andric   if (m_cu_data)
8105f29bb8aSDimitry Andric     return;
81194994d37SDimitry Andric 
8125f29bb8aSDimitry Andric   m_cu_data.emplace();
813145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Symbols);
8145f29bb8aSDimitry Andric   addr_t base = GetBaseFileAddress();
8155f29bb8aSDimitry Andric   if (base == LLDB_INVALID_ADDRESS) {
8165f29bb8aSDimitry Andric     LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "
8175f29bb8aSDimitry Andric                   "of object file.");
8185f29bb8aSDimitry Andric   }
8195f29bb8aSDimitry Andric 
8205f29bb8aSDimitry Andric   // We shall create one compile unit for each FUNC record. So, count the number
8215f29bb8aSDimitry Andric   // of FUNC records, and store them in m_cu_data, together with their ranges.
822ead24645SDimitry Andric   for (LineIterator It(*m_objfile_sp, Record::Func), End(*m_objfile_sp);
823ead24645SDimitry Andric        It != End; ++It) {
8245f29bb8aSDimitry Andric     if (auto record = FuncRecord::parse(*It)) {
8255f29bb8aSDimitry Andric       m_cu_data->Append(CompUnitMap::Entry(base + record->Address, record->Size,
8265f29bb8aSDimitry Andric                                            CompUnitData(It.GetBookmark())));
8275f29bb8aSDimitry Andric     } else
8285f29bb8aSDimitry Andric       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
8295f29bb8aSDimitry Andric   }
8305f29bb8aSDimitry Andric   m_cu_data->Sort();
8315f29bb8aSDimitry Andric }
8325f29bb8aSDimitry Andric 
8335f29bb8aSDimitry Andric // Construct the list of support files and line table entries for the given
8345f29bb8aSDimitry Andric // compile unit.
ParseLineTableAndSupportFiles(CompileUnit & cu,CompUnitData & data)8355f29bb8aSDimitry Andric void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu,
8365f29bb8aSDimitry Andric                                                        CompUnitData &data) {
8375f29bb8aSDimitry Andric   addr_t base = GetBaseFileAddress();
8385f29bb8aSDimitry Andric   assert(base != LLDB_INVALID_ADDRESS &&
8395f29bb8aSDimitry Andric          "How did we create compile units without a base address?");
8405f29bb8aSDimitry Andric 
8415f29bb8aSDimitry Andric   SupportFileMap map;
842cfca06d7SDimitry Andric   std::vector<std::unique_ptr<LineSequence>> sequences;
843cfca06d7SDimitry Andric   std::unique_ptr<LineSequence> line_seq_up =
844cfca06d7SDimitry Andric       LineTable::CreateLineSequenceContainer();
845e3b55780SDimitry Andric   std::optional<addr_t> next_addr;
8465f29bb8aSDimitry Andric   auto finish_sequence = [&]() {
847cfca06d7SDimitry Andric     LineTable::AppendLineEntryToSequence(
848344a3780SDimitry Andric         line_seq_up.get(), *next_addr, /*line=*/0, /*column=*/0,
849344a3780SDimitry Andric         /*file_idx=*/0, /*is_start_of_statement=*/false,
850344a3780SDimitry Andric         /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false,
851344a3780SDimitry Andric         /*is_epilogue_begin=*/false, /*is_terminal_entry=*/true);
852cfca06d7SDimitry Andric     sequences.push_back(std::move(line_seq_up));
853cfca06d7SDimitry Andric     line_seq_up = LineTable::CreateLineSequenceContainer();
8545f29bb8aSDimitry Andric   };
8555f29bb8aSDimitry Andric 
856ead24645SDimitry Andric   LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),
857ead24645SDimitry Andric       End(*m_objfile_sp);
8585f29bb8aSDimitry Andric   assert(Record::classify(*It) == Record::Func);
8595f29bb8aSDimitry Andric   for (++It; It != End; ++It) {
860c0981da4SDimitry Andric     // Skip INLINE records
861c0981da4SDimitry Andric     if (Record::classify(*It) == Record::Inline)
862c0981da4SDimitry Andric       continue;
863c0981da4SDimitry Andric 
8645f29bb8aSDimitry Andric     auto record = LineRecord::parse(*It);
8655f29bb8aSDimitry Andric     if (!record)
8665f29bb8aSDimitry Andric       break;
8675f29bb8aSDimitry Andric 
8685f29bb8aSDimitry Andric     record->Address += base;
8695f29bb8aSDimitry Andric 
8705f29bb8aSDimitry Andric     if (next_addr && *next_addr != record->Address) {
8715f29bb8aSDimitry Andric       // Discontiguous entries. Finish off the previous sequence and reset.
8725f29bb8aSDimitry Andric       finish_sequence();
8735f29bb8aSDimitry Andric     }
874cfca06d7SDimitry Andric     LineTable::AppendLineEntryToSequence(
875344a3780SDimitry Andric         line_seq_up.get(), record->Address, record->LineNum, /*column=*/0,
876344a3780SDimitry Andric         map[record->FileNum], /*is_start_of_statement=*/true,
877344a3780SDimitry Andric         /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false,
878344a3780SDimitry Andric         /*is_epilogue_begin=*/false, /*is_terminal_entry=*/false);
8795f29bb8aSDimitry Andric     next_addr = record->Address + record->Size;
8805f29bb8aSDimitry Andric   }
8815f29bb8aSDimitry Andric   if (next_addr)
8825f29bb8aSDimitry Andric     finish_sequence();
883cfca06d7SDimitry Andric   data.line_table_up = std::make_unique<LineTable>(&cu, std::move(sequences));
884706b4fc4SDimitry Andric   data.support_files = map.translate(cu.GetPrimaryFile(), *m_files);
8855f29bb8aSDimitry Andric }
8865f29bb8aSDimitry Andric 
ParseUnwindData()8875f29bb8aSDimitry Andric void SymbolFileBreakpad::ParseUnwindData() {
8885f29bb8aSDimitry Andric   if (m_unwind_data)
8895f29bb8aSDimitry Andric     return;
8905f29bb8aSDimitry Andric   m_unwind_data.emplace();
891ead24645SDimitry Andric 
892145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Symbols);
8935f29bb8aSDimitry Andric   addr_t base = GetBaseFileAddress();
8945f29bb8aSDimitry Andric   if (base == LLDB_INVALID_ADDRESS) {
8955f29bb8aSDimitry Andric     LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "
8965f29bb8aSDimitry Andric                   "of object file.");
8975f29bb8aSDimitry Andric   }
8985f29bb8aSDimitry Andric 
899ead24645SDimitry Andric   for (LineIterator It(*m_objfile_sp, Record::StackCFI), End(*m_objfile_sp);
9005f29bb8aSDimitry Andric        It != End; ++It) {
9015f29bb8aSDimitry Andric     if (auto record = StackCFIRecord::parse(*It)) {
9025f29bb8aSDimitry Andric       if (record->Size)
903ead24645SDimitry Andric         m_unwind_data->cfi.Append(UnwindMap::Entry(
9045f29bb8aSDimitry Andric             base + record->Address, *record->Size, It.GetBookmark()));
9055f29bb8aSDimitry Andric     } else
9065f29bb8aSDimitry Andric       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
9075f29bb8aSDimitry Andric   }
908ead24645SDimitry Andric   m_unwind_data->cfi.Sort();
909ead24645SDimitry Andric 
910ead24645SDimitry Andric   for (LineIterator It(*m_objfile_sp, Record::StackWin), End(*m_objfile_sp);
911ead24645SDimitry Andric        It != End; ++It) {
912ead24645SDimitry Andric     if (auto record = StackWinRecord::parse(*It)) {
913ead24645SDimitry Andric       m_unwind_data->win.Append(UnwindMap::Entry(
914ead24645SDimitry Andric           base + record->RVA, record->CodeSize, It.GetBookmark()));
915ead24645SDimitry Andric     } else
916ead24645SDimitry Andric       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
917ead24645SDimitry Andric   }
918ead24645SDimitry Andric   m_unwind_data->win.Sort();
91994994d37SDimitry Andric }
920c0981da4SDimitry Andric 
GetDebugInfoSize(bool load_all_debug_info)921ac9a064cSDimitry Andric uint64_t SymbolFileBreakpad::GetDebugInfoSize(bool load_all_debug_info) {
922c0981da4SDimitry Andric   // Breakpad files are all debug info.
923c0981da4SDimitry Andric   return m_objfile_sp->GetByteSize();
924c0981da4SDimitry Andric }
925