Linux-libre 5.4.48-gnu
[librecmc/linux-libre.git] / scripts / gdb / linux / lists.py
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
14 import gdb
15
16 from linux import utils
17
18 list_head = utils.CachedType("struct list_head")
19 hlist_head = utils.CachedType("struct hlist_head")
20 hlist_node = utils.CachedType("struct hlist_node")
21
22
23 def list_for_each(head):
24     if head.type == list_head.get_type().pointer():
25         head = head.dereference()
26     elif head.type != list_head.get_type():
27         raise TypeError("Must be struct list_head not {}"
28                            .format(head.type))
29
30     node = head['next'].dereference()
31     while node.address != head.address:
32         yield node.address
33         node = node['next'].dereference()
34
35
36 def list_for_each_entry(head, gdbtype, member):
37     for node in list_for_each(head):
38         yield utils.container_of(node, gdbtype, member)
39
40
41 def hlist_for_each(head):
42     if head.type == hlist_head.get_type().pointer():
43         head = head.dereference()
44     elif head.type != hlist_head.get_type():
45         raise TypeError("Must be struct hlist_head not {}"
46                            .format(head.type))
47
48     node = head['first'].dereference()
49     while node.address:
50         yield node.address
51         node = node['next'].dereference()
52
53
54 def hlist_for_each_entry(head, gdbtype, member):
55     for node in hlist_for_each(head):
56         yield utils.container_of(node, gdbtype, member)
57
58
59 def list_check(head):
60     nb = 0
61     if (head.type == list_head.get_type().pointer()):
62         head = head.dereference()
63     elif (head.type != list_head.get_type()):
64         raise gdb.GdbError('argument must be of type (struct list_head [*])')
65     c = head
66     try:
67         gdb.write("Starting with: {}\n".format(c))
68     except gdb.MemoryError:
69         gdb.write('head is not accessible\n')
70         return
71     while True:
72         p = c['prev'].dereference()
73         n = c['next'].dereference()
74         try:
75             if p['next'] != c.address:
76                 gdb.write('prev.next != current: '
77                           'current@{current_addr}={current} '
78                           'prev@{p_addr}={p}\n'.format(
79                               current_addr=c.address,
80                               current=c,
81                               p_addr=p.address,
82                               p=p,
83                           ))
84                 return
85         except gdb.MemoryError:
86             gdb.write('prev is not accessible: '
87                       'current@{current_addr}={current}\n'.format(
88                           current_addr=c.address,
89                           current=c
90                       ))
91             return
92         try:
93             if n['prev'] != c.address:
94                 gdb.write('next.prev != current: '
95                           'current@{current_addr}={current} '
96                           'next@{n_addr}={n}\n'.format(
97                               current_addr=c.address,
98                               current=c,
99                               n_addr=n.address,
100                               n=n,
101                           ))
102                 return
103         except gdb.MemoryError:
104             gdb.write('next is not accessible: '
105                       'current@{current_addr}={current}\n'.format(
106                           current_addr=c.address,
107                           current=c
108                       ))
109             return
110         c = n
111         nb += 1
112         if c == head:
113             gdb.write("list is consistent: {} node(s)\n".format(nb))
114             return
115
116
117 class LxListChk(gdb.Command):
118     """Verify a list consistency"""
119
120     def __init__(self):
121         super(LxListChk, self).__init__("lx-list-check", gdb.COMMAND_DATA,
122                                         gdb.COMPLETE_EXPRESSION)
123
124     def invoke(self, arg, from_tty):
125         argv = gdb.string_to_argv(arg)
126         if len(argv) != 1:
127             raise gdb.GdbError("lx-list-check takes one argument")
128         list_check(gdb.parse_and_eval(argv[0]))
129
130
131 LxListChk()