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