Linux Audio

Check our new training course

Loading...
v6.13.7
  1#
  2# gdb helper commands and functions for Linux kernel debugging
  3#
  4#  per-cpu tools
  5#
  6# Copyright (c) Siemens AG, 2011-2013
  7#
  8# Authors:
  9#  Jan Kiszka <jan.kiszka@siemens.com>
 10#
 11# This work is licensed under the terms of the GNU GPL version 2.
 12#
 13
 14import gdb
 15
 16from linux import tasks, utils
 17
 18
 19task_type = utils.CachedType("struct task_struct")
 20
 21
 22MAX_CPUS = 4096
 23
 24
 25def get_current_cpu():
 26    if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU:
 27        return gdb.selected_thread().num - 1
 28    elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB:
 29        return gdb.parse_and_eval("kgdb_active.counter")
 
 
 
 
 30    else:
 31        raise gdb.GdbError("Sorry, obtaining the current CPU is not yet "
 32                           "supported with this gdb server.")
 33
 34
 35def per_cpu(var_ptr, cpu):
 36    if cpu == -1:
 37        cpu = get_current_cpu()
 38    if utils.is_target_arch("sparc:v9"):
 39        offset = gdb.parse_and_eval(
 40            "trap_block[{0}].__per_cpu_base".format(str(cpu)))
 41    else:
 42        try:
 43            offset = gdb.parse_and_eval(
 44                "__per_cpu_offset[{0}]".format(str(cpu)))
 45        except gdb.error:
 46            # !CONFIG_SMP case
 47            offset = 0
 48    pointer = var_ptr.cast(utils.get_long_type()) + offset
 49    return pointer.cast(var_ptr.type).dereference()
 50
 51
 52cpu_mask = {}
 53
 54
 55def cpu_mask_invalidate(event):
 56    global cpu_mask
 57    cpu_mask = {}
 58    gdb.events.stop.disconnect(cpu_mask_invalidate)
 59    if hasattr(gdb.events, 'new_objfile'):
 60        gdb.events.new_objfile.disconnect(cpu_mask_invalidate)
 61
 62
 63def cpu_list(mask_name):
 64    global cpu_mask
 65    mask = None
 66    if mask_name in cpu_mask:
 67        mask = cpu_mask[mask_name]
 68    if mask is None:
 69        mask = gdb.parse_and_eval(mask_name + ".bits")
 70        if hasattr(gdb, 'events'):
 71            cpu_mask[mask_name] = mask
 72            gdb.events.stop.connect(cpu_mask_invalidate)
 73            if hasattr(gdb.events, 'new_objfile'):
 74                gdb.events.new_objfile.connect(cpu_mask_invalidate)
 75    bits_per_entry = mask[0].type.sizeof * 8
 76    num_entries = mask.type.sizeof * 8 / bits_per_entry
 77    entry = -1
 78    bits = 0
 79
 80    while True:
 81        while bits == 0:
 82            entry += 1
 83            if entry == num_entries:
 84                return
 85            bits = mask[entry]
 86            if bits != 0:
 87                bit = 0
 88                break
 89
 90        while bits & 1 == 0:
 91            bits >>= 1
 92            bit += 1
 93
 94        cpu = entry * bits_per_entry + bit
 95
 96        bits >>= 1
 97        bit += 1
 98
 99        yield int(cpu)
100
101
102def each_online_cpu():
103    for cpu in cpu_list("__cpu_online_mask"):
104        yield cpu
105
106
107def each_present_cpu():
108    for cpu in cpu_list("__cpu_present_mask"):
109        yield cpu
110
111
112def each_possible_cpu():
113    for cpu in cpu_list("__cpu_possible_mask"):
114        yield cpu
115
116
117def each_active_cpu():
118    for cpu in cpu_list("__cpu_active_mask"):
119        yield cpu
120
121
122class LxCpus(gdb.Command):
123    """List CPU status arrays
124
125Displays the known state of each CPU based on the kernel masks
126and can help identify the state of hotplugged CPUs"""
127
128    def __init__(self):
129        super(LxCpus, self).__init__("lx-cpus", gdb.COMMAND_DATA)
130
131    def invoke(self, arg, from_tty):
132        gdb.write("Possible CPUs : {}\n".format(list(each_possible_cpu())))
133        gdb.write("Present CPUs  : {}\n".format(list(each_present_cpu())))
134        gdb.write("Online CPUs   : {}\n".format(list(each_online_cpu())))
135        gdb.write("Active CPUs   : {}\n".format(list(each_active_cpu())))
136
137
138LxCpus()
139
140
141class PerCpu(gdb.Function):
142    """Return per-cpu variable.
143
144$lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the
145given CPU number. If CPU is omitted, the CPU of the current context is used.
146Note that VAR has to be quoted as string."""
147
148    def __init__(self):
149        super(PerCpu, self).__init__("lx_per_cpu")
150
151    def invoke(self, var, cpu=-1):
152        return per_cpu(var.address, cpu)
 
