CI: Use higher-level interaction with GDB in example tests and test apps

This commit is contained in:
Roland Dobai
2020-05-19 14:27:31 +02:00
committed by bot
parent 8526cb577c
commit 493c852b73
10 changed files with 159 additions and 145 deletions

View File

@@ -15,7 +15,10 @@
from __future__ import unicode_literals
from io import open
from tiny_test_fw import Utility
import debug_backend
import logging
import pexpect
import pygdbmi.gdbcontroller
class CustomProcess(object):
@@ -37,63 +40,68 @@ class CustomProcess(object):
self.f.close()
class OCDProcess(CustomProcess):
def __init__(self, logfile_path, extra_args='', verbose=True):
class OCDBackend(object):
def __init__(self, logfile_path, target, cfg_cmds=[], extra_args=[]):
# TODO Use configuration file implied by the test environment (board)
cmd = 'openocd {} -f board/esp32-wrover-kit-3.3v.cfg'.format(extra_args)
super(OCDProcess, self).__init__(cmd, logfile_path, verbose)
patterns = ['Info : Listening on port 3333 for gdb connections']
self.oocd = debug_backend.create_oocd(chip_name=target,
oocd_exec='openocd',
oocd_scripts=None,
oocd_cfg_files=['board/esp32-wrover-kit-3.3v.cfg'],
oocd_cfg_cmds=cfg_cmds,
oocd_debug=2,
oocd_args=extra_args,
host='localhost',
log_level=logging.DEBUG,
log_stream_handler=None,
log_file_handler=logging.FileHandler(logfile_path, 'w'),
scope=None)
self.oocd.start()
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.oocd.stop()
def cmd_exec(self, cmd):
return self.oocd.cmd_exec(cmd)
class GDBBackend(object):
def __init__(self, logfile_path, elffile_path, target, gdbinit_path=None, working_dir=None):
self.gdb = debug_backend.create_gdb(chip_name=target,
gdb_path='xtensa-{}-elf-gdb'.format(target),
remote_target=None,
extended_remote_mode=False,
gdb_log_file=logfile_path,
log_level=None,
log_stream_handler=None,
log_file_handler=None,
scope=None)
if working_dir:
self.gdb.console_cmd_run('directory {}'.format(working_dir))
self.gdb.exec_file_set(elffile_path)
if gdbinit_path:
try:
self.gdb.console_cmd_run('source {}'.format(gdbinit_path))
except debug_backend.defs.DebuggerTargetStateTimeoutError:
# The internal timeout is not enough on RPI for more time consuming operations, e.g. "load".
# So lets try to apply the commands one-by-one:
with open(gdbinit_path, 'r') as f:
for line in f:
line = line.strip()
if len(line) > 0 and not line.startswith('#'):
self.gdb.console_cmd_run(line)
# Note that some commands cannot be applied with console_cmd_run, e.g. "commands"
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
try:
while True:
i = self.pexpect_proc.expect_exact(patterns, timeout=30)
# TIMEOUT or EOF exceptions will be thrown upon other errors
if i == 0:
if self.verbose:
Utility.console_log('openocd is listening for gdb connections')
break # success
except Exception:
if self.verbose:
Utility.console_log('openocd initialization has failed', 'R')
raise
def close(self):
try:
self.pexpect_proc.sendcontrol('c')
self.pexpect_proc.expect_exact('shutdown command invoked')
except Exception:
if self.verbose:
Utility.console_log('openocd needs to be killed', 'O')
super(OCDProcess, self).close()
class GDBProcess(CustomProcess):
def __init__(self, logfile_path, elffile_path, target, extra_args='', verbose=True):
cmd = 'xtensa-{}-elf-gdb {} {}'.format(target, extra_args, elffile_path)
super(GDBProcess, self).__init__(cmd, logfile_path, verbose)
def close(self):
try:
self.pexpect_proc.sendline('q')
self.pexpect_proc.expect_exact('Quit anyway? (y or n)')
self.pexpect_proc.sendline('y')
self.pexpect_proc.expect_exact('Ending remote debugging.')
except Exception:
if self.verbose:
Utility.console_log('gdb needs to be killed', 'O')
super(GDBProcess, self).close()
class TelnetProcess(CustomProcess):
def __init__(self, logfile_path, host='localhost', port=4444, verbose=True):
cmd = 'telnet {} {}'.format(host, port)
super(TelnetProcess, self).__init__(cmd, logfile_path, verbose)
def close(self):
try:
self.pexpect_proc.sendline('exit')
self.pexpect_proc.expect_exact('Connection closed by foreign host.')
except Exception:
if self.verbose:
Utility.console_log('telnet needs to be killed', 'O')
super(TelnetProcess, self).close()
self.gdb.gdb_exit()
except pygdbmi.gdbcontroller.NoGdbProcessError as e:
# the debug backend can fail on gdb exit when it tries to read the response after issuing the exit command.
Utility.console_log('Ignoring exception: {}'.format(e), 'O')
except debug_backend.defs.DebuggerTargetStateTimeoutError:
Utility.console_log('Ignoring timeout exception for GDB exit', 'O')