lists.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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 <thiebaud@weksteen.fr>
  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. def list_for_each(head):
  17. if head.type == list_head.get_type().pointer():
  18. head = head.dereference()
  19. elif head.type != list_head.get_type():
  20. raise gdb.GdbError("Must be struct list_head not {}"
  21. .format(head.type))
  22. node = head['next'].dereference()
  23. while node.address != head.address:
  24. yield node.address
  25. node = node['next'].dereference()
  26. def list_for_each_entry(head, gdbtype, member):
  27. for node in list_for_each(head):
  28. if node.type != list_head.get_type().pointer():
  29. raise TypeError("Type {} found. Expected struct list_head *."
  30. .format(node.type))
  31. yield utils.container_of(node, gdbtype, member)
  32. def list_check(head):
  33. nb = 0
  34. if (head.type == list_head.get_type().pointer()):
  35. head = head.dereference()
  36. elif (head.type != list_head.get_type()):
  37. raise gdb.GdbError('argument must be of type (struct list_head [*])')
  38. c = head
  39. try:
  40. gdb.write("Starting with: {}\n".format(c))
  41. except gdb.MemoryError:
  42. gdb.write('head is not accessible\n')
  43. return
  44. while True:
  45. p = c['prev'].dereference()
  46. n = c['next'].dereference()
  47. try:
  48. if p['next'] != c.address:
  49. gdb.write('prev.next != current: '
  50. 'current@{current_addr}={current} '
  51. 'prev@{p_addr}={p}\n'.format(
  52. current_addr=c.address,
  53. current=c,
  54. p_addr=p.address,
  55. p=p,
  56. ))
  57. return
  58. except gdb.MemoryError:
  59. gdb.write('prev is not accessible: '
  60. 'current@{current_addr}={current}\n'.format(
  61. current_addr=c.address,
  62. current=c
  63. ))
  64. return
  65. try:
  66. if n['prev'] != c.address:
  67. gdb.write('next.prev != current: '
  68. 'current@{current_addr}={current} '
  69. 'next@{n_addr}={n}\n'.format(
  70. current_addr=c.address,
  71. current=c,
  72. n_addr=n.address,
  73. n=n,
  74. ))
  75. return
  76. except gdb.MemoryError:
  77. gdb.write('next is not accessible: '
  78. 'current@{current_addr}={current}\n'.format(
  79. current_addr=c.address,
  80. current=c
  81. ))
  82. return
  83. c = n
  84. nb += 1
  85. if c == head:
  86. gdb.write("list is consistent: {} node(s)\n".format(nb))
  87. return
  88. class LxListChk(gdb.Command):
  89. """Verify a list consistency"""
  90. def __init__(self):
  91. super(LxListChk, self).__init__("lx-list-check", gdb.COMMAND_DATA,
  92. gdb.COMPLETE_EXPRESSION)
  93. def invoke(self, arg, from_tty):
  94. argv = gdb.string_to_argv(arg)
  95. if len(argv) != 1:
  96. raise gdb.GdbError("lx-list-check takes one argument")
  97. list_check(gdb.parse_and_eval(argv[0]))
  98. LxListChk()