summaryrefslogtreecommitdiffstats
path: root/lldb/tools/debugserver/source/JSONGenerator.h
diff options
context:
space:
mode:
authorGreg Clayton <gclayton@apple.com>2015-06-22 23:12:45 +0000
committerGreg Clayton <gclayton@apple.com>2015-06-22 23:12:45 +0000
commitffb2d44ab93184a723e37793efc50ddafc5afbe1 (patch)
tree7d0241bd8bf0ecf2ed6be6119a65b3cc1d5fe73b /lldb/tools/debugserver/source/JSONGenerator.h
parentab9db51042d1b821d324a209f3ba37e5ee7525a7 (diff)
downloadbcm5719-llvm-ffb2d44ab93184a723e37793efc50ddafc5afbe1.tar.gz
bcm5719-llvm-ffb2d44ab93184a723e37793efc50ddafc5afbe1.zip
Reduced packet counts to the remote GDB server where possible.
We have been working on reducing the packet count that is sent between LLDB and the debugserver on MacOSX and iOS. Our approach to this was to reduce the packets required when debugging multiple threads. We currently make one qThreadStopInfoXXXX call (where XXXX is the thread ID in hex) per thread except the thread that stopped with a stop reply packet. In order to implement multiple thread infos in a single reply, we need to use structured data, which means JSON. The new jThreadsInfo packet will attempt to retrieve all thread infos in a single packet. The data is very similar to the stop reply packets, but packaged in JSON and uses JSON arrays where applicable. The JSON output looks like: [ { "tid":1580681, "metype":6, "medata":[2,0], "reason":"exception", "qaddr":140735118423168, "registers": { "0":"8000000000000000", "1":"0000000000000000", "2":"20fabf5fff7f0000", "3":"e8f8bf5fff7f0000", "4":"0100000000000000", "5":"d8f8bf5fff7f0000", "6":"b0f8bf5fff7f0000", "7":"20f4bf5fff7f0000", "8":"8000000000000000", "9":"61a8db78a61500db", "10":"3200000000000000", "11":"4602000000000000", "12":"0000000000000000", "13":"0000000000000000", "14":"0000000000000000", "15":"0000000000000000", "16":"960b000001000000", "17":"0202000000000000", "18":"2b00000000000000", "19":"0000000000000000", "20":"0000000000000000"}, "memory":[ {"address":140734799804592,"bytes":"c8f8bf5fff7f0000c9a59e8cff7f0000"}, {"address":140734799804616,"bytes":"00000000000000000100000000000000"} ] } ] It contains an array of dicitionaries with all of the key value pairs that are normally in the stop reply packet. Including the expedited registers. Notice that is also contains expedited memory in the "memory" key. Any values in this memory will get included in a new L1 cache in lldb_private::Process where if a memory read request is made and that memory request fits into one of the L1 memory cache blocks, it will use that memory data. If a memory request fails in the L1 cache, it will fall back to the L2 cache which is the same block sized caching we were using before these changes. This allows a process to expedite memory that you are likely to use and it reduces packet count. On MacOSX with debugserver, we expedite the frame pointer backchain for a thread (up to 256 entries) by reading 2 pointers worth of bytes at the frame pointer (for the previous FP and PC), and follow the backchain. Most backtraces on MacOSX and iOS now don't require us to read any memory! We will try these packets out and if successful, we should port these to lldb-server in the near future. <rdar://problem/21494354> llvm-svn: 240354
Diffstat (limited to 'lldb/tools/debugserver/source/JSONGenerator.h')
-rw-r--r--lldb/tools/debugserver/source/JSONGenerator.h490
1 files changed, 490 insertions, 0 deletions
diff --git a/lldb/tools/debugserver/source/JSONGenerator.h b/lldb/tools/debugserver/source/JSONGenerator.h
new file mode 100644
index 00000000000..423b2bd5792
--- /dev/null
+++ b/lldb/tools/debugserver/source/JSONGenerator.h
@@ -0,0 +1,490 @@
+//===-- JSONGenerator.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __JSONGenerator_h_
+#define __JSONGenerator_h_
+
+// C Includes
+// C++ Includes
+
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+//----------------------------------------------------------------------
+/// @class JSONGenerator JSONGenerator.h
+/// @brief A class which can construct structured data for the sole purpose
+/// of printing it in JSON format.
+///
+/// A stripped down version of lldb's StructuredData objects which are much
+/// general purpose. This variant is intended only for assembling information
+/// and printing it as a JSON string.
+//----------------------------------------------------------------------
+
+class JSONGenerator
+{
+public:
+
+ class Object;
+ class Array;
+ class Integer;
+ class Float;
+ class Boolean;
+ class String;
+ class Dictionary;
+ class Generic;
+
+ typedef std::shared_ptr<Object> ObjectSP;
+ typedef std::shared_ptr<Array> ArraySP;
+ typedef std::shared_ptr<Integer> IntegerSP;
+ typedef std::shared_ptr<Float> FloatSP;
+ typedef std::shared_ptr<Boolean> BooleanSP;
+ typedef std::shared_ptr<String> StringSP;
+ typedef std::shared_ptr<Dictionary> DictionarySP;
+ typedef std::shared_ptr<Generic> GenericSP;
+
+ enum class Type
+ {
+ eTypeInvalid = -1,
+ eTypeNull = 0,
+ eTypeGeneric,
+ eTypeArray,
+ eTypeInteger,
+ eTypeFloat,
+ eTypeBoolean,
+ eTypeString,
+ eTypeDictionary
+ };
+
+ class Object :
+ public std::enable_shared_from_this<Object>
+ {
+ public:
+
+ Object (Type t = Type::eTypeInvalid) :
+ m_type (t)
+ {
+ }
+
+ virtual ~Object ()
+ {
+ }
+
+ virtual bool
+ IsValid() const
+ {
+ return true;
+ }
+
+ virtual void
+ Clear ()
+ {
+ m_type = Type::eTypeInvalid;
+ }
+
+ Type
+ GetType () const
+ {
+ return m_type;
+ }
+
+ void
+ SetType (Type t)
+ {
+ m_type = t;
+ }
+
+ Array *
+ GetAsArray ()
+ {
+ if (m_type == Type::eTypeArray)
+ return (Array *)this;
+ return NULL;
+ }
+
+ Dictionary *
+ GetAsDictionary ()
+ {
+ if (m_type == Type::eTypeDictionary)
+ return (Dictionary *)this;
+ return NULL;
+ }
+
+ Integer *
+ GetAsInteger ()
+ {
+ if (m_type == Type::eTypeInteger)
+ return (Integer *)this;
+ return NULL;
+ }
+
+ Float *
+ GetAsFloat ()
+ {
+ if (m_type == Type::eTypeFloat)
+ return (Float *)this;
+ return NULL;
+ }
+
+ Boolean *
+ GetAsBoolean ()
+ {
+ if (m_type == Type::eTypeBoolean)
+ return (Boolean *)this;
+ return NULL;
+ }
+
+ String *
+ GetAsString ()
+ {
+ if (m_type == Type::eTypeString)
+ return (String *)this;
+ return NULL;
+ }
+
+ Generic *
+ GetAsGeneric()
+ {
+ if (m_type == Type::eTypeGeneric)
+ return (Generic *)this;
+ return NULL;
+ }
+
+ virtual void
+ Dump (std::ostream &s) const = 0;
+
+ private:
+ Type m_type;
+ };
+
+ class Array : public Object
+ {
+ public:
+ Array () :
+ Object (Type::eTypeArray)
+ {
+ }
+
+ virtual
+ ~Array()
+ {
+ }
+
+ void
+ AddItem(ObjectSP item)
+ {
+ m_items.push_back(item);
+ }
+
+ void Dump(std::ostream &s) const override
+ {
+ s << "[";
+ const size_t arrsize = m_items.size();
+ for (size_t i = 0; i < arrsize; ++i)
+ {
+ m_items[i]->Dump(s);
+ if (i + 1 < arrsize)
+ s << ",";
+ }
+ s << "]";
+ }
+
+ protected:
+ typedef std::vector<ObjectSP> collection;
+ collection m_items;
+ };
+
+
+ class Integer : public Object
+ {
+ public:
+ Integer (uint64_t value = 0) :
+ Object (Type::eTypeInteger),
+ m_value (value)
+ {
+ }
+
+ virtual ~Integer()
+ {
+ }
+
+ void
+ SetValue (uint64_t value)
+ {
+ m_value = value;
+ }
+
+ void Dump(std::ostream &s) const override
+ {
+ s << m_value;
+ }
+
+ protected:
+ uint64_t m_value;
+ };
+
+ class Float : public Object
+ {
+ public:
+ Float (double d = 0.0) :
+ Object (Type::eTypeFloat),
+ m_value (d)
+ {
+ }
+
+ virtual ~Float()
+ {
+ }
+
+ void
+ SetValue (double value)
+ {
+ m_value = value;
+ }
+
+ void Dump(std::ostream &s) const override
+ {
+ s << m_value;
+ }
+
+ protected:
+ double m_value;
+ };
+
+ class Boolean : public Object
+ {
+ public:
+ Boolean (bool b = false) :
+ Object (Type::eTypeBoolean),
+ m_value (b)
+ {
+ }
+
+ virtual ~Boolean()
+ {
+ }
+
+ void
+ SetValue (bool value)
+ {
+ m_value = value;
+ }
+
+ void Dump(std::ostream &s) const override
+ {
+ if (m_value == true)
+ s << "true";
+ else
+ s << "false";
+ }
+
+ protected:
+ bool m_value;
+ };
+
+
+
+ class String : public Object
+ {
+ public:
+ String () :
+ Object (Type::eTypeString),
+ m_value ()
+ {
+ }
+
+ String (const std::string &s) :
+ Object (Type::eTypeString),
+ m_value (s)
+ {
+ }
+
+ String (const std::string &&s) :
+ Object (Type::eTypeString),
+ m_value (s)
+ {
+ }
+
+ void
+ SetValue (const std::string &string)
+ {
+ m_value = string;
+ }
+
+ void Dump(std::ostream &s) const override
+ {
+ std::string quoted;
+ const size_t strsize = m_value.size();
+ for (size_t i = 0; i < strsize ; ++i)
+ {
+ char ch = m_value[i];
+ if (ch == '"')
+ quoted.push_back ('\\');
+ quoted.push_back (ch);
+ }
+ s << '"' << quoted.c_str() << '"';
+ }
+
+ protected:
+ std::string m_value;
+ };
+
+ class Dictionary : public Object
+ {
+ public:
+ Dictionary () :
+ Object (Type::eTypeDictionary),
+ m_dict ()
+ {
+ }
+
+ virtual ~Dictionary()
+ {
+ }
+
+ void
+ AddItem (std::string key, ObjectSP value)
+ {
+ m_dict.push_back(Pair(key, value));
+ }
+
+ void
+ AddIntegerItem (std::string key, uint64_t value)
+ {
+ AddItem (key, ObjectSP (new Integer(value)));
+ }
+
+ void
+ AddFloatItem (std::string key, double value)
+ {
+ AddItem (key, ObjectSP (new Float(value)));
+ }
+
+ void
+ AddStringItem (std::string key, std::string value)
+ {
+ AddItem (key, ObjectSP (new String(std::move(value))));
+ }
+
+ void
+ AddBytesAsHexASCIIString (std::string key, const uint8_t *src, size_t src_len)
+ {
+ if (src && src_len)
+ {
+ std::ostringstream strm;
+ for (size_t i = 0; i < src_len; i++)
+ strm << std::setfill('0') << std::hex << std::right << std::setw(2) << ((uint32_t)(src[i]));
+ AddItem (key, ObjectSP (new String(std::move(strm.str()))));
+ }
+ else
+ {
+ AddItem (key, ObjectSP (new String()));
+ }
+ }
+
+ void
+ AddBooleanItem (std::string key, bool value)
+ {
+ AddItem (key, ObjectSP (new Boolean(value)));
+ }
+
+ void Dump(std::ostream &s) const override
+ {
+ bool have_printed_one_elem = false;
+ s << "{";
+ for (collection::const_iterator iter = m_dict.begin(); iter != m_dict.end(); ++iter)
+ {
+ if (have_printed_one_elem == false)
+ {
+ have_printed_one_elem = true;
+ }
+ else
+ {
+ s << ",";
+ }
+ s << "\"" << iter->first.c_str() << "\":";
+ iter->second->Dump(s);
+ }
+ s << "}";
+ }
+
+ protected:
+ // Keep the dictionary as a vector so the dictionary doesn't reorder itself when you dump it
+ // We aren't accessing keys by name, so this won't affect performance
+ typedef std::pair<std::string, ObjectSP> Pair;
+ typedef std::vector<Pair> collection;
+ collection m_dict;
+ };
+
+ class Null : public Object
+ {
+ public:
+ Null () :
+ Object (Type::eTypeNull)
+ {
+ }
+
+ virtual ~Null()
+ {
+ }
+
+ bool
+ IsValid() const override
+ {
+ return false;
+ }
+
+ void Dump(std::ostream &s) const override
+ {
+ s << "null";
+ }
+
+ protected:
+ };
+
+ class Generic : public Object
+ {
+ public:
+ explicit Generic(void *object = nullptr)
+ : Object(Type::eTypeGeneric)
+ , m_object(object)
+ {
+ }
+
+ void
+ SetValue(void *value)
+ {
+ m_object = value;
+ }
+
+ void *
+ GetValue() const
+ {
+ return m_object;
+ }
+
+ bool
+ IsValid() const override
+ {
+ return m_object != nullptr;
+ }
+
+ void Dump(std::ostream &s) const override;
+
+ private:
+ void *m_object;
+ };
+
+}; // class JSONGenerator
+
+
+
+#endif // __JSONGenerator_h_
OpenPOWER on IntegriCloud