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