diff options
-rw-r--r-- | .gdbinit | 1 | ||||
-rw-r--r-- | buildscripts/gdb/mongo.py | 139 |
2 files changed, 73 insertions, 67 deletions
@@ -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") |