blob: 8045871e2840189b34730dfcc8c548690241be66 [file] [log] [blame]
Jan Kiszkafe7f9ed2015-02-17 13:47:21 -08001#
2# gdb helper commands and functions for Linux kernel debugging
3#
4# per-cpu tools
5#
6# Copyright (c) Siemens AG, 2011-2013
7#
8# Authors:
9# Jan Kiszka <jan.kiszka@siemens.com>
10#
11# This work is licensed under the terms of the GNU GPL version 2.
12#
13
14import gdb
15
16from linux import tasks, utils
17
18
19MAX_CPUS = 4096
20
21
22def get_current_cpu():
23 if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU:
24 return gdb.selected_thread().num - 1
25 elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB:
26 tid = gdb.selected_thread().ptid[2]
27 if tid > (0x100000000 - MAX_CPUS - 2):
28 return 0x100000000 - tid - 2
29 else:
30 return tasks.get_thread_info(tasks.get_task_by_pid(tid))['cpu']
31 else:
32 raise gdb.GdbError("Sorry, obtaining the current CPU is not yet "
33 "supported with this gdb server.")
34
35
36def per_cpu(var_ptr, cpu):
37 if cpu == -1:
38 cpu = get_current_cpu()
39 if utils.is_target_arch("sparc:v9"):
40 offset = gdb.parse_and_eval(
41 "trap_block[{0}].__per_cpu_base".format(str(cpu)))
42 else:
43 try:
44 offset = gdb.parse_and_eval(
45 "__per_cpu_offset[{0}]".format(str(cpu)))
46 except gdb.error:
47 # !CONFIG_SMP case
48 offset = 0
49 pointer = var_ptr.cast(utils.get_long_type()) + offset
50 return pointer.cast(var_ptr.type).dereference()
51
52
Jan Kiszka3d4cd9c2015-02-17 13:47:27 -080053cpu_mask = {}
54
55
56def cpu_mask_invalidate(event):
57 global cpu_mask
58 cpu_mask = {}
59 gdb.events.stop.disconnect(cpu_mask_invalidate)
60 if hasattr(gdb.events, 'new_objfile'):
61 gdb.events.new_objfile.disconnect(cpu_mask_invalidate)
62
63
64class CpuList():
65 def __init__(self, mask_name):
66 global cpu_mask
67 self.mask = None
68 if mask_name in cpu_mask:
69 self.mask = cpu_mask[mask_name]
70 if self.mask is None:
71 self.mask = gdb.parse_and_eval(mask_name + ".bits")
72 if hasattr(gdb, 'events'):
73 cpu_mask[mask_name] = self.mask
74 gdb.events.stop.connect(cpu_mask_invalidate)
75 if hasattr(gdb.events, 'new_objfile'):
76 gdb.events.new_objfile.connect(cpu_mask_invalidate)
77 self.bits_per_entry = self.mask[0].type.sizeof * 8
78 self.num_entries = self.mask.type.sizeof * 8 / self.bits_per_entry
79 self.entry = -1
80 self.bits = 0
81
82 def __iter__(self):
83 return self
84
Pantelis Koukousoulas276d97d2015-02-17 13:47:35 -080085 def __next__(self):
Jan Kiszka3d4cd9c2015-02-17 13:47:27 -080086 while self.bits == 0:
87 self.entry += 1
88 if self.entry == self.num_entries:
89 raise StopIteration
90 self.bits = self.mask[self.entry]
91 if self.bits != 0:
92 self.bit = 0
93 break
94
95 while self.bits & 1 == 0:
96 self.bits >>= 1
97 self.bit += 1
98
99 cpu = self.entry * self.bits_per_entry + self.bit
100
101 self.bits >>= 1
102 self.bit += 1
103
104 return cpu
105
Pantelis Koukousoulas276d97d2015-02-17 13:47:35 -0800106 def next(self):
107 return self.__next__()
108
Jan Kiszka3d4cd9c2015-02-17 13:47:27 -0800109
Jan Kiszkafe7f9ed2015-02-17 13:47:21 -0800110class PerCpu(gdb.Function):
111 """Return per-cpu variable.
112
113$lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the
114given CPU number. If CPU is omitted, the CPU of the current context is used.
115Note that VAR has to be quoted as string."""
116
117 def __init__(self):
118 super(PerCpu, self).__init__("lx_per_cpu")
119
120 def invoke(self, var_name, cpu=-1):
121 var_ptr = gdb.parse_and_eval("&" + var_name.string())
122 return per_cpu(var_ptr, cpu)
123
124
125PerCpu()
Jan Kiszka116b47b2015-02-17 13:47:24 -0800126
127
128class LxCurrentFunc(gdb.Function):
129 """Return current task.
130
131$lx_current([CPU]): Return the per-cpu task variable for the given CPU
132number. If CPU is omitted, the CPU of the current context is used."""
133
134 def __init__(self):
135 super(LxCurrentFunc, self).__init__("lx_current")
136
137 def invoke(self, cpu=-1):
138 var_ptr = gdb.parse_and_eval("&current_task")
139 return per_cpu(var_ptr, cpu).dereference()
140
141
142LxCurrentFunc()