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(llvm::ArrayRef<CompilerContext> pattern,
311                                    LanguageSet languages, TypeMap &types) {}
312 
313 void SymbolFileBreakpad::AddSymbols(Symtab &symtab) {
314   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
315   Module &module = *m_objfile_sp->GetModule();
316   addr_t base = GetBaseFileAddress();
317   if (base == LLDB_INVALID_ADDRESS) {
318     LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping "
319                   "symtab population.");
320     return;
321   }
322 
323   const SectionList &list = *module.GetSectionList();
324   llvm::DenseMap<addr_t, 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     symbols.try_emplace(
337         address, /*symID*/ 0, Mangled(name), eSymbolTypeCode,
338         /*is_global*/ true, /*is_debug*/ false,
339         /*is_trampoline*/ false, /*is_artificial*/ false,
340         AddressRange(section_sp, address - section_sp->GetFileAddress(),
341                      size.getValueOr(0)),
342         size.hasValue(), /*contains_linker_annotations*/ false, /*flags*/ 0);
343   };
344 
345   for (llvm::StringRef line : lines(Record::Func)) {
346     if (auto record = FuncRecord::parse(line))
347       add_symbol(record->Address, record->Size, record->Name);
348   }
349 
350   for (llvm::StringRef line : lines(Record::Public)) {
351     if (auto record = PublicRecord::parse(line))
352       add_symbol(record->Address, llvm::None, record->Name);
353     else
354       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
355   }
356 
357   for (auto &KV : symbols)
358     symtab.AddSymbol(std::move(KV.second));
359   symtab.CalculateSymbolSizes();
360 }
361 
362 llvm::Expected<lldb::addr_t>
363 SymbolFileBreakpad::GetParameterStackSize(Symbol &symbol) {
364   ParseUnwindData();
365   if (auto *entry = m_unwind_data->win.FindEntryThatContains(
366           symbol.GetAddress().GetFileAddress())) {
367     auto record = StackWinRecord::parse(
368         *LineIterator(*m_objfile_sp, Record::StackWin, entry->data));
369     assert(record.hasValue());
370     return record->ParameterSize;
371   }
372   return llvm::createStringError(llvm::inconvertibleErrorCode(),
373                                  "Parameter size unknown.");
374 }
375 
376 static llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
377 GetRule(llvm::StringRef &unwind_rules) {
378   // Unwind rules are of the form
379   //   register1: expression1 register2: expression2 ...
380   // We assume none of the tokens in expression<n> end with a colon.
381 
382   llvm::StringRef lhs, rest;
383   std::tie(lhs, rest) = getToken(unwind_rules);
384   if (!lhs.consume_back(":"))
385     return llvm::None;
386 
387   // Seek forward to the next register: expression pair
388   llvm::StringRef::size_type pos = rest.find(": ");
389   if (pos == llvm::StringRef::npos) {
390     // No pair found, this means the rest of the string is a single expression.
391     unwind_rules = llvm::StringRef();
392     return std::make_pair(lhs, rest);
393   }
394 
395   // Go back one token to find the end of the current rule.
396   pos = rest.rfind(' ', pos);
397   if (pos == llvm::StringRef::npos)
398     return llvm::None;
399 
400   llvm::StringRef rhs = rest.take_front(pos);
401   unwind_rules = rest.drop_front(pos);
402   return std::make_pair(lhs, rhs);
403 }
404 
405 static const RegisterInfo *
406 ResolveRegister(const SymbolFile::RegisterInfoResolver &resolver,
407                 llvm::StringRef name) {
408   if (name.consume_front("$"))
409     return resolver.ResolveName(name);
410 
411   return nullptr;
412 }
413 
414 static const RegisterInfo *
415 ResolveRegisterOrRA(const SymbolFile::RegisterInfoResolver &resolver,
416                     llvm::StringRef name) {
417   if (name == ".ra")
418     return resolver.ResolveNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
419   return ResolveRegister(resolver, name);
420 }
421 
422 llvm::ArrayRef<uint8_t> SymbolFileBreakpad::SaveAsDWARF(postfix::Node &node) {
423   ArchSpec arch = m_objfile_sp->GetArchitecture();
424   StreamString dwarf(Stream::eBinary, arch.GetAddressByteSize(),
425                      arch.GetByteOrder());
426   ToDWARF(node, dwarf);
427   uint8_t *saved = m_allocator.Allocate<uint8_t>(dwarf.GetSize());
428   std::memcpy(saved, dwarf.GetData(), dwarf.GetSize());
429   return {saved, dwarf.GetSize()};
430 }
431 
432 bool SymbolFileBreakpad::ParseCFIUnwindRow(llvm::StringRef unwind_rules,
433                                         const RegisterInfoResolver &resolver,
434                                         UnwindPlan::Row &row) {
435   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
436 
437   llvm::BumpPtrAllocator node_alloc;
438   while (auto rule = GetRule(unwind_rules)) {
439     node_alloc.Reset();
440     llvm::StringRef lhs = rule->first;
441     postfix::Node *rhs = postfix::ParseOneExpression(rule->second, node_alloc);
442     if (!rhs) {
443       LLDB_LOG(log, "Could not parse `{0}` as unwind rhs.", rule->second);
444       return false;
445     }
446 
447     bool success = postfix::ResolveSymbols(
448         rhs, [&](postfix::SymbolNode &symbol) -> postfix::Node * {
449           llvm::StringRef name = symbol.GetName();
450           if (name == ".cfa" && lhs != ".cfa")
451             return postfix::MakeNode<postfix::InitialValueNode>(node_alloc);
452 
453           if (const RegisterInfo *info = ResolveRegister(resolver, name)) {
454             return postfix::MakeNode<postfix::RegisterNode>(
455                 node_alloc, info->kinds[eRegisterKindLLDB]);
456           }
457           return nullptr;
458         });
459 
460     if (!success) {
461       LLDB_LOG(log, "Resolving symbols in `{0}` failed.", rule->second);
462       return false;
463     }
464 
465     llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*rhs);
466     if (lhs == ".cfa") {
467       row.GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size());
468     } else if (const RegisterInfo *info = ResolveRegisterOrRA(resolver, lhs)) {
469       UnwindPlan::Row::RegisterLocation loc;
470       loc.SetIsDWARFExpression(saved.data(), saved.size());
471       row.SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc);
472     } else
473       LLDB_LOG(log, "Invalid register `{0}` in unwind rule.", lhs);
474   }
475   if (unwind_rules.empty())
476     return true;
477 
478   LLDB_LOG(log, "Could not parse `{0}` as an unwind rule.", unwind_rules);
479   return false;
480 }
481 
482 UnwindPlanSP
483 SymbolFileBreakpad::GetUnwindPlan(const Address &address,
484                                   const RegisterInfoResolver &resolver) {
485   ParseUnwindData();
486   if (auto *entry =
487           m_unwind_data->cfi.FindEntryThatContains(address.GetFileAddress()))
488     return ParseCFIUnwindPlan(entry->data, resolver);
489   if (auto *entry =
490           m_unwind_data->win.FindEntryThatContains(address.GetFileAddress()))
491     return ParseWinUnwindPlan(entry->data, resolver);
492   return nullptr;
493 }
494 
495 UnwindPlanSP
496 SymbolFileBreakpad::ParseCFIUnwindPlan(const Bookmark &bookmark,
497                                        const RegisterInfoResolver &resolver) {
498   addr_t base = GetBaseFileAddress();
499   if (base == LLDB_INVALID_ADDRESS)
500     return nullptr;
501 
502   LineIterator It(*m_objfile_sp, Record::StackCFI, bookmark),
503       End(*m_objfile_sp);
504   llvm::Optional<StackCFIRecord> init_record = StackCFIRecord::parse(*It);
505   assert(init_record.hasValue() && init_record->Size.hasValue() &&
506          "Record already parsed successfully in ParseUnwindData!");
507 
508   auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB);
509   plan_sp->SetSourceName("breakpad STACK CFI");
510   plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
511   plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);
512   plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
513   plan_sp->SetPlanValidAddressRange(
514       AddressRange(base + init_record->Address, *init_record->Size,
515                    m_objfile_sp->GetModule()->GetSectionList()));
516 
517   auto row_sp = std::make_shared<UnwindPlan::Row>();
518   row_sp->SetOffset(0);
519   if (!ParseCFIUnwindRow(init_record->UnwindRules, resolver, *row_sp))
520     return nullptr;
521   plan_sp->AppendRow(row_sp);
522   for (++It; It != End; ++It) {
523     llvm::Optional<StackCFIRecord> record = StackCFIRecord::parse(*It);
524     if (!record.hasValue())
525       return nullptr;
526     if (record->Size.hasValue())
527       break;
528 
529     row_sp = std::make_shared<UnwindPlan::Row>(*row_sp);
530     row_sp->SetOffset(record->Address - init_record->Address);
531     if (!ParseCFIUnwindRow(record->UnwindRules, resolver, *row_sp))
532       return nullptr;
533     plan_sp->AppendRow(row_sp);
534   }
535   return plan_sp;
536 }
537 
538 UnwindPlanSP
539 SymbolFileBreakpad::ParseWinUnwindPlan(const Bookmark &bookmark,
540                                        const RegisterInfoResolver &resolver) {
541   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
542   addr_t base = GetBaseFileAddress();
543   if (base == LLDB_INVALID_ADDRESS)
544     return nullptr;
545 
546   LineIterator It(*m_objfile_sp, Record::StackWin, bookmark);
547   llvm::Optional<StackWinRecord> record = StackWinRecord::parse(*It);
548   assert(record.hasValue() &&
549          "Record already parsed successfully in ParseUnwindData!");
550 
551   auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB);
552   plan_sp->SetSourceName("breakpad STACK WIN");
553   plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
554   plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);
555   plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
556   plan_sp->SetPlanValidAddressRange(
557       AddressRange(base + record->RVA, record->CodeSize,
558                    m_objfile_sp->GetModule()->GetSectionList()));
559 
560   auto row_sp = std::make_shared<UnwindPlan::Row>();
561   row_sp->SetOffset(0);
562 
563   llvm::BumpPtrAllocator node_alloc;
564   std::vector<std::pair<llvm::StringRef, postfix::Node *>> program =
565       postfix::ParseFPOProgram(record->ProgramString, node_alloc);
566 
567   if (program.empty()) {
568     LLDB_LOG(log, "Invalid unwind rule: {0}.", record->ProgramString);
569     return nullptr;
570   }
571   auto it = program.begin();
572   const auto &symbol_resolver =
573       [&](postfix::SymbolNode &symbol) -> postfix::Node * {
574     llvm::StringRef name = symbol.GetName();
575     for (const auto &rule : llvm::make_range(program.begin(), it)) {
576       if (rule.first == name)
577         return rule.second;
578     }
579     if (const RegisterInfo *info = ResolveRegister(resolver, name))
580       return postfix::MakeNode<postfix::RegisterNode>(
581           node_alloc, info->kinds[eRegisterKindLLDB]);
582     return nullptr;
583   };
584 
585   // We assume the first value will be the CFA. It is usually called T0, but
586   // clang will use T1, if it needs to realign the stack.
587   auto *symbol = llvm::dyn_cast<postfix::SymbolNode>(it->second);
588   if (symbol && symbol->GetName() == ".raSearch") {
589     row_sp->GetCFAValue().SetRaSearch(record->LocalSize +
590                                       record->SavedRegisterSize);
591   } else {
592     if (!postfix::ResolveSymbols(it->second, symbol_resolver)) {
593       LLDB_LOG(log, "Resolving symbols in `{0}` failed.",
594                record->ProgramString);
595       return nullptr;
596     }
597     llvm::ArrayRef<uint8_t> saved  = SaveAsDWARF(*it->second);
598     row_sp->GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size());
599   }
600 
601   // Replace the node value with InitialValueNode, so that subsequent
602   // expressions refer to the CFA value instead of recomputing the whole
603   // expression.
604   it->second = postfix::MakeNode<postfix::InitialValueNode>(node_alloc);
605 
606 
607   // Now process the rest of the assignments.
608   for (++it; it != program.end(); ++it) {
609     const RegisterInfo *info = ResolveRegister(resolver, it->first);
610     // It is not an error if the resolution fails because the program may
611     // contain temporary variables.
612     if (!info)
613       continue;
614     if (!postfix::ResolveSymbols(it->second, symbol_resolver)) {
615       LLDB_LOG(log, "Resolving symbols in `{0}` failed.",
616                record->ProgramString);
617       return nullptr;
618     }
619 
620     llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*it->second);
621     UnwindPlan::Row::RegisterLocation loc;
622     loc.SetIsDWARFExpression(saved.data(), saved.size());
623     row_sp->SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc);
624   }
625 
626   plan_sp->AppendRow(row_sp);
627   return plan_sp;
628 }
629 
630 addr_t SymbolFileBreakpad::GetBaseFileAddress() {
631   return m_objfile_sp->GetModule()
632       ->GetObjectFile()
633       ->GetBaseAddress()
634       .GetFileAddress();
635 }
636 
637 // Parse out all the FILE records from the breakpad file. These will be needed
638 // when constructing the support file lists for individual compile units.
639 void SymbolFileBreakpad::ParseFileRecords() {
640   if (m_files)
641     return;
642   m_files.emplace();
643 
644   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
645   for (llvm::StringRef line : lines(Record::File)) {
646     auto record = FileRecord::parse(line);
647     if (!record) {
648       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
649       continue;
650     }
651 
652     if (record->Number >= m_files->size())
653       m_files->resize(record->Number + 1);
654     FileSpec::Style style = FileSpec::GuessPathStyle(record->Name)
655                                 .getValueOr(FileSpec::Style::native);
656     (*m_files)[record->Number] = FileSpec(record->Name, style);
657   }
658 }
659 
660 void SymbolFileBreakpad::ParseCUData() {
661   if (m_cu_data)
662     return;
663 
664   m_cu_data.emplace();
665   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
666   addr_t base = GetBaseFileAddress();
667   if (base == LLDB_INVALID_ADDRESS) {
668     LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "
669                   "of object file.");
670   }
671 
672   // We shall create one compile unit for each FUNC record. So, count the number
673   // of FUNC records, and store them in m_cu_data, together with their ranges.
674   for (LineIterator It(*m_objfile_sp, Record::Func), End(*m_objfile_sp);
675        It != End; ++It) {
676     if (auto record = FuncRecord::parse(*It)) {
677       m_cu_data->Append(CompUnitMap::Entry(base + record->Address, record->Size,
678                                            CompUnitData(It.GetBookmark())));
679     } else
680       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
681   }
682   m_cu_data->Sort();
683 }
684 
685 // Construct the list of support files and line table entries for the given
686 // compile unit.
687 void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu,
688                                                        CompUnitData &data) {
689   addr_t base = GetBaseFileAddress();
690   assert(base != LLDB_INVALID_ADDRESS &&
691          "How did we create compile units without a base address?");
692 
693   SupportFileMap map;
694   data.line_table_up = std::make_unique<LineTable>(&cu);
695   std::unique_ptr<LineSequence> line_seq_up(
696       data.line_table_up->CreateLineSequenceContainer());
697   llvm::Optional<addr_t> next_addr;
698   auto finish_sequence = [&]() {
699     data.line_table_up->AppendLineEntryToSequence(
700         line_seq_up.get(), *next_addr, /*line*/ 0, /*column*/ 0,
701         /*file_idx*/ 0, /*is_start_of_statement*/ false,
702         /*is_start_of_basic_block*/ false, /*is_prologue_end*/ false,
703         /*is_epilogue_begin*/ false, /*is_terminal_entry*/ true);
704     data.line_table_up->InsertSequence(line_seq_up.get());
705     line_seq_up->Clear();
706   };
707 
708   LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),
709       End(*m_objfile_sp);
710   assert(Record::classify(*It) == Record::Func);
711   for (++It; It != End; ++It) {
712     auto record = LineRecord::parse(*It);
713     if (!record)
714       break;
715 
716     record->Address += base;
717 
718     if (next_addr && *next_addr != record->Address) {
719       // Discontiguous entries. Finish off the previous sequence and reset.
720       finish_sequence();
721     }
722     data.line_table_up->AppendLineEntryToSequence(
723         line_seq_up.get(), record->Address, record->LineNum, /*column*/ 0,
724         map[record->FileNum], /*is_start_of_statement*/ true,
725         /*is_start_of_basic_block*/ false, /*is_prologue_end*/ false,
726         /*is_epilogue_begin*/ false, /*is_terminal_entry*/ false);
727     next_addr = record->Address + record->Size;
728   }
729   if (next_addr)
730     finish_sequence();
731   data.support_files = map.translate(cu, *m_files);
732 }
733 
734 void SymbolFileBreakpad::ParseUnwindData() {
735   if (m_unwind_data)
736     return;
737   m_unwind_data.emplace();
738 
739   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
740   addr_t base = GetBaseFileAddress();
741   if (base == LLDB_INVALID_ADDRESS) {
742     LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "
743                   "of object file.");
744   }
745 
746   for (LineIterator It(*m_objfile_sp, Record::StackCFI), End(*m_objfile_sp);
747        It != End; ++It) {
748     if (auto record = StackCFIRecord::parse(*It)) {
749       if (record->Size)
750         m_unwind_data->cfi.Append(UnwindMap::Entry(
751             base + record->Address, *record->Size, It.GetBookmark()));
752     } else
753       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
754   }
755   m_unwind_data->cfi.Sort();
756 
757   for (LineIterator It(*m_objfile_sp, Record::StackWin), End(*m_objfile_sp);
758        It != End; ++It) {
759     if (auto record = StackWinRecord::parse(*It)) {
760       m_unwind_data->win.Append(UnwindMap::Entry(
761           base + record->RVA, record->CodeSize, It.GetBookmark()));
762     } else
763       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
764   }
765   m_unwind_data->win.Sort();
766 }
767