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