summaryrefslogtreecommitdiffstats
path: root/libcxx/utils
diff options
context:
space:
mode:
Diffstat (limited to 'libcxx/utils')
-rw-r--r--libcxx/utils/gdb/libcxx/printers.py992
1 files changed, 0 insertions, 992 deletions
diff --git a/libcxx/utils/gdb/libcxx/printers.py b/libcxx/utils/gdb/libcxx/printers.py
deleted file mode 100644
index dc2f2e97aec..00000000000
--- a/libcxx/utils/gdb/libcxx/printers.py
+++ /dev/null
@@ -1,992 +0,0 @@
-#===----------------------------------------------------------------------===##
-#
-# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-# See https://llvm.org/LICENSE.txt for license information.
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#
-#===----------------------------------------------------------------------===##
-"""GDB pretty-printers for libc++.
-
-These should work for objects compiled when _LIBCPP_ABI_UNSTABLE is defined
-and when it is undefined.
-"""
-
-from __future__ import print_function
-
-import re
-import gdb
-
-# One under-documented feature of the gdb pretty-printer API
-# is that clients can call any other member of the API
-# before they call to_string.
-# Therefore all self.FIELDs must be set in the pretty-printer's
-# __init__ function.
-
-_void_pointer_type = gdb.lookup_type("void").pointer()
-
-
-_long_int_type = gdb.lookup_type("unsigned long long")
-
-
-def addr_as_long(addr):
- return int(addr.cast(_long_int_type))
-
-
-# The size of a pointer in bytes.
-_pointer_size = _void_pointer_type.sizeof
-
-
-def _remove_cxx_namespace(typename):
- """Removed libc++ specific namespace from the type.
-
- Arguments:
- typename(string): A type, such as std::__u::something.
-
- Returns:
- A string without the libc++ specific part, such as std::something.
- """
-
- return re.sub("std::__.*?::", "std::", typename)
-
-
-def _remove_generics(typename):
- """Remove generics part of the type. Assumes typename is not empty.
-
- Arguments:
- typename(string): A type such as std::my_collection<element>.
-
- Returns:
- The prefix up to the generic part, such as std::my_collection.
- """
-
- match = re.match("^([^<]+)", typename)
- return match.group(1)
-
-
-# Some common substitutions on the types to reduce visual clutter (A user who
-# wants to see the actual details can always use print/r).
-_common_substitutions = [
- ("std::basic_string<char, std::char_traits<char>, std::allocator<char> >",
- "std::string"),
-]
-
-
-def _prettify_typename(gdb_type):
- """Returns a pretty name for the type, or None if no name can be found.
-
- Arguments:
- gdb_type(gdb.Type): A type object.
-
- Returns:
- A string, without type_defs, libc++ namespaces, and common substitutions
- applied.
- """
-
- type_without_typedefs = gdb_type.strip_typedefs()
- typename = type_without_typedefs.name or type_without_typedefs.tag or \
- str(type_without_typedefs)
- result = _remove_cxx_namespace(typename)
- for find_str, subst_str in _common_substitutions:
- result = re.sub(find_str, subst_str, result)
- return result
-
-
-def _typename_for_nth_generic_argument(gdb_type, n):
- """Returns a pretty string for the nth argument of the given type.
-
- Arguments:
- gdb_type(gdb.Type): A type object, such as the one for std::map<int, int>
- n: The (zero indexed) index of the argument to return.
-
- Returns:
- A string for the nth argument, such a "std::string"
- """
- element_type = gdb_type.template_argument(n)
- return _prettify_typename(element_type)
-
-
-def _typename_with_n_generic_arguments(gdb_type, n):
- """Return a string for the type with the first n (1, ...) generic args."""
-
- base_type = _remove_generics(_prettify_typename(gdb_type))
- arg_list = [base_type]
- template = "%s<"
- for i in range(n):
- arg_list.append(_typename_for_nth_generic_argument(gdb_type, i))
- template += "%s, "
- result = (template[:-2] + ">") % tuple(arg_list)
- return result
-
-
-def _typename_with_first_generic_argument(gdb_type):
- return _typename_with_n_generic_arguments(gdb_type, 1)
-
-
-class StdTuplePrinter(object):
- """Print a std::tuple."""
-
- class _Children(object):
- """Class to iterate over the tuple's children."""
-
- def __init__(self, val):
- self.val = val
- self.child_iter = iter(self.val["__base_"].type.fields())
- self.count = 0
-
- def __iter__(self):
- return self
-
- def next(self):
- # child_iter raises StopIteration when appropriate.
- field_name = self.child_iter.next()
- child = self.val["__base_"][field_name]["__value_"]
- self.count += 1
- return ("[%d]" % self.count, child)
-
- def __init__(self, val):
- self.val = val
-
- def to_string(self):
- typename = _remove_generics(_prettify_typename(self.val.type))
- if not self.val.type.fields():
- return "empty %s" % typename
- return "%s containing" % typename
-
- def children(self):
- if not self.val.type.fields():
- return iter(())
- return self._Children(self.val)
-
-
-def _get_base_subobject(child_class_value, index=0):
- """Returns the object's value in the form of the parent class at index.
-
- This function effectively casts the child_class_value to the base_class's
- type, but the type-to-cast to is stored in the field at index, and once
- we know the field, we can just return the data.
-
- Args:
- child_class_value: the value to cast
- index: the parent class index
-
- Raises:
- Exception: field at index was not a base-class field.
- """
-
- field = child_class_value.type.fields()[index]
- if not field.is_base_class:
- raise Exception("Not a base-class field.")
- return child_class_value[field]
-
-
-def _value_of_pair_first(value):
- """Convenience for _get_base_subobject, for the common case."""
- return _get_base_subobject(value, 0)["__value_"]
-
-
-class StdStringPrinter(object):
- """Print a std::string."""
-
- def _get_short_size(self, short_field, short_size):
- """Short size depends on both endianness and a compile-time define."""
-
- # If the padding field is present after all this indirection, then string
- # was compiled with _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT defined.
- field = short_field.type.fields()[1].type.fields()[0]
- libcpp_abi_alternate_string_layout = field.name and "__padding" in field.name
-
- # Strictly, this only tells us the current mode, not how libcxx was
- # compiled.
- libcpp_big_endian = "big endian" in gdb.execute("show endian",
- to_string=True)
-
- # This logical structure closely follows the original code (which is clearer
- # in C++). Keep them parallel to make them easier to compare.
- if libcpp_abi_alternate_string_layout:
- if libcpp_big_endian:
- return short_size >> 1
- else:
- return short_size
- elif libcpp_big_endian:
- return short_size
- else:
- return short_size >> 1
-
- def __init__(self, val):
- self.val = val
-
- def to_string(self):
- """Build a python string from the data whether stored inline or separately."""
-
- value_field = _value_of_pair_first(self.val["__r_"])
- short_field = value_field["__s"]
- short_size = short_field["__size_"]
- if short_size == 0:
- return ""
- short_mask = self.val["__short_mask"]
- # Counter intuitive to compare the size and short_mask to see if the string
- # is long, but that's the way the implementation does it. Note that
- # __is_long() doesn't use get_short_size in C++.
- is_long = short_size & short_mask
- if is_long:
- long_field = value_field["__l"]
- data = long_field["__data_"]
- size = long_field["__size_"]
- else:
- data = short_field["__data_"]
- size = self._get_short_size(short_field, short_size)
- if hasattr(data, "lazy_string"):
- return data.lazy_string(length=size)
- return data.string(length=size)
-
- def display_hint(self):
- return "string"
-
-
-class StdUniquePtrPrinter(object):
- """Print a std::unique_ptr."""
-
- def __init__(self, val):
- self.val = val
- self.addr = _value_of_pair_first(self.val["__ptr_"])
- self.pointee_type = self.val.type.template_argument(0)
-
- def to_string(self):
- typename = _remove_generics(_prettify_typename(self.val.type))
- if not self.addr:
- return "%s is nullptr" % typename
- return ("%s<%s> containing" %
- (typename,
- _remove_generics(_prettify_typename(self.pointee_type))))
-
- def __iter__(self):
- if self.addr:
- yield "__ptr_", self.addr.cast(self.pointee_type.pointer())
-
- def children(self):
- return self
-
-
-class StdSharedPointerPrinter(object):
- """Print a std::shared_ptr."""
-
- def __init__(self, val):
- self.val = val
- self.addr = self.val["__ptr_"]
-
- def to_string(self):
- """Returns self as a string."""
- typename = _remove_generics(_prettify_typename(self.val.type))
- pointee_type = _remove_generics(
- _prettify_typename(self.val.type.template_argument(0)))
- if not self.addr:
- return "%s is nullptr" % typename
- refcount = self.val["__cntrl_"]
- if refcount != 0:
- usecount = refcount["__shared_owners_"] + 1
- weakcount = refcount["__shared_weak_owners_"]
- if usecount == 0:
- state = "expired, weak %d" % weakcount
- else:
- state = "count %d, weak %d" % (usecount, weakcount)
- return "%s<%s> %s containing" % (typename, pointee_type, state)
-
- def __iter__(self):
- if self.addr:
- yield "__ptr_", self.addr
-
- def children(self):
- return self
-
-
-class StdVectorPrinter(object):
- """Print a std::vector."""
-
- class _VectorBoolIterator(object):
- """Class to iterate over the bool vector's children."""
-
- def __init__(self, begin, size, bits_per_word):
- self.item = begin
- self.size = size
- self.bits_per_word = bits_per_word
- self.count = 0
- self.offset = 0
-
- def __iter__(self):
- return self
-
- def next(self):
- """Retrieve the next element."""
-
- self.count += 1
- if self.count > self.size:
- raise StopIteration
- entry = self.item.dereference()
- if entry & (1 << self.offset):
- outbit = 1
- else:
- outbit = 0
- self.offset += 1
- if self.offset >= self.bits_per_word:
- self.item += 1
- self.offset = 0
- return ("[%d]" % self.count, outbit)
-
- class _VectorIterator(object):
- """Class to iterate over the non-bool vector's children."""
-
- def __init__(self, begin, end):
- self.item = begin
- self.end = end
- self.count = 0
-
- def __iter__(self):
- return self
-
- def next(self):
- self.count += 1
- if self.item == self.end:
- raise StopIteration
- entry = self.item.dereference()
- self.item += 1
- return ("[%d]" % self.count, entry)
-
- def __init__(self, val):
- """Set val, length, capacity, and iterator for bool and normal vectors."""
- self.val = val
- self.typename = _remove_generics(_prettify_typename(val.type))
- begin = self.val["__begin_"]
- if self.val.type.template_argument(0).code == gdb.TYPE_CODE_BOOL:
- self.typename += "<bool>"
- self.length = self.val["__size_"]
- bits_per_word = self.val["__bits_per_word"]
- self.capacity = _value_of_pair_first(
- self.val["__cap_alloc_"]) * bits_per_word
- self.iterator = self._VectorBoolIterator(
- begin, self.length, bits_per_word)
- else:
- end = self.val["__end_"]
- self.length = end - begin
- self.capacity = _get_base_subobject(
- self.val["__end_cap_"])["__value_"] - begin
- self.iterator = self._VectorIterator(begin, end)
-
- def to_string(self):
- return ("%s of length %d, capacity %d" %
- (self.typename, self.length, self.capacity))
-
- def children(self):
- return self.iterator
-
- def display_hint(self):
- return "array"
-
-
-class StdBitsetPrinter(object):
- """Print a std::bitset."""
-
- def __init__(self, val):
- self.val = val
- self.n_words = int(self.val["__n_words"])
- self.bits_per_word = int(self.val["__bits_per_word"])
- if self.n_words == 1:
- self.values = [int(self.val["__first_"])]
- else:
- self.values = [int(self.val["__first_"][index])
- for index in range(self.n_words)]
-
- def to_string(self):
- typename = _prettify_typename(self.val.type)
- return "%s" % typename
-
- def _byte_it(self, value):
- index = -1
- while value:
- index += 1
- will_yield = value % 2
- value /= 2
- if will_yield:
- yield index
-
- def _list_it(self):
- for word_index in range(self.n_words):
- current = self.values[word_index]
- if current:
- for n in self._byte_it(current):
- yield ("[%d]" % (word_index * self.bits_per_word + n), 1)
-
- def __iter__(self):
- return self._list_it()
-
- def children(self):
- return self
-
-
-class StdDequePrinter(object):
- """Print a std::deque."""
-
- def __init__(self, val):
- self.val = val
- self.size = int(_value_of_pair_first(val["__size_"]))
- self.start_ptr = self.val["__map_"]["__begin_"]
- self.first_block_start_index = int(self.val["__start_"])
- self.node_type = self.start_ptr.type
- self.block_size = self._calculate_block_size(
- val.type.template_argument(0))
-
- def _calculate_block_size(self, element_type):
- """Calculates the number of elements in a full block."""
- size = element_type.sizeof
- # Copied from struct __deque_block_size implementation of libcxx.
- return 4096 / size if size < 256 else 16
-
- def _bucket_it(self, start_addr, start_index, end_index):
- for i in range(start_index, end_index):
- yield i, (start_addr.dereference() + i).dereference()
-
- def _list_it(self):
- """Primary iteration worker."""
- num_emitted = 0
- current_addr = self.start_ptr
- start_index = self.first_block_start_index
- while num_emitted < self.size:
- end_index = min(start_index + self.size -
- num_emitted, self.block_size)
- for _, elem in self._bucket_it(current_addr, start_index, end_index):
- yield "", elem
- num_emitted += end_index - start_index
- current_addr = gdb.Value(addr_as_long(current_addr) + _pointer_size) \
- .cast(self.node_type)
- start_index = 0
-
- def to_string(self):
- typename = _remove_generics(_prettify_typename(self.val.type))
- if self.size:
- return "%s with %d elements" % (typename, self.size)
- return "%s is empty" % typename
-
- def __iter__(self):
- return self._list_it()
-
- def children(self):
- return self
-
- def display_hint(self):
- return "array"
-
-
-class StdListPrinter(object):
- """Print a std::list."""
-
- def __init__(self, val):
- self.val = val
- size_alloc_field = self.val["__size_alloc_"]
- self.size = int(_value_of_pair_first(size_alloc_field))
- dummy_node = self.val["__end_"]
- self.nodetype = gdb.lookup_type(
- re.sub("__list_node_base", "__list_node",
- str(dummy_node.type.strip_typedefs()))).pointer()
- self.first_node = dummy_node["__next_"]
-
- def to_string(self):
- typename = _remove_generics(_prettify_typename(self.val.type))
- if self.size:
- return "%s with %d elements" % (typename, self.size)
- return "%s is empty" % typename
-
- def _list_iter(self):
- current_node = self.first_node
- for _ in range(self.size):
- yield "", current_node.cast(self.nodetype).dereference()["__value_"]
- current_node = current_node.dereference()["__next_"]
-
- def __iter__(self):
- return self._list_iter()
-
- def children(self):
- return self if self.nodetype else iter(())
-
- def display_hint(self):
- return "array"
-
-
-class StdQueueOrStackPrinter(object):
- """Print a std::queue or std::stack."""
-
- def __init__(self, val):
- self.val = val
- self.underlying = val["c"]
-
- def to_string(self):
- typename = _remove_generics(_prettify_typename(self.val.type))
- return "%s wrapping" % typename
-
- def children(self):
- return iter([("", self.underlying)])
-
- def display_hint(self):
- return "array"
-
-
-class StdPriorityQueuePrinter(object):
- """Print a std::priority_queue."""
-
- def __init__(self, val):
- self.val = val
- self.underlying = val["c"]
-
- def to_string(self):
- # TODO(tamur): It would be nice to print the top element. The technical
- # difficulty is that, the implementation refers to the underlying
- # container, which is a generic class. libstdcxx pretty printers do not
- # print the top element.
- typename = _remove_generics(_prettify_typename(self.val.type))
- return "%s wrapping" % typename
-
- def children(self):
- return iter([("", self.underlying)])
-
- def display_hint(self):
- return "array"
-
-
-class RBTreeUtils(object):
- """Utility class for std::(multi)map, and std::(multi)set and iterators."""
-
- def __init__(self, cast_type, root):
- self.cast_type = cast_type
- self.root = root
-
- def left_child(self, node):
- result = node.cast(self.cast_type).dereference()["__left_"]
- return result
-
- def right_child(self, node):
- result = node.cast(self.cast_type).dereference()["__right_"]
- return result
-
- def parent(self, node):
- """Return the parent of node, if it exists."""
- # If this is the root, then from the algorithm's point of view, it has no
- # parent.
- if node == self.root:
- return None
-
- # We don't have enough information to tell if this is the end_node (which
- # doesn't have a __parent_ field), or the root (which doesn't have a parent
- # from the algorithm's point of view), so cast_type may not be correct for
- # this particular node. Use heuristics.
-
- # The end_node's left child is the root. Note that when printing interators
- # in isolation, the root is unknown.
- if self.left_child(node) == self.root:
- return None
-
- parent = node.cast(self.cast_type).dereference()["__parent_"]
- # If the value at the offset of __parent_ doesn't look like a valid pointer,
- # then assume that node is the end_node (and therefore has no parent).
- # End_node type has a pointer embedded, so should have pointer alignment.
- if addr_as_long(parent) % _void_pointer_type.alignof:
- return None
- # This is ugly, but the only other option is to dereference an invalid
- # pointer. 0x8000 is fairly arbitrary, but has had good results in
- # practice. If there was a way to tell if a pointer is invalid without
- # actually dereferencing it and spewing error messages, that would be ideal.
- if parent < 0x8000:
- return None
- return parent
-
- def is_left_child(self, node):
- parent = self.parent(node)
- return parent is not None and self.left_child(parent) == node
-
- def is_right_child(self, node):
- parent = self.parent(node)
- return parent is not None and self.right_child(parent) == node
-
-
-class AbstractRBTreePrinter(object):
- """Abstract super class for std::(multi)map, and std::(multi)set."""
-
- def __init__(self, val):
- self.val = val
- tree = self.val["__tree_"]
- self.size = int(_value_of_pair_first(tree["__pair3_"]))
- dummy_root = tree["__pair1_"]
- root = _value_of_pair_first(dummy_root)["__left_"]
- cast_type = self._init_cast_type(val.type)
- self.util = RBTreeUtils(cast_type, root)
-
- def _get_key_value(self, node):
- """Subclasses should override to return a list of values to yield."""
- raise NotImplementedError
-
- def _traverse(self):
- """Traverses the binary search tree in order."""
- current = self.util.root
- skip_left_child = False
- while True:
- if not skip_left_child and self.util.left_child(current):
- current = self.util.left_child(current)
- continue
- skip_left_child = False
- for key_value in self._get_key_value(current):
- yield "", key_value
- right_child = self.util.right_child(current)
- if right_child:
- current = right_child
- continue
- while self.util.is_right_child(current):
- current = self.util.parent(current)
- if self.util.is_left_child(current):
- current = self.util.parent(current)
- skip_left_child = True
- continue
- break
-
- def __iter__(self):
- return self._traverse()
-
- def children(self):
- return self if self.util.cast_type and self.size > 0 else iter(())
-
- def to_string(self):
- typename = _remove_generics(_prettify_typename(self.val.type))
- if self.size:
- return "%s with %d elements" % (typename, self.size)
- return "%s is empty" % typename
-
-
-class StdMapPrinter(AbstractRBTreePrinter):
- """Print a std::map or std::multimap."""
-
- def _init_cast_type(self, val_type):
- map_it_type = gdb.lookup_type(
- str(val_type) + "::iterator").strip_typedefs()
- tree_it_type = map_it_type.template_argument(0)
- node_ptr_type = tree_it_type.template_argument(1)
- return node_ptr_type
-
- def display_hint(self):
- return "map"
-
- def _get_key_value(self, node):
- key_value = node.cast(self.util.cast_type).dereference()[
- "__value_"]["__cc"]
- return [key_value["first"], key_value["second"]]
-
-
-class StdSetPrinter(AbstractRBTreePrinter):
- """Print a std::set."""
-
- def _init_cast_type(self, val_type):
- set_it_type = gdb.lookup_type(
- str(val_type) + "::iterator").strip_typedefs()
- node_ptr_type = set_it_type.template_argument(1)
- return node_ptr_type
-
- def display_hint(self):
- return "array"
-
- def _get_key_value(self, node):
- key_value = node.cast(self.util.cast_type).dereference()["__value_"]
- return [key_value]
-
-
-class AbstractRBTreeIteratorPrinter(object):
- """Abstract super class for std::(multi)map, and std::(multi)set iterator."""
-
- def _initialize(self, val, typename):
- self.typename = typename
- self.val = val
- self.addr = self.val["__ptr_"]
- cast_type = self.val.type.template_argument(1)
- self.util = RBTreeUtils(cast_type, None)
- if self.addr:
- self.node = self.addr.cast(cast_type).dereference()
-
- def _is_valid_node(self):
- if not self.util.parent(self.addr):
- return False
- return self.util.is_left_child(self.addr) or \
- self.util.is_right_child(self.addr)
-
- def to_string(self):
- if not self.addr:
- return "%s is nullptr" % self.typename
- return "%s " % self.typename
-
- def _get_node_value(self, node):
- raise NotImplementedError
-
- def __iter__(self):
- addr_str = "[%s]" % str(self.addr)
- if not self._is_valid_node():
- yield addr_str, " end()"
- else:
- yield addr_str, self._get_node_value(self.node)
-
- def children(self):
- return self if self.addr else iter(())
-
-
-class MapIteratorPrinter(AbstractRBTreeIteratorPrinter):
- """Print a std::(multi)map iterator."""
-
- def __init__(self, val):
- self._initialize(val["__i_"],
- _remove_generics(_prettify_typename(val.type)))
-
- def _get_node_value(self, node):
- return node["__value_"]["__cc"]
-
-
-class SetIteratorPrinter(AbstractRBTreeIteratorPrinter):
- """Print a std::(multi)set iterator."""
-
- def __init__(self, val):
- self._initialize(val, _remove_generics(_prettify_typename(val.type)))
-
- def _get_node_value(self, node):
- return node["__value_"]
-
-
-class StdFposPrinter(object):
- """Print a std::fpos or std::streampos."""
-
- def __init__(self, val):
- self.val = val
-
- def to_string(self):
- typename = _remove_generics(_prettify_typename(self.val.type))
- offset = self.val["__off_"]
- state = self.val["__st_"]
- count = state["__count"]
- value = state["__value"]["__wch"]
- return "%s with stream offset:%s with state: {count:%s value:%s}" % (
- typename, offset, count, value)
-
-
-class AbstractUnorderedCollectionPrinter(object):
- """Abstract super class for std::unordered_(multi)[set|map]."""
-
- def __init__(self, val):
- self.val = val
- self.table = val["__table_"]
- self.sentinel = self.table["__p1_"]
- self.size = int(_value_of_pair_first(self.table["__p2_"]))
- node_base_type = self.sentinel.type.template_argument(0)
- self.cast_type = node_base_type.template_argument(0)
-
- def _list_it(self, sentinel_ptr):
- next_ptr = _value_of_pair_first(sentinel_ptr)["__next_"]
- while str(next_ptr.cast(_void_pointer_type)) != "0x0":
- next_val = next_ptr.cast(self.cast_type).dereference()
- for key_value in self._get_key_value(next_val):
- yield "", key_value
- next_ptr = next_val["__next_"]
-
- def to_string(self):
- typename = _remove_generics(_prettify_typename(self.val.type))
- if self.size:
- return "%s with %d elements" % (typename, self.size)
- return "%s is empty" % typename
-
- def _get_key_value(self, node):
- """Subclasses should override to return a list of values to yield."""
- raise NotImplementedError
-
- def children(self):
- return self if self.cast_type and self.size > 0 else iter(())
-
- def __iter__(self):
- return self._list_it(self.sentinel)
-
-
-class StdUnorderedSetPrinter(AbstractUnorderedCollectionPrinter):
- """Print a std::unordered_(multi)set."""
-
- def _get_key_value(self, node):
- return [node["__value_"]]
-
- def display_hint(self):
- return "array"
-
-
-class StdUnorderedMapPrinter(AbstractUnorderedCollectionPrinter):
- """Print a std::unordered_(multi)map."""
-
- def _get_key_value(self, node):
- key_value = node["__value_"]["__cc"]
- return [key_value["first"], key_value["second"]]
-
- def display_hint(self):
- return "map"
-
-
-class AbstractHashMapIteratorPrinter(object):
- """Abstract class for unordered collection iterators."""
-
- def _initialize(self, val, addr):
- self.val = val
- self.typename = _remove_generics(_prettify_typename(self.val.type))
- self.addr = addr
- if self.addr:
- self.node = self.addr.cast(self.cast_type).dereference()
-
- def _get_key_value(self):
- """Subclasses should override to return a list of values to yield."""
- raise NotImplementedError
-
- def to_string(self):
- if not self.addr:
- return "%s = end()" % self.typename
- return "%s " % self.typename
-
- def children(self):
- return self if self.addr else iter(())
-
- def __iter__(self):
- for key_value in self._get_key_value():
- yield "", key_value
-
-
-class StdUnorderedSetIteratorPrinter(AbstractHashMapIteratorPrinter):
- """Print a std::(multi)set iterator."""
-
- def __init__(self, val):
- self.cast_type = val.type.template_argument(0)
- self._initialize(val, val["__node_"])
-
- def _get_key_value(self):
- return [self.node["__value_"]]
-
- def display_hint(self):
- return "array"
-
-
-class StdUnorderedMapIteratorPrinter(AbstractHashMapIteratorPrinter):
- """Print a std::(multi)map iterator."""
-
- def __init__(self, val):
- self.cast_type = val.type.template_argument(0).template_argument(0)
- self._initialize(val, val["__i_"]["__node_"])
-
- def _get_key_value(self):
- key_value = self.node["__value_"]["__cc"]
- return [key_value["first"], key_value["second"]]
-
- def display_hint(self):
- return "map"
-
-
-def _remove_std_prefix(typename):
- match = re.match("^std::(.+)", typename)
- return match.group(1) if match is not None else ""
-
-
-class LibcxxPrettyPrinter(object):
- """PrettyPrinter object so gdb-commands like 'info pretty-printers' work."""
-
- def __init__(self, name):
- super(LibcxxPrettyPrinter, self).__init__()
- self.name = name
- self.enabled = True
-
- self.lookup = {
- "basic_string": StdStringPrinter,
- "string": StdStringPrinter,
- "tuple": StdTuplePrinter,
- "unique_ptr": StdUniquePtrPrinter,
- "shared_ptr": StdSharedPointerPrinter,
- "weak_ptr": StdSharedPointerPrinter,
- "bitset": StdBitsetPrinter,
- "deque": StdDequePrinter,
- "list": StdListPrinter,
- "queue": StdQueueOrStackPrinter,
- "stack": StdQueueOrStackPrinter,
- "priority_queue": StdPriorityQueuePrinter,
- "map": StdMapPrinter,
- "multimap": StdMapPrinter,
- "set": StdSetPrinter,
- "multiset": StdSetPrinter,
- "vector": StdVectorPrinter,
- "__map_iterator": MapIteratorPrinter,
- "__map_const_iterator": MapIteratorPrinter,
- "__tree_iterator": SetIteratorPrinter,
- "__tree_const_iterator": SetIteratorPrinter,
- "fpos": StdFposPrinter,
- "unordered_set": StdUnorderedSetPrinter,
- "unordered_multiset": StdUnorderedSetPrinter,
- "unordered_map": StdUnorderedMapPrinter,
- "unordered_multimap": StdUnorderedMapPrinter,
- "__hash_map_iterator": StdUnorderedMapIteratorPrinter,
- "__hash_map_const_iterator": StdUnorderedMapIteratorPrinter,
- "__hash_iterator": StdUnorderedSetIteratorPrinter,
- "__hash_const_iterator": StdUnorderedSetIteratorPrinter,
- }
-
- self.subprinters = []
- for name, subprinter in self.lookup.items():
- # Subprinters and names are used only for the rarely used command "info
- # pretty" (and related), so the name of the first data structure it prints
- # is a reasonable choice.
- if subprinter not in self.subprinters:
- subprinter.name = name
- self.subprinters.append(subprinter)
-
- def __call__(self, val):
- """Return the pretty printer for a val, if the type is supported."""
-
- # Do not handle any type that is not a struct/class.
- if val.type.strip_typedefs().code != gdb.TYPE_CODE_STRUCT:
- return None
-
- # Don't attempt types known to be inside libstdcxx.
- typename = val.type.name or val.type.tag or str(val.type)
- match = re.match("^std::(__.*?)::", typename)
- if match is None or match.group(1) in ["__cxx1998",
- "__debug",
- "__7",
- "__g"]:
- return None
-
- # Handle any using declarations or other typedefs.
- typename = _prettify_typename(val.type)
- if not typename:
- return None
- without_generics = _remove_generics(typename)
- lookup_name = _remove_std_prefix(without_generics)
- if lookup_name in self.lookup:
- return self.lookup[lookup_name](val)
- return None
-
-
-_libcxx_printer_name = "libcxx_pretty_printer"
-
-
-# These are called for every binary object file, which could be thousands in
-# certain pathological cases. Limit our pretty printers to the progspace.
-def _register_libcxx_printers(event):
- progspace = event.new_objfile.progspace
- if not getattr(progspace, _libcxx_printer_name, False):
- print("Loading libc++ pretty-printers.")
- gdb.printing.register_pretty_printer(
- progspace, LibcxxPrettyPrinter(_libcxx_printer_name))
- setattr(progspace, _libcxx_printer_name, True)
-
-
-def _unregister_libcxx_printers(event):
- progspace = event.progspace
- if getattr(progspace, _libcxx_printer_name, False):
- for printer in progspace.pretty_printers:
- if getattr(printer, "name", "none") == _libcxx_printer_name:
- progspace.pretty_printers.remove(printer)
- setattr(progspace, _libcxx_printer_name, False)
- break
-
-
-def register_libcxx_printer_loader():
- """Register event handlers to load libc++ pretty-printers."""
- gdb.events.new_objfile.connect(_register_libcxx_printers)
- gdb.events.clear_objfiles.connect(_unregister_libcxx_printers)
OpenPOWER on IntegriCloud