]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
tests: Add mode for running UML kernel under gdb
authorJohannes Berg <johannes.berg@intel.com>
Mon, 13 Jun 2022 13:25:37 +0000 (15:25 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 28 Nov 2022 13:43:00 +0000 (15:43 +0200)
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>
tests/hwsim/vm/linux.gdb [new file with mode: 0644]
tests/hwsim/vm/vm-run.sh

diff --git a/tests/hwsim/vm/linux.gdb b/tests/hwsim/vm/linux.gdb
new file mode 100644 (file)
index 0000000..539d73e
--- /dev/null
@@ -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
index a4d5a8e762e33e2f587bfcfb521e8b2c0c160f82..e891676a4dfdbbbe72349e5fbcd0fb2b71f1865a 100755 (executable)
@@ -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 \