Merge branch 'fix/test_idf_gdb_v5.4' into 'release/v5.4'

test(system): mark gdb test runners properly (v5.4)

See merge request espressif/esp-idf!35586
This commit is contained in:
Roland Dobai
2025-01-10 18:15:32 +08:00
3 changed files with 93 additions and 29 deletions

View File

@ -8,7 +8,6 @@ function(__get_openocd_options openocd_option_var)
elseif(CONFIG_SOC_USB_SERIAL_JTAG_SUPPORTED) elseif(CONFIG_SOC_USB_SERIAL_JTAG_SUPPORTED)
set(${openocd_option_var} "-f board/${CONFIG_IDF_TARGET}-builtin.cfg" PARENT_SCOPE) set(${openocd_option_var} "-f board/${CONFIG_IDF_TARGET}-builtin.cfg" PARENT_SCOPE)
else() else()
set(${openocd_option_var} set(${openocd_option_var} "-f board/${CONFIG_IDF_TARGET}-ftdi.cfg" PARENT_SCOPE)
"-f interface/ftdi/esp32_devkitj_v1.cfg -f target/${CONFIG_IDF_TARGET}.cfg" PARENT_SCOPE)
endif() endif()
endfunction() endfunction()

View File

@ -36,6 +36,12 @@ tools/test_apps/system/g0_components:
tools/test_apps/system/g1_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: tools/test_apps/system/gdb_loadable_elf:
disable_test: disable_test:
- if: IDF_TARGET != "esp32" - if: IDF_TARGET != "esp32"

View File

@ -1,19 +1,72 @@
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0 # SPDX-License-Identifier: Unlicense OR CC0-1.0
import json import json
import logging import logging
import os import os
import re import re
import subprocess import subprocess
import time
from subprocess import Popen
from typing import Optional
import pexpect import pexpect
import pytest import pytest
from pytest_embedded_idf import IdfDut from pytest_embedded_idf import IdfDut
MAX_RETRIES = 3
RETRY_DELAY = 3 # seconds
@pytest.mark.supported_targets
@pytest.mark.jtag def run_openocd(dut: IdfDut) -> Optional[Popen]:
def test_idf_gdb(dut: IdfDut) -> None:
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. # Need to wait a moment to connect via OpenOCD after the hard reset happened.
# Along with this check that app runs ok # Along with this check that app runs ok
dut.expect('Hello world!') dut.expect('Hello world!')
@ -21,29 +74,35 @@ def test_idf_gdb(dut: IdfDut) -> None:
# Don't need to have output from UART anymore # Don't need to have output from UART anymore
dut.serial.stop_redirect_thread() dut.serial.stop_redirect_thread()
desc_path = os.path.join(dut.app.binary_path, 'project_description.json') ocd = run_openocd(dut)
with open(desc_path, 'r') as f: assert ocd
project_desc = json.load(f)
with open(os.path.join(dut.logdir, 'ocd.txt'), 'w') as ocd_log: try:
cmd = ['openocd'] + project_desc['debug_arguments_openocd'].split() with open(os.path.join(dut.logdir, 'gdb.txt'), 'w') as gdb_log, \
openocd_scripts = os.getenv('OPENOCD_SCRIPTS') pexpect.spawn(f'idf.py -B {dut.app.binary_path} gdb --batch',
if openocd_scripts: timeout=60,
cmd.extend(['-s', openocd_scripts]) logfile=gdb_log,
encoding='utf-8',
logging.info('Running %s', cmd) codec_errors='ignore') as p:
ocd = subprocess.Popen(cmd, stdout=ocd_log, stderr=ocd_log) 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
try: p.expect_exact('hit Temporary breakpoint 1, app_main ()')
with open(os.path.join(dut.logdir, 'gdb.txt'), 'w') as gdb_log, \ finally:
pexpect.spawn(f'idf.py -B {dut.app.binary_path} gdb --batch', # Check if the process is still running
timeout=60, if ocd.poll() is None:
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:
ocd.terminate() ocd.terminate()
ocd.kill() 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)