diff --git a/README.md b/README.md index a7da065..5087fb0 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ which are `printk` messages from `init` and `cleanup` methods of those modules. Each module comes from a C file under `kernel_module/`. For module usage see: - head kernel_module/*.c + head kernel_module/modulename.c Good bets inside guest are: @@ -211,6 +211,62 @@ ARM TODOs: - - +## KGDB + +KGDB is kernel dark magic that allows you to GDB the kernel on real hardware without any extra hardware support. + +It is useless with QEMU since we already have full system visibility with `-gdb`, but this is a good way to learn it. + +Cheaper than JTAG (free) and easier to setup (no wires), but with less visibility as it depends on the kernel working, so e.g.: dies on panic, does not see boot sequence. + +Usage: + + ./runqemu -k + ./rungdb -k + +In GDB: + + c + +In QEMU: + + /count.sh & + /kgdb.sh + +In GDB: + + b sys_write + c + c + c + c + +And now you can count from GDB! + +If you do: `b sys_write` immediately after `./rungdb -k`, it fails with `KGDB: BP remove failed:
`. I think this is because it would break too early on the boot sequence, and KGDB is not yet ready. + +See also: + +- + +### KGDB kernel modules + +In QEMU: + + /kgdb-mod.sh + +In GDB: + + lx-symbols ../kernel_module-1.0/ + b fop_write + c + c + c + +and you now control the count. + +TODO: if I `-ex lx-symbols` to the `gdb` command, just like done for QEMU `-gdb`, the kernel oops. How to automate this step? + ## Table of contents 1. [Introduction](introduction.md) diff --git a/kernel_config_fragment b/kernel_config_fragment index a85dbbc..3678a68 100644 --- a/kernel_config_fragment +++ b/kernel_config_fragment @@ -5,3 +5,18 @@ CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_INFO=y CONFIG_GDB_SCRIPTS=y + +# KGDB. +CONFIG_CONSOLE_POLL=y +CONFIG_KDB_CONTINUE_CATASTROPHIC=0 +CONFIG_KDB_DEFAULT_ENABLE=0x1 +CONFIG_KDB_KEYBOARD=y +CONFIG_KGDB=y +CONFIG_KGDB_KDB=y +CONFIG_KGDB_LOW_LEVEL_TRAP=y +CONFIG_KGDB_SERIAL_CONSOLE=y +CONFIG_KGDB_TESTS=y +CONFIG_KGDB_TESTS_ON_BOOT=n +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_SERIAL_KGDB_NMI=n diff --git a/rootfs_overlay/kgdb-mod.sh b/rootfs_overlay/kgdb-mod.sh new file mode 100755 index 0000000..3e3940f --- /dev/null +++ b/rootfs_overlay/kgdb-mod.sh @@ -0,0 +1,9 @@ +#!/bin/sh +insmod /fops.ko +cd /sys/kernel/debug/kernel_module_cheat +i=0 +while true; do + printf "$i" >fops + i=$(($i+1)) +done & +/kgdb.sh diff --git a/rootfs_overlay/kgdb.sh b/rootfs_overlay/kgdb.sh new file mode 100755 index 0000000..b7b7409 --- /dev/null +++ b/rootfs_overlay/kgdb.sh @@ -0,0 +1,2 @@ +#!/bin/sh +echo g > /proc/sysrq-trigger diff --git a/rungdb b/rungdb index 438a2bc..7017253 100755 --- a/rungdb +++ b/rungdb @@ -3,11 +3,15 @@ set -e arch=x86_64 -while getopts a: OPT; do +kgdb=false +while getopts a:k OPT; do case "$OPT" in a) arch=$OPTARG ;; + k) + kgdb=true + ;; esac done shift "$(($OPTIND - 1))" @@ -19,33 +23,42 @@ fi gdb="$(pwd)/buildroot/output/host/usr/bin/${arch}-linux-gdb" cd buildroot/output/build/linux-*.*.*/ -case "$arch" in - x86_64) - # http://stackoverflow.com/questions/11408041/how-to-debug-the-linux-kernel-with-gdb-and-qemu/33203642#33203642 - # http://stackoverflow.com/questions/4943857/linux-kernel-live-debugging-how-its-done-and-what-tools-are-used/42316607#42316607 - # http://stackoverflow.com/questions/28607538/how-to-debug-linux-kernel-modules-with-qemu/44095831#44095831 +if $kgdb; then cmd="$gdb \ -q \ -ex 'add-auto-load-safe-path $(pwd)' \ -ex 'file vmlinux' \ - -ex 'set arch i386:x86-64:intel' \ - -ex 'target remote localhost:1234' \ - $brk \ - -ex 'continue' \ - -ex 'disconnect' \ - -ex 'set arch i386:x86-64' \ - -ex 'target remote localhost:1234' \ - -ex 'lx-symbols ../kernel_module-1.0/' + -ex 'target remote localhost:1234' " - ;; - arm) - cmd="$gdb \ - -q \ - -ex 'add-auto-load-safe-path $(pwd)' \ - -ex 'file vmlinux' \ - -ex 'target remote localhost:1234' \ - -ex 'lx-symbols ../kernel_module-1.0/' - " - ;; -esac +else + case "$arch" in + x86_64) + # http://stackoverflow.com/questions/11408041/how-to-debug-the-linux-kernel-with-gdb-and-qemu/33203642#33203642 + # http://stackoverflow.com/questions/4943857/linux-kernel-live-debugging-how-its-done-and-what-tools-are-used/42316607#42316607 + # http://stackoverflow.com/questions/28607538/how-to-debug-linux-kernel-modules-with-qemu/44095831#44095831 + cmd="$gdb \ + -q \ + -ex 'add-auto-load-safe-path $(pwd)' \ + -ex 'file vmlinux' \ + -ex 'set arch i386:x86-64:intel' \ + -ex 'target remote localhost:1234' \ + $brk \ + -ex 'continue' \ + -ex 'disconnect' \ + -ex 'set arch i386:x86-64' \ + -ex 'target remote localhost:1234' \ + -ex 'lx-symbols ../kernel_module-1.0/' + " + ;; + arm) + cmd="$gdb \ + -q \ + -ex 'add-auto-load-safe-path $(pwd)' \ + -ex 'file vmlinux' \ + -ex 'target remote localhost:1234' \ + -ex 'lx-symbols ../kernel_module-1.0/' + " + ;; + esac +fi eval "$cmd" diff --git a/runqemu b/runqemu index 69c1eb9..5bc1913 100755 --- a/runqemu +++ b/runqemu @@ -8,7 +8,7 @@ debug=false nographic=false extra_append='' extra_flags='' -while getopts a:dn OPT; do +while getopts a:dkn OPT; do case "$OPT" in a) arch=$OPTARG @@ -17,6 +17,11 @@ while getopts a:dn OPT; do debug=true extra_flags="$extra_flags -S -s" ;; + k) + debug=true + extra_append="$extra_append kgdbwait kgdboc=ttyS0,115200" + extra_flags="$extra_flags -serial tcp::1234,server,nowait" + ;; n) extra_append="$extra_append console=ttyS0" extra_flags="$extra_flags -nographic"