1 //===-- ObjectFileBreakpad.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/ObjectFile/Breakpad/ObjectFileBreakpad.h"
10 #include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"
11 #include "lldb/Core/ModuleSpec.h"
12 #include "lldb/Core/PluginManager.h"
13 #include "lldb/Core/Section.h"
17 using namespace lldb_private
;
18 using namespace lldb_private::breakpad
;
20 LLDB_PLUGIN_DEFINE(ObjectFileBreakpad
)
26 static std::optional
<Header
> parse(llvm::StringRef text
);
30 std::optional
<Header
> Header::parse(llvm::StringRef text
) {
32 std::tie(line
, text
) = text
.split('\n');
33 auto Module
= ModuleRecord::parse(line
);
38 triple
.setArch(Module
->Arch
);
39 triple
.setOS(Module
->OS
);
41 std::tie(line
, text
) = text
.split('\n');
43 auto Info
= InfoRecord::parse(line
);
44 UUID uuid
= Info
&& Info
->ID
? Info
->ID
: Module
->ID
;
45 return Header
{ArchSpec(triple
), std::move(uuid
)};
48 char ObjectFileBreakpad::ID
;
50 void ObjectFileBreakpad::Initialize() {
51 PluginManager::RegisterPlugin(GetPluginNameStatic(),
52 GetPluginDescriptionStatic(), CreateInstance
,
53 CreateMemoryInstance
, GetModuleSpecifications
);
56 void ObjectFileBreakpad::Terminate() {
57 PluginManager::UnregisterPlugin(CreateInstance
);
60 ObjectFile
*ObjectFileBreakpad::CreateInstance(
61 const ModuleSP
&module_sp
, DataBufferSP data_sp
, offset_t data_offset
,
62 const FileSpec
*file
, offset_t file_offset
, offset_t length
) {
64 data_sp
= MapFileData(*file
, length
, file_offset
);
69 auto text
= toStringRef(data_sp
->GetData());
70 std::optional
<Header
> header
= Header::parse(text
);
74 // Update the data to contain the entire file if it doesn't already
75 if (data_sp
->GetByteSize() < length
) {
76 data_sp
= MapFileData(*file
, length
, file_offset
);
82 return new ObjectFileBreakpad(module_sp
, data_sp
, data_offset
, file
,
83 file_offset
, length
, std::move(header
->arch
),
84 std::move(header
->uuid
));
87 ObjectFile
*ObjectFileBreakpad::CreateMemoryInstance(
88 const ModuleSP
&module_sp
, WritableDataBufferSP data_sp
,
89 const ProcessSP
&process_sp
, addr_t header_addr
) {
93 size_t ObjectFileBreakpad::GetModuleSpecifications(
94 const FileSpec
&file
, DataBufferSP
&data_sp
, offset_t data_offset
,
95 offset_t file_offset
, offset_t length
, ModuleSpecList
&specs
) {
96 auto text
= toStringRef(data_sp
->GetData());
97 std::optional
<Header
> header
= Header::parse(text
);
100 ModuleSpec
spec(file
, std::move(header
->arch
));
101 spec
.GetUUID() = std::move(header
->uuid
);
106 ObjectFileBreakpad::ObjectFileBreakpad(const ModuleSP
&module_sp
,
107 DataBufferSP
&data_sp
,
108 offset_t data_offset
,
109 const FileSpec
*file
, offset_t offset
,
110 offset_t length
, ArchSpec arch
,
112 : ObjectFile(module_sp
, file
, offset
, length
, data_sp
, data_offset
),
113 m_arch(std::move(arch
)), m_uuid(std::move(uuid
)) {}
115 bool ObjectFileBreakpad::ParseHeader() {
116 // We already parsed the header during initialization.
120 void ObjectFileBreakpad::ParseSymtab(Symtab
&symtab
) {
121 // Nothing to do for breakpad files, all information is parsed as debug info
122 // which means "lldb_private::Function" objects are used, or symbols are added
123 // by the SymbolFileBreakpad::AddSymbols(...) function in the symbol file.
126 void ObjectFileBreakpad::CreateSections(SectionList
&unified_section_list
) {
129 m_sections_up
= std::make_unique
<SectionList
>();
131 std::optional
<Record::Kind
> current_section
;
132 offset_t section_start
;
133 llvm::StringRef text
= toStringRef(m_data
.GetData());
134 uint32_t next_section_id
= 1;
135 auto maybe_add_section
= [&](const uint8_t *end_ptr
) {
136 if (!current_section
)
137 return; // We have been called before parsing the first line.
139 offset_t end_offset
= end_ptr
- m_data
.GetDataStart();
140 auto section_sp
= std::make_shared
<Section
>(
141 GetModule(), this, next_section_id
++,
142 ConstString(toString(*current_section
)), eSectionTypeOther
,
143 /*file_vm_addr*/ 0, /*vm_size*/ 0, section_start
,
144 end_offset
- section_start
, /*log2align*/ 0, /*flags*/ 0);
145 m_sections_up
->AddSection(section_sp
);
146 unified_section_list
.AddSection(section_sp
);
148 while (!text
.empty()) {
149 llvm::StringRef line
;
150 std::tie(line
, text
) = text
.split('\n');
152 std::optional
<Record::Kind
> next_section
= Record::classify(line
);
153 if (next_section
== Record::Line
|| next_section
== Record::Inline
) {
154 // Line/Inline records logically belong to the preceding Func record, so
155 // we put them in the same section.
156 next_section
= Record::Func
;
158 if (next_section
== current_section
)
161 // Changing sections, finish off the previous one, if there was any.
162 maybe_add_section(line
.bytes_begin());
163 // And start a new one.
164 current_section
= next_section
;
165 section_start
= line
.bytes_begin() - m_data
.GetDataStart();
167 // Finally, add the last section.
168 maybe_add_section(m_data
.GetDataEnd());