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