1fe7f9ed9SJan Kiszka# 2fe7f9ed9SJan Kiszka# gdb helper commands and functions for Linux kernel debugging 3fe7f9ed9SJan Kiszka# 4fe7f9ed9SJan Kiszka# per-cpu tools 5fe7f9ed9SJan Kiszka# 6fe7f9ed9SJan Kiszka# Copyright (c) Siemens AG, 2011-2013 7fe7f9ed9SJan Kiszka# 8fe7f9ed9SJan Kiszka# Authors: 9fe7f9ed9SJan Kiszka# Jan Kiszka <[email protected]> 10fe7f9ed9SJan Kiszka# 11fe7f9ed9SJan Kiszka# This work is licensed under the terms of the GNU GPL version 2. 12fe7f9ed9SJan Kiszka# 13fe7f9ed9SJan Kiszka 14fe7f9ed9SJan Kiszkaimport gdb 15fe7f9ed9SJan Kiszka 16fe7f9ed9SJan Kiszkafrom linux import tasks, utils 17fe7f9ed9SJan Kiszka 18fe7f9ed9SJan Kiszka 19526940e3SBarry Songtask_type = utils.CachedType("struct task_struct") 20526940e3SBarry Song 21526940e3SBarry Song 22fe7f9ed9SJan KiszkaMAX_CPUS = 4096 23fe7f9ed9SJan Kiszka 24fe7f9ed9SJan Kiszka 25fe7f9ed9SJan Kiszkadef get_current_cpu(): 26fe7f9ed9SJan Kiszka if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU: 27fe7f9ed9SJan Kiszka return gdb.selected_thread().num - 1 28fe7f9ed9SJan Kiszka elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB: 2940eea5abSFlorian Rommel return gdb.parse_and_eval("kgdb_active.counter") 30fe7f9ed9SJan Kiszka else: 31fe7f9ed9SJan Kiszka raise gdb.GdbError("Sorry, obtaining the current CPU is not yet " 32fe7f9ed9SJan Kiszka "supported with this gdb server.") 33fe7f9ed9SJan Kiszka 34fe7f9ed9SJan Kiszka 35fe7f9ed9SJan Kiszkadef per_cpu(var_ptr, cpu): 36fe7f9ed9SJan Kiszka if cpu == -1: 37fe7f9ed9SJan Kiszka cpu = get_current_cpu() 38fe7f9ed9SJan Kiszka if utils.is_target_arch("sparc:v9"): 39fe7f9ed9SJan Kiszka offset = gdb.parse_and_eval( 40fe7f9ed9SJan Kiszka "trap_block[{0}].__per_cpu_base".format(str(cpu))) 41fe7f9ed9SJan Kiszka else: 42fe7f9ed9SJan Kiszka try: 43fe7f9ed9SJan Kiszka offset = gdb.parse_and_eval( 44fe7f9ed9SJan Kiszka "__per_cpu_offset[{0}]".format(str(cpu))) 45fe7f9ed9SJan Kiszka except gdb.error: 46fe7f9ed9SJan Kiszka # !CONFIG_SMP case 47fe7f9ed9SJan Kiszka offset = 0 48fe7f9ed9SJan Kiszka pointer = var_ptr.cast(utils.get_long_type()) + offset 49*40229188SBrendan Jackman return pointer.cast(var_ptr.type) 50fe7f9ed9SJan Kiszka 51fe7f9ed9SJan Kiszka 523d4cd9c9SJan Kiszkacpu_mask = {} 533d4cd9c9SJan Kiszka 543d4cd9c9SJan Kiszka 553d4cd9c9SJan Kiszkadef cpu_mask_invalidate(event): 563d4cd9c9SJan Kiszka global cpu_mask 573d4cd9c9SJan Kiszka cpu_mask = {} 583d4cd9c9SJan Kiszka gdb.events.stop.disconnect(cpu_mask_invalidate) 593d4cd9c9SJan Kiszka if hasattr(gdb.events, 'new_objfile'): 603d4cd9c9SJan Kiszka gdb.events.new_objfile.disconnect(cpu_mask_invalidate) 613d4cd9c9SJan Kiszka 623d4cd9c9SJan Kiszka 63a77e15e8SJan Kiszkadef cpu_list(mask_name): 643d4cd9c9SJan Kiszka global cpu_mask 65a77e15e8SJan Kiszka mask = None 663d4cd9c9SJan Kiszka if mask_name in cpu_mask: 67a77e15e8SJan Kiszka mask = cpu_mask[mask_name] 68a77e15e8SJan Kiszka if mask is None: 69a77e15e8SJan Kiszka mask = gdb.parse_and_eval(mask_name + ".bits") 703d4cd9c9SJan Kiszka if hasattr(gdb, 'events'): 71a77e15e8SJan Kiszka cpu_mask[mask_name] = mask 723d4cd9c9SJan Kiszka gdb.events.stop.connect(cpu_mask_invalidate) 733d4cd9c9SJan Kiszka if hasattr(gdb.events, 'new_objfile'): 743d4cd9c9SJan Kiszka gdb.events.new_objfile.connect(cpu_mask_invalidate) 75a77e15e8SJan Kiszka bits_per_entry = mask[0].type.sizeof * 8 76a77e15e8SJan Kiszka num_entries = mask.type.sizeof * 8 / bits_per_entry 77a77e15e8SJan Kiszka entry = -1 78a77e15e8SJan Kiszka bits = 0 793d4cd9c9SJan Kiszka 80a77e15e8SJan Kiszka while True: 81a77e15e8SJan Kiszka while bits == 0: 82a77e15e8SJan Kiszka entry += 1 83a77e15e8SJan Kiszka if entry == num_entries: 84a77e15e8SJan Kiszka return 85a77e15e8SJan Kiszka bits = mask[entry] 86a77e15e8SJan Kiszka if bits != 0: 87a77e15e8SJan Kiszka bit = 0 883d4cd9c9SJan Kiszka break 893d4cd9c9SJan Kiszka 90a77e15e8SJan Kiszka while bits & 1 == 0: 91a77e15e8SJan Kiszka bits >>= 1 92a77e15e8SJan Kiszka bit += 1 933d4cd9c9SJan Kiszka 94a77e15e8SJan Kiszka cpu = entry * bits_per_entry + bit 953d4cd9c9SJan Kiszka 96a77e15e8SJan Kiszka bits >>= 1 97a77e15e8SJan Kiszka bit += 1 983d4cd9c9SJan Kiszka 994bc393dbSJan Kiszka yield int(cpu) 100276d97d9SPantelis Koukousoulas 1013d4cd9c9SJan Kiszka 102b1503934SKieran Binghamdef each_online_cpu(): 103b1503934SKieran Bingham for cpu in cpu_list("__cpu_online_mask"): 104b1503934SKieran Bingham yield cpu 105b1503934SKieran Bingham 106b1503934SKieran Bingham 107b1503934SKieran Binghamdef each_present_cpu(): 108b1503934SKieran Bingham for cpu in cpu_list("__cpu_present_mask"): 109b1503934SKieran Bingham yield cpu 110b1503934SKieran Bingham 111b1503934SKieran Bingham 112b1503934SKieran Binghamdef each_possible_cpu(): 113b1503934SKieran Bingham for cpu in cpu_list("__cpu_possible_mask"): 114b1503934SKieran Bingham yield cpu 115b1503934SKieran Bingham 116b1503934SKieran Bingham 117b1503934SKieran Binghamdef each_active_cpu(): 118b1503934SKieran Bingham for cpu in cpu_list("__cpu_active_mask"): 119b1503934SKieran Bingham yield cpu 120b1503934SKieran Bingham 121b1503934SKieran Bingham 122b1503934SKieran Binghamclass LxCpus(gdb.Command): 123b1503934SKieran Bingham """List CPU status arrays 124b1503934SKieran Bingham 125b1503934SKieran BinghamDisplays the known state of each CPU based on the kernel masks 126b1503934SKieran Binghamand can help identify the state of hotplugged CPUs""" 127b1503934SKieran Bingham 128b1503934SKieran Bingham def __init__(self): 129b1503934SKieran Bingham super(LxCpus, self).__init__("lx-cpus", gdb.COMMAND_DATA) 130b1503934SKieran Bingham 131b1503934SKieran Bingham def invoke(self, arg, from_tty): 132b1503934SKieran Bingham gdb.write("Possible CPUs : {}\n".format(list(each_possible_cpu()))) 133b1503934SKieran Bingham gdb.write("Present CPUs : {}\n".format(list(each_present_cpu()))) 134b1503934SKieran Bingham gdb.write("Online CPUs : {}\n".format(list(each_online_cpu()))) 135b1503934SKieran Bingham gdb.write("Active CPUs : {}\n".format(list(each_active_cpu()))) 136b1503934SKieran Bingham 137494dbe02SStephen Boyd 138b1503934SKieran BinghamLxCpus() 139b1503934SKieran Bingham 140b1503934SKieran Bingham 141fe7f9ed9SJan Kiszkaclass PerCpu(gdb.Function): 142fe7f9ed9SJan Kiszka """Return per-cpu variable. 143fe7f9ed9SJan Kiszka 144fe7f9ed9SJan Kiszka$lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the 145fe7f9ed9SJan Kiszkagiven CPU number. If CPU is omitted, the CPU of the current context is used. 146fe7f9ed9SJan KiszkaNote that VAR has to be quoted as string.""" 147fe7f9ed9SJan Kiszka 148fe7f9ed9SJan Kiszka def __init__(self): 149fe7f9ed9SJan Kiszka super(PerCpu, self).__init__("lx_per_cpu") 150fe7f9ed9SJan Kiszka 151db08c53fSFlorian Rommel def invoke(self, var, cpu=-1): 152*40229188SBrendan Jackman return per_cpu(var.address, cpu).dereference() 153fe7f9ed9SJan Kiszka 154fe7f9ed9SJan Kiszka 155fe7f9ed9SJan KiszkaPerCpu() 156116b47b4SJan Kiszka 157*40229188SBrendan Jackman 158*40229188SBrendan Jackmanclass PerCpuPtr(gdb.Function): 159*40229188SBrendan Jackman """Return per-cpu pointer. 160*40229188SBrendan Jackman 161*40229188SBrendan Jackman$lx_per_cpu_ptr("VAR"[, CPU]): Return the per-cpu pointer called VAR for the 162*40229188SBrendan Jackmangiven CPU number. If CPU is omitted, the CPU of the current context is used. 163*40229188SBrendan JackmanNote that VAR has to be quoted as string.""" 164*40229188SBrendan Jackman 165*40229188SBrendan Jackman def __init__(self): 166*40229188SBrendan Jackman super(PerCpuPtr, self).__init__("lx_per_cpu_ptr") 167*40229188SBrendan Jackman 168*40229188SBrendan Jackman def invoke(self, var, cpu=-1): 169*40229188SBrendan Jackman return per_cpu(var, cpu) 170*40229188SBrendan Jackman 171*40229188SBrendan Jackman 172*40229188SBrendan JackmanPerCpuPtr() 173*40229188SBrendan Jackman 174*40229188SBrendan Jackman 175dc958682SBarry Songdef get_current_task(cpu): 176526940e3SBarry Song task_ptr_type = task_type.get_type().pointer() 177526940e3SBarry Song 178dc958682SBarry Song if utils.is_target_arch("x86"): 1796d51363dSGlenn Washburn if gdb.lookup_global_symbol("cpu_tasks"): 1806d51363dSGlenn Washburn # This is a UML kernel, which stores the current task 1816d51363dSGlenn Washburn # differently than other x86 sub architectures 1826d51363dSGlenn Washburn var_ptr = gdb.parse_and_eval("(struct task_struct *)cpu_tasks[0].task") 1836d51363dSGlenn Washburn return var_ptr.dereference() 1846d51363dSGlenn Washburn else: 185c16a3b11SJeff Xie var_ptr = gdb.parse_and_eval("¤t_task") 186dc958682SBarry Song return per_cpu(var_ptr, cpu).dereference() 187526940e3SBarry Song elif utils.is_target_arch("aarch64"): 1884ebc417eSJan Kiszka current_task_addr = gdb.parse_and_eval("(unsigned long)$SP_EL0") 18956fe4870SGlenn Washburn if (current_task_addr >> 63) != 0: 190526940e3SBarry Song current_task = current_task_addr.cast(task_ptr_type) 191526940e3SBarry Song return current_task.dereference() 192526940e3SBarry Song else: 193526940e3SBarry Song raise gdb.GdbError("Sorry, obtaining the current task is not allowed " 194526940e3SBarry Song "while running in userspace(EL0)") 195cd24f440SDeepak Gupta elif utils.is_target_arch("riscv"): 196cd24f440SDeepak Gupta current_tp = gdb.parse_and_eval("$tp") 197cd24f440SDeepak Gupta scratch_reg = gdb.parse_and_eval("$sscratch") 198cd24f440SDeepak Gupta 199cd24f440SDeepak Gupta # by default tp points to current task 200cd24f440SDeepak Gupta current_task = current_tp.cast(task_ptr_type) 201cd24f440SDeepak Gupta 202cd24f440SDeepak Gupta # scratch register is set 0 in trap handler after entering kernel. 203cd24f440SDeepak Gupta # When hart is in user mode, scratch register is pointing to task_struct. 204cd24f440SDeepak Gupta # and tp is used by user mode. So when scratch register holds larger value 205cd24f440SDeepak Gupta # (negative address as ulong is larger value) than tp, then use scratch register. 206cd24f440SDeepak Gupta if (scratch_reg.cast(utils.get_ulong_type()) > current_tp.cast(utils.get_ulong_type())): 207cd24f440SDeepak Gupta current_task = scratch_reg.cast(task_ptr_type) 208cd24f440SDeepak Gupta 209cd24f440SDeepak Gupta return current_task.dereference() 210dc958682SBarry Song else: 211dc958682SBarry Song raise gdb.GdbError("Sorry, obtaining the current task is not yet " 212dc958682SBarry Song "supported with this arch") 213116b47b4SJan Kiszka 214116b47b4SJan Kiszkaclass LxCurrentFunc(gdb.Function): 215116b47b4SJan Kiszka """Return current task. 216116b47b4SJan Kiszka 217116b47b4SJan Kiszka$lx_current([CPU]): Return the per-cpu task variable for the given CPU 218116b47b4SJan Kiszkanumber. If CPU is omitted, the CPU of the current context is used.""" 219116b47b4SJan Kiszka 220116b47b4SJan Kiszka def __init__(self): 221116b47b4SJan Kiszka super(LxCurrentFunc, self).__init__("lx_current") 222116b47b4SJan Kiszka 223116b47b4SJan Kiszka def invoke(self, cpu=-1): 224dc958682SBarry Song return get_current_task(cpu) 225116b47b4SJan Kiszka 226116b47b4SJan Kiszka 227116b47b4SJan KiszkaLxCurrentFunc() 228