From 485c071a4dfdb2e1fc2da7c5d00f05c8b6931fb8 Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Wed, 5 Sep 2018 08:03:48 +0100 Subject: [PATCH] get_elf_entry trace2txt fully ported --- README.adoc | 51 ++++++++++++++++++--------------------------------- common.py | 14 ++++++++++++++ run | 16 ++++++++++------ rungdb-user | 16 ++-------------- trace-boot | 33 +++++++++++++++++++++++++-------- 5 files changed, 69 insertions(+), 61 deletions(-) diff --git a/README.adoc b/README.adoc index 1d46cb9..83eeb97 100644 --- a/README.adoc +++ b/README.adoc @@ -5288,9 +5288,9 @@ QEMU: sample output: .... -instruction count all: 1833863 -entry address: 0x1000000 -instruction count firmware: 20708 +instructions 1833863 +entry_address 0x1000000 +instructions_firmware 20708 .... gem5: @@ -5328,7 +5328,7 @@ It only appears once on every log I've seen so far, checked with `grep 0x1000000 + Then when we count the instructions that run before the kernel entry point, there is only about 100k instructions, which is insignificant compared to the kernel boot itself. + -TODO `-a arm` and `-a aarch64` does not count firmware instructions properly because the entry point address of the ELF file does not show up on the trace at all. +TODO `-a arm` and `-a aarch64` does not count firmware instructions properly because the entry point address of the ELF file (`ffffff8008080000` for `aarch64`) does not show up on the trace at all. Tested on link:http://github.com/cirosantilli/linux-kernel-module-cheat/commit/f8c0502bb2680f2dbe7c1f3d7958f60265347005[f8c0502bb2680f2dbe7c1f3d7958f60265347005]. * 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: + .... @@ -9046,42 +9046,19 @@ So for example when you run: ./run -a arm .... -Stdout shows a line with the full command of type: +the very first stdout output of that script is the actual QEMU command that is being run. -.... -time \ -/home/ciro/bak/git/linux-kernel-module-cheat/out/arm/buildroot/build/host-qemu-custom.default/arm-softmmu/qemu-system-arm \ --device rtl8139,netdev=net0 \ --gdb 'tcp::45457' \ --kernel '/home/ciro/bak/git/linux-kernel-module-cheat/out/arm/buildroot/build/linux-custom.default/arch/arm/boot/zImage' \ --m '256M' \ --monitor 'telnet::45454,server,nowait' \ --netdev 'user,hostfwd=tcp::45455-:45455,hostfwd=tcp::45456-:22,id=net0' \ --no-reboot \ --serial mon:stdio \ --smp '1' \ --trace 'enable=pr_manager_run,file=/home/ciro/bak/git/linux-kernel-module-cheat/out/arm/qemu/0/trace.bin' \ --virtfs 'local,path=/home/ciro/bak/git/linux-kernel-module-cheat/data/9p,mount_tag=host_scratch,security_model=mapped,id=host_scratch' \ --virtfs 'local,path=/home/ciro/bak/git/linux-kernel-module-cheat/out/arm/buildroot/build,mount_tag=host_out,security_model=mapped,id=host_out' \ --M virt,highmem=off \ --append 'root=/dev/vda console_msg_format=syslog nokaslr norandmaps panic=-1 printk.devkmsg=on printk.time=y' \ --cpu cortex-a15 \ --device virtio-gpu-pci \ --nographic \ --drive 'file=/home/ciro/bak/git/linux-kernel-module-cheat/out/arm/buildroot/images/rootfs.ext2.qcow2,format=qcow2,if=virtio,snapshot' \ -|& tee >(ts -s %.s > /home/ciro/bak/git/linux-kernel-module-cheat/out/arm/qemu/0/termout.txt) -.... - -and this line is also saved to a file for convenience: +The command is also saved to a file for convenience: .... cat "$(./getvar -a arm run_cmd_file)" .... -or for gem5: +which you can manually modify and execute during your experiments later: .... -cat "$(./getvar -a arm -g run_cmd_file)" +vim "$(./getvar -a arm run_cmd_file)" +./"$(./getvar -a arm run_cmd_file)" .... Next, you will also want to give the relevant images to save them time. Zip the images with: @@ -9091,7 +9068,15 @@ Next, you will also want to give the relevant images to save them time. Zip the ./zip-img .... -and then upload the `out/lkmc-*.zip` file somewhere, e.g. GitHub release assets as in https://github.com/cirosantilli/linux-kernel-module-cheat/releases/tag/test-replay-arm +Source: link:zip-img[] + +This generates a zip file: + +.... +out/lkmc-*.zip +.... + +which you can then upload somewhere, e.g. GitHub release assets as in https://github.com/cirosantilli/linux-kernel-module-cheat/releases/tag/test-replay-arm Finally, do a clone of the relevant repository out of tree and reproduce the bug there, to be 100% sure that it is an actual upstream bug, and to provide developers with the cleanest possible commands. diff --git a/common.py b/common.py index 5f73856..112c705 100644 --- a/common.py +++ b/common.py @@ -133,6 +133,20 @@ around when you checkout between branches. parser.set_defaults(**defaults) return parser +def get_elf_entry(elf_file_path): + global this + readelf_header = subprocess.check_output([ + this.get_toolchain_tool('readelf'), + '-h', + elf_file_path + ]) + for line in readelf_header.decode().split('\n'): + split = line.split() + if line.startswith(' Entry point address:'): + addr = line.split()[-1] + break + return int(addr, 0) + def get_stats(stat_re=None, stats_file=None): global this if stat_re is None: diff --git a/run b/run index 6dcf8b6..2a4b055 100755 --- a/run +++ b/run @@ -84,16 +84,20 @@ def main(args, extra_args=None): if kernel_cli_extra_after_dash: kernel_cli_extra += " -{}".format(kernel_cli_extra_after_dash) extra_env = {} - - # A dummy value that is already turned on by default and does not produce large output, - # just to prevent QEMU from emitting a warning that '' is not valid. - trace_type = 'pr_manager_run' + if args.trace is None: + do_trace = False + # A dummy value that is already turned on by default and does not produce large output, + # just to prevent QEMU from emitting a warning that '' is not valid. + trace_type = 'pr_manager_run' + else: + do_trace = True + trace_type = args.trace if args.gem5: memory = '{}B'.format(args.memory) gem5_exe_args = shlex.split(args.gem5_exe_args) - if args.trace is not None: - gem5_exe_args.append('--debug-flags={}'.format(args.trace)) + if do_trace: + gem5_exe_args.append('--debug-flags={}'.format(trace_type)) extra_env['M5_PATH'] = common.gem5_system_dir cmd = ( debug_vm + diff --git a/rungdb-user b/rungdb-user index a6a96b2..49e477b 100755 --- a/rungdb-user +++ b/rungdb-user @@ -2,8 +2,6 @@ import imp import os -import subprocess -import re import common rungdb = imp.load_source('rungdb', os.path.join(common.root_dir, 'rungdb')) @@ -25,19 +23,9 @@ parser.add_argument( nargs='?' ) args = common.setup(parser) -readelf_header = subprocess.check_output([ - common.get_toolchain_tool('readelf'), - '-h', - os.path.join(common.build_dir, args.executable), -]) -for line in readelf_header.decode().split('\n'): - split = line.split() - if line.startswith(' Entry point address:'): - addr = line.split()[-1] - break -print(addr) +addr = common.get_elf_entry(os.path.join(common.build_dir, args.executable)) extra_args = {} -extra_args['before'] = '-ex \"add-symbol-file {} {}\"'.format(args.executable, addr) +extra_args['before'] = '-ex \"add-symbol-file {} {}\"'.format(args.executable, hex(addr)) # Or else lx-symbols throws for arm: # gdb.MemoryError: Cannot access memory at address 0xbf0040cc # TODO understand better. diff --git a/trace-boot b/trace-boot index bc5fbbc..135f99b 100755 --- a/trace-boot +++ b/trace-boot @@ -36,11 +36,28 @@ else: }) run.main(args, extra_args) qemu_trace2txt.main() - ## Instruction count. - ## We could put this on a separate script, but it just adds more arch boilerplate to a new script. - ## So let's just leave it here for now since it did not add a significant processing time. - #echo "instructions $(wc -l "${common_trace_txt_file}" | cut -d' ' -f1)" - #entry_addr=$("${common_root_dir}/runtc" readelf -h "${common_build_dir}/linux-custom/vmlinux" | grep 'Entry point address' | sed -E 's/.*: *//') - #echo "entry_address ${entry_addr}" - #sed "/${entry_addr}/q" "${common_trace_txt_file}" >"${common_qemu_run_dir}/trace-boot.txt" - #echo "instructions_firmware $(wc -l "${common_qemu_run_dir}/trace-boot.txt" | cut -d' ' -f1)" + # Instruction count. + # We could put this on a separate script, but it just adds more arch boilerplate to a new script. + # So let's just leave it here for now since it did not add a significant processing time. + kernel_entry_addr = hex(common.get_elf_entry(common.vmlinux)) + nlines = 0 + nlines_firmware = 0 + with open(common.qemu_trace_txt_file, 'r') as trace_file: + in_firmware = True + for line in trace_file: + line = line.rstrip() + nlines += 1 + pc = line.split('=')[-1] + if pc == kernel_entry_addr: + in_firmware = False + if in_firmware: + nlines_firmware += 1 + print('''\ +instructions {} +entry_address {} +instructions_firmware {}\ +'''.format( + nlines, + kernel_entry_addr, + nlines_firmware + ))