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 § =
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(§, 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 § = *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(§, 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 ®ex,
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