pretty-print.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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: gdb.Value):
  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 stringViewPrinter:
  103. def __init__(self, val: gdb.Value):
  104. self.val = val
  105. self.string = val['m_str']
  106. self.length = val['m_len']
  107. def to_string(self):
  108. return self.string.string(length=self.length)
  109. def display_hint(self):
  110. return 'string'
  111. class listPrinter:
  112. def __init__(self, val):
  113. self.val: gdb.Value = val
  114. self.type: gdb.Type = val.type
  115. this_type = self.type.unqualified().strip_typedefs()
  116. if this_type.tag == None:
  117. this_type = this_type.target()
  118. self.value_node_type = gdb.lookup_type(this_type.tag + '::node').pointer()
  119. def to_string(self):
  120. size, alloc = parseCompressedPair(self.val['m_pair'])
  121. return 'std::list of size %d' % size
  122. def display_hint(self):
  123. return 'array'
  124. def num_children(self):
  125. size, alloc = parseCompressedPair(self.val['m_pair'])
  126. return size
  127. def children(self):
  128. head = self.val['m_head']
  129. node = head['next']
  130. idx = 0
  131. while node != head.address:
  132. nodeval = node.reinterpret_cast(self.value_node_type)
  133. yield str(idx), nodeval['value']
  134. idx += 1
  135. node = node['next']
  136. class listIteratorPrinter:
  137. def __init__(self, val):
  138. self.val = val
  139. this_type: gdb.Type = val.type
  140. this_type = this_type.unqualified().strip_typedefs()
  141. if this_type.tag == None:
  142. this_type = this_type.target()
  143. type_tag: str = this_type.tag
  144. type_tag = type_tag[:type_tag.rfind('::')]
  145. self.value_node_type = gdb.lookup_type(type_tag + '::node').pointer()
  146. def children(self):
  147. yield 'addr', self.val['p']
  148. if self.val['p'] == 0:
  149. return
  150. nodeptr = self.val['p'].cast(self.value_node_type)
  151. yield 'value', nodeptr['value']
  152. class rbtreeIteratorPrinter:
  153. def __init__(self, val):
  154. self.val = val
  155. def children(self):
  156. yield 'addr', self.val['p']
  157. if self.val['p'] == 0:
  158. return
  159. yield 'value', self.val['p']['value']
  160. class vectorIteratorPrinter:
  161. def __init__(self, val):
  162. self.val = val
  163. def children(self):
  164. yield 'value', self.val['m_ptr'].dereference()
  165. class pairPrinter:
  166. def __init__(self, val):
  167. self.val = val
  168. def children(self):
  169. yield 'first', self.val['first']
  170. yield 'second', self.val['second']
  171. class tuplePrinter:
  172. def __init__(self, val):
  173. self.val = val
  174. def children(self):
  175. i = 0
  176. try:
  177. cur = self.val
  178. while True:
  179. yield '<%d>' % i, cur['val']
  180. i += 1
  181. cur = cur['next']
  182. except Exception:
  183. if i == 0:
  184. yield 'tuple of size 0', ''
  185. class functionPrinter:
  186. def __init__(self, val: gdb.Value):
  187. self.val = val
  188. def to_string(self):
  189. return self.val.type.name
  190. class referenceWrapperPrinter:
  191. def __init__(self, val):
  192. self.val = val
  193. def to_string(self):
  194. return "std::reference_wrapper to %x" % self.val['_ptr']
  195. def children(self):
  196. yield 'addr', self.val['_ptr'].cast(gdb.lookup_type('void').pointer())
  197. yield 'reference', self.val['_ptr']
  198. class sharedPointerPrinter:
  199. def __init__(self, val: gdb.Value):
  200. self.val = val
  201. self.pointer = val['ptr']
  202. self.controlBlock = val['cb']
  203. def to_string(self):
  204. if self.pointer == 0:
  205. return 'nullptr of %s' % self.val.type.name
  206. refCount = self.controlBlock['ref_count']
  207. weakCount = self.controlBlock['weak_count']
  208. realPointer = self.controlBlock['ptr']
  209. return '%s to 0x%x, ref(%d), wref(%d), cb(0x%x), memp(0x%x)' % (
  210. self.val.type.name,
  211. self.pointer,
  212. refCount,
  213. weakCount,
  214. self.controlBlock,
  215. realPointer)
  216. def children(self):
  217. if self.pointer == 0:
  218. return []
  219. content = self.pointer.dereference()
  220. return delegateChildren(content)
  221. class uniquePointerPrinter:
  222. def __init__(self, val: gdb.Value):
  223. self.val = val
  224. self.data = val['data']
  225. def to_string(self):
  226. pointer, deleter = parseCompressedPair(self.data)
  227. if pointer == 0:
  228. return 'nullptr of %s' % self.val.type.name
  229. return "%s to 0x%x" % (self.val.type.name, pointer)
  230. def children(self):
  231. pointer, deleter = parseCompressedPair(self.data)
  232. yield '[deleter]', deleter
  233. if pointer == 0:
  234. return
  235. for item in delegateChildren(pointer.dereference()):
  236. yield item
  237. def build_pretty_printer(val: gdb.Value):
  238. type: gdb.Type = val.type.unqualified().strip_typedefs()
  239. typename = type.tag
  240. if typename == None:
  241. return None
  242. if re.compile(r"^std::pair<.*, .*>$").match(typename):
  243. return pairPrinter(val)
  244. if re.compile(r"^std::tuple<.*>$").match(typename):
  245. return tuplePrinter(val)
  246. if re.compile(r"^std::function<.*>$").match(typename):
  247. return functionPrinter(val)
  248. if re.compile(r"^std::reference_wrapper<.*>$").match(typename):
  249. return referenceWrapperPrinter(val)
  250. if re.compile(r"^std::list<.*, .*>::_iterator<.*?>$").match(typename):
  251. return listIteratorPrinter(val)
  252. if re.compile(r"^std::vector<.*, .*>::_iterator<.*?>$").match(typename):
  253. return vectorIteratorPrinter(val)
  254. if re.compile(r"^std::list<.*, .*>$").match(typename):
  255. return listPrinter(val)
  256. if re.compile(r"^std::vector<.*, .*>$").match(typename):
  257. return vectorPrinter(val)
  258. if re.compile(r"^std::map<.*, .*, .*, .*>$").match(typename):
  259. return rbtreePrinter("std::map", val)
  260. if re.compile(r"^std::set<.*, .*, .*>$").match(typename):
  261. return rbtreePrinter("std::set", val)
  262. if re.compile(r"^std::impl::rbtree<.*, .*, .*>::_iterator<.*?>$").match(typename):
  263. return rbtreeIteratorPrinter(val)
  264. if re.compile(r"^std::basic_string<.*>$").match(typename):
  265. return stringPrinter(val)
  266. if re.compile(r"^types::string_view$").match(typename):
  267. return stringViewPrinter(val)
  268. if re.compile(r"^std::shared_ptr<.*>$").match(typename):
  269. return sharedPointerPrinter(val)
  270. if re.compile(r"^std::unique_ptr<.*>$").match(typename):
  271. return uniquePointerPrinter(val)
  272. return None
  273. gdb.pretty_printers.append(build_pretty_printer)