Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scripts/gdb: add a timer list command

Implement a command to print the timer list, much like how
/proc/timer_list is implemented. This can be used to look at the
pending timers on a crashed system.

[swboyd@chromium.org: v2]
Link: http://lkml.kernel.org/r/20190329220844.38234-5-swboyd@chromium.org
Link: http://lkml.kernel.org/r/20190325184522.260535-5-swboyd@chromium.org
Signed-off-by: Stephen Boyd <swboyd@chromium.org>
Cc: Douglas Anderson <dianders@chromium.org>
Cc: Nikolay Borisov <n.borisov.lkml@gmail.com>
Cc: Kieran Bingham <kbingham@kernel.org>
Cc: Jan Kiszka <jan.kiszka@siemens.com>
Cc: Jackie Liu <liuyun01@kylinos.cn>
Cc: Jason Wessel <jason.wessel@windriver.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Stephen Boyd and committed by
Linus Torvalds
442284a8 449ca0c9

+233
+13
scripts/gdb/linux/constants.py.in
··· 13 13 */ 14 14 15 15 #include <linux/fs.h> 16 + #include <linux/hrtimer.h> 16 17 #include <linux/mount.h> 17 18 #include <linux/of_fdt.h> 19 + #include <linux/threads.h> 18 20 19 21 /* We need to stringify expanded macros so that they can be parsed */ 20 22 ··· 46 44 LX_VALUE(SB_NOATIME) 47 45 LX_VALUE(SB_NODIRATIME) 48 46 47 + /* linux/htimer.h */ 48 + LX_GDBPARSED(hrtimer_resolution) 49 + 49 50 /* linux/mount.h */ 50 51 LX_VALUE(MNT_NOSUID) 51 52 LX_VALUE(MNT_NODEV) ··· 57 52 LX_VALUE(MNT_NODIRATIME) 58 53 LX_VALUE(MNT_RELATIME) 59 54 55 + /* linux/threads.h */ 56 + LX_VALUE(NR_CPUS) 57 + 60 58 /* linux/of_fdt.h> */ 61 59 LX_VALUE(OF_DT_HEADER) 62 60 63 61 /* Kernel Configs */ 62 + LX_CONFIG(CONFIG_GENERIC_CLOCKEVENTS) 63 + LX_CONFIG(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) 64 + LX_CONFIG(CONFIG_HIGH_RES_TIMERS) 65 + LX_CONFIG(CONFIG_NR_CPUS) 64 66 LX_CONFIG(CONFIG_OF) 67 + LX_CONFIG(CONFIG_TICK_ONESHOT)
+219
scripts/gdb/linux/timerlist.py
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + # Copyright 2019 Google LLC. 4 + 5 + import binascii 6 + import gdb 7 + 8 + from linux import constants 9 + from linux import cpus 10 + from linux import rbtree 11 + from linux import utils 12 + 13 + timerqueue_node_type = utils.CachedType("struct timerqueue_node").get_type() 14 + hrtimer_type = utils.CachedType("struct hrtimer").get_type() 15 + 16 + 17 + def ktime_get(): 18 + """Returns the current time, but not very accurately 19 + 20 + We can't read the hardware timer itself to add any nanoseconds 21 + that need to be added since we last stored the time in the 22 + timekeeper. But this is probably good enough for debug purposes.""" 23 + tk_core = gdb.parse_and_eval("&tk_core") 24 + 25 + return tk_core['timekeeper']['tkr_mono']['base'] 26 + 27 + 28 + def print_timer(rb_node, idx): 29 + timerqueue = utils.container_of(rb_node, timerqueue_node_type.pointer(), 30 + "node") 31 + timer = utils.container_of(timerqueue, hrtimer_type.pointer(), "node") 32 + 33 + function = str(timer['function']).split(" ")[1].strip("<>") 34 + softexpires = timer['_softexpires'] 35 + expires = timer['node']['expires'] 36 + now = ktime_get() 37 + 38 + text = " #{}: <{}>, {}, ".format(idx, timer, function) 39 + text += "S:{:02x}\n".format(int(timer['state'])) 40 + text += " # expires at {}-{} nsecs [in {} to {} nsecs]\n".format( 41 + softexpires, expires, softexpires - now, expires - now) 42 + return text 43 + 44 + 45 + def print_active_timers(base): 46 + curr = base['active']['next']['node'] 47 + curr = curr.address.cast(rbtree.rb_node_type.get_type().pointer()) 48 + idx = 0 49 + while curr: 50 + yield print_timer(curr, idx) 51 + curr = rbtree.rb_next(curr) 52 + idx += 1 53 + 54 + 55 + def print_base(base): 56 + text = " .base: {}\n".format(base.address) 57 + text += " .index: {}\n".format(base['index']) 58 + 59 + text += " .resolution: {} nsecs\n".format(constants.LX_hrtimer_resolution) 60 + 61 + text += " .get_time: {}\n".format(base['get_time']) 62 + if constants.LX_CONFIG_HIGH_RES_TIMERS: 63 + text += " .offset: {} nsecs\n".format(base['offset']) 64 + text += "active timers:\n" 65 + text += "".join([x for x in print_active_timers(base)]) 66 + return text 67 + 68 + 69 + def print_cpu(hrtimer_bases, cpu, max_clock_bases): 70 + cpu_base = cpus.per_cpu(hrtimer_bases, cpu) 71 + jiffies = gdb.parse_and_eval("jiffies_64") 72 + tick_sched_ptr = gdb.parse_and_eval("&tick_cpu_sched") 73 + ts = cpus.per_cpu(tick_sched_ptr, cpu) 74 + 75 + text = "cpu: {}\n".format(cpu) 76 + for i in xrange(max_clock_bases): 77 + text += " clock {}:\n".format(i) 78 + text += print_base(cpu_base['clock_base'][i]) 79 + 80 + if constants.LX_CONFIG_HIGH_RES_TIMERS: 81 + fmts = [(" .{} : {} nsecs", 'expires_next'), 82 + (" .{} : {}", 'hres_active'), 83 + (" .{} : {}", 'nr_events'), 84 + (" .{} : {}", 'nr_retries'), 85 + (" .{} : {}", 'nr_hangs'), 86 + (" .{} : {}", 'max_hang_time')] 87 + text += "\n".join([s.format(f, cpu_base[f]) for s, f in fmts]) 88 + text += "\n" 89 + 90 + if constants.LX_CONFIG_TICK_ONESHOT: 91 + fmts = [(" .{} : {}", 'nohz_mode'), 92 + (" .{} : {} nsecs", 'last_tick'), 93 + (" .{} : {}", 'tick_stopped'), 94 + (" .{} : {}", 'idle_jiffies'), 95 + (" .{} : {}", 'idle_calls'), 96 + (" .{} : {}", 'idle_sleeps'), 97 + (" .{} : {} nsecs", 'idle_entrytime'), 98 + (" .{} : {} nsecs", 'idle_waketime'), 99 + (" .{} : {} nsecs", 'idle_exittime'), 100 + (" .{} : {} nsecs", 'idle_sleeptime'), 101 + (" .{}: {} nsecs", 'iowait_sleeptime'), 102 + (" .{} : {}", 'last_jiffies'), 103 + (" .{} : {}", 'next_timer'), 104 + (" .{} : {} nsecs", 'idle_expires')] 105 + text += "\n".join([s.format(f, ts[f]) for s, f in fmts]) 106 + text += "\njiffies: {}\n".format(jiffies) 107 + 108 + text += "\n" 109 + 110 + return text 111 + 112 + 113 + def print_tickdevice(td, cpu): 114 + dev = td['evtdev'] 115 + text = "Tick Device: mode: {}\n".format(td['mode']) 116 + if cpu < 0: 117 + text += "Broadcast device\n" 118 + else: 119 + text += "Per CPU device: {}\n".format(cpu) 120 + 121 + text += "Clock Event Device: " 122 + if dev == 0: 123 + text += "<NULL>\n" 124 + return text 125 + 126 + text += "{}\n".format(dev['name']) 127 + text += " max_delta_ns: {}\n".format(dev['max_delta_ns']) 128 + text += " min_delta_ns: {}\n".format(dev['min_delta_ns']) 129 + text += " mult: {}\n".format(dev['mult']) 130 + text += " shift: {}\n".format(dev['shift']) 131 + text += " mode: {}\n".format(dev['state_use_accessors']) 132 + text += " next_event: {} nsecs\n".format(dev['next_event']) 133 + 134 + text += " set_next_event: {}\n".format(dev['set_next_event']) 135 + 136 + members = [('set_state_shutdown', " shutdown: {}\n"), 137 + ('set_state_periodic', " periodic: {}\n"), 138 + ('set_state_oneshot', " oneshot: {}\n"), 139 + ('set_state_oneshot_stopped', " oneshot stopped: {}\n"), 140 + ('tick_resume', " resume: {}\n")] 141 + for member, fmt in members: 142 + if dev[member]: 143 + text += fmt.format(dev[member]) 144 + 145 + text += " event_handler: {}\n".format(dev['event_handler']) 146 + text += " retries: {}\n".format(dev['retries']) 147 + 148 + return text 149 + 150 + 151 + def pr_cpumask(mask): 152 + nr_cpu_ids = 1 153 + if constants.LX_NR_CPUS > 1: 154 + nr_cpu_ids = gdb.parse_and_eval("nr_cpu_ids") 155 + 156 + inf = gdb.inferiors()[0] 157 + bits = mask['bits'] 158 + num_bytes = (nr_cpu_ids + 7) / 8 159 + buf = utils.read_memoryview(inf, bits, num_bytes).tobytes() 160 + buf = binascii.b2a_hex(buf) 161 + 162 + chunks = [] 163 + i = num_bytes 164 + while i > 0: 165 + i -= 1 166 + start = i * 2 167 + end = start + 2 168 + chunks.append(buf[start:end]) 169 + if i != 0 and i % 4 == 0: 170 + chunks.append(',') 171 + 172 + extra = nr_cpu_ids % 8 173 + if 0 < extra <= 4: 174 + chunks[0] = chunks[0][0] # Cut off the first 0 175 + 176 + return "".join(chunks) 177 + 178 + 179 + class LxTimerList(gdb.Command): 180 + """Print /proc/timer_list""" 181 + 182 + def __init__(self): 183 + super(LxTimerList, self).__init__("lx-timerlist", gdb.COMMAND_DATA) 184 + 185 + def invoke(self, arg, from_tty): 186 + hrtimer_bases = gdb.parse_and_eval("&hrtimer_bases") 187 + max_clock_bases = gdb.parse_and_eval("HRTIMER_MAX_CLOCK_BASES") 188 + 189 + text = "Timer List Version: gdb scripts\n" 190 + text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format(max_clock_bases) 191 + text += "now at {} nsecs\n".format(ktime_get()) 192 + 193 + for cpu in cpus.each_online_cpu(): 194 + text += print_cpu(hrtimer_bases, cpu, max_clock_bases) 195 + 196 + if constants.LX_CONFIG_GENERIC_CLOCKEVENTS: 197 + if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST: 198 + bc_dev = gdb.parse_and_eval("&tick_broadcast_device") 199 + text += print_tickdevice(bc_dev, -1) 200 + text += "\n" 201 + mask = gdb.parse_and_eval("tick_broadcast_mask") 202 + mask = pr_cpumask(mask) 203 + text += "tick_broadcast_mask: {}\n".format(mask) 204 + if constants.LX_CONFIG_TICK_ONESHOT: 205 + mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask") 206 + mask = pr_cpumask(mask) 207 + text += "tick_broadcast_oneshot_mask: {}\n".format(mask) 208 + text += "\n" 209 + 210 + tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device") 211 + for cpu in cpus.each_online_cpu(): 212 + tick_dev = cpus.per_cpu(tick_cpu_devices, cpu) 213 + text += print_tickdevice(tick_dev, cpu) 214 + text += "\n" 215 + 216 + gdb.write(text) 217 + 218 + 219 + LxTimerList()
+1
scripts/gdb/vmlinux-gdb.py
··· 33 33 import linux.rbtree 34 34 import linux.proc 35 35 import linux.constants 36 + import linux.timerlist