mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
run-gdb-user: killed it, all that was needed was to pass --userland
Fixes part of https://github.com/cirosantilli/linux-kernel-module-cheat/issues/63
This commit is contained in:
29
README.adoc
29
README.adoc
@@ -1944,6 +1944,8 @@ You will generally want to use <<gdbserver>> for this as it is more reliable, bu
|
|||||||
Known limitations of direct userland debugging:
|
Known limitations of direct userland debugging:
|
||||||
|
|
||||||
* the kernel might switch context to another process or to the kernel itself e.g. on a system call, and then TODO confirm the PIC would go to weird places and source code would be missing.
|
* the kernel might switch context to another process or to the kernel itself e.g. on a system call, and then TODO confirm the PIC would go to weird places and source code would be missing.
|
||||||
|
+
|
||||||
|
Solutions to this are being researched at: <<lx-ps>>.
|
||||||
* TODO step into shared libraries. If I attempt to load them explicitly:
|
* TODO step into shared libraries. If I attempt to load them explicitly:
|
||||||
+
|
+
|
||||||
....
|
....
|
||||||
@@ -1967,13 +1969,13 @@ For executables from the link:userland/[] directory such as link:userland/posix/
|
|||||||
* Shell 2:
|
* Shell 2:
|
||||||
+
|
+
|
||||||
....
|
....
|
||||||
./run-gdb-user userland/posix/count.c main
|
./run-gdb --userland userland/posix/count.c main
|
||||||
....
|
....
|
||||||
+
|
+
|
||||||
Alternatively, we could also pass the full path to the executable:
|
Alternatively, we could also pass the full path to the executable:
|
||||||
+
|
+
|
||||||
....
|
....
|
||||||
./run-gdb-user "$(./getvar userland_build_dir)/posix/count.out" main
|
./run-gdb --userland "$(./getvar userland_build_dir)/posix/count.out" main
|
||||||
....
|
....
|
||||||
+
|
+
|
||||||
Path resolution is analogous to <<baremetal-setup-getting-started,that of `./run --baremetal`>>.
|
Path resolution is analogous to <<baremetal-setup-getting-started,that of `./run --baremetal`>>.
|
||||||
@@ -1992,7 +1994,7 @@ BusyBox custom init process:
|
|||||||
* Shell 2:
|
* Shell 2:
|
||||||
+
|
+
|
||||||
....
|
....
|
||||||
./run-gdb-user "$(./getvar buildroot_build_build_dir)"/busybox-*/busybox ls_main
|
./run-gdb --userland "$(./getvar buildroot_build_build_dir)"/busybox-*/busybox ls_main
|
||||||
....
|
....
|
||||||
|
|
||||||
This follows BusyBox' convention of calling the main for each executable as `<exec>_main` since the `busybox` executable has many "mains".
|
This follows BusyBox' convention of calling the main for each executable as `<exec>_main` since the `busybox` executable has many "mains".
|
||||||
@@ -2007,7 +2009,7 @@ BusyBox default init process:
|
|||||||
* Shell 2:
|
* Shell 2:
|
||||||
+
|
+
|
||||||
....
|
....
|
||||||
./run-gdb-user "$(./getvar buildroot_build_build_dir)"/busybox-*/busybox init_main
|
./run-gdb --userland "$(./getvar buildroot_build_build_dir)"/busybox-*/busybox init_main
|
||||||
....
|
....
|
||||||
|
|
||||||
`init` cannot be debugged with <<gdbserver>> without modifying the source, or else `/sbin/init` exits early with:
|
`init` cannot be debugged with <<gdbserver>> without modifying the source, or else `/sbin/init` exits early with:
|
||||||
@@ -2028,19 +2030,20 @@ Non-init process:
|
|||||||
* Shell 2:
|
* Shell 2:
|
||||||
+
|
+
|
||||||
....
|
....
|
||||||
./run-gdb-user userland/linux/myinsmod.c main
|
./run-gdb --userland userland/linux/rand_check.c main
|
||||||
....
|
....
|
||||||
* Shell 1 after the boot finishes:
|
* Shell 1 after the boot finishes:
|
||||||
+
|
+
|
||||||
....
|
....
|
||||||
./linux/myinsmod.out hello.ko
|
./linux/rand_check.out
|
||||||
....
|
....
|
||||||
|
|
||||||
This is the least reliable setup as there might be other processes that use the given virtual address.
|
This is the least reliable setup as there might be other processes that use the given virtual address.
|
||||||
|
|
||||||
|
[[gdb-step-debug-userland-non-init-without-gdb-wait]]
|
||||||
===== GDB step debug userland non-init without --gdb-wait
|
===== GDB step debug userland non-init without --gdb-wait
|
||||||
|
|
||||||
TODO: without `--gdb-wait` and the `break main` that we do inside `./run-gdb-user` says:
|
TODO: if I try <<gdb-step-debug-userland-non-init>> without `--gdb-wait` and the `break main` that we do inside `./run-gdb` says:
|
||||||
|
|
||||||
....
|
....
|
||||||
Cannot access memory at address 0x10604
|
Cannot access memory at address 0x10604
|
||||||
@@ -2195,7 +2198,7 @@ so we see that the affinity was restricted to the second core from the start.
|
|||||||
|
|
||||||
Let's do a QEMU observation to justify this example being in the repository with <<gdb-step-debug-userland-non-init,userland breakpoints>>.
|
Let's do a QEMU observation to justify this example being in the repository with <<gdb-step-debug-userland-non-init,userland breakpoints>>.
|
||||||
|
|
||||||
We will run our `./linux/sched_getaffinity.out` infinitely many time, on core 0 and core 1 alternatively:
|
We will run our `./linux/sched_getaffinity.out` infinitely many times, on core 0 and core 1 alternatively:
|
||||||
|
|
||||||
....
|
....
|
||||||
./run \
|
./run \
|
||||||
@@ -2208,7 +2211,7 @@ We will run our `./linux/sched_getaffinity.out` infinitely many time, on core 0
|
|||||||
on another shell:
|
on another shell:
|
||||||
|
|
||||||
....
|
....
|
||||||
./run-gdb-user "$(./getvar userland_build_dir)/linux/sched_getaffinity.out" main
|
./run-gdb --userland "$(./getvar userland_build_dir)/linux/sched_getaffinity.out" main
|
||||||
....
|
....
|
||||||
|
|
||||||
Then, inside GDB:
|
Then, inside GDB:
|
||||||
@@ -2239,7 +2242,7 @@ TODO we then tried:
|
|||||||
and:
|
and:
|
||||||
|
|
||||||
....
|
....
|
||||||
./run-gdb-user "$(./getvar userland_build_dir)/linux/sched_getaffinity_threads.out"
|
./run-gdb --userland "$(./getvar userland_build_dir)/linux/sched_getaffinity_threads.out"
|
||||||
....
|
....
|
||||||
|
|
||||||
to switch between two simultaneous live threads with different affinities, it just didn't break on our threads:
|
to switch between two simultaneous live threads with different affinities, it just didn't break on our threads:
|
||||||
@@ -7807,7 +7810,7 @@ TODO `--arch arm` and `--arch aarch64` does not count firmware instructions prop
|
|||||||
* We can also discount the instructions after `init` runs by using `readelf` to get the initial address of `init`. One easy way to do that now is to just run:
|
* We can also discount the instructions after `init` runs by using `readelf` to get the initial address of `init`. One easy way to do that now is to just run:
|
||||||
+
|
+
|
||||||
....
|
....
|
||||||
./run-gdb-user "$(./getvar userland_build_dir)/linux/poweroff.out" main
|
./run-gdb --userland "$(./getvar userland_build_dir)/linux/poweroff.out" main
|
||||||
....
|
....
|
||||||
+
|
+
|
||||||
And get that from the traces, e.g. if the address is `4003a0`, then we search:
|
And get that from the traces, e.g. if the address is `4003a0`, then we search:
|
||||||
@@ -10518,7 +10521,7 @@ We are unable to use `gdbserver` because of networking: <<gem5-host-to-guest-net
|
|||||||
|
|
||||||
The alternative is to do as in <<gdb-step-debug-userland-processes>>.
|
The alternative is to do as in <<gdb-step-debug-userland-processes>>.
|
||||||
|
|
||||||
Next, follow the exact same steps explained at <<gdb-step-debug-userland-non-init-without--d>>, but passing `-g` to every command as usual.
|
Next, follow the exact same steps explained at <<gdb-step-debug-userland-non-init-without-gdb-wait>>, but passing `--emulator gem5` to every command as usual.
|
||||||
|
|
||||||
But then TODO (I'll still go crazy one of those days): for `arm`, while debugging `./linux/myinsmod.out hello.ko`, after then line:
|
But then TODO (I'll still go crazy one of those days): for `arm`, while debugging `./linux/myinsmod.out hello.ko`, after then line:
|
||||||
|
|
||||||
@@ -10532,7 +10535,7 @@ I press `n`, it just runs the program until the end, instead of stopping on the
|
|||||||
TODO:
|
TODO:
|
||||||
|
|
||||||
....
|
....
|
||||||
./run-gdb-user --arch arm --emulator gem5 gem5-1.0/gem5/util/m5/m5 main
|
./run-gdb --arch arm --emulator gem5 --userland gem5-1.0/gem5/util/m5/m5 main
|
||||||
....
|
....
|
||||||
|
|
||||||
breaks when `m5` is run on guest, but does not show the source code.
|
breaks when `m5` is run on guest, but does not show the source code.
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class PathProperties:
|
|||||||
# https://stackoverflow.com/questions/51310756/how-to-gdb-step-debug-a-dynamically-linked-executable-in-qemu-user-mode/51343326#51343326
|
# https://stackoverflow.com/questions/51310756/how-to-gdb-step-debug-a-dynamically-linked-executable-in-qemu-user-mode/51343326#51343326
|
||||||
# * when writing assembly code, we have to constantly think about it:
|
# * when writing assembly code, we have to constantly think about it:
|
||||||
# https://stackoverflow.com/questions/2463150/what-is-the-fpie-option-for-position-independent-executables-in-gcc-and-ld/51308031#51308031
|
# https://stackoverflow.com/questions/2463150/what-is-the-fpie-option-for-position-independent-executables-in-gcc-and-ld/51308031#51308031
|
||||||
# As of 91986fb2955f96e06d1c5ffcc5536ba9f0af1fd9, our Buildroot toolchain
|
# As of lkmc 91986fb2955f96e06d1c5ffcc5536ba9f0af1fd9, our Buildroot toolchain
|
||||||
# does not have it enabled by default, but the Ubuntu 18.04 host toolchain does.
|
# does not have it enabled by default, but the Ubuntu 18.04 host toolchain does.
|
||||||
'-fno-pie', LF,
|
'-fno-pie', LF,
|
||||||
'-no-pie', LF,
|
'-no-pie', LF,
|
||||||
|
|||||||
4
run-gdb
4
run-gdb
@@ -149,13 +149,15 @@ the script is a .py file next to the source code.
|
|||||||
break_at = ['-ex', 'break {}'.format(self.env['break_at']), LF]
|
break_at = ['-ex', 'break {}'.format(self.env['break_at']), LF]
|
||||||
else:
|
else:
|
||||||
break_at = []
|
break_at = []
|
||||||
linux_full_system = (self.env['baremetal'] is None and self.env['userland'] is None)
|
|
||||||
if self.env['userland']:
|
if self.env['userland']:
|
||||||
image = self.env['image']
|
image = self.env['image']
|
||||||
|
linux_full_system = False
|
||||||
elif self.env['baremetal']:
|
elif self.env['baremetal']:
|
||||||
image = self.env['image']
|
image = self.env['image']
|
||||||
|
linux_full_system = False
|
||||||
else:
|
else:
|
||||||
image = self.env['vmlinux']
|
image = self.env['vmlinux']
|
||||||
|
linux_full_system = True
|
||||||
cmd = (
|
cmd = (
|
||||||
[self.env['gdb_path'], LF] +
|
[self.env['gdb_path'], LF] +
|
||||||
before
|
before
|
||||||
|
|||||||
43
run-gdb-user
43
run-gdb-user
@@ -1,43 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
import common
|
|
||||||
import lkmc.import_path
|
|
||||||
|
|
||||||
class Main(common.LkmcCliFunction):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__(
|
|
||||||
description='''GDB step debug guest userland processes without gdbserver.
|
|
||||||
|
|
||||||
More information at: https://github.com/cirosantilli/linux-kernel-module-cheat#gdb-step-debug-userland-processes
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
self.add_argument(
|
|
||||||
'executable',
|
|
||||||
help='Path to the executable to be debugged relative to the Buildroot build directory.'
|
|
||||||
)
|
|
||||||
self.add_argument(
|
|
||||||
'break_at',
|
|
||||||
default=None,
|
|
||||||
help='Break at this point, e.g. main.',
|
|
||||||
nargs='?'
|
|
||||||
)
|
|
||||||
|
|
||||||
def timed_main(self):
|
|
||||||
raise Exception("This is known to be broken, but fixing shouldn't be too hard! Keyword: get_argparse. See also: https://github.com/cirosantilli/linux-kernel-module-cheat/issues/63")
|
|
||||||
executable = self.env['image']
|
|
||||||
addr = self.get_elf_entry(os.path.join(self.env['buildroot_build_build_dir'], executable))
|
|
||||||
args = {}
|
|
||||||
args['before'] = '-ex \"add-symbol-file {} {}\"'.format(executable, hex(addr))
|
|
||||||
# Or else lx-symbols throws for arm:
|
|
||||||
# gdb.MemoryError: Cannot access memory at address 0xbf0040cc
|
|
||||||
# TODO understand better.
|
|
||||||
# Also, lx-symbols overrides the add-symbol-file commands.
|
|
||||||
args['no_lxsymbols'] = True
|
|
||||||
args['break_at'] = self.env['break_at']
|
|
||||||
rungdb = lkmc.import_path.import_path_main('run-gdb')
|
|
||||||
return rungdb(**args)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
Main().cli()
|
|
||||||
Reference in New Issue
Block a user