1# SPDX-License-Identifier: GPL-2.0 2# 3# Copyright 2019 Google LLC. 4 5import binascii 6import gdb 7 8from linux import constants 9from linux import cpus 10from linux import rbtree 11from linux import utils 12 13timerqueue_node_type = utils.CachedType("struct timerqueue_node").get_type() 14hrtimer_type = utils.CachedType("struct hrtimer").get_type() 15 16 17def 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 28def 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 45def print_active_timers(base): 46 curr = base['active']['rb_root']['rb_leftmost'] 47 idx = 0 48 while curr: 49 yield print_timer(curr, idx) 50 curr = rbtree.rb_next(curr) 51 idx += 1 52 53 54def print_base(base): 55 text = " .base: {}\n".format(base.address) 56 text += " .index: {}\n".format(base['index']) 57 58 text += " .resolution: {} nsecs\n".format(constants.LX_hrtimer_resolution) 59 60 text += " .get_time: {}\n".format(base['get_time']) 61 if constants.LX_CONFIG_HIGH_RES_TIMERS: 62 text += " .offset: {} nsecs\n".format(base['offset']) 63 text += "active timers:\n" 64 text += "".join([x for x in print_active_timers(base)]) 65 return text 66 67 68def print_cpu(hrtimer_bases, cpu, max_clock_bases): 69 cpu_base = cpus.per_cpu(hrtimer_bases, cpu) 70 jiffies = gdb.parse_and_eval("jiffies_64") 71 tick_sched_ptr = gdb.parse_and_eval("&tick_cpu_sched") 72 ts = cpus.per_cpu(tick_sched_ptr, cpu) 73 74 text = "cpu: {}\n".format(cpu) 75 for i in xrange(max_clock_bases): 76 text += " clock {}:\n".format(i) 77 text += print_base(cpu_base['clock_base'][i]) 78 79 if constants.LX_CONFIG_HIGH_RES_TIMERS: 80 fmts = [(" .{} : {} nsecs", 'expires_next'), 81 (" .{} : {}", 'hres_active'), 82 (" .{} : {}", 'nr_events'), 83 (" .{} : {}", 'nr_retries'), 84 (" .{} : {}", 'nr_hangs'), 85 (" .{} : {}", 'max_hang_time')] 86 text += "\n".join([s.format(f, cpu_base[f]) for s, f in fmts]) 87 text += "\n" 88 89 if constants.LX_CONFIG_TICK_ONESHOT: 90 fmts = [(" .{} : {}", 'nohz_mode'), 91 (" .{} : {} nsecs", 'last_tick'), 92 (" .{} : {}", 'tick_stopped'), 93 (" .{} : {}", 'idle_jiffies'), 94 (" .{} : {}", 'idle_calls'), 95 (" .{} : {}", 'idle_sleeps'), 96 (" .{} : {} nsecs", 'idle_entrytime'), 97 (" .{} : {} nsecs", 'idle_waketime'), 98 (" .{} : {} nsecs", 'idle_exittime'), 99 (" .{} : {} nsecs", 'idle_sleeptime'), 100 (" .{}: {} nsecs", 'iowait_sleeptime'), 101 (" .{} : {}", 'last_jiffies'), 102 (" .{} : {}", 'next_timer'), 103 (" .{} : {} nsecs", 'idle_expires')] 104 text += "\n".join([s.format(f, ts[f]) for s, f in fmts]) 105 text += "\njiffies: {}\n".format(jiffies) 106 107 text += "\n" 108 109 return text 110 111 112def print_tickdevice(td, cpu): 113 dev = td['evtdev'] 114 text = "Tick Device: mode: {}\n".format(td['mode']) 115 if cpu < 0: 116 text += "Broadcast device\n" 117 else: 118 text += "Per CPU device: {}\n".format(cpu) 119 120 text += "Clock Event Device: " 121 if dev == 0: 122 text += "<NULL>\n" 123 return text 124 125 text += "{}\n".format(dev['name']) 126 text += " max_delta_ns: {}\n".format(dev['max_delta_ns']) 127 text += " min_delta_ns: {}\n".format(dev['min_delta_ns']) 128 text += " mult: {}\n".format(dev['mult']) 129 text += " shift: {}\n".format(dev['shift']) 130 text += " mode: {}\n".format(dev['state_use_accessors']) 131 text += " next_event: {} nsecs\n".format(dev['next_event']) 132 133 text += " set_next_event: {}\n".format(dev['set_next_event']) 134 135 members = [('set_state_shutdown', " shutdown: {}\n"), 136 ('set_state_periodic', " periodic: {}\n"), 137 ('set_state_oneshot', " oneshot: {}\n"), 138 ('set_state_oneshot_stopped', " oneshot stopped: {}\n"), 139 ('tick_resume', " resume: {}\n")] 140 for member, fmt in members: 141 if dev[member]: 142 text += fmt.format(dev[member]) 143 144 text += " event_handler: {}\n".format(dev['event_handler']) 145 text += " retries: {}\n".format(dev['retries']) 146 147 return text 148 149 150def pr_cpumask(mask): 151 nr_cpu_ids = 1 152 if constants.LX_NR_CPUS > 1: 153 nr_cpu_ids = gdb.parse_and_eval("nr_cpu_ids") 154 155 inf = gdb.inferiors()[0] 156 bits = mask['bits'] 157 num_bytes = (nr_cpu_ids + 7) / 8 158 buf = utils.read_memoryview(inf, bits, num_bytes).tobytes() 159 buf = binascii.b2a_hex(buf) 160 161 chunks = [] 162 i = num_bytes 163 while i > 0: 164 i -= 1 165 start = i * 2 166 end = start + 2 167 chunks.append(buf[start:end]) 168 if i != 0 and i % 4 == 0: 169 chunks.append(',') 170 171 extra = nr_cpu_ids % 8 172 if 0 < extra <= 4: 173 chunks[0] = chunks[0][0] # Cut off the first 0 174 175 return "".join(chunks) 176 177 178class LxTimerList(gdb.Command): 179 """Print /proc/timer_list""" 180 181 def __init__(self): 182 super(LxTimerList, self).__init__("lx-timerlist", gdb.COMMAND_DATA) 183 184 def invoke(self, arg, from_tty): 185 hrtimer_bases = gdb.parse_and_eval("&hrtimer_bases") 186 max_clock_bases = gdb.parse_and_eval("HRTIMER_MAX_CLOCK_BASES") 187 188 text = "Timer List Version: gdb scripts\n" 189 text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format(max_clock_bases) 190 text += "now at {} nsecs\n".format(ktime_get()) 191 192 for cpu in cpus.each_online_cpu(): 193 text += print_cpu(hrtimer_bases, cpu, max_clock_bases) 194 195 if constants.LX_CONFIG_GENERIC_CLOCKEVENTS: 196 if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST: 197 bc_dev = gdb.parse_and_eval("&tick_broadcast_device") 198 text += print_tickdevice(bc_dev, -1) 199 text += "\n" 200 mask = gdb.parse_and_eval("tick_broadcast_mask") 201 mask = pr_cpumask(mask) 202 text += "tick_broadcast_mask: {}\n".format(mask) 203 if constants.LX_CONFIG_TICK_ONESHOT: 204 mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask") 205 mask = pr_cpumask(mask) 206 text += "tick_broadcast_oneshot_mask: {}\n".format(mask) 207 text += "\n" 208 209 tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device") 210 for cpu in cpus.each_online_cpu(): 211 tick_dev = cpus.per_cpu(tick_cpu_devices, cpu) 212 text += print_tickdevice(tick_dev, cpu) 213 text += "\n" 214 215 gdb.write(text) 216 217 218LxTimerList() 219