zephyr/scripts/west_commands/runners/blackmagicprobe.py
Martí Bolívar 2024fb531a scripts: runners: fix blackmagicprobe SIGINT behavior
The blackmagicprobe runner's Python process fails to ignore SIGINT
when it runs GDB from the debug and flash callbacks, which is wrong.

The other runners tend to use run_server_and_client() to properly
handle this, since they start a GDB server and connect to it with a
client. The BMP USB device presents itself as a serial device which
speaks the GDB serial protocol instead, so there's no server/client,
and thus no call to run_server_and_client().

The problem is that blackmagicprobe essentially uses
subprocess.check_call() to start GDB directly, without ignoring SIGINT
in the python process. Easy fix.

Fixes: #21139

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2019-12-03 14:15:30 -06:00

102 lines
3.7 KiB
Python

# Copyright (c) 2018 Roman Tataurov <diytronic@yandex.ru>
# Modified 2018 Tavish Naruka <tavishnaruka@gmail.com>
#
# SPDX-License-Identifier: Apache-2.0
'''Runner for flashing with Black Magic Probe.'''
# https://github.com/blacksphere/blackmagic/wiki
import signal
from runners.core import ZephyrBinaryRunner, RunnerCaps
class BlackMagicProbeRunner(ZephyrBinaryRunner):
'''Runner front-end for Black Magic probe.'''
def __init__(self, cfg, gdb_serial):
super(BlackMagicProbeRunner, self).__init__(cfg)
self.gdb = [cfg.gdb] if cfg.gdb else None
self.elf_file = cfg.elf_file
self.gdb_serial = gdb_serial
@classmethod
def name(cls):
return 'blackmagicprobe'
@classmethod
def capabilities(cls):
return RunnerCaps(commands={'flash', 'debug', 'attach'})
@classmethod
def create(cls, cfg, args):
return BlackMagicProbeRunner(cfg, args.gdb_serial)
@classmethod
def do_add_parser(cls, parser):
parser.add_argument('--gdb-serial', default='/dev/ttyACM0',
help='GDB serial port')
def bmp_flash(self, command, **kwargs):
if self.elf_file is None:
raise ValueError('Cannot debug; elf file is missing')
command = (self.gdb +
['-ex', "set confirm off",
'-ex', "target extended-remote {}".format(self.gdb_serial),
'-ex', "monitor swdp_scan",
'-ex', "attach 1",
'-ex', "load {}".format(self.elf_file),
'-ex', "kill",
'-ex', "quit",
'-silent'])
self.check_call(command)
def check_call_ignore_sigint(self, command):
previous = signal.signal(signal.SIGINT, signal.SIG_IGN)
try:
self.check_call(command)
finally:
signal.signal(signal.SIGINT, previous)
def bmp_attach(self, command, **kwargs):
if self.elf_file is None:
command = (self.gdb +
['-ex', "set confirm off",
'-ex', "target extended-remote {}".format(
self.gdb_serial),
'-ex', "monitor swdp_scan",
'-ex', "attach 1"])
else:
command = (self.gdb +
['-ex', "set confirm off",
'-ex', "target extended-remote {}".format(
self.gdb_serial),
'-ex', "monitor swdp_scan",
'-ex', "attach 1",
'-ex', "file {}".format(self.elf_file)])
self.check_call_ignore_sigint(command)
def bmp_debug(self, command, **kwargs):
if self.elf_file is None:
raise ValueError('Cannot debug; elf file is missing')
command = (self.gdb +
['-ex', "set confirm off",
'-ex', "target extended-remote {}".format(self.gdb_serial),
'-ex', "monitor swdp_scan",
'-ex', "attach 1",
'-ex', "file {}".format(self.elf_file),
'-ex', "load {}".format(self.elf_file)])
self.check_call_ignore_sigint(command)
def do_run(self, command, **kwargs):
if self.gdb is None:
raise ValueError('Cannot execute; gdb not specified')
self.require(self.gdb[0])
if command == 'flash':
self.bmp_flash(command, **kwargs)
elif command == 'debug':
self.bmp_debug(command, **kwargs)
elif command == 'attach':
self.bmp_attach(command, **kwargs)
else:
self.bmp_flash(command, **kwargs)