DebugUtils.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. # SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
  2. # SPDX-License-Identifier: Apache-2.0
  3. from __future__ import unicode_literals
  4. import logging
  5. from io import open
  6. import pexpect
  7. from tiny_test_fw import Utility
  8. try:
  9. import debug_backend
  10. except ImportError:
  11. # Exception is ignored so the package is not required for those who don't use debug utils.
  12. err_msg = 'Please install py_debug_backend for debug utils to work properly!'
  13. class debug_backend(object): # type: ignore
  14. @staticmethod
  15. def create_oocd(*args, **kwargs):
  16. raise RuntimeError(err_msg)
  17. @staticmethod
  18. def create_gdb(*args, **kwargs):
  19. raise RuntimeError(err_msg)
  20. try:
  21. from debug_backend.defs import NoGdbProcessError
  22. except ImportError:
  23. # fallback for pygdbmi<0.10.0.0 which is used in the previous version of debug_backend
  24. try:
  25. from pygdbmi.gdbcontroller import NoGdbProcessError
  26. except ImportError:
  27. # If debug_backend is not installed, the exception is ignored.
  28. class NoGdbProcessError(ValueError): # type: ignore
  29. pass
  30. class CustomProcess(object):
  31. def __init__(self, cmd, logfile, verbose=True):
  32. self.verbose = verbose
  33. self.f = open(logfile, 'w')
  34. if self.verbose:
  35. Utility.console_log('Starting {} > {}'.format(cmd, self.f.name))
  36. self.pexpect_proc = pexpect.spawn(cmd, timeout=60, logfile=self.f, encoding='utf-8', codec_errors='ignore')
  37. def __enter__(self):
  38. return self
  39. def close(self):
  40. self.pexpect_proc.terminate(force=True)
  41. def __exit__(self, type, value, traceback):
  42. self.close()
  43. self.f.close()
  44. class OCDBackend(object):
  45. def __init__(self, logfile_path, target, cfg_cmds=[], extra_args=[]):
  46. # TODO Use configuration file implied by the test environment (board)
  47. self.oocd = debug_backend.create_oocd(chip_name=target,
  48. oocd_exec='openocd',
  49. oocd_scripts=None,
  50. oocd_cfg_files=['board/esp32-wrover-kit-3.3v.cfg'],
  51. oocd_cfg_cmds=cfg_cmds,
  52. oocd_debug=2,
  53. oocd_args=extra_args,
  54. host='localhost',
  55. log_level=logging.DEBUG,
  56. log_stream_handler=None,
  57. log_file_handler=logging.FileHandler(logfile_path, 'w'),
  58. scope=None)
  59. self.oocd.start()
  60. def __enter__(self):
  61. return self
  62. def __exit__(self, type, value, traceback):
  63. self.oocd.stop()
  64. def cmd_exec(self, cmd):
  65. return self.oocd.cmd_exec(cmd)
  66. def apptrace_start(self, trace_args):
  67. self.oocd.apptrace_start(trace_args)
  68. def apptrace_stop(self):
  69. self.oocd.apptrace_stop()
  70. def apptrace_wait_stop(self, tmo=10):
  71. self.oocd.apptrace_wait_stop(tmo=tmo)
  72. class GDBBackend(object):
  73. def __init__(self, logfile_path, elffile_path, target, gdbinit_path=None, working_dir=None):
  74. self.gdb = debug_backend.create_gdb(chip_name=target,
  75. gdb_path='xtensa-{}-elf-gdb'.format(target),
  76. remote_target=None,
  77. extended_remote_mode=False,
  78. gdb_log_file=logfile_path,
  79. log_level=None,
  80. log_stream_handler=None,
  81. log_file_handler=None,
  82. scope=None)
  83. if working_dir:
  84. self.gdb.console_cmd_run('directory {}'.format(working_dir))
  85. self.gdb.exec_file_set(elffile_path)
  86. if gdbinit_path:
  87. try:
  88. self.gdb.console_cmd_run('source {}'.format(gdbinit_path))
  89. except debug_backend.defs.DebuggerTargetStateTimeoutError:
  90. # The internal timeout is not enough on RPI for more time consuming operations, e.g. "load".
  91. # So lets try to apply the commands one-by-one:
  92. with open(gdbinit_path, 'r') as f:
  93. for line in f:
  94. line = line.strip()
  95. if len(line) > 0 and not line.startswith('#'):
  96. self.gdb.console_cmd_run(line)
  97. # Note that some commands cannot be applied with console_cmd_run, e.g. "commands"
  98. def __enter__(self):
  99. return self
  100. def __exit__(self, type, value, traceback):
  101. try:
  102. self.gdb.gdb_exit()
  103. except NoGdbProcessError as e:
  104. # the debug backend can fail on gdb exit
  105. # when it tries to read the response after issuing the exit command.
  106. Utility.console_log('Ignoring exception: {}'.format(e), 'O')
  107. except debug_backend.defs.DebuggerTargetStateTimeoutError:
  108. Utility.console_log('Ignoring timeout exception for GDB exit', 'O')