162306a36Sopenharmony_ci#
262306a36Sopenharmony_ci# gdb helper commands and functions for Linux kernel debugging
362306a36Sopenharmony_ci#
462306a36Sopenharmony_ci#  per-cpu tools
562306a36Sopenharmony_ci#
662306a36Sopenharmony_ci# Copyright (c) Siemens AG, 2011-2013
762306a36Sopenharmony_ci#
862306a36Sopenharmony_ci# Authors:
962306a36Sopenharmony_ci#  Jan Kiszka <jan.kiszka@siemens.com>
1062306a36Sopenharmony_ci#
1162306a36Sopenharmony_ci# This work is licensed under the terms of the GNU GPL version 2.
1262306a36Sopenharmony_ci#
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ciimport gdb
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cifrom linux import tasks, utils
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_citask_type = utils.CachedType("struct task_struct")
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciMAX_CPUS = 4096
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cidef get_current_cpu():
2662306a36Sopenharmony_ci    if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU:
2762306a36Sopenharmony_ci        return gdb.selected_thread().num - 1
2862306a36Sopenharmony_ci    elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB:
2962306a36Sopenharmony_ci        tid = gdb.selected_thread().ptid[2]
3062306a36Sopenharmony_ci        if tid > (0x100000000 - MAX_CPUS - 2):
3162306a36Sopenharmony_ci            return 0x100000000 - tid - 2
3262306a36Sopenharmony_ci        else:
3362306a36Sopenharmony_ci            return tasks.get_thread_info(tasks.get_task_by_pid(tid))['cpu']
3462306a36Sopenharmony_ci    else:
3562306a36Sopenharmony_ci        raise gdb.GdbError("Sorry, obtaining the current CPU is not yet "
3662306a36Sopenharmony_ci                           "supported with this gdb server.")
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cidef per_cpu(var_ptr, cpu):
4062306a36Sopenharmony_ci    if cpu == -1:
4162306a36Sopenharmony_ci        cpu = get_current_cpu()
4262306a36Sopenharmony_ci    if utils.is_target_arch("sparc:v9"):
4362306a36Sopenharmony_ci        offset = gdb.parse_and_eval(
4462306a36Sopenharmony_ci            "trap_block[{0}].__per_cpu_base".format(str(cpu)))
4562306a36Sopenharmony_ci    else:
4662306a36Sopenharmony_ci        try:
4762306a36Sopenharmony_ci            offset = gdb.parse_and_eval(
4862306a36Sopenharmony_ci                "__per_cpu_offset[{0}]".format(str(cpu)))
4962306a36Sopenharmony_ci        except gdb.error:
5062306a36Sopenharmony_ci            # !CONFIG_SMP case
5162306a36Sopenharmony_ci            offset = 0
5262306a36Sopenharmony_ci    pointer = var_ptr.cast(utils.get_long_type()) + offset
5362306a36Sopenharmony_ci    return pointer.cast(var_ptr.type).dereference()
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cicpu_mask = {}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cidef cpu_mask_invalidate(event):
6062306a36Sopenharmony_ci    global cpu_mask
6162306a36Sopenharmony_ci    cpu_mask = {}
6262306a36Sopenharmony_ci    gdb.events.stop.disconnect(cpu_mask_invalidate)
6362306a36Sopenharmony_ci    if hasattr(gdb.events, 'new_objfile'):
6462306a36Sopenharmony_ci        gdb.events.new_objfile.disconnect(cpu_mask_invalidate)
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cidef cpu_list(mask_name):
6862306a36Sopenharmony_ci    global cpu_mask
6962306a36Sopenharmony_ci    mask = None
7062306a36Sopenharmony_ci    if mask_name in cpu_mask:
7162306a36Sopenharmony_ci        mask = cpu_mask[mask_name]
7262306a36Sopenharmony_ci    if mask is None:
7362306a36Sopenharmony_ci        mask = gdb.parse_and_eval(mask_name + ".bits")
7462306a36Sopenharmony_ci        if hasattr(gdb, 'events'):
7562306a36Sopenharmony_ci            cpu_mask[mask_name] = mask
7662306a36Sopenharmony_ci            gdb.events.stop.connect(cpu_mask_invalidate)
7762306a36Sopenharmony_ci            if hasattr(gdb.events, 'new_objfile'):
7862306a36Sopenharmony_ci                gdb.events.new_objfile.connect(cpu_mask_invalidate)
7962306a36Sopenharmony_ci    bits_per_entry = mask[0].type.sizeof * 8
8062306a36Sopenharmony_ci    num_entries = mask.type.sizeof * 8 / bits_per_entry
8162306a36Sopenharmony_ci    entry = -1
8262306a36Sopenharmony_ci    bits = 0
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci    while True:
8562306a36Sopenharmony_ci        while bits == 0:
8662306a36Sopenharmony_ci            entry += 1
8762306a36Sopenharmony_ci            if entry == num_entries:
8862306a36Sopenharmony_ci                return
8962306a36Sopenharmony_ci            bits = mask[entry]
9062306a36Sopenharmony_ci            if bits != 0:
9162306a36Sopenharmony_ci                bit = 0
9262306a36Sopenharmony_ci                break
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci        while bits & 1 == 0:
9562306a36Sopenharmony_ci            bits >>= 1
9662306a36Sopenharmony_ci            bit += 1
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci        cpu = entry * bits_per_entry + bit
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci        bits >>= 1
10162306a36Sopenharmony_ci        bit += 1
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci        yield int(cpu)
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cidef each_online_cpu():
10762306a36Sopenharmony_ci    for cpu in cpu_list("__cpu_online_mask"):
10862306a36Sopenharmony_ci        yield cpu
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cidef each_present_cpu():
11262306a36Sopenharmony_ci    for cpu in cpu_list("__cpu_present_mask"):
11362306a36Sopenharmony_ci        yield cpu
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cidef each_possible_cpu():
11762306a36Sopenharmony_ci    for cpu in cpu_list("__cpu_possible_mask"):
11862306a36Sopenharmony_ci        yield cpu
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cidef each_active_cpu():
12262306a36Sopenharmony_ci    for cpu in cpu_list("__cpu_active_mask"):
12362306a36Sopenharmony_ci        yield cpu
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ciclass LxCpus(gdb.Command):
12762306a36Sopenharmony_ci    """List CPU status arrays
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ciDisplays the known state of each CPU based on the kernel masks
13062306a36Sopenharmony_ciand can help identify the state of hotplugged CPUs"""
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci    def __init__(self):
13362306a36Sopenharmony_ci        super(LxCpus, self).__init__("lx-cpus", gdb.COMMAND_DATA)
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci    def invoke(self, arg, from_tty):
13662306a36Sopenharmony_ci        gdb.write("Possible CPUs : {}\n".format(list(each_possible_cpu())))
13762306a36Sopenharmony_ci        gdb.write("Present CPUs  : {}\n".format(list(each_present_cpu())))
13862306a36Sopenharmony_ci        gdb.write("Online CPUs   : {}\n".format(list(each_online_cpu())))
13962306a36Sopenharmony_ci        gdb.write("Active CPUs   : {}\n".format(list(each_active_cpu())))
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ciLxCpus()
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ciclass PerCpu(gdb.Function):
14662306a36Sopenharmony_ci    """Return per-cpu variable.
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci$lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the
14962306a36Sopenharmony_cigiven CPU number. If CPU is omitted, the CPU of the current context is used.
15062306a36Sopenharmony_ciNote that VAR has to be quoted as string."""
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci    def __init__(self):
15362306a36Sopenharmony_ci        super(PerCpu, self).__init__("lx_per_cpu")
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci    def invoke(self, var_name, cpu=-1):
15662306a36Sopenharmony_ci        var_ptr = gdb.parse_and_eval("&" + var_name.string())
15762306a36Sopenharmony_ci        return per_cpu(var_ptr, cpu)
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ciPerCpu()
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cidef get_current_task(cpu):
16362306a36Sopenharmony_ci    task_ptr_type = task_type.get_type().pointer()
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci    if utils.is_target_arch("x86"):
16662306a36Sopenharmony_ci        if gdb.lookup_global_symbol("cpu_tasks"):
16762306a36Sopenharmony_ci            # This is a UML kernel, which stores the current task
16862306a36Sopenharmony_ci            # differently than other x86 sub architectures
16962306a36Sopenharmony_ci            var_ptr = gdb.parse_and_eval("(struct task_struct *)cpu_tasks[0].task")
17062306a36Sopenharmony_ci            return var_ptr.dereference()
17162306a36Sopenharmony_ci        else:
17262306a36Sopenharmony_ci            var_ptr = gdb.parse_and_eval("&pcpu_hot.current_task")
17362306a36Sopenharmony_ci            return per_cpu(var_ptr, cpu).dereference()
17462306a36Sopenharmony_ci    elif utils.is_target_arch("aarch64"):
17562306a36Sopenharmony_ci        current_task_addr = gdb.parse_and_eval("$SP_EL0")
17662306a36Sopenharmony_ci        if (current_task_addr >> 63) != 0:
17762306a36Sopenharmony_ci            current_task = current_task_addr.cast(task_ptr_type)
17862306a36Sopenharmony_ci            return current_task.dereference()
17962306a36Sopenharmony_ci        else:
18062306a36Sopenharmony_ci            raise gdb.GdbError("Sorry, obtaining the current task is not allowed "
18162306a36Sopenharmony_ci                               "while running in userspace(EL0)")
18262306a36Sopenharmony_ci    else:
18362306a36Sopenharmony_ci        raise gdb.GdbError("Sorry, obtaining the current task is not yet "
18462306a36Sopenharmony_ci                           "supported with this arch")
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ciclass LxCurrentFunc(gdb.Function):
18762306a36Sopenharmony_ci    """Return current task.
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci$lx_current([CPU]): Return the per-cpu task variable for the given CPU
19062306a36Sopenharmony_cinumber. If CPU is omitted, the CPU of the current context is used."""
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci    def __init__(self):
19362306a36Sopenharmony_ci        super(LxCurrentFunc, self).__init__("lx_current")
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci    def invoke(self, cpu=-1):
19662306a36Sopenharmony_ci        return get_current_task(cpu)
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ciLxCurrentFunc()
200