xref: /freebsd/sys/tools/gdb/freebsd.py (revision ea675a43f09ba569adf1dd17b4f1ced970e48de4)
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