-
Notifications
You must be signed in to change notification settings - Fork 280
Expand file tree
/
Copy pathMetadataSerializable.hpp
More file actions
254 lines (223 loc) · 11 KB
/
MetadataSerializable.hpp
File metadata and controls
254 lines (223 loc) · 11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
//
// Created by kat on 5/31/23.
//
/*
* Welcome to, this file.
*
* This is a metadata serialization helper.
*
* Have you ever wished turning a complex datastructure into a Metadata object was as easy in C++ as it is in python?
* Do you like macros and templates?
*
* Great news.
*
* Implement these on your `public MetadataSerializable<T>` subclass:
* ```
class MyClass : public MetadataSerializable<MyClass> {
void Store(SerializationContext& context) const {
MSS(m_someVariable);
MSS(m_someOtherVariable);
}
void Load(DeserializationContext& context) {
MSL(m_someVariable);
MSL(m_someOtherVariable);
}
}
```
* Then, you can turn your object into a Metadata object with `AsMetadata()`, and load it back with
`LoadFromMetadata()`.
*
* Serialized fields will be automatically repopulated.
*
* Other ser/deser formats (rapidjson objects, strings) also exist. You can use these to achieve nesting, but probably
avoid that.
* */
#ifndef KERNELCACHE_CORE_METADATASERIALIZABLE_HPP
#define KERNELCACHE_CORE_METADATASERIALIZABLE_HPP
#include <cassert>
#include "binaryninjaapi.h"
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/prettywriter.h"
#include "../api/kernelcachecore.h"
#include "macho/types.h"
using namespace BinaryNinja;
namespace KernelCacheCore {
#define MSS(name) context.store(#name, name)
#define MSS_CAST(name, type) context.store(#name, (type) name)
#define MSS_SUBCLASS(name) Serialize(context, #name, name)
#define MSL(name) name = context.load<decltype(name)>(#name)
#define MSL_CAST(name, storedType, type) name = (type)context.load<storedType>(#name)
struct DeserializationContext;
struct SerializationContext {
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer;
SerializationContext() : buffer(), writer(buffer) {
}
template <typename T>
void store(std::string_view x, const T& y)
{
Serialize(*this, x, y);
}
};
struct DeserializationContext {
rapidjson::Document doc;
template <typename T>
T load(std::string_view x)
{
T value;
Deserialize(*this, x, value);
return value;
}
};
template <typename Derived, typename LoadResult = Derived>
class MetadataSerializable {
public:
template <typename... Args>
std::string AsString(Args&&... args) const {
SerializationContext context;
Store(context, std::forward<Args>(args)...);
return context.buffer.GetString();
}
static LoadResult LoadFromString(const std::string& s) {
DeserializationContext context;
[[maybe_unused]] rapidjson::ParseResult result = context.doc.Parse(s.c_str());
assert(result);
return Derived::Load(context);
}
static LoadResult LoadFromValue(rapidjson::Value& s) {
DeserializationContext context;
context.doc.CopyFrom(s, context.doc.GetAllocator());
return Derived::Load(context);
}
template <typename... Args>
Ref<Metadata> AsMetadata(Args&&... args) const {
return new Metadata(AsString(std::forward<Args>(args)...));
}
template <typename... Args>
void Store(SerializationContext& context, Args&&... args) const {
context.writer.StartObject();
AsDerived().Store(context, std::forward<Args>(args)...);
context.writer.EndObject();
}
private:
const Derived& AsDerived() const { return static_cast<const Derived&>(*this); }
Derived& AsDerived() { return static_cast<Derived&>(*this); }
};
// The functions below are not part of the FFI API, but are exported so they can be shared with sharedcacheui.
KERNELCACHE_FFI_API void Serialize(SerializationContext& context, std::string_view str);
template <typename T>
inline void Serialize(SerializationContext& context, const MetadataSerializable<T>& value)
{
value.Store(context);
}
template <typename T>
inline void Serialize(SerializationContext& context, std::string_view name, const T& value)
{
Serialize(context, name);
Serialize(context, value);
}
template <typename First, typename Second>
void Serialize(SerializationContext& context, const std::pair<First, Second>& value)
{
context.writer.StartArray();
Serialize(context, value.first);
Serialize(context, value.second);
context.writer.EndArray();
}
template <typename K, typename V, typename L>
void Serialize(SerializationContext& context, const std::map<K, V, L>& value)
{
context.writer.StartArray();
for (auto& pair : value)
{
Serialize(context, pair);
}
context.writer.EndArray();
}
template <typename K, typename V>
void Serialize(SerializationContext& context, const std::unordered_map<K, V>& value)
{
context.writer.StartArray();
for (auto& pair : value)
{
Serialize(context, pair);
}
context.writer.EndArray();
}
template <typename T>
void Serialize(SerializationContext& context, const std::vector<T>& values)
{
context.writer.StartArray();
for (const auto& value : values)
{
Serialize(context, value);
}
context.writer.EndArray();
}
template <typename T>
void Serialize(SerializationContext& context, const std::optional<T>& value)
{
if (value.has_value())
Serialize(context, *value);
else
context.writer.Null();
}
KERNELCACHE_FFI_API void Serialize(SerializationContext& context, const char*);
KERNELCACHE_FFI_API void Serialize(SerializationContext& context, bool b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, bool& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext& context, uint8_t b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, uint8_t& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext& context, uint16_t b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, uint16_t& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext& context, uint32_t b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, uint32_t& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext& context, uint64_t b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, uint64_t& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext& context, int8_t b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, int8_t& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext& context, int16_t b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, int16_t& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext& context, int32_t b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, int32_t& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext& context, int64_t b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, int64_t& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext& context, std::string_view b);
KERNELCACHE_FFI_API void Serialize(SerializationContext& context, const std::pair<uint64_t, std::pair<uint64_t, uint64_t>>& value);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::string& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::map<uint64_t, std::string>& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map<uint64_t, std::string>& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map<uint64_t, uint64_t>& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map<std::string, std::unordered_map<uint64_t, uint64_t>>& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map<std::string, std::string>& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::vector<std::string>& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::vector<std::pair<uint64_t, std::pair<uint64_t, uint64_t>>>& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::vector<std::pair<uint64_t, bool>>& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::vector<uint64_t>& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map<std::string, uint64_t>& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::vector<std::pair<uint64_t, std::vector<std::pair<uint64_t, std::string>>>>& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext&, const mach_header_64& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, mach_header_64& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext&, const symtab_command& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, symtab_command& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext&, const dysymtab_command& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, dysymtab_command& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext&, const dyld_info_command& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, dyld_info_command& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext&, const routines_command_64& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, routines_command_64& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext&, const function_starts_command& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, function_starts_command& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext&, const section_64& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, std::vector<section_64>& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext&, const linkedit_data_command& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, linkedit_data_command& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext&, const segment_command_64& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, segment_command_64& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, std::vector<segment_command_64>& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext&, const build_version_command& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, build_version_command& b);
KERNELCACHE_FFI_API void Serialize(SerializationContext&, const build_tool_version& b);
KERNELCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, std::vector<build_tool_version>& b);
} // namespace SharedCacheCore
#endif // KERNELCACHE_METADATASERIALIZABLE_HPP