brintos

brintos / llvm-project-archived public Read only

0
0
Text · 31.9 KiB · ce2ba69 Raw
918 lines · cpp
1//===-- SymbolFileBreakpad.cpp --------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h"10#include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"11#include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h"12#include "lldb/Core/Module.h"13#include "lldb/Core/PluginManager.h"14#include "lldb/Core/Section.h"15#include "lldb/Host/FileSystem.h"16#include "lldb/Symbol/CompileUnit.h"17#include "lldb/Symbol/ObjectFile.h"18#include "lldb/Symbol/SymbolVendor.h"19#include "lldb/Symbol/TypeMap.h"20#include "lldb/Utility/LLDBLog.h"21#include "lldb/Utility/Log.h"22#include "lldb/Utility/StreamString.h"23#include "llvm/ADT/StringExtras.h"24#include <optional>25 26using namespace lldb;27using namespace lldb_private;28using namespace lldb_private::breakpad;29 30LLDB_PLUGIN_DEFINE(SymbolFileBreakpad)31 32char SymbolFileBreakpad::ID;33 34class SymbolFileBreakpad::LineIterator {35public:36  // begin iterator for sections of given type37  LineIterator(ObjectFile &obj, Record::Kind section_type)38      : m_obj(&obj), m_section_type(toString(section_type)),39        m_next_section_idx(0), m_next_line(llvm::StringRef::npos) {40    ++*this;41  }42 43  // An iterator starting at the position given by the bookmark.44  LineIterator(ObjectFile &obj, Record::Kind section_type, Bookmark bookmark);45 46  // end iterator47  explicit LineIterator(ObjectFile &obj)48      : m_obj(&obj),49        m_next_section_idx(m_obj->GetSectionList()->GetNumSections(0)),50        m_current_line(llvm::StringRef::npos),51        m_next_line(llvm::StringRef::npos) {}52 53  friend bool operator!=(const LineIterator &lhs, const LineIterator &rhs) {54    assert(lhs.m_obj == rhs.m_obj);55    if (lhs.m_next_section_idx != rhs.m_next_section_idx)56      return true;57    if (lhs.m_current_line != rhs.m_current_line)58      return true;59    assert(lhs.m_next_line == rhs.m_next_line);60    return false;61  }62 63  const LineIterator &operator++();64  llvm::StringRef operator*() const {65    return m_section_text.slice(m_current_line, m_next_line);66  }67 68  Bookmark GetBookmark() const {69    return Bookmark{m_next_section_idx, m_current_line};70  }71 72private:73  ObjectFile *m_obj;74  ConstString m_section_type;75  uint32_t m_next_section_idx;76  llvm::StringRef m_section_text;77  size_t m_current_line;78  size_t m_next_line;79 80  void FindNextLine() {81    m_next_line = m_section_text.find('\n', m_current_line);82    if (m_next_line != llvm::StringRef::npos) {83      ++m_next_line;84      if (m_next_line >= m_section_text.size())85        m_next_line = llvm::StringRef::npos;86    }87  }88};89 90SymbolFileBreakpad::LineIterator::LineIterator(ObjectFile &obj,91                                               Record::Kind section_type,92                                               Bookmark bookmark)93    : m_obj(&obj), m_section_type(toString(section_type)),94      m_next_section_idx(bookmark.section), m_current_line(bookmark.offset) {95  Section &sect =96      *obj.GetSectionList()->GetSectionAtIndex(m_next_section_idx - 1);97  assert(sect.GetName() == m_section_type);98 99  DataExtractor data;100  obj.ReadSectionData(&sect, data);101  m_section_text = toStringRef(data.GetData());102 103  assert(m_current_line < m_section_text.size());104  FindNextLine();105}106 107const SymbolFileBreakpad::LineIterator &108SymbolFileBreakpad::LineIterator::operator++() {109  const SectionList &list = *m_obj->GetSectionList();110  size_t num_sections = list.GetNumSections(0);111  while (m_next_line != llvm::StringRef::npos ||112         m_next_section_idx < num_sections) {113    if (m_next_line != llvm::StringRef::npos) {114      m_current_line = m_next_line;115      FindNextLine();116      return *this;117    }118 119    Section &sect = *list.GetSectionAtIndex(m_next_section_idx++);120    if (sect.GetName() != m_section_type)121      continue;122    DataExtractor data;123    m_obj->ReadSectionData(&sect, data);124    m_section_text = toStringRef(data.GetData());125    m_next_line = 0;126  }127  // We've reached the end.128  m_current_line = m_next_line;129  return *this;130}131 132llvm::iterator_range<SymbolFileBreakpad::LineIterator>133SymbolFileBreakpad::lines(Record::Kind section_type) {134  return llvm::make_range(LineIterator(*m_objfile_sp, section_type),135                          LineIterator(*m_objfile_sp));136}137 138namespace {139// A helper class for constructing the list of support files for a given compile140// unit.141class SupportFileMap {142public:143  // Given a breakpad file ID, return a file ID to be used in the support files144  // for this compile unit.145  size_t operator[](size_t file) {146    return m_map.try_emplace(file, m_map.size() + 1).first->second;147  }148 149  // Construct a FileSpecList containing only the support files relevant for150  // this compile unit (in the correct order).151  FileSpecList translate(const FileSpec &cu_spec,152                         llvm::ArrayRef<FileSpec> all_files);153 154private:155  llvm::DenseMap<size_t, size_t> m_map;156};157} // namespace158 159FileSpecList SupportFileMap::translate(const FileSpec &cu_spec,160                                       llvm::ArrayRef<FileSpec> all_files) {161  std::vector<FileSpec> result;162  result.resize(m_map.size() + 1);163  result[0] = cu_spec;164  for (const auto &KV : m_map) {165    if (KV.first < all_files.size())166      result[KV.second] = all_files[KV.first];167  }168  return FileSpecList(std::move(result));169}170 171void SymbolFileBreakpad::Initialize() {172  PluginManager::RegisterPlugin(GetPluginNameStatic(),173                                GetPluginDescriptionStatic(), CreateInstance,174                                DebuggerInitialize);175}176 177void SymbolFileBreakpad::Terminate() {178  PluginManager::UnregisterPlugin(CreateInstance);179}180 181uint32_t SymbolFileBreakpad::CalculateAbilities() {182  if (!m_objfile_sp || !llvm::isa<ObjectFileBreakpad>(*m_objfile_sp))183    return 0;184 185  return CompileUnits | Functions | LineTables;186}187 188uint32_t SymbolFileBreakpad::CalculateNumCompileUnits() {189  ParseCUData();190  return m_cu_data->GetSize();191}192 193CompUnitSP SymbolFileBreakpad::ParseCompileUnitAtIndex(uint32_t index) {194  if (index >= m_cu_data->GetSize())195    return nullptr;196 197  CompUnitData &data = m_cu_data->GetEntryRef(index).data;198 199  ParseFileRecords();200 201  FileSpec spec;202 203  // The FileSpec of the compile unit will be the file corresponding to the204  // first LINE record.205  LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),206      End(*m_objfile_sp);207  assert(Record::classify(*It) == Record::Func);208  ++It; // Skip FUNC record.209  // Skip INLINE records.210  while (It != End && Record::classify(*It) == Record::Inline)211    ++It;212 213  if (It != End) {214    auto record = LineRecord::parse(*It);215    if (record && record->FileNum < m_files->size())216      spec = (*m_files)[record->FileNum];217  }218 219  auto cu_sp = std::make_shared<CompileUnit>(220      m_objfile_sp->GetModule(),221      /*user_data*/ nullptr, std::make_shared<SupportFile>(spec), index,222      eLanguageTypeUnknown,223      /*is_optimized*/ eLazyBoolNo);224 225  SetCompileUnitAtIndex(index, cu_sp);226  return cu_sp;227}228 229FunctionSP SymbolFileBreakpad::GetOrCreateFunction(CompileUnit &comp_unit) {230  user_id_t id = comp_unit.GetID();231  if (FunctionSP func_sp = comp_unit.FindFunctionByUID(id))232    return func_sp;233 234  Log *log = GetLog(LLDBLog::Symbols);235  FunctionSP func_sp;236  addr_t base = GetBaseFileAddress();237  if (base == LLDB_INVALID_ADDRESS) {238    LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping "239                  "symtab population.");240    return func_sp;241  }242 243  const SectionList *list = comp_unit.GetModule()->GetSectionList();244  CompUnitData &data = m_cu_data->GetEntryRef(id).data;245  LineIterator It(*m_objfile_sp, Record::Func, data.bookmark);246  assert(Record::classify(*It) == Record::Func);247 248  if (auto record = FuncRecord::parse(*It)) {249    Mangled func_name;250    func_name.SetValue(ConstString(record->Name));251    addr_t address = record->Address + base;252    SectionSP section_sp = list->FindSectionContainingFileAddress(address);253    if (section_sp) {254      Address func_addr(section_sp, address - section_sp->GetFileAddress());255      // Use the CU's id because every CU has only one function inside.256      func_sp = std::make_shared<Function>(257          &comp_unit, id, 0, func_name, nullptr, func_addr,258          AddressRanges{AddressRange(func_addr, record->Size)});259      comp_unit.AddFunction(func_sp);260    }261  }262  return func_sp;263}264 265size_t SymbolFileBreakpad::ParseFunctions(CompileUnit &comp_unit) {266  std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());267  return GetOrCreateFunction(comp_unit) ? 1 : 0;268}269 270bool SymbolFileBreakpad::ParseLineTable(CompileUnit &comp_unit) {271  std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());272  CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data;273 274  if (!data.line_table_up)275    ParseLineTableAndSupportFiles(comp_unit, data);276 277  comp_unit.SetLineTable(data.line_table_up.release());278  return true;279}280 281bool SymbolFileBreakpad::ParseSupportFiles(CompileUnit &comp_unit,282                                           SupportFileList &support_files) {283  std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());284  CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data;285  if (!data.support_files)286    ParseLineTableAndSupportFiles(comp_unit, data);287 288  for (auto &fs : *data.support_files)289    support_files.Append(fs);290  return true;291}292 293size_t SymbolFileBreakpad::ParseBlocksRecursive(Function &func) {294  std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());295  CompileUnit *comp_unit = func.GetCompileUnit();296  lldbassert(comp_unit);297  ParseInlineOriginRecords();298  // A vector of current each level's parent block. For example, when parsing299  // "INLINE 0 ...", the current level is 0 and its parent block is the300  // function block at index 0.301  std::vector<Block *> blocks;302  blocks.push_back(&func.GetBlock(false));303 304  size_t blocks_added = 0;305  addr_t func_base = func.GetAddress().GetOffset();306  CompUnitData &data = m_cu_data->GetEntryRef(comp_unit->GetID()).data;307  LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),308      End(*m_objfile_sp);309  ++It; // Skip the FUNC record.310  size_t last_added_nest_level = 0;311  while (It != End && Record::classify(*It) == Record::Inline) {312    if (auto record = InlineRecord::parse(*It)) {313      if (record->InlineNestLevel == 0 ||314          record->InlineNestLevel <= last_added_nest_level + 1) {315        last_added_nest_level = record->InlineNestLevel;316        BlockSP block_sp = blocks[record->InlineNestLevel]->CreateChild(317            It.GetBookmark().offset);318        FileSpec callsite_file;319        if (record->CallSiteFileNum < m_files->size())320          callsite_file = (*m_files)[record->CallSiteFileNum];321        llvm::StringRef name;322        if (record->OriginNum < m_inline_origins->size())323          name = (*m_inline_origins)[record->OriginNum];324 325        Declaration callsite(callsite_file, record->CallSiteLineNum);326        block_sp->SetInlinedFunctionInfo(name.str().c_str(),327                                         /*mangled=*/nullptr,328                                         /*decl_ptr=*/nullptr, &callsite);329        for (const auto &range : record->Ranges) {330          block_sp->AddRange(331              Block::Range(range.first - func_base, range.second));332        }333        block_sp->FinalizeRanges();334 335        if (record->InlineNestLevel + 1 >= blocks.size()) {336          blocks.resize(blocks.size() + 1);337        }338        blocks[record->InlineNestLevel + 1] = block_sp.get();339        ++blocks_added;340      }341    }342    ++It;343  }344  return blocks_added;345}346 347void SymbolFileBreakpad::ParseInlineOriginRecords() {348  if (m_inline_origins)349    return;350  m_inline_origins.emplace();351 352  Log *log = GetLog(LLDBLog::Symbols);353  for (llvm::StringRef line : lines(Record::InlineOrigin)) {354    auto record = InlineOriginRecord::parse(line);355    if (!record) {356      LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);357      continue;358    }359 360    if (record->Number >= m_inline_origins->size())361      m_inline_origins->resize(record->Number + 1);362    (*m_inline_origins)[record->Number] = record->Name;363  }364}365 366uint32_t367SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr,368                                         SymbolContextItem resolve_scope,369                                         SymbolContext &sc) {370  std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());371  if (!(resolve_scope & (eSymbolContextCompUnit | eSymbolContextLineEntry |372                         eSymbolContextFunction | eSymbolContextBlock)))373    return 0;374 375  ParseCUData();376  uint32_t idx =377      m_cu_data->FindEntryIndexThatContains(so_addr.GetFileAddress());378  if (idx == UINT32_MAX)379    return 0;380 381  sc.comp_unit = GetCompileUnitAtIndex(idx).get();382  SymbolContextItem result = eSymbolContextCompUnit;383  if (resolve_scope & eSymbolContextLineEntry) {384    if (sc.comp_unit->GetLineTable()->FindLineEntryByAddress(so_addr,385                                                             sc.line_entry)) {386      result |= eSymbolContextLineEntry;387    }388  }389 390  if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) {391    FunctionSP func_sp = GetOrCreateFunction(*sc.comp_unit);392    if (func_sp) {393      sc.function = func_sp.get();394      result |= eSymbolContextFunction;395      if (resolve_scope & eSymbolContextBlock) {396        Block &block = func_sp->GetBlock(true);397        sc.block = block.FindInnermostBlockByOffset(398            so_addr.GetFileAddress() -399            sc.function->GetAddress().GetFileAddress());400        if (sc.block)401          result |= eSymbolContextBlock;402      }403    }404  }405 406  return result;407}408 409uint32_t SymbolFileBreakpad::ResolveSymbolContext(410    const SourceLocationSpec &src_location_spec,411    lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) {412  std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());413  if (!(resolve_scope & eSymbolContextCompUnit))414    return 0;415 416  uint32_t old_size = sc_list.GetSize();417  for (size_t i = 0, size = GetNumCompileUnits(); i < size; ++i) {418    CompileUnit &cu = *GetCompileUnitAtIndex(i);419    cu.ResolveSymbolContext(src_location_spec, resolve_scope, sc_list);420  }421  return sc_list.GetSize() - old_size;422}423 424void SymbolFileBreakpad::FindFunctions(425    const Module::LookupInfo &lookup_info,426    const CompilerDeclContext &parent_decl_ctx, bool include_inlines,427    SymbolContextList &sc_list) {428  std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());429  // TODO: Implement this with supported FunctionNameType.430 431  ConstString name = lookup_info.GetLookupName();432  for (uint32_t i = 0; i < GetNumCompileUnits(); ++i) {433    CompUnitSP cu_sp = GetCompileUnitAtIndex(i);434    FunctionSP func_sp = GetOrCreateFunction(*cu_sp);435    if (func_sp && name == func_sp->GetNameNoArguments()) {436      SymbolContext sc;437      sc.comp_unit = cu_sp.get();438      sc.function = func_sp.get();439      sc.module_sp = func_sp->CalculateSymbolContextModule();440      sc_list.Append(sc);441    }442  }443}444 445void SymbolFileBreakpad::FindFunctions(const RegularExpression &regex,446                                       bool include_inlines,447                                       SymbolContextList &sc_list) {448  // TODO449}450 451void SymbolFileBreakpad::AddSymbols(Symtab &symtab) {452  Log *log = GetLog(LLDBLog::Symbols);453  Module &module = *m_objfile_sp->GetModule();454  addr_t base = GetBaseFileAddress();455  if (base == LLDB_INVALID_ADDRESS) {456    LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping "457                  "symtab population.");458    return;459  }460 461  const SectionList &list = *module.GetSectionList();462  llvm::DenseSet<addr_t> found_symbol_addresses;463  std::vector<Symbol> symbols;464  auto add_symbol = [&](addr_t address, std::optional<addr_t> size,465                        llvm::StringRef name) {466    address += base;467    SectionSP section_sp = list.FindSectionContainingFileAddress(address);468    if (!section_sp) {469      LLDB_LOG(log,470               "Ignoring symbol {0}, whose address ({1}) is outside of the "471               "object file. Mismatched symbol file?",472               name, address);473      return;474    }475    // Keep track of what addresses were already added so far and only add476    // the symbol with the first address.477    if (!found_symbol_addresses.insert(address).second)478      return;479    symbols.emplace_back(480        /*symID*/ 0, Mangled(name), eSymbolTypeCode,481        /*is_global*/ true, /*is_debug*/ false,482        /*is_trampoline*/ false, /*is_artificial*/ false,483        AddressRange(section_sp, address - section_sp->GetFileAddress(),484                     size.value_or(0)),485        size.has_value(), /*contains_linker_annotations*/ false, /*flags*/ 0);486  };487 488  for (llvm::StringRef line : lines(Record::Public)) {489    if (auto record = PublicRecord::parse(line))490      add_symbol(record->Address, std::nullopt, record->Name);491    else492      LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);493  }494 495  for (Symbol &symbol : symbols)496    symtab.AddSymbol(std::move(symbol));497  symtab.Finalize();498}499 500llvm::Expected<lldb::addr_t>501SymbolFileBreakpad::GetParameterStackSize(Symbol &symbol) {502  ParseUnwindData();503  if (auto *entry = m_unwind_data->win.FindEntryThatContains(504          symbol.GetAddress().GetFileAddress())) {505    auto record = StackWinRecord::parse(506        *LineIterator(*m_objfile_sp, Record::StackWin, entry->data));507    assert(record);508    return record->ParameterSize;509  }510  return llvm::createStringError(llvm::inconvertibleErrorCode(),511                                 "Parameter size unknown.");512}513 514static std::optional<std::pair<llvm::StringRef, llvm::StringRef>>515GetRule(llvm::StringRef &unwind_rules) {516  // Unwind rules are of the form517  //   register1: expression1 register2: expression2 ...518  // We assume none of the tokens in expression<n> end with a colon.519 520  llvm::StringRef lhs, rest;521  std::tie(lhs, rest) = getToken(unwind_rules);522  if (!lhs.consume_back(":"))523    return std::nullopt;524 525  // Seek forward to the next register: expression pair526  llvm::StringRef::size_type pos = rest.find(": ");527  if (pos == llvm::StringRef::npos) {528    // No pair found, this means the rest of the string is a single expression.529    unwind_rules = llvm::StringRef();530    return std::make_pair(lhs, rest);531  }532 533  // Go back one token to find the end of the current rule.534  pos = rest.rfind(' ', pos);535  if (pos == llvm::StringRef::npos)536    return std::nullopt;537 538  llvm::StringRef rhs = rest.take_front(pos);539  unwind_rules = rest.drop_front(pos);540  return std::make_pair(lhs, rhs);541}542 543static const RegisterInfo *544ResolveRegister(const llvm::Triple &triple,545                const SymbolFile::RegisterInfoResolver &resolver,546                llvm::StringRef name) {547  if (triple.isX86() || triple.isMIPS()) {548    // X86 and MIPS registers have '$' in front of their register names. Arm and549    // AArch64 don't.550    if (!name.consume_front("$"))551      return nullptr;552  }553  return resolver.ResolveName(name);554}555 556static const RegisterInfo *557ResolveRegisterOrRA(const llvm::Triple &triple,558                    const SymbolFile::RegisterInfoResolver &resolver,559                    llvm::StringRef name) {560  if (name == ".ra")561    return resolver.ResolveNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);562  return ResolveRegister(triple, resolver, name);563}564 565llvm::ArrayRef<uint8_t> SymbolFileBreakpad::SaveAsDWARF(postfix::Node &node) {566  ArchSpec arch = m_objfile_sp->GetArchitecture();567  StreamString dwarf(Stream::eBinary, arch.GetAddressByteSize(),568                     arch.GetByteOrder());569  ToDWARF(node, dwarf);570  uint8_t *saved = m_allocator.Allocate<uint8_t>(dwarf.GetSize());571  std::memcpy(saved, dwarf.GetData(), dwarf.GetSize());572  return {saved, dwarf.GetSize()};573}574 575bool SymbolFileBreakpad::ParseCFIUnwindRow(llvm::StringRef unwind_rules,576                                        const RegisterInfoResolver &resolver,577                                        UnwindPlan::Row &row) {578  Log *log = GetLog(LLDBLog::Symbols);579 580  llvm::BumpPtrAllocator node_alloc;581  llvm::Triple triple = m_objfile_sp->GetArchitecture().GetTriple();582  while (auto rule = GetRule(unwind_rules)) {583    node_alloc.Reset();584    llvm::StringRef lhs = rule->first;585    postfix::Node *rhs = postfix::ParseOneExpression(rule->second, node_alloc);586    if (!rhs) {587      LLDB_LOG(log, "Could not parse `{0}` as unwind rhs.", rule->second);588      return false;589    }590 591    bool success = postfix::ResolveSymbols(592        rhs, [&](postfix::SymbolNode &symbol) -> postfix::Node * {593          llvm::StringRef name = symbol.GetName();594          if (name == ".cfa" && lhs != ".cfa")595            return postfix::MakeNode<postfix::InitialValueNode>(node_alloc);596 597          if (const RegisterInfo *info =598                  ResolveRegister(triple, resolver, name)) {599            return postfix::MakeNode<postfix::RegisterNode>(600                node_alloc, info->kinds[eRegisterKindLLDB]);601          }602          return nullptr;603        });604 605    if (!success) {606      LLDB_LOG(log, "Resolving symbols in `{0}` failed.", rule->second);607      return false;608    }609 610    llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*rhs);611    if (lhs == ".cfa") {612      row.GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size());613    } else if (const RegisterInfo *info =614                   ResolveRegisterOrRA(triple, resolver, lhs)) {615      UnwindPlan::Row::AbstractRegisterLocation loc;616      loc.SetIsDWARFExpression(saved.data(), saved.size());617      row.SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc);618    } else619      LLDB_LOG(log, "Invalid register `{0}` in unwind rule.", lhs);620  }621  if (unwind_rules.empty())622    return true;623 624  LLDB_LOG(log, "Could not parse `{0}` as an unwind rule.", unwind_rules);625  return false;626}627 628UnwindPlanSP629SymbolFileBreakpad::GetUnwindPlan(const Address &address,630                                  const RegisterInfoResolver &resolver) {631  ParseUnwindData();632  if (auto *entry =633          m_unwind_data->cfi.FindEntryThatContains(address.GetFileAddress()))634    return ParseCFIUnwindPlan(entry->data, resolver);635  if (auto *entry =636          m_unwind_data->win.FindEntryThatContains(address.GetFileAddress()))637    return ParseWinUnwindPlan(entry->data, resolver);638  return nullptr;639}640 641UnwindPlanSP642SymbolFileBreakpad::ParseCFIUnwindPlan(const Bookmark &bookmark,643                                       const RegisterInfoResolver &resolver) {644  addr_t base = GetBaseFileAddress();645  if (base == LLDB_INVALID_ADDRESS)646    return nullptr;647 648  LineIterator It(*m_objfile_sp, Record::StackCFI, bookmark),649      End(*m_objfile_sp);650  std::optional<StackCFIRecord> init_record = StackCFIRecord::parse(*It);651  assert(init_record && init_record->Size &&652         "Record already parsed successfully in ParseUnwindData!");653 654  auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB);655  plan_sp->SetSourceName("breakpad STACK CFI");656  plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);657  plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);658  plan_sp->SetSourcedFromCompiler(eLazyBoolYes);659  plan_sp->SetPlanValidAddressRanges(660      {AddressRange(base + init_record->Address, *init_record->Size,661                    m_objfile_sp->GetModule()->GetSectionList())});662 663  UnwindPlan::Row row;664  if (!ParseCFIUnwindRow(init_record->UnwindRules, resolver, row))665    return nullptr;666  plan_sp->AppendRow(row);667  for (++It; It != End; ++It) {668    std::optional<StackCFIRecord> record = StackCFIRecord::parse(*It);669    if (!record)670      return nullptr;671    if (record->Size)672      break;673 674    row.SetOffset(record->Address - init_record->Address);675    if (!ParseCFIUnwindRow(record->UnwindRules, resolver, row))676      return nullptr;677    plan_sp->AppendRow(row);678  }679  return plan_sp;680}681 682UnwindPlanSP683SymbolFileBreakpad::ParseWinUnwindPlan(const Bookmark &bookmark,684                                       const RegisterInfoResolver &resolver) {685  Log *log = GetLog(LLDBLog::Symbols);686  addr_t base = GetBaseFileAddress();687  if (base == LLDB_INVALID_ADDRESS)688    return nullptr;689 690  LineIterator It(*m_objfile_sp, Record::StackWin, bookmark);691  std::optional<StackWinRecord> record = StackWinRecord::parse(*It);692  assert(record && "Record already parsed successfully in ParseUnwindData!");693 694  auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB);695  plan_sp->SetSourceName("breakpad STACK WIN");696  plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);697  plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);698  plan_sp->SetSourcedFromCompiler(eLazyBoolYes);699  plan_sp->SetPlanValidAddressRanges(700      {AddressRange(base + record->RVA, record->CodeSize,701                    m_objfile_sp->GetModule()->GetSectionList())});702 703  UnwindPlan::Row row;704 705  llvm::BumpPtrAllocator node_alloc;706  std::vector<std::pair<llvm::StringRef, postfix::Node *>> program =707      postfix::ParseFPOProgram(record->ProgramString, node_alloc);708 709  if (program.empty()) {710    LLDB_LOG(log, "Invalid unwind rule: {0}.", record->ProgramString);711    return nullptr;712  }713  auto it = program.begin();714  llvm::Triple triple = m_objfile_sp->GetArchitecture().GetTriple();715  const auto &symbol_resolver =716      [&](postfix::SymbolNode &symbol) -> postfix::Node * {717    llvm::StringRef name = symbol.GetName();718    for (const auto &rule : llvm::make_range(program.begin(), it)) {719      if (rule.first == name)720        return rule.second;721    }722    if (const RegisterInfo *info = ResolveRegister(triple, resolver, name))723      return postfix::MakeNode<postfix::RegisterNode>(724          node_alloc, info->kinds[eRegisterKindLLDB]);725    return nullptr;726  };727 728  // We assume the first value will be the CFA. It is usually called T0, but729  // clang will use T1, if it needs to realign the stack.730  auto *symbol = llvm::dyn_cast<postfix::SymbolNode>(it->second);731  if (symbol && symbol->GetName() == ".raSearch") {732    row.GetCFAValue().SetRaSearch(record->LocalSize +733                                  record->SavedRegisterSize);734  } else {735    if (!postfix::ResolveSymbols(it->second, symbol_resolver)) {736      LLDB_LOG(log, "Resolving symbols in `{0}` failed.",737               record->ProgramString);738      return nullptr;739    }740    llvm::ArrayRef<uint8_t> saved  = SaveAsDWARF(*it->second);741    row.GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size());742  }743 744  // Replace the node value with InitialValueNode, so that subsequent745  // expressions refer to the CFA value instead of recomputing the whole746  // expression.747  it->second = postfix::MakeNode<postfix::InitialValueNode>(node_alloc);748 749 750  // Now process the rest of the assignments.751  for (++it; it != program.end(); ++it) {752    const RegisterInfo *info = ResolveRegister(triple, resolver, it->first);753    // It is not an error if the resolution fails because the program may754    // contain temporary variables.755    if (!info)756      continue;757    if (!postfix::ResolveSymbols(it->second, symbol_resolver)) {758      LLDB_LOG(log, "Resolving symbols in `{0}` failed.",759               record->ProgramString);760      return nullptr;761    }762 763    llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*it->second);764    UnwindPlan::Row::AbstractRegisterLocation loc;765    loc.SetIsDWARFExpression(saved.data(), saved.size());766    row.SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc);767  }768 769  plan_sp->AppendRow(std::move(row));770  return plan_sp;771}772 773addr_t SymbolFileBreakpad::GetBaseFileAddress() {774  return m_objfile_sp->GetModule()775      ->GetObjectFile()776      ->GetBaseAddress()777      .GetFileAddress();778}779 780// Parse out all the FILE records from the breakpad file. These will be needed781// when constructing the support file lists for individual compile units.782void SymbolFileBreakpad::ParseFileRecords() {783  if (m_files)784    return;785  m_files.emplace();786 787  Log *log = GetLog(LLDBLog::Symbols);788  for (llvm::StringRef line : lines(Record::File)) {789    auto record = FileRecord::parse(line);790    if (!record) {791      LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);792      continue;793    }794 795    if (record->Number >= m_files->size())796      m_files->resize(record->Number + 1);797    FileSpec::Style style = FileSpec::GuessPathStyle(record->Name)798                                .value_or(FileSpec::Style::native);799    (*m_files)[record->Number] = FileSpec(record->Name, style);800  }801}802 803void SymbolFileBreakpad::ParseCUData() {804  if (m_cu_data)805    return;806 807  m_cu_data.emplace();808  Log *log = GetLog(LLDBLog::Symbols);809  addr_t base = GetBaseFileAddress();810  if (base == LLDB_INVALID_ADDRESS) {811    LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "812                  "of object file.");813  }814 815  // We shall create one compile unit for each FUNC record. So, count the number816  // of FUNC records, and store them in m_cu_data, together with their ranges.817  for (LineIterator It(*m_objfile_sp, Record::Func), End(*m_objfile_sp);818       It != End; ++It) {819    if (auto record = FuncRecord::parse(*It)) {820      m_cu_data->Append(CompUnitMap::Entry(base + record->Address, record->Size,821                                           CompUnitData(It.GetBookmark())));822    } else823      LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);824  }825  m_cu_data->Sort();826}827 828// Construct the list of support files and line table entries for the given829// compile unit.830void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu,831                                                       CompUnitData &data) {832  addr_t base = GetBaseFileAddress();833  assert(base != LLDB_INVALID_ADDRESS &&834         "How did we create compile units without a base address?");835 836  SupportFileMap map;837  std::vector<LineTable::Sequence> sequences;838  LineTable::Sequence sequence;839  std::optional<addr_t> next_addr;840  auto finish_sequence = [&]() {841    LineTable::AppendLineEntryToSequence(842        sequence, *next_addr, /*line=*/0, /*column=*/0,843        /*file_idx=*/0, /*is_start_of_statement=*/false,844        /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false,845        /*is_epilogue_begin=*/false, /*is_terminal_entry=*/true);846    sequences.push_back(std::move(sequence));847  };848 849  LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),850      End(*m_objfile_sp);851  assert(Record::classify(*It) == Record::Func);852  for (++It; It != End; ++It) {853    // Skip INLINE records854    if (Record::classify(*It) == Record::Inline)855      continue;856 857    auto record = LineRecord::parse(*It);858    if (!record)859      break;860 861    record->Address += base;862 863    if (next_addr && *next_addr != record->Address) {864      // Discontiguous entries. Finish off the previous sequence and reset.865      finish_sequence();866    }867    LineTable::AppendLineEntryToSequence(868        sequence, record->Address, record->LineNum, /*column=*/0,869        map[record->FileNum], /*is_start_of_statement=*/true,870        /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false,871        /*is_epilogue_begin=*/false, /*is_terminal_entry=*/false);872    next_addr = record->Address + record->Size;873  }874  if (next_addr)875    finish_sequence();876  data.line_table_up = std::make_unique<LineTable>(&cu, std::move(sequences));877  data.support_files = map.translate(cu.GetPrimaryFile(), *m_files);878}879 880void SymbolFileBreakpad::ParseUnwindData() {881  if (m_unwind_data)882    return;883  m_unwind_data.emplace();884 885  Log *log = GetLog(LLDBLog::Symbols);886  addr_t base = GetBaseFileAddress();887  if (base == LLDB_INVALID_ADDRESS) {888    LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "889                  "of object file.");890  }891 892  for (LineIterator It(*m_objfile_sp, Record::StackCFI), End(*m_objfile_sp);893       It != End; ++It) {894    if (auto record = StackCFIRecord::parse(*It)) {895      if (record->Size)896        m_unwind_data->cfi.Append(UnwindMap::Entry(897            base + record->Address, *record->Size, It.GetBookmark()));898    } else899      LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);900  }901  m_unwind_data->cfi.Sort();902 903  for (LineIterator It(*m_objfile_sp, Record::StackWin), End(*m_objfile_sp);904       It != End; ++It) {905    if (auto record = StackWinRecord::parse(*It)) {906      m_unwind_data->win.Append(UnwindMap::Entry(907          base + record->RVA, record->CodeSize, It.GetBookmark()));908    } else909      LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);910  }911  m_unwind_data->win.Sort();912}913 914uint64_t SymbolFileBreakpad::GetDebugInfoSize(bool load_all_debug_info) {915  // Breakpad files are all debug info.916  return m_objfile_sp->GetByteSize();917}918