tests: Add mode for running UML kernel under gdb

The new --gdb option can be used when KERNELDIR (and optionally
MODULEDIR) are set and we therefore run UML. It runs the entire
VM under the debugger, with a script to load the right modules
into gdb so you can debug easily.

This needs CONFIG_GDB_SCRIPTS=y to be used in the kernel build.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2022-06-13 15:25:37 +02:00 committed by Jouni Malinen
parent 74874275dc
commit 48c7e04be6
2 changed files with 82 additions and 5 deletions

68
tests/hwsim/vm/linux.gdb Normal file
View file

@ -0,0 +1,68 @@
python
import os, subprocess
kdir = os.environ['KERNELDIR']
mdir = os.environ['MODULEDIR'] or '/lib/modules'
gdb.execute(f'add-auto-load-safe-path {kdir}/scripts/gdb/')
cwd=os.getcwd()
gdb.execute(f'cd {kdir}')
gdb.execute(f'source {kdir}/vmlinux-gdb.py')
p = subprocess.run([f'./linux', '--version'], capture_output=True)
ver = p.stdout.strip().decode('ascii')
gdb.execute(f'cd {cwd}')
end
break os_early_checks
commands
silent
python
gdb.execute(f'cd {kdir}')
gdb.execute(f'lx-symbols {mdir}/{ver}/')
gdb.execute(f'cd {cwd}')
end
# only once
del 1
continue
end
handle 11 nostop noprint pass
#
# So ... this is complicated. When gdb installs a regular breakpoint
# on some place, it writes there a breakpoint instruction (which is
# a single 0xCC byte on x86). This breaks out into the debugger and
# it can then restart/simulate the correct instruction when continuing
# across the breakpoint.
#
# Additionally, gdb (correctly) removes these breakpoint instructions
# from forked children when detaching from them. This also seems fine.
#
# However, due to how user-mode-linux works, this causes issues with
# kernel modules. These are loaded into the vmalloc area, and even if
# that isn't quite part of physmem, it's still mapped as MAP_SHARED.
#
# Unfortunately, this means that gdb deletes breakpoints in modules
# when a new userspace process is started, since that causes a new
# process to be created by clone() and gdb has to detach from it.
#
# The other thing to know is that when gdb hits a breakpoint it will
# restore all the code to normal, and reinstall breakpoints when we
# continue.
#
# Thus we can use that behaviour to work around the module issue:
# simply put a breakpoint on init_new_ldt which happens just after
# the clone() for a new userspace process, and do nothing there but
# continue, which reinstalls all breakpoints, including the ones in
# modules.
#
break init_new_ldt
commands
silent
continue
end
echo \n
echo Welcome to hwsim kernel debugging\n
echo ---------------------------------\n\n
echo You can install breakpoints in modules, they're treated\n
echo as shared libraries, so just say 'y' if asked to make the\n
echo breakpoint pending on future load.\n\n
echo Do NOT, however, delete the breakpoint on 'init_new_ldt'!\n\n
echo Now enter 'run' to start the run.\n\n
echo Have fun!\n\n

View file

@ -62,6 +62,7 @@ TIMESTAMP=$(date +%s)
DATE=$TIMESTAMP DATE=$TIMESTAMP
CODECOV=no CODECOV=no
TIMEWARP=0 TIMEWARP=0
GDB=0
TELNET_QEMU= TELNET_QEMU=
TELNET_ARG=0 TELNET_ARG=0
CODECOV_DIR= CODECOV_DIR=
@ -85,6 +86,9 @@ while [ "$1" != "" ]; do
--timewrap ) shift --timewrap ) shift
TIMEWARP=1 TIMEWARP=1
;; ;;
--gdb ) shift
GDB=1
;;
--telnet ) shift --telnet ) shift
TELNET_ARG=1 TELNET_ARG=1
TELNET_QEMU="-net nic,model=virtio -net user,id=telnet,restrict=on,net=172.16.0.0/24,hostfwd=tcp:127.0.0.1:$1-:23" TELNET_QEMU="-net nic,model=virtio -net user,id=telnet,restrict=on,net=172.16.0.0/24,hostfwd=tcp:127.0.0.1:$1-:23"
@ -162,17 +166,22 @@ fi
A+="ro" A+="ro"
if [ -z $KVM ]; then if [ -z $KVM ]; then
$KERNEL \ UML_ARGS="mem=${MEMORY}M \
mem=${MEMORY}M \
LOGDIR=$LOGDIR \ LOGDIR=$LOGDIR \
time-travel=inf-cpu \ time-travel=inf-cpu \
$A \ $A \
root=none hostfs=/ rootfstype=hostfs rootflags=/ \ root=none hostfs=/ rootfstype=hostfs rootflags=/ \
ssl0=fd:0,fd:1 \ ssl0=fd:0,fd:1 \
ssl1=fd:100 \ ssl1=fd:100 \
ssl-non-raw \ ssl-non-raw"
100<>$LOGDIR/console 2>&1 | \
sed -u '0,/VM has started up/d' if [ "$GDB" = "1" ] ; then
export KERNELDIR=$KERNELDIR
export MODULEDIR=$MODULEDIR
gdb -ex "source linux.gdb" --args $KERNEL $UML_ARGS 100<>$LOGDIR/console
else
$KERNEL $UML_ARGS 100<>$LOGDIR/console 2>&1 | sed -u '0,/VM has started up/d'
fi
else else
$KVM \ $KVM \
-kernel $KERNEL \ -kernel $KERNEL \