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