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