170 lines · cpp
1//===-- ObjectFileBreakpad.cpp --------------------------------------------===//2//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-exception6//7//===----------------------------------------------------------------------===//8 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"14#include <optional>15 16using namespace lldb;17using namespace lldb_private;18using namespace lldb_private::breakpad;19 20LLDB_PLUGIN_DEFINE(ObjectFileBreakpad)21 22namespace {23struct Header {24 ArchSpec arch;25 UUID uuid;26 static std::optional<Header> parse(llvm::StringRef text);27};28} // namespace29 30std::optional<Header> Header::parse(llvm::StringRef text) {31 llvm::StringRef line;32 std::tie(line, text) = text.split('\n');33 auto Module = ModuleRecord::parse(line);34 if (!Module)35 return std::nullopt;36 37 llvm::Triple triple;38 triple.setArch(Module->Arch);39 triple.setOS(Module->OS);40 41 std::tie(line, text) = text.split('\n');42 43 auto Info = InfoRecord::parse(line);44 UUID uuid = Info && Info->ID ? Info->ID : Module->ID;45 return Header{ArchSpec(triple), std::move(uuid)};46}47 48char ObjectFileBreakpad::ID;49 50void ObjectFileBreakpad::Initialize() {51 PluginManager::RegisterPlugin(GetPluginNameStatic(),52 GetPluginDescriptionStatic(), CreateInstance,53 CreateMemoryInstance, GetModuleSpecifications);54}55 56void ObjectFileBreakpad::Terminate() {57 PluginManager::UnregisterPlugin(CreateInstance);58}59 60ObjectFile *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) {63 if (!data_sp) {64 data_sp = MapFileData(*file, length, file_offset);65 if (!data_sp)66 return nullptr;67 data_offset = 0;68 }69 auto text = toStringRef(data_sp->GetData());70 std::optional<Header> header = Header::parse(text);71 if (!header)72 return nullptr;73 74 // Update the data to contain the entire file if it doesn't already75 if (data_sp->GetByteSize() < length) {76 data_sp = MapFileData(*file, length, file_offset);77 if (!data_sp)78 return nullptr;79 data_offset = 0;80 }81 82 return new ObjectFileBreakpad(module_sp, data_sp, data_offset, file,83 file_offset, length, std::move(header->arch),84 std::move(header->uuid));85}86 87ObjectFile *ObjectFileBreakpad::CreateMemoryInstance(88 const ModuleSP &module_sp, WritableDataBufferSP data_sp,89 const ProcessSP &process_sp, addr_t header_addr) {90 return nullptr;91}92 93size_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);98 if (!header)99 return 0;100 ModuleSpec spec(file, std::move(header->arch));101 spec.GetUUID() = std::move(header->uuid);102 specs.Append(spec);103 return 1;104}105 106ObjectFileBreakpad::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,111 UUID uuid)112 : ObjectFile(module_sp, file, offset, length, data_sp, data_offset),113 m_arch(std::move(arch)), m_uuid(std::move(uuid)) {}114 115bool ObjectFileBreakpad::ParseHeader() {116 // We already parsed the header during initialization.117 return true;118}119 120void ObjectFileBreakpad::ParseSymtab(Symtab &symtab) {121 // Nothing to do for breakpad files, all information is parsed as debug info122 // which means "lldb_private::Function" objects are used, or symbols are added123 // by the SymbolFileBreakpad::AddSymbols(...) function in the symbol file.124}125 126void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) {127 if (m_sections_up)128 return;129 m_sections_up = std::make_unique<SectionList>();130 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.138 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);147 };148 while (!text.empty()) {149 llvm::StringRef line;150 std::tie(line, text) = text.split('\n');151 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, so155 // we put them in the same section.156 next_section = Record::Func;157 }158 if (next_section == current_section)159 continue;160 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();166 }167 // Finally, add the last section.168 maybe_add_section(m_data.GetDataEnd());169}170