1*ea675a43SMark Johnston# 2*ea675a43SMark Johnston# Copyright (c) 2025 Mark Johnston <markj@FreeBSD.org> 3*ea675a43SMark Johnston# 4*ea675a43SMark Johnston# SPDX-License-Identifier: BSD-2-Clause 5*ea675a43SMark Johnston# 6*ea675a43SMark Johnston 7*ea675a43SMark Johnstonimport gdb 8*ea675a43SMark Johnstonfrom freebsd import * 9*ea675a43SMark Johnston 10*ea675a43SMark Johnstonclass pcpu(gdb.Function): 11*ea675a43SMark Johnston """ 12*ea675a43SMark Johnston Register a function to lookup PCPU and DPCPU variables by name. 13*ea675a43SMark Johnston 14*ea675a43SMark Johnston To look up the value of the PCPU field foo on CPU n, use 15*ea675a43SMark Johnston $PCPU("foo", n). This works for DPCPU fields too. If the CPU ID is 16*ea675a43SMark Johnston omitted, and the currently selected thread is on-CPU, that CPU is 17*ea675a43SMark Johnston used, otherwise an error is raised. 18*ea675a43SMark Johnston """ 19*ea675a43SMark Johnston def __init__(self): 20*ea675a43SMark Johnston super(pcpu, self).__init__("PCPU") 21*ea675a43SMark Johnston 22*ea675a43SMark Johnston def invoke(self, field, cpuid=-1): 23*ea675a43SMark Johnston if cpuid == -1: 24*ea675a43SMark Johnston cpuid = tdfind(gdb.selected_thread().ptid[2])['td_oncpu'] 25*ea675a43SMark Johnston if cpuid == -1: 26*ea675a43SMark Johnston raise gdb.error("Currently selected thread is off-CPU") 27*ea675a43SMark Johnston if cpuid < 0 or cpuid > symval("mp_maxid"): 28*ea675a43SMark Johnston raise gdb.error(f"Currently selected on invalid CPU {cpuid}") 29*ea675a43SMark Johnston pcpu = symval("cpuid_to_pcpu")[cpuid] 30*ea675a43SMark Johnston 31*ea675a43SMark Johnston # Are we dealing with a PCPU or DPCPU field? 32*ea675a43SMark Johnston field = field.string() 33*ea675a43SMark Johnston for f in gdb.lookup_type("struct pcpu").fields(): 34*ea675a43SMark Johnston if f.name == "pc_" + field: 35*ea675a43SMark Johnston return pcpu["pc_" + field] 36*ea675a43SMark Johnston 37*ea675a43SMark Johnston def uintptr_t(val): 38*ea675a43SMark Johnston return val.cast(gdb.lookup_type("uintptr_t")) 39*ea675a43SMark Johnston 40*ea675a43SMark Johnston # We're dealing with a DPCPU field. This is handled similarly 41*ea675a43SMark Johnston # to VNET symbols, see vnet.py for comments. 42*ea675a43SMark Johnston pcpu_base = pcpu['pc_dynamic'] 43*ea675a43SMark Johnston pcpu_entry = symval("pcpu_entry_" + field) 44*ea675a43SMark Johnston pcpu_entry_addr = uintptr_t(pcpu_entry.address) 45*ea675a43SMark Johnston 46*ea675a43SMark Johnston for lf in linker_file_foreach(): 47*ea675a43SMark Johnston block = gdb.block_for_pc(lf['ops']['cls']['methods'][0]['func']) 48*ea675a43SMark Johnston elf_file_t = gdb.lookup_type("elf_file_t", block).target() 49*ea675a43SMark Johnston ef = lf.cast(elf_file_t) 50*ea675a43SMark Johnston 51*ea675a43SMark Johnston file_type = lf['ops']['cls']['name'].string() 52*ea675a43SMark Johnston if file_type == "elf64": 53*ea675a43SMark Johnston start = uintptr_t(ef['pcpu_start']) 54*ea675a43SMark Johnston if start == 0: 55*ea675a43SMark Johnston continue 56*ea675a43SMark Johnston end = uintptr_t(ef['pcpu_stop']) 57*ea675a43SMark Johnston base = uintptr_t(ef['pcpu_base']) 58*ea675a43SMark Johnston elif file_type == "elf64_obj": 59*ea675a43SMark Johnston for i in range(ef['nprogtab']): 60*ea675a43SMark Johnston pe = ef['progtab'][i] 61*ea675a43SMark Johnston if pe['name'].string() == "set_pcpu": 62*ea675a43SMark Johnston start = uintptr_t(pe['origaddr']) 63*ea675a43SMark Johnston end = start + uintptr_t(pe['size']) 64*ea675a43SMark Johnston base = uintptr_t(pe['addr']) 65*ea675a43SMark Johnston break 66*ea675a43SMark Johnston else: 67*ea675a43SMark Johnston continue 68*ea675a43SMark Johnston else: 69*ea675a43SMark Johnston path = lf['pathname'].string() 70*ea675a43SMark Johnston raise gdb.error(f"{path} has unexpected linker file type {file_type}") 71*ea675a43SMark Johnston 72*ea675a43SMark Johnston if pcpu_entry_addr >= start and pcpu_entry_addr < end: 73*ea675a43SMark Johnston obj = gdb.Value(pcpu_base + pcpu_entry_addr - start + base) 74*ea675a43SMark Johnston return obj.cast(pcpu_entry.type.pointer()).dereference() 75*ea675a43SMark Johnston 76*ea675a43SMark Johnston# Register with gdb. 77*ea675a43SMark Johnstonpcpu() 78