17fa27ce4SDimitry Andric //===-- ObjectFileJSON.cpp ------------------------------------------------===//
27fa27ce4SDimitry Andric //
37fa27ce4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47fa27ce4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
57fa27ce4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67fa27ce4SDimitry Andric //
77fa27ce4SDimitry Andric //===----------------------------------------------------------------------===//
87fa27ce4SDimitry Andric
97fa27ce4SDimitry Andric #include "Plugins/ObjectFile/JSON/ObjectFileJSON.h"
107fa27ce4SDimitry Andric #include "lldb/Core/Module.h"
117fa27ce4SDimitry Andric #include "lldb/Core/ModuleSpec.h"
127fa27ce4SDimitry Andric #include "lldb/Core/PluginManager.h"
137fa27ce4SDimitry Andric #include "lldb/Core/Section.h"
147fa27ce4SDimitry Andric #include "lldb/Symbol/Symbol.h"
157fa27ce4SDimitry Andric #include "lldb/Utility/LLDBLog.h"
167fa27ce4SDimitry Andric #include "lldb/Utility/Log.h"
177fa27ce4SDimitry Andric #include "llvm/ADT/DenseSet.h"
187fa27ce4SDimitry Andric #include <optional>
197fa27ce4SDimitry Andric
207fa27ce4SDimitry Andric using namespace llvm;
217fa27ce4SDimitry Andric using namespace lldb;
227fa27ce4SDimitry Andric using namespace lldb_private;
237fa27ce4SDimitry Andric
247fa27ce4SDimitry Andric LLDB_PLUGIN_DEFINE(ObjectFileJSON)
257fa27ce4SDimitry Andric
267fa27ce4SDimitry Andric char ObjectFileJSON::ID;
277fa27ce4SDimitry Andric
Initialize()287fa27ce4SDimitry Andric void ObjectFileJSON::Initialize() {
297fa27ce4SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(),
307fa27ce4SDimitry Andric GetPluginDescriptionStatic(), CreateInstance,
317fa27ce4SDimitry Andric CreateMemoryInstance, GetModuleSpecifications);
327fa27ce4SDimitry Andric }
337fa27ce4SDimitry Andric
Terminate()347fa27ce4SDimitry Andric void ObjectFileJSON::Terminate() {
357fa27ce4SDimitry Andric PluginManager::UnregisterPlugin(CreateInstance);
367fa27ce4SDimitry Andric }
377fa27ce4SDimitry Andric
387fa27ce4SDimitry Andric ObjectFile *
CreateInstance(const ModuleSP & module_sp,DataBufferSP data_sp,offset_t data_offset,const FileSpec * file,offset_t file_offset,offset_t length)397fa27ce4SDimitry Andric ObjectFileJSON::CreateInstance(const ModuleSP &module_sp, DataBufferSP data_sp,
407fa27ce4SDimitry Andric offset_t data_offset, const FileSpec *file,
417fa27ce4SDimitry Andric offset_t file_offset, offset_t length) {
427fa27ce4SDimitry Andric if (!data_sp) {
437fa27ce4SDimitry Andric data_sp = MapFileData(*file, length, file_offset);
447fa27ce4SDimitry Andric if (!data_sp)
457fa27ce4SDimitry Andric return nullptr;
467fa27ce4SDimitry Andric data_offset = 0;
477fa27ce4SDimitry Andric }
487fa27ce4SDimitry Andric
497fa27ce4SDimitry Andric if (!MagicBytesMatch(data_sp, 0, data_sp->GetByteSize()))
507fa27ce4SDimitry Andric return nullptr;
517fa27ce4SDimitry Andric
527fa27ce4SDimitry Andric // Update the data to contain the entire file if it doesn't already.
537fa27ce4SDimitry Andric if (data_sp->GetByteSize() < length) {
547fa27ce4SDimitry Andric data_sp = MapFileData(*file, length, file_offset);
557fa27ce4SDimitry Andric if (!data_sp)
567fa27ce4SDimitry Andric return nullptr;
577fa27ce4SDimitry Andric data_offset = 0;
587fa27ce4SDimitry Andric }
597fa27ce4SDimitry Andric
607fa27ce4SDimitry Andric Log *log = GetLog(LLDBLog::Symbols);
617fa27ce4SDimitry Andric
627fa27ce4SDimitry Andric auto text =
637fa27ce4SDimitry Andric llvm::StringRef(reinterpret_cast<const char *>(data_sp->GetBytes()));
647fa27ce4SDimitry Andric
657fa27ce4SDimitry Andric Expected<json::Value> json = json::parse(text);
667fa27ce4SDimitry Andric if (!json) {
677fa27ce4SDimitry Andric LLDB_LOG_ERROR(log, json.takeError(),
687fa27ce4SDimitry Andric "failed to parse JSON object file: {0}");
697fa27ce4SDimitry Andric return nullptr;
707fa27ce4SDimitry Andric }
717fa27ce4SDimitry Andric
727fa27ce4SDimitry Andric json::Path::Root root;
737fa27ce4SDimitry Andric Header header;
747fa27ce4SDimitry Andric if (!fromJSON(*json, header, root)) {
757fa27ce4SDimitry Andric LLDB_LOG_ERROR(log, root.getError(),
767fa27ce4SDimitry Andric "failed to parse JSON object file header: {0}");
777fa27ce4SDimitry Andric return nullptr;
787fa27ce4SDimitry Andric }
797fa27ce4SDimitry Andric
807fa27ce4SDimitry Andric ArchSpec arch(header.triple);
817fa27ce4SDimitry Andric UUID uuid;
827fa27ce4SDimitry Andric uuid.SetFromStringRef(header.uuid);
837fa27ce4SDimitry Andric Type type = header.type.value_or(eTypeDebugInfo);
847fa27ce4SDimitry Andric
857fa27ce4SDimitry Andric Body body;
867fa27ce4SDimitry Andric if (!fromJSON(*json, body, root)) {
877fa27ce4SDimitry Andric LLDB_LOG_ERROR(log, root.getError(),
887fa27ce4SDimitry Andric "failed to parse JSON object file body: {0}");
897fa27ce4SDimitry Andric return nullptr;
907fa27ce4SDimitry Andric }
917fa27ce4SDimitry Andric
927fa27ce4SDimitry Andric return new ObjectFileJSON(module_sp, data_sp, data_offset, file, file_offset,
937fa27ce4SDimitry Andric length, std::move(arch), std::move(uuid), type,
947fa27ce4SDimitry Andric std::move(body.symbols), std::move(body.sections));
957fa27ce4SDimitry Andric }
967fa27ce4SDimitry Andric
CreateMemoryInstance(const ModuleSP & module_sp,WritableDataBufferSP data_sp,const ProcessSP & process_sp,addr_t header_addr)977fa27ce4SDimitry Andric ObjectFile *ObjectFileJSON::CreateMemoryInstance(const ModuleSP &module_sp,
987fa27ce4SDimitry Andric WritableDataBufferSP data_sp,
997fa27ce4SDimitry Andric const ProcessSP &process_sp,
1007fa27ce4SDimitry Andric addr_t header_addr) {
1017fa27ce4SDimitry Andric return nullptr;
1027fa27ce4SDimitry Andric }
1037fa27ce4SDimitry Andric
GetModuleSpecifications(const FileSpec & file,DataBufferSP & data_sp,offset_t data_offset,offset_t file_offset,offset_t length,ModuleSpecList & specs)1047fa27ce4SDimitry Andric size_t ObjectFileJSON::GetModuleSpecifications(
1057fa27ce4SDimitry Andric const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
1067fa27ce4SDimitry Andric offset_t file_offset, offset_t length, ModuleSpecList &specs) {
1077fa27ce4SDimitry Andric if (!MagicBytesMatch(data_sp, data_offset, data_sp->GetByteSize()))
1087fa27ce4SDimitry Andric return 0;
1097fa27ce4SDimitry Andric
1107fa27ce4SDimitry Andric // Update the data to contain the entire file if it doesn't already.
1117fa27ce4SDimitry Andric if (data_sp->GetByteSize() < length) {
1127fa27ce4SDimitry Andric data_sp = MapFileData(file, length, file_offset);
1137fa27ce4SDimitry Andric if (!data_sp)
1147fa27ce4SDimitry Andric return 0;
1157fa27ce4SDimitry Andric data_offset = 0;
1167fa27ce4SDimitry Andric }
1177fa27ce4SDimitry Andric
1187fa27ce4SDimitry Andric Log *log = GetLog(LLDBLog::Symbols);
1197fa27ce4SDimitry Andric
1207fa27ce4SDimitry Andric auto text =
1217fa27ce4SDimitry Andric llvm::StringRef(reinterpret_cast<const char *>(data_sp->GetBytes()));
1227fa27ce4SDimitry Andric
1237fa27ce4SDimitry Andric Expected<json::Value> json = json::parse(text);
1247fa27ce4SDimitry Andric if (!json) {
1257fa27ce4SDimitry Andric LLDB_LOG_ERROR(log, json.takeError(),
1267fa27ce4SDimitry Andric "failed to parse JSON object file: {0}");
1277fa27ce4SDimitry Andric return 0;
1287fa27ce4SDimitry Andric }
1297fa27ce4SDimitry Andric
1307fa27ce4SDimitry Andric json::Path::Root root;
1317fa27ce4SDimitry Andric Header header;
1327fa27ce4SDimitry Andric if (!fromJSON(*json, header, root)) {
1337fa27ce4SDimitry Andric LLDB_LOG_ERROR(log, root.getError(),
1347fa27ce4SDimitry Andric "failed to parse JSON object file header: {0}");
1357fa27ce4SDimitry Andric return 0;
1367fa27ce4SDimitry Andric }
1377fa27ce4SDimitry Andric
1387fa27ce4SDimitry Andric ArchSpec arch(header.triple);
1397fa27ce4SDimitry Andric UUID uuid;
1407fa27ce4SDimitry Andric uuid.SetFromStringRef(header.uuid);
1417fa27ce4SDimitry Andric
1427fa27ce4SDimitry Andric ModuleSpec spec(file, std::move(arch));
1437fa27ce4SDimitry Andric spec.GetUUID() = std::move(uuid);
1447fa27ce4SDimitry Andric specs.Append(spec);
1457fa27ce4SDimitry Andric return 1;
1467fa27ce4SDimitry Andric }
1477fa27ce4SDimitry Andric
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<JSONSymbol> symbols,std::vector<JSONSection> sections)1487fa27ce4SDimitry Andric ObjectFileJSON::ObjectFileJSON(const ModuleSP &module_sp, DataBufferSP &data_sp,
1497fa27ce4SDimitry Andric offset_t data_offset, const FileSpec *file,
1507fa27ce4SDimitry Andric offset_t offset, offset_t length, ArchSpec arch,
1517fa27ce4SDimitry Andric UUID uuid, Type type,
1527fa27ce4SDimitry Andric std::vector<JSONSymbol> symbols,
1537fa27ce4SDimitry Andric std::vector<JSONSection> sections)
1547fa27ce4SDimitry Andric : ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
1557fa27ce4SDimitry Andric m_arch(std::move(arch)), m_uuid(std::move(uuid)), m_type(type),
1567fa27ce4SDimitry Andric m_symbols(std::move(symbols)), m_sections(std::move(sections)) {}
1577fa27ce4SDimitry Andric
ParseHeader()1587fa27ce4SDimitry Andric bool ObjectFileJSON::ParseHeader() {
1597fa27ce4SDimitry Andric // We already parsed the header during initialization.
1607fa27ce4SDimitry Andric return true;
1617fa27ce4SDimitry Andric }
1627fa27ce4SDimitry Andric
ParseSymtab(Symtab & symtab)1637fa27ce4SDimitry Andric void ObjectFileJSON::ParseSymtab(Symtab &symtab) {
1647fa27ce4SDimitry Andric Log *log = GetLog(LLDBLog::Symbols);
1657fa27ce4SDimitry Andric SectionList *section_list = GetModule()->GetSectionList();
1667fa27ce4SDimitry Andric for (JSONSymbol json_symbol : m_symbols) {
1677fa27ce4SDimitry Andric llvm::Expected<Symbol> symbol = Symbol::FromJSON(json_symbol, section_list);
1687fa27ce4SDimitry Andric if (!symbol) {
1697fa27ce4SDimitry Andric LLDB_LOG_ERROR(log, symbol.takeError(), "invalid symbol: {0}");
1707fa27ce4SDimitry Andric continue;
1717fa27ce4SDimitry Andric }
1727fa27ce4SDimitry Andric symtab.AddSymbol(*symbol);
1737fa27ce4SDimitry Andric }
1747fa27ce4SDimitry Andric symtab.Finalize();
1757fa27ce4SDimitry Andric }
1767fa27ce4SDimitry Andric
CreateSections(SectionList & unified_section_list)1777fa27ce4SDimitry Andric void ObjectFileJSON::CreateSections(SectionList &unified_section_list) {
1787fa27ce4SDimitry Andric if (m_sections_up)
1797fa27ce4SDimitry Andric return;
1807fa27ce4SDimitry Andric m_sections_up = std::make_unique<SectionList>();
1817fa27ce4SDimitry Andric
1827fa27ce4SDimitry Andric lldb::user_id_t id = 1;
1837fa27ce4SDimitry Andric for (const auto §ion : m_sections) {
1847fa27ce4SDimitry Andric auto section_sp = std::make_shared<Section>(
1857fa27ce4SDimitry Andric GetModule(), this, id++, ConstString(section.name),
1867fa27ce4SDimitry Andric section.type.value_or(eSectionTypeCode), 0, section.size.value_or(0), 0,
1877fa27ce4SDimitry Andric section.size.value_or(0), /*log2align*/ 0, /*flags*/ 0);
1887fa27ce4SDimitry Andric m_sections_up->AddSection(section_sp);
1897fa27ce4SDimitry Andric unified_section_list.AddSection(section_sp);
1907fa27ce4SDimitry Andric }
1917fa27ce4SDimitry Andric }
1927fa27ce4SDimitry Andric
MagicBytesMatch(DataBufferSP data_sp,lldb::addr_t data_offset,lldb::addr_t data_length)1937fa27ce4SDimitry Andric bool ObjectFileJSON::MagicBytesMatch(DataBufferSP data_sp,
1947fa27ce4SDimitry Andric lldb::addr_t data_offset,
1957fa27ce4SDimitry Andric lldb::addr_t data_length) {
1967fa27ce4SDimitry Andric DataExtractor data;
1977fa27ce4SDimitry Andric data.SetData(data_sp, data_offset, data_length);
1987fa27ce4SDimitry Andric lldb::offset_t offset = 0;
1997fa27ce4SDimitry Andric uint32_t magic = data.GetU8(&offset);
2007fa27ce4SDimitry Andric return magic == '{';
2017fa27ce4SDimitry Andric }
2027fa27ce4SDimitry Andric
2037fa27ce4SDimitry Andric namespace lldb_private {
2047fa27ce4SDimitry Andric
fromJSON(const json::Value & value,ObjectFileJSON::Header & header,json::Path path)2057fa27ce4SDimitry Andric bool fromJSON(const json::Value &value, ObjectFileJSON::Header &header,
2067fa27ce4SDimitry Andric json::Path path) {
2077fa27ce4SDimitry Andric json::ObjectMapper o(value, path);
2087fa27ce4SDimitry Andric return o && o.map("triple", header.triple) && o.map("uuid", header.uuid) &&
2097fa27ce4SDimitry Andric o.map("type", header.type);
2107fa27ce4SDimitry Andric }
2117fa27ce4SDimitry Andric
fromJSON(const json::Value & value,ObjectFileJSON::Body & body,json::Path path)2127fa27ce4SDimitry Andric bool fromJSON(const json::Value &value, ObjectFileJSON::Body &body,
2137fa27ce4SDimitry Andric json::Path path) {
2147fa27ce4SDimitry Andric json::ObjectMapper o(value, path);
2157fa27ce4SDimitry Andric return o && o.mapOptional("symbols", body.symbols) &&
2167fa27ce4SDimitry Andric o.mapOptional("sections", body.sections);
2177fa27ce4SDimitry Andric }
2187fa27ce4SDimitry Andric
2197fa27ce4SDimitry Andric } // namespace lldb_private
220