libexec/kgdb: Add new modules and install them together with debug info

This change simplifies integration of gdb python scripts with our kernel
debugging infrastructure.  Rather than putting debugging scripts in
/usr/libexec/kgdb, move them to <path-to-kernel-debug-symbols>/gdb, and
add a kernel-gdb.py which automatically loads modules from that
directory.  kernel-gdb.py will be automatically executed by kgdb when
loading kernel debug symbols (assuming a default configuration), so one
no longer needs to do anything to use these modules.

The change also adds a couple of new modules, vnet.py and pcpu.py, for
conveniently accessing VNET symbols and PCPU/DPCPU fields, respectively.
Note that these require a change to the kernel linker when accessing
symbols from a loadable kernel module.

sys/tools/gdb/README.txt describes the scheme in more detail and
provides some rudiementary documentation for the commands and functions
added by these modules.  It should be updated when adding new features.

sys/tools/gdb/selftest.py can be used to do some primitive testing of
the modules.  All it does is execute a number of gdb commands making use
of commands and functions added by these modules.  The developer is
expected to verify that the commands complete without errors and that
the output looks sane.

Discussed with:	kp, avg, jhb, glebius
MFC after:	2 weeks
Differential Revision:	https://reviews.freebsd.org/D50825
This commit is contained in:
Mark Johnston
2025-10-03 14:25:53 +00:00
parent 07747afd51
commit ea675a43f0
14 changed files with 374 additions and 39 deletions
-1
View File
@@ -10,7 +10,6 @@ SUBDIR= ${_atf} \
flua \
getty \
${_hyperv} \
kgdb \
${_mail.local} \
${_makewhatis.local} \
${_mknetid} \
-5
View File
@@ -1,5 +0,0 @@
FILESDIR?= /usr/libexec/kgdb
FILES= acttrace.py
.include <bsd.prog.mk>
-63
View File
@@ -1,63 +0,0 @@
#-
# Copyright (c) 2022 The FreeBSD Foundation
#
# This software was developed by Mark Johnston under sponsorship from the
# FreeBSD Foundation.
#
import gdb
def symval(name):
return gdb.lookup_global_symbol(name).value()
def tid_to_gdb_thread(tid):
for thread in gdb.inferiors()[0].threads():
if thread.ptid[2] == tid:
return thread
else:
return None
def all_pcpus():
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
class acttrace(gdb.Command):
def __init__(self):
super(acttrace, self).__init__("acttrace", gdb.COMMAND_USER)
def invoke(self, arg, from_tty):
# Save the current thread so that we can switch back after.
curthread = gdb.selected_thread()
for pcpu in all_pcpus():
td = pcpu['pc_curthread']
tid = td['td_tid']
gdb_thread = tid_to_gdb_thread(tid)
if gdb_thread is None:
print("failed to find GDB thread with TID {}".format(tid))
else:
gdb_thread.switch()
p = td['td_proc']
print("Tracing command {} pid {} tid {} (CPU {})".format(
p['p_comm'], p['p_pid'], td['td_tid'], pcpu['pc_cpuid']))
gdb.execute("bt")
print()
curthread.switch()
# Registers the command with gdb, doesn't do anything.
acttrace()