1*4882a593Smuzhiyun# 2*4882a593Smuzhiyun# gdb helper commands and functions for Linux kernel debugging 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# per-cpu tools 5*4882a593Smuzhiyun# 6*4882a593Smuzhiyun# Copyright (c) Siemens AG, 2011-2013 7*4882a593Smuzhiyun# 8*4882a593Smuzhiyun# Authors: 9*4882a593Smuzhiyun# Jan Kiszka <jan.kiszka@siemens.com> 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 tasks, utils 17*4882a593Smuzhiyun 18*4882a593Smuzhiyun 19*4882a593SmuzhiyunMAX_CPUS = 4096 20*4882a593Smuzhiyun 21*4882a593Smuzhiyun 22*4882a593Smuzhiyundef get_current_cpu(): 23*4882a593Smuzhiyun if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU: 24*4882a593Smuzhiyun return gdb.selected_thread().num - 1 25*4882a593Smuzhiyun elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB: 26*4882a593Smuzhiyun tid = gdb.selected_thread().ptid[2] 27*4882a593Smuzhiyun if tid > (0x100000000 - MAX_CPUS - 2): 28*4882a593Smuzhiyun return 0x100000000 - tid - 2 29*4882a593Smuzhiyun else: 30*4882a593Smuzhiyun return tasks.get_thread_info(tasks.get_task_by_pid(tid))['cpu'] 31*4882a593Smuzhiyun else: 32*4882a593Smuzhiyun raise gdb.GdbError("Sorry, obtaining the current CPU is not yet " 33*4882a593Smuzhiyun "supported with this gdb server.") 34*4882a593Smuzhiyun 35*4882a593Smuzhiyun 36*4882a593Smuzhiyundef per_cpu(var_ptr, cpu): 37*4882a593Smuzhiyun if cpu == -1: 38*4882a593Smuzhiyun cpu = get_current_cpu() 39*4882a593Smuzhiyun if utils.is_target_arch("sparc:v9"): 40*4882a593Smuzhiyun offset = gdb.parse_and_eval( 41*4882a593Smuzhiyun "trap_block[{0}].__per_cpu_base".format(str(cpu))) 42*4882a593Smuzhiyun else: 43*4882a593Smuzhiyun try: 44*4882a593Smuzhiyun offset = gdb.parse_and_eval( 45*4882a593Smuzhiyun "__per_cpu_offset[{0}]".format(str(cpu))) 46*4882a593Smuzhiyun except gdb.error: 47*4882a593Smuzhiyun # !CONFIG_SMP case 48*4882a593Smuzhiyun offset = 0 49*4882a593Smuzhiyun pointer = var_ptr.cast(utils.get_long_type()) + offset 50*4882a593Smuzhiyun return pointer.cast(var_ptr.type).dereference() 51*4882a593Smuzhiyun 52*4882a593Smuzhiyun 53*4882a593Smuzhiyuncpu_mask = {} 54*4882a593Smuzhiyun 55*4882a593Smuzhiyun 56*4882a593Smuzhiyundef cpu_mask_invalidate(event): 57*4882a593Smuzhiyun global cpu_mask 58*4882a593Smuzhiyun cpu_mask = {} 59*4882a593Smuzhiyun gdb.events.stop.disconnect(cpu_mask_invalidate) 60*4882a593Smuzhiyun if hasattr(gdb.events, 'new_objfile'): 61*4882a593Smuzhiyun gdb.events.new_objfile.disconnect(cpu_mask_invalidate) 62*4882a593Smuzhiyun 63*4882a593Smuzhiyun 64*4882a593Smuzhiyundef cpu_list(mask_name): 65*4882a593Smuzhiyun global cpu_mask 66*4882a593Smuzhiyun mask = None 67*4882a593Smuzhiyun if mask_name in cpu_mask: 68*4882a593Smuzhiyun mask = cpu_mask[mask_name] 69*4882a593Smuzhiyun if mask is None: 70*4882a593Smuzhiyun mask = gdb.parse_and_eval(mask_name + ".bits") 71*4882a593Smuzhiyun if hasattr(gdb, 'events'): 72*4882a593Smuzhiyun cpu_mask[mask_name] = mask 73*4882a593Smuzhiyun gdb.events.stop.connect(cpu_mask_invalidate) 74*4882a593Smuzhiyun if hasattr(gdb.events, 'new_objfile'): 75*4882a593Smuzhiyun gdb.events.new_objfile.connect(cpu_mask_invalidate) 76*4882a593Smuzhiyun bits_per_entry = mask[0].type.sizeof * 8 77*4882a593Smuzhiyun num_entries = mask.type.sizeof * 8 / bits_per_entry 78*4882a593Smuzhiyun entry = -1 79*4882a593Smuzhiyun bits = 0 80*4882a593Smuzhiyun 81*4882a593Smuzhiyun while True: 82*4882a593Smuzhiyun while bits == 0: 83*4882a593Smuzhiyun entry += 1 84*4882a593Smuzhiyun if entry == num_entries: 85*4882a593Smuzhiyun return 86*4882a593Smuzhiyun bits = mask[entry] 87*4882a593Smuzhiyun if bits != 0: 88*4882a593Smuzhiyun bit = 0 89*4882a593Smuzhiyun break 90*4882a593Smuzhiyun 91*4882a593Smuzhiyun while bits & 1 == 0: 92*4882a593Smuzhiyun bits >>= 1 93*4882a593Smuzhiyun bit += 1 94*4882a593Smuzhiyun 95*4882a593Smuzhiyun cpu = entry * bits_per_entry + bit 96*4882a593Smuzhiyun 97*4882a593Smuzhiyun bits >>= 1 98*4882a593Smuzhiyun bit += 1 99*4882a593Smuzhiyun 100*4882a593Smuzhiyun yield int(cpu) 101*4882a593Smuzhiyun 102*4882a593Smuzhiyun 103*4882a593Smuzhiyundef each_online_cpu(): 104*4882a593Smuzhiyun for cpu in cpu_list("__cpu_online_mask"): 105*4882a593Smuzhiyun yield cpu 106*4882a593Smuzhiyun 107*4882a593Smuzhiyun 108*4882a593Smuzhiyundef each_present_cpu(): 109*4882a593Smuzhiyun for cpu in cpu_list("__cpu_present_mask"): 110*4882a593Smuzhiyun yield cpu 111*4882a593Smuzhiyun 112*4882a593Smuzhiyun 113*4882a593Smuzhiyundef each_possible_cpu(): 114*4882a593Smuzhiyun for cpu in cpu_list("__cpu_possible_mask"): 115*4882a593Smuzhiyun yield cpu 116*4882a593Smuzhiyun 117*4882a593Smuzhiyun 118*4882a593Smuzhiyundef each_active_cpu(): 119*4882a593Smuzhiyun for cpu in cpu_list("__cpu_active_mask"): 120*4882a593Smuzhiyun yield cpu 121*4882a593Smuzhiyun 122*4882a593Smuzhiyun 123*4882a593Smuzhiyunclass LxCpus(gdb.Command): 124*4882a593Smuzhiyun """List CPU status arrays 125*4882a593Smuzhiyun 126*4882a593SmuzhiyunDisplays the known state of each CPU based on the kernel masks 127*4882a593Smuzhiyunand can help identify the state of hotplugged CPUs""" 128*4882a593Smuzhiyun 129*4882a593Smuzhiyun def __init__(self): 130*4882a593Smuzhiyun super(LxCpus, self).__init__("lx-cpus", gdb.COMMAND_DATA) 131*4882a593Smuzhiyun 132*4882a593Smuzhiyun def invoke(self, arg, from_tty): 133*4882a593Smuzhiyun gdb.write("Possible CPUs : {}\n".format(list(each_possible_cpu()))) 134*4882a593Smuzhiyun gdb.write("Present CPUs : {}\n".format(list(each_present_cpu()))) 135*4882a593Smuzhiyun gdb.write("Online CPUs : {}\n".format(list(each_online_cpu()))) 136*4882a593Smuzhiyun gdb.write("Active CPUs : {}\n".format(list(each_active_cpu()))) 137*4882a593Smuzhiyun 138*4882a593Smuzhiyun 139*4882a593SmuzhiyunLxCpus() 140*4882a593Smuzhiyun 141*4882a593Smuzhiyun 142*4882a593Smuzhiyunclass PerCpu(gdb.Function): 143*4882a593Smuzhiyun """Return per-cpu variable. 144*4882a593Smuzhiyun 145*4882a593Smuzhiyun$lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the 146*4882a593Smuzhiyungiven CPU number. If CPU is omitted, the CPU of the current context is used. 147*4882a593SmuzhiyunNote that VAR has to be quoted as string.""" 148*4882a593Smuzhiyun 149*4882a593Smuzhiyun def __init__(self): 150*4882a593Smuzhiyun super(PerCpu, self).__init__("lx_per_cpu") 151*4882a593Smuzhiyun 152*4882a593Smuzhiyun def invoke(self, var_name, cpu=-1): 153*4882a593Smuzhiyun var_ptr = gdb.parse_and_eval("&" + var_name.string()) 154*4882a593Smuzhiyun return per_cpu(var_ptr, cpu) 155*4882a593Smuzhiyun 156*4882a593Smuzhiyun 157*4882a593SmuzhiyunPerCpu() 158*4882a593Smuzhiyun 159*4882a593Smuzhiyun 160*4882a593Smuzhiyunclass LxCurrentFunc(gdb.Function): 161*4882a593Smuzhiyun """Return current task. 162*4882a593Smuzhiyun 163*4882a593Smuzhiyun$lx_current([CPU]): Return the per-cpu task variable for the given CPU 164*4882a593Smuzhiyunnumber. If CPU is omitted, the CPU of the current context is used.""" 165*4882a593Smuzhiyun 166*4882a593Smuzhiyun def __init__(self): 167*4882a593Smuzhiyun super(LxCurrentFunc, self).__init__("lx_current") 168*4882a593Smuzhiyun 169*4882a593Smuzhiyun def invoke(self, cpu=-1): 170*4882a593Smuzhiyun var_ptr = gdb.parse_and_eval("¤t_task") 171*4882a593Smuzhiyun return per_cpu(var_ptr, cpu).dereference() 172*4882a593Smuzhiyun 173*4882a593Smuzhiyun 174*4882a593SmuzhiyunLxCurrentFunc() 175