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 <jan.kiszka@siemens.com> 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: 29*40eea5abSFlorian 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 49fe7f9ed9SJan Kiszka return pointer.cast(var_ptr.type).dereference() 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): 152db08c53fSFlorian Rommel return per_cpu(var.address, cpu) 153fe7f9ed9SJan Kiszka 154fe7f9ed9SJan Kiszka 155fe7f9ed9SJan KiszkaPerCpu() 156116b47b4SJan Kiszka 157dc958682SBarry Songdef get_current_task(cpu): 158526940e3SBarry Song task_ptr_type = task_type.get_type().pointer() 159526940e3SBarry Song 160dc958682SBarry Song if utils.is_target_arch("x86"): 1616d51363dSGlenn Washburn if gdb.lookup_global_symbol("cpu_tasks"): 1626d51363dSGlenn Washburn # This is a UML kernel, which stores the current task 1636d51363dSGlenn Washburn # differently than other x86 sub architectures 1646d51363dSGlenn Washburn var_ptr = gdb.parse_and_eval("(struct task_struct *)cpu_tasks[0].task") 1656d51363dSGlenn Washburn return var_ptr.dereference() 1666d51363dSGlenn Washburn else: 167c16a3b11SJeff Xie var_ptr = gdb.parse_and_eval("&pcpu_hot.current_task") 168dc958682SBarry Song return per_cpu(var_ptr, cpu).dereference() 169526940e3SBarry Song elif utils.is_target_arch("aarch64"): 170526940e3SBarry Song current_task_addr = gdb.parse_and_eval("$SP_EL0") 17156fe4870SGlenn Washburn if (current_task_addr >> 63) != 0: 172526940e3SBarry Song current_task = current_task_addr.cast(task_ptr_type) 173526940e3SBarry Song return current_task.dereference() 174526940e3SBarry Song else: 175526940e3SBarry Song raise gdb.GdbError("Sorry, obtaining the current task is not allowed " 176526940e3SBarry Song "while running in userspace(EL0)") 177cd24f440SDeepak Gupta elif utils.is_target_arch("riscv"): 178cd24f440SDeepak Gupta current_tp = gdb.parse_and_eval("$tp") 179cd24f440SDeepak Gupta scratch_reg = gdb.parse_and_eval("$sscratch") 180cd24f440SDeepak Gupta 181cd24f440SDeepak Gupta # by default tp points to current task 182cd24f440SDeepak Gupta current_task = current_tp.cast(task_ptr_type) 183cd24f440SDeepak Gupta 184cd24f440SDeepak Gupta # scratch register is set 0 in trap handler after entering kernel. 185cd24f440SDeepak Gupta # When hart is in user mode, scratch register is pointing to task_struct. 186cd24f440SDeepak Gupta # and tp is used by user mode. So when scratch register holds larger value 187cd24f440SDeepak Gupta # (negative address as ulong is larger value) than tp, then use scratch register. 188cd24f440SDeepak Gupta if (scratch_reg.cast(utils.get_ulong_type()) > current_tp.cast(utils.get_ulong_type())): 189cd24f440SDeepak Gupta current_task = scratch_reg.cast(task_ptr_type) 190cd24f440SDeepak Gupta 191cd24f440SDeepak Gupta return current_task.dereference() 192dc958682SBarry Song else: 193dc958682SBarry Song raise gdb.GdbError("Sorry, obtaining the current task is not yet " 194dc958682SBarry Song "supported with this arch") 195116b47b4SJan Kiszka 196116b47b4SJan Kiszkaclass LxCurrentFunc(gdb.Function): 197116b47b4SJan Kiszka """Return current task. 198116b47b4SJan Kiszka 199116b47b4SJan Kiszka$lx_current([CPU]): Return the per-cpu task variable for the given CPU 200116b47b4SJan Kiszkanumber. If CPU is omitted, the CPU of the current context is used.""" 201116b47b4SJan Kiszka 202116b47b4SJan Kiszka def __init__(self): 203116b47b4SJan Kiszka super(LxCurrentFunc, self).__init__("lx_current") 204116b47b4SJan Kiszka 205116b47b4SJan Kiszka def invoke(self, cpu=-1): 206dc958682SBarry Song return get_current_task(cpu) 207116b47b4SJan Kiszka 208116b47b4SJan Kiszka 209116b47b4SJan KiszkaLxCurrentFunc() 210