diff --git a/components/espcoredump/test_apps/README.md b/components/espcoredump/test_apps/README.md index b4c0aa7c509..cffd17e11b8 100644 --- a/components/espcoredump/test_apps/README.md +++ b/components/espcoredump/test_apps/README.md @@ -7,7 +7,7 @@ The unit tests are currently run only on the chips listed above just to save CI When adding new test cases, check if the `depends_components` list in `.build-test-rules.yml` needs to be updated to include additional components. The test app will only be built and tested when these components are modified. -See also the [panic test app](../../../tools/test_apps/system/panic) which serves as an integration test for espcoredump and is run on all supported chips. +See also the [panic coredump test app](../../../tools/test_apps/system/panic/coredump) which serves as an integration test for espcoredump and is run on all supported chips. To build and run this test app, using esp32c3 target for example: diff --git a/docs/en/contribute/esp-idf-tests-with-pytest.rst b/docs/en/contribute/esp-idf-tests-with-pytest.rst index 6213b84384a..562fae9df58 100644 --- a/docs/en/contribute/esp-idf-tests-with-pytest.rst +++ b/docs/en/contribute/esp-idf-tests-with-pytest.rst @@ -688,7 +688,7 @@ Usually, you may want to write a custom class under these conditions: 1. Add more reusable functions for a certain number of DUTs. 2. Add custom setup and teardown functions -This code example is taken from :idf_file:`panic/conftest.py `. +This code example is taken from :idf_file:`panic/panic_base/conftest.py `. .. code-block:: python @@ -735,7 +735,7 @@ Sometimes, a test can consistently fail for the following reasons: Now you may mark this test case with marker `xfail `__ with a user-friendly readable reason. -This code example is taken from :idf_file:`pytest_panic.py ` +This code example is taken from :idf_file:`pytest_panic.py ` .. code-block:: python diff --git a/docs/zh_CN/contribute/esp-idf-tests-with-pytest.rst b/docs/zh_CN/contribute/esp-idf-tests-with-pytest.rst index 957ea8906c1..9b5a455c635 100644 --- a/docs/zh_CN/contribute/esp-idf-tests-with-pytest.rst +++ b/docs/zh_CN/contribute/esp-idf-tests-with-pytest.rst @@ -688,7 +688,7 @@ Pytest 使用技巧 1. 向一定数量的 DUT 添加更多可复用功能。 2. 为不同阶段添加自定义的前置和后置函数。 -以下代码示例来自 :idf_file:`panic/conftest.py `。 +以下代码示例来自 :idf_file:`panic/panic_base/conftest.py `。 .. code-block:: python @@ -735,7 +735,7 @@ Pytest 使用技巧 可使用 `xfail `__ marker 来标记此测试用例,并写出原因。 -以下代码来自 :idf_file:`pytest_panic.py `。 +以下代码来自 :idf_file:`pytest_panic.py `。 .. code-block:: python diff --git a/tools/test_apps/system/.build-test-rules.yml b/tools/test_apps/system/.build-test-rules.yml index 4e7c8a685f1..94ab300d305 100644 --- a/tools/test_apps/system/.build-test-rules.yml +++ b/tools/test_apps/system/.build-test-rules.yml @@ -141,7 +141,14 @@ tools/test_apps/system/no_embedded_paths: temporary: true reason: the other targets are not tested yet -tools/test_apps/system/panic: +tools/test_apps/system/panic/coredump: + enable: + - if: IDF_TARGET in ["esp32", "esp32c2", "esp32c3", "esp32c5", "esp32c6", "esp32c61", "esp32h2", "esp32p4", "esp32s2", "esp32s3", "esp32s31"] + depends_components: + - espcoredump + - esp_system + +tools/test_apps/system/panic/panic_base: enable: - if: INCLUDE_DEFAULT == 1 or IDF_TARGET in ["esp32s31", "esp32h4"] diff --git a/tools/test_apps/system/gdbstub_runtime/conftest.py b/tools/test_apps/system/gdbstub_runtime/conftest.py index 986d24ae124..7ce415f9a1f 100644 --- a/tools/test_apps/system/gdbstub_runtime/conftest.py +++ b/tools/test_apps/system/gdbstub_runtime/conftest.py @@ -10,7 +10,7 @@ import pytest from _pytest.fixtures import FixtureRequest from _pytest.monkeypatch import MonkeyPatch -sys.path.append(os.path.expandvars(os.path.join('$IDF_PATH', 'tools', 'test_apps', 'system', 'panic'))) +sys.path.append(os.path.normpath(os.path.join(os.path.dirname(__file__), '..', 'panic', 'panic_base'))) from test_panic_util import PanicTestDut # noqa: E402 diff --git a/tools/test_apps/system/gdbstub_runtime/pytest_gdbstub_runtime.py b/tools/test_apps/system/gdbstub_runtime/pytest_gdbstub_runtime.py index 75d84b7cb12..dd5e22b26f8 100644 --- a/tools/test_apps/system/gdbstub_runtime/pytest_gdbstub_runtime.py +++ b/tools/test_apps/system/gdbstub_runtime/pytest_gdbstub_runtime.py @@ -9,7 +9,7 @@ from typing import Any import pytest from pytest_embedded_idf.utils import idf_parametrize -sys.path.append(path.expandvars(path.join('$IDF_PATH', 'tools', 'test_apps', 'system', 'panic'))) +sys.path.append(path.normpath(path.join(path.dirname(__file__), '..', 'panic', 'panic_base'))) from test_panic_util import PanicTestDut # noqa: E402 diff --git a/tools/test_apps/system/panic/main/CMakeLists.txt b/tools/test_apps/system/panic/common/main/CMakeLists.txt similarity index 79% rename from tools/test_apps/system/panic/main/CMakeLists.txt rename to tools/test_apps/system/panic/common/main/CMakeLists.txt index 57c2d3b3493..38e5c720e33 100644 --- a/tools/test_apps/system/panic/main/CMakeLists.txt +++ b/tools/test_apps/system/panic/common/main/CMakeLists.txt @@ -1,4 +1,5 @@ set(srcs "test_app_main.c" "test_panic.c") +set(priv_requires esp_gdbstub espcoredump esp_hal_security) if(CONFIG_TEST_MEMPROT) list(APPEND srcs "test_memprot.c") @@ -13,10 +14,14 @@ else() list(APPEND srcs "panic_utils/panic_utils.c") endif() +if(CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH) + list(APPEND srcs "test_panic_coredump_summary.c") +endif() + idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "include" REQUIRES spi_flash esp_psram esp_system esp_partition - PRIV_REQUIRES esp_gdbstub espcoredump esp_hal_security) + PRIV_REQUIRES ${priv_requires}) target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-unused-variable" "-Wno-infinite-recursion" diff --git a/tools/test_apps/system/panic/main/Kconfig.projbuild b/tools/test_apps/system/panic/common/main/Kconfig.projbuild similarity index 100% rename from tools/test_apps/system/panic/main/Kconfig.projbuild rename to tools/test_apps/system/panic/common/main/Kconfig.projbuild diff --git a/tools/test_apps/system/panic/main/include/test_memprot.h b/tools/test_apps/system/panic/common/main/include/test_memprot.h similarity index 100% rename from tools/test_apps/system/panic/main/include/test_memprot.h rename to tools/test_apps/system/panic/common/main/include/test_memprot.h diff --git a/tools/test_apps/system/panic/main/include/test_panic.h b/tools/test_apps/system/panic/common/main/include/test_panic.h similarity index 100% rename from tools/test_apps/system/panic/main/include/test_panic.h rename to tools/test_apps/system/panic/common/main/include/test_panic.h diff --git a/tools/test_apps/system/panic/main/panic_utils/memprot_panic_utils_riscv.c b/tools/test_apps/system/panic/common/main/panic_utils/memprot_panic_utils_riscv.c similarity index 100% rename from tools/test_apps/system/panic/main/panic_utils/memprot_panic_utils_riscv.c rename to tools/test_apps/system/panic/common/main/panic_utils/memprot_panic_utils_riscv.c diff --git a/tools/test_apps/system/panic/main/panic_utils/memprot_panic_utils_xtensa.c b/tools/test_apps/system/panic/common/main/panic_utils/memprot_panic_utils_xtensa.c similarity index 100% rename from tools/test_apps/system/panic/main/panic_utils/memprot_panic_utils_xtensa.c rename to tools/test_apps/system/panic/common/main/panic_utils/memprot_panic_utils_xtensa.c diff --git a/tools/test_apps/system/panic/main/panic_utils/panic_utils.c b/tools/test_apps/system/panic/common/main/panic_utils/panic_utils.c similarity index 100% rename from tools/test_apps/system/panic/main/panic_utils/panic_utils.c rename to tools/test_apps/system/panic/common/main/panic_utils/panic_utils.c diff --git a/tools/test_apps/system/panic/main/test_app_main.c b/tools/test_apps/system/panic/common/main/test_app_main.c similarity index 100% rename from tools/test_apps/system/panic/main/test_app_main.c rename to tools/test_apps/system/panic/common/main/test_app_main.c diff --git a/tools/test_apps/system/panic/main/test_memprot.c b/tools/test_apps/system/panic/common/main/test_memprot.c similarity index 100% rename from tools/test_apps/system/panic/main/test_memprot.c rename to tools/test_apps/system/panic/common/main/test_memprot.c diff --git a/tools/test_apps/system/panic/main/test_panic.c b/tools/test_apps/system/panic/common/main/test_panic.c similarity index 91% rename from tools/test_apps/system/panic/main/test_panic.c rename to tools/test_apps/system/panic/common/main/test_panic.c index 62edf6ef487..bb82d279b58 100644 --- a/tools/test_apps/system/panic/main/test_panic.c +++ b/tools/test_apps/system/panic/common/main/test_panic.c @@ -13,10 +13,6 @@ #include "esp_flash.h" #include "esp_system.h" #include "spi_flash_mmap.h" -#if CONFIG_ESP_COREDUMP_ENABLE -#include "esp_core_dump.h" -#endif - #include "esp_private/cache_utils.h" #include "esp_memory_utils.h" #include "esp_heap_caps.h" @@ -321,38 +317,6 @@ void test_ub(void) printf("%d\n", stuff[rand()]); } -#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH -void test_setup_coredump_summary(void) -{ - if (esp_core_dump_image_erase() != ESP_OK) - die("Coredump image can not be erased!"); - assert(0); -} - -void test_coredump_summary(void) -{ - esp_core_dump_summary_t *summary = malloc(sizeof(esp_core_dump_summary_t)); - if (summary) { - esp_err_t err = esp_core_dump_get_summary(summary); - if (err == ESP_OK) { - printf("App ELF file SHA256: %s\n", (char *)summary->app_elf_sha256); - printf("Crashed task: %s\n", summary->exc_task); -#if __XTENSA__ - printf("Exception cause: %ld\n", summary->ex_info.exc_cause); -#else - printf("Exception cause: %ld\n", summary->ex_info.mcause); -#endif - char panic_reason[200]; - err = esp_core_dump_get_panic_reason(panic_reason, sizeof(panic_reason)); - if (err == ESP_OK) { - printf("Panic reason: %s\n", panic_reason); - } - } - free(summary); - } -} -#endif - void test_tcb_corrupted(void) { StaticTask_t *tcb = (StaticTask_t *)xTaskGetIdleTaskHandleForCore(0); diff --git a/tools/test_apps/system/panic/common/main/test_panic_coredump_summary.c b/tools/test_apps/system/panic/common/main/test_panic_coredump_summary.c new file mode 100644 index 00000000000..bbd0aa9e7a4 --- /dev/null +++ b/tools/test_apps/system/panic/common/main/test_panic_coredump_summary.c @@ -0,0 +1,47 @@ +/* + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include + +#include "esp_core_dump.h" +#include "esp_err.h" + +#include "test_panic.h" + +#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH +void test_setup_coredump_summary(void) +{ + if (esp_core_dump_image_erase() != ESP_OK) { + die("Coredump image can not be erased!"); + } + assert(0); +} + +void test_coredump_summary(void) +{ + esp_core_dump_summary_t *summary = malloc(sizeof(esp_core_dump_summary_t)); + if (summary) { + esp_err_t err = esp_core_dump_get_summary(summary); + if (err == ESP_OK) { + printf("App ELF file SHA256: %s\n", (char *)summary->app_elf_sha256); + printf("Crashed task: %s\n", summary->exc_task); +#if __XTENSA__ + printf("Exception cause: %ld\n", summary->ex_info.exc_cause); +#else + printf("Exception cause: %ld\n", summary->ex_info.mcause); +#endif + char panic_reason[200]; + err = esp_core_dump_get_panic_reason(panic_reason, sizeof(panic_reason)); + if (err == ESP_OK) { + printf("Panic reason: %s\n", panic_reason); + } + } + free(summary); + } +} +#endif diff --git a/tools/test_apps/system/panic/coredump/CMakeLists.txt b/tools/test_apps/system/panic/coredump/CMakeLists.txt new file mode 100644 index 00000000000..e1304f0189b --- /dev/null +++ b/tools/test_apps/system/panic/coredump/CMakeLists.txt @@ -0,0 +1,10 @@ +# 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.22) + +set(COMPONENTS main esp_gdbstub espcoredump) +set(EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}/../common") + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +project(test_panic_coredump) diff --git a/tools/test_apps/system/panic/coredump/README.md b/tools/test_apps/system/panic/coredump/README.md new file mode 100644 index 00000000000..fa84e37d2d7 --- /dev/null +++ b/tools/test_apps/system/panic/coredump/README.md @@ -0,0 +1,18 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | + +# Introduction + +The `coredump` test app contains the coredump-enabled panic coverage that was split out of the `panic_base` app so CI can route it separately with `depends_components`. + +The C test logic is shared with the base panic app through [common/main](../common/main). Pytest wrappers live in [pytest_panic_coredump.py](pytest_panic_coredump.py) and reuse the panic test bodies for scenarios that should run with both panic and coredump configurations. + +For guidance on where to add new tests, see [panic_base/README.md](../panic_base/README.md#where-to-add-a-new-test). + +# Building + +For example, to build the coredump panic app with configuration `coredump_flash_default` for ESP32-C3, run: + +```bash +idf.py -DIDF_TARGET=esp32c3 -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.ci.coredump_flash_default" build +``` diff --git a/tools/test_apps/system/panic/coredump/conftest.py b/tools/test_apps/system/panic/coredump/conftest.py new file mode 100644 index 00000000000..77cb2197f36 --- /dev/null +++ b/tools/test_apps/system/panic/coredump/conftest.py @@ -0,0 +1,28 @@ +# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +# pylint: disable=W0621 # redefined-outer-name + +import sys +from pathlib import Path + +import pytest +from _pytest.fixtures import FixtureRequest +from _pytest.monkeypatch import MonkeyPatch + +PANIC_BASE_APP = Path(__file__).resolve().parent.parent / 'panic_base' +sys.path.insert(0, str(PANIC_BASE_APP)) + +from test_panic_util import PanicTestDut # noqa: E402 + + +@pytest.fixture(scope='module') +def monkeypatch_module(request: FixtureRequest) -> MonkeyPatch: + mp = MonkeyPatch() + request.addfinalizer(mp.undo) + return mp + + +@pytest.fixture(scope='module', autouse=True) +def replace_dut_class(monkeypatch_module: MonkeyPatch) -> None: + monkeypatch_module.setattr('pytest_embedded_idf.IdfDut', PanicTestDut) diff --git a/tools/test_apps/system/panic/partitions_capture_dram.csv b/tools/test_apps/system/panic/coredump/partitions_capture_dram.csv similarity index 100% rename from tools/test_apps/system/panic/partitions_capture_dram.csv rename to tools/test_apps/system/panic/coredump/partitions_capture_dram.csv diff --git a/tools/test_apps/system/panic/partitions_coredump_encrypted.csv b/tools/test_apps/system/panic/coredump/partitions_coredump_encrypted.csv similarity index 100% rename from tools/test_apps/system/panic/partitions_coredump_encrypted.csv rename to tools/test_apps/system/panic/coredump/partitions_coredump_encrypted.csv diff --git a/tools/test_apps/system/panic/partitions_coredump_plain.csv b/tools/test_apps/system/panic/coredump/partitions_coredump_plain.csv similarity index 100% rename from tools/test_apps/system/panic/partitions_coredump_plain.csv rename to tools/test_apps/system/panic/coredump/partitions_coredump_plain.csv diff --git a/tools/test_apps/system/panic/coredump/pytest_panic_coredump.py b/tools/test_apps/system/panic/coredump/pytest_panic_coredump.py new file mode 100644 index 00000000000..615f7280fb9 --- /dev/null +++ b/tools/test_apps/system/panic/coredump/pytest_panic_coredump.py @@ -0,0 +1,331 @@ +# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import re +import sys +from pathlib import Path + +import pytest +from pytest_embedded_idf.utils import idf_parametrize + +PANIC_BASE_APP = Path(__file__).resolve().parent.parent / 'panic_base' +sys.path.insert(0, str(PANIC_BASE_APP)) + +import pytest_panic as panic_tests # noqa: E402 +from pytest_panic import PANIC_ABORT_PREFIX # noqa: E402 +from pytest_panic import common_test # noqa: E402 +from pytest_panic import expect_coredump_flash_write_logs # noqa: E402 +from pytest_panic import expect_coredump_uart_write_logs # noqa: E402 +from pytest_panic import get_default_backtrace # noqa: E402 +from test_panic_util import PanicTestDut # noqa: E402 + +TARGETS_ALL = panic_tests.TARGETS_ALL +TARGETS_DUAL_CORE = panic_tests.TARGETS_DUAL_CORE +TARGETS_RISCV = panic_tests.TARGETS_RISCV +TARGETS_RISCV_DUAL_CORE = panic_tests.TARGETS_RISCV_DUAL_CORE +COREDUMP_APP = str(Path(__file__).resolve().parent) + +COREDUMP_UNSUPPORTED_TARGETS = {'esp32h4'} +COREDUMP_TARGETS_ALL = [target for target in TARGETS_ALL if target not in COREDUMP_UNSUPPORTED_TARGETS] +COREDUMP_TARGETS_DUAL_CORE = [target for target in TARGETS_DUAL_CORE if target not in COREDUMP_UNSUPPORTED_TARGETS] +COREDUMP_TARGETS_RISCV = [target for target in TARGETS_RISCV if target not in COREDUMP_UNSUPPORTED_TARGETS] +COREDUMP_TARGETS_RISCV_DUAL_CORE = [ + target for target in TARGETS_RISCV_DUAL_CORE if target not in COREDUMP_UNSUPPORTED_TARGETS +] + +CONFIGS = panic_tests.configs_for_app( + COREDUMP_APP, + [ + 'coredump_flash_default', + 'coredump_flash_soft_sha', + 'coredump_uart_default', + 'coredump_flash_custom_stack', + ], +) + +CONFIGS_DUAL_CORE = panic_tests.configs_for_app( + COREDUMP_APP, + [ + 'coredump_flash_default', + 'coredump_uart_default', + ], +) + +CONFIGS_HW_STACK_GUARD = panic_tests.configs_for_app(COREDUMP_APP, ['coredump_uart_default']) +CONFIGS_HW_STACK_GUARD_DUAL_CORE = panic_tests.configs_for_app(COREDUMP_APP, ['coredump_uart_default']) +CONFIG_CAPTURE_DRAM = panic_tests.configs_for_app( + COREDUMP_APP, ['coredump_flash_capture_dram', 'coredump_uart_capture_dram'] +) +CONFIG_COREDUMP_SUMMARY = panic_tests.configs_for_app(COREDUMP_APP, ['coredump_flash_default']) +CONFIG_COREDUMP_SUMMARY_FLASH_ENCRYPTED = panic_tests.configs_for_app( + COREDUMP_APP, ['coredump_flash_encrypted', 'coredump_flash_encrypted_coredump_plain'] +) +CONFIG_GDBSTUB_COREDUMP = panic_tests.configs_for_app(COREDUMP_APP, ['gdbstub_coredump']) +CONFIG_TCB_CORRUPTED = panic_tests.configs_for_app(COREDUMP_APP, ['coredump_flash_default']) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_task_wdt_cpu0(dut: PanicTestDut, config: str, test_func_name: str) -> None: + panic_tests.test_task_wdt_cpu0(dut, config, test_func_name) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS_DUAL_CORE, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_DUAL_CORE, indirect=['target']) +def test_task_wdt_cpu1(dut: PanicTestDut, config: str, test_func_name: str) -> None: + panic_tests.test_task_wdt_cpu1(dut, config, test_func_name) + + +@pytest.mark.parametrize( + 'app_path, config, target', + [ + pytest.param(COREDUMP_APP, 'coredump_flash_extram_stack_heap_esp32', 'esp32', marks=(pytest.mark.psram,)), + pytest.param(COREDUMP_APP, 'coredump_flash_extram_stack_heap_esp32s2', 'esp32s2', marks=(pytest.mark.generic,)), + pytest.param( + COREDUMP_APP, 'coredump_flash_extram_stack_heap_esp32s3', 'esp32s3', marks=(pytest.mark.quad_psram,) + ), + pytest.param(COREDUMP_APP, 'coredump_flash_extram_stack_bss_esp32', 'esp32', marks=(pytest.mark.psram,)), + pytest.param(COREDUMP_APP, 'coredump_flash_extram_stack_bss_esp32s2', 'esp32s2', marks=(pytest.mark.generic,)), + pytest.param( + COREDUMP_APP, 'coredump_flash_extram_stack_bss_esp32s3', 'esp32s3', marks=(pytest.mark.quad_psram,) + ), + ], + indirect=True, +) +def test_panic_extram_stack(dut: PanicTestDut, config: str) -> None: + if 'heap' in config: + dut.run_test_func('test_panic_extram_stack_heap') + else: + dut.run_test_func('test_panic_extram_stack_bss') + dut.expect_none('Allocated stack is not in external RAM') + dut.expect_none('Guru Meditation') + dut.expect_backtrace() + dut.expect_elf_sha256() + + if dut.target == 'esp32': + # ESP32 External data memory range [0x3f800000-0x3fc00000) + coredump_pattern = re.compile('.coredump.tasks.data (0x3[fF][8-9a-bA-B][0-9a-fA-F]{5}) (0x[a-fA-F0-9]+) RW') + elif dut.target == 'esp32s2': + # ESP32-S2 External data memory range [0x3f500000-0x3ff80000) + coredump_pattern = re.compile( + '.coredump.tasks.data (0x3[fF][5-9a-fA-F][0-7][0-9a-fA-F]{4}) (0x[a-fA-F0-9]+) RW' + ) + else: + # ESP32-S3 External data memory range [0x3c000000-0x3e000000) + coredump_pattern = re.compile('.coredump.tasks.data (0x3[c-dC-D][0-9a-fA-F]{6}) (0x[a-fA-F0-9]+) RW') + + common_test(dut, config, expected_backtrace=None, expected_coredump=[coredump_pattern]) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_int_wdt(dut: PanicTestDut, target: str, config: str, test_func_name: str) -> None: + panic_tests.test_int_wdt(dut, target, config, test_func_name) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_int_wdt_cache_disabled(dut: PanicTestDut, target: str, config: str, test_func_name: str) -> None: + panic_tests.test_int_wdt_cache_disabled(dut, target, config, test_func_name) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_cache_error(dut: PanicTestDut, config: str, test_func_name: str) -> None: + panic_tests.test_cache_error(dut, config, test_func_name) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_stack_overflow(dut: PanicTestDut, config: str, test_func_name: str) -> None: + panic_tests.test_stack_overflow(dut, config, test_func_name) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_instr_fetch_prohibited(dut: PanicTestDut, config: str, test_func_name: str) -> None: + panic_tests.test_instr_fetch_prohibited(dut, config, test_func_name) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_illegal_instruction(dut: PanicTestDut, config: str, test_func_name: str) -> None: + panic_tests.test_illegal_instruction(dut, config, test_func_name) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_storeprohibited(dut: PanicTestDut, config: str, test_func_name: str) -> None: + panic_tests.test_storeprohibited(dut, config, test_func_name) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_loadprohibited(dut: PanicTestDut, config: str, test_func_name: str) -> None: + panic_tests.test_loadprohibited(dut, config, test_func_name) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_abort(dut: PanicTestDut, config: str, test_func_name: str) -> None: + panic_tests.test_abort(dut, config, test_func_name) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_abort_cache_disabled(dut: PanicTestDut, config: str, test_func_name: str) -> None: + panic_tests.test_abort_cache_disabled(dut, config, test_func_name) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_assert(dut: PanicTestDut, config: str, test_func_name: str) -> None: + panic_tests.test_assert(dut, config, test_func_name) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_assert_cache_disabled(dut: PanicTestDut, config: str, test_func_name: str) -> None: + panic_tests.test_assert_cache_disabled(dut, config, test_func_name) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIG_GDBSTUB_COREDUMP, indirect=True) +@idf_parametrize('target', ['esp32'], indirect=['target']) +def test_gdbstub_coredump(dut: PanicTestDut) -> None: + test_func_name = 'test_storeprohibited' + dut.run_test_func(test_func_name) + common_test(dut, 'gdbstub_coredump', get_default_backtrace(test_func_name)) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS_HW_STACK_GUARD, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_RISCV, indirect=['target']) +def test_hw_stack_guard_cpu0(dut: PanicTestDut, config: str, test_func_name: str) -> None: + panic_tests.test_hw_stack_guard_cpu0(dut, config, test_func_name) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIGS_HW_STACK_GUARD_DUAL_CORE, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_RISCV_DUAL_CORE, indirect=['target']) +def test_hw_stack_guard_cpu1(dut: PanicTestDut, config: str, test_func_name: str) -> None: + panic_tests.test_hw_stack_guard_cpu1(dut, config, test_func_name) + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIG_CAPTURE_DRAM, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_capture_dram(dut: PanicTestDut, config: str, test_func_name: str) -> None: + dut.run_test_func(test_func_name) + regex_pattern = rb'assert failed:[\s\w()]*?\s[.\w/]*\.(?:c|cpp|h|hpp):\d.*$' + dut.expect(re.compile(regex_pattern, re.MULTILINE)) + if dut.is_xtensa: + dut.expect_backtrace() + else: + dut.expect_stack_dump() + dut.expect_elf_sha256() + dut.expect_none(['Guru Meditation', 'Re-entered core dump']) + + core_elf_file = None + if 'flash' in config: + expect_coredump_flash_write_logs(dut, config) + core_elf_file = dut.process_coredump_flash() + elif 'uart' in config: + coredump_base64 = expect_coredump_uart_write_logs(dut) + core_elf_file = dut.process_coredump_uart(coredump_base64) + assert core_elf_file is not None + + dut.start_gdb_for_coredump(core_elf_file) + + assert dut.gdb_data_eval_expr('g_data_var') == '43' + assert dut.gdb_data_eval_expr('g_bss_var') == '55' + assert re.search(r'0x[0-9a-fA-F]+ "Coredump Test"', dut.gdb_data_eval_expr('g_heap_ptr')) + assert int(dut.gdb_data_eval_expr('g_cd_iram')) == 0x4243 + assert int(dut.gdb_data_eval_expr('g_cd_dram')) == 0x4344 + assert int(dut.gdb_data_eval_expr('g_noinit_var')) == 0xCAFEBABE + buffer_value = str(dut.gdb_data_eval_expr('g_noinit_buffer')) + assert 'NOINIT_TEST_STRING' in buffer_value + + if dut.target not in ['esp32c61', 'esp32c2']: + assert int(dut.gdb_data_eval_expr('g_rtc_data_var')) == 0x55AA + assert int(dut.gdb_data_eval_expr('g_rtc_fast_var')) == 0xAABBCCDD + + +def _test_coredump_summary(dut: PanicTestDut, flash_encrypted: bool, coredump_encrypted: bool) -> None: + dut.run_test_func('test_setup_coredump_summary') + dut.expect_cpu_reset() + if flash_encrypted: + dut.expect_exact('Flash encryption mode is DEVELOPMENT (not secure)') + dut.run_test_func('test_coredump_summary') + if flash_encrypted and not coredump_encrypted: + dut.expect_exact('Flash encryption enabled in hardware and core dump partition is not encrypted!') + return + dut.expect_elf_sha256('App ELF file SHA256: ') + dut.expect_exact('Crashed task: main') + if dut.is_xtensa: + dut.expect_exact('Exception cause: 0') + else: + dut.expect_exact('Exception cause: 2') + dut.expect(PANIC_ABORT_PREFIX + r'assert failed:[\s\w()]*?\s[.\w/]*\.(?:c|cpp|h|hpp):\d.*$') + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIG_COREDUMP_SUMMARY, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_coredump_summary(dut: PanicTestDut) -> None: + _test_coredump_summary(dut, False, False) + + +@pytest.mark.flash_encryption +@pytest.mark.parametrize('app_path, config', CONFIG_COREDUMP_SUMMARY_FLASH_ENCRYPTED, indirect=True) +@idf_parametrize('target', ['esp32', 'esp32c3'], indirect=['target']) +def test_coredump_summary_flash_encrypted(dut: PanicTestDut, config: str) -> None: + _test_coredump_summary(dut, True, config == 'coredump_flash_encrypted') + + +@pytest.mark.generic +@pytest.mark.parametrize('app_path, config', CONFIG_TCB_CORRUPTED, indirect=True) +@idf_parametrize('target', COREDUMP_TARGETS_ALL, indirect=['target']) +def test_tcb_corrupted(dut: PanicTestDut, target: str, config: str, test_func_name: str) -> None: + dut.run_test_func(test_func_name) + if dut.is_xtensa: + dut.expect(re.compile(rb"Guru Meditation Error: Core\s+\d\s+panic'ed \((LoadProhibited|StoreProhibited)\)")) + dut.expect_reg_dump() + dut.expect_backtrace() + else: + dut.expect(re.compile(rb"Guru Meditation Error: Core\s+\d\s+panic'ed \((Load|Store) access fault\)")) + dut.expect_reg_dump() + dut.expect_stack_dump() + + dut.expect_elf_sha256() + dut.expect_none('Guru Meditation') + + # Verify that valid tasks are captured in coredump despite IDLE task corruption + # TCB NAME + # ---------- ---------------- + if dut.is_multi_core: + regex_patterns = [ + rb'[0-9xa-fA-F] main', + rb'[0-9xa-fA-F] ipc0', + rb'[0-9xa-fA-F] ipc1', + ] + else: + regex_patterns = [rb'[0-9xa-fA-F] main'] + + coredump_pattern = [re.compile(pattern.decode('utf-8')) for pattern in regex_patterns] + + common_test(dut, config, expected_backtrace=None, expected_coredump=coredump_pattern) diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_bin_crc b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_bin_crc similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_bin_crc rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_bin_crc diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_capture_dram b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_capture_dram similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_capture_dram rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_capture_dram diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_custom_stack b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_custom_stack similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_custom_stack rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_custom_stack diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_default b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_default similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_default rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_default diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_encrypted b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_encrypted similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_encrypted rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_encrypted diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_encrypted_coredump_plain b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_encrypted_coredump_plain similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_encrypted_coredump_plain rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_encrypted_coredump_plain diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_extram_attr_esp32 b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_extram_attr_esp32 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_extram_attr_esp32 rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_extram_attr_esp32 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_extram_stack_bss_esp32 b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_extram_stack_bss_esp32 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_extram_stack_bss_esp32 rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_extram_stack_bss_esp32 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_extram_stack_bss_esp32s2 b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_extram_stack_bss_esp32s2 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_extram_stack_bss_esp32s2 rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_extram_stack_bss_esp32s2 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_extram_stack_bss_esp32s3 b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_extram_stack_bss_esp32s3 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_extram_stack_bss_esp32s3 rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_extram_stack_bss_esp32s3 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_extram_stack_heap_esp32 b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_extram_stack_heap_esp32 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_extram_stack_heap_esp32 rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_extram_stack_heap_esp32 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_extram_stack_heap_esp32s2 b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_extram_stack_heap_esp32s2 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_extram_stack_heap_esp32s2 rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_extram_stack_heap_esp32s2 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_extram_stack_heap_esp32s3 b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_extram_stack_heap_esp32s3 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_extram_stack_heap_esp32s3 rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_extram_stack_heap_esp32s3 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_soft_sha b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_soft_sha similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_soft_sha rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_flash_soft_sha diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_uart_capture_dram b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_uart_capture_dram similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_uart_capture_dram rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_uart_capture_dram diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_uart_default b/tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_uart_default similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.coredump_uart_default rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.coredump_uart_default diff --git a/tools/test_apps/system/panic/sdkconfig.ci.gdbstub_coredump b/tools/test_apps/system/panic/coredump/sdkconfig.ci.gdbstub_coredump similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.gdbstub_coredump rename to tools/test_apps/system/panic/coredump/sdkconfig.ci.gdbstub_coredump diff --git a/tools/test_apps/system/panic/sdkconfig.defaults b/tools/test_apps/system/panic/coredump/sdkconfig.defaults similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.defaults rename to tools/test_apps/system/panic/coredump/sdkconfig.defaults diff --git a/tools/test_apps/system/panic/CMakeLists.txt b/tools/test_apps/system/panic/panic_base/CMakeLists.txt similarity index 92% rename from tools/test_apps/system/panic/CMakeLists.txt rename to tools/test_apps/system/panic/panic_base/CMakeLists.txt index faafff77bf0..69effc2e08c 100644 --- a/tools/test_apps/system/panic/CMakeLists.txt +++ b/tools/test_apps/system/panic/panic_base/CMakeLists.txt @@ -3,10 +3,7 @@ cmake_minimum_required(VERSION 3.22) set(COMPONENTS main esp_gdbstub) - -if(CONFIG_ESP_COREDUMP_ENABLE) - list(APPEND COMPONENTS espcoredump) -endif() +set(EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}/../common") include($ENV{IDF_PATH}/tools/cmake/project.cmake) @@ -20,9 +17,7 @@ if(CONFIG_TEST_MEMPROT) target_link_libraries(${project_elf} PRIVATE "-Wl,--wrap=panic_arch_fill_info") endif() endif() -endif() - -if(NOT CONFIG_TEST_MEMPROT AND NOT CONFIG_ESP_COREDUMP_ENABLE) +else() # Enable UBSAN checks # # shift-base sanitizer is disabled due to the following pattern found in register header files: diff --git a/tools/test_apps/system/panic/README.md b/tools/test_apps/system/panic/panic_base/README.md similarity index 64% rename from tools/test_apps/system/panic/README.md rename to tools/test_apps/system/panic/panic_base/README.md index 709fe3550e1..662c1448c64 100644 --- a/tools/test_apps/system/panic/README.md +++ b/tools/test_apps/system/panic/panic_base/README.md @@ -10,9 +10,17 @@ This test app is relatively complex because it has to check many possible combin - Chip target: esp32, esp32c3, ... - Configuration: default, GDB Stub, Core Dump to UART, ... -Failure scenarios are implemented in [test_panic.c](main/test_panic.c). The test application receives the name of the scenario from console (e.g. `test_illegal_instruction` ). The failure scenario is executed and the app panics. Once the panic output is printed, the pytest-based test case parses the output and verifies that the behavior of the panic handler was correct. +Failure scenarios are implemented in the shared component at [common/main/test_panic.c](../common/main/test_panic.c). The test application receives the name of the scenario from console (e.g. `test_illegal_instruction` ). The failure scenario is executed and the app panics. Once the panic output is printed, the pytest-based test case parses the output and verifies that the behavior of the panic handler was correct. -In [pytest_panic.py](pytest_panic.py), there typically is one test function for each failure scenario. Each test function is then parametrized by `config` parameter. This creates "copies" of the test case for each of the configurations (default, GDB Stub, etc.) Tests are also parametrized with target-specific markers. Most tests can run on every target, but there are a few exceptions, such as failure scenarios specific to the dual-core chips. +The `panic_base` app owns the non-coredump configurations. Coredump-specific sdkconfigs, partitions, and pytest wrappers live in the sibling [coredump](../coredump) app so CI can route them separately. + +In [pytest_panic.py](pytest_panic.py), there typically is one test function for each failure scenario. Each test function is then parametrized by `config` parameter. This creates "copies" of the test case for each of the non-coredump configurations (default, GDB Stub, etc.) Tests are also parametrized with target-specific markers. Most tests can run on every target, but there are a few exceptions, such as failure scenarios specific to the dual-core chips. + +## Where to add a new test + +- **Scenario that should run under both panic and coredump configs** (e.g. a new watchdog or fault test): put the test body in `panic_base/pytest_panic.py`, then add a thin wrapper in `coredump/pytest_panic_coredump.py` that calls into it with coredump configs and `COREDUMP_TARGETS_ALL`. Shared helpers (`common_test`, `expect_coredump_*`) also live in `pytest_panic.py`. +- **Scenario that only makes sense with coredump enabled** (extram stack, capture_dram, coredump_summary, tcb_corrupted, gdbstub_coredump, …): add the test directly in `coredump/pytest_panic_coredump.py`. Do not put it in `panic_base`. +- **New C-level failure scenario**: add it to [common/main/test_panic.c](../common/main/test_panic.c) so both apps pick it up. The test cases use a customized DUT class `PanicTestDut`, defined in [panic_dut.py](test_panic_util/panic_dut.py). This class is derived from [`IdfDut`](https://docs.espressif.com/projects/pytest-embedded/en/latest/references/pytest_embedded_idf/#pytest_embedded_idf.dut.IdfDut). It defines several helper functions to make the test cases easier to read. diff --git a/tools/test_apps/system/panic/conftest.py b/tools/test_apps/system/panic/panic_base/conftest.py similarity index 100% rename from tools/test_apps/system/panic/conftest.py rename to tools/test_apps/system/panic/panic_base/conftest.py diff --git a/tools/test_apps/system/panic/panic_utils.py b/tools/test_apps/system/panic/panic_base/panic_utils.py similarity index 91% rename from tools/test_apps/system/panic/panic_utils.py rename to tools/test_apps/system/panic/panic_base/panic_utils.py index dfb38dda702..9d6448d41a0 100644 --- a/tools/test_apps/system/panic/panic_utils.py +++ b/tools/test_apps/system/panic/panic_base/panic_utils.py @@ -42,10 +42,7 @@ def verify_valid_gdb_subprocess(gdb_process: Popen) -> None: raise NoGdbProcessError('gdb process is not attached') elif gdb_process.poll() is not None: - raise NoGdbProcessError( - 'gdb process has already finished with return code: %s' - % str(gdb_process.poll()) - ) + raise NoGdbProcessError(f'gdb process has already finished with return code: {gdb_process.poll()}') def attach_logger() -> logging.Logger: diff --git a/tools/test_apps/system/panic/pytest_panic.py b/tools/test_apps/system/panic/panic_base/pytest_panic.py similarity index 82% rename from tools/test_apps/system/panic/pytest_panic.py rename to tools/test_apps/system/panic/panic_base/pytest_panic.py index fbd151725d5..55510798e34 100644 --- a/tools/test_apps/system/panic/pytest_panic.py +++ b/tools/test_apps/system/panic/panic_base/pytest_panic.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 import itertools +import os import re from collections.abc import Sequence from re import Pattern @@ -27,33 +28,16 @@ TARGETS_ALL = TARGETS_XTENSA + TARGETS_RISCV # Some tests only run on dual-core targets, they use the config below. TARGETS_DUAL_CORE = TARGETS_XTENSA_DUAL_CORE + TARGETS_RISCV_DUAL_CORE -CONFIGS = list( - itertools.chain( - itertools.product( - [ - 'coredump_flash_default', - 'coredump_flash_soft_sha', - 'coredump_uart_default', - 'coredump_flash_custom_stack', - 'gdbstub', - 'panic', - ], - TARGETS_ALL, - ) - ) -) +PANIC_APP = os.path.dirname(__file__) -CONFIGS_UBSAN = list( - itertools.chain( - itertools.product( - [ - 'gdbstub', - 'panic', - ], - TARGETS_ALL, - ) - ) -) + +def configs_for_app(app_path: str, configs: Sequence[str]) -> list[tuple[str, str]]: + return [(app_path, config) for config in configs] + + +CONFIGS = configs_for_app(PANIC_APP, ['gdbstub', 'panic']) + +CONFIGS_UBSAN = configs_for_app(PANIC_APP, ['gdbstub', 'panic']) CONFIG_PANIC = list( itertools.chain( @@ -78,50 +62,11 @@ CONFIG_PANIC = list( CONFIG_PANIC_DUAL_CORE = list(itertools.chain(itertools.product(['panic'], TARGETS_DUAL_CORE))) CONFIG_PANIC_HALT = list(itertools.chain(itertools.product(['panic_halt'], TARGETS_ALL))) -CONFIGS_DUAL_CORE = list( - itertools.chain( - itertools.product( - [ - 'coredump_flash_default', - 'coredump_uart_default', - 'gdbstub', - 'panic', - ], - TARGETS_DUAL_CORE, - ) - ) -) +CONFIGS_DUAL_CORE = configs_for_app(PANIC_APP, ['gdbstub', 'panic']) -CONFIGS_HW_STACK_GUARD = list( - itertools.chain( - itertools.product( - ['coredump_uart_default', 'gdbstub', 'panic'], - TARGETS_RISCV, - ) - ) -) +CONFIGS_HW_STACK_GUARD = configs_for_app(PANIC_APP, ['gdbstub', 'panic']) -CONFIGS_HW_STACK_GUARD_DUAL_CORE = list( - itertools.chain( - itertools.product( - ['coredump_uart_default', 'gdbstub', 'panic'], - TARGETS_RISCV_DUAL_CORE, - ) - ) -) - -CONFIG_CAPTURE_DRAM = list( - itertools.chain(itertools.product(['coredump_flash_capture_dram', 'coredump_uart_capture_dram'], TARGETS_ALL)) -) - -CONFIG_COREDUMP_SUMMARY = list(itertools.chain(itertools.product(['coredump_flash_default'], TARGETS_ALL))) - -CONFIG_COREDUMP_SUMMARY_FLASH_ENCRYPTED = list( - itertools.chain( - itertools.product(['coredump_flash_encrypted'], ['esp32', 'esp32c3']), - itertools.product(['coredump_flash_encrypted_coredump_plain'], ['esp32', 'esp32c3']), - ) -) +CONFIGS_HW_STACK_GUARD_DUAL_CORE = configs_for_app(PANIC_APP, ['gdbstub', 'panic']) # Panic abort information will start with this string. PANIC_ABORT_PREFIX = 'Panic reason: ' @@ -199,7 +144,8 @@ def common_test( @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', TARGETS_ALL, indirect=['target']) def test_task_wdt_cpu0(dut: PanicTestDut, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) dut.expect_exact('Task watchdog got triggered. The following tasks/users did not reset the watchdog in time:') @@ -231,7 +177,8 @@ def test_task_wdt_cpu0(dut: PanicTestDut, config: str, test_func_name: str) -> N @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS_DUAL_CORE, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS_DUAL_CORE, indirect=True) +@idf_parametrize('target', TARGETS_DUAL_CORE, indirect=['target']) def test_task_wdt_cpu1(dut: PanicTestDut, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) dut.expect_exact('Task watchdog got triggered. The following tasks/users did not reset the watchdog in time:') @@ -257,45 +204,9 @@ def test_task_wdt_cpu1(dut: PanicTestDut, config: str, test_func_name: str) -> N common_test(dut, config, expected_backtrace=expected_backtrace, expected_coredump=[coredump_pattern]) -@idf_parametrize( - 'config,target,markers', - [ - ('coredump_flash_extram_stack_heap_esp32', 'esp32', (pytest.mark.psram,)), - ('coredump_flash_extram_stack_heap_esp32s2', 'esp32s2', (pytest.mark.generic,)), - ('coredump_flash_extram_stack_heap_esp32s3', 'esp32s3', (pytest.mark.quad_psram,)), - ('coredump_flash_extram_stack_bss_esp32', 'esp32', (pytest.mark.psram,)), - ('coredump_flash_extram_stack_bss_esp32s2', 'esp32s2', (pytest.mark.generic,)), - ('coredump_flash_extram_stack_bss_esp32s3', 'esp32s3', (pytest.mark.quad_psram,)), - ], - indirect=['config', 'target'], -) -def test_panic_extram_stack(dut: PanicTestDut, config: str) -> None: - if 'heap' in config: - dut.run_test_func('test_panic_extram_stack_heap') - else: - dut.run_test_func('test_panic_extram_stack_bss') - dut.expect_none('Allocated stack is not in external RAM') - dut.expect_none('Guru Meditation') - dut.expect_backtrace() - dut.expect_elf_sha256() - - if dut.target == 'esp32': - # ESP32 External data memory range [0x3f800000-0x3fc00000) - coredump_pattern = re.compile('.coredump.tasks.data (0x3[fF][8-9a-bA-B][0-9a-fA-F]{5}) (0x[a-fA-F0-9]+) RW') - elif dut.target == 'esp32s2': - # ESP32-S2 External data memory range [0x3f500000-0x3ff80000) - coredump_pattern = re.compile( - '.coredump.tasks.data (0x3[fF][5-9a-fA-F][0-7][0-9a-fA-F]{4}) (0x[a-fA-F0-9]+) RW' - ) - else: - # ESP32-S3 External data memory range [0x3c000000-0x3e000000) - coredump_pattern = re.compile('.coredump.tasks.data (0x3[c-dC-D][0-9a-fA-F]{6}) (0x[a-fA-F0-9]+) RW') - - common_test(dut, config, expected_backtrace=None, expected_coredump=[coredump_pattern]) - - @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', TARGETS_ALL, indirect=['target']) def test_int_wdt(dut: PanicTestDut, target: str, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) dut.expect_gme('Interrupt wdt timeout on CPU0') @@ -317,7 +228,8 @@ def test_int_wdt(dut: PanicTestDut, target: str, config: str, test_func_name: st @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', TARGETS_ALL, indirect=['target']) def test_int_wdt_cache_disabled(dut: PanicTestDut, target: str, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) dut.expect_gme('Interrupt wdt timeout on CPU0') @@ -339,7 +251,8 @@ def test_int_wdt_cache_disabled(dut: PanicTestDut, target: str, config: str, tes @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', TARGETS_ALL, indirect=['target']) def test_cache_error(dut: PanicTestDut, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) if dut.target in ['esp32c3', 'esp32c2']: @@ -370,7 +283,8 @@ def test_cache_error(dut: PanicTestDut, config: str, test_func_name: str) -> Non @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', TARGETS_ALL, indirect=['target']) def test_stack_overflow(dut: PanicTestDut, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) if dut.is_xtensa: @@ -391,7 +305,8 @@ def test_stack_overflow(dut: PanicTestDut, config: str, test_func_name: str) -> @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', TARGETS_ALL, indirect=['target']) def test_instr_fetch_prohibited(dut: PanicTestDut, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) if dut.is_xtensa: @@ -418,7 +333,8 @@ def test_instr_fetch_prohibited(dut: PanicTestDut, config: str, test_func_name: @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', TARGETS_ALL, indirect=['target']) def test_illegal_instruction(dut: PanicTestDut, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) if dut.is_xtensa: @@ -454,19 +370,22 @@ def check_x_prohibited(dut: PanicTestDut, config: str, test_func_name: str, oper @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', TARGETS_ALL, indirect=['target']) def test_storeprohibited(dut: PanicTestDut, config: str, test_func_name: str) -> None: check_x_prohibited(dut, config, test_func_name, 'Store') @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', TARGETS_ALL, indirect=['target']) def test_loadprohibited(dut: PanicTestDut, config: str, test_func_name: str) -> None: check_x_prohibited(dut, config, test_func_name, 'Load') @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', TARGETS_ALL, indirect=['target']) def test_abort(dut: PanicTestDut, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) regex_pattern = rb'abort\(\) was called at PC [0-9xa-f]+ on core 0' @@ -488,7 +407,8 @@ def test_abort(dut: PanicTestDut, config: str, test_func_name: str) -> None: @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS_UBSAN, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS_UBSAN, indirect=True) +@idf_parametrize('target', TARGETS_ALL, indirect=['target']) def test_ub(dut: PanicTestDut, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) regex_pattern = rb'Undefined behavior of type out_of_bounds' @@ -514,7 +434,8 @@ def test_ub(dut: PanicTestDut, config: str, test_func_name: str) -> None: @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', TARGETS_ALL, indirect=['target']) def test_abort_cache_disabled(dut: PanicTestDut, config: str, test_func_name: str) -> None: if dut.target == 'esp32s2': pytest.xfail(reason='Crashes in itoa which is not in ROM, IDF-3572') @@ -538,7 +459,8 @@ def test_abort_cache_disabled(dut: PanicTestDut, config: str, test_func_name: st @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', TARGETS_ALL, indirect=['target']) def test_assert(dut: PanicTestDut, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) regex_pattern = rb'assert failed:[\s\w()]*?\s[.\w/]*\.(?:c|cpp|h|hpp):\d.*$' @@ -560,7 +482,8 @@ def test_assert(dut: PanicTestDut, config: str, test_func_name: str) -> None: @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS, indirect=True) +@idf_parametrize('target', TARGETS_ALL, indirect=['target']) def test_assert_cache_disabled(dut: PanicTestDut, config: str, test_func_name: str) -> None: if dut.target == 'esp32s2': pytest.xfail(reason='Crashes in itoa which is not in ROM, IDF-3572') @@ -1267,15 +1190,6 @@ def test_invalid_memory_region_execute_violation(dut: PanicTestDut, test_func_na dut.expect_cpu_reset() -@pytest.mark.generic -@pytest.mark.parametrize('config', ['gdbstub_coredump'], indirect=True) -@idf_parametrize('target', ['esp32'], indirect=['target']) -def test_gdbstub_coredump(dut: PanicTestDut) -> None: - test_func_name = 'test_storeprohibited' - dut.run_test_func(test_func_name) - common_test(dut, 'gdbstub_coredump', get_default_backtrace(test_func_name)) - - def test_hw_stack_guard_cpu(dut: PanicTestDut, cpu: int) -> None: dut.expect_exact(f"Guru Meditation Error: Core {cpu} panic'ed (Stack protection fault).") dut.expect_none('ASSIST_DEBUG is not triggered BUT interrupt occurred!') @@ -1294,7 +1208,8 @@ def test_hw_stack_guard_cpu(dut: PanicTestDut, cpu: int) -> None: @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS_HW_STACK_GUARD, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS_HW_STACK_GUARD, indirect=True) +@idf_parametrize('target', TARGETS_RISCV, indirect=['target']) def test_hw_stack_guard_cpu0(dut: PanicTestDut, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) test_hw_stack_guard_cpu(dut, 0) @@ -1302,7 +1217,8 @@ def test_hw_stack_guard_cpu0(dut: PanicTestDut, config: str, test_func_name: str @pytest.mark.generic -@idf_parametrize('config, target', CONFIGS_HW_STACK_GUARD_DUAL_CORE, indirect=['config', 'target']) +@pytest.mark.parametrize('app_path, config', CONFIGS_HW_STACK_GUARD_DUAL_CORE, indirect=True) +@idf_parametrize('target', TARGETS_RISCV_DUAL_CORE, indirect=['target']) def test_hw_stack_guard_cpu1(dut: PanicTestDut, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) test_hw_stack_guard_cpu(dut, 1) @@ -1323,108 +1239,6 @@ def test_illegal_access(dut: PanicTestDut, config: str, test_func_name: str) -> dut.expect_none('Guru Meditation') -@pytest.mark.generic -@idf_parametrize('config, target', CONFIG_CAPTURE_DRAM, indirect=['config', 'target']) -def test_capture_dram(dut: PanicTestDut, config: str, test_func_name: str) -> None: - dut.run_test_func(test_func_name) - regex_pattern = rb'assert failed:[\s\w()]*?\s[.\w/]*\.(?:c|cpp|h|hpp):\d.*$' - dut.expect(re.compile(regex_pattern, re.MULTILINE)) - if dut.is_xtensa: - dut.expect_backtrace() - else: - dut.expect_stack_dump() - dut.expect_elf_sha256() - dut.expect_none(['Guru Meditation', 'Re-entered core dump']) - - core_elf_file = None - if 'flash' in config: - expect_coredump_flash_write_logs(dut, config) - core_elf_file = dut.process_coredump_flash() - elif 'uart' in config: - coredump_base64 = expect_coredump_uart_write_logs(dut) - core_elf_file = dut.process_coredump_uart(coredump_base64) - assert core_elf_file is not None - - dut.start_gdb_for_coredump(core_elf_file) - - assert dut.gdb_data_eval_expr('g_data_var') == '43' - assert dut.gdb_data_eval_expr('g_bss_var') == '55' - assert re.search(r'0x[0-9a-fA-F]+ "Coredump Test"', dut.gdb_data_eval_expr('g_heap_ptr')) - assert int(dut.gdb_data_eval_expr('g_cd_iram')) == 0x4243 - assert int(dut.gdb_data_eval_expr('g_cd_dram')) == 0x4344 - assert int(dut.gdb_data_eval_expr('g_noinit_var')) == 0xCAFEBABE - buffer_value = str(dut.gdb_data_eval_expr('g_noinit_buffer')) - assert 'NOINIT_TEST_STRING' in buffer_value - - if dut.target not in ['esp32c61', 'esp32c2']: - assert int(dut.gdb_data_eval_expr('g_rtc_data_var')) == 0x55AA - assert int(dut.gdb_data_eval_expr('g_rtc_fast_var')) == 0xAABBCCDD - - -def _test_coredump_summary(dut: PanicTestDut, flash_encrypted: bool, coredump_encrypted: bool) -> None: - dut.run_test_func('test_setup_coredump_summary') - dut.expect_cpu_reset() - if flash_encrypted: - dut.expect_exact('Flash encryption mode is DEVELOPMENT (not secure)') - dut.run_test_func('test_coredump_summary') - if flash_encrypted and not coredump_encrypted: - dut.expect_exact('Flash encryption enabled in hardware and core dump partition is not encrypted!') - return - dut.expect_elf_sha256('App ELF file SHA256: ') - dut.expect_exact('Crashed task: main') - if dut.is_xtensa: - dut.expect_exact('Exception cause: 0') - else: - dut.expect_exact('Exception cause: 2') - dut.expect(PANIC_ABORT_PREFIX + r'assert failed:[\s\w()]*?\s[.\w/]*\.(?:c|cpp|h|hpp):\d.*$') - - -@pytest.mark.generic -@idf_parametrize('config, target', CONFIG_COREDUMP_SUMMARY, indirect=['config', 'target']) -def test_coredump_summary(dut: PanicTestDut) -> None: - _test_coredump_summary(dut, False, False) - - -@pytest.mark.flash_encryption -@idf_parametrize('config, target', CONFIG_COREDUMP_SUMMARY_FLASH_ENCRYPTED, indirect=['config', 'target']) -def test_coredump_summary_flash_encrypted(dut: PanicTestDut, config: str) -> None: - _test_coredump_summary(dut, True, config == 'coredump_flash_encrypted') - - -@pytest.mark.generic -@idf_parametrize('config', ['coredump_flash_default'], indirect=['config']) -@idf_parametrize('target', TARGETS_ALL, indirect=['target']) -def test_tcb_corrupted(dut: PanicTestDut, target: str, config: str, test_func_name: str) -> None: - dut.run_test_func(test_func_name) - if dut.is_xtensa: - dut.expect(re.compile(rb"Guru Meditation Error: Core\s+\d\s+panic'ed \((LoadProhibited|StoreProhibited)\)")) - dut.expect_reg_dump() - dut.expect_backtrace() - else: - dut.expect(re.compile(rb"Guru Meditation Error: Core\s+\d\s+panic'ed \((Load|Store) access fault\)")) - dut.expect_reg_dump() - dut.expect_stack_dump() - - dut.expect_elf_sha256() - dut.expect_none('Guru Meditation') - - # Verify that valid tasks are captured in coredump despite IDLE task corruption - # TCB NAME - # ---------- ---------------- - if dut.is_multi_core: - regex_patterns = [ - rb'[0-9xa-fA-F] main', - rb'[0-9xa-fA-F] ipc0', - rb'[0-9xa-fA-F] ipc1', - ] - else: - regex_patterns = [rb'[0-9xa-fA-F] main'] - - coredump_pattern = [re.compile(pattern.decode('utf-8')) for pattern in regex_patterns] - - common_test(dut, config, expected_backtrace=None, expected_coredump=coredump_pattern) - - @pytest.mark.generic @idf_parametrize('config, target', CONFIG_PANIC_HALT, indirect=['config', 'target']) def test_panic_halt(dut: PanicTestDut) -> None: diff --git a/tools/test_apps/system/panic/sdkconfig.ci.framepointer b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.framepointer similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.framepointer rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.framepointer diff --git a/tools/test_apps/system/panic/sdkconfig.ci.gdbstub b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.gdbstub similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.gdbstub rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.gdbstub diff --git a/tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32c2 b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32c2 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32c2 rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32c2 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32c3 b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32c3 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32c3 rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32c3 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32c5 b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32c5 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32c5 rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32c5 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32c6 b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32c6 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32c6 rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32c6 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32c61 b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32c61 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32c61 rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32c61 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32h2 b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32h2 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32h2 rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32h2 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32h21 b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32h21 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32h21 rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32h21 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32p4 b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32p4 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32p4 rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32p4 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32s2 b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32s2 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32s2 rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32s2 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32s3 b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32s3 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.memprot_esp32s3 rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_esp32s3 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.memprot_spiram_xip_esp32c5 b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_spiram_xip_esp32c5 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.memprot_spiram_xip_esp32c5 rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_spiram_xip_esp32c5 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.memprot_spiram_xip_esp32c61 b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_spiram_xip_esp32c61 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.memprot_spiram_xip_esp32c61 rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_spiram_xip_esp32c61 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.memprot_spiram_xip_esp32p4 b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_spiram_xip_esp32p4 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.memprot_spiram_xip_esp32p4 rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_spiram_xip_esp32p4 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.memprot_spiram_xip_esp32s3 b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_spiram_xip_esp32s3 similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.memprot_spiram_xip_esp32s3 rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.memprot_spiram_xip_esp32s3 diff --git a/tools/test_apps/system/panic/sdkconfig.ci.panic b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.panic similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.panic rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.panic diff --git a/tools/test_apps/system/panic/sdkconfig.ci.panic_delay b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.panic_delay similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.panic_delay rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.panic_delay diff --git a/tools/test_apps/system/panic/sdkconfig.ci.panic_halt b/tools/test_apps/system/panic/panic_base/sdkconfig.ci.panic_halt similarity index 100% rename from tools/test_apps/system/panic/sdkconfig.ci.panic_halt rename to tools/test_apps/system/panic/panic_base/sdkconfig.ci.panic_halt diff --git a/tools/test_apps/system/panic/panic_base/sdkconfig.defaults b/tools/test_apps/system/panic/panic_base/sdkconfig.defaults new file mode 100644 index 00000000000..722718ce589 --- /dev/null +++ b/tools/test_apps/system/panic/panic_base/sdkconfig.defaults @@ -0,0 +1,18 @@ +# Flash DOUT mode (QEMU limitation) +CONFIG_ESPTOOLPY_FLASHMODE_DOUT=y + +# Less noisy output +CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y +CONFIG_LOG_DEFAULT_LEVEL_WARN=y + +# To check for stack overflows +CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y + +# To panic on task WDT +CONFIG_ESP_TASK_WDT_PANIC=y + +# For vTaskGetInfo() used in test_stack_overflow() +CONFIG_FREERTOS_USE_TRACE_FACILITY=y + +# Increase main task stack size +CONFIG_ESP_MAIN_TASK_STACK_SIZE=4096 diff --git a/tools/test_apps/system/panic/test_panic_util/__init__.py b/tools/test_apps/system/panic/panic_base/test_panic_util/__init__.py similarity index 100% rename from tools/test_apps/system/panic/test_panic_util/__init__.py rename to tools/test_apps/system/panic/panic_base/test_panic_util/__init__.py diff --git a/tools/test_apps/system/panic/test_panic_util/panic_dut.py b/tools/test_apps/system/panic/panic_base/test_panic_util/panic_dut.py similarity index 100% rename from tools/test_apps/system/panic/test_panic_util/panic_dut.py rename to tools/test_apps/system/panic/panic_base/test_panic_util/panic_dut.py