This commit is contained in:
Ciro Santilli
2017-05-21 12:30:43 +01:00
parent f628c6e07f
commit 960eca1008
6 changed files with 142 additions and 35 deletions

View File

@@ -1,6 +1,6 @@
# Linux Kernel Module Cheat
Run one command, get into QEMU Buildroot BusyBox with several minimal Linux kernel 4.9 module example tutorials with GDB debug support. Tested in Ubuntu 14.04 - 16.10 hosts.
Run one command, get into QEMU Buildroot BusyBox with several minimal Linux kernel 4.9 module example tutorials with GDB debug support. x86 and ARM guests supported. Tested in Ubuntu 14.04 - 16.10 hosts.
Usage:
@@ -176,6 +176,37 @@ And then tell GDB where the module was loaded with:
Ctrl + C
add-symbol-file ../kernel_module-1.0/fops.ko 0xfffffffa00000000
## ARM
The portability of the kernel and toolchains is amazing.
If you already have an x86 build present, first:
cd buildroot
mv output output.x86~
First ARM build:
./run -a arm
Run without build:
./runqemu -a arm
Debug:
./runqemu -a arm -d
# On another terminal.
./rungdb -a arm
ARM TODOs:
- only managed to run in the terminal interface (but weirdly an blank QEMU window is still opened)
- Ctrl + C kills the emulator, not sent to guest. See:
- <https://github.com/cloudius-systems/osv/issues/49>
- <https://unix.stackexchange.com/questions/167165/how-to-pass-ctrl-c-in-qemu>
- `fops.ko`, `printf a >fops` crashes with `BUG: recent printk recursion!`
## Table of contents
1. [Introduction](introduction.md)

View File

@@ -9,7 +9,14 @@ KERNEL_MODULE_SITE = $(BR2_EXTERNAL_KERNEL_MODULE_PATH)
KERNEL_MODULE_SITE_METHOD = local
define KERNEL_MODULE_BUILD_CMDS
$(MAKE) -C '$(@D)' LINUX_DIR='$(LINUX_DIR)' PWD='$(@D)' CC='$(TARGET_CC)' LD='$(TARGET_LD)'
$(MAKE) \
-C '$(@D)' \
ARCH='$(KERNEL_ARCH)' \
CC='$(TARGET_CC)' \
CROSS_COMPILE='$(TARGET_CROSS)' \
LD='$(TARGET_LD)' \
LINUX_DIR='$(LINUX_DIR)' \
PWD='$(@D)'
endef
define KERNEL_MODULE_INSTALL_TARGET_CMDS

View File

@@ -15,7 +15,7 @@ int main(int argc, char **argv) {
return EXIT_FAILURE;
}
if (delete_module(argv[1], O_NONBLOCK) != 0) {
perror("delete_modul");
perror("delete_module");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;

20
run
View File

@@ -1,7 +1,25 @@
#!/usr/bin/env bash
set -e
cd buildroot
make BR2_EXTERNAL="$(pwd)/../kernel_module" qemu_x86_64_defconfig
arch='x86_64'
while getopts a: OPT; do
case "$OPT" in
a)
arch=$OPTARG
;;
esac
done
case "$arch" in
x86_64)
defconfig=qemu_x86_64_defconfig
;;
arm)
# qemu_arm_vexpress_defconfig required a newer QEMU than 2.0.0 on a Ubuntu host.
# so let's stick to versatile for now.
defconfig=qemu_arm_versatile_defconfig
;;
esac
make BR2_EXTERNAL="$(pwd)/../kernel_module" "$defconfig"
# Can't get rid of this for now.
# http://stackoverflow.com/questions/44078245/is-it-possible-to-use-config-fragments-with-buildroots-config
cat ../buildroot_config_fragment >> .config

57
rungdb
View File

@@ -1,22 +1,51 @@
#!/usr/bin/env bash
set -e
arch=x86_64
while getopts a: OPT; do
case "$OPT" in
a)
arch=$OPTARG
;;
esac
done
shift "$(($OPTIND - 1))"
if [ "$#" -gt 0 ]; then
brk="-ex 'break $1'"
else
brk=""
fi
gdb="$(pwd)/buildroot/output/host/usr/bin/x86_64-linux-gdb"
gdb="$(pwd)/buildroot/output/host/usr/bin/${arch}-linux-gdb"
cd buildroot/output/build/linux-*.*.*/
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/'
"
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
eval "$cmd"

56
runqemu
View File

@@ -3,12 +3,16 @@
set -e
# CLI handling.
arch=x86_64
debug=false
nographic=false
extra_append=''
extra_flags=''
while getopts dn OPT; do
while getopts a:dn OPT; do
case "$OPT" in
a)
arch=$OPTARG
;;
d)
debug=true
extra_flags="$extra_flags -S -s"
@@ -21,23 +25,41 @@ while getopts dn OPT; do
esac
done
# If we turn on buildroot host QEMU some day.
#cmd="./buildroot/output/host/usr/bin/qemu-system-x86_64 \
cmd="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 \
;
"
images_dir='buildroot/output/images'
case "$arch" in
x86_64)
# If we turn on buildroot host QEMU some day.
#cmd="./buildroot/output/host/usr/bin/qemu-system-x86_64 \
cmd="qemu-system-x86_64 \
-M pc \
-append 'root=/dev/vda $extra_append' \
-drive file=${images_dir}/rootfs.ext2,if=virtio,format=raw \
-kernel ${images_dir}/bzImage \
-m 128M \
-net nic,model=virtio \
-net user \
-smp 1 \
$extra_flags
"
;;
arm)
cmd="qemu-system-arm \
-M versatilepb \
-append 'root=/dev/sda console=ttyAMA0,115200' \
-drive file=${images_dir}/rootfs.ext2,if=scsi,format=raw \
-dtb ${images_dir}/versatile-pb.dtb \
-kernel ${images_dir}/zImage \
-m 128M \
-net nic,model=rtl8139 \
-net user \
-serial stdio \
-smp 1 \
$extra_flags"
;;
esac
if $debug && ! $nographic; then
eval nohup "$cmd" &>/dev/null &
if "$debug" && ! "$nographic" && [ ! "$arch" = 'arm' ]; then
eval "$cmd" &>/dev/null &
# TODO: Ctrl +C gets sent to QEMU? Why? Does not happen if I run
# ./rungdb manually from outside this script!!! But why?!?!
# eval has nothing to do with it, minimized example with explicit