Skip to content

Commit 2af5204

Browse files
committed
[lldb] Make ObjectFileJSON loadable as a module
This patch adds support for creating modules from JSON object files. This is necessary for the crashlog use case where we don't have either a module or a symbol file. In that case the ObjectFileJSON serves as both. The patch adds support for an object file type (i.e. executable, shared library, etc). It also adds the ability to specify sections, which is necessary in order specify symbols by address. Finally, this patch improves error handling and fixes a bug where we wouldn't read more than the initial 512 bytes in GetModuleSpecifications. Differential revision: https://reviews.llvm.org/D148062 (cherry picked from commit 0e5cdbf)
1 parent 7cedca1 commit 2af5204

File tree

7 files changed

+255
-17
lines changed

7 files changed

+255
-17
lines changed

lldb/include/lldb/Core/Section.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "lldb/lldb-enumerations.h"
1818
#include "lldb/lldb-forward.h"
1919
#include "lldb/lldb-types.h"
20+
#include "llvm/Support/JSON.h"
2021

2122
#include <memory>
2223
#include <vector>
@@ -99,6 +100,13 @@ class SectionList {
99100
collection m_sections;
100101
};
101102

103+
struct JSONSection {
104+
std::string name;
105+
std::optional<lldb::SectionType> type;
106+
std::optional<uint64_t> address;
107+
std::optional<uint64_t> size;
108+
};
109+
102110
class Section : public std::enable_shared_from_this<Section>,
103111
public ModuleChild,
104112
public UserID,
@@ -294,4 +302,16 @@ class Section : public std::enable_shared_from_this<Section>,
294302

295303
} // namespace lldb_private
296304

305+
namespace llvm {
306+
namespace json {
307+
308+
bool fromJSON(const llvm::json::Value &value,
309+
lldb_private::JSONSection &section, llvm::json::Path path);
310+
311+
bool fromJSON(const llvm::json::Value &value, lldb::SectionType &type,
312+
llvm::json::Path path);
313+
314+
} // namespace json
315+
} // namespace llvm
316+
297317
#endif // LLDB_CORE_SECTION_H

lldb/include/lldb/Symbol/ObjectFile.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,11 @@ template <> struct format_provider<lldb_private::ObjectFile::Strata> {
799799
static void format(const lldb_private::ObjectFile::Strata &strata,
800800
raw_ostream &OS, StringRef Style);
801801
};
802+
803+
namespace json {
804+
bool fromJSON(const llvm::json::Value &value, lldb_private::ObjectFile::Type &,
805+
llvm::json::Path path);
806+
} // namespace json
802807
} // namespace llvm
803808

804809
#endif // LLDB_SYMBOL_OBJECTFILE_H

lldb/source/Core/Section.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,3 +691,36 @@ uint64_t SectionList::GetDebugInfoSize() const {
691691
}
692692
return debug_info_size;
693693
}
694+
695+
namespace llvm {
696+
namespace json {
697+
698+
bool fromJSON(const llvm::json::Value &value,
699+
lldb_private::JSONSection &section, llvm::json::Path path) {
700+
llvm::json::ObjectMapper o(value, path);
701+
return o && o.map("name", section.name) && o.map("type", section.type) &&
702+
o.map("size", section.address) && o.map("size", section.size);
703+
}
704+
705+
bool fromJSON(const llvm::json::Value &value, lldb::SectionType &type,
706+
llvm::json::Path path) {
707+
if (auto str = value.getAsString()) {
708+
type = llvm::StringSwitch<lldb::SectionType>(*str)
709+
.Case("code", eSectionTypeCode)
710+
.Case("container", eSectionTypeContainer)
711+
.Case("data", eSectionTypeData)
712+
.Case("debug", eSectionTypeDebug)
713+
.Default(eSectionTypeInvalid);
714+
715+
if (type == eSectionTypeInvalid) {
716+
path.report("invalid section type");
717+
return false;
718+
}
719+
720+
return true;
721+
}
722+
path.report("expected string");
723+
return false;
724+
}
725+
} // namespace json
726+
} // namespace llvm

lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,37 +49,49 @@ ObjectFileJSON::CreateInstance(const ModuleSP &module_sp, DataBufferSP data_sp,
4949
if (!MagicBytesMatch(data_sp, 0, data_sp->GetByteSize()))
5050
return nullptr;
5151

52+
// Update the data to contain the entire file if it doesn't already.
5253
if (data_sp->GetByteSize() < length) {
5354
data_sp = MapFileData(*file, length, file_offset);
5455
if (!data_sp)
5556
return nullptr;
5657
data_offset = 0;
5758
}
5859

60+
Log *log = GetLog(LLDBLog::Symbols);
61+
5962
auto text =
6063
llvm::StringRef(reinterpret_cast<const char *>(data_sp->GetBytes()));
6164

6265
Expected<json::Value> json = json::parse(text);
6366
if (!json) {
64-
llvm::consumeError(json.takeError());
67+
LLDB_LOG_ERROR(log, json.takeError(),
68+
"failed to parse JSON object file: {0}");
6569
return nullptr;
6670
}
6771

6872
json::Path::Root root;
6973
Header header;
70-
if (!fromJSON(*json, header, root))
74+
if (!fromJSON(*json, header, root)) {
75+
LLDB_LOG_ERROR(log, root.getError(),
76+
"failed to parse JSON object file header: {0}");
7177
return nullptr;
78+
}
7279

7380
ArchSpec arch(header.triple);
7481
UUID uuid;
7582
uuid.SetFromStringRef(header.uuid);
83+
Type type = header.type.value_or(eTypeDebugInfo);
7684

7785
Body body;
78-
fromJSON(*json, body, root);
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+
}
7991

8092
return new ObjectFileJSON(module_sp, data_sp, data_offset, file, file_offset,
81-
length, std::move(arch), std::move(uuid),
82-
std::move(body.symbols));
93+
length, std::move(arch), std::move(uuid), type,
94+
std::move(body.symbols), std::move(body.sections));
8395
}
8496

