diff options
author | Sterling Augustine <saugustine@google.com> | 2019-08-31 00:00:34 +0000 |
---|---|---|
committer | Sterling Augustine <saugustine@google.com> | 2019-08-31 00:00:34 +0000 |
commit | 33e17db59105fc9be904135a8e921e0c01348a2c (patch) | |
tree | 7aad3ea17f678474548d6502b9c255ce66ff75c3 /libcxx/utils | |
parent | 1ea909270c6d9ad612a46c2a15c13acc4f6d623a (diff) | |
download | bcm5719-llvm-33e17db59105fc9be904135a8e921e0c01348a2c.tar.gz bcm5719-llvm-33e17db59105fc9be904135a8e921e0c01348a2c.zip |
Revert "Add gdb pretty printers for a wide variety of libc++ data structures."
This reverts commit d8c9f2f572fe06a34ccfc28ee9223b64d7d275d3.
llvm-svn: 370553
Diffstat (limited to 'libcxx/utils')
-rw-r--r-- | libcxx/utils/gdb/libcxx/printers.py | 992 |
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) |