import gdb
def symval(name):
sym = gdb.lookup_global_symbol(name)
if sym is None:
sym = gdb.lookup_static_symbol(name)
if sym is None:
raise gdb.GdbError(f"Symbol '{name}' not found")
return sym.value()
def _queue_foreach(head, field, headf, nextf):
elm = head[headf]
while elm != 0:
yield elm
elm = elm[field][nextf]
def list_foreach(head, field):
"""sys/queue.h-style iterator."""
return _queue_foreach(head, field, "lh_first", "le_next")
def tailq_foreach(head, field):
"""sys/queue.h-style iterator."""
return _queue_foreach(head, field, "tqh_first", "tqe_next")
def linker_file_foreach():
"""Iterate over loaded linker files."""
return tailq_foreach(symval("linker_files"), "link")
def pcpu_foreach():
mp_maxid = symval("mp_maxid")
cpuid_to_pcpu = symval("cpuid_to_pcpu")
cpu = 0
while cpu <= mp_maxid:
pcpu = cpuid_to_pcpu[cpu]
if pcpu:
yield pcpu
cpu = cpu + 1
def tid_to_gdb_thread(tid):
"""Convert a FreeBSD kernel thread ID to a gdb inferior thread."""
for thread in gdb.inferiors()[0].threads():
if thread.ptid[2] == tid:
return thread
else:
return None
def tdfind(tid, pid=-1):
"""Convert a FreeBSD kernel thread ID to a struct thread pointer."""
td = tdfind.cached_threads.get(int(tid))
if td:
return td
for p in list_foreach(symval("allproc"), "p_list"):
if pid != -1 and pid != p['p_pid']:
continue
for td in tailq_foreach(p['p_threads'], "td_plist"):
ntid = td['td_tid']
tdfind.cached_threads[int(ntid)] = td
if ntid == tid:
return td
tdfind.cached_threads = dict()