1 # 2 # gdb helper commands and functions for Linux 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 12 # 13 14 import gdb 15 16 from linux import tasks, utils 17 18 19 task_type = utils.CachedType("struct task_stru 20 21 22 MAX_CPUS = 4096 23 24 25 def get_current_cpu(): 26 if utils.get_gdbserver_type() == utils.GDB 27 return gdb.selected_thread().num - 1 28 elif utils.get_gdbserver_type() == utils.G 29 return gdb.parse_and_eval("kgdb_active 30 else: 31 raise gdb.GdbError("Sorry, obtaining t 32 "supported with thi 33 34 35 def per_cpu(var_ptr, cpu): 36 if cpu == -1: 37 cpu = get_current_cpu() 38 if utils.is_target_arch("sparc:v9"): 39 offset = gdb.parse_and_eval( 40 "trap_block[{0}].__per_cpu_base".f 41 else: 42 try: 43 offset = gdb.parse_and_eval( 44 "__per_cpu_offset[{0}]".format 45 except gdb.error: 46 # !CONFIG_SMP case 47 offset = 0 48 pointer = var_ptr.cast(utils.get_long_type 49 return pointer.cast(var_ptr.type).derefere 50 51 52 cpu_mask = {} 53 54 55 def cpu_mask_invalidate(event): 56 global cpu_mask 57 cpu_mask = {} 58 gdb.events.stop.disconnect(cpu_mask_invali 59 if hasattr(gdb.events, 'new_objfile'): 60 gdb.events.new_objfile.disconnect(cpu_ 61 62 63 def cpu_list(mask_name): 64 global cpu_mask 65 mask = None 66 if mask_name in cpu_mask: 67 mask = cpu_mask[mask_name] 68 if mask is None: 69 mask = gdb.parse_and_eval(mask_name + 70 if hasattr(gdb, 'events'): 71 cpu_mask[mask_name] = mask 72 gdb.events.stop.connect(cpu_mask_i 73 if hasattr(gdb.events, 'new_objfil 74 gdb.events.new_objfile.connect 75 bits_per_entry = mask[0].type.sizeof * 8 76 num_entries = mask.type.sizeof * 8 / bits_ 77 entry = -1 78 bits = 0 79 80 while True: 81 while bits == 0: 82 entry += 1 83 if entry == num_entries: 84 return 85 bits = mask[entry] 86 if bits != 0: 87 bit = 0 88 break 89 90 while bits & 1 == 0: 91 bits >>= 1 92 bit += 1 93 94 cpu = entry * bits_per_entry + bit 95 96 bits >>= 1 97 bit += 1 98 99 yield int(cpu) 100 101 102 def each_online_cpu(): 103 for cpu in cpu_list("__cpu_online_mask"): 104 yield cpu 105 106 107 def each_present_cpu(): 108 for cpu in cpu_list("__cpu_present_mask"): 109 yield cpu 110 111 112 def each_possible_cpu(): 113 for cpu in cpu_list("__cpu_possible_mask") 114 yield cpu 115 116 117 def each_active_cpu(): 118 for cpu in cpu_list("__cpu_active_mask"): 119 yield cpu 120 121 122 class LxCpus(gdb.Command): 123 """List CPU status arrays 124 125 Displays the known state of each CPU based on 126 and can help identify the state of hotplugged 127 128 def __init__(self): 129 super(LxCpus, self).__init__("lx-cpus" 130 131 def invoke(self, arg, from_tty): 132 gdb.write("Possible CPUs : {}\n".forma 133 gdb.write("Present CPUs : {}\n".forma 134 gdb.write("Online CPUs : {}\n".forma 135 gdb.write("Active CPUs : {}\n".forma 136 137 138 LxCpus() 139 140 141 class PerCpu(gdb.Function): 142 """Return per-cpu variable. 143 144 $lx_per_cpu("VAR"[, CPU]): Return the per-cpu 145 given CPU number. If CPU is omitted, the CPU o 146 Note that VAR has to be quoted as string.""" 147 148 def __init__(self): 149 super(PerCpu, self).__init__("lx_per_c 150 151 def invoke(self, var, cpu=-1): 152 return per_cpu(var.address, cpu) 153 154 155 PerCpu() 156 157 def get_current_task(cpu): 158 task_ptr_type = task_type.get_type().point 159 160 if utils.is_target_arch("x86"): 161 if gdb.lookup_global_symbol("cpu_tasks 162 # This is a UML kernel, which stor 163 # differently than other x86 sub a 164 var_ptr = gdb.parse_and_eval("(str 165 return var_ptr.dereference() 166 else: 167 var_ptr = gdb.parse_and_eval("&pcp 168 return per_cpu(var_ptr, cpu).deref 169 elif utils.is_target_arch("aarch64"): 170 current_task_addr = gdb.parse_and_eval 171 if (current_task_addr >> 63) != 0: 172 current_task = current_task_addr.c 173 return current_task.dereference() 174 else: 175 raise gdb.GdbError("Sorry, obtaini 176 "while running 177 elif utils.is_target_arch("riscv"): 178 current_tp = gdb.parse_and_eval("$tp") 179 scratch_reg = gdb.parse_and_eval("$ssc 180 181 # by default tp points to current task 182 current_task = current_tp.cast(task_pt 183 184 # scratch register is set 0 in trap ha 185 # When hart is in user mode, scratch r 186 # and tp is used by user mode. So when 187 # (negative address as ulong is larger 188 if (scratch_reg.cast(utils.get_ulong_t 189 current_task = scratch_reg.cast(ta 190 191 return current_task.dereference() 192 else: 193 raise gdb.GdbError("Sorry, obtaining t 194 "supported with thi 195 196 class LxCurrentFunc(gdb.Function): 197 """Return current task. 198 199 $lx_current([CPU]): Return the per-cpu task va 200 number. If CPU is omitted, the CPU of the curr 201 202 def __init__(self): 203 super(LxCurrentFunc, self).__init__("l 204 205 def invoke(self, cpu=-1): 206 return get_current_task(cpu) 207 208 209 LxCurrentFunc()
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.