lists.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. #
  2. # gdb helper commands and functions for Linux kernel debugging
  3. #
  4. # list tools
  5. #
  6. # Copyright (c) Thiebaud Weksteen, 2015
  7. #
  8. # Authors:
  9. # Thiebaud Weksteen <[email protected]>
  10. #
  11. # This work is licensed under the terms of the GNU GPL version 2.
  12. #
  13. import gdb
  14. from linux import utils
  15. list_head = utils.CachedType("struct list_head")
  16. hlist_head = utils.CachedType("struct hlist_head")
  17. hlist_node = utils.CachedType("struct hlist_node")
  18. def list_for_each(head):
  19. if head.type == list_head.get_type().pointer():
  20. head = head.dereference()
  21. elif head.type != list_head.get_type():
  22. raise TypeError("Must be struct list_head not {}"
  23. .format(head.type))
  24. if head['next'] == 0:
  25. gdb.write("list_for_each: Uninitialized list '{}' treated as empty\n"
  26. .format(head.address))
  27. return
  28. node = head['next'].dereference()
  29. while node.address != head.address:
  30. yield node.address
  31. node = node['next'].dereference()
  32. def list_for_each_entry(head, gdbtype, member):
  33. for node in list_for_each(head):
  34. yield utils.container_of(node, gdbtype, member)
  35. def hlist_for_each(head):
  36. if head.type == hlist_head.get_type().pointer():
  37. head = head.dereference()
  38. elif head.type != hlist_head.get_type():
  39. raise TypeError("Must be struct hlist_head not {}"
  40. .format(head.type))
  41. node = head['first'].dereference()
  42. while node.address:
  43. yield node.address
  44. node = node['next'].dereference()
  45. def hlist_for_each_entry(head, gdbtype, member):
  46. for node in hlist_for_each(head):
  47. yield utils.container_of(node, gdbtype, member)
  48. def list_check(head):
  49. nb = 0
  50. if (head.type == list_head.get_type().pointer()):
  51. head = head.dereference()
  52. elif (head.type != list_head.get_type()):
  53. raise gdb.GdbError('argument must be of type (struct list_head [*])')
  54. c = head
  55. try:
  56. gdb.write("Starting with: {}\n".format(c))
  57. except gdb.MemoryError:
  58. gdb.write('head is not accessible\n')
  59. return
  60. while True:
  61. p = c['prev'].dereference()
  62. n = c['next'].dereference()
  63. try:
  64. if p['next'] != c.address:
  65. gdb.write('prev.next != current: '
  66. 'current@{current_addr}={current} '
  67. 'prev@{p_addr}={p}\n'.format(
  68. current_addr=c.address,
  69. current=c,
  70. p_addr=p.address,
  71. p=p,
  72. ))
  73. return
  74. except gdb.MemoryError:
  75. gdb.write('prev is not accessible: '
  76. 'current@{current_addr}={current}\n'.format(
  77. current_addr=c.address,
  78. current=c
  79. ))
  80. return
  81. try:
  82. if n['prev'] != c.address:
  83. gdb.write('next.prev != current: '
  84. 'current@{current_addr}={current} '
  85. 'next@{n_addr}={n}\n'.format(
  86. current_addr=c.address,
  87. current=c,
  88. n_addr=n.address,
  89. n=n,
  90. ))
  91. return
  92. except gdb.MemoryError:
  93. gdb.write('next is not accessible: '
  94. 'current@{current_addr}={current}\n'.format(
  95. current_addr=c.address,
  96. current=c
  97. ))
  98. return
  99. c = n
  100. nb += 1
  101. if c == head:
  102. gdb.write("list is consistent: {} node(s)\n".format(nb))
  103. return
  104. class LxListChk(gdb.Command):
  105. """Verify a list consistency"""
  106. def __init__(self):
  107. super(LxListChk, self).__init__("lx-list-check", gdb.COMMAND_DATA,
  108. gdb.COMPLETE_EXPRESSION)
  109. def invoke(self, arg, from_tty):
  110. argv = gdb.string_to_argv(arg)
  111. if len(argv) != 1:
  112. raise gdb.GdbError("lx-list-check takes one argument")
  113. list_check(gdb.parse_and_eval(argv[0]))
  114. LxListChk()