xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp (revision b73445a32f8a3648372c0042ef633fe61b38d135)
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