0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 import gdb
0015
0016 from linux import utils
0017
0018 list_head = utils.CachedType("struct list_head")
0019 hlist_head = utils.CachedType("struct hlist_head")
0020 hlist_node = utils.CachedType("struct hlist_node")
0021
0022
0023 def list_for_each(head):
0024 if head.type == list_head.get_type().pointer():
0025 head = head.dereference()
0026 elif head.type != list_head.get_type():
0027 raise TypeError("Must be struct list_head not {}"
0028 .format(head.type))
0029
0030 if head['next'] == 0:
0031 gdb.write("list_for_each: Uninitialized list '{}' treated as empty\n"
0032 .format(head.address))
0033 return
0034
0035 node = head['next'].dereference()
0036 while node.address != head.address:
0037 yield node.address
0038 node = node['next'].dereference()
0039
0040
0041 def list_for_each_entry(head, gdbtype, member):
0042 for node in list_for_each(head):
0043 yield utils.container_of(node, gdbtype, member)
0044
0045
0046 def hlist_for_each(head):
0047 if head.type == hlist_head.get_type().pointer():
0048 head = head.dereference()
0049 elif head.type != hlist_head.get_type():
0050 raise TypeError("Must be struct hlist_head not {}"
0051 .format(head.type))
0052
0053 node = head['first'].dereference()
0054 while node.address:
0055 yield node.address
0056 node = node['next'].dereference()
0057
0058
0059 def hlist_for_each_entry(head, gdbtype, member):
0060 for node in hlist_for_each(head):
0061 yield utils.container_of(node, gdbtype, member)
0062
0063
0064 def list_check(head):
0065 nb = 0
0066 if (head.type == list_head.get_type().pointer()):
0067 head = head.dereference()
0068 elif (head.type != list_head.get_type()):
0069 raise gdb.GdbError('argument must be of type (struct list_head [*])')
0070 c = head
0071 try:
0072 gdb.write("Starting with: {}\n".format(c))
0073 except gdb.MemoryError:
0074 gdb.write('head is not accessible\n')
0075 return
0076 while True:
0077 p = c['prev'].dereference()
0078 n = c['next'].dereference()
0079 try:
0080 if p['next'] != c.address:
0081 gdb.write('prev.next != current: '
0082 'current@{current_addr}={current} '
0083 'prev@{p_addr}={p}\n'.format(
0084 current_addr=c.address,
0085 current=c,
0086 p_addr=p.address,
0087 p=p,
0088 ))
0089 return
0090 except gdb.MemoryError:
0091 gdb.write('prev is not accessible: '
0092 'current@{current_addr}={current}\n'.format(
0093 current_addr=c.address,
0094 current=c
0095 ))
0096 return
0097 try:
0098 if n['prev'] != c.address:
0099 gdb.write('next.prev != current: '
0100 'current@{current_addr}={current} '
0101 'next@{n_addr}={n}\n'.format(
0102 current_addr=c.address,
0103 current=c,
0104 n_addr=n.address,
0105 n=n,
0106 ))
0107 return
0108 except gdb.MemoryError:
0109 gdb.write('next is not accessible: '
0110 'current@{current_addr}={current}\n'.format(
0111 current_addr=c.address,
0112 current=c
0113 ))
0114 return
0115 c = n
0116 nb += 1
0117 if c == head:
0118 gdb.write("list is consistent: {} node(s)\n".format(nb))
0119 return
0120
0121
0122 class LxListChk(gdb.Command):
0123 """Verify a list consistency"""
0124
0125 def __init__(self):
0126 super(LxListChk, self).__init__("lx-list-check", gdb.COMMAND_DATA,
0127 gdb.COMPLETE_EXPRESSION)
0128
0129 def invoke(self, arg, from_tty):
0130 argv = gdb.string_to_argv(arg)
0131 if len(argv) != 1:
0132 raise gdb.GdbError("lx-list-check takes one argument")
0133 list_check(gdb.parse_and_eval(argv[0]))
0134
0135
0136 LxListChk()