GEM5 gdb debug

Improve GEM5 documentation in general.

Fix documentation for x86 kernel module debugging example, fop_write had been made static,
and use timer.ko instead of fops which is more reliable and fun.
This commit is contained in:
Ciro Santilli
2018-02-22 09:42:17 +00:00
parent ff71f19fa6
commit 6420c31986
3 changed files with 77 additions and 33 deletions

View File

@@ -463,30 +463,26 @@ However, the Linux kernel GDB scripts offer the `lx-symbols` command, which take
In QEMU:
....
insmod /fops.ko
insmod /timer.ko
....
In GDB, hit `Ctrl + C`, and note how it says:
....
scanning for modules in ../kernel_module-1.0/
loading @0xffffffffa0000000: ../kernel_module-1.0//fops.ko
scanning for modules in /home/ciro/bak/git/linux-kernel-module-cheat/buildroot/output.x86_64~/build/linux-custom
loading @0xffffffffc0000000: ../kernel_module-1.0//timer.ko
....
That's `lx-symbols` working! Now simply:
....
b fop_write
b lkmc_timer_callback
c
c
c
....
In QEMU:
....
printf a >/sys/kernel/debug/lkmc_fops/f
....
and GDB now breaks at our `fop_write` function!
and we now control the callback from GDB!
Just don't forget to remove your breakpoints after `rmmod`, or they will point to stale memory locations.
@@ -929,7 +925,7 @@ TODOs:
When the Linux kernel finishes booting, it runs an executable as the first and only userland process.
The default path is `/init`, but we an set a custom one with the `init=` kernel command line argument.
The default path is `/init`, but we an set a custom one with the `init=` <<kernel-boot-command-line-arguments,kernel boot command line option>>.
This process is then responsible for setting up the entire userland (or destroying everything when you want to have fun).
@@ -1219,35 +1215,70 @@ On another shell:
./rungem5-shell
....
===== GEM5 kernel command line arguments
===== GEM5 kernel boot command line arguments
E.g., to add `printk.time=y`, run:
Analogous <<kernel-boot-command-line-arguments,to QEMU>>:
....
./run -a arm -e 'init=/poweroff.out' -g
....
Internals: when we give `--command-line=` to GEM5, it overrides default command lines, which are required to boot properly.
So if you pass just `--command-line='printk.time=y'` for example, it removes the required options, and boot fails.
Internals: when we give `--command-line=` to GEM5, it overrides default command lines, including some mandatory ones which are required to boot properly.
Our run script hardcodes the require options in the default `--command-line` and appends extra options given by `-e`.
The default options can be found found with:
To find the default options in the first place, we removed `--command-line` and ran:
....
./run -a arm -g
....
and then look at the line of the linux kernel that starts with:
and then looked at the line of the Linux kernel that starts with:
....
Kernel command line:
....
===== QEMU with GEM5 kernel configuration
[[gem5-gdb]]
===== GEM5 GDB step debugging
TODO: QEMU did not work with the GEM5 kernel configurations.
Analogous <<gdb,to QEMU>>, on the first shell:
....
./run -a arm -d -g
....
On the second shell:
....
./rungdb -a arm -g
....
This makes the VM stop, so from inside GDB:
....
continue
....
On a third shell:
....
./rungem5-shell
....
And we now see the boot messages, and then get a shell. Now try the `/continue.sh` procedure described for QEMU.
TODO: how to stop at `start_kernel`? GEM5 listens for GDB by default, and therefore does not wait for a GDB connection to start like QEMU does. So when GDB connects we might have already passed `start_kernel`. Maybe `--debug-break=0` can be used?
===== QEMU and GEM5 with the same kernel configuration
We would like to be able to run both GEM5 and QEMU with the same kernel build to avoid duplication, but TODO we haven't been able to get that working yet.
This documents our failed attempts so far.
As a result, we currently have to create two full `buildroot/output*` directories, which means two full GCC builds.
====== QEMU with GEM5 kernel configuration
To test this, hack up `run` to use the `buildroot/output.arm-gem5~` directory, and then run:
@@ -1267,7 +1298,7 @@ and the display shows:
Guest has not initialized the display (yet).
....
===== GEM5 with QEMU kernel configuration
====== GEM5 with QEMU kernel configuration
Test it out with:
@@ -1715,13 +1746,13 @@ Sample output:
0) 5.016 us | update_vsyscall();
0) | raw_notifier_call_chain() {
0) 2.241 us | notifier_call_chain();
0) + 19.879 us | }
0) + 19.879 us | }
0) 3.144 us | update_fast_timekeeper();
0) 2.738 us | update_fast_timekeeper();
0) ! 117.147 us | }
0) | _raw_spin_unlock_irqrestore() {
0) 4.045 us | _raw_write_unlock_irqrestore();
0) + 22.066 us | }
0) + 22.066 us | }
0) ! 265.278 us | } /* update_wall_time */
....

