test-gdb: exit gracefully on failure instead of raising

Just print the traceback instead.

Pass extra CLI options to produce nicer output like --no-show-stdout.
This commit is contained in:
Ciro Santilli 六四事件 法轮功
2019-05-28 00:00:01 +00:00
parent 04c54a6369
commit cd44e3b5e2
3 changed files with 58 additions and 45 deletions

View File

@@ -939,19 +939,18 @@ Incompatible archs are skipped.
env['qcow2_file'] = env['buildroot_qcow2_file'] env['qcow2_file'] = env['buildroot_qcow2_file']
# Image # Image
if env['_args_given']['baremetal']: if env['baremetal'] is not None:
env['disk_image'] = env['gem5_fake_iso'] env['disk_image'] = env['gem5_fake_iso']
path = self.resolve_baremetal_executable(env['baremetal']) env['image'] = self.resolve_baremetal_executable(env['baremetal'])
source_path_noext = os.path.splitext(join( source_path_noext = os.path.splitext(join(
env['root_dir'], env['root_dir'],
os.path.relpath(path, env['baremetal_build_dir']) os.path.relpath(env['image'], env['baremetal_build_dir'])
))[0] ))[0]
for ext in [env['c_ext'], env['asm_ext']]: for ext in env['baremetal_build_in_exts']:
source_path = source_path_noext + ext source_path = source_path_noext + ext
if os.path.exists(source_path): if os.path.exists(source_path):
env['source_path'] = source_path env['source_path'] = source_path
break break
env['image'] = path
elif env['userland'] is not None: elif env['userland'] is not None:
env['image'] = self.resolve_userland_executable(env['userland']) env['image'] = self.resolve_userland_executable(env['userland'])
else: else:
@@ -1688,6 +1687,15 @@ class TestCliFunction(LkmcCliFunction):
Automates test reporting boilerplate for those commands. Automates test reporting boilerplate for those commands.
''' '''
base_run_args = {
'background': True,
'ctrl_c_host': True,
'print_cmd_oneline': True,
'show_cmds': False,
'show_stdout': False,
'show_time': False,
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
defaults = { defaults = {
'quit_on_fail': False, 'quit_on_fail': False,
@@ -1739,14 +1747,9 @@ class TestCliFunction(LkmcCliFunction):
''' '''
if run_obj.is_arch_supported(run_args['archs'][0]): if run_obj.is_arch_supported(run_args['archs'][0]):
cur_run_args = { cur_run_args = {
'background': True,
'ctrl_c_host': True,
'print_cmd_oneline': True,
'run_id': thread_id, 'run_id': thread_id,
'show_cmds': False,
'show_stdout': False,
'show_time': False,
} }
cur_run_args.update(self.base_run_args)
if run_args is not None: if run_args is not None:
cur_run_args.update(run_args) cur_run_args.update(run_args)
test_id_string = self.test_setup(run_args, test_id) test_id_string = self.test_setup(run_args, test_id)

68
run-gdb
View File

@@ -5,9 +5,10 @@ import signal
import subprocess import subprocess
import sys import sys
from shell_helpers import LF
import common import common
import lkmc.import_path import lkmc.import_path
from shell_helpers import LF import thread_pool
class GdbTestcase: class GdbTestcase:
def __init__( def __init__(
@@ -38,12 +39,11 @@ class GdbTestcase:
exception = None exception = None
try: try:
test.test(self) test.test(self)
except AssertionError as e: except Exception as e:
exception = e exception = e
self.child.sendcontrol('d') self.child.sendcontrol('d')
self.child.close() self.child.close()
if exception is not None: self.exception = exception
raise exception
def before(self): def before(self):
return self.child.before.rstrip() return self.child.before.rstrip()
@@ -83,48 +83,53 @@ class Main(common.LkmcCliFunction):
Connect with GDB to an emulator to debug Linux itself Connect with GDB to an emulator to debug Linux itself
''') ''')
self.add_argument( self.add_argument(
'--after', default='', '--after',
default='',
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'
) )
self.add_argument( self.add_argument(
'--before', default='', '--before',
default='',
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'
) )
self.add_argument( self.add_argument(
'break_at', nargs='?', '--continue',
help='Extra options to append at the end of the emulator command line' default=True,
)
self.add_argument(
'-k', '--kgdb', default=False,
)
self.add_argument(
'-C', '--no-continue', default=False,
help="Don't run continue after connecting" help="Don't run continue after connecting"
) )
self.add_argument( self.add_argument(
'-X', '--no-lxsymbols', default=False, '--kgdb',
default=False,
) )
self.add_argument( self.add_argument(
'--test', default=False, '--lxsymbols',
default=True,
)
self.add_argument(
'--sim',
default=False,
help='''Use the built-in GDB CPU simulator
See: https://github.com/cirosantilli/linux-kernel-module-cheat#gdb-builtin-cpu-simulator
'''
)
self.add_argument(
'--test',
default=False,
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.
''' '''
) )
self.add_argument( self.add_argument(
'--sim', default=False, 'break_at',
help='''Use the built-in GDB CPU simulator nargs='?',
See: https://github.com/cirosantilli/linux-kernel-module-cheat#gdb-builtin-cpu-simulator help='Extra options to append at the end of the emulator command line'
'''
)
self.add_argument(
'-u', '--userland',
) )
def timed_main(self): def timed_main(self):
after = self.sh.shlex_split(self.env['after']) after = self.sh.shlex_split(self.env['after'])
before = self.sh.shlex_split(self.env['before']) before = self.sh.shlex_split(self.env['before'])
no_continue = self.env['no_continue'] no_continue = not self.env['continue']
if self.env['test']: if self.env['test']:
no_continue = True no_continue = True
before.extend([ before.extend([
@@ -149,7 +154,6 @@ See: https://github.com/cirosantilli/linux-kernel-module-cheat#gdb-builtin-cpu-s
image = self.env['image'] image = self.env['image']
elif self.env['baremetal']: elif self.env['baremetal']:
image = self.env['image'] image = self.env['image']
test_script_path = os.path.splitext(self.env['source_path'])[0] + '.py'
else: else:
image = self.env['vmlinux'] image = self.env['vmlinux']
cmd = ( cmd = (
@@ -193,18 +197,24 @@ See: https://github.com/cirosantilli/linux-kernel-module-cheat#gdb-builtin-cpu-s
# The lx-symbols commands gets loaded through the file vmlinux-gdb.py # The lx-symbols commands gets loaded through the file vmlinux-gdb.py
# which gets put on the kernel build root when python debugging scripts are enabled. # which gets put on the kernel build root when python debugging scripts are enabled.
cmd.extend(['-ex', 'continue', LF]) cmd.extend(['-ex', 'continue', LF])
if not self.env['no_lxsymbols'] and linux_full_system: if self.env['lxsymbols'] and linux_full_system:
cmd.extend(['-ex', 'lx-symbols {}'.format(self.env['kernel_modules_build_subdir']), LF]) cmd.extend(['-ex', 'lx-symbols {}'.format(self.env['kernel_modules_build_subdir']), LF])
cmd.extend(after) cmd.extend(after)
if self.env['test']: if self.env['test']:
self.sh.print_cmd(cmd) self.sh.print_cmd(cmd)
if not self.env['dry_run']: if not self.env['dry_run']:
GdbTestcase( exception = GdbTestcase(
self.env['source_path'], self.env['source_path'],
test_script_path, os.path.splitext(self.env['source_path'])[0] + '.py',
self.sh.strip_newlines(cmd), self.sh.strip_newlines(cmd),
verbose=self.env['verbose'], verbose=self.env['verbose'],
) ).exception
if exception is None:
exit_status = 0
else:
exit_status = 1
self.log_info(thread_pool.ThreadPool.exception_traceback_string(exception))
return exit_status
else: else:
# I would rather have cwd be out_rootfs_overlay_dir, # I would rather have cwd be out_rootfs_overlay_dir,
# but then lx-symbols cannot fine the vmlinux and fails with: # but then lx-symbols cannot fine the vmlinux and fails with:

View File

@@ -34,8 +34,6 @@ found by searching for the Python test files.
) )
def timed_main(self): def timed_main(self):
run = lkmc.import_path.import_path_main('run')
run_gdb = lkmc.import_path.import_path_main('run-gdb')
rootdir_abs_len = len(self.env['root_dir']) rootdir_abs_len = len(self.env['root_dir'])
for test in self.env['tests']: for test in self.env['tests']:
for path, in_dirnames, in_filenames in self.sh.walk(test): for path, in_dirnames, in_filenames in self.sh.walk(test):
@@ -48,19 +46,21 @@ found by searching for the Python test files.
if ext in self.env['baremetal_build_in_exts'] and os.path.exists(path_relative_root_base + '.py'): if ext in self.env['baremetal_build_in_exts'] and os.path.exists(path_relative_root_base + '.py'):
my_path_properties = path_properties.get(path_relative_root) my_path_properties = path_properties.get(path_relative_root)
if my_path_properties.should_be_tested(self.env, is_baremetal=True): if my_path_properties.should_be_tested(self.env, is_baremetal=True):
run = lkmc.import_path.import_path_main('run')
run_gdb = lkmc.import_path.import_path_main('run-gdb')
common_args = self.get_common_args() common_args = self.get_common_args()
common_args['baremetal'] = path_relative_root common_args['baremetal'] = path_relative_root
run_args = common_args.copy() run_args = common_args.copy()
run_args['gdb_wait'] = True run_args['gdb_wait'] = True
run_args['background'] = True run_args.update(self.base_run_args)
test_id_string = self.test_setup(run_args, path_relative_root) test_id_string = self.test_setup(run_args, path_relative_root)
run_thread = threading.Thread(target=lambda: run(**run_args)) run_thread = threading.Thread(target=lambda: run(**run_args))
run_thread.start() run_thread.start()
gdb_args = common_args.copy() gdb_args = common_args.copy()
gdb_args['test'] = True gdb_args['test'] = True
run_gdb(**gdb_args) exit_status = run_gdb(**gdb_args)
run_thread.join() run_thread.join()
self.test_teardown(run, 0, test_id_string) self.test_teardown(run, exit_status, test_id_string)
if __name__ == '__main__': if __name__ == '__main__':
Main().cli() Main().cli()