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:
parent
74874275dc
commit
48c7e04be6
2 changed files with 82 additions and 5 deletions
68
tests/hwsim/vm/linux.gdb
Normal file
68
tests/hwsim/vm/linux.gdb
Normal 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
|
|
@ -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 \
|
||||||
|
|
Loading…
Reference in a new issue