298 lines · cpp
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-exception6//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/Target/Target.h"16#include "lldb/Utility/LLDBLog.h"17#include "lldb/Utility/Log.h"18#include "llvm/ADT/DenseSet.h"19#include <optional>20 21using namespace llvm;22using namespace lldb;23using namespace lldb_private;24 25LLDB_PLUGIN_DEFINE(ObjectFileJSON)26 27char ObjectFileJSON::ID;28 29void ObjectFileJSON::Initialize() {30 PluginManager::RegisterPlugin(GetPluginNameStatic(),31 GetPluginDescriptionStatic(), CreateInstance,32 CreateMemoryInstance, GetModuleSpecifications);33}34 35void ObjectFileJSON::Terminate() {36 PluginManager::UnregisterPlugin(CreateInstance);37}38 39ObjectFile *40ObjectFileJSON::CreateInstance(const ModuleSP &module_sp, DataBufferSP data_sp,41 offset_t data_offset, const FileSpec *file,42 offset_t file_offset, offset_t length) {43 if (!data_sp) {44 data_sp = MapFileData(*file, length, file_offset);45 if (!data_sp)46 return nullptr;47 data_offset = 0;48 }49 50 if (!MagicBytesMatch(data_sp, 0, data_sp->GetByteSize()))51 return nullptr;52 53 // Update the data to contain the entire file if it doesn't already.54 if (data_sp->GetByteSize() < length) {55 data_sp = MapFileData(*file, length, file_offset);56 if (!data_sp)57 return nullptr;58 data_offset = 0;59 }60 61 Log *log = GetLog(LLDBLog::Symbols);62 63 auto text =64 llvm::StringRef(reinterpret_cast<const char *>(data_sp->GetBytes()));65 66 Expected<json::Value> json = json::parse(text);67 if (!json) {68 LLDB_LOG_ERROR(log, json.takeError(),69 "failed to parse JSON object file: {0}");70 return nullptr;71 }72 73 json::Path::Root root;74 Header header;75 if (!fromJSON(*json, header, root)) {76 LLDB_LOG_ERROR(log, root.getError(),77 "failed to parse JSON object file header: {0}");78 return nullptr;79 }80 81 ArchSpec arch(header.triple);82 UUID uuid;83 uuid.SetFromStringRef(header.uuid);84 Type type = header.type.value_or(eTypeDebugInfo);85 86 Body body;87 if (!fromJSON(*json, body, root)) {88 LLDB_LOG_ERROR(log, root.getError(),89 "failed to parse JSON object file body: {0}");90 return nullptr;91 }92 93 return new ObjectFileJSON(module_sp, data_sp, data_offset, file, file_offset,94 length, std::move(arch), std::move(uuid), type,95 std::move(body.symbols), std::move(body.sections));96}97 98ObjectFile *ObjectFileJSON::CreateMemoryInstance(const ModuleSP &module_sp,99 WritableDataBufferSP data_sp,100 const ProcessSP &process_sp,101 addr_t header_addr) {102 return nullptr;103}104 105size_t ObjectFileJSON::GetModuleSpecifications(106 const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,107 offset_t file_offset, offset_t length, ModuleSpecList &specs) {108 if (!MagicBytesMatch(data_sp, data_offset, data_sp->GetByteSize()))109 return 0;110 111 // Update the data to contain the entire file if it doesn't already.112 if (data_sp->GetByteSize() < length) {113 data_sp = MapFileData(file, length, file_offset);114 if (!data_sp)115 return 0;116 data_offset = 0;117 }118 119 Log *log = GetLog(LLDBLog::Symbols);120 121 auto text =122 llvm::StringRef(reinterpret_cast<const char *>(data_sp->GetBytes()));123 124 Expected<json::Value> json = json::parse(text);125 if (!json) {126 LLDB_LOG_ERROR(log, json.takeError(),127 "failed to parse JSON object file: {0}");128 return 0;129 }130 131 json::Path::Root root;132 Header header;133 if (!fromJSON(*json, header, root)) {134 LLDB_LOG_ERROR(log, root.getError(),135 "failed to parse JSON object file header: {0}");136 return 0;137 }138 139 ArchSpec arch(header.triple);140 UUID uuid;141 uuid.SetFromStringRef(header.uuid);142 143 ModuleSpec spec(file, std::move(arch));144 spec.GetUUID() = std::move(uuid);145 specs.Append(spec);146 return 1;147}148 149ObjectFileJSON::ObjectFileJSON(const ModuleSP &module_sp, DataBufferSP &data_sp,150 offset_t data_offset, const FileSpec *file,151 offset_t offset, offset_t length, ArchSpec arch,152 UUID uuid, Type type,153 std::vector<JSONSymbol> symbols,154 std::vector<JSONSection> sections)155 : ObjectFile(module_sp, file, offset, length, data_sp, data_offset),156 m_arch(std::move(arch)), m_uuid(std::move(uuid)), m_type(type),157 m_symbols(std::move(symbols)), m_sections(std::move(sections)) {}158 159bool ObjectFileJSON::ParseHeader() {160 // We already parsed the header during initialization.161 return true;162}163 164void ObjectFileJSON::ParseSymtab(Symtab &symtab) {165 Log *log = GetLog(LLDBLog::Symbols);166 SectionList *section_list = GetModule()->GetSectionList();167 for (JSONSymbol json_symbol : m_symbols) {168 llvm::Expected<Symbol> symbol = Symbol::FromJSON(json_symbol, section_list);169 if (!symbol) {170 LLDB_LOG_ERROR(log, symbol.takeError(), "invalid symbol: {0}");171 continue;172 }173 symtab.AddSymbol(*symbol);174 }175 symtab.Finalize();176}177 178void ObjectFileJSON::CreateSections(SectionList &unified_section_list) {179 if (m_sections_up)180 return;181 m_sections_up = std::make_unique<SectionList>();182 183 lldb::user_id_t id = 0;184 for (const auto &json_section : m_sections) {185 auto make_section = [this, &id](const JSONSection §ion,186 SectionSP parent_section_sp =187 nullptr) -> SectionSP {188 SectionSP section_sp;189 auto sect_id = section.user_id.value_or(id + 1);190 if (!section.user_id.has_value())191 ++id;192 const auto name = ConstString(section.name);193 const auto sect_type = section.type.value_or(eSectionTypeCode);194 const auto vm_addr = section.address.value_or(0);195 const auto vm_size = section.size.value_or(0);196 const auto file_offset = section.file_offset.value_or(0);197 const auto file_size = section.file_size.value_or(0);198 const auto log2align = section.log2align.value_or(0);199 const auto flags = section.flags.value_or(0);200 if (parent_section_sp) {201 section_sp = std::make_shared<Section>(202 parent_section_sp, GetModule(), this, sect_id, name, sect_type,203 vm_addr - parent_section_sp->GetFileAddress(), vm_size, file_offset,204 file_size, log2align, flags);205 206 } else {207 section_sp = std::make_shared<Section>(208 GetModule(), this, sect_id, name, sect_type, vm_addr, vm_size,209 file_offset, file_size, log2align, flags);210 }211 // Set permissions212 uint32_t permissions = 0;213 if (section.read.value_or(0))214 permissions |= lldb::ePermissionsReadable;215 if (section.write.value_or(0))216 permissions |= lldb::ePermissionsWritable;217 if (section.execute.value_or(0))218 permissions |= lldb::ePermissionsExecutable;219 if (permissions)220 section_sp->SetPermissions(permissions);221 section_sp->SetIsFake(section.fake.value_or(false));222 section_sp->SetIsEncrypted(section.encrypted.value_or(false));223 section_sp->SetIsThreadSpecific(section.thread_specific.value_or(false));224 return section_sp;225 };226 auto section_sp = make_section(json_section);227 for (const auto &subsection : json_section.subsections) {228 SectionSP subsection_sp = make_section(subsection, section_sp);229 section_sp->GetChildren().AddSection(subsection_sp);230 }231 232 m_sections_up->AddSection(section_sp);233 unified_section_list.AddSection(section_sp);234 }235}236 237bool ObjectFileJSON::SetLoadAddress(Target &target, lldb::addr_t value,238 bool value_is_offset) {239 Log *log(GetLog(LLDBLog::DynamicLoader));240 if (!m_sections_up)241 return true;242 243 addr_t slide = value;244 if (!value_is_offset) {245 addr_t lowest_addr = LLDB_INVALID_ADDRESS;246 for (const SectionSP §ion_sp : *m_sections_up) {247 addr_t section_load_addr = section_sp->GetFileAddress();248 lowest_addr = std::min(lowest_addr, section_load_addr);249 }250 if (lowest_addr == LLDB_INVALID_ADDRESS)251 return false;252 slide = value - lowest_addr;253 }254 255 // Apply slide to each section's file address.256 for (const SectionSP §ion_sp : *m_sections_up) {257 addr_t section_load_addr = section_sp->GetFileAddress();258 if (section_load_addr != LLDB_INVALID_ADDRESS) {259 LLDB_LOGF(260 log,261 "ObjectFileJSON::SetLoadAddress section %s to load addr 0x%" PRIx64,262 section_sp->GetName().AsCString(), section_load_addr + slide);263 target.SetSectionLoadAddress(section_sp, section_load_addr + slide,264 /*warn_multiple=*/true);265 }266 }267 268 return true;269}270 271bool ObjectFileJSON::MagicBytesMatch(DataBufferSP data_sp,272 lldb::addr_t data_offset,273 lldb::addr_t data_length) {274 DataExtractor data;275 data.SetData(data_sp, data_offset, data_length);276 lldb::offset_t offset = 0;277 uint32_t magic = data.GetU8(&offset);278 return magic == '{';279}280 281namespace lldb_private {282 283bool fromJSON(const json::Value &value, ObjectFileJSON::Header &header,284 json::Path path) {285 json::ObjectMapper o(value, path);286 return o && o.map("triple", header.triple) && o.map("uuid", header.uuid) &&287 o.map("type", header.type);288}289 290bool fromJSON(const json::Value &value, ObjectFileJSON::Body &body,291 json::Path path) {292 json::ObjectMapper o(value, path);293 return o && o.mapOptional("symbols", body.symbols) &&294 o.mapOptional("sections", body.sections);295}296 297} // namespace lldb_private298