run kind of runs

This commit is contained in:
Ciro Santilli 六四事件 法轮功
2018-12-09 00:00:01 +00:00
parent 5e20ba833b
commit fa1e4ffa7d
34 changed files with 848 additions and 838 deletions

View File

@@ -960,7 +960,7 @@ This automatically clears the GDB pane, and starts a new one.
Pass extra GDB arguments with: Pass extra GDB arguments with:
.... ....
./run --wait-gdb --tmux=start_kernel ./run --wait-gdb --tmux --tmux-args start_kernel
.... ....
See the tmux manual for further details: See the tmux manual for further details:
@@ -2986,7 +2986,8 @@ Or alternatively, if you are using <<tmux>>, do everything in one go with:
./run \ ./run \
--arch aarch64 \ --arch aarch64 \
--userland print_argv \ --userland print_argv \
--tmux=main \ --tmux \
--tmux-args main \
--wait-gdb \ --wait-gdb \
-- \ -- \
asdf qwer \ asdf qwer \
@@ -5056,7 +5057,7 @@ If `CONFIG_KALLSYMS=n`, then addresses are shown on traces instead of symbol plu
In v4.16 it does not seem possible to configure that at runtime. GDB step debugging with: In v4.16 it does not seem possible to configure that at runtime. GDB step debugging with:
.... ....
./run --eval-after 'insmod /dump_stack.ko' --wait-gdb --tmux=dump_stack ./run --eval-after 'insmod /dump_stack.ko' --wait-gdb --tmux --tmux-args dump_stack
.... ....
shows that traces are printed at `arch/x86/kernel/dumpstack.c`: shows that traces are printed at `arch/x86/kernel/dumpstack.c`:
@@ -8168,7 +8169,7 @@ And in QEMU:
Or for a faster development loop: Or for a faster development loop:
.... ....
./run --debug-vm='-ex "break edu_mmio_read" -ex "run"' ./run --debug-vm --debug-vm-args '-ex "break edu_mmio_read" -ex "run"'
.... ....
When in <<qemu-text-mode>>, using `--debug-vm` makes Ctrl-C not get passed to the QEMU guest anymore: it is instead captured by GDB itself, so allow breaking. So e.g. you won't be able to easily quit from a guest program like: When in <<qemu-text-mode>>, using `--debug-vm` makes Ctrl-C not get passed to the QEMU guest anymore: it is instead captured by GDB itself, so allow breaking. So e.g. you won't be able to easily quit from a guest program like:
@@ -10259,13 +10260,13 @@ then on the second shell:
Or if you are a <<tmux,tmux pro>>, do everything in one go with: Or if you are a <<tmux,tmux pro>>, do everything in one go with:
.... ....
./run --arch arm --baremetal interactive/prompt --wait-gdb --tmux=main ./run --arch arm --baremetal interactive/prompt --wait-gdb --tmux --tmux-args main
.... ....
Alternatively, to start from the very first executed instruction of our tiny <<baremetal-bootloaders>>: Alternatively, to start from the very first executed instruction of our tiny <<baremetal-bootloaders>>:
.... ....
./run --arch arm --baremetal interactive/prompt --wait-gdb --tmux=--no-continue ./run --arch arm --baremetal interactive/prompt --wait-gdb --tmux --tmux-args --no-continue
.... ....
Now you can just `stepi` to when jumping into main to go to the C code in link:baremetal/interactive/prompt.c[]. Now you can just `stepi` to when jumping into main to go to the C code in link:baremetal/interactive/prompt.c[].
@@ -10273,7 +10274,7 @@ Now you can just `stepi` to when jumping into main to go to the C code in link:b
This is specially interesting for the executables that don't use the bootloader from under `baremetal/arch/<arch>/no_bootloader/*.S`, e.g.: This is specially interesting for the executables that don't use the bootloader from under `baremetal/arch/<arch>/no_bootloader/*.S`, e.g.:
.... ....
./run --arch arm --baremetal arch/arm/no_bootloader/semihost_exit --wait-gdb --tmux=--no-continue ./run --arch arm --baremetal arch/arm/no_bootloader/semihost_exit --wait-gdb --tmux --tmux-args --no-continue
.... ....
The cool thing about those examples is that you start at the very first instruction of your program, which gives more control. The cool thing about those examples is that you start at the very first instruction of your program, which gives more control.

View File

