11f6b2477SPavel Labath //===-- ObjectFileBreakpad.cpp -------------------------------- -*- C++ -*-===// 21f6b2477SPavel Labath // 31f6b2477SPavel Labath // The LLVM Compiler Infrastructure 41f6b2477SPavel Labath // 51f6b2477SPavel Labath // This file is distributed under the University of Illinois Open Source 61f6b2477SPavel Labath // License. See LICENSE.TXT for details. 71f6b2477SPavel Labath // 81f6b2477SPavel Labath //===----------------------------------------------------------------------===// 91f6b2477SPavel Labath 101f6b2477SPavel Labath #include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h" 11*2cf5486cSPavel Labath #include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h" 121f6b2477SPavel Labath #include "lldb/Core/ModuleSpec.h" 131f6b2477SPavel Labath #include "lldb/Core/PluginManager.h" 14ed42ea47SPavel Labath #include "lldb/Core/Section.h" 151f6b2477SPavel Labath 161f6b2477SPavel Labath using namespace lldb; 171f6b2477SPavel Labath using namespace lldb_private; 181f6b2477SPavel Labath using namespace lldb_private::breakpad; 191f6b2477SPavel Labath 201f6b2477SPavel Labath namespace { 211f6b2477SPavel Labath struct Header { 221f6b2477SPavel Labath ArchSpec arch; 231f6b2477SPavel Labath UUID uuid; 241f6b2477SPavel Labath static llvm::Optional<Header> parse(llvm::StringRef text); 251f6b2477SPavel Labath }; 261f6b2477SPavel Labath } // namespace 271f6b2477SPavel Labath 281f6b2477SPavel Labath llvm::Optional<Header> Header::parse(llvm::StringRef text) { 29*2cf5486cSPavel Labath llvm::StringRef line; 301f6b2477SPavel Labath std::tie(line, text) = text.split('\n'); 31*2cf5486cSPavel Labath auto Module = ModuleRecord::parse(line); 32*2cf5486cSPavel Labath if (!Module) 331f6b2477SPavel Labath return llvm::None; 341f6b2477SPavel Labath 351f6b2477SPavel Labath llvm::Triple triple; 36*2cf5486cSPavel Labath triple.setArch(Module->getArch()); 37*2cf5486cSPavel Labath triple.setOS(Module->getOS()); 381f6b2477SPavel Labath 391f6b2477SPavel Labath std::tie(line, text) = text.split('\n'); 401f6b2477SPavel Labath 41*2cf5486cSPavel Labath auto Info = InfoRecord::parse(line); 42*2cf5486cSPavel Labath UUID uuid = Info && Info->getID() ? Info->getID() : Module->getID(); 43*2cf5486cSPavel Labath return Header{ArchSpec(triple), std::move(uuid)}; 441f6b2477SPavel Labath } 451f6b2477SPavel Labath 461f6b2477SPavel Labath void ObjectFileBreakpad::Initialize() { 471f6b2477SPavel Labath PluginManager::RegisterPlugin(GetPluginNameStatic(), 481f6b2477SPavel Labath GetPluginDescriptionStatic(), CreateInstance, 49871f2b65SPavel Labath CreateMemoryInstance, GetModuleSpecifications); 501f6b2477SPavel Labath } 511f6b2477SPavel Labath 521f6b2477SPavel Labath void ObjectFileBreakpad::Terminate() { 531f6b2477SPavel Labath PluginManager::UnregisterPlugin(CreateInstance); 541f6b2477SPavel Labath } 551f6b2477SPavel Labath 561f6b2477SPavel Labath ConstString ObjectFileBreakpad::GetPluginNameStatic() { 571f6b2477SPavel Labath static ConstString g_name("breakpad"); 581f6b2477SPavel Labath return g_name; 591f6b2477SPavel Labath } 601f6b2477SPavel Labath 611f6b2477SPavel Labath ObjectFile *ObjectFileBreakpad::CreateInstance( 621f6b2477SPavel Labath const ModuleSP &module_sp, DataBufferSP &data_sp, offset_t data_offset, 631f6b2477SPavel Labath const FileSpec *file, offset_t file_offset, offset_t length) { 641f6b2477SPavel Labath if (!data_sp) { 651f6b2477SPavel Labath data_sp = MapFileData(*file, length, file_offset); 661f6b2477SPavel Labath if (!data_sp) 671f6b2477SPavel Labath return nullptr; 681f6b2477SPavel Labath data_offset = 0; 691f6b2477SPavel Labath } 701f6b2477SPavel Labath auto text = toStringRef(data_sp->GetData()); 711f6b2477SPavel Labath llvm::Optional<Header> header = Header::parse(text); 721f6b2477SPavel Labath if (!header) 731f6b2477SPavel Labath return nullptr; 741f6b2477SPavel Labath 751f6b2477SPavel Labath // Update the data to contain the entire file if it doesn't already 761f6b2477SPavel Labath if (data_sp->GetByteSize() < length) { 771f6b2477SPavel Labath data_sp = MapFileData(*file, length, file_offset); 781f6b2477SPavel Labath if (!data_sp) 791f6b2477SPavel Labath return nullptr; 801f6b2477SPavel Labath data_offset = 0; 811f6b2477SPavel Labath } 821f6b2477SPavel Labath 831f6b2477SPavel Labath return new ObjectFileBreakpad(module_sp, data_sp, data_offset, file, 841f6b2477SPavel Labath file_offset, length, std::move(header->arch), 851f6b2477SPavel Labath std::move(header->uuid)); 861f6b2477SPavel Labath } 871f6b2477SPavel Labath 881f6b2477SPavel Labath ObjectFile *ObjectFileBreakpad::CreateMemoryInstance( 891f6b2477SPavel Labath const ModuleSP &module_sp, DataBufferSP &data_sp, 901f6b2477SPavel Labath const ProcessSP &process_sp, addr_t header_addr) { 911f6b2477SPavel Labath return nullptr; 921f6b2477SPavel Labath } 931f6b2477SPavel Labath 941f6b2477SPavel Labath size_t ObjectFileBreakpad::GetModuleSpecifications( 951f6b2477SPavel Labath const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, 961f6b2477SPavel Labath offset_t file_offset, offset_t length, ModuleSpecList &specs) { 971f6b2477SPavel Labath auto text = toStringRef(data_sp->GetData()); 981f6b2477SPavel Labath llvm::Optional<Header> header = Header::parse(text); 991f6b2477SPavel Labath if (!header) 1001f6b2477SPavel Labath return 0; 1011f6b2477SPavel Labath ModuleSpec spec(file, std::move(header->arch)); 1021f6b2477SPavel Labath spec.GetUUID() = std::move(header->uuid); 1031f6b2477SPavel Labath specs.Append(spec); 1041f6b2477SPavel Labath return 1; 1051f6b2477SPavel Labath } 1061f6b2477SPavel Labath 1071f6b2477SPavel Labath ObjectFileBreakpad::ObjectFileBreakpad(const ModuleSP &module_sp, 1081f6b2477SPavel Labath DataBufferSP &data_sp, 1091f6b2477SPavel Labath offset_t data_offset, 1101f6b2477SPavel Labath const FileSpec *file, offset_t offset, 1111f6b2477SPavel Labath offset_t length, ArchSpec arch, 1121f6b2477SPavel Labath UUID uuid) 1131f6b2477SPavel Labath : ObjectFile(module_sp, file, offset, length, data_sp, data_offset), 1141f6b2477SPavel Labath m_arch(std::move(arch)), m_uuid(std::move(uuid)) {} 1151f6b2477SPavel Labath 1161f6b2477SPavel Labath bool ObjectFileBreakpad::ParseHeader() { 1171f6b2477SPavel Labath // We already parsed the header during initialization. 1181f6b2477SPavel Labath return true; 1191f6b2477SPavel Labath } 1201f6b2477SPavel Labath 1211f6b2477SPavel Labath Symtab *ObjectFileBreakpad::GetSymtab() { 1221f6b2477SPavel Labath // TODO 1231f6b2477SPavel Labath return nullptr; 1241f6b2477SPavel Labath } 1251f6b2477SPavel Labath 1261f6b2477SPavel Labath bool ObjectFileBreakpad::GetUUID(UUID *uuid) { 1271f6b2477SPavel Labath *uuid = m_uuid; 1281f6b2477SPavel Labath return true; 1291f6b2477SPavel Labath } 1301f6b2477SPavel Labath 1311f6b2477SPavel Labath void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) { 132ed42ea47SPavel Labath if (m_sections_ap) 133ed42ea47SPavel Labath return; 134ed42ea47SPavel Labath m_sections_ap = llvm::make_unique<SectionList>(); 135ed42ea47SPavel Labath 136*2cf5486cSPavel Labath llvm::Optional<Record::Kind> current_section; 137ed42ea47SPavel Labath offset_t section_start; 138ed42ea47SPavel Labath llvm::StringRef text = toStringRef(m_data.GetData()); 139ed42ea47SPavel Labath uint32_t next_section_id = 1; 140ed42ea47SPavel Labath auto maybe_add_section = [&](const uint8_t *end_ptr) { 141*2cf5486cSPavel Labath if (!current_section) 142ed42ea47SPavel Labath return; // We have been called before parsing the first line. 143ed42ea47SPavel Labath 144ed42ea47SPavel Labath offset_t end_offset = end_ptr - m_data.GetDataStart(); 145ed42ea47SPavel Labath auto section_sp = std::make_shared<Section>( 146ed42ea47SPavel Labath GetModule(), this, next_section_id++, 147*2cf5486cSPavel Labath ConstString(toString(*current_section)), eSectionTypeOther, 148ed42ea47SPavel Labath /*file_vm_addr*/ 0, /*vm_size*/ 0, section_start, 149ed42ea47SPavel Labath end_offset - section_start, /*log2align*/ 0, /*flags*/ 0); 150ed42ea47SPavel Labath m_sections_ap->AddSection(section_sp); 151ed42ea47SPavel Labath unified_section_list.AddSection(section_sp); 152ed42ea47SPavel Labath }; 153ed42ea47SPavel Labath while (!text.empty()) { 154ed42ea47SPavel Labath llvm::StringRef line; 155ed42ea47SPavel Labath std::tie(line, text) = text.split('\n'); 156ed42ea47SPavel Labath 157*2cf5486cSPavel Labath Record::Kind next_section = Record::classify(line); 158*2cf5486cSPavel Labath if (next_section == Record::Line) { 159*2cf5486cSPavel Labath // Line records logically belong to the preceding Func record, so we put 160*2cf5486cSPavel Labath // them in the same section. 161*2cf5486cSPavel Labath next_section = Record::Func; 162ed42ea47SPavel Labath } 163*2cf5486cSPavel Labath if (next_section == current_section) 164ed42ea47SPavel Labath continue; 165ed42ea47SPavel Labath 166ed42ea47SPavel Labath // Changing sections, finish off the previous one, if there was any. 167ed42ea47SPavel Labath maybe_add_section(line.bytes_begin()); 168ed42ea47SPavel Labath // And start a new one. 169*2cf5486cSPavel Labath current_section = next_section; 170ed42ea47SPavel Labath section_start = line.bytes_begin() - m_data.GetDataStart(); 171ed42ea47SPavel Labath } 172ed42ea47SPavel Labath // Finally, add the last section. 173ed42ea47SPavel Labath maybe_add_section(m_data.GetDataEnd()); 1741f6b2477SPavel Labath } 175