summaryrefslogtreecommitdiff
path: root/buildscripts
diff options
context:
space:
mode:
authorMathew Robinson <chasinglogic@gmail.com>2019-05-31 13:45:27 -0400
committerMathew Robinson <chasinglogic@gmail.com>2019-06-17 09:48:39 -0400
commit277229505fd9f05d0ea2f6baa25afbdb8d8171a4 (patch)
tree691065932977d2ec8047b3fc5495dafa231aa9a7 /buildscripts
parent211db32dc1838d591778f5c3c24e00435d3b59a0 (diff)
downloadmongo-277229505fd9f05d0ea2f6baa25afbdb8d8171a4.tar.gz
SERVER-41167 Write mongo type pretty printers for LLDB
Diffstat (limited to 'buildscripts')
-rw-r--r--buildscripts/lldb/lldb_printers.py158
1 files changed, 158 insertions, 0 deletions
diff --git a/buildscripts/lldb/lldb_printers.py b/buildscripts/lldb/lldb_printers.py
new file mode 100644
index 00000000000..669c65ef647
--- /dev/null
+++ b/buildscripts/lldb/lldb_printers.py
@@ -0,0 +1,158 @@
+"""LLDB Pretty-printers for MongoDB.
+
+To import script in lldb, run:
+
+ command script import buildscripts/lldb/lldb_printers.py
+
+This file must maintain Python 2 and 3 compatibility until Apple
+upgrades to Python 3 and updates their LLDB to use it.
+"""
+from __future__ import print_function
+
+import string
+import struct
+import sys
+import uuid
+
+import lldb
+
+try:
+ import bson
+ import collections
+ from bson import json_util
+ from bson.codec_options import CodecOptions
+except ImportError as err:
+ print("Warning: Could not load bson library for Python {}.".format(sys.version))
+ print("Check with the pip command if pymongo 3.x is installed.")
+ bson = None
+
+
+def __lldb_init_module(debugger, dict):
+ ############################
+ # register pretty printers #
+ ############################
+ debugger.HandleCommand("type summary add -s 'A${*var.__ptr_.__value_}' -x '^std::__1::unique_ptr<.+>$'")
+ debugger.HandleCommand("type summary add mongo::BSONObj -F lldb_printers.BSONObjPrinter")
+ debugger.HandleCommand("type summary add mongo::Status -F lldb_printers.StatusPrinter")
+ debugger.HandleCommand("type summary add mongo::StatusWith -F lldb_printers.StatusWithPrinter")
+ debugger.HandleCommand("type summary add mongo::StringData -F lldb_printers.StringDataPrinter")
+ debugger.HandleCommand("type summary add mongo::UUID -F lldb_printers.UUIDPrinter")
+ debugger.HandleCommand("type summary add --summary-string '${var.m_pathname}' 'boost::filesystem::path'")
+ debugger.HandleCommand("type synthetic add -x '^boost::optional<.+>$' --python-class lldb_printers.OptionalPrinter")
+ debugger.HandleCommand("type synthetic add -x '^std::unique_ptr<.+>$' --python-class lldb_printers.UniquePtrPrinter")
+
+
+#############################
+# Pretty Printer Defintions #
+#############################
+
+def StatusPrinter(valobj, *args):
+ err = valobj.GetChildMemberWithName("_error")
+ code = err.\
+ GetChildMemberWithName("code").\
+ GetValue()
+ if code is None:
+ return "Status::OK()"
+ reason = err.\
+ GetChildMemberWithName("reason").\
+ GetSummary()
+ return "Status({}, {})".format(code, reason)
+
+
+def StatusWithPrinter(valobj, *args):
+ status = valobj.GetChildMemberWithName("_status")
+ code = status.GetChildMemberWithName("_error").\
+ GetChildMemberWithName("code").\
+ GetValue()
+ if code is None:
+ return "StatusWith(OK, {})".format(valobj.GetChildMemberWithName("_t").GetValue())
+ rep = StatusPrinter(status)
+ return rep.replace("Status", "StatusWith", 1)
+
+
+def StringDataPrinter(valobj, *args):
+ ptr = valobj.GetChildMemberWithName("_data").GetValueAsUnsigned()
+ size1 = valobj.GetChildMemberWithName("_size").GetValueAsUnsigned(0)
+ return '"{}"'.format(valobj.GetProcess().ReadMemory(ptr, size1, lldb.SBError()).encode("utf-8"))
+
+
+def BSONObjPrinter(valobj, *args):
+ ptr = valobj.GetChildMemberWithName("_objdata").GetValueAsUnsigned()
+ size = struct.unpack("<I", valobj.GetProcess().ReadMemory(ptr, 4, lldb.SBError()))[0]
+ if size < 5 or size > 17 * 1024 * 1024:
+ return
+ buf = bson.BSON(bytes(valobj.GetProcess().ReadMemory(ptr, size, lldb.SBError())))
+ buf_str = buf.decode()
+ obj = json_util.dumps(buf_str, indent=4)
+ # If the object is huge then just dump it as one line
+ if obj.count("\n") > 1000:
+ return json_util.dumps(buf_str)
+ # Otherwise try to be nice and pretty print the JSON
+ return obj
+
+
+def UUIDPrinter(valobj, *args):
+ char_array = valobj.GetChildMemberWithName("_uuid").GetChildAtIndex(0)
+ raw_bytes = [x.GetValueAsUnsigned() for x in char_array]
+ uuid_hex_bytes = [hex(b)[2:].zfill(2) for b in raw_bytes]
+ return str(uuid.UUID("".join(uuid_hex_bytes)))
+
+
+class UniquePtrPrinter:
+ def __init__(self, valobj, dict):
+ self.valobj = valobj
+ self.update()
+
+ def num_children(self):
+ return 1
+
+ def get_child_index(self, name):
+ if name == "ptr":
+ return 0
+ else:
+ return None
+
+ def get_child_at_index(self, index):
+ if index == 0:
+ return self.valobj.GetChildMemberWithName("__ptr_").GetChildMemberWithName("__value_").Dereference()
+ else:
+ return None
+
+ def has_children():
+ return True
+
+ def update(self):
+ pass
+
+
+class OptionalPrinter:
+ def __init__(self, valobj, dict):
+ self.valobj = valobj
+ self.update()
+
+ def num_children(self):
+ return 1
+
+ def get_child_index(self, name):
+ if name == "value":
+ return 0
+ else:
+ return None
+
+ def get_child_at_index(self, index):
+ if index == 0:
+ return self.value
+ else:
+ return None
+
+ def has_children():
+ return True
+
+ def update(self):
+ self.is_init = self.valobj.GetChildMemberWithName("m_initialized").GetValueAsUnsigned() != 0
+ self.value = None
+ if self.is_init:
+ temp_type = self.valobj.GetType().GetTemplateArgumentType(0)
+ storage = self.valobj.GetChildMemberWithName("m_storage")
+ self.value = storage.Cast(temp_type)
+