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