153
154
155PerCpu()
156
157def get_current_task(cpu):
158    task_ptr_type = task_type.get_type().pointer()
159
160    if utils.is_target_arch("x86"):
161        if gdb.lookup_global_symbol("cpu_tasks"):
162            # This is a UML kernel, which stores the current task
163            # differently than other x86 sub architectures
164            var_ptr = gdb.parse_and_eval("(struct task_struct *)cpu_tasks[0].task")
165            return var_ptr.dereference()
166        else:
167            var_ptr = gdb.parse_and_eval("&pcpu_hot.current_task")
168            return per_cpu(var_ptr, cpu).dereference()
169    elif utils.is_target_arch("aarch64"):
170        current_task_addr = gdb.parse_and_eval("(unsigned long)$SP_EL0")
171        if (current_task_addr >> 63) != 0:
172            current_task = current_task_addr.cast(task_ptr_type)
173            return current_task.dereference()
174        else:
175            raise gdb.GdbError("Sorry, obtaining the current task is not allowed "
176                               "while running in userspace(EL0)")
177    elif utils.is_target_arch("riscv"):
178        current_tp = gdb.parse_and_eval("$tp")
179        scratch_reg = gdb.parse_and_eval("$sscratch")
180
181        # by default tp points to current task
182        current_task = current_tp.cast(task_ptr_type)
183
184        # scratch register is set 0 in trap handler after entering kernel.
185        # When hart is in user mode, scratch register is pointing to task_struct.
186        # and tp is used by user mode. So when scratch register holds larger value
187        # (negative address as ulong is larger value) than tp, then use scratch register.
188        if (scratch_reg.cast(utils.get_ulong_type()) > current_tp.cast(utils.get_ulong_type())):
189            current_task = scratch_reg.cast(task_ptr_type)
190
191        return current_task.dereference()
192    else:
193        raise gdb.GdbError("Sorry, obtaining the current task is not yet "
194                           "supported with this arch")
195
196class LxCurrentFunc(gdb.Function):
197    """Return current task.
198
199$lx_current([CPU]): Return the per-cpu task variable for the given CPU
200number. If CPU is omitted, the CPU of the current context is used."""
201
202    def __init__(self):
203        super(LxCurrentFunc, self).__init__("lx_current")
204
205    def invoke(self, cpu=-1):
206        return get_current_task(cpu)
 
