xref: /linux/scripts/gdb/linux/lists.py (revision d0034a7a4ac7fae708146ac0059b9c47a1543f0d)
1084f6b1eSThiébaud Weksteen#
2084f6b1eSThiébaud Weksteen# gdb helper commands and functions for Linux kernel debugging
3084f6b1eSThiébaud Weksteen#
4084f6b1eSThiébaud Weksteen#  list tools
5084f6b1eSThiébaud Weksteen#
6084f6b1eSThiébaud Weksteen# Copyright (c) Thiebaud Weksteen, 2015
7084f6b1eSThiébaud Weksteen#
8084f6b1eSThiébaud Weksteen# Authors:
9084f6b1eSThiébaud Weksteen#  Thiebaud Weksteen <thiebaud@weksteen.fr>
10084f6b1eSThiébaud Weksteen#
11084f6b1eSThiébaud Weksteen# This work is licensed under the terms of the GNU GPL version 2.
12084f6b1eSThiébaud Weksteen#
13084f6b1eSThiébaud Weksteen
14084f6b1eSThiébaud Weksteenimport gdb
15084f6b1eSThiébaud Weksteen
16084f6b1eSThiébaud Weksteenfrom linux import utils
17084f6b1eSThiébaud Weksteen
18084f6b1eSThiébaud Weksteenlist_head = utils.CachedType("struct list_head")
1947d0d128SLeonard Crestezhlist_head = utils.CachedType("struct hlist_head")
2047d0d128SLeonard Crestezhlist_node = utils.CachedType("struct hlist_node")
21084f6b1eSThiébaud Weksteen
22084f6b1eSThiébaud Weksteen
23a84be61dSKieran Binghamdef list_for_each(head):
24a84be61dSKieran Bingham    if head.type == list_head.get_type().pointer():
25a84be61dSKieran Bingham        head = head.dereference()
26a84be61dSKieran Bingham    elif head.type != list_head.get_type():
2766d5c7c6SLeonard Crestez        raise TypeError("Must be struct list_head not {}"
28a84be61dSKieran Bingham                           .format(head.type))
29a84be61dSKieran Bingham
30*db7fbf49SGeorge Prekas    if head['next'] == 0:
31*db7fbf49SGeorge Prekas        gdb.write("list_for_each: Uninitialized list '{}' treated as empty\n"
32*db7fbf49SGeorge Prekas                     .format(head.address))
33*db7fbf49SGeorge Prekas        return
34*db7fbf49SGeorge Prekas
35a84be61dSKieran Bingham    node = head['next'].dereference()
36a84be61dSKieran Bingham    while node.address != head.address:
37a84be61dSKieran Bingham        yield node.address
38a84be61dSKieran Bingham        node = node['next'].dereference()
39a84be61dSKieran Bingham
40a84be61dSKieran Bingham
41a84be61dSKieran Binghamdef list_for_each_entry(head, gdbtype, member):
42a84be61dSKieran Bingham    for node in list_for_each(head):
43a84be61dSKieran Bingham        yield utils.container_of(node, gdbtype, member)
44a84be61dSKieran Bingham
45a84be61dSKieran Bingham
4647d0d128SLeonard Crestezdef hlist_for_each(head):
4747d0d128SLeonard Crestez    if head.type == hlist_head.get_type().pointer():
4847d0d128SLeonard Crestez        head = head.dereference()
4947d0d128SLeonard Crestez    elif head.type != hlist_head.get_type():
5066d5c7c6SLeonard Crestez        raise TypeError("Must be struct hlist_head not {}"
5147d0d128SLeonard Crestez                           .format(head.type))
5247d0d128SLeonard Crestez
5347d0d128SLeonard Crestez    node = head['first'].dereference()
5447d0d128SLeonard Crestez    while node.address:
5547d0d128SLeonard Crestez        yield node.address
5647d0d128SLeonard Crestez        node = node['next'].dereference()
5747d0d128SLeonard Crestez
5847d0d128SLeonard Crestez
5947d0d128SLeonard Crestezdef hlist_for_each_entry(head, gdbtype, member):
6047d0d128SLeonard Crestez    for node in hlist_for_each(head):
6147d0d128SLeonard Crestez        yield utils.container_of(node, gdbtype, member)
6247d0d128SLeonard Crestez
6347d0d128SLeonard Crestez
64084f6b1eSThiébaud Weksteendef list_check(head):
65084f6b1eSThiébaud Weksteen    nb = 0
66433296b3SJan Kiszka    if (head.type == list_head.get_type().pointer()):
67433296b3SJan Kiszka        head = head.dereference()
68433296b3SJan Kiszka    elif (head.type != list_head.get_type()):
69433296b3SJan Kiszka        raise gdb.GdbError('argument must be of type (struct list_head [*])')
70084f6b1eSThiébaud Weksteen    c = head
71084f6b1eSThiébaud Weksteen    try:
72084f6b1eSThiébaud Weksteen        gdb.write("Starting with: {}\n".format(c))
73084f6b1eSThiébaud Weksteen    except gdb.MemoryError:
74084f6b1eSThiébaud Weksteen        gdb.write('head is not accessible\n')
75084f6b1eSThiébaud Weksteen        return
76084f6b1eSThiébaud Weksteen    while True:
77084f6b1eSThiébaud Weksteen        p = c['prev'].dereference()
78084f6b1eSThiébaud Weksteen        n = c['next'].dereference()
79084f6b1eSThiébaud Weksteen        try:
80084f6b1eSThiébaud Weksteen            if p['next'] != c.address:
81084f6b1eSThiébaud Weksteen                gdb.write('prev.next != current: '
82084f6b1eSThiébaud Weksteen                          'current@{current_addr}={current} '
83084f6b1eSThiébaud Weksteen                          'prev@{p_addr}={p}\n'.format(
84084f6b1eSThiébaud Weksteen                              current_addr=c.address,
85084f6b1eSThiébaud Weksteen                              current=c,
86084f6b1eSThiébaud Weksteen                              p_addr=p.address,
87084f6b1eSThiébaud Weksteen                              p=p,
88084f6b1eSThiébaud Weksteen                          ))
89084f6b1eSThiébaud Weksteen                return
90084f6b1eSThiébaud Weksteen        except gdb.MemoryError:
91084f6b1eSThiébaud Weksteen            gdb.write('prev is not accessible: '
92084f6b1eSThiébaud Weksteen                      'current@{current_addr}={current}\n'.format(
93084f6b1eSThiébaud Weksteen                          current_addr=c.address,
94084f6b1eSThiébaud Weksteen                          current=c
95084f6b1eSThiébaud Weksteen                      ))
96084f6b1eSThiébaud Weksteen            return
97084f6b1eSThiébaud Weksteen        try:
98084f6b1eSThiébaud Weksteen            if n['prev'] != c.address:
99084f6b1eSThiébaud Weksteen                gdb.write('next.prev != current: '
100084f6b1eSThiébaud Weksteen                          'current@{current_addr}={current} '
101084f6b1eSThiébaud Weksteen                          'next@{n_addr}={n}\n'.format(
102084f6b1eSThiébaud Weksteen                              current_addr=c.address,
103084f6b1eSThiébaud Weksteen                              current=c,
104084f6b1eSThiébaud Weksteen                              n_addr=n.address,
105084f6b1eSThiébaud Weksteen                              n=n,
106084f6b1eSThiébaud Weksteen                          ))
107084f6b1eSThiébaud Weksteen                return
108084f6b1eSThiébaud Weksteen        except gdb.MemoryError:
109084f6b1eSThiébaud Weksteen            gdb.write('next is not accessible: '
110084f6b1eSThiébaud Weksteen                      'current@{current_addr}={current}\n'.format(
111084f6b1eSThiébaud Weksteen                          current_addr=c.address,
112084f6b1eSThiébaud Weksteen                          current=c
113084f6b1eSThiébaud Weksteen                      ))
114084f6b1eSThiébaud Weksteen            return
115084f6b1eSThiébaud Weksteen        c = n
116084f6b1eSThiébaud Weksteen        nb += 1
117084f6b1eSThiébaud Weksteen        if c == head:
118084f6b1eSThiébaud Weksteen            gdb.write("list is consistent: {} node(s)\n".format(nb))
119084f6b1eSThiébaud Weksteen            return
120084f6b1eSThiébaud Weksteen
121084f6b1eSThiébaud Weksteen
122084f6b1eSThiébaud Weksteenclass LxListChk(gdb.Command):
123084f6b1eSThiébaud Weksteen    """Verify a list consistency"""
124084f6b1eSThiébaud Weksteen
125084f6b1eSThiébaud Weksteen    def __init__(self):
1263328bc9eSJan Kiszka        super(LxListChk, self).__init__("lx-list-check", gdb.COMMAND_DATA,
1273328bc9eSJan Kiszka                                        gdb.COMPLETE_EXPRESSION)
128084f6b1eSThiébaud Weksteen
129084f6b1eSThiébaud Weksteen    def invoke(self, arg, from_tty):
130084f6b1eSThiébaud Weksteen        argv = gdb.string_to_argv(arg)
131084f6b1eSThiébaud Weksteen        if len(argv) != 1:
132084f6b1eSThiébaud Weksteen            raise gdb.GdbError("lx-list-check takes one argument")
133084f6b1eSThiébaud Weksteen        list_check(gdb.parse_and_eval(argv[0]))
134084f6b1eSThiébaud Weksteen
135494dbe02SStephen Boyd
136084f6b1eSThiébaud WeksteenLxListChk()
137