summaryrefslogtreecommitdiff
path: root/libstdc++-v3/python/libstdcxx
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2015-04-22 10:21:45 +0000
committer <>2015-04-25 21:44:09 +0000
commitf80b5ea1605c9f9408c5aa386ba71c16d918ebbf (patch)
treebb7eafaa81fc4b8c5c215bc08d517fd158db234a /libstdc++-v3/python/libstdcxx
parentc27a97d04853380f1e80525391b3f0d156ed4c84 (diff)
downloadgcc-tarball-f80b5ea1605c9f9408c5aa386ba71c16d918ebbf.tar.gz
Imported from /home/lorry/working-area/delta_gcc-tarball/gcc-5.1.0.tar.bz2.gcc-5.1.0
Diffstat (limited to 'libstdc++-v3/python/libstdcxx')
-rw-r--r--libstdc++-v3/python/libstdcxx/v6/__init__.py31
-rw-r--r--libstdc++-v3/python/libstdcxx/v6/printers.py287
-rw-r--r--libstdc++-v3/python/libstdcxx/v6/xmethods.py528
3 files changed, 828 insertions, 18 deletions
diff --git a/libstdc++-v3/python/libstdcxx/v6/__init__.py b/libstdc++-v3/python/libstdcxx/v6/__init__.py
index 8b13789179..de3aa728ce 100644
--- a/libstdc++-v3/python/libstdcxx/v6/__init__.py
+++ b/libstdc++-v3/python/libstdcxx/v6/__init__.py
@@ -1 +1,32 @@
+# Copyright (C) 2014-2015 Free Software Foundation, Inc.
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import gdb
+
+# Load the pretty-printers.
+from .printers import register_libstdcxx_printers
+register_libstdcxx_printers(gdb.current_objfile())
+
+# Load the xmethods if GDB supports them.
+def gdb_has_xmethods():
+ try:
+ import gdb.xmethod
+ return True
+ except ImportError:
+ return False
+
+if gdb_has_xmethods():
+ from .xmethods import register_libstdcxx_xmethods
+ register_libstdcxx_xmethods(gdb.current_objfile())
diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index 1fa08fbd57..5a414c59a7 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -1,6 +1,6 @@
# Pretty-printers for libstdc++.
-# Copyright (C) 2008-2014 Free Software Foundation, Inc.
+# Copyright (C) 2008-2015 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -327,22 +327,35 @@ class StdTuplePrinter:
return self
def __next__ (self):
- nodes = self.head.type.fields ()
# Check for further recursions in the inheritance tree.
+ # For a GCC 5+ tuple self.head is None after visiting all nodes:
+ if not self.head:
+ raise StopIteration
+ nodes = self.head.type.fields ()
+ # For a GCC 4.x tuple there is a final node with no fields:
if len (nodes) == 0:
raise StopIteration
# Check that this iteration has an expected structure.
- if len (nodes) != 2:
+ if len (nodes) > 2:
raise ValueError("Cannot parse more than 2 nodes in a tuple tree.")
- # - Left node is the next recursion parent.
- # - Right node is the actual class contained in the tuple.
+ if len (nodes) == 1:
+ # This is the last node of a GCC 5+ std::tuple.
+ impl = self.head.cast (nodes[0].type)
+ self.head = None
+ else:
+ # Either a node before the last node, or the last node of
+ # a GCC 4.x tuple (which has an empty parent).
- # Process right node.
- impl = self.head.cast (nodes[1].type)
+ # - Left node is the next recursion parent.
+ # - Right node is the actual class contained in the tuple.
+
+ # Process right node.
+ impl = self.head.cast (nodes[1].type)
+
+ # Process left node and set it as head.
+ self.head = self.head.cast (nodes[0].type)
- # Process left node and set it as head.
- self.head = self.head.cast (nodes[0].type)
self.count = self.count + 1
# Finally, check the implementation. If it is
@@ -460,7 +473,7 @@ class StdDebugIteratorPrinter:
# and return the wrapped iterator value.
def to_string (self):
itype = self.val.type.template_argument(0)
- return self.val['_M_current'].cast(itype)
+ return self.val.cast(itype)
class StdMapPrinter:
"Print a std::map or std::multimap"
@@ -660,6 +673,7 @@ class StdStringPrinter:
def __init__(self, typename, val):
self.val = val
+ self.new_string = typename.find("::__cxx11::basic_string") != -1
def to_string(self):
# Make sure &string works, too.
@@ -671,13 +685,18 @@ class StdStringPrinter:
# the string according to length, not according to first null
# encountered.
ptr = self.val ['_M_dataplus']['_M_p']
- realtype = type.unqualified ().strip_typedefs ()
- reptype = gdb.lookup_type (str (realtype) + '::_Rep').pointer ()
- header = ptr.cast(reptype) - 1
- len = header.dereference ()['_M_length']
+ if self.new_string:
+ length = self.val['_M_string_length']
+ # https://sourceware.org/bugzilla/show_bug.cgi?id=17728
+ ptr = ptr.cast(ptr.type.strip_typedefs())
+ else:
+ realtype = type.unqualified ().strip_typedefs ()
+ reptype = gdb.lookup_type (str (realtype) + '::_Rep').pointer ()
+ header = ptr.cast(reptype) - 1
+ length = header.dereference ()['_M_length']
if hasattr(ptr, "lazy_string"):
- return ptr.lazy_string (length = len)
- return ptr.string (length = len)
+ return ptr.lazy_string (length = length)
+ return ptr.string (length = length)
def display_hint (self):
return 'string'
@@ -836,6 +855,129 @@ class StdForwardListPrinter:
return 'empty %s' % (self.typename)
return '%s' % (self.typename)
+class SingleObjContainerPrinter(object):
+ "Base class for printers of containers of single objects"
+
+ def __init__ (self, val, viz):
+ self.contained_value = val
+ self.visualizer = viz
+
+ def _recognize(self, type):
+ """Return TYPE as a string after applying type printers"""
+ global _use_type_printing
+ if not _use_type_printing:
+ return str(type)
+ return gdb.types.apply_type_recognizers(gdb.types.get_type_recognizers(),
+ type) or str(type)
+
+ class _contained(Iterator):
+ def __init__ (self, val):
+ self.val = val
+
+ def __iter__ (self):
+ return self
+
+ def __next__(self):
+ if self.val is None:
+ raise StopIteration
+ retval = self.val
+ self.val = None
+ return ('[contained value]', retval)
+
+ def children (self):
+ if self.contained_value is None:
+ return self._contained (None)
+ if hasattr (self.visualizer, 'children'):
+ return self.visualizer.children ()
+ return self._contained (self.contained_value)
+
+ def display_hint (self):
+ # if contained value is a map we want to display in the same way
+ if hasattr (self.visualizer, 'children') and hasattr (self.visualizer, 'display_hint'):
+ return self.visualizer.display_hint ()
+ return None
+
+
+class StdExpAnyPrinter(SingleObjContainerPrinter):
+ "Print a std::experimental::any"
+
+ def __init__ (self, typename, val):
+ self.typename = 'std::experimental::any'
+ self.val = val
+ self.contained_type = None
+ contained_value = None
+ visualizer = None
+ mgr = self.val['_M_manager']
+ if mgr != 0:
+ func = gdb.block_for_pc(int(mgr.cast(gdb.lookup_type('intptr_t'))))
+ if not func:
+ raise ValueError("Invalid function pointer in std::experimental::any")
+ rx = r"""({0}::_Manager_\w+<.*>)::_S_manage\({0}::_Op, {0} const\*, {0}::_Arg\*\)""".format(typename)
+ m = re.match(rx, func.function.name)
+ if not m:
+ raise ValueError("Unknown manager function in std::experimental::any")
+
+ # FIXME need to expand 'std::string' so that gdb.lookup_type works
+ mgrname = re.sub("std::string(?!\w)", str(gdb.lookup_type('std::string').strip_typedefs()), m.group(1))
+ mgrtype = gdb.lookup_type(mgrname)
+ self.contained_type = mgrtype.template_argument(0)
+ valptr = None
+ if '::_Manager_internal' in mgrname:
+ valptr = self.val['_M_storage']['_M_buffer'].address
+ elif '::_Manager_external' in mgrname:
+ valptr = self.val['_M_storage']['_M_ptr']
+ elif '::_Manager_alloc' in mgrname:
+ datatype = gdb.lookup_type(mgrname + '::_Data')
+ valptr = self.val['_M_storage']['_M_ptr'].cast(datatype.pointer())
+ valptr = valptr.dereference()['_M_data'].address
+ else:
+ raise ValueError("Unknown manager function in std::experimental::any")
+ contained_value = valptr.cast(self.contained_type.pointer()).dereference()
+ visualizer = gdb.default_visualizer(contained_value)
+ super(StdExpAnyPrinter, self).__init__ (contained_value, visualizer)
+
+ def to_string (self):
+ if self.contained_type is None:
+ return '%s [no contained value]' % self.typename
+ desc = "%s containing " % self.typename
+ if hasattr (self.visualizer, 'children'):
+ return desc + self.visualizer.to_string ()
+ valtype = self._recognize (self.contained_type)
+ return desc + valtype
+
+class StdExpOptionalPrinter(SingleObjContainerPrinter):
+ "Print a std::experimental::optional"
+
+ def __init__ (self, typename, val):
+ valtype = self._recognize (val.type.template_argument(0))
+ self.typename = "std::experimental::optional<%s>" % valtype
+ self.val = val
+ contained_value = val['_M_payload'] if self.val['_M_engaged'] else None
+ visualizer = gdb.default_visualizer (val['_M_payload'])
+ super (StdExpOptionalPrinter, self).__init__ (contained_value, visualizer)
+
+ def to_string (self):
+ if self.contained_value is None:
+ return self.typename + " [no contained value]"
+ if hasattr (self.visualizer, 'children'):
+ return self.typename + " containing " + self.visualizer.to_string ()
+ return self.typename
+
+class StdExpStringViewPrinter:
+ "Print a std::experimental::basic_string_view"
+
+ def __init__ (self, typename, val):
+ self.val = val
+
+ def to_string (self):
+ ptr = self.val['_M_str']
+ len = self.val['_M_len']
+ if hasattr (ptr, "lazy_string"):
+ return ptr.lazy_string (length = len)
+ return ptr.string (length = len)
+
+ def display_hint (self):
+ return 'string'
# A "regular expression" printer which conforms to the
# "SubPrettyPrinter" protocol from gdb.printing.
@@ -865,12 +1007,12 @@ class Printer(object):
self.subprinters = []
self.lookup = {}
self.enabled = True
- self.compiled_rx = re.compile('^([a-zA-Z0-9_:]+)<.*>$')
+ self.compiled_rx = re.compile('^([a-zA-Z0-9_:]+)(<.*>)?$')
def add(self, name, function):
# A small sanity check.
# FIXME
- if not self.compiled_rx.match(name + '<>'):
+ if not self.compiled_rx.match(name):
raise ValueError('libstdc++ programming error: "%s" does not match' % name)
printer = RxPrinter(name, function)
self.subprinters.append(printer)
@@ -922,6 +1064,57 @@ class Printer(object):
libstdcxx_printer = None
+class TemplateTypePrinter(object):
+ r"""A type printer for class templates.
+
+ Recognizes type names that match a regular expression.
+ Replaces them with a formatted string which can use replacement field
+ {N} to refer to the \N subgroup of the regex match.
+ Type printers are recusively applied to the subgroups.
+
+ This allows recognizing e.g. "std::vector<(.*), std::allocator<\\1> >"
+ and replacing it with "std::vector<{1}>", omitting the template argument
+ that uses the default type.
+ """
+
+ def __init__(self, name, pattern, subst):
+ self.name = name
+ self.pattern = re.compile(pattern)
+ self.subst = subst
+ self.enabled = True
+
+ class _recognizer(object):
+ def __init__(self, pattern, subst):
+ self.pattern = pattern
+ self.subst = subst
+ self.type_obj = None
+
+ def recognize(self, type_obj):
+ if type_obj.tag is None:
+ return None
+
+ m = self.pattern.match(type_obj.tag)
+ if m:
+ subs = list(m.groups())
+ for i, sub in enumerate(subs):
+ if ('{%d}' % (i+1)) in self.subst:
+ # apply recognizers to subgroup
+ rep = gdb.types.apply_type_recognizers(
+ gdb.types.get_type_recognizers(),
+ gdb.lookup_type(sub))
+ if rep:
+ subs[i] = rep
+ subs = [None] + subs
+ return self.subst.format(*subs)
+ return None
+
+ def instantiate(self):
+ return self._recognizer(self.pattern, self.subst)
+
+def add_one_template_type_printer(obj, name, match, subst):
+ printer = TemplateTypePrinter(name, '^std::' + match + '$', 'std::' + subst)
+ gdb.types.register_type_printer(obj, printer)
+
class FilteringTypePrinter(object):
def __init__(self, match, name):
self.match = match
@@ -1013,6 +1206,56 @@ def register_type_printers(obj):
add_one_type_printer(obj, 'discard_block_engine', 'ranlux48')
add_one_type_printer(obj, 'shuffle_order_engine', 'knuth_b')
+ # Do not show defaulted template arguments in class templates
+ add_one_template_type_printer(obj, 'unique_ptr<T>',
+ 'unique_ptr<(.*), std::default_delete<\\1 ?> >',
+ 'unique_ptr<{1}>')
+
+ add_one_template_type_printer(obj, 'deque<T>',
+ 'deque<(.*), std::allocator<\\1 ?> >',
+ 'deque<{1}>')
+ add_one_template_type_printer(obj, 'forward_list<T>',
+ 'forward_list<(.*), std::allocator<\\1 ?> >',
+ 'forward_list<{1}>')
+ add_one_template_type_printer(obj, 'list<T>',
+ 'list<(.*), std::allocator<\\1 ?> >',
+ 'list<{1}>')
+ add_one_template_type_printer(obj, 'vector<T>',
+ 'vector<(.*), std::allocator<\\1 ?> >',
+ 'vector<{1}>')
+ add_one_template_type_printer(obj, 'map<Key, T>',
+ 'map<(.*), (.*), std::less<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
+ 'map<{1}, {2}>')
+ add_one_template_type_printer(obj, 'multimap<Key, T>',
+ 'multimap<(.*), (.*), std::less<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
+ 'multimap<{1}, {2}>')
+ add_one_template_type_printer(obj, 'set<T>',
+ 'set<(.*), std::less<\\1 ?>, std::allocator<\\1 ?> >',
+ 'set<{1}>')
+ add_one_template_type_printer(obj, 'multiset<T>',
+ 'multiset<(.*), std::less<\\1 ?>, std::allocator<\\1 ?> >',
+ 'multiset<{1}>')
+ add_one_template_type_printer(obj, 'unordered_map<Key, T>',
+ 'unordered_map<(.*), (.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
+ 'unordered_map<{1}, {2}>')
+ add_one_template_type_printer(obj, 'unordered_multimap<Key, T>',
+ 'unordered_multimap<(.*), (.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
+ 'unordered_multimap<{1}, {2}>')
+ add_one_template_type_printer(obj, 'unordered_set<T>',
+ 'unordered_set<(.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<\\1 ?> >',
+ 'unordered_set<{1}>')
+ add_one_template_type_printer(obj, 'unordered_multiset<T>',
+ 'unordered_multiset<(.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<\\1 ?> >',
+ 'unordered_multiset<{1}>')
+
+ # strip the "fundamentals_v1" inline namespace from these types
+ add_one_template_type_printer(obj, 'optional<T>',
+ 'experimental::fundamentals_v1::optional<(.*)>',
+ 'experimental::optional<\\1>')
+ add_one_template_type_printer(obj, 'basic_string_view<C>',
+ 'experimental::fundamentals_v1::basic_string_view<(.*), std::char_traits<\\1> >',
+ 'experimental::basic_string_view<\\1>')
+
def register_libstdcxx_printers (obj):
"Register libstdc++ pretty-printers with objfile Obj."
@@ -1042,6 +1285,7 @@ def build_libstdcxx_dictionary ():
# In order from:
# http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html
libstdcxx_printer.add_version('std::', 'basic_string', StdStringPrinter)
+ libstdcxx_printer.add_version('std::', '__cxx11::basic_string', StdStringPrinter)
libstdcxx_printer.add_container('std::', 'bitset', StdBitsetPrinter)
libstdcxx_printer.add_container('std::', 'deque', StdDequePrinter)
libstdcxx_printer.add_container('std::', 'list', StdListPrinter)
@@ -1113,6 +1357,13 @@ def build_libstdcxx_dictionary ():
libstdcxx_printer.add('std::__debug::forward_list',
StdForwardListPrinter)
+ # Library Fundamentals TS components
+ libstdcxx_printer.add_version('std::experimental::fundamentals_v1::',
+ 'any', StdExpAnyPrinter)
+ libstdcxx_printer.add_version('std::experimental::fundamentals_v1::',
+ 'optional', StdExpOptionalPrinter)
+ libstdcxx_printer.add_version('std::experimental::fundamentals_v1::',
+ 'basic_string_view', StdExpStringViewPrinter)
# Extensions.
libstdcxx_printer.add_version('__gnu_cxx::', 'slist', StdSlistPrinter)
diff --git a/libstdc++-v3/python/libstdcxx/v6/xmethods.py b/libstdc++-v3/python/libstdcxx/v6/xmethods.py
new file mode 100644
index 0000000000..85e51ad1c2
--- /dev/null
+++ b/libstdc++-v3/python/libstdcxx/v6/xmethods.py
@@ -0,0 +1,528 @@
+# Xmethods for libstdc++.
+
+# Copyright (C) 2014-2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import gdb
+import gdb.xmethod
+import re
+
+matcher_name_prefix = 'libstdc++::'
+
+class LibStdCxxXMethod(gdb.xmethod.XMethod):
+ def __init__(self, name, worker_class):
+ gdb.xmethod.XMethod.__init__(self, name)
+ self.worker_class = worker_class
+
+# Xmethods for std::array
+
+class ArrayWorkerBase(gdb.xmethod.XMethodWorker):
+ def __init__(self, valtype, size):
+ self._valtype = valtype
+ self._size = size
+
+ def null_value(self):
+ nullptr = gdb.parse_and_eval('(void *) 0')
+ return nullptr.cast(self._valtype.pointer()).dereference()
+
+class ArraySizeWorker(ArrayWorkerBase):
+ def __init__(self, valtype, size):
+ ArrayWorkerBase.__init__(self, valtype, size)
+
+ def get_arg_types(self):
+ return None
+
+ def __call__(self, obj):
+ return self._size
+
+class ArrayEmptyWorker(ArrayWorkerBase):
+ def __init__(self, valtype, size):
+ ArrayWorkerBase.__init__(self, valtype, size)
+
+ def get_arg_types(self):
+ return None
+
+ def __call__(self, obj):
+ return (int(self._size) == 0)
+
+class ArrayFrontWorker(ArrayWorkerBase):
+ def __init__(self, valtype, size):
+ ArrayWorkerBase.__init__(self, valtype, size)
+
+ def get_arg_types(self):
+ return None
+
+ def __call__(self, obj):
+ if int(self._size) > 0:
+ return obj['_M_elems'][0]
+ else:
+ return self.null_value()
+
+class ArrayBackWorker(ArrayWorkerBase):
+ def __init__(self, valtype, size):
+ ArrayWorkerBase.__init__(self, valtype, size)
+
+ def get_arg_types(self):
+ return None
+
+ def __call__(self, obj):
+ if int(self._size) > 0:
+ return obj['_M_elems'][self._size - 1]
+ else:
+ return self.null_value()
+
+class ArrayAtWorker(ArrayWorkerBase):
+ def __init__(self, valtype, size):
+ ArrayWorkerBase.__init__(self, valtype, size)
+
+ def get_arg_types(self):
+ return gdb.lookup_type('std::size_t')
+
+ def __call__(self, obj, index):
+ if int(index) >= int(self._size):
+ raise IndexError('Array index "%d" should not be >= %d.' %
+ ((int(index), self._size)))
+ return obj['_M_elems'][index]
+
+class ArraySubscriptWorker(ArrayWorkerBase):
+ def __init__(self, valtype, size):
+ ArrayWorkerBase.__init__(self, valtype, size)
+
+ def get_arg_types(self):
+ return gdb.lookup_type('std::size_t')
+
+ def __call__(self, obj, index):
+ if int(self._size) > 0:
+ return obj['_M_elems'][index]
+ else:
+ return self.null_value()
+
+class ArrayMethodsMatcher(gdb.xmethod.XMethodMatcher):
+ def __init__(self):
+ gdb.xmethod.XMethodMatcher.__init__(self,
+ matcher_name_prefix + 'array')
+ self._method_dict = {
+ 'size': LibStdCxxXMethod('size', ArraySizeWorker),
+ 'empty': LibStdCxxXMethod('empty', ArrayEmptyWorker),
+ 'front': LibStdCxxXMethod('front', ArrayFrontWorker),
+ 'back': LibStdCxxXMethod('back', ArrayBackWorker),
+ 'at': LibStdCxxXMethod('at', ArrayAtWorker),
+ 'operator[]': LibStdCxxXMethod('operator[]', ArraySubscriptWorker),
+ }
+ self.methods = [self._method_dict[m] for m in self._method_dict]
+
+ def match(self, class_type, method_name):
+ if not re.match('^std::array<.*>$', class_type.tag):
+ return None
+ method = self._method_dict.get(method_name)
+ if method is None or not method.enabled:
+ return None
+ try:
+ value_type = class_type.template_argument(0)
+ size = class_type.template_argument(1)
+ except:
+ return None
+ return method.worker_class(value_type, size)
+
+# Xmethods for std::deque
+
+class DequeWorkerBase(gdb.xmethod.XMethodWorker):
+ def __init__(self, elemtype):
+ self._bufsize = (512 / elemtype.sizeof) or 1
+
+ def size(self, obj):
+ first_node = obj['_M_impl']['_M_start']['_M_node']
+ last_node = obj['_M_impl']['_M_finish']['_M_node']
+ cur = obj['_M_impl']['_M_finish']['_M_cur']
+ first = obj['_M_impl']['_M_finish']['_M_first']
+ return (last_node - first_node) * self._bufsize + (cur - first)
+
+ def index(self, obj, index):
+ first_node = obj['_M_impl']['_M_start']['_M_node']
+ index_node = first_node + index / self._bufsize
+ return index_node[0][index % self._bufsize]
+
+class DequeEmptyWorker(DequeWorkerBase):
+ def get_arg_types(self):
+ return None
+
+ def __call__(self, obj):
+ return (obj['_M_impl']['_M_start']['_M_cur'] ==
+ obj['_M_impl']['_M_finish']['_M_cur'])
+
+class DequeSizeWorker(DequeWorkerBase):
+ def get_arg_types(self):
+ return None
+
+ def __call__(self, obj):
+ return self.size(obj)
+
+class DequeFrontWorker(DequeWorkerBase):
+ def get_arg_types(self):
+ return None
+
+ def __call__(self, obj):
+ return obj['_M_impl']['_M_start']['_M_cur'][0]
+
+class DequeBackWorker(DequeWorkerBase):
+ def get_arg_types(self):
+ return None
+
+ def __call__(self, obj):
+ if (obj['_M_impl']['_M_finish']['_M_cur'] ==
+ obj['_M_impl']['_M_finish']['_M_first']):
+ prev_node = obj['_M_impl']['_M_finish']['_M_node'] - 1
+ return prev_node[0][self._bufsize - 1]
+ else:
+ return obj['_M_impl']['_M_finish']['_M_cur'][-1]
+
+class DequeSubscriptWorker(DequeWorkerBase):
+ def get_arg_types(self):
+ return gdb.lookup_type('std::size_t')
+
+ def __call__(self, obj, subscript):
+ return self.index(obj, subscript)
+
+class DequeAtWorker(DequeWorkerBase):
+ def get_arg_types(self):
+ return gdb.lookup_type('std::size_t')
+
+ def __call__(self, obj, index):
+ deque_size = int(self.size(obj))
+ if int(index) >= deque_size:
+ raise IndexError('Deque index "%d" should not be >= %d.' %
+ (int(index), deque_size))
+ else:
+ return self.index(obj, index)
+
+class DequeMethodsMatcher(gdb.xmethod.XMethodMatcher):
+ def __init__(self):
+ gdb.xmethod.XMethodMatcher.__init__(self,
+ matcher_name_prefix + 'deque')
+ self._method_dict = {
+ 'empty': LibStdCxxXMethod('empty', DequeEmptyWorker),
+ 'size': LibStdCxxXMethod('size', DequeSizeWorker),
+ 'front': LibStdCxxXMethod('front', DequeFrontWorker),
+ 'back': LibStdCxxXMethod('back', DequeBackWorker),
+ 'operator[]': LibStdCxxXMethod('operator[]', DequeSubscriptWorker),
+ 'at': LibStdCxxXMethod('at', DequeAtWorker)
+ }
+ self.methods = [self._method_dict[m] for m in self._method_dict]
+
+ def match(self, class_type, method_name):
+ if not re.match('^std::deque<.*>$', class_type.tag):
+ return None
+ method = self._method_dict.get(method_name)
+ if method is None or not method.enabled:
+ return None
+ return method.worker_class(class_type.template_argument(0))
+
+# Xmethods for std::forward_list
+
+class ForwardListWorkerBase(gdb.xmethod.XMethodMatcher):
+ def __init__(self, elem_type, node_type):
+ self._elem_type = elem_type
+ self._node_type = node_type
+
+ def get_arg_types(self):
+ return None
+
+class ForwardListEmptyWorker(ForwardListWorkerBase):
+ def __call__(self, obj):
+ return obj['_M_impl']['_M_head']['_M_next'] == 0
+
+class ForwardListFrontWorker(ForwardListWorkerBase):
+ def __call__(self, obj):
+ node = obj['_M_impl']['_M_head']['_M_next'].cast(self._node_type)
+ elem_address = node['_M_storage']['_M_storage'].address
+ return elem_address.cast(self._elem_type.pointer()).dereference()
+
+class ForwardListMethodsMatcher(gdb.xmethod.XMethodMatcher):
+ def __init__(self):
+ matcher_name = matcher_name_prefix + 'forward_list'
+ gdb.xmethod.XMethodMatcher.__init__(self, matcher_name)
+ self._method_dict = {
+ 'empty': LibStdCxxXMethod('empty', ForwardListEmptyWorker),
+ 'front': LibStdCxxXMethod('front', ForwardListFrontWorker)
+ }
+ self.methods = [self._method_dict[m] for m in self._method_dict]
+
+ def match(self, class_type, method_name):
+ if not re.match('^std::forward_list<.*>$', class_type.tag):
+ return None
+ method = self._method_dict.get(method_name)
+ if method is None or not method.enabled:
+ return None
+ elem_type = class_type.template_argument(0)
+ node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer()
+ return method.worker_class(elem_type, node_type)
+
+# Xmethods for std::list
+
+class ListWorkerBase(gdb.xmethod.XMethodWorker):
+ def __init__(self, node_type):
+ self._node_type = node_type
+
+ def get_arg_types(self):
+ return None
+
+class ListEmptyWorker(ListWorkerBase):
+ def __call__(self, obj):
+ base_node = obj['_M_impl']['_M_node']
+ if base_node['_M_next'] == base_node.address:
+ return True
+ else:
+ return False
+
+class ListSizeWorker(ListWorkerBase):
+ def __call__(self, obj):
+ begin_node = obj['_M_impl']['_M_node']['_M_next']
+ end_node = obj['_M_impl']['_M_node'].address
+ size = 0
+ while begin_node != end_node:
+ begin_node = begin_node['_M_next']
+ size += 1
+ return size
+
+class ListFrontWorker(ListWorkerBase):
+ def __call__(self, obj):
+ node = obj['_M_impl']['_M_node']['_M_next'].cast(self._node_type)
+ return node['_M_data']
+
+class ListBackWorker(ListWorkerBase):
+ def __call__(self, obj):
+ prev_node = obj['_M_impl']['_M_node']['_M_prev'].cast(self._node_type)
+ return prev_node['_M_data']
+
+class ListMethodsMatcher(gdb.xmethod.XMethodMatcher):
+ def __init__(self):
+ gdb.xmethod.XMethodMatcher.__init__(self,
+ matcher_name_prefix + 'list')
+ self._method_dict = {
+ 'empty': LibStdCxxXMethod('empty', ListEmptyWorker),
+ 'size': LibStdCxxXMethod('size', ListSizeWorker),
+ 'front': LibStdCxxXMethod('front', ListFrontWorker),
+ 'back': LibStdCxxXMethod('back', ListBackWorker)
+ }
+ self.methods = [self._method_dict[m] for m in self._method_dict]
+
+ def match(self, class_type, method_name):
+ if not re.match('^std::list<.*>$', class_type.tag):
+ return None
+ method = self._method_dict.get(method_name)
+ if method is None or not method.enabled:
+ return None
+ node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer()
+ return method.worker_class(node_type)
+
+# Xmethods for std::vector
+
+class VectorWorkerBase(gdb.xmethod.XMethodWorker):
+ def __init__(self, elemtype):
+ self._elemtype = elemtype
+
+ def size(self, obj):
+ if self._elemtype.code == gdb.TYPE_CODE_BOOL:
+ start = obj['_M_impl']['_M_start']['_M_p']
+ finish = obj['_M_impl']['_M_finish']['_M_p']
+ finish_offset = obj['_M_impl']['_M_finish']['_M_offset']
+ bit_size = start.dereference().type.sizeof * 8
+ return (finish - start) * bit_size + finish_offset
+ else:
+ return obj['_M_impl']['_M_finish'] - obj['_M_impl']['_M_start']
+
+ def get(self, obj, index):
+ if self._elemtype.code == gdb.TYPE_CODE_BOOL:
+ start = obj['_M_impl']['_M_start']['_M_p']
+ bit_size = start.dereference().type.sizeof * 8
+ valp = start + index / bit_size
+ offset = index % bit_size
+ return (valp.dereference() & (1 << offset)) > 0
+ else:
+ return obj['_M_impl']['_M_start'][index]
+
+class VectorEmptyWorker(VectorWorkerBase):
+ def get_arg_types(self):
+ return None
+
+ def __call__(self, obj):
+ return int(self.size(obj)) == 0
+
+class VectorSizeWorker(VectorWorkerBase):
+ def get_arg_types(self):
+ return None
+
+ def __call__(self, obj):
+ return self.size(obj)
+
+class VectorFrontWorker(VectorWorkerBase):
+ def get_arg_types(self):
+ return None
+
+ def __call__(self, obj):
+ return self.get(obj, 0)
+
+class VectorBackWorker(VectorWorkerBase):
+ def get_arg_types(self):
+ return None
+
+ def __call__(self, obj):
+ return self.get(obj, int(self.size(obj)) - 1)
+
+class VectorAtWorker(VectorWorkerBase):
+ def get_arg_types(self):
+ return gdb.lookup_type('std::size_t')
+
+ def __call__(self, obj, index):
+ size = int(self.size(obj))
+ if int(index) >= size:
+ raise IndexError('Vector index "%d" should not be >= %d.' %
+ ((int(index), size)))
+ return self.get(obj, int(index))
+
+class VectorSubscriptWorker(VectorWorkerBase):
+ def get_arg_types(self):
+ return gdb.lookup_type('std::size_t')
+
+ def __call__(self, obj, subscript):
+ return self.get(obj, int(subscript))
+
+class VectorMethodsMatcher(gdb.xmethod.XMethodMatcher):
+ def __init__(self):
+ gdb.xmethod.XMethodMatcher.__init__(self,
+ matcher_name_prefix + 'vector')
+ self._method_dict = {
+ 'size': LibStdCxxXMethod('size', VectorSizeWorker),
+ 'empty': LibStdCxxXMethod('empty', VectorEmptyWorker),
+ 'front': LibStdCxxXMethod('front', VectorFrontWorker),
+ 'back': LibStdCxxXMethod('back', VectorBackWorker),
+ 'at': LibStdCxxXMethod('at', VectorAtWorker),
+ 'operator[]': LibStdCxxXMethod('operator[]',
+ VectorSubscriptWorker),
+ }
+ self.methods = [self._method_dict[m] for m in self._method_dict]
+
+ def match(self, class_type, method_name):
+ if not re.match('^std::vector<.*>$', class_type.tag):
+ return None
+ method = self._method_dict.get(method_name)
+ if method is None or not method.enabled:
+ return None
+ return method.worker_class(class_type.template_argument(0))
+
+# Xmethods for associative containers
+
+class AssociativeContainerWorkerBase(gdb.xmethod.XMethodWorker):
+ def __init__(self, unordered):
+ self._unordered = unordered
+
+ def node_count(self, obj):
+ if self._unordered:
+ return obj['_M_h']['_M_element_count']
+ else:
+ return obj['_M_t']['_M_impl']['_M_node_count']
+
+ def get_arg_types(self):
+ return None
+
+class AssociativeContainerEmptyWorker(AssociativeContainerWorkerBase):
+ def __call__(self, obj):
+ return int(self.node_count(obj)) == 0
+
+class AssociativeContainerSizeWorker(AssociativeContainerWorkerBase):
+ def __call__(self, obj):
+ return self.node_count(obj)
+
+class AssociativeContainerMethodsMatcher(gdb.xmethod.XMethodMatcher):
+ def __init__(self, name):
+ gdb.xmethod.XMethodMatcher.__init__(self,
+ matcher_name_prefix + name)
+ self._name = name
+ self._method_dict = {
+ 'size': LibStdCxxXMethod('size', AssociativeContainerSizeWorker),
+ 'empty': LibStdCxxXMethod('empty',
+ AssociativeContainerEmptyWorker),
+ }
+ self.methods = [self._method_dict[m] for m in self._method_dict]
+
+ def match(self, class_type, method_name):
+ if not re.match('^std::%s<.*>$' % self._name, class_type.tag):
+ return None
+ method = self._method_dict.get(method_name)
+ if method is None or not method.enabled:
+ return None
+ unordered = 'unordered' in self._name
+ return method.worker_class(unordered)
+
+# Xmethods for std::unique_ptr
+
+class UniquePtrGetWorker(gdb.xmethod.XMethodWorker):
+ def __init__(self):
+ self.name = 'get'
+ self.enabled = True
+
+ def get_arg_types(self):
+ return None
+
+ def __call__(self, obj):
+ return obj['_M_t']['_M_head_impl']
+
+class UniquePtrDerefWorker(UniquePtrGetWorker):
+ def __init__(self):
+ UniquePtrGetWorker.__init__(self)
+ self.name = 'operator*'
+
+ def __call__(self, obj):
+ return UniquePtrGetWorker.__call__(self, obj).dereference()
+
+class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
+ def __init__(self):
+ gdb.xmethod.XMethodMatcher.__init__(self,
+ matcher_name_prefix + 'unique_ptr')
+ self._get_worker = UniquePtrGetWorker()
+ self._deref_worker = UniquePtrDerefWorker()
+ self.methods = [self._get_worker, self._deref_worker]
+
+ def match(self, class_type, method_name):
+ if not re.match('^std::unique_ptr<.*>$', class_type.tag):
+ return None
+ if method_name == 'operator*' and self._deref_worker.enabled:
+ return self._deref_worker
+ elif method_name == 'get' and self._get_worker.enabled:
+ return self._get_worker
+
+def register_libstdcxx_xmethods(locus):
+ gdb.xmethod.register_xmethod_matcher(locus, ArrayMethodsMatcher())
+ gdb.xmethod.register_xmethod_matcher(locus, ForwardListMethodsMatcher())
+ gdb.xmethod.register_xmethod_matcher(locus, DequeMethodsMatcher())
+ gdb.xmethod.register_xmethod_matcher(locus, ListMethodsMatcher())
+ gdb.xmethod.register_xmethod_matcher(locus, VectorMethodsMatcher())
+ gdb.xmethod.register_xmethod_matcher(
+ locus, AssociativeContainerMethodsMatcher('set'))
+ gdb.xmethod.register_xmethod_matcher(
+ locus, AssociativeContainerMethodsMatcher('map'))
+ gdb.xmethod.register_xmethod_matcher(
+ locus, AssociativeContainerMethodsMatcher('multiset'))
+ gdb.xmethod.register_xmethod_matcher(
+ locus, AssociativeContainerMethodsMatcher('multimap'))
+ gdb.xmethod.register_xmethod_matcher(
+ locus, AssociativeContainerMethodsMatcher('unordered_set'))
+ gdb.xmethod.register_xmethod_matcher(
+ locus, AssociativeContainerMethodsMatcher('unordered_map'))
+ gdb.xmethod.register_xmethod_matcher(
+ locus, AssociativeContainerMethodsMatcher('unordered_multiset'))
+ gdb.xmethod.register_xmethod_matcher(
+ locus, AssociativeContainerMethodsMatcher('unordered_multimap'))
+ gdb.xmethod.register_xmethod_matcher(locus, UniquePtrMethodsMatcher())