You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

806 line
28KB

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