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