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