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
>(
220 m_objfile_sp
->GetModule(),
221 /*user_data*/ nullptr, std::make_shared
<SupportFile
>(spec
), index
,
222 eLanguageTypeUnknown
,
223 /*is_optimized*/ eLazyBoolNo
);
225 SetCompileUnitAtIndex(index
, cu_sp
);
229 FunctionSP
SymbolFileBreakpad::GetOrCreateFunction(CompileUnit
&comp_unit
) {
230 user_id_t id
= comp_unit
.GetID();
231 if (FunctionSP func_sp
= comp_unit
.FindFunctionByUID(id
))
234 Log
*log
= GetLog(LLDBLog::Symbols
);
236 addr_t base
= GetBaseFileAddress();
237 if (base
== LLDB_INVALID_ADDRESS
) {
238 LLDB_LOG(log
, "Unable to fetch the base address of object file. Skipping "
239 "symtab population.");
243 const SectionList
*list
= comp_unit
.GetModule()->GetSectionList();
244 CompUnitData
&data
= m_cu_data
->GetEntryRef(id
).data
;
245 LineIterator
It(*m_objfile_sp
, Record::Func
, data
.bookmark
);
246 assert(Record::classify(*It
) == Record::Func
);
248 if (auto record
= FuncRecord::parse(*It
)) {
250 func_name
.SetValue(ConstString(record
->Name
));
251 addr_t address
= record
->Address
+ base
;
252 SectionSP section_sp
= list
->FindSectionContainingFileAddress(address
);
254 AddressRange
func_range(
255 section_sp
, address
- section_sp
->GetFileAddress(), record
->Size
);
256 // Use the CU's id because every CU has only one function inside.
257 func_sp
= std::make_shared
<Function
>(&comp_unit
, id
, 0, func_name
,
258 nullptr, AddressRanges
{func_range
});
259 comp_unit
.AddFunction(func_sp
);
265 size_t SymbolFileBreakpad::ParseFunctions(CompileUnit
&comp_unit
) {
266 std::lock_guard
<std::recursive_mutex
> guard(GetModuleMutex());
267 return GetOrCreateFunction(comp_unit
) ? 1 : 0;
270 bool SymbolFileBreakpad::ParseLineTable(CompileUnit
&comp_unit
) {
271 std::lock_guard
<std::recursive_mutex
> guard(GetModuleMutex());
272 CompUnitData
&data
= m_cu_data
->GetEntryRef(comp_unit
.GetID()).data
;
274 if (!data
.line_table_up
)
275 ParseLineTableAndSupportFiles(comp_unit
, data
);
277 comp_unit
.SetLineTable(data
.line_table_up
.release());
281 bool SymbolFileBreakpad::ParseSupportFiles(CompileUnit
&comp_unit
,
282 SupportFileList
&support_files
) {
283 std::lock_guard
<std::recursive_mutex
> guard(GetModuleMutex());
284 CompUnitData
&data
= m_cu_data
->GetEntryRef(comp_unit
.GetID()).data
;
285 if (!data
.support_files
)
286 ParseLineTableAndSupportFiles(comp_unit
, data
);
288 for (auto &fs
: *data
.support_files
)
289 support_files
.Append(fs
);
293 size_t SymbolFileBreakpad::ParseBlocksRecursive(Function
&func
) {
294 std::lock_guard
<std::recursive_mutex
> guard(GetModuleMutex());
295 CompileUnit
*comp_unit
= func
.GetCompileUnit();
296 lldbassert(comp_unit
);
297 ParseInlineOriginRecords();
298 // A vector of current each level's parent block. For example, when parsing
299 // "INLINE 0 ...", the current level is 0 and its parent block is the
300 // function block at index 0.
301 std::vector
<Block
*> blocks
;
302 Block
&block
= func
.GetBlock(false);
303 block
.AddRange(Block::Range(0, func
.GetAddressRange().GetByteSize()));
304 blocks
.push_back(&block
);
306 size_t blocks_added
= 0;
307 addr_t func_base
= func
.GetAddressRange().GetBaseAddress().GetOffset();
308 CompUnitData
&data
= m_cu_data
->GetEntryRef(comp_unit
->GetID()).data
;
309 LineIterator
It(*m_objfile_sp
, Record::Func
, data
.bookmark
),
311 ++It
; // Skip the FUNC record.
312 size_t last_added_nest_level
= 0;
313 while (It
!= End
&& Record::classify(*It
) == Record::Inline
) {
314 if (auto record
= InlineRecord::parse(*It
)) {
315 if (record
->InlineNestLevel
== 0 ||
316 record
->InlineNestLevel
<= last_added_nest_level
+ 1) {
317 last_added_nest_level
= record
->InlineNestLevel
;
318 BlockSP block_sp
= std::make_shared
<Block
>(It
.GetBookmark().offset
);
319 FileSpec callsite_file
;
320 if (record
->CallSiteFileNum
< m_files
->size())
321 callsite_file
= (*m_files
)[record
->CallSiteFileNum
];
322 llvm::StringRef name
;
323 if (record
->OriginNum
< m_inline_origins
->size())
324 name
= (*m_inline_origins
)[record
->OriginNum
];
326 Declaration
callsite(callsite_file
, record
->CallSiteLineNum
);
327 block_sp
->SetInlinedFunctionInfo(name
.str().c_str(),
329 /*decl_ptr=*/nullptr, &callsite
);
330 for (const auto &range
: record
->Ranges
) {
332 Block::Range(range
.first
- func_base
, range
.second
));
334 block_sp
->FinalizeRanges();
336 blocks
[record
->InlineNestLevel
]->AddChild(block_sp
);
337 if (record
->InlineNestLevel
+ 1 >= blocks
.size()) {
338 blocks
.resize(blocks
.size() + 1);
340 blocks
[record
->InlineNestLevel
+ 1] = block_sp
.get();
349 void SymbolFileBreakpad::ParseInlineOriginRecords() {
350 if (m_inline_origins
)
352 m_inline_origins
.emplace();
354 Log
*log
= GetLog(LLDBLog::Symbols
);
355 for (llvm::StringRef line
: lines(Record::InlineOrigin
)) {
356 auto record
= InlineOriginRecord::parse(line
);
358 LLDB_LOG(log
, "Failed to parse: {0}. Skipping record.", line
);
362 if (record
->Number
>= m_inline_origins
->size())
363 m_inline_origins
->resize(record
->Number
+ 1);
364 (*m_inline_origins
)[record
->Number
] = record
->Name
;
369 SymbolFileBreakpad::ResolveSymbolContext(const Address
&so_addr
,
370 SymbolContextItem resolve_scope
,
372 std::lock_guard
<std::recursive_mutex
> guard(GetModuleMutex());
373 if (!(resolve_scope
& (eSymbolContextCompUnit
| eSymbolContextLineEntry
|
374 eSymbolContextFunction
| eSymbolContextBlock
)))
379 m_cu_data
->FindEntryIndexThatContains(so_addr
.GetFileAddress());
380 if (idx
== UINT32_MAX
)
383 sc
.comp_unit
= GetCompileUnitAtIndex(idx
).get();
384 SymbolContextItem result
= eSymbolContextCompUnit
;
385 if (resolve_scope
& eSymbolContextLineEntry
) {
386 if (sc
.comp_unit
->GetLineTable()->FindLineEntryByAddress(so_addr
,
388 result
|= eSymbolContextLineEntry
;
392 if (resolve_scope
& (eSymbolContextFunction
| eSymbolContextBlock
)) {
393 FunctionSP func_sp
= GetOrCreateFunction(*sc
.comp_unit
);
395 sc
.function
= func_sp
.get();
396 result
|= eSymbolContextFunction
;
397 if (resolve_scope
& eSymbolContextBlock
) {
398 Block
&block
= func_sp
->GetBlock(true);
399 sc
.block
= block
.FindInnermostBlockByOffset(
400 so_addr
.GetFileAddress() -
401 sc
.function
->GetAddressRange().GetBaseAddress().GetFileAddress());
403 result
|= eSymbolContextBlock
;
411 uint32_t SymbolFileBreakpad::ResolveSymbolContext(
412 const SourceLocationSpec
&src_location_spec
,
413 lldb::SymbolContextItem resolve_scope
, SymbolContextList
&sc_list
) {
414 std::lock_guard
<std::recursive_mutex
> guard(GetModuleMutex());
415 if (!(resolve_scope
& eSymbolContextCompUnit
))
418 uint32_t old_size
= sc_list
.GetSize();
419 for (size_t i
= 0, size
= GetNumCompileUnits(); i
< size
; ++i
) {
420 CompileUnit
&cu
= *GetCompileUnitAtIndex(i
);
421 cu
.ResolveSymbolContext(src_location_spec
, resolve_scope
, sc_list
);
423 return sc_list
.GetSize() - old_size
;
426 void SymbolFileBreakpad::FindFunctions(
427 const Module::LookupInfo
&lookup_info
,
428 const CompilerDeclContext
&parent_decl_ctx
, bool include_inlines
,
429 SymbolContextList
&sc_list
) {
430 std::lock_guard
<std::recursive_mutex
> guard(GetModuleMutex());
431 // TODO: Implement this with supported FunctionNameType.
433 ConstString name
= lookup_info
.GetLookupName();
434 for (uint32_t i
= 0; i
< GetNumCompileUnits(); ++i
) {
435 CompUnitSP cu_sp
= GetCompileUnitAtIndex(i
);
436 FunctionSP func_sp
= GetOrCreateFunction(*cu_sp
);
437 if (func_sp
&& name
== func_sp
->GetNameNoArguments()) {
439 sc
.comp_unit
= cu_sp
.get();
440 sc
.function
= func_sp
.get();
441 sc
.module_sp
= func_sp
->CalculateSymbolContextModule();
447 void SymbolFileBreakpad::FindFunctions(const RegularExpression
®ex
,
448 bool include_inlines
,
449 SymbolContextList
&sc_list
) {
453 void SymbolFileBreakpad::AddSymbols(Symtab
&symtab
) {
454 Log
*log
= GetLog(LLDBLog::Symbols
);
455 Module
&module
= *m_objfile_sp
->GetModule();
456 addr_t base
= GetBaseFileAddress();
457 if (base
== LLDB_INVALID_ADDRESS
) {
458 LLDB_LOG(log
, "Unable to fetch the base address of object file. Skipping "
459 "symtab population.");
463 const SectionList
&list
= *module
.GetSectionList();
464 llvm::DenseSet
<addr_t
> found_symbol_addresses
;
465 std::vector
<Symbol
> symbols
;
466 auto add_symbol
= [&](addr_t address
, std::optional
<addr_t
> size
,
467 llvm::StringRef name
) {
469 SectionSP section_sp
= list
.FindSectionContainingFileAddress(address
);
472 "Ignoring symbol {0}, whose address ({1}) is outside of the "
473 "object file. Mismatched symbol file?",
477 // Keep track of what addresses were already added so far and only add
478 // the symbol with the first address.
479 if (!found_symbol_addresses
.insert(address
).second
)
481 symbols
.emplace_back(
482 /*symID*/ 0, Mangled(name
), eSymbolTypeCode
,
483 /*is_global*/ true, /*is_debug*/ false,
484 /*is_trampoline*/ false, /*is_artificial*/ false,
485 AddressRange(section_sp
, address
- section_sp
->GetFileAddress(),
487 size
.has_value(), /*contains_linker_annotations*/ false, /*flags*/ 0);
490 for (llvm::StringRef line
: lines(Record::Public
)) {
491 if (auto record
= PublicRecord::parse(line
))
492 add_symbol(record
->Address
, std::nullopt
, record
->Name
);
494 LLDB_LOG(log
, "Failed to parse: {0}. Skipping record.", line
);
497 for (Symbol
&symbol
: symbols
)
498 symtab
.AddSymbol(std::move(symbol
));
502 llvm::Expected
<lldb::addr_t
>
503 SymbolFileBreakpad::GetParameterStackSize(Symbol
&symbol
) {
505 if (auto *entry
= m_unwind_data
->win
.FindEntryThatContains(
506 symbol
.GetAddress().GetFileAddress())) {
507 auto record
= StackWinRecord::parse(
508 *LineIterator(*m_objfile_sp
, Record::StackWin
, entry
->data
));
510 return record
->ParameterSize
;
512 return llvm::createStringError(llvm::inconvertibleErrorCode(),
513 "Parameter size unknown.");
516 static std::optional
<std::pair
<llvm::StringRef
, llvm::StringRef
>>
517 GetRule(llvm::StringRef
&unwind_rules
) {
518 // Unwind rules are of the form
519 // register1: expression1 register2: expression2 ...
520 // We assume none of the tokens in expression<n> end with a colon.
522 llvm::StringRef lhs
, rest
;
523 std::tie(lhs
, rest
) = getToken(unwind_rules
);
524 if (!lhs
.consume_back(":"))
527 // Seek forward to the next register: expression pair
528 llvm::StringRef::size_type pos
= rest
.find(": ");
529 if (pos
== llvm::StringRef::npos
) {
530 // No pair found, this means the rest of the string is a single expression.
531 unwind_rules
= llvm::StringRef();
532 return std::make_pair(lhs
, rest
);
535 // Go back one token to find the end of the current rule.
536 pos
= rest
.rfind(' ', pos
);
537 if (pos
== llvm::StringRef::npos
)
540 llvm::StringRef rhs
= rest
.take_front(pos
);
541 unwind_rules
= rest
.drop_front(pos
);
542 return std::make_pair(lhs
, rhs
);
545 static const RegisterInfo
*
546 ResolveRegister(const llvm::Triple
&triple
,
547 const SymbolFile::RegisterInfoResolver
&resolver
,
548 llvm::StringRef name
) {
549 if (triple
.isX86() || triple
.isMIPS()) {
550 // X86 and MIPS registers have '$' in front of their register names. Arm and
552 if (!name
.consume_front("$"))
555 return resolver
.ResolveName(name
);
558 static const RegisterInfo
*
559 ResolveRegisterOrRA(const llvm::Triple
&triple
,
560 const SymbolFile::RegisterInfoResolver
&resolver
,
561 llvm::StringRef name
) {
563 return resolver
.ResolveNumber(eRegisterKindGeneric
, LLDB_REGNUM_GENERIC_PC
);
564 return ResolveRegister(triple
, resolver
, name
);
567 llvm::ArrayRef
<uint8_t> SymbolFileBreakpad::SaveAsDWARF(postfix::Node
&node
) {
568 ArchSpec arch
= m_objfile_sp
->GetArchitecture();
569 StreamString
dwarf(Stream::eBinary
, arch
.GetAddressByteSize(),
570 arch
.GetByteOrder());
571 ToDWARF(node
, dwarf
);
572 uint8_t *saved
= m_allocator
.Allocate
<uint8_t>(dwarf
.GetSize());
573 std::memcpy(saved
, dwarf
.GetData(), dwarf
.GetSize());
574 return {saved
, dwarf
.GetSize()};
577 bool SymbolFileBreakpad::ParseCFIUnwindRow(llvm::StringRef unwind_rules
,
578 const RegisterInfoResolver
&resolver
,
579 UnwindPlan::Row
&row
) {
580 Log
*log
= GetLog(LLDBLog::Symbols
);
582 llvm::BumpPtrAllocator node_alloc
;
583 llvm::Triple triple
= m_objfile_sp
->GetArchitecture().GetTriple();
584 while (auto rule
= GetRule(unwind_rules
)) {
586 llvm::StringRef lhs
= rule
->first
;
587 postfix::Node
*rhs
= postfix::ParseOneExpression(rule
->second
, node_alloc
);
589 LLDB_LOG(log
, "Could not parse `{0}` as unwind rhs.", rule
->second
);
593 bool success
= postfix::ResolveSymbols(
594 rhs
, [&](postfix::SymbolNode
&symbol
) -> postfix::Node
* {
595 llvm::StringRef name
= symbol
.GetName();
596 if (name
== ".cfa" && lhs
!= ".cfa")
597 return postfix::MakeNode
<postfix::InitialValueNode
>(node_alloc
);
599 if (const RegisterInfo
*info
=
600 ResolveRegister(triple
, resolver
, name
)) {
601 return postfix::MakeNode
<postfix::RegisterNode
>(
602 node_alloc
, info
->kinds
[eRegisterKindLLDB
]);
608 LLDB_LOG(log
, "Resolving symbols in `{0}` failed.", rule
->second
);
612 llvm::ArrayRef
<uint8_t> saved
= SaveAsDWARF(*rhs
);
614 row
.GetCFAValue().SetIsDWARFExpression(saved
.data(), saved
.size());
615 } else if (const RegisterInfo
*info
=
616 ResolveRegisterOrRA(triple
, resolver
, lhs
)) {
617 UnwindPlan::Row::AbstractRegisterLocation loc
;
618 loc
.SetIsDWARFExpression(saved
.data(), saved
.size());
619 row
.SetRegisterInfo(info
->kinds
[eRegisterKindLLDB
], loc
);
621 LLDB_LOG(log
, "Invalid register `{0}` in unwind rule.", lhs
);
623 if (unwind_rules
.empty())
626 LLDB_LOG(log
, "Could not parse `{0}` as an unwind rule.", unwind_rules
);
631 SymbolFileBreakpad::GetUnwindPlan(const Address
&address
,
632 const RegisterInfoResolver
&resolver
) {
635 m_unwind_data
->cfi
.FindEntryThatContains(address
.GetFileAddress()))
636 return ParseCFIUnwindPlan(entry
->data
, resolver
);
638 m_unwind_data
->win
.FindEntryThatContains(address
.GetFileAddress()))
639 return ParseWinUnwindPlan(entry
->data
, resolver
);
644 SymbolFileBreakpad::ParseCFIUnwindPlan(const Bookmark
&bookmark
,
645 const RegisterInfoResolver
&resolver
) {
646 addr_t base
= GetBaseFileAddress();
647 if (base
== LLDB_INVALID_ADDRESS
)
650 LineIterator
It(*m_objfile_sp
, Record::StackCFI
, bookmark
),
652 std::optional
<StackCFIRecord
> init_record
= StackCFIRecord::parse(*It
);
653 assert(init_record
&& init_record
->Size
&&
654 "Record already parsed successfully in ParseUnwindData!");
656 auto plan_sp
= std::make_shared
<UnwindPlan
>(lldb::eRegisterKindLLDB
);
657 plan_sp
->SetSourceName("breakpad STACK CFI");
658 plan_sp
->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo
);
659 plan_sp
->SetUnwindPlanForSignalTrap(eLazyBoolNo
);
660 plan_sp
->SetSourcedFromCompiler(eLazyBoolYes
);
661 plan_sp
->SetPlanValidAddressRange(
662 AddressRange(base
+ init_record
->Address
, *init_record
->Size
,
663 m_objfile_sp
->GetModule()->GetSectionList()));
665 auto row_sp
= std::make_shared
<UnwindPlan::Row
>();
666 row_sp
->SetOffset(0);
667 if (!ParseCFIUnwindRow(init_record
->UnwindRules
, resolver
, *row_sp
))
669 plan_sp
->AppendRow(row_sp
);
670 for (++It
; It
!= End
; ++It
) {
671 std::optional
<StackCFIRecord
> record
= StackCFIRecord::parse(*It
);
677 row_sp
= std::make_shared
<UnwindPlan::Row
>(*row_sp
);
678 row_sp
->SetOffset(record
->Address
- init_record
->Address
);
679 if (!ParseCFIUnwindRow(record
->UnwindRules
, resolver
, *row_sp
))
681 plan_sp
->AppendRow(row_sp
);
687 SymbolFileBreakpad::ParseWinUnwindPlan(const Bookmark
&bookmark
,
688 const RegisterInfoResolver
&resolver
) {
689 Log
*log
= GetLog(LLDBLog::Symbols
);
690 addr_t base
= GetBaseFileAddress();
691 if (base
== LLDB_INVALID_ADDRESS
)
694 LineIterator
It(*m_objfile_sp
, Record::StackWin
, bookmark
);
695 std::optional
<StackWinRecord
> record
= StackWinRecord::parse(*It
);
696 assert(record
&& "Record already parsed successfully in ParseUnwindData!");
698 auto plan_sp
= std::make_shared
<UnwindPlan
>(lldb::eRegisterKindLLDB
);
699 plan_sp
->SetSourceName("breakpad STACK WIN");
700 plan_sp
->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo
);
701 plan_sp
->SetUnwindPlanForSignalTrap(eLazyBoolNo
);
702 plan_sp
->SetSourcedFromCompiler(eLazyBoolYes
);
703 plan_sp
->SetPlanValidAddressRange(
704 AddressRange(base
+ record
->RVA
, record
->CodeSize
,
705 m_objfile_sp
->GetModule()->GetSectionList()));
707 auto row_sp
= std::make_shared
<UnwindPlan::Row
>();
708 row_sp
->SetOffset(0);
710 llvm::BumpPtrAllocator node_alloc
;
711 std::vector
<std::pair
<llvm::StringRef
, postfix::Node
*>> program
=
712 postfix::ParseFPOProgram(record
->ProgramString
, node_alloc
);
714 if (program
.empty()) {
715 LLDB_LOG(log
, "Invalid unwind rule: {0}.", record
->ProgramString
);
718 auto it
= program
.begin();
719 llvm::Triple triple
= m_objfile_sp
->GetArchitecture().GetTriple();
720 const auto &symbol_resolver
=
721 [&](postfix::SymbolNode
&symbol
) -> postfix::Node
* {
722 llvm::StringRef name
= symbol
.GetName();
723 for (const auto &rule
: llvm::make_range(program
.begin(), it
)) {
724 if (rule
.first
== name
)
727 if (const RegisterInfo
*info
= ResolveRegister(triple
, resolver
, name
))
728 return postfix::MakeNode
<postfix::RegisterNode
>(
729 node_alloc
, info
->kinds
[eRegisterKindLLDB
]);
733 // We assume the first value will be the CFA. It is usually called T0, but
734 // clang will use T1, if it needs to realign the stack.
735 auto *symbol
= llvm::dyn_cast
<postfix::SymbolNode
>(it
->second
);
736 if (symbol
&& symbol
->GetName() == ".raSearch") {
737 row_sp
->GetCFAValue().SetRaSearch(record
->LocalSize
+
738 record
->SavedRegisterSize
);
740 if (!postfix::ResolveSymbols(it
->second
, symbol_resolver
)) {
741 LLDB_LOG(log
, "Resolving symbols in `{0}` failed.",
742 record
->ProgramString
);
745 llvm::ArrayRef
<uint8_t> saved
= SaveAsDWARF(*it
->second
);
746 row_sp
->GetCFAValue().SetIsDWARFExpression(saved
.data(), saved
.size());
749 // Replace the node value with InitialValueNode, so that subsequent
750 // expressions refer to the CFA value instead of recomputing the whole
752 it
->second
= postfix::MakeNode
<postfix::InitialValueNode
>(node_alloc
);
755 // Now process the rest of the assignments.
756 for (++it
; it
!= program
.end(); ++it
) {
757 const RegisterInfo
*info
= ResolveRegister(triple
, resolver
, it
->first
);
758 // It is not an error if the resolution fails because the program may
759 // contain temporary variables.
762 if (!postfix::ResolveSymbols(it
->second
, symbol_resolver
)) {
763 LLDB_LOG(log
, "Resolving symbols in `{0}` failed.",
764 record
->ProgramString
);
768 llvm::ArrayRef
<uint8_t> saved
= SaveAsDWARF(*it
->second
);
769 UnwindPlan::Row::AbstractRegisterLocation loc
;
770 loc
.SetIsDWARFExpression(saved
.data(), saved
.size());
771 row_sp
->SetRegisterInfo(info
->kinds
[eRegisterKindLLDB
], loc
);
774 plan_sp
->AppendRow(row_sp
);
778 addr_t
SymbolFileBreakpad::GetBaseFileAddress() {
779 return m_objfile_sp
->GetModule()
785 // Parse out all the FILE records from the breakpad file. These will be needed
786 // when constructing the support file lists for individual compile units.
787 void SymbolFileBreakpad::ParseFileRecords() {
792 Log
*log
= GetLog(LLDBLog::Symbols
);
793 for (llvm::StringRef line
: lines(Record::File
)) {
794 auto record
= FileRecord::parse(line
);
796 LLDB_LOG(log
, "Failed to parse: {0}. Skipping record.", line
);
800 if (record
->Number
>= m_files
->size())
801 m_files
->resize(record
->Number
+ 1);
802 FileSpec::Style style
= FileSpec::GuessPathStyle(record
->Name
)
803 .value_or(FileSpec::Style::native
);
804 (*m_files
)[record
->Number
] = FileSpec(record
->Name
, style
);
808 void SymbolFileBreakpad::ParseCUData() {
813 Log
*log
= GetLog(LLDBLog::Symbols
);
814 addr_t base
= GetBaseFileAddress();
815 if (base
== LLDB_INVALID_ADDRESS
) {
816 LLDB_LOG(log
, "SymbolFile parsing failed: Unable to fetch the base address "
820 // We shall create one compile unit for each FUNC record. So, count the number
821 // of FUNC records, and store them in m_cu_data, together with their ranges.
822 for (LineIterator
It(*m_objfile_sp
, Record::Func
), End(*m_objfile_sp
);
824 if (auto record
= FuncRecord::parse(*It
)) {
825 m_cu_data
->Append(CompUnitMap::Entry(base
+ record
->Address
, record
->Size
,
826 CompUnitData(It
.GetBookmark())));
828 LLDB_LOG(log
, "Failed to parse: {0}. Skipping record.", *It
);
833 // Construct the list of support files and line table entries for the given
835 void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit
&cu
,
836 CompUnitData
&data
) {
837 addr_t base
= GetBaseFileAddress();
838 assert(base
!= LLDB_INVALID_ADDRESS
&&
839 "How did we create compile units without a base address?");
842 std::vector
<std::unique_ptr
<LineSequence
>> sequences
;
843 std::unique_ptr
<LineSequence
> line_seq_up
=
844 LineTable::CreateLineSequenceContainer();
845 std::optional
<addr_t
> next_addr
;
846 auto finish_sequence
= [&]() {
847 LineTable::AppendLineEntryToSequence(
848 line_seq_up
.get(), *next_addr
, /*line=*/0, /*column=*/0,
849 /*file_idx=*/0, /*is_start_of_statement=*/false,
850 /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false,
851 /*is_epilogue_begin=*/false, /*is_terminal_entry=*/true);
852 sequences
.push_back(std::move(line_seq_up
));
853 line_seq_up
= LineTable::CreateLineSequenceContainer();
856 LineIterator
It(*m_objfile_sp
, Record::Func
, data
.bookmark
),
858 assert(Record::classify(*It
) == Record::Func
);
859 for (++It
; It
!= End
; ++It
) {
860 // Skip INLINE records
861 if (Record::classify(*It
) == Record::Inline
)
864 auto record
= LineRecord::parse(*It
);
868 record
->Address
+= base
;
870 if (next_addr
&& *next_addr
!= record
->Address
) {
871 // Discontiguous entries. Finish off the previous sequence and reset.
874 LineTable::AppendLineEntryToSequence(
875 line_seq_up
.get(), record
->Address
, record
->LineNum
, /*column=*/0,
876 map
[record
->FileNum
], /*is_start_of_statement=*/true,
877 /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false,
878 /*is_epilogue_begin=*/false, /*is_terminal_entry=*/false);
879 next_addr
= record
->Address
+ record
->Size
;
883 data
.line_table_up
= std::make_unique
<LineTable
>(&cu
, std::move(sequences
));
884 data
.support_files
= map
.translate(cu
.GetPrimaryFile(), *m_files
);
887 void SymbolFileBreakpad::ParseUnwindData() {
890 m_unwind_data
.emplace();
892 Log
*log
= GetLog(LLDBLog::Symbols
);
893 addr_t base
= GetBaseFileAddress();
894 if (base
== LLDB_INVALID_ADDRESS
) {
895 LLDB_LOG(log
, "SymbolFile parsing failed: Unable to fetch the base address "
899 for (LineIterator
It(*m_objfile_sp
, Record::StackCFI
), End(*m_objfile_sp
);
901 if (auto record
= StackCFIRecord::parse(*It
)) {
903 m_unwind_data
->cfi
.Append(UnwindMap::Entry(
904 base
+ record
->Address
, *record
->Size
, It
.GetBookmark()));
906 LLDB_LOG(log
, "Failed to parse: {0}. Skipping record.", *It
);
908 m_unwind_data
->cfi
.Sort();
910 for (LineIterator
It(*m_objfile_sp
, Record::StackWin
), End(*m_objfile_sp
);
912 if (auto record
= StackWinRecord::parse(*It
)) {
913 m_unwind_data
->win
.Append(UnwindMap::Entry(
914 base
+ record
->RVA
, record
->CodeSize
, It
.GetBookmark()));
916 LLDB_LOG(log
, "Failed to parse: {0}. Skipping record.", *It
);
918 m_unwind_data
->win
.Sort();
921 uint64_t SymbolFileBreakpad::GetDebugInfoSize(bool load_all_debug_info
) {
922 // Breakpad files are all debug info.
923 return m_objfile_sp
->GetByteSize();