diff --git a/common.py b/common.py index 2afbd71..180f614 100644 --- a/common.py +++ b/common.py @@ -1,9 +1,11 @@ #!/usr/bin/env python3 import argparse +import base64 import imp import subprocess import os +import shlex import sys this = sys.modules[__name__] @@ -27,6 +29,9 @@ this = sys.modules[__name__] # printf "exit_status $?\n" >> "$results_file" #) +def base64_encode(string): + return base64.b64encode(string.encode()).decode() + def get_argparse(**kwargs): """ Return an argument parser with common arguments set. @@ -104,6 +109,12 @@ around when you checkout between branches. parser.set_defaults(**this.configs) return parser +def print_cmd(cmd): + out = [] + for arg in cmd: + out.extend([shlex.quote(arg), ' \\\n']) + print(''.join(out)) + def setup(parser): """ Parse the command line arguments, and setup several variables based on them. @@ -138,6 +149,7 @@ def setup(parser): this.qemu_executable = os.path.join(this.qemu_variant_dir, '{}-softmmu'.format(args.arch), 'qemu-system-{}'.format(args.arch)) this.qemu_guest_custom_dir = os.path.join(this.build_dir, 'qemu-custom') this.host_dir = os.path.join(this.buildroot_out_dir, 'host') + this.host_bin_dir = os.path.join(this.host_dir, 'usr', 'bin') this.images_dir = os.path.join(this.buildroot_out_dir, 'images') this.ext2_file = os.path.join(this.images_dir, 'rootfs.ext2') this.qcow2_file = os.path.join(this.images_dir, 'rootfs.ext2.qcow2') diff --git a/run b/run index 80144e6..e538116 100755 --- a/run +++ b/run @@ -1,17 +1,14 @@ #!/usr/bin/env python3 -import base64 - -import common import os import shlex import subprocess import sys +import common + # Argparse. -parser = common.get_argparse( - description='Run Linux on an emulator' -) +parser = common.get_argparse(description='Run Linux on an emulator') init_group = parser.add_mutually_exclusive_group() kvm_group = parser.add_mutually_exclusive_group() parser.add_argument( @@ -176,7 +173,7 @@ else: if args.debug: extra_qemu_args.append('-S') if args.kernel_cli_extra_after_dash_base64 is not None: - kernel_cli_extra_after_dash += ' lkmc_eval_base64="{}"'.format(base64.b64encode(args.kernel_cli_extra_after_dash_base64)) + kernel_cli_extra_after_dash += ' lkmc_eval_base64="{}"'.format(common.base64_encode(args.kernel_cli_extra_after_dash_base64)) if args.kernel_cli_extra_after_dash is not None: kernel_cli_extra_after_dash += ' {}'.format(args.kernel_cli_extra_after_dash) if args.kgdb: @@ -195,13 +192,13 @@ if args.eval is not None: else: initarg = 'init' kernel_cli_extra += ' {}=/eval_base64.sh'.format(initarg) - kernel_cli_extra_after_dash += ' lkmc_eval="{}"'.format(base64.b64encode(args.eval)) + kernel_cli_extra_after_dash += ' lkmc_eval="{}"'.format(common.base64_encode(args.eval)) if not args.graphic: if args.arch == 'x86_64': kernel_cli_extra += ' console=ttyS0' extra_qemu_args.append('-nographic') if kernel_cli_extra_after_dash: - kernel_cli_extra += " - {}".format(kernel_cli_extra_after_dash) + kernel_cli_extra += " -{}".format(kernel_cli_extra_after_dash) # 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. @@ -361,13 +358,6 @@ else: virtio_gpu_pci ) -cmd += extra_emulator_args -print(' \\\n'.join(cmd)) -try: - subprocess.Popen(cmd, env=env).wait() -except KeyboardInterrupt: - pass - #if args.tmux: # if args.gem5: # eval "./tmu 'sleep 2;./gem5-shell -n ${common_run_id} ${tmux_args};'" @@ -377,6 +367,11 @@ except KeyboardInterrupt: # extra_emulator_args="${extra_emulator_args}${@} \\ #" #fi + +cmd += extra_emulator_args +common.print_cmd(cmd) +subprocess.Popen(cmd, env=env).wait() + #cmd="time \\ #${cmd}${extra_emulator_args}" #if [ -z "$debug_vm" ]; then diff --git a/rungdb b/rungdb index 4f36a36..7a7eb61 100755 --- a/rungdb +++ b/rungdb @@ -1,87 +1,87 @@ -#!/usr/bin/env bash -. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common" -after= -before= -lx_symbols="-ex 'lx-symbols ../kernel_module-1.0/' \\ -" -kgdb=false -docontinue=true -while getopts "A:a:b:CgkL:n:X${common_getopts_flags}" OPT; do - case "$OPT" in - A) - after="$OPTARG" - ;; - b) - before="$OPTARG" - ;; - C) - # No Continue. - docontinue=false - ;; - k) - kgdb=true - ;; - X) - lx_symbols= - ;; - ?) - common_getopts_case "$OPT" - ;; - esac -done -shift "$(($OPTIND - 1))" -if [ "$#" -gt 0 ]; then - brk="-ex 'break ${1}' \\ -" - shift -else - brk= -fi -common_setup -gdb="${common_host_dir}/usr/bin/${common_arch}-linux-gdb \\ -${before}" -if "$kgdb"; then - cmd="\ -${gdb}\ --q \\ --ex 'add-auto-load-safe-path $(pwd)' \\ --ex 'file vmlinux' \\ --ex 'target remote localhost:${common_gdb_port}' \\ -" -else - # ## lx-symbols - # - # ### lx-symbols after continue - # - # lx symbols must be run after continue. - # - # running it immediately after the connect on the bootloader leads to failure, - # likely because kernel structure on which it depends are not yet available. - # - # With this setup, continue runs, and lx-symbols only runs when a break happens, - # either by hitting the breakpoint, or by entering Ctrl + C. - # - # Sure, if the user sets a break on a raw address of the bootloader, - # problems will still arise, but let's think about that some other time. - # - # ### lx-symbols autoload - # - # The lx-symbols commands gets loaded through the file vmlinux-gdb.py - # which gets put on the kernel build root when python debugging scripts are enabled. - cmd="\ -${gdb}\ --q \\ --ex 'add-auto-load-safe-path $(pwd)' \\ --ex 'file vmlinux' \\ --ex 'target remote localhost:${common_gdb_port}' \\ -${brk}\ -" -fi -if "$docontinue"; then - cmd="${cmd}\ --ex continue \\ -${lx_symbols}\ -" -fi -"${common_root_dir}/eeval" "cd '${common_linux_variant_dir}' && \\ -$cmd $after" "${common_run_dir}/rungdb.sh" +#!/usr/bin/env python3 + +import os +import shlex +import signal +import subprocess + +import common + +parser = common.get_argparse(description='Connect with GDB to an emulator to debug Linux itself') +parser.add_argument( + '-A', '--after', default='', + help='Pass extra arguments to GDB, to be appended after all other arguments' +) +parser.add_argument( + '-b', '--before', default='', + help='Pass extra arguments to GDB to be prepended before any of the arguments passed by this script' +) +parser.add_argument( + '-C', '--no-continue', default=False, action='store_true', + help="Don't run continue after connecting" +) +parser.add_argument( + '-k', '--kgdb', default=False, action='store_true' +) +parser.add_argument( + '-X', '--no-lxsymbols', default=False, action='store_true' +) +parser.add_argument( + 'break_at', nargs='?', + help='Extra options to append at the end of the emulator command line' +) +args = common.setup(parser) +after = shlex.split(args.after) +before = shlex.split(args.before) +if args.no_lxsymbols: + lx_symbols = [] +else: + lx_symbols = ['-ex', 'lx-symbols ../kernel_module-1.0/'] +if args.break_at is not None: + break_at = ['-ex', 'break {}'.format(args.break_at)] +else: + break_at = [] +cmd = ( + [ + os.path.join(common.host_bin_dir, + '{}-linux-gdb'.format(args.arch)) + ] + + before + + [ + '-q', + '-ex', 'add-auto-load-safe-path {}'.format(common.linux_variant_dir), + '-ex', 'file {}'.format(common.vmlinux), + '-ex', 'target remote localhost:{}'.format(common.gdb_port), + ] +) +if not args.kgdb: + cmd.extend(break_at) +if not args.no_continue: + # ## lx-symbols + # + # ### lx-symbols after continue + # + # lx symbols must be run after continue. + # + # running it immediately after the connect on the bootloader leads to failure, + # likely because kernel structure on which it depends are not yet available. + # + # With this setup, continue runs, and lx-symbols only runs when a break happens, + # either by hitting the breakpoint, or by entering Ctrl + C. + # + # Sure, if the user sets a break on a raw address of the bootloader, + # problems will still arise, but let's think about that some other time. + # + # ### lx-symbols autoload + # + # The lx-symbols commands gets loaded through the file vmlinux-gdb.py + # which gets put on the kernel build root when python debugging scripts are enabled. + cmd.extend(['-ex', 'continue'] + lx_symbols) +cmd.extend(after) +common.print_cmd(cmd) + +# TODO eeval +# "${common.root_dir}/eeval" "$cmd $after" "${common.run_dir}/rungdb.sh" +def signal_handler(sig, frame): pass +signal.signal(signal.SIGINT, signal_handler) +subprocess.Popen(cmd, cwd=common.linux_variant_dir).wait()