Back to home page

OSCL-LXR

 
 

    


0001 #
0002 # gdb helper commands and functions for Linux kernel debugging
0003 #
0004 #  per-cpu tools
0005 #
0006 # Copyright (c) Siemens AG, 2011-2013
0007 #
0008 # Authors:
0009 #  Jan Kiszka <jan.kiszka@siemens.com>
0010 #
0011 # This work is licensed under the terms of the GNU GPL version 2.
0012 #
0013 
0014 import gdb
0015 
0016 from linux import tasks, utils
0017 
0018 
0019 task_type = utils.CachedType("struct task_struct")
0020 
0021 
0022 MAX_CPUS = 4096
0023 
0024 
0025 def get_current_cpu():
0026     if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU:
0027         return gdb.selected_thread().num - 1
0028     elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB:
0029         tid = gdb.selected_thread().ptid[2]
0030         if tid > (0x100000000 - MAX_CPUS - 2):
0031             return 0x100000000 - tid - 2
0032         else:
0033             return tasks.get_thread_info(tasks.get_task_by_pid(tid))['cpu']
0034     else:
0035         raise gdb.GdbError("Sorry, obtaining the current CPU is not yet "
0036                            "supported with this gdb server.")
0037 
0038 
0039 def per_cpu(var_ptr, cpu):
0040     if cpu == -1:
0041         cpu = get_current_cpu()
0042     if utils.is_target_arch("sparc:v9"):
0043         offset = gdb.parse_and_eval(
0044             "trap_block[{0}].__per_cpu_base".format(str(cpu)))
0045     else:
0046         try:
0047             offset = gdb.parse_and_eval(
0048                 "__per_cpu_offset[{0}]".format(str(cpu)))
0049         except gdb.error:
0050             # !CONFIG_SMP case
0051             offset = 0
0052     pointer = var_ptr.cast(utils.get_long_type()) + offset
0053     return pointer.cast(var_ptr.type).dereference()
0054 
0055 
0056 cpu_mask = {}
0057 
0058 
0059 def cpu_mask_invalidate(event):
0060     global cpu_mask
0061     cpu_mask = {}
0062     gdb.events.stop.disconnect(cpu_mask_invalidate)
0063     if hasattr(gdb.events, 'new_objfile'):
0064         gdb.events.new_objfile.disconnect(cpu_mask_invalidate)
0065 
0066 
0067 def cpu_list(mask_name):
0068     global cpu_mask
0069     mask = None
0070     if mask_name in cpu_mask:
0071         mask = cpu_mask[mask_name]
0072     if mask is None:
0073         mask = gdb.parse_and_eval(mask_name + ".bits")
0074         if hasattr(gdb, 'events'):
0075             cpu_mask[mask_name] = mask
0076             gdb.events.stop.connect(cpu_mask_invalidate)
0077             if hasattr(gdb.events, 'new_objfile'):
0078                 gdb.events.new_objfile.connect(cpu_mask_invalidate)
0079     bits_per_entry = mask[0].type.sizeof * 8
0080     num_entries = mask.type.sizeof * 8 / bits_per_entry
0081     entry = -1
0082     bits = 0
0083 
0084     while True:
0085         while bits == 0:
0086             entry += 1
0087             if entry == num_entries:
0088                 return
0089             bits = mask[entry]
0090             if bits != 0:
0091                 bit = 0
0092                 break
0093 
0094         while bits & 1 == 0:
0095             bits >>= 1
0096             bit += 1
0097 
0098         cpu = entry * bits_per_entry + bit
0099 
0100         bits >>= 1
0101         bit += 1
0102 
0103         yield int(cpu)
0104 
0105 
0106 def each_online_cpu():
0107     for cpu in cpu_list("__cpu_online_mask"):
0108         yield cpu
0109 
0110 
0111 def each_present_cpu():
0112     for cpu in cpu_list("__cpu_present_mask"):
0113         yield cpu
0114 
0115 
0116 def each_possible_cpu():
0117     for cpu in cpu_list("__cpu_possible_mask"):
0118         yield cpu
0119 
0120 
0121 def each_active_cpu():
0122     for cpu in cpu_list("__cpu_active_mask"):
0123         yield cpu
0124 
0125 
0126 class LxCpus(gdb.Command):
0127     """List CPU status arrays
0128 
0129 Displays the known state of each CPU based on the kernel masks
0130 and can help identify the state of hotplugged CPUs"""
0131 
0132     def __init__(self):
0133         super(LxCpus, self).__init__("lx-cpus", gdb.COMMAND_DATA)
0134 
0135     def invoke(self, arg, from_tty):
0136         gdb.write("Possible CPUs : {}\n".format(list(each_possible_cpu())))
0137         gdb.write("Present CPUs  : {}\n".format(list(each_present_cpu())))
0138         gdb.write("Online CPUs   : {}\n".format(list(each_online_cpu())))
0139         gdb.write("Active CPUs   : {}\n".format(list(each_active_cpu())))
0140 
0141 
0142 LxCpus()
0143 
0144 
0145 class PerCpu(gdb.Function):
0146     """Return per-cpu variable.
0147 
0148 $lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the
0149 given CPU number. If CPU is omitted, the CPU of the current context is used.
0150 Note that VAR has to be quoted as string."""
0151 
0152     def __init__(self):
0153         super(PerCpu, self).__init__("lx_per_cpu")
0154 
0155     def invoke(self, var_name, cpu=-1):
0156         var_ptr = gdb.parse_and_eval("&" + var_name.string())
0157         return per_cpu(var_ptr, cpu)
0158 
0159 
0160 PerCpu()
0161 
0162 def get_current_task(cpu):
0163     task_ptr_type = task_type.get_type().pointer()
0164 
0165     if utils.is_target_arch("x86"):
0166          var_ptr = gdb.parse_and_eval("&current_task")
0167          return per_cpu(var_ptr, cpu).dereference()
0168     elif utils.is_target_arch("aarch64"):
0169          current_task_addr = gdb.parse_and_eval("$SP_EL0")
0170          if((current_task_addr >> 63) != 0):
0171              current_task = current_task_addr.cast(task_ptr_type)
0172              return current_task.dereference()
0173          else:
0174              raise gdb.GdbError("Sorry, obtaining the current task is not allowed "
0175                                 "while running in userspace(EL0)")
0176     else:
0177         raise gdb.GdbError("Sorry, obtaining the current task is not yet "
0178                            "supported with this arch")
0179 
0180 class LxCurrentFunc(gdb.Function):
0181     """Return current task.
0182 
0183 $lx_current([CPU]): Return the per-cpu task variable for the given CPU
0184 number. If CPU is omitted, the CPU of the current context is used."""
0185 
0186     def __init__(self):
0187         super(LxCurrentFunc, self).__init__("lx_current")
0188 
0189     def invoke(self, cpu=-1):
0190         return get_current_task(cpu)
0191 
0192 
0193 LxCurrentFunc()