ObjectFileBreakpad.cpp revision 360784
1//===-- ObjectFileBreakpad.cpp -------------------------------- -*- C++ -*-===// 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-exception 6// 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 15using namespace lldb; 16using namespace lldb_private; 17using namespace lldb_private::breakpad; 18 19namespace { 20struct Header { 21 ArchSpec arch; 22 UUID uuid; 23 static llvm::Optional<Header> parse(llvm::StringRef text); 24}; 25} // namespace 26 27llvm::Optional<Header> Header::parse(llvm::StringRef text) { 28 llvm::StringRef line; 29 std::tie(line, text) = text.split('\n'); 30 auto Module = ModuleRecord::parse(line); 31 if (!Module) 32 return llvm::None; 33 34 llvm::Triple triple; 35 triple.setArch(Module->Arch); 36 triple.setOS(Module->OS); 37 38 std::tie(line, text) = text.split('\n'); 39 40 auto Info = InfoRecord::parse(line); 41 UUID uuid = Info && Info->ID ? Info->ID : Module->ID; 42 return Header{ArchSpec(triple), std::move(uuid)}; 43} 44 45char ObjectFileBreakpad::ID; 46 47void ObjectFileBreakpad::Initialize() { 48 PluginManager::RegisterPlugin(GetPluginNameStatic(), 49 GetPluginDescriptionStatic(), CreateInstance, 50 CreateMemoryInstance, GetModuleSpecifications); 51} 52 53void ObjectFileBreakpad::Terminate() { 54 PluginManager::UnregisterPlugin(CreateInstance); 55} 56 57ConstString ObjectFileBreakpad::GetPluginNameStatic() { 58 static ConstString g_name("breakpad"); 59 return g_name; 60} 61 62ObjectFile *ObjectFileBreakpad::CreateInstance( 63 const ModuleSP &module_sp, DataBufferSP &data_sp, offset_t data_offset, 64 const FileSpec *file, offset_t file_offset, offset_t length) { 65 if (!data_sp) { 66 data_sp = MapFileData(*file, length, file_offset); 67 if (!data_sp) 68 return nullptr; 69 data_offset = 0; 70 } 71 auto text = toStringRef(data_sp->GetData()); 72 llvm::Optional<Header> header = Header::parse(text); 73 if (!header) 74 return nullptr; 75 76 // Update the data to contain the entire file if it doesn't already 77 if (data_sp->GetByteSize() < length) { 78 data_sp = MapFileData(*file, length, file_offset); 79 if (!data_sp) 80 return nullptr; 81 data_offset = 0; 82 } 83 84 return new ObjectFileBreakpad(module_sp, data_sp, data_offset, file, 85 file_offset, length, std::move(header->arch), 86 std::move(header->uuid)); 87} 88 89ObjectFile *ObjectFileBreakpad::CreateMemoryInstance( 90 const ModuleSP &module_sp, DataBufferSP &data_sp, 91 const ProcessSP &process_sp, addr_t header_addr) { 92 return nullptr; 93} 94 95size_t ObjectFileBreakpad::GetModuleSpecifications( 96 const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, 97 offset_t file_offset, offset_t length, ModuleSpecList &specs) { 98 auto text = toStringRef(data_sp->GetData()); 99 llvm::Optional<Header> header = Header::parse(text); 100 if (!header) 101 return 0; 102 ModuleSpec spec(file, std::move(header->arch)); 103 spec.GetUUID() = std::move(header->uuid); 104 specs.Append(spec); 105 return 1; 106} 107 108ObjectFileBreakpad::ObjectFileBreakpad(const ModuleSP &module_sp, 109 DataBufferSP &data_sp, 110 offset_t data_offset, 111 const FileSpec *file, offset_t offset, 112 offset_t length, ArchSpec arch, 113 UUID uuid) 114 : ObjectFile(module_sp, file, offset, length, data_sp, data_offset), 115 m_arch(std::move(arch)), m_uuid(std::move(uuid)) {} 116 117bool ObjectFileBreakpad::ParseHeader() { 118 // We already parsed the header during initialization. 119 return true; 120} 121 122Symtab *ObjectFileBreakpad::GetSymtab() { 123 // TODO 124 return nullptr; 125} 126 127void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) { 128 if (m_sections_up) 129 return; 130 m_sections_up = std::make_unique<SectionList>(); 131 132 llvm::Optional<Record::Kind> current_section; 133 offset_t section_start; 134 llvm::StringRef text = toStringRef(m_data.GetData()); 135 uint32_t next_section_id = 1; 136 auto maybe_add_section = [&](const uint8_t *end_ptr) { 137 if (!current_section) 138 return; // We have been called before parsing the first line. 139 140 offset_t end_offset = end_ptr - m_data.GetDataStart(); 141 auto section_sp = std::make_shared<Section>( 142 GetModule(), this, next_section_id++, 143 ConstString(toString(*current_section)), eSectionTypeOther, 144 /*file_vm_addr*/ 0, /*vm_size*/ 0, section_start, 145 end_offset - section_start, /*log2align*/ 0, /*flags*/ 0); 146 m_sections_up->AddSection(section_sp); 147 unified_section_list.AddSection(section_sp); 148 }; 149 while (!text.empty()) { 150 llvm::StringRef line; 151 std::tie(line, text) = text.split('\n'); 152 153 llvm::Optional<Record::Kind> next_section = Record::classify(line); 154 if (next_section == Record::Line) { 155 // Line records logically belong to the preceding Func record, so we put 156 // them in the same section. 157 next_section = Record::Func; 158 } 159 if (next_section == current_section) 160 continue; 161 162 // Changing sections, finish off the previous one, if there was any. 163 maybe_add_section(line.bytes_begin()); 164 // And start a new one. 165 current_section = next_section; 166 section_start = line.bytes_begin() - m_data.GetDataStart(); 167 } 168 // Finally, add the last section. 169 maybe_add_section(m_data.GetDataEnd()); 170} 171