207
208
209LxCurrentFunc()
v4.10.11
  1#
  2# gdb helper commands and functions for Linux kernel debugging
  3#
  4#  per-cpu tools
  5#
  6# Copyright (c) Siemens AG, 2011-2013
  7#
  8# Authors:
  9#  Jan Kiszka <jan.kiszka@siemens.com>
 10#
 11# This work is licensed under the terms of the GNU GPL version 2.
 12#
 13
 14import gdb
 15
 16from linux import tasks, utils
 17
 18
 
 
 
 19MAX_CPUS = 4096
 20
 21
 22def get_current_cpu():
 23    if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU:
 24        return gdb.selected_thread().num - 1
 25    elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB:
 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']
 31    else:
 32        raise gdb.GdbError("Sorry, obtaining the current CPU is not yet "
 33                           "supported with this gdb server.")
 34
 35
 36def per_cpu(var_ptr, cpu):
 37    if cpu == -1:
 38        cpu = get_current_cpu()
 39    if utils.is_target_arch("sparc:v9"):
 40        offset = gdb.parse_and_eval(
 41            "trap_block[{0}].__per_cpu_base".format(str(cpu)))
 42    else:
 43        try:
 44            offset = gdb.parse_and_eval(
 45                "__per_cpu_offset[{0}]".format(str(cpu)))
 46        except gdb.error:
 47            # !CONFIG_SMP case
 48            offset = 0
 49    pointer = var_ptr.cast(utils.get_long_type()) + offset
 50    return pointer.cast(var_ptr.type).dereference()
 51
 52
 53cpu_mask = {}
 54
 55
 56def cpu_mask_invalidate(event):
 57    global cpu_mask
 58    cpu_mask = {}
 59    gdb.events.stop.disconnect(cpu_mask_invalidate)
 60    if hasattr(gdb.events, 'new_objfile'):
 61        gdb.events.new_objfile.disconnect(cpu_mask_invalidate)
 62
 63
 64def cpu_list(mask_name):
 65    global cpu_mask
 66    mask = None
 67    if mask_name in cpu_mask:
 68        mask = cpu_mask[mask_name]
 69    if mask is None:
 70        mask = gdb.parse_and_eval(mask_name + ".bits")
 71        if hasattr(gdb, 'events'):
 72            cpu_mask[mask_name] = mask
 73            gdb.events.stop.connect(cpu_mask_invalidate)
 74            if hasattr(gdb.events, 'new_objfile'):
 75                gdb.events.new_objfile.connect(cpu_mask_invalidate)
 76    bits_per_entry = mask[0].type.sizeof * 8
 77    num_entries = mask.type.sizeof * 8 / bits_per_entry
 78    entry = -1
 79    bits = 0
 80
 81    while True:
 82        while bits == 0:
 83            entry += 1
 84            if entry == num_entries:
 85                return
 86            bits = mask[entry]
 87            if bits != 0:
 88                bit = 0
 89                break
 90
 91        while bits & 1 == 0:
 92            bits >>= 1
 93            bit += 1
 94
 95        cpu = entry * bits_per_entry + bit
 96
 97        bits >>= 1
 98        bit += 1
 99
100        yield int(cpu)
101
102
103def each_online_cpu():
104    for cpu in cpu_list("__cpu_online_mask"):
105        yield cpu
106
107
108def each_present_cpu():
109    for cpu in cpu_list("__cpu_present_mask"):
110        yield cpu
111
112
113def each_possible_cpu():
114    for cpu in cpu_list("__cpu_possible_mask"):
115        yield cpu
116
117
118def each_active_cpu():
119    for cpu in cpu_list("__cpu_active_mask"):
120        yield cpu
121
122
123class LxCpus(gdb.Command):
124    """List CPU status arrays
125
126Displays the known state of each CPU based on the kernel masks
127and can help identify the state of hotplugged CPUs"""
128
129    def __init__(self):
130        super(LxCpus, self).__init__("lx-cpus", gdb.COMMAND_DATA)
131
132    def invoke(self, arg, from_tty):
133        gdb.write("Possible CPUs : {}\n".format(list(each_possible_cpu())))
134        gdb.write("Present CPUs  : {}\n".format(list(each_present_cpu())))
135        gdb.write("Online CPUs   : {}\n".format(list(each_online_cpu())))
136        gdb.write("Active CPUs   : {}\n".format(list(each_active_cpu())))
137
 
138LxCpus()
139
140
141class PerCpu(gdb.Function):
142    """Return per-cpu variable.
143
144$lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the
145given CPU number. If CPU is omitted, the CPU of the current context is used.
146Note that VAR has to be quoted as string."""
147
148    def __init__(self):
149        super(PerCpu, self).__init__("lx_per_cpu")
150
151    def invoke(self, var_name, cpu=-1):
152        var_ptr = gdb.parse_and_eval("&" + var_name.string())
153        return per_cpu(var_ptr, cpu)
154
155
156PerCpu()
157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
159class LxCurrentFunc(gdb.Function):
160    """Return current task.
161
162$lx_current([CPU]): Return the per-cpu task variable for the given CPU
163number. If CPU is omitted, the CPU of the current context is used."""
164
165    def __init__(self):
166        super(LxCurrentFunc, self).__init__("lx_current")
167
168    def invoke(self, cpu=-1):
169        var_ptr = gdb.parse_and_eval("&current_task")
170        return per_cpu(var_ptr, cpu).dereference()
171
172
173LxCurrentFunc()