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 ObjectFile *ObjectFileBreakpad::CreateInstance( 60 const ModuleSP &module_sp, DataBufferSP &data_sp, offset_t data_offset, 61 const FileSpec *file, offset_t file_offset, offset_t length) { 62 if (!data_sp) { 63 data_sp = MapFileData(*file, length, file_offset); 64 if (!data_sp) 65 return nullptr; 66 data_offset = 0; 67 } 68 auto text = toStringRef(data_sp->GetData()); 69 llvm::Optional<Header> header = Header::parse(text); 70 if (!header) 71 return nullptr; 72 73 // Update the data to contain the entire file if it doesn't already 74 if (data_sp->GetByteSize() < length) { 75 data_sp = MapFileData(*file, length, file_offset); 76 if (!data_sp) 77 return nullptr; 78 data_offset = 0; 79 } 80 81 return new ObjectFileBreakpad(module_sp, data_sp, data_offset, file, 82 file_offset, length, std::move(header->arch), 83 std::move(header->uuid)); 84 } 85 86 ObjectFile *ObjectFileBreakpad::CreateMemoryInstance( 87 const ModuleSP &module_sp, DataBufferSP &data_sp, 88 const ProcessSP &process_sp, addr_t header_addr) { 89 return nullptr; 90 } 91 92 size_t ObjectFileBreakpad::GetModuleSpecifications( 93 const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, 94 offset_t file_offset, offset_t length, ModuleSpecList &specs) { 95 auto text = toStringRef(data_sp->GetData()); 96 llvm::Optional<Header> header = Header::parse(text); 97 if (!header) 98 return 0; 99 ModuleSpec spec(file, std::move(header->arch)); 100 spec.GetUUID() = std::move(header->uuid); 101 specs.Append(spec); 102 return 1; 103 } 104 105 ObjectFileBreakpad::ObjectFileBreakpad(const ModuleSP &module_sp, 106 DataBufferSP &data_sp, 107 offset_t data_offset, 108 const FileSpec *file, offset_t offset, 109 offset_t length, ArchSpec arch, 110 UUID uuid) 111 : ObjectFile(module_sp, file, offset, length, data_sp, data_offset), 112 m_arch(std::move(arch)), m_uuid(std::move(uuid)) {} 113 114 bool ObjectFileBreakpad::ParseHeader() { 115 // We already parsed the header during initialization. 116 return true; 117 } 118 119 void ObjectFileBreakpad::ParseSymtab(Symtab &symtab) { 120 // Nothing to do for breakpad files, all information is parsed as debug info 121 // which means "lldb_private::Function" objects are used, or symbols are added 122 // by the SymbolFileBreakpad::AddSymbols(...) function in the symbol file. 123 } 124 125 void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) { 126 if (m_sections_up) 127 return; 128 m_sections_up = std::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 || next_section == Record::Inline) { 153 // Line/Inline records logically belong to the preceding Func record, so 154 // we put 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