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