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 20using namespace llvm; 21using namespace lldb; 22using namespace lldb_private; 23 24LLDB_PLUGIN_DEFINE(ObjectFileJSON) 25 26char ObjectFileJSON::ID; 27 28void ObjectFileJSON::Initialize() { 29 PluginManager::RegisterPlugin(GetPluginNameStatic(), 30 GetPluginDescriptionStatic(), CreateInstance, 31 CreateMemoryInstance, GetModuleSpecifications); 32} 33 34void ObjectFileJSON::Terminate() { 35 PluginManager::UnregisterPlugin(CreateInstance); 36} 37 38ObjectFile * 39ObjectFileJSON::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 97ObjectFile *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 104size_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 148ObjectFileJSON::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 158bool ObjectFileJSON::ParseHeader() { 159 // We already parsed the header during initialization. 160 return true; 161} 162 163void 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 177void 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 193bool 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 203namespace lldb_private { 204 205bool 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 212bool 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