View File

@@ -17,12 +17,14 @@ See also:
#include <linux/module.h>
#include <linux/timer.h>
static void callback(struct timer_list *data);
/* We would normally mark this as static and give it a more generic name.
* But let's do it like this this time for the sake of our GDB kernel module step debugging example. */
void lkmc_timer_callback(struct timer_list *data);
static unsigned long onesec;
DEFINE_TIMER(mytimer, callback);
DEFINE_TIMER(mytimer, lkmc_timer_callback);
static void callback(struct timer_list *data)
void lkmc_timer_callback(struct timer_list *data)
{
pr_info("%u\n", (unsigned)jiffies);
mod_timer(&mytimer, jiffies + onesec);

23
rungdb
View File

@@ -4,8 +4,9 @@ set -e
arch='x86_64'
bdfore=''
gem5=false
kgdb=false
while getopts A:a:b:k OPT; do
while getopts A:a:b:gk OPT; do
case "$OPT" in
a)
arch="$OPTARG"
@@ -16,6 +17,9 @@ while getopts A:a:b:k OPT; do
b)
before="$OPTARG"
;;
g)
gem5=true
;;
k)
kgdb=true
;;
@@ -28,8 +32,15 @@ if [ "$#" -gt 0 ]; then
else
brk=''
fi
if "$gem5"; then
arch_dir="${arch}-gem5"
port=7000
else
arch_dir="$arch"
port=1234
fi
buildroot_out_dir="$(pwd)/buildroot/output.${arch}~"
buildroot_out_dir="$(pwd)/buildroot/output.${arch_dir}~"
gdb="${buildroot_out_dir}/host/usr/bin/${arch}-linux-gdb $before"
cd "${buildroot_out_dir}/build/linux-custom/"
if "$kgdb"; then
@@ -37,7 +48,7 @@ if "$kgdb"; then
-q \
-ex 'add-auto-load-safe-path $(pwd)' \
-ex 'file vmlinux' \
-ex 'target remote localhost:1234'
-ex 'target remote localhost:$port'
"
else
case "$arch" in
@@ -47,12 +58,12 @@ else
-ex 'add-auto-load-safe-path $(pwd)' \
-ex 'file vmlinux' \
-ex 'set arch i386:x86-64:intel' \
-ex 'target remote localhost:1234' \
-ex 'target remote localhost:$port' \
$brk \
-ex 'continue' \
-ex 'disconnect' \
-ex 'set arch i386:x86-64' \
-ex 'target remote localhost:1234' \
-ex 'target remote localhost:$port' \
-ex 'lx-symbols ../kernel_module-1.0/' \
"
;;
@@ -61,7 +72,7 @@ $brk \
-q \
-ex 'add-auto-load-safe-path $(pwd)' \
-ex 'file vmlinux' \
-ex 'target remote localhost:1234' \
-ex 'target remote localhost:$port' \
-ex 'lx-symbols ../kernel_module-1.0/' \
$brk \
"