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 << 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 100 yield cpu 120 101 121 102 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): 103 class PerCpu(gdb.Function): 142 """Return per-cpu variable. 104 """Return per-cpu variable. 143 105 144 $lx_per_cpu("VAR"[, CPU]): Return the per-cpu 106 $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 107 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.""" 108 Note that VAR has to be quoted as string.""" 147 109 148 def __init__(self): 110 def __init__(self): 149 super(PerCpu, self).__init__("lx_per_c 111 super(PerCpu, self).__init__("lx_per_cpu") 150 112 151 def invoke(self, var, cpu=-1): !! 113 def invoke(self, var_name, cpu=-1): 152 return per_cpu(var.address, cpu) !! 114 var_ptr = gdb.parse_and_eval("&" + var_name.string()) >> 115 return per_cpu(var_ptr, cpu) 153 116 154 117 155 PerCpu() 118 PerCpu() 156 119 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 120 196 class LxCurrentFunc(gdb.Function): 121 class LxCurrentFunc(gdb.Function): 197 """Return current task. 122 """Return current task. 198 123 199 $lx_current([CPU]): Return the per-cpu task va 124 $lx_current([CPU]): Return the per-cpu task variable for the given CPU 200 number. If CPU is omitted, the CPU of the curr 125 number. If CPU is omitted, the CPU of the current context is used.""" 201 126 202 def __init__(self): 127 def __init__(self): 203 super(LxCurrentFunc, self).__init__("l 128 super(LxCurrentFunc, self).__init__("lx_current") 204 129 205 def invoke(self, cpu=-1): 130 def invoke(self, cpu=-1): 206 return get_current_task(cpu) !! 131 var_ptr = gdb.parse_and_eval("¤t_task") >> 132 return per_cpu(var_ptr, cpu).dereference() 207 133 208 134 209 LxCurrentFunc() 135 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.