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