import gdb import gdb.types import itertools import re log_file = None GDB_FLATTENED_CHILDREN_WORKAROUND = False CHILDREN_MAX_RECURSION_LEVEL = 0 # workaround: don't cast the following DOHs to it's actual type # to avoid infinite pretty-print loops cast_black_list = { 'Hash': set(['parentNode', 'symtab', 'csymtab', 'sym:symtab', 'inherit', 'nextSibling', 'previousSibling']) } def print_(msg): global log_file; if True: if log_file == None: log_file = open('swig_gdb.log', 'w') log_file.write(msg) print(msg) class SwigStringPrinter: """ Pretty print Swig String* types. """ def __init__ (self, typename, val): self.typename = typename self.val = val try: self.t_swigstr_ptr = gdb.lookup_type("struct String").pointer() self.t_doh_base_ptr = gdb.lookup_type("DohBase").pointer() except Exception as err: print_("SwigStringPrinter: Could not retrieve gdb types.\n %s.\n"%(str(err))) def display_hint(self): return 'string' def to_string(self): ret = "" # Conversion taken from Swig Internals manual: # http://peregrine.hpc.uwm.edu/Head-node-docs/swig/2.0.4/Devel/internals.html#7 # (*(struct String *)(((DohBase *)s)->data)).str dohbase = None; str_data = None; char_ptr = None; try: dohbase = self.val.reinterpret_cast(self.t_doh_base_ptr).dereference() except Exception as err: print_("SwigStringPrinter: Could not dereference DOHBase*\n"); return ""; try: str_data = dohbase['data'].reinterpret_cast(self.t_swigstr_ptr).dereference() except Exception as err: print_("SwigStringPrinter: Could not dereference struct String*\n"); return ""; try: char_ptr = str_data['str'] except Exception as err: print_("SwigStringPrinter: Could not access field (struct String).str\n"); return ""; if char_ptr.is_lazy is True: char_ptr.fetch_lazy () try: ret = char_ptr.string() except Exception as err: print_("SwigStringPrinter: Could not convert const char* to string\n"); return ""; return ret class SwigIterator: def __init__(self): self.t_doh_base_ptr = gdb.lookup_type("DohBase").pointer() self.t_string_ptr = gdb.lookup_type("String").pointer() self.t_node_ptr = gdb.lookup_type("Node").pointer() self.t_hash_ptr = gdb.lookup_type("Hash").pointer() self.t_file_ptr = gdb.lookup_type("File").pointer() self.t_void_ptr = gdb.lookup_type("void").pointer() def cast_doh(self, doh, name = None): if doh == 0: return doh doh = doh.reinterpret_cast(self.t_doh_base_ptr); val_base = doh.dereference() val_type = val_base['type'].dereference() val_typestr = val_type['objname'].string() if not name == None and val_typestr in cast_black_list: blacklist = cast_black_list[val_typestr] if name in blacklist: return doh if "String" == val_typestr: doh = doh.reinterpret_cast(self.t_string_ptr) elif "File" == val_typestr: doh = doh.reinterpret_cast(self.t_file_ptr) # BUG: GDB Pyhton can not handle cyclic references yet # so these casts are deactivated elif "Hash" == val_typestr: doh = doh.reinterpret_cast(self.t_hash_ptr) elif "Node" == val_typestr: doh = doh.reinterpret_cast(self.t_node_ptr) return doh class SwigListIterator(SwigIterator): def __init__(self, val): SwigIterator.__init__(self); try: self.valid = False self.val = val.reinterpret_cast(self.t_doh_base_ptr) val_base = self.val.dereference() val_type = val_base['type'].dereference() val_typestr = val_type['objname'].string() #print_("SwigListIterator: constructing iterator for value of type %s"%val_typestr) self.t_struct_list_ptr = gdb.lookup_type("struct List").pointer() doh_base = self.val.dereference() self.l = doh_base['data'].reinterpret_cast(self.t_struct_list_ptr).dereference() self.address = 0 self._index = 0 self.key = 0 self.item = 0 self.address = self.val.dereference().address self.is_first = True self.valid = True except Exception as err: print_("SwigListIterator: Construction failed.\n %s.\n"%(str(err))) def __iter__(self): return self def List_first(self): self.object = None; self._index = 0 self.key = 0 self.nitems = int(self.l['nitems']) self.items = self.l['items'] if self.nitems > 0: self.item = self.items[0] else: self.stop() def List_next(self): self._index = self._index + 1 if self._index >= self.nitems: self.stop() else: self.item = self.items[self._index] def next(self): if not self.valid: self.stop() if self.is_first: self.is_first = False try: self.List_first() except StopIteration: raise StopIteration except Exception as err: print_("Error during iteration to first node: \n %s \n" %(str(err))) self.stop() else: try: self.List_next() except StopIteration: raise StopIteration except Exception as err: print_("Error during iteration to first node: \n %s \n" %(str(err))) self.stop() key_str = "[%d]"%self._index item = 0 try: item = self.cast_doh(self.item) except Exception as err: print_("SwigListIterator(%s): Exception during casting of value doh:\n %s\n" % (str(self.address), str(err)) ) self.stop() return (key_str, item) def stop(self): self.is_first = True self.item = 0 self.key = 0 raise StopIteration class SwigHashIterator(SwigIterator): def __init__(self, val): SwigIterator.__init__(self); try: self.valid = False self.val = val.reinterpret_cast(self.t_doh_base_ptr) self.t_struct_hash_ptr = gdb.lookup_type("struct Hash").pointer() self.t_struct_hash_node_ptr = gdb.lookup_type("struct HashNode").pointer() doh_base = self.val.dereference() hash_ = doh_base['data'].reinterpret_cast(self.t_struct_hash_ptr).dereference() self.hashtable = hash_['hashtable'] self.hashsize = int(hash_['hashsize']) self.nitems = int(hash_['nitems']) self.next_ = 0 self.address = 0 self.pos = 0; self._current = 0 self.item = 0 self.key = 0 self._index = 0 self.address = self.val.dereference().address self.is_first = True self.valid = True except Exception as err: print_("SwigHashIterator: Construction failed.\n %s.\n"%(str(err))) def __iter__(self): return self def Hash_firstiter(self): self._current = 0; self.item = 0; self.key = 0; self._index = 0; while (self._index < self.hashsize) and (self.hashtable[self._index] == 0): self._index = self._index+1; if self._index >= self.hashsize: self.stop(); self._current = self.hashtable[self._index] self._current = self._current.reinterpret_cast(self.t_struct_hash_node_ptr); self.item = self._current['object']; self.key = self._current['key']; self._current = self._current['next']; def Hash_nextiter(self): if self._current == 0: self._index = self._index + 1 while (self._index < self.hashsize) and (self.hashtable[self._index] == 0): self._index = self._index + 1 if self._index >= self.hashsize: self.item = 0; self.key = 0; self._current = 0; self.stop() self._current = self.hashtable[self._index]; self._current = self._current.reinterpret_cast(self.t_struct_hash_node_ptr); self.key = self._current['key']; self.item = self._current['object']; self._current = self._current['next']; def next(self): if not self.valid: self.stop() if self.is_first: self.is_first = False try: self.Hash_firstiter() except StopIteration: raise StopIteration except Exception as err: print_("Error during iteration to first node: \n %s \n" %(str(err))) self.stop() else: try: self.Hash_nextiter() except StopIteration: raise StopIteration except Exception as err: print_("Error during iteration to first node: \n %s \n" %(str(err))) self.stop() key_str = "" item = 0 try: string_printer = SwigStringPrinter("String *", self.key) key_str = string_printer.to_string() except Exception as err: print_("SwigHashIterator(%s): Exception during extracting key string:\n %s\n" % (str(self.address), str(err)) ) self.stop() try: item = self.cast_doh(self.item, key_str) except Exception as err: print_("SwigHashIterator(%s): Exception during casting of value doh:\n %s\n" % (str(self.address), str(err)) ) self.stop() return (key_str, item) def stop(self): self.is_first = True raise StopIteration class AlternateKeyValueIterator(): def __init__(self, iterable): self.it = iterable.__iter__() self._next = None self.count = -1 def __iter__(self): return self def next(self): if self._next == None: key, value = self.it.next() self._next = value self.count = self.count + 1 return ("[%d]"%self.count, key) else: value = self._next self._next = None return ("[%d]"%self.count, value) class NopIterator: def __init__(self): pass def __iter__(self): return self def next(self): raise StopIteration class SwigListPrinter: """ Pretty print Swig List* types (also ParmList*). """ def __init__ (self, typename, val): self.typename = typename self.val = val it = SwigListIterator(val) self.valid = it.valid self.address = it.address def display_hint(self): return 'array' def to_string(self): return "%s(%s)" % (str(self.typename), str(self.address)) def children(self): if not self.valid: print_("SwigListPrinter: Invalid state.\n") return NopIterator() try: it = SwigListIterator(self.val) return it except Exception as err: print_("SwigListPrinter: Error during creation of children iterator. \n %s \n" %(str(err))) raise err class SwigHashPrinter: """ Pretty print Swig Hash* types (also Node*). """ def __init__ (self, typename, val): self.typename = typename self.val = val it = SwigHashIterator(val) self.valid = it.valid self.address = it.address self.level = 0; def display_hint(self): return 'map' def to_string(self): return "%s(%s)" % (str(self.typename), str(self.address)) def children(self): global GDB_FLATTENED_CHILDREN_WORKAROUND global CHILDREN_MAX_RECURSION_LEVEL if not self.valid: print_("SwigHashPrinter: Invalid state.\n") return NopIterator() if self.level > CHILDREN_MAX_RECURSION_LEVEL: return NopIterator() try: it = SwigHashIterator(self.val) if GDB_FLATTENED_CHILDREN_WORKAROUND: return AlternateKeyValueIterator(it) return it except Exception as err: print_("SwigHashPrinter: Error during creation of children iterator. \n %s \n" %(str(err))) raise err class SwigSimplePrinter: def __init__ (self, typename, val): self.typename = typename self.val = val def display_hint(self): return "string" def to_string(self): return "%s(%s)"%(self.typename, str(self.val.address)) class SwigDelegatingPrinter: def __init__ (self, typename, val): t_doh_base_ptr = gdb.lookup_type("DohBase").pointer() val_base = val.reinterpret_cast(t_doh_base_ptr).dereference() val_type = val_base['type'].dereference() val_typestr = val_type['objname'].string() self.has_children = False if val_typestr == "Hash": self.delegate = SwigHashPrinter(typename, val) self.has_children = True elif val_typestr == "List": self.delegate = SwigListPrinter(typename, val) self.has_children = True elif val_typestr == "String": self.delegate = SwigStringPrinter(typename, val) else: self.delegate = SwigSimplePrinter(typename, val) def display_hint(self): return self.delegate.display_hint() def to_string(self): return self.delegate.to_string() def children(self): if not self.has_children: return NopIterator() return self.delegate.children() class RxPrinter(object): def __init__(self, name, function): super(RxPrinter, self).__init__() self.name = name self.function = function self.enabled = True def invoke(self, value): if not self.enabled: return None return self.function(self.name, value) # A pretty-printer that conforms to the "PrettyPrinter" protocol from # gdb.printing. It can also be used directly as an old-style printer. class Printer(object): def __init__(self, name): super(Printer, self).__init__() self.name = name self.subprinters = [] self.lookup = {} self.enabled = True self.compiled_rx = re.compile('^([a-zA-Z0-9_: *]+)$') def add(self, name, function): if not self.compiled_rx.match(name): raise ValueError, 'error: "%s" does not match' % name printer = RxPrinter(name, function) self.subprinters.append(printer) self.lookup[name] = printer print('Added pretty printer for %s. ' % (name)) def __call__(self, val): typename = str(val.type) if typename in self.lookup: ret = self.lookup[typename].invoke(val) return ret # Cannot find a pretty printer. Return None. return None swig_printer = None def register_swig_printers(obj): global swig_printer if obj is None: obj = gdb obj.pretty_printers.append(swig_printer) def build_swig_printer(): global swig_printer swig_printer = Printer("swig") swig_printer.add('String *', SwigStringPrinter) swig_printer.add('const String *', SwigStringPrinter) swig_printer.add('SwigType *', SwigStringPrinter) swig_printer.add('Hash *', SwigHashPrinter) swig_printer.add('const Hash *', SwigHashPrinter) swig_printer.add('Node *', SwigHashPrinter) swig_printer.add('const Node *', SwigHashPrinter) swig_printer.add('Parm *', SwigHashPrinter) swig_printer.add('const Parm *', SwigHashPrinter) swig_printer.add('List *', SwigListPrinter) swig_printer.add('const List *', SwigListPrinter) swig_printer.add('ParmList *', SwigDelegatingPrinter) swig_printer.add('const ParmList *', SwigDelegatingPrinter) swig_printer.add('File *', SwigDelegatingPrinter) #swig_printer.add('DOH *', SwigDelegatingPrinter) #swig_printer.add('const DOH *', SwigDelegatingPrinter) print_("Loaded swig printers\n"); def enableGdbPrintWorkaround(): global GDB_FLATTENED_CHILDREN_WORKAROUND GDB_FLATTENED_CHILDREN_WORKAROUND = True def setChildrenRecursionLevel(level): global CHILDREN_MAX_RECURSION_LEVEL CHILDREN_MAX_RECURSION_LEVEL = level build_swig_printer()