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 tid = gdb.selected_thread().ptid[2] >> 30 if tid > (0x100000000 - MAX_CPUS - 2): >> 31 return 0x100000000 - tid - 2 >> 32 else: >> 33 return tasks.get_thread_info(tasks.get_task_by_pid(tid))['cpu'] 30 else: 34 else: 31 raise gdb.GdbError("Sorry, obtaining t 35 raise gdb.GdbError("Sorry, obtaining the current CPU is not yet " 32 "supported with thi 36 "supported with this gdb server.") 33 37 34 38 35 def per_cpu(var_ptr, cpu): 39 def per_cpu(var_ptr, cpu): 36 if cpu == -1: 40 if cpu == -1: 37 cpu = get_current_cpu() 41 cpu = get_current_cpu() 38 if utils.is_target_arch("sparc:v9"): 42 if utils.is_target_arch("sparc:v9"): 39 offset = gdb.parse_and_eval( 43 offset = gdb.parse_and_eval( 40 "trap_block[{0}].__per_cpu_base".f 44 "trap_block[{0}].__per_cpu_base".format(str(cpu))) 41 else: 45 else: 42 try: 46 try: 43 offset = gdb.parse_and_eval( 47 offset = gdb.parse_and_eval( 44 "__per_cpu_offset[{0}]".format 48 "__per_cpu_offset[{0}]".format(str(cpu))) 45 except gdb.error: 49 except gdb.error: 46 # !CONFIG_SMP case 50 # !CONFIG_SMP case 47 offset = 0 51 offset = 0 48 pointer = var_ptr.cast(utils.get_long_type 52 pointer = var_ptr.cast(utils.get_long_type()) + offset 49 return pointer.cast(var_ptr.type).derefere 53 return pointer.cast(var_ptr.type).dereference() 50 54 51 55 52 cpu_mask = {} 56 cpu_mask = {} 53 57 54 58 55 def cpu_mask_invalidate(event): 59 def cpu_mask_invalidate(event): 56 global cpu_mask 60 global cpu_mask 57 cpu_mask = {} 61 cpu_mask = {} 58 gdb.events.stop.disconnect(cpu_mask_invali 62 gdb.events.stop.disconnect(cpu_mask_invalidate) 59 if hasattr(gdb.events, 'new_objfile'): 63 if hasattr(gdb.events, 'new_objfile'): 60 gdb.events.new_objfile.disconnect(cpu_ 64 gdb.events.new_objfile.disconnect(cpu_mask_invalidate) 61 65 62 66 63 def cpu_list(mask_name): 67 def cpu_list(mask_name): 64 global cpu_mask 68 global cpu_mask 65 mask = None 69 mask = None 66 if mask_name in cpu_mask: 70 if mask_name in cpu_mask: 67 mask = cpu_mask[mask_name] 71 mask = cpu_mask[mask_name] 68 if mask is None: 72 if mask is None: 69 mask = gdb.parse_and_eval(mask_name + 73 mask = gdb.parse_and_eval(mask_name + ".bits") 70 if hasattr(gdb, 'events'): 74 if hasattr(gdb, 'events'): 71 cpu_mask[mask_name] = mask 75 cpu_mask[mask_name] = mask 72 gdb.events.stop.connect(cpu_mask_i 76 gdb.events.stop.connect(cpu_mask_invalidate) 73 if hasattr(gdb.events, 'new_objfil 77 if hasattr(gdb.events, 'new_objfile'): 74 gdb.events.new_objfile.connect 78 gdb.events.new_objfile.connect(cpu_mask_invalidate) 75 bits_per_entry = mask[0].type.sizeof * 8 79 bits_per_entry = mask[0].type.sizeof * 8 76 num_entries = mask.type.sizeof * 8 / bits_ 80 num_entries = mask.type.sizeof * 8 / bits_per_entry 77 entry = -1 81 entry = -1 78 bits = 0 82 bits = 0 79 83 80 while True: 84 while True: 81 while bits == 0: 85 while bits == 0: 82 entry += 1 86 entry += 1 83 if entry == num_entries: 87 if entry == num_entries: 84 return 88 return 85 bits = mask[entry] 89 bits = mask[entry] 86 if bits != 0: 90 if bits != 0: 87 bit = 0 91 bit = 0 88 break 92 break 89 93 90 while bits & 1 == 0: 94 while bits & 1 == 0: 91 bits >>= 1 95 bits >>= 1 92 bit += 1 96 bit += 1 93 97 94 cpu = entry * bits_per_entry + bit 98 cpu = entry * bits_per_entry + bit 95 99 96 bits >>= 1 100 bits >>= 1 97 bit += 1 101 bit += 1 98 102 99 yield int(cpu) 103 yield int(cpu) 100 104 101 105 102 def each_online_cpu(): 106 def each_online_cpu(): 103 for cpu in cpu_list("__cpu_online_mask"): 107 for cpu in cpu_list("__cpu_online_mask"): 104 yield cpu 108 yield cpu 105 109 106 110 107 def each_present_cpu(): 111 def each_present_cpu(): 108 for cpu in cpu_list("__cpu_present_mask"): 112 for cpu in cpu_list("__cpu_present_mask"): 109 yield cpu 113 yield cpu 110 114 111 115 112 def each_possible_cpu(): 116 def each_possible_cpu(): 113 for cpu in cpu_list("__cpu_possible_mask") 117 for cpu in cpu_list("__cpu_possible_mask"): 114 yield cpu 118 yield cpu 115 119 116 120 117 def each_active_cpu(): 121 def each_active_cpu(): 118 for cpu in cpu_list("__cpu_active_mask"): 122 for cpu in cpu_list("__cpu_active_mask"): 119 yield cpu 123 yield cpu 120 124 121 125 122 class LxCpus(gdb.Command): 126 class LxCpus(gdb.Command): 123 """List CPU status arrays 127 """List CPU status arrays 124 128 125 Displays the known state of each CPU based on 129 Displays the known state of each CPU based on the kernel masks 126 and can help identify the state of hotplugged 130 and can help identify the state of hotplugged CPUs""" 127 131 128 def __init__(self): 132 def __init__(self): 129 super(LxCpus, self).__init__("lx-cpus" 133 super(LxCpus, self).__init__("lx-cpus", gdb.COMMAND_DATA) 130 134 131 def invoke(self, arg, from_tty): 135 def invoke(self, arg, from_tty): 132 gdb.write("Possible CPUs : {}\n".forma 136 gdb.write("Possible CPUs : {}\n".format(list(each_possible_cpu()))) 133 gdb.write("Present CPUs : {}\n".forma 137 gdb.write("Present CPUs : {}\n".format(list(each_present_cpu()))) 134 gdb.write("Online CPUs : {}\n".forma 138 gdb.write("Online CPUs : {}\n".format(list(each_online_cpu()))) 135 gdb.write("Active CPUs : {}\n".forma 139 gdb.write("Active CPUs : {}\n".format(list(each_active_cpu()))) 136 140 137 141 138 LxCpus() 142 LxCpus() 139 143 140 144 141 class PerCpu(gdb.Function): 145 class PerCpu(gdb.Function): 142 """Return per-cpu variable. 146 """Return per-cpu variable. 143 147 144 $lx_per_cpu("VAR"[, CPU]): Return the per-cpu 148 $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 149 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.""" 150 Note that VAR has to be quoted as string.""" 147 151 148 def __init__(self): 152 def __init__(self): 149 super(PerCpu, self).__init__("lx_per_c 153 super(PerCpu, self).__init__("lx_per_cpu") 150 154 151 def invoke(self, var, cpu=-1): !! 155 def invoke(self, var_name, cpu=-1): 152 return per_cpu(var.address, cpu) !! 156 var_ptr = gdb.parse_and_eval("&" + var_name.string()) >> 157 return per_cpu(var_ptr, cpu) 153 158 154 159 155 PerCpu() 160 PerCpu() 156 161 157 def get_current_task(cpu): 162 def get_current_task(cpu): 158 task_ptr_type = task_type.get_type().point 163 task_ptr_type = task_type.get_type().pointer() 159 164 160 if utils.is_target_arch("x86"): 165 if utils.is_target_arch("x86"): 161 if gdb.lookup_global_symbol("cpu_tasks !! 166 var_ptr = gdb.parse_and_eval("&pcpu_hot.current_task") 162 # This is a UML kernel, which stor !! 167 return per_cpu(var_ptr, cpu).dereference() 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"): 168 elif utils.is_target_arch("aarch64"): 170 current_task_addr = gdb.parse_and_eval !! 169 current_task_addr = gdb.parse_and_eval("$SP_EL0") 171 if (current_task_addr >> 63) != 0: !! 170 if((current_task_addr >> 63) != 0): 172 current_task = current_task_addr.c !! 171 current_task = current_task_addr.cast(task_ptr_type) 173 return current_task.dereference() !! 172 return current_task.dereference() 174 else: !! 173 else: 175 raise gdb.GdbError("Sorry, obtaini !! 174 raise gdb.GdbError("Sorry, obtaining the current task is not allowed " 176 "while running !! 175 "while running in userspace(EL0)") 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: 176 else: 193 raise gdb.GdbError("Sorry, obtaining t 177 raise gdb.GdbError("Sorry, obtaining the current task is not yet " 194 "supported with thi 178 "supported with this arch") 195 179 196 class LxCurrentFunc(gdb.Function): 180 class LxCurrentFunc(gdb.Function): 197 """Return current task. 181 """Return current task. 198 182 199 $lx_current([CPU]): Return the per-cpu task va 183 $lx_current([CPU]): Return the per-cpu task variable for the given CPU 200 number. If CPU is omitted, the CPU of the curr 184 number. If CPU is omitted, the CPU of the current context is used.""" 201 185 202 def __init__(self): 186 def __init__(self): 203 super(LxCurrentFunc, self).__init__("l 187 super(LxCurrentFunc, self).__init__("lx_current") 204 188 205 def invoke(self, cpu=-1): 189 def invoke(self, cpu=-1): 206 return get_current_task(cpu) 190 return get_current_task(cpu) 207 191 208 192 209 LxCurrentFunc() 193 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.