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") 19 20 21def 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 34def 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 42def list_check(head): 43 nb = 0 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 [*])') 48 c = head 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 100class LxListChk(gdb.Command): 101 """Verify a list consistency""" 102 103 def __init__(self): 104 super(LxListChk, self).__init__("lx-list-check", gdb.COMMAND_DATA, 105 gdb.COMPLETE_EXPRESSION) 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 113LxListChk() 114