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 "llvm/ADT/StringExtras.h"
20#include <optional>
21
22using namespace llvm;
23using namespace lldb;
24using namespace lldb_private;
25
27
29
30/// Returns the JSON text in the buffer, which is not NULL terminated and may
31/// be zero padded past the end of the file.
32static StringRef GetText(const lldb_private::DataExtractor &data) {
33 StringRef text = toStringRef(data.GetData());
34 return text.substr(0, text.find('\0'));
35}
36
42
46
48 DataExtractorSP extractor_sp,
49 offset_t data_offset,
50 const FileSpec *file,
51 offset_t file_offset,
52 offset_t length) {
53 if (!extractor_sp || !extractor_sp->HasData()) {
54 DataBufferSP data_sp = MapFileData(*file, length, file_offset);
55 if (!data_sp)
56 return nullptr;
57 extractor_sp = std::make_shared<DataExtractor>(data_sp);
58 data_offset = 0;
59 }
60 if (!extractor_sp->HasData())
61 return nullptr;
62
63 if (!MagicBytesMatch(extractor_sp->GetSubsetExtractorSP(data_offset)))
64 return nullptr;
65
66 // Update the data to contain the entire file if it doesn't already.
67 if (extractor_sp->GetByteSize() < length) {
68 DataBufferSP data_sp = MapFileData(*file, length, file_offset);
69 if (!data_sp)
70 return nullptr;
71 extractor_sp->SetData(data_sp);
72 data_offset = 0;
73 }
74
76
77 StringRef text = GetText(*extractor_sp);
78
79 Expected<json::Value> json = json::parse(text);
80 if (!json) {
81 LLDB_LOG_ERROR(log, json.takeError(),
82 "failed to parse JSON object file: {0}");
83 return nullptr;
84 }
85
86 json::Path::Root root;
87 Header header;
88 if (!fromJSON(*json, header, root)) {
89 LLDB_LOG_ERROR(log, root.getError(),
90 "failed to parse JSON object file header: {0}");
91 return nullptr;
92 }
93
94 ArchSpec arch(header.triple);
95 UUID uuid;
96 uuid.SetFromStringRef(header.uuid);
97 Type type = header.type.value_or(eTypeDebugInfo);
98
99 Body body;
100 if (!fromJSON(*json, body, root)) {
101 LLDB_LOG_ERROR(log, root.getError(),
102 "failed to parse JSON object file body: {0}");
103 return nullptr;
104 }
105
106 return new ObjectFileJSON(module_sp, extractor_sp, data_offset, file,
107 file_offset, length, std::move(arch),
108 std::move(uuid), type, std::move(body.symbols),
109 std::move(body.sections));
110}
111
113 WritableDataBufferSP data_sp,
114 const ProcessSP &process_sp,
115 addr_t header_addr) {
116 return nullptr;
117}
118
121 DataExtractorSP &extractor_sp,
122 offset_t file_offset, offset_t length) {
123 if (!extractor_sp || !MagicBytesMatch(extractor_sp))
124 return {};
125
126 // Update the data to contain the entire file if it doesn't already.
127 if (extractor_sp->GetByteSize() < length) {
128 if (DataBufferSP file_data_sp = MapFileData(file, length, file_offset))
129 extractor_sp->SetData(file_data_sp);
130 if (!extractor_sp->HasData())
131 return {};
132 }
133
135
136 StringRef text = GetText(*extractor_sp);
137
138 Expected<json::Value> json = json::parse(text);
139 if (!json) {
140 LLDB_LOG_ERROR(log, json.takeError(),
141 "failed to parse JSON object file: {0}");
142 return {};
143 }
144
145 json::Path::Root root;
146 Header header;
147 if (!fromJSON(*json, header, root)) {
148 LLDB_LOG_ERROR(log, root.getError(),
149 "failed to parse JSON object file header: {0}");
150 return {};
151 }
152
153 ArchSpec arch(header.triple);
154 UUID uuid;
155 uuid.SetFromStringRef(header.uuid);
156
157 ModuleSpec spec(file, std::move(arch));
158 spec.GetUUID() = std::move(uuid);
159 ModuleSpecList specs;
160 specs.Append(spec);
161 return specs;
162}
163
165 DataExtractorSP extractor_sp,
166 offset_t data_offset, const FileSpec *file,
167 offset_t offset, offset_t length, ArchSpec arch,
168 UUID uuid, Type type,
169 std::vector<JSONSymbol> symbols,
170 std::vector<JSONSection> sections)
171 : ObjectFile(module_sp, file, offset, length, extractor_sp, data_offset),
172 m_arch(std::move(arch)), m_uuid(std::move(uuid)), m_type(type),
173 m_symbols(std::move(symbols)), m_sections(std::move(sections)) {}
174
176 // We already parsed the header during initialization.
177 return true;
178}
179
182 SectionList *section_list = GetModule()->GetSectionList();
183 for (JSONSymbol json_symbol : m_symbols) {
184 llvm::Expected<Symbol> symbol = Symbol::FromJSON(json_symbol, section_list);
185 if (!symbol) {
186 LLDB_LOG_ERROR(log, symbol.takeError(), "invalid symbol: {0}");
187 continue;
188 }
189 symtab.AddSymbol(*symbol);
190 }
191 symtab.Finalize();
192}
193
194void ObjectFileJSON::CreateSections(SectionList &unified_section_list) {
195 if (m_sections_up)
196 return;
197 m_sections_up = std::make_unique<SectionList>();
198
199 lldb::user_id_t id = 0;
200 for (const auto &json_section : m_sections) {
201 auto make_section = [this, &id](const JSONSection &section,
202 SectionSP parent_section_sp =
203 nullptr) -> SectionSP {
204 SectionSP section_sp;
205 auto sect_id = section.user_id.value_or(id + 1);
206 if (!section.user_id.has_value())
207 ++id;
208 const auto name = ConstString(section.name);
209 const auto sect_type = section.type.value_or(eSectionTypeCode);
210 const auto vm_addr = section.address.value_or(0);
211 const auto vm_size = section.size.value_or(0);
212 const auto file_offset = section.file_offset.value_or(0);
213 const auto file_size = section.file_size.value_or(0);
214 const auto log2align = section.log2align.value_or(0);
215 const auto flags = section.flags.value_or(0);
216 if (parent_section_sp) {
217 section_sp = std::make_shared<Section>(
218 parent_section_sp, GetModule(), this, sect_id, name, sect_type,
219 vm_addr - parent_section_sp->GetFileAddress(), vm_size, file_offset,
220 file_size, log2align, flags);
221
222 } else {
223 section_sp = std::make_shared<Section>(
224 GetModule(), this, sect_id, name, sect_type, vm_addr, vm_size,
225 file_offset, file_size, log2align, flags);
226 }
227 // Set permissions
228 uint32_t permissions = 0;
229 if (section.read.value_or(0))
230 permissions |= lldb::ePermissionsReadable;
231 if (section.write.value_or(0))
232 permissions |= lldb::ePermissionsWritable;
233 if (section.execute.value_or(0))
234 permissions |= lldb::ePermissionsExecutable;
235 if (permissions)
236 section_sp->SetPermissions(permissions);
237 section_sp->SetIsFake(section.fake.value_or(false));
238 section_sp->SetIsEncrypted(section.encrypted.value_or(false));
239 section_sp->SetIsThreadSpecific(section.thread_specific.value_or(false));
240 return section_sp;
241 };
242 auto section_sp = make_section(json_section);
243 for (const auto &subsection : json_section.subsections) {
244 SectionSP subsection_sp = make_section(subsection, section_sp);
245 section_sp->GetChildren().AddSection(subsection_sp);
246 }
247
248 m_sections_up->AddSection(section_sp);
249 unified_section_list.AddSection(section_sp);
250 }
251}
252
254 bool value_is_offset) {
256 if (!m_sections_up)
257 return true;
258
259 addr_t slide = value;
260 if (!value_is_offset) {
261 addr_t lowest_addr = LLDB_INVALID_ADDRESS;
262 for (const SectionSP &section_sp : *m_sections_up) {
263 addr_t section_load_addr = section_sp->GetFileAddress();
264 lowest_addr = std::min(lowest_addr, section_load_addr);
265 }
266 if (lowest_addr == LLDB_INVALID_ADDRESS)
267 return false;
268 slide = value - lowest_addr;
269 }
270
271 // Apply slide to each section's file address.
272 for (const SectionSP &section_sp : *m_sections_up) {
273 addr_t section_load_addr = section_sp->GetFileAddress();
274 if (section_load_addr != LLDB_INVALID_ADDRESS) {
275 LLDB_LOG(log,
276 "ObjectFileJSON::SetLoadAddress section {0} to load addr {1:x}",
277 section_sp->GetName(), section_load_addr + slide);
278 target.SetSectionLoadAddress(section_sp, section_load_addr + slide,
279 /*warn_multiple=*/true);
280 }
281 }
282
283 return true;
284}
285
287 lldb::offset_t offset = 0;
288 char magic = extractor_sp->GetU8(&offset);
289 return magic == '{';
290}
291
292namespace lldb_private {
293
294bool fromJSON(const json::Value &value, ObjectFileJSON::Header &header,
295 json::Path path) {
296 json::ObjectMapper o(value, path);
297 return o && o.map("triple", header.triple) && o.map("uuid", header.uuid) &&
298 o.map("type", header.type);
299}
300
301bool fromJSON(const json::Value &value, ObjectFileJSON::Body &body,
302 json::Path path) {
303 json::ObjectMapper o(value, path);
304 return o && o.mapOptional("symbols", body.symbols) &&
305 o.mapOptional("sections", body.sections);
306}
307
308} // namespace lldb_private
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:375
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:405
static StringRef GetText(const lldb_private::DataExtractor &data)
Returns the JSON text in the buffer, which is not NULL terminated and may be zero padded past the end...
#define LLDB_PLUGIN_DEFINE(PluginName)
An architecture specification class.
Definition ArchSpec.h:32
A uniqued constant string class.
Definition ConstString.h:40
An data extractor class.
virtual const void * GetData(lldb::offset_t *offset_ptr, lldb::offset_t length) const
Extract length bytes from *offset_ptr.
A file utility class.
Definition FileSpec.h:56
lldb::ModuleSP GetModule() const
Get const accessor for the module pointer.
void Append(const ModuleSpec &spec)
Definition ModuleSpec.h:371
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 ModuleSpecList GetModuleSpecifications(const FileSpec &file, lldb::DataExtractorSP &extractor_sp, lldb::offset_t file_offset, lldb::offset_t length)
static bool MagicBytesMatch(lldb::DataExtractorSP extractor_sp)
ObjectFileJSON(const lldb::ModuleSP &module_sp, lldb::DataExtractorSP extractor_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 const char * GetPluginDescriptionStatic()
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 ObjectFile * CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataExtractorSP extractor_sp, lldb::offset_t data_offset, const FileSpec *file, lldb::offset_t file_offset, lldb::offset_t length)
static llvm::StringRef GetPluginNameStatic()
std::unique_ptr< lldb_private::SectionList > m_sections_up
Definition ObjectFile.h:785
static lldb::DataBufferSP MapFileData(const FileSpec &file, uint64_t Size, uint64_t Offset)
@ eTypeDebugInfo
An object file that contains only debug information.
Definition ObjectFile.h:57
ObjectFile(const lldb::ModuleSP &module_sp, const FileSpec *file_spec_ptr, lldb::offset_t file_offset, lldb::offset_t length, lldb::DataExtractorSP extractor_sp, lldb::offset_t data_offset)
Construct with a parent module, offset, and header data.
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:483
static llvm::Expected< Symbol > FromJSON(const JSONSymbol &symbol, SectionList *section_list)
Definition Symbol.cpp:127
uint32_t AddSymbol(const Symbol &symbol)
Definition Symtab.cpp:61
bool SetSectionLoadAddress(const lldb::SectionSP &section, lldb::addr_t load_addr, bool warn_multiple=false)
Definition Target.cpp:3506
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:338
bool fromJSON(const llvm::json::Value &value, SymbolValue &data, llvm::json::Path path)
uint64_t offset_t
Definition lldb-types.h:86
std::shared_ptr< lldb_private::Process > ProcessSP
uint64_t user_id_t
Definition lldb-types.h:83
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::DataExtractor > DataExtractorSP
std::shared_ptr< lldb_private::Module > ModuleSP
std::optional< lldb::user_id_t > user_id
Definition Section.h:117
std::optional< uint64_t > log2align
Definition Section.h:124
std::optional< uint64_t > size
Definition Section.h:121
std::optional< uint64_t > flags
Definition Section.h:125
std::optional< bool > encrypted
Definition Section.h:133
std::optional< bool > fake
Definition Section.h:132
std::optional< lldb::SectionType > type
Definition Section.h:119
std::optional< bool > write
Definition Section.h:129
std::optional< bool > execute
Definition Section.h:130
std::optional< uint64_t > file_offset
Definition Section.h:122
std::optional< uint64_t > address
Definition Section.h:120
std::optional< bool > thread_specific
Definition Section.h:134
std::optional< uint64_t > file_size
Definition Section.h:123
std::optional< bool > read
Definition Section.h:128
std::vector< JSONSymbol > symbols
std::vector< JSONSection > sections
std::optional< ObjectFile::Type > type