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