pretty-print.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. from typing import Any, Iterator
  2. from gdb import Frame
  3. import gdb.printing
  4. from gdb.FrameDecorator import FrameDecorator
  5. import re
  6. def parseCompressedPairElement(elem: gdb.Value) -> gdb.Value:
  7. return elem[elem.type.fields()[0]]
  8. def parseCompressedPair(cpair: gdb.Value) -> tuple[gdb.Value, gdb.Value]:
  9. fields = cpair.type.fields()
  10. first = cpair[fields[0]]
  11. second = cpair[fields[1]]
  12. return parseCompressedPairElement(first), parseCompressedPairElement(second)
  13. def delegateChildren(val: gdb.Value):
  14. try:
  15. for field in val.type.fields():
  16. try:
  17. yield field.name, val[field]
  18. except:
  19. yield field.name, '<Error>'
  20. except TypeError:
  21. return
  22. def delegateToString(val: gdb.Value):
  23. try:
  24. val.type.fields()
  25. return None
  26. except:
  27. return val
  28. class vectorPrinter:
  29. class _iterator:
  30. def __init__(self, item, end, idx):
  31. self.item = item
  32. self.end = end
  33. self.size = self.end - self.item
  34. self.idx = idx
  35. def __iter__(self):
  36. return self
  37. def __next__(self):
  38. if self.item >= self.end:
  39. raise StopIteration
  40. key = str(self.idx)
  41. iter = self.item.dereference()
  42. self.item += 1
  43. self.idx += 1
  44. return key, iter
  45. def __init__(self, val):
  46. self.val = val
  47. def to_string(self):
  48. return "std::vector of size %d, capacity %d" % (self.val['m_size'], self.val['m_capacity'])
  49. def display_hint(self):
  50. return 'array'
  51. def children(self):
  52. if self.val['m_size'] == 0:
  53. return []
  54. data, alloc = parseCompressedPair(self.val['m_data'])
  55. return self._iterator(data, data + self.val['m_size'], 0)
  56. def _leftmost(node):
  57. ret = node
  58. while ret['left'] != 0:
  59. ret = ret['left'].dereference()
  60. return ret
  61. def _next(node):
  62. if node['right']:
  63. return _leftmost(node['right'].dereference())
  64. else:
  65. if node['parent'] == 0:
  66. return None
  67. parent = node['parent'].dereference()
  68. if parent['left'] == node.address:
  69. return parent
  70. ret = node
  71. while True:
  72. ret = ret['parent'].dereference()
  73. if ret['parent'] == 0:
  74. return None
  75. if ret['parent'].dereference()['left'] == ret.address:
  76. break
  77. return ret['parent'].dereference()
  78. class rbtreePrinter:
  79. def __init__(self, type, val):
  80. self.type: gdb.Type = type
  81. self.val: gdb.Value = val['tree']
  82. def to_string(self):
  83. return "%s of size %d" % (self.type, self.num_children())
  84. def display_hint(self):
  85. return 'array'
  86. def num_children(self):
  87. size, _ = parseCompressedPair(self.val['size_data'])
  88. return size
  89. def children(self):
  90. root, alloc = parseCompressedPair(self.val['root_data'])
  91. size, comp = parseCompressedPair(self.val['size_data'])
  92. # yield '[alloc]', alloc
  93. # yield '[comp]', comp
  94. # yield '[root]', root
  95. if root == 0:
  96. return
  97. nd = _leftmost(root.dereference())
  98. for i in range(size):
  99. yield str(i), nd['value']
  100. nd = _next(nd)
  101. if nd == None:
  102. break
  103. class stringPrinter:
  104. def __init__(self, val: gdb.Value):
  105. self.val = val
  106. def to_string(self):
  107. data, alloc = parseCompressedPair(self.val['m_data'])
  108. data = data['in']
  109. if data['stackdata']['end'] == 0:
  110. return data['stackdata']['str'].string()
  111. return data['heapdata']['m_ptr'].string()
  112. def display_hint(self):
  113. return 'string'
  114. class stringViewPrinter:
  115. def __init__(self, val: gdb.Value):
  116. self.val = val
  117. self.string = val['m_str']
  118. self.length = val['m_len']
  119. def to_string(self):
  120. return self.string.string(length=self.length)
  121. def display_hint(self):
  122. return 'string'
  123. class listPrinter:
  124. def __init__(self, val):
  125. self.val: gdb.Value = val
  126. self.type: gdb.Type = val.type
  127. this_type = self.type.unqualified().strip_typedefs()
  128. if this_type.tag == None:
  129. this_type = this_type.target()
  130. self.value_node_type = gdb.lookup_type(this_type.tag + '::node').pointer()
  131. def to_string(self):
  132. size, alloc = parseCompressedPair(self.val['m_pair'])
  133. return 'std::list of size %d' % size
  134. def display_hint(self):
  135. return 'array'
  136. def num_children(self):
  137. size, alloc = parseCompressedPair(self.val['m_pair'])
  138. return size
  139. def children(self):
  140. head = self.val['m_head']
  141. node = head['next']
  142. idx = 0
  143. while node != head.address:
  144. nodeval = node.reinterpret_cast(self.value_node_type)
  145. yield str(idx), nodeval['value']
  146. idx += 1
  147. node = node['next']
  148. class listIteratorPrinter:
  149. def __init__(self, val):
  150. self.val = val
  151. this_type: gdb.Type = val.type
  152. this_type = this_type.unqualified().strip_typedefs()
  153. if this_type.tag == None:
  154. this_type = this_type.target()
  155. type_tag: str = this_type.tag
  156. type_tag = type_tag[:type_tag.rfind('::')]
  157. self.value_node_type = gdb.lookup_type(type_tag + '::node').pointer()
  158. def children(self):
  159. yield 'addr', self.val['p']
  160. if self.val['p'] == 0:
  161. return
  162. nodeptr = self.val['p'].cast(self.value_node_type)
  163. yield 'value', nodeptr['value']
  164. class rbtreeIteratorPrinter:
  165. def __init__(self, val):
  166. self.val = val
  167. def children(self):
  168. yield 'addr', self.val['p']
  169. if self.val['p'] == 0:
  170. return
  171. yield 'value', self.val['p']['value']
  172. class vectorIteratorPrinter:
  173. def __init__(self, val):
  174. self.val = val
  175. def children(self):
  176. yield 'value', self.val['m_ptr'].dereference()
  177. class pairPrinter:
  178. def __init__(self, val):
  179. self.val = val
  180. def children(self):
  181. yield 'first', self.val['first']
  182. yield 'second', self.val['second']
  183. class tuplePrinter:
  184. def __init__(self, val):
  185. self.val = val
  186. def children(self):
  187. i = 0
  188. try:
  189. cur = self.val
  190. while True:
  191. yield '<%d>' % i, cur['val']
  192. i += 1
  193. cur = cur['next']
  194. except Exception:
  195. if i == 0:
  196. yield 'tuple of size 0', ''
  197. class functionPrinter:
  198. def __init__(self, val: gdb.Value):
  199. self.val = val
  200. def to_string(self):
  201. return self.val.type.name
  202. class referenceWrapperPrinter:
  203. def __init__(self, val):
  204. self.val = val
  205. def to_string(self):
  206. return "std::reference_wrapper to %x" % self.val['_ptr']
  207. def children(self):
  208. yield 'addr', self.val['_ptr'].cast(gdb.lookup_type('void').pointer())
  209. yield 'reference', self.val['_ptr']
  210. class sharedPointerPrinter:
  211. def __init__(self, val: gdb.Value):
  212. self.val = val
  213. self.pointer = val['ptr']
  214. self.controlBlock = val['cb']
  215. def to_string(self):
  216. if self.pointer == 0:
  217. return 'nullptr of %s' % self.val.type.name
  218. refCount = self.controlBlock['ref_count']
  219. weakCount = self.controlBlock['weak_count']
  220. realPointer = self.controlBlock['ptr']
  221. return '%s to 0x%x, ref(%d), wref(%d), cb(0x%x), memp(0x%x)' % (
  222. self.val.type.name,
  223. self.pointer,
  224. refCount,
  225. weakCount,
  226. self.controlBlock,
  227. realPointer)
  228. def children(self):
  229. if self.pointer == 0:
  230. return []
  231. content = self.pointer.dereference()
  232. return delegateChildren(content)
  233. class uniquePointerPrinter:
  234. def __init__(self, val: gdb.Value):
  235. self.val = val
  236. self.data = val['data']
  237. def to_string(self):
  238. pointer, deleter = parseCompressedPair(self.data)
  239. if pointer == 0:
  240. return 'nullptr of %s' % self.val.type.name
  241. return "%s to 0x%x" % (self.val.type.name, pointer)
  242. def children(self):
  243. pointer, deleter = parseCompressedPair(self.data)
  244. yield '[deleter]', deleter
  245. if pointer == 0:
  246. return
  247. for item in delegateChildren(pointer.dereference()):
  248. yield item
  249. class NonNull:
  250. def __init__(self, val: gdb.Value):
  251. pointer = val['pointer']
  252. if pointer.type.code == gdb.TYPE_CODE_PTR:
  253. self.pointer = pointer
  254. self.length = None
  255. self.type = pointer.type.target().name
  256. else:
  257. fields = pointer.type.fields()
  258. self.pointer, self.length = pointer[fields[0]], pointer[fields[1]]
  259. self.type = '[%s]' % self.pointer['data'].type
  260. def is_slice(self):
  261. return self.length is not None
  262. class NonNullPrinter:
  263. def __init__(self, val: gdb.Value):
  264. self.ptr = NonNull(val)
  265. def to_string(self):
  266. return 'NonNull<%s>(0x%x)' % (self.ptr.type, self.ptr.pointer)
  267. def children(self):
  268. try:
  269. for item in delegateChildren(self.ptr.pointer.dereference()):
  270. yield item
  271. except:
  272. yield '[error]', '<Error>'
  273. class ThreadLocalPrinter:
  274. def tls_base(self):
  275. return gdb.parse_and_eval("$gs_base")
  276. def __init__(self, val: gdb.Value):
  277. name = val.type.unqualified().strip_typedefs().name
  278. symbol, _ = gdb.lookup_symbol(name.replace('_access_', '_percpu_inner_'))
  279. value = symbol.value()
  280. value_type = value.type
  281. self.address = self.tls_base() + value.address.cast(gdb.lookup_type('size_t'))
  282. self.address = self.address.cast(value_type.pointer())
  283. def to_string(self):
  284. return delegateToString(self.address.dereference())
  285. def children(self):
  286. yield '[data]', self.address.dereference()
  287. class LockPrinter:
  288. def __init__(self, val: gdb.Value):
  289. self.val = val
  290. def to_string(self):
  291. return delegateToString(self.val['value']['value'])
  292. def children(self):
  293. return delegateChildren(self.val['value']['value'])
  294. class PagePrinter:
  295. def PAGE_ARRAY():
  296. return 0xffffff8040000000
  297. def __init__(self, val: gdb.Value):
  298. self.val = val
  299. def display_hint(self):
  300. 'string'
  301. def to_string(self):
  302. return 'Pages of order %d' % self.val['order']
  303. class UnwrapPrinter:
  304. def __init__(self, val: gdb.Value, name: str):
  305. self.val = val
  306. self.name = name
  307. def to_string(self):
  308. return delegateToString(self.val[self.name])
  309. def children(self):
  310. return delegateChildren(self.val[self.name])
  311. class DentryPrinter:
  312. def __init__(self, val: gdb.Value):
  313. self.val = val
  314. def to_string(self):
  315. try:
  316. return 'Dentry'
  317. except:
  318. return '<Error>'
  319. def children(self):
  320. yield 'hash', self.val['hash']
  321. yield 'name', self.val['name']
  322. class ArcPrinter:
  323. def __init__(self, valobj: gdb.Value):
  324. self._valobj = valobj
  325. self._ptr = NonNull(valobj['ptr'])
  326. for field in self._ptr.pointer.type.fields():
  327. print(field.name, self._ptr.pointer[field])
  328. self._value = self._ptr.pointer['data']
  329. self._strong = self._ptr.pointer['strong']['v']['value']
  330. self._weak = self._ptr.pointer['weak']['v']['value'] - 1
  331. def to_string(self):
  332. if self._ptr.type == '[u8]':
  333. return 'Arc(%s)' % self._value.address.lazy_string(encoding='utf-8', length=self._ptr.length)
  334. else:
  335. return 'Arc(strong={}, weak={})'.format(int(self._strong), int(self._weak))
  336. def children(self):
  337. if not self._ptr.is_slice():
  338. for item in delegateChildren(self._value):
  339. yield item
  340. else:
  341. iter = (self._value.address + idx for idx in range(self._ptr.length))
  342. for idx, ptr in enumerate(iter):
  343. elem = ptr.dereference()
  344. try:
  345. str(elem)
  346. yield str(idx), elem
  347. except RuntimeError:
  348. yield str(idx), '[inaccessible]'
  349. break
  350. def build_pretty_printer(val: gdb.Value):
  351. type: gdb.Type = val.type.unqualified().strip_typedefs()
  352. typename = type.tag
  353. if typename == None:
  354. return None
  355. if re.compile(r"^std::pair<.*, .*>$").match(typename):
  356. return pairPrinter(val)
  357. if re.compile(r"^std::tuple<.*>$").match(typename):
  358. return tuplePrinter(val)
  359. if re.compile(r"^std::function<.*>$").match(typename):
  360. return functionPrinter(val)
  361. if re.compile(r"^std::reference_wrapper<.*>$").match(typename):
  362. return referenceWrapperPrinter(val)
  363. if re.compile(r"^std::list<.*, .*>::_iterator<.*?>$").match(typename):
  364. return listIteratorPrinter(val)
  365. if re.compile(r"^std::vector<.*, .*>::_iterator<.*?>$").match(typename):
  366. return vectorIteratorPrinter(val)
  367. if re.compile(r"^std::list<.*, .*>$").match(typename):
  368. return listPrinter(val)
  369. if re.compile(r"^std::vector<.*, .*>$").match(typename):
  370. return vectorPrinter(val)
  371. if re.compile(r"^std::map<.*, .*, .*, .*>$").match(typename):
  372. return rbtreePrinter("std::map", val)
  373. if re.compile(r"^std::set<.*, .*, .*>$").match(typename):
  374. return rbtreePrinter("std::set", val)
  375. if re.compile(r"^std::impl::rbtree<.*, .*, .*>::_iterator<.*?>$").match(typename):
  376. return rbtreeIteratorPrinter(val)
  377. if re.compile(r"^std::basic_string<.*>$").match(typename):
  378. return stringPrinter(val)
  379. if re.compile(r"^types::string_view$").match(typename):
  380. return stringViewPrinter(val)
  381. if re.compile(r"^std::shared_ptr<.*>$").match(typename):
  382. return sharedPointerPrinter(val)
  383. if re.compile(r"^std::unique_ptr<.*>$").match(typename):
  384. return uniquePointerPrinter(val)
  385. if re.compile(r"^.*::_access_[a-zA-Z0-9_]*$").match(typename):
  386. return ThreadLocalPrinter(val)
  387. if re.compile(r"^gbos_rust_part::sync::lock::Lock<.*>$").match(typename):
  388. return LockPrinter(val)
  389. if re.compile(r"^gbos_rust_part::kernel::mem::paging::Page$").match(typename):
  390. return PagePrinter(val)
  391. if re.compile(r"^gbos_rust_part::kernel::([a-zA-Z_]+::)*Dentry$").match(typename):
  392. return DentryPrinter(val)
  393. if re.compile(r"^(core::([a-z_]+::)+)UnsafeCell<.+>$").match(typename):
  394. return UnwrapPrinter(val, 'value')
  395. if re.compile(r"^(core::([a-z_]+::)+)NonNull<.+>$").match(typename):
  396. return NonNullPrinter(val)
  397. if re.compile(r"^(alloc::([a-z_]+::)+)Arc<.+>$").match(typename):
  398. return ArcPrinter(val)
  399. return None
  400. gdb.execute('skip -rfu ^core::([a-zA-Z0-9_]+::)*[a-zA-Z0-9_<>]+')
  401. gdb.execute('skip -rfu ^alloc::([a-zA-Z0-9_]+::)*[a-zA-Z0-9_<>]+')
  402. gdb.execute('skip -rfu "^gbos_rust_part::sync::lock::Lock<[a-zA-Z0-9_<>: ,]+, [a-zA-Z0-9_<>: ,]+>::new<[a-zA-Z0-9_<>: ,]+, [a-zA-Z0-9_<>: ,]+>"')
  403. gdb.execute('skip -rfu "^gbos_rust_part::sync::locked::Locked<[a-zA-Z0-9_<>: ,]+, [a-zA-Z0-9_<>: ,]+>::new<[a-zA-Z0-9_<>: ,]+, [a-zA-Z0-9_<>: ,]+>"')
  404. gdb.pretty_printers.append(build_pretty_printer)