Merge branch 'extend_coredump_tests_v5.3' into 'release/v5.3'

Extend coredump tests v5.3

See merge request espressif/esp-idf!33456
This commit is contained in:
Alexey Gerenkov
2024-12-10 21:54:42 +08:00
16 changed files with 253 additions and 94 deletions

View File

@@ -18,6 +18,7 @@
#ifdef CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF #ifdef CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF
#include <sys/param.h> // for the MIN macro #include <sys/param.h> // for the MIN macro
#include "esp_app_desc.h" #include "esp_app_desc.h"
#include "esp_memory_utils.h"
#endif #endif
#define ELF_CLASS ELFCLASS32 #define ELF_CLASS ELFCLASS32
@@ -300,22 +301,6 @@ static int elf_add_regs(core_dump_elf_t *self, core_dump_task_header_t *task)
len); len);
} }
static int elf_add_stack(core_dump_elf_t *self, core_dump_task_header_t *task)
{
uint32_t stack_vaddr, stack_len = 0, stack_paddr = 0;
ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid task pointer.");
stack_len = esp_core_dump_get_stack(task, &stack_vaddr, &stack_paddr);
ESP_COREDUMP_LOG_PROCESS("Add stack for task 0x%x: addr 0x%x, sz %u",
task->tcb_addr, stack_vaddr, stack_len);
int ret = elf_add_segment(self, PT_LOAD,
(uint32_t)stack_vaddr,
(void*)stack_paddr,
(uint32_t) stack_len);
return ret;
}
static int elf_add_tcb(core_dump_elf_t *self, core_dump_task_header_t *task) static int elf_add_tcb(core_dump_elf_t *self, core_dump_task_header_t *task)
{ {
ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid task pointer."); ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid task pointer.");
@@ -348,17 +333,39 @@ static int elf_process_task_tcb(core_dump_elf_t *self, core_dump_task_header_t *
static int elf_process_task_stack(core_dump_elf_t *self, core_dump_task_header_t *task) static int elf_process_task_stack(core_dump_elf_t *self, core_dump_task_header_t *task)
{ {
int ret = ELF_PROC_ERR_OTHER; int ret = 0;
uint32_t stack_vaddr;
uint32_t stack_len = 0;
uint32_t stack_paddr = 0;
ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid input data."); ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid input data.");
ret = elf_add_stack(self, task); stack_len = esp_core_dump_get_stack(task, &stack_vaddr, &stack_paddr);
ESP_COREDUMP_LOG_PROCESS("Add stack for task 0x%x: addr 0x%x, sz %u",
task->tcb_addr, stack_vaddr, stack_len);
#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM
/*
When saving all data sections (enabled by `CONFIG_ESP_COREDUMP_CAPTURE_DRAM`),
the task stack located in DRAM will be saved in `esp_core_dump_store_section()`.
Therefore, we filter them out here.
PSRAM data do not fall into any ELF section, so we always save such stacks here.
*/
if (esp_ptr_external_ram((void *)stack_vaddr))
#endif
{
ret = elf_add_segment(self, PT_LOAD,
(uint32_t)stack_vaddr,
(void*)stack_paddr,
(uint32_t) stack_len);
if (ret <= 0) { if (ret <= 0) {
ESP_COREDUMP_LOGE("Task (TCB:%x), (Stack:%x), stack processing failure = %d.", ESP_COREDUMP_LOGE("Task (TCB:%x), (Stack:%x), stack processing failure = %d.",
task->tcb_addr, task->tcb_addr,
task->stack_start, task->stack_start,
ret); ret);
} }
}
return ret; return ret;
} }
@@ -453,21 +460,15 @@ static int elf_save_task(core_dump_elf_t *self, core_dump_task_header_t *task)
return elf_len; return elf_len;
} }
static int elf_write_tasks_data(core_dump_elf_t *self) static int elf_process_task_data(core_dump_elf_t *self)
{ {
int elf_len = 0; int elf_len = 0;
core_dump_task_header_t task_hdr = { 0 }; core_dump_task_header_t task_hdr = { 0 };
core_dump_mem_seg_header_t interrupted_stack = { 0 }; core_dump_mem_seg_header_t interrupted_stack = { 0 };
TaskIterator_t task_iter; TaskIterator_t task_iter;
int ret = ELF_PROC_ERR_OTHER;
uint16_t tasks_num = 0; uint16_t tasks_num = 0;
uint16_t bad_tasks_num = 0; uint16_t bad_tasks_num = 0;
ESP_COREDUMP_LOG_PROCESS("================ Processing task registers ================");
ret = elf_process_tasks_regs(self);
ELF_CHECK_ERR((ret > 0), ret, "Tasks regs addition failed, return (%d).", ret);
elf_len += ret;
ESP_COREDUMP_LOG_PROCESS("================ Processing task data ================"); ESP_COREDUMP_LOG_PROCESS("================ Processing task data ================");
// processes all task's stack data and writes segment data into partition // processes all task's stack data and writes segment data into partition
// if flash configuration is set // if flash configuration is set
@@ -479,17 +480,16 @@ static int elf_write_tasks_data(core_dump_elf_t *self)
bad_tasks_num++; bad_tasks_num++;
continue; continue;
} }
int ret = elf_save_task(self, &task_hdr);
#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM
/* Only crashed task data will be saved here. The other task's data will be automatically saved within the sections */
if (esp_core_dump_get_current_task_handle() == task_iter.pxTaskHandle)
#endif
{
ret = elf_save_task(self, &task_hdr);
ELF_CHECK_ERR((ret > 0), ret, ELF_CHECK_ERR((ret > 0), ret,
"Task %x, TCB write failed, return (%d).", task_iter.pxTaskHandle, ret); "Task %x, TCB write failed, return (%d).", task_iter.pxTaskHandle, ret);
elf_len += ret; elf_len += ret;
} /* interrupt stacks:
- 'port_IntStack' is in the data section for xtensa
- 'xIsrStack' is in the bss section for risc-v
When DRAM capture is enabled, interrupt stack saving can be done during the full section store
*/
#if !CONFIG_ESP_COREDUMP_CAPTURE_DRAM
if (interrupted_stack.size > 0) { if (interrupted_stack.size > 0) {
ESP_COREDUMP_LOG_PROCESS("Add interrupted task stack %lu bytes @ %x", ESP_COREDUMP_LOG_PROCESS("Add interrupted task stack %lu bytes @ %x",
interrupted_stack.size, interrupted_stack.start); interrupted_stack.size, interrupted_stack.start);
@@ -500,11 +500,28 @@ static int elf_write_tasks_data(core_dump_elf_t *self)
ELF_CHECK_ERR((ret > 0), ret, "Interrupted task stack write failed, return (%d).", ret); ELF_CHECK_ERR((ret > 0), ret, "Interrupted task stack write failed, return (%d).", ret);
elf_len += ret; elf_len += ret;
} }
#endif
} }
ESP_COREDUMP_LOG_PROCESS("Found %d bad task out of %d", bad_tasks_num, tasks_num); ESP_COREDUMP_LOG_PROCESS("Found %d bad task out of %d", bad_tasks_num, tasks_num);
return elf_len; return elf_len;
} }
static int elf_write_tasks_data(core_dump_elf_t *self)
{
ESP_COREDUMP_LOG_PROCESS("================ Processing task registers ================");
int ret = elf_process_tasks_regs(self);
ELF_CHECK_ERR((ret > 0), ret, "Tasks regs addition failed, return (%d).", ret);
int elf_len = ret;
ret = elf_process_task_data(self);
if (ret <= 0) {
return ret;
}
return elf_len + ret;
}
#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM #if CONFIG_ESP_COREDUMP_CAPTURE_DRAM
/* Coredump stack will also be used by the checksum functions while saving sections. /* Coredump stack will also be used by the checksum functions while saving sections.

View File

@@ -17,7 +17,7 @@ if(CONFIG_TEST_MEMPROT)
endif() endif()
endif() endif()
if(NOT CONFIG_TEST_MEMPROT AND NOT CONFIG_ESP_COREDUMP_CAPTURE_DRAM) if(NOT CONFIG_TEST_MEMPROT AND NOT CONFIG_ESP_COREDUMP_CAPTURE_DRAM AND NOT CONFIG_SPIRAM)
# Enable UBSAN checks # Enable UBSAN checks
# #
# shift-base sanitizer is disabled due to the following pattern found in register header files: # shift-base sanitizer is disabled due to the following pattern found in register header files:

View File

@@ -13,8 +13,8 @@ endif()
idf_component_register(SRCS "${srcs}" idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include" INCLUDE_DIRS "include"
REQUIRES spi_flash esp_psram esp_system esp_partition espcoredump REQUIRES spi_flash esp_psram esp_system esp_partition
PRIV_REQUIRES esp_gdbstub) PRIV_REQUIRES esp_gdbstub espcoredump)
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-unused-variable" target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-unused-variable"
"-Wno-infinite-recursion" "-Wno-infinite-recursion"

View File

@@ -32,7 +32,10 @@ void test_hw_stack_guard_cpu1(void);
#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD #endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
void test_panic_extram_stack(void); void test_panic_extram_stack_heap(void);
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
void test_panic_extram_stack_bss(void);
#endif
#endif #endif
#if !CONFIG_FREERTOS_UNICORE #if !CONFIG_FREERTOS_UNICORE
@@ -67,6 +70,8 @@ void test_illegal_access(void);
void test_capture_dram(void); void test_capture_dram(void);
void test_tcb_corrupted(void);
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF
void test_setup_coredump_summary(void); void test_setup_coredump_summary(void);
void test_coredump_summary(void); void test_coredump_summary(void);

View File

@@ -96,7 +96,10 @@ void app_main(void)
#endif // CONFIG_FREERTOS_UNICORE #endif // CONFIG_FREERTOS_UNICORE
#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD #endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
HANDLE_TEST(test_name, test_panic_extram_stack); HANDLE_TEST(test_name, test_panic_extram_stack_heap);
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
HANDLE_TEST(test_name, test_panic_extram_stack_bss);
#endif
#endif #endif
#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM #if CONFIG_ESP_COREDUMP_CAPTURE_DRAM
HANDLE_TEST(test_name, test_capture_dram); HANDLE_TEST(test_name, test_capture_dram);
@@ -116,6 +119,7 @@ void app_main(void)
HANDLE_TEST(test_name, test_assert_cache_disabled); HANDLE_TEST(test_name, test_assert_cache_disabled);
HANDLE_TEST(test_name, test_assert_cache_write_back_error_can_print_backtrace); HANDLE_TEST(test_name, test_assert_cache_write_back_error_can_print_backtrace);
HANDLE_TEST(test_name, test_assert_cache_write_back_error_can_print_backtrace2); HANDLE_TEST(test_name, test_assert_cache_write_back_error_can_print_backtrace2);
HANDLE_TEST(test_name, test_tcb_corrupted);
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF
HANDLE_TEST(test_name, test_setup_coredump_summary); HANDLE_TEST(test_name, test_setup_coredump_summary);
HANDLE_TEST(test_name, test_coredump_summary); HANDLE_TEST(test_name, test_coredump_summary);

View File

@@ -104,7 +104,7 @@ static void stack_in_extram(void* arg) {
abort(); abort();
} }
void test_panic_extram_stack(void) { void test_panic_extram_stack_heap(void) {
/* Start by initializing a Task which has a stack in external RAM */ /* Start by initializing a Task which has a stack in external RAM */
StaticTask_t handle; StaticTask_t handle;
const uint32_t stack_size = 8192; const uint32_t stack_size = 8192;
@@ -119,8 +119,17 @@ void test_panic_extram_stack(void) {
vTaskDelay(1000); vTaskDelay(1000);
} }
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
static EXT_RAM_BSS_ATTR StackType_t stack[8192];
void test_panic_extram_stack_bss(void)
{
StaticTask_t handle;
xTaskCreateStatic(stack_in_extram, "Task_stack_extram", sizeof(stack), NULL, 4, stack, &handle);
vTaskDelay(1000);
}
#endif
#endif // ESP_COREDUMP_ENABLE_TO_FLASH && SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY #endif // ESP_COREDUMP_ENABLE_TO_FLASH && SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
@@ -301,6 +310,15 @@ void test_coredump_summary(void)
} }
#endif #endif
void test_tcb_corrupted(void)
{
uint32_t *tcb_ptr = (uint32_t *)xTaskGetIdleTaskHandleForCore(0);
for (size_t i = 0; i < sizeof(StaticTask_t) / sizeof(uint32_t); ++i) {
tcb_ptr[i] = 0xDEADBEE0;
}
vTaskDelay(2);
}
/* NOTE: The following test verifies the behaviour for the /* NOTE: The following test verifies the behaviour for the
* Xtensa-specific MPU instructions (Refer WDTLB, DSYNC, WDTIB, ISYNC) * Xtensa-specific MPU instructions (Refer WDTLB, DSYNC, WDTIB, ISYNC)
* used for memory protection. * used for memory protection.

View File

@@ -1,8 +1,11 @@
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0 # SPDX-License-Identifier: CC0-1.0
import re import re
from typing import Any
from typing import List from typing import List
from typing import Optional from typing import Optional
from typing import Pattern
from typing import Sequence
from typing import Union from typing import Union
import pexpect import pexpect
@@ -67,11 +70,13 @@ CONFIGS_DUAL_CORE = [
# This list is used to check if the target is a dual-core one. # This list is used to check if the target is a dual-core one.
TARGETS_DUAL_CORE_NAMES = [x.mark.name for x in TARGETS_DUAL_CORE] TARGETS_DUAL_CORE_NAMES = [x.mark.name for x in TARGETS_DUAL_CORE]
# The tests which panic on external stack require PSRAM capable runners
CONFIGS_EXTRAM_STACK = [ CONFIGS_EXTRAM_STACK = [
pytest.param('coredump_extram_stack', marks=[pytest.mark.esp32, pytest.mark.psram]), pytest.param('coredump_flash_extram_stack_heap_esp32', marks=[pytest.mark.esp32, pytest.mark.psram]),
pytest.param('coredump_extram_stack', marks=[pytest.mark.esp32s2, pytest.mark.generic]), pytest.param('coredump_flash_extram_stack_heap_esp32s2', marks=[pytest.mark.esp32s2, pytest.mark.generic]),
pytest.param('coredump_extram_stack', marks=[pytest.mark.esp32s3, pytest.mark.quad_psram]), pytest.param('coredump_flash_extram_stack_heap_esp32s3', marks=[pytest.mark.esp32s3, pytest.mark.quad_psram]),
pytest.param('coredump_flash_extram_stack_bss_esp32', marks=[pytest.mark.esp32, pytest.mark.psram]),
pytest.param('coredump_flash_extram_stack_bss_esp32s2', marks=[pytest.mark.esp32s2, pytest.mark.generic]),
pytest.param('coredump_flash_extram_stack_bss_esp32s3', marks=[pytest.mark.esp32s3, pytest.mark.quad_psram]),
] ]
CONFIGS_HW_STACK_GUARD = [ CONFIGS_HW_STACK_GUARD = [
@@ -107,9 +112,20 @@ def get_default_backtrace(config: str) -> List[str]:
return [config, 'app_main', 'main_task', 'vPortTaskWrapper'] return [config, 'app_main', 'main_task', 'vPortTaskWrapper']
def expect_coredump_flash_write_logs(dut: PanicTestDut, config: str) -> None:
dut.expect_exact('Save core dump to flash...')
if 'extram_stack' in config:
dut.expect_exact('Backing up stack @')
dut.expect_exact('Restoring stack')
dut.expect_exact('Core dump has been saved to flash.')
dut.expect('Rebooting...')
def common_test(dut: PanicTestDut, config: str, expected_backtrace: Optional[List[str]] = None, check_cpu_reset: Optional[bool] = True, def common_test(dut: PanicTestDut, config: str, expected_backtrace: Optional[List[str]] = None, check_cpu_reset: Optional[bool] = True,
expected_coredump: Optional[List[Union[str, re.Pattern]]] = None) -> None: expected_coredump: Optional[Sequence[Union[str, Pattern[Any]]]] = None) -> None:
if 'gdbstub' in config: if 'gdbstub' in config:
if 'coredump' in config:
dut.process_coredump_uart(expected_coredump, False)
dut.expect_exact('Entering gdb stub now.') dut.expect_exact('Entering gdb stub now.')
dut.start_gdb_for_gdbstub() dut.start_gdb_for_gdbstub()
frames = dut.gdb_backtrace() frames = dut.gdb_backtrace()
@@ -125,10 +141,9 @@ def common_test(dut: PanicTestDut, config: str, expected_backtrace: Optional[Lis
if 'uart' in config: if 'uart' in config:
dut.process_coredump_uart(expected_coredump) dut.process_coredump_uart(expected_coredump)
elif 'flash' in config: elif 'flash' in config:
expect_coredump_flash_write_logs(dut, config)
dut.process_coredump_flash(expected_coredump) dut.process_coredump_flash(expected_coredump)
elif 'panic' in config: elif 'panic' in config:
pass
dut.expect('Rebooting...') dut.expect('Rebooting...')
if check_cpu_reset: if check_cpu_reset:
@@ -205,21 +220,32 @@ def test_task_wdt_cpu1(dut: PanicTestDut, config: str, test_func_name: str) -> N
@pytest.mark.parametrize('config', CONFIGS_EXTRAM_STACK, indirect=True) @pytest.mark.parametrize('config', CONFIGS_EXTRAM_STACK, indirect=True)
def test_panic_extram_stack(dut: PanicTestDut, config: str, test_func_name: str) -> None: def test_panic_extram_stack(dut: PanicTestDut, config: str) -> None:
dut.run_test_func(test_func_name) 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('Allocated stack is not in external RAM')
dut.expect_none('Guru Meditation') dut.expect_none('Guru Meditation')
dut.expect_backtrace() dut.expect_backtrace()
dut.expect_elf_sha256() dut.expect_elf_sha256()
# Check that coredump is getting written to flash
dut.expect_exact('Save core dump to flash...')
# And that the stack is replaced and restored
dut.expect_exact('Backing up stack @')
dut.expect_exact('Restoring stack')
# The caller must be accessible after restoring the stack
dut.expect_exact('Core dump has been saved to flash.')
common_test(dut, config) 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.parametrize('config', CONFIGS, indirect=True) @pytest.mark.parametrize('config', CONFIGS, indirect=True)
@@ -859,7 +885,7 @@ def test_rtc_slow_reg1_execute_violation(dut: PanicTestDut, test_func_name: str)
dut.expect_gme('Memory protection fault') dut.expect_gme('Memory protection fault')
dut.expect(r'Read operation at address [0-9xa-f]+ not permitted \((\S+)\)') dut.expect(r'Read operation at address [0-9xa-f]+ not permitted \((\S+)\)')
dut.expect_reg_dump(0) dut.expect_reg_dump(0)
dut.expect_corrupted_backtrace() dut.expect_backtrace(corrupted=True)
dut.expect_cpu_reset() dut.expect_cpu_reset()
@@ -870,7 +896,7 @@ def test_rtc_slow_reg2_execute_violation(dut: PanicTestDut, test_func_name: str)
dut.expect_gme('Memory protection fault') dut.expect_gme('Memory protection fault')
dut.expect(r'Read operation at address [0-9xa-f]+ not permitted \((\S+)\)') dut.expect(r'Read operation at address [0-9xa-f]+ not permitted \((\S+)\)')
dut.expect_reg_dump(0) dut.expect_reg_dump(0)
dut.expect_corrupted_backtrace() dut.expect_backtrace(corrupted=True)
dut.expect_cpu_reset() dut.expect_cpu_reset()
@@ -925,15 +951,7 @@ def test_invalid_memory_region_execute_violation(dut: PanicTestDut, test_func_na
def test_gdbstub_coredump(dut: PanicTestDut) -> None: def test_gdbstub_coredump(dut: PanicTestDut) -> None:
test_func_name = 'test_storeprohibited' test_func_name = 'test_storeprohibited'
dut.run_test_func(test_func_name) dut.run_test_func(test_func_name)
common_test(dut, 'gdbstub_coredump', get_default_backtrace(test_func_name))
dut.process_coredump_uart()
dut.expect_exact('Entering gdb stub now.')
dut.start_gdb_for_gdbstub()
frames = dut.gdb_backtrace()
dut.verify_gdb_backtrace(frames, get_default_backtrace(test_func_name))
dut.revert_log_level()
return # don't expect "Rebooting" output below
def test_hw_stack_guard_cpu(dut: PanicTestDut, cpu: int) -> None: def test_hw_stack_guard_cpu(dut: PanicTestDut, cpu: int) -> None:
@@ -996,9 +1014,7 @@ def test_capture_dram(dut: PanicTestDut, config: str, test_func_name: str) -> No
dut.expect_elf_sha256() dut.expect_elf_sha256()
dut.expect_none(['Guru Meditation', 'Re-entered core dump']) dut.expect_none(['Guru Meditation', 'Re-entered core dump'])
dut.expect_exact('Save core dump to flash...') expect_coredump_flash_write_logs(dut, config)
dut.expect_exact('Core dump has been saved to flash.')
dut.expect('Rebooting...')
core_elf_file = dut.process_coredump_flash() core_elf_file = dut.process_coredump_flash()
dut.start_gdb_for_coredump(core_elf_file) dut.start_gdb_for_coredump(core_elf_file)
@@ -1042,3 +1058,38 @@ def test_coredump_summary(dut: PanicTestDut) -> None:
@pytest.mark.parametrize('config', CONFIG_COREDUMP_SUMMARY_FLASH_ENCRYPTED, indirect=True) @pytest.mark.parametrize('config', CONFIG_COREDUMP_SUMMARY_FLASH_ENCRYPTED, indirect=True)
def test_coredump_summary_flash_encrypted(dut: PanicTestDut, config: str) -> None: def test_coredump_summary_flash_encrypted(dut: PanicTestDut, config: str) -> None:
_test_coredump_summary(dut, True, config == 'coredump_flash_encrypted') _test_coredump_summary(dut, True, config == 'coredump_flash_encrypted')
@pytest.mark.parametrize('config', [pytest.param('coredump_flash_elf_sha', marks=TARGETS_ALL)], indirect=True)
@pytest.mark.generic
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_gme('LoadProhibited')
dut.expect_reg_dump()
dut.expect_backtrace()
else:
dut.expect_gme('Load access fault')
dut.expect_reg_dump()
dut.expect_stack_dump()
dut.expect_elf_sha256()
dut.expect_none('Guru Meditation')
# 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
)

View File

@@ -1,6 +1,7 @@
CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y
CONFIG_ESP_COREDUMP_DATA_FORMAT_BIN=y CONFIG_ESP_COREDUMP_DATA_FORMAT_BIN=y
CONFIG_ESP_COREDUMP_CHECKSUM_CRC32=y CONFIG_ESP_COREDUMP_CHECKSUM_CRC32=y
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
# static D/IRAM usage 97%, add this to reduce # static D/IRAM usage 97%, add this to reduce
CONFIG_HAL_ASSERTION_DISABLE=y CONFIG_HAL_ASSERTION_DISABLE=y

View File

@@ -1,3 +1,4 @@
CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y
CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y
CONFIG_ESP_COREDUMP_CHECKSUM_SHA256=y CONFIG_ESP_COREDUMP_CHECKSUM_SHA256=y
CONFIG_LOG_DEFAULT_LEVEL_INFO=y

View File

@@ -0,0 +1,13 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y
CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y
CONFIG_ESP_COREDUMP_CHECKSUM_SHA256=y
# We need to have the coredump info log
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y
CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
CONFIG_ESP_COREDUMP_USE_STACK_SIZE=y
CONFIG_ESP_COREDUMP_CAPTURE_DRAM=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_capture_dram.csv"

View File

@@ -0,0 +1,13 @@
CONFIG_IDF_TARGET="esp32s2"
CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y
CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y
CONFIG_ESP_COREDUMP_CHECKSUM_SHA256=y
# We need to have the coredump info log
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y
CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
CONFIG_ESP_COREDUMP_USE_STACK_SIZE=y
CONFIG_ESP_COREDUMP_CAPTURE_DRAM=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_capture_dram.csv"

View File

@@ -0,0 +1,13 @@
CONFIG_IDF_TARGET="esp32s3"
CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y
CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y
CONFIG_ESP_COREDUMP_CHECKSUM_SHA256=y
# We need to have the coredump info log
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y
CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
CONFIG_ESP_COREDUMP_USE_STACK_SIZE=y
CONFIG_ESP_COREDUMP_CAPTURE_DRAM=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_capture_dram.csv"

View File

@@ -2,8 +2,6 @@ CONFIG_IDF_TARGET="esp32"
CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y
CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y
CONFIG_ESP_COREDUMP_CHECKSUM_SHA256=y CONFIG_ESP_COREDUMP_CHECKSUM_SHA256=y
# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set
CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y
# We need to have the coredump info log # We need to have the coredump info log
CONFIG_LOG_DEFAULT_LEVEL_INFO=y CONFIG_LOG_DEFAULT_LEVEL_INFO=y
CONFIG_SPIRAM=y CONFIG_SPIRAM=y

View File

@@ -0,0 +1,9 @@
CONFIG_IDF_TARGET="esp32s2"
CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y
CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y
CONFIG_ESP_COREDUMP_CHECKSUM_SHA256=y
# We need to have the coredump info log
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y
CONFIG_ESP_COREDUMP_USE_STACK_SIZE=y

View File

@@ -0,0 +1,9 @@
CONFIG_IDF_TARGET="esp32s3"
CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y
CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y
CONFIG_ESP_COREDUMP_CHECKSUM_SHA256=y
# We need to have the coredump info log
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y
CONFIG_ESP_COREDUMP_USE_STACK_SIZE=y

View File

@@ -80,15 +80,13 @@ class PanicTestDut(IdfDut):
except pexpect.TIMEOUT: except pexpect.TIMEOUT:
pass pass
def expect_backtrace(self) -> None: def expect_backtrace(self, corrupted: bool = False) -> None:
assert self.is_xtensa, 'Backtrace can be printed only on Xtensa' assert self.is_xtensa, 'Backtrace can be printed only on Xtensa'
match = self.expect(r'Backtrace:( 0x[0-9a-fA-F]{8}:0x[0-9a-fA-F]{8})+(?P<corrupted> \|<-CORRUPTED)?') match = self.expect(r'Backtrace:( 0x[0-9a-fA-F]{8}:0x[0-9a-fA-F]{8})+(?P<corrupted> \|<-CORRUPTED)?')
assert not match.group('corrupted') if corrupted:
assert match.group('corrupted')
def expect_corrupted_backtrace(self) -> None: else:
assert self.is_xtensa, 'Backtrace can be printed only on Xtensa' assert match
self.expect_exact('Backtrace:')
self.expect_exact('CORRUPTED')
def expect_stack_dump(self) -> None: def expect_stack_dump(self) -> None:
assert not self.is_xtensa, 'Stack memory dump is only printed on RISC-V' assert not self.is_xtensa, 'Stack memory dump is only printed on RISC-V'
@@ -98,9 +96,13 @@ class PanicTestDut(IdfDut):
"""Expect method for Guru Meditation Errors""" """Expect method for Guru Meditation Errors"""
self.expect_exact(f"Guru Meditation Error: Core 0 panic'ed ({reason})") self.expect_exact(f"Guru Meditation Error: Core 0 panic'ed ({reason})")
def expect_reg_dump(self, core: int = 0) -> None: def expect_reg_dump(self, core: Optional[int] = None) -> None:
"""Expect method for the register dump""" if core is None:
self.expect(r'Core\s+%d register dump:' % core) # Match any core num
self.expect(r'Core\s+\d+\s+register dump:')
else:
# Match the exact core num provided
self.expect(r'Core\s+%d\s+register dump:' % core)
def expect_cpu_reset(self) -> None: def expect_cpu_reset(self) -> None:
# no digital system reset for panic handling restarts (see IDF-7255) # no digital system reset for panic handling restarts (see IDF-7255)
@@ -153,11 +155,16 @@ class PanicTestDut(IdfDut):
self.coredump_output.flush() self.coredump_output.flush()
self.coredump_output.seek(0) self.coredump_output.seek(0)
def process_coredump_uart(self, expected: Optional[List[Union[str, re.Pattern]]] = None) -> None: def process_coredump_uart(
self, expected: Optional[List[Union[str, re.Pattern]]] = None, wait_reboot: bool = True
) -> None:
"""Extract the core dump from UART output of the test, run espcoredump on it""" """Extract the core dump from UART output of the test, run espcoredump on it"""
self.expect(self.COREDUMP_UART_START) self.expect(self.COREDUMP_UART_START)
res = self.expect('(.+)' + self.COREDUMP_UART_END) uart_data = self.expect('(.+)' + self.COREDUMP_UART_END)
coredump_base64 = res.group(1).decode('utf8') self.expect(re.compile(r"Coredump checksum='([a-fA-F0-9]+)'"))
if wait_reboot:
self.expect('Rebooting...')
coredump_base64 = uart_data.group(1).decode('utf8')
with open(os.path.join(self.logdir, 'coredump_data.b64'), 'w') as coredump_file: with open(os.path.join(self.logdir, 'coredump_data.b64'), 'w') as coredump_file:
logging.info('Writing UART base64 core dump to %s', coredump_file.name) logging.info('Writing UART base64 core dump to %s', coredump_file.name)
coredump_file.write(coredump_base64) coredump_file.write(coredump_base64)