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 <[email protected]> 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 gdb.GdbError("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 if node.type != list_head.get_type().pointer(): 39 raise TypeError("Type {} found. Expected struct list_head *." 40 .format(node.type)) 41 yield utils.container_of(node, gdbtype, member) 42 43 44def hlist_for_each(head): 45 if head.type == hlist_head.get_type().pointer(): 46 head = head.dereference() 47 elif head.type != hlist_head.get_type(): 48 raise gdb.GdbError("Must be struct hlist_head not {}" 49 .format(head.type)) 50 51 node = head['first'].dereference() 52 while node.address: 53 yield node.address 54 node = node['next'].dereference() 55 56 57def hlist_for_each_entry(head, gdbtype, member): 58 for node in hlist_for_each(head): 59 if node.type != hlist_node.get_type().pointer(): 60 raise TypeError("Type {} found. Expected struct hlist_head *." 61 .format(node.type)) 62 yield utils.container_of(node, gdbtype, member) 63 64 65def list_check(head): 66 nb = 0 67 if (head.type == list_head.get_type().pointer()): 68 head = head.dereference() 69 elif (head.type != list_head.get_type()): 70 raise gdb.GdbError('argument must be of type (struct list_head [*])') 71 c = head 72 try: 73 gdb.write("Starting with: {}\n".format(c)) 74 except gdb.MemoryError: 75 gdb.write('head is not accessible\n') 76 return 77 while True: 78 p = c['prev'].dereference() 79 n = c['next'].dereference() 80 try: 81 if p['next'] != c.address: 82 gdb.write('prev.next != current: ' 83 'current@{current_addr}={current} ' 84 'prev@{p_addr}={p}\n'.format( 85 current_addr=c.address, 86 current=c, 87 p_addr=p.address, 88 p=p, 89 )) 90 return 91 except gdb.MemoryError: 92 gdb.write('prev is not accessible: ' 93 'current@{current_addr}={current}\n'.format( 94 current_addr=c.address, 95 current=c 96 )) 97 return 98 try: 99 if n['prev'] != c.address: 100 gdb.write('next.prev != current: ' 101 'current@{current_addr}={current} ' 102 'next@{n_addr}={n}\n'.format( 103 current_addr=c.address, 104 current=c, 105 n_addr=n.address, 106 n=n, 107 )) 108 return 109 except gdb.MemoryError: 110 gdb.write('next is not accessible: ' 111 'current@{current_addr}={current}\n'.format( 112 current_addr=c.address, 113 current=c 114 )) 115 return 116 c = n 117 nb += 1 118 if c == head: 119 gdb.write("list is consistent: {} node(s)\n".format(nb)) 120 return 121 122 123class LxListChk(gdb.Command): 124 """Verify a list consistency""" 125 126 def __init__(self): 127 super(LxListChk, self).__init__("lx-list-check", gdb.COMMAND_DATA, 128 gdb.COMPLETE_EXPRESSION) 129 130 def invoke(self, arg, from_tty): 131 argv = gdb.string_to_argv(arg) 132 if len(argv) != 1: 133 raise gdb.GdbError("lx-list-check takes one argument") 134 list_check(gdb.parse_and_eval(argv[0])) 135 136 137LxListChk() 138