From 75613678086a90a518d7260e37a7c2dfa16fd1bb Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Thu, 8 Sep 2022 00:45:04 +0400 Subject: [PATCH] tools: add test for ROM symbols in GDB --- .gitlab/ci/build.yml | 1 + tools/idf_py_actions/constants.py | 8 +++ tools/idf_py_actions/debug_ext.py | 34 +++++++----- tools/test_apps/system/gdb/CMakeLists.txt | 6 +++ tools/test_apps/system/gdb/README.md | 6 +++ .../test_apps/system/gdb/main/CMakeLists.txt | 3 ++ .../system/gdb/main/hello_world_main.c | 46 ++++++++++++++++ tools/test_apps/system/gdb/pytest_gdb.py | 53 +++++++++++++++++++ 8 files changed, 143 insertions(+), 14 deletions(-) create mode 100644 tools/test_apps/system/gdb/CMakeLists.txt create mode 100644 tools/test_apps/system/gdb/README.md create mode 100644 tools/test_apps/system/gdb/main/CMakeLists.txt create mode 100644 tools/test_apps/system/gdb/main/hello_world_main.c create mode 100644 tools/test_apps/system/gdb/pytest_gdb.py diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 80b3ae9feced..db483fc73c97 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -31,6 +31,7 @@ - "**/build*/flash_project_args" - "**/build*/config/sdkconfig.json" - "**/build*/bootloader/*.bin" + - "**/build*/bootloader/*.elf" - "**/build*/partition_table/*.bin" - $SIZE_INFO_LOCATION when: always diff --git a/tools/idf_py_actions/constants.py b/tools/idf_py_actions/constants.py index 18ae271592a4..f225534da896 100644 --- a/tools/idf_py_actions/constants.py +++ b/tools/idf_py_actions/constants.py @@ -34,3 +34,11 @@ SUPPORTED_TARGETS = ['esp32', 'esp32s2', 'esp32c3', 'esp32s3', 'esp32c2'] PREVIEW_TARGETS = ['linux', 'esp32h2'] + +OPENOCD_TAGET_CONFIG_DEFAULT = '-f interface/ftdi/esp32_devkitj_v1.cfg -f target/{target}.cfg' +OPENOCD_TAGET_CONFIG: Dict[str, str] = { + 'esp32': '-f board/esp32-wrover-kit-3.3v.cfg', + 'esp32s2': '-f board/esp32s2-kaluga-1.cfg', + 'esp32c3': '-f board/esp32c3-builtin.cfg', + 'esp32s3': '-f board/esp32s3-builtin.cfg', +} diff --git a/tools/idf_py_actions/debug_ext.py b/tools/idf_py_actions/debug_ext.py index 734b19fa16b1..313adb18db25 100644 --- a/tools/idf_py_actions/debug_ext.py +++ b/tools/idf_py_actions/debug_ext.py @@ -14,6 +14,7 @@ from typing import Any, Dict, List, Optional from click.core import Context +from idf_py_actions.constants import OPENOCD_TAGET_CONFIG, OPENOCD_TAGET_CONFIG_DEFAULT from idf_py_actions.errors import FatalError from idf_py_actions.tools import PropertyDict, ensure_build_directory @@ -59,6 +60,11 @@ ''' +def get_openocd_arguments(target: str) -> str: + default_args = OPENOCD_TAGET_CONFIG_DEFAULT.format(target=target) + return str(OPENOCD_TAGET_CONFIG.get(target, default_args)) + + def action_extensions(base_actions: Dict, project_path: str) -> Dict: OPENOCD_OUT_FILE = 'openocd_out.txt' GDBGUI_OUT_FILE = 'gdbgui_out.txt' @@ -286,12 +292,6 @@ def openocd(action: str, ctx: Context, args: PropertyDict, openocd_scripts: Opti """ Execute openocd as external tool """ - OPENOCD_TAGET_CONFIG = { - 'esp32': '-f board/esp32-wrover-kit-3.3v.cfg', - 'esp32s2': '-f board/esp32s2-kaluga-1.cfg', - 'esp32c3': '-f board/esp32c3-builtin.cfg', - 'esp32s3': '-f board/esp32s3-builtin.cfg', - } if os.getenv('OPENOCD_SCRIPTS') is None: raise FatalError('OPENOCD_SCRIPTS not found in the environment: Please run export.sh/export.bat', ctx) openocd_arguments = os.getenv('OPENOCD_COMMANDS') if openocd_commands is None else openocd_commands @@ -299,8 +299,7 @@ def openocd(action: str, ctx: Context, args: PropertyDict, openocd_scripts: Opti if openocd_arguments is None: # use default value if commands not defined in the environment nor command line target = project_desc['target'] - default_args = '-f interface/ftdi/esp32_devkitj_v1.cfg -f target/{}.cfg'.format(target) - openocd_arguments = OPENOCD_TAGET_CONFIG.get(target, default_args) + openocd_arguments = get_openocd_arguments(target) print('Note: OpenOCD cfg not found (via env variable OPENOCD_COMMANDS nor as a --openocd-commands argument)\n' 'OpenOCD arguments default to: "{}"'.format(openocd_arguments)) # script directory is taken from the environment by OpenOCD, update only if command line arguments to override @@ -405,9 +404,9 @@ def gdbtui(action: str, ctx: Context, args: PropertyDict, gdbinit: str, require_ """ Synchronous GDB target with text ui mode """ - gdb(action, ctx, args, 1, gdbinit, require_openocd) + gdb(action, ctx, args, False, 1, gdbinit, require_openocd) - def gdb(action: str, ctx: Context, args: PropertyDict, gdb_tui: Optional[int], gdbinit: Optional[str], require_openocd: bool) -> None: + def gdb(action: str, ctx: Context, args: PropertyDict, batch: bool, gdb_tui: Optional[int], gdbinit: Optional[str], require_openocd: bool) -> None: """ Synchronous GDB target """ @@ -420,6 +419,8 @@ def gdb(action: str, ctx: Context, args: PropertyDict, gdb_tui: Optional[int], g args = [gdb, *get_gdb_args(project_desc)] if gdb_tui is not None: args += ['-tui'] + if batch: + args += ['--batch'] t = Thread(target=run_gdb, args=(args,)) t.start() while True: @@ -476,12 +477,17 @@ def gdb(action: str, ctx: Context, args: PropertyDict, gdb_tui: Optional[int], g 'callback': gdb, 'help': 'Run the GDB.', 'options': [ + { + 'names': ['--batch'], + 'help': ('exit after processing gdbinit.\n'), + 'hidden': True, + 'is_flag': True, + 'default': False, + }, { 'names': ['--gdb-tui', '--gdb_tui'], - 'help': - ('run gdb in TUI mode\n'), - 'default': - None, + 'help': ('run gdb in TUI mode\n'), + 'default': None, }, gdbinit, fail_if_openocd_failed ], 'order_dependencies': ['all', 'flash'], diff --git a/tools/test_apps/system/gdb/CMakeLists.txt b/tools/test_apps/system/gdb/CMakeLists.txt new file mode 100644 index 000000000000..1c0bd7090373 --- /dev/null +++ b/tools/test_apps/system/gdb/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(gdb) diff --git a/tools/test_apps/system/gdb/README.md b/tools/test_apps/system/gdb/README.md new file mode 100644 index 000000000000..0b4b22e8c3a8 --- /dev/null +++ b/tools/test_apps/system/gdb/README.md @@ -0,0 +1,6 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | + +# IDF GDB test application + +This project tests if `idf.py gdb` works correct diff --git a/tools/test_apps/system/gdb/main/CMakeLists.txt b/tools/test_apps/system/gdb/main/CMakeLists.txt new file mode 100644 index 000000000000..69def7bc1d88 --- /dev/null +++ b/tools/test_apps/system/gdb/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "hello_world_main.c" + INCLUDE_DIRS "") +target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/tools/test_apps/system/gdb/main/hello_world_main.c b/tools/test_apps/system/gdb/main/hello_world_main.c new file mode 100644 index 000000000000..915866a4c2d6 --- /dev/null +++ b/tools/test_apps/system/gdb/main/hello_world_main.c @@ -0,0 +1,46 @@ +/* + * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ + +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_chip_info.h" +#include "esp_flash.h" + +void app_main(void) +{ + printf("Hello world!\n"); + + /* Print chip information */ + esp_chip_info_t chip_info; + uint32_t flash_size; + esp_chip_info(&chip_info); + printf("This is %s chip with %d CPU core(s), WiFi%s%s, ", + CONFIG_IDF_TARGET, + chip_info.cores, + (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "", + (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : ""); + + printf("silicon revision %d, ", chip_info.revision); + if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) { + printf("Get flash size failed"); + return; + } + + printf("%uMB %s flash\n", flash_size / (1024 * 1024), + (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external"); + + printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size()); + + for (int i = 10; i >= 0; i--) { + printf("Restarting in %d seconds...\n", i); + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + printf("Restarting now.\n"); + fflush(stdout); + esp_restart(); +} diff --git a/tools/test_apps/system/gdb/pytest_gdb.py b/tools/test_apps/system/gdb/pytest_gdb.py new file mode 100644 index 000000000000..0bb16d8e8151 --- /dev/null +++ b/tools/test_apps/system/gdb/pytest_gdb.py @@ -0,0 +1,53 @@ +# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import os +import re +import signal +import subprocess +import sys + +import pexpect +import pytest +from pytest_embedded import Dut + +try: + from idf_py_actions.debug_ext import get_openocd_arguments +except ModuleNotFoundError: + sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..')) + from idf_py_actions.debug_ext import get_openocd_arguments + + +@pytest.mark.supported_targets +@pytest.mark.test_jtag_arm +def test_idf_gdb(dut: Dut) -> 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!') + + # Don't need to have output from UART any more + dut.serial.stop_redirect_thread() + + with open(os.path.join(dut.logdir, 'ocd.log'), 'w') as ocd_log: + ocd = subprocess.Popen(f'openocd {get_openocd_arguments(dut.target)}', stdout=ocd_log, stderr=ocd_log, shell=True) + + try: + gdb_env = os.environ.copy() + gdb_env['ESP_IDF_GDB_TESTING'] = '1' + + with open(os.path.join(dut.logdir, 'gdb.log'), 'w') as gdb_log, \ + pexpect.spawn(f'idf.py -B {dut.app.binary_path} gdb --batch', + env=gdb_env, + 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')) + p.expect_exact('hit Temporary breakpoint 1, app_main ()') + finally: + try: + ocd.send_signal(signal.SIGINT) + ocd.communicate(timeout=15) + except subprocess.TimeoutExpired: + ocd.kill() + ocd.communicate()