11f6b2477SPavel Labath //===-- ObjectFileBreakpad.cpp -------------------------------- -*- C++ -*-===// 21f6b2477SPavel Labath // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler 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; 355b18ddb6SPavel Labath triple.setArch(Module->Arch); 365b18ddb6SPavel Labath triple.setOS(Module->OS); 371f6b2477SPavel Labath 381f6b2477SPavel Labath std::tie(line, text) = text.split('\n'); 391f6b2477SPavel Labath 402cf5486cSPavel Labath auto Info = InfoRecord::parse(line); 415b18ddb6SPavel Labath UUID uuid = Info && Info->ID ? Info->ID : Module->ID; 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 void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) { 126d5b44036SJonas Devlieghere if (m_sections_up) 127ed42ea47SPavel Labath return; 128d5b44036SJonas Devlieghere m_sections_up = llvm::make_unique<SectionList>(); 129ed42ea47SPavel Labath 1302cf5486cSPavel Labath llvm::Optional<Record::Kind> current_section; 131ed42ea47SPavel Labath offset_t section_start; 132ed42ea47SPavel Labath llvm::StringRef text = toStringRef(m_data.GetData()); 133ed42ea47SPavel Labath uint32_t next_section_id = 1; 134ed42ea47SPavel Labath auto maybe_add_section = [&](const uint8_t *end_ptr) { 1352cf5486cSPavel Labath if (!current_section) 136ed42ea47SPavel Labath return; // We have been called before parsing the first line. 137ed42ea47SPavel Labath 138ed42ea47SPavel Labath offset_t end_offset = end_ptr - m_data.GetDataStart(); 139ed42ea47SPavel Labath auto section_sp = std::make_shared<Section>( 140ed42ea47SPavel Labath GetModule(), this, next_section_id++, 1412cf5486cSPavel Labath ConstString(toString(*current_section)), eSectionTypeOther, 142ed42ea47SPavel Labath /*file_vm_addr*/ 0, /*vm_size*/ 0, section_start, 143ed42ea47SPavel Labath end_offset - section_start, /*log2align*/ 0, /*flags*/ 0); 144d5b44036SJonas Devlieghere m_sections_up->AddSection(section_sp); 145ed42ea47SPavel Labath unified_section_list.AddSection(section_sp); 146ed42ea47SPavel Labath }; 147ed42ea47SPavel Labath while (!text.empty()) { 148ed42ea47SPavel Labath llvm::StringRef line; 149ed42ea47SPavel Labath std::tie(line, text) = text.split('\n'); 150ed42ea47SPavel Labath 151*dfaafbcfSPavel Labath llvm::Optional<Record::Kind> next_section = Record::classify(line); 1522cf5486cSPavel Labath if (next_section == Record::Line) { 1532cf5486cSPavel Labath // Line records logically belong to the preceding Func record, so we put 1542cf5486cSPavel Labath // them in the same section. 1552cf5486cSPavel Labath next_section = Record::Func; 156*dfaafbcfSPavel Labath } else if (next_section == Record::StackCFI) { 157*dfaafbcfSPavel Labath // Same goes for StackCFI and StackCFIInit 158*dfaafbcfSPavel Labath next_section = Record::StackCFIInit; 159ed42ea47SPavel Labath } 1602cf5486cSPavel Labath if (next_section == current_section) 161ed42ea47SPavel Labath continue; 162ed42ea47SPavel Labath 163ed42ea47SPavel Labath // Changing sections, finish off the previous one, if there was any. 164ed42ea47SPavel Labath maybe_add_section(line.bytes_begin()); 165ed42ea47SPavel Labath // And start a new one. 1662cf5486cSPavel Labath current_section = next_section; 167ed42ea47SPavel Labath section_start = line.bytes_begin() - m_data.GetDataStart(); 168ed42ea47SPavel Labath } 169ed42ea47SPavel Labath // Finally, add the last section. 170ed42ea47SPavel Labath maybe_add_section(m_data.GetDataEnd()); 1711f6b2477SPavel Labath } 172