1cfca06d7SDimitry Andric //===-- ObjectFileBreakpad.cpp --------------------------------------------===//
294994d37SDimitry Andric //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
694994d37SDimitry Andric //
794994d37SDimitry Andric //===----------------------------------------------------------------------===//
894994d37SDimitry Andric
994994d37SDimitry Andric #include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h"
105f29bb8aSDimitry Andric #include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"
1194994d37SDimitry Andric #include "lldb/Core/ModuleSpec.h"
1294994d37SDimitry Andric #include "lldb/Core/PluginManager.h"
1394994d37SDimitry Andric #include "lldb/Core/Section.h"
14e3b55780SDimitry Andric #include <optional>
1594994d37SDimitry Andric
1694994d37SDimitry Andric using namespace lldb;
1794994d37SDimitry Andric using namespace lldb_private;
1894994d37SDimitry Andric using namespace lldb_private::breakpad;
1994994d37SDimitry Andric
20cfca06d7SDimitry Andric LLDB_PLUGIN_DEFINE(ObjectFileBreakpad)
21cfca06d7SDimitry Andric
2294994d37SDimitry Andric namespace {
2394994d37SDimitry Andric struct Header {
2494994d37SDimitry Andric ArchSpec arch;
2594994d37SDimitry Andric UUID uuid;
26e3b55780SDimitry Andric static std::optional<Header> parse(llvm::StringRef text);
2794994d37SDimitry Andric };
2894994d37SDimitry Andric } // namespace
2994994d37SDimitry Andric
parse(llvm::StringRef text)30e3b55780SDimitry Andric std::optional<Header> Header::parse(llvm::StringRef text) {
315f29bb8aSDimitry Andric llvm::StringRef line;
3294994d37SDimitry Andric std::tie(line, text) = text.split('\n');
335f29bb8aSDimitry Andric auto Module = ModuleRecord::parse(line);
345f29bb8aSDimitry Andric if (!Module)
35e3b55780SDimitry Andric return std::nullopt;
3694994d37SDimitry Andric
3794994d37SDimitry Andric llvm::Triple triple;
385f29bb8aSDimitry Andric triple.setArch(Module->Arch);
395f29bb8aSDimitry Andric triple.setOS(Module->OS);
4094994d37SDimitry Andric
4194994d37SDimitry Andric std::tie(line, text) = text.split('\n');
4294994d37SDimitry Andric
435f29bb8aSDimitry Andric auto Info = InfoRecord::parse(line);
445f29bb8aSDimitry Andric UUID uuid = Info && Info->ID ? Info->ID : Module->ID;
455f29bb8aSDimitry Andric return Header{ArchSpec(triple), std::move(uuid)};
4694994d37SDimitry Andric }
4794994d37SDimitry Andric
48ead24645SDimitry Andric char ObjectFileBreakpad::ID;
49ead24645SDimitry Andric
Initialize()5094994d37SDimitry Andric void ObjectFileBreakpad::Initialize() {
5194994d37SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(),
5294994d37SDimitry Andric GetPluginDescriptionStatic(), CreateInstance,
5394994d37SDimitry Andric CreateMemoryInstance, GetModuleSpecifications);
5494994d37SDimitry Andric }
5594994d37SDimitry Andric
Terminate()5694994d37SDimitry Andric void ObjectFileBreakpad::Terminate() {
5794994d37SDimitry Andric PluginManager::UnregisterPlugin(CreateInstance);
5894994d37SDimitry Andric }
5994994d37SDimitry Andric
CreateInstance(const ModuleSP & module_sp,DataBufferSP data_sp,offset_t data_offset,const FileSpec * file,offset_t file_offset,offset_t length)6094994d37SDimitry Andric ObjectFile *ObjectFileBreakpad::CreateInstance(
61145449b1SDimitry Andric const ModuleSP &module_sp, DataBufferSP data_sp, offset_t data_offset,
6294994d37SDimitry Andric const FileSpec *file, offset_t file_offset, offset_t length) {
6394994d37SDimitry Andric if (!data_sp) {
6494994d37SDimitry Andric data_sp = MapFileData(*file, length, file_offset);
6594994d37SDimitry Andric if (!data_sp)
6694994d37SDimitry Andric return nullptr;
6794994d37SDimitry Andric data_offset = 0;
6894994d37SDimitry Andric }
6994994d37SDimitry Andric auto text = toStringRef(data_sp->GetData());
70e3b55780SDimitry Andric std::optional<Header> header = Header::parse(text);
7194994d37SDimitry Andric if (!header)
7294994d37SDimitry Andric return nullptr;
7394994d37SDimitry Andric
7494994d37SDimitry Andric // Update the data to contain the entire file if it doesn't already
7594994d37SDimitry Andric if (data_sp->GetByteSize() < length) {
7694994d37SDimitry Andric data_sp = MapFileData(*file, length, file_offset);
7794994d37SDimitry Andric if (!data_sp)
7894994d37SDimitry Andric return nullptr;
7994994d37SDimitry Andric data_offset = 0;
8094994d37SDimitry Andric }
8194994d37SDimitry Andric
8294994d37SDimitry Andric return new ObjectFileBreakpad(module_sp, data_sp, data_offset, file,
8394994d37SDimitry Andric file_offset, length, std::move(header->arch),
8494994d37SDimitry Andric std::move(header->uuid));
8594994d37SDimitry Andric }
8694994d37SDimitry Andric
CreateMemoryInstance(const ModuleSP & module_sp,WritableDataBufferSP data_sp,const ProcessSP & process_sp,addr_t header_addr)8794994d37SDimitry Andric ObjectFile *ObjectFileBreakpad::CreateMemoryInstance(
88145449b1SDimitry Andric const ModuleSP &module_sp, WritableDataBufferSP data_sp,
8994994d37SDimitry Andric const ProcessSP &process_sp, addr_t header_addr) {
9094994d37SDimitry Andric return nullptr;
9194994d37SDimitry Andric }
9294994d37SDimitry Andric
GetModuleSpecifications(const FileSpec & file,DataBufferSP & data_sp,offset_t data_offset,offset_t file_offset,offset_t length,ModuleSpecList & specs)9394994d37SDimitry Andric size_t ObjectFileBreakpad::GetModuleSpecifications(
9494994d37SDimitry Andric const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
9594994d37SDimitry Andric offset_t file_offset, offset_t length, ModuleSpecList &specs) {
9694994d37SDimitry Andric auto text = toStringRef(data_sp->GetData());
97e3b55780SDimitry Andric std::optional<Header> header = Header::parse(text);
9894994d37SDimitry Andric if (!header)
9994994d37SDimitry Andric return 0;
10094994d37SDimitry Andric ModuleSpec spec(file, std::move(header->arch));
10194994d37SDimitry Andric spec.GetUUID() = std::move(header->uuid);
10294994d37SDimitry Andric specs.Append(spec);
10394994d37SDimitry Andric return 1;
10494994d37SDimitry Andric }
10594994d37SDimitry Andric
ObjectFileBreakpad(const ModuleSP & module_sp,DataBufferSP & data_sp,offset_t data_offset,const FileSpec * file,offset_t offset,offset_t length,ArchSpec arch,UUID uuid)10694994d37SDimitry Andric ObjectFileBreakpad::ObjectFileBreakpad(const ModuleSP &module_sp,
10794994d37SDimitry Andric DataBufferSP &data_sp,
10894994d37SDimitry Andric offset_t data_offset,
10994994d37SDimitry Andric const FileSpec *file, offset_t offset,
11094994d37SDimitry Andric offset_t length, ArchSpec arch,
11194994d37SDimitry Andric UUID uuid)
11294994d37SDimitry Andric : ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
11394994d37SDimitry Andric m_arch(std::move(arch)), m_uuid(std::move(uuid)) {}
11494994d37SDimitry Andric
ParseHeader()11594994d37SDimitry Andric bool ObjectFileBreakpad::ParseHeader() {
11694994d37SDimitry Andric // We already parsed the header during initialization.
11794994d37SDimitry Andric return true;
11894994d37SDimitry Andric }
11994994d37SDimitry Andric
ParseSymtab(Symtab & symtab)120f65dcba8SDimitry Andric void ObjectFileBreakpad::ParseSymtab(Symtab &symtab) {
121f65dcba8SDimitry Andric // Nothing to do for breakpad files, all information is parsed as debug info
122f65dcba8SDimitry Andric // which means "lldb_private::Function" objects are used, or symbols are added
123f65dcba8SDimitry Andric // by the SymbolFileBreakpad::AddSymbols(...) function in the symbol file.
12494994d37SDimitry Andric }
12594994d37SDimitry Andric
CreateSections(SectionList & unified_section_list)12694994d37SDimitry Andric void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) {
1275f29bb8aSDimitry Andric if (m_sections_up)
12894994d37SDimitry Andric return;
129ead24645SDimitry Andric m_sections_up = std::make_unique<SectionList>();
13094994d37SDimitry Andric
131e3b55780SDimitry Andric std::optional<Record::Kind> current_section;
13294994d37SDimitry Andric offset_t section_start;
13394994d37SDimitry Andric llvm::StringRef text = toStringRef(m_data.GetData());
13494994d37SDimitry Andric uint32_t next_section_id = 1;
13594994d37SDimitry Andric auto maybe_add_section = [&](const uint8_t *end_ptr) {
1365f29bb8aSDimitry Andric if (!current_section)
13794994d37SDimitry Andric return; // We have been called before parsing the first line.
13894994d37SDimitry Andric
13994994d37SDimitry Andric offset_t end_offset = end_ptr - m_data.GetDataStart();
14094994d37SDimitry Andric auto section_sp = std::make_shared<Section>(
14194994d37SDimitry Andric GetModule(), this, next_section_id++,
1425f29bb8aSDimitry Andric ConstString(toString(*current_section)), eSectionTypeOther,
14394994d37SDimitry Andric /*file_vm_addr*/ 0, /*vm_size*/ 0, section_start,
14494994d37SDimitry Andric end_offset - section_start, /*log2align*/ 0, /*flags*/ 0);
1455f29bb8aSDimitry Andric m_sections_up->AddSection(section_sp);
14694994d37SDimitry Andric unified_section_list.AddSection(section_sp);
14794994d37SDimitry Andric };
14894994d37SDimitry Andric while (!text.empty()) {
14994994d37SDimitry Andric llvm::StringRef line;
15094994d37SDimitry Andric std::tie(line, text) = text.split('\n');
15194994d37SDimitry Andric
152e3b55780SDimitry Andric std::optional<Record::Kind> next_section = Record::classify(line);
153c0981da4SDimitry Andric if (next_section == Record::Line || next_section == Record::Inline) {
154c0981da4SDimitry Andric // Line/Inline records logically belong to the preceding Func record, so
155c0981da4SDimitry Andric // we put them in the same section.
1565f29bb8aSDimitry Andric next_section = Record::Func;
15794994d37SDimitry Andric }
1585f29bb8aSDimitry Andric if (next_section == current_section)
15994994d37SDimitry Andric continue;
16094994d37SDimitry Andric
16194994d37SDimitry Andric // Changing sections, finish off the previous one, if there was any.
16294994d37SDimitry Andric maybe_add_section(line.bytes_begin());
16394994d37SDimitry Andric // And start a new one.
1645f29bb8aSDimitry Andric current_section = next_section;
16594994d37SDimitry Andric section_start = line.bytes_begin() - m_data.GetDataStart();
16694994d37SDimitry Andric }
16794994d37SDimitry Andric // Finally, add the last section.
16894994d37SDimitry Andric maybe_add_section(m_data.GetDataEnd());
16994994d37SDimitry Andric }
170