Commit | Line | Data |
---|---|---|
fe7f9ed9 JK |
1 | # |
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 | ||
14 | import gdb | |
15 | ||
16 | from linux import tasks, utils | |
17 | ||
18 | ||
19 | MAX_CPUS = 4096 | |
20 | ||
21 | ||
22 | def 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 | ||
36 | def 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 | ||
3d4cd9c9 JK |
53 | cpu_mask = {} |
54 | ||
55 | ||
56 | def 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 | ||
64 | class 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 | ||
85 | def next(self): | |
86 | 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 | ||
106 | ||
fe7f9ed9 JK |
107 | class PerCpu(gdb.Function): |
108 | """Return per-cpu variable. | |
109 | ||
110 | $lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the | |
111 | given CPU number. If CPU is omitted, the CPU of the current context is used. | |
112 | Note that VAR has to be quoted as string.""" | |
113 | ||
114 | def __init__(self): | |
115 | super(PerCpu, self).__init__("lx_per_cpu") | |
116 | ||
117 | def invoke(self, var_name, cpu=-1): | |
118 | var_ptr = gdb.parse_and_eval("&" + var_name.string()) | |
119 | return per_cpu(var_ptr, cpu) | |
120 | ||
121 | ||
122 | PerCpu() | |
116b47b4 JK |
123 | |
124 | ||
125 | class LxCurrentFunc(gdb.Function): | |
126 | """Return current task. | |
127 | ||
128 | $lx_current([CPU]): Return the per-cpu task variable for the given CPU | |
129 | number. If CPU is omitted, the CPU of the current context is used.""" | |
130 | ||
131 | def __init__(self): | |
132 | super(LxCurrentFunc, self).__init__("lx_current") | |
133 | ||
134 | def invoke(self, cpu=-1): | |
135 | var_ptr = gdb.parse_and_eval("¤t_task") | |
136 | return per_cpu(var_ptr, cpu).dereference() | |
137 | ||
138 | ||
139 | LxCurrentFunc() |