LLDB mainline
ObjectFileJSON.cpp
Go to the documentation of this file.
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
10#include "lldb/Core/Module.h"
13#include "lldb/Core/Section.h"
14#include "lldb/Symbol/Symbol.h"
15#include "lldb/Target/Target.h"
17#include "lldb/Utility/Log.h"
18#include "llvm/ADT/DenseSet.h"
19#include <optional>
20
21using namespace llvm;
22using namespace lldb;
23using namespace lldb_private;
24
26
28
34
38
41 offset_t data_offset, const FileSpec *file,
42 offset_t file_offset, offset_t length) {
43 if (!data_sp) {
44 data_sp = MapFileData(*file, length, file_offset);
45 if (!data_sp)
46 return nullptr;
47 data_offset = 0;
48 }
49
50 if (!MagicBytesMatch(data_sp, 0, data_sp->GetByteSize()))
51 return nullptr;
52
53 // Update the data to contain the entire file if it doesn't already.
54 if (data_sp->GetByteSize() < length) {
55 data_sp = MapFileData(*file, length, file_offset);
56 if (!data_sp)
57 return nullptr;
58 data_offset = 0;
59 }
60
62
63 auto text =
64 llvm::StringRef(reinterpret_cast<const char *>(data_sp->GetBytes()));
65
66 Expected<json::Value> json = json::parse(text);
67 if (!json) {
68 LLDB_LOG_ERROR(log, json.takeError(),
69 "failed to parse JSON object file: {0}");
70 return nullptr;
71 }
72
73 json::Path::Root root;
74 Header header;
75 if (!fromJSON(*json, header, root)) {
76 LLDB_LOG_ERROR(log, root.getError(),
77 "failed to parse JSON object file header: {0}");
78 return nullptr;
79 }
80
81 ArchSpec arch(header.triple);
82 UUID uuid;
83 uuid.SetFromStringRef(header.uuid);
84 Type type = header.type.value_or(eTypeDebugInfo);
85
86 Body body;
87 if (!fromJSON(*json, body, root)) {
88 LLDB_LOG_ERROR(log, root.getError(),
89 "failed to parse JSON object file body: {0}");
90 return nullptr;
91 }
92
93 return new ObjectFileJSON(module_sp, data_sp, data_offset, file, file_offset,
94 length, std::move(arch), std::move(uuid), type,
95 std::move(body.symbols), std::move(body.sections));
96}
97
100 const ProcessSP &process_sp,
101 addr_t header_addr) {
102 return nullptr;
103}
104
106 const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
107 offset_t file_offset, offset_t length, ModuleSpecList &specs) {
108 if (!MagicBytesMatch(data_sp, data_offset, data_sp->GetByteSize()))
109 return 0;
110
111 // Update the data to contain the entire file if it doesn't already.
112 if (data_sp->GetByteSize() < length) {
113 data_sp = MapFileData(file, length, file_offset);
114 if (!data_sp)
115 return 0;
116 data_offset = 0;
117 }
118
120
121 auto text =
122 llvm::StringRef(reinterpret_cast<const char *>(data_sp->GetBytes()));
123
124 Expected<json::Value> json = json::parse(text);
125 if (!json) {
126 LLDB_LOG_ERROR(log, json.takeError(),
127 "failed to parse JSON object file: {0}");
128 return 0;
129 }
130
131 json::Path::Root root;
132 Header header;
133 if (!fromJSON(*json, header, root)) {
134 LLDB_LOG_ERROR(log, root.getError(),
135 "failed to parse JSON object file header: {0}");
136 return 0;
137 }
138
139 ArchSpec arch(header.triple);
140 UUID uuid;
141 uuid.SetFromStringRef(header.uuid);
142
143 ModuleSpec spec(file, std::move(arch));
144 spec.GetUUID() = std::move(uuid);
145 specs.Append(spec);
146 return 1;
147}
148
150 offset_t data_offset, const FileSpec *file,
151 offset_t offset, offset_t length, ArchSpec arch,
152 UUID uuid, Type type,
153 std::vector<JSONSymbol> symbols,
154 std::vector<JSONSection> sections)
155 : ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
156 m_arch(std::move(arch)), m_uuid(std::move(uuid)), m_type(type),
157 m_symbols(std::move(symbols)), m_sections(std::move(sections)) {}
158
160 // We already parsed the header during initialization.
161 return true;
162}
163
166 SectionList *section_list = GetModule()->GetSectionList();
167 for (JSONSymbol json_symbol : m_symbols) {
168 llvm::Expected<Symbol> symbol = Symbol::FromJSON(json_symbol, section_list);
169 if (!symbol) {
170 LLDB_LOG_ERROR(log, symbol.takeError(), "invalid symbol: {0}");
171 continue;
172 }
173 symtab.AddSymbol(*symbol);
174 }
175 symtab.Finalize();
176}
177
178void ObjectFileJSON::CreateSections(SectionList &unified_section_list) {
179 if (m_sections_up)
180 return;
181 m_sections_up = std::make_unique<SectionList>();
182
183 lldb::user_id_t id = 0;
184 for (const auto &json_section : m_sections) {
185 auto make_section = [this, &id](const JSONSection &section,
186 SectionSP parent_section_sp =
187 nullptr) -> SectionSP {
188 SectionSP section_sp;
189 auto sect_id = section.user_id.value_or(id + 1);
190 if (!section.user_id.has_value())
191 ++id;
192 const auto name = ConstString(section.name);
193 const auto sect_type = section.type.value_or(eSectionTypeCode);
194 const auto vm_addr = section.address.value_or(0);
195 const auto vm_size = section.size.value_or(0);
196 const auto file_offset = section.file_offset.value_or(0);
197 const auto file_size = section.file_size.value_or(0);
198 const auto log2align = section.log2align.value_or(0);
199 const auto flags = section.flags.value_or(0);
200 if (parent_section_sp) {
201 section_sp = std::make_shared<Section>(
202 parent_section_sp, GetModule(), this, sect_id, name, sect_type,
203 vm_addr - parent_section_sp->GetFileAddress(), vm_size, file_offset,
204 file_size, log2align, flags);
205
206 } else {
207 section_sp = std::make_shared<Section>(
208 GetModule(), this, sect_id, name, sect_type, vm_addr, vm_size,
209 file_offset, file_size, log2align, flags);
210 }
211 // Set permissions
212 uint32_t permissions = 0;
213 if (section.read.value_or(0))
214 permissions |= lldb::ePermissionsReadable;
215 if (section.write.value_or(0))
216 permissions |= lldb::ePermissionsWritable;
217 if (section.execute.value_or(0))
218 permissions |= lldb::ePermissionsExecutable;
219 if (permissions)
220 section_sp->SetPermissions(permissions);
221 section_sp->SetIsFake(section.fake.value_or(false));
222 section_sp->SetIsEncrypted(section.encrypted.value_or(false));
223 section_sp->SetIsThreadSpecific(section.thread_specific.value_or(false));
224 return section_sp;
225 };
226 auto section_sp = make_section(json_section);
227 for (const auto &subsection : json_section.subsections) {
228 SectionSP subsection_sp = make_section(subsection, section_sp);
229 section_sp->GetChildren().AddSection(subsection_sp);
230 }
231
232 m_sections_up->AddSection(section_sp);
233 unified_section_list.AddSection(section_sp);
234 }
235}
236
238 bool value_is_offset) {
240 if (!m_sections_up)
241 return true;
242
243 addr_t slide = value;
244 if (!value_is_offset) {
245 addr_t lowest_addr = LLDB_INVALID_ADDRESS;
246 for (const SectionSP &section_sp : *m_sections_up) {
247 addr_t section_load_addr = section_sp->GetFileAddress();
248 lowest_addr = std::min(lowest_addr, section_load_addr);
249 }
250 if (lowest_addr == LLDB_INVALID_ADDRESS)
251 return false;
252 slide = value - lowest_addr;
253 }
254
255 // Apply slide to each section's file address.
256 for (const SectionSP &section_sp : *m_sections_up) {
257 addr_t section_load_addr = section_sp->GetFileAddress();
258 if (section_load_addr != LLDB_INVALID_ADDRESS) {
259 LLDB_LOGF(
260 log,
261 "ObjectFileJSON::SetLoadAddress section %s to load addr 0x%" PRIx64,
262 section_sp->GetName().AsCString(), section_load_addr + slide);
263 target.SetSectionLoadAddress(section_sp, section_load_addr + slide,
264 /*warn_multiple=*/true);
265 }
266 }
267
268 return true;
269}
270
272 lldb::addr_t data_offset,
273 lldb::addr_t data_length) {
274 DataExtractor data;
275 data.SetData(data_sp, data_offset, data_length);
276 lldb::offset_t offset = 0;
277 uint32_t magic = data.GetU8(&offset);
278 return magic == '{';
279}
280
281namespace lldb_private {
282
283bool fromJSON(const json::Value &value, ObjectFileJSON::Header &header,
284 json::Path path) {
285 json::ObjectMapper o(value, path);
286 return o && o.map("triple", header.triple) && o.map("uuid", header.uuid) &&
287 o.map("type", header.type);
288}
289
290bool fromJSON(const json::Value &value, ObjectFileJSON::Body &body,
291 json::Path path) {
292 json::ObjectMapper o(value, path);
293 return o && o.mapOptional("symbols", body.symbols) &&
294 o.mapOptional("sections", body.sections);
295}
296
297} // namespace lldb_private
#define LLDB_LOGF(log,...)
Definition Log.h:376
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:392
#define LLDB_PLUGIN_DEFINE(PluginName)
An architecture specification class.
Definition ArchSpec.h:31
A uniqued constant string class.
Definition ConstString.h:40
An data extractor class.
lldb::offset_t SetData(const void *bytes, lldb::offset_t length, lldb::ByteOrder byte_order)
Set data with a buffer that is caller owned.
uint8_t GetU8(lldb::offset_t *offset_ptr) const
Extract a uint8_t value from *offset_ptr.
A file utility class.
Definition FileSpec.h:57
lldb::ModuleSP GetModule() const
Get const accessor for the module pointer.
void Append(const ModuleSpec &spec)
Definition ModuleSpec.h:308
std::vector< JSONSection > m_sections
bool SetLoadAddress(Target &target, lldb::addr_t value, bool value_is_offset) override
Sets the load address for an entire module, assuming a rigid slide of sections, if possible in the im...
static ObjectFile * CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, lldb::offset_t data_offset, const FileSpec *file, lldb::offset_t file_offset, lldb::offset_t length)
ObjectFileJSON(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, const FileSpec *file, lldb::offset_t offset, lldb::offset_t length, ArchSpec arch, UUID uuid, Type type, std::vector< JSONSymbol > symbols, std::vector< JSONSection > sections)
void ParseSymtab(lldb_private::Symtab &symtab) override
Parse the symbol table into the provides symbol table object.
static bool MagicBytesMatch(lldb::DataBufferSP data_sp, lldb::addr_t offset, lldb::addr_t length)
static const char * GetPluginDescriptionStatic()
static size_t GetModuleSpecifications(const FileSpec &file, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, ModuleSpecList &specs)
void CreateSections(SectionList &unified_section_list) override
bool ParseHeader() override
Attempts to parse the object header.
static ObjectFile * CreateMemoryInstance(const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, const lldb::ProcessSP &process_sp, lldb::addr_t header_addr)
std::vector< JSONSymbol > m_symbols
static llvm::StringRef GetPluginNameStatic()
A plug-in interface definition class for object file parsers.
Definition ObjectFile.h:45
std::unique_ptr< lldb_private::SectionList > m_sections_up
Definition ObjectFile.h:788
static lldb::DataBufferSP MapFileData(const FileSpec &file, uint64_t Size, uint64_t Offset)
ObjectFile(const lldb::ModuleSP &module_sp, const FileSpec *file_spec_ptr, lldb::offset_t file_offset, lldb::offset_t length, lldb::DataBufferSP data_sp, lldb::offset_t data_offset)
Construct with a parent module, offset, and header data.
@ eTypeDebugInfo
An object file that contains only debug information.
Definition ObjectFile.h:56
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
size_t AddSection(const lldb::SectionSP &section_sp)
Definition Section.cpp:482
static llvm::Expected< Symbol > FromJSON(const JSONSymbol &symbol, SectionList *section_list)
Definition Symbol.cpp:101
uint32_t AddSymbol(const Symbol &symbol)
Definition Symtab.cpp:64
bool SetSectionLoadAddress(const lldb::SectionSP &section, lldb::addr_t load_addr, bool warn_multiple=false)
Definition Target.cpp:3296
Represents UUID's of various sizes.
Definition UUID.h:27
bool SetFromStringRef(llvm::StringRef str)
Definition UUID.cpp:101
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:332
bool fromJSON(const llvm::json::Value &value, TraceSupportedResponse &info, llvm::json::Path path)
uint64_t offset_t
Definition lldb-types.h:85
std::shared_ptr< lldb_private::Process > ProcessSP
uint64_t user_id_t
Definition lldb-types.h:82
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
std::shared_ptr< lldb_private::Section > SectionSP
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::Module > ModuleSP
std::optional< lldb::user_id_t > user_id
Definition Section.h:104
std::optional< uint64_t > log2align
Definition Section.h:111
std::optional< uint64_t > size
Definition Section.h:108
std::optional< uint64_t > flags
Definition Section.h:112
std::optional< bool > encrypted
Definition Section.h:120
std::optional< bool > fake
Definition Section.h:119
std::optional< lldb::SectionType > type
Definition Section.h:106
std::optional< bool > write
Definition Section.h:116
std::optional< bool > execute
Definition Section.h:117
std::optional< uint64_t > file_offset
Definition Section.h:109
std::optional< uint64_t > address
Definition Section.h:107
std::optional< bool > thread_specific
Definition Section.h:121
std::optional< uint64_t > file_size
Definition Section.h:110
std::optional< bool > read
Definition Section.h:115
std::vector< JSONSymbol > symbols
std::vector< JSONSection > sections
std::optional< ObjectFile::Type > type