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