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