pretty-print.py 15 KB

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