diff --git a/README.md b/README.md index 5e53022..506f338 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # Linux Kernel Module Cheat -Run one command, get into QEMU Buildroot BusyBox with several minimal Linux kernel 4.9 module example tutorials. Tested in Ubuntu 14.04. +Run one command, get into QEMU Buildroot BusyBox with several minimal Linux kernel 4.9 module example tutorials. Tested in Ubuntu 14.04 host. Usage: + sudo apt-get install qemu ./run First build will take a while (GCC, Linux kernel). @@ -22,19 +23,72 @@ Each module comes from a C file under `kernel_module/`. For module usage do: grep BR2_LINUX_KERNEL_VERSION buildroot/.config +After the first build, you can also run just: + + ./runqemu + +to save a few seconds. `./run` wouldn't rebuild everything, but checking timestamps takes a few moments. + We use `printk` a lot, and it shows on the QEMU terminal by default. If that annoys you (e.g. you want to see stdout separately), do: dmesg -n 1 See also: -When your kernel starts crashing, get the full trace with: +## Debugging + +GDB the linux kernel: + + ./runqemu -d + +If you want to break immediately at a symbol, e.g. `start_kernel` of the boot sequence, open another terminal and run for example: + + ./rungdb start_kernel + +Now QEMU will stop there, and you can use the normal GDB commands: + + l + n + c + +To skip the boot, run just: + + ./rungdb + +and when you want to break, do `Ctrl + C` from GDB. + +To have some fun, you can first run inside QEMU: + + /count.sh + +which counts to infinity to stdout, and then: + + Ctrl + C + break sys_write + +And now you can control the counting from GDB: + + continue + continue + continue + +## Text mode + +Show serial output of QEMU directly on the current terminal, without opening a QEMU window: ./run -n +To exit, just do a regular: + + poweroff + +This is particularly useful to get full panic traces when you start making the kernel crashing :-) + +In case of a panic, you want your terminal back with `Ctrl + C, A` and type `quit`. See also: + See also: -Then if you want your terminal back, hit `Ctrl + C, A` and type `quit`. See also: +## Table of contents 1. [Introduction](introduction.md) 1. [Build](build.md) diff --git a/kernel_config_fragment b/kernel_config_fragment index f9aa7f7..a85dbbc 100644 --- a/kernel_config_fragment +++ b/kernel_config_fragment @@ -1,4 +1,7 @@ # If you change this file, you need to run: # rm -rf buildroot/output/build/linux-*.*.*/ # before ./run +CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_FS=y +CONFIG_DEBUG_INFO=y +CONFIG_GDB_SCRIPTS=y diff --git a/rootfs_overlay/count.sh b/rootfs_overlay/count.sh new file mode 100755 index 0000000..d084b81 --- /dev/null +++ b/rootfs_overlay/count.sh @@ -0,0 +1,8 @@ +#!/bin/sh +# Generate infinitely many system calls :-) +i=0 +while true; do + echo "$i" + i=$(($i+1)) + sleep 1 +done diff --git a/run b/run index c16b9dd..8161f3f 100755 --- a/run +++ b/run @@ -1,36 +1,8 @@ #!/usr/bin/env bash set -e - -# CLI handling. -nographic=false -while getopts n OPT; do - case "$OPT" in - n) - nographic=true - ;; - esac -done -if $nographic; then - extra_append='console=ttyS0' - extra_flags='-nographic' -else - extra_append='' - extra_flags='' -fi - -# Work. cd buildroot make BR2_EXTERNAL="$(pwd)/../kernel_module" qemu_x86_64_defconfig cat ../buildroot_config_fragment >> .config env -u LD_LIBRARY_PATH make BR2_JLEVEL="$(($(nproc) - 2))" kernel_module-rebuild all -qemu-system-x86_64 \ - -M pc \ - -append "root=/dev/vda $extra_append" \ - -drive file=output/images/rootfs.ext2,if=virtio,format=raw \ - -kernel output/images/bzImage \ - -m 128M \ - -net nic,model=virtio \ - -net user \ - -smp 1 \ - $extra_flags \ -; +cd .. +./runqemu "$@" diff --git a/rungdb b/rungdb new file mode 100755 index 0000000..5f159b5 --- /dev/null +++ b/rungdb @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +if [ "$#" -gt 0 ]; then + brk="-ex 'break $1'" +else + brk="" +fi +cd buildroot/output/build/linux-*.*.*/ +cmd="gdb \ + -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' +" +echo "$cmd" +eval "$cmd" diff --git a/runqemu b/runqemu new file mode 100755 index 0000000..0cbb7d0 --- /dev/null +++ b/runqemu @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +set -e + +# CLI handling. +extra_append='' +extra_flags='' +while getopts dn OPT; do + case "$OPT" in + d) + extra_flags="$extra_flags -S -s" + ;; + n) + extra_append="$extra_append console=ttyS0" + extra_flags="$extra_flags -nographic" + ;; + esac +done + +qemu-system-x86_64 \ + -M pc \ + -append "root=/dev/vda $extra_append" \ + -drive file=buildroot/output/images/rootfs.ext2,if=virtio,format=raw \ + -kernel buildroot/output/images/bzImage \ + -m 128M \ + -net nic,model=virtio \ + -net user \ + -smp 1 \ + $extra_flags \ +;