xref: /linux/scripts/gdb/linux/cpus.py (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
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:
29fe7f9ed9SJan Kiszka        tid = gdb.selected_thread().ptid[2]
30fe7f9ed9SJan Kiszka        if tid > (0x100000000 - MAX_CPUS - 2):
31fe7f9ed9SJan Kiszka            return 0x100000000 - tid - 2
32fe7f9ed9SJan Kiszka        else:
33fe7f9ed9SJan Kiszka            return tasks.get_thread_info(tasks.get_task_by_pid(tid))['cpu']
34fe7f9ed9SJan Kiszka    else:
35fe7f9ed9SJan Kiszka        raise gdb.GdbError("Sorry, obtaining the current CPU is not yet "
36fe7f9ed9SJan Kiszka                           "supported with this gdb server.")
37fe7f9ed9SJan Kiszka
38fe7f9ed9SJan Kiszka
39fe7f9ed9SJan Kiszkadef per_cpu(var_ptr, cpu):
40fe7f9ed9SJan Kiszka    if cpu == -1:
41fe7f9ed9SJan Kiszka        cpu = get_current_cpu()
42fe7f9ed9SJan Kiszka    if utils.is_target_arch("sparc:v9"):
43fe7f9ed9SJan Kiszka        offset = gdb.parse_and_eval(
44fe7f9ed9SJan Kiszka            "trap_block[{0}].__per_cpu_base".format(str(cpu)))
45fe7f9ed9SJan Kiszka    else:
46fe7f9ed9SJan Kiszka        try:
47fe7f9ed9SJan Kiszka            offset = gdb.parse_and_eval(
48fe7f9ed9SJan Kiszka                "__per_cpu_offset[{0}]".format(str(cpu)))
49fe7f9ed9SJan Kiszka        except gdb.error:
50fe7f9ed9SJan Kiszka            # !CONFIG_SMP case
51fe7f9ed9SJan Kiszka            offset = 0
52fe7f9ed9SJan Kiszka    pointer = var_ptr.cast(utils.get_long_type()) + offset
53fe7f9ed9SJan Kiszka    return pointer.cast(var_ptr.type).dereference()
54fe7f9ed9SJan Kiszka
55fe7f9ed9SJan Kiszka
563d4cd9c9SJan Kiszkacpu_mask = {}
573d4cd9c9SJan Kiszka
583d4cd9c9SJan Kiszka
593d4cd9c9SJan Kiszkadef cpu_mask_invalidate(event):
603d4cd9c9SJan Kiszka    global cpu_mask
613d4cd9c9SJan Kiszka    cpu_mask = {}
623d4cd9c9SJan Kiszka    gdb.events.stop.disconnect(cpu_mask_invalidate)
633d4cd9c9SJan Kiszka    if hasattr(gdb.events, 'new_objfile'):
643d4cd9c9SJan Kiszka        gdb.events.new_objfile.disconnect(cpu_mask_invalidate)
653d4cd9c9SJan Kiszka
663d4cd9c9SJan Kiszka
67a77e15e8SJan Kiszkadef cpu_list(mask_name):
683d4cd9c9SJan Kiszka    global cpu_mask
69a77e15e8SJan Kiszka    mask = None
703d4cd9c9SJan Kiszka    if mask_name in cpu_mask:
71a77e15e8SJan Kiszka        mask = cpu_mask[mask_name]
72a77e15e8SJan Kiszka    if mask is None:
73a77e15e8SJan Kiszka        mask = gdb.parse_and_eval(mask_name + ".bits")
743d4cd9c9SJan Kiszka        if hasattr(gdb, 'events'):
75a77e15e8SJan Kiszka            cpu_mask[mask_name] = mask
763d4cd9c9SJan Kiszka            gdb.events.stop.connect(cpu_mask_invalidate)
773d4cd9c9SJan Kiszka            if hasattr(gdb.events, 'new_objfile'):
783d4cd9c9SJan Kiszka                gdb.events.new_objfile.connect(cpu_mask_invalidate)
79a77e15e8SJan Kiszka    bits_per_entry = mask[0].type.sizeof * 8
80a77e15e8SJan Kiszka    num_entries = mask.type.sizeof * 8 / bits_per_entry
81a77e15e8SJan Kiszka    entry = -1
82a77e15e8SJan Kiszka    bits = 0
833d4cd9c9SJan Kiszka
84a77e15e8SJan Kiszka    while True:
85a77e15e8SJan Kiszka        while bits == 0:
86a77e15e8SJan Kiszka            entry += 1
87a77e15e8SJan Kiszka            if entry == num_entries:
88a77e15e8SJan Kiszka                return
89a77e15e8SJan Kiszka            bits = mask[entry]
90a77e15e8SJan Kiszka            if bits != 0:
91a77e15e8SJan Kiszka                bit = 0
923d4cd9c9SJan Kiszka                break
933d4cd9c9SJan Kiszka
94a77e15e8SJan Kiszka        while bits & 1 == 0:
95a77e15e8SJan Kiszka            bits >>= 1
96a77e15e8SJan Kiszka            bit += 1
973d4cd9c9SJan Kiszka
98a77e15e8SJan Kiszka        cpu = entry * bits_per_entry + bit
993d4cd9c9SJan Kiszka
100a77e15e8SJan Kiszka        bits >>= 1
101a77e15e8SJan Kiszka        bit += 1
1023d4cd9c9SJan Kiszka
1034bc393dbSJan Kiszka        yield int(cpu)
104276d97d9SPantelis Koukousoulas
1053d4cd9c9SJan Kiszka
106b1503934SKieran Binghamdef each_online_cpu():
107b1503934SKieran Bingham    for cpu in cpu_list("__cpu_online_mask"):
108b1503934SKieran Bingham        yield cpu
109b1503934SKieran Bingham
110b1503934SKieran Bingham
111b1503934SKieran Binghamdef each_present_cpu():
112b1503934SKieran Bingham    for cpu in cpu_list("__cpu_present_mask"):
113b1503934SKieran Bingham        yield cpu
114b1503934SKieran Bingham
115b1503934SKieran Bingham
116b1503934SKieran Binghamdef each_possible_cpu():
117b1503934SKieran Bingham    for cpu in cpu_list("__cpu_possible_mask"):
118b1503934SKieran Bingham        yield cpu
119b1503934SKieran Bingham
120b1503934SKieran Bingham
121b1503934SKieran Binghamdef each_active_cpu():
122b1503934SKieran Bingham    for cpu in cpu_list("__cpu_active_mask"):
123b1503934SKieran Bingham        yield cpu
124b1503934SKieran Bingham
125b1503934SKieran Bingham
126b1503934SKieran Binghamclass LxCpus(gdb.Command):
127b1503934SKieran Bingham    """List CPU status arrays
128b1503934SKieran Bingham
129b1503934SKieran BinghamDisplays the known state of each CPU based on the kernel masks
130b1503934SKieran Binghamand can help identify the state of hotplugged CPUs"""
131b1503934SKieran Bingham
132b1503934SKieran Bingham    def __init__(self):
133b1503934SKieran Bingham        super(LxCpus, self).__init__("lx-cpus", gdb.COMMAND_DATA)
134b1503934SKieran Bingham
135b1503934SKieran Bingham    def invoke(self, arg, from_tty):
136b1503934SKieran Bingham        gdb.write("Possible CPUs : {}\n".format(list(each_possible_cpu())))
137b1503934SKieran Bingham        gdb.write("Present CPUs  : {}\n".format(list(each_present_cpu())))
138b1503934SKieran Bingham        gdb.write("Online CPUs   : {}\n".format(list(each_online_cpu())))
139b1503934SKieran Bingham        gdb.write("Active CPUs   : {}\n".format(list(each_active_cpu())))
140b1503934SKieran Bingham
141494dbe02SStephen Boyd
142b1503934SKieran BinghamLxCpus()
143b1503934SKieran Bingham
144b1503934SKieran Bingham
145fe7f9ed9SJan Kiszkaclass PerCpu(gdb.Function):
146fe7f9ed9SJan Kiszka    """Return per-cpu variable.
147fe7f9ed9SJan Kiszka
148fe7f9ed9SJan Kiszka$lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the
149fe7f9ed9SJan Kiszkagiven CPU number. If CPU is omitted, the CPU of the current context is used.
150fe7f9ed9SJan KiszkaNote that VAR has to be quoted as string."""
151fe7f9ed9SJan Kiszka
152fe7f9ed9SJan Kiszka    def __init__(self):
153fe7f9ed9SJan Kiszka        super(PerCpu, self).__init__("lx_per_cpu")
154fe7f9ed9SJan Kiszka
155fe7f9ed9SJan Kiszka    def invoke(self, var_name, cpu=-1):
156fe7f9ed9SJan Kiszka        var_ptr = gdb.parse_and_eval("&" + var_name.string())
157fe7f9ed9SJan Kiszka        return per_cpu(var_ptr, cpu)
158fe7f9ed9SJan Kiszka
159fe7f9ed9SJan Kiszka
160fe7f9ed9SJan KiszkaPerCpu()
161116b47b4SJan Kiszka
162dc958682SBarry Songdef get_current_task(cpu):
163526940e3SBarry Song    task_ptr_type = task_type.get_type().pointer()
164526940e3SBarry Song
165dc958682SBarry Song    if utils.is_target_arch("x86"):
1666d51363dSGlenn Washburn        if gdb.lookup_global_symbol("cpu_tasks"):
1676d51363dSGlenn Washburn            # This is a UML kernel, which stores the current task
1686d51363dSGlenn Washburn            # differently than other x86 sub architectures
1696d51363dSGlenn Washburn            var_ptr = gdb.parse_and_eval("(struct task_struct *)cpu_tasks[0].task")
1706d51363dSGlenn Washburn            return var_ptr.dereference()
1716d51363dSGlenn Washburn        else:
172c16a3b11SJeff Xie            var_ptr = gdb.parse_and_eval("&pcpu_hot.current_task")
173dc958682SBarry Song            return per_cpu(var_ptr, cpu).dereference()
174526940e3SBarry Song    elif utils.is_target_arch("aarch64"):
175526940e3SBarry Song        current_task_addr = gdb.parse_and_eval("$SP_EL0")
17656fe4870SGlenn Washburn        if (current_task_addr >> 63) != 0:
177526940e3SBarry Song            current_task = current_task_addr.cast(task_ptr_type)
178526940e3SBarry Song            return current_task.dereference()
179526940e3SBarry Song        else:
180526940e3SBarry Song            raise gdb.GdbError("Sorry, obtaining the current task is not allowed "
181526940e3SBarry Song                               "while running in userspace(EL0)")
182*cd24f440SDeepak Gupta    elif utils.is_target_arch("riscv"):
183*cd24f440SDeepak Gupta        current_tp = gdb.parse_and_eval("$tp")
184*cd24f440SDeepak Gupta        scratch_reg = gdb.parse_and_eval("$sscratch")
185*cd24f440SDeepak Gupta
186*cd24f440SDeepak Gupta        # by default tp points to current task
187*cd24f440SDeepak Gupta        current_task = current_tp.cast(task_ptr_type)
188*cd24f440SDeepak Gupta
189*cd24f440SDeepak Gupta        # scratch register is set 0 in trap handler after entering kernel.
190*cd24f440SDeepak Gupta        # When hart is in user mode, scratch register is pointing to task_struct.
191*cd24f440SDeepak Gupta        # and tp is used by user mode. So when scratch register holds larger value
192*cd24f440SDeepak Gupta        # (negative address as ulong is larger value) than tp, then use scratch register.
193*cd24f440SDeepak Gupta        if (scratch_reg.cast(utils.get_ulong_type()) > current_tp.cast(utils.get_ulong_type())):
194*cd24f440SDeepak Gupta            current_task = scratch_reg.cast(task_ptr_type)
195*cd24f440SDeepak Gupta
196*cd24f440SDeepak Gupta        return current_task.dereference()
197dc958682SBarry Song    else:
198dc958682SBarry Song        raise gdb.GdbError("Sorry, obtaining the current task is not yet "
199dc958682SBarry Song                           "supported with this arch")
200116b47b4SJan Kiszka
201116b47b4SJan Kiszkaclass LxCurrentFunc(gdb.Function):
202116b47b4SJan Kiszka    """Return current task.
203116b47b4SJan Kiszka
204116b47b4SJan Kiszka$lx_current([CPU]): Return the per-cpu task variable for the given CPU
205116b47b4SJan Kiszkanumber. If CPU is omitted, the CPU of the current context is used."""
206116b47b4SJan Kiszka
207116b47b4SJan Kiszka    def __init__(self):
208116b47b4SJan Kiszka        super(LxCurrentFunc, self).__init__("lx_current")
209116b47b4SJan Kiszka
210116b47b4SJan Kiszka    def invoke(self, cpu=-1):
211dc958682SBarry Song        return get_current_task(cpu)
212116b47b4SJan Kiszka
213116b47b4SJan Kiszka
214116b47b4SJan KiszkaLxCurrentFunc()
215