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