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