@@ -9,7 +9,7 @@ import common
build_linux = imp.load_source('build-linux', os.path.join(kwargs['root_dir'], 'build_linux')) build_linux = imp.load_source('build-linux', os.path.join(kwargs['root_dir'], 'build_linux'))
run = imp.load_source('run', os.path.join(kwargs['root_dir'], 'run')) run = imp.load_source('run', os.path.join(kwargs['root_dir'], 'run'))
parser = common.get_argparse( parser = self.get_argparse(
argparse_args={ argparse_args={
'description': '''Bisect the Linux kernel on gem5 boots. 'description': '''Bisect the Linux kernel on gem5 boots.
@@ -20,11 +20,11 @@ More information at: https://github.com/cirosantilli/linux-kernel-module-cheat#b
'linux_build_id': 'bisect', 'linux_build_id': 'bisect',
}, },
) )
args = common.setup(parser) args = self.setup(parser)
# We need a clean rebuild because rebuilds at different revisions: # We need a clean rebuild because rebuilds at different revisions:
# - may fail # - may fail
# - may not actually rebuild all files, e.g. on header changes # - may not actually rebuild all files, e.g. on header changes
common.rmrf(kwargs['linux_build_dir']) self.rmrf(kwargs['linux_build_dir'])
build_linux.LinuxComponent().do_build(args) build_linux.LinuxComponent().do_build(args)
status = run.main(args, { status = run.main(args, {
'eval': 'm5 exit', 'eval': 'm5 exit',

View File

@@ -1,10 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import common import common
parser = common.get_argparse( parser = self.get_argparse(
argparse_args={'description':'Convert a BST vs heap stat file into a gnuplot input'} argparse_args={'description':'Convert a BST vs heap stat file into a gnuplot input'}
) )
args = common.setup(parser) args = self.setup(parser)
stats = common.get_stats() stats = self.get_stats()
it = iter(stats) it = iter(stats)
i = 1 i = 1
for stat in it: for stat in it:

4
build
View File

@@ -315,9 +315,9 @@ Extra args to pass to all scripts.
parser.add_argument('components', choices=list(name_to_component_map.keys()) + [[]], default=[], nargs='*', help='''\ parser.add_argument('components', choices=list(name_to_component_map.keys()) + [[]], default=[], nargs='*', help='''\
Which components to build. Default: qemu-buildroot Which components to build. Default: qemu-buildroot
'''.format(kwargs['default_arch'])) '''.format(kwargs['default_arch']))
common.add_dry_run_argument(parser) self.add_dry_run_argument(parser)
args = parser.parse_args() args = parser.parse_args()
common.setup_dry_run_arguments(args) self.setup_dry_run_arguments(args)
# Decide archs. # Decide archs.
if kwargs['arch'] == []: if kwargs['arch'] == []:

View File

@@ -4,9 +4,9 @@ import os
import common import common
class BaremetalComponent(common.Component): class BaremetalComponent(self.Component):
def do_build(self, args): def do_build(self, args):
common.assert_crosstool_ng_supports_arch(kwargs['arch']) self.assert_crosstool_ng_supports_arch(kwargs['arch'])
build_dir = self.get_build_dir(args) build_dir = self.get_build_dir(args)
bootloader_obj = os.path.join(kwargs['baremetal_build_lib_dir'], 'bootloader{}'.format(kwargs['obj_ext'])) bootloader_obj = os.path.join(kwargs['baremetal_build_lib_dir'], 'bootloader{}'.format(kwargs['obj_ext']))
common_basename_noext = 'common' common_basename_noext = 'common'
@@ -28,7 +28,7 @@ class BaremetalComponent(common.Component):
gcc = 'arm-none-eabi-gcc' gcc = 'arm-none-eabi-gcc'
else: else:
os.environ['PATH'] = kwargs['crosstool_ng_bin_dir'] + os.environ['PATH'] os.environ['PATH'] = kwargs['crosstool_ng_bin_dir'] + os.environ['PATH']
gcc = common.get_toolchain_tool('gcc', allowed_toolchains=['crosstool-ng']) gcc = self.get_toolchain_tool('gcc', allowed_toolchains=['crosstool-ng'])
if kwargs['emulator'] == 'gem5': if kwargs['emulator'] == 'gem5':
if kwargs['machine'] == 'VExpress_GEM5_V1': if kwargs['machine'] == 'VExpress_GEM5_V1':
entry_address = 0x80000000 entry_address = 0x80000000
@@ -45,7 +45,7 @@ class BaremetalComponent(common.Component):
os.makedirs(build_dir, exist_ok=True) os.makedirs(build_dir, exist_ok=True)
os.makedirs(kwargs['baremetal_build_lib_dir'], exist_ok=True) os.makedirs(kwargs['baremetal_build_lib_dir'], exist_ok=True)
src = os.path.join(kwargs['baremetal_src_lib_dir'], '{}{}'.format(kwargs['arch'], kwargs['asm_ext'])) src = os.path.join(kwargs['baremetal_src_lib_dir'], '{}{}'.format(kwargs['arch'], kwargs['asm_ext']))
if common.need_rebuild([src], bootloader_obj): if self.need_rebuild([src], bootloader_obj):
self.sh.run_cmd( self.sh.run_cmd(
[gcc, LF] + [gcc, LF] +
cflags + cflags +
@@ -59,7 +59,7 @@ class BaremetalComponent(common.Component):
(common_src, common_obj), (common_src, common_obj),
(syscalls_src, syscalls_obj), (syscalls_src, syscalls_obj),
]: ]:
if common.need_rebuild([src], obj): if self.need_rebuild([src], obj):
self.sh.run_cmd( self.sh.run_cmd(
[gcc, LF] + [gcc, LF] +
cflags + cflags +
@@ -149,7 +149,7 @@ Build the baremetal examples with crosstool-NG.
in_name = os.path.splitext(in_basename)[0] in_name = os.path.splitext(in_basename)[0]
main_obj = os.path.join(kwargs['baremetal_build_dir'], subpath, '{}{}'.format(in_name, kwargs['obj_ext'])) main_obj = os.path.join(kwargs['baremetal_build_dir'], subpath, '{}{}'.format(in_name, kwargs['obj_ext']))
src = os.path.join(kwargs['baremetal_src_dir'], in_path) src = os.path.join(kwargs['baremetal_src_dir'], in_path)
if common.need_rebuild([src], main_obj): if self.need_rebuild([src], main_obj):
self.sh.run_cmd( self.sh.run_cmd(
[gcc, LF] + [gcc, LF] +
cflags + cflags +
@@ -162,7 +162,7 @@ Build the baremetal examples with crosstool-NG.
objs = common_objs + [main_obj] objs = common_objs + [main_obj]
out = os.path.join(kwargs['baremetal_build_dir'], subpath, in_name + kwargs['baremetal_build_ext']) out = os.path.join(kwargs['baremetal_build_dir'], subpath, in_name + kwargs['baremetal_build_ext'])
link_script = os.path.join(kwargs['baremetal_src_dir'], 'link.ld') link_script = os.path.join(kwargs['baremetal_src_dir'], 'link.ld')
if common.need_rebuild(objs + [link_script], out): if self.need_rebuild(objs + [link_script], out):
self.sh.run_cmd( self.sh.run_cmd(
[gcc, LF] + [gcc, LF] +
cflags + cflags +

View File

@@ -10,10 +10,10 @@ import re
import common import common
class BuildrootComponent(common.Component): class BuildrootComponent(self.Component):
def add_parser_arguments(self, parser): def add_parser_arguments(self, parser):
parser.add_argument( parser.add_argument(
'--build-linux', default=self._defaults['build_linux'], action='store_true', '--build-linux', default=self._defaults['build_linux'],
help='''\ help='''\
Enable building the Linux kernel with Buildroot. This is done mostly Enable building the Linux kernel with Buildroot. This is done mostly
to extract Buildroot's default kernel configurations when updating Buildroot. to extract Buildroot's default kernel configurations when updating Buildroot.
@@ -22,7 +22,7 @@ not currently supported, juse use ./build-linux script if you want to do that.
''' '''
) )
parser.add_argument( parser.add_argument(
'--baseline', default=self._defaults['baseline'], action='store_true', '--baseline', default=self._defaults['baseline'],
help='''Do a default-ish Buildroot defconfig build, without any of our extra options. help='''Do a default-ish Buildroot defconfig build, without any of our extra options.
Mostly to track how much slower we are than a basic build. Mostly to track how much slower we are than a basic build.
''' '''
@@ -42,14 +42,14 @@ Pass multiple times to use multiple fragment files.
''' '''
) )
parser.add_argument( parser.add_argument(
'--no-all', default=self._defaults['no_all'], action='store_true', '--no-all', default=self._defaults['no_all'],
help='''\ help='''\
Don't build the all target which normally gets build by default. Don't build the all target which normally gets build by default.
That target builds the root filesystem and all its dependencies. That target builds the root filesystem and all its dependencies.
''' '''
) )
parser.add_argument( parser.add_argument(
'--no-overlay', default=self._defaults['no_all'], action='store_true', '--no-overlay', default=self._defaults['no_all'],
help='''\ help='''\
Don't add our overlay which contains all files we build without going through Buildroot. Don't add our overlay which contains all files we build without going through Buildroot.
This prevents us from overwriting certain Buildroot files. Remember however that you must This prevents us from overwriting certain Buildroot files. Remember however that you must
@@ -140,7 +140,7 @@ usually extra Buildroot targets.
], ],
cwd=kwargs['buildroot_src_dir'], cwd=kwargs['buildroot_src_dir'],
) )
common.make_build_dirs() self.make_build_dirs()
if not kwargs['no_all']: if not kwargs['no_all']:
extra_make_args.extend(['all', LF]) extra_make_args.extend(['all', LF])
self.sh.run_cmd( self.sh.run_cmd(
@@ -161,7 +161,7 @@ usually extra Buildroot targets.
# Skip if qemu is not present, because gem5 does not need the qcow2. # Skip if qemu is not present, because gem5 does not need the qcow2.
# so we don't force a QEMU build for gem5. # so we don't force a QEMU build for gem5.
if not kwargs['no_all'] and os.path.exists(kwargs['qemu_img_executable']): if not kwargs['no_all'] and os.path.exists(kwargs['qemu_img_executable']):
common.raw_to_qcow2() self.raw_to_qcow2()
def get_argparse_args(self): def get_argparse_args(self):
return { return {

View File

@@ -4,9 +4,9 @@ import os
import common import common
class CrosstoolNgComponent(common.Component): class CrosstoolNgComponent(self.Component):
def do_build(self, args): def do_build(self, args):
common.assert_crosstool_ng_supports_arch(kwargs['arch']) self.assert_crosstool_ng_supports_arch(kwargs['arch'])
build_dir = self.get_build_dir(args) build_dir = self.get_build_dir(args)
defconfig_dest = os.path.join(kwargs['crosstool_ng_util_dir'], 'defconfig') defconfig_dest = os.path.join(kwargs['crosstool_ng_util_dir'], 'defconfig')
os.makedirs(kwargs['crosstool_ng_util_dir'], exist_ok=True) os.makedirs(kwargs['crosstool_ng_util_dir'], exist_ok=True)
@@ -37,7 +37,7 @@ class CrosstoolNgComponent(common.Component):
os.path.join(kwargs['root_dir'], 'crosstool_ng_config', kwargs['arch']), os.path.join(kwargs['root_dir'], 'crosstool_ng_config', kwargs['arch']),
defconfig_dest defconfig_dest
) )
common.write_configs( self.write_configs(
kwargs['crosstool_ng_defconfig'], kwargs['crosstool_ng_defconfig'],
[ [
'CT_PREFIX_DIR="{}"'.format(kwargs['crosstool_ng_install_dir']), 'CT_PREFIX_DIR="{}"'.format(kwargs['crosstool_ng_install_dir']),

View File

@@ -7,7 +7,7 @@ import tarfile
import common import common
class DockerComponent(common.Component): class DockerComponent(self.Component):
def get_argparse_args(self): def get_argparse_args(self):
return { return {
'description': '''\ 'description': '''\
@@ -68,7 +68,7 @@ See also:https://github.com/cirosantilli/linux-kernel-module-cheat#ubuntu-guest-
kwargs['docker_tar_dir'], kwargs['docker_tar_dir'],
kwargs['docker_rootfs_raw_file'], kwargs['docker_rootfs_raw_file'],
]) ])
common.raw_to_qcow2(prebuilt=True) self.raw_to_qcow2(prebuilt=True)
def get_build_dir(self, args): def get_build_dir(self, args):
return kwargs['docker_build_dir'] return kwargs['docker_build_dir']

View File

@@ -37,7 +37,7 @@ Still uses options explicitly passed with `--config` and
''' '''
) )
self.add_argument( self.add_argument(
'--config-only', default=False, action='store_true', '--config-only', default=False,
help='''\ help='''\
Configure the kernel, but don't build it. Configure the kernel, but don't build it.
''' '''
@@ -91,7 +91,7 @@ Configure the kernel, but don't build it.
if self.env['config'] != []: if self.env['config'] != []:
cli_config_fragment_path = os.path.join(build_dir, 'lkmc_cli_config_fragment') cli_config_fragment_path = os.path.join(build_dir, 'lkmc_cli_config_fragment')
cli_config_str = '\n'.join(self.env['config']) cli_config_str = '\n'.join(self.env['config'])
common.write_string_to_file(cli_config_fragment_path, cli_config_str) self.write_string_to_file(cli_config_fragment_path, cli_config_str)
config_fragments.append(cli_config_fragment_path) config_fragments.append(cli_config_fragment_path)
self.sh.cp( self.sh.cp(
base_config_file, base_config_file,
@@ -133,7 +133,7 @@ Configure the kernel, but don't build it.
) )
# TODO: remove build and source https://stackoverflow.com/questions/13578618/what-does-build-and-source-link-do-in-lib-modules-kernel-version # TODO: remove build and source https://stackoverflow.com/questions/13578618/what-does-build-and-source-link-do-in-lib-modules-kernel-version
# TODO Basically all kernel modules also basically leak full host paths. Just terrible. Buildroot deals with that stuff nicely for us. # TODO Basically all kernel modules also basically leak full host paths. Just terrible. Buildroot deals with that stuff nicely for us.
# common.rmrf() # self.rmrf()
def get_build_dir(self): def get_build_dir(self):
return self.env['linux_build_dir'] return self.env['linux_build_dir']

View File

@@ -4,11 +4,11 @@ import os
import common import common
class M5Component(common.Component): class M5Component(self.Component):
def get_make_cmd(self, args): def get_make_cmd(self, args):
allowed_toolchains = ['buildroot'] allowed_toolchains = ['buildroot']
cc = common.get_toolchain_tool('gcc', allowed_toolchains=allowed_toolchains) cc = self.get_toolchain_tool('gcc', allowed_toolchains=allowed_toolchains)
ld = common.get_toolchain_tool('ld', allowed_toolchains=allowed_toolchains) ld = self.get_toolchain_tool('ld', allowed_toolchains=allowed_toolchains)
if kwargs['arch'] == 'x86_64': if kwargs['arch'] == 'x86_64':
arch = 'x86' arch = 'x86'
else: else:

View File

@@ -7,7 +7,7 @@ import shutil
import common import common
class ModulesComponent(common.Component): class ModulesComponent(self.Component):
def add_parser_arguments(self, parser): def add_parser_arguments(self, parser):
parser.add_argument( parser.add_argument(
'--make-args', '--make-args',
@@ -15,7 +15,6 @@ class ModulesComponent(common.Component):
) )
parser.add_argument( parser.add_argument(
'--host', '--host',
action='store_true',
default=False, default=False,
help='''\ help='''\
Build the Linux kernel modules for the host instead of guest. Build the Linux kernel modules for the host instead of guest.
@@ -70,7 +69,7 @@ Use the host packaged cross toolchain.
else: else:
allowed_toolchains = None allowed_toolchains = None
build_subdir = kwargs['kernel_modules_build_subdir'] build_subdir = kwargs['kernel_modules_build_subdir']
gcc = common.get_toolchain_tool(tool, allowed_toolchains=allowed_toolchains) gcc = self.get_toolchain_tool(tool, allowed_toolchains=allowed_toolchains)
prefix = gcc[:-len(tool)] prefix = gcc[:-len(tool)]
ccache = shutil.which('ccache') ccache = shutil.which('ccache')
if ccache is not None: if ccache is not None:
@@ -97,13 +96,13 @@ Use the host packaged cross toolchain.
'M={}'.format(build_subdir), LF, 'M={}'.format(build_subdir), LF,
'OBJECT_FILES={}'.format(' '.join(object_files)), LF, 'OBJECT_FILES={}'.format(' '.join(object_files)), LF,
] + ] +
common.shlex_split(kwargs['make_args']) + self.sh.shlex_split(kwargs['make_args']) +
verbose verbose
), ),
cwd=os.path.join(kwargs['kernel_modules_build_subdir']), cwd=os.path.join(kwargs['kernel_modules_build_subdir']),
) )
if not kwargs['host']: if not kwargs['host']:
common.copy_dir_if_update_non_recursive( self.copy_dir_if_update_non_recursive(
srcdir=kwargs['kernel_modules_build_subdir'], srcdir=kwargs['kernel_modules_build_subdir'],
destdir=kwargs['out_rootfs_overlay_dir'], destdir=kwargs['out_rootfs_overlay_dir'],
filter_ext=kwargs['kernel_module_ext'], filter_ext=kwargs['kernel_module_ext'],

View File

@@ -4,12 +4,11 @@ import os
import common import common
class QemuComponent(common.Component): class QemuComponent(self.Component):
def add_parser_arguments(self, parser): def add_parser_arguments(self, parser):
parser.add_argument( parser.add_argument(
'--userland', '--userland',
default=False, default=False,
action='store_true',
help='Build QEMU user mode instead of system.', help='Build QEMU user mode instead of system.',
) )
parser.add_argument( parser.add_argument(

View File

@@ -8,7 +8,7 @@ import subprocess
import common import common
class UserlandComponent(common.Component): class UserlandComponent(self.Component):
def add_parser_arguments(self, parser): def add_parser_arguments(self, parser):
parser.add_argument( parser.add_argument(
'--has-package', '--has-package',
@@ -21,7 +21,6 @@ allows us to build examples that rely on it.
) )
parser.add_argument( parser.add_argument(
'--host', '--host',
action='store_true',
default=False, default=False,
help='''\ help='''\
Build the userland programs for the host instead of guest. Build the userland programs for the host instead of guest.
@@ -51,8 +50,8 @@ has the OpenBLAS libraries and headers installed.
allowed_toolchains = ['host'] allowed_toolchains = ['host']
else: else:
allowed_toolchains = ['buildroot'] allowed_toolchains = ['buildroot']
cc = common.get_toolchain_tool('gcc', allowed_toolchains=allowed_toolchains) cc = self.get_toolchain_tool('gcc', allowed_toolchains=allowed_toolchains)
cxx = common.get_toolchain_tool('g++', allowed_toolchains=allowed_toolchains) cxx = self.get_toolchain_tool('g++', allowed_toolchains=allowed_toolchains)
self.sh.run_cmd( self.sh.run_cmd(
( (
[ [
@@ -74,7 +73,7 @@ has the OpenBLAS libraries and headers installed.
cwd=kwargs['userland_src_dir'], cwd=kwargs['userland_src_dir'],
extra_paths=[kwargs['ccache_dir']], extra_paths=[kwargs['ccache_dir']],
) )
common.copy_dir_if_update_non_recursive( self.copy_dir_if_update_non_recursive(
srcdir=build_dir, srcdir=build_dir,
destdir=kwargs['out_rootfs_overlay_dir'], destdir=kwargs['out_rootfs_overlay_dir'],
filter_ext=kwargs['userland_build_ext'], filter_ext=kwargs['userland_build_ext'],

73
cli_function.py Normal file → Executable file
View File

@@ -41,15 +41,17 @@ class Argument:
if nargs is not None: if nargs is not None:
self.kwargs['nargs'] = nargs self.kwargs['nargs'] = nargs
if default is True: if default is True:
self.kwargs['action'] = 'store_false' bool_action = 'store_false'
self.is_bool = True self.is_bool = True
elif default is False: elif default is False:
self.kwargs['action'] = 'store_true' bool_action = 'store_true'
self.is_bool = True self.is_bool = True
else: else:
self.is_bool = False self.is_bool = False
if default is None and nargs in ('*', '+'): if default is None and nargs in ('*', '+'):
default = [] default = []
if self.is_bool and not 'action' in kwargs:
self.kwargs['action'] = bool_action
if help is not None: if help is not None:
if not self.is_bool and default: if not self.is_bool and default:
help += ' Default: {}'.format(default) help += ' Default: {}'.format(default)
@@ -131,6 +133,9 @@ class CliFunction:
help='Path to the configuration file to use' help='Path to the configuration file to use'
) )
def __str__(self):
return '\n'.join(str(arg) for arg in self._arguments)
def add_argument( def add_argument(
self, self,
*args, *args,
@@ -155,11 +160,10 @@ class CliFunction:
new_longname = '--no' + argument.longname[1:] new_longname = '--no' + argument.longname[1:]
kwargs = argument.kwargs.copy() kwargs = argument.kwargs.copy()
kwargs['default'] = not argument.default kwargs['default'] = not argument.default
if argument.default: if kwargs['action'] == 'store_false':
action = 'store_true' kwargs['action'] = 'store_true'
else: elif kwargs['action'] == 'store_true':
action = 'store_false' kwargs['action'] = 'store_false'
kwargs['action'] = action
if 'help' in kwargs: if 'help' in kwargs:
del kwargs['help'] del kwargs['help']
parser.add_argument(new_longname, dest=argument.key, **kwargs) parser.add_argument(new_longname, dest=argument.key, **kwargs)
@@ -188,6 +192,7 @@ amazing function!
self.add_argument('-q', '--qwer', default='Q', help='Help for qwer'), self.add_argument('-q', '--qwer', default='Q', help='Help for qwer'),
self.add_argument('-b', '--bool', default=True, help='Help for bool'), self.add_argument('-b', '--bool', default=True, help='Help for bool'),
self.add_argument('--bool-cli', default=False, help='Help for bool'), self.add_argument('--bool-cli', default=False, help='Help for bool'),
self.add_argument('--bool-nargs', default=False, nargs='?', action='store', const='')
self.add_argument('--no-default', help='Help for no-bool'), self.add_argument('--no-default', help='Help for no-bool'),
self.add_argument('pos-mandatory', help='Help for pos-mandatory', type=int), self.add_argument('pos-mandatory', help='Help for pos-mandatory', type=int),
self.add_argument('pos-optional', default=0, help='Help for pos-optional', type=int), self.add_argument('pos-optional', default=0, help='Help for pos-optional', type=int),
@@ -196,32 +201,62 @@ amazing function!
del kwargs['config_file'] del kwargs['config_file']
return kwargs return kwargs
# Code calls. one_cli_function = OneCliFunction()
default = OneCliFunction()(pos_mandatory=1)
assert default == {'asdf': 'A', 'qwer': 'Q', 'bool': True, 'bool_cli': True, 'no_default': None, 'pos_mandatory': 1, 'pos_optional': 0, 'args_star': []} # Default code call.
default = one_cli_function(pos_mandatory=1)
assert default == {
'asdf': 'A',
'qwer': 'Q',
'bool': True,
'bool_nargs': False,
'bool_cli': True,
'no_default': None,
'pos_mandatory': 1,
'pos_optional': 0,
'args_star': []
}
# Default CLI call.
out = one_cli_function.cli(['1'])
assert out == default
# asdf # asdf
out = OneCliFunction()(pos_mandatory=1, asdf='B') out = one_cli_function(pos_mandatory=1, asdf='B')
assert out['asdf'] == 'B' assert out['asdf'] == 'B'
out['asdf'] = default['asdf'] out['asdf'] = default['asdf']
assert(out == default) assert(out == default)
# asdf and qwer # asdf and qwer
out = OneCliFunction()(pos_mandatory=1, asdf='B', qwer='R') out = one_cli_function(pos_mandatory=1, asdf='B', qwer='R')
assert out['asdf'] == 'B' assert out['asdf'] == 'B'
assert out['qwer'] == 'R' assert out['qwer'] == 'R'
out['asdf'] = default['asdf'] out['asdf'] = default['asdf']
out['qwer'] = default['qwer'] out['qwer'] = default['qwer']
assert(out == default) assert(out == default)
# bool if '--bool':
out = OneCliFunction()(pos_mandatory=1, bool=False) out = one_cli_function(pos_mandatory=1, bool=False)
assert out['bool'] == False cli_out = one_cli_function.cli(['--bool', '1'])
out['bool'] = default['bool'] assert out == cli_out
assert(out == default) assert out['bool'] == False
out['bool'] = default['bool']
assert(out == default)
if '--bool-nargs':
out = one_cli_function(pos_mandatory=1, bool_nargs=True)
assert out['bool_nargs'] == True
out['bool_nargs'] = default['bool_nargs']
assert(out == default)
out = one_cli_function(pos_mandatory=1, bool_nargs='asdf')
assert out['bool_nargs'] == 'asdf'
out['bool_nargs'] = default['bool_nargs']
assert(out == default)
# Force a boolean value set on the config to be False on CLI. # Force a boolean value set on the config to be False on CLI.
assert OneCliFunction().cli(['--no-bool-cli', '1'])['bool_cli'] is False assert one_cli_function.cli(['--no-bool-cli', '1'])['bool_cli'] is False
# CLI call. # CLI call.
print(OneCliFunction().cli()) print(one_cli_function.cli())

349
common.py
View File

@@ -13,7 +13,6 @@ import os
import re import re
import shutil import shutil
import signal import signal
import stat
import subprocess import subprocess
import sys import sys
import time import time
@@ -120,7 +119,7 @@ mkdir are generally omitted since those are obvious
''' '''
) )
self.add_argument( self.add_argument(
'-v', '--verbose', default=False, action='store_true', '-v', '--verbose', default=False,
help='Show full compilation commands when they are not shown by default.' help='Show full compilation commands when they are not shown by default.'
) )
@@ -163,10 +162,10 @@ Linux build ID. Allows you to keep multiple separate Linux builds.
''' '''
) )
self.add_argument( self.add_argument(
'--initramfs', default=False, action='store_true', '--initramfs', default=False,
) )
self.add_argument( self.add_argument(
'--initrd', default=False, action='store_true', '--initrd', default=False,
) )
# Baremetal. # Baremetal.
@@ -189,7 +188,7 @@ inside baremetal/ and then try to use corresponding executable.
help='Buildroot build ID. Allows you to keep multiple separate gem5 builds.' help='Buildroot build ID. Allows you to keep multiple separate gem5 builds.'
) )
self.add_argument( self.add_argument(
'--buildroot-linux', default=False, action='store_true', '--buildroot-linux', default=False,
help='Boot with the Buildroot Linux kernel instead of our custom built one. Mostly for sanity checks.' help='Boot with the Buildroot Linux kernel instead of our custom built one. Mostly for sanity checks.'
) )
@@ -199,7 +198,7 @@ inside baremetal/ and then try to use corresponding executable.
help='Crosstool-NG build ID. Allows you to keep multiple separate crosstool-NG builds.' help='Crosstool-NG build ID. Allows you to keep multiple separate crosstool-NG builds.'
) )
self.add_argument( self.add_argument(
'--docker', default=False, action='store_true', '--docker', default=False,
help='''\ help='''\
Use the docker download Ubuntu root filesystem instead of the default Buildroot one. Use the docker download Ubuntu root filesystem instead of the default Buildroot one.
''' '''
@@ -234,7 +233,7 @@ and then inspect separate outputs later in different output directories.
''' '''
) )
self.add_argument( self.add_argument(
'-P', '--prebuilt', default=False, action='store_true', '-P', '--prebuilt', default=False,
help='''\ help='''\
Use prebuilt packaged host utilities as much as possible instead Use prebuilt packaged host utilities as much as possible instead
of the ones we built ourselves. Saves build time, but decreases of the ones we built ourselves. Saves build time, but decreases
@@ -251,11 +250,11 @@ instances in parallel. Default: the run ID (-n) if that is an integer, otherwise
# Misc. # Misc.
self.add_argument( self.add_argument(
'-g', '--gem5', default=False, action='store_true', '-g', '--gem5', default=False,
help='Use gem5 instead of QEMU.' help='Use gem5 instead of QEMU.'
) )
self.add_argument( self.add_argument(
'--qemu', default=False, action='store_true', '--qemu', default=False,
help='''\ help='''\
Use QEMU as the emulator. This option exists in addition to --gem5 Use QEMU as the emulator. This option exists in addition to --gem5
to allow overriding configs from the CLI. to allow overriding configs from the CLI.
@@ -426,6 +425,7 @@ to allow overriding configs from the CLI.
env['executable'] = env['qemu_executable'] env['executable'] = env['qemu_executable']
env['run_dir'] = env['qemu_run_dir'] env['run_dir'] = env['qemu_run_dir']
env['termout_file'] = env['qemu_termout_file'] env['termout_file'] = env['qemu_termout_file']
env['guest_terminal_file'] = env['qemu_termout_file']
env['trace_txt_file'] = env['qemu_trace_txt_file'] env['trace_txt_file'] = env['qemu_trace_txt_file']
env['run_cmd_file'] = join(env['run_dir'], 'run.sh') env['run_cmd_file'] = join(env['run_dir'], 'run.sh')
@@ -497,7 +497,7 @@ to allow overriding configs from the CLI.
if env['baremetal'] == 'all': if env['baremetal'] == 'all':
path = env['baremetal'] path = env['baremetal']
else: else:
path = resolve_executable( path = self.resolve_executable(
env['baremetal'], env['baremetal'],
env['baremetal_src_dir'], env['baremetal_src_dir'],
env['baremetal_build_dir'], env['baremetal_build_dir'],
@@ -515,6 +515,23 @@ to allow overriding configs from the CLI.
env['image'] = path env['image'] = path
self.env = env self.env = env
def assert_crosstool_ng_supports_arch(self, arch):
if arch not in self.env['crosstool_ng_supported_archs']:
raise Exception('arch not yet supported: ' + arch)
@staticmethod
def base64_encode(string):
return base64.b64encode(string.encode()).decode()
def gem_list_checkpoint_dirs(self):
'''
List checkpoint directory, oldest first.
'''
prefix_re = re.compile(self.env['gem5_cpt_prefix'])
files = list(filter(lambda x: os.path.isdir(os.path.join(self.env['m5out_dir'], x)) and prefix_re.search(x), os.listdir(self.env['m5out_dir'])))
files.sort(key=lambda x: os.path.getmtime(os.path.join(self.env['m5out_dir'], x)))
return files
def get_elf_entry(self, elf_file_path): def get_elf_entry(self, elf_file_path):
readelf_header = subprocess.check_output([ readelf_header = subprocess.check_output([
self.get_toolchain_tool('readelf'), self.get_toolchain_tool('readelf'),
@@ -528,6 +545,21 @@ to allow overriding configs from the CLI.
break break
return int(addr, 0) return int(addr, 0)
def get_stats(self, stat_re=None, stats_file=None):
if stat_re is None:
stat_re = '^system.cpu[0-9]*.numCycles$'
if stats_file is None:
stats_file = self.env['stats_file']
stat_re = re.compile(stat_re)
ret = []
with open(stats_file, 'r') as statfile:
for line in statfile:
if line[0] != '-':
cols = line.split()
if len(cols) > 1 and stat_re.search(cols[0]):
ret.append(cols[1])
return ret
def get_toolchain_prefix(self, tool, allowed_toolchains=None): def get_toolchain_prefix(self, tool, allowed_toolchains=None):
buildroot_full_prefix = os.path.join(self.env['host_bin_dir'], self.env['buildroot_toolchain_prefix']) buildroot_full_prefix = os.path.join(self.env['host_bin_dir'], self.env['buildroot_toolchain_prefix'])
buildroot_exists = os.path.exists('{}-{}'.format(buildroot_full_prefix, tool)) buildroot_exists = os.path.exists('{}-{}'.format(buildroot_full_prefix, tool))
@@ -562,6 +594,41 @@ to allow overriding configs from the CLI.
def get_toolchain_tool(self, tool, allowed_toolchains=None): def get_toolchain_tool(self, tool, allowed_toolchains=None):
return '{}-{}'.format(self.get_toolchain_prefix(tool, allowed_toolchains), tool) return '{}-{}'.format(self.get_toolchain_prefix(tool, allowed_toolchains), tool)
@staticmethod
def github_make_request(
authenticate=False,
data=None,
extra_headers=None,
path='',
subdomain='api',
url_params=None,
**extra_request_args
):
if extra_headers is None:
extra_headers = {}
headers = {'Accept': 'application/vnd.github.v3+json'}
headers.update(extra_headers)
if authenticate:
headers['Authorization'] = 'token ' + os.environ['LKMC_GITHUB_TOKEN']
if url_params is not None:
path += '?' + urllib.parse.urlencode(url_params)
request = urllib.request.Request(
'https://' + subdomain + '.github.com/repos/' + github_repo_id + path,
headers=headers,
data=data,
**extra_request_args
)
response_body = urllib.request.urlopen(request).read().decode()
if response_body:
_json = json.loads(response_body)
else:
_json = {}
return _json
@staticmethod
def log_error(msg):
print('error: {}'.format(msg), file=sys.stderr)
def main(self, **kwargs): def main(self, **kwargs):
''' '''
Time the main of the derived class. Time the main of the derived class.
@@ -571,13 +638,107 @@ to allow overriding configs from the CLI.
kwargs.update(consts) kwargs.update(consts)
self._init_env(kwargs) self._init_env(kwargs)
self.sh = shell_helpers.ShellHelpers(dry_run=self.env['dry_run']) self.sh = shell_helpers.ShellHelpers(dry_run=self.env['dry_run'])
self.timed_main() ret = self.timed_main()
if not kwargs['dry_run']: if not kwargs['dry_run']:
end_time = time.time() end_time = time.time()
print_time(end_time - start_time) self.print_time(end_time - start_time)
return ret
def run_cmd(self, *args, **kwargs): def make_build_dirs(self):
self.sh.run_cmd(*args, **kwargs) os.makedirs(self.env['buildroot_build_build_dir'], exist_ok=True)
os.makedirs(self.env['gem5_build_dir'], exist_ok=True)
os.makedirs(self.env['out_rootfs_overlay_dir'], exist_ok=True)
def make_run_dirs(self):
'''
Make directories required for the run.
The user could nuke those anytime between runs to try and clean things up.
'''
os.makedirs(self.env['gem5_run_dir'], exist_ok=True)
os.makedirs(self.env['p9_dir'], exist_ok=True)
os.makedirs(self.env['qemu_run_dir'], exist_ok=True)
@staticmethod
def need_rebuild(srcs, dst):
if not os.path.exists(dst):
return True
for src in srcs:
if os.path.getmtime(src) > os.path.getmtime(dst):
return True
return False
@staticmethod
def print_time(ellapsed_seconds):
hours, rem = divmod(ellapsed_seconds, 3600)
minutes, seconds = divmod(rem, 60)
print("time {:02}:{:02}:{:02}".format(int(hours), int(minutes), int(seconds)))
def raw_to_qcow2(eslf, prebuilt=False, reverse=False):
if prebuilt or not os.path.exists(self.env['qemu_img_executable']):
disable_trace = []
qemu_img_executable = self.env['qemu_img_basename']
else:
# Prevent qemu-img from generating trace files like QEMU. Disgusting.
disable_trace = ['-T', 'pr_manager_run,file=/dev/null', LF,]
qemu_img_executable = self.env['qemu_img_executable']
infmt = 'raw'
outfmt = 'qcow2'
infile = self.env['rootfs_raw_file']
outfile = self.env['qcow2_file']
if reverse:
tmp = infmt
infmt = outfmt
outfmt = tmp
tmp = infile
infile = outfile
outfile = tmp
self.sh.run_cmd(
[
qemu_img_executable, LF,
] +
disable_trace +
[
'convert', LF,
'-f', infmt, LF,
'-O', outfmt, LF,
infile, LF,
outfile, LF,
]
)
@staticmethod
def resolve_args(defaults, args, extra_args):
if extra_args is None:
extra_args = {}
argcopy = copy.copy(args)
argcopy.__dict__ = dict(list(defaults.items()) + list(argcopy.__dict__.items()) + list(extra_args.items()))
return argcopy
@staticmethod
def resolve_executable(in_path, magic_in_dir, magic_out_dir, out_ext):
if os.path.isabs(in_path):
return in_path
else:
paths = [
os.path.join(magic_out_dir, in_path),
os.path.join(
magic_out_dir,
os.path.relpath(in_path, magic_in_dir),
)
]
paths[:] = [os.path.splitext(path)[0] + out_ext for path in paths]
for path in paths:
if os.path.exists(path):
return path
raise Exception('Executable file not found. Tried:\n' + '\n'.join(paths))
def resolve_userland(self, path):
return self.resolve_executable(
path,
self.env['userland_src_dir'],
self.env['userland_build_dir'],
self.env['userland_build_ext'],
)
def timed_main(self): def timed_main(self):
''' '''
@@ -628,162 +789,6 @@ class BuildCliFunction(LkmcCliFunction):
The actual build work is done by do_build in implementing classes. The actual build work is done by do_build in implementing classes.
''' '''
if self.env['clean']: if self.env['clean']:
self.clean() return self.clean()
else: else:
self.build() return self.build()
def assert_crosstool_ng_supports_arch(arch):
if arch not in kwargs['crosstool_ng_supported_archs']:
raise Exception('arch not yet supported: ' + arch)
def base64_encode(string):
return base64.b64encode(string.encode()).decode()
def gem_list_checkpoint_dirs():
'''
List checkpoint directory, oldest first.
'''
prefix_re = re.compile(kwargs['gem5_cpt_prefix'])
files = list(filter(lambda x: os.path.isdir(os.path.join(kwargs['m5out_dir'], x)) and prefix_re.search(x), os.listdir(kwargs['m5out_dir'])))
files.sort(key=lambda x: os.path.getmtime(os.path.join(kwargs['m5out_dir'], x)))
return files
def get_stats(stat_re=None, stats_file=None):
if stat_re is None:
stat_re = '^system.cpu[0-9]*.numCycles$'
if stats_file is None:
stats_file = kwargs['stats_file']
stat_re = re.compile(stat_re)
ret = []
with open(stats_file, 'r') as statfile:
for line in statfile:
if line[0] != '-':
cols = line.split()
if len(cols) > 1 and stat_re.search(cols[0]):
ret.append(cols[1])
return ret
def github_make_request(
authenticate=False,
data=None,
extra_headers=None,
path='',
subdomain='api',
url_params=None,
**extra_request_args
):
if extra_headers is None:
extra_headers = {}
headers = {'Accept': 'application/vnd.github.v3+json'}
headers.update(extra_headers)
if authenticate:
headers['Authorization'] = 'token ' + os.environ['LKMC_GITHUB_TOKEN']
if url_params is not None:
path += '?' + urllib.parse.urlencode(url_params)
request = urllib.request.Request(
'https://' + subdomain + '.github.com/repos/' + github_repo_id + path,
headers=headers,
data=data,
**extra_request_args
)
response_body = urllib.request.urlopen(request).read().decode()
if response_body:
_json = json.loads(response_body)
else:
_json = {}
return _json
def log_error(msg):
print('error: {}'.format(msg), file=sys.stderr)
def make_build_dirs():
os.makedirs(kwargs['buildroot_build_build_dir'], exist_ok=True)
os.makedirs(kwargs['gem5_build_dir'], exist_ok=True)
os.makedirs(kwargs['out_rootfs_overlay_dir'], exist_ok=True)
def make_run_dirs():
'''
Make directories required for the run.
The user could nuke those anytime between runs to try and clean things up.
'''
os.makedirs(kwargs['gem5_run_dir'], exist_ok=True)
os.makedirs(kwargs['p9_dir'], exist_ok=True)
os.makedirs(kwargs['qemu_run_dir'], exist_ok=True)
def need_rebuild(srcs, dst):
if not os.path.exists(dst):
return True
for src in srcs:
if os.path.getmtime(src) > os.path.getmtime(dst):
return True
return False
def print_time(ellapsed_seconds):
hours, rem = divmod(ellapsed_seconds, 3600)
minutes, seconds = divmod(rem, 60)
print("time {:02}:{:02}:{:02}".format(int(hours), int(minutes), int(seconds)))
def raw_to_qcow2(prebuilt=False, reverse=False):
if prebuilt or not os.path.exists(kwargs['qemu_img_executable']):
disable_trace = []
qemu_img_executable = kwargs['qemu_img_basename']
else:
# Prevent qemu-img from generating trace files like QEMU. Disgusting.
disable_trace = ['-T', 'pr_manager_run,file=/dev/null', LF,]
qemu_img_executable = kwargs['qemu_img_executable']
infmt = 'raw'
outfmt = 'qcow2'
infile = kwargs['rootfs_raw_file']
outfile = kwargs['qcow2_file']
if reverse:
tmp = infmt
infmt = outfmt
outfmt = tmp
tmp = infile
infile = outfile
outfile = tmp
self.sh.run_cmd(
[
qemu_img_executable, LF,
] +
disable_trace +
[
'convert', LF,
'-f', infmt, LF,
'-O', outfmt, LF,
infile, LF,
outfile, LF,
]
)
def resolve_args(defaults, args, extra_args):
if extra_args is None:
extra_args = {}
argcopy = copy.copy(args)
argcopy.__dict__ = dict(list(defaults.items()) + list(argcopy.__dict__.items()) + list(extra_args.items()))
return argcopy
def resolve_executable(in_path, magic_in_dir, magic_out_dir, out_ext):
if os.path.isabs(in_path):
return in_path
else:
paths = [
os.path.join(magic_out_dir, in_path),
os.path.join(
magic_out_dir,
os.path.relpath(in_path, magic_in_dir),
)
]
paths[:] = [os.path.splitext(path)[0] + out_ext for path in paths]
for path in paths:
if os.path.exists(path):
return path
raise Exception('Executable file not found. Tried:\n' + '\n'.join(paths))
def resolve_userland(path):
return resolve_executable(
path,
kwargs['userland_src_dir'],
kwargs['userland_build_dir'],
kwargs['userland_build_ext'],
)

View File

@@ -6,7 +6,7 @@ import shutil
import common import common
class CopyOverlayComponent(common.Component): class CopyOverlayComponent(self.Component):
def do_build(self, args): def do_build(self, args):
distutils.dir_util.copy_tree( distutils.dir_util.copy_tree(
kwargs['rootfs_overlay_dir'], kwargs['rootfs_overlay_dir'],

View File

@@ -4,11 +4,11 @@ import sys
import common import common
parser = common.get_argparse( parser = self.get_argparse(
default_args={'gem5':True}, default_args={'gem5':True},
argparse_args={'description':'Connect a terminal to a running gem5 instance'} argparse_args={'description':'Connect a terminal to a running gem5 instance'}
) )
args = common.setup(parser) args = self.setup(parser)
sys.exit(self.sh.run_cmd([ sys.exit(self.sh.run_cmd([
kwargs['gem5_m5term'], LF, kwargs['gem5_m5term'], LF,
'localhost', LF, 'localhost', LF,

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import common import common
parser = common.get_argparse( parser = self.get_argparse(
argparse_args={'description':'Get the value of a gem5 stat from the stats.txt file.'} argparse_args={'description':'Get the value of a gem5 stat from the stats.txt file.'}
) )
parser.add_argument( parser.add_argument(
@@ -9,6 +9,6 @@ parser.add_argument(
help='Python regexp matching the full stat name of interest', help='Python regexp matching the full stat name of interest',
nargs='?', nargs='?',
) )
args = common.setup(parser) args = self.setup(parser)
stats = common.get_stats(kwargs['stat']) stats = self.get_stats(kwargs['stat'])
print('\n'.join(stats)) print('\n'.join(stats))

4
getvar
View File

@@ -4,7 +4,7 @@ import types
import common import common
parser = common.get_argparse(argparse_args={ parser = self.get_argparse(argparse_args={
'description': '''Print the value of a kwargs['py'] variable. 'description': '''Print the value of a kwargs['py'] variable.
This is useful to: This is useful to:
@@ -27,7 +27,7 @@ List all available variables:
''' '''
}) })
parser.add_argument('variable', nargs='?') parser.add_argument('variable', nargs='?')
args = common.setup(parser) args = self.setup(parser)
if kwargs['variable']: if kwargs['variable']:
print(getattr(common, kwargs['variable'])) print(getattr(common, kwargs['variable']))
else: else:

View File

@@ -8,7 +8,7 @@ import common
prompt = b'\n(qemu) ' prompt = b'\n(qemu) '
parser = common.get_argparse({ parser = self.get_argparse({
'description': '''\ 'description': '''\
Run a command on the QEMU monitor of a running QEMU instance Run a command on the QEMU monitor of a running QEMU instance
@@ -21,7 +21,7 @@ parser.add_argument(
help='If given, run this command and quit', help='If given, run this command and quit',
nargs='*', nargs='*',
) )
args = common.setup(parser) args = self.setup(parser)
def write_and_read(tn, cmd, prompt): def write_and_read(tn, cmd, prompt):
tn.write(cmd.encode('utf-8')) tn.write(cmd.encode('utf-8'))

View File

@@ -19,8 +19,8 @@ def main():
) )
if __name__ == '__main__': if __name__ == '__main__':
parser = common.get_argparse(argparse_args={ parser = self.get_argparse(argparse_args={
'description': 'Convert a QEMU `-trace exec_tb` to text form.' 'description': 'Convert a QEMU `-trace exec_tb` to text form.'
}) })
args = common.setup(parser) args = self.setup(parser)
sys.exit(main()) sys.exit(main())

View File

@@ -29,4 +29,4 @@ release_zip.main()
subprocess.check_call(['git', 'push']) subprocess.check_call(['git', 'push'])
release_upload.main() release_upload.main()
end_time = time.time() end_time = time.time()
common.print_time(end_time - start_time) self.print_time(end_time - start_time)

View File

@@ -11,6 +11,6 @@ import urllib.request
import common import common
_json = common.github_make_request(path='/releases') _json = self.github_make_request(path='/releases')
asset = _json[0]['assets'][0] asset = _json[0]['assets'][0]
urllib.request.urlretrieve(asset['browser_download_url'], asset['name']) urllib.request.urlretrieve(asset['browser_download_url'], asset['name'])

View File

@@ -24,7 +24,7 @@ def main():
# Check the release already exists. # Check the release already exists.
try: try:
_json = common.github_make_request(path='/releases/tags/' + tag) _json = self.github_make_request(path='/releases/tags/' + tag)
except urllib.error.HTTPError as e: except urllib.error.HTTPError as e:
if e.code == 404: if e.code == 404:
release_exists = False release_exists = False
@@ -36,7 +36,7 @@ def main():
# Create release if not yet created. # Create release if not yet created.
if not release_exists: if not release_exists:
_json = common.github_make_request( _json = self.github_make_request(
authenticate=True, authenticate=True,
data=json.dumps({ data=json.dumps({
'tag_name': tag, 'tag_name': tag,
@@ -50,12 +50,12 @@ def main():
asset_name = os.path.split(upload_path)[1] asset_name = os.path.split(upload_path)[1]
# Clear the prebuilts for a upload. # Clear the prebuilts for a upload.
_json = common.github_make_request( _json = self.github_make_request(
path=('/releases/' + str(release_id) + '/assets'), path=('/releases/' + str(release_id) + '/assets'),
) )
for asset in _json: for asset in _json:
if asset['name'] == asset_name: if asset['name'] == asset_name:
_json = common.github_make_request( _json = self.github_make_request(
authenticate=True, authenticate=True,
path=('/releases/assets/' + str(asset['id'])), path=('/releases/assets/' + str(asset['id'])),
method='DELETE', method='DELETE',
@@ -65,7 +65,7 @@ def main():
# Upload the prebuilt. # Upload the prebuilt.
with open(upload_path, 'br') as myfile: with open(upload_path, 'br') as myfile:
content = myfile.read() content = myfile.read()
_json = common.github_make_request( _json = self.github_make_request(
authenticate=True, authenticate=True,
data=content, data=content,
extra_headers={'Content-Type': 'application/zip'}, extra_headers={'Content-Type': 'application/zip'},

View File

@@ -16,7 +16,7 @@ def main():
os.unlink(kwargs['release_zip_file']) os.unlink(kwargs['release_zip_file'])
zipf = zipfile.ZipFile(kwargs['release_zip_file'], 'w', zipfile.ZIP_DEFLATED) zipf = zipfile.ZipFile(kwargs['release_zip_file'], 'w', zipfile.ZIP_DEFLATED)
for arch in kwargs['all_archs']: for arch in kwargs['all_archs']:
common.setup(common.get_argparse(default_args={'arch': arch})) self.setup(common.get_argparse(default_args={'arch': arch}))
zipf.write(kwargs['qcow2_file'], arcname=os.path.relpath(kwargs['qcow2_file'], kwargs['root_dir'])) zipf.write(kwargs['qcow2_file'], arcname=os.path.relpath(kwargs['qcow2_file'], kwargs['root_dir']))
zipf.write(kwargs['linux_image'], arcname=os.path.relpath(kwargs['linux_image'], kwargs['root_dir'])) zipf.write(kwargs['linux_image'], arcname=os.path.relpath(kwargs['linux_image'], kwargs['root_dir']))
zipf.close() zipf.close()

1051
run

File diff suppressed because it is too large Load Diff

View File

@@ -58,7 +58,7 @@ cmd_action_map = {
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('cmd', choices=cmd_action_map) parser.add_argument('cmd', choices=cmd_action_map)
parser.add_argument('args', nargs='*') parser.add_argument('args', nargs='*')
common.add_dry_run_argument(parser) self.add_dry_run_argument(parser)
args = parser.parse_args() args = parser.parse_args()
common.setup_dry_run_arguments(args) self.setup_dry_run_arguments(args)
cmd_action_map[kwargs['cmd']](kwargs['args']) cmd_action_map[kwargs['cmd']](kwargs['args'])

28
run-gdb
View File

@@ -34,8 +34,8 @@ class GdbTestcase:
''' '''
self.prompt = '\(gdb\) ' self.prompt = '\(gdb\) '
self.source_path = source_path self.source_path = source_path
common.print_cmd(cmd) self.print_cmd(cmd)
cmd = common.strip_newlines(cmd) cmd = self.strip_newlines(cmd)
import pexpect import pexpect
self.child = pexpect.spawn( self.child = pexpect.spawn(
cmd[0], cmd[0],
@@ -97,9 +97,9 @@ def main(args, extra_args=None):
:rtype: int :rtype: int
''' '''
global defaults global defaults
args = common.resolve_args(defaults, args, extra_args) args = self.resolve_args(defaults, args, extra_args)
after = common.shlex_split(kwargs['after']) after = self.sh.shlex_split(kwargs['after'])
before = common.shlex_split(kwargs['before']) before = self.sh.shlex_split(kwargs['before'])
no_continue = kwargs['no_continue'] no_continue = kwargs['no_continue']
if kwargs['test']: if kwargs['test']:
no_continue = True no_continue = True
@@ -122,7 +122,7 @@ def main(args, extra_args=None):
break_at = [] break_at = []
linux_full_system = (kwargs['baremetal'] is None and kwargs['userland'] is None) linux_full_system = (kwargs['baremetal'] is None and kwargs['userland'] is None)
if kwargs['userland']: if kwargs['userland']:
image = common.resolve_userland(kwargs['userland']) image = self.resolve_userland(kwargs['userland'])
elif kwargs['baremetal']: elif kwargs['baremetal']:
image = kwargs['image'] image = kwargs['image']
test_script_path = os.path.splitext(kwargs['source_path'])[0] + '.py' test_script_path = os.path.splitext(kwargs['source_path'])[0] + '.py'
@@ -133,7 +133,7 @@ def main(args, extra_args=None):
else: else:
allowed_toolchains = ['buildroot', 'crosstool-ng', 'host'] allowed_toolchains = ['buildroot', 'crosstool-ng', 'host']
cmd = ( cmd = (
[common.get_toolchain_tool('gdb', allowed_toolchains=allowed_toolchains), LF] + [self.get_toolchain_tool('gdb', allowed_toolchains=allowed_toolchains), LF] +
before + before +
['-q', LF] ['-q', LF]
) )
@@ -195,7 +195,7 @@ def main(args, extra_args=None):
) )
if __name__ == '__main__': if __name__ == '__main__':
parser = common.get_argparse(argparse_args={'description': 'Connect with GDB to an emulator to debug Linux itself'}) parser = self.get_argparse(argparse_args={'description': 'Connect with GDB to an emulator to debug Linux itself'})
parser.add_argument( parser.add_argument(
'-A', '--after', default=defaults['after'], '-A', '--after', default=defaults['after'],
help='Pass extra arguments to GDB, to be appended after all other arguments' help='Pass extra arguments to GDB, to be appended after all other arguments'
@@ -205,23 +205,23 @@ if __name__ == '__main__':
help='Pass extra arguments to GDB to be prepended before any of the arguments passed by this script' help='Pass extra arguments to GDB to be prepended before any of the arguments passed by this script'
) )
parser.add_argument( parser.add_argument(
'-C', '--no-continue', default=defaults['no_continue'], action='store_true', '-C', '--no-continue', default=defaults['no_continue'],
help="Don't run continue after connecting" help="Don't run continue after connecting"
) )
parser.add_argument( parser.add_argument(
'-k', '--kgdb', default=defaults['kgdb'], action='store_true' '-k', '--kgdb', default=defaults['kgdb'],
) )
parser.add_argument( parser.add_argument(
'--sim', default=defaults['sim'], action='store_true', '--sim', default=defaults['sim'],
help='''Use the built-in GDB CPU simulator help='''Use the built-in GDB CPU simulator
See: https://github.com/cirosantilli/linux-kernel-module-cheat#gdb-builtin-cpu-simulator See: https://github.com/cirosantilli/linux-kernel-module-cheat#gdb-builtin-cpu-simulator
''' '''
) )
parser.add_argument( parser.add_argument(
'-X', '--no-lxsymbols', default=defaults['no_lxsymbols'], action='store_true' '-X', '--no-lxsymbols', default=defaults['no_lxsymbols'],
) )
parser.add_argument( parser.add_argument(
'--test', default=defaults['test'], action='store_true', '--test', default=defaults['test'],
help='''\ help='''\
Run an expect test case instead of interactive usage. For baremetal and userland, Run an expect test case instead of interactive usage. For baremetal and userland,
the script is a .py file next to the source code. the script is a .py file next to the source code.
@@ -234,5 +234,5 @@ the script is a .py file next to the source code.
'break_at', nargs='?', 'break_at', nargs='?',
help='Extra options to append at the end of the emulator command line' help='Extra options to append at the end of the emulator command line'
) )
args = common.setup(parser) args = self.setup(parser)
sys.exit(main(args)) sys.exit(main(args))

View File

@@ -7,7 +7,7 @@ import sys
import common import common
rungdb = imp.load_source('rungdb', os.path.join(kwargs['root_dir'], 'run-gdb')) rungdb = imp.load_source('rungdb', os.path.join(kwargs['root_dir'], 'run-gdb'))
parser = common.get_argparse(argparse_args={ parser = self.get_argparse(argparse_args={
'description': '''GDB step debug guest userland processes without gdbserver. '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 More information at: https://github.com/cirosantilli/linux-kernel-module-cheat#gdb-step-debug-userland-processes
@@ -23,9 +23,9 @@ parser.add_argument(
help='Break at this point, e.g. main.', help='Break at this point, e.g. main.',
nargs='?' nargs='?'
) )
args = common.setup(parser) args = self.setup(parser)
executable = common.resolve_userland(kwargs['executable']) executable = self.resolve_userland(kwargs['executable'])
addr = common.get_elf_entry(os.path.join(kwargs['buildroot_build_build_dir'], executable)) addr = self.get_elf_entry(os.path.join(kwargs['buildroot_build_build_dir'], executable))
extra_args = {} extra_args = {}
extra_args['before'] = '-ex \"add-symbol-file {} {}\"'.format(executable, hex(addr)) extra_args['before'] = '-ex \"add-symbol-file {} {}\"'.format(executable, hex(addr))
# Or else lx-symbols throws for arm: # Or else lx-symbols throws for arm:

View File

@@ -6,7 +6,7 @@ import sys
import common import common
parser = common.get_argparse(argparse_args={ parser = self.get_argparse(argparse_args={
'description':'Connect to gdbserver running on the guest.' 'description':'Connect to gdbserver running on the guest.'
}) })
parser.add_argument( parser.add_argument(
@@ -16,13 +16,13 @@ parser.add_argument(
parser.add_argument( parser.add_argument(
'break_at', default='main', nargs='?' 'break_at', default='main', nargs='?'
) )
args = common.setup(parser) args = self.setup(parser)
sys.exit(subprocess.Popen([ sys.exit(subprocess.Popen([
common.get_toolchain_tool('gdb'), self.get_toolchain_tool('gdb'),
'-q', '-q',
'-ex', 'set sysroot {}'.format(kwargs['buildroot_staging_dir']), '-ex', 'set sysroot {}'.format(kwargs['buildroot_staging_dir']),
'-ex', 'target remote localhost:{}'.format(kwargs['qemu_hostfwd_generic_port']), '-ex', 'target remote localhost:{}'.format(kwargs['qemu_hostfwd_generic_port']),
'-ex', 'tbreak {}'.format(kwargs['break_at']), '-ex', 'tbreak {}'.format(kwargs['break_at']),
'-ex', 'continue', '-ex', 'continue',
os.path.join(kwargs['buildroot_build_build_dir'], common.resolve_userland(kwargs['executable'])), os.path.join(kwargs['buildroot_build_build_dir'], self.resolve_userland(kwargs['executable'])),
]).wait()) ]).wait())

View File

@@ -5,7 +5,7 @@ import sys
import common import common
parser = common.get_argparse(argparse_args={ parser = self.get_argparse(argparse_args={
'description': '''Run a Buildroot ToolChain tool like readelf or objdump. 'description': '''Run a Buildroot ToolChain tool like readelf or objdump.
For example, to get some information about the arm vmlinux: For example, to get some information about the arm vmlinux:
@@ -24,7 +24,6 @@ ls "$(./getvar -a arm host_bin_dir)"
parser.add_argument( parser.add_argument(
'--dry', '--dry',
help='Just output the tool path to stdout but actually run it', help='Just output the tool path to stdout but actually run it',
action='store_true',
) )
parser.add_argument('tool', help='Which tool to run.') parser.add_argument('tool', help='Which tool to run.')
parser.add_argument( parser.add_argument(
@@ -34,12 +33,12 @@ parser.add_argument(
metavar='extra-args', metavar='extra-args',
nargs='*' nargs='*'
) )
args = common.setup(parser) args = self.setup(parser)
if kwargs['baremetal'] is None: if kwargs['baremetal'] is None:
image = kwargs['vmlinux'] image = kwargs['vmlinux']
else: else:
image = kwargs['image'] image = kwargs['image']
tool= common.get_toolchain_tool(kwargs['tool']) tool= self.get_toolchain_tool(kwargs['tool'])
if kwargs['dry']: if kwargs['dry']:
print(tool) print(tool)
else: else:

View File

@@ -6,7 +6,9 @@ import os
import shlex import shlex
import shutil import shutil
import signal import signal
import stat
import subprocess import subprocess
import sys
class LF: class LF:
''' '''

View File

@@ -9,7 +9,7 @@ import common
run = imp.load_source('run', os.path.join(kwargs['root_dir'], 'run')) run = imp.load_source('run', os.path.join(kwargs['root_dir'], 'run'))
qemu_trace2txt = imp.load_source('qemu_trace2txt', os.path.join(kwargs['root_dir'], 'qemu-trace2txt')) qemu_trace2txt = imp.load_source('qemu_trace2txt', os.path.join(kwargs['root_dir'], 'qemu-trace2txt'))
parser = common.get_argparse(argparse_args={ parser = self.get_argparse(argparse_args={
'description': '''Trace the PIC addresses executed on a Linux kernel boot. 'description': '''Trace the PIC addresses executed on a Linux kernel boot.
More information at: https://github.com/cirosantilli/linux-kernel-module-cheat#tracing More information at: https://github.com/cirosantilli/linux-kernel-module-cheat#tracing
@@ -19,7 +19,7 @@ parser.add_argument(
'extra_emulator_args', nargs='*', 'extra_emulator_args', nargs='*',
help='Extra options to append at the end of the emulator command line' help='Extra options to append at the end of the emulator command line'
) )
args = common.setup(parser) args = self.setup(parser)
extra_args = { extra_args = {
'extra_emulator_args': kwargs['extra_emulator_args'], 'extra_emulator_args': kwargs['extra_emulator_args'],
} }
@@ -39,7 +39,7 @@ else:
# Instruction count. # Instruction count.
# We could put this on a separate script, but it just adds more arch boilerplate to a new script. # 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. # 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(kwargs['vmlinux'])) kernel_entry_addr = hex(self.get_elf_entry(kwargs['vmlinux']))
nlines = 0 nlines = 0
nlines_firmware = 0 nlines_firmware = 0
with open(kwargs['qemu_trace_txt_file'], 'r') as trace_file: with open(kwargs['qemu_trace_txt_file'], 'r') as trace_file:

View File

@@ -14,15 +14,15 @@ import sys
import common import common
parser = common.get_argparse(argparse_args={ parser = self.get_argparse(argparse_args={
'description': 'Convert an execution trace containing PC values into the Linux kernel linex executed' 'description': 'Convert an execution trace containing PC values into the Linux kernel linex executed'
}) })
args = common.setup(parser) args = self.setup(parser)
sys.exit(subprocess.Popen([ sys.exit(subprocess.Popen([
os.path.join(kwargs['root_dir'], 'trace2line.sh'), os.path.join(kwargs['root_dir'], 'trace2line.sh'),
'true' if kwargs['emulator'] == 'gem5' else 'false', 'true' if kwargs['emulator'] == 'gem5' else 'false',
kwargs['trace_txt_file'], kwargs['trace_txt_file'],
common.get_toolchain_tool('addr2line'), self.get_toolchain_tool('addr2line'),
kwargs['vmlinux'], kwargs['vmlinux'],
kwargs['run_dir'], kwargs['run_dir'],
]).wait()) ]).wait())
@@ -40,7 +40,7 @@ sys.exit(subprocess.Popen([
# with \ # with \
# subprocess.Popen( # subprocess.Popen(
# [ # [
# common.get_toolchain_tool('addr2line'), # self.get_toolchain_tool('addr2line'),
# '-e', # '-e',
# kwargs['vmlinux'], # kwargs['vmlinux'],
# '-f', # '-f',