1*4882a593Smuzhiyun# 2*4882a593Smuzhiyun# gdb helper commands and functions for Linux kernel debugging 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# list tools 5*4882a593Smuzhiyun# 6*4882a593Smuzhiyun# Copyright (c) Thiebaud Weksteen, 2015 7*4882a593Smuzhiyun# 8*4882a593Smuzhiyun# Authors: 9*4882a593Smuzhiyun# Thiebaud Weksteen <thiebaud@weksteen.fr> 10*4882a593Smuzhiyun# 11*4882a593Smuzhiyun# This work is licensed under the terms of the GNU GPL version 2. 12*4882a593Smuzhiyun# 13*4882a593Smuzhiyun 14*4882a593Smuzhiyunimport gdb 15*4882a593Smuzhiyun 16*4882a593Smuzhiyunfrom linux import utils 17*4882a593Smuzhiyun 18*4882a593Smuzhiyunlist_head = utils.CachedType("struct list_head") 19*4882a593Smuzhiyunhlist_head = utils.CachedType("struct hlist_head") 20*4882a593Smuzhiyunhlist_node = utils.CachedType("struct hlist_node") 21*4882a593Smuzhiyun 22*4882a593Smuzhiyun 23*4882a593Smuzhiyundef list_for_each(head): 24*4882a593Smuzhiyun if head.type == list_head.get_type().pointer(): 25*4882a593Smuzhiyun head = head.dereference() 26*4882a593Smuzhiyun elif head.type != list_head.get_type(): 27*4882a593Smuzhiyun raise TypeError("Must be struct list_head not {}" 28*4882a593Smuzhiyun .format(head.type)) 29*4882a593Smuzhiyun 30*4882a593Smuzhiyun node = head['next'].dereference() 31*4882a593Smuzhiyun while node.address != head.address: 32*4882a593Smuzhiyun yield node.address 33*4882a593Smuzhiyun node = node['next'].dereference() 34*4882a593Smuzhiyun 35*4882a593Smuzhiyun 36*4882a593Smuzhiyundef list_for_each_entry(head, gdbtype, member): 37*4882a593Smuzhiyun for node in list_for_each(head): 38*4882a593Smuzhiyun yield utils.container_of(node, gdbtype, member) 39*4882a593Smuzhiyun 40*4882a593Smuzhiyun 41*4882a593Smuzhiyundef hlist_for_each(head): 42*4882a593Smuzhiyun if head.type == hlist_head.get_type().pointer(): 43*4882a593Smuzhiyun head = head.dereference() 44*4882a593Smuzhiyun elif head.type != hlist_head.get_type(): 45*4882a593Smuzhiyun raise TypeError("Must be struct hlist_head not {}" 46*4882a593Smuzhiyun .format(head.type)) 47*4882a593Smuzhiyun 48*4882a593Smuzhiyun node = head['first'].dereference() 49*4882a593Smuzhiyun while node.address: 50*4882a593Smuzhiyun yield node.address 51*4882a593Smuzhiyun node = node['next'].dereference() 52*4882a593Smuzhiyun 53*4882a593Smuzhiyun 54*4882a593Smuzhiyundef hlist_for_each_entry(head, gdbtype, member): 55*4882a593Smuzhiyun for node in hlist_for_each(head): 56*4882a593Smuzhiyun yield utils.container_of(node, gdbtype, member) 57*4882a593Smuzhiyun 58*4882a593Smuzhiyun 59*4882a593Smuzhiyundef list_check(head): 60*4882a593Smuzhiyun nb = 0 61*4882a593Smuzhiyun if (head.type == list_head.get_type().pointer()): 62*4882a593Smuzhiyun head = head.dereference() 63*4882a593Smuzhiyun elif (head.type != list_head.get_type()): 64*4882a593Smuzhiyun raise gdb.GdbError('argument must be of type (struct list_head [*])') 65*4882a593Smuzhiyun c = head 66*4882a593Smuzhiyun try: 67*4882a593Smuzhiyun gdb.write("Starting with: {}\n".format(c)) 68*4882a593Smuzhiyun except gdb.MemoryError: 69*4882a593Smuzhiyun gdb.write('head is not accessible\n') 70*4882a593Smuzhiyun return 71*4882a593Smuzhiyun while True: 72*4882a593Smuzhiyun p = c['prev'].dereference() 73*4882a593Smuzhiyun n = c['next'].dereference() 74*4882a593Smuzhiyun try: 75*4882a593Smuzhiyun if p['next'] != c.address: 76*4882a593Smuzhiyun gdb.write('prev.next != current: ' 77*4882a593Smuzhiyun 'current@{current_addr}={current} ' 78*4882a593Smuzhiyun 'prev@{p_addr}={p}\n'.format( 79*4882a593Smuzhiyun current_addr=c.address, 80*4882a593Smuzhiyun current=c, 81*4882a593Smuzhiyun p_addr=p.address, 82*4882a593Smuzhiyun p=p, 83*4882a593Smuzhiyun )) 84*4882a593Smuzhiyun return 85*4882a593Smuzhiyun except gdb.MemoryError: 86*4882a593Smuzhiyun gdb.write('prev is not accessible: ' 87*4882a593Smuzhiyun 'current@{current_addr}={current}\n'.format( 88*4882a593Smuzhiyun current_addr=c.address, 89*4882a593Smuzhiyun current=c 90*4882a593Smuzhiyun )) 91*4882a593Smuzhiyun return 92*4882a593Smuzhiyun try: 93*4882a593Smuzhiyun if n['prev'] != c.address: 94*4882a593Smuzhiyun gdb.write('next.prev != current: ' 95*4882a593Smuzhiyun 'current@{current_addr}={current} ' 96*4882a593Smuzhiyun 'next@{n_addr}={n}\n'.format( 97*4882a593Smuzhiyun current_addr=c.address, 98*4882a593Smuzhiyun current=c, 99*4882a593Smuzhiyun n_addr=n.address, 100*4882a593Smuzhiyun n=n, 101*4882a593Smuzhiyun )) 102*4882a593Smuzhiyun return 103*4882a593Smuzhiyun except gdb.MemoryError: 104*4882a593Smuzhiyun gdb.write('next is not accessible: ' 105*4882a593Smuzhiyun 'current@{current_addr}={current}\n'.format( 106*4882a593Smuzhiyun current_addr=c.address, 107*4882a593Smuzhiyun current=c 108*4882a593Smuzhiyun )) 109*4882a593Smuzhiyun return 110*4882a593Smuzhiyun c = n 111*4882a593Smuzhiyun nb += 1 112*4882a593Smuzhiyun if c == head: 113*4882a593Smuzhiyun gdb.write("list is consistent: {} node(s)\n".format(nb)) 114*4882a593Smuzhiyun return 115*4882a593Smuzhiyun 116*4882a593Smuzhiyun 117*4882a593Smuzhiyunclass LxListChk(gdb.Command): 118*4882a593Smuzhiyun """Verify a list consistency""" 119*4882a593Smuzhiyun 120*4882a593Smuzhiyun def __init__(self): 121*4882a593Smuzhiyun super(LxListChk, self).__init__("lx-list-check", gdb.COMMAND_DATA, 122*4882a593Smuzhiyun gdb.COMPLETE_EXPRESSION) 123*4882a593Smuzhiyun 124*4882a593Smuzhiyun def invoke(self, arg, from_tty): 125*4882a593Smuzhiyun argv = gdb.string_to_argv(arg) 126*4882a593Smuzhiyun if len(argv) != 1: 127*4882a593Smuzhiyun raise gdb.GdbError("lx-list-check takes one argument") 128*4882a593Smuzhiyun list_check(gdb.parse_and_eval(argv[0])) 129*4882a593Smuzhiyun 130*4882a593Smuzhiyun 131*4882a593SmuzhiyunLxListChk() 132