mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-25 19:21:35 +01:00
add a --quiet flag
test-gdb and test-userland produce beautiful output by default create def get_common_args to help forward common args to child calls... it is ugly, but I'm lazy for a perfect solution now
This commit is contained in:
@@ -2914,7 +2914,7 @@ The target Linux kernel of the executable is a GCC toolchain build-time configur
|
||||
First let's run a dynamically linked executable built with the Buildroot toolchain:
|
||||
|
||||
....
|
||||
./build-qemu --arch aarch64 --userland
|
||||
./build-qemu --arch aarch64 --user-mode
|
||||
./build-userland --arch aarch64
|
||||
./build-buildroot --arch aarch64
|
||||
./run \
|
||||
@@ -2931,7 +2931,7 @@ asdf
|
||||
qw er
|
||||
....
|
||||
|
||||
This runs link:userland/print_argv.c[]. `--userland` path resolution is analogous to <<baremetal-setup-getting-started,that of `./run --baremetal`>>.
|
||||
This runs link:userland/print_argv.c[]. `--user-mode` path resolution is analogous to <<baremetal-setup-getting-started,that of `./run --baremetal`>>.
|
||||
|
||||
`./build-userland` is further documented at: <<userland-directory>>.
|
||||
|
||||
|
||||
41
build
41
build
@@ -48,12 +48,11 @@ class _Component:
|
||||
(self.build_callback is not None) and
|
||||
(self.supported_archs is None or arch in self.supported_archs)
|
||||
):
|
||||
self.build_callback(arch)
|
||||
self.build_callback()
|
||||
|
||||
class Main(cli_function.CliFunction):
|
||||
class Main(common.LkmcCliFunction):
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
config_file=common.consts['config_file'],
|
||||
description='''\
|
||||
Build a component and all its dependencies.
|
||||
|
||||
@@ -110,24 +109,24 @@ This is equivalent to:
|
||||
self.name_to_component_map = {
|
||||
# Leaves without dependencies.
|
||||
'baremetal-qemu': _Component(
|
||||
lambda arch: self._run_cmd(['build-baremetal', '--emulator', 'qemu'], arch),
|
||||
lambda: self.import_path_main('build-baremetal')(archs=self.env['archs'], emulators=['qemu']),
|
||||
supported_archs=common.consts['crosstool_ng_supported_archs'],
|
||||
),
|
||||
'baremetal-gem5': _Component(
|
||||
lambda arch: self._run_cmd(['build-baremetal', '--gem5'], arch),
|
||||
lambda: self.import_path_main('build-baremetal')(archs=self.env['archs'], emulators=['gem5']),
|
||||
supported_archs=common.consts['crosstool_ng_supported_archs'],
|
||||
),
|
||||
'baremetal-gem5-pbx': _Component(
|
||||
lambda arch: self._run_cmd(['build-baremetal', '--gem5', '--machine', 'RealViewPBX'], arch),
|
||||
lambda: self.import_path_main('build-baremetal')(archs=self.env['archs'], emulators=['gem5'], machine='RealViewPBX'),
|
||||
supported_archs=common.consts['crosstool_ng_supported_archs'],
|
||||
),
|
||||
'buildroot': buildroot_component,
|
||||
'buildroot-gcc': buildroot_component,
|
||||
'copy-overlay': _Component(
|
||||
lambda arch: self._run_cmd(['copy-overlay'], arch),
|
||||
lambda: self.import_path_main('copy-overlay')(archs=self.env['archs']),
|
||||
),
|
||||
'crosstool-ng': _Component(
|
||||
lambda arch: self._run_cmd(['build-crosstool-ng'], arch),
|
||||
lambda: self.import_path_main('build-crosstool-ng')(archs=self.env['archs']),
|
||||
supported_archs=common.consts['crosstool_ng_supported_archs'],
|
||||
# http://crosstool-ng.github.io/docs/os-setup/
|
||||
apt_get_pkgs={
|
||||
@@ -147,7 +146,7 @@ This is equivalent to:
|
||||
submodules={'crosstool-ng'},
|
||||
),
|
||||
'gem5': _Component(
|
||||
lambda arch: self._run_cmd(['build-gem5'], arch),
|
||||
lambda: self.import_path_main('build-gem5')(archs=self.env['archs']),
|
||||
# TODO test it out on Docker and answer that question properly:
|
||||
# https://askubuntu.com/questions/350475/how-can-i-install-gem5
|
||||
apt_get_pkgs={
|
||||
@@ -170,7 +169,7 @@ This is equivalent to:
|
||||
submodules={'gem5'},
|
||||
),
|
||||
'gem5-debug': _Component(
|
||||
lambda arch: self._run_cmd(['build-gem5', '--gem5-build-type', 'debug'], arch),
|
||||
lambda: self.import_path_main('build-gem5')(archs=self.env['archs'], gem5_build_type='debug'),
|
||||
),
|
||||
'gem5-fast': _Component(
|
||||
lambda arch: self._run_cmd(['build-gem5', '--gem5-build-type', 'fast'], arch),
|
||||
@@ -309,18 +308,12 @@ Which components to build. Default: qemu-buildroot
|
||||
'''
|
||||
)
|
||||
|
||||
def _run_cmd(self, python_file, **kwargs):
|
||||
python_file = os.path.join(common.consts['root_dir'], python_file)
|
||||
run = common.import_path(python_file).Main()
|
||||
run(**kwargs)
|
||||
self.sh.run_cmd(cmd_abs)
|
||||
|
||||
def main(self, **kwargs):
|
||||
self.sh = shell_helpers.ShellHelpers(dry_run=kwargs['dry_run'])
|
||||
def timed_main(self):
|
||||
self.sh = shell_helpers.ShellHelpers(dry_run=self.env['dry_run'])
|
||||
|
||||
# Decide components.
|
||||
components = kwargs['components']
|
||||
if kwargs['all']:
|
||||
components = self.env['components']
|
||||
if self.env['all']:
|
||||
components = ['all']
|
||||
elif components == []:
|
||||
components = ['qemu-buildroot']
|
||||
@@ -336,7 +329,7 @@ Which components to build. Default: qemu-buildroot
|
||||
selected_components.append(component)
|
||||
todo.extend(component.dependencies)
|
||||
|
||||
if kwargs['download_dependencies']:
|
||||
if self.env['download_dependencies']:
|
||||
apt_get_pkgs = {
|
||||
# Core requirements for this repo.
|
||||
'git',
|
||||
@@ -374,7 +367,7 @@ Which components to build. Default: qemu-buildroot
|
||||
python2_pkgs.update(component.python2_pkgs)
|
||||
python3_pkgs.update(component.python3_pkgs)
|
||||
if apt_get_pkgs or apt_build_deps:
|
||||
if kwargs['travis']:
|
||||
if self.env['travis']:
|
||||
interacive_pkgs = {
|
||||
'libsdl2-dev',
|
||||
}
|
||||
@@ -392,7 +385,7 @@ Which components to build. Default: qemu-buildroot
|
||||
f.write(sources_txt)
|
||||
else:
|
||||
sudo = ['sudo']
|
||||
if common.consts['in_docker'] or kwargs['travis']:
|
||||
if common.consts['in_docker'] or self.env['travis']:
|
||||
y = ['-y']
|
||||
else:
|
||||
y = []
|
||||
@@ -465,7 +458,7 @@ Which components to build. Default: qemu-buildroot
|
||||
|
||||
# Do the build.
|
||||
for component in selected_components:
|
||||
component.build()
|
||||
component.build(self.env['arch'])
|
||||
|
||||
if __name__ == '__main__':
|
||||
Main().cli()
|
||||
|
||||
@@ -9,7 +9,7 @@ class Main(common.BuildCliFunction):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.add_argument(
|
||||
'--userland',
|
||||
'--user-mode',
|
||||
default=False,
|
||||
help='Build QEMU user mode instead of system.',
|
||||
)
|
||||
@@ -27,7 +27,7 @@ class Main(common.BuildCliFunction):
|
||||
verbose = ['V=1']
|
||||
else:
|
||||
verbose = []
|
||||
if self.env['userland']:
|
||||
if self.env['user_mode']:
|
||||
target_list = '{}-linux-user'.format(self.env['arch'])
|
||||
else:
|
||||
target_list = '{}-softmmu'.format(self.env['arch'])
|
||||
|
||||
107
common.py
107
common.py
@@ -110,7 +110,7 @@ class LkmcCliFunction(cli_function.CliFunction):
|
||||
Common functionality shared across our CLI functions:
|
||||
|
||||
* command timing
|
||||
* some common flags, e.g.: --arch, --dry-run, --verbose
|
||||
* some common flags, e.g.: --arch, --dry-run, --quiet, --verbose
|
||||
'''
|
||||
def __init__(self, *args, defaults=None, supported_archs=None, **kwargs):
|
||||
'''
|
||||
@@ -122,6 +122,8 @@ class LkmcCliFunction(cli_function.CliFunction):
|
||||
if defaults is None:
|
||||
defaults = {}
|
||||
self._defaults = defaults
|
||||
self._is_common = True
|
||||
self._common_args = set()
|
||||
super().__init__(*args, **kwargs)
|
||||
self.supported_archs = supported_archs
|
||||
|
||||
@@ -165,7 +167,17 @@ mkdir are generally omitted since those are obvious
|
||||
)
|
||||
self.add_argument(
|
||||
'--print-time', default=True,
|
||||
help='Print how long it took to run the command at the end.'
|
||||
help='''\
|
||||
Print how long it took to run the command at the end.
|
||||
Implied by --quiet.
|
||||
'''
|
||||
)
|
||||
self.add_argument(
|
||||
'-q', '--quiet', default=False,
|
||||
help='''\
|
||||
Don't print anything to stdout, except if it is part of an interactive terminal.
|
||||
TODO: implement fully, some stuff is escaping currently.
|
||||
'''
|
||||
)
|
||||
self.add_argument(
|
||||
'-v', '--verbose', default=False,
|
||||
@@ -284,7 +296,22 @@ See the documentation for other values known to work.
|
||||
|
||||
# Userland.
|
||||
self.add_argument(
|
||||
'--userland-build-id', default=None
|
||||
'-u', '--userland',
|
||||
help='''\
|
||||
Run the given userland executable in user mode instead of booting the Linux kernel
|
||||
in full system mode. In gem5, user mode is called Syscall Emulation (SE) mode and
|
||||
uses se.py.
|
||||
Path resolution is similar to --baremetal.
|
||||
'''
|
||||
)
|
||||
self.add_argument(
|
||||
'--userland-args',
|
||||
help='''\
|
||||
CLI arguments to pass to the userland executable.
|
||||
'''
|
||||
)
|
||||
self.add_argument(
|
||||
'--userland-build-id'
|
||||
)
|
||||
|
||||
# Run.
|
||||
@@ -336,16 +363,21 @@ Emulator to use. If given multiple times, semantics are similar to --arch.
|
||||
Valid emulators: {}
|
||||
'''.format(emulators_string)
|
||||
)
|
||||
self._is_common = False
|
||||
|
||||
def __call__(self, **kwargs):
|
||||
'''
|
||||
For Python code calls, print the CLI equivalent of the call.
|
||||
For Python code calls, in addition to base:
|
||||
|
||||
- print the CLI equivalent of the call
|
||||
- automatically forward common arguments
|
||||
'''
|
||||
print_cmd = ['./' + self.extra_config_params, LF]
|
||||
for line in self.get_cli(**kwargs):
|
||||
print_cmd.extend(line)
|
||||
print_cmd.append(LF)
|
||||
shell_helpers.ShellHelpers.print_cmd(print_cmd)
|
||||
if not ('quiet' in kwargs and kwargs['quiet']):
|
||||
shell_helpers.ShellHelpers().print_cmd(print_cmd)
|
||||
return super().__call__(**kwargs)
|
||||
|
||||
def _init_env(self, env):
|
||||
@@ -606,24 +638,23 @@ Valid emulators: {}
|
||||
env['image'] = path
|
||||
|
||||
def add_argument(self, *args, **kwargs):
|
||||
'''
|
||||
Also handle:
|
||||
|
||||
- modified defaults from child classes.
|
||||
- common arguments to forward on Python calls
|
||||
'''
|
||||
shortname, longname, key, is_option = self.get_key(*args, **kwargs)
|
||||
if key in self._defaults:
|
||||
kwargs['default'] = self._defaults[key]
|
||||
if self._is_common:
|
||||
self._common_args.add(key)
|
||||
super().add_argument(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def base64_encode(string):
|
||||
return base64.b64encode(string.encode()).decode()
|
||||
|
||||
def gem5_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):
|
||||
readelf_header = subprocess.check_output([
|
||||
self.get_toolchain_tool('readelf'),
|
||||
@@ -637,6 +668,18 @@ Valid emulators: {}
|
||||
break
|
||||
return int(addr, 0)
|
||||
|
||||
def gem5_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_common_args(self):
|
||||
return {key:self.env[key] for key in self._common_args}
|
||||
|
||||
def get_stats(self, stat_re=None, stats_file=None):
|
||||
if stat_re is None:
|
||||
stat_re = '^system.cpu[0-9]*.numCycles$'
|
||||
@@ -737,29 +780,41 @@ Valid emulators: {}
|
||||
'''
|
||||
env = kwargs.copy()
|
||||
env.update(consts)
|
||||
if env['all_archs']:
|
||||
env['archs'] = consts['all_long_archs']
|
||||
real_all_archs= env['all_archs']
|
||||
if real_all_archs:
|
||||
real_archs = consts['all_long_archs']
|
||||
else:
|
||||
real_archs = env['archs']
|
||||
if env['all_emulators']:
|
||||
env['emulators'] = consts['all_long_emulators']
|
||||
for emulator in env['emulators']:
|
||||
for arch in env['archs']:
|
||||
real_emulators = consts['all_long_emulators']
|
||||
else:
|
||||
real_emulators = env['emulators']
|
||||
for emulator in real_emulators:
|
||||
for arch in real_archs:
|
||||
if arch in env['arch_short_to_long_dict']:
|
||||
arch = env['arch_short_to_long_dict'][arch]
|
||||
if self.supported_archs is None or arch in self.supported_archs:
|
||||
if not env['dry_run']:
|
||||
start_time = time.time()
|
||||
env['arch'] = arch
|
||||
env['archs'] = [arch]
|
||||
env['all_archs'] = False
|
||||
env['emulator'] = emulator
|
||||
env['emulators'] = [emulator]
|
||||
env['all_emulators'] = False
|
||||
self.env = env.copy()
|
||||
self._init_env(self.env)
|
||||
self.sh = shell_helpers.ShellHelpers(dry_run=self.env['dry_run'])
|
||||
self.sh = shell_helpers.ShellHelpers(
|
||||
dry_run=self.env['dry_run'],
|
||||
quiet=self.env['quiet'],
|
||||
)
|
||||
ret = self.timed_main()
|
||||
if not env['dry_run']:
|
||||
end_time = time.time()
|
||||
self._print_time(end_time - start_time)
|
||||
if ret is not None and ret != 0:
|
||||
return ret
|
||||
elif not env['all_archs']:
|
||||
elif not real_all_archs:
|
||||
raise Exception('Unsupported arch for this action: ' + arch)
|
||||
return 0
|
||||
|
||||
@@ -787,7 +842,7 @@ Valid emulators: {}
|
||||
return False
|
||||
|
||||
def _print_time(self, ellapsed_seconds):
|
||||
if self.env['print_time']:
|
||||
if self.env['print_time'] and not self.env['quiet']:
|
||||
hours, rem = divmod(ellapsed_seconds, 3600)
|
||||
minutes, seconds = divmod(rem, 60)
|
||||
print('time {:02}:{:02}:{:02}'.format(int(hours), int(minutes), int(seconds)))
|
||||
@@ -859,6 +914,14 @@ Valid emulators: {}
|
||||
self.env['userland_build_ext'],
|
||||
)
|
||||
|
||||
def test_setup(self, test_env, source):
|
||||
if not self.env['verbose']:
|
||||
test_env['quiet'] = True
|
||||
test_id_string = '{} {} {}'.format(self.env['emulator'], self.env['arch'], source)
|
||||
if not self.env['quiet']:
|
||||
print(test_id_string)
|
||||
return test_id_string
|
||||
|
||||
def timed_main(self):
|
||||
'''
|
||||
Main action of the derived class.
|
||||
|
||||
91
run
91
run
@@ -178,21 +178,6 @@ to use this option:
|
||||
'--tmux-args',
|
||||
help='''\
|
||||
Parameters to pass to the program running on the tmux split. Implies --tmux.
|
||||
'''
|
||||
)
|
||||
self.add_argument(
|
||||
'-u', '--userland',
|
||||
help='''\
|
||||
Run the given userland executable in user mode instead of booting the Linux kernel
|
||||
in full system mode. In gem5, user mode is called Syscall Emulation (SE) mode and
|
||||
uses se.py.
|
||||
Path resolution is similar to --baremetal.
|
||||
'''
|
||||
)
|
||||
self.add_argument(
|
||||
'--userland-args',
|
||||
help='''\
|
||||
CLI arguments to pass to the userland executable.
|
||||
'''
|
||||
)
|
||||
self.add_argument(
|
||||
@@ -221,6 +206,8 @@ Run QEMU with VNC instead of the default SDL. Connect to it with:
|
||||
# * https://unix.stackexchange.com/questions/397939/turning-off-kaslr-to-debug-linux-kernel-using-qemu-and-gdb
|
||||
# * https://stackoverflow.com/questions/44612822/unable-to-debug-kernel-with-qemu-gdb/49840927#49840927
|
||||
# Turned on by default since v4.12
|
||||
raise_on_failure = True
|
||||
show_stdout = True
|
||||
kernel_cli = 'console_msg_format=syslog nokaslr norandmaps panic=-1 printk.devkmsg=on printk.time=y rw'
|
||||
if self.env['kernel_cli'] is not None:
|
||||
kernel_cli += ' {}'.format(self.env['kernel_cli'])
|
||||
@@ -303,6 +290,8 @@ Run QEMU with VNC instead of the default SDL. Connect to it with:
|
||||
raise Exception('Baremetal ELF file not found. Tried:\n' + '\n'.join(paths))
|
||||
cmd = debug_vm.copy()
|
||||
if self.env['emulator'] == 'gem5':
|
||||
if self.env['quiet']:
|
||||
show_stdout = False
|
||||
if self.env['baremetal'] is None:
|
||||
if not os.path.exists(self.env['rootfs_raw_file']):
|
||||
if not os.path.exists(self.env['qcow2_file']):
|
||||
@@ -415,7 +404,7 @@ Run QEMU with VNC instead of the default SDL. Connect to it with:
|
||||
if self.env['wait_gdb']:
|
||||
# https://stackoverflow.com/questions/49296092/how-to-make-gem5-wait-for-gdb-to-connect-to-reliably-break-at-start-kernel-of-th
|
||||
cmd.extend(['--param', 'system.cpu[0].wait_for_remote_gdb = True', LF])
|
||||
else:
|
||||
elif self.env['emulator'] == 'qemu':
|
||||
qemu_user_and_system_options = [
|
||||
'-trace', 'enable={},file={}'.format(trace_type, self.env['qemu_trace_file']), LF,
|
||||
]
|
||||
@@ -432,6 +421,8 @@ Run QEMU with VNC instead of the default SDL. Connect to it with:
|
||||
qemu_user_and_system_options +
|
||||
debug_args
|
||||
)
|
||||
show_stdout = False
|
||||
raise_on_failure = False
|
||||
else:
|
||||
if not os.path.exists(self.env['image']):
|
||||
raise_image_not_found()
|
||||
@@ -452,6 +443,8 @@ Run QEMU with VNC instead of the default SDL. Connect to it with:
|
||||
else:
|
||||
if self.env['background']:
|
||||
serial_monitor = ['-serial', 'file:{}'.format(self.env['qemu_background_serial_file']), LF]
|
||||
if self.env['quiet']:
|
||||
show_stdout = False
|
||||
else:
|
||||
serial_monitor = ['-serial', 'mon:stdio', LF]
|
||||
if self.env['kvm']:
|
||||
@@ -592,36 +585,44 @@ Run QEMU with VNC instead of the default SDL. Connect to it with:
|
||||
out_file = None
|
||||
else:
|
||||
out_file = self.env['termout_file']
|
||||
self.sh.run_cmd(cmd, cmd_file=self.env['run_cmd_file'], out_file=out_file, extra_env=extra_env)
|
||||
# Check if guest panicked.
|
||||
if self.env['emulator'] == 'gem5':
|
||||
# We have to do some parsing here because gem5 exits with status 0 even when panic happens.
|
||||
# Grepping for '^panic: ' does not work because some errors don't show that message.
|
||||
panic_msg = b'--- BEGIN LIBC BACKTRACE ---$'
|
||||
else:
|
||||
panic_msg = b'Kernel panic - not syncing'
|
||||
panic_re = re.compile(panic_msg)
|
||||
error_string_found = False
|
||||
exit_status = 0
|
||||
if out_file is not None and not self.env['dry_run']:
|
||||
with open(self.env['termout_file'], 'br') as logfile:
|
||||
line = None
|
||||
for line in logfile:
|
||||
if panic_re.search(line):
|
||||
exit_status = 1
|
||||
if line is not None:
|
||||
last_line = line.rstrip()
|
||||
match = re.search(b'Simulated exit code not 0! Exit code is (\d+)', last_line)
|
||||
if match:
|
||||
exit_status = int(match.group(1))
|
||||
if not self.env['userland']:
|
||||
if os.path.exists(self.env['guest_terminal_file']):
|
||||
with open(self.env['guest_terminal_file'], 'br') as logfile:
|
||||
lines = logfile.readlines()
|
||||
if lines and lines[-1].rstrip() == self.env['magic_fail_string']:
|
||||
exit_status = self.sh.run_cmd(
|
||||
cmd,
|
||||
cmd_file=self.env['run_cmd_file'],
|
||||
extra_env=extra_env,
|
||||
out_file=out_file,
|
||||
raise_on_failure=raise_on_failure,
|
||||
show_stdout=show_stdout,
|
||||
)
|
||||
if exit_status == 0:
|
||||
# Check if guest panicked.
|
||||
if self.env['emulator'] == 'gem5':
|
||||
# We have to do some parsing here because gem5 exits with status 0 even when panic happens.
|
||||
# Grepping for '^panic: ' does not work because some errors don't show that message.
|
||||
panic_msg = b'--- BEGIN LIBC BACKTRACE ---$'
|
||||
else:
|
||||
panic_msg = b'Kernel panic - not syncing'
|
||||
panic_re = re.compile(panic_msg)
|
||||
error_string_found = False
|
||||
exit_status = 0
|
||||
if out_file is not None and not self.env['dry_run']:
|
||||
with open(self.env['termout_file'], 'br') as logfile:
|
||||
line = None
|
||||
for line in logfile:
|
||||
if panic_re.search(line):
|
||||
exit_status = 1
|
||||
if exit_status != 0:
|
||||
self.log_error('simulation error detected by parsing logs')
|
||||
if line is not None:
|
||||
last_line = line.rstrip()
|
||||
match = re.search(b'Simulated exit code not 0! Exit code is (\d+)', last_line)
|
||||
if match:
|
||||
exit_status = int(match.group(1))
|
||||
if not self.env['userland']:
|
||||
if os.path.exists(self.env['guest_terminal_file']):
|
||||
with open(self.env['guest_terminal_file'], 'br') as logfile:
|
||||
lines = logfile.readlines()
|
||||
if lines and lines[-1].rstrip() == self.env['magic_fail_string']:
|
||||
exit_status = 1
|
||||
if exit_status != 0:
|
||||
self.log_error('simulation error detected by parsing logs')
|
||||
return exit_status
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -31,18 +31,25 @@ class ShellHelpers:
|
||||
|
||||
_print_lock = threading.Lock()
|
||||
|
||||
def __init__(self, dry_run=False):
|
||||
def __init__(self, dry_run=False, quiet=False):
|
||||
'''
|
||||
:param dry_run: don't run the commands, just potentially print them. Debug aid.
|
||||
:type dry_run: Bool
|
||||
|
||||
:param quiet: don't print the commands.
|
||||
:type dry_run: Bool
|
||||
'''
|
||||
self.dry_run = dry_run
|
||||
self.quiet = quiet
|
||||
|
||||
@classmethod
|
||||
def _print_thread_safe(cls, string):
|
||||
# Python sucks: a naive print adds a bunch of random spaces to stdout,
|
||||
# and then copy pasting the command fails.
|
||||
# https://stackoverflow.com/questions/3029816/how-do-i-get-a-thread-safe-print-in-python-2-6
|
||||
'''
|
||||
Python sucks: a naive print adds a bunch of random spaces to stdout,
|
||||
and then copy pasting the command fails.
|
||||
https://stackoverflow.com/questions/3029816/how-do-i-get-a-thread-safe-print-in-python-2-6
|
||||
The initial use case was test-gdb which must create a thread for GDB to run the program in parallel.
|
||||
'''
|
||||
cls._print_lock.acquire()
|
||||
sys.stdout.write(string + '\n')
|
||||
sys.stdout.flush()
|
||||
@@ -107,8 +114,7 @@ class ShellHelpers:
|
||||
update=1,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def print_cmd(cls, cmd, cwd=None, cmd_file=None, extra_env=None, extra_paths=None):
|
||||
def print_cmd(self, cmd, cwd=None, cmd_file=None, extra_env=None, extra_paths=None):
|
||||
'''
|
||||
Print cmd_to_string to stdout.
|
||||
|
||||
@@ -121,8 +127,9 @@ class ShellHelpers:
|
||||
if type(cmd) is str:
|
||||
cmd_string = cmd
|
||||
else:
|
||||
cmd_string = cls.cmd_to_string(cmd, cwd=cwd, extra_env=extra_env, extra_paths=extra_paths)
|
||||
cls._print_thread_safe('+ ' + cmd_string)
|
||||
cmd_string = self.cmd_to_string(cmd, cwd=cwd, extra_env=extra_env, extra_paths=extra_paths)
|
||||
if not self.quiet:
|
||||
self._print_thread_safe('+ ' + cmd_string)
|
||||
if cmd_file is not None:
|
||||
with open(cmd_file, 'w') as f:
|
||||
f.write('#!/usr/bin/env bash\n')
|
||||
|
||||
35
test-gdb
35
test-gdb
@@ -7,7 +7,11 @@ import common
|
||||
|
||||
class Main(common.LkmcCliFunction):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
super().__init__(
|
||||
defaults={
|
||||
'print_time': False,
|
||||
},
|
||||
)
|
||||
self.add_argument(
|
||||
'tests',
|
||||
metavar='tests',
|
||||
@@ -19,8 +23,8 @@ found by searching for the Python test files.
|
||||
)
|
||||
|
||||
def timed_main(self):
|
||||
run = self.import_path('run').Main()
|
||||
run_gdb = self.import_path('run-gdb').Main()
|
||||
run = self.import_path_main('run')
|
||||
run_gdb = self.import_path_main('run-gdb')
|
||||
if self.env['arch'] in self.env['crosstool_ng_supported_archs']:
|
||||
if self.env['tests'] == []:
|
||||
test_scripts_noext = []
|
||||
@@ -38,22 +42,17 @@ found by searching for the Python test files.
|
||||
else:
|
||||
test_scripts_noext = self.env['tests']
|
||||
for test_script_noext in test_scripts_noext:
|
||||
run_thread = threading.Thread(target=lambda: run(
|
||||
archs=[self.env['arch']],
|
||||
background=True,
|
||||
baremetal=test_script_noext,
|
||||
dry_run=self.env['dry_run'],
|
||||
emulators=self.env['emulator'],
|
||||
wait_gdb=True
|
||||
))
|
||||
common_args = self.get_common_args()
|
||||
common_args['baremetal'] = test_script_noext
|
||||
test_id_string = self.test_setup(common_args, test_script_noext)
|
||||
run_args = common_args.copy()
|
||||
run_args['wait_gdb'] = True
|
||||
run_args['background'] = True
|
||||
run_thread = threading.Thread(target=lambda: run(**run_args))
|
||||
run_thread.start()
|
||||
run_gdb(
|
||||
archs=[self.env['arch']],
|
||||
baremetal=test_script_noext,
|
||||
dry_run=self.env['dry_run'],
|
||||
emulators=self.env['emulator'],
|
||||
test=True,
|
||||
)
|
||||
gdb_args = common_args.copy()
|
||||
gdb_args['test'] = True
|
||||
run_gdb(**gdb_args)
|
||||
run_thread.join()
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import common
|
||||
|
||||
class Main(common.LkmcCliFunction):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
super().__init__(
|
||||
defaults={
|
||||
'print_time': False,
|
||||
},
|
||||
)
|
||||
self.add_argument(
|
||||
'tests',
|
||||
metavar='tests',
|
||||
@@ -17,13 +22,10 @@ If given, run only the given tests. Otherwise, run all tests.
|
||||
)
|
||||
|
||||
def timed_main(self):
|
||||
run = self.import_path('run').Main()
|
||||
run = self.import_path_main('run')
|
||||
run_args = self.get_common_args()
|
||||
if self.env['emulator'] == 'gem5':
|
||||
extra_args = {
|
||||
'userland_build_id': 'static',
|
||||
}
|
||||
else:
|
||||
extra_args = {}
|
||||
run_args['userland_build_id'] = 'static'
|
||||
if self.env['tests'] == []:
|
||||
sources = [
|
||||
'add.c',
|
||||
@@ -46,21 +48,19 @@ If given, run only the given tests. Otherwise, run all tests.
|
||||
else:
|
||||
sources = self.env['tests']
|
||||
for source in sources:
|
||||
exit_status = run(
|
||||
archs=[self.env['arch']],
|
||||
dry_run=self.env['dry_run'],
|
||||
userland=source,
|
||||
emulators=[self.env['emulator']],
|
||||
**extra_args,
|
||||
)
|
||||
run_args['userland'] = source
|
||||
test_id_string = self.test_setup(run_args, source)
|
||||
run_args['background'] = True
|
||||
exit_status = run(**run_args)
|
||||
# TODO forward all args attempt. In particular, --dry-run.
|
||||
#new_env = self.env.copy()
|
||||
#new_env['userland'] = source
|
||||
#new_env['emulator'] = emulator
|
||||
#new_env.update(extra_args)
|
||||
#new_env.update(run_args)
|
||||
#exit_status = run(**new_env)
|
||||
if exit_status != 0:
|
||||
raise Exception('Test failed: {} {} {} {}'.format(emulator, arch, source, exit_status))
|
||||
self.log_error('test failed, program exit status: {} test id: {}'.format(exit_status, test_id_string))
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
Main().cli()
|
||||
|
||||
Reference in New Issue
Block a user