180814287SRaphael Isemann //===-- SymbolFileBreakpad.cpp --------------------------------------------===//
21cf23e1aSPavel Labath //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61cf23e1aSPavel Labath //
71cf23e1aSPavel Labath //===----------------------------------------------------------------------===//
81cf23e1aSPavel Labath 
91cf23e1aSPavel Labath #include "Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h"
102cf5486cSPavel Labath #include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"
111cf23e1aSPavel Labath #include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h"
121cf23e1aSPavel Labath #include "lldb/Core/Module.h"
131cf23e1aSPavel Labath #include "lldb/Core/PluginManager.h"
141cf23e1aSPavel Labath #include "lldb/Core/Section.h"
151cf23e1aSPavel Labath #include "lldb/Host/FileSystem.h"
163f35ab8bSPavel Labath #include "lldb/Symbol/CompileUnit.h"
171cf23e1aSPavel Labath #include "lldb/Symbol/ObjectFile.h"
183f35ab8bSPavel Labath #include "lldb/Symbol/SymbolVendor.h"
191cf23e1aSPavel Labath #include "lldb/Symbol/TypeMap.h"
20c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
211cf23e1aSPavel Labath #include "lldb/Utility/Log.h"
221211baa5SPavel Labath #include "lldb/Utility/StreamString.h"
231cf23e1aSPavel Labath #include "llvm/ADT/StringExtras.h"
241cf23e1aSPavel Labath 
251cf23e1aSPavel Labath using namespace lldb;
261cf23e1aSPavel Labath using namespace lldb_private;
271cf23e1aSPavel Labath using namespace lldb_private::breakpad;
281cf23e1aSPavel Labath 
29bba9ba8dSJonas Devlieghere LLDB_PLUGIN_DEFINE(SymbolFileBreakpad)
30fbb4d1e4SJonas Devlieghere 
317d71dd92SAdrian Prantl char SymbolFileBreakpad::ID;
327d71dd92SAdrian Prantl 
333f35ab8bSPavel Labath class SymbolFileBreakpad::LineIterator {
341cf23e1aSPavel Labath public:
351cf23e1aSPavel Labath   // begin iterator for sections of given type
LineIterator(ObjectFile & obj,Record::Kind section_type)3606bb3735SPavel Labath   LineIterator(ObjectFile &obj, Record::Kind section_type)
3706bb3735SPavel Labath       : m_obj(&obj), m_section_type(toString(section_type)),
383f35ab8bSPavel Labath         m_next_section_idx(0), m_next_line(llvm::StringRef::npos) {
391cf23e1aSPavel Labath     ++*this;
401cf23e1aSPavel Labath   }
411cf23e1aSPavel Labath 
423f35ab8bSPavel Labath   // An iterator starting at the position given by the bookmark.
433f35ab8bSPavel Labath   LineIterator(ObjectFile &obj, Record::Kind section_type, Bookmark bookmark);
443f35ab8bSPavel Labath 
451cf23e1aSPavel Labath   // end iterator
LineIterator(ObjectFile & obj)461cf23e1aSPavel Labath   explicit LineIterator(ObjectFile &obj)
471cf23e1aSPavel Labath       : m_obj(&obj),
483f35ab8bSPavel Labath         m_next_section_idx(m_obj->GetSectionList()->GetNumSections(0)),
493f35ab8bSPavel Labath         m_current_line(llvm::StringRef::npos),
503f35ab8bSPavel Labath         m_next_line(llvm::StringRef::npos) {}
511cf23e1aSPavel Labath 
operator !=(const LineIterator & lhs,const LineIterator & rhs)521cf23e1aSPavel Labath   friend bool operator!=(const LineIterator &lhs, const LineIterator &rhs) {
531cf23e1aSPavel Labath     assert(lhs.m_obj == rhs.m_obj);
541cf23e1aSPavel Labath     if (lhs.m_next_section_idx != rhs.m_next_section_idx)
551cf23e1aSPavel Labath       return true;
563f35ab8bSPavel Labath     if (lhs.m_current_line != rhs.m_current_line)
571cf23e1aSPavel Labath       return true;
583f35ab8bSPavel Labath     assert(lhs.m_next_line == rhs.m_next_line);
591cf23e1aSPavel Labath     return false;
601cf23e1aSPavel Labath   }
611cf23e1aSPavel Labath 
621cf23e1aSPavel Labath   const LineIterator &operator++();
operator *() const633f35ab8bSPavel Labath   llvm::StringRef operator*() const {
643f35ab8bSPavel Labath     return m_section_text.slice(m_current_line, m_next_line);
653f35ab8bSPavel Labath   }
663f35ab8bSPavel Labath 
GetBookmark() const673f35ab8bSPavel Labath   Bookmark GetBookmark() const {
683f35ab8bSPavel Labath     return Bookmark{m_next_section_idx, m_current_line};
693f35ab8bSPavel Labath   }
701cf23e1aSPavel Labath 
711cf23e1aSPavel Labath private:
721cf23e1aSPavel Labath   ObjectFile *m_obj;
731cf23e1aSPavel Labath   ConstString m_section_type;
741cf23e1aSPavel Labath   uint32_t m_next_section_idx;
753f35ab8bSPavel Labath   llvm::StringRef m_section_text;
763f35ab8bSPavel Labath   size_t m_current_line;
773f35ab8bSPavel Labath   size_t m_next_line;
781cf23e1aSPavel Labath 
FindNextLine()793f35ab8bSPavel Labath   void FindNextLine() {
803f35ab8bSPavel Labath     m_next_line = m_section_text.find('\n', m_current_line);
813f35ab8bSPavel Labath     if (m_next_line != llvm::StringRef::npos) {
823f35ab8bSPavel Labath       ++m_next_line;
833f35ab8bSPavel Labath       if (m_next_line >= m_section_text.size())
843f35ab8bSPavel Labath         m_next_line = llvm::StringRef::npos;
853f35ab8bSPavel Labath     }
863f35ab8bSPavel Labath   }
873f35ab8bSPavel Labath };
883f35ab8bSPavel Labath 
LineIterator(ObjectFile & obj,Record::Kind section_type,Bookmark bookmark)893f35ab8bSPavel Labath SymbolFileBreakpad::LineIterator::LineIterator(ObjectFile &obj,
903f35ab8bSPavel Labath                                                Record::Kind section_type,
913f35ab8bSPavel Labath                                                Bookmark bookmark)
923f35ab8bSPavel Labath     : m_obj(&obj), m_section_type(toString(section_type)),
933f35ab8bSPavel Labath       m_next_section_idx(bookmark.section), m_current_line(bookmark.offset) {
943f35ab8bSPavel Labath   Section &sect =
953f35ab8bSPavel Labath       *obj.GetSectionList()->GetSectionAtIndex(m_next_section_idx - 1);
963f35ab8bSPavel Labath   assert(sect.GetName() == m_section_type);
973f35ab8bSPavel Labath 
983f35ab8bSPavel Labath   DataExtractor data;
993f35ab8bSPavel Labath   obj.ReadSectionData(&sect, data);
1003f35ab8bSPavel Labath   m_section_text = toStringRef(data.GetData());
1013f35ab8bSPavel Labath 
1023f35ab8bSPavel Labath   assert(m_current_line < m_section_text.size());
1033f35ab8bSPavel Labath   FindNextLine();
1043f35ab8bSPavel Labath }
1053f35ab8bSPavel Labath 
1063f35ab8bSPavel Labath const SymbolFileBreakpad::LineIterator &
operator ++()1073f35ab8bSPavel Labath SymbolFileBreakpad::LineIterator::operator++() {
1081cf23e1aSPavel Labath   const SectionList &list = *m_obj->GetSectionList();
1091cf23e1aSPavel Labath   size_t num_sections = list.GetNumSections(0);
1103f35ab8bSPavel Labath   while (m_next_line != llvm::StringRef::npos ||
1113f35ab8bSPavel Labath          m_next_section_idx < num_sections) {
1123f35ab8bSPavel Labath     if (m_next_line != llvm::StringRef::npos) {
1133f35ab8bSPavel Labath       m_current_line = m_next_line;
1143f35ab8bSPavel Labath       FindNextLine();
1153f35ab8bSPavel Labath       return *this;
1163f35ab8bSPavel Labath     }
1173f35ab8bSPavel Labath 
1181cf23e1aSPavel Labath     Section &sect = *list.GetSectionAtIndex(m_next_section_idx++);
1191cf23e1aSPavel Labath     if (sect.GetName() != m_section_type)
1201cf23e1aSPavel Labath       continue;
1211cf23e1aSPavel Labath     DataExtractor data;
1221cf23e1aSPavel Labath     m_obj->ReadSectionData(&sect, data);
1233f35ab8bSPavel Labath     m_section_text = toStringRef(data.GetData());
1243f35ab8bSPavel Labath     m_next_line = 0;
1251cf23e1aSPavel Labath   }
1263f35ab8bSPavel Labath   // We've reached the end.
1273f35ab8bSPavel Labath   m_current_line = m_next_line;
1281cf23e1aSPavel Labath   return *this;
1291cf23e1aSPavel Labath }
1301cf23e1aSPavel Labath 
1313f35ab8bSPavel Labath llvm::iterator_range<SymbolFileBreakpad::LineIterator>
lines(Record::Kind section_type)1323f35ab8bSPavel Labath SymbolFileBreakpad::lines(Record::Kind section_type) {
133d2deeb44SPavel Labath   return llvm::make_range(LineIterator(*m_objfile_sp, section_type),
134d2deeb44SPavel Labath                           LineIterator(*m_objfile_sp));
1353f35ab8bSPavel Labath }
1363f35ab8bSPavel Labath 
1373f35ab8bSPavel Labath namespace {
1383f35ab8bSPavel Labath // A helper class for constructing the list of support files for a given compile
1393f35ab8bSPavel Labath // unit.
1403f35ab8bSPavel Labath class SupportFileMap {
1413f35ab8bSPavel Labath public:
1423f35ab8bSPavel Labath   // Given a breakpad file ID, return a file ID to be used in the support files
1433f35ab8bSPavel Labath   // for this compile unit.
operator [](size_t file)1443f35ab8bSPavel Labath   size_t operator[](size_t file) {
1453f35ab8bSPavel Labath     return m_map.try_emplace(file, m_map.size() + 1).first->second;
1463f35ab8bSPavel Labath   }
1473f35ab8bSPavel Labath 
1483f35ab8bSPavel Labath   // Construct a FileSpecList containing only the support files relevant for
1493f35ab8bSPavel Labath   // this compile unit (in the correct order).
1503f35ab8bSPavel Labath   FileSpecList translate(const FileSpec &cu_spec,
1513f35ab8bSPavel Labath                          llvm::ArrayRef<FileSpec> all_files);
1523f35ab8bSPavel Labath 
1533f35ab8bSPavel Labath private:
1543f35ab8bSPavel Labath   llvm::DenseMap<size_t, size_t> m_map;
1553f35ab8bSPavel Labath };
1563f35ab8bSPavel Labath } // namespace
1573f35ab8bSPavel Labath 
translate(const FileSpec & cu_spec,llvm::ArrayRef<FileSpec> all_files)1583f35ab8bSPavel Labath FileSpecList SupportFileMap::translate(const FileSpec &cu_spec,
1593f35ab8bSPavel Labath                                        llvm::ArrayRef<FileSpec> all_files) {
1603f35ab8bSPavel Labath   std::vector<FileSpec> result;
1613f35ab8bSPavel Labath   result.resize(m_map.size() + 1);
1623f35ab8bSPavel Labath   result[0] = cu_spec;
1633f35ab8bSPavel Labath   for (const auto &KV : m_map) {
1643f35ab8bSPavel Labath     if (KV.first < all_files.size())
1653f35ab8bSPavel Labath       result[KV.second] = all_files[KV.first];
1663f35ab8bSPavel Labath   }
1673f35ab8bSPavel Labath   return FileSpecList(std::move(result));
1681cf23e1aSPavel Labath }
1691cf23e1aSPavel Labath 
Initialize()1701cf23e1aSPavel Labath void SymbolFileBreakpad::Initialize() {
1711cf23e1aSPavel Labath   PluginManager::RegisterPlugin(GetPluginNameStatic(),
1721cf23e1aSPavel Labath                                 GetPluginDescriptionStatic(), CreateInstance,
1731cf23e1aSPavel Labath                                 DebuggerInitialize);
1741cf23e1aSPavel Labath }
1751cf23e1aSPavel Labath 
Terminate()1761cf23e1aSPavel Labath void SymbolFileBreakpad::Terminate() {
1771cf23e1aSPavel Labath   PluginManager::UnregisterPlugin(CreateInstance);
1781cf23e1aSPavel Labath }
1791cf23e1aSPavel Labath 
CalculateAbilities()1801cf23e1aSPavel Labath uint32_t SymbolFileBreakpad::CalculateAbilities() {
181e84f7841SPavel Labath   if (!m_objfile_sp || !llvm::isa<ObjectFileBreakpad>(*m_objfile_sp))
1821cf23e1aSPavel Labath     return 0;
1831cf23e1aSPavel Labath 
1843f35ab8bSPavel Labath   return CompileUnits | Functions | LineTables;
1851cf23e1aSPavel Labath }
1861cf23e1aSPavel Labath 
CalculateNumCompileUnits()187e0119909SPavel Labath uint32_t SymbolFileBreakpad::CalculateNumCompileUnits() {
1883f35ab8bSPavel Labath   ParseCUData();
1893f35ab8bSPavel Labath   return m_cu_data->GetSize();
1901cf23e1aSPavel Labath }
1911cf23e1aSPavel Labath 
ParseCompileUnitAtIndex(uint32_t index)1921cf23e1aSPavel Labath CompUnitSP SymbolFileBreakpad::ParseCompileUnitAtIndex(uint32_t index) {
1933f35ab8bSPavel Labath   if (index >= m_cu_data->GetSize())
1941cf23e1aSPavel Labath     return nullptr;
1953f35ab8bSPavel Labath 
1963f35ab8bSPavel Labath   CompUnitData &data = m_cu_data->GetEntryRef(index).data;
1973f35ab8bSPavel Labath 
1983f35ab8bSPavel Labath   ParseFileRecords();
1993f35ab8bSPavel Labath 
2003f35ab8bSPavel Labath   FileSpec spec;
2013f35ab8bSPavel Labath 
2023f35ab8bSPavel Labath   // The FileSpec of the compile unit will be the file corresponding to the
2033f35ab8bSPavel Labath   // first LINE record.
204d2deeb44SPavel Labath   LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),
205d2deeb44SPavel Labath       End(*m_objfile_sp);
2063f35ab8bSPavel Labath   assert(Record::classify(*It) == Record::Func);
2073f35ab8bSPavel Labath   ++It; // Skip FUNC record.
208cc9ced0eSZequan Wu   // Skip INLINE records.
209cc9ced0eSZequan Wu   while (It != End && Record::classify(*It) == Record::Inline)
210cc9ced0eSZequan Wu     ++It;
211cc9ced0eSZequan Wu 
2123f35ab8bSPavel Labath   if (It != End) {
2133f35ab8bSPavel Labath     auto record = LineRecord::parse(*It);
2143f35ab8bSPavel Labath     if (record && record->FileNum < m_files->size())
2153f35ab8bSPavel Labath       spec = (*m_files)[record->FileNum];
2163f35ab8bSPavel Labath   }
2173f35ab8bSPavel Labath 
218d2deeb44SPavel Labath   auto cu_sp = std::make_shared<CompileUnit>(m_objfile_sp->GetModule(),
2193f35ab8bSPavel Labath                                              /*user_data*/ nullptr, spec, index,
2203f35ab8bSPavel Labath                                              eLanguageTypeUnknown,
2213f35ab8bSPavel Labath                                              /*is_optimized*/ eLazyBoolNo);
2223f35ab8bSPavel Labath 
223e0119909SPavel Labath   SetCompileUnitAtIndex(index, cu_sp);
2243f35ab8bSPavel Labath   return cu_sp;
2251cf23e1aSPavel Labath }
2261cf23e1aSPavel Labath 
GetOrCreateFunction(CompileUnit & comp_unit)227fbf665a0SZequan Wu FunctionSP SymbolFileBreakpad::GetOrCreateFunction(CompileUnit &comp_unit) {
228fbf665a0SZequan Wu   user_id_t id = comp_unit.GetID();
229fbf665a0SZequan Wu   if (FunctionSP func_sp = comp_unit.FindFunctionByUID(id))
230fbf665a0SZequan Wu     return func_sp;
231fbf665a0SZequan Wu 
232a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Symbols);
233fbf665a0SZequan Wu   FunctionSP func_sp;
234fbf665a0SZequan Wu   addr_t base = GetBaseFileAddress();
235fbf665a0SZequan Wu   if (base == LLDB_INVALID_ADDRESS) {
236fbf665a0SZequan Wu     LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping "
237fbf665a0SZequan Wu                   "symtab population.");
238fbf665a0SZequan Wu     return func_sp;
239fbf665a0SZequan Wu   }
240fbf665a0SZequan Wu 
241fbf665a0SZequan Wu   const SectionList *list = comp_unit.GetModule()->GetSectionList();
242fbf665a0SZequan Wu   CompUnitData &data = m_cu_data->GetEntryRef(id).data;
243fbf665a0SZequan Wu   LineIterator It(*m_objfile_sp, Record::Func, data.bookmark);
244fbf665a0SZequan Wu   assert(Record::classify(*It) == Record::Func);
245fbf665a0SZequan Wu 
246fbf665a0SZequan Wu   if (auto record = FuncRecord::parse(*It)) {
247fbf665a0SZequan Wu     Mangled func_name;
248fbf665a0SZequan Wu     func_name.SetValue(ConstString(record->Name), false);
249fbf665a0SZequan Wu     addr_t address = record->Address + base;
250fbf665a0SZequan Wu     SectionSP section_sp = list->FindSectionContainingFileAddress(address);
251fbf665a0SZequan Wu     if (section_sp) {
252fbf665a0SZequan Wu       AddressRange func_range(
253fbf665a0SZequan Wu           section_sp, address - section_sp->GetFileAddress(), record->Size);
254fbf665a0SZequan Wu       // Use the CU's id because every CU has only one function inside.
255fbf665a0SZequan Wu       func_sp = std::make_shared<Function>(&comp_unit, id, 0, func_name,
256fbf665a0SZequan Wu                                            nullptr, func_range);
257fbf665a0SZequan Wu       comp_unit.AddFunction(func_sp);
258fbf665a0SZequan Wu     }
259fbf665a0SZequan Wu   }
260fbf665a0SZequan Wu   return func_sp;
261fbf665a0SZequan Wu }
262fbf665a0SZequan Wu 
ParseFunctions(CompileUnit & comp_unit)263ce386e30SZachary Turner size_t SymbolFileBreakpad::ParseFunctions(CompileUnit &comp_unit) {
264fbf665a0SZequan Wu   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
265fbf665a0SZequan Wu   return GetOrCreateFunction(comp_unit) ? 1 : 0;
2661cf23e1aSPavel Labath }
2671cf23e1aSPavel Labath 
ParseLineTable(CompileUnit & comp_unit)268ce386e30SZachary Turner bool SymbolFileBreakpad::ParseLineTable(CompileUnit &comp_unit) {
269656ddeb2SPavel Labath   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
2703f35ab8bSPavel Labath   CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data;
2713f35ab8bSPavel Labath 
2723f35ab8bSPavel Labath   if (!data.line_table_up)
2733f35ab8bSPavel Labath     ParseLineTableAndSupportFiles(comp_unit, data);
2743f35ab8bSPavel Labath 
2753f35ab8bSPavel Labath   comp_unit.SetLineTable(data.line_table_up.release());
2763f35ab8bSPavel Labath   return true;
2773f35ab8bSPavel Labath }
2783f35ab8bSPavel Labath 
ParseSupportFiles(CompileUnit & comp_unit,FileSpecList & support_files)2793f35ab8bSPavel Labath bool SymbolFileBreakpad::ParseSupportFiles(CompileUnit &comp_unit,
2803f35ab8bSPavel Labath                                            FileSpecList &support_files) {
281656ddeb2SPavel Labath   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
2823f35ab8bSPavel Labath   CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data;
2833f35ab8bSPavel Labath   if (!data.support_files)
2843f35ab8bSPavel Labath     ParseLineTableAndSupportFiles(comp_unit, data);
2853f35ab8bSPavel Labath 
2863f35ab8bSPavel Labath   support_files = std::move(*data.support_files);
2873f35ab8bSPavel Labath   return true;
2881cf23e1aSPavel Labath }
2891cf23e1aSPavel Labath 
ParseBlocksRecursive(Function & func)290cc9ced0eSZequan Wu size_t SymbolFileBreakpad::ParseBlocksRecursive(Function &func) {
291cc9ced0eSZequan Wu   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
292cc9ced0eSZequan Wu   CompileUnit *comp_unit = func.GetCompileUnit();
293cc9ced0eSZequan Wu   lldbassert(comp_unit);
294cc9ced0eSZequan Wu   ParseInlineOriginRecords();
295cc9ced0eSZequan Wu   // A vector of current each level's parent block. For example, when parsing
296cc9ced0eSZequan Wu   // "INLINE 0 ...", the current level is 0 and its parent block is the
297cc9ced0eSZequan Wu   // funciton block at index 0.
298cc9ced0eSZequan Wu   std::vector<Block *> blocks;
299cc9ced0eSZequan Wu   Block &block = func.GetBlock(false);
300cc9ced0eSZequan Wu   block.AddRange(Block::Range(0, func.GetAddressRange().GetByteSize()));
301cc9ced0eSZequan Wu   blocks.push_back(&block);
302cc9ced0eSZequan Wu 
303cc9ced0eSZequan Wu   size_t blocks_added = 0;
304cc9ced0eSZequan Wu   addr_t func_base = func.GetAddressRange().GetBaseAddress().GetOffset();
305cc9ced0eSZequan Wu   CompUnitData &data = m_cu_data->GetEntryRef(comp_unit->GetID()).data;
306cc9ced0eSZequan Wu   LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),
307cc9ced0eSZequan Wu       End(*m_objfile_sp);
308cc9ced0eSZequan Wu   ++It; // Skip the FUNC record.
309cc9ced0eSZequan Wu   size_t last_added_nest_level = 0;
310cc9ced0eSZequan Wu   while (It != End && Record::classify(*It) == Record::Inline) {
311cc9ced0eSZequan Wu     if (auto record = InlineRecord::parse(*It)) {
312cc9ced0eSZequan Wu       if (record->InlineNestLevel == 0 ||
313cc9ced0eSZequan Wu           record->InlineNestLevel <= last_added_nest_level + 1) {
314cc9ced0eSZequan Wu         last_added_nest_level = record->InlineNestLevel;
315cc9ced0eSZequan Wu         BlockSP block_sp = std::make_shared<Block>(It.GetBookmark().offset);
316cc9ced0eSZequan Wu         FileSpec callsite_file;
317cc9ced0eSZequan Wu         if (record->CallSiteFileNum < m_files->size())
318cc9ced0eSZequan Wu           callsite_file = (*m_files)[record->CallSiteFileNum];
319cc9ced0eSZequan Wu         llvm::StringRef name;
320cc9ced0eSZequan Wu         if (record->OriginNum < m_inline_origins->size())
321cc9ced0eSZequan Wu           name = (*m_inline_origins)[record->OriginNum];
322cc9ced0eSZequan Wu 
323cc9ced0eSZequan Wu         Declaration callsite(callsite_file, record->CallSiteLineNum);
324cc9ced0eSZequan Wu         block_sp->SetInlinedFunctionInfo(name.str().c_str(),
325cc9ced0eSZequan Wu                                          /*mangled=*/nullptr,
326cc9ced0eSZequan Wu                                          /*decl_ptr=*/nullptr, &callsite);
327cc9ced0eSZequan Wu         for (const auto &range : record->Ranges) {
328cc9ced0eSZequan Wu           block_sp->AddRange(
329cc9ced0eSZequan Wu               Block::Range(range.first - func_base, range.second));
330cc9ced0eSZequan Wu         }
331cc9ced0eSZequan Wu         block_sp->FinalizeRanges();
332cc9ced0eSZequan Wu 
333cc9ced0eSZequan Wu         blocks[record->InlineNestLevel]->AddChild(block_sp);
334cc9ced0eSZequan Wu         if (record->InlineNestLevel + 1 >= blocks.size()) {
335cc9ced0eSZequan Wu           blocks.resize(blocks.size() + 1);
336cc9ced0eSZequan Wu         }
337cc9ced0eSZequan Wu         blocks[record->InlineNestLevel + 1] = block_sp.get();
338cc9ced0eSZequan Wu         ++blocks_added;
339cc9ced0eSZequan Wu       }
340cc9ced0eSZequan Wu     }
341cc9ced0eSZequan Wu     ++It;
342cc9ced0eSZequan Wu   }
343cc9ced0eSZequan Wu   return blocks_added;
344cc9ced0eSZequan Wu }
345cc9ced0eSZequan Wu 
ParseInlineOriginRecords()346cc9ced0eSZequan Wu void SymbolFileBreakpad::ParseInlineOriginRecords() {
347cc9ced0eSZequan Wu   if (m_inline_origins)
348cc9ced0eSZequan Wu     return;
349cc9ced0eSZequan Wu   m_inline_origins.emplace();
350cc9ced0eSZequan Wu 
351a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Symbols);
352cc9ced0eSZequan Wu   for (llvm::StringRef line : lines(Record::InlineOrigin)) {
353cc9ced0eSZequan Wu     auto record = InlineOriginRecord::parse(line);
354cc9ced0eSZequan Wu     if (!record) {
355cc9ced0eSZequan Wu       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
356cc9ced0eSZequan Wu       continue;
357cc9ced0eSZequan Wu     }
358cc9ced0eSZequan Wu 
359cc9ced0eSZequan Wu     if (record->Number >= m_inline_origins->size())
360cc9ced0eSZequan Wu       m_inline_origins->resize(record->Number + 1);
361cc9ced0eSZequan Wu     (*m_inline_origins)[record->Number] = record->Name;
362cc9ced0eSZequan Wu   }
363cc9ced0eSZequan Wu }
364cc9ced0eSZequan Wu 
3651cf23e1aSPavel Labath uint32_t
ResolveSymbolContext(const Address & so_addr,SymbolContextItem resolve_scope,SymbolContext & sc)3661cf23e1aSPavel Labath SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr,
3671cf23e1aSPavel Labath                                          SymbolContextItem resolve_scope,
3681cf23e1aSPavel Labath                                          SymbolContext &sc) {
369656ddeb2SPavel Labath   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
370fbf665a0SZequan Wu   if (!(resolve_scope & (eSymbolContextCompUnit | eSymbolContextLineEntry |
371cc9ced0eSZequan Wu                          eSymbolContextFunction | eSymbolContextBlock)))
3721cf23e1aSPavel Labath     return 0;
3733f35ab8bSPavel Labath 
3743f35ab8bSPavel Labath   ParseCUData();
3753f35ab8bSPavel Labath   uint32_t idx =
3763f35ab8bSPavel Labath       m_cu_data->FindEntryIndexThatContains(so_addr.GetFileAddress());
3773f35ab8bSPavel Labath   if (idx == UINT32_MAX)
3783f35ab8bSPavel Labath     return 0;
3793f35ab8bSPavel Labath 
380e0119909SPavel Labath   sc.comp_unit = GetCompileUnitAtIndex(idx).get();
3813f35ab8bSPavel Labath   SymbolContextItem result = eSymbolContextCompUnit;
3823f35ab8bSPavel Labath   if (resolve_scope & eSymbolContextLineEntry) {
3833f35ab8bSPavel Labath     if (sc.comp_unit->GetLineTable()->FindLineEntryByAddress(so_addr,
3843f35ab8bSPavel Labath                                                              sc.line_entry)) {
3853f35ab8bSPavel Labath       result |= eSymbolContextLineEntry;
3863f35ab8bSPavel Labath     }
3873f35ab8bSPavel Labath   }
388cc9ced0eSZequan Wu 
389cc9ced0eSZequan Wu   if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) {
390fbf665a0SZequan Wu     FunctionSP func_sp = GetOrCreateFunction(*sc.comp_unit);
391fbf665a0SZequan Wu     if (func_sp) {
392fbf665a0SZequan Wu       sc.function = func_sp.get();
393fbf665a0SZequan Wu       result |= eSymbolContextFunction;
394cc9ced0eSZequan Wu       if (resolve_scope & eSymbolContextBlock) {
395cc9ced0eSZequan Wu         Block &block = func_sp->GetBlock(true);
396cc9ced0eSZequan Wu         sc.block = block.FindInnermostBlockByOffset(
397cc9ced0eSZequan Wu             so_addr.GetFileAddress() -
398cc9ced0eSZequan Wu             sc.function->GetAddressRange().GetBaseAddress().GetFileAddress());
399cc9ced0eSZequan Wu         if (sc.block)
400cc9ced0eSZequan Wu           result |= eSymbolContextBlock;
401cc9ced0eSZequan Wu       }
402fbf665a0SZequan Wu     }
403fbf665a0SZequan Wu   }
4043f35ab8bSPavel Labath 
4053f35ab8bSPavel Labath   return result;
4063f35ab8bSPavel Labath }
4073f35ab8bSPavel Labath 
ResolveSymbolContext(const SourceLocationSpec & src_location_spec,lldb::SymbolContextItem resolve_scope,SymbolContextList & sc_list)4083f35ab8bSPavel Labath uint32_t SymbolFileBreakpad::ResolveSymbolContext(
4093e2ed744SMed Ismail Bennani     const SourceLocationSpec &src_location_spec,
4103f35ab8bSPavel Labath     lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
411656ddeb2SPavel Labath   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
4123f35ab8bSPavel Labath   if (!(resolve_scope & eSymbolContextCompUnit))
4133f35ab8bSPavel Labath     return 0;
4143f35ab8bSPavel Labath 
4153f35ab8bSPavel Labath   uint32_t old_size = sc_list.GetSize();
4163f35ab8bSPavel Labath   for (size_t i = 0, size = GetNumCompileUnits(); i < size; ++i) {
417e0119909SPavel Labath     CompileUnit &cu = *GetCompileUnitAtIndex(i);
4183e2ed744SMed Ismail Bennani     cu.ResolveSymbolContext(src_location_spec, resolve_scope, sc_list);
4193f35ab8bSPavel Labath   }
4203f35ab8bSPavel Labath   return sc_list.GetSize() - old_size;
4211cf23e1aSPavel Labath }
4221cf23e1aSPavel Labath 
FindFunctions(ConstString name,const CompilerDeclContext & parent_decl_ctx,FunctionNameType name_type_mask,bool include_inlines,SymbolContextList & sc_list)4231ad655e2SAdrian Prantl void SymbolFileBreakpad::FindFunctions(
424f9568a95SRaphael Isemann     ConstString name, const CompilerDeclContext &parent_decl_ctx,
4251ad655e2SAdrian Prantl     FunctionNameType name_type_mask, bool include_inlines,
4261cf23e1aSPavel Labath     SymbolContextList &sc_list) {
427fbf665a0SZequan Wu   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
428fbf665a0SZequan Wu   // TODO: Implement this with supported FunctionNameType.
429fbf665a0SZequan Wu 
430fbf665a0SZequan Wu   for (uint32_t i = 0; i < GetNumCompileUnits(); ++i) {
431fbf665a0SZequan Wu     CompUnitSP cu_sp = GetCompileUnitAtIndex(i);
432fbf665a0SZequan Wu     FunctionSP func_sp = GetOrCreateFunction(*cu_sp);
433fbf665a0SZequan Wu     if (func_sp && name == func_sp->GetNameNoArguments()) {
434fbf665a0SZequan Wu       SymbolContext sc;
435fbf665a0SZequan Wu       sc.comp_unit = cu_sp.get();
436fbf665a0SZequan Wu       sc.function = func_sp.get();
437fbf665a0SZequan Wu       sc.module_sp = func_sp->CalculateSymbolContextModule();
438fbf665a0SZequan Wu       sc_list.Append(sc);
439fbf665a0SZequan Wu     }
440fbf665a0SZequan Wu   }
4411cf23e1aSPavel Labath }
4421cf23e1aSPavel Labath 
FindFunctions(const RegularExpression & regex,bool include_inlines,SymbolContextList & sc_list)4431ad655e2SAdrian Prantl void SymbolFileBreakpad::FindFunctions(const RegularExpression &regex,
4441ad655e2SAdrian Prantl                                        bool include_inlines,
4451cf23e1aSPavel Labath                                        SymbolContextList &sc_list) {
4461cf23e1aSPavel Labath   // TODO
4471cf23e1aSPavel Labath }
4481cf23e1aSPavel Labath 
FindTypes(ConstString name,const CompilerDeclContext & parent_decl_ctx,uint32_t max_matches,llvm::DenseSet<SymbolFile * > & searched_symbol_files,TypeMap & types)449bf9d84c0SAdrian Prantl void SymbolFileBreakpad::FindTypes(
450f9568a95SRaphael Isemann     ConstString name, const CompilerDeclContext &parent_decl_ctx,
451d4d428efSAdrian Prantl     uint32_t max_matches, llvm::DenseSet<SymbolFile *> &searched_symbol_files,
452bf9d84c0SAdrian Prantl     TypeMap &types) {}
4531cf23e1aSPavel Labath 
FindTypes(llvm::ArrayRef<CompilerContext> pattern,LanguageSet languages,llvm::DenseSet<SymbolFile * > & searched_symbol_files,TypeMap & types)4543b73dcdcSAdrian Prantl void SymbolFileBreakpad::FindTypes(
4553b73dcdcSAdrian Prantl     llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages,
4563b73dcdcSAdrian Prantl     llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {}
4571cf23e1aSPavel Labath 
AddSymbols(Symtab & symtab)4581cf23e1aSPavel Labath void SymbolFileBreakpad::AddSymbols(Symtab &symtab) {
459a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Symbols);
460d2deeb44SPavel Labath   Module &module = *m_objfile_sp->GetModule();
4613f35ab8bSPavel Labath   addr_t base = GetBaseFileAddress();
4621cf23e1aSPavel Labath   if (base == LLDB_INVALID_ADDRESS) {
4631cf23e1aSPavel Labath     LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping "
4641cf23e1aSPavel Labath                   "symtab population.");
4651cf23e1aSPavel Labath     return;
4661cf23e1aSPavel Labath   }
4671cf23e1aSPavel Labath 
4681cf23e1aSPavel Labath   const SectionList &list = *module.GetSectionList();
4695b354d20SRaphael Isemann   llvm::DenseSet<addr_t> found_symbol_addresses;
4705b354d20SRaphael Isemann   std::vector<Symbol> symbols;
47106bb3735SPavel Labath   auto add_symbol = [&](addr_t address, llvm::Optional<addr_t> size,
47206bb3735SPavel Labath                         llvm::StringRef name) {
47306bb3735SPavel Labath     address += base;
47406bb3735SPavel Labath     SectionSP section_sp = list.FindSectionContainingFileAddress(address);
4751cf23e1aSPavel Labath     if (!section_sp) {
4761cf23e1aSPavel Labath       LLDB_LOG(log,
4771cf23e1aSPavel Labath                "Ignoring symbol {0}, whose address ({1}) is outside of the "
4781cf23e1aSPavel Labath                "object file. Mismatched symbol file?",
47906bb3735SPavel Labath                name, address);
48006bb3735SPavel Labath       return;
48106bb3735SPavel Labath     }
4825b354d20SRaphael Isemann     // Keep track of what addresses were already added so far and only add
4835b354d20SRaphael Isemann     // the symbol with the first address.
4845b354d20SRaphael Isemann     if (!found_symbol_addresses.insert(address).second)
4855b354d20SRaphael Isemann       return;
4865b354d20SRaphael Isemann     symbols.emplace_back(
4875b354d20SRaphael Isemann         /*symID*/ 0, Mangled(name), eSymbolTypeCode,
488939411c1SAdrian Prantl         /*is_global*/ true, /*is_debug*/ false,
48906bb3735SPavel Labath         /*is_trampoline*/ false, /*is_artificial*/ false,
49006bb3735SPavel Labath         AddressRange(section_sp, address - section_sp->GetFileAddress(),
491aa88161bSKazu Hirata                      size.value_or(0)),
4920916d96dSKazu Hirata         size.has_value(), /*contains_linker_annotations*/ false, /*flags*/ 0);
49306bb3735SPavel Labath   };
49406bb3735SPavel Labath 
4953f35ab8bSPavel Labath   for (llvm::StringRef line : lines(Record::Public)) {
49606bb3735SPavel Labath     if (auto record = PublicRecord::parse(line))
4975b18ddb6SPavel Labath       add_symbol(record->Address, llvm::None, record->Name);
49806bb3735SPavel Labath     else
49906bb3735SPavel Labath       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
5001cf23e1aSPavel Labath   }
5011cf23e1aSPavel Labath 
5025b354d20SRaphael Isemann   for (Symbol &symbol : symbols)
5035b354d20SRaphael Isemann     symtab.AddSymbol(std::move(symbol));
5047e6df41fSGreg Clayton   symtab.Finalize();
5051cf23e1aSPavel Labath }
5063f35ab8bSPavel Labath 
507a8b284eeSPavel Labath llvm::Expected<lldb::addr_t>
GetParameterStackSize(Symbol & symbol)508a8b284eeSPavel Labath SymbolFileBreakpad::GetParameterStackSize(Symbol &symbol) {
509a8b284eeSPavel Labath   ParseUnwindData();
510a8b284eeSPavel Labath   if (auto *entry = m_unwind_data->win.FindEntryThatContains(
511a8b284eeSPavel Labath           symbol.GetAddress().GetFileAddress())) {
512a8b284eeSPavel Labath     auto record = StackWinRecord::parse(
513a8b284eeSPavel Labath         *LineIterator(*m_objfile_sp, Record::StackWin, entry->data));
5145413bf1bSKazu Hirata     assert(record);
515a8b284eeSPavel Labath     return record->ParameterSize;
516a8b284eeSPavel Labath   }
517a8b284eeSPavel Labath   return llvm::createStringError(llvm::inconvertibleErrorCode(),
518a8b284eeSPavel Labath                                  "Parameter size unknown.");
519a8b284eeSPavel Labath }
520a8b284eeSPavel Labath 
5211211baa5SPavel Labath static llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
GetRule(llvm::StringRef & unwind_rules)5221211baa5SPavel Labath GetRule(llvm::StringRef &unwind_rules) {
5231211baa5SPavel Labath   // Unwind rules are of the form
5241211baa5SPavel Labath   //   register1: expression1 register2: expression2 ...
5251211baa5SPavel Labath   // We assume none of the tokens in expression<n> end with a colon.
5261211baa5SPavel Labath 
5271211baa5SPavel Labath   llvm::StringRef lhs, rest;
5281211baa5SPavel Labath   std::tie(lhs, rest) = getToken(unwind_rules);
5291211baa5SPavel Labath   if (!lhs.consume_back(":"))
5301211baa5SPavel Labath     return llvm::None;
5311211baa5SPavel Labath 
5321211baa5SPavel Labath   // Seek forward to the next register: expression pair
5331211baa5SPavel Labath   llvm::StringRef::size_type pos = rest.find(": ");
5341211baa5SPavel Labath   if (pos == llvm::StringRef::npos) {
5351211baa5SPavel Labath     // No pair found, this means the rest of the string is a single expression.
5361211baa5SPavel Labath     unwind_rules = llvm::StringRef();
5371211baa5SPavel Labath     return std::make_pair(lhs, rest);
5381211baa5SPavel Labath   }
5391211baa5SPavel Labath 
5401211baa5SPavel Labath   // Go back one token to find the end of the current rule.
5411211baa5SPavel Labath   pos = rest.rfind(' ', pos);
5421211baa5SPavel Labath   if (pos == llvm::StringRef::npos)
5431211baa5SPavel Labath     return llvm::None;
5441211baa5SPavel Labath 
5451211baa5SPavel Labath   llvm::StringRef rhs = rest.take_front(pos);
5461211baa5SPavel Labath   unwind_rules = rest.drop_front(pos);
5471211baa5SPavel Labath   return std::make_pair(lhs, rhs);
5481211baa5SPavel Labath }
5491211baa5SPavel Labath 
5501211baa5SPavel Labath static const RegisterInfo *
ResolveRegister(const llvm::Triple & triple,const SymbolFile::RegisterInfoResolver & resolver,llvm::StringRef name)551e22f0dabSPavel Labath ResolveRegister(const llvm::Triple &triple,
552e22f0dabSPavel Labath                 const SymbolFile::RegisterInfoResolver &resolver,
5531211baa5SPavel Labath                 llvm::StringRef name) {
554e22f0dabSPavel Labath   if (triple.isX86() || triple.isMIPS()) {
555e22f0dabSPavel Labath     // X86 and MIPS registers have '$' in front of their register names. Arm and
556e22f0dabSPavel Labath     // AArch64 don't.
557e22f0dabSPavel Labath     if (!name.consume_front("$"))
5581211baa5SPavel Labath       return nullptr;
5591211baa5SPavel Labath   }
560e22f0dabSPavel Labath   return resolver.ResolveName(name);
561e22f0dabSPavel Labath }
5621211baa5SPavel Labath 
5631211baa5SPavel Labath static const RegisterInfo *
ResolveRegisterOrRA(const llvm::Triple & triple,const SymbolFile::RegisterInfoResolver & resolver,llvm::StringRef name)564e22f0dabSPavel Labath ResolveRegisterOrRA(const llvm::Triple &triple,
565e22f0dabSPavel Labath                     const SymbolFile::RegisterInfoResolver &resolver,
5661211baa5SPavel Labath                     llvm::StringRef name) {
5671211baa5SPavel Labath   if (name == ".ra")
5681211baa5SPavel Labath     return resolver.ResolveNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
569e22f0dabSPavel Labath   return ResolveRegister(triple, resolver, name);
5701211baa5SPavel Labath }
5711211baa5SPavel Labath 
SaveAsDWARF(postfix::Node & node)572c3bea40bSPavel Labath llvm::ArrayRef<uint8_t> SymbolFileBreakpad::SaveAsDWARF(postfix::Node &node) {
573c3bea40bSPavel Labath   ArchSpec arch = m_objfile_sp->GetArchitecture();
574c3bea40bSPavel Labath   StreamString dwarf(Stream::eBinary, arch.GetAddressByteSize(),
575c3bea40bSPavel Labath                      arch.GetByteOrder());
576c3bea40bSPavel Labath   ToDWARF(node, dwarf);
577c3bea40bSPavel Labath   uint8_t *saved = m_allocator.Allocate<uint8_t>(dwarf.GetSize());
578c3bea40bSPavel Labath   std::memcpy(saved, dwarf.GetData(), dwarf.GetSize());
579c3bea40bSPavel Labath   return {saved, dwarf.GetSize()};
580c3bea40bSPavel Labath }
581c3bea40bSPavel Labath 
ParseCFIUnwindRow(llvm::StringRef unwind_rules,const RegisterInfoResolver & resolver,UnwindPlan::Row & row)582c3bea40bSPavel Labath bool SymbolFileBreakpad::ParseCFIUnwindRow(llvm::StringRef unwind_rules,
5831211baa5SPavel Labath                                         const RegisterInfoResolver &resolver,
5841211baa5SPavel Labath                                         UnwindPlan::Row &row) {
585a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Symbols);
5861211baa5SPavel Labath 
5871211baa5SPavel Labath   llvm::BumpPtrAllocator node_alloc;
588e22f0dabSPavel Labath   llvm::Triple triple = m_objfile_sp->GetArchitecture().GetTriple();
5891211baa5SPavel Labath   while (auto rule = GetRule(unwind_rules)) {
5901211baa5SPavel Labath     node_alloc.Reset();
5911211baa5SPavel Labath     llvm::StringRef lhs = rule->first;
592c7deb7f8SPavel Labath     postfix::Node *rhs = postfix::ParseOneExpression(rule->second, node_alloc);
5931211baa5SPavel Labath     if (!rhs) {
5941211baa5SPavel Labath       LLDB_LOG(log, "Could not parse `{0}` as unwind rhs.", rule->second);
5951211baa5SPavel Labath       return false;
5961211baa5SPavel Labath     }
5971211baa5SPavel Labath 
5981211baa5SPavel Labath     bool success = postfix::ResolveSymbols(
5991211baa5SPavel Labath         rhs, [&](postfix::SymbolNode &symbol) -> postfix::Node * {
6001211baa5SPavel Labath           llvm::StringRef name = symbol.GetName();
6011211baa5SPavel Labath           if (name == ".cfa" && lhs != ".cfa")
6021211baa5SPavel Labath             return postfix::MakeNode<postfix::InitialValueNode>(node_alloc);
6031211baa5SPavel Labath 
604e22f0dabSPavel Labath           if (const RegisterInfo *info =
605e22f0dabSPavel Labath                   ResolveRegister(triple, resolver, name)) {
6061211baa5SPavel Labath             return postfix::MakeNode<postfix::RegisterNode>(
6071211baa5SPavel Labath                 node_alloc, info->kinds[eRegisterKindLLDB]);
6081211baa5SPavel Labath           }
6091211baa5SPavel Labath           return nullptr;
6101211baa5SPavel Labath         });
6111211baa5SPavel Labath 
6121211baa5SPavel Labath     if (!success) {
6131211baa5SPavel Labath       LLDB_LOG(log, "Resolving symbols in `{0}` failed.", rule->second);
6141211baa5SPavel Labath       return false;
6151211baa5SPavel Labath     }
6161211baa5SPavel Labath 
617c3bea40bSPavel Labath     llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*rhs);
6181211baa5SPavel Labath     if (lhs == ".cfa") {
619c3bea40bSPavel Labath       row.GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size());
620e22f0dabSPavel Labath     } else if (const RegisterInfo *info =
621e22f0dabSPavel Labath                    ResolveRegisterOrRA(triple, resolver, lhs)) {
6221211baa5SPavel Labath       UnwindPlan::Row::RegisterLocation loc;
623c3bea40bSPavel Labath       loc.SetIsDWARFExpression(saved.data(), saved.size());
6241211baa5SPavel Labath       row.SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc);
6251211baa5SPavel Labath     } else
6261211baa5SPavel Labath       LLDB_LOG(log, "Invalid register `{0}` in unwind rule.", lhs);
6271211baa5SPavel Labath   }
6281211baa5SPavel Labath   if (unwind_rules.empty())
6291211baa5SPavel Labath     return true;
6301211baa5SPavel Labath 
6311211baa5SPavel Labath   LLDB_LOG(log, "Could not parse `{0}` as an unwind rule.", unwind_rules);
6321211baa5SPavel Labath   return false;
6331211baa5SPavel Labath }
6341211baa5SPavel Labath 
6351211baa5SPavel Labath UnwindPlanSP
GetUnwindPlan(const Address & address,const RegisterInfoResolver & resolver)6361211baa5SPavel Labath SymbolFileBreakpad::GetUnwindPlan(const Address &address,
6371211baa5SPavel Labath                                   const RegisterInfoResolver &resolver) {
6381211baa5SPavel Labath   ParseUnwindData();
639c3bea40bSPavel Labath   if (auto *entry =
640c3bea40bSPavel Labath           m_unwind_data->cfi.FindEntryThatContains(address.GetFileAddress()))
641c3bea40bSPavel Labath     return ParseCFIUnwindPlan(entry->data, resolver);
642c3bea40bSPavel Labath   if (auto *entry =
643c3bea40bSPavel Labath           m_unwind_data->win.FindEntryThatContains(address.GetFileAddress()))
644c3bea40bSPavel Labath     return ParseWinUnwindPlan(entry->data, resolver);
6451211baa5SPavel Labath   return nullptr;
646c3bea40bSPavel Labath }
6471211baa5SPavel Labath 
648c3bea40bSPavel Labath UnwindPlanSP
ParseCFIUnwindPlan(const Bookmark & bookmark,const RegisterInfoResolver & resolver)649c3bea40bSPavel Labath SymbolFileBreakpad::ParseCFIUnwindPlan(const Bookmark &bookmark,
650c3bea40bSPavel Labath                                        const RegisterInfoResolver &resolver) {
6511211baa5SPavel Labath   addr_t base = GetBaseFileAddress();
6521211baa5SPavel Labath   if (base == LLDB_INVALID_ADDRESS)
6531211baa5SPavel Labath     return nullptr;
6541211baa5SPavel Labath 
655c3bea40bSPavel Labath   LineIterator It(*m_objfile_sp, Record::StackCFI, bookmark),
656d2deeb44SPavel Labath       End(*m_objfile_sp);
6571211baa5SPavel Labath   llvm::Optional<StackCFIRecord> init_record = StackCFIRecord::parse(*It);
6585413bf1bSKazu Hirata   assert(init_record && init_record->Size &&
659c3bea40bSPavel Labath          "Record already parsed successfully in ParseUnwindData!");
6601211baa5SPavel Labath 
6611211baa5SPavel Labath   auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB);
6621211baa5SPavel Labath   plan_sp->SetSourceName("breakpad STACK CFI");
6631211baa5SPavel Labath   plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
6643fd917d8SJoseph Tremoulet   plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);
6651211baa5SPavel Labath   plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
6661211baa5SPavel Labath   plan_sp->SetPlanValidAddressRange(
6671211baa5SPavel Labath       AddressRange(base + init_record->Address, *init_record->Size,
668d2deeb44SPavel Labath                    m_objfile_sp->GetModule()->GetSectionList()));
6691211baa5SPavel Labath 
6701211baa5SPavel Labath   auto row_sp = std::make_shared<UnwindPlan::Row>();
6711211baa5SPavel Labath   row_sp->SetOffset(0);
672c3bea40bSPavel Labath   if (!ParseCFIUnwindRow(init_record->UnwindRules, resolver, *row_sp))
6731211baa5SPavel Labath     return nullptr;
6741211baa5SPavel Labath   plan_sp->AppendRow(row_sp);
6751211baa5SPavel Labath   for (++It; It != End; ++It) {
6761211baa5SPavel Labath     llvm::Optional<StackCFIRecord> record = StackCFIRecord::parse(*It);
677*96d1b4ddSKazu Hirata     if (!record)
6781211baa5SPavel Labath       return nullptr;
679*96d1b4ddSKazu Hirata     if (record->Size)
6801211baa5SPavel Labath       break;
6811211baa5SPavel Labath 
6821211baa5SPavel Labath     row_sp = std::make_shared<UnwindPlan::Row>(*row_sp);
6831211baa5SPavel Labath     row_sp->SetOffset(record->Address - init_record->Address);
684c3bea40bSPavel Labath     if (!ParseCFIUnwindRow(record->UnwindRules, resolver, *row_sp))
6851211baa5SPavel Labath       return nullptr;
6861211baa5SPavel Labath     plan_sp->AppendRow(row_sp);
6871211baa5SPavel Labath   }
6881211baa5SPavel Labath   return plan_sp;
6891211baa5SPavel Labath }
6901211baa5SPavel Labath 
691c3bea40bSPavel Labath UnwindPlanSP
ParseWinUnwindPlan(const Bookmark & bookmark,const RegisterInfoResolver & resolver)692c3bea40bSPavel Labath SymbolFileBreakpad::ParseWinUnwindPlan(const Bookmark &bookmark,
693c3bea40bSPavel Labath                                        const RegisterInfoResolver &resolver) {
694a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Symbols);
695c3bea40bSPavel Labath   addr_t base = GetBaseFileAddress();
696c3bea40bSPavel Labath   if (base == LLDB_INVALID_ADDRESS)
697c3bea40bSPavel Labath     return nullptr;
698c3bea40bSPavel Labath 
699c3bea40bSPavel Labath   LineIterator It(*m_objfile_sp, Record::StackWin, bookmark);
700c3bea40bSPavel Labath   llvm::Optional<StackWinRecord> record = StackWinRecord::parse(*It);
701ad7ce1e7SKazu Hirata   assert(record && "Record already parsed successfully in ParseUnwindData!");
702c3bea40bSPavel Labath 
703c3bea40bSPavel Labath   auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB);
704c3bea40bSPavel Labath   plan_sp->SetSourceName("breakpad STACK WIN");
705c3bea40bSPavel Labath   plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
706c3bea40bSPavel Labath   plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);
707c3bea40bSPavel Labath   plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
708c3bea40bSPavel Labath   plan_sp->SetPlanValidAddressRange(
709c3bea40bSPavel Labath       AddressRange(base + record->RVA, record->CodeSize,
710c3bea40bSPavel Labath                    m_objfile_sp->GetModule()->GetSectionList()));
711c3bea40bSPavel Labath 
712c3bea40bSPavel Labath   auto row_sp = std::make_shared<UnwindPlan::Row>();
713c3bea40bSPavel Labath   row_sp->SetOffset(0);
714c3bea40bSPavel Labath 
715c3bea40bSPavel Labath   llvm::BumpPtrAllocator node_alloc;
716c3bea40bSPavel Labath   std::vector<std::pair<llvm::StringRef, postfix::Node *>> program =
717c3bea40bSPavel Labath       postfix::ParseFPOProgram(record->ProgramString, node_alloc);
718c3bea40bSPavel Labath 
719c3bea40bSPavel Labath   if (program.empty()) {
720c3bea40bSPavel Labath     LLDB_LOG(log, "Invalid unwind rule: {0}.", record->ProgramString);
721c3bea40bSPavel Labath     return nullptr;
722c3bea40bSPavel Labath   }
723c3bea40bSPavel Labath   auto it = program.begin();
724e22f0dabSPavel Labath   llvm::Triple triple = m_objfile_sp->GetArchitecture().GetTriple();
725c3bea40bSPavel Labath   const auto &symbol_resolver =
726c3bea40bSPavel Labath       [&](postfix::SymbolNode &symbol) -> postfix::Node * {
727c3bea40bSPavel Labath     llvm::StringRef name = symbol.GetName();
728c3bea40bSPavel Labath     for (const auto &rule : llvm::make_range(program.begin(), it)) {
729c3bea40bSPavel Labath       if (rule.first == name)
730c3bea40bSPavel Labath         return rule.second;
731c3bea40bSPavel Labath     }
732e22f0dabSPavel Labath     if (const RegisterInfo *info = ResolveRegister(triple, resolver, name))
733c3bea40bSPavel Labath       return postfix::MakeNode<postfix::RegisterNode>(
734c3bea40bSPavel Labath           node_alloc, info->kinds[eRegisterKindLLDB]);
735c3bea40bSPavel Labath     return nullptr;
736c3bea40bSPavel Labath   };
737c3bea40bSPavel Labath 
738c3bea40bSPavel Labath   // We assume the first value will be the CFA. It is usually called T0, but
739c3bea40bSPavel Labath   // clang will use T1, if it needs to realign the stack.
740a8b284eeSPavel Labath   auto *symbol = llvm::dyn_cast<postfix::SymbolNode>(it->second);
741a8b284eeSPavel Labath   if (symbol && symbol->GetName() == ".raSearch") {
742a8b284eeSPavel Labath     row_sp->GetCFAValue().SetRaSearch(record->LocalSize +
743a8b284eeSPavel Labath                                       record->SavedRegisterSize);
744a8b284eeSPavel Labath   } else {
745c3bea40bSPavel Labath     if (!postfix::ResolveSymbols(it->second, symbol_resolver)) {
746a8b284eeSPavel Labath       LLDB_LOG(log, "Resolving symbols in `{0}` failed.",
747a8b284eeSPavel Labath                record->ProgramString);
748c3bea40bSPavel Labath       return nullptr;
749c3bea40bSPavel Labath     }
750c3bea40bSPavel Labath     llvm::ArrayRef<uint8_t> saved  = SaveAsDWARF(*it->second);
751c3bea40bSPavel Labath     row_sp->GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size());
752a8b284eeSPavel Labath   }
753c3bea40bSPavel Labath 
754c3bea40bSPavel Labath   // Replace the node value with InitialValueNode, so that subsequent
755c3bea40bSPavel Labath   // expressions refer to the CFA value instead of recomputing the whole
756c3bea40bSPavel Labath   // expression.
757c3bea40bSPavel Labath   it->second = postfix::MakeNode<postfix::InitialValueNode>(node_alloc);
758c3bea40bSPavel Labath 
759c3bea40bSPavel Labath 
760c3bea40bSPavel Labath   // Now process the rest of the assignments.
761c3bea40bSPavel Labath   for (++it; it != program.end(); ++it) {
762e22f0dabSPavel Labath     const RegisterInfo *info = ResolveRegister(triple, resolver, it->first);
763c3bea40bSPavel Labath     // It is not an error if the resolution fails because the program may
764c3bea40bSPavel Labath     // contain temporary variables.
765c3bea40bSPavel Labath     if (!info)
766c3bea40bSPavel Labath       continue;
767c3bea40bSPavel Labath     if (!postfix::ResolveSymbols(it->second, symbol_resolver)) {
768c3bea40bSPavel Labath       LLDB_LOG(log, "Resolving symbols in `{0}` failed.",
769c3bea40bSPavel Labath                record->ProgramString);
770c3bea40bSPavel Labath       return nullptr;
771c3bea40bSPavel Labath     }
772c3bea40bSPavel Labath 
773c3bea40bSPavel Labath     llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*it->second);
774c3bea40bSPavel Labath     UnwindPlan::Row::RegisterLocation loc;
775c3bea40bSPavel Labath     loc.SetIsDWARFExpression(saved.data(), saved.size());
776c3bea40bSPavel Labath     row_sp->SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc);
777c3bea40bSPavel Labath   }
778c3bea40bSPavel Labath 
779c3bea40bSPavel Labath   plan_sp->AppendRow(row_sp);
780c3bea40bSPavel Labath   return plan_sp;
781c3bea40bSPavel Labath }
782c3bea40bSPavel Labath 
GetBaseFileAddress()7833f35ab8bSPavel Labath addr_t SymbolFileBreakpad::GetBaseFileAddress() {
784d2deeb44SPavel Labath   return m_objfile_sp->GetModule()
7853f35ab8bSPavel Labath       ->GetObjectFile()
7863f35ab8bSPavel Labath       ->GetBaseAddress()
7873f35ab8bSPavel Labath       .GetFileAddress();
7883f35ab8bSPavel Labath }
7893f35ab8bSPavel Labath 
7903f35ab8bSPavel Labath // Parse out all the FILE records from the breakpad file. These will be needed
7913f35ab8bSPavel Labath // when constructing the support file lists for individual compile units.
ParseFileRecords()7923f35ab8bSPavel Labath void SymbolFileBreakpad::ParseFileRecords() {
7933f35ab8bSPavel Labath   if (m_files)
7943f35ab8bSPavel Labath     return;
7953f35ab8bSPavel Labath   m_files.emplace();
7963f35ab8bSPavel Labath 
797a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Symbols);
7983f35ab8bSPavel Labath   for (llvm::StringRef line : lines(Record::File)) {
7993f35ab8bSPavel Labath     auto record = FileRecord::parse(line);
8003f35ab8bSPavel Labath     if (!record) {
8013f35ab8bSPavel Labath       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
8023f35ab8bSPavel Labath       continue;
8033f35ab8bSPavel Labath     }
8043f35ab8bSPavel Labath 
8053f35ab8bSPavel Labath     if (record->Number >= m_files->size())
8063f35ab8bSPavel Labath       m_files->resize(record->Number + 1);
807841bea93SPavel Labath     FileSpec::Style style = FileSpec::GuessPathStyle(record->Name)
808aa88161bSKazu Hirata                                 .value_or(FileSpec::Style::native);
809841bea93SPavel Labath     (*m_files)[record->Number] = FileSpec(record->Name, style);
8103f35ab8bSPavel Labath   }
8113f35ab8bSPavel Labath }
8123f35ab8bSPavel Labath 
ParseCUData()8133f35ab8bSPavel Labath void SymbolFileBreakpad::ParseCUData() {
8143f35ab8bSPavel Labath   if (m_cu_data)
8153f35ab8bSPavel Labath     return;
8163f35ab8bSPavel Labath 
8173f35ab8bSPavel Labath   m_cu_data.emplace();
818a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Symbols);
8193f35ab8bSPavel Labath   addr_t base = GetBaseFileAddress();
8203f35ab8bSPavel Labath   if (base == LLDB_INVALID_ADDRESS) {
8213f35ab8bSPavel Labath     LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "
8223f35ab8bSPavel Labath                   "of object file.");
8233f35ab8bSPavel Labath   }
8243f35ab8bSPavel Labath 
8253f35ab8bSPavel Labath   // We shall create one compile unit for each FUNC record. So, count the number
8263f35ab8bSPavel Labath   // of FUNC records, and store them in m_cu_data, together with their ranges.
827d2deeb44SPavel Labath   for (LineIterator It(*m_objfile_sp, Record::Func), End(*m_objfile_sp);
828d2deeb44SPavel Labath        It != End; ++It) {
8293f35ab8bSPavel Labath     if (auto record = FuncRecord::parse(*It)) {
8303f35ab8bSPavel Labath       m_cu_data->Append(CompUnitMap::Entry(base + record->Address, record->Size,
8313f35ab8bSPavel Labath                                            CompUnitData(It.GetBookmark())));
8323f35ab8bSPavel Labath     } else
8333f35ab8bSPavel Labath       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
8343f35ab8bSPavel Labath   }
8353f35ab8bSPavel Labath   m_cu_data->Sort();
8363f35ab8bSPavel Labath }
8373f35ab8bSPavel Labath 
8383f35ab8bSPavel Labath // Construct the list of support files and line table entries for the given
8393f35ab8bSPavel Labath // compile unit.
ParseLineTableAndSupportFiles(CompileUnit & cu,CompUnitData & data)8403f35ab8bSPavel Labath void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu,
8413f35ab8bSPavel Labath                                                        CompUnitData &data) {
8423f35ab8bSPavel Labath   addr_t base = GetBaseFileAddress();
8433f35ab8bSPavel Labath   assert(base != LLDB_INVALID_ADDRESS &&
8443f35ab8bSPavel Labath          "How did we create compile units without a base address?");
8453f35ab8bSPavel Labath 
8463f35ab8bSPavel Labath   SupportFileMap map;
8475e70f4bdSPavel Labath   std::vector<std::unique_ptr<LineSequence>> sequences;
8485e70f4bdSPavel Labath   std::unique_ptr<LineSequence> line_seq_up =
8495e70f4bdSPavel Labath       LineTable::CreateLineSequenceContainer();
8503f35ab8bSPavel Labath   llvm::Optional<addr_t> next_addr;
8513f35ab8bSPavel Labath   auto finish_sequence = [&]() {
8525e70f4bdSPavel Labath     LineTable::AppendLineEntryToSequence(
8533e2ed744SMed Ismail Bennani         line_seq_up.get(), *next_addr, /*line=*/0, /*column=*/0,
8543e2ed744SMed Ismail Bennani         /*file_idx=*/0, /*is_start_of_statement=*/false,
8553e2ed744SMed Ismail Bennani         /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false,
8563e2ed744SMed Ismail Bennani         /*is_epilogue_begin=*/false, /*is_terminal_entry=*/true);
8575e70f4bdSPavel Labath     sequences.push_back(std::move(line_seq_up));
8585e70f4bdSPavel Labath     line_seq_up = LineTable::CreateLineSequenceContainer();
8593f35ab8bSPavel Labath   };
8603f35ab8bSPavel Labath 
861d2deeb44SPavel Labath   LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),
862d2deeb44SPavel Labath       End(*m_objfile_sp);
8633f35ab8bSPavel Labath   assert(Record::classify(*It) == Record::Func);
8643f35ab8bSPavel Labath   for (++It; It != End; ++It) {
865cc9ced0eSZequan Wu     // Skip INLINE records
866cc9ced0eSZequan Wu     if (Record::classify(*It) == Record::Inline)
867cc9ced0eSZequan Wu       continue;
868cc9ced0eSZequan Wu 
8693f35ab8bSPavel Labath     auto record = LineRecord::parse(*It);
8703f35ab8bSPavel Labath     if (!record)
8713f35ab8bSPavel Labath       break;
8723f35ab8bSPavel Labath 
8733f35ab8bSPavel Labath     record->Address += base;
8743f35ab8bSPavel Labath 
8753f35ab8bSPavel Labath     if (next_addr && *next_addr != record->Address) {
8763f35ab8bSPavel Labath       // Discontiguous entries. Finish off the previous sequence and reset.
8773f35ab8bSPavel Labath       finish_sequence();
8783f35ab8bSPavel Labath     }
8795e70f4bdSPavel Labath     LineTable::AppendLineEntryToSequence(
8803e2ed744SMed Ismail Bennani         line_seq_up.get(), record->Address, record->LineNum, /*column=*/0,
8813e2ed744SMed Ismail Bennani         map[record->FileNum], /*is_start_of_statement=*/true,
8823e2ed744SMed Ismail Bennani         /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false,
8833e2ed744SMed Ismail Bennani         /*is_epilogue_begin=*/false, /*is_terminal_entry=*/false);
8843f35ab8bSPavel Labath     next_addr = record->Address + record->Size;
8853f35ab8bSPavel Labath   }
8863f35ab8bSPavel Labath   if (next_addr)
8873f35ab8bSPavel Labath     finish_sequence();
8885e70f4bdSPavel Labath   data.line_table_up = std::make_unique<LineTable>(&cu, std::move(sequences));
88938870af8SPavel Labath   data.support_files = map.translate(cu.GetPrimaryFile(), *m_files);
8903f35ab8bSPavel Labath }
8911211baa5SPavel Labath 
ParseUnwindData()8921211baa5SPavel Labath void SymbolFileBreakpad::ParseUnwindData() {
8931211baa5SPavel Labath   if (m_unwind_data)
8941211baa5SPavel Labath     return;
8951211baa5SPavel Labath   m_unwind_data.emplace();
896c3bea40bSPavel Labath 
897a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Symbols);
8981211baa5SPavel Labath   addr_t base = GetBaseFileAddress();
8991211baa5SPavel Labath   if (base == LLDB_INVALID_ADDRESS) {
9001211baa5SPavel Labath     LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "
9011211baa5SPavel Labath                   "of object file.");
9021211baa5SPavel Labath   }
9031211baa5SPavel Labath 
904d2deeb44SPavel Labath   for (LineIterator It(*m_objfile_sp, Record::StackCFI), End(*m_objfile_sp);
9051211baa5SPavel Labath        It != End; ++It) {
9061211baa5SPavel Labath     if (auto record = StackCFIRecord::parse(*It)) {
9071211baa5SPavel Labath       if (record->Size)
908c3bea40bSPavel Labath         m_unwind_data->cfi.Append(UnwindMap::Entry(
9091211baa5SPavel Labath             base + record->Address, *record->Size, It.GetBookmark()));
9101211baa5SPavel Labath     } else
9111211baa5SPavel Labath       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
9121211baa5SPavel Labath   }
913c3bea40bSPavel Labath   m_unwind_data->cfi.Sort();
914c3bea40bSPavel Labath 
915c3bea40bSPavel Labath   for (LineIterator It(*m_objfile_sp, Record::StackWin), End(*m_objfile_sp);
916c3bea40bSPavel Labath        It != End; ++It) {
917c3bea40bSPavel Labath     if (auto record = StackWinRecord::parse(*It)) {
918c3bea40bSPavel Labath       m_unwind_data->win.Append(UnwindMap::Entry(
919c3bea40bSPavel Labath           base + record->RVA, record->CodeSize, It.GetBookmark()));
920c3bea40bSPavel Labath     } else
921c3bea40bSPavel Labath       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
922c3bea40bSPavel Labath   }
923c3bea40bSPavel Labath   m_unwind_data->win.Sort();
9241211baa5SPavel Labath }
9252887d9fdSGreg Clayton 
GetDebugInfoSize()9262887d9fdSGreg Clayton uint64_t SymbolFileBreakpad::GetDebugInfoSize() {
9272887d9fdSGreg Clayton   // Breakpad files are all debug info.
9282887d9fdSGreg Clayton   return m_objfile_sp->GetByteSize();
9292887d9fdSGreg Clayton }
930