disas works with the linux kernel, it's beautiful

This commit is contained in:
Ciro Santilli 六四事件 法轮功
2020-06-25 07:00:06 +00:00
parent e658498578
commit 49117d3c1c
4 changed files with 42 additions and 23 deletions

View File

@@ -14756,19 +14756,17 @@ where 120 == 0x78 (it logs addresses in decimal? Really??) and the size 4 which
Now that we are here, we might as well learn how to log the data that was fetched from DRAM. Now that we are here, we might as well learn how to log the data that was fetched from DRAM.
Fist we determine the expected bytes from: Fist we determine the expected bytes from the <<disas,disassembly>>:
.... ....
./run-toolchain --arch aarch64 objdump -- \ ./disas --arch aarch64 --userland userland/arch/aarch64/freestanding/linux/hello.S _start
-D "$(./getvar --arch aarch64 userland_build_dir)/arch/aarch64/freestanding/linux/hello.out"
.... ....
which shows us the initial instruction encodings near the entry point `_start`: which shows us the initial instruction encodings near the entry point `_start`:
.... ....
0000000000400078 <_start>: 0x0000000000400078 <+0>: 20 00 80 d2 mov x0, #0x1 // #1
400078: d2800020 mov x0, #0x1 // #1 0x000000000040007c <+4>: e1 00 00 10 adr x1, 0x400098 <msg>
40007c: 100000e1 adr x1, 400098 <msg>
.... ....
Now, TODO :-) The `DRAM` logs don't contain data. Maybe this can be done with https://github.com/gem5/gem5/blob/9fc9c67b4242c03f165951775be5cd0812f2a705/src/mem/comm_monitor.hh#L55[`CommMonitor`], but it is no exposed on fs.py Now, TODO :-) The `DRAM` logs don't contain data. Maybe this can be done with https://github.com/gem5/gem5/blob/9fc9c67b4242c03f165951775be5cd0812f2a705/src/mem/comm_monitor.hh#L55[`CommMonitor`], but it is no exposed on fs.py
@@ -17874,16 +17872,10 @@ link:userland/c/atomic.c[]
Demonstrates `atomic_int` and `thrd_create`. Demonstrates `atomic_int` and `thrd_create`.
Disassembly with GDB at LKMC 619fef4b04bddc4a5a38aec5e207dd4d5a25d206 + 1: <<disas,Disassembly with GDB>> at LKMC 619fef4b04bddc4a5a38aec5e207dd4d5a25d206 + 1:
.... ....
./run-toolchain \ ./disas --arch aarch64 --userland userland/c/atomic.c my_thread_main
--arch aarch64 gdb \
-- \
-batch \
-ex 'disas/rs my_thread_main' $(./getvar \
--arch aarch64 userland_build_dir)/c/atomic.out \
;
.... ....
shows on ARM: shows on ARM:
@@ -24499,10 +24491,10 @@ link:userland/gcc/busy_loop.c[]
The hard part is how to prevent the compiler from optimizing it away: https://stackoverflow.com/questions/7083482/how-to-prevent-gcc-from-optimizing-out-a-busy-wait-loop/58758133#58758133 The hard part is how to prevent the compiler from optimizing it away: https://stackoverflow.com/questions/7083482/how-to-prevent-gcc-from-optimizing-out-a-busy-wait-loop/58758133#58758133
Disassembly analysis: <<disas,Disassembly>> analysis:
.... ....
./run-toolchain --arch aarch64 gdb -- -nh -batch -ex 'disas/rs busy_loop' "$(./getvar --arch aarch64 userland_build_dir)/gcc/busy_loop.out" ./disas --arch aarch64 --userland userland/gcc/busy_loop.out busy_loop
.... ....
which contains at LKMC eb22fd3b6e7fff7e9ef946a88b208debf5b419d5: which contains at LKMC eb22fd3b6e7fff7e9ef946a88b208debf5b419d5:
@@ -25362,6 +25354,14 @@ you can save some typing and get portability across directory structure changes
./run-toolchain --arch aarch64 objdump -- -D a.out ./run-toolchain --arch aarch64 objdump -- -D a.out
.... ....
This plays nicely with <<getvar>> e.g. you could disassembly link:userland/c/hello.c[] with:
....
./run-toolchain --arch aarch64 objdump -- -D $(./getvar --arch aarch64 userland_build_dir)/c/hello.out
....
however disassembly is such a common use case that we have a shortcut for it: <<disas>>.
Alternatively, if you just need a variable to feed into your own Build system, you can also use <<getvar>>: Alternatively, if you just need a variable to feed into your own Build system, you can also use <<getvar>>:
.... ....
@@ -25374,12 +25374,28 @@ which outputs as of LKMC b15a0e455d691afa49f3b813ad9b09394dfb02b7:
/path/to/linux-kernel-module-cheat/out/buildroot/build/default/aarch64/host/usr/bin/aarch64-buildroot-linux-gnu /path/to/linux-kernel-module-cheat/out/buildroot/build/default/aarch64/host/usr/bin/aarch64-buildroot-linux-gnu
.... ....
Since disassembly of a single function with GDB is such a common use case https://stackoverflow.com/questions/22769246/how-to-disassemble-one-single-function-using-objdump[], we have a shortcut for it: ===== disas
Since disassembly of a single function of a LKMC executable with GDB is such a common use case for <<run-toolchain>> via https://stackoverflow.com/questions/22769246/how-to-disassemble-one-single-function-using-objdump[], we have this shortcut for it.
For example to disassemle a function from an <<userland-content,userland binary>>:
.... ....
./disas --arch aarch64 --userland userland/c/hello.c main ./disas --arch aarch64 --userland userland/c/hello.c main
.... ....
or to disassemble a function from the <<linux-kernel>>:
....
./disas --arch aarch64 start_kernel
....
and a <<baremetal-setup,baremetal>> executable:
....
./disas --arch aarch64 --baremetal baremetal/arch/aarch64/no_bootloader/exit.S _start
....
=== Rebuild Buildroot while running === Rebuild Buildroot while running
It is not possible to rebuild the root filesystem while running QEMU because QEMU holds the file qcow2 file: It is not possible to rebuild the root filesystem while running QEMU because QEMU holds the file qcow2 file:

