feat(coredump): add panic details to the elf file

This commit is contained in:
Erhan Kurubas 2023-08-03 23:47:58 +02:00
parent d3f2e4dab5
commit 568c397822
10 changed files with 212 additions and 66 deletions

View File

@ -19,7 +19,7 @@ extern "C" {
#endif
extern bool g_panic_abort;
extern char *g_panic_abort_details;
extern void *g_exc_frames[SOC_CPU_CORES_NUM];
// Function to print longer amounts of information such as the details

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -63,7 +63,7 @@
#define MWDT_DEFAULT_TICKS_PER_US 500
bool g_panic_abort = false;
static char *s_panic_abort_details = NULL;
char *g_panic_abort_details = NULL;
static wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
@ -222,7 +222,7 @@ static inline void disable_all_wdts(void)
static void print_abort_details(const void *f)
{
panic_print_str(s_panic_abort_details);
panic_print_str(g_panic_abort_details);
}
// Control arrives from chip-specific panic handler, environment prepared for
@ -237,7 +237,7 @@ void esp_panic_handler(panic_info_t *info)
// If the exception was due to an abort, override some of the panic info
if (g_panic_abort) {
info->description = NULL;
info->details = s_panic_abort_details ? print_abort_details : NULL;
info->details = g_panic_abort_details ? print_abort_details : NULL;
info->reason = NULL;
info->exception = PANIC_EXCEPTION_ABORT;
}
@ -438,7 +438,7 @@ void esp_panic_handler(panic_info_t *info)
void IRAM_ATTR __attribute__((noreturn, no_sanitize_undefined)) panic_abort(const char *details)
{
g_panic_abort = true;
s_panic_abort_details = (char *) details;
g_panic_abort_details = (char *) details;
#if CONFIG_APPTRACE_ENABLE
#if CONFIG_APPTRACE_SV_ENABLE

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -127,6 +127,30 @@ esp_err_t esp_core_dump_image_erase(void);
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF
/**
* @brief Get panic reason from the core dump.
*
* This function retrieves the panic reason from the core dump data and copies it to the provided buffer.
*
* @param[in,out] reason_buffer Pointer to the buffer where the panic reason will be copied.
* @param[in] buffer_size Size of the destination buffer in bytes.
* @return
* - ESP_OK if the panic reason was successfully copied.
* - ESP_ERR_INVALID_ARG if reason_buffer is NULL or buffer_size is 0.
* - Other error codes indicating the outcome of the core dump retrieval.
* - ESP_ERR_NOT_FOUND if the panic reason is not found in the core dump.
*
* Example usage:
* @code{c}
char panic_reason[200];
esp_err_t err = esp_core_dump_get_panic_reason(panic_reason, sizeof(panic_reason));
if (err == ESP_OK) {
ESP_LOGW(TAG, "%s", panic_reason);
}
* @endcode
*/
esp_err_t esp_core_dump_get_panic_reason(char *reason_buffer, size_t buffer_size);
/**
* @brief Get the summary of a core dump.
*

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

View File

@ -15,6 +15,7 @@
#include "esp_core_dump_common.h"
#ifdef CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF
#include <sys/param.h> // for the MIN macro
#include "esp_app_desc.h"
#endif
@ -29,6 +30,7 @@
#define ELF_PR_STATUS_SEG_NUM 0
#define ELF_ESP_CORE_DUMP_INFO_TYPE 8266
#define ELF_ESP_CORE_DUMP_EXTRA_INFO_TYPE 677
#define ELF_ESP_CORE_DUMP_PANIC_DETAILS_TYPE 679
#define ELF_NOTE_NAME_MAX_SIZE 32
#define ELF_APP_SHA256_SIZE 66
@ -517,13 +519,23 @@ static int elf_write_core_dump_info(core_dump_elf_t *self)
}
ret = elf_add_note(self,
"EXTRA_INFO",
"ESP_EXTRA_INFO",
ELF_ESP_CORE_DUMP_EXTRA_INFO_TYPE,
extra_info,
extra_info_len);
ELF_CHECK_ERR((ret > 0), ret, "Extra info note write failed. Returned (%d).", ret);
data_len += ret;
if (g_panic_abort_details && strlen(g_panic_abort_details) > 0) {
ret = elf_add_note(self,
"ESP_PANIC_DETAILS",
ELF_ESP_CORE_DUMP_PANIC_DETAILS_TYPE,
g_panic_abort_details,
strlen(g_panic_abort_details));
ELF_CHECK_ERR((ret > 0), ret, "Panic details note write failed. Returned (%d).", ret);
data_len += ret;
}
ret = elf_process_note_segment(self, data_len);
ELF_CHECK_ERR((ret > 0), ret,
"EXTRA_INFO note segment processing failure, returned(%d).", ret);
@ -642,8 +654,18 @@ esp_err_t esp_core_dump_write_elf(core_dump_write_config_t *write_cfg)
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
/* Below are the helper function to parse the core dump ELF stored in flash */
typedef struct {
#if ELF_CLASS == ELFCLASS32
Elf32_Word n_type;
Elf32_Word n_descsz;
#else
Elf64_Word n_type;
Elf64_Word n_descsz;
#endif
void *n_ptr;
} elf_note_content_t;
/* Below are the helper function to parse the core dump ELF stored in flash */
static esp_err_t elf_core_dump_image_mmap(esp_partition_mmap_handle_t* core_data_handle, const void **map_addr)
{
size_t out_size;
@ -700,62 +722,118 @@ static void elf_parse_exc_task_name(esp_core_dump_summary_t *summary, void *tcb_
ESP_COREDUMP_LOGD("Crashing task %s", summary->exc_task);
}
esp_err_t esp_core_dump_get_summary(esp_core_dump_summary_t *summary)
static uint8_t *elf_core_dump_image_ptr(esp_partition_mmap_handle_t *core_data_handle)
{
int i;
elf_phdr *ph;
elf_note *note;
const void *map_addr;
size_t consumed_note_sz;
esp_partition_mmap_handle_t core_data_handle;
if (!core_data_handle) {
return NULL;
}
if (!summary) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = elf_core_dump_image_mmap(&core_data_handle, &map_addr);
const void *map_addr;
esp_err_t err = elf_core_dump_image_mmap(core_data_handle, &map_addr);
if (err != ESP_OK) {
return err;
return NULL;
}
uint8_t *ptr = (uint8_t *) map_addr + sizeof(core_dump_header_t);
elfhdr *eh = (elfhdr *)ptr;
return (uint8_t *)map_addr + sizeof(core_dump_header_t);
}
ESP_COREDUMP_LOGD("ELF ident %02x %c %c %c", eh->e_ident[0], eh->e_ident[1], eh->e_ident[2], eh->e_ident[3]);
static void esp_core_dump_parse_note_section(uint8_t *coredump_data, elf_note_content_t *target_notes, size_t size)
{
elfhdr *eh = (elfhdr *)coredump_data;
elf_phdr *phdr = (elf_phdr *)(coredump_data + eh->e_phoff);
ESP_COREDUMP_LOGD("ELF ident %02x %c %c %c", eh->e_ident[0], eh->e_ident[1], eh->e_ident[2], eh->e_ident[3]);
ESP_COREDUMP_LOGD("Ph_num %d offset %x", eh->e_phnum, eh->e_phoff);
for (i = 0; i < eh->e_phnum; i++) {
ph = (elf_phdr *)((ptr + i * sizeof(*ph)) + eh->e_phoff);
ESP_COREDUMP_LOGD("PHDR type %d off %x vaddr %x paddr %x filesz %x memsz %x flags %x align %x",
ph->p_type, ph->p_offset, ph->p_vaddr, ph->p_paddr, ph->p_filesz, ph->p_memsz,
ph->p_flags, ph->p_align);
for (unsigned int i = 0; i < eh->e_phnum; i++) {
const elf_phdr *ph = &phdr[i];
ESP_COREDUMP_LOGD("PHDR type %d off %x vaddr %x paddr %x filesz %x memsz %x flags %x align %x",
ph->p_type, ph->p_offset, ph->p_vaddr, ph->p_paddr, ph->p_filesz, ph->p_memsz,
ph->p_flags, ph->p_align);
if (ph->p_type == PT_NOTE) {
consumed_note_sz = 0;
while(consumed_note_sz < ph->p_memsz) {
note = (elf_note *)(ptr + ph->p_offset + consumed_note_sz);
char *nm = (char *)(ptr + ph->p_offset + consumed_note_sz + sizeof(elf_note));
ESP_COREDUMP_LOGD("Note NameSZ %x DescSZ %x Type %x name %s", note->n_namesz,
note->n_descsz, note->n_type, nm);
if (strncmp(nm, "EXTRA_INFO", note->n_namesz) == 0 ) {
esp_core_dump_summary_parse_extra_info(summary, (void *)(nm + note->n_namesz));
}
if (strncmp(nm, "ESP_CORE_DUMP_INFO", note->n_namesz) == 0 ) {
elf_parse_version_info(summary, (void *)(nm + note->n_namesz));
}
size_t consumed_note_sz = 0;
while (consumed_note_sz < ph->p_memsz) {
const elf_note *note = (const elf_note *)(coredump_data + ph->p_offset + consumed_note_sz);
for (size_t idx = 0; idx < size; ++idx) {
if (target_notes[idx].n_type == note->n_type) {
char *nm = (char *)&note[1];
target_notes[idx].n_ptr = nm + note->n_namesz;
target_notes[idx].n_descsz = note->n_descsz;
ESP_COREDUMP_LOGD("%d bytes target note (%X) found in the note section",
note->n_descsz, note->n_type);
break;
}
}
consumed_note_sz += note->n_namesz + note->n_descsz + sizeof(elf_note);
ALIGN(4, consumed_note_sz);
}
}
}
}
esp_err_t esp_core_dump_get_panic_reason(char *reason_buffer, size_t buffer_size)
{
if (!reason_buffer || buffer_size == 0) {
return ESP_ERR_INVALID_ARG;
}
esp_partition_mmap_handle_t core_data_handle;
uint8_t *ptr = elf_core_dump_image_ptr(&core_data_handle);
if (ptr == NULL) {
return ESP_FAIL;
}
elf_note_content_t target_note = { .n_type = ELF_ESP_CORE_DUMP_PANIC_DETAILS_TYPE, .n_ptr = NULL };
esp_core_dump_parse_note_section(ptr, &target_note, 1);
if (target_note.n_ptr) {
size_t len = MIN(target_note.n_descsz, buffer_size - 1);
strncpy(reason_buffer, target_note.n_ptr, len);
reason_buffer[len] = '\0';
}
esp_partition_munmap(core_data_handle);
return target_note.n_ptr ? ESP_OK : ESP_ERR_NOT_FOUND;
}
esp_err_t esp_core_dump_get_summary(esp_core_dump_summary_t *summary)
{
if (!summary) {
return ESP_ERR_INVALID_ARG;
}
esp_partition_mmap_handle_t core_data_handle;
uint8_t *ptr = elf_core_dump_image_ptr(&core_data_handle);
if (ptr == NULL) {
return ESP_FAIL;
}
elf_note_content_t target_notes[2] = {
[0] = { .n_type = ELF_ESP_CORE_DUMP_EXTRA_INFO_TYPE, .n_ptr = NULL },
[1] = { .n_type = ELF_ESP_CORE_DUMP_INFO_TYPE, .n_ptr = NULL }
};
esp_core_dump_parse_note_section(ptr, target_notes, sizeof(target_notes) / sizeof(target_notes[0]));
if (target_notes[0].n_ptr) {
esp_core_dump_summary_parse_extra_info(summary, target_notes[0].n_ptr);
}
if (target_notes[1].n_ptr) {
elf_parse_version_info(summary, target_notes[1].n_ptr);
}
/* Following code assumes that task stack segment follows the TCB segment for the respective task.
* In general ELF does not impose any restrictions on segments' order so this can be changed without impacting core dump version.
* More universal and flexible way would be to retrieve stack start address from crashed task TCB segment and then look for the stack segment with that address.
*/
elfhdr *eh = (elfhdr *)ptr;
elf_phdr *phdr = (elf_phdr *)(ptr + eh->e_phoff);
int flag = 0;
for (i = 0; i < eh->e_phnum; i++) {
ph = (elf_phdr *)((ptr + i * sizeof(*ph)) + eh->e_phoff);
for (unsigned int i = 0; i < eh->e_phnum; i++) {
const elf_phdr *ph = &phdr[i];
if (ph->p_type == PT_LOAD) {
if (flag) {
esp_core_dump_summary_parse_exc_regs(summary, (void *)(ptr + ph->p_offset));
esp_core_dump_summary_parse_backtrace_info(&summary->exc_bt_info, (void *) ph->p_vaddr,
esp_core_dump_summary_parse_backtrace_info(&summary->exc_bt_info, (void *)ph->p_vaddr,
(void *)(ptr + ph->p_offset), ph->p_memsz);
break;
}
@ -765,7 +843,9 @@ esp_err_t esp_core_dump_get_summary(esp_core_dump_summary_t *summary)
}
}
}
esp_partition_munmap(core_data_handle);
return ESP_OK;
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

View File

@ -10,7 +10,7 @@ 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_main.c](main/test_panic_main.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 [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.
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.

View File

@ -2,7 +2,7 @@
# SPDX-License-Identifier: CC0-1.0
import re
from typing import List, Optional
from typing import List, Optional, Union
import pexpect
import pytest
@ -52,12 +52,16 @@ CONFIGS_EXTRAM_STACK = [
pytest.param('coredump_extram_stack', marks=[pytest.mark.esp32, pytest.mark.esp32s2, pytest.mark.psram, pytest.mark.esp32s3, pytest.mark.quad_psram])
]
# Panic abort information will start with this string.
PANIC_ABORT_PREFIX = 'Panic reason: '
def get_default_backtrace(config: str) -> List[str]:
return [config, 'app_main', 'main_task', 'vPortTaskWrapper']
def common_test(dut: PanicTestDut, config: str, expected_backtrace: Optional[List[str]] = None) -> None:
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:
if 'gdbstub' in config:
dut.expect_exact('Entering gdb stub now.')
dut.start_gdb()
@ -67,10 +71,14 @@ def common_test(dut: PanicTestDut, config: str, expected_backtrace: Optional[Lis
dut.revert_log_level()
return # don't expect "Rebooting" output below
# We will only perform comparisons for ELF files, as we are not introducing any new fields to the binary file format.
if 'bin' in config:
expected_coredump = None
if 'uart' in config:
dut.process_coredump_uart()
dut.process_coredump_uart(expected_coredump)
elif 'flash' in config:
dut.process_coredump_flash()
dut.process_coredump_flash(expected_coredump)
elif 'panic' in config:
pass
@ -347,7 +355,8 @@ def test_storeprohibited(dut: PanicTestDut, config: str, test_func_name: str) ->
@pytest.mark.generic
def test_abort(dut: PanicTestDut, config: str, test_func_name: str) -> None:
dut.run_test_func(test_func_name)
dut.expect(r'abort\(\) was called at PC [0-9xa-f]+ on core 0')
regex_pattern = rb'abort\(\) was called at PC [0-9xa-f]+ on core 0'
dut.expect(regex_pattern)
if dut.is_xtensa:
dut.expect_backtrace()
else:
@ -355,6 +364,7 @@ def test_abort(dut: PanicTestDut, config: str, test_func_name: str) -> None:
dut.expect_elf_sha256()
dut.expect_none(['Guru Meditation', 'Re-entered core dump'])
coredump_pattern = re.compile(PANIC_ABORT_PREFIX + regex_pattern.decode('utf-8'))
common_test(
dut,
config,
@ -363,6 +373,7 @@ def test_abort(dut: PanicTestDut, config: str, test_func_name: str) -> None:
'esp_system_abort',
'abort'
] + get_default_backtrace(test_func_name),
expected_coredump=[coredump_pattern]
)
@ -370,7 +381,8 @@ def test_abort(dut: PanicTestDut, config: str, test_func_name: str) -> None:
@pytest.mark.generic
def test_ub(dut: PanicTestDut, config: str, test_func_name: str) -> None:
dut.run_test_func(test_func_name)
dut.expect('Undefined behavior of type out_of_bounds')
regex_pattern = rb'Undefined behavior of type out_of_bounds'
dut.expect(regex_pattern)
if dut.is_xtensa:
dut.expect_backtrace()
else:
@ -378,6 +390,7 @@ def test_ub(dut: PanicTestDut, config: str, test_func_name: str) -> None:
dut.expect_elf_sha256()
dut.expect_none(['Guru Meditation', 'Re-entered core dump'])
coredump_pattern = re.compile(PANIC_ABORT_PREFIX + regex_pattern.decode('utf-8'))
common_test(
dut,
config,
@ -387,6 +400,7 @@ def test_ub(dut: PanicTestDut, config: str, test_func_name: str) -> None:
'__ubsan_default_handler',
'__ubsan_handle_out_of_bounds'
] + get_default_backtrace(test_func_name),
expected_coredump=[coredump_pattern]
)
@ -398,13 +412,16 @@ def test_abort_cache_disabled(
if dut.target == 'esp32s2':
pytest.xfail(reason='Crashes in itoa which is not in ROM, IDF-3572')
dut.run_test_func(test_func_name)
dut.expect(r'abort\(\) was called at PC [0-9xa-f]+ on core 0')
regex_pattern = rb'abort\(\) was called at PC [0-9xa-f]+ on core 0'
dut.expect(regex_pattern)
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'])
coredump_pattern = re.compile(PANIC_ABORT_PREFIX + regex_pattern.decode('utf-8'))
common_test(
dut,
config,
@ -413,6 +430,7 @@ def test_abort_cache_disabled(
'esp_system_abort',
'abort'
] + get_default_backtrace(test_func_name),
expected_coredump=[coredump_pattern]
)
@ -420,17 +438,16 @@ def test_abort_cache_disabled(
@pytest.mark.generic
def test_assert(dut: PanicTestDut, config: str, test_func_name: str) -> None:
dut.run_test_func(test_func_name)
dut.expect(
re.compile(
rb'assert failed:[\s\w()]*?\s[.\w/]*\.(?:c|cpp|h|hpp):\d.*$', re.MULTILINE
)
)
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'])
coredump_pattern = re.compile(PANIC_ABORT_PREFIX + regex_pattern.decode('utf-8'), re.MULTILINE)
common_test(
dut,
config,
@ -438,7 +455,9 @@ def test_assert(dut: PanicTestDut, config: str, test_func_name: str) -> None:
'panic_abort',
'esp_system_abort',
'__assert_func'
] + get_default_backtrace(test_func_name))
] + get_default_backtrace(test_func_name),
expected_coredump=[coredump_pattern]
)
@pytest.mark.parametrize('config', CONFIGS, indirect=True)
@ -449,13 +468,16 @@ def test_assert_cache_disabled(
if dut.target == 'esp32s2':
pytest.xfail(reason='Crashes in itoa which is not in ROM, IDF-3572')
dut.run_test_func(test_func_name)
dut.expect(re.compile(rb'assert failed: [0-9xa-fA-F]+.*$', re.MULTILINE))
regex_pattern = rb'assert failed: [0-9xa-fA-F]+.*$'
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'])
coredump_pattern = re.compile(PANIC_ABORT_PREFIX + regex_pattern.decode('utf-8'), re.MULTILINE)
common_test(
dut,
config,
@ -463,7 +485,9 @@ def test_assert_cache_disabled(
'panic_abort',
'esp_system_abort',
'__assert_func'
] + get_default_backtrace(test_func_name))
] + get_default_backtrace(test_func_name),
expected_coredump=[coredump_pattern]
)
@pytest.mark.esp32

View File

@ -2,9 +2,10 @@
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import logging
import os
import re
import subprocess
import sys
from typing import Any, Dict, List, Optional, TextIO
from typing import Any, Dict, List, Optional, TextIO, Union
import pexpect
from panic_utils import NoGdbProcessError, attach_logger, quote_string, sha256, verify_valid_gdb_subprocess
@ -96,6 +97,19 @@ class PanicTestDut(IdfDut):
)
self.expect_exact('ELF file SHA256: ' + elf_sha256[0:elf_sha256_len])
def expect_coredump(self, output_file_name: str, patterns: List[Union[str, re.Pattern]]) -> None:
with open(output_file_name, 'r') as file:
coredump = file.read()
for pattern in patterns:
if isinstance(pattern, str):
position = coredump.find(pattern)
assert position != -1, f"'{pattern}' not found in the coredump output"
elif isinstance(pattern, re.Pattern):
match = pattern.findall(coredump)
assert match, f"'{pattern.pattern}' not found in the coredump output"
else:
raise ValueError(f'Unsupported input type: {type(pattern).__name__}')
def _call_espcoredump(
self, extra_args: List[str], coredump_file_name: str, output_file_name: str
) -> None:
@ -122,7 +136,7 @@ class PanicTestDut(IdfDut):
self.coredump_output.flush()
self.coredump_output.seek(0)
def process_coredump_uart(self) -> None:
def process_coredump_uart(self, expected: Optional[List[Union[str, re.Pattern]]] = None) -> None:
"""Extract the core dump from UART output of the test, run espcoredump on it"""
self.expect(self.COREDUMP_UART_START)
res = self.expect('(.+)' + self.COREDUMP_UART_END)
@ -135,8 +149,10 @@ class PanicTestDut(IdfDut):
self._call_espcoredump(
['--core-format', 'b64'], coredump_file.name, output_file_name
)
if expected:
self.expect_coredump(output_file_name, expected)
def process_coredump_flash(self) -> None:
def process_coredump_flash(self, expected: Optional[List[Union[str, re.Pattern]]] = None) -> None:
"""Extract the core dump from flash, run espcoredump on it"""
coredump_file_name = os.path.join(self.logdir, 'coredump_data.bin')
logging.info('Writing flash binary core dump to %s', coredump_file_name)
@ -146,6 +162,8 @@ class PanicTestDut(IdfDut):
self._call_espcoredump(
['--core-format', 'raw'], coredump_file_name, output_file_name
)
if expected:
self.expect_coredump(output_file_name, expected)
def gdb_write(self, command: str) -> Any:
"""