OpenCloudOS-Kernel/scripts/gdb/linux/cpus.py

175 lines
4.4 KiB
Python
Raw Normal View History

#
# gdb helper commands and functions for Linux kernel debugging
#
# per-cpu tools
#
# Copyright (c) Siemens AG, 2011-2013
#
# Authors:
# Jan Kiszka <jan.kiszka@siemens.com>
#
# This work is licensed under the terms of the GNU GPL version 2.
#
import gdb
from linux import tasks, utils
MAX_CPUS = 4096
def get_current_cpu():
if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU:
return gdb.selected_thread().num - 1
elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB:
tid = gdb.selected_thread().ptid[2]
if tid > (0x100000000 - MAX_CPUS - 2):
return 0x100000000 - tid - 2
else:
return tasks.get_thread_info(tasks.get_task_by_pid(tid))['cpu']
else:
raise gdb.GdbError("Sorry, obtaining the current CPU is not yet "
"supported with this gdb server.")
def per_cpu(var_ptr, cpu):
if cpu == -1:
cpu = get_current_cpu()
if utils.is_target_arch("sparc:v9"):
offset = gdb.parse_and_eval(
"trap_block[{0}].__per_cpu_base".format(str(cpu)))
else:
try:
offset = gdb.parse_and_eval(
"__per_cpu_offset[{0}]".format(str(cpu)))
except gdb.error:
# !CONFIG_SMP case
offset = 0
pointer = var_ptr.cast(utils.get_long_type()) + offset
return pointer.cast(var_ptr.type).dereference()
cpu_mask = {}
def cpu_mask_invalidate(event):
global cpu_mask
cpu_mask = {}
gdb.events.stop.disconnect(cpu_mask_invalidate)
if hasattr(gdb.events, 'new_objfile'):
gdb.events.new_objfile.disconnect(cpu_mask_invalidate)
def cpu_list(mask_name):
global cpu_mask
mask = None
if mask_name in cpu_mask:
mask = cpu_mask[mask_name]
if mask is None:
mask = gdb.parse_and_eval(mask_name + ".bits")
if hasattr(gdb, 'events'):
cpu_mask[mask_name] = mask
gdb.events.stop.connect(cpu_mask_invalidate)
if hasattr(gdb.events, 'new_objfile'):
gdb.events.new_objfile.connect(cpu_mask_invalidate)
bits_per_entry = mask[0].type.sizeof * 8
num_entries = mask.type.sizeof * 8 / bits_per_entry
entry = -1
bits = 0
while True:
while bits == 0:
entry += 1
if entry == num_entries:
return
bits = mask[entry]
if bits != 0:
bit = 0
break
while bits & 1 == 0:
bits >>= 1
bit += 1
cpu = entry * bits_per_entry + bit
bits >>= 1
bit += 1
yield int(cpu)
scripts/gdb: port to python3 / gdb7.7 I tried to use these scripts in an ubuntu 14.04 host (gdb 7.7 compiled against python 3.3) but there were several errors. I believe this patch fixes these issues so that the commands now work (I tested lx-symbols, lx-dmesg, lx-lsmod). Main issues that needed to be resolved: * In python 2 iterators have a "next()" method. In python 3 it is __next__() instead (so let's just add both). * In older python versions there was an implicit conversion in object.__format__() (used when an object is in string.format()) where it was converting the object to str first and then calling str's __format__(). This has now been removed so we must explicitly convert to str the objects for which we need to keep this behavior. * In dmesg.py: in python 3 log_buf is now a "memoryview" object which needs to be converted to a string in order to use string methods like "splitlines()". Luckily memoryview exists in python 2.7.6 as well, so we can convert log_buf to memoryview and use the same code in both python 2 and python 3. This version of the patch has now been tested with gdb 7.7 and both python 3.4 and python 2.7.6 (I think asking for at least python 2.7.6 is a reasonable requirement instead of complicating the code with version checks etc). Signed-off-by: Pantelis Koukousoulas <pktoss@gmail.com> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Jason Wessel <jason.wessel@windriver.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Ben Widawsky <ben@bwidawsk.net> Cc: Borislav Petkov <bp@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-02-18 05:47:35 +08:00
def each_online_cpu():
for cpu in cpu_list("__cpu_online_mask"):
yield cpu
def each_present_cpu():
for cpu in cpu_list("__cpu_present_mask"):
yield cpu
def each_possible_cpu():
for cpu in cpu_list("__cpu_possible_mask"):
yield cpu
def each_active_cpu():
for cpu in cpu_list("__cpu_active_mask"):
yield cpu
class LxCpus(gdb.Command):
"""List CPU status arrays
Displays the known state of each CPU based on the kernel masks
and can help identify the state of hotplugged CPUs"""
def __init__(self):
super(LxCpus, self).__init__("lx-cpus", gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
gdb.write("Possible CPUs : {}\n".format(list(each_possible_cpu())))
gdb.write("Present CPUs : {}\n".format(list(each_present_cpu())))
gdb.write("Online CPUs : {}\n".format(list(each_online_cpu())))
gdb.write("Active CPUs : {}\n".format(list(each_active_cpu())))
LxCpus()
class PerCpu(gdb.Function):
"""Return per-cpu variable.
$lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the
given CPU number. If CPU is omitted, the CPU of the current context is used.
Note that VAR has to be quoted as string."""
def __init__(self):
super(PerCpu, self).__init__("lx_per_cpu")
def invoke(self, var_name, cpu=-1):
var_ptr = gdb.parse_and_eval("&" + var_name.string())
return per_cpu(var_ptr, cpu)
PerCpu()
class LxCurrentFunc(gdb.Function):
"""Return current task.
$lx_current([CPU]): Return the per-cpu task variable for the given CPU
number. If CPU is omitted, the CPU of the current context is used."""
def __init__(self):
super(LxCurrentFunc, self).__init__("lx_current")
def invoke(self, cpu=-1):
var_ptr = gdb.parse_and_eval("&current_task")
return per_cpu(var_ptr, cpu).dereference()
LxCurrentFunc()