//===-- ObjectFileJSON.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "Plugins/ObjectFile/JSON/ObjectFileJSON.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "llvm/ADT/DenseSet.h" #include using namespace llvm; using namespace lldb; using namespace lldb_private; LLDB_PLUGIN_DEFINE(ObjectFileJSON) char ObjectFileJSON::ID; void ObjectFileJSON::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, CreateMemoryInstance, GetModuleSpecifications); } void ObjectFileJSON::Terminate() { PluginManager::UnregisterPlugin(CreateInstance); } ObjectFile * ObjectFileJSON::CreateInstance(const ModuleSP &module_sp, DataBufferSP data_sp, offset_t data_offset, const FileSpec *file, offset_t file_offset, offset_t length) { if (!data_sp) { data_sp = MapFileData(*file, length, file_offset); if (!data_sp) return nullptr; data_offset = 0; } if (!MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) return nullptr; // Update the data to contain the entire file if it doesn't already. if (data_sp->GetByteSize() < length) { data_sp = MapFileData(*file, length, file_offset); if (!data_sp) return nullptr; data_offset = 0; } Log *log = GetLog(LLDBLog::Symbols); auto text = llvm::StringRef(reinterpret_cast(data_sp->GetBytes())); Expected json = json::parse(text); if (!json) { LLDB_LOG_ERROR(log, json.takeError(), "failed to parse JSON object file: {0}"); return nullptr; } json::Path::Root root; Header header; if (!fromJSON(*json, header, root)) { LLDB_LOG_ERROR(log, root.getError(), "failed to parse JSON object file header: {0}"); return nullptr; } ArchSpec arch(header.triple); UUID uuid; uuid.SetFromStringRef(header.uuid); Type type = header.type.value_or(eTypeDebugInfo); Body body; if (!fromJSON(*json, body, root)) { LLDB_LOG_ERROR(log, root.getError(), "failed to parse JSON object file body: {0}"); return nullptr; } return new ObjectFileJSON(module_sp, data_sp, data_offset, file, file_offset, length, std::move(arch), std::move(uuid), type, std::move(body.symbols), std::move(body.sections)); } ObjectFile *ObjectFileJSON::CreateMemoryInstance(const ModuleSP &module_sp, WritableDataBufferSP data_sp, const ProcessSP &process_sp, addr_t header_addr) { return nullptr; } size_t ObjectFileJSON::GetModuleSpecifications( const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, offset_t file_offset, offset_t length, ModuleSpecList &specs) { if (!MagicBytesMatch(data_sp, data_offset, data_sp->GetByteSize())) return 0; // Update the data to contain the entire file if it doesn't already. if (data_sp->GetByteSize() < length) { data_sp = MapFileData(file, length, file_offset); if (!data_sp) return 0; data_offset = 0; } Log *log = GetLog(LLDBLog::Symbols); auto text = llvm::StringRef(reinterpret_cast(data_sp->GetBytes())); Expected json = json::parse(text); if (!json) { LLDB_LOG_ERROR(log, json.takeError(), "failed to parse JSON object file: {0}"); return 0; } json::Path::Root root; Header header; if (!fromJSON(*json, header, root)) { LLDB_LOG_ERROR(log, root.getError(), "failed to parse JSON object file header: {0}"); return 0; } ArchSpec arch(header.triple); UUID uuid; uuid.SetFromStringRef(header.uuid); ModuleSpec spec(file, std::move(arch)); spec.GetUUID() = std::move(uuid); specs.Append(spec); return 1; } ObjectFileJSON::ObjectFileJSON(const ModuleSP &module_sp, DataBufferSP &data_sp, offset_t data_offset, const FileSpec *file, offset_t offset, offset_t length, ArchSpec arch, UUID uuid, Type type, std::vector symbols, std::vector sections) : ObjectFile(module_sp, file, offset, length, data_sp, data_offset), m_arch(std::move(arch)), m_uuid(std::move(uuid)), m_type(type), m_symbols(std::move(symbols)), m_sections(std::move(sections)) {} bool ObjectFileJSON::ParseHeader() { // We already parsed the header during initialization. return true; } void ObjectFileJSON::ParseSymtab(Symtab &symtab) { Log *log = GetLog(LLDBLog::Symbols); SectionList *section_list = GetModule()->GetSectionList(); for (JSONSymbol json_symbol : m_symbols) { llvm::Expected symbol = Symbol::FromJSON(json_symbol, section_list); if (!symbol) { LLDB_LOG_ERROR(log, symbol.takeError(), "invalid symbol: {0}"); continue; } symtab.AddSymbol(*symbol); } symtab.Finalize(); } void ObjectFileJSON::CreateSections(SectionList &unified_section_list) { if (m_sections_up) return; m_sections_up = std::make_unique(); lldb::user_id_t id = 1; for (const auto §ion : m_sections) { auto section_sp = std::make_shared
( GetModule(), this, id++, ConstString(section.name), section.type.value_or(eSectionTypeCode), 0, section.size.value_or(0), 0, section.size.value_or(0), /*log2align*/ 0, /*flags*/ 0); m_sections_up->AddSection(section_sp); unified_section_list.AddSection(section_sp); } } bool ObjectFileJSON::MagicBytesMatch(DataBufferSP data_sp, lldb::addr_t data_offset, lldb::addr_t data_length) { DataExtractor data; data.SetData(data_sp, data_offset, data_length); lldb::offset_t offset = 0; uint32_t magic = data.GetU8(&offset); return magic == '{'; } namespace lldb_private { bool fromJSON(const json::Value &value, ObjectFileJSON::Header &header, json::Path path) { json::ObjectMapper o(value, path); return o && o.map("triple", header.triple) && o.map("uuid", header.uuid) && o.map("type", header.type); } bool fromJSON(const json::Value &value, ObjectFileJSON::Body &body, json::Path path) { json::ObjectMapper o(value, path); return o && o.mapOptional("symbols", body.symbols) && o.mapOptional("sections", body.sections); } } // namespace lldb_private