1 //===-- SymbolFileBreakpad.cpp --------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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/LLDBLog.h"
21 #include "lldb/Utility/Log.h"
22 #include "lldb/Utility/StreamString.h"
23 #include "llvm/ADT/StringExtras.h"
27 using namespace lldb_private
;
28 using namespace lldb_private::breakpad
;
30 LLDB_PLUGIN_DEFINE(SymbolFileBreakpad
)
32 char SymbolFileBreakpad::ID
;
34 class SymbolFileBreakpad::LineIterator
{
36 // begin iterator for sections of given type
37 LineIterator(ObjectFile
&obj
, Record::Kind section_type
)
38 : m_obj(&obj
), m_section_type(toString(section_type
)),
39 m_next_section_idx(0), m_next_line(llvm::StringRef::npos
) {
43 // An iterator starting at the position given by the bookmark.
44 LineIterator(ObjectFile
&obj
, Record::Kind section_type
, Bookmark bookmark
);
47 explicit LineIterator(ObjectFile
&obj
)
49 m_next_section_idx(m_obj
->GetSectionList()->GetNumSections(0)),
50 m_current_line(llvm::StringRef::npos
),
51 m_next_line(llvm::StringRef::npos
) {}
53 friend bool operator!=(const LineIterator
&lhs
, const LineIterator
&rhs
) {
54 assert(lhs
.m_obj
== rhs
.m_obj
);
55 if (lhs
.m_next_section_idx
!= rhs
.m_next_section_idx
)
57 if (lhs
.m_current_line
!= rhs
.m_current_line
)
59 assert(lhs
.m_next_line
== rhs
.m_next_line
);
63 const LineIterator
&operator++();
64 llvm::StringRef
operator*() const {
65 return m_section_text
.slice(m_current_line
, m_next_line
);
68 Bookmark
GetBookmark() const {
69 return Bookmark
{m_next_section_idx
, m_current_line
};
74 ConstString m_section_type
;
75 uint32_t m_next_section_idx
;
76 llvm::StringRef m_section_text
;
77 size_t m_current_line
;
81 m_next_line
= m_section_text
.find('\n', m_current_line
);
82 if (m_next_line
!= llvm::StringRef::npos
) {
84 if (m_next_line
>= m_section_text
.size())
85 m_next_line
= llvm::StringRef::npos
;
90 SymbolFileBreakpad::LineIterator::LineIterator(ObjectFile
&obj
,
91 Record::Kind section_type
,
93 : m_obj(&obj
), m_section_type(toString(section_type
)),
94 m_next_section_idx(bookmark
.section
), m_current_line(bookmark
.offset
) {
96 *obj
.GetSectionList()->GetSectionAtIndex(m_next_section_idx
- 1);
97 assert(sect
.GetName() == m_section_type
);
100 obj
.ReadSectionData(§
, data
);
101 m_section_text
= toStringRef(data
.GetData());
103 assert(m_current_line
< m_section_text
.size());
107 const SymbolFileBreakpad::LineIterator
&
108 SymbolFileBreakpad::LineIterator::operator++() {
109 const SectionList
&list
= *m_obj
->GetSectionList();
110 size_t num_sections
= list
.GetNumSections(0);
111 while (m_next_line
!= llvm::StringRef::npos
||
112 m_next_section_idx
< num_sections
) {
113 if (m_next_line
!= llvm::StringRef::npos
) {
114 m_current_line
= m_next_line
;
119 Section
§
= *list
.GetSectionAtIndex(m_next_section_idx
++);
120 if (sect
.GetName() != m_section_type
)
123 m_obj
->ReadSectionData(§
, data
);
124 m_section_text
= toStringRef(data
.GetData());
127 // We've reached the end.
128 m_current_line
= m_next_line
;
132 llvm::iterator_range
<SymbolFileBreakpad::LineIterator
>
133 SymbolFileBreakpad::lines(Record::Kind section_type
) {
134 return llvm::make_range(LineIterator(*m_objfile_sp
, section_type
),
135 LineIterator(*m_objfile_sp
));
139 // A helper class for constructing the list of support files for a given compile
141 class SupportFileMap
{
143 // Given a breakpad file ID, return a file ID to be used in the support files
144 // for this compile unit.
145 size_t operator[](size_t file
) {
146 return m_map
.try_emplace(file
, m_map
.size() + 1).first
->second
;
149 // Construct a FileSpecList containing only the support files relevant for
150 // this compile unit (in the correct order).
151 FileSpecList
translate(const FileSpec
&cu_spec
,
152 llvm::ArrayRef
<FileSpec
> all_files
);
155 llvm::DenseMap
<size_t, size_t> m_map
;
159 FileSpecList
SupportFileMap::translate(const FileSpec
&cu_spec
,
160 llvm::ArrayRef
<FileSpec
> all_files
) {
161 std::vector
<FileSpec
> result
;
162 result
.resize(m_map
.size() + 1);
164 for (const auto &KV
: m_map
) {
165 if (KV
.first
< all_files
.size())
166 result
[KV
.second
] = all_files
[KV
.first
];
168 return FileSpecList(std::move(result
));
171 void SymbolFileBreakpad::Initialize() {
172 PluginManager::RegisterPlugin(GetPluginNameStatic(),
173 GetPluginDescriptionStatic(), CreateInstance
,
177 void SymbolFileBreakpad::Terminate() {
178 PluginManager::UnregisterPlugin(CreateInstance
);
181 uint32_t SymbolFileBreakpad::CalculateAbilities() {
182 if (!m_objfile_sp
|| !llvm::isa
<ObjectFileBreakpad
>(*m_objfile_sp
))
185 return CompileUnits
| Functions
| LineTables
;
188 uint32_t SymbolFileBreakpad::CalculateNumCompileUnits() {
190 return m_cu_data
->GetSize();
193 CompUnitSP
SymbolFileBreakpad::ParseCompileUnitAtIndex(uint32_t index
) {
194 if (index
>= m_cu_data
->GetSize())
197 CompUnitData
&data
= m_cu_data
->GetEntryRef(index
).data
;
203 // The FileSpec of the compile unit will be the file corresponding to the
204 // first LINE record.
205 LineIterator
It(*m_objfile_sp
, Record::Func
, data
.bookmark
),
207 assert(Record::classify(*It
) == Record::Func
);
208 ++It
; // Skip FUNC record.
209 // Skip INLINE records.
210 while (It
!= End
&& Record::classify(*It
) == Record::Inline
)
214 auto record
= LineRecord::parse(*It
);
215 if (record
&& record
->FileNum
< m_files
->size())
216 spec
= (*m_files
)[record
->FileNum
];
219 auto cu_sp
= std::make_shared
<CompileUnit
>(m_objfile_sp
->GetModule(),
220 /*user_data*/ nullptr, spec
, index
,
221 eLanguageTypeUnknown
,
222 /*is_optimized*/ eLazyBoolNo
);
224 SetCompileUnitAtIndex(index
, cu_sp
);
228 FunctionSP
SymbolFileBreakpad::GetOrCreateFunction(CompileUnit
&comp_unit
) {
229 user_id_t id
= comp_unit
.GetID();
230 if (FunctionSP func_sp
= comp_unit
.FindFunctionByUID(id
))
233 Log
*log
= GetLog(LLDBLog::Symbols
);
235 addr_t base
= GetBaseFileAddress();
236 if (base
== LLDB_INVALID_ADDRESS
) {
237 LLDB_LOG(log
, "Unable to fetch the base address of object file. Skipping "
238 "symtab population.");
242 const SectionList
*list
= comp_unit
.GetModule()->GetSectionList();
243 CompUnitData
&data
= m_cu_data
->GetEntryRef(id
).data
;
244 LineIterator
It(*m_objfile_sp
, Record::Func
, data
.bookmark
);
245 assert(Record::classify(*It
) == Record::Func
);
247 if (auto record
= FuncRecord::parse(*It
)) {
249 func_name
.SetValue(ConstString(record
->Name
));
250 addr_t address
= record
->Address
+ base
;
251 SectionSP section_sp
= list
->FindSectionContainingFileAddress(address
);
253 AddressRange
func_range(
254 section_sp
, address
- section_sp
->GetFileAddress(), record
->Size
);
255 // Use the CU's id because every CU has only one function inside.
256 func_sp
= std::make_shared
<Function
>(&comp_unit
, id
, 0, func_name
,
257 nullptr, func_range
);
258 comp_unit
.AddFunction(func_sp
);
264 size_t SymbolFileBreakpad::ParseFunctions(CompileUnit
&comp_unit
) {
265 std::lock_guard
<std::recursive_mutex
> guard(GetModuleMutex());
266 return GetOrCreateFunction(comp_unit
) ? 1 : 0;
269 bool SymbolFileBreakpad::ParseLineTable(CompileUnit
&comp_unit
) {
270 std::lock_guard
<std::recursive_mutex
> guard(GetModuleMutex());
271 CompUnitData
&data
= m_cu_data
->GetEntryRef(comp_unit
.GetID()).data
;
273 if (!data
.line_table_up
)
274 ParseLineTableAndSupportFiles(comp_unit
, data
);
276 comp_unit
.SetLineTable(data
.line_table_up
.release());
280 bool SymbolFileBreakpad::ParseSupportFiles(CompileUnit
&comp_unit
,
281 FileSpecList
&support_files
) {
282 std::lock_guard
<std::recursive_mutex
> guard(GetModuleMutex());
283 CompUnitData
&data
= m_cu_data
->GetEntryRef(comp_unit
.GetID()).data
;
284 if (!data
.support_files
)
285 ParseLineTableAndSupportFiles(comp_unit
, data
);
287 support_files
= std::move(*data
.support_files
);
291 size_t SymbolFileBreakpad::ParseBlocksRecursive(Function
&func
) {
292 std::lock_guard
<std::recursive_mutex
> guard(GetModuleMutex());
293 CompileUnit
*comp_unit
= func
.GetCompileUnit();
294 lldbassert(comp_unit
);
295 ParseInlineOriginRecords();
296 // A vector of current each level's parent block. For example, when parsing
297 // "INLINE 0 ...", the current level is 0 and its parent block is the
298 // function block at index 0.
299 std::vector
<Block
*> blocks
;
300 Block
&block
= func
.GetBlock(false);
301 block
.AddRange(Block::Range(0, func
.GetAddressRange().GetByteSize()));
302 blocks
.push_back(&block
);
304 size_t blocks_added
= 0;
305 addr_t func_base
= func
.GetAddressRange().GetBaseAddress().GetOffset();
306 CompUnitData
&data
= m_cu_data
->GetEntryRef(comp_unit
->GetID()).data
;
307 LineIterator
It(*m_objfile_sp
, Record::Func
, data
.bookmark
),
309 ++It
; // Skip the FUNC record.
310 size_t last_added_nest_level
= 0;
311 while (It
!= End
&& Record::classify(*It
) == Record::Inline
) {
312 if (auto record
= InlineRecord::parse(*It
)) {
313 if (record
->InlineNestLevel
== 0 ||
314 record
->InlineNestLevel
<= last_added_nest_level
+ 1) {
315 last_added_nest_level
= record
->InlineNestLevel
;
316 BlockSP block_sp
= std::make_shared
<Block
>(It
.GetBookmark().offset
);
317 FileSpec callsite_file
;
318 if (record
->CallSiteFileNum
< m_files
->size())
319 callsite_file
= (*m_files
)[record
->CallSiteFileNum
];
320 llvm::StringRef name
;
321 if (record
->OriginNum
< m_inline_origins
->size())
322 name
= (*m_inline_origins
)[record
->OriginNum
];
324 Declaration
callsite(callsite_file
, record
->CallSiteLineNum
);
325 block_sp
->SetInlinedFunctionInfo(name
.str().c_str(),
327 /*decl_ptr=*/nullptr, &callsite
);
328 for (const auto &range
: record
->Ranges
) {
330 Block::Range(range
.first
- func_base
, range
.second
));
332 block_sp
->FinalizeRanges();
334 blocks
[record
->InlineNestLevel
]->AddChild(block_sp
);
335 if (record
->InlineNestLevel
+ 1 >= blocks
.size()) {
336 blocks
.resize(blocks
.size() + 1);
338 blocks
[record
->InlineNestLevel
+ 1] = block_sp
.get();
347 void SymbolFileBreakpad::ParseInlineOriginRecords() {
348 if (m_inline_origins
)
350 m_inline_origins
.emplace();
352 Log
*log
= GetLog(LLDBLog::Symbols
);
353 for (llvm::StringRef line
: lines(Record::InlineOrigin
)) {
354 auto record
= InlineOriginRecord::parse(line
);
356 LLDB_LOG(log
, "Failed to parse: {0}. Skipping record.", line
);
360 if (record
->Number
>= m_inline_origins
->size())
361 m_inline_origins
->resize(record
->Number
+ 1);
362 (*m_inline_origins
)[record
->Number
] = record
->Name
;
367 SymbolFileBreakpad::ResolveSymbolContext(const Address
&so_addr
,
368 SymbolContextItem resolve_scope
,
370 std::lock_guard
<std::recursive_mutex
> guard(GetModuleMutex());
371 if (!(resolve_scope
& (eSymbolContextCompUnit
| eSymbolContextLineEntry
|
372 eSymbolContextFunction
| eSymbolContextBlock
)))
377 m_cu_data
->FindEntryIndexThatContains(so_addr
.GetFileAddress());
378 if (idx
== UINT32_MAX
)
381 sc
.comp_unit
= GetCompileUnitAtIndex(idx
).get();
382 SymbolContextItem result
= eSymbolContextCompUnit
;
383 if (resolve_scope
& eSymbolContextLineEntry
) {
384 if (sc
.comp_unit
->GetLineTable()->FindLineEntryByAddress(so_addr
,
386 result
|= eSymbolContextLineEntry
;
390 if (resolve_scope
& (eSymbolContextFunction
| eSymbolContextBlock
)) {
391 FunctionSP func_sp
= GetOrCreateFunction(*sc
.comp_unit
);
393 sc
.function
= func_sp
.get();
394 result
|= eSymbolContextFunction
;
395 if (resolve_scope
& eSymbolContextBlock
) {
396 Block
&block
= func_sp
->GetBlock(true);
397 sc
.block
= block
.FindInnermostBlockByOffset(
398 so_addr
.GetFileAddress() -
399 sc
.function
->GetAddressRange().GetBaseAddress().GetFileAddress());
401 result
|= eSymbolContextBlock
;
409 uint32_t SymbolFileBreakpad::ResolveSymbolContext(
410 const SourceLocationSpec
&src_location_spec
,
411 lldb::SymbolContextItem resolve_scope
, SymbolContextList
&sc_list
) {
412 std::lock_guard
<std::recursive_mutex
> guard(GetModuleMutex());
413 if (!(resolve_scope
& eSymbolContextCompUnit
))
416 uint32_t old_size
= sc_list
.GetSize();
417 for (size_t i
= 0, size
= GetNumCompileUnits(); i
< size
; ++i
) {
418 CompileUnit
&cu
= *GetCompileUnitAtIndex(i
);
419 cu
.ResolveSymbolContext(src_location_spec
, resolve_scope
, sc_list
);
421 return sc_list
.GetSize() - old_size
;
424 void SymbolFileBreakpad::FindFunctions(
425 const Module::LookupInfo
&lookup_info
,
426 const CompilerDeclContext
&parent_decl_ctx
, bool include_inlines
,
427 SymbolContextList
&sc_list
) {
428 std::lock_guard
<std::recursive_mutex
> guard(GetModuleMutex());
429 // TODO: Implement this with supported FunctionNameType.
431 ConstString name
= lookup_info
.GetLookupName();
432 for (uint32_t i
= 0; i
< GetNumCompileUnits(); ++i
) {
433 CompUnitSP cu_sp
= GetCompileUnitAtIndex(i
);
434 FunctionSP func_sp
= GetOrCreateFunction(*cu_sp
);
435 if (func_sp
&& name
== func_sp
->GetNameNoArguments()) {
437 sc
.comp_unit
= cu_sp
.get();
438 sc
.function
= func_sp
.get();
439 sc
.module_sp
= func_sp
->CalculateSymbolContextModule();
445 void SymbolFileBreakpad::FindFunctions(const RegularExpression
®ex
,
446 bool include_inlines
,
447 SymbolContextList
&sc_list
) {
451 void SymbolFileBreakpad::FindTypes(
452 ConstString name
, const CompilerDeclContext
&parent_decl_ctx
,
453 uint32_t max_matches
, llvm::DenseSet
<SymbolFile
*> &searched_symbol_files
,
456 void SymbolFileBreakpad::FindTypes(
457 llvm::ArrayRef
<CompilerContext
> pattern
, LanguageSet languages
,
458 llvm::DenseSet
<SymbolFile
*> &searched_symbol_files
, TypeMap
&types
) {}
460 void SymbolFileBreakpad::AddSymbols(Symtab
&symtab
) {
461 Log
*log
= GetLog(LLDBLog::Symbols
);
462 Module
&module
= *m_objfile_sp
->GetModule();
463 addr_t base
= GetBaseFileAddress();
464 if (base
== LLDB_INVALID_ADDRESS
) {
465 LLDB_LOG(log
, "Unable to fetch the base address of object file. Skipping "
466 "symtab population.");
470 const SectionList
&list
= *module
.GetSectionList();
471 llvm::DenseSet
<addr_t
> found_symbol_addresses
;
472 std::vector
<Symbol
> symbols
;
473 auto add_symbol
= [&](addr_t address
, std::optional
<addr_t
> size
,
474 llvm::StringRef name
) {
476 SectionSP section_sp
= list
.FindSectionContainingFileAddress(address
);
479 "Ignoring symbol {0}, whose address ({1}) is outside of the "
480 "object file. Mismatched symbol file?",
484 // Keep track of what addresses were already added so far and only add
485 // the symbol with the first address.
486 if (!found_symbol_addresses
.insert(address
).second
)
488 symbols
.emplace_back(
489 /*symID*/ 0, Mangled(name
), eSymbolTypeCode
,
490 /*is_global*/ true, /*is_debug*/ false,
491 /*is_trampoline*/ false, /*is_artificial*/ false,
492 AddressRange(section_sp
, address
- section_sp
->GetFileAddress(),
494 size
.has_value(), /*contains_linker_annotations*/ false, /*flags*/ 0);
497 for (llvm::StringRef line
: lines(Record::Public
)) {
498 if (auto record
= PublicRecord::parse(line
))
499 add_symbol(record
->Address
, std::nullopt
, record
->Name
);
501 LLDB_LOG(log
, "Failed to parse: {0}. Skipping record.", line
);
504 for (Symbol
&symbol
: symbols
)
505 symtab
.AddSymbol(std::move(symbol
));
509 llvm::Expected
<lldb::addr_t
>
510 SymbolFileBreakpad::GetParameterStackSize(Symbol
&symbol
) {
512 if (auto *entry
= m_unwind_data
->win
.FindEntryThatContains(
513 symbol
.GetAddress().GetFileAddress())) {
514 auto record
= StackWinRecord::parse(
515 *LineIterator(*m_objfile_sp
, Record::StackWin
, entry
->data
));
517 return record
->ParameterSize
;
519 return llvm::createStringError(llvm::inconvertibleErrorCode(),
520 "Parameter size unknown.");
523 static std::optional
<std::pair
<llvm::StringRef
, llvm::StringRef
>>
524 GetRule(llvm::StringRef
&unwind_rules
) {
525 // Unwind rules are of the form
526 // register1: expression1 register2: expression2 ...
527 // We assume none of the tokens in expression<n> end with a colon.
529 llvm::StringRef lhs
, rest
;
530 std::tie(lhs
, rest
) = getToken(unwind_rules
);
531 if (!lhs
.consume_back(":"))
534 // Seek forward to the next register: expression pair
535 llvm::StringRef::size_type pos
= rest
.find(": ");
536 if (pos
== llvm::StringRef::npos
) {
537 // No pair found, this means the rest of the string is a single expression.
538 unwind_rules
= llvm::StringRef();
539 return std::make_pair(lhs
, rest
);
542 // Go back one token to find the end of the current rule.
543 pos
= rest
.rfind(' ', pos
);
544 if (pos
== llvm::StringRef::npos
)
547 llvm::StringRef rhs
= rest
.take_front(pos
);
548 unwind_rules
= rest
.drop_front(pos
);
549 return std::make_pair(lhs
, rhs
);
552 static const RegisterInfo
*
553 ResolveRegister(const llvm::Triple
&triple
,
554 const SymbolFile::RegisterInfoResolver
&resolver
,
555 llvm::StringRef name
) {
556 if (triple
.isX86() || triple
.isMIPS()) {
557 // X86 and MIPS registers have '$' in front of their register names. Arm and
559 if (!name
.consume_front("$"))
562 return resolver
.ResolveName(name
);
565 static const RegisterInfo
*
566 ResolveRegisterOrRA(const llvm::Triple
&triple
,
567 const SymbolFile::RegisterInfoResolver
&resolver
,
568 llvm::StringRef name
) {
570 return resolver
.ResolveNumber(eRegisterKindGeneric
, LLDB_REGNUM_GENERIC_PC
);
571 return ResolveRegister(triple
, resolver
, name
);
574 llvm::ArrayRef
<uint8_t> SymbolFileBreakpad::SaveAsDWARF(postfix::Node
&node
) {
575 ArchSpec arch
= m_objfile_sp
->GetArchitecture();
576 StreamString
dwarf(Stream::eBinary
, arch
.GetAddressByteSize(),
577 arch
.GetByteOrder());
578 ToDWARF(node
, dwarf
);
579 uint8_t *saved
= m_allocator
.Allocate
<uint8_t>(dwarf
.GetSize());
580 std::memcpy(saved
, dwarf
.GetData(), dwarf
.GetSize());
581 return {saved
, dwarf
.GetSize()};
584 bool SymbolFileBreakpad::ParseCFIUnwindRow(llvm::StringRef unwind_rules
,
585 const RegisterInfoResolver
&resolver
,
586 UnwindPlan::Row
&row
) {
587 Log
*log
= GetLog(LLDBLog::Symbols
);
589 llvm::BumpPtrAllocator node_alloc
;
590 llvm::Triple triple
= m_objfile_sp
->GetArchitecture().GetTriple();
591 while (auto rule
= GetRule(unwind_rules
)) {
593 llvm::StringRef lhs
= rule
->first
;
594 postfix::Node
*rhs
= postfix::ParseOneExpression(rule
->second
, node_alloc
);
596 LLDB_LOG(log
, "Could not parse `{0}` as unwind rhs.", rule
->second
);
600 bool success
= postfix::ResolveSymbols(
601 rhs
, [&](postfix::SymbolNode
&symbol
) -> postfix::Node
* {
602 llvm::StringRef name
= symbol
.GetName();
603 if (name
== ".cfa" && lhs
!= ".cfa")
604 return postfix::MakeNode
<postfix::InitialValueNode
>(node_alloc
);
606 if (const RegisterInfo
*info
=
607 ResolveRegister(triple
, resolver
, name
)) {
608 return postfix::MakeNode
<postfix::RegisterNode
>(
609 node_alloc
, info
->kinds
[eRegisterKindLLDB
]);
615 LLDB_LOG(log
, "Resolving symbols in `{0}` failed.", rule
->second
);
619 llvm::ArrayRef
<uint8_t> saved
= SaveAsDWARF(*rhs
);
621 row
.GetCFAValue().SetIsDWARFExpression(saved
.data(), saved
.size());
622 } else if (const RegisterInfo
*info
=
623 ResolveRegisterOrRA(triple
, resolver
, lhs
)) {
624 UnwindPlan::Row::RegisterLocation loc
;
625 loc
.SetIsDWARFExpression(saved
.data(), saved
.size());
626 row
.SetRegisterInfo(info
->kinds
[eRegisterKindLLDB
], loc
);
628 LLDB_LOG(log
, "Invalid register `{0}` in unwind rule.", lhs
);
630 if (unwind_rules
.empty())
633 LLDB_LOG(log
, "Could not parse `{0}` as an unwind rule.", unwind_rules
);
638 SymbolFileBreakpad::GetUnwindPlan(const Address
&address
,
639 const RegisterInfoResolver
&resolver
) {
642 m_unwind_data
->cfi
.FindEntryThatContains(address
.GetFileAddress()))
643 return ParseCFIUnwindPlan(entry
->data
, resolver
);
645 m_unwind_data
->win
.FindEntryThatContains(address
.GetFileAddress()))
646 return ParseWinUnwindPlan(entry
->data
, resolver
);
651 SymbolFileBreakpad::ParseCFIUnwindPlan(const Bookmark
&bookmark
,
652 const RegisterInfoResolver
&resolver
) {
653 addr_t base
= GetBaseFileAddress();
654 if (base
== LLDB_INVALID_ADDRESS
)
657 LineIterator
It(*m_objfile_sp
, Record::StackCFI
, bookmark
),
659 std::optional
<StackCFIRecord
> init_record
= StackCFIRecord::parse(*It
);
660 assert(init_record
&& init_record
->Size
&&
661 "Record already parsed successfully in ParseUnwindData!");
663 auto plan_sp
= std::make_shared
<UnwindPlan
>(lldb::eRegisterKindLLDB
);
664 plan_sp
->SetSourceName("breakpad STACK CFI");
665 plan_sp
->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo
);
666 plan_sp
->SetUnwindPlanForSignalTrap(eLazyBoolNo
);
667 plan_sp
->SetSourcedFromCompiler(eLazyBoolYes
);
668 plan_sp
->SetPlanValidAddressRange(
669 AddressRange(base
+ init_record
->Address
, *init_record
->Size
,
670 m_objfile_sp
->GetModule()->GetSectionList()));
672 auto row_sp
= std::make_shared
<UnwindPlan::Row
>();
673 row_sp
->SetOffset(0);
674 if (!ParseCFIUnwindRow(init_record
->UnwindRules
, resolver
, *row_sp
))
676 plan_sp
->AppendRow(row_sp
);
677 for (++It
; It
!= End
; ++It
) {
678 std::optional
<StackCFIRecord
> record
= StackCFIRecord::parse(*It
);
684 row_sp
= std::make_shared
<UnwindPlan::Row
>(*row_sp
);
685 row_sp
->SetOffset(record
->Address
- init_record
->Address
);
686 if (!ParseCFIUnwindRow(record
->UnwindRules
, resolver
, *row_sp
))
688 plan_sp
->AppendRow(row_sp
);
694 SymbolFileBreakpad::ParseWinUnwindPlan(const Bookmark
&bookmark
,
695 const RegisterInfoResolver
&resolver
) {
696 Log
*log
= GetLog(LLDBLog::Symbols
);
697 addr_t base
= GetBaseFileAddress();
698 if (base
== LLDB_INVALID_ADDRESS
)
701 LineIterator
It(*m_objfile_sp
, Record::StackWin
, bookmark
);
702 std::optional
<StackWinRecord
> record
= StackWinRecord::parse(*It
);
703 assert(record
&& "Record already parsed successfully in ParseUnwindData!");
705 auto plan_sp
= std::make_shared
<UnwindPlan
>(lldb::eRegisterKindLLDB
);
706 plan_sp
->SetSourceName("breakpad STACK WIN");
707 plan_sp
->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo
);
708 plan_sp
->SetUnwindPlanForSignalTrap(eLazyBoolNo
);
709 plan_sp
->SetSourcedFromCompiler(eLazyBoolYes
);
710 plan_sp
->SetPlanValidAddressRange(
711 AddressRange(base
+ record
->RVA
, record
->CodeSize
,
712 m_objfile_sp
->GetModule()->GetSectionList()));
714 auto row_sp
= std::make_shared
<UnwindPlan::Row
>();
715 row_sp
->SetOffset(0);
717 llvm::BumpPtrAllocator node_alloc
;
718 std::vector
<std::pair
<llvm::StringRef
, postfix::Node
*>> program
=
719 postfix::ParseFPOProgram(record
->ProgramString
, node_alloc
);
721 if (program
.empty()) {
722 LLDB_LOG(log
, "Invalid unwind rule: {0}.", record
->ProgramString
);
725 auto it
= program
.begin();
726 llvm::Triple triple
= m_objfile_sp
->GetArchitecture().GetTriple();
727 const auto &symbol_resolver
=
728 [&](postfix::SymbolNode
&symbol
) -> postfix::Node
* {
729 llvm::StringRef name
= symbol
.GetName();
730 for (const auto &rule
: llvm::make_range(program
.begin(), it
)) {
731 if (rule
.first
== name
)
734 if (const RegisterInfo
*info
= ResolveRegister(triple
, resolver
, name
))
735 return postfix::MakeNode
<postfix::RegisterNode
>(
736 node_alloc
, info
->kinds
[eRegisterKindLLDB
]);
740 // We assume the first value will be the CFA. It is usually called T0, but
741 // clang will use T1, if it needs to realign the stack.
742 auto *symbol
= llvm::dyn_cast
<postfix::SymbolNode
>(it
->second
);
743 if (symbol
&& symbol
->GetName() == ".raSearch") {
744 row_sp
->GetCFAValue().SetRaSearch(record
->LocalSize
+
745 record
->SavedRegisterSize
);
747 if (!postfix::ResolveSymbols(it
->second
, symbol_resolver
)) {
748 LLDB_LOG(log
, "Resolving symbols in `{0}` failed.",
749 record
->ProgramString
);
752 llvm::ArrayRef
<uint8_t> saved
= SaveAsDWARF(*it
->second
);
753 row_sp
->GetCFAValue().SetIsDWARFExpression(saved
.data(), saved
.size());
756 // Replace the node value with InitialValueNode, so that subsequent
757 // expressions refer to the CFA value instead of recomputing the whole
759 it
->second
= postfix::MakeNode
<postfix::InitialValueNode
>(node_alloc
);
762 // Now process the rest of the assignments.
763 for (++it
; it
!= program
.end(); ++it
) {
764 const RegisterInfo
*info
= ResolveRegister(triple
, resolver
, it
->first
);
765 // It is not an error if the resolution fails because the program may
766 // contain temporary variables.
769 if (!postfix::ResolveSymbols(it
->second
, symbol_resolver
)) {
770 LLDB_LOG(log
, "Resolving symbols in `{0}` failed.",
771 record
->ProgramString
);
775 llvm::ArrayRef
<uint8_t> saved
= SaveAsDWARF(*it
->second
);
776 UnwindPlan::Row::RegisterLocation loc
;
777 loc
.SetIsDWARFExpression(saved
.data(), saved
.size());
778 row_sp
->SetRegisterInfo(info
->kinds
[eRegisterKindLLDB
], loc
);
781 plan_sp
->AppendRow(row_sp
);
785 addr_t
SymbolFileBreakpad::GetBaseFileAddress() {
786 return m_objfile_sp
->GetModule()
792 // Parse out all the FILE records from the breakpad file. These will be needed
793 // when constructing the support file lists for individual compile units.
794 void SymbolFileBreakpad::ParseFileRecords() {
799 Log
*log
= GetLog(LLDBLog::Symbols
);
800 for (llvm::StringRef line
: lines(Record::File
)) {
801 auto record
= FileRecord::parse(line
);
803 LLDB_LOG(log
, "Failed to parse: {0}. Skipping record.", line
);
807 if (record
->Number
>= m_files
->size())
808 m_files
->resize(record
->Number
+ 1);
809 FileSpec::Style style
= FileSpec::GuessPathStyle(record
->Name
)
810 .value_or(FileSpec::Style::native
);
811 (*m_files
)[record
->Number
] = FileSpec(record
->Name
, style
);
815 void SymbolFileBreakpad::ParseCUData() {
820 Log
*log
= GetLog(LLDBLog::Symbols
);
821 addr_t base
= GetBaseFileAddress();
822 if (base
== LLDB_INVALID_ADDRESS
) {
823 LLDB_LOG(log
, "SymbolFile parsing failed: Unable to fetch the base address "
827 // We shall create one compile unit for each FUNC record. So, count the number
828 // of FUNC records, and store them in m_cu_data, together with their ranges.
829 for (LineIterator
It(*m_objfile_sp
, Record::Func
), End(*m_objfile_sp
);
831 if (auto record
= FuncRecord::parse(*It
)) {
832 m_cu_data
->Append(CompUnitMap::Entry(base
+ record
->Address
, record
->Size
,
833 CompUnitData(It
.GetBookmark())));
835 LLDB_LOG(log
, "Failed to parse: {0}. Skipping record.", *It
);
840 // Construct the list of support files and line table entries for the given
842 void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit
&cu
,
843 CompUnitData
&data
) {
844 addr_t base
= GetBaseFileAddress();
845 assert(base
!= LLDB_INVALID_ADDRESS
&&
846 "How did we create compile units without a base address?");
849 std::vector
<std::unique_ptr
<LineSequence
>> sequences
;
850 std::unique_ptr
<LineSequence
> line_seq_up
=
851 LineTable::CreateLineSequenceContainer();
852 std::optional
<addr_t
> next_addr
;
853 auto finish_sequence
= [&]() {
854 LineTable::AppendLineEntryToSequence(
855 line_seq_up
.get(), *next_addr
, /*line=*/0, /*column=*/0,
856 /*file_idx=*/0, /*is_start_of_statement=*/false,
857 /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false,
858 /*is_epilogue_begin=*/false, /*is_terminal_entry=*/true);
859 sequences
.push_back(std::move(line_seq_up
));
860 line_seq_up
= LineTable::CreateLineSequenceContainer();
863 LineIterator
It(*m_objfile_sp
, Record::Func
, data
.bookmark
),
865 assert(Record::classify(*It
) == Record::Func
);
866 for (++It
; It
!= End
; ++It
) {
867 // Skip INLINE records
868 if (Record::classify(*It
) == Record::Inline
)
871 auto record
= LineRecord::parse(*It
);
875 record
->Address
+= base
;
877 if (next_addr
&& *next_addr
!= record
->Address
) {
878 // Discontiguous entries. Finish off the previous sequence and reset.
881 LineTable::AppendLineEntryToSequence(
882 line_seq_up
.get(), record
->Address
, record
->LineNum
, /*column=*/0,
883 map
[record
->FileNum
], /*is_start_of_statement=*/true,
884 /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false,
885 /*is_epilogue_begin=*/false, /*is_terminal_entry=*/false);
886 next_addr
= record
->Address
+ record
->Size
;
890 data
.line_table_up
= std::make_unique
<LineTable
>(&cu
, std::move(sequences
));
891 data
.support_files
= map
.translate(cu
.GetPrimaryFile(), *m_files
);
894 void SymbolFileBreakpad::ParseUnwindData() {
897 m_unwind_data
.emplace();
899 Log
*log
= GetLog(LLDBLog::Symbols
);
900 addr_t base
= GetBaseFileAddress();
901 if (base
== LLDB_INVALID_ADDRESS
) {
902 LLDB_LOG(log
, "SymbolFile parsing failed: Unable to fetch the base address "
906 for (LineIterator
It(*m_objfile_sp
, Record::StackCFI
), End(*m_objfile_sp
);
908 if (auto record
= StackCFIRecord::parse(*It
)) {
910 m_unwind_data
->cfi
.Append(UnwindMap::Entry(
911 base
+ record
->Address
, *record
->Size
, It
.GetBookmark()));
913 LLDB_LOG(log
, "Failed to parse: {0}. Skipping record.", *It
);
915 m_unwind_data
->cfi
.Sort();
917 for (LineIterator
It(*m_objfile_sp
, Record::StackWin
), End(*m_objfile_sp
);
919 if (auto record
= StackWinRecord::parse(*It
)) {
920 m_unwind_data
->win
.Append(UnwindMap::Entry(
921 base
+ record
->RVA
, record
->CodeSize
, It
.GetBookmark()));
923 LLDB_LOG(log
, "Failed to parse: {0}. Skipping record.", *It
);
925 m_unwind_data
->win
.Sort();
928 uint64_t SymbolFileBreakpad::GetDebugInfoSize() {
929 // Breakpad files are all debug info.
930 return m_objfile_sp
->GetByteSize();