View File

@@ -1166,6 +1166,10 @@ Incompatible archs are skipped.
# Image # Image
if env['baremetal']: if env['baremetal']:
env['image'] = self.resolve_baremetal_executable(env['baremetal'][0]) env['image'] = self.resolve_baremetal_executable(env['baremetal'][0])
# This is needed because the Linux kerne limage for certain emulators like QEMU
# might not be in plain ELF format, but rather some crazy compressed kernel format.
# https://cirosantilli.com/linux-kernel-module-cheat#vmlinux-vs-bzimage-vs-zimage-vs-image
env['image_elf'] = env['image']
source_path_noext = os.path.splitext(join( source_path_noext = os.path.splitext(join(
env['root_dir'], env['root_dir'],
env['image'][len(env['baremetal_build_dir']) + 1:] env['image'][len(env['baremetal_build_dir']) + 1:]
@@ -1178,6 +1182,7 @@ Incompatible archs are skipped.
break break
elif env['userland']: elif env['userland']:
env['image'] = self.resolve_userland_executable(env['userland'][0]) env['image'] = self.resolve_userland_executable(env['userland'][0])
env['image_elf'] = env['image']
source_path_noext = os.path.splitext(join( source_path_noext = os.path.splitext(join(
env['userland_source_dir'], env['userland_source_dir'],
env['image'][len(env['userland_build_dir']) + 1:] env['image'][len(env['userland_build_dir']) + 1:]
@@ -1195,6 +1200,7 @@ Incompatible archs are skipped.
else: else:
if not env['_args_given']['linux_exec']: if not env['_args_given']['linux_exec']:
env['image'] = env['linux_image'] env['image'] = env['linux_image']
env['image_elf'] = env['vmlinux']
if env['_args_given']['linux_exec']: if env['_args_given']['linux_exec']:
env['image'] = env['linux_exec'] env['image'] = env['linux_exec']
if env['emulator'] == 'gem5': if env['emulator'] == 'gem5':

4
disas
View File

@@ -18,7 +18,7 @@ Disassemble one function of the given executable.
https://cirosantilli.com/linux-kernel-module-cheat#run-toolchain https://cirosantilli.com/linux-kernel-module-cheat#run-toolchain
''', ''',
) )
self.add_argument('function', help='Which function to disassemble.') self.add_argument('function', default='main', help='Which function to disassemble.')
def timed_main(self): def timed_main(self):
lkmc.import_path.import_path_main('run-toolchain')( lkmc.import_path.import_path_main('run-toolchain')(
@@ -28,7 +28,7 @@ https://cirosantilli.com/linux-kernel-module-cheat#run-toolchain
'-batch', '-batch',
'-ex', '-ex',
'disas/rs {}'.format(self.env['function']), 'disas/rs {}'.format(self.env['function']),
self.env['image'], self.env['image_elf'],
], ],
quiet=True, quiet=True,
**self.get_common_args() **self.get_common_args()

View File

@@ -171,17 +171,14 @@ by default due to --continue if this breakpoint is reached.
else: else:
break_at = [] break_at = []
if self.env['userland']: if self.env['userland']:
image = self.env['image']
linux_full_system = False linux_full_system = False
if self.env['gdbserver']: if self.env['gdbserver']:
before.extend([ before.extend([
'-ex', 'set sysroot {}'.format(self.env['buildroot_staging_dir']), '-ex', 'set sysroot {}'.format(self.env['buildroot_staging_dir']),
]) ])
elif self.env['baremetal']: elif self.env['baremetal']:
image = self.env['image']
linux_full_system = False linux_full_system = False
else: else:
image = self.env['vmlinux']
linux_full_system = True linux_full_system = True
cmd = ( cmd = (
[self.env['gdb_path'], LF] + [self.env['gdb_path'], LF] +
@@ -200,7 +197,7 @@ by default due to --continue if this breakpoint is reached.
port = self.env['gdb_port'] port = self.env['gdb_port']
target = 'remote localhost:{}'.format(port) target = 'remote localhost:{}'.format(port)
cmd.extend([ cmd.extend([
'-ex', 'file {}'.format(image), LF, '-ex', 'file {}'.format(self.env['image_elf']), LF,
'-ex', 'target {}'.format(target), LF, '-ex', 'target {}'.format(target), LF,
]) ])
if not self.env['kgdb']: if not self.env['kgdb']: