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