change(tools): fix the style of debug_ext.py

This commit is contained in:
Roland Dobai
2025-05-22 12:56:04 +02:00
committed by BOT
parent ea4787e6e6
commit 532ea1ad6d

View File

@ -19,14 +19,15 @@ from typing import Union
from click import INT from click import INT
from click.core import Context from click.core import Context
from esp_coredump import CoreDump from esp_coredump import CoreDump
from idf_py_actions.errors import FatalError from idf_py_actions.errors import FatalError
from idf_py_actions.serial_ext import BAUD_RATE from idf_py_actions.serial_ext import BAUD_RATE
from idf_py_actions.serial_ext import PORT from idf_py_actions.serial_ext import PORT
from idf_py_actions.tools import PropertyDict
from idf_py_actions.tools import ensure_build_directory from idf_py_actions.tools import ensure_build_directory
from idf_py_actions.tools import generate_hints from idf_py_actions.tools import generate_hints
from idf_py_actions.tools import get_default_serial_port from idf_py_actions.tools import get_default_serial_port
from idf_py_actions.tools import get_sdkconfig_value from idf_py_actions.tools import get_sdkconfig_value
from idf_py_actions.tools import PropertyDict
from idf_py_actions.tools import yellow_print from idf_py_actions.tools import yellow_print
@ -105,17 +106,19 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
print('Failed to close/kill {}'.format(target)) print('Failed to close/kill {}'.format(target))
processes[target] = None # to indicate this has ended processes[target] = None # to indicate this has ended
def _get_espcoredump_instance(ctx: Context, def _get_espcoredump_instance(
args: PropertyDict, ctx: Context,
gdb_timeout_sec: Optional[int] = None, args: PropertyDict,
core: Optional[str] = None, gdb_timeout_sec: Optional[int] = None,
chip_rev: Optional[str] = None, core: Optional[str] = None,
save_core: Optional[str] = None) -> CoreDump: chip_rev: Optional[str] = None,
save_core: Optional[str] = None,
) -> CoreDump:
ensure_build_directory(args, ctx.info_name) ensure_build_directory(args, ctx.info_name)
project_desc = get_project_desc(args, ctx) project_desc = get_project_desc(args, ctx)
coredump_to_flash_config = get_sdkconfig_value(project_desc['config_file'], coredump_to_flash_config = get_sdkconfig_value(
'CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH') project_desc['config_file'], 'CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH'
)
coredump_to_flash = coredump_to_flash_config.rstrip().endswith('y') if coredump_to_flash_config else False coredump_to_flash = coredump_to_flash_config.rstrip().endswith('y') if coredump_to_flash_config else False
prog = os.path.join(project_desc['build_dir'], project_desc['app_elf']) prog = os.path.join(project_desc['build_dir'], project_desc['app_elf'])
@ -141,13 +144,16 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
# The format will be determined automatically # The format will be determined automatically
args.port = args.port or get_default_serial_port() args.port = args.port or get_default_serial_port()
else: else:
print('Path to core dump file is not provided. ' print(
"Core dump can't be read from flash since this option is not enabled in menuconfig") 'Path to core dump file is not provided. '
"Core dump can't be read from flash since this option is not enabled in menuconfig"
)
sys.exit(1) sys.exit(1)
espcoredump_kwargs['port'] = args.port espcoredump_kwargs['port'] = args.port
espcoredump_kwargs['parttable_off'] = get_sdkconfig_value(project_desc['config_file'], espcoredump_kwargs['parttable_off'] = get_sdkconfig_value(
'CONFIG_PARTITION_TABLE_OFFSET') project_desc['config_file'], 'CONFIG_PARTITION_TABLE_OFFSET'
)
if save_core: if save_core:
espcoredump_kwargs['save_core'] = save_core espcoredump_kwargs['save_core'] = save_core
@ -169,8 +175,10 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
def is_gdb_with_python(gdb: str) -> bool: def is_gdb_with_python(gdb: str) -> bool:
# execute simple python command to check is it supported # execute simple python command to check is it supported
return subprocess.run([gdb, '--batch-silent', '--ex', 'python import os'], return (
stderr=subprocess.DEVNULL).returncode == 0 subprocess.run([gdb, '--batch-silent', '--ex', 'python import os'], stderr=subprocess.DEVNULL).returncode
== 0
)
def debug_cleanup() -> None: def debug_cleanup() -> None:
print('cleaning up debug targets') print('cleaning up debug targets')
@ -182,7 +190,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
_terminate_async_target('gdb') _terminate_async_target('gdb')
def post_debug(action: str, ctx: Context, args: PropertyDict, **kwargs: str) -> None: def post_debug(action: str, ctx: Context, args: PropertyDict, **kwargs: str) -> None:
""" Deal with asynchronous targets, such as openocd running in background """ """Deal with asynchronous targets, such as openocd running in background"""
if kwargs['block'] == 1: if kwargs['block'] == 1:
for target in ['openocd', 'gdbgui']: for target in ['openocd', 'gdbgui']:
if target in processes and processes[target] is not None: if target in processes and processes[target] is not None:
@ -216,8 +224,9 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
project_desc = json.load(f) project_desc = json.load(f)
return project_desc return project_desc
def openocd(action: str, ctx: Context, args: PropertyDict, openocd_scripts: Optional[str], def openocd(
openocd_commands: str) -> None: action: str, ctx: Context, args: PropertyDict, openocd_scripts: Optional[str], openocd_commands: str
) -> None:
""" """
Execute openocd as external tool Execute openocd as external tool
""" """
@ -230,7 +239,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
openocd_arguments = project_desc.get('debug_arguments_openocd', '') openocd_arguments = project_desc.get('debug_arguments_openocd', '')
print( print(
'Note: OpenOCD cfg not found (via env variable OPENOCD_COMMANDS nor as a --openocd-commands argument)\n' 'Note: OpenOCD cfg not found (via env variable OPENOCD_COMMANDS nor as a --openocd-commands argument)\n'
'OpenOCD arguments default to: "{}"'.format(openocd_arguments)) 'OpenOCD arguments default to: "{}"'.format(openocd_arguments)
)
# script directory is taken from the environment by OpenOCD, update only if command line arguments to override # script directory is taken from the environment by OpenOCD, update only if command line arguments to override
if openocd_scripts is not None: if openocd_scripts is not None:
openocd_arguments += ' -s {}'.format(openocd_scripts) openocd_arguments += ' -s {}'.format(openocd_scripts)
@ -243,14 +253,17 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
except Exception as e: except Exception as e:
print(e) print(e)
raise FatalError( raise FatalError(
'Error starting openocd. Please make sure it is installed and is present in executable paths', ctx) 'Error starting openocd. Please make sure it is installed and is present in executable paths', ctx
)
processes['openocd'] = process processes['openocd'] = process
processes['openocd_outfile'] = openocd_out processes['openocd_outfile'] = openocd_out
processes['openocd_outfile_name'] = openocd_out_name processes['openocd_outfile_name'] = openocd_out_name
print('OpenOCD started as a background task {}'.format(process.pid)) print('OpenOCD started as a background task {}'.format(process.pid))
def get_gdb_args(project_desc: Dict[str, Any], gdb_x: Tuple, gdb_ex: Tuple, gdb_commands: Optional[str]) -> List[str]: def get_gdb_args(
project_desc: Dict[str, Any], gdb_x: Tuple, gdb_ex: Tuple, gdb_commands: Optional[str]
) -> List[str]:
# check if the application was built and ELF file is in place. # check if the application was built and ELF file is in place.
app_elf = os.path.join(project_desc.get('build_dir', ''), project_desc.get('app_elf', '')) app_elf = os.path.join(project_desc.get('build_dir', ''), project_desc.get('app_elf', ''))
if not os.path.exists(app_elf): if not os.path.exists(app_elf):
@ -260,13 +273,16 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
gdb_args = [gdb_name] gdb_args = [gdb_name]
gdbinit_files = project_desc.get('gdbinit_files') gdbinit_files = project_desc.get('gdbinit_files')
if not gdbinit_files: if not gdbinit_files:
raise FatalError('Please check if the project was configured correctly ("gdbinit_files" not found in "project_description.json").') raise FatalError(
'Please check if the project was configured correctly ("gdbinit_files" not found in '
'"project_description.json").'
)
gdbinit_files = sorted(gdbinit_files.items()) gdbinit_files = sorted(gdbinit_files.items())
gdb_x_list = list(gdb_x) gdb_x_list = list(gdb_x)
gdb_x_names = [os.path.basename(x) for x in gdb_x_list] gdb_x_names = [os.path.basename(x) for x in gdb_x_list]
# compile predefined gdbinit files options. # compile predefined gdbinit files options.
for name, path in gdbinit_files: for name, path in gdbinit_files:
name = name[len('xx_'):] name = name[len('xx_') :]
if name == 'py_extensions': if name == 'py_extensions':
if not is_gdb_with_python(gdb_name): if not is_gdb_with_python(gdb_name):
continue continue
@ -296,7 +312,9 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
def _get_gdbgui_version(ctx: Context) -> Tuple[int, ...]: def _get_gdbgui_version(ctx: Context) -> Tuple[int, ...]:
subprocess_success = False subprocess_success = False
try: try:
completed_process = subprocess.run(['gdbgui', '--version'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) completed_process = subprocess.run(
['gdbgui', '--version'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT
)
captured_output = completed_process.stdout.decode('utf-8', 'ignore') captured_output = completed_process.stdout.decode('utf-8', 'ignore')
subprocess_success = True subprocess_success = True
except FileNotFoundError: except FileNotFoundError:
@ -305,24 +323,39 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
if not subprocess_success or completed_process.returncode != 0: if not subprocess_success or completed_process.returncode != 0:
if sys.version_info[:2] >= (3, 11) and sys.platform == 'win32': if sys.version_info[:2] >= (3, 11) and sys.platform == 'win32':
raise SystemExit('Unfortunately, gdbgui is supported only with Python 3.10 or older. ' raise SystemExit(
'See: https://github.com/espressif/esp-idf/issues/10116. ' 'Unfortunately, gdbgui is supported only with Python 3.10 or older. '
'Please use "idf.py gdb" or debug in Eclipse/Vscode instead.') 'See: https://github.com/espressif/esp-idf/issues/10116. '
'Please use "idf.py gdb" or debug in Eclipse/Vscode instead.'
)
if sys.version_info[:2] >= (3, 13) and sys.platform != 'win32': if sys.version_info[:2] >= (3, 13) and sys.platform != 'win32':
raise SystemExit('Unfortunately, gdbgui is supported only with Python 3.12 or older. ' raise SystemExit(
'See: https://github.com/cs01/gdbgui/issues/494. ' 'Unfortunately, gdbgui is supported only with Python 3.12 or older. '
'Please use "idf.py gdb" or debug in Eclipse/Vscode instead.') 'See: https://github.com/cs01/gdbgui/issues/494. '
raise FatalError('Error starting gdbgui. Please make sure gdbgui has been installed with ' 'Please use "idf.py gdb" or debug in Eclipse/Vscode instead.'
'"install.{sh,bat,ps1,fish} --enable-gdbgui" and can be started. ' )
f'Error: {captured_output if subprocess_success else "Unknown"}', ctx) raise FatalError(
'Error starting gdbgui. Please make sure gdbgui has been installed with '
'"install.{sh,bat,ps1,fish} --enable-gdbgui" and can be started. '
f'Error: {captured_output if subprocess_success else "Unknown"}',
ctx,
)
v = re.search(r'(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?', captured_output) v = re.search(r'(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?', captured_output)
if not v: if not v:
raise SystemExit(f'Error: "gdbgui --version" returned "{captured_output}"') raise SystemExit(f'Error: "gdbgui --version" returned "{captured_output}"')
return tuple(int(i) if i else 0 for i in (v[1], v[2], v[3], v[4])) return tuple(int(i) if i else 0 for i in (v[1], v[2], v[3], v[4]))
def gdbui(action: str, ctx: Context, args: PropertyDict, gdbgui_port: Optional[str], gdbinit: Tuple, def gdbui(
ex: Tuple, gdb_commands: Optional[str], require_openocd: bool) -> None: action: str,
ctx: Context,
args: PropertyDict,
gdbgui_port: Optional[str],
gdbinit: Tuple,
ex: Tuple,
gdb_commands: Optional[str],
require_openocd: bool,
) -> None:
""" """
Asynchronous GDB-UI target Asynchronous GDB-UI target
""" """
@ -344,7 +377,9 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
# so for one item, use extra double quotes. for more items, use no extra double quotes. # so for one item, use extra double quotes. for more items, use no extra double quotes.
gdb = gdb_args[0] gdb = gdb_args[0]
gdb_args_list = gdb_args[1:] gdb_args_list = gdb_args[1:]
gdb_args_str = '"{}"'.format(' '.join(gdb_args_list)) if len(gdb_args_list) == 1 else ' '.join(gdb_args_list) gdb_args_str = (
'"{}"'.format(' '.join(gdb_args_list)) if len(gdb_args_list) == 1 else ' '.join(gdb_args_list)
)
gdbgui_args = ['gdbgui', '-g', gdb, '--gdb-args', gdb_args_str] gdbgui_args = ['gdbgui', '-g', gdb, '--gdb-args', gdb_args_str]
if gdbgui_port is not None: if gdbgui_port is not None:
@ -396,18 +431,42 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
if task.name in ('gdb', 'gdbgui', 'gdbtui'): if task.name in ('gdb', 'gdbgui', 'gdbtui'):
task.action_args['require_openocd'] = True task.action_args['require_openocd'] = True
def gdbtui(action: str, ctx: Context, args: PropertyDict, gdbinit: Tuple, ex: Tuple, gdb_commands: str, require_openocd: bool) -> None: def gdbtui(
action: str,
ctx: Context,
args: PropertyDict,
gdbinit: Tuple,
ex: Tuple,
gdb_commands: str,
require_openocd: bool,
) -> None:
""" """
Synchronous GDB target with text ui mode Synchronous GDB target with text ui mode
""" """
gdb(action, ctx, args, False, 1, gdbinit, ex, gdb_commands, require_openocd) gdb(action, ctx, args, False, 1, gdbinit, ex, gdb_commands, require_openocd)
def gdb(action: str, ctx: Context, args: PropertyDict, batch: bool, gdb_tui: Optional[int], gdbinit: Tuple, def gdb(
ex: Tuple, gdb_commands: Optional[str], require_openocd: bool) -> None: action: str,
ctx: Context,
args: PropertyDict,
batch: bool,
gdb_tui: Optional[int],
gdbinit: Tuple,
ex: Tuple,
gdb_commands: Optional[str],
require_openocd: bool,
) -> None:
""" """
Synchronous GDB target Synchronous GDB target
""" """
watch_openocd = Thread(target=_check_openocd_errors, args=(fail_if_openocd_failed, action, ctx,)) watch_openocd = Thread(
target=_check_openocd_errors,
args=(
fail_if_openocd_failed,
action,
ctx,
),
)
watch_openocd.start() watch_openocd.start()
processes['threads_to_join'].append(watch_openocd) processes['threads_to_join'].append(watch_openocd)
project_desc = get_project_desc(args, ctx) project_desc = get_project_desc(args, ctx)
@ -433,25 +492,29 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
# Valid scenario: watch_openocd task won't be in the list if openocd not started from idf.py # Valid scenario: watch_openocd task won't be in the list if openocd not started from idf.py
pass pass
def coredump_info(action: str, def coredump_info(
ctx: Context, action: str,
args: PropertyDict, ctx: Context,
gdb_timeout_sec: int, args: PropertyDict,
core: Optional[str] = None, gdb_timeout_sec: int,
chip_rev: Optional[str] = None, core: Optional[str] = None,
save_core: Optional[str] = None) -> None: chip_rev: Optional[str] = None,
espcoredump = _get_espcoredump_instance(ctx=ctx, args=args, gdb_timeout_sec=gdb_timeout_sec, core=core, save_core: Optional[str] = None,
chip_rev=chip_rev, ) -> None:
save_core=save_core) espcoredump = _get_espcoredump_instance(
ctx=ctx, args=args, gdb_timeout_sec=gdb_timeout_sec, core=core, chip_rev=chip_rev, save_core=save_core
)
espcoredump.info_corefile() espcoredump.info_corefile()
def coredump_debug(action: str, def coredump_debug(
ctx: Context, action: str,
args: PropertyDict, ctx: Context,
core: Optional[str] = None, args: PropertyDict,
chip_rev: Optional[str] = None, core: Optional[str] = None,
save_core: Optional[str] = None) -> None: chip_rev: Optional[str] = None,
save_core: Optional[str] = None,
) -> None:
espcoredump = _get_espcoredump_instance(ctx=ctx, args=args, core=core, chip_rev=chip_rev, save_core=save_core) espcoredump = _get_espcoredump_instance(ctx=ctx, args=args, core=core, chip_rev=chip_rev, save_core=save_core)
espcoredump.dbg_corefile() espcoredump.dbg_corefile()
@ -464,8 +527,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
{ {
'names': ['--chip-rev'], 'names': ['--chip-rev'],
'help': 'Specify the chip revision (e.g., 0.1). If provided, the corresponding ROM ELF file will be used ' 'help': 'Specify the chip revision (e.g., 0.1). If provided, the corresponding ROM ELF file will be used '
'for decoding the core dump, improving stack traces. This is only needed for core dumps from ' 'for decoding the core dump, improving stack traces. This is only needed for core dumps from '
'ESP-IDF older than v5.2. Newer versions already contain chip revision information.', 'ESP-IDF older than v5.2. Newer versions already contain chip revision information.',
'hidden': True, 'hidden': True,
}, },
{ {
@ -493,15 +556,13 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
} }
ex = { ex = {
'names': ['--ex', '-ex'], 'names': ['--ex', '-ex'],
'help': 'help': ('Execute given GDB command.\n'),
('Execute given GDB command.\n'),
'default': None, 'default': None,
'multiple': True, 'multiple': True,
} }
gdb_commands = { gdb_commands = {
'names': ['--gdb-commands', '--gdb_commands'], 'names': ['--gdb-commands', '--gdb_commands'],
'help': 'help': ('Command line arguments for gdb.\n'),
('Command line arguments for gdb.\n'),
'default': None, 'default': None,
} }
debug_actions = { debug_actions = {
@ -513,17 +574,14 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
'options': [ 'options': [
{ {
'names': ['--openocd-scripts', '--openocd_scripts'], 'names': ['--openocd-scripts', '--openocd_scripts'],
'help': 'help': ('Script directory for openocd cfg files.\n'),
('Script directory for openocd cfg files.\n'), 'default': None,
'default':
None,
}, },
{ {
'names': ['--openocd-commands', '--openocd_commands'], 'names': ['--openocd-commands', '--openocd_commands'],
'help': 'help': ('Command line arguments for openocd.\n'),
('Command line arguments for openocd.\n'),
'default': None, 'default': None,
} },
], ],
'order_dependencies': ['all', 'flash'], 'order_dependencies': ['all', 'flash'],
}, },
@ -542,7 +600,11 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
'names': ['--gdb-tui', '--gdb_tui'], 'names': ['--gdb-tui', '--gdb_tui'],
'help': ('run gdb in TUI mode\n'), 'help': ('run gdb in TUI mode\n'),
'default': None, 'default': None,
}, gdbinit, ex, gdb_commands, fail_if_openocd_failed },
gdbinit,
ex,
gdb_commands,
fail_if_openocd_failed,
], ],
'order_dependencies': ['all', 'flash'], 'order_dependencies': ['all', 'flash'],
}, },
@ -552,11 +614,13 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
'options': [ 'options': [
{ {
'names': ['--gdbgui-port', '--gdbgui_port'], 'names': ['--gdbgui-port', '--gdbgui_port'],
'help': 'help': ('The port on which gdbgui will be hosted. Default: 5000\n'),
('The port on which gdbgui will be hosted. Default: 5000\n'), 'default': None,
'default': },
None, gdbinit,
}, gdbinit, ex, gdb_commands, fail_if_openocd_failed ex,
gdb_commands,
fail_if_openocd_failed,
], ],
'order_dependencies': ['all', 'flash'], 'order_dependencies': ['all', 'flash'],
}, },
@ -569,7 +633,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
'coredump-info': { 'coredump-info': {
'callback': coredump_info, 'callback': coredump_info,
'help': 'Print crashed tasks registers, callstack, list of available tasks in the system, ' 'help': 'Print crashed tasks registers, callstack, list of available tasks in the system, '
'memory regions and contents of memory stored in core dump (TCBs and stacks)', 'memory regions and contents of memory stored in core dump (TCBs and stacks)',
'options': coredump_base + [PORT, BAUD_RATE, gdb_timeout_sec_opt], # type: ignore 'options': coredump_base + [PORT, BAUD_RATE, gdb_timeout_sec_opt], # type: ignore
'order_dependencies': ['all', 'flash'], 'order_dependencies': ['all', 'flash'],
}, },
@ -585,8 +649,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
'options': [ 'options': [
{ {
'names': ['--block', '--block'], 'names': ['--block', '--block'],
'help': 'help': ('Set to 1 for blocking the console on the outputs of async debug actions\n'),
('Set to 1 for blocking the console on the outputs of async debug actions\n'),
'default': 0, 'default': 0,
}, },
], ],
@ -605,8 +668,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
'options': [ 'options': [
{ {
'names': ['--block', '--block'], 'names': ['--block', '--block'],
'help': 'help': ('Set to 1 for blocking the console on the outputs of async debug actions\n'),
('Set to 1 for blocking the console on the outputs of async debug actions\n'),
'default': 0, 'default': 0,
}, },
], ],