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
|
||||
CODECOV=no
|
||||
TIMEWARP=0
|
||||
GDB=0
|
||||
TELNET_QEMU=
|
||||
TELNET_ARG=0
|
||||
CODECOV_DIR=
|
||||
|
@ -85,6 +86,9 @@ while [ "$1" != "" ]; do
|
|||
--timewrap ) shift
|
||||
TIMEWARP=1
|
||||
;;
|
||||
--gdb ) shift
|
||||
GDB=1
|
||||
;;
|
||||
--telnet ) shift
|
||||
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"
|
||||
|
@ -162,17 +166,22 @@ fi
|
|||
A+="ro"
|
||||
|
||||
if [ -z $KVM ]; then
|
||||
$KERNEL \
|
||||
mem=${MEMORY}M \
|
||||
UML_ARGS="mem=${MEMORY}M \
|
||||
LOGDIR=$LOGDIR \
|
||||
time-travel=inf-cpu \
|
||||
$A \
|
||||
root=none hostfs=/ rootfstype=hostfs rootflags=/ \
|
||||
ssl0=fd:0,fd:1 \
|
||||
ssl1=fd:100 \
|
||||
ssl-non-raw \
|
||||
100<>$LOGDIR/console 2>&1 | \
|
||||
sed -u '0,/VM has started up/d'
|
||||
ssl-non-raw"
|
||||
|
||||
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
|
||||
$KVM \
|
||||
-kernel $KERNEL \
|
||||
|
|
Loading…
Reference in a new issue