diff mbox series

[v2] tests: hwsim: vm-run: add mode for running under gdb

Message ID 20220613133447.ace3da88d425.Ic1fccb979199d4f33e048e9361dd4231e421d4ab@changeid
State Superseded
Headers show
Series [v2] tests: hwsim: vm-run: add mode for running under gdb | expand

Commit Message

Johannes Berg June 13, 2022, 11:34 a.m. UTC
From: Johannes Berg <johannes.berg@intel.com>

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.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 tests/hwsim/vm/linux.gdb | 68 ++++++++++++++++++++++++++++++++++++++++
 tests/hwsim/vm/vm-run.sh | 19 ++++++++---
 2 files changed, 82 insertions(+), 5 deletions(-)
 create mode 100644 tests/hwsim/vm/linux.gdb
diff mbox series

Patch

diff --git a/tests/hwsim/vm/linux.gdb b/tests/hwsim/vm/linux.gdb
new file mode 100644
index 000000000000..539d73e5659d
--- /dev/null
+++ b/tests/hwsim/vm/linux.gdb
@@ -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
diff --git a/tests/hwsim/vm/vm-run.sh b/tests/hwsim/vm/vm-run.sh
index defea43e8723..0978581b47f2 100755
--- a/tests/hwsim/vm/vm-run.sh
+++ b/tests/hwsim/vm/vm-run.sh
@@ -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 \