pretty-print.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. import gdb.printing
  2. import re
  3. def parseCompressedPairElement(elem: gdb.Value) -> gdb.Value:
  4. return elem[elem.type.fields()[0]]
  5. def parseCompressedPair(cpair: gdb.Value) -> tuple[gdb.Value, gdb.Value]:
  6. fields = cpair.type.fields()
  7. first = cpair[fields[0]]
  8. second = cpair[fields[1]]
  9. return parseCompressedPairElement(first), parseCompressedPairElement(second)
  10. def delegateChildren(val: gdb.Value):
  11. try:
  12. for field in val.type.fields():
  13. yield field.name, val[field]
  14. except TypeError:
  15. yield '[value]', val
  16. class vectorPrinter:
  17. class _iterator:
  18. def __init__(self, item, end, idx):
  19. self.item = item
  20. self.end = end
  21. self.size = self.end - self.item
  22. self.idx = idx
  23. def __iter__(self):
  24. return self
  25. def __next__(self):
  26. if self.item >= self.end:
  27. raise StopIteration
  28. key = str(self.idx)
  29. iter = self.item.dereference()
  30. self.item += 1
  31. self.idx += 1
  32. return key, iter
  33. def __init__(self, val):
  34. self.val = val
  35. def to_string(self):
  36. return "std::vector of size %d, capacity %d" % (self.val['m_size'], self.val['m_capacity'])
  37. def display_hint(self):
  38. return 'array'
  39. def children(self):
  40. if self.val['m_size'] == 0:
  41. return []
  42. data, alloc = parseCompressedPair(self.val['m_data'])
  43. return self._iterator(data, data + self.val['m_size'], 0)
  44. def _leftmost(node):
  45. ret = node
  46. while ret['left'] != 0:
  47. ret = ret['left'].dereference()
  48. return ret
  49. def _next(node):
  50. if node['right']:
  51. return _leftmost(node['right'].dereference())
  52. else:
  53. if node['parent'] == 0:
  54. return None
  55. parent = node['parent'].dereference()
  56. if parent['left'] == node.address:
  57. return parent
  58. ret = node
  59. while True:
  60. ret = ret['parent'].dereference()
  61. if ret['parent'] == 0:
  62. return None
  63. if ret['parent'].dereference()['left'] == ret.address:
  64. break
  65. return ret['parent'].dereference()
  66. class rbtreePrinter:
  67. def __init__(self, type, val):
  68. self.type: gdb.Type = type
  69. self.val: gdb.Value = val['tree']
  70. def to_string(self):
  71. return "%s of size %d" % (self.type, self.num_children())
  72. def display_hint(self):
  73. return 'array'
  74. def num_children(self):
  75. size, _ = parseCompressedPair(self.val['size_data'])
  76. return size
  77. def children(self):
  78. root, alloc = parseCompressedPair(self.val['root_data'])
  79. size, comp = parseCompressedPair(self.val['size_data'])
  80. # yield '[alloc]', alloc
  81. # yield '[comp]', comp
  82. # yield '[root]', root
  83. if root == 0:
  84. return
  85. nd = _leftmost(root.dereference())
  86. for i in range(size):
  87. yield str(i), nd['value']
  88. nd = _next(nd)
  89. if nd == None:
  90. break
  91. class stringPrinter:
  92. def __init__(self, val):
  93. self.val = val
  94. def to_string(self):
  95. data, alloc = parseCompressedPair(self.val['m_data'])
  96. data = data['in']
  97. if data['stackdata']['end'] == 0:
  98. return data['stackdata']['str'].string()
  99. return data['heapdata']['m_ptr'].string()
  100. def display_hint(self):
  101. return 'string'
  102. class listPrinter:
  103. def __init__(self, val):
  104. self.val: gdb.Value = val
  105. self.type: gdb.Type = val.type
  106. this_type = self.type.unqualified().strip_typedefs()
  107. if this_type.tag == None:
  108. this_type = this_type.target()
  109. self.value_node_type = gdb.lookup_type(this_type.tag + '::node').pointer()
  110. def to_string(self):
  111. size, alloc = parseCompressedPair(self.val['m_pair'])
  112. return 'std::list of size %d' % size
  113. def display_hint(self):
  114. return 'array'
  115. def num_children(self):
  116. size, alloc = parseCompressedPair(self.val['m_pair'])
  117. return size
  118. def children(self):
  119. head = self.val['m_head']
  120. node = head['next']
  121. idx = 0
  122. while node != head.address:
  123. nodeval = node.reinterpret_cast(self.value_node_type)
  124. yield str(idx), nodeval['value']
  125. idx += 1
  126. node = node['next']
  127. class listIteratorPrinter:
  128. def __init__(self, val):
  129. self.val = val
  130. this_type: gdb.Type = val.type
  131. this_type = this_type.unqualified().strip_typedefs()
  132. if this_type.tag == None:
  133. this_type = this_type.target()
  134. type_tag: str = this_type.tag
  135. type_tag = type_tag[:type_tag.rfind('::')]
  136. self.value_node_type = gdb.lookup_type(type_tag + '::node').pointer()
  137. def children(self):
  138. yield 'addr', self.val['p']
  139. if self.val['p'] == 0:
  140. return
  141. nodeptr = self.val['p'].cast(self.value_node_type)
  142. yield 'value', nodeptr['value']
  143. class rbtreeIteratorPrinter:
  144. def __init__(self, val):
  145. self.val = val
  146. def children(self):
  147. yield 'addr', self.val['p']
  148. if self.val['p'] == 0:
  149. return
  150. yield 'value', self.val['p']['value']
  151. class vectorIteratorPrinter:
  152. def __init__(self, val):
  153. self.val = val
  154. def children(self):
  155. yield 'value', self.val['m_ptr'].dereference()
  156. class pairPrinter:
  157. def __init__(self, val):
  158. self.val = val
  159. def children(self):
  160. yield 'first', self.val['first']
  161. yield 'second', self.val['second']
  162. class tuplePrinter:
  163. def __init__(self, val):
  164. self.val = val
  165. def children(self):
  166. i = 0
  167. try:
  168. cur = self.val
  169. while True:
  170. yield '<%d>' % i, cur['val']
  171. i += 1
  172. cur = cur['next']
  173. except Exception:
  174. if i == 0:
  175. yield 'tuple of size 0', ''
  176. class functionPrinter:
  177. def __init__(self, val: gdb.Value):
  178. self.val = val
  179. def to_string(self):
  180. return self.val.type.name
  181. class referenceWrapperPrinter:
  182. def __init__(self, val):
  183. self.val = val
  184. def to_string(self):
  185. return "std::reference_wrapper to %x" % self.val['_ptr']
  186. def children(self):
  187. yield 'addr', self.val['_ptr'].cast(gdb.lookup_type('void').pointer())
  188. yield 'reference', self.val['_ptr']
  189. class sharedPointerPrinter:
  190. def __init__(self, val: gdb.Value):
  191. self.val = val
  192. self.pointer = val['ptr']
  193. self.controlBlock = val['cb']
  194. def to_string(self):
  195. if self.pointer == 0:
  196. return 'nullptr of %s' % self.val.type.name
  197. refCount = self.controlBlock['ref_count']
  198. weakCount = self.controlBlock['weak_count']
  199. realPointer = self.controlBlock['ptr']
  200. return '%s to 0x%x, ref(%d), wref(%d), cb(0x%x), memp(0x%x)' % (
  201. self.val.type.name,
  202. self.pointer,
  203. refCount,
  204. weakCount,
  205. self.controlBlock,
  206. realPointer)
  207. def children(self):
  208. if self.pointer == 0:
  209. return []
  210. content = self.pointer.dereference()
  211. return delegateChildren(content)
  212. class uniquePointerPrinter:
  213. def __init__(self, val: gdb.Value):
  214. self.val = val
  215. self.data = val['data']
  216. def to_string(self):
  217. pointer, deleter = parseCompressedPair(self.data)
  218. if pointer == 0:
  219. return 'nullptr of %s' % self.val.type.name
  220. return "%s to 0x%x" % (self.val.type.name, pointer)
  221. def children(self):
  222. pointer, deleter = parseCompressedPair(self.data)
  223. yield '[deleter]', deleter
  224. if pointer == 0:
  225. return
  226. for item in delegateChildren(pointer.dereference()):
  227. yield item
  228. def build_pretty_printer(val: gdb.Value):
  229. type: gdb.Type = val.type.unqualified().strip_typedefs()
  230. typename = type.tag
  231. if typename == None:
  232. return None
  233. if re.compile(r"^std::pair<.*, .*>$").match(typename):
  234. return pairPrinter(val)
  235. if re.compile(r"^std::tuple<.*>$").match(typename):
  236. return tuplePrinter(val)
  237. if re.compile(r"^std::function<.*>$").match(typename):
  238. return functionPrinter(val)
  239. if re.compile(r"^std::reference_wrapper<.*>$").match(typename):
  240. return referenceWrapperPrinter(val)
  241. if re.compile(r"^std::list<.*, .*>::_iterator<.*?>$").match(typename):
  242. return listIteratorPrinter(val)
  243. if re.compile(r"^std::vector<.*, .*>::_iterator<.*?>$").match(typename):
  244. return vectorIteratorPrinter(val)
  245. if re.compile(r"^std::list<.*, .*>$").match(typename):
  246. return listPrinter(val)
  247. if re.compile(r"^std::vector<.*, .*>$").match(typename):
  248. return vectorPrinter(val)
  249. if re.compile(r"^std::map<.*, .*, .*, .*>$").match(typename):
  250. return rbtreePrinter("std::map", val)
  251. if re.compile(r"^std::set<.*, .*, .*>$").match(typename):
  252. return rbtreePrinter("std::set", val)
  253. if re.compile(r"^std::impl::rbtree<.*, .*, .*>::_iterator<.*?>$").match(typename):
  254. return rbtreeIteratorPrinter(val)
  255. if re.compile(r"^std::basic_string<.*>$").match(typename):
  256. return stringPrinter(val)
  257. if re.compile(r"^std::shared_ptr<.*>$").match(typename):
  258. return sharedPointerPrinter(val)
  259. if re.compile(r"^std::unique_ptr<.*>$").match(typename):
  260. return uniquePointerPrinter(val)
  261. return None
  262. gdb.pretty_printers.append(build_pretty_printer)