xref: /linux/scripts/gdb/linux/cpus.py (revision 40eea5ab)
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