1# 2# gdb helper commands and functions for Linux kernel debugging 3# 4# per-cpu tools 5# 6# Copyright (c) Siemens AG, 2011-2013 7# 8# Authors: 9# Jan Kiszka <jan.kiszka@siemens.com> 10# 11# This work is licensed under the terms of the GNU GPL version 2. 12# 13 14import gdb 15 16from linux import tasks, utils 17 18 19MAX_CPUS = 4096 20 21 22def get_current_cpu(): 23 if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU: 24 return gdb.selected_thread().num - 1 25 elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB: 26 tid = gdb.selected_thread().ptid[2] 27 if tid > (0x100000000 - MAX_CPUS - 2): 28 return 0x100000000 - tid - 2 29 else: 30 return tasks.get_thread_info(tasks.get_task_by_pid(tid))['cpu'] 31 else: 32 raise gdb.GdbError("Sorry, obtaining the current CPU is not yet " 33 "supported with this gdb server.") 34 35 36def per_cpu(var_ptr, cpu): 37 if cpu == -1: 38 cpu = get_current_cpu() 39 if utils.is_target_arch("sparc:v9"): 40 offset = gdb.parse_and_eval( 41 "trap_block[{0}].__per_cpu_base".format(str(cpu))) 42 else: 43 try: 44 offset = gdb.parse_and_eval( 45 "__per_cpu_offset[{0}]".format(str(cpu))) 46 except gdb.error: 47 # !CONFIG_SMP case 48 offset = 0 49 pointer = var_ptr.cast(utils.get_long_type()) + offset 50 return pointer.cast(var_ptr.type).dereference() 51 52 53cpu_mask = {} 54 55 56def cpu_mask_invalidate(event): 57 global cpu_mask 58 cpu_mask = {} 59 gdb.events.stop.disconnect(cpu_mask_invalidate) 60 if hasattr(gdb.events, 'new_objfile'): 61 gdb.events.new_objfile.disconnect(cpu_mask_invalidate) 62 63 64def cpu_list(mask_name): 65 global cpu_mask 66 mask = None 67 if mask_name in cpu_mask: 68 mask = cpu_mask[mask_name] 69 if mask is None: 70 mask = gdb.parse_and_eval(mask_name + ".bits") 71 if hasattr(gdb, 'events'): 72 cpu_mask[mask_name] = mask 73 gdb.events.stop.connect(cpu_mask_invalidate) 74 if hasattr(gdb.events, 'new_objfile'): 75 gdb.events.new_objfile.connect(cpu_mask_invalidate) 76 bits_per_entry = mask[0].type.sizeof * 8 77 num_entries = mask.type.sizeof * 8 / bits_per_entry 78 entry = -1 79 bits = 0 80 81 while True: 82 while bits == 0: 83 entry += 1 84 if entry == num_entries: 85 return 86 bits = mask[entry] 87 if bits != 0: 88 bit = 0 89 break 90 91 while bits & 1 == 0: 92 bits >>= 1 93 bit += 1 94 95 cpu = entry * bits_per_entry + bit 96 97 bits >>= 1 98 bit += 1 99 100 yield cpu 101 102 103class PerCpu(gdb.Function): 104 """Return per-cpu variable. 105 106$lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the 107given CPU number. If CPU is omitted, the CPU of the current context is used. 108Note that VAR has to be quoted as string.""" 109 110 def __init__(self): 111 super(PerCpu, self).__init__("lx_per_cpu") 112 113 def invoke(self, var_name, cpu=-1): 114 var_ptr = gdb.parse_and_eval("&" + var_name.string()) 115 return per_cpu(var_ptr, cpu) 116 117 118PerCpu() 119 120 121class LxCurrentFunc(gdb.Function): 122 """Return current task. 123 124$lx_current([CPU]): Return the per-cpu task variable for the given CPU 125number. If CPU is omitted, the CPU of the current context is used.""" 126 127 def __init__(self): 128 super(LxCurrentFunc, self).__init__("lx_current") 129 130 def invoke(self, cpu=-1): 131 var_ptr = gdb.parse_and_eval("¤t_task") 132 return per_cpu(var_ptr, cpu).dereference() 133 134 135LxCurrentFunc() 136