blob: d5f51458eb137646a291d2ae8f4db7f2bd48b938 [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) {
Pavel Labathd2deeb42019-07-31 08:25:25 +0000129 return llvm::make_range(LineIterator(*m_objfile_sp, section_type),
130 LineIterator(*m_objfile_sp));
Pavel Labath3f35ab82019-02-07 13:42:32 +0000131}
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() {
Pavel Labathe84f7842019-07-31 11:57:34 +0000182 if (!m_objfile_sp || !llvm::isa<ObjectFileBreakpad>(*m_objfile_sp))
Pavel Labath1cf23e12019-01-11 11:17:51 +0000183 return 0;
184
Pavel Labath3f35ab82019-02-07 13:42:32 +0000185 return CompileUnits | Functions | LineTables;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000186}
187
Pavel Labathe0119902019-07-23 09:24:02 +0000188uint32_t SymbolFileBreakpad::CalculateNumCompileUnits() {
Pavel Labath3f35ab82019-02-07 13:42:32 +0000189 ParseCUData();
190 return m_cu_data->GetSize();
Pavel Labath1cf23e12019-01-11 11:17:51 +0000191}
192
193CompUnitSP SymbolFileBreakpad::ParseCompileUnitAtIndex(uint32_t index) {
Pavel Labath3f35ab82019-02-07 13:42:32 +0000194 if (index >= m_cu_data->GetSize())
195 return nullptr;
196
197 CompUnitData &data = m_cu_data->GetEntryRef(index).data;
198
199 ParseFileRecords();
200
201 FileSpec spec;
202
203 // The FileSpec of the compile unit will be the file corresponding to the
204 // first LINE record.
Pavel Labathd2deeb42019-07-31 08:25:25 +0000205 LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),
206 End(*m_objfile_sp);
Pavel Labath3f35ab82019-02-07 13:42:32 +0000207 assert(Record::classify(*It) == Record::Func);
208 ++It; // Skip FUNC record.
209 if (It != End) {
210 auto record = LineRecord::parse(*It);
211 if (record && record->FileNum < m_files->size())
212 spec = (*m_files)[record->FileNum];
213 }
214
Pavel Labathd2deeb42019-07-31 08:25:25 +0000215 auto cu_sp = std::make_shared<CompileUnit>(m_objfile_sp->GetModule(),
Pavel Labath3f35ab82019-02-07 13:42:32 +0000216 /*user_data*/ nullptr, spec, index,
217 eLanguageTypeUnknown,
218 /*is_optimized*/ eLazyBoolNo);
219
Pavel Labathe0119902019-07-23 09:24:02 +0000220 SetCompileUnitAtIndex(index, cu_sp);
Pavel Labath3f35ab82019-02-07 13:42:32 +0000221 return cu_sp;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000222}
223
Zachary Turnerce386e32019-01-11 18:35:58 +0000224size_t SymbolFileBreakpad::ParseFunctions(CompileUnit &comp_unit) {
Pavel Labath1cf23e12019-01-11 11:17:51 +0000225 // TODO
226 return 0;
227}
228
Zachary Turnerce386e32019-01-11 18:35:58 +0000229bool SymbolFileBreakpad::ParseLineTable(CompileUnit &comp_unit) {
Pavel Labath656ddeb2019-07-30 08:20:05 +0000230 std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
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) {
Pavel Labath656ddeb2019-07-30 08:20:05 +0000242 std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
Pavel Labath3f35ab82019-02-07 13:42:32 +0000243 CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data;
244 if (!data.support_files)
245 ParseLineTableAndSupportFiles(comp_unit, data);
246
247 support_files = std::move(*data.support_files);
248 return true;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000249}
250
251uint32_t
252SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr,
253 SymbolContextItem resolve_scope,
254 SymbolContext &sc) {
Pavel Labath656ddeb2019-07-30 08:20:05 +0000255 std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
Pavel Labath3f35ab82019-02-07 13:42:32 +0000256 if (!(resolve_scope & (eSymbolContextCompUnit | eSymbolContextLineEntry)))
257 return 0;
258
259 ParseCUData();
260 uint32_t idx =
261 m_cu_data->FindEntryIndexThatContains(so_addr.GetFileAddress());
262 if (idx == UINT32_MAX)
263 return 0;
264
Pavel Labathe0119902019-07-23 09:24:02 +0000265 sc.comp_unit = GetCompileUnitAtIndex(idx).get();
Pavel Labath3f35ab82019-02-07 13:42:32 +0000266 SymbolContextItem result = eSymbolContextCompUnit;
267 if (resolve_scope & eSymbolContextLineEntry) {
268 if (sc.comp_unit->GetLineTable()->FindLineEntryByAddress(so_addr,
269 sc.line_entry)) {
270 result |= eSymbolContextLineEntry;
271 }
272 }
273
274 return result;
275}
276
277uint32_t SymbolFileBreakpad::ResolveSymbolContext(
278 const FileSpec &file_spec, uint32_t line, bool check_inlines,
279 lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
Pavel Labath656ddeb2019-07-30 08:20:05 +0000280 std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
Pavel Labath3f35ab82019-02-07 13:42:32 +0000281 if (!(resolve_scope & eSymbolContextCompUnit))
282 return 0;
283
284 uint32_t old_size = sc_list.GetSize();
285 for (size_t i = 0, size = GetNumCompileUnits(); i < size; ++i) {
Pavel Labathe0119902019-07-23 09:24:02 +0000286 CompileUnit &cu = *GetCompileUnitAtIndex(i);
Pavel Labath3f35ab82019-02-07 13:42:32 +0000287 cu.ResolveSymbolContext(file_spec, line, check_inlines,
288 /*exact*/ false, resolve_scope, sc_list);
289 }
290 return sc_list.GetSize() - old_size;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000291}
292
293uint32_t SymbolFileBreakpad::FindFunctions(
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000294 ConstString name, const CompilerDeclContext *parent_decl_ctx,
Pavel Labath1cf23e12019-01-11 11:17:51 +0000295 FunctionNameType name_type_mask, bool include_inlines, bool append,
296 SymbolContextList &sc_list) {
297 // TODO
298 if (!append)
299 sc_list.Clear();
300 return sc_list.GetSize();
301}
302
303uint32_t SymbolFileBreakpad::FindFunctions(const RegularExpression &regex,
304 bool include_inlines, bool append,
305 SymbolContextList &sc_list) {
306 // TODO
307 if (!append)
308 sc_list.Clear();
309 return sc_list.GetSize();
310}
311
312uint32_t SymbolFileBreakpad::FindTypes(
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000313 ConstString name, const CompilerDeclContext *parent_decl_ctx,
Zachary Turner576495e2019-01-14 22:41:21 +0000314 bool append, uint32_t max_matches,
315 llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {
Pavel Labath1cf23e12019-01-11 11:17:51 +0000316 if (!append)
317 types.Clear();
318 return types.GetSize();
319}
320
Adrian Prantl330ae19a2019-08-21 18:06:56 +0000321size_t SymbolFileBreakpad::FindTypes(llvm::ArrayRef<CompilerContext> pattern,
322 bool append, TypeMap &types) {
Pavel Labath1cf23e12019-01-11 11:17:51 +0000323 if (!append)
324 types.Clear();
325 return types.GetSize();
326}
327
328void SymbolFileBreakpad::AddSymbols(Symtab &symtab) {
329 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
Pavel Labathd2deeb42019-07-31 08:25:25 +0000330 Module &module = *m_objfile_sp->GetModule();
Pavel Labath3f35ab82019-02-07 13:42:32 +0000331 addr_t base = GetBaseFileAddress();
Pavel Labath1cf23e12019-01-11 11:17:51 +0000332 if (base == LLDB_INVALID_ADDRESS) {
333 LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping "
334 "symtab population.");
335 return;
336 }
337
338 const SectionList &list = *module.GetSectionList();
Pavel Labath06bb3732019-01-22 04:56:31 +0000339 llvm::DenseMap<addr_t, Symbol> symbols;
340 auto add_symbol = [&](addr_t address, llvm::Optional<addr_t> size,
341 llvm::StringRef name) {
342 address += base;
343 SectionSP section_sp = list.FindSectionContainingFileAddress(address);
Pavel Labath1cf23e12019-01-11 11:17:51 +0000344 if (!section_sp) {
345 LLDB_LOG(log,
346 "Ignoring symbol {0}, whose address ({1}) is outside of the "
347 "object file. Mismatched symbol file?",
Pavel Labath06bb3732019-01-22 04:56:31 +0000348 name, address);
349 return;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000350 }
Pavel Labath06bb3732019-01-22 04:56:31 +0000351 symbols.try_emplace(
352 address, /*symID*/ 0, Mangled(name, /*is_mangled*/ false),
353 eSymbolTypeCode, /*is_global*/ true, /*is_debug*/ false,
354 /*is_trampoline*/ false, /*is_artificial*/ false,
355 AddressRange(section_sp, address - section_sp->GetFileAddress(),
356 size.getValueOr(0)),
357 size.hasValue(), /*contains_linker_annotations*/ false, /*flags*/ 0);
358 };
Pavel Labath1cf23e12019-01-11 11:17:51 +0000359
Pavel Labath3f35ab82019-02-07 13:42:32 +0000360 for (llvm::StringRef line : lines(Record::Func)) {
Pavel Labath06bb3732019-01-22 04:56:31 +0000361 if (auto record = FuncRecord::parse(line))
Pavel Labath5b18ddb2019-01-24 04:17:59 +0000362 add_symbol(record->Address, record->Size, record->Name);
Pavel Labath1cf23e12019-01-11 11:17:51 +0000363 }
364
Pavel Labath3f35ab82019-02-07 13:42:32 +0000365 for (llvm::StringRef line : lines(Record::Public)) {
Pavel Labath06bb3732019-01-22 04:56:31 +0000366 if (auto record = PublicRecord::parse(line))
Pavel Labath5b18ddb2019-01-24 04:17:59 +0000367 add_symbol(record->Address, llvm::None, record->Name);
Pavel Labath06bb3732019-01-22 04:56:31 +0000368 else
369 LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
370 }
Pavel Labath1cf23e12019-01-11 11:17:51 +0000371
Pavel Labath06bb3732019-01-22 04:56:31 +0000372 for (auto &KV : symbols)
373 symtab.AddSymbol(std::move(KV.second));
Pavel Labath1cf23e12019-01-11 11:17:51 +0000374 symtab.CalculateSymbolSizes();
375}
Pavel Labath3f35ab82019-02-07 13:42:32 +0000376
Pavel Labath1211baa2019-05-13 11:25:35 +0000377static llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
378GetRule(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
406static const RegisterInfo *
407ResolveRegister(const SymbolFile::RegisterInfoResolver &resolver,
408 llvm::StringRef name) {
409 if (name.consume_front("$"))
410 return resolver.ResolveName(name);
411
412 return nullptr;
413}
414
415static const RegisterInfo *
416ResolveRegisterOrRA(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
423bool SymbolFileBreakpad::ParseUnwindRow(llvm::StringRef unwind_rules,
424 const RegisterInfoResolver &resolver,
425 UnwindPlan::Row &row) {
426 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
427
428 llvm::BumpPtrAllocator node_alloc;
429 while (auto rule = GetRule(unwind_rules)) {
430 node_alloc.Reset();
431 llvm::StringRef lhs = rule->first;
432 postfix::Node *rhs = postfix::Parse(rule->second, node_alloc);
433 if (!rhs) {
434 LLDB_LOG(log, "Could not parse `{0}` as unwind rhs.", rule->second);
435 return false;
436 }
437
438 bool success = postfix::ResolveSymbols(
439 rhs, [&](postfix::SymbolNode &symbol) -> postfix::Node * {
440 llvm::StringRef name = symbol.GetName();
441 if (name == ".cfa" && lhs != ".cfa")
442 return postfix::MakeNode<postfix::InitialValueNode>(node_alloc);
443
444 if (const RegisterInfo *info = ResolveRegister(resolver, name)) {
445 return postfix::MakeNode<postfix::RegisterNode>(
446 node_alloc, info->kinds[eRegisterKindLLDB]);
447 }
448 return nullptr;
449 });
450
451 if (!success) {
452 LLDB_LOG(log, "Resolving symbols in `{0}` failed.", rule->second);
453 return false;
454 }
455
Pavel Labathd2deeb42019-07-31 08:25:25 +0000456 ArchSpec arch = m_objfile_sp->GetArchitecture();
Pavel Labath1211baa2019-05-13 11:25:35 +0000457 StreamString dwarf(Stream::eBinary, arch.GetAddressByteSize(),
458 arch.GetByteOrder());
459 ToDWARF(*rhs, dwarf);
460 uint8_t *saved = m_allocator.Allocate<uint8_t>(dwarf.GetSize());
461 std::memcpy(saved, dwarf.GetData(), dwarf.GetSize());
462
463 if (lhs == ".cfa") {
464 row.GetCFAValue().SetIsDWARFExpression(saved, dwarf.GetSize());
465 } else if (const RegisterInfo *info = ResolveRegisterOrRA(resolver, lhs)) {
466 UnwindPlan::Row::RegisterLocation loc;
467 loc.SetIsDWARFExpression(saved, dwarf.GetSize());
468 row.SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc);
469 } else
470 LLDB_LOG(log, "Invalid register `{0}` in unwind rule.", lhs);
471 }
472 if (unwind_rules.empty())
473 return true;
474
475 LLDB_LOG(log, "Could not parse `{0}` as an unwind rule.", unwind_rules);
476 return false;
477}
478
479UnwindPlanSP
480SymbolFileBreakpad::GetUnwindPlan(const Address &address,
481 const RegisterInfoResolver &resolver) {
482 ParseUnwindData();
483 const UnwindMap::Entry *entry =
484 m_unwind_data->FindEntryThatContains(address.GetFileAddress());
485 if (!entry)
486 return nullptr;
487
488 addr_t base = GetBaseFileAddress();
489 if (base == LLDB_INVALID_ADDRESS)
490 return nullptr;
491
Pavel Labathd2deeb42019-07-31 08:25:25 +0000492 LineIterator It(*m_objfile_sp, Record::StackCFI, entry->data),
493 End(*m_objfile_sp);
Pavel Labath1211baa2019-05-13 11:25:35 +0000494 llvm::Optional<StackCFIRecord> init_record = StackCFIRecord::parse(*It);
495 assert(init_record.hasValue());
496 assert(init_record->Size.hasValue());
497
498 auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB);
499 plan_sp->SetSourceName("breakpad STACK CFI");
500 plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
Joseph Tremoulet3fd917d2019-07-19 14:05:55 +0000501 plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);
Pavel Labath1211baa2019-05-13 11:25:35 +0000502 plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
503 plan_sp->SetPlanValidAddressRange(
504 AddressRange(base + init_record->Address, *init_record->Size,
Pavel Labathd2deeb42019-07-31 08:25:25 +0000505 m_objfile_sp->GetModule()->GetSectionList()));
Pavel Labath1211baa2019-05-13 11:25:35 +0000506
507 auto row_sp = std::make_shared<UnwindPlan::Row>();
508 row_sp->SetOffset(0);
509 if (!ParseUnwindRow(init_record->UnwindRules, resolver, *row_sp))
510 return nullptr;
511 plan_sp->AppendRow(row_sp);
512 for (++It; It != End; ++It) {
513 llvm::Optional<StackCFIRecord> record = StackCFIRecord::parse(*It);
514 if (!record.hasValue())
515 return nullptr;
516 if (record->Size.hasValue())
517 break;
518
519 row_sp = std::make_shared<UnwindPlan::Row>(*row_sp);
520 row_sp->SetOffset(record->Address - init_record->Address);
521 if (!ParseUnwindRow(record->UnwindRules, resolver, *row_sp))
522 return nullptr;
523 plan_sp->AppendRow(row_sp);
524 }
525 return plan_sp;
526}
527
Pavel Labath3f35ab82019-02-07 13:42:32 +0000528addr_t SymbolFileBreakpad::GetBaseFileAddress() {
Pavel Labathd2deeb42019-07-31 08:25:25 +0000529 return m_objfile_sp->GetModule()
Pavel Labath3f35ab82019-02-07 13:42:32 +0000530 ->GetObjectFile()
531 ->GetBaseAddress()
532 .GetFileAddress();
533}
534
535// Parse out all the FILE records from the breakpad file. These will be needed
536// when constructing the support file lists for individual compile units.
537void SymbolFileBreakpad::ParseFileRecords() {
538 if (m_files)
539 return;
540 m_files.emplace();
541
542 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
543 for (llvm::StringRef line : lines(Record::File)) {
544 auto record = FileRecord::parse(line);
545 if (!record) {
546 LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
547 continue;
548 }
549
550 if (record->Number >= m_files->size())
551 m_files->resize(record->Number + 1);
Pavel Labath841bea92019-02-11 14:11:00 +0000552 FileSpec::Style style = FileSpec::GuessPathStyle(record->Name)
553 .getValueOr(FileSpec::Style::native);
554 (*m_files)[record->Number] = FileSpec(record->Name, style);
Pavel Labath3f35ab82019-02-07 13:42:32 +0000555 }
556}
557
558void SymbolFileBreakpad::ParseCUData() {
559 if (m_cu_data)
560 return;
561
562 m_cu_data.emplace();
563 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
564 addr_t base = GetBaseFileAddress();
565 if (base == LLDB_INVALID_ADDRESS) {
566 LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "
567 "of object file.");
568 }
569
570 // We shall create one compile unit for each FUNC record. So, count the number
571 // of FUNC records, and store them in m_cu_data, together with their ranges.
Pavel Labathd2deeb42019-07-31 08:25:25 +0000572 for (LineIterator It(*m_objfile_sp, Record::Func), End(*m_objfile_sp);
573 It != End; ++It) {
Pavel Labath3f35ab82019-02-07 13:42:32 +0000574 if (auto record = FuncRecord::parse(*It)) {
575 m_cu_data->Append(CompUnitMap::Entry(base + record->Address, record->Size,
576 CompUnitData(It.GetBookmark())));
577 } else
578 LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
579 }
580 m_cu_data->Sort();
581}
582
583// Construct the list of support files and line table entries for the given
584// compile unit.
585void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu,
586 CompUnitData &data) {
587 addr_t base = GetBaseFileAddress();
588 assert(base != LLDB_INVALID_ADDRESS &&
589 "How did we create compile units without a base address?");
590
591 SupportFileMap map;
Jonas Devliegherea8f3ae72019-08-14 22:19:23 +0000592 data.line_table_up = std::make_unique<LineTable>(&cu);
Pavel Labath3f35ab82019-02-07 13:42:32 +0000593 std::unique_ptr<LineSequence> line_seq_up(
594 data.line_table_up->CreateLineSequenceContainer());
595 llvm::Optional<addr_t> next_addr;
596 auto finish_sequence = [&]() {
597 data.line_table_up->AppendLineEntryToSequence(
598 line_seq_up.get(), *next_addr, /*line*/ 0, /*column*/ 0,
599 /*file_idx*/ 0, /*is_start_of_statement*/ false,
600 /*is_start_of_basic_block*/ false, /*is_prologue_end*/ false,
601 /*is_epilogue_begin*/ false, /*is_terminal_entry*/ true);
602 data.line_table_up->InsertSequence(line_seq_up.get());
603 line_seq_up->Clear();
604 };
605
Pavel Labathd2deeb42019-07-31 08:25:25 +0000606 LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),
607 End(*m_objfile_sp);
Pavel Labath3f35ab82019-02-07 13:42:32 +0000608 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
Pavel Labathd2deeb42019-07-31 08:25:25 +0000644 for (LineIterator It(*m_objfile_sp, Record::StackCFI), End(*m_objfile_sp);
Pavel Labath1211baa2019-05-13 11:25:35 +0000645 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}