xref: /llvm-project/lldb/tools/debugserver/source/JSONGenerator.h (revision 7ebcd8891a7acc265cee4996d55a287a035f8771)
1 //===-- JSONGenerator.h ----------------------------------------*- C++ -*-===//
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 #ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_JSONGENERATOR_H
10 #define LLDB_TOOLS_DEBUGSERVER_SOURCE_JSONGENERATOR_H
11 
12 #include <iomanip>
13 #include <sstream>
14 #include <string>
15 #include <utility>
16 #include <vector>
17 
18 /// \class JSONGenerator JSONGenerator.h
19 /// A class which can construct structured data for the sole purpose
20 /// of printing it in JSON format.
21 ///
22 /// A stripped down version of lldb's StructuredData objects which are much
23 /// general purpose.  This variant is intended only for assembling information
24 /// and printing it as a JSON string.
25 
26 class JSONGenerator {
27 public:
28   class Object;
29   class Array;
30   class Integer;
31   class Float;
32   class Boolean;
33   class String;
34   class Dictionary;
35   class Generic;
36 
37   typedef std::shared_ptr<Object> ObjectSP;
38   typedef std::shared_ptr<Array> ArraySP;
39   typedef std::shared_ptr<Integer> IntegerSP;
40   typedef std::shared_ptr<Float> FloatSP;
41   typedef std::shared_ptr<Boolean> BooleanSP;
42   typedef std::shared_ptr<String> StringSP;
43   typedef std::shared_ptr<Dictionary> DictionarySP;
44   typedef std::shared_ptr<Generic> GenericSP;
45 
46   enum class Type {
47     eTypeInvalid = -1,
48     eTypeNull = 0,
49     eTypeGeneric,
50     eTypeArray,
51     eTypeInteger,
52     eTypeFloat,
53     eTypeBoolean,
54     eTypeString,
55     eTypeDictionary
56   };
57 
58   class Object : public std::enable_shared_from_this<Object> {
59   public:
m_type(t)60     Object(Type t = Type::eTypeInvalid) : m_type(t) {}
61 
~Object()62     virtual ~Object() {}
63 
IsValid()64     virtual bool IsValid() const { return true; }
65 
Clear()66     virtual void Clear() { m_type = Type::eTypeInvalid; }
67 
GetType()68     Type GetType() const { return m_type; }
69 
SetType(Type t)70     void SetType(Type t) { m_type = t; }
71 
GetAsArray()72     Array *GetAsArray() {
73       if (m_type == Type::eTypeArray)
74         return (Array *)this;
75       return NULL;
76     }
77 
GetAsDictionary()78     Dictionary *GetAsDictionary() {
79       if (m_type == Type::eTypeDictionary)
80         return (Dictionary *)this;
81       return NULL;
82     }
83 
GetAsInteger()84     Integer *GetAsInteger() {
85       if (m_type == Type::eTypeInteger)
86         return (Integer *)this;
87       return NULL;
88     }
89 
GetAsFloat()90     Float *GetAsFloat() {
91       if (m_type == Type::eTypeFloat)
92         return (Float *)this;
93       return NULL;
94     }
95 
GetAsBoolean()96     Boolean *GetAsBoolean() {
97       if (m_type == Type::eTypeBoolean)
98         return (Boolean *)this;
99       return NULL;
100     }
101 
GetAsString()102     String *GetAsString() {
103       if (m_type == Type::eTypeString)
104         return (String *)this;
105       return NULL;
106     }
107 
GetAsGeneric()108     Generic *GetAsGeneric() {
109       if (m_type == Type::eTypeGeneric)
110         return (Generic *)this;
111       return NULL;
112     }
113 
114     virtual void Dump(std::ostream &s) const = 0;
115 
116     virtual void DumpBinaryEscaped(std::ostream &s) const = 0;
117 
118   private:
119     Type m_type;
120   };
121 
122   class Array : public Object {
123   public:
Array()124     Array() : Object(Type::eTypeArray) {}
125 
~Array()126     virtual ~Array() {}
127 
AddItem(ObjectSP item)128     void AddItem(ObjectSP item) { m_items.push_back(item); }
129 
Dump(std::ostream & s)130     void Dump(std::ostream &s) const override {
131       s << "[";
132       const size_t arrsize = m_items.size();
133       for (size_t i = 0; i < arrsize; ++i) {
134         m_items[i]->Dump(s);
135         if (i + 1 < arrsize)
136           s << ",";
137       }
138       s << "]";
139     }
140 
DumpBinaryEscaped(std::ostream & s)141     void DumpBinaryEscaped(std::ostream &s) const override {
142       s << "[";
143       const size_t arrsize = m_items.size();
144       for (size_t i = 0; i < arrsize; ++i) {
145         m_items[i]->DumpBinaryEscaped(s);
146         if (i + 1 < arrsize)
147           s << ",";
148       }
149       s << "]";
150     }
151 
152   protected:
153     typedef std::vector<ObjectSP> collection;
154     collection m_items;
155   };
156 
157   class Integer : public Object {
158   public:
Object(Type::eTypeInteger)159     Integer(uint64_t value = 0) : Object(Type::eTypeInteger), m_value(value) {}
160 
~Integer()161     virtual ~Integer() {}
162 
SetValue(uint64_t value)163     void SetValue(uint64_t value) { m_value = value; }
164 
Dump(std::ostream & s)165     void Dump(std::ostream &s) const override { s << m_value; }
166 
DumpBinaryEscaped(std::ostream & s)167     void DumpBinaryEscaped(std::ostream &s) const override { Dump(s); }
168 
169   protected:
170     uint64_t m_value;
171   };
172 
173   class Float : public Object {
174   public:
Object(Type::eTypeFloat)175     Float(double d = 0.0) : Object(Type::eTypeFloat), m_value(d) {}
176 
~Float()177     virtual ~Float() {}
178 
SetValue(double value)179     void SetValue(double value) { m_value = value; }
180 
Dump(std::ostream & s)181     void Dump(std::ostream &s) const override { s << m_value; }
182 
DumpBinaryEscaped(std::ostream & s)183     void DumpBinaryEscaped(std::ostream &s) const override { Dump(s); }
184 
185   protected:
186     double m_value;
187   };
188 
189   class Boolean : public Object {
190   public:
Object(Type::eTypeBoolean)191     Boolean(bool b = false) : Object(Type::eTypeBoolean), m_value(b) {}
192 
~Boolean()193     virtual ~Boolean() {}
194 
SetValue(bool value)195     void SetValue(bool value) { m_value = value; }
196 
Dump(std::ostream & s)197     void Dump(std::ostream &s) const override {
198       if (m_value)
199         s << "true";
200       else
201         s << "false";
202     }
203 
DumpBinaryEscaped(std::ostream & s)204     void DumpBinaryEscaped(std::ostream &s) const override { Dump(s); }
205 
206   protected:
207     bool m_value;
208   };
209 
210   class String : public Object {
211   public:
String()212     String() : Object(Type::eTypeString), m_value() {}
213 
String(const std::string & s)214     String(const std::string &s) : Object(Type::eTypeString), m_value(s) {}
215 
String(const std::string && s)216     String(const std::string &&s) : Object(Type::eTypeString), m_value(s) {}
217 
SetValue(const std::string & string)218     void SetValue(const std::string &string) { m_value = string; }
219 
Dump(std::ostream & s)220     void Dump(std::ostream &s) const override {
221       s << '"';
222       const size_t strsize = m_value.size();
223       for (size_t i = 0; i < strsize; ++i) {
224         char ch = m_value[i];
225         if (ch == '"')
226           s << '\\';
227         s << ch;
228       }
229       s << '"';
230     }
231 
DumpBinaryEscaped(std::ostream & s)232     void DumpBinaryEscaped(std::ostream &s) const override {
233       s << '"';
234       const size_t strsize = m_value.size();
235       for (size_t i = 0; i < strsize; ++i) {
236         char ch = m_value[i];
237         if (ch == '"')
238           s << '\\';
239         // gdb remote serial protocol binary escaping
240         if (ch == '#' || ch == '$' || ch == '}' || ch == '*') {
241           s << '}'; // 0x7d next character is escaped
242           s << static_cast<char>(ch ^ 0x20);
243         } else {
244           s << ch;
245         }
246       }
247       s << '"';
248     }
249 
250   protected:
251     std::string m_value;
252   };
253 
254   class Dictionary : public Object {
255   public:
Dictionary()256     Dictionary() : Object(Type::eTypeDictionary), m_dict() {}
257 
~Dictionary()258     virtual ~Dictionary() {}
259 
AddItem(std::string key,ObjectSP value)260     void AddItem(std::string key, ObjectSP value) {
261       m_dict.push_back(Pair(key, value));
262     }
263 
AddIntegerItem(std::string key,uint64_t value)264     void AddIntegerItem(std::string key, uint64_t value) {
265       AddItem(key, ObjectSP(new Integer(value)));
266     }
267 
AddFloatItem(std::string key,double value)268     void AddFloatItem(std::string key, double value) {
269       AddItem(key, ObjectSP(new Float(value)));
270     }
271 
AddStringItem(std::string key,std::string value)272     void AddStringItem(std::string key, std::string value) {
273       AddItem(key, ObjectSP(new String(std::move(value))));
274     }
275 
AddBytesAsHexASCIIString(std::string key,const uint8_t * src,size_t src_len)276     void AddBytesAsHexASCIIString(std::string key, const uint8_t *src,
277                                   size_t src_len) {
278       if (src && src_len) {
279         std::ostringstream strm;
280         for (size_t i = 0; i < src_len; i++)
281           strm << std::setfill('0') << std::hex << std::right << std::setw(2)
282                << ((uint32_t)(src[i]));
283         AddItem(key, ObjectSP(new String(std::move(strm.str()))));
284       } else {
285         AddItem(key, ObjectSP(new String()));
286       }
287     }
288 
AddBooleanItem(std::string key,bool value)289     void AddBooleanItem(std::string key, bool value) {
290       AddItem(key, ObjectSP(new Boolean(value)));
291     }
292 
Dump(std::ostream & s)293     void Dump(std::ostream &s) const override {
294       bool have_printed_one_elem = false;
295       s << "{";
296       for (collection::const_iterator iter = m_dict.begin();
297            iter != m_dict.end(); ++iter) {
298         if (!have_printed_one_elem) {
299           have_printed_one_elem = true;
300         } else {
301           s << ",";
302         }
303         s << "\"" << iter->first.c_str() << "\":";
304         iter->second->Dump(s);
305       }
306       s << "}";
307     }
308 
DumpBinaryEscaped(std::ostream & s)309     void DumpBinaryEscaped(std::ostream &s) const override {
310       bool have_printed_one_elem = false;
311       s << "{";
312       for (collection::const_iterator iter = m_dict.begin();
313            iter != m_dict.end(); ++iter) {
314         if (!have_printed_one_elem) {
315           have_printed_one_elem = true;
316         } else {
317           s << ",";
318         }
319         s << "\"" << binary_encode_string(iter->first) << "\":";
320         iter->second->DumpBinaryEscaped(s);
321       }
322       // '}' must be escaped for the gdb remote serial
323       // protocol.
324       s << "}";
325       s << static_cast<char>('}' ^ 0x20);
326     }
327 
328   protected:
binary_encode_string(const std::string & s)329     std::string binary_encode_string(const std::string &s) const {
330       std::string output;
331       const size_t s_size = s.size();
332       const char *s_chars = s.c_str();
333 
334       for (size_t i = 0; i < s_size; i++) {
335         unsigned char ch = *(s_chars + i);
336         if (ch == '#' || ch == '$' || ch == '}' || ch == '*') {
337           output.push_back('}'); // 0x7d
338           output.push_back(ch ^ 0x20);
339         } else {
340           output.push_back(ch);
341         }
342       }
343       return output;
344     }
345 
346     // Keep the dictionary as a vector so the dictionary doesn't reorder itself
347     // when you dump it
348     // We aren't accessing keys by name, so this won't affect performance
349     typedef std::pair<std::string, ObjectSP> Pair;
350     typedef std::vector<Pair> collection;
351     collection m_dict;
352   };
353 
354   class Null : public Object {
355   public:
Null()356     Null() : Object(Type::eTypeNull) {}
357 
~Null()358     virtual ~Null() {}
359 
IsValid()360     bool IsValid() const override { return false; }
361 
Dump(std::ostream & s)362     void Dump(std::ostream &s) const override { s << "null"; }
363 
DumpBinaryEscaped(std::ostream & s)364     void DumpBinaryEscaped(std::ostream &s) const override { Dump(s); }
365 
366   protected:
367   };
368 
369   class Generic : public Object {
370   public:
371     explicit Generic(void *object = nullptr)
Object(Type::eTypeGeneric)372         : Object(Type::eTypeGeneric), m_object(object) {}
373 
SetValue(void * value)374     void SetValue(void *value) { m_object = value; }
375 
GetValue()376     void *GetValue() const { return m_object; }
377 
IsValid()378     bool IsValid() const override { return m_object != nullptr; }
379 
380     void Dump(std::ostream &s) const override;
381 
382     void DumpBinaryEscaped(std::ostream &s) const override;
383 
384   private:
385     void *m_object;
386   };
387 
388 }; // class JSONGenerator
389 
390 #endif // LLDB_TOOLS_DEBUGSERVER_SOURCE_JSONGENERATOR_H
391