11f6b2477SPavel Labath //===-- ObjectFileBreakpad.cpp -------------------------------- -*- C++ -*-===// 21f6b2477SPavel Labath // 3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 61f6b2477SPavel Labath // 71f6b2477SPavel Labath //===----------------------------------------------------------------------===// 81f6b2477SPavel Labath 91f6b2477SPavel Labath #include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h" 102cf5486cSPavel Labath #include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h" 111f6b2477SPavel Labath #include "lldb/Core/ModuleSpec.h" 121f6b2477SPavel Labath #include "lldb/Core/PluginManager.h" 13ed42ea47SPavel Labath #include "lldb/Core/Section.h" 141f6b2477SPavel Labath 151f6b2477SPavel Labath using namespace lldb; 161f6b2477SPavel Labath using namespace lldb_private; 171f6b2477SPavel Labath using namespace lldb_private::breakpad; 181f6b2477SPavel Labath 191f6b2477SPavel Labath namespace { 201f6b2477SPavel Labath struct Header { 211f6b2477SPavel Labath ArchSpec arch; 221f6b2477SPavel Labath UUID uuid; 231f6b2477SPavel Labath static llvm::Optional<Header> parse(llvm::StringRef text); 241f6b2477SPavel Labath }; 251f6b2477SPavel Labath } // namespace 261f6b2477SPavel Labath 271f6b2477SPavel Labath llvm::Optional<Header> Header::parse(llvm::StringRef text) { 282cf5486cSPavel Labath llvm::StringRef line; 291f6b2477SPavel Labath std::tie(line, text) = text.split('\n'); 302cf5486cSPavel Labath auto Module = ModuleRecord::parse(line); 312cf5486cSPavel Labath if (!Module) 321f6b2477SPavel Labath return llvm::None; 331f6b2477SPavel Labath 341f6b2477SPavel Labath llvm::Triple triple; 352cf5486cSPavel Labath triple.setArch(Module->getArch()); 362cf5486cSPavel Labath triple.setOS(Module->getOS()); 371f6b2477SPavel Labath 381f6b2477SPavel Labath std::tie(line, text) = text.split('\n'); 391f6b2477SPavel Labath 402cf5486cSPavel Labath auto Info = InfoRecord::parse(line); 412cf5486cSPavel Labath UUID uuid = Info && Info->getID() ? Info->getID() : Module->getID(); 422cf5486cSPavel Labath return Header{ArchSpec(triple), std::move(uuid)}; 431f6b2477SPavel Labath } 441f6b2477SPavel Labath 451f6b2477SPavel Labath void ObjectFileBreakpad::Initialize() { 461f6b2477SPavel Labath PluginManager::RegisterPlugin(GetPluginNameStatic(), 471f6b2477SPavel Labath GetPluginDescriptionStatic(), CreateInstance, 48871f2b65SPavel Labath CreateMemoryInstance, GetModuleSpecifications); 491f6b2477SPavel Labath } 501f6b2477SPavel Labath 511f6b2477SPavel Labath void ObjectFileBreakpad::Terminate() { 521f6b2477SPavel Labath PluginManager::UnregisterPlugin(CreateInstance); 531f6b2477SPavel Labath } 541f6b2477SPavel Labath 551f6b2477SPavel Labath ConstString ObjectFileBreakpad::GetPluginNameStatic() { 561f6b2477SPavel Labath static ConstString g_name("breakpad"); 571f6b2477SPavel Labath return g_name; 581f6b2477SPavel Labath } 591f6b2477SPavel Labath 601f6b2477SPavel Labath ObjectFile *ObjectFileBreakpad::CreateInstance( 611f6b2477SPavel Labath const ModuleSP &module_sp, DataBufferSP &data_sp, offset_t data_offset, 621f6b2477SPavel Labath const FileSpec *file, offset_t file_offset, offset_t length) { 631f6b2477SPavel Labath if (!data_sp) { 641f6b2477SPavel Labath data_sp = MapFileData(*file, length, file_offset); 651f6b2477SPavel Labath if (!data_sp) 661f6b2477SPavel Labath return nullptr; 671f6b2477SPavel Labath data_offset = 0; 681f6b2477SPavel Labath } 691f6b2477SPavel Labath auto text = toStringRef(data_sp->GetData()); 701f6b2477SPavel Labath llvm::Optional<Header> header = Header::parse(text); 711f6b2477SPavel Labath if (!header) 721f6b2477SPavel Labath return nullptr; 731f6b2477SPavel Labath 741f6b2477SPavel Labath // Update the data to contain the entire file if it doesn't already 751f6b2477SPavel Labath if (data_sp->GetByteSize() < length) { 761f6b2477SPavel Labath data_sp = MapFileData(*file, length, file_offset); 771f6b2477SPavel Labath if (!data_sp) 781f6b2477SPavel Labath return nullptr; 791f6b2477SPavel Labath data_offset = 0; 801f6b2477SPavel Labath } 811f6b2477SPavel Labath 821f6b2477SPavel Labath return new ObjectFileBreakpad(module_sp, data_sp, data_offset, file, 831f6b2477SPavel Labath file_offset, length, std::move(header->arch), 841f6b2477SPavel Labath std::move(header->uuid)); 851f6b2477SPavel Labath } 861f6b2477SPavel Labath 871f6b2477SPavel Labath ObjectFile *ObjectFileBreakpad::CreateMemoryInstance( 881f6b2477SPavel Labath const ModuleSP &module_sp, DataBufferSP &data_sp, 891f6b2477SPavel Labath const ProcessSP &process_sp, addr_t header_addr) { 901f6b2477SPavel Labath return nullptr; 911f6b2477SPavel Labath } 921f6b2477SPavel Labath 931f6b2477SPavel Labath size_t ObjectFileBreakpad::GetModuleSpecifications( 941f6b2477SPavel Labath const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, 951f6b2477SPavel Labath offset_t file_offset, offset_t length, ModuleSpecList &specs) { 961f6b2477SPavel Labath auto text = toStringRef(data_sp->GetData()); 971f6b2477SPavel Labath llvm::Optional<Header> header = Header::parse(text); 981f6b2477SPavel Labath if (!header) 991f6b2477SPavel Labath return 0; 1001f6b2477SPavel Labath ModuleSpec spec(file, std::move(header->arch)); 1011f6b2477SPavel Labath spec.GetUUID() = std::move(header->uuid); 1021f6b2477SPavel Labath specs.Append(spec); 1031f6b2477SPavel Labath return 1; 1041f6b2477SPavel Labath } 1051f6b2477SPavel Labath 1061f6b2477SPavel Labath ObjectFileBreakpad::ObjectFileBreakpad(const ModuleSP &module_sp, 1071f6b2477SPavel Labath DataBufferSP &data_sp, 1081f6b2477SPavel Labath offset_t data_offset, 1091f6b2477SPavel Labath const FileSpec *file, offset_t offset, 1101f6b2477SPavel Labath offset_t length, ArchSpec arch, 1111f6b2477SPavel Labath UUID uuid) 1121f6b2477SPavel Labath : ObjectFile(module_sp, file, offset, length, data_sp, data_offset), 1131f6b2477SPavel Labath m_arch(std::move(arch)), m_uuid(std::move(uuid)) {} 1141f6b2477SPavel Labath 1151f6b2477SPavel Labath bool ObjectFileBreakpad::ParseHeader() { 1161f6b2477SPavel Labath // We already parsed the header during initialization. 1171f6b2477SPavel Labath return true; 1181f6b2477SPavel Labath } 1191f6b2477SPavel Labath 1201f6b2477SPavel Labath Symtab *ObjectFileBreakpad::GetSymtab() { 1211f6b2477SPavel Labath // TODO 1221f6b2477SPavel Labath return nullptr; 1231f6b2477SPavel Labath } 1241f6b2477SPavel Labath 1251f6b2477SPavel Labath bool ObjectFileBreakpad::GetUUID(UUID *uuid) { 1261f6b2477SPavel Labath *uuid = m_uuid; 1271f6b2477SPavel Labath return true; 1281f6b2477SPavel Labath } 1291f6b2477SPavel Labath 1301f6b2477SPavel Labath void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) { 131ed42ea47SPavel Labath if (m_sections_ap) 132ed42ea47SPavel Labath return; 133ed42ea47SPavel Labath m_sections_ap = llvm::make_unique<SectionList>(); 134ed42ea47SPavel Labath 1352cf5486cSPavel Labath llvm::Optional<Record::Kind> current_section; 136ed42ea47SPavel Labath offset_t section_start; 137ed42ea47SPavel Labath llvm::StringRef text = toStringRef(m_data.GetData()); 138ed42ea47SPavel Labath uint32_t next_section_id = 1; 139ed42ea47SPavel Labath auto maybe_add_section = [&](const uint8_t *end_ptr) { 1402cf5486cSPavel Labath if (!current_section) 141ed42ea47SPavel Labath return; // We have been called before parsing the first line. 142ed42ea47SPavel Labath 143ed42ea47SPavel Labath offset_t end_offset = end_ptr - m_data.GetDataStart(); 144ed42ea47SPavel Labath auto section_sp = std::make_shared<Section>( 145ed42ea47SPavel Labath GetModule(), this, next_section_id++, 1462cf5486cSPavel Labath ConstString(toString(*current_section)), eSectionTypeOther, 147ed42ea47SPavel Labath /*file_vm_addr*/ 0, /*vm_size*/ 0, section_start, 148ed42ea47SPavel Labath end_offset - section_start, /*log2align*/ 0, /*flags*/ 0); 149ed42ea47SPavel Labath m_sections_ap->AddSection(section_sp); 150ed42ea47SPavel Labath unified_section_list.AddSection(section_sp); 151ed42ea47SPavel Labath }; 152ed42ea47SPavel Labath while (!text.empty()) { 153ed42ea47SPavel Labath llvm::StringRef line; 154ed42ea47SPavel Labath std::tie(line, text) = text.split('\n'); 155ed42ea47SPavel Labath 1562cf5486cSPavel Labath Record::Kind next_section = Record::classify(line); 1572cf5486cSPavel Labath if (next_section == Record::Line) { 1582cf5486cSPavel Labath // Line records logically belong to the preceding Func record, so we put 1592cf5486cSPavel Labath // them in the same section. 1602cf5486cSPavel Labath next_section = Record::Func; 161ed42ea47SPavel Labath } 1622cf5486cSPavel Labath if (next_section == current_section) 163ed42ea47SPavel Labath continue; 164ed42ea47SPavel Labath 165ed42ea47SPavel Labath // Changing sections, finish off the previous one, if there was any. 166ed42ea47SPavel Labath maybe_add_section(line.bytes_begin()); 167ed42ea47SPavel Labath // And start a new one. 1682cf5486cSPavel Labath current_section = next_section; 169ed42ea47SPavel Labath section_start = line.bytes_begin() - m_data.GetDataStart(); 170ed42ea47SPavel Labath } 171ed42ea47SPavel Labath // Finally, add the last section. 172ed42ea47SPavel Labath maybe_add_section(m_data.GetDataEnd()); 1731f6b2477SPavel Labath } 174