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 14import gdb 15 16from linux import utils 17 18list_head = utils.CachedType("struct list_head") 19hlist_head = utils.CachedType("struct hlist_head") 20hlist_node = utils.CachedType("struct hlist_node") 21 22 23def 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 36def 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 41def 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 54def 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 59def 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 117class 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 131LxListChk() 132