From 7fda1332155cf377ac80a5567d32dc0aac24db20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciro=20Santilli=20=E5=85=AD=E5=9B=9B=E4=BA=8B=E4=BB=B6=20?= =?UTF-8?q?=E6=B3=95=E8=BD=AE=E5=8A=9F?= Date: Sun, 2 Jun 2019 00:00:03 +0000 Subject: [PATCH] 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 --- README.adoc | 29 ++++++++++++++++------------- path_properties.py | 2 +- run-gdb | 4 +++- run-gdb-user | 43 ------------------------------------------- 4 files changed, 20 insertions(+), 58 deletions(-) delete mode 100755 run-gdb-user diff --git a/README.adoc b/README.adoc index 6a904f7..e98d7c4 100644 --- a/README.adoc +++ b/README.adoc @@ -1944,6 +1944,8 @@ You will generally want to use <> for this as it is more reliable, bu 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. ++ +Solutions to this are being researched at: <>. * 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: + .... -./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: + .... -./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 <>. @@ -1992,7 +1994,7 @@ BusyBox custom init process: * 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 `_main` since the `busybox` executable has many "mains". @@ -2007,7 +2009,7 @@ BusyBox default init process: * 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 <> without modifying the source, or else `/sbin/init` exits early with: @@ -2028,19 +2030,20 @@ Non-init process: * 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: + .... -./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. +[[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 <> without `--gdb-wait` and the `break main` that we do inside `./run-gdb` says: .... 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 <>. -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 \ @@ -2208,7 +2211,7 @@ We will run our `./linux/sched_getaffinity.out` infinitely many time, on core 0 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: @@ -2239,7 +2242,7 @@ TODO we then tried: 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: @@ -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: + .... -./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: @@ -10518,7 +10521,7 @@ We are unable to use `gdbserver` because of networking: <>. -Next, follow the exact same steps explained at <>, but passing `-g` to every command as usual. +Next, follow the exact same steps explained at <>, 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: @@ -10532,7 +10535,7 @@ I press `n`, it just runs the program until the end, instead of stopping on the 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. diff --git a/path_properties.py b/path_properties.py index c9d32c1..3354a82 100644 --- a/path_properties.py +++ b/path_properties.py @@ -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 # * 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 - # 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. '-fno-pie', LF, '-no-pie', LF, diff --git a/run-gdb b/run-gdb index e7d601e..a650286 100755 --- a/run-gdb +++ b/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] else: break_at = [] - linux_full_system = (self.env['baremetal'] is None and self.env['userland'] is None) if self.env['userland']: image = self.env['image'] + linux_full_system = False elif self.env['baremetal']: image = self.env['image'] + linux_full_system = False else: image = self.env['vmlinux'] + linux_full_system = True cmd = ( [self.env['gdb_path'], LF] + before diff --git a/run-gdb-user b/run-gdb-user deleted file mode 100755 index be7a485..0000000 --- a/run-gdb-user +++ /dev/null @@ -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()