mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-28 12:34:26 +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:
|
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-userland --arch aarch64
|
||||||
./build-buildroot --arch aarch64
|
./build-buildroot --arch aarch64
|
||||||
./run \
|
./run \
|
||||||
@@ -2931,7 +2931,7 @@ asdf
|
|||||||
qw er
|
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>>.
|
`./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.build_callback is not None) and
|
||||||
(self.supported_archs is None or arch in self.supported_archs)
|
(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):
|
def __init__(self):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
config_file=common.consts['config_file'],
|
|
||||||
description='''\
|
description='''\
|
||||||
Build a component and all its dependencies.
|
Build a component and all its dependencies.
|
||||||
|
|
||||||
@@ -110,24 +109,24 @@ This is equivalent to:
|
|||||||
self.name_to_component_map = {
|
self.name_to_component_map = {
|
||||||
# Leaves without dependencies.
|
# Leaves without dependencies.
|
||||||
'baremetal-qemu': _Component(
|
'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'],
|
supported_archs=common.consts['crosstool_ng_supported_archs'],
|
||||||
),
|
),
|
||||||
'baremetal-gem5': _Component(
|
'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'],
|
supported_archs=common.consts['crosstool_ng_supported_archs'],
|
||||||
),
|
),
|
||||||
'baremetal-gem5-pbx': _Component(
|
'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'],
|
supported_archs=common.consts['crosstool_ng_supported_archs'],
|
||||||
),
|
),
|
||||||
'buildroot': buildroot_component,
|
'buildroot': buildroot_component,
|
||||||
'buildroot-gcc': buildroot_component,
|
'buildroot-gcc': buildroot_component,
|
||||||
'copy-overlay': _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(
|
'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'],
|
supported_archs=common.consts['crosstool_ng_supported_archs'],
|
||||||
# http://crosstool-ng.github.io/docs/os-setup/
|
# http://crosstool-ng.github.io/docs/os-setup/
|
||||||
apt_get_pkgs={
|
apt_get_pkgs={
|
||||||
@@ -147,7 +146,7 @@ This is equivalent to:
|
|||||||
submodules={'crosstool-ng'},
|
submodules={'crosstool-ng'},
|
||||||
),
|
),
|
||||||
'gem5': _Component(
|
'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:
|
# TODO test it out on Docker and answer that question properly:
|
||||||
# https://askubuntu.com/questions/350475/how-can-i-install-gem5
|
# https://askubuntu.com/questions/350475/how-can-i-install-gem5
|
||||||
apt_get_pkgs={
|
apt_get_pkgs={
|
||||||
@@ -170,7 +169,7 @@ This is equivalent to:
|
|||||||
submodules={'gem5'},
|
submodules={'gem5'},
|
||||||
),
|
),
|
||||||
'gem5-debug': _Component(
|
'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(
|
'gem5-fast': _Component(
|
||||||
lambda arch: self._run_cmd(['build-gem5', '--gem5-build-type', 'fast'], arch),
|
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):
|
def timed_main(self):
|
||||||
python_file = os.path.join(common.consts['root_dir'], python_file)
|
self.sh = shell_helpers.ShellHelpers(dry_run=self.env['dry_run'])
|
||||||
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'])
|
|
||||||
|
|
||||||
# Decide components.
|
# Decide components.
|
||||||
components = kwargs['components']
|
components = self.env['components']
|
||||||
if kwargs['all']:
|
if self.env['all']:
|
||||||
components = ['all']
|
components = ['all']
|
||||||
elif components == []:
|
elif components == []:
|
||||||
components = ['qemu-buildroot']
|
components = ['qemu-buildroot']
|
||||||
@@ -336,7 +329,7 @@ Which components to build. Default: qemu-buildroot
|
|||||||
selected_components.append(component)
|
selected_components.append(component)
|
||||||
todo.extend(component.dependencies)
|
todo.extend(component.dependencies)
|
||||||
|
|
||||||
if kwargs['download_dependencies']:
|
if self.env['download_dependencies']:
|
||||||
apt_get_pkgs = {
|
apt_get_pkgs = {
|
||||||
# Core requirements for this repo.
|
# Core requirements for this repo.
|
||||||
'git',
|
'git',
|
||||||
@@ -374,7 +367,7 @@ Which components to build. Default: qemu-buildroot
|
|||||||
python2_pkgs.update(component.python2_pkgs)
|
python2_pkgs.update(component.python2_pkgs)
|
||||||
python3_pkgs.update(component.python3_pkgs)
|
python3_pkgs.update(component.python3_pkgs)
|
||||||
if apt_get_pkgs or apt_build_deps:
|
if apt_get_pkgs or apt_build_deps:
|
||||||
if kwargs['travis']:
|
if self.env['travis']:
|
||||||
interacive_pkgs = {
|
interacive_pkgs = {
|
||||||
'libsdl2-dev',
|
'libsdl2-dev',
|
||||||
}
|
}
|
||||||
@@ -392,7 +385,7 @@ Which components to build. Default: qemu-buildroot
|
|||||||
f.write(sources_txt)
|
f.write(sources_txt)
|
||||||
else:
|
else:
|
||||||
sudo = ['sudo']
|
sudo = ['sudo']
|
||||||
if common.consts['in_docker'] or kwargs['travis']:
|
if common.consts['in_docker'] or self.env['travis']:
|
||||||
y = ['-y']
|
y = ['-y']
|
||||||
else:
|
else:
|
||||||
y = []
|
y = []
|
||||||
@@ -465,7 +458,7 @@ Which components to build. Default: qemu-buildroot
|
|||||||
|
|
||||||
# Do the build.
|
# Do the build.
|
||||||
for component in selected_components:
|
for component in selected_components:
|
||||||
component.build()
|
component.build(self.env['arch'])
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
Main().cli()
|
Main().cli()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class Main(common.BuildCliFunction):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.add_argument(
|
self.add_argument(
|
||||||
'--userland',
|
'--user-mode',
|
||||||
default=False,
|
default=False,
|
||||||
help='Build QEMU user mode instead of system.',
|
help='Build QEMU user mode instead of system.',
|
||||||
)
|
)
|
||||||
@@ -27,7 +27,7 @@ class Main(common.BuildCliFunction):
|
|||||||
verbose = ['V=1']
|
verbose = ['V=1']
|
||||||
else:
|
else:
|
||||||
verbose = []
|
verbose = []
|
||||||
if self.env['userland']:
|
if self.env['user_mode']:
|
||||||
target_list = '{}-linux-user'.format(self.env['arch'])
|
target_list = '{}-linux-user'.format(self.env['arch'])
|
||||||
else:
|
else:
|
||||||
target_list = '{}-softmmu'.format(self.env['arch'])
|
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:
|
Common functionality shared across our CLI functions:
|
||||||
|
|
||||||
* command timing
|
* 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):
|
def __init__(self, *args, defaults=None, supported_archs=None, **kwargs):
|
||||||
'''
|
'''
|
||||||
@@ -122,6 +122,8 @@ class LkmcCliFunction(cli_function.CliFunction):
|
|||||||
if defaults is None:
|
if defaults is None:
|
||||||
defaults = {}
|
defaults = {}
|
||||||
self._defaults = defaults
|
self._defaults = defaults
|
||||||
|
self._is_common = True
|
||||||
|
self._common_args = set()
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.supported_archs = supported_archs
|
self.supported_archs = supported_archs
|
||||||
|
|
||||||
@@ -165,7 +167,17 @@ mkdir are generally omitted since those are obvious
|
|||||||
)
|
)
|
||||||
self.add_argument(
|
self.add_argument(
|
||||||
'--print-time', default=True,
|
'--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(
|
self.add_argument(
|
||||||
'-v', '--verbose', default=False,
|
'-v', '--verbose', default=False,
|
||||||
@@ -284,7 +296,22 @@ See the documentation for other values known to work.
|
|||||||
|
|
||||||
# Userland.
|
# Userland.
|
||||||
self.add_argument(
|
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.
|
# Run.
|
||||||
@@ -336,16 +363,21 @@ Emulator to use. If given multiple times, semantics are similar to --arch.
|
|||||||
Valid emulators: {}
|
Valid emulators: {}
|
||||||
'''.format(emulators_string)
|
'''.format(emulators_string)
|
||||||
)
|
)
|
||||||
|
self._is_common = False
|
||||||
|
|
||||||
def __call__(self, **kwargs):
|
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]
|
print_cmd = ['./' + self.extra_config_params, LF]
|
||||||
for line in self.get_cli(**kwargs):
|
for line in self.get_cli(**kwargs):
|
||||||
print_cmd.extend(line)
|
print_cmd.extend(line)
|
||||||
print_cmd.append(LF)
|
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)
|
return super().__call__(**kwargs)
|
||||||
|
|
||||||
def _init_env(self, env):
|
def _init_env(self, env):
|
||||||
@@ -606,24 +638,23 @@ Valid emulators: {}
|
|||||||
env['image'] = path
|
env['image'] = path
|
||||||
|
|
||||||
def add_argument(self, *args, **kwargs):
|
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)
|
shortname, longname, key, is_option = self.get_key(*args, **kwargs)
|
||||||
if key in self._defaults:
|
if key in self._defaults:
|
||||||
kwargs['default'] = self._defaults[key]
|
kwargs['default'] = self._defaults[key]
|
||||||
|
if self._is_common:
|
||||||
|
self._common_args.add(key)
|
||||||
super().add_argument(*args, **kwargs)
|
super().add_argument(*args, **kwargs)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def base64_encode(string):
|
def base64_encode(string):
|
||||||
return base64.b64encode(string.encode()).decode()
|
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):
|
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'),
|
||||||
@@ -637,6 +668,18 @@ Valid emulators: {}
|
|||||||
break
|
break
|
||||||
return int(addr, 0)
|
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):
|
def get_stats(self, stat_re=None, stats_file=None):
|
||||||
if stat_re is None:
|
if stat_re is None:
|
||||||
stat_re = '^system.cpu[0-9]*.numCycles$'
|
stat_re = '^system.cpu[0-9]*.numCycles$'
|
||||||
@@ -737,29 +780,41 @@ Valid emulators: {}
|
|||||||
'''
|
'''
|
||||||
env = kwargs.copy()
|
env = kwargs.copy()
|
||||||
env.update(consts)
|
env.update(consts)
|
||||||
if env['all_archs']:
|
real_all_archs= env['all_archs']
|
||||||
env['archs'] = consts['all_long_archs']
|
if real_all_archs:
|
||||||
|
real_archs = consts['all_long_archs']
|
||||||
|
else:
|
||||||
|
real_archs = env['archs']
|
||||||
if env['all_emulators']:
|
if env['all_emulators']:
|
||||||
env['emulators'] = consts['all_long_emulators']
|
real_emulators = consts['all_long_emulators']
|
||||||
for emulator in env['emulators']:
|
else:
|
||||||
for arch in env['archs']:
|
real_emulators = env['emulators']
|
||||||
|
for emulator in real_emulators:
|
||||||
|
for arch in real_archs:
|
||||||
if arch in env['arch_short_to_long_dict']:
|
if arch in env['arch_short_to_long_dict']:
|
||||||
arch = env['arch_short_to_long_dict'][arch]
|
arch = env['arch_short_to_long_dict'][arch]
|
||||||
if self.supported_archs is None or arch in self.supported_archs:
|
if self.supported_archs is None or arch in self.supported_archs:
|
||||||
if not env['dry_run']:
|
if not env['dry_run']:
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
env['arch'] = arch
|
env['arch'] = arch
|
||||||
|
env['archs'] = [arch]
|
||||||
|
env['all_archs'] = False
|
||||||
env['emulator'] = emulator
|
env['emulator'] = emulator
|
||||||
|
env['emulators'] = [emulator]
|
||||||
|
env['all_emulators'] = False
|
||||||
self.env = env.copy()
|
self.env = env.copy()
|
||||||
self._init_env(self.env)
|
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()
|
ret = self.timed_main()
|
||||||
if not env['dry_run']:
|
if not env['dry_run']:
|
||||||
end_time = time.time()
|
end_time = time.time()
|
||||||
self._print_time(end_time - start_time)
|
self._print_time(end_time - start_time)
|
||||||
if ret is not None and ret != 0:
|
if ret is not None and ret != 0:
|
||||||
return ret
|
return ret
|
||||||
elif not env['all_archs']:
|
elif not real_all_archs:
|
||||||
raise Exception('Unsupported arch for this action: ' + arch)
|
raise Exception('Unsupported arch for this action: ' + arch)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -787,7 +842,7 @@ Valid emulators: {}
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def _print_time(self, ellapsed_seconds):
|
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)
|
hours, rem = divmod(ellapsed_seconds, 3600)
|
||||||
minutes, seconds = divmod(rem, 60)
|
minutes, seconds = divmod(rem, 60)
|
||||||
print('time {:02}:{:02}:{:02}'.format(int(hours), int(minutes), int(seconds)))
|
print('time {:02}:{:02}:{:02}'.format(int(hours), int(minutes), int(seconds)))
|
||||||
@@ -859,6 +914,14 @@ Valid emulators: {}
|
|||||||
self.env['userland_build_ext'],
|
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):
|
def timed_main(self):
|
||||||
'''
|
'''
|
||||||
Main action of the derived class.
|
Main action of the derived class.
|
||||||
|
|||||||
91
run
91
run
@@ -178,21 +178,6 @@ to use this option:
|
|||||||
'--tmux-args',
|
'--tmux-args',
|
||||||
help='''\
|
help='''\
|
||||||
Parameters to pass to the program running on the tmux split. Implies --tmux.
|
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(
|
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://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
|
# * https://stackoverflow.com/questions/44612822/unable-to-debug-kernel-with-qemu-gdb/49840927#49840927
|
||||||
# Turned on by default since v4.12
|
# 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'
|
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:
|
if self.env['kernel_cli'] is not None:
|
||||||
kernel_cli += ' {}'.format(self.env['kernel_cli'])
|
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))
|
raise Exception('Baremetal ELF file not found. Tried:\n' + '\n'.join(paths))
|
||||||
cmd = debug_vm.copy()
|
cmd = debug_vm.copy()
|
||||||
if self.env['emulator'] == 'gem5':
|
if self.env['emulator'] == 'gem5':
|
||||||
|
if self.env['quiet']:
|
||||||
|
show_stdout = False
|
||||||
if self.env['baremetal'] is None:
|
if self.env['baremetal'] is None:
|
||||||
if not os.path.exists(self.env['rootfs_raw_file']):
|
if not os.path.exists(self.env['rootfs_raw_file']):
|
||||||
if not os.path.exists(self.env['qcow2_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']:
|
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
|
# 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])
|
cmd.extend(['--param', 'system.cpu[0].wait_for_remote_gdb = True', LF])
|
||||||
else:
|
elif self.env['emulator'] == 'qemu':
|
||||||
qemu_user_and_system_options = [
|
qemu_user_and_system_options = [
|
||||||
'-trace', 'enable={},file={}'.format(trace_type, self.env['qemu_trace_file']), LF,
|
'-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 +
|
qemu_user_and_system_options +
|
||||||
debug_args
|
debug_args
|
||||||
)
|
)
|
||||||
|
show_stdout = False
|
||||||
|
raise_on_failure = False
|
||||||
else:
|
else:
|
||||||
if not os.path.exists(self.env['image']):
|
if not os.path.exists(self.env['image']):
|
||||||
raise_image_not_found()
|
raise_image_not_found()
|
||||||
@@ -452,6 +443,8 @@ Run QEMU with VNC instead of the default SDL. Connect to it with:
|
|||||||
else:
|
else:
|
||||||
if self.env['background']:
|
if self.env['background']:
|
||||||
serial_monitor = ['-serial', 'file:{}'.format(self.env['qemu_background_serial_file']), LF]
|
serial_monitor = ['-serial', 'file:{}'.format(self.env['qemu_background_serial_file']), LF]
|
||||||
|
if self.env['quiet']:
|
||||||
|
show_stdout = False
|
||||||
else:
|
else:
|
||||||
serial_monitor = ['-serial', 'mon:stdio', LF]
|
serial_monitor = ['-serial', 'mon:stdio', LF]
|
||||||
if self.env['kvm']:
|
if self.env['kvm']:
|
||||||
@@ -592,36 +585,44 @@ Run QEMU with VNC instead of the default SDL. Connect to it with:
|
|||||||
out_file = None
|
out_file = None
|
||||||
else:
|
else:
|
||||||
out_file = self.env['termout_file']
|
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)
|
exit_status = self.sh.run_cmd(
|
||||||
# Check if guest panicked.
|
cmd,
|
||||||
if self.env['emulator'] == 'gem5':
|
cmd_file=self.env['run_cmd_file'],
|
||||||
# We have to do some parsing here because gem5 exits with status 0 even when panic happens.
|
extra_env=extra_env,
|
||||||
# Grepping for '^panic: ' does not work because some errors don't show that message.
|
out_file=out_file,
|
||||||
panic_msg = b'--- BEGIN LIBC BACKTRACE ---$'
|
raise_on_failure=raise_on_failure,
|
||||||
else:
|
show_stdout=show_stdout,
|
||||||
panic_msg = b'Kernel panic - not syncing'
|
)
|
||||||
panic_re = re.compile(panic_msg)
|
if exit_status == 0:
|
||||||
error_string_found = False
|
# Check if guest panicked.
|
||||||
exit_status = 0
|
if self.env['emulator'] == 'gem5':
|
||||||
if out_file is not None and not self.env['dry_run']:
|
# We have to do some parsing here because gem5 exits with status 0 even when panic happens.
|
||||||
with open(self.env['termout_file'], 'br') as logfile:
|
# Grepping for '^panic: ' does not work because some errors don't show that message.
|
||||||
line = None
|
panic_msg = b'--- BEGIN LIBC BACKTRACE ---$'
|
||||||
for line in logfile:
|
else:
|
||||||
if panic_re.search(line):
|
panic_msg = b'Kernel panic - not syncing'
|
||||||
exit_status = 1
|
panic_re = re.compile(panic_msg)
|
||||||
if line is not None:
|
error_string_found = False
|
||||||
last_line = line.rstrip()
|
exit_status = 0
|
||||||
match = re.search(b'Simulated exit code not 0! Exit code is (\d+)', last_line)
|
if out_file is not None and not self.env['dry_run']:
|
||||||
if match:
|
with open(self.env['termout_file'], 'br') as logfile:
|
||||||
exit_status = int(match.group(1))
|
line = None
|
||||||
if not self.env['userland']:
|
for line in logfile:
|
||||||
if os.path.exists(self.env['guest_terminal_file']):
|
if panic_re.search(line):
|
||||||
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
|
exit_status = 1
|
||||||
if exit_status != 0:
|
if line is not None:
|
||||||
self.log_error('simulation error detected by parsing logs')
|
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
|
return exit_status
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -31,18 +31,25 @@ class ShellHelpers:
|
|||||||
|
|
||||||
_print_lock = threading.Lock()
|
_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.
|
:param dry_run: don't run the commands, just potentially print them. Debug aid.
|
||||||
:type dry_run: Bool
|
:type dry_run: Bool
|
||||||
|
|
||||||
|
:param quiet: don't print the commands.
|
||||||
|
:type dry_run: Bool
|
||||||
'''
|
'''
|
||||||
self.dry_run = dry_run
|
self.dry_run = dry_run
|
||||||
|
self.quiet = quiet
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _print_thread_safe(cls, string):
|
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.
|
Python sucks: a naive print adds a bunch of random spaces to stdout,
|
||||||
# https://stackoverflow.com/questions/3029816/how-do-i-get-a-thread-safe-print-in-python-2-6
|
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()
|
cls._print_lock.acquire()
|
||||||
sys.stdout.write(string + '\n')
|
sys.stdout.write(string + '\n')
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
@@ -107,8 +114,7 @@ class ShellHelpers:
|
|||||||
update=1,
|
update=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
def print_cmd(self, cmd, cwd=None, cmd_file=None, extra_env=None, extra_paths=None):
|
||||||
def print_cmd(cls, cmd, cwd=None, cmd_file=None, extra_env=None, extra_paths=None):
|
|
||||||
'''
|
'''
|
||||||
Print cmd_to_string to stdout.
|
Print cmd_to_string to stdout.
|
||||||
|
|
||||||
@@ -121,8 +127,9 @@ class ShellHelpers:
|
|||||||
if type(cmd) is str:
|
if type(cmd) is str:
|
||||||
cmd_string = cmd
|
cmd_string = cmd
|
||||||
else:
|
else:
|
||||||
cmd_string = cls.cmd_to_string(cmd, cwd=cwd, extra_env=extra_env, extra_paths=extra_paths)
|
cmd_string = self.cmd_to_string(cmd, cwd=cwd, extra_env=extra_env, extra_paths=extra_paths)
|
||||||
cls._print_thread_safe('+ ' + cmd_string)
|
if not self.quiet:
|
||||||
|
self._print_thread_safe('+ ' + cmd_string)
|
||||||
if cmd_file is not None:
|
if cmd_file is not None:
|
||||||
with open(cmd_file, 'w') as f:
|
with open(cmd_file, 'w') as f:
|
||||||
f.write('#!/usr/bin/env bash\n')
|
f.write('#!/usr/bin/env bash\n')
|
||||||
|
|||||||
35
test-gdb
35
test-gdb
@@ -7,7 +7,11 @@ import common
|
|||||||
|
|
||||||
class Main(common.LkmcCliFunction):
|
class Main(common.LkmcCliFunction):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__(
|
||||||
|
defaults={
|
||||||
|
'print_time': False,
|
||||||
|
},
|
||||||
|
)
|
||||||
self.add_argument(
|
self.add_argument(
|
||||||
'tests',
|
'tests',
|
||||||
metavar='tests',
|
metavar='tests',
|
||||||
@@ -19,8 +23,8 @@ found by searching for the Python test files.
|
|||||||
)
|
)
|
||||||
|
|
||||||
def timed_main(self):
|
def timed_main(self):
|
||||||
run = self.import_path('run').Main()
|
run = self.import_path_main('run')
|
||||||
run_gdb = self.import_path('run-gdb').Main()
|
run_gdb = self.import_path_main('run-gdb')
|
||||||
if self.env['arch'] in self.env['crosstool_ng_supported_archs']:
|
if self.env['arch'] in self.env['crosstool_ng_supported_archs']:
|
||||||
if self.env['tests'] == []:
|
if self.env['tests'] == []:
|
||||||
test_scripts_noext = []
|
test_scripts_noext = []
|
||||||
@@ -38,22 +42,17 @@ found by searching for the Python test files.
|
|||||||
else:
|
else:
|
||||||
test_scripts_noext = self.env['tests']
|
test_scripts_noext = self.env['tests']
|
||||||
for test_script_noext in test_scripts_noext:
|
for test_script_noext in test_scripts_noext:
|
||||||
run_thread = threading.Thread(target=lambda: run(
|
common_args = self.get_common_args()
|
||||||
archs=[self.env['arch']],
|
common_args['baremetal'] = test_script_noext
|
||||||
background=True,
|
test_id_string = self.test_setup(common_args, test_script_noext)
|
||||||
baremetal=test_script_noext,
|
run_args = common_args.copy()
|
||||||
dry_run=self.env['dry_run'],
|
run_args['wait_gdb'] = True
|
||||||
emulators=self.env['emulator'],
|
run_args['background'] = True
|
||||||
wait_gdb=True
|
run_thread = threading.Thread(target=lambda: run(**run_args))
|
||||||
))
|
|
||||||
run_thread.start()
|
run_thread.start()
|
||||||
run_gdb(
|
gdb_args = common_args.copy()
|
||||||
archs=[self.env['arch']],
|
gdb_args['test'] = True
|
||||||
baremetal=test_script_noext,
|
run_gdb(**gdb_args)
|
||||||
dry_run=self.env['dry_run'],
|
|
||||||
emulators=self.env['emulator'],
|
|
||||||
test=True,
|
|
||||||
)
|
|
||||||
run_thread.join()
|
run_thread.join()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
import common
|
import common
|
||||||
|
|
||||||
class Main(common.LkmcCliFunction):
|
class Main(common.LkmcCliFunction):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__(
|
||||||
|
defaults={
|
||||||
|
'print_time': False,
|
||||||
|
},
|
||||||
|
)
|
||||||
self.add_argument(
|
self.add_argument(
|
||||||
'tests',
|
'tests',
|
||||||
metavar='tests',
|
metavar='tests',
|
||||||
@@ -17,13 +22,10 @@ If given, run only the given tests. Otherwise, run all tests.
|
|||||||
)
|
)
|
||||||
|
|
||||||
def timed_main(self):
|
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':
|
if self.env['emulator'] == 'gem5':
|
||||||
extra_args = {
|
run_args['userland_build_id'] = 'static'
|
||||||
'userland_build_id': 'static',
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
extra_args = {}
|
|
||||||
if self.env['tests'] == []:
|
if self.env['tests'] == []:
|
||||||
sources = [
|
sources = [
|
||||||
'add.c',
|
'add.c',
|
||||||
@@ -46,21 +48,19 @@ If given, run only the given tests. Otherwise, run all tests.
|
|||||||
else:
|
else:
|
||||||
sources = self.env['tests']
|
sources = self.env['tests']
|
||||||
for source in sources:
|
for source in sources:
|
||||||
exit_status = run(
|
run_args['userland'] = source
|
||||||
archs=[self.env['arch']],
|
test_id_string = self.test_setup(run_args, source)
|
||||||
dry_run=self.env['dry_run'],
|
run_args['background'] = True
|
||||||
userland=source,
|
exit_status = run(**run_args)
|
||||||
emulators=[self.env['emulator']],
|
|
||||||
**extra_args,
|
|
||||||
)
|
|
||||||
# TODO forward all args attempt. In particular, --dry-run.
|
# TODO forward all args attempt. In particular, --dry-run.
|
||||||
#new_env = self.env.copy()
|
#new_env = self.env.copy()
|
||||||
#new_env['userland'] = source
|
#new_env['userland'] = source
|
||||||
#new_env['emulator'] = emulator
|
#new_env['emulator'] = emulator
|
||||||
#new_env.update(extra_args)
|
#new_env.update(run_args)
|
||||||
#exit_status = run(**new_env)
|
#exit_status = run(**new_env)
|
||||||
if exit_status != 0:
|
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__':
|
if __name__ == '__main__':
|
||||||
Main().cli()
|
Main().cli()
|
||||||
|
|||||||
Reference in New Issue
Block a user