8597
ObjectFile *ObjectFileJSON::CreateMemoryInstance(const ModuleSP &module_sp,
@@ -92,23 +104,36 @@ ObjectFile *ObjectFileJSON::CreateMemoryInstance(const ModuleSP &module_sp,
92104
size_t ObjectFileJSON::GetModuleSpecifications(
93105
const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
94106
offset_t file_offset, offset_t length, ModuleSpecList &specs) {
95-
96107
if (!MagicBytesMatch(data_sp, data_offset, data_sp->GetByteSize()))
97108
return 0;
98109

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+
99120
auto text =
100121
llvm::StringRef(reinterpret_cast<const char *>(data_sp->GetBytes()));
101122

102123
Expected<json::Value> json = json::parse(text);
103124
if (!json) {
104-
llvm::consumeError(json.takeError());
125+
LLDB_LOG_ERROR(log, json.takeError(),
126+
"failed to parse JSON object file: {0}");
105127
return 0;
106128
}
107129

108130
json::Path::Root root;
109131
Header header;
110-
if (!fromJSON(*json, header, root))
132+
if (!fromJSON(*json, header, root)) {
133+
LLDB_LOG_ERROR(log, root.getError(),
134+
"failed to parse JSON object file header: {0}");
111135
return 0;
136+
}
112137

113138
ArchSpec arch(header.triple);
114139
UUID uuid;
@@ -123,10 +148,12 @@ size_t ObjectFileJSON::GetModuleSpecifications(
123148
ObjectFileJSON::ObjectFileJSON(const ModuleSP &module_sp, DataBufferSP &data_sp,
124149
offset_t data_offset, const FileSpec *file,
125150
offset_t offset, offset_t length, ArchSpec arch,
126-
UUID uuid, std::vector<JSONSymbol> symbols)
151+
UUID uuid, Type type,
152+
std::vector<JSONSymbol> symbols,
153+
std::vector<JSONSection> sections)
127154
: ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
128-
m_arch(std::move(arch)), m_uuid(std::move(uuid)),
129-
m_symbols(std::move(symbols)) {}
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)) {}
130157

131158
bool ObjectFileJSON::ParseHeader() {
132159
// We already parsed the header during initialization.
@@ -139,15 +166,29 @@ void ObjectFileJSON::ParseSymtab(Symtab &symtab) {
139166
for (JSONSymbol json_symbol : m_symbols) {
140167
llvm::Expected<Symbol> symbol = Symbol::FromJSON(json_symbol, section_list);
141168
if (!symbol) {
142-
LLDB_LOG_ERROR(log, symbol.takeError(), "invalid symbol");
169+
LLDB_LOG_ERROR(log, symbol.takeError(), "invalid symbol: {0}");
143170
continue;
144171
}
145172
symtab.AddSymbol(*symbol);
146173
}
147174
symtab.Finalize();
148175
}
149176

150-
void ObjectFileJSON::CreateSections(SectionList &unified_section_list) {}
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+
}
151192

152193
bool ObjectFileJSON::MagicBytesMatch(DataBufferSP data_sp,
153194
lldb::addr_t data_offset,
@@ -164,13 +205,15 @@ namespace lldb_private {
164205
bool fromJSON(const json::Value &value, ObjectFileJSON::Header &header,
165206
json::Path path) {
166207
json::ObjectMapper o(value, path);
167-
return o && o.map("triple", header.triple) && o.map("uuid", header.uuid);
208+
return o && o.map("triple", header.triple) && o.map("uuid", header.uuid) &&
209+
o.map("type", header.type);
168210
}
169211

170212
bool fromJSON(const json::Value &value, ObjectFileJSON::Body &body,
171213
json::Path path) {
172214
json::ObjectMapper o(value, path);
173-
return o && o.map("symbols", body.symbols);
215+
return o && o.mapOptional("symbols", body.symbols) &&
216+
o.mapOptional("sections", body.sections);
174217
}
175218

176219
} // namespace lldb_private

lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class ObjectFileJSON : public ObjectFile {
8282

8383
uint32_t GetDependentModules(FileSpecList &files) override { return 0; }
8484

85-
Type CalculateType() override { return eTypeDebugInfo; }
85+
Type CalculateType() override { return m_type; }
8686

8787
Strata CalculateStrata() override { return eStrataUser; }
8888

@@ -92,21 +92,27 @@ class ObjectFileJSON : public ObjectFile {
9292
struct Header {
9393
std::string triple;
9494
std::string uuid;
95+
std::optional<ObjectFile::Type> type;
9596
};
9697

9798
struct Body {
99+
std::vector<JSONSection> sections;
98100
std::vector<JSONSymbol> symbols;
99101
};
100102

101103
private:
102104
ArchSpec m_arch;
103105
UUID m_uuid;
106+
ObjectFile::Type m_type;
107+
std::optional<uint64_t> m_size;
104108
std::vector<JSONSymbol> m_symbols;
109+
std::vector<JSONSection> m_sections;
105110

106111
ObjectFileJSON(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
107112
lldb::offset_t data_offset, const FileSpec *file,
108113
lldb::offset_t offset, lldb::offset_t length, ArchSpec arch,
109-
UUID uuid, std::vector<JSONSymbol> symbols);
114+
UUID uuid, Type type, std::vector<JSONSymbol> symbols,
115+
std::vector<JSONSection> sections);
110116
};
111117

112118
bool fromJSON(const llvm::json::Value &value, ObjectFileJSON::Header &header,

lldb/source/Symbol/ObjectFile.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,3 +777,34 @@ uint32_t ObjectFile::GetCacheHash() {
777777
m_cache_hash = llvm::djbHash(strm.GetString());
778778
return *m_cache_hash;
779779
}
780+
781+
namespace llvm {
782+
namespace json {
783+
784+
bool fromJSON(const llvm::json::Value &value,
785+
lldb_private::ObjectFile::Type &type, llvm::json::Path path) {
786+
if (auto str = value.getAsString()) {
787+
type = llvm::StringSwitch<ObjectFile::Type>(*str)
788+
.Case("corefile", ObjectFile::eTypeCoreFile)
789+
.Case("executable", ObjectFile::eTypeExecutable)
790+
.Case("debuginfo", ObjectFile::eTypeDebugInfo)
791+
.Case("dynamiclinker", ObjectFile::eTypeDynamicLinker)
792+
.Case("objectfile", ObjectFile::eTypeObjectFile)
793+
.Case("sharedlibrary", ObjectFile::eTypeSharedLibrary)
794+
.Case("stublibrary", ObjectFile::eTypeStubLibrary)
795+
.Case("jit", ObjectFile::eTypeJIT)
796+
.Case("unknown", ObjectFile::eTypeUnknown)
797+
.Default(ObjectFile::eTypeInvalid);
798+
799+
if (type == ObjectFile::eTypeInvalid) {
800+
path.report("invalid object type");
801+
return false;
802+
}
803+
804+
return true;
805+
}
806+
path.report("expected string");
807+
return false;
808+
}
809+
} // namespace json
810+
} // namespace llvm

0 commit comments

Comments
 (0)