1fe7f9ed9SJan Kiszka# 2fe7f9ed9SJan Kiszka# gdb helper commands and functions for Linux kernel debugging 3fe7f9ed9SJan Kiszka# 4fe7f9ed9SJan Kiszka# per-cpu tools 5fe7f9ed9SJan Kiszka# 6fe7f9ed9SJan Kiszka# Copyright (c) Siemens AG, 2011-2013 7fe7f9ed9SJan Kiszka# 8fe7f9ed9SJan Kiszka# Authors: 9fe7f9ed9SJan Kiszka# Jan Kiszka <jan.kiszka@siemens.com> 10fe7f9ed9SJan Kiszka# 11fe7f9ed9SJan Kiszka# This work is licensed under the terms of the GNU GPL version 2. 12fe7f9ed9SJan Kiszka# 13fe7f9ed9SJan Kiszka 14fe7f9ed9SJan Kiszkaimport gdb 15fe7f9ed9SJan Kiszka 16fe7f9ed9SJan Kiszkafrom linux import tasks, utils 17fe7f9ed9SJan Kiszka 18fe7f9ed9SJan Kiszka 19fe7f9ed9SJan KiszkaMAX_CPUS = 4096 20fe7f9ed9SJan Kiszka 21fe7f9ed9SJan Kiszka 22fe7f9ed9SJan Kiszkadef get_current_cpu(): 23fe7f9ed9SJan Kiszka if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU: 24fe7f9ed9SJan Kiszka return gdb.selected_thread().num - 1 25fe7f9ed9SJan Kiszka elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB: 26fe7f9ed9SJan Kiszka tid = gdb.selected_thread().ptid[2] 27fe7f9ed9SJan Kiszka if tid > (0x100000000 - MAX_CPUS - 2): 28fe7f9ed9SJan Kiszka return 0x100000000 - tid - 2 29fe7f9ed9SJan Kiszka else: 30fe7f9ed9SJan Kiszka return tasks.get_thread_info(tasks.get_task_by_pid(tid))['cpu'] 31fe7f9ed9SJan Kiszka else: 32fe7f9ed9SJan Kiszka raise gdb.GdbError("Sorry, obtaining the current CPU is not yet " 33fe7f9ed9SJan Kiszka "supported with this gdb server.") 34fe7f9ed9SJan Kiszka 35fe7f9ed9SJan Kiszka 36fe7f9ed9SJan Kiszkadef per_cpu(var_ptr, cpu): 37fe7f9ed9SJan Kiszka if cpu == -1: 38fe7f9ed9SJan Kiszka cpu = get_current_cpu() 39fe7f9ed9SJan Kiszka if utils.is_target_arch("sparc:v9"): 40fe7f9ed9SJan Kiszka offset = gdb.parse_and_eval( 41fe7f9ed9SJan Kiszka "trap_block[{0}].__per_cpu_base".format(str(cpu))) 42fe7f9ed9SJan Kiszka else: 43fe7f9ed9SJan Kiszka try: 44fe7f9ed9SJan Kiszka offset = gdb.parse_and_eval( 45fe7f9ed9SJan Kiszka "__per_cpu_offset[{0}]".format(str(cpu))) 46fe7f9ed9SJan Kiszka except gdb.error: 47fe7f9ed9SJan Kiszka # !CONFIG_SMP case 48fe7f9ed9SJan Kiszka offset = 0 49fe7f9ed9SJan Kiszka pointer = var_ptr.cast(utils.get_long_type()) + offset 50fe7f9ed9SJan Kiszka return pointer.cast(var_ptr.type).dereference() 51fe7f9ed9SJan Kiszka 52fe7f9ed9SJan Kiszka 533d4cd9c9SJan Kiszkacpu_mask = {} 543d4cd9c9SJan Kiszka 553d4cd9c9SJan Kiszka 563d4cd9c9SJan Kiszkadef cpu_mask_invalidate(event): 573d4cd9c9SJan Kiszka global cpu_mask 583d4cd9c9SJan Kiszka cpu_mask = {} 593d4cd9c9SJan Kiszka gdb.events.stop.disconnect(cpu_mask_invalidate) 603d4cd9c9SJan Kiszka if hasattr(gdb.events, 'new_objfile'): 613d4cd9c9SJan Kiszka gdb.events.new_objfile.disconnect(cpu_mask_invalidate) 623d4cd9c9SJan Kiszka 633d4cd9c9SJan Kiszka 64*a77e15e8SJan Kiszkadef cpu_list(mask_name): 653d4cd9c9SJan Kiszka global cpu_mask 66*a77e15e8SJan Kiszka mask = None 673d4cd9c9SJan Kiszka if mask_name in cpu_mask: 68*a77e15e8SJan Kiszka mask = cpu_mask[mask_name] 69*a77e15e8SJan Kiszka if mask is None: 70*a77e15e8SJan Kiszka mask = gdb.parse_and_eval(mask_name + ".bits") 713d4cd9c9SJan Kiszka if hasattr(gdb, 'events'): 72*a77e15e8SJan Kiszka cpu_mask[mask_name] = mask 733d4cd9c9SJan Kiszka gdb.events.stop.connect(cpu_mask_invalidate) 743d4cd9c9SJan Kiszka if hasattr(gdb.events, 'new_objfile'): 753d4cd9c9SJan Kiszka gdb.events.new_objfile.connect(cpu_mask_invalidate) 76*a77e15e8SJan Kiszka bits_per_entry = mask[0].type.sizeof * 8 77*a77e15e8SJan Kiszka num_entries = mask.type.sizeof * 8 / bits_per_entry 78*a77e15e8SJan Kiszka entry = -1 79*a77e15e8SJan Kiszka bits = 0 803d4cd9c9SJan Kiszka 81*a77e15e8SJan Kiszka while True: 82*a77e15e8SJan Kiszka while bits == 0: 83*a77e15e8SJan Kiszka entry += 1 84*a77e15e8SJan Kiszka if entry == num_entries: 85*a77e15e8SJan Kiszka return 86*a77e15e8SJan Kiszka bits = mask[entry] 87*a77e15e8SJan Kiszka if bits != 0: 88*a77e15e8SJan Kiszka bit = 0 893d4cd9c9SJan Kiszka break 903d4cd9c9SJan Kiszka 91*a77e15e8SJan Kiszka while bits & 1 == 0: 92*a77e15e8SJan Kiszka bits >>= 1 93*a77e15e8SJan Kiszka bit += 1 943d4cd9c9SJan Kiszka 95*a77e15e8SJan Kiszka cpu = entry * bits_per_entry + bit 963d4cd9c9SJan Kiszka 97*a77e15e8SJan Kiszka bits >>= 1 98*a77e15e8SJan Kiszka bit += 1 993d4cd9c9SJan Kiszka 100*a77e15e8SJan Kiszka yield cpu 101276d97d9SPantelis Koukousoulas 1023d4cd9c9SJan Kiszka 103fe7f9ed9SJan Kiszkaclass PerCpu(gdb.Function): 104fe7f9ed9SJan Kiszka """Return per-cpu variable. 105fe7f9ed9SJan Kiszka 106fe7f9ed9SJan Kiszka$lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the 107fe7f9ed9SJan Kiszkagiven CPU number. If CPU is omitted, the CPU of the current context is used. 108fe7f9ed9SJan KiszkaNote that VAR has to be quoted as string.""" 109fe7f9ed9SJan Kiszka 110fe7f9ed9SJan Kiszka def __init__(self): 111fe7f9ed9SJan Kiszka super(PerCpu, self).__init__("lx_per_cpu") 112fe7f9ed9SJan Kiszka 113fe7f9ed9SJan Kiszka def invoke(self, var_name, cpu=-1): 114fe7f9ed9SJan Kiszka var_ptr = gdb.parse_and_eval("&" + var_name.string()) 115fe7f9ed9SJan Kiszka return per_cpu(var_ptr, cpu) 116fe7f9ed9SJan Kiszka 117fe7f9ed9SJan Kiszka 118fe7f9ed9SJan KiszkaPerCpu() 119116b47b4SJan Kiszka 120116b47b4SJan Kiszka 121116b47b4SJan Kiszkaclass LxCurrentFunc(gdb.Function): 122116b47b4SJan Kiszka """Return current task. 123116b47b4SJan Kiszka 124116b47b4SJan Kiszka$lx_current([CPU]): Return the per-cpu task variable for the given CPU 125116b47b4SJan Kiszkanumber. If CPU is omitted, the CPU of the current context is used.""" 126116b47b4SJan Kiszka 127116b47b4SJan Kiszka def __init__(self): 128116b47b4SJan Kiszka super(LxCurrentFunc, self).__init__("lx_current") 129116b47b4SJan Kiszka 130116b47b4SJan Kiszka def invoke(self, cpu=-1): 131116b47b4SJan Kiszka var_ptr = gdb.parse_and_eval("¤t_task") 132116b47b4SJan Kiszka return per_cpu(var_ptr, cpu).dereference() 133116b47b4SJan Kiszka 134116b47b4SJan Kiszka 135116b47b4SJan KiszkaLxCurrentFunc() 136