Created gdb pretty printers for wesnoth data types...
...t_interned, t_token, t_string, config and config::attribute_value. Create pretty printers for boost::unordered_map.
This commit is contained in:
parent
cad4b5e5a5
commit
38c351d523
3 changed files with 353 additions and 0 deletions
86
utils/gdb/register_wesnoth_pretty_printers.py
Normal file
86
utils/gdb/register_wesnoth_pretty_printers.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
|
||||
# This file registers pretty printers
|
||||
|
||||
"""
|
||||
Usage:
|
||||
|
||||
|
||||
"""
|
||||
|
||||
import gdb
|
||||
import re
|
||||
import itertools
|
||||
|
||||
def strip_type(val):
|
||||
"Strip the typename of all qualifiers and typedefs"
|
||||
# Get the type.
|
||||
type = val.type
|
||||
|
||||
# If it points to a reference, get the reference.
|
||||
if (type.code == gdb.TYPE_CODE_REF) or (type.code == gdb.TYPE_CODE_PTR):
|
||||
try: type = type.target ()
|
||||
except TypeError: type = val.type
|
||||
|
||||
# Get the unqualified type, stripped of typedefs.
|
||||
type = type.unqualified().strip_typedefs()
|
||||
|
||||
return type
|
||||
|
||||
|
||||
class NullPointerPrinter(object) :
|
||||
"""Print NULL for null pointers"""
|
||||
def __init__(self, val) :
|
||||
pass
|
||||
|
||||
def to_string(self) :
|
||||
return "NULL"
|
||||
|
||||
def display_hint(self) :
|
||||
return 'string'
|
||||
|
||||
def create_wesnoth_lookup_function(pretty_printers_dict) :
|
||||
"""Closure for lookup function """
|
||||
def wesnoth_lookup_function (val):
|
||||
"Look-up and return a pretty-printer that can print val."
|
||||
|
||||
#If it is a null pointer or object return the null pointer printer
|
||||
if (val.type.code == gdb.TYPE_CODE_PTR and long(val) == 0) or (val.address == 0):
|
||||
return NullPointerPrinter(val)
|
||||
|
||||
# Get the type name.
|
||||
type = strip_type(val)
|
||||
|
||||
# Get the type name.
|
||||
typename = type.tag
|
||||
|
||||
if typename == None:
|
||||
return None
|
||||
|
||||
# Iterate over local dictionary of types to determine
|
||||
# if a printer is registered for that type. Return an
|
||||
# instantiation of the printer if found.
|
||||
for function in pretty_printers_dict :
|
||||
if function.match (typename) :
|
||||
return pretty_printers_dict[function] (val)
|
||||
|
||||
# Cannot find a pretty printer. Return None.
|
||||
return None
|
||||
|
||||
return wesnoth_lookup_function
|
||||
|
||||
|
||||
|
||||
def register (new_pretty_printers):
|
||||
"""register the regex and printers from the dictionary with gdb"""
|
||||
|
||||
#delete all previous wesnoth printers
|
||||
remove_printers=[]
|
||||
for a in gdb.pretty_printers:
|
||||
if a.__name__ == 'wesnoth_lookup_function':
|
||||
remove_printers.append(a)
|
||||
for a in remove_printers:
|
||||
gdb.pretty_printers.remove(a)
|
||||
|
||||
#Add the new printers with the new dictionary
|
||||
gdb.pretty_printers.append(create_wesnoth_lookup_function(new_pretty_printers))
|
||||
|
46
utils/gdb/wesnoth_gdb.py
Normal file
46
utils/gdb/wesnoth_gdb.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
|
||||
# This file loads Wesnoth specific code into gdb
|
||||
|
||||
"""
|
||||
Usage:
|
||||
1. Add these lines line into your .gdbinit that you use for wesnoth file:
|
||||
|
||||
#Load the wesnoth pretty-printers
|
||||
python sys.path.append(os.path.abspath('utils/gdb/'))
|
||||
python import wesnoth_gdb
|
||||
|
||||
#Set expanded printing on
|
||||
set print pretty on
|
||||
|
||||
#Hide static members
|
||||
set print static-members off
|
||||
|
||||
|
||||
|
||||
"""
|
||||
|
||||
"""
|
||||
Notes
|
||||
You can interactively reload it in gdb with
|
||||
python reload(wesnoth_gdb)
|
||||
"""
|
||||
|
||||
|
||||
import sys, gdb
|
||||
|
||||
#Force a reload, which is handy if you are interactively editting
|
||||
if 'register_wesnoth_pretty_printers' in sys.modules:
|
||||
reload (register_wesnoth_pretty_printers)
|
||||
else:
|
||||
import register_wesnoth_pretty_printers
|
||||
|
||||
if 'wesnoth_pretty_printers' in sys.modules:
|
||||
reload(wesnoth_pretty_printers)
|
||||
else:
|
||||
import wesnoth_pretty_printers
|
||||
|
||||
pretty_printers_dict = {}
|
||||
pretty_printers_dict = wesnoth_pretty_printers.add_printers(pretty_printers_dict)
|
||||
register_wesnoth_pretty_printers.register(pretty_printers_dict)
|
||||
|
||||
|
221
utils/gdb/wesnoth_pretty_printers.py
Normal file
221
utils/gdb/wesnoth_pretty_printers.py
Normal file
|
@ -0,0 +1,221 @@
|
|||
|
||||
# Assorted Pretty printers for wesnoth data structures in gdb
|
||||
|
||||
import gdb
|
||||
import re
|
||||
import itertools
|
||||
|
||||
def strip_type(val):
|
||||
"Strip the typename of all qualifiers and typedefs"
|
||||
# Get the type.
|
||||
type = val.type
|
||||
|
||||
# If it points to a reference, get the reference.
|
||||
if (type.code == gdb.TYPE_CODE_REF) or (type.code == gdb.TYPE_CODE_PTR):
|
||||
try: type = type.target ()
|
||||
except TypeError: type = val.type
|
||||
|
||||
# Get the unqualified type, stripped of typedefs.
|
||||
type = type.unqualified().strip_typedefs()
|
||||
|
||||
return type
|
||||
|
||||
#Printer for n_interned::t_interned
|
||||
class T_InternedPrinter(object) :
|
||||
"""Print a t_interned_token<T>"""
|
||||
def __init__(self, val) :
|
||||
self.val = val
|
||||
|
||||
def to_string(self) :
|
||||
#Returns either a string or an other convertible to string
|
||||
return self.val['iter_']['first']
|
||||
|
||||
def display_hint(self) :
|
||||
#one of 'string' 'array' 'map'
|
||||
return 'string'
|
||||
|
||||
#Printer for n_token::t_token
|
||||
class T_TokenPrinter(object) :
|
||||
"""Print a t_token"""
|
||||
def __init__(self, val) :
|
||||
self.val = val
|
||||
|
||||
def to_string(self) :
|
||||
# Get the type.
|
||||
type = self.val.type
|
||||
|
||||
# Get the type name.
|
||||
type = strip_type(self.val)
|
||||
|
||||
#Return the underlying base class
|
||||
baseclass = type.fields()[0].type
|
||||
|
||||
return self.val.cast(baseclass)
|
||||
|
||||
def display_hint(self) :
|
||||
#one of 'string' 'array' 'map'
|
||||
return 'string'
|
||||
|
||||
class TstringPrinter(object) :
|
||||
"""Print a t_string"""
|
||||
def __init__(self, val) :
|
||||
self.val = val
|
||||
|
||||
def to_string(self) :
|
||||
# Get the type.
|
||||
type = self.val.type
|
||||
|
||||
# Get the type name.
|
||||
type = strip_type(self.val)
|
||||
|
||||
#Return the underlying base class
|
||||
baseclass = type.fields()[0].type
|
||||
|
||||
shared = self.val.cast(baseclass)['val_']
|
||||
if shared == 0 :
|
||||
return 'NULL'
|
||||
return shared.dereference()['val']['value_']
|
||||
|
||||
def display_hint(self) :
|
||||
#one of 'string' 'array' 'map'
|
||||
return 'string'
|
||||
|
||||
class AttributeValuePrinter(object) :
|
||||
"""Print an attribute_value"""
|
||||
def __init__(self, val) :
|
||||
self.val = val
|
||||
|
||||
def to_string(self) :
|
||||
# Get the type.
|
||||
type = self.val.type
|
||||
|
||||
# Get the type name.
|
||||
type = strip_type(self.val)
|
||||
|
||||
attr = self.val.cast(type)
|
||||
attr_type = attr['type_']
|
||||
|
||||
if attr_type == 0:
|
||||
return ""
|
||||
elif attr_type == 1 :
|
||||
return 'true' if attr['bool_value_'] else 'false'
|
||||
elif attr_type == 2 :
|
||||
return 'int ' + ('%s' % attr['int_value_'])
|
||||
elif attr_type == 3 :
|
||||
return 'double ' + ('%s' % attr['double_value_'])
|
||||
elif attr_type == 4 :
|
||||
return 'token ' + ('%s' % attr['token_value_'])
|
||||
else :
|
||||
return 't_string ' + ('%s' % attr['t_string_value_'])
|
||||
|
||||
return "attribute pretty printer found an unknown type"
|
||||
|
||||
def display_hint(self) :
|
||||
#one of 'string' 'array' 'map'
|
||||
return 'string'
|
||||
|
||||
|
||||
#This will be brittle as it depends on the underlying boost implementation, but its better than nothing
|
||||
#With much help from http://stackoverflow.com/questions/2804641/pretty-printing-boostunordered-map-on-gdb
|
||||
class BoostUnorderedMapPrinter(object) :
|
||||
""" Print a boost unordered map"""
|
||||
|
||||
class _iterator:
|
||||
def __init__ (self, val):
|
||||
t_key = val.type.template_argument(0)
|
||||
t_val = val.type.template_argument(1)
|
||||
self.buckets = val['table_']['buckets_']
|
||||
self.bucket_count = val['table_']['bucket_count_']
|
||||
self.current_bucket = 0
|
||||
pair = "std::pair<%s const, %s>" % (t_key, t_val)
|
||||
self.pair_pointer = gdb.lookup_type(pair).pointer()
|
||||
self.base_pointer = gdb.lookup_type("boost::unordered_detail::value_base< %s >" % pair).pointer()
|
||||
self.node_pointer = gdb.lookup_type("boost::unordered_detail::hash_node<std::allocator< %s >, boost::unordered_detail::ungrouped>" % pair).pointer()
|
||||
self.node = self.buckets[self.current_bucket]['next_']
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
if self.buckets == 0 :
|
||||
raise StopIteration
|
||||
while not self.node:
|
||||
self.current_bucket = self.current_bucket + 1
|
||||
if self.current_bucket >= self.bucket_count:
|
||||
raise StopIteration
|
||||
self.node = self.buckets[self.current_bucket]['next_']
|
||||
|
||||
iterator = self.node.cast(self.node_pointer).cast(self.base_pointer).cast(self.pair_pointer).dereference()
|
||||
self.node = self.node['next_']
|
||||
|
||||
return ('%s' % iterator['first']), iterator['second']
|
||||
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
self.buckets = val['table_']['buckets_']
|
||||
|
||||
def children(self):
|
||||
return self._iterator(self.val)
|
||||
|
||||
def to_string(self):
|
||||
ret = "boost::unordered_map"
|
||||
if self.buckets == 0 :
|
||||
ret += " EMPTY"
|
||||
return ret
|
||||
|
||||
def display_hint(self):
|
||||
return 'string'
|
||||
|
||||
|
||||
class BoostUnorderedMapIteratorPrinter(object):
|
||||
def __init__ (self, val):
|
||||
pair = val.type.template_argument(0).template_argument(0)
|
||||
t_key = pair.template_argument(0)
|
||||
t_val = pair.template_argument(1)
|
||||
self.node = val['base_']['node_']
|
||||
self.pair_pointer = pair.pointer()
|
||||
self.base_pointer = gdb.lookup_type("boost::unordered_detail::value_base< %s >" % pair).pointer()
|
||||
self.node_pointer = gdb.lookup_type("boost::unordered_detail::hash_node<std::allocator< %s >, boost::unordered_detail::ungrouped>" % pair).pointer()
|
||||
self.bucket_pointer = gdb.lookup_type("boost::unordered_detail::hash_bucket<std::allocator< %s > >" % pair).pointer()
|
||||
|
||||
def to_string(self):
|
||||
if not self.node:
|
||||
return 'NULL'
|
||||
iterator = self.node.cast(self.node_pointer).cast(self.base_pointer).cast(self.pair_pointer).dereference()
|
||||
return iterator['second']
|
||||
|
||||
def display_hint(self):
|
||||
return 'string'
|
||||
|
||||
|
||||
class ConfigPrinter(object) :
|
||||
"""Print a config"""
|
||||
def __init__(self, val) :
|
||||
self.val = val
|
||||
|
||||
def to_string(self) :
|
||||
return "config"
|
||||
def children(self) :
|
||||
#yield "invalid", self.val['invalid']
|
||||
yield "values", self.val['values']
|
||||
yield "children", self.val['children']
|
||||
yield "ordered_children", self.val['ordered_children']
|
||||
|
||||
def display_hint(self) :
|
||||
#one of 'string' 'array' 'map'
|
||||
return 'string'
|
||||
|
||||
|
||||
|
||||
# register the pretty-printers
|
||||
def add_printers(pretty_printers_dict) :
|
||||
pretty_printers_dict[re.compile ('^n_interned::t_interned_token.*$')] = T_InternedPrinter
|
||||
pretty_printers_dict[re.compile ('^n_token::t_token$')] = T_TokenPrinter
|
||||
pretty_printers_dict[re.compile ('^t_string$')] = TstringPrinter
|
||||
pretty_printers_dict[re.compile ('^config::attribute_value$')] = AttributeValuePrinter
|
||||
pretty_printers_dict[re.compile ('^boost::unordered_map.*$')] = BoostUnorderedMapPrinter
|
||||
pretty_printers_dict[re.compile ('^boost::unordered_detail::hash_iterator\<std::allocator\<std::pair\<.*$')] = BoostUnorderedMapIteratorPrinter
|
||||
pretty_printers_dict[re.compile ('^config$')] = ConfigPrinter
|
||||
|
||||
return pretty_printers_dict
|
||||
|
Loading…
Add table
Reference in a new issue