From d3ffbcb8a5a5ab0343b5147cd972f0baec863645 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Tue, 3 Dec 2024 05:34:43 +0100 Subject: [PATCH 1/2] test(system): mark gdb test runners properly --- tools/test_apps/system/.build-test-rules.yml | 6 + tools/test_apps/system/gdb/pytest_gdb.py | 112 ++++++++++++++----- 2 files changed, 92 insertions(+), 26 deletions(-) diff --git a/tools/test_apps/system/.build-test-rules.yml b/tools/test_apps/system/.build-test-rules.yml index 04c5748599..33b559db90 100644 --- a/tools/test_apps/system/.build-test-rules.yml +++ b/tools/test_apps/system/.build-test-rules.yml @@ -36,6 +36,12 @@ tools/test_apps/system/g0_components: tools/test_apps/system/g1_components: +tools/test_apps/system/gdb: + disable_test: + - if: IDF_TARGET in ["esp32s3", "esp32c2", "esp32c3", "esp32c5", "esp32c61", "esp32p4"] + temporary: true + reason: lack of runners + tools/test_apps/system/gdb_loadable_elf: disable_test: - if: IDF_TARGET != "esp32" diff --git a/tools/test_apps/system/gdb/pytest_gdb.py b/tools/test_apps/system/gdb/pytest_gdb.py index dbac6c8c70..f43bb74556 100644 --- a/tools/test_apps/system/gdb/pytest_gdb.py +++ b/tools/test_apps/system/gdb/pytest_gdb.py @@ -5,15 +5,69 @@ import logging import os import re import subprocess +import time +from subprocess import Popen +from typing import Optional import pexpect import pytest from pytest_embedded_idf import IdfDut -@pytest.mark.supported_targets -@pytest.mark.jtag -def test_idf_gdb(dut: IdfDut) -> None: +MAX_RETRIES = 3 +RETRY_DELAY = 3 # seconds + + +def run_openocd(dut: IdfDut) -> Optional[Popen]: + + desc_path = os.path.join(dut.app.binary_path, 'project_description.json') + try: + with open(desc_path, 'r') as f: + project_desc = json.load(f) + except FileNotFoundError: + logging.error('Project description file not found at %s', desc_path) + return None + + openocd_scripts = os.getenv('OPENOCD_SCRIPTS') + if not openocd_scripts: + logging.error('OPENOCD_SCRIPTS environment variable is not set.') + return None + + debug_args = project_desc.get('debug_arguments_openocd') + if not debug_args: + logging.error("'debug_arguments_openocd' key is missing in project_description.json") + return None + + cmd = ['openocd'] + ['-s', openocd_scripts] + debug_args.split() + + # For debug purpose, make the value '4' + ocd_env = os.environ.copy() + ocd_env['LIBUSB_DEBUG'] = '1' + + for attempt in range(1, MAX_RETRIES + 1): + logging.info('Attempt %d: Running %s', attempt, cmd) + with open(os.path.join(dut.logdir, 'ocd.txt'), 'w') as ocd_log: + try: + ocd = subprocess.Popen(cmd, stdout=ocd_log, stderr=ocd_log, env=ocd_env) + time.sleep(1) + + # Check if the process is running successfully + if ocd.poll() is None: + return ocd + else: + logging.error('OpenOCD exited with error code %d', ocd.returncode) + except subprocess.SubprocessError as e: + logging.error('Error running OpenOCD: %s', e) + + logging.warning("OpenOCD couldn't be run. Retrying in %d seconds...", RETRY_DELAY) + time.sleep(RETRY_DELAY) + + logging.error('Failed to run OpenOCD after %d attempts.', MAX_RETRIES) + + return None + + +def _test_idf_gdb(dut: IdfDut) -> None: # Need to wait a moment to connect via OpenOCD after the hard reset happened. # Along with this check that app runs ok dut.expect('Hello world!') @@ -21,29 +75,35 @@ def test_idf_gdb(dut: IdfDut) -> None: # Don't need to have output from UART anymore dut.serial.stop_redirect_thread() - desc_path = os.path.join(dut.app.binary_path, 'project_description.json') - with open(desc_path, 'r') as f: - project_desc = json.load(f) + ocd = run_openocd(dut) + assert ocd - with open(os.path.join(dut.logdir, 'ocd.txt'), 'w') as ocd_log: - cmd = ['openocd'] + project_desc['debug_arguments_openocd'].split() - openocd_scripts = os.getenv('OPENOCD_SCRIPTS') - if openocd_scripts: - cmd.extend(['-s', openocd_scripts]) - - logging.info('Running %s', cmd) - ocd = subprocess.Popen(cmd, stdout=ocd_log, stderr=ocd_log) - - try: - with open(os.path.join(dut.logdir, 'gdb.txt'), 'w') as gdb_log, \ - pexpect.spawn(f'idf.py -B {dut.app.binary_path} gdb --batch', - timeout=60, - logfile=gdb_log, - encoding='utf-8', - codec_errors='ignore') as p: - p.expect(re.compile(r'add symbol table from file.*bootloader.elf')) - p.expect(re.compile(r'add symbol table from file.*rom.elf')) # if fail here: add target support here https://github.com/espressif/esp-rom-elfs - p.expect_exact('hit Temporary breakpoint 1, app_main ()') - finally: + try: + with open(os.path.join(dut.logdir, 'gdb.txt'), 'w') as gdb_log, \ + pexpect.spawn(f'idf.py -B {dut.app.binary_path} gdb --batch', + timeout=60, + logfile=gdb_log, + encoding='utf-8', + codec_errors='ignore') as p: + p.expect(re.compile(r'add symbol table from file.*bootloader.elf')) + p.expect(re.compile(r'add symbol table from file.*rom.elf')) # if fail here: add target support here https://github.com/espressif/esp-rom-elfs + p.expect_exact('hit Temporary breakpoint 1, app_main ()') + finally: + # Check if the process is still running + if ocd.poll() is None: ocd.terminate() ocd.kill() + + +@pytest.mark.esp32 +@pytest.mark.esp32s2 +@pytest.mark.jtag +def test_idf_gdb(dut: IdfDut) -> None: + _test_idf_gdb(dut) + + +@pytest.mark.esp32c6 +@pytest.mark.esp32h2 +@pytest.mark.usb_serial_jtag +def test_idf_gdb_usj(dut: IdfDut) -> None: + _test_idf_gdb(dut) From d195bc67cf1fc36c7fbb236ed7468969060e0871 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Wed, 4 Dec 2024 22:09:33 +0100 Subject: [PATCH 2/2] change(cmake): use board configuration file for ftdi interface --- tools/cmake/openocd.cmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/cmake/openocd.cmake b/tools/cmake/openocd.cmake index a1bd546bc1..b67cb06e39 100644 --- a/tools/cmake/openocd.cmake +++ b/tools/cmake/openocd.cmake @@ -8,7 +8,6 @@ function(__get_openocd_options openocd_option_var) elseif(CONFIG_SOC_USB_SERIAL_JTAG_SUPPORTED) set(${openocd_option_var} "-f board/${CONFIG_IDF_TARGET}-builtin.cfg" PARENT_SCOPE) else() - set(${openocd_option_var} - "-f interface/ftdi/esp32_devkitj_v1.cfg -f target/${CONFIG_IDF_TARGET}.cfg" PARENT_SCOPE) + set(${openocd_option_var} "-f board/${CONFIG_IDF_TARGET}-ftdi.cfg" PARENT_SCOPE) endif() endfunction()