blob: ef034292839b2af1b366374356e1709aedb8d40e [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 Labathd2deeb42019-07-31 08:25:25 +0000182 if (!m_objfile_sp)
Pavel Labath1cf23e12019-01-11 11:17:51 +0000183 return 0;
Pavel Labathd2deeb42019-07-31 08:25:25 +0000184 if (m_objfile_sp->GetPluginName() !=
185 ObjectFileBreakpad::GetPluginNameStatic())
Pavel Labath1cf23e12019-01-11 11:17:51 +0000186 return 0;
187
Pavel Labath3f35ab82019-02-07 13:42:32 +0000188 return CompileUnits | Functions | LineTables;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000189}
190
Pavel Labathe0119902019-07-23 09:24:02 +0000191uint32_t SymbolFileBreakpad::CalculateNumCompileUnits() {
Pavel Labath3f35ab82019-02-07 13:42:32 +0000192 ParseCUData();
193 return m_cu_data->GetSize();
Pavel Labath1cf23e12019-01-11 11:17:51 +0000194}
195
196CompUnitSP SymbolFileBreakpad::ParseCompileUnitAtIndex(uint32_t index) {
Pavel Labath3f35ab82019-02-07 13:42:32 +0000197 if (index >= m_cu_data->GetSize())
198 return nullptr;
199
200 CompUnitData &data = m_cu_data->GetEntryRef(index).data;
201
202 ParseFileRecords();
203
204 FileSpec spec;
205
206 // The FileSpec of the compile unit will be the file corresponding to the
207 // first LINE record.
Pavel Labathd2deeb42019-07-31 08:25:25 +0000208 LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),
209 End(*m_objfile_sp);
Pavel Labath3f35ab82019-02-07 13:42:32 +0000210 assert(Record::classify(*It) == Record::Func);
211 ++It; // Skip FUNC record.
212 if (It != End) {
213 auto record = LineRecord::parse(*It);
214 if (record && record->FileNum < m_files->size())
215 spec = (*m_files)[record->FileNum];
216 }
217
Pavel Labathd2deeb42019-07-31 08:25:25 +0000218 auto cu_sp = std::make_shared<CompileUnit>(m_objfile_sp->GetModule(),
Pavel Labath3f35ab82019-02-07 13:42:32 +0000219 /*user_data*/ nullptr, spec, index,
220 eLanguageTypeUnknown,
221 /*is_optimized*/ eLazyBoolNo);
222
Pavel Labathe0119902019-07-23 09:24:02 +0000223 SetCompileUnitAtIndex(index, cu_sp);
Pavel Labath3f35ab82019-02-07 13:42:32 +0000224 return cu_sp;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000225}
226
Zachary Turnerce386e32019-01-11 18:35:58 +0000227size_t SymbolFileBreakpad::ParseFunctions(CompileUnit &comp_unit) {
Pavel Labath1cf23e12019-01-11 11:17:51 +0000228 // TODO
229 return 0;
230}
231
Zachary Turnerce386e32019-01-11 18:35:58 +0000232bool SymbolFileBreakpad::ParseLineTable(CompileUnit &comp_unit) {
Pavel Labath656ddeb2019-07-30 08:20:05 +0000233 std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
Pavel Labath3f35ab82019-02-07 13:42:32 +0000234 CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data;
235
236 if (!data.line_table_up)
237 ParseLineTableAndSupportFiles(comp_unit, data);
238
239 comp_unit.SetLineTable(data.line_table_up.release());
240 return true;
241}
242
243bool SymbolFileBreakpad::ParseSupportFiles(CompileUnit &comp_unit,
244 FileSpecList &support_files) {
Pavel Labath656ddeb2019-07-30 08:20:05 +0000245 std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
Pavel Labath3f35ab82019-02-07 13:42:32 +0000246 CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data;
247 if (!data.support_files)
248 ParseLineTableAndSupportFiles(comp_unit, data);
249
250 support_files = std::move(*data.support_files);
251 return true;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000252}
253
254uint32_t
255SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr,
256 SymbolContextItem resolve_scope,
257 SymbolContext &sc) {
Pavel Labath656ddeb2019-07-30 08:20:05 +0000258 std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
Pavel Labath3f35ab82019-02-07 13:42:32 +0000259 if (!(resolve_scope & (eSymbolContextCompUnit | eSymbolContextLineEntry)))
260 return 0;
261
262 ParseCUData();
263 uint32_t idx =
264 m_cu_data->FindEntryIndexThatContains(so_addr.GetFileAddress());
265 if (idx == UINT32_MAX)
266 return 0;
267
Pavel Labathe0119902019-07-23 09:24:02 +0000268 sc.comp_unit = GetCompileUnitAtIndex(idx).get();
Pavel Labath3f35ab82019-02-07 13:42:32 +0000269 SymbolContextItem result = eSymbolContextCompUnit;
270 if (resolve_scope & eSymbolContextLineEntry) {
271 if (sc.comp_unit->GetLineTable()->FindLineEntryByAddress(so_addr,
272 sc.line_entry)) {
273 result |= eSymbolContextLineEntry;
274 }
275 }
276
277 return result;
278}
279
280uint32_t SymbolFileBreakpad::ResolveSymbolContext(
281 const FileSpec &file_spec, uint32_t line, bool check_inlines,
282 lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
Pavel Labath656ddeb2019-07-30 08:20:05 +0000283 std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
Pavel Labath3f35ab82019-02-07 13:42:32 +0000284 if (!(resolve_scope & eSymbolContextCompUnit))
285 return 0;
286
287 uint32_t old_size = sc_list.GetSize();
288 for (size_t i = 0, size = GetNumCompileUnits(); i < size; ++i) {
Pavel Labathe0119902019-07-23 09:24:02 +0000289 CompileUnit &cu = *GetCompileUnitAtIndex(i);
Pavel Labath3f35ab82019-02-07 13:42:32 +0000290 cu.ResolveSymbolContext(file_spec, line, check_inlines,
291 /*exact*/ false, resolve_scope, sc_list);
292 }
293 return sc_list.GetSize() - old_size;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000294}
295
296uint32_t SymbolFileBreakpad::FindFunctions(
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000297 ConstString name, const CompilerDeclContext *parent_decl_ctx,
Pavel Labath1cf23e12019-01-11 11:17:51 +0000298 FunctionNameType name_type_mask, bool include_inlines, bool append,
299 SymbolContextList &sc_list) {
300 // TODO
301 if (!append)
302 sc_list.Clear();
303 return sc_list.GetSize();
304}
305
306uint32_t SymbolFileBreakpad::FindFunctions(const RegularExpression &regex,
307 bool include_inlines, bool append,
308 SymbolContextList &sc_list) {
309 // TODO
310 if (!append)
311 sc_list.Clear();
312 return sc_list.GetSize();
313}
314
315uint32_t SymbolFileBreakpad::FindTypes(
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000316 ConstString name, const CompilerDeclContext *parent_decl_ctx,
Zachary Turner576495e2019-01-14 22:41:21 +0000317 bool append, uint32_t max_matches,
318 llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {
Pavel Labath1cf23e12019-01-11 11:17:51 +0000319 if (!append)
320 types.Clear();
321 return types.GetSize();
322}
323
324size_t
325SymbolFileBreakpad::FindTypes(const std::vector<CompilerContext> &context,
326 bool append, TypeMap &types) {
327 if (!append)
328 types.Clear();
329 return types.GetSize();
330}
331
332void SymbolFileBreakpad::AddSymbols(Symtab &symtab) {
333 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
Pavel Labathd2deeb42019-07-31 08:25:25 +0000334 Module &module = *m_objfile_sp->GetModule();
Pavel Labath3f35ab82019-02-07 13:42:32 +0000335 addr_t base = GetBaseFileAddress();
Pavel Labath1cf23e12019-01-11 11:17:51 +0000336 if (base == LLDB_INVALID_ADDRESS) {
337 LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping "
338 "symtab population.");
339 return;
340 }
341
342 const SectionList &list = *module.GetSectionList();
Pavel Labath06bb3732019-01-22 04:56:31 +0000343 llvm::DenseMap<addr_t, Symbol> symbols;
344 auto add_symbol = [&](addr_t address, llvm::Optional<addr_t> size,
345 llvm::StringRef name) {
346 address += base;
347 SectionSP section_sp = list.FindSectionContainingFileAddress(address);
Pavel Labath1cf23e12019-01-11 11:17:51 +0000348 if (!section_sp) {
349 LLDB_LOG(log,
350 "Ignoring symbol {0}, whose address ({1}) is outside of the "
351 "object file. Mismatched symbol file?",
Pavel Labath06bb3732019-01-22 04:56:31 +0000352 name, address);
353 return;
Pavel Labath1cf23e12019-01-11 11:17:51 +0000354 }
Pavel Labath06bb3732019-01-22 04:56:31 +0000355 symbols.try_emplace(
356 address, /*symID*/ 0, Mangled(name, /*is_mangled*/ false),
357 eSymbolTypeCode, /*is_global*/ true, /*is_debug*/ false,
358 /*is_trampoline*/ false, /*is_artificial*/ false,
359 AddressRange(section_sp, address - section_sp->GetFileAddress(),
360 size.getValueOr(0)),
361 size.hasValue(), /*contains_linker_annotations*/ false, /*flags*/ 0);
362 };
Pavel Labath1cf23e12019-01-11 11:17:51 +0000363
Pavel Labath3f35ab82019-02-07 13:42:32 +0000364 for (llvm::StringRef line : lines(Record::Func)) {
Pavel Labath06bb3732019-01-22 04:56:31 +0000365 if (auto record = FuncRecord::parse(line))
Pavel Labath5b18ddb2019-01-24 04:17:59 +0000366 add_symbol(record->Address, record->Size, record->Name);
Pavel Labath1cf23e12019-01-11 11:17:51 +0000367 }
368
Pavel Labath3f35ab82019-02-07 13:42:32 +0000369 for (llvm::StringRef line : lines(Record::Public)) {
Pavel Labath06bb3732019-01-22 04:56:31 +0000370 if (auto record = PublicRecord::parse(line))
Pavel Labath5b18ddb2019-01-24 04:17:59 +0000371 add_symbol(record->Address, llvm::None, record->Name);
Pavel Labath06bb3732019-01-22 04:56:31 +0000372 else
373 LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
374 }
Pavel Labath1cf23e12019-01-11 11:17:51 +0000375
Pavel Labath06bb3732019-01-22 04:56:31 +0000376 for (auto &KV : symbols)
377 symtab.AddSymbol(std::move(KV.second));
Pavel Labath1cf23e12019-01-11 11:17:51 +0000378 symtab.CalculateSymbolSizes();
379}
Pavel Labath3f35ab82019-02-07 13:42:32 +0000380
Pavel Labath1211baa2019-05-13 11:25:35 +0000381static llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
382GetRule(llvm::StringRef &unwind_rules) {
383 // Unwind rules are of the form
384 // register1: expression1 register2: expression2 ...
385 // We assume none of the tokens in expression<n> end with a colon.
386
387 llvm::StringRef lhs, rest;
388 std::tie(lhs, rest) = getToken(unwind_rules);
389 if (!lhs.consume_back(":"))
390 return llvm::None;
391
392 // Seek forward to the next register: expression pair
393 llvm::StringRef::size_type pos = rest.find(": ");
394 if (pos == llvm::StringRef::npos) {
395 // No pair found, this means the rest of the string is a single expression.
396 unwind_rules = llvm::StringRef();
397 return std::make_pair(lhs, rest);
398 }
399
400 // Go back one token to find the end of the current rule.
401 pos = rest.rfind(' ', pos);
402 if (pos == llvm::StringRef::npos)
403 return llvm::None;
404
405 llvm::StringRef rhs = rest.take_front(pos);
406 unwind_rules = rest.drop_front(pos);
407 return std::make_pair(lhs, rhs);
408}
409
410static const RegisterInfo *
411ResolveRegister(const SymbolFile::RegisterInfoResolver &resolver,
412 llvm::StringRef name) {
413 if (name.consume_front("$"))
414 return resolver.ResolveName(name);
415
416 return nullptr;
417}
418
419static const RegisterInfo *
420ResolveRegisterOrRA(const SymbolFile::RegisterInfoResolver &resolver,
421 llvm::StringRef name) {
422 if (name == ".ra")
423 return resolver.ResolveNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
424 return ResolveRegister(resolver, name);
425}
426
427bool SymbolFileBreakpad::ParseUnwindRow(llvm::StringRef unwind_rules,
428 const RegisterInfoResolver &resolver,
429 UnwindPlan::Row &row) {
430 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
431
432 llvm::BumpPtrAllocator node_alloc;
433 while (auto rule = GetRule(unwind_rules)) {
434 node_alloc.Reset();
435 llvm::StringRef lhs = rule->first;
436 postfix::Node *rhs = postfix::Parse(rule->second, node_alloc);
437 if (!rhs) {
438 LLDB_LOG(log, "Could not parse `{0}` as unwind rhs.", rule->second);
439 return false;
440 }
441
442 bool success = postfix::ResolveSymbols(
443 rhs, [&](postfix::SymbolNode &symbol) -> postfix::Node * {
444 llvm::StringRef name = symbol.GetName();
445 if (name == ".cfa" && lhs != ".cfa")
446 return postfix::MakeNode<postfix::InitialValueNode>(node_alloc);
447
448 if (const RegisterInfo *info = ResolveRegister(resolver, name)) {
449 return postfix::MakeNode<postfix::RegisterNode>(
450 node_alloc, info->kinds[eRegisterKindLLDB]);
451 }
452 return nullptr;
453 });
454
455 if (!success) {
456 LLDB_LOG(log, "Resolving symbols in `{0}` failed.", rule->second);
457 return false;
458 }
459
Pavel Labathd2deeb42019-07-31 08:25:25 +0000460 ArchSpec arch = m_objfile_sp->GetArchitecture();
Pavel Labath1211baa2019-05-13 11:25:35 +0000461 StreamString dwarf(Stream::eBinary, arch.GetAddressByteSize(),
462 arch.GetByteOrder());
463 ToDWARF(*rhs, dwarf);
464 uint8_t *saved = m_allocator.Allocate<uint8_t>(dwarf.GetSize());
465 std::memcpy(saved, dwarf.GetData(), dwarf.GetSize());
466
467 if (lhs == ".cfa") {
468 row.GetCFAValue().SetIsDWARFExpression(saved, dwarf.GetSize());
469 } else if (const RegisterInfo *info = ResolveRegisterOrRA(resolver, lhs)) {
470 UnwindPlan::Row::RegisterLocation loc;
471 loc.SetIsDWARFExpression(saved, dwarf.GetSize());
472 row.SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc);
473 } else
474 LLDB_LOG(log, "Invalid register `{0}` in unwind rule.", lhs);
475 }
476 if (unwind_rules.empty())
477 return true;
478
479 LLDB_LOG(log, "Could not parse `{0}` as an unwind rule.", unwind_rules);
480 return false;
481}
482
483UnwindPlanSP
484SymbolFileBreakpad::GetUnwindPlan(const Address &address,
485 const RegisterInfoResolver &resolver) {
486 ParseUnwindData();
487 const UnwindMap::Entry *entry =
488 m_unwind_data->FindEntryThatContains(address.GetFileAddress());
489 if (!entry)
490 return nullptr;
491
492 addr_t base = GetBaseFileAddress();
493 if (base == LLDB_INVALID_ADDRESS)
494 return nullptr;
495
Pavel Labathd2deeb42019-07-31 08:25:25 +0000496 LineIterator It(*m_objfile_sp, Record::StackCFI, entry->data),
497 End(*m_objfile_sp);
Pavel Labath1211baa2019-05-13 11:25:35 +0000498 llvm::Optional<StackCFIRecord> init_record = StackCFIRecord::parse(*It);
499 assert(init_record.hasValue());
500 assert(init_record->Size.hasValue());
501
502 auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB);
503 plan_sp->SetSourceName("breakpad STACK CFI");
504 plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
Joseph Tremoulet3fd917d2019-07-19 14:05:55 +0000505 plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);
Pavel Labath1211baa2019-05-13 11:25:35 +0000506 plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
507 plan_sp->SetPlanValidAddressRange(
508 AddressRange(base + init_record->Address, *init_record->Size,
Pavel Labathd2deeb42019-07-31 08:25:25 +0000509 m_objfile_sp->GetModule()->GetSectionList()));
Pavel Labath1211baa2019-05-13 11:25:35 +0000510
511 auto row_sp = std::make_shared<UnwindPlan::Row>();
512 row_sp->SetOffset(0);
513 if (!ParseUnwindRow(init_record->UnwindRules, resolver, *row_sp))
514 return nullptr;
515 plan_sp->AppendRow(row_sp);
516 for (++It; It != End; ++It) {
517 llvm::Optional<StackCFIRecord> record = StackCFIRecord::parse(*It);
518 if (!record.hasValue())
519 return nullptr;
520 if (record->Size.hasValue())
521 break;
522
523 row_sp = std::make_shared<UnwindPlan::Row>(*row_sp);
524 row_sp->SetOffset(record->Address - init_record->Address);
525 if (!ParseUnwindRow(record->UnwindRules, resolver, *row_sp))
526 return nullptr;
527 plan_sp->AppendRow(row_sp);
528 }
529 return plan_sp;
530}
531
Pavel Labath3f35ab82019-02-07 13:42:32 +0000532addr_t SymbolFileBreakpad::GetBaseFileAddress() {
Pavel Labathd2deeb42019-07-31 08:25:25 +0000533 return m_objfile_sp->GetModule()
Pavel Labath3f35ab82019-02-07 13:42:32 +0000534 ->GetObjectFile()
535 ->GetBaseAddress()
536 .GetFileAddress();
537}
538
539// Parse out all the FILE records from the breakpad file. These will be needed
540// when constructing the support file lists for individual compile units.
541void SymbolFileBreakpad::ParseFileRecords() {
542 if (m_files)
543 return;
544 m_files.emplace();
545
546 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
547 for (llvm::StringRef line : lines(Record::File)) {
548 auto record = FileRecord::parse(line);
549 if (!record) {
550 LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
551 continue;
552 }
553
554 if (record->Number >= m_files->size())
555 m_files->resize(record->Number + 1);
Pavel Labath841bea92019-02-11 14:11:00 +0000556 FileSpec::Style style = FileSpec::GuessPathStyle(record->Name)
557 .getValueOr(FileSpec::Style::native);
558 (*m_files)[record->Number] = FileSpec(record->Name, style);
Pavel Labath3f35ab82019-02-07 13:42:32 +0000559 }
560}
561
562void SymbolFileBreakpad::ParseCUData() {
563 if (m_cu_data)
564 return;
565
566 m_cu_data.emplace();
567 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
568 addr_t base = GetBaseFileAddress();
569 if (base == LLDB_INVALID_ADDRESS) {
570 LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "
571 "of object file.");
572 }
573
574 // We shall create one compile unit for each FUNC record. So, count the number
575 // of FUNC records, and store them in m_cu_data, together with their ranges.
Pavel Labathd2deeb42019-07-31 08:25:25 +0000576 for (LineIterator It(*m_objfile_sp, Record::Func), End(*m_objfile_sp);
577 It != End; ++It) {
Pavel Labath3f35ab82019-02-07 13:42:32 +0000578 if (auto record = FuncRecord::parse(*It)) {
579 m_cu_data->Append(CompUnitMap::Entry(base + record->Address, record->Size,
580 CompUnitData(It.GetBookmark())));
581 } else
582 LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
583 }
584 m_cu_data->Sort();
585}
586
587// Construct the list of support files and line table entries for the given
588// compile unit.
589void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu,
590 CompUnitData &data) {
591 addr_t base = GetBaseFileAddress();
592 assert(base != LLDB_INVALID_ADDRESS &&
593 "How did we create compile units without a base address?");
594
595 SupportFileMap map;
596 data.line_table_up = llvm::make_unique<LineTable>(&cu);
597 std::unique_ptr<LineSequence> line_seq_up(
598 data.line_table_up->CreateLineSequenceContainer());
599 llvm::Optional<addr_t> next_addr;
600 auto finish_sequence = [&]() {
601 data.line_table_up->AppendLineEntryToSequence(
602 line_seq_up.get(), *next_addr, /*line*/ 0, /*column*/ 0,
603 /*file_idx*/ 0, /*is_start_of_statement*/ false,
604 /*is_start_of_basic_block*/ false, /*is_prologue_end*/ false,
605 /*is_epilogue_begin*/ false, /*is_terminal_entry*/ true);
606 data.line_table_up->InsertSequence(line_seq_up.get());
607 line_seq_up->Clear();
608 };
609
Pavel Labathd2deeb42019-07-31 08:25:25 +0000610 LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),
611 End(*m_objfile_sp);
Pavel Labath3f35ab82019-02-07 13:42:32 +0000612 assert(Record::classify(*It) == Record::Func);
613 for (++It; It != End; ++It) {
614 auto record = LineRecord::parse(*It);
615 if (!record)
616 break;
617
618 record->Address += base;
619
620 if (next_addr && *next_addr != record->Address) {
621 // Discontiguous entries. Finish off the previous sequence and reset.
622 finish_sequence();
623 }
624 data.line_table_up->AppendLineEntryToSequence(
625 line_seq_up.get(), record->Address, record->LineNum, /*column*/ 0,
626 map[record->FileNum], /*is_start_of_statement*/ true,
627 /*is_start_of_basic_block*/ false, /*is_prologue_end*/ false,
628 /*is_epilogue_begin*/ false, /*is_terminal_entry*/ false);
629 next_addr = record->Address + record->Size;
630 }
631 if (next_addr)
632 finish_sequence();
633 data.support_files = map.translate(cu, *m_files);
634}
Pavel Labath1211baa2019-05-13 11:25:35 +0000635
636void SymbolFileBreakpad::ParseUnwindData() {
637 if (m_unwind_data)
638 return;
639
640 m_unwind_data.emplace();
641 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
642 addr_t base = GetBaseFileAddress();
643 if (base == LLDB_INVALID_ADDRESS) {
644 LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "
645 "of object file.");
646 }
647
Pavel Labathd2deeb42019-07-31 08:25:25 +0000648 for (LineIterator It(*m_objfile_sp, Record::StackCFI), End(*m_objfile_sp);
Pavel Labath1211baa2019-05-13 11:25:35 +0000649 It != End; ++It) {
650 if (auto record = StackCFIRecord::parse(*It)) {
651 if (record->Size)
652 m_unwind_data->Append(UnwindMap::Entry(
653 base + record->Address, *record->Size, It.GetBookmark()));
654 } else
655 LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
656 }
657 m_unwind_data->Sort();
658}