1 //===-- ObjectFileJSON.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/JSON/ObjectFileJSON.h" 10 #include "lldb/Core/Module.h" 11 #include "lldb/Core/ModuleSpec.h" 12 #include "lldb/Core/PluginManager.h" 13 #include "lldb/Core/Section.h" 14 #include "lldb/Symbol/Symbol.h" 15 #include "lldb/Utility/LLDBLog.h" 16 #include "lldb/Utility/Log.h" 17 #include "llvm/ADT/DenseSet.h" 18 #include <optional> 19 20 using namespace llvm; 21 using namespace lldb; 22 using namespace lldb_private; 23 24 LLDB_PLUGIN_DEFINE(ObjectFileJSON) 25 26 char ObjectFileJSON::ID; 27 28 void ObjectFileJSON::Initialize() { 29 PluginManager::RegisterPlugin(GetPluginNameStatic(), 30 GetPluginDescriptionStatic(), CreateInstance, 31 CreateMemoryInstance, GetModuleSpecifications); 32 } 33 34 void ObjectFileJSON::Terminate() { 35 PluginManager::UnregisterPlugin(CreateInstance); 36 } 37 38 ObjectFile * 39 ObjectFileJSON::CreateInstance(const ModuleSP &module_sp, DataBufferSP data_sp, 40 offset_t data_offset, const FileSpec *file, 41 offset_t file_offset, offset_t length) { 42 if (!data_sp) { 43 data_sp = MapFileData(*file, length, file_offset); 44 if (!data_sp) 45 return nullptr; 46 data_offset = 0; 47 } 48 49 if (!MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) 50 return nullptr; 51 52 // Update the data to contain the entire file if it doesn't already. 53 if (data_sp->GetByteSize() < length) { 54 data_sp = MapFileData(*file, length, file_offset); 55 if (!data_sp) 56 return nullptr; 57 data_offset = 0; 58 } 59 60 Log *log = GetLog(LLDBLog::Symbols); 61 62 auto text = 63 llvm::StringRef(reinterpret_cast<const char *>(data_sp->GetBytes())); 64 65 Expected<json::Value> json = json::parse(text); 66 if (!json) { 67 LLDB_LOG_ERROR(log, json.takeError(), 68 "failed to parse JSON object file: {0}"); 69 return nullptr; 70 } 71 72 json::Path::Root root; 73 Header header; 74 if (!fromJSON(*json, header, root)) { 75 LLDB_LOG_ERROR(log, root.getError(), 76 "failed to parse JSON object file header: {0}"); 77 return nullptr; 78 } 79 80 ArchSpec arch(header.triple); 81 UUID uuid; 82 uuid.SetFromStringRef(header.uuid); 83 Type type = header.type.value_or(eTypeDebugInfo); 84 85 Body body; 86 if (!fromJSON(*json, body, root)) { 87 LLDB_LOG_ERROR(log, root.getError(), 88 "failed to parse JSON object file body: {0}"); 89 return nullptr; 90 } 91 92 return new ObjectFileJSON(module_sp, data_sp, data_offset, file, file_offset, 93 length, std::move(arch), std::move(uuid), type, 94 std::move(body.symbols), std::move(body.sections)); 95 } 96 97 ObjectFile *ObjectFileJSON::CreateMemoryInstance(const ModuleSP &module_sp, 98 WritableDataBufferSP data_sp, 99 const ProcessSP &process_sp, 100 addr_t header_addr) { 101 return nullptr; 102 } 103 104 size_t ObjectFileJSON::GetModuleSpecifications( 105 const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, 106 offset_t file_offset, offset_t length, ModuleSpecList &specs) { 107 if (!MagicBytesMatch(data_sp, data_offset, data_sp->GetByteSize())) 108 return 0; 109 110 // Update the data to contain the entire file if it doesn't already. 111 if (data_sp->GetByteSize() < length) { 112 data_sp = MapFileData(file, length, file_offset); 113 if (!data_sp) 114 return 0; 115 data_offset = 0; 116 } 117 118 Log *log = GetLog(LLDBLog::Symbols); 119 120 auto text = 121 llvm::StringRef(reinterpret_cast<const char *>(data_sp->GetBytes())); 122 123 Expected<json::Value> json = json::parse(text); 124 if (!json) { 125 LLDB_LOG_ERROR(log, json.takeError(), 126 "failed to parse JSON object file: {0}"); 127 return 0; 128 } 129 130 json::Path::Root root; 131 Header header; 132 if (!fromJSON(*json, header, root)) { 133 LLDB_LOG_ERROR(log, root.getError(), 134 "failed to parse JSON object file header: {0}"); 135 return 0; 136 } 137 138 ArchSpec arch(header.triple); 139 UUID uuid; 140 uuid.SetFromStringRef(header.uuid); 141 142 ModuleSpec spec(file, std::move(arch)); 143 spec.GetUUID() = std::move(uuid); 144 specs.Append(spec); 145 return 1; 146 } 147 148 ObjectFileJSON::ObjectFileJSON(const ModuleSP &module_sp, DataBufferSP &data_sp, 149 offset_t data_offset, const FileSpec *file, 150 offset_t offset, offset_t length, ArchSpec arch, 151 UUID uuid, Type type, 152 std::vector<JSONSymbol> symbols, 153 std::vector<JSONSection> sections) 154 : ObjectFile(module_sp, file, offset, length, data_sp, data_offset), 155 m_arch(std::move(arch)), m_uuid(std::move(uuid)), m_type(type), 156 m_symbols(std::move(symbols)), m_sections(std::move(sections)) {} 157 158 bool ObjectFileJSON::ParseHeader() { 159 // We already parsed the header during initialization. 160 return true; 161 } 162 163 void ObjectFileJSON::ParseSymtab(Symtab &symtab) { 164 Log *log = GetLog(LLDBLog::Symbols); 165 SectionList *section_list = GetModule()->GetSectionList(); 166 for (JSONSymbol json_symbol : m_symbols) { 167 llvm::Expected<Symbol> symbol = Symbol::FromJSON(json_symbol, section_list); 168 if (!symbol) { 169 LLDB_LOG_ERROR(log, symbol.takeError(), "invalid symbol: {0}"); 170 continue; 171 } 172 symtab.AddSymbol(*symbol); 173 } 174 symtab.Finalize(); 175 } 176 177 void ObjectFileJSON::CreateSections(SectionList &unified_section_list) { 178 if (m_sections_up) 179 return; 180 m_sections_up = std::make_unique<SectionList>(); 181 182 lldb::user_id_t id = 1; 183 for (const auto §ion : m_sections) { 184 auto section_sp = std::make_shared<Section>( 185 GetModule(), this, id++, ConstString(section.name), 186 section.type.value_or(eSectionTypeCode), 0, section.size.value_or(0), 0, 187 section.size.value_or(0), /*log2align*/ 0, /*flags*/ 0); 188 m_sections_up->AddSection(section_sp); 189 unified_section_list.AddSection(section_sp); 190 } 191 } 192 193 bool ObjectFileJSON::MagicBytesMatch(DataBufferSP data_sp, 194 lldb::addr_t data_offset, 195 lldb::addr_t data_length) { 196 DataExtractor data; 197 data.SetData(data_sp, data_offset, data_length); 198 lldb::offset_t offset = 0; 199 uint32_t magic = data.GetU8(&offset); 200 return magic == '{'; 201 } 202 203 namespace lldb_private { 204 205 bool fromJSON(const json::Value &value, ObjectFileJSON::Header &header, 206 json::Path path) { 207 json::ObjectMapper o(value, path); 208 return o && o.map("triple", header.triple) && o.map("uuid", header.uuid) && 209 o.map("type", header.type); 210 } 211 212 bool fromJSON(const json::Value &value, ObjectFileJSON::Body &body, 213 json::Path path) { 214 json::ObjectMapper o(value, path); 215 return o && o.mapOptional("symbols", body.symbols) && 216 o.mapOptional("sections", body.sections); 217 } 218 219 } // namespace lldb_private 220