1# 2# Copyright (c) 2025 Mark Johnston <markj@FreeBSD.org> 3# 4# SPDX-License-Identifier: BSD-2-Clause 5# 6 7import gdb 8 9 10def symval(name): 11 sym = gdb.lookup_global_symbol(name) 12 if sym is None: 13 sym = gdb.lookup_static_symbol(name) 14 if sym is None: 15 raise gdb.GdbError(f"Symbol '{name}' not found") 16 return sym.value() 17 18 19def _queue_foreach(head, field, headf, nextf): 20 elm = head[headf] 21 while elm != 0: 22 yield elm 23 elm = elm[field][nextf] 24 25 26def list_foreach(head, field): 27 """sys/queue.h-style iterator.""" 28 return _queue_foreach(head, field, "lh_first", "le_next") 29 30 31def tailq_foreach(head, field): 32 """sys/queue.h-style iterator.""" 33 return _queue_foreach(head, field, "tqh_first", "tqe_next") 34 35 36def linker_file_foreach(): 37 """Iterate over loaded linker files.""" 38 return tailq_foreach(symval("linker_files"), "link") 39 40 41def pcpu_foreach(): 42 mp_maxid = symval("mp_maxid") 43 cpuid_to_pcpu = symval("cpuid_to_pcpu") 44 45 cpu = 0 46 while cpu <= mp_maxid: 47 pcpu = cpuid_to_pcpu[cpu] 48 if pcpu: 49 yield pcpu 50 cpu = cpu + 1 51 52 53def tid_to_gdb_thread(tid): 54 """Convert a FreeBSD kernel thread ID to a gdb inferior thread.""" 55 for thread in gdb.inferiors()[0].threads(): 56 if thread.ptid[2] == tid: 57 return thread 58 else: 59 return None 60 61 62def tdfind(tid, pid=-1): 63 """Convert a FreeBSD kernel thread ID to a struct thread pointer.""" 64 td = tdfind.cached_threads.get(int(tid)) 65 if td: 66 return td 67 68 for p in list_foreach(symval("allproc"), "p_list"): 69 if pid != -1 and pid != p['p_pid']: 70 continue 71 for td in tailq_foreach(p['p_threads'], "td_plist"): 72 ntid = td['td_tid'] 73 tdfind.cached_threads[int(ntid)] = td 74 if ntid == tid: 75 return td 76 77 78tdfind.cached_threads = dict() 79