1  # Xmethods for libstdc++.
       2  
       3  # Copyright (C) 2014-2023 Free Software Foundation, Inc.
       4  
       5  # This program is free software; you can redistribute it and/or modify
       6  # it under the terms of the GNU General Public License as published by
       7  # the Free Software Foundation; either version 3 of the License, or
       8  # (at your option) any later version.
       9  #
      10  # This program is distributed in the hope that it will be useful,
      11  # but WITHOUT ANY WARRANTY; without even the implied warranty of
      12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13  # GNU General Public License for more details.
      14  #
      15  # You should have received a copy of the GNU General Public License
      16  # along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17  
      18  import gdb
      19  import gdb.xmethod
      20  import re
      21  
      22  matcher_name_prefix = 'libstdc++::'
      23  
      24  def get_bool_type():
      25      return gdb.lookup_type('bool')
      26  
      27  def get_std_size_type():
      28      return gdb.lookup_type('std::size_t')
      29  
      30  class ESC[4;38;5;81mLibStdCxxXMethod(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethod):
      31      def __init__(self, name, worker_class):
      32          gdb.xmethod.XMethod.__init__(self, name)
      33          self.worker_class = worker_class
      34  
      35  # Xmethods for std::array
      36  
      37  class ESC[4;38;5;81mArrayWorkerBase(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodWorker):
      38      def __init__(self, val_type, size):
      39          self._val_type = val_type
      40          self._size = size
      41  
      42      def null_value(self):
      43          nullptr = gdb.parse_and_eval('(void *) 0')
      44          return nullptr.cast(self._val_type.pointer()).dereference()
      45  
      46  class ESC[4;38;5;81mArraySizeWorker(ESC[4;38;5;149mArrayWorkerBase):
      47      def __init__(self, val_type, size):
      48          ArrayWorkerBase.__init__(self, val_type, size)
      49  
      50      def get_arg_types(self):
      51          return None
      52  
      53      def get_result_type(self, obj):
      54          return get_std_size_type()
      55  
      56      def __call__(self, obj):
      57          return self._size
      58  
      59  class ESC[4;38;5;81mArrayEmptyWorker(ESC[4;38;5;149mArrayWorkerBase):
      60      def __init__(self, val_type, size):
      61          ArrayWorkerBase.__init__(self, val_type, size)
      62  
      63      def get_arg_types(self):
      64          return None
      65  
      66      def get_result_type(self, obj):
      67          return get_bool_type()
      68  
      69      def __call__(self, obj):
      70          return (int(self._size) == 0)
      71  
      72  class ESC[4;38;5;81mArrayFrontWorker(ESC[4;38;5;149mArrayWorkerBase):
      73      def __init__(self, val_type, size):
      74          ArrayWorkerBase.__init__(self, val_type, size)
      75  
      76      def get_arg_types(self):
      77          return None
      78  
      79      def get_result_type(self, obj):
      80          return self._val_type
      81  
      82      def __call__(self, obj):
      83          if int(self._size) > 0:
      84              return obj['_M_elems'][0]
      85          else:
      86              return self.null_value()
      87  
      88  class ESC[4;38;5;81mArrayBackWorker(ESC[4;38;5;149mArrayWorkerBase):
      89      def __init__(self, val_type, size):
      90          ArrayWorkerBase.__init__(self, val_type, size)
      91  
      92      def get_arg_types(self):
      93          return None
      94  
      95      def get_result_type(self, obj):
      96          return self._val_type
      97  
      98      def __call__(self, obj):
      99          if int(self._size) > 0:
     100              return obj['_M_elems'][self._size - 1]
     101          else:
     102              return self.null_value()
     103  
     104  class ESC[4;38;5;81mArrayAtWorker(ESC[4;38;5;149mArrayWorkerBase):
     105      def __init__(self, val_type, size):
     106          ArrayWorkerBase.__init__(self, val_type, size)
     107  
     108      def get_arg_types(self):
     109          return get_std_size_type()
     110  
     111      def get_result_type(self, obj, index):
     112          return self._val_type
     113  
     114      def __call__(self, obj, index):
     115          if int(index) >= int(self._size):
     116              raise IndexError('Array index "%d" should not be >= %d.' %
     117                               ((int(index), self._size)))
     118          return obj['_M_elems'][index]
     119  
     120  class ESC[4;38;5;81mArraySubscriptWorker(ESC[4;38;5;149mArrayWorkerBase):
     121      def __init__(self, val_type, size):
     122          ArrayWorkerBase.__init__(self, val_type, size)
     123  
     124      def get_arg_types(self):
     125          return get_std_size_type()
     126  
     127      def get_result_type(self, obj, index):
     128          return self._val_type
     129  
     130      def __call__(self, obj, index):
     131          if int(self._size) > 0:
     132              return obj['_M_elems'][index]
     133          else:
     134              return self.null_value()
     135  
     136  class ESC[4;38;5;81mArrayMethodsMatcher(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodMatcher):
     137      def __init__(self):
     138          gdb.xmethod.XMethodMatcher.__init__(self,
     139                                              matcher_name_prefix + 'array')
     140          self._method_dict = {
     141              'size': LibStdCxxXMethod('size', ArraySizeWorker),
     142              'empty': LibStdCxxXMethod('empty', ArrayEmptyWorker),
     143              'front': LibStdCxxXMethod('front', ArrayFrontWorker),
     144              'back': LibStdCxxXMethod('back', ArrayBackWorker),
     145              'at': LibStdCxxXMethod('at', ArrayAtWorker),
     146              'operator[]': LibStdCxxXMethod('operator[]', ArraySubscriptWorker),
     147          }
     148          self.methods = [self._method_dict[m] for m in self._method_dict]
     149  
     150      def match(self, class_type, method_name):
     151          if not re.match('^std::(__\d+::)?array<.*>$', class_type.tag):
     152              return None
     153          method = self._method_dict.get(method_name)
     154          if method is None or not method.enabled:
     155              return None
     156          try:
     157              value_type = class_type.template_argument(0)
     158              size = class_type.template_argument(1)
     159          except:
     160              return None
     161          return method.worker_class(value_type, size)
     162  
     163  # Xmethods for std::deque
     164  
     165  class ESC[4;38;5;81mDequeWorkerBase(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodWorker):
     166      def __init__(self, val_type):
     167          self._val_type = val_type
     168          self._bufsize = 512 // val_type.sizeof or 1
     169  
     170      def size(self, obj):
     171          first_node = obj['_M_impl']['_M_start']['_M_node']
     172          last_node = obj['_M_impl']['_M_finish']['_M_node']
     173          cur = obj['_M_impl']['_M_finish']['_M_cur']
     174          first = obj['_M_impl']['_M_finish']['_M_first']
     175          return (last_node - first_node) * self._bufsize + (cur - first)
     176  
     177      def index(self, obj, idx):
     178          first_node = obj['_M_impl']['_M_start']['_M_node']
     179          index_node = first_node + int(idx) // self._bufsize
     180          return index_node[0][idx % self._bufsize]
     181  
     182  class ESC[4;38;5;81mDequeEmptyWorker(ESC[4;38;5;149mDequeWorkerBase):
     183      def get_arg_types(self):
     184          return None
     185  
     186      def get_result_type(self, obj):
     187          return get_bool_type()
     188  
     189      def __call__(self, obj):
     190          return (obj['_M_impl']['_M_start']['_M_cur'] ==
     191                  obj['_M_impl']['_M_finish']['_M_cur'])
     192  
     193  class ESC[4;38;5;81mDequeSizeWorker(ESC[4;38;5;149mDequeWorkerBase):
     194      def get_arg_types(self):
     195          return None
     196  
     197      def get_result_type(self, obj):
     198          return get_std_size_type()
     199  
     200      def __call__(self, obj):
     201          return self.size(obj)
     202  
     203  class ESC[4;38;5;81mDequeFrontWorker(ESC[4;38;5;149mDequeWorkerBase):
     204      def get_arg_types(self):
     205          return None
     206  
     207      def get_result_type(self, obj):
     208          return self._val_type
     209  
     210      def __call__(self, obj):
     211          return obj['_M_impl']['_M_start']['_M_cur'][0]
     212  
     213  class ESC[4;38;5;81mDequeBackWorker(ESC[4;38;5;149mDequeWorkerBase):
     214      def get_arg_types(self):
     215          return None
     216  
     217      def get_result_type(self, obj):
     218          return self._val_type
     219  
     220      def __call__(self, obj):
     221          if (obj['_M_impl']['_M_finish']['_M_cur'] ==
     222              obj['_M_impl']['_M_finish']['_M_first']):
     223              prev_node = obj['_M_impl']['_M_finish']['_M_node'] - 1
     224              return prev_node[0][self._bufsize - 1]
     225          else:
     226              return obj['_M_impl']['_M_finish']['_M_cur'][-1]
     227  
     228  class ESC[4;38;5;81mDequeSubscriptWorker(ESC[4;38;5;149mDequeWorkerBase):
     229      def get_arg_types(self):
     230          return get_std_size_type()
     231  
     232      def get_result_type(self, obj, subscript):
     233          return self._val_type
     234  
     235      def __call__(self, obj, subscript):
     236          return self.index(obj, subscript)
     237  
     238  class ESC[4;38;5;81mDequeAtWorker(ESC[4;38;5;149mDequeWorkerBase):
     239      def get_arg_types(self):
     240          return get_std_size_type()
     241  
     242      def get_result_type(self, obj, index):
     243          return self._val_type
     244  
     245      def __call__(self, obj, index):
     246          deque_size = int(self.size(obj))
     247          if int(index) >= deque_size:
     248              raise IndexError('Deque index "%d" should not be >= %d.' %
     249                               (int(index), deque_size))
     250          else:
     251             return self.index(obj, index)
     252  
     253  class ESC[4;38;5;81mDequeMethodsMatcher(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodMatcher):
     254      def __init__(self):
     255          gdb.xmethod.XMethodMatcher.__init__(self,
     256                                              matcher_name_prefix + 'deque')
     257          self._method_dict = {
     258              'empty': LibStdCxxXMethod('empty', DequeEmptyWorker),
     259              'size': LibStdCxxXMethod('size', DequeSizeWorker),
     260              'front': LibStdCxxXMethod('front', DequeFrontWorker),
     261              'back': LibStdCxxXMethod('back', DequeBackWorker),
     262              'operator[]': LibStdCxxXMethod('operator[]', DequeSubscriptWorker),
     263              'at': LibStdCxxXMethod('at', DequeAtWorker)
     264          }
     265          self.methods = [self._method_dict[m] for m in self._method_dict]
     266  
     267      def match(self, class_type, method_name):
     268          if not re.match('^std::(__\d+::)?deque<.*>$', class_type.tag):
     269              return None
     270          method = self._method_dict.get(method_name)
     271          if method is None or not method.enabled:
     272              return None
     273          return method.worker_class(class_type.template_argument(0))
     274  
     275  # Xmethods for std::forward_list
     276  
     277  class ESC[4;38;5;81mForwardListWorkerBase(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodMatcher):
     278      def __init__(self, val_type, node_type):
     279          self._val_type = val_type
     280          self._node_type = node_type
     281  
     282      def get_arg_types(self):
     283          return None
     284  
     285  class ESC[4;38;5;81mForwardListEmptyWorker(ESC[4;38;5;149mForwardListWorkerBase):
     286      def get_result_type(self, obj):
     287          return get_bool_type()
     288  
     289      def __call__(self, obj):
     290          return obj['_M_impl']['_M_head']['_M_next'] == 0
     291  
     292  class ESC[4;38;5;81mForwardListFrontWorker(ESC[4;38;5;149mForwardListWorkerBase):
     293      def get_result_type(self, obj):
     294          return self._val_type
     295  
     296      def __call__(self, obj):
     297          node = obj['_M_impl']['_M_head']['_M_next'].cast(self._node_type)
     298          val_address = node['_M_storage']['_M_storage'].address
     299          return val_address.cast(self._val_type.pointer()).dereference()
     300  
     301  class ESC[4;38;5;81mForwardListMethodsMatcher(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodMatcher):
     302      def __init__(self):
     303          matcher_name = matcher_name_prefix + 'forward_list'
     304          gdb.xmethod.XMethodMatcher.__init__(self, matcher_name)
     305          self._method_dict = {
     306              'empty': LibStdCxxXMethod('empty', ForwardListEmptyWorker),
     307              'front': LibStdCxxXMethod('front', ForwardListFrontWorker)
     308          }
     309          self.methods = [self._method_dict[m] for m in self._method_dict]
     310  
     311      def match(self, class_type, method_name):
     312          if not re.match('^std::(__\d+::)?forward_list<.*>$', class_type.tag):
     313              return None
     314          method = self._method_dict.get(method_name)
     315          if method is None or not method.enabled:
     316              return None
     317          val_type = class_type.template_argument(0)
     318          node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer()
     319          return method.worker_class(val_type, node_type)
     320  
     321  # Xmethods for std::list
     322  
     323  class ESC[4;38;5;81mListWorkerBase(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodWorker):
     324      def __init__(self, val_type, node_type):
     325          self._val_type = val_type
     326          self._node_type = node_type
     327  
     328      def get_arg_types(self):
     329          return None
     330  
     331      def get_value_from_node(self, node):
     332          node = node.dereference()
     333          if node.type.fields()[1].name == '_M_data':
     334              # C++03 implementation, node contains the value as a member
     335              return node['_M_data']
     336          # C++11 implementation, node stores value in __aligned_membuf
     337          addr = node['_M_storage'].address
     338          return addr.cast(self._val_type.pointer()).dereference()
     339  
     340  class ESC[4;38;5;81mListEmptyWorker(ESC[4;38;5;149mListWorkerBase):
     341      def get_result_type(self, obj):
     342          return get_bool_type()
     343  
     344      def __call__(self, obj):
     345          base_node = obj['_M_impl']['_M_node']
     346          if base_node['_M_next'] == base_node.address:
     347              return True
     348          else:
     349              return False
     350  
     351  class ESC[4;38;5;81mListSizeWorker(ESC[4;38;5;149mListWorkerBase):
     352      def get_result_type(self, obj):
     353          return get_std_size_type()
     354  
     355      def __call__(self, obj):
     356          begin_node = obj['_M_impl']['_M_node']['_M_next']
     357          end_node = obj['_M_impl']['_M_node'].address
     358          size = 0
     359          while begin_node != end_node:
     360              begin_node = begin_node['_M_next']
     361              size += 1
     362          return size
     363  
     364  class ESC[4;38;5;81mListFrontWorker(ESC[4;38;5;149mListWorkerBase):
     365      def get_result_type(self, obj):
     366          return self._val_type
     367  
     368      def __call__(self, obj):
     369          node = obj['_M_impl']['_M_node']['_M_next'].cast(self._node_type)
     370          return self.get_value_from_node(node)
     371  
     372  class ESC[4;38;5;81mListBackWorker(ESC[4;38;5;149mListWorkerBase):
     373      def get_result_type(self, obj):
     374          return self._val_type
     375  
     376      def __call__(self, obj):
     377          prev_node = obj['_M_impl']['_M_node']['_M_prev'].cast(self._node_type)
     378          return self.get_value_from_node(prev_node)
     379  
     380  class ESC[4;38;5;81mListMethodsMatcher(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodMatcher):
     381      def __init__(self):
     382          gdb.xmethod.XMethodMatcher.__init__(self,
     383                                              matcher_name_prefix + 'list')
     384          self._method_dict = {
     385              'empty': LibStdCxxXMethod('empty', ListEmptyWorker),
     386              'size': LibStdCxxXMethod('size', ListSizeWorker),
     387              'front': LibStdCxxXMethod('front', ListFrontWorker),
     388              'back': LibStdCxxXMethod('back', ListBackWorker)
     389          }
     390          self.methods = [self._method_dict[m] for m in self._method_dict]
     391  
     392      def match(self, class_type, method_name):
     393          if not re.match('^std::(__\d+::)?(__cxx11::)?list<.*>$', class_type.tag):
     394              return None
     395          method = self._method_dict.get(method_name)
     396          if method is None or not method.enabled:
     397              return None
     398          val_type = class_type.template_argument(0)
     399          node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer()
     400          return method.worker_class(val_type, node_type)
     401  
     402  # Xmethods for std::vector
     403  
     404  class ESC[4;38;5;81mVectorWorkerBase(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodWorker):
     405      def __init__(self, val_type):
     406          self._val_type = val_type
     407  
     408      def size(self, obj):
     409          if self._val_type.code == gdb.TYPE_CODE_BOOL:
     410              start = obj['_M_impl']['_M_start']['_M_p']
     411              finish = obj['_M_impl']['_M_finish']['_M_p']
     412              finish_offset = obj['_M_impl']['_M_finish']['_M_offset']
     413              bit_size = start.dereference().type.sizeof * 8
     414              return (finish - start) * bit_size + finish_offset
     415          else:
     416              return obj['_M_impl']['_M_finish'] - obj['_M_impl']['_M_start']
     417  
     418      def get(self, obj, index):
     419          if self._val_type.code == gdb.TYPE_CODE_BOOL:
     420              start = obj['_M_impl']['_M_start']['_M_p']
     421              bit_size = start.dereference().type.sizeof * 8
     422              valp = start + index // bit_size
     423              offset = index % bit_size
     424              return (valp.dereference() & (1 << offset)) > 0
     425          else:
     426              return obj['_M_impl']['_M_start'][index]
     427  
     428  class ESC[4;38;5;81mVectorEmptyWorker(ESC[4;38;5;149mVectorWorkerBase):
     429      def get_arg_types(self):
     430          return None
     431  
     432      def get_result_type(self, obj):
     433          return get_bool_type()
     434  
     435      def __call__(self, obj):
     436          return int(self.size(obj)) == 0
     437  
     438  class ESC[4;38;5;81mVectorSizeWorker(ESC[4;38;5;149mVectorWorkerBase):
     439      def get_arg_types(self):
     440          return None
     441  
     442      def get_result_type(self, obj):
     443          return get_std_size_type()
     444  
     445      def __call__(self, obj):
     446          return self.size(obj)
     447  
     448  class ESC[4;38;5;81mVectorFrontWorker(ESC[4;38;5;149mVectorWorkerBase):
     449      def get_arg_types(self):
     450          return None
     451  
     452      def get_result_type(self, obj):
     453          return self._val_type
     454  
     455      def __call__(self, obj):
     456          return self.get(obj, 0)
     457  
     458  class ESC[4;38;5;81mVectorBackWorker(ESC[4;38;5;149mVectorWorkerBase):
     459      def get_arg_types(self):
     460          return None
     461  
     462      def get_result_type(self, obj):
     463          return self._val_type
     464  
     465      def __call__(self, obj):
     466          return self.get(obj, int(self.size(obj)) - 1)
     467  
     468  class ESC[4;38;5;81mVectorAtWorker(ESC[4;38;5;149mVectorWorkerBase):
     469      def get_arg_types(self):
     470          return get_std_size_type()
     471  
     472      def get_result_type(self, obj, index):
     473          return self._val_type
     474  
     475      def __call__(self, obj, index):
     476          size = int(self.size(obj))
     477          if int(index) >= size:
     478              raise IndexError('Vector index "%d" should not be >= %d.' %
     479                               ((int(index), size)))
     480          return self.get(obj, int(index))
     481  
     482  class ESC[4;38;5;81mVectorSubscriptWorker(ESC[4;38;5;149mVectorWorkerBase):
     483      def get_arg_types(self):
     484          return get_std_size_type()
     485  
     486      def get_result_type(self, obj, subscript):
     487          return self._val_type
     488  
     489      def __call__(self, obj, subscript):
     490          return self.get(obj, int(subscript))
     491  
     492  class ESC[4;38;5;81mVectorMethodsMatcher(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodMatcher):
     493      def __init__(self):
     494          gdb.xmethod.XMethodMatcher.__init__(self,
     495                                              matcher_name_prefix + 'vector')
     496          self._method_dict = {
     497              'size': LibStdCxxXMethod('size', VectorSizeWorker),
     498              'empty': LibStdCxxXMethod('empty', VectorEmptyWorker),
     499              'front': LibStdCxxXMethod('front', VectorFrontWorker),
     500              'back': LibStdCxxXMethod('back', VectorBackWorker),
     501              'at': LibStdCxxXMethod('at', VectorAtWorker),
     502              'operator[]': LibStdCxxXMethod('operator[]',
     503                                             VectorSubscriptWorker),
     504          }
     505          self.methods = [self._method_dict[m] for m in self._method_dict]
     506  
     507      def match(self, class_type, method_name):
     508          if not re.match('^std::(__\d+::)?vector<.*>$', class_type.tag):
     509              return None
     510          method = self._method_dict.get(method_name)
     511          if method is None or not method.enabled:
     512              return None
     513          return method.worker_class(class_type.template_argument(0))
     514  
     515  # Xmethods for associative containers
     516  
     517  class ESC[4;38;5;81mAssociativeContainerWorkerBase(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodWorker):
     518      def __init__(self, unordered):
     519          self._unordered = unordered
     520  
     521      def node_count(self, obj):
     522          if self._unordered:
     523              return obj['_M_h']['_M_element_count']
     524          else:
     525              return obj['_M_t']['_M_impl']['_M_node_count']
     526  
     527      def get_arg_types(self):
     528          return None
     529  
     530  class ESC[4;38;5;81mAssociativeContainerEmptyWorker(ESC[4;38;5;149mAssociativeContainerWorkerBase):
     531      def get_result_type(self, obj):
     532          return get_bool_type()
     533  
     534      def __call__(self, obj):
     535          return int(self.node_count(obj)) == 0
     536  
     537  class ESC[4;38;5;81mAssociativeContainerSizeWorker(ESC[4;38;5;149mAssociativeContainerWorkerBase):
     538      def get_result_type(self, obj):
     539          return get_std_size_type()
     540  
     541      def __call__(self, obj):
     542          return self.node_count(obj)
     543  
     544  class ESC[4;38;5;81mAssociativeContainerMethodsMatcher(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodMatcher):
     545      def __init__(self, name):
     546          gdb.xmethod.XMethodMatcher.__init__(self,
     547                                              matcher_name_prefix + name)
     548          self._name = name
     549          self._method_dict = {
     550              'size': LibStdCxxXMethod('size', AssociativeContainerSizeWorker),
     551              'empty': LibStdCxxXMethod('empty',
     552                                        AssociativeContainerEmptyWorker),
     553          }
     554          self.methods = [self._method_dict[m] for m in self._method_dict]
     555  
     556      def match(self, class_type, method_name):
     557          if not re.match('^std::(__\d+::)?%s<.*>$' % self._name, class_type.tag):
     558              return None
     559          method = self._method_dict.get(method_name)
     560          if method is None or not method.enabled:
     561              return None
     562          unordered = 'unordered' in self._name
     563          return method.worker_class(unordered)
     564  
     565  # Xmethods for std::unique_ptr
     566  
     567  class ESC[4;38;5;81mUniquePtrGetWorker(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodWorker):
     568      "Implements std::unique_ptr<T>::get() and std::unique_ptr<T>::operator->()"
     569  
     570      def __init__(self, elem_type):
     571          self._is_array = elem_type.code == gdb.TYPE_CODE_ARRAY
     572          if self._is_array:
     573              self._elem_type = elem_type.target()
     574          else:
     575              self._elem_type = elem_type
     576  
     577      def get_arg_types(self):
     578          return None
     579  
     580      def get_result_type(self, obj):
     581          return self._elem_type.pointer()
     582  
     583      def _supports(self, method_name):
     584          "operator-> is not supported for unique_ptr<T[]>"
     585          return method_name == 'get' or not self._is_array
     586  
     587      def __call__(self, obj):
     588          impl_type = obj.dereference().type.fields()[0].type.tag
     589          # Check for new implementations first:
     590          if re.match('^std::(__\d+::)?__uniq_ptr_(data|impl)<.*>$', impl_type):
     591              tuple_member = obj['_M_t']['_M_t']
     592          elif re.match('^std::(__\d+::)?tuple<.*>$', impl_type):
     593              tuple_member = obj['_M_t']
     594          else:
     595              return None
     596          tuple_impl_type = tuple_member.type.fields()[0].type # _Tuple_impl
     597          tuple_head_type = tuple_impl_type.fields()[1].type   # _Head_base
     598          head_field = tuple_head_type.fields()[0]
     599          if head_field.name == '_M_head_impl':
     600              return tuple_member.cast(tuple_head_type)['_M_head_impl']
     601          elif head_field.is_base_class:
     602              return tuple_member.cast(head_field.type)
     603          else:
     604              return None
     605  
     606  class ESC[4;38;5;81mUniquePtrDerefWorker(ESC[4;38;5;149mUniquePtrGetWorker):
     607      "Implements std::unique_ptr<T>::operator*()"
     608  
     609      def __init__(self, elem_type):
     610          UniquePtrGetWorker.__init__(self, elem_type)
     611  
     612      def get_result_type(self, obj):
     613          return self._elem_type
     614  
     615      def _supports(self, method_name):
     616          "operator* is not supported for unique_ptr<T[]>"
     617          return not self._is_array
     618  
     619      def __call__(self, obj):
     620          return UniquePtrGetWorker.__call__(self, obj).dereference()
     621  
     622  class ESC[4;38;5;81mUniquePtrSubscriptWorker(ESC[4;38;5;149mUniquePtrGetWorker):
     623      "Implements std::unique_ptr<T>::operator[](size_t)"
     624  
     625      def __init__(self, elem_type):
     626          UniquePtrGetWorker.__init__(self, elem_type)
     627  
     628      def get_arg_types(self):
     629          return get_std_size_type()
     630  
     631      def get_result_type(self, obj, index):
     632          return self._elem_type
     633  
     634      def _supports(self, method_name):
     635          "operator[] is only supported for unique_ptr<T[]>"
     636          return self._is_array
     637  
     638      def __call__(self, obj, index):
     639          return UniquePtrGetWorker.__call__(self, obj)[index]
     640  
     641  class ESC[4;38;5;81mUniquePtrMethodsMatcher(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodMatcher):
     642      def __init__(self):
     643          gdb.xmethod.XMethodMatcher.__init__(self,
     644                                              matcher_name_prefix + 'unique_ptr')
     645          self._method_dict = {
     646              'get': LibStdCxxXMethod('get', UniquePtrGetWorker),
     647              'operator->': LibStdCxxXMethod('operator->', UniquePtrGetWorker),
     648              'operator*': LibStdCxxXMethod('operator*', UniquePtrDerefWorker),
     649              'operator[]': LibStdCxxXMethod('operator[]', UniquePtrSubscriptWorker),
     650          }
     651          self.methods = [self._method_dict[m] for m in self._method_dict]
     652  
     653      def match(self, class_type, method_name):
     654          if not re.match('^std::(__\d+::)?unique_ptr<.*>$', class_type.tag):
     655              return None
     656          method = self._method_dict.get(method_name)
     657          if method is None or not method.enabled:
     658              return None
     659          worker = method.worker_class(class_type.template_argument(0))
     660          if worker._supports(method_name):
     661              return worker
     662          return None
     663  
     664  # Xmethods for std::shared_ptr
     665  
     666  class ESC[4;38;5;81mSharedPtrGetWorker(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodWorker):
     667      "Implements std::shared_ptr<T>::get() and std::shared_ptr<T>::operator->()"
     668  
     669      def __init__(self, elem_type):
     670          self._is_array = elem_type.code == gdb.TYPE_CODE_ARRAY
     671          if self._is_array:
     672              self._elem_type = elem_type.target()
     673          else:
     674              self._elem_type = elem_type
     675  
     676      def get_arg_types(self):
     677          return None
     678  
     679      def get_result_type(self, obj):
     680          return self._elem_type.pointer()
     681  
     682      def _supports(self, method_name):
     683          "operator-> is not supported for shared_ptr<T[]>"
     684          return method_name == 'get' or not self._is_array
     685  
     686      def __call__(self, obj):
     687          return obj['_M_ptr']
     688  
     689  class ESC[4;38;5;81mSharedPtrDerefWorker(ESC[4;38;5;149mSharedPtrGetWorker):
     690      "Implements std::shared_ptr<T>::operator*()"
     691  
     692      def __init__(self, elem_type):
     693          SharedPtrGetWorker.__init__(self, elem_type)
     694  
     695      def get_result_type(self, obj):
     696          return self._elem_type
     697  
     698      def _supports(self, method_name):
     699          "operator* is not supported for shared_ptr<T[]>"
     700          return not self._is_array
     701  
     702      def __call__(self, obj):
     703          return SharedPtrGetWorker.__call__(self, obj).dereference()
     704  
     705  class ESC[4;38;5;81mSharedPtrSubscriptWorker(ESC[4;38;5;149mSharedPtrGetWorker):
     706      "Implements std::shared_ptr<T>::operator[](size_t)"
     707  
     708      def __init__(self, elem_type):
     709          SharedPtrGetWorker.__init__(self, elem_type)
     710  
     711      def get_arg_types(self):
     712          return get_std_size_type()
     713  
     714      def get_result_type(self, obj, index):
     715          return self._elem_type
     716  
     717      def _supports(self, method_name):
     718          "operator[] is only supported for shared_ptr<T[]>"
     719          return self._is_array
     720  
     721      def __call__(self, obj, index):
     722          # Check bounds if _elem_type is an array of known bound
     723          m = re.match('.*\[(\d+)]$', str(self._elem_type))
     724          if m and index >= int(m.group(1)):
     725              raise IndexError('shared_ptr<%s> index "%d" should not be >= %d.' %
     726                               (self._elem_type, int(index), int(m.group(1))))
     727          return SharedPtrGetWorker.__call__(self, obj)[index]
     728  
     729  class ESC[4;38;5;81mSharedPtrUseCountWorker(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodWorker):
     730      "Implements std::shared_ptr<T>::use_count()"
     731  
     732      def __init__(self, elem_type):
     733          pass
     734  
     735      def get_arg_types(self):
     736          return None
     737  
     738      def get_result_type(self, obj):
     739          return gdb.lookup_type('long')
     740  
     741      def _supports(self, method_name):
     742          return True
     743  
     744      def __call__(self, obj):
     745          refcounts = obj['_M_refcount']['_M_pi']
     746          return refcounts['_M_use_count'] if refcounts else 0
     747  
     748  class ESC[4;38;5;81mSharedPtrUniqueWorker(ESC[4;38;5;149mSharedPtrUseCountWorker):
     749      "Implements std::shared_ptr<T>::unique()"
     750  
     751      def __init__(self, elem_type):
     752          SharedPtrUseCountWorker.__init__(self, elem_type)
     753  
     754      def get_result_type(self, obj):
     755          return gdb.lookup_type('bool')
     756  
     757      def __call__(self, obj):
     758          return SharedPtrUseCountWorker.__call__(self, obj) == 1
     759  
     760  class ESC[4;38;5;81mSharedPtrMethodsMatcher(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mxmethodESC[4;38;5;149m.ESC[4;38;5;149mXMethodMatcher):
     761      def __init__(self):
     762          gdb.xmethod.XMethodMatcher.__init__(self,
     763                                              matcher_name_prefix + 'shared_ptr')
     764          self._method_dict = {
     765              'get': LibStdCxxXMethod('get', SharedPtrGetWorker),
     766              'operator->': LibStdCxxXMethod('operator->', SharedPtrGetWorker),
     767              'operator*': LibStdCxxXMethod('operator*', SharedPtrDerefWorker),
     768              'operator[]': LibStdCxxXMethod('operator[]', SharedPtrSubscriptWorker),
     769              'use_count': LibStdCxxXMethod('use_count', SharedPtrUseCountWorker),
     770              'unique': LibStdCxxXMethod('unique', SharedPtrUniqueWorker),
     771          }
     772          self.methods = [self._method_dict[m] for m in self._method_dict]
     773  
     774      def match(self, class_type, method_name):
     775          if not re.match('^std::(__\d+::)?shared_ptr<.*>$', class_type.tag):
     776              return None
     777          method = self._method_dict.get(method_name)
     778          if method is None or not method.enabled:
     779              return None
     780          worker = method.worker_class(class_type.template_argument(0))
     781          if worker._supports(method_name):
     782              return worker
     783          return None
     784  
     785  def register_libstdcxx_xmethods(locus):
     786      gdb.xmethod.register_xmethod_matcher(locus, ArrayMethodsMatcher())
     787      gdb.xmethod.register_xmethod_matcher(locus, ForwardListMethodsMatcher())
     788      gdb.xmethod.register_xmethod_matcher(locus, DequeMethodsMatcher())
     789      gdb.xmethod.register_xmethod_matcher(locus, ListMethodsMatcher())
     790      gdb.xmethod.register_xmethod_matcher(locus, VectorMethodsMatcher())
     791      gdb.xmethod.register_xmethod_matcher(
     792          locus, AssociativeContainerMethodsMatcher('set'))
     793      gdb.xmethod.register_xmethod_matcher(
     794          locus, AssociativeContainerMethodsMatcher('map'))
     795      gdb.xmethod.register_xmethod_matcher(
     796          locus, AssociativeContainerMethodsMatcher('multiset'))
     797      gdb.xmethod.register_xmethod_matcher(
     798          locus, AssociativeContainerMethodsMatcher('multimap'))
     799      gdb.xmethod.register_xmethod_matcher(
     800          locus, AssociativeContainerMethodsMatcher('unordered_set'))
     801      gdb.xmethod.register_xmethod_matcher(
     802          locus, AssociativeContainerMethodsMatcher('unordered_map'))
     803      gdb.xmethod.register_xmethod_matcher(
     804          locus, AssociativeContainerMethodsMatcher('unordered_multiset'))
     805      gdb.xmethod.register_xmethod_matcher(
     806          locus, AssociativeContainerMethodsMatcher('unordered_multimap'))
     807      gdb.xmethod.register_xmethod_matcher(locus, UniquePtrMethodsMatcher())
     808      gdb.xmethod.register_xmethod_matcher(locus, SharedPtrMethodsMatcher())