Sindbad~EG File Manager
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
# Pretty-printers for libc++.
import gdb
import gdb.printing
def find_field(type, name):
for field in type.fields():
if field.name == name:
return field
return None
class IteratorBase:
"""Provide python 2.x compat for iterators"""
def next(self):
return self.__next__()
def dequeBlockSize(value_type):
if value_type.sizeof < 256:
return 4096 / value_type.sizeof
else:
return 16
class StdDequePrinter:
"""Print a std::deque"""
class __iterator(IteratorBase):
def __init__(self, block_size, begin, end, start, size):
self.block_size = block_size
self.begin = begin
self.end = end
self.start = start
self.count = size
def __iter__(self):
return self
def __next__(self):
if self.count == 0:
raise StopIteration
item_ptr = self.begin.dereference() + self.start
item = item_ptr.dereference()
self.start = self.start + 1
if self.start == self.block_size:
self.begin = self.begin + 1
self.start = 0
self.count = self.count - 1
return ("", item)
def __init__(self, val, name="deque"):
self.val = val
self.name = name
# __block_size is generally optimized out and not available here
value_type = self.val.type.template_argument(0)
self.block_size = dequeBlockSize(value_type)
def children(self):
map_val = self.val['__map_']
return self.__iterator(self.block_size, map_val['__begin_'],
map_val['__end_'], self.val['__start_'],
self.val['__size_']['__value_'])
def display_hint(self):
return 'array'
def to_string(self):
i = self.val['__size_']['__value_']
return "std::%s with %d element%s" % (self.name, i,
"" if i == 1 else "s")
class StdDequeIteratorPrinter:
"""Print a std::deque::iterator"""
def __init__(self, val):
self.val = val
def to_string(self):
item = self.val['__ptr_'].dereference()
return str(item)
class StdForwardListPrinter:
"""Print a std::forward_list"""
class __iterator(IteratorBase):
def __init__(self, head):
self.current = head
self.count = 0
def __iter__(self):
return self
def __next__(self):
if self.current == 0:
raise StopIteration
else:
item = self.current['__value_']
count = self.count
self.current = self.current['__next_']
self.count = self.count + 1
return ('[%d]' % count, item)
def __init__(self, val):
self.val = val
def children(self):
return self.__iterator(self.val['__before_begin_']['__value_']['__next_'])
def to_string(self):
if self.val['__before_begin_']['__value_']['__next_'] == 0:
return "empty std::forward_list"
return "std::forward_list"
class StdForwardListIteratorPrinter:
"""Print a std::forward_list::iterator"""
def __init__(self, val):
self.val = val
link_type = self.val['__ptr_'].type.strip_typedefs().target()
self.node_type = link_type.template_argument(0)
def to_string(self):
node = self.val['__ptr_'].cast(self.node_type)
item = node['__value_']
return str(item)
class StdListPrinter:
"""Print a std::list"""
class __iterator(IteratorBase):
def __init__(self, head, node_type):
self.current = head['__next_']
self.end = head.address
self.node_type = node_type
self.count = 0
def __iter__(self):
return self
def __next__(self):
if self.current == self.end:
raise StopIteration
else:
node = self.current.cast(self.node_type)
item = node['__value_']
count = self.count
self.current = self.current['__next_']
self.count = self.count + 1
return ('[%d]' % count, item)
def __init__(self, val):
self.val = val
self.node_type = gdb.lookup_type(self.val.type.name + '::__node_pointer')
def size(self):
return self.val['__size_alloc_']['__value_']
def children(self):
head = self.val['__end_']
return self.__iterator(self.val['__end_'], self.node_type)
def to_string(self):
if self.size() == 0:
return "empty std::list"
return "std::list"
class StdListIteratorPrinter:
"""Print a std::list::iterator"""
def __init__(self, val):
self.val = val
link_type = self.val['__ptr_'].type.strip_typedefs().target()
node_type_name = str(link_type).replace('__list_node_base', '__list_node', 1)
self.node_type = gdb.lookup_type(node_type_name).pointer()
def to_string(self):
node = self.val['__ptr_'].cast(self.node_type)
item = node['__value_']
return str(item)
class StdUniquePtrPrinter:
"""Print a std::unique_ptr"""
def __init__(self, val):
self.val = val
def to_string(self):
v = self.val['__ptr_']['__value_']
return "std::unique_ptr<%s> = %s" % (v.type.target(), v)
class StdUnorderedMapPrinter:
"""Print a std::unordered_map"""
class __iterator(IteratorBase):
def __init__(self, begin, node_type, cc_field):
self.current = begin
self.node_type = node_type
self.cc_field = cc_field
self.state = 0
def __iter__(self):
return self
def __next__(self):
if self.current == 0:
raise StopIteration
else:
node = self.current.cast(self.node_type)
if self.state == 0:
name = 'key'
item = node['__value_'][self.cc_field]['first']
self.state = 1
else:
name = 'value'
item = node['__value_'][self.cc_field]['second']
self.state = 0
self.current = self.current['__next_']
return (name, item)
def __init__(self, val):
self.val = val
next_type = val['__table_']['__p1_']['__value_'].type
self.node_type = next_type.template_argument(0)
value_type = self.node_type.target().template_argument(0)
if find_field(value_type, '__cc_'):
self.cc_field = '__cc_'
else:
self.cc_field = '__cc'
def children(self):
return self.__iterator(self.val['__table_']['__p1_']['__value_']['__next_'],
self.node_type, self.cc_field)
def display_hint(self):
return 'map'
def to_string(self):
i = self.val['__table_']['__p2_']['__value_']
return "std::unordered_map with %d element%s" % (i, "" if i == 1 else "s")
class StdUnorderedMapIteratorPrinter:
"""Print a std::unordered_map::iterator"""
def __init__(self, val):
self.val = val
iter_type = self.val.type.template_argument(0)
self.node_type = iter_type.template_argument(0)
value_type = self.node_type.target().template_argument(0)
if find_field(value_type, '__cc_'):
self.cc_field = '__cc_'
else:
self.cc_field = '__cc'
def to_string(self):
node = self.val['__i_']['__node_'].cast(self.node_type)
if node == 0:
return "end()"
key = node['__value_'][self.cc_field]['first']
value = node['__value_'][self.cc_field]['second']
return "[%s] = %s" % (str(key), str(value))
class StdVectorPrinter:
"""Print a std::vector"""
class __iterator(IteratorBase):
def __init__(self, begin, end):
self.current = begin
self.end = end
self.count = 0
def __iter__(self):
return self
def __next__(self):
if self.current == self.end:
raise StopIteration
else:
item = self.current.dereference()
count = self.count
self.current = self.current + 1
self.count = self.count + 1
return ('[%d]' % count, item)
def __init__(self, val):
self.val = val
def children(self):
return self.__iterator(self.val['__begin_'], self.val['__end_'])
def display_hint(self):
return 'array'
def to_string(self):
begin = self.val['__begin_']
end = self.val['__end_']
return "std::vector of length %d" % int(end - begin)
class StdStackPrinter:
"""Print a std::stack"""
def __init__(self, val):
self.child = StdDequePrinter(val['c'], "stack")
def children(self):
return self.child.children()
def display_hint(self):
return self.child.display_hint()
def to_string(self):
return self.child.to_string()
class StdStringPrinter:
"""Print a std::string"""
def __init__(self, val):
self.val = val
def display_hint(self):
return 'string'
def to_string(self):
# libcxx commit 29c8c070a1770fc510ccad3be753f6f50336f8cc changed how
# short vs long strings are encoded.
has_short_mask = find_field(self.val.type, '__short_mask') != None
r_first = self.val['__r_']['__value_']
if has_short_mask:
is_long = (r_first['__s']['__size_'] & self.val['__short_mask']) != 0
else:
is_long = r_first['__s']['__is_long_'] != 0
if is_long:
pointer = r_first['__l']['__data_']
size = r_first['__l']['__size_']
else:
pointer = r_first['__s']['__data_']
size = r_first['__s']['__size_']
if has_short_mask:
if int(self.val['__short_mask']) == 1:
size = size >> 1
return pointer.string(length = size)
def build_pretty_printers():
pp = gdb.printing.RegexpCollectionPrettyPrinter("libc++")
pp.add_printer('deque', '^std::__1::deque<.*>$', StdDequePrinter)
pp.add_printer('deque::iterator', '^std::__1::__deque_iterator<.*>$',
StdDequeIteratorPrinter)
pp.add_printer('forward_list', '^std::__1::forward_list<.*>$', StdForwardListPrinter)
pp.add_printer('forward_list::iterator', '^std::__1::__forward_list_(const_)?iterator<.*>$',
StdForwardListIteratorPrinter)
pp.add_printer('list', '^std::__1::list<.*>$', StdListPrinter)
pp.add_printer('list::iterator', '^std::__1::__list_(const_)?iterator<.*>$',
StdListIteratorPrinter)
pp.add_printer('stack', '^std::__1::stack<.*>$', StdStackPrinter)
pp.add_printer('unique_ptr', '^std::__1::unique_ptr<.*>$',
StdUniquePtrPrinter)
pp.add_printer('unordered_map', '^std::__1::unordered_map<.*>$',
StdUnorderedMapPrinter)
pp.add_printer('unordered_map::iterator', '^std::__1::__hash_map_(const_)?iterator<.*>$',
StdUnorderedMapIteratorPrinter)
pp.add_printer('vector', '^std::__1::vector<.*>$', StdVectorPrinter)
pp.add_printer('string', '^std::__1::basic_string<.*>$', StdStringPrinter)
return pp
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists