commit aedd1591cd8be6ec2bcf1d23d6495fbb7bbb2f9a Author: Jonathan Wakely Date: Mon May 9 12:07:26 2022 libstdc++: Create Python wrappers for std::tuple and std::unique_ptr libstdc++-v3/ChangeLog: * python/Makefile.am: Install new scripts. * python/Makefile.in: Regenerate. * python/libstdcxx/v6/printers.py: * python/libstdcxx/v6/types.py: New file. * python/libstdcxx/v6/util.py: New file. diff --git a/libstdc++-v3/python/Makefile.am b/libstdc++-v3/python/Makefile.am index f523d3a44dc..70b34f74b49 100644 --- a/libstdc++-v3/python/Makefile.am +++ b/libstdc++-v3/python/Makefile.am @@ -39,6 +39,8 @@ all-local: gdb.py nobase_python_DATA = \ libstdcxx/v6/printers.py \ + libstdcxx/v6/types.py \ + libstdcxx/v6/util.py \ libstdcxx/v6/xmethods.py \ libstdcxx/v6/__init__.py \ libstdcxx/__init__.py diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py index 0bd793c0897..f71f12245be 100644 --- a/libstdc++-v3/python/libstdcxx/v6/printers.py +++ b/libstdc++-v3/python/libstdcxx/v6/printers.py @@ -19,6 +19,10 @@ import gdb import itertools import re import sys, os, errno +from libstdcxx.v6 import types +from libstdcxx.v6.util import _versioned_namespace +from libstdcxx.v6.util import is_specialization_of +from libstdcxx.v6.util import get_template_arg_list ### Python 2 + Python 3 compatibility code @@ -100,8 +104,6 @@ def find_type(orig, name): else: raise ValueError("Cannot find type %s::%s" % (str(orig), name)) -_versioned_namespace = '__8::' - def lookup_templ_spec(templ, *args): """ Lookup template specialization templ @@ -165,15 +167,6 @@ def is_member_of_namespace(typ, *namespaces): return True return False -def is_specialization_of(x, template_name): - "Test if a type is a given template instantiation." - global _versioned_namespace - if type(x) is gdb.Type: - x = x.tag - if _versioned_namespace: - return re.match('^std::(%s)?%s<.*>$' % (_versioned_namespace, template_name), x) is not None - return re.match('^std::%s<.*>$' % template_name, x) is not None - def strip_versioned_namespace(typename): global _versioned_namespace if _versioned_namespace: @@ -191,17 +184,6 @@ def strip_inline_namespaces(type_str): type_str = type_str.replace(fs_ns+'v1::', fs_ns) return type_str -def get_template_arg_list(type_obj): - "Return a type's template arguments as a list" - n = 0 - template_args = [] - while True: - try: - template_args.append(type_obj.template_argument(n)) - except: - return template_args - n += 1 - class SmartPtrIterator(Iterator): "An iterator for smart pointer types with a single 'child' value" @@ -252,55 +234,6 @@ class SharedPointerPrinter: state = 'use count %d, weak count %d' % (usecount, weakcount - 1) return '%s<%s> (%s)' % (self.typename, str(targ), state) -def _tuple_impl_get(val): - "Return the tuple element stored in a _Tuple_impl base class." - bases = val.type.fields() - if not bases[-1].is_base_class: - raise ValueError("Unsupported implementation for std::tuple: %s" % str(val.type)) - # Get the _Head_base base class: - head_base = val.cast(bases[-1].type) - fields = head_base.type.fields() - if len(fields) == 0: - raise ValueError("Unsupported implementation for std::tuple: %s" % str(val.type)) - if fields[0].name == '_M_head_impl': - # The tuple element is the _Head_base::_M_head_impl data member. - return head_base['_M_head_impl'] - elif fields[0].is_base_class: - # The tuple element is an empty base class of _Head_base. - # Cast to that empty base class. - return head_base.cast(fields[0].type) - else: - raise ValueError("Unsupported implementation for std::tuple: %s" % str(val.type)) - -def tuple_get(n, val): - "Return the result of std::get(val) on a std::tuple" - tuple_size = len(get_template_arg_list(val.type)) - if n > tuple_size: - raise ValueError("Out of range index for std::get on std::tuple") - # Get the first _Tuple_impl<0, T...> base class: - node = val.cast(val.type.fields()[0].type) - while n > 0: - # Descend through the base classes until the Nth one. - node = node.cast(node.type.fields()[0].type) - n -= 1 - return _tuple_impl_get(node) - -def unique_ptr_get(val): - "Return the result of val.get() on a std::unique_ptr" - # std::unique_ptr contains a std::tuple, - # either as a direct data member _M_t (the old implementation) - # or within a data member of type __uniq_ptr_data. - impl_type = val.type.fields()[0].type.strip_typedefs() - # Check for new implementations first: - if is_specialization_of(impl_type, '__uniq_ptr_data') \ - or is_specialization_of(impl_type, '__uniq_ptr_impl'): - tuple_member = val['_M_t']['_M_t'] - elif is_specialization_of(impl_type, 'tuple'): - tuple_member = val['_M_t'] - else: - raise ValueError("Unsupported implementation for unique_ptr: %s" % str(impl_type)) - return tuple_get(0, tuple_member) - class UniquePointerPrinter: "Print a unique_ptr" @@ -308,7 +241,7 @@ class UniquePointerPrinter: self.val = val def children (self): - return SmartPtrIterator(unique_ptr_get(self.val)) + return SmartPtrIterator(types.UniquePtr(self.val).get()) def to_string (self): return ('std::unique_ptr<%s>' % (str(self.val.type.template_argument(0)))) @@ -1413,7 +1346,7 @@ class StdPathPrinter: def __init__ (self, typename, val): self.val = val self.typename = typename - impl = unique_ptr_get(self.val['_M_cmpts']['_M_impl']) + impl = types.UniquePtr(self.val['_M_cmpts']['_M_impl']).get() self.type = impl.cast(gdb.lookup_type('uintptr_t')) & 3 if self.type == 0: self.impl = impl diff --git a/libstdc++-v3/python/libstdcxx/v6/types.py b/libstdc++-v3/python/libstdcxx/v6/types.py new file mode 100644 index 00000000000..65feac0d600 --- /dev/null +++ b/libstdc++-v3/python/libstdcxx/v6/types.py @@ -0,0 +1,87 @@ +import gdb +from libstdcxx.v6.util import is_specialization_of +from libstdcxx.v6.util import get_template_arg_list + +class Tuple: + "Python wrapper for std::tuple" + + def __init__(self, val): + self.val = val + + def tuple_size(self): + "Return tuple_size_v>" + return len(get_template_arg_list(self.val.type)) + + def element_type(self, n): + "Return a gdb.Type for the tuple_element_t> type" + return self._nth_element(n).template_argument(1) + + def get(self, n): + "Return the result of std::get on a std::tuple" + return self._impl_get(self._nth_element(n)) + + def _nth_element(self, n): + "Return a gdb.Value for the _Tuple_impl base class" + if n >= self.tuple_size(): + raise ValueError("Out of range index for std::get<{}> on std::tuple".format(n)) + # Get the first _Tuple_impl<0, T...> base class: + node = self.val.cast(self.val.type.fields()[0].type) + while n > 0: + # Descend through the base classes until the Nth one. + node = node.cast(node.type.fields()[0].type) + n -= 1 + return node + + def _impl_get(self, node): + "Return the tuple element stored in a _Tuple_impl base class." + bases = node.type.fields() + if not bases[-1].is_base_class: + raise ValueError("Unsupported implementation for std::tuple: %s" % str(node.type)) + # Get the _Head_base base class: + head_base = node.cast(bases[-1].type) + fields = head_base.type.fields() + if len(fields) == 0: + raise ValueError("Unsupported implementation for std::tuple: %s" % str(node.type)) + if fields[0].name == '_M_head_impl': + # The tuple element is the _Head_base::_M_head_impl data member. + return head_base['_M_head_impl'] + elif fields[0].is_base_class: + # The tuple element is an empty base class of _Head_base. + # Cast to that empty base class. + return head_base.cast(fields[0].type) + else: + raise ValueError("Unsupported implementation for std::tuple: %s" % str(node.type)) + +class UniquePtr: + "Python wrapper for std::unique_ptr" + + def __init__ (self, val): + self.val = val + + #def pointer_type(self): + # "Return a gdb.Type for pointer typedef" + # return TODO + + def element_type(self): + "Return a gdb.Type for the element_type typedef" + return self.val.type.template_argument(0) + + def deleter_type(self): + "Return a gdb.Type for the deleter_type typedef" + return self.val.type.template_argument(1) + + def get(self): + "Return a gdb.Value for the get() member function" + # std::unique_ptr contains a std::tuple, + # either as a direct data member _M_t (the old implementation) + # or within a data member of type __uniq_ptr_data. + impl_type = self.val.type.fields()[0].type.strip_typedefs() + # Check for new implementations first: + if is_specialization_of(impl_type, '__uniq_ptr_data') \ + or is_specialization_of(impl_type, '__uniq_ptr_impl'): + tuple_member = self.val['_M_t']['_M_t'] + elif is_specialization_of(impl_type, 'tuple'): + tuple_member = self.val['_M_t'] + else: + raise ValueError("Unsupported implementation for unique_ptr: %s" % str(impl_type)) + return Tuple(tuple_member).get(0) diff --git a/libstdc++-v3/python/libstdcxx/v6/util.py b/libstdc++-v3/python/libstdcxx/v6/util.py new file mode 100644 index 00000000000..82e9ce665e0 --- /dev/null +++ b/libstdc++-v3/python/libstdcxx/v6/util.py @@ -0,0 +1,24 @@ +import re +import gdb + +_versioned_namespace = '__8::' + +def is_specialization_of(x, template_name): + "Test if a type is a given template instantiation." + global _versioned_namespace + if type(x) is gdb.Type: + x = x.tag + if _versioned_namespace: + return re.match('^std::(%s)?%s<.*>$' % (_versioned_namespace, template_name), x) is not None + return re.match('^std::%s<.*>$' % template_name, x) is not None + +def get_template_arg_list(type_obj): + "Return a type's template arguments as a list" + n = 0 + template_args = [] + while True: + try: + template_args.append(type_obj.template_argument(n)) + except: + return template_args + n += 1