xmethods.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. # Xmethods for libstdc++.
  2. # Copyright (C) 2014-2015 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::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, index):
  138. first_node = obj['_M_impl']['_M_start']['_M_node']
  139. index_node = first_node + index / self._bufsize
  140. return index_node[0][index % 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::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::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. class ListEmptyWorker(ListWorkerBase):
  259. def get_result_type(self, obj):
  260. return get_bool_type()
  261. def __call__(self, obj):
  262. base_node = obj['_M_impl']['_M_node']
  263. if base_node['_M_next'] == base_node.address:
  264. return True
  265. else:
  266. return False
  267. class ListSizeWorker(ListWorkerBase):
  268. def get_result_type(self, obj):
  269. return get_std_size_type()
  270. def __call__(self, obj):
  271. begin_node = obj['_M_impl']['_M_node']['_M_next']
  272. end_node = obj['_M_impl']['_M_node'].address
  273. size = 0
  274. while begin_node != end_node:
  275. begin_node = begin_node['_M_next']
  276. size += 1
  277. return size
  278. class ListFrontWorker(ListWorkerBase):
  279. def get_result_type(self, obj):
  280. return self._val_type
  281. def __call__(self, obj):
  282. node = obj['_M_impl']['_M_node']['_M_next'].cast(self._node_type)
  283. return node['_M_data']
  284. class ListBackWorker(ListWorkerBase):
  285. def get_result_type(self, obj):
  286. return self._val_type
  287. def __call__(self, obj):
  288. prev_node = obj['_M_impl']['_M_node']['_M_prev'].cast(self._node_type)
  289. return prev_node['_M_data']
  290. class ListMethodsMatcher(gdb.xmethod.XMethodMatcher):
  291. def __init__(self):
  292. gdb.xmethod.XMethodMatcher.__init__(self,
  293. matcher_name_prefix + 'list')
  294. self._method_dict = {
  295. 'empty': LibStdCxxXMethod('empty', ListEmptyWorker),
  296. 'size': LibStdCxxXMethod('size', ListSizeWorker),
  297. 'front': LibStdCxxXMethod('front', ListFrontWorker),
  298. 'back': LibStdCxxXMethod('back', ListBackWorker)
  299. }
  300. self.methods = [self._method_dict[m] for m in self._method_dict]
  301. def match(self, class_type, method_name):
  302. if not re.match('^std::list<.*>$', class_type.tag):
  303. return None
  304. method = self._method_dict.get(method_name)
  305. if method is None or not method.enabled:
  306. return None
  307. val_type = class_type.template_argument(0)
  308. node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer()
  309. return method.worker_class(val_type, node_type)
  310. # Xmethods for std::vector
  311. class VectorWorkerBase(gdb.xmethod.XMethodWorker):
  312. def __init__(self, val_type):
  313. self._val_type = val_type
  314. def size(self, obj):
  315. if self._val_type.code == gdb.TYPE_CODE_BOOL:
  316. start = obj['_M_impl']['_M_start']['_M_p']
  317. finish = obj['_M_impl']['_M_finish']['_M_p']
  318. finish_offset = obj['_M_impl']['_M_finish']['_M_offset']
  319. bit_size = start.dereference().type.sizeof * 8
  320. return (finish - start) * bit_size + finish_offset
  321. else:
  322. return obj['_M_impl']['_M_finish'] - obj['_M_impl']['_M_start']
  323. def get(self, obj, index):
  324. if self._val_type.code == gdb.TYPE_CODE_BOOL:
  325. start = obj['_M_impl']['_M_start']['_M_p']
  326. bit_size = start.dereference().type.sizeof * 8
  327. valp = start + index / bit_size
  328. offset = index % bit_size
  329. return (valp.dereference() & (1 << offset)) > 0
  330. else:
  331. return obj['_M_impl']['_M_start'][index]
  332. class VectorEmptyWorker(VectorWorkerBase):
  333. def get_arg_types(self):
  334. return None
  335. def get_result_type(self, obj):
  336. return get_bool_type()
  337. def __call__(self, obj):
  338. return int(self.size(obj)) == 0
  339. class VectorSizeWorker(VectorWorkerBase):
  340. def get_arg_types(self):
  341. return None
  342. def get_result_type(self, obj):
  343. return get_std_size_type()
  344. def __call__(self, obj):
  345. return self.size(obj)
  346. class VectorFrontWorker(VectorWorkerBase):
  347. def get_arg_types(self):
  348. return None
  349. def get_result_type(self, obj):
  350. return self._val_type
  351. def __call__(self, obj):
  352. return self.get(obj, 0)
  353. class VectorBackWorker(VectorWorkerBase):
  354. def get_arg_types(self):
  355. return None
  356. def get_result_type(self, obj):
  357. return self._val_type
  358. def __call__(self, obj):
  359. return self.get(obj, int(self.size(obj)) - 1)
  360. class VectorAtWorker(VectorWorkerBase):
  361. def get_arg_types(self):
  362. return get_std_size_type()
  363. def get_result_type(self, obj, index):
  364. return self._val_type
  365. def __call__(self, obj, index):
  366. size = int(self.size(obj))
  367. if int(index) >= size:
  368. raise IndexError('Vector index "%d" should not be >= %d.' %
  369. ((int(index), size)))
  370. return self.get(obj, int(index))
  371. class VectorSubscriptWorker(VectorWorkerBase):
  372. def get_arg_types(self):
  373. return get_std_size_type()
  374. def get_result_type(self, obj, subscript):
  375. return self._val_type
  376. def __call__(self, obj, subscript):
  377. return self.get(obj, int(subscript))
  378. class VectorMethodsMatcher(gdb.xmethod.XMethodMatcher):
  379. def __init__(self):
  380. gdb.xmethod.XMethodMatcher.__init__(self,
  381. matcher_name_prefix + 'vector')
  382. self._method_dict = {
  383. 'size': LibStdCxxXMethod('size', VectorSizeWorker),
  384. 'empty': LibStdCxxXMethod('empty', VectorEmptyWorker),
  385. 'front': LibStdCxxXMethod('front', VectorFrontWorker),
  386. 'back': LibStdCxxXMethod('back', VectorBackWorker),
  387. 'at': LibStdCxxXMethod('at', VectorAtWorker),
  388. 'operator[]': LibStdCxxXMethod('operator[]',
  389. VectorSubscriptWorker),
  390. }
  391. self.methods = [self._method_dict[m] for m in self._method_dict]
  392. def match(self, class_type, method_name):
  393. if not re.match('^std::vector<.*>$', 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. return method.worker_class(class_type.template_argument(0))
  399. # Xmethods for associative containers
  400. class AssociativeContainerWorkerBase(gdb.xmethod.XMethodWorker):
  401. def __init__(self, unordered):
  402. self._unordered = unordered
  403. def node_count(self, obj):
  404. if self._unordered:
  405. return obj['_M_h']['_M_element_count']
  406. else:
  407. return obj['_M_t']['_M_impl']['_M_node_count']
  408. def get_arg_types(self):
  409. return None
  410. class AssociativeContainerEmptyWorker(AssociativeContainerWorkerBase):
  411. def get_result_type(self, obj):
  412. return get_bool_type()
  413. def __call__(self, obj):
  414. return int(self.node_count(obj)) == 0
  415. class AssociativeContainerSizeWorker(AssociativeContainerWorkerBase):
  416. def get_result_type(self, obj):
  417. return get_std_size_type()
  418. def __call__(self, obj):
  419. return self.node_count(obj)
  420. class AssociativeContainerMethodsMatcher(gdb.xmethod.XMethodMatcher):
  421. def __init__(self, name):
  422. gdb.xmethod.XMethodMatcher.__init__(self,
  423. matcher_name_prefix + name)
  424. self._name = name
  425. self._method_dict = {
  426. 'size': LibStdCxxXMethod('size', AssociativeContainerSizeWorker),
  427. 'empty': LibStdCxxXMethod('empty',
  428. AssociativeContainerEmptyWorker),
  429. }
  430. self.methods = [self._method_dict[m] for m in self._method_dict]
  431. def match(self, class_type, method_name):
  432. if not re.match('^std::%s<.*>$' % self._name, class_type.tag):
  433. return None
  434. method = self._method_dict.get(method_name)
  435. if method is None or not method.enabled:
  436. return None
  437. unordered = 'unordered' in self._name
  438. return method.worker_class(unordered)
  439. # Xmethods for std::unique_ptr
  440. class UniquePtrGetWorker(gdb.xmethod.XMethodWorker):
  441. def __init__(self, elem_type):
  442. self._elem_type = elem_type
  443. def get_arg_types(self):
  444. return None
  445. def get_result_type(self, obj):
  446. return self._elem_type.pointer()
  447. def __call__(self, obj):
  448. return obj['_M_t']['_M_head_impl']
  449. class UniquePtrDerefWorker(UniquePtrGetWorker):
  450. def __init__(self, elem_type):
  451. UniquePtrGetWorker.__init__(self, elem_type)
  452. def get_result_type(self, obj):
  453. return self._elem_type
  454. def __call__(self, obj):
  455. return UniquePtrGetWorker.__call__(self, obj).dereference()
  456. class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
  457. def __init__(self):
  458. gdb.xmethod.XMethodMatcher.__init__(self,
  459. matcher_name_prefix + 'unique_ptr')
  460. self._method_dict = {
  461. 'get': LibStdCxxXMethod('get', UniquePtrGetWorker),
  462. 'operator*': LibStdCxxXMethod('operator*', UniquePtrDerefWorker),
  463. }
  464. self.methods = [self._method_dict[m] for m in self._method_dict]
  465. def match(self, class_type, method_name):
  466. if not re.match('^std::unique_ptr<.*>$', class_type.tag):
  467. return None
  468. method = self._method_dict.get(method_name)
  469. if method is None or not method.enabled:
  470. return None
  471. return method.worker_class(class_type.template_argument(0))
  472. def register_libstdcxx_xmethods(locus):
  473. gdb.xmethod.register_xmethod_matcher(locus, ArrayMethodsMatcher())
  474. gdb.xmethod.register_xmethod_matcher(locus, ForwardListMethodsMatcher())
  475. gdb.xmethod.register_xmethod_matcher(locus, DequeMethodsMatcher())
  476. gdb.xmethod.register_xmethod_matcher(locus, ListMethodsMatcher())
  477. gdb.xmethod.register_xmethod_matcher(locus, VectorMethodsMatcher())
  478. gdb.xmethod.register_xmethod_matcher(
  479. locus, AssociativeContainerMethodsMatcher('set'))
  480. gdb.xmethod.register_xmethod_matcher(
  481. locus, AssociativeContainerMethodsMatcher('map'))
  482. gdb.xmethod.register_xmethod_matcher(
  483. locus, AssociativeContainerMethodsMatcher('multiset'))
  484. gdb.xmethod.register_xmethod_matcher(
  485. locus, AssociativeContainerMethodsMatcher('multimap'))
  486. gdb.xmethod.register_xmethod_matcher(
  487. locus, AssociativeContainerMethodsMatcher('unordered_set'))
  488. gdb.xmethod.register_xmethod_matcher(
  489. locus, AssociativeContainerMethodsMatcher('unordered_map'))
  490. gdb.xmethod.register_xmethod_matcher(
  491. locus, AssociativeContainerMethodsMatcher('unordered_multiset'))
  492. gdb.xmethod.register_xmethod_matcher(
  493. locus, AssociativeContainerMethodsMatcher('unordered_multimap'))
  494. gdb.xmethod.register_xmethod_matcher(locus, UniquePtrMethodsMatcher())