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