| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- # SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
- # SPDX-License-Identifier: Apache-2.0
- import os
- import re
- import subprocess
- import sys
- import tempfile
- from .constants import PANIC_OUTPUT_DECODE_SCRIPT
- from .logger import Logger
- from .output_helpers import normal_print, red_print, yellow_print
- from .web_socket_client import WebSocketClient
- class GDBHelper:
- def __init__(self, toolchain_prefix, websocket_client, elf_file, port, baud_rate):
- # type: (str, WebSocketClient, str, int, int) -> None
- self._gdb_buffer = b'' # type: bytes
- self._gdb_exit = False # type: bool
- self.toolchain_prefix = toolchain_prefix
- self.websocket_client = websocket_client
- self.elf_file = elf_file
- self.port = port
- self.baud_rate = baud_rate
- @property
- def gdb_buffer(self): # type: () -> bytes
- return self._gdb_buffer
- @gdb_buffer.setter
- def gdb_buffer(self, value): # type: (bytes) -> None
- self._gdb_buffer = value
- @property
- def gdb_exit(self): # type: () -> bool
- return self._gdb_exit
- @gdb_exit.setter
- def gdb_exit(self, value): # type: (bool) -> None
- self._gdb_exit = value
- def run_gdb(self):
- # type: () -> None
- normal_print('')
- try:
- cmd = ['%sgdb' % self.toolchain_prefix,
- '-ex', 'set serial baud %d' % self.baud_rate,
- '-ex', 'target remote %s' % self.port,
- self.elf_file]
- # Here we handling GDB as a process
- # Open GDB process
- try:
- process = subprocess.Popen(cmd, cwd='.')
- except KeyboardInterrupt:
- pass
- # We ignore Ctrl+C interrupt form external process abd wait response util GDB will be finished.
- while True:
- try:
- process.wait()
- break
- except KeyboardInterrupt:
- pass # We ignore the Ctrl+C
- self.gdb_exit = True
- except OSError as e:
- red_print('%s: %s' % (' '.join(cmd), e))
- except KeyboardInterrupt:
- pass # happens on Windows, maybe other OSes
- finally:
- try:
- # on Linux, maybe other OSes, gdb sometimes seems to be alive even after wait() returns...
- process.terminate()
- except Exception: # noqa
- pass
- try:
- # also on Linux, maybe other OSes, gdb sometimes exits uncleanly and breaks the tty mode
- subprocess.call(['stty', 'sane'])
- except Exception: # noqa
- pass # don't care if there's no stty, we tried...
- def check_gdb_stub_trigger(self, line):
- # type: (bytes) -> bool
- line = self.gdb_buffer + line
- self.gdb_buffer = b''
- m = re.search(b'\\$(T..)#(..)', line) # look for a gdb "reason" for a break
- if m is not None:
- try:
- chsum = sum(ord(bytes([p])) for p in m.group(1)) & 0xFF
- calc_chsum = int(m.group(2), 16)
- except ValueError: # payload wasn't valid hex digits
- return False
- if chsum == calc_chsum:
- if self.websocket_client:
- yellow_print('Communicating through WebSocket')
- self.websocket_client.send({'event': 'gdb_stub',
- 'port': self.port,
- 'prog': self.elf_file})
- yellow_print('Waiting for debug finished event')
- self.websocket_client.wait([('event', 'debug_finished')])
- yellow_print('Communications through WebSocket is finished')
- else:
- return True
- else:
- red_print('Malformed gdb message... calculated checksum %02x received %02x' % (chsum, calc_chsum))
- return False
- def process_panic_output(self, panic_output, logger, target): # type: (bytes, Logger, str) -> None
- panic_output_file = None
- try:
- # On Windows, the temporary file can't be read unless it is closed.
- # Set delete=False and delete the file manually later.
- with tempfile.NamedTemporaryFile(mode='wb', delete=False) as panic_output_file:
- panic_output_file.write(panic_output)
- panic_output_file.flush()
- cmd = [self.toolchain_prefix + 'gdb',
- '--batch', '-n',
- self.elf_file,
- '-ex', "target remote | \"{python}\" \"{script}\" --target {target} \"{output_file}\""
- .format(python=sys.executable,
- script=PANIC_OUTPUT_DECODE_SCRIPT,
- target=target,
- output_file=panic_output_file.name),
- '-ex', 'bt']
- output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
- yellow_print('\nBacktrace:\n\n')
- logger.print(output) # noqa: E999
- except subprocess.CalledProcessError as e:
- yellow_print('Failed to run gdb_panic_server.py script: {}\n{}\n\n'.format(e, e.output))
- logger.print(panic_output)
- finally:
- if panic_output_file is not None:
- try:
- os.unlink(panic_output_file.name)
- except OSError as e:
- yellow_print('Couldn\'t remove temporary panic output file ({})'.format(e))
|