0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
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
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("¤t_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()