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 15 using namespace lldb; 16 using namespace lldb_private; 17 using namespace lldb_private::breakpad; 18 19 namespace { 20 struct Header { 21 ArchSpec arch; 22 UUID uuid; 23 static llvm::Optional<Header> parse(llvm::StringRef text); 24 }; 25 } // namespace 26 27 llvm::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 45 void ObjectFileBreakpad::Initialize() { 46 PluginManager::RegisterPlugin(GetPluginNameStatic(), 47 GetPluginDescriptionStatic(), CreateInstance, 48 CreateMemoryInstance, GetModuleSpecifications); 49 } 50 51 void ObjectFileBreakpad::Terminate() { 52 PluginManager::UnregisterPlugin(CreateInstance); 53 } 54 55 ConstString ObjectFileBreakpad::GetPluginNameStatic() { 56 static ConstString g_name("breakpad"); 57 return g_name; 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 llvm::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, DataBufferSP &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 llvm::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 Symtab *ObjectFileBreakpad::GetSymtab() { 121 // TODO 122 return nullptr; 123 } 124 125 void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) { 126 if (m_sections_up) 127 return; 128 m_sections_up = llvm::make_unique<SectionList>(); 129 130 llvm::Optional<Record::Kind> current_section; 131 offset_t section_start; 132 llvm::StringRef text = toStringRef(m_data.GetData()); 133 uint32_t next_section_id = 1; 134 auto maybe_add_section = [&](const uint8_t *end_ptr) { 135 if (!current_section) 136 return; // We have been called before parsing the first line. 137 138 offset_t end_offset = end_ptr - m_data.GetDataStart(); 139 auto section_sp = std::make_shared<Section>( 140 GetModule(), this, next_section_id++, 141 ConstString(toString(*current_section)), eSectionTypeOther, 142 /*file_vm_addr*/ 0, /*vm_size*/ 0, section_start, 143 end_offset - section_start, /*log2align*/ 0, /*flags*/ 0); 144 m_sections_up->AddSection(section_sp); 145 unified_section_list.AddSection(section_sp); 146 }; 147 while (!text.empty()) { 148 llvm::StringRef line; 149 std::tie(line, text) = text.split('\n'); 150 151 llvm::Optional<Record::Kind> next_section = Record::classify(line); 152 if (next_section == Record::Line) { 153 // Line records logically belong to the preceding Func record, so we put 154 // them in the same section. 155 next_section = Record::Func; 156 } 157 if (next_section == current_section) 158 continue; 159 160 // Changing sections, finish off the previous one, if there was any. 161 maybe_add_section(line.bytes_begin()); 162 // And start a new one. 163 current_section = next_section; 164 section_start = line.bytes_begin() - m_data.GetDataStart(); 165 } 166 // Finally, add the last section. 167 maybe_add_section(m_data.GetDataEnd()); 168 } 169