blob: 7415659979214a049fbd69a1f95052158d3efadd [file] [log] [blame]
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 = "<invalid>"
# 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 "<invalid>";
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 "<invalid>";
try:
char_ptr = str_data['str']
except Exception as err:
print_("SwigStringPrinter: Could not access field (struct String).str\n");
return "<invalid>";
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 "<invalid>";
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 = "<err>"
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()