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