gcc/libstdc++-v3/python/libstdcxx/v6/xmethods.py
Doug Evans 419587a0bb xmethods.py (UniquePtrMethodsMatcher): Add operator-> support.
* python/libstdcxx/v6/xmethods.py (UniquePtrMethodsMatcher): Add
	operator-> support.
	* testsuite/libstdc++-xmethods/unique_ptr.cc: Add tests for
	operator->.

From-SVN: r223723
2015-05-26 23:06:55 +00:00

623 lines
21 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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++::'
def get_bool_type():
return gdb.lookup_type('bool')
def get_std_size_type():
return gdb.lookup_type('std::size_t')
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, val_type, size):
self._val_type = val_type
self._size = size
def null_value(self):
nullptr = gdb.parse_and_eval('(void *) 0')
return nullptr.cast(self._val_type.pointer()).dereference()
class ArraySizeWorker(ArrayWorkerBase):
def __init__(self, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
def get_arg_types(self):
return None
def get_result_type(self, obj):
return get_std_size_type()
def __call__(self, obj):
return self._size
class ArrayEmptyWorker(ArrayWorkerBase):
def __init__(self, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
def get_arg_types(self):
return None
def get_result_type(self, obj):
return get_bool_type()
def __call__(self, obj):
return (int(self._size) == 0)
class ArrayFrontWorker(ArrayWorkerBase):
def __init__(self, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
def get_arg_types(self):
return None
def get_result_type(self, obj):
return self._val_type
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, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
def get_arg_types(self):
return None
def get_result_type(self, obj):
return self._val_type
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, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
def get_arg_types(self):
return get_std_size_type()
def get_result_type(self, obj, index):
return self._val_type
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, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
def get_arg_types(self):
return get_std_size_type()
def get_result_type(self, obj, index):
return self._val_type
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, val_type):
self._val_type = val_type
self._bufsize = (512 / val_type.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 get_result_type(self, obj):
return get_bool_type()
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 get_result_type(self, obj):
return get_std_size_type()
def __call__(self, obj):
return self.size(obj)
class DequeFrontWorker(DequeWorkerBase):
def get_arg_types(self):
return None
def get_result_type(self, obj):
return self._val_type
def __call__(self, obj):
return obj['_M_impl']['_M_start']['_M_cur'][0]
class DequeBackWorker(DequeWorkerBase):
def get_arg_types(self):
return None
def get_result_type(self, obj):
return self._val_type
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 get_std_size_type()
def get_result_type(self, obj, subscript):
return self._val_type
def __call__(self, obj, subscript):
return self.index(obj, subscript)
class DequeAtWorker(DequeWorkerBase):
def get_arg_types(self):
return get_std_size_type()
def get_result_type(self, obj, index):
return self._val_type
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, val_type, node_type):
self._val_type = val_type
self._node_type = node_type
def get_arg_types(self):
return None
class ForwardListEmptyWorker(ForwardListWorkerBase):
def get_result_type(self, obj):
return get_bool_type()
def __call__(self, obj):
return obj['_M_impl']['_M_head']['_M_next'] == 0
class ForwardListFrontWorker(ForwardListWorkerBase):
def get_result_type(self, obj):
return self._val_type
def __call__(self, obj):
node = obj['_M_impl']['_M_head']['_M_next'].cast(self._node_type)
val_address = node['_M_storage']['_M_storage'].address
return val_address.cast(self._val_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
val_type = class_type.template_argument(0)
node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer()
return method.worker_class(val_type, node_type)
# Xmethods for std::list
class ListWorkerBase(gdb.xmethod.XMethodWorker):
def __init__(self, val_type, node_type):
self._val_type = val_type
self._node_type = node_type
def get_arg_types(self):
return None
class ListEmptyWorker(ListWorkerBase):
def get_result_type(self, obj):
return get_bool_type()
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 get_result_type(self, obj):
return get_std_size_type()
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 get_result_type(self, obj):
return self._val_type
def __call__(self, obj):
node = obj['_M_impl']['_M_node']['_M_next'].cast(self._node_type)
return node['_M_data']
class ListBackWorker(ListWorkerBase):
def get_result_type(self, obj):
return self._val_type
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
val_type = class_type.template_argument(0)
node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer()
return method.worker_class(val_type, node_type)
# Xmethods for std::vector
class VectorWorkerBase(gdb.xmethod.XMethodWorker):
def __init__(self, val_type):
self._val_type = val_type
def size(self, obj):
if self._val_type.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._val_type.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 get_result_type(self, obj):
return get_bool_type()
def __call__(self, obj):
return int(self.size(obj)) == 0
class VectorSizeWorker(VectorWorkerBase):
def get_arg_types(self):
return None
def get_result_type(self, obj):
return get_std_size_type()
def __call__(self, obj):
return self.size(obj)
class VectorFrontWorker(VectorWorkerBase):
def get_arg_types(self):
return None
def get_result_type(self, obj):
return self._val_type
def __call__(self, obj):
return self.get(obj, 0)
class VectorBackWorker(VectorWorkerBase):
def get_arg_types(self):
return None
def get_result_type(self, obj):
return self._val_type
def __call__(self, obj):
return self.get(obj, int(self.size(obj)) - 1)
class VectorAtWorker(VectorWorkerBase):
def get_arg_types(self):
return get_std_size_type()
def get_result_type(self, obj, index):
return self._val_type
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 get_std_size_type()
def get_result_type(self, obj, subscript):
return self._val_type
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 get_result_type(self, obj):
return get_bool_type()
def __call__(self, obj):
return int(self.node_count(obj)) == 0
class AssociativeContainerSizeWorker(AssociativeContainerWorkerBase):
def get_result_type(self, obj):
return get_std_size_type()
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, elem_type):
self._elem_type = elem_type
def get_arg_types(self):
return None
def get_result_type(self, obj):
return self._elem_type.pointer()
def __call__(self, obj):
return obj['_M_t']['_M_head_impl']
class UniquePtrDerefWorker(UniquePtrGetWorker):
def __init__(self, elem_type):
UniquePtrGetWorker.__init__(self, elem_type)
def get_result_type(self, obj):
return self._elem_type
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._method_dict = {
'get': LibStdCxxXMethod('get', UniquePtrGetWorker),
'operator->': LibStdCxxXMethod('operator->', UniquePtrGetWorker),
'operator*': LibStdCxxXMethod('operator*', UniquePtrDerefWorker),
}
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
if not re.match('^std::unique_ptr<.*>$', 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))
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())