blob: 5e275e34c3ba32a7bf7c524ab615019d1c3ca964 [file] [log] [blame]
Pavel Labath1cf23e12019-01-11 11:17:51 +00001//===-- SymbolFileBreakpad.cpp ----------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Pavel Labath1cf23e12019-01-11 11:17:51 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h"
Pavel Labath2cf54862019-01-18 10:37:04 +000010#include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"
Pavel Labath1cf23e12019-01-11 11:17:51 +000011#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"
Pavel Labath3f35ab82019-02-07 13:42:32 +000016#include "lldb/Symbol/CompileUnit.h"
Pavel Labath1cf23e12019-01-11 11:17:51 +000017#include "lldb/Symbol/ObjectFile.h"
Pavel Labath1211baa2019-05-13 11:25:35 +000018#include "lldb/Symbol/PostfixExpression.h"
Pavel Labath3f35ab82019-02-07 13:42:32 +000019#include "lldb/Symbol/SymbolVendor.h"
Pavel Labath1cf23e12019-01-11 11:17:51 +000020#include "lldb/Symbol/TypeMap.h"
21#include "lldb/Utility/Log.h"
Pavel Labath1211baa2019-05-13 11:25:35 +000022#include "lldb/Utility/StreamString.h"
Pavel Labath1cf23e12019-01-11 11:17:51 +000023#include "llvm/ADT/StringExtras.h"
24
25using namespace lldb;
26using namespace lldb_private;
27using namespace lldb_private::breakpad;
28
Pavel Labath3f35ab82019-02-07 13:42:32 +000029class SymbolFileBreakpad::LineIterator {
Pavel Labath1cf23e12019-01-11 11:17:51 +000030public:
31 // begin iterator for sections of given type
Pavel Labath06bb3732019-01-22 04:56:31 +000032 LineIterator(ObjectFile &obj, Record::Kind section_type)
33 : m_obj(&obj), m_section_type(toString(section_type)),
Pavel Labath3f35ab82019-02-07 13:42:32 +000034 m_next_section_idx(0), m_next_line(llvm::StringRef::npos) {
Pavel Labath1cf23e12019-01-11 11:17:51 +000035 ++*this;
36 }
37
Pavel Labath3f35ab82019-02-07 13:42:32 +000038 // An iterator starting at the position given by the bookmark.
39 LineIterator(ObjectFile &obj, Record::Kind section_type, Bookmark bookmark);
40
Pavel Labath1cf23e12019-01-11 11:17:51 +000041 // end iterator
42 explicit LineIterator(ObjectFile &obj)
43 : m_obj(&obj),
Pavel Labath3f35ab82019-02-07 13:42:32 +000044 m_next_section_idx(m_obj->GetSectionList()->GetNumSections(0)),
45 m_current_line(llvm::StringRef::npos),
46 m_next_line(llvm::StringRef::npos) {}
Pavel Labath1cf23e12019-01-11 11:17:51 +000047
48 friend bool operator!=(const LineIterator &lhs, const LineIterator &rhs) {
49 assert(lhs.m_obj == rhs.m_obj);
50 if (lhs.m_next_section_idx != rhs.m_next_section_idx)
51 return true;
Pavel Labath3f35ab82019-02-07 13:42:32 +000052 if (lhs.m_current_line != rhs.m_current_line)
Pavel Labath1cf23e12019-01-11 11:17:51 +000053 return true;
Pavel Labath3f35ab82019-02-07 13:42:32 +000054 assert(lhs.m_next_line == rhs.m_next_line);
Pavel Labath1cf23e12019-01-11 11:17:51 +000055 return false;
56 }
57
58 const LineIterator &operator++();
Pavel Labath3f35ab82019-02-07 13:42:32 +000059 llvm::StringRef operator*() const {
60 return m_section_text.slice(m_current_line, m_next_line);
61 }
62
63 Bookmark GetBookmark() const {
64 return Bookmark{m_next_section_idx, m_current_line};
65 }
Pavel Labath1cf23e12019-01-11 11:17:51 +000066
67private:
68 ObjectFile *m_obj;
69 ConstString m_section_type;
70 uint32_t m_next_section_idx;
Pavel Labath3f35ab82019-02-07 13:42:32 +000071 llvm::StringRef m_section_text;
72 size_t m_current_line;
73 size_t m_next_line;
Pavel Labath1cf23e12019-01-11 11:17:51 +000074
Pavel Labath3f35ab82019-02-07 13:42:32 +000075 void FindNextLine() {
76 m_next_line = m_section_text.find('\n', m_current_line);
77 if (m_next_line != llvm::StringRef::npos) {
78 ++m_next_line;
79 if (m_next_line >= m_section_text.size())
80 m_next_line = llvm::StringRef::npos;
81 }
82 }
83};
84
85SymbolFileBreakpad::LineIterator::LineIterator(ObjectFile &obj,
86 Record::Kind section_type,
87 Bookmark bookmark)
88 : m_obj(&obj), m_section_type(toString(section_type)),
89 m_next_section_idx(bookmark.section), m_current_line(bookmark.offset) {
90 Section &sect =
91 *obj.GetSectionList()->GetSectionAtIndex(m_next_section_idx - 1);
92 assert(sect.GetName() == m_section_type);
93
94 DataExtractor data;
95 obj.ReadSectionData(&sect, data);
96 m_section_text = toStringRef(data.GetData());
97
98 assert(m_current_line < m_section_text.size());
99 FindNextLine();
100}
101
102const SymbolFileBreakpad::LineIterator &
103SymbolFileBreakpad::LineIterator::operator++() {
Pavel Labath1cf23e12019-01-11 11:17:51 +0000104 const SectionList &list = *m_obj->GetSectionList();
105 size_t num_sections = list.GetNumSections(0);
Pavel Labath3f35ab82019-02-07 13:42:32 +0000106 while (m_next_line != llvm::StringRef::npos ||
107 m_next_section_idx < num_sections) {
108 if (m_next_line != llvm::StringRef::npos) {
109 m_current_line = m_next_line;
110 FindNextLine();
111 return *this;
112 }
113
Pavel Labath1cf23e12019-01-11 11:17:51 +0000114 Section &sect = *list.GetSectionAtIndex(m_next_section_idx++);
115 if (sect.GetName() != m_section_type)
116 continue;
117 DataExtractor data;
118 m_obj->ReadSectionData(&sect, data);
Pavel Labath3f35ab82019-02-07 13:42:32 +0000119 m_section_text = toStringRef(data.GetData());
120 m_next_line = 0;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000121 }
Pavel Labath3f35ab82019-02-07 13:42:32 +0000122 // We've reached the end.
123 m_current_line = m_next_line;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000124 return *this;
125}
126
Pavel Labath3f35ab82019-02-07 13:42:32 +0000127llvm::iterator_range<SymbolFileBreakpad::LineIterator>
128SymbolFileBreakpad::lines(Record::Kind section_type) {
129 return llvm::make_range(LineIterator(*m_obj_file, section_type),
130 LineIterator(*m_obj_file));
131}
132
133namespace {
134// A helper class for constructing the list of support files for a given compile
135// unit.
136class SupportFileMap {
137public:
138 // Given a breakpad file ID, return a file ID to be used in the support files
139 // for this compile unit.
140 size_t operator[](size_t file) {
141 return m_map.try_emplace(file, m_map.size() + 1).first->second;
142 }
143
144 // Construct a FileSpecList containing only the support files relevant for
145 // this compile unit (in the correct order).
146 FileSpecList translate(const FileSpec &cu_spec,
147 llvm::ArrayRef<FileSpec> all_files);
148
149private:
150 llvm::DenseMap<size_t, size_t> m_map;
151};
152} // namespace
153
154FileSpecList SupportFileMap::translate(const FileSpec &cu_spec,
155 llvm::ArrayRef<FileSpec> all_files) {
156 std::vector<FileSpec> result;
157 result.resize(m_map.size() + 1);
158 result[0] = cu_spec;
159 for (const auto &KV : m_map) {
160 if (KV.first < all_files.size())
161 result[KV.second] = all_files[KV.first];
162 }
163 return FileSpecList(std::move(result));
Pavel Labath1cf23e12019-01-11 11:17:51 +0000164}
165
166void SymbolFileBreakpad::Initialize() {
167 PluginManager::RegisterPlugin(GetPluginNameStatic(),
168 GetPluginDescriptionStatic(), CreateInstance,
169 DebuggerInitialize);
170}
171
172void SymbolFileBreakpad::Terminate() {
173 PluginManager::UnregisterPlugin(CreateInstance);
174}
175
176ConstString SymbolFileBreakpad::GetPluginNameStatic() {
177 static ConstString g_name("breakpad");
178 return g_name;
179}
180
181uint32_t SymbolFileBreakpad::CalculateAbilities() {
182 if (!m_obj_file)
183 return 0;
184 if (m_obj_file->GetPluginName() != ObjectFileBreakpad::GetPluginNameStatic())
185 return 0;
186
Pavel Labath3f35ab82019-02-07 13:42:32 +0000187 return CompileUnits | Functions | LineTables;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000188}
189
190uint32_t SymbolFileBreakpad::GetNumCompileUnits() {
Pavel Labath3f35ab82019-02-07 13:42:32 +0000191 ParseCUData();
192 return m_cu_data->GetSize();
Pavel Labath1cf23e12019-01-11 11:17:51 +0000193}
194
195CompUnitSP SymbolFileBreakpad::ParseCompileUnitAtIndex(uint32_t index) {
Pavel Labath3f35ab82019-02-07 13:42:32 +0000196 if (index >= m_cu_data->GetSize())
197 return nullptr;
198
199 CompUnitData &data = m_cu_data->GetEntryRef(index).data;
200
201 ParseFileRecords();
202
203 FileSpec spec;
204
205 // The FileSpec of the compile unit will be the file corresponding to the
206 // first LINE record.
207 LineIterator It(*m_obj_file, Record::Func, data.bookmark), End(*m_obj_file);
208 assert(Record::classify(*It) == Record::Func);
209 ++It; // Skip FUNC record.
210 if (It != End) {
211 auto record = LineRecord::parse(*It);
212 if (record && record->FileNum < m_files->size())
213 spec = (*m_files)[record->FileNum];
214 }
215
216 auto cu_sp = std::make_shared<CompileUnit>(m_obj_file->GetModule(),
217 /*user_data*/ nullptr, spec, index,
218 eLanguageTypeUnknown,
219 /*is_optimized*/ eLazyBoolNo);
220
221 GetSymbolVendor().SetCompileUnitAtIndex(index, cu_sp);
222 return cu_sp;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000223}
224
Zachary Turnerce386e32019-01-11 18:35:58 +0000225size_t SymbolFileBreakpad::ParseFunctions(CompileUnit &comp_unit) {
Pavel Labath1cf23e12019-01-11 11:17:51 +0000226 // TODO
227 return 0;
228}
229
Zachary Turnerce386e32019-01-11 18:35:58 +0000230bool SymbolFileBreakpad::ParseLineTable(CompileUnit &comp_unit) {
Pavel Labath3f35ab82019-02-07 13:42:32 +0000231 CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data;
232
233 if (!data.line_table_up)
234 ParseLineTableAndSupportFiles(comp_unit, data);
235
236 comp_unit.SetLineTable(data.line_table_up.release());
237 return true;
238}
239
240bool SymbolFileBreakpad::ParseSupportFiles(CompileUnit &comp_unit,
241 FileSpecList &support_files) {
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;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000248}
249
250uint32_t
251SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr,
252 SymbolContextItem resolve_scope,
253 SymbolContext &sc) {
Pavel Labath3f35ab82019-02-07 13:42:32 +0000254 if (!(resolve_scope & (eSymbolContextCompUnit | eSymbolContextLineEntry)))
255 return 0;
256
257 ParseCUData();
258 uint32_t idx =
259 m_cu_data->FindEntryIndexThatContains(so_addr.GetFileAddress());
260 if (idx == UINT32_MAX)
261 return 0;
262
263 sc.comp_unit = GetSymbolVendor().GetCompileUnitAtIndex(idx).get();
264 SymbolContextItem result = eSymbolContextCompUnit;
265 if (resolve_scope & eSymbolContextLineEntry) {
266 if (sc.comp_unit->GetLineTable()->FindLineEntryByAddress(so_addr,
267 sc.line_entry)) {
268 result |= eSymbolContextLineEntry;
269 }
270 }
271
272 return result;
273}
274
275uint32_t SymbolFileBreakpad::ResolveSymbolContext(
276 const FileSpec &file_spec, uint32_t line, bool check_inlines,
277 lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
278 if (!(resolve_scope & eSymbolContextCompUnit))
279 return 0;
280
281 uint32_t old_size = sc_list.GetSize();
282 for (size_t i = 0, size = GetNumCompileUnits(); i < size; ++i) {
283 CompileUnit &cu = *GetSymbolVendor().GetCompileUnitAtIndex(i);
284 cu.ResolveSymbolContext(file_spec, line, check_inlines,
285 /*exact*/ false, resolve_scope, sc_list);
286 }
287 return sc_list.GetSize() - old_size;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000288}
289
290uint32_t SymbolFileBreakpad::FindFunctions(
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000291 ConstString name, const CompilerDeclContext *parent_decl_ctx,
Pavel Labath1cf23e12019-01-11 11:17:51 +0000292 FunctionNameType name_type_mask, bool include_inlines, bool append,
293 SymbolContextList &sc_list) {
294 // TODO
295 if (!append)
296 sc_list.Clear();
297 return sc_list.GetSize();
298}
299
300uint32_t SymbolFileBreakpad::FindFunctions(const RegularExpression &regex,
301 bool include_inlines, bool append,
302 SymbolContextList &sc_list) {
303 // TODO
304 if (!append)
305 sc_list.Clear();
306 return sc_list.GetSize();
307}
308
309uint32_t SymbolFileBreakpad::FindTypes(
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000310 ConstString name, const CompilerDeclContext *parent_decl_ctx,
Zachary Turner576495e2019-01-14 22:41:21 +0000311 bool append, uint32_t max_matches,
312 llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {
Pavel Labath1cf23e12019-01-11 11:17:51 +0000313 if (!append)
314 types.Clear();
315 return types.GetSize();
316}
317
318size_t
319SymbolFileBreakpad::FindTypes(const std::vector<CompilerContext> &context,
320 bool append, TypeMap &types) {
321 if (!append)
322 types.Clear();
323 return types.GetSize();
324}
325
326void SymbolFileBreakpad::AddSymbols(Symtab &symtab) {
327 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
328 Module &module = *m_obj_file->GetModule();
Pavel Labath3f35ab82019-02-07 13:42:32 +0000329 addr_t base = GetBaseFileAddress();
Pavel Labath1cf23e12019-01-11 11:17:51 +0000330 if (base == LLDB_INVALID_ADDRESS) {
331 LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping "
332 "symtab population.");
333 return;
334 }
335
336 const SectionList &list = *module.GetSectionList();
Pavel Labath06bb3732019-01-22 04:56:31 +0000337 llvm::DenseMap<addr_t, Symbol> symbols;
338 auto add_symbol = [&](addr_t address, llvm::Optional<addr_t> size,
339 llvm::StringRef name) {
340 address += base;
341 SectionSP section_sp = list.FindSectionContainingFileAddress(address);
Pavel Labath1cf23e12019-01-11 11:17:51 +0000342 if (!section_sp) {
343 LLDB_LOG(log,
344 "Ignoring symbol {0}, whose address ({1}) is outside of the "
345 "object file. Mismatched symbol file?",
Pavel Labath06bb3732019-01-22 04:56:31 +0000346 name, address);
347 return;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000348 }
Pavel Labath06bb3732019-01-22 04:56:31 +0000349 symbols.try_emplace(
350 address, /*symID*/ 0, Mangled(name, /*is_mangled*/ false),
351 eSymbolTypeCode, /*is_global*/ true, /*is_debug*/ false,
352 /*is_trampoline*/ false, /*is_artificial*/ false,
353 AddressRange(section_sp, address - section_sp->GetFileAddress(),
354 size.getValueOr(0)),
355 size.hasValue(), /*contains_linker_annotations*/ false, /*flags*/ 0);
356 };
Pavel Labath1cf23e12019-01-11 11:17:51 +0000357
Pavel Labath3f35ab82019-02-07 13:42:32 +0000358 for (llvm::StringRef line : lines(Record::Func)) {
Pavel Labath06bb3732019-01-22 04:56:31 +0000359 if (auto record = FuncRecord::parse(line))
Pavel Labath5b18ddb2019-01-24 04:17:59 +0000360 add_symbol(record->Address, record->Size, record->Name);
Pavel Labath1cf23e12019-01-11 11:17:51 +0000361 }
362
Pavel Labath3f35ab82019-02-07 13:42:32 +0000363 for (llvm::StringRef line : lines(Record::Public)) {
Pavel Labath06bb3732019-01-22 04:56:31 +0000364 if (auto record = PublicRecord::parse(line))
Pavel Labath5b18ddb2019-01-24 04:17:59 +0000365 add_symbol(record->Address, llvm::None, record->Name);
Pavel Labath06bb3732019-01-22 04:56:31 +0000366 else
367 LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
368 }
Pavel Labath1cf23e12019-01-11 11:17:51 +0000369
Pavel Labath06bb3732019-01-22 04:56:31 +0000370 for (auto &KV : symbols)
371 symtab.AddSymbol(std::move(KV.second));
Pavel Labath1cf23e12019-01-11 11:17:51 +0000372 symtab.CalculateSymbolSizes();
373}
Pavel Labath3f35ab82019-02-07 13:42:32 +0000374
Pavel Labath1211baa2019-05-13 11:25:35 +0000375static llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
376GetRule(llvm::StringRef &unwind_rules) {
377 // Unwind rules are of the form
378 // register1: expression1 register2: expression2 ...
379 // We assume none of the tokens in expression<n> end with a colon.
380
381 llvm::StringRef lhs, rest;
382 std::tie(lhs, rest) = getToken(unwind_rules);
383 if (!lhs.consume_back(":"))
384 return llvm::None;
385
386 // Seek forward to the next register: expression pair
387 llvm::StringRef::size_type pos = rest.find(": ");
388 if (pos == llvm::StringRef::npos) {
389 // No pair found, this means the rest of the string is a single expression.
390 unwind_rules = llvm::StringRef();
391 return std::make_pair(lhs, rest);
392 }
393
394 // Go back one token to find the end of the current rule.
395 pos = rest.rfind(' ', pos);
396 if (pos == llvm::StringRef::npos)
397 return llvm::None;
398
399 llvm::StringRef rhs = rest.take_front(pos);
400 unwind_rules = rest.drop_front(pos);
401 return std::make_pair(lhs, rhs);
402}
403
404static const RegisterInfo *
405ResolveRegister(const SymbolFile::RegisterInfoResolver &resolver,
406 llvm::StringRef name) {
407 if (name.consume_front("$"))
408 return resolver.ResolveName(name);
409
410 return nullptr;
411}
412
413static const RegisterInfo *
414ResolveRegisterOrRA(const SymbolFile::RegisterInfoResolver &resolver,
415 llvm::StringRef name) {
416 if (name == ".ra")
417 return resolver.ResolveNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
418 return ResolveRegister(resolver, name);
419}
420
421bool SymbolFileBreakpad::ParseUnwindRow(llvm::StringRef unwind_rules,
422 const RegisterInfoResolver &resolver,
423 UnwindPlan::Row &row) {
424 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
425
426 llvm::BumpPtrAllocator node_alloc;
427 while (auto rule = GetRule(unwind_rules)) {
428 node_alloc.Reset();
429 llvm::StringRef lhs = rule->first;
430 postfix::Node *rhs = postfix::Parse(rule->second, node_alloc);
431 if (!rhs) {
432 LLDB_LOG(log, "Could not parse `{0}` as unwind rhs.", rule->second);
433 return false;
434 }
435
436 bool success = postfix::ResolveSymbols(
437 rhs, [&](postfix::SymbolNode &symbol) -> postfix::Node * {
438 llvm::StringRef name = symbol.GetName();
439 if (name == ".cfa" && lhs != ".cfa")
440 return postfix::MakeNode<postfix::InitialValueNode>(node_alloc);
441
442 if (const RegisterInfo *info = ResolveRegister(resolver, name)) {
443 return postfix::MakeNode<postfix::RegisterNode>(
444 node_alloc, info->kinds[eRegisterKindLLDB]);
445 }
446 return nullptr;
447 });
448
449 if (!success) {
450 LLDB_LOG(log, "Resolving symbols in `{0}` failed.", rule->second);
451 return false;
452 }
453
454 ArchSpec arch = m_obj_file->GetArchitecture();
455 StreamString dwarf(Stream::eBinary, arch.GetAddressByteSize(),
456 arch.GetByteOrder());
457 ToDWARF(*rhs, dwarf);
458 uint8_t *saved = m_allocator.Allocate<uint8_t>(dwarf.GetSize());
459 std::memcpy(saved, dwarf.GetData(), dwarf.GetSize());
460
461 if (lhs == ".cfa") {
462 row.GetCFAValue().SetIsDWARFExpression(saved, dwarf.GetSize());
463 } else if (const RegisterInfo *info = ResolveRegisterOrRA(resolver, lhs)) {
464 UnwindPlan::Row::RegisterLocation loc;
465 loc.SetIsDWARFExpression(saved, dwarf.GetSize());
466 row.SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc);
467 } else
468 LLDB_LOG(log, "Invalid register `{0}` in unwind rule.", lhs);
469 }
470 if (unwind_rules.empty())
471 return true;
472
473 LLDB_LOG(log, "Could not parse `{0}` as an unwind rule.", unwind_rules);
474 return false;
475}
476
477UnwindPlanSP
478SymbolFileBreakpad::GetUnwindPlan(const Address &address,
479 const RegisterInfoResolver &resolver) {
480 ParseUnwindData();
481 const UnwindMap::Entry *entry =
482 m_unwind_data->FindEntryThatContains(address.GetFileAddress());
483 if (!entry)
484 return nullptr;
485
486 addr_t base = GetBaseFileAddress();
487 if (base == LLDB_INVALID_ADDRESS)
488 return nullptr;
489
490 LineIterator It(*m_obj_file, Record::StackCFI, entry->data), End(*m_obj_file);
491 llvm::Optional<StackCFIRecord> init_record = StackCFIRecord::parse(*It);
492 assert(init_record.hasValue());
493 assert(init_record->Size.hasValue());
494
495 auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB);
496 plan_sp->SetSourceName("breakpad STACK CFI");
497 plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
Joseph Tremoulet3fd917d2019-07-19 14:05:55 +0000498 plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);
Pavel Labath1211baa2019-05-13 11:25:35 +0000499 plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
500 plan_sp->SetPlanValidAddressRange(
501 AddressRange(base + init_record->Address, *init_record->Size,
502 m_obj_file->GetModule()->GetSectionList()));
503
504 auto row_sp = std::make_shared<UnwindPlan::Row>();
505 row_sp->SetOffset(0);
506 if (!ParseUnwindRow(init_record->UnwindRules, resolver, *row_sp))
507 return nullptr;
508 plan_sp->AppendRow(row_sp);
509 for (++It; It != End; ++It) {
510 llvm::Optional<StackCFIRecord> record = StackCFIRecord::parse(*It);
511 if (!record.hasValue())
512 return nullptr;
513 if (record->Size.hasValue())
514 break;
515
516 row_sp = std::make_shared<UnwindPlan::Row>(*row_sp);
517 row_sp->SetOffset(record->Address - init_record->Address);
518 if (!ParseUnwindRow(record->UnwindRules, resolver, *row_sp))
519 return nullptr;
520 plan_sp->AppendRow(row_sp);
521 }
522 return plan_sp;
523}
524
Pavel Labath3f35ab82019-02-07 13:42:32 +0000525SymbolVendor &SymbolFileBreakpad::GetSymbolVendor() {
526 return *m_obj_file->GetModule()->GetSymbolVendor();
527}
528
529addr_t SymbolFileBreakpad::GetBaseFileAddress() {
530 return m_obj_file->GetModule()
531 ->GetObjectFile()
532 ->GetBaseAddress()
533 .GetFileAddress();
534}
535
536// Parse out all the FILE records from the breakpad file. These will be needed
537// when constructing the support file lists for individual compile units.
538void SymbolFileBreakpad::ParseFileRecords() {
539 if (m_files)
540 return;
541 m_files.emplace();
542
543 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
544 for (llvm::StringRef line : lines(Record::File)) {
545 auto record = FileRecord::parse(line);
546 if (!record) {
547 LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
548 continue;
549 }
550
551 if (record->Number >= m_files->size())
552 m_files->resize(record->Number + 1);
Pavel Labath841bea92019-02-11 14:11:00 +0000553 FileSpec::Style style = FileSpec::GuessPathStyle(record->Name)
554 .getValueOr(FileSpec::Style::native);
555 (*m_files)[record->Number] = FileSpec(record->Name, style);
Pavel Labath3f35ab82019-02-07 13:42:32 +0000556 }
557}
558
559void SymbolFileBreakpad::ParseCUData() {
560 if (m_cu_data)
561 return;
562
563 m_cu_data.emplace();
564 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
565 addr_t base = GetBaseFileAddress();
566 if (base == LLDB_INVALID_ADDRESS) {
567 LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "
568 "of object file.");
569 }
570
571 // We shall create one compile unit for each FUNC record. So, count the number
572 // of FUNC records, and store them in m_cu_data, together with their ranges.
573 for (LineIterator It(*m_obj_file, Record::Func), End(*m_obj_file); It != End;
574 ++It) {
575 if (auto record = FuncRecord::parse(*It)) {
576 m_cu_data->Append(CompUnitMap::Entry(base + record->Address, record->Size,
577 CompUnitData(It.GetBookmark())));
578 } else
579 LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
580 }
581 m_cu_data->Sort();
582}
583
584// Construct the list of support files and line table entries for the given
585// compile unit.
586void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu,
587 CompUnitData &data) {
588 addr_t base = GetBaseFileAddress();
589 assert(base != LLDB_INVALID_ADDRESS &&
590 "How did we create compile units without a base address?");
591
592 SupportFileMap map;
593 data.line_table_up = llvm::make_unique<LineTable>(&cu);
594 std::unique_ptr<LineSequence> line_seq_up(
595 data.line_table_up->CreateLineSequenceContainer());
596 llvm::Optional<addr_t> next_addr;
597 auto finish_sequence = [&]() {
598 data.line_table_up->AppendLineEntryToSequence(
599 line_seq_up.get(), *next_addr, /*line*/ 0, /*column*/ 0,
600 /*file_idx*/ 0, /*is_start_of_statement*/ false,
601 /*is_start_of_basic_block*/ false, /*is_prologue_end*/ false,
602 /*is_epilogue_begin*/ false, /*is_terminal_entry*/ true);
603 data.line_table_up->InsertSequence(line_seq_up.get());
604 line_seq_up->Clear();
605 };
606
607 LineIterator It(*m_obj_file, Record::Func, data.bookmark), End(*m_obj_file);
608 assert(Record::classify(*It) == Record::Func);
609 for (++It; It != End; ++It) {
610 auto record = LineRecord::parse(*It);
611 if (!record)
612 break;
613
614 record->Address += base;
615
616 if (next_addr && *next_addr != record->Address) {
617 // Discontiguous entries. Finish off the previous sequence and reset.
618 finish_sequence();
619 }
620 data.line_table_up->AppendLineEntryToSequence(
621 line_seq_up.get(), record->Address, record->LineNum, /*column*/ 0,
622 map[record->FileNum], /*is_start_of_statement*/ true,
623 /*is_start_of_basic_block*/ false, /*is_prologue_end*/ false,
624 /*is_epilogue_begin*/ false, /*is_terminal_entry*/ false);
625 next_addr = record->Address + record->Size;
626 }
627 if (next_addr)
628 finish_sequence();
629 data.support_files = map.translate(cu, *m_files);
630}
Pavel Labath1211baa2019-05-13 11:25:35 +0000631
632void SymbolFileBreakpad::ParseUnwindData() {
633 if (m_unwind_data)
634 return;
635
636 m_unwind_data.emplace();
637 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
638 addr_t base = GetBaseFileAddress();
639 if (base == LLDB_INVALID_ADDRESS) {
640 LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "
641 "of object file.");
642 }
643
644 for (LineIterator It(*m_obj_file, Record::StackCFI), End(*m_obj_file);
645 It != End; ++It) {
646 if (auto record = StackCFIRecord::parse(*It)) {
647 if (record->Size)
648 m_unwind_data->Append(UnwindMap::Entry(
649 base + record->Address, *record->Size, It.GetBookmark()));
650 } else
651 LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
652 }
653 m_unwind_data->Sort();
654}