mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-22 17:55:57 +01:00
kgdb is perfect
baremetal works on docker. Missing deps + virtfs now skips missing dirs.
This commit is contained in:
115
README.adoc
115
README.adoc
@@ -1059,8 +1059,8 @@ Shell 2:
|
|||||||
In GDB, hit `Ctrl-C`, and note how it says:
|
In GDB, hit `Ctrl-C`, and note how it says:
|
||||||
|
|
||||||
....
|
....
|
||||||
scanning for modules in /full/path/to/linux-kernel-module-cheat/out/kernel_modules/x86_64/kernel_modules
|
scanning for modules in /root/linux-kernel-module-cheat/out/kernel_modules/x86_64/kernel_modules
|
||||||
loading @0xffffffffc0000000: /full/path/to/linux-kernel-module-cheat/out/kernel_modules/x86_64/kernel_modules/timer.ko
|
loading @0xffffffffc0000000: /root/linux-kernel-module-cheat/out/kernel_modules/x86_64/kernel_modules/timer.ko
|
||||||
....
|
....
|
||||||
|
|
||||||
That's `lx-symbols` working! Now simply:
|
That's `lx-symbols` working! Now simply:
|
||||||
@@ -1839,9 +1839,9 @@ See also: https://stackoverflow.com/questions/13496389/gdb-remote-protocol-how-t
|
|||||||
|
|
||||||
KGDB is kernel dark magic that allows you to GDB the kernel on real hardware without any extra hardware support.
|
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.
|
It is useless with QEMU since we already have full system visibility with `-gdb`. So the goal of this setup is just to prepare you for what to expect when you will be in the treches of real hardware.
|
||||||
|
|
||||||
Cheaper than JTAG (free) and easier to setup (all you need is serial), but with less visibility as it depends on the kernel working, so e.g.: dies on panic, does not see boot sequence.
|
KGDB is cheaper than JTAG (free) and easier to setup (all you need is serial), but with less visibility as it depends on the kernel working, so e.g.: dies on panic, does not see boot sequence.
|
||||||
|
|
||||||
First run the kernel with:
|
First run the kernel with:
|
||||||
|
|
||||||
@@ -1872,7 +1872,9 @@ Entering kdb (current=0x(____ptrval____), pid 1) on processor 0 due to Keyboard
|
|||||||
|
|
||||||
KGDB expects the connection at `ttyS1`, our second serial port after `ttyS0` which contains the terminal.
|
KGDB expects the connection at `ttyS1`, our second serial port after `ttyS0` which contains the terminal.
|
||||||
|
|
||||||
So now we can connect to the serial port with GDB:
|
The last line is the KDB prompt, and is covered at: <<kdb>>. Typing now shows nothing because that prompt is expecting input from `ttyS1`.
|
||||||
|
|
||||||
|
Instad, we connect to the serial port `ttyS1` with GDB:
|
||||||
|
|
||||||
....
|
....
|
||||||
./run-gdb --kgdb --no-continue
|
./run-gdb --kgdb --no-continue
|
||||||
@@ -1924,31 +1926,11 @@ See also:
|
|||||||
|
|
||||||
=== KGDB ARM
|
=== KGDB ARM
|
||||||
|
|
||||||
GDB not connecting to KGDB in `arm` and `aarch64`.
|
TODO: we would need a second serial for KGDB to work, but it is not currently supported on `arm` and `aarch64` with `-M virt` that we use: https://unix.stackexchange.com/questions/479085/can-qemu-m-virt-on-arm-aarch64-have-multiple-serial-ttys-like-such-as-pl011-t/479340#479340
|
||||||
|
|
||||||
Main question: https://stackoverflow.com/questions/14155577/how-to-use-kgdb-on-arm
|
One possible workaround for this would be to use <<kdb-arm>>.
|
||||||
|
|
||||||
The main console just hangs on:
|
Main more generic question: https://stackoverflow.com/questions/14155577/how-to-use-kgdb-on-arm
|
||||||
|
|
||||||
....
|
|
||||||
Entering kdb (current=0xf8ce07d3, pid 1) due to Keyboard Entry
|
|
||||||
kdb>
|
|
||||||
....
|
|
||||||
|
|
||||||
and GDB shell gives:
|
|
||||||
|
|
||||||
....
|
|
||||||
Reading symbols from vmlinux...done.
|
|
||||||
Remote debugging using localhost:1234
|
|
||||||
Ignoring packet error, continuing...
|
|
||||||
warning: unrecognized item "timeout" in "qSupported" response
|
|
||||||
Ignoring packet error, continuing...
|
|
||||||
Remote replied unexpectedly to 'vMustReplyEmpty': timeout
|
|
||||||
....
|
|
||||||
|
|
||||||
I wanted to try to and run run KGDB on a second serial to see if it makes a difference, but QEMU `-M virt` does not seem to support it: https://stackoverflow.com/questions/53080745/can-qemu-m-virt-on-arm-aarch64-have-multiple-serial-ttys-like-such-as-pl011-t
|
|
||||||
|
|
||||||
Tested on d089c4660615abaf5ae16255fc0195cf989ce437.
|
|
||||||
|
|
||||||
=== KGDB kernel modules
|
=== KGDB kernel modules
|
||||||
|
|
||||||
@@ -1976,43 +1958,96 @@ TODO: if I `-ex lx-symbols` to the `gdb` command, just like done for QEMU `-gdb`
|
|||||||
|
|
||||||
=== KDB
|
=== KDB
|
||||||
|
|
||||||
If you modify `run` to use:
|
KDB is a way to use KDB directly in your main console, without GDB.
|
||||||
|
|
||||||
Advantage over KGDB: you can do everything in one serial. This can actually be important if you only have one serial for both shell and .
|
Advantage over KGDB: you can do everything in one serial. This can actually be important if you only have one serial for both shell and .
|
||||||
|
|
||||||
Disadvantage: not as much functionality as GDB, especially when you use Python scripts.
|
Disadvantage: not as much functionality as GDB, especially when you use Python scripts. Notably, TODO confirm you can't see the the kernel source code and line step as from GDB, since the kernel source is not available on guest (ah, if only debugging information supported full source, or if the kernel had a crazy mechanism to embed it).
|
||||||
|
|
||||||
TODO: only works in <<graphics,graphic mode>>. On the serial, prompt hangs, and the characters I type don't show up at all.
|
Run QEMU as:
|
||||||
|
|
||||||
In QEMU:
|
....
|
||||||
|
./run --kdb
|
||||||
|
....
|
||||||
|
|
||||||
|
This passes `kgdboc=ttyS0` to the Linux CLI, therefore using our main console. Then QEMU:
|
||||||
|
|
||||||
....
|
....
|
||||||
[0]kdb> go
|
[0]kdb> go
|
||||||
....
|
....
|
||||||
|
|
||||||
Boot finishes, then:
|
And now the `kdb>` prompt is responsive because it is listening to the main console.
|
||||||
|
|
||||||
|
After boot finishes, run the usual:
|
||||||
|
|
||||||
....
|
....
|
||||||
|
/count.sh &
|
||||||
/kgdb.sh
|
/kgdb.sh
|
||||||
....
|
....
|
||||||
|
|
||||||
Source: link:rootfs_overlay/kgdb-mod.sh[].
|
And you are back in KDB. Now you can count with:
|
||||||
|
|
||||||
And you are back in KDB. Now you can:
|
|
||||||
|
|
||||||
....
|
....
|
||||||
[0]kdb> help
|
|
||||||
[0]kdb> bp __x64_sys_write
|
[0]kdb> bp __x64_sys_write
|
||||||
[0]kdb> go
|
[0]kdb> go
|
||||||
|
[0]kdb> go
|
||||||
|
[0]kdb> go
|
||||||
|
[0]kdb> go
|
||||||
....
|
....
|
||||||
|
|
||||||
And you will break whenever `__x64_sys_write` is hit.
|
And you will break whenever `__x64_sys_write` is hit.
|
||||||
|
|
||||||
TODO: `bp __x64_sys_write` is failing with `illegal numeric value` as of 10dd9178c6dccf1964002cc9368a5aa83b345487. I think it worked before, so needs bisection.
|
You can get see further commands with:
|
||||||
|
|
||||||
|
....
|
||||||
|
[0]kdb> help
|
||||||
|
....
|
||||||
|
|
||||||
The other KDB commands allow you to instruction steps, view memory, registers and some higher level kernel runtime data.
|
The other KDB commands allow you to instruction steps, view memory, registers and some higher level kernel runtime data.
|
||||||
|
|
||||||
But TODO I don't think you can see where you are in the kernel source code and line step as from GDB, since the kernel source is not available on guest (ah, if only debugging information supported full source).
|
==== KDB graphic
|
||||||
|
|
||||||
|
You can also use KDB directly from the <<graphics,graphic>> window with:
|
||||||
|
|
||||||
|
....
|
||||||
|
./run --graphic --kdb
|
||||||
|
....
|
||||||
|
|
||||||
|
This setup could be used to debug the kernel on machines without serial, such as modern desktops.
|
||||||
|
|
||||||
|
This works because `--graphics` This adds `kbd` (which stands for `KeyBoarD`!) to `kgdboc`.
|
||||||
|
|
||||||
|
==== KDB ARM
|
||||||
|
|
||||||
|
TODO neither `arm` and `aarch64` are working as of 1cd1e58b023791606498ca509256cc48e95e4f5b + 1.
|
||||||
|
|
||||||
|
`arm` seems to place and hit the breakpoint correctly, but no matter how many `go` commands I do, the `count.sh` stdout simply does not show.
|
||||||
|
|
||||||
|
`aarch64` seems to place the breakpoint correctly, but after the first `go` the kernel oopses with warning:
|
||||||
|
|
||||||
|
....
|
||||||
|
WARNING: CPU: 0 PID: 46 at /root/linux-kernel-module-cheat/submodules/linux/kernel/smp.c:416 smp_call_function_many+0xdc/0x358
|
||||||
|
....
|
||||||
|
|
||||||
|
and stack trace:
|
||||||
|
|
||||||
|
....
|
||||||
|
smp_call_function_many+0xdc/0x358
|
||||||
|
kick_all_cpus_sync+0x30/0x38
|
||||||
|
kgdb_flush_swbreak_addr+0x3c/0x48
|
||||||
|
dbg_deactivate_sw_breakpoints+0x7c/0xb8
|
||||||
|
kgdb_cpu_enter+0x284/0x6a8
|
||||||
|
kgdb_handle_exception+0x138/0x240
|
||||||
|
kgdb_brk_fn+0x2c/0x40
|
||||||
|
brk_handler+0x7c/0xc8
|
||||||
|
do_debug_exception+0xa4/0x1c0
|
||||||
|
el1_dbg+0x18/0x78
|
||||||
|
__arm64_sys_write+0x0/0x30
|
||||||
|
el0_svc_handler+0x74/0x90
|
||||||
|
el0_svc+0x8/0xc
|
||||||
|
....
|
||||||
|
|
||||||
|
My theory is that every serious ARM developer has either serial or JTAG, and no one ever tests this, and the kernel code is just broken.
|
||||||
|
|
||||||
== gdbserver
|
== gdbserver
|
||||||
|
|
||||||
@@ -8876,7 +8911,7 @@ Large input may also require tweaking:
|
|||||||
The easiest thing to do, is to link:https://superuser.com/questions/231002/how-can-i-search-within-the-output-buffer-of-a-tmux-shell/1253137#1253137[scroll up on the host shell] after the build, and look for a line of type:
|
The easiest thing to do, is to link:https://superuser.com/questions/231002/how-can-i-search-within-the-output-buffer-of-a-tmux-shell/1253137#1253137[scroll up on the host shell] after the build, and look for a line of type:
|
||||||
|
|
||||||
....
|
....
|
||||||
Running /full/path/to/linux-kernel-module-cheat/out/aarch64/buildroot/build/parsec-benchmark-custom/ext/splash2x/apps/ocean_ncp/inst/aarch64-linux.gcc/bin/ocean_ncp -n2050 -p1 -e1e-07 -r20000 -t28800
|
Running /root/linux-kernel-module-cheat/out/aarch64/buildroot/build/parsec-benchmark-custom/ext/splash2x/apps/ocean_ncp/inst/aarch64-linux.gcc/bin/ocean_ncp -n2050 -p1 -e1e-07 -r20000 -t28800
|
||||||
....
|
....
|
||||||
|
|
||||||
and then tweak the command found in `test.sh` accordingly.
|
and then tweak the command found in `test.sh` accordingly.
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ CT_DEBUG_GDB=y
|
|||||||
CT_GDB_CROSS_SIM=y
|
CT_GDB_CROSS_SIM=y
|
||||||
|
|
||||||
# For Docker.
|
# For Docker.
|
||||||
|
# https://stackoverflow.com/questions/17466017/how-to-solve-you-must-not-be-root-to-run-crosstool-ng-when-using-ct-ng/53099177#53099177
|
||||||
CT_EXPERIMENTAL=y
|
CT_EXPERIMENTAL=y
|
||||||
CT_ALLOW_BUILD_AS_ROOT=y
|
CT_ALLOW_BUILD_AS_ROOT=y
|
||||||
CT_ALLOW_BUILD_AS_ROOT_SURE=y
|
CT_ALLOW_BUILD_AS_ROOT_SURE=y
|
||||||
|
|||||||
@@ -117,10 +117,19 @@ scons \
|
|||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
if "$baremetal"; then
|
if "$baremetal"; then
|
||||||
|
# http://crosstool-ng.github.io/docs/os-setup/
|
||||||
pkgs="${pkgs} \
|
pkgs="${pkgs} \
|
||||||
|
bison \
|
||||||
docbook2x \
|
docbook2x \
|
||||||
|
flex \
|
||||||
|
gcc \
|
||||||
|
gperf \
|
||||||
help2man \
|
help2man \
|
||||||
|
libncurses5-dev \
|
||||||
libtool-bin \
|
libtool-bin \
|
||||||
|
make \
|
||||||
|
python-dev \
|
||||||
|
texinfo \
|
||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
command -v apt-get >/dev/null 2>&1 || {
|
command -v apt-get >/dev/null 2>&1 || {
|
||||||
|
|||||||
1
hello_host_kernel_module/README.adoc
Normal file
1
hello_host_kernel_module/README.adoc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
https://github.com/cirosantilli/linux-kernel-module-cheat#hello-host
|
||||||
29
run
29
run
@@ -89,15 +89,19 @@ def main(args, extra_args=None):
|
|||||||
elif common.is_arm:
|
elif common.is_arm:
|
||||||
console_type = 'ttyAMA'
|
console_type = 'ttyAMA'
|
||||||
console = '{}{}'.format(console_type, console_count)
|
console = '{}{}'.format(console_type, console_count)
|
||||||
|
console_count += 1
|
||||||
if not (args.arch == 'x86_64' and args.graphic):
|
if not (args.arch == 'x86_64' and args.graphic):
|
||||||
console_count += 1
|
|
||||||
kernel_cli += ' console={}'.format(console)
|
kernel_cli += ' console={}'.format(console)
|
||||||
extra_console = '{}{}'.format(console_type, console_count)
|
extra_console = '{}{}'.format(console_type, console_count)
|
||||||
console_count += 1
|
console_count += 1
|
||||||
if args.kdb or args.kgdb:
|
if args.kdb or args.kgdb:
|
||||||
kernel_cli += ' kgdbwait'
|
kernel_cli += ' kgdbwait'
|
||||||
if args.kdb:
|
if args.kdb:
|
||||||
kernel_cli += ' kgdboc={},115200'.format(console)
|
if args.graphic:
|
||||||
|
kdb_cmd = 'kbd,'
|
||||||
|
else:
|
||||||
|
kdb_cmd = ''
|
||||||
|
kernel_cli += ' kgdboc={}{},115200'.format(kdb_cmd, console)
|
||||||
if args.kgdb:
|
if args.kgdb:
|
||||||
kernel_cli += ' kgdboc={},115200'.format(extra_console)
|
kernel_cli += ' kgdboc={},115200'.format(extra_console)
|
||||||
if kernel_cli_after_dash:
|
if kernel_cli_after_dash:
|
||||||
@@ -249,6 +253,20 @@ def main(args, extra_args=None):
|
|||||||
if args.kvm:
|
if args.kvm:
|
||||||
extra_emulator_args.append('-enable-kvm')
|
extra_emulator_args.append('-enable-kvm')
|
||||||
extra_emulator_args.extend(['-serial', 'tcp::{},server,nowait'.format(common.extra_serial_port)])
|
extra_emulator_args.extend(['-serial', 'tcp::{},server,nowait'.format(common.extra_serial_port)])
|
||||||
|
virtfs_data = [
|
||||||
|
(common.p9_dir, 'host_data'),
|
||||||
|
(common.out_dir, 'host_out'),
|
||||||
|
(common.out_rootfs_overlay_dir, 'host_out_rootfs_overlay'),
|
||||||
|
(common.rootfs_overlay_dir, 'host_rootfs_overlay'),
|
||||||
|
]
|
||||||
|
virtfs_cmd = []
|
||||||
|
for virtfs_dir, virtfs_tag in virtfs_data:
|
||||||
|
if os.path.exists(virtfs_dir):
|
||||||
|
virtfs_cmd.extend([
|
||||||
|
'-virtfs',
|
||||||
|
'local,path={virtfs_dir},mount_tag={virtfs_tag},security_model=mapped,id={virtfs_tag}' \
|
||||||
|
.format(virtfs_dir=virtfs_dir, virtfs_tag=virtfs_tag
|
||||||
|
)])
|
||||||
cmd.extend(
|
cmd.extend(
|
||||||
[
|
[
|
||||||
qemu_executable,
|
qemu_executable,
|
||||||
@@ -260,11 +278,8 @@ def main(args, extra_args=None):
|
|||||||
'-netdev', 'user,hostfwd=tcp::{}-:{},hostfwd=tcp::{}-:22,id=net0'.format(common.qemu_hostfwd_generic_port, common.qemu_hostfwd_generic_port, common.qemu_hostfwd_ssh_port),
|
'-netdev', 'user,hostfwd=tcp::{}-:{},hostfwd=tcp::{}-:22,id=net0'.format(common.qemu_hostfwd_generic_port, common.qemu_hostfwd_generic_port, common.qemu_hostfwd_ssh_port),
|
||||||
'-no-reboot',
|
'-no-reboot',
|
||||||
'-smp', str(args.cpus),
|
'-smp', str(args.cpus),
|
||||||
'-virtfs', 'local,path={},mount_tag=host_data,security_model=mapped,id=host_data'.format(common.p9_dir),
|
|
||||||
'-virtfs', 'local,path={},mount_tag=host_out,security_model=mapped,id=host_out'.format(common.out_dir),
|
|
||||||
'-virtfs', 'local,path={},mount_tag=host_out_rootfs_overlay,security_model=mapped,id=host_out_rootfs_overlay'.format(common.out_rootfs_overlay_dir),
|
|
||||||
'-virtfs', 'local,path={},mount_tag=host_rootfs_overlay,security_model=mapped,id=host_rootfs_overlay'.format(common.rootfs_overlay_dir),
|
|
||||||
] +
|
] +
|
||||||
|
virtfs_cmd +
|
||||||
qemu_user_and_system_options +
|
qemu_user_and_system_options +
|
||||||
serial_monitor +
|
serial_monitor +
|
||||||
vnc
|
vnc
|
||||||
@@ -518,7 +533,7 @@ to the program running on the split.
|
|||||||
'''
|
'''
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--userland', default=defaults['userland'],
|
'-u', '--userland', default=defaults['userland'],
|
||||||
help='''\
|
help='''\
|
||||||
Run the given userland executable in user mode instead of booting the Linux kernel
|
Run the given userland executable in user mode instead of booting the Linux kernel
|
||||||
in full system mode. In gem5, user mode is called Syscall Emulation (SE) mode and
|
in full system mode. In gem5, user mode is called Syscall Emulation (SE) mode and
|
||||||
|
|||||||
Reference in New Issue
Block a user