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-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 #include <optional> 15 16 using namespace lldb; 17 using namespace lldb_private; 18 using namespace lldb_private::breakpad; 19 20 LLDB_PLUGIN_DEFINE(ObjectFileBreakpad) 21 22 namespace { 23 struct Header { 24 ArchSpec arch; 25 UUID uuid; 26 static std::optional<Header> parse(llvm::StringRef text); 27 }; 28 } // namespace 29 30 std::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 48 char ObjectFileBreakpad::ID; 49 50 void ObjectFileBreakpad::Initialize() { 51 PluginManager::RegisterPlugin(GetPluginNameStatic(), 52 GetPluginDescriptionStatic(), CreateInstance, 53 CreateMemoryInstance, GetModuleSpecifications); 54 } 55 56 void ObjectFileBreakpad::Terminate() { 57 PluginManager::UnregisterPlugin(CreateInstance); 58 } 59 60 ObjectFile *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 already 75 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 87 ObjectFile *ObjectFileBreakpad::CreateMemoryInstance( 88 const ModuleSP &module_sp, WritableDataBufferSP data_sp, 89 const ProcessSP &process_sp, addr_t header_addr) { 90 return nullptr; 91 } 92 93 size_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 106 ObjectFileBreakpad::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 115 bool ObjectFileBreakpad::ParseHeader() { 116 // We already parsed the header during initialization. 117 return true; 118 } 119 120 void ObjectFileBreakpad::ParseSymtab(Symtab &symtab) { 121 // Nothing to do for breakpad files, all information is parsed as debug info 122 // which means "lldb_private::Function" objects are used, or symbols are added 123 // by the SymbolFileBreakpad::AddSymbols(...) function in the symbol file. 124 } 125 126 void 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, so 155 // 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