summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Benvenuto <mark.benvenuto@mongodb.com>2016-12-09 17:57:35 -0500
committerMark Benvenuto <mark.benvenuto@mongodb.com>2016-12-09 17:57:44 -0500
commit586ac20773ff7dc18cabf329c238bf261e00387d (patch)
treeadd6a1d33a95bbaf6a2db50df4e78fc14c490340
parent93fc176c5e5092aa47741a29405240ebf81fab16 (diff)
downloadmongo-586ac20773ff7dc18cabf329c238bf261e00387d.tar.gz
SERVER-26634 GDB Pretty-Printers and Commands
-rw-r--r--.gdbinit1
-rw-r--r--buildscripts/gdb/mongo.py139
2 files changed, 73 insertions, 67 deletions
diff --git a/.gdbinit b/.gdbinit
index bda63f0b508..d82d81f02ba 100644
--- a/.gdbinit
+++ b/.gdbinit
@@ -1,4 +1,3 @@
-
# Print the full stack trace on python exceptions to aid debugging
set python print-stack full
diff --git a/buildscripts/gdb/mongo.py b/buildscripts/gdb/mongo.py
index 54578d1da58..e6f4209bb5e 100644
--- a/buildscripts/gdb/mongo.py
+++ b/buildscripts/gdb/mongo.py
@@ -25,6 +25,8 @@ def get_unique_ptr(obj):
# Pretty-Printers
#
###################################################################################################
+
+
class StatusPrinter(object):
"""Pretty-printer for mongo::Status"""
OK = 0 # ErrorCodes::OK
@@ -33,10 +35,10 @@ class StatusPrinter(object):
self.val = val
def to_string(self):
- code = self.code()
- if code == StatusPrinter.OK:
+ if not self.val['_error']:
return 'Status::OK()'
+ code = self.val['_error']['code']
# Remove the mongo::ErrorCodes:: prefix. Does nothing if not a real ErrorCode.
code = str(code).split('::')[-1]
@@ -44,47 +46,37 @@ class StatusPrinter(object):
location = info['location']
reason = info['reason']
if location:
- return 'Status(%s, %s, %s)'%(code, reason, location)
+ return 'Status(%s, %s, %s)' % (code, reason, location)
else:
- return 'Status(%s, %s)'%(code, reason)
-
- def code(self):
- if not self.val['_error']:
- return StatusPrinter.OK
- return self.val['_error'].dereference()['code']
+ return 'Status(%s, %s)' % (code, reason)
class StatusWithPrinter:
"""Pretty-printer for mongo::StatusWith<>"""
- OK = 0 # ErrorCodes::OK
-
def __init__(self, val):
self.val = val
def to_string(self):
- code = self.code()
- if code == StatusPrinter.OK:
- return 'StatusWith(%s, %s)'%(code, self.val['_t'])
+ if not self.val['_status']['_error']:
+ return 'StatusWith(OK, %s)' % (self.val['_t'])
+
+ code = self.val['_status']['_error']['code']
# Remove the mongo::ErrorCodes:: prefix. Does nothing if not a real ErrorCode.
code = str(code).split('::')[-1]
info = self.val['_status']['_error'].dereference()
- location = info['_status']['location']
- reason = info['_status']['reason']
+ location = info['location']
+ reason = info['reason']
if location:
- return 'StatusWith(%s, %s, %s)'%(code, reason, location)
+ return 'StatusWith(%s, %s, %s)' % (code, reason, location)
else:
- return 'StatusWith(%s, %s)'%(code, reason)
-
- def code(self):
- if not self.val['_status']['_error']:
- return StatusWithPrinter.OK
- return self.val['_status'].dereference()['code']
+ return 'StatusWith(%s, %s)' % (code, reason)
class StringDataPrinter:
"""Pretty-printer for mongo::StringData"""
+
def __init__(self, val):
self.val = val
@@ -96,11 +88,12 @@ class StringDataPrinter:
if size == -1:
return self.val['_data'].lazy_string()
else:
- return self.val['_data'].lazy_string(length = size)
+ return self.val['_data'].lazy_string(length=size)
class BSONObjPrinter:
"""Pretty-printer for mongo::BSONObj"""
+
def __init__(self, val):
self.val = val
self.ptr = self.val['_objdata'].cast(gdb.lookup_type('void').pointer())
@@ -110,6 +103,9 @@ class BSONObjPrinter:
return 'map'
def children(self):
+ if not bson:
+ return
+
inferior = gdb.selected_inferior()
buf = bytes(inferior.read_memory(self.ptr, self.size))
options = CodecOptions(document_class=collections.OrderedDict)
@@ -123,14 +119,13 @@ class BSONObjPrinter:
ownership = "owned" if self.val['_ownedBuffer']['_buffer']['_holder']['px'] else "unowned"
size = self.size
- if size < 5 or size > 17*1024*1024:
- # TODO: print invalid sizes in hex as they may be sentinel bytes.
+ if size < 5 or size > 17 * 1024 * 1024:
size = hex(size)
if size == 5:
- return "%s empty BSONObj @ %s"%(ownership, self.ptr)
+ return "%s empty BSONObj @ %s" % (ownership, self.ptr)
else:
- return "%s BSONObj %s bytes @ %s"%(ownership, size, self.ptr)
+ return "%s BSONObj %s bytes @ %s" % (ownership, size, self.ptr)
class UnorderedFastKeyTablePrinter:
@@ -144,12 +139,12 @@ class UnorderedFastKeyTablePrinter:
valueType = gdb.lookup_type(valueTypeName).target()
self.valueTypePtr = valueType.pointer()
- def display_hint (self):
+ def display_hint(self):
return 'map'
def to_string(self):
return "UnorderedFastKeyTablePrinter<%s> with %s elems " % (
- self.val.type.template_argument(0), self.val["_size"])
+ self.val.type.template_argument(0), self.val["_size"])
def children(self):
cap = self.val["_area"]["_hashMask"] + 1
@@ -182,17 +177,16 @@ class DecorablePrinter:
self.start = decl_vector["_M_impl"]["_M_start"]
finish = decl_vector["_M_impl"]["_M_finish"]
decinfo_t = gdb.lookup_type('mongo::DecorationRegistry::DecorationInfo')
- self.count = int( (int(finish) - int(self.start)) / decinfo_t.sizeof )
+ self.count = int((int(finish) - int(self.start)) / decinfo_t.sizeof)
- def display_hint (self):
+ def display_hint(self):
return 'map'
def to_string(self):
return "Decorable<%s> with %s elems " % (self.val.type.template_argument(0),
- self.count)
+ self.count)
def children(self):
-
decorationData = get_unique_ptr(self.val["_decorations"]["_decorationData"])
for index in range(self.count):
@@ -216,13 +210,13 @@ class DecorablePrinter:
type_t = gdb.lookup_type(type_name)
obj = decorationData[dindex].cast(type_t)
- yield ('key', type_name)
- yield ('value', obj.address)
+ yield ('key', "%d:%s:%s" % (index, obj.address, type_name))
+ yield ('value', obj)
def find_match_brackets(search, opening='<', closing='>'):
"""Returns the index of the closing bracket that matches the first opening bracket.
- Returns -1 if no last matching bracket is found, i.e. not a a template.
+ Returns -1 if no last matching bracket is found, i.e. not a template.
Example:
'Foo<T>::iterator<U>''
@@ -232,41 +226,43 @@ def find_match_brackets(search, opening='<', closing='>'):
if index == -1:
return -1
- index = index + 1
+ start = index + 1
count = 1
str_len = len(search)
- while index < str_len and count > 0:
+ for index in range(start, str_len):
c = search[index]
- index = index + 1
if c == opening:
- count = count + 1
+ count += 1
elif c == closing:
- count = count - 1
+ count -= 1
if count == 0:
- return index - 1
+ return index
return -1
class MongoSubPrettyPrinter(gdb.printing.SubPrettyPrinter):
"""Sub pretty printer managed by the pretty-printer collection"""
- def __init__(self, name, prefix, printer):
+
+ def __init__(self, name, prefix, is_template, printer):
super(MongoSubPrettyPrinter, self).__init__(name)
self.prefix = prefix
self.printer = printer
+ self.is_template = is_template
class MongoPrettyPrinterCollection(gdb.printing.PrettyPrinter):
"""MongoDB-specific printer printer collection that ignores subtypes.
- It will match 'HashTable<T> but not 'HashTable<T>::iterator' when asked for 'HashTable'
+ It will match 'HashTable<T> but not 'HashTable<T>::iterator' when asked for 'HashTable'.
"""
+
def __init__(self):
super(MongoPrettyPrinterCollection, self).__init__("mongo", [])
- def add(self, name, prefix, printer):
- self.subprinters.append(MongoSubPrettyPrinter(name, prefix, printer))
+ def add(self, name, prefix, is_template, printer):
+ self.subprinters.append(MongoSubPrettyPrinter(name, prefix, is_template, printer))
def __call__(self, val):
@@ -283,7 +279,9 @@ class MongoPrettyPrinterCollection(gdb.printing.PrettyPrinter):
# We do not want HashTable<T>::iterator as an example, just HashTable<T>
if index == -1 or index + 1 == len(lookup_tag):
for printer in self.subprinters:
- if printer.enabled and lookup_tag.find(printer.prefix) == 0:
+ if printer.enabled and (
+ (printer.is_template and lookup_tag.find(printer.prefix) == 0) or
+ (not printer.is_template and lookup_tag == printer.prefix)):
return printer.printer(val)
return None
@@ -291,13 +289,12 @@ class MongoPrettyPrinterCollection(gdb.printing.PrettyPrinter):
def build_pretty_printer():
pp = MongoPrettyPrinterCollection()
- if bson is not None:
- pp.add('BSONObj', 'mongo::BSONObj', BSONObjPrinter)
- pp.add('Decorable', 'mongo::Decorable', DecorablePrinter)
- pp.add('Status', 'mongo::Status', StatusPrinter)
- pp.add('StatusWith', 'mongo::StatusWith', StatusWithPrinter)
- pp.add('StringData', 'mongo::StringData', StringDataPrinter)
- pp.add('UnorderedFastKeyTable', 'mongo::UnorderedFastKeyTable', UnorderedFastKeyTablePrinter)
+ pp.add('BSONObj', 'mongo::BSONObj', False, BSONObjPrinter)
+ pp.add('Decorable', 'mongo::Decorable', True, DecorablePrinter)
+ pp.add('Status', 'mongo::Status', False, StatusPrinter)
+ pp.add('StatusWith', 'mongo::StatusWith', True, StatusWithPrinter)
+ pp.add('StringData', 'mongo::StringData', False, StringDataPrinter)
+ pp.add('UnorderedFastKeyTable', 'mongo::UnorderedFastKeyTable', True, UnorderedFastKeyTablePrinter)
return pp
###################################################################################################
@@ -308,6 +305,7 @@ def build_pretty_printer():
# Dictionary of commands so we can write a help function that describes the MongoDB commands.
mongo_commands = {}
+
def register_mongo_command(obj, name, command_class):
"""Register a command with no completer as a mongo command"""
global mongo_commands
@@ -315,15 +313,19 @@ def register_mongo_command(obj, name, command_class):
mongo_commands[name] = obj.__doc__
+
class DumpGlobalServiceContext(gdb.Command):
"""Dump the Global Service Context"""
def __init__(self):
- register_mongo_command(self, "mongodb-services", gdb.COMMAND_DATA)
+ register_mongo_command(self, "mongodb-service-context", gdb.COMMAND_DATA)
def invoke(self, arg, _from_tty):
gdb.execute("print *('mongo::(anonymous namespace)::globalServiceContext')")
+# Register command
+DumpGlobalServiceContext()
+
class MongoDBAnalyze(gdb.Command):
"""Analyze MongoDB process"""
@@ -347,10 +349,17 @@ class MongoDBAnalyze(gdb.Command):
def analyze_mongod(self):
"""GDB in-process python supplement"""
- # Call into mongod, and dump the state of lock manager
- # Note that output will go to mongod's standard output, not the debugger output window
- gdb.execute("call ('mongo::(anonymous namespace)::globalLockManager').dump()",
- from_tty=False, to_string=False)
+ try:
+
+ # Call into mongod, and dump the state of lock manager
+ # Note that output will go to mongod's standard output, not the debugger output window
+ gdb.execute("call ('mongo::(anonymous namespace)::globalLockManager').dump()",
+ from_tty=False, to_string=False)
+ except gdb.Error as gdberr:
+ print("Ignoring error '%s'" % str(gdberr))
+
+# Register command
+MongoDBAnalyze()
class MongoDBHelp(gdb.Command):
@@ -364,9 +373,7 @@ class MongoDBHelp(gdb.Command):
for key in mongo_commands:
print("%s - %s" % (key, mongo_commands[key]))
-# Initialize Commands
-DumpGlobalServiceContext()
-MongoDBAnalyze()
+# Register command
MongoDBHelp()
###################################################################################################
@@ -377,8 +384,8 @@ MongoDBHelp()
# Register pretty-printers, replace existing mongo printers
gdb.printing.register_pretty_printer(
- gdb.current_objfile(),
- build_pretty_printer(),
- True)
+ gdb.current_objfile(),
+ build_pretty_printer(),
+ True)
print("MongoDB GDB pretty-printers and commands loaded, run 'mongodb-help' for list of commands")