Merge branch 'feature/coredump_allow_variable_dumping' into 'master'

Added coredump user defined variable into coredump

Closes IDF-44

See merge request espressif/esp-idf!8730
This commit is contained in:
Krzysztof Budzynski 2020-06-15 02:35:38 +08:00
commit 79a0e892a0
11 changed files with 327 additions and 19 deletions

View file

@ -36,8 +36,14 @@ SECTIONS
{
. = ALIGN(4);
_rtc_force_fast_start = ABSOLUTE(.);
_coredump_rtc_fast_start = ABSOLUTE(.);
mapping[rtc_fast_coredump]
_coredump_rtc_fast_end = ABSOLUTE(.);
*(.rtc.force_fast .rtc.force_fast.*)
. = ALIGN(4) ;
_rtc_force_fast_end = ABSOLUTE(.);
} > rtc_data_seg
@ -52,10 +58,17 @@ SECTIONS
{
_rtc_data_start = ABSOLUTE(.);
mapping[rtc_data]
/* coredump mapping */
_coredump_rtc_start = ABSOLUTE(.);
mapping[rtc_coredump]
_coredump_rtc_end = ABSOLUTE(.);
/* should be placed after coredump mapping */
mapping[rtc_data]
*rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .bss .bss.*)
_rtc_data_end = ABSOLUTE(.);
} > rtc_data_location
/* RTC bss, from any source file named rtc_wake_stub*.c */
@ -151,6 +164,7 @@ SECTIONS
*(.entry.text)
*(.init.literal)
*(.init)
_init_end = ABSOLUTE(.);
} > iram0_0_seg
@ -188,7 +202,12 @@ SECTIONS
*(.gnu.linkonce.s2.*)
*(.jcr)
/* coredump mapping */
_coredump_dram_start = ABSOLUTE(.);
mapping[dram_coredump]
_coredump_dram_end = ABSOLUTE(.);
/* should be placed after coredump mapping */
mapping[dram0_data]
_data_end = ABSOLUTE(.);
@ -346,6 +365,12 @@ SECTIONS
. = ALIGN(4);
_iram_data_start = ABSOLUTE(.);
/* coredump mapping */
_coredump_iram_start = ABSOLUTE(.);
mapping[iram_coredump]
_coredump_iram_end = ABSOLUTE(.);
/* should be placed after coredump mapping */
mapping[iram0_data]
_iram_data_end = ABSOLUTE(.);

View file

@ -36,6 +36,22 @@ entries:
entries:
.rtc.bss
[sections:rtc_fast_coredump]
entries:
.rtc.fast.coredump+
[sections:rtc_coredump]
entries:
.rtc.coredump+
[sections:dram_coredump]
entries:
.dram1.coredump+
[sections:iram_coredump]
entries:
.iram.data.coredump+
[sections:iram]
entries:
.iram1+
@ -81,6 +97,10 @@ entries:
rtc_bss -> rtc_bss
wifi_iram -> flash_text
wifi_rx_iram -> flash_text
dram_coredump -> dram_coredump
iram_coredump -> iram_coredump
rtc_coredump -> rtc_coredump
rtc_fast_coredump -> rtc_fast_coredump
[scheme:rtc]
entries:

View file

@ -36,6 +36,11 @@ SECTIONS
{
. = ALIGN(4);
_rtc_force_fast_start = ABSOLUTE(.);
_coredump_rtc_fast_start = ABSOLUTE(.);
mapping[rtc_fast_coredump]
_coredump_rtc_fast_end = ABSOLUTE(.);
*(.rtc.force_fast .rtc.force_fast.*)
. = ALIGN(4) ;
_rtc_force_fast_end = ABSOLUTE(.);
@ -52,6 +57,12 @@ SECTIONS
{
_rtc_data_start = ABSOLUTE(.);
/* coredump mapping */
_coredump_rtc_start = ABSOLUTE(.);
mapping[rtc_coredump]
_coredump_rtc_end = ABSOLUTE(.);
/* should be placed after coredump mapping */
mapping[rtc_data]
*rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .bss .bss.*)
@ -161,6 +172,10 @@ SECTIONS
mapping[iram0_text]
/* added to maintain compability */
_coredump_iram_start = 0;
_coredump_iram_end = 0;
/* align + add 16B for the possibly overlapping instructions */
. = ALIGN(4) + 16;
_iram_text_end = ABSOLUTE(.);
@ -193,6 +208,12 @@ SECTIONS
*(.gnu.linkonce.s2.*)
*(.jcr)
/* coredump mapping */
_coredump_dram_start = ABSOLUTE(.);
mapping[dram_coredump]
_coredump_dram_end = ABSOLUTE(.);
/* should be placed after coredump mapping */
mapping[dram0_data]
_data_end = ABSOLUTE(.);

View file

@ -36,6 +36,18 @@ entries:
entries:
.rtc.bss
[sections:rtc_fast_coredump]
entries:
.rtc.fast.coredump+
[sections:rtc_coredump]
entries:
.rtc.coredump+
[sections:dram_coredump]
entries:
.dram1.coredump+
[sections:iram]
entries:
.iram1+
@ -67,6 +79,9 @@ entries:
rtc_bss -> rtc_bss
wifi_iram -> flash_text
wifi_rx_iram -> flash_text
dram_coredump -> dram_coredump
rtc_coredump -> rtc_coredump
rtc_fast_coredump -> rtc_fast_coredump
[scheme:rtc]
entries:

View file

@ -1727,11 +1727,6 @@ def info_corefile(args):
def main():
parser = argparse.ArgumentParser(description='espcoredump.py v%s - ESP32 Core Dump Utility' % __version__, prog='espcoredump')
parser.add_argument('--chip', '-c',
help='Target chip type',
choices=['auto', 'esp32'],
default=os.environ.get('ESPTOOL_CHIP', 'auto'))
parser.add_argument(
'--port', '-p',
help='Serial port device',

View file

@ -41,6 +41,15 @@ extern "C" {
#define COREDUMP_TCB_SIZE sizeof(StaticTask_t)
typedef enum {
COREDUMP_MEMORY_DRAM,
COREDUMP_MEMORY_IRAM,
COREDUMP_MEMORY_RTC,
COREDUMP_MEMORY_RTC_FAST,
COREDUMP_MEMORY_MAX,
COREDUMP_MEMORY_START = COREDUMP_MEMORY_DRAM
} coredump_region_t;
// Gets RTOS tasks snapshot
uint32_t esp_core_dump_get_tasks_snapshot(core_dump_task_header_t** const tasks,
const uint32_t snapshot_size);
@ -60,6 +69,10 @@ uint32_t esp_core_dump_get_task_regs_dump(core_dump_task_header_t *task, void **
void esp_core_dump_init_extra_info(void);
uint32_t esp_core_dump_get_extra_info(void **info);
uint32_t esp_core_dump_get_user_ram_segments(void);
uint32_t esp_core_dump_get_user_ram_size(void);
int esp_core_dump_get_user_ram_info(coredump_region_t region, uint32_t *start);
// Data integrity check functions
void esp_core_dump_checksum_init(core_dump_write_data_t* wr_data);
void esp_core_dump_checksum_update(core_dump_write_data_t* wr_data, void* data, size_t data_len);
@ -122,6 +135,16 @@ extern uint8_t *s_core_dump_sp;
}
#endif
// coredump memory regions defined during compile timing
extern int _coredump_dram_start;
extern int _coredump_dram_end;
extern int _coredump_iram_start;
extern int _coredump_iram_end;
extern int _coredump_rtc_start;
extern int _coredump_rtc_end;
extern int _coredump_rtc_fast_start;
extern int _coredump_rtc_fast_end;
#ifdef __cplusplus
}
#endif

View file

@ -29,7 +29,7 @@ static inline uint32_t esp_core_dump_get_tcb_len(void)
return COREDUMP_TCB_SIZE;
}
static inline uint32_t esp_core_dump_get_stack_len(uint32_t stack_start, uint32_t stack_end)
static inline uint32_t esp_core_dump_get_memory_len(uint32_t stack_start, uint32_t stack_end)
{
uint32_t len = stack_end - stack_start;
// Take stack padding into account
@ -43,7 +43,7 @@ static esp_err_t esp_core_dump_save_task(core_dump_write_config_t *write_cfg,
uint32_t stk_vaddr, stk_len;
uint32_t stk_paddr = esp_core_dump_get_stack(task, &stk_vaddr, &stk_len);
stk_len = esp_core_dump_get_stack_len(stk_vaddr, stk_vaddr+stk_len);
stk_len = esp_core_dump_get_memory_len(stk_vaddr, stk_vaddr+stk_len);
// Save TCB address, stack base and stack top addr
err = write_cfg->write(write_cfg->priv, (void*)task, sizeof(core_dump_task_header_t));
@ -114,6 +114,7 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_
ESP_COREDUMP_LOGI("Found tasks: %d!", task_num);
// Verifies all tasks in the snapshot
for (task_id = 0; task_id < task_num; task_id++) {
bool is_current_task = false, stack_is_valid = false;
bool tcb_is_valid = esp_core_dump_check_task(frame, tasks[task_id], &is_current_task, &stack_is_valid);
@ -131,21 +132,21 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_
// Increase core dump size by task stack size
uint32_t stk_vaddr, stk_len;
esp_core_dump_get_stack(tasks[task_id], &stk_vaddr, &stk_len);
data_len += esp_core_dump_get_stack_len(stk_vaddr, stk_vaddr+stk_len);
data_len += esp_core_dump_get_memory_len(stk_vaddr, stk_vaddr+stk_len);
// Add tcb size
data_len += (tcb_sz + sizeof(core_dump_task_header_t));
}
if (esp_core_dump_in_isr_context()) {
interrupted_task_stack.start = tasks[curr_task_index]->stack_start;
interrupted_task_stack.size = esp_core_dump_get_stack_len(tasks[curr_task_index]->stack_start, tasks[curr_task_index]->stack_end);
interrupted_task_stack.size = esp_core_dump_get_memory_len(tasks[curr_task_index]->stack_start, tasks[curr_task_index]->stack_end);
// size of the task's stack has been already taken into account, also addresses have also been checked
data_len += sizeof(core_dump_mem_seg_header_t);
tasks[curr_task_index]->stack_start = (uint32_t)frame;
tasks[curr_task_index]->stack_end = esp_core_dump_get_isr_stack_end();
ESP_COREDUMP_LOG_PROCESS("Add ISR stack %lu to %lu", tasks[curr_task_index]->stack_end - tasks[curr_task_index]->stack_start, data_len);
// take into account size of the ISR stack
data_len += esp_core_dump_get_stack_len(tasks[curr_task_index]->stack_start, tasks[curr_task_index]->stack_end);
data_len += esp_core_dump_get_memory_len(tasks[curr_task_index]->stack_start, tasks[curr_task_index]->stack_end);
}
// Check if current task TCB is broken
@ -154,6 +155,22 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_
curr_task_index = 0;
}
// Add user memory region header size
data_len += esp_core_dump_get_user_ram_segments() * sizeof(core_dump_mem_seg_header_t);
for (coredump_region_t i = COREDUMP_MEMORY_START; i < COREDUMP_MEMORY_MAX; i++) {
uint32_t start = 0;
int data_sz = esp_core_dump_get_user_ram_info(i, &start);
if (data_sz < 0) {
ESP_COREDUMP_LOGE("Invalid memory segment size");
return ESP_FAIL;
}
if (data_sz > 0) {
data_len += esp_core_dump_get_memory_len(start, start + data_sz);
}
}
// Add core dump header size
data_len += sizeof(core_dump_header_t);
@ -185,6 +202,7 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_
if (xPortInterruptedFromISRContext()) {
hdr.mem_segs_num++; // stack of interrupted task
}
hdr.mem_segs_num += esp_core_dump_get_user_ram_segments(); // stack of user mapped memory
hdr.tcb_sz = tcb_sz;
err = write_cfg->write(write_cfg->priv, &hdr, sizeof(core_dump_header_t));
if (err != ESP_OK) {
@ -221,6 +239,30 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_
}
}
// save user memory regions
if (esp_core_dump_get_user_ram_segments() > 0) {
core_dump_mem_seg_header_t user_ram_stack_size;
for (coredump_region_t i = COREDUMP_MEMORY_START; i < COREDUMP_MEMORY_MAX; i++) {
uint32_t start = 0;
int data_sz = esp_core_dump_get_user_ram_info(i, &start);
if (data_sz < 0) {
ESP_COREDUMP_LOGE("Invalid memory segment size");
return ESP_FAIL;
}
if (data_sz > 0) {
user_ram_stack_size.start = start;
user_ram_stack_size.size = esp_core_dump_get_memory_len(start, start + data_sz);;
err = esp_core_dump_save_mem_segment(write_cfg, &user_ram_stack_size);
if (err != ESP_OK) {
ESP_COREDUMP_LOGE("Failed to save user memory data, error=%d!", err);
return err;
}
}
}
}
// Write end
if (write_cfg->end) {
err = write_cfg->end(write_cfg->priv);
@ -234,6 +276,7 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_
}
return err;
}
#endif
inline void esp_core_dump_write(void *frame, core_dump_write_config_t *write_cfg)

View file

@ -23,7 +23,9 @@
#include "elf.h" // for ELF file types
#define ELF_SEG_HEADERS_COUNT(_self_, _task_num_) (uint32_t)((_task_num_) * 2/*stack + tcb*/ \
+ 1/* regs notes */ + 1/* ver info + extra note */ + ((_self_)->interrupted_task.stack_start ? 1 : 0))
+ 1/* regs notes */ + 1/* ver info + extra note */ + ((_self_)->interrupted_task.stack_start ? 1 : 0) \
+ /* user mapped variables */ esp_core_dump_get_user_ram_segments())
#define ELF_HLEN 52
#define ELF_CORE_SEC_TYPE 1
@ -508,6 +510,31 @@ static int elf_write_tasks_data(core_dump_elf_t *self, void* frame,
return elf_len;
}
static int elf_write_core_dump_user_data(core_dump_elf_t *self)
{
int data_len = 0;
int total_sz = 0;
uint32_t start = 0;
for (coredump_region_t i = COREDUMP_MEMORY_START; i < COREDUMP_MEMORY_MAX; i++) {
data_len = esp_core_dump_get_user_ram_info(i, &start);
ELF_CHECK_ERR((data_len >= 0), ELF_PROC_ERR_OTHER, "invalid memory region");
if (data_len > 0) {
int ret = elf_add_segment(self, PT_LOAD,
(uint32_t)start,
(void*)start,
(uint32_t) data_len);
ELF_CHECK_ERR((ret > 0), ret, "memory region write failed. Returned (%d).", ret);
total_sz += ret;
}
}
return total_sz;
}
static int elf_write_core_dump_info(core_dump_elf_t *self)
{
void *extra_info;
@ -562,6 +589,12 @@ static int esp_core_dump_do_write_elf_pass(core_dump_elf_t *self, void* frame,
data_sz = elf_write_tasks_data(self, frame, tasks, task_num);
ELF_CHECK_ERR((data_sz > 0), data_sz, "ELF Size writing error, returned (%d).", data_sz);
tot_len += data_sz;
// write core dump memory regions defined by user
data_sz = elf_write_core_dump_user_data(self);
ELF_CHECK_ERR((data_sz >= 0), data_sz, "memory regions writing error, returned (%d).", data_sz);
tot_len += data_sz;
// write data with version control information and some extra info
// this should go after tasks processing
data_sz = elf_write_core_dump_info(self);

View file

@ -37,6 +37,8 @@ const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_port"
#define COREDUMP_GET_EPS(reg, ptr) \
if (reg - EPS_2 + 2 <= XCHAL_NUM_INTLEVELS) COREDUMP_GET_REG_PAIR(reg, ptr)
#define COREDUMP_GET_MEMORY_SIZE(end, start) (end - start)
// Enumeration of registers of exception stack frame
// and solicited stack frame
typedef enum
@ -260,8 +262,14 @@ inline uint16_t esp_core_dump_get_arch_id()
inline bool esp_core_dump_mem_seg_is_sane(uint32_t addr, uint32_t sz)
{
//TODO: currently core dump supports memory segments in DRAM only, external SRAM not supported yet
return esp_ptr_in_dram((void *)addr) && esp_ptr_in_dram((void *)(addr+sz-1));
//TODO: external SRAM not supported yet
return (esp_ptr_in_dram((void *)addr) && esp_ptr_in_dram((void *)(addr+sz-1))) ||
(esp_ptr_in_rtc_slow((void *)addr) && esp_ptr_in_rtc_slow((void *)(addr+sz-1))) ||
(esp_ptr_in_rtc_dram_fast((void *)addr) && esp_ptr_in_rtc_dram_fast((void *)(addr+sz-1)))
#if CONFIG_IDF_TARGET_ESP32 && CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY
|| (esp_ptr_in_iram((void *)addr) && esp_ptr_in_iram((void *)(addr+sz-1)))
#endif
;
}
inline bool esp_core_dump_task_stack_end_is_sane(uint32_t sp)
@ -568,4 +576,61 @@ uint32_t esp_core_dump_get_extra_info(void **info)
return sizeof(s_extra_info);
}
uint32_t esp_core_dump_get_user_ram_segments(void)
{
uint32_t total_sz = 0;
// count number of memory segments to insert into ELF structure
total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_dram_end, &_coredump_dram_start) > 0 ? 1 : 0;
total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_rtc_end, &_coredump_rtc_start) > 0 ? 1 : 0;
total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_rtc_fast_end, &_coredump_rtc_fast_start) > 0 ? 1 : 0;
total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_iram_end, &_coredump_iram_start) > 0 ? 1 : 0;
return total_sz;
}
uint32_t esp_core_dump_get_user_ram_size(void)
{
uint32_t total_sz = 0;
total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_dram_end, &_coredump_dram_start);
total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_rtc_end, &_coredump_rtc_start);
total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_rtc_fast_end, &_coredump_rtc_fast_start);
total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_iram_end, &_coredump_iram_start);
return total_sz;
}
int esp_core_dump_get_user_ram_info(coredump_region_t region, uint32_t *start) {
int total_sz = -1;
switch (region) {
case COREDUMP_MEMORY_DRAM:
*start = (uint32_t)&_coredump_dram_start;
total_sz = (uint8_t *)&_coredump_dram_end - (uint8_t *)&_coredump_dram_start;
break;
case COREDUMP_MEMORY_IRAM:
*start = (uint32_t)&_coredump_iram_start;
total_sz = (uint8_t *)&_coredump_iram_end - (uint8_t *)&_coredump_iram_start;
break;
case COREDUMP_MEMORY_RTC:
*start = (uint32_t)&_coredump_rtc_start;
total_sz = (uint8_t *)&_coredump_rtc_end - (uint8_t *)&_coredump_rtc_start;
break;
case COREDUMP_MEMORY_RTC_FAST:
*start = (uint32_t)&_coredump_rtc_fast_start;
total_sz = (uint8_t *)&_coredump_rtc_fast_end - (uint8_t *)&_coredump_rtc_fast_start;
break;
default:
break;
}
return total_sz;
}
#endif

View file

@ -32,9 +32,13 @@
// Forces data into IRAM instead of DRAM
#define IRAM_DATA_ATTR __attribute__((section(".iram.data")))
// Forces data into IRAM instead of DRAM and map it to coredump
#define COREDUMP_IRAM_DATA_ATTR _SECTION_ATTR_IMPL(".iram.data.coredump", __COUNTER__)
// Forces bss into IRAM instead of DRAM
#define IRAM_BSS_ATTR __attribute__((section(".iram.bss")))
#else
#define COREDUMP_IRAM_DATA_ATTR
#define IRAM_DATA_ATTR
#define IRAM_BSS_ATTR
@ -85,6 +89,15 @@
// after restart or during a deep sleep / wake cycle.
#define RTC_NOINIT_ATTR _SECTION_ATTR_IMPL(".rtc_noinit", __COUNTER__)
// Forces code into DRAM instead of flash and map it to coredump
#define COREDUMP_DRAM_ATTR _SECTION_ATTR_IMPL(".dram1.coredump", __COUNTER__)
// Forces data into RTC memory and map it to coredump
#define COREDUMP_RTC_DATA_ATTR _SECTION_ATTR_IMPL(".rtc.coredump", __COUNTER__)
// Allows to place data into RTC_FAST memory and map it to coredump
#define COREDUMP_RTC_FAST_ATTR _SECTION_ATTR_IMPL(".rtc.fast.coredump", __COUNTER__)
// Forces to not inline function
#define NOINLINE_ATTR __attribute__((noinline))

View file

@ -13,7 +13,8 @@ Overview
ESP-IDF provides support to generate core dumps on unrecoverable software errors. This useful technique allows post-mortem analysis of software state at the moment of failure.
Upon the crash system enters panic state, prints some information and halts or reboots depending configuration. User can choose to generate core dump in order to analyse
the reason of failure on PC later on. Core dump contains snapshots of all tasks in the system at the moment of failure. Snapshots include tasks control blocks (TCB) and stacks.
So it is possible to find out what task, at what instruction (line of code) and what callstack of that task lead to the crash.
So it is possible to find out what task, at what instruction (line of code) and what callstack of that task lead to the crash. It is also possible dumping variables content on
demand if previously attributed accordingly.
ESP-IDF provides special script `espcoredump.py` to help users to retrieve and analyse core dumps. This tool provides two commands for core dumps analysis:
* info_corefile - prints crashed task's registers, callstack, list of available tasks in the system, memory regions and contents of memory stored in core dump (TCBs and stacks)
@ -94,8 +95,63 @@ ROM Functions in Backtraces
It is possible situation that at the moment of crash some tasks or/and crashed task itself have one or more ROM functions in their callstacks.
Since ROM is not part of the program ELF it will be impossible for GDB to parse such callstacks, because it tries to analyse functions' prologues to acomplish that.
In that case callstack printing will be broken with error message at the first ROM function.
To overcome this issue you can use ROM ELF provided by Espressif (https://dl.espressif.com/dl/esp32_rom.elf) and pass it to 'espcoredump.py'.
To overcome this issue you can use ROM ELF provided by Espressif (https://dl.espressif.com/dl/{IDF_TARGET_PATH_NAME}_rom.elf) and pass it to 'espcoredump.py'.
Dumping variables on demand
---------------------------
Sometimes you want to read the last value of a variable to understand the root cause of a crash.
Core dump supports retrieving variable data over GDB by attributing special notations declared variables.
Supported notations and RAM regions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. only:: esp32
- ``COREDUMP_DRAM_ATTR`` places variable into DRAM area which will be included into dump.
- ``COREDUMP_RTC_ATTR`` places variable into RTC area which will be included into dump.
- ``COREDUMP_RTC_FAST_ATTR`` places variable into RTC_FAST area which will be included into dump.
- ``COREDUMP_IRAM_ATTR`` places variable into IRAM area which will be included into dump when :ref:`Enable IRAM as 8 bit accessible memory <CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY>` is set.
.. only:: esp32s2
- ``COREDUMP_DRAM_ATTR`` places variable into DRAM area which will be included into dump.
- ``COREDUMP_RTC_ATTR`` places variable into RTC area which will be included into dump.
- ``COREDUMP_RTC_FAST_ATTR`` places variable into RTC_FAST area which will be included into dump.
Example
^^^^^^^
1. In :ref:`project-configuration-menu`, enable :ref:`COREDUMP TO FLASH <CONFIG_ESP32_COREDUMP_TO_FLASH_OR_UART>`, then save and exit.
2. In your project, create a global variable in DRAM area as such as:
.. code-block:: bash
// uint8_t global_var;
COREDUMP_DRAM_ATTR uint8_t global_var;
3. In main application, set the variable to any value and `assert(0)` to cause a crash.
.. code-block:: bash
global_var = 25;
assert(0);
4. Build, flash and run the application on a target device and wait for the dumping information.
5. Run the command below to start core dumping in GDB, where ``PORT`` is the device USB port:
.. code-block:: bash
espcoredump.py -p PORT dbg_corefile <path/to/elf>
6. In GDB shell, type ``p global_var`` to get the variable content:
.. code-block:: bash
(gdb) p global_var
$1 = 25 '\031'
Running 'espcoredump.py'
------------------------
@ -105,7 +161,6 @@ Generic command syntax:
`espcoredump.py [options] command [args]`
:Script Options:
* --chip,-c {auto,esp32}. Target chip type. Supported values are `auto` and `esp32`.
* --port,-p PORT. Serial port device.
* --baud,-b BAUD. Serial port baud rate used when flashing/reading.
:Commands:
@ -120,4 +175,4 @@ Generic command syntax:
* --save-core,-s SAVE_CORE. Save core to file. Othwerwise temporary core file will be deleted. Ignored with "-c".
* --rom-elf,-r ROM_ELF. Path to ROM ELF file to use (if skipped "esp32_rom.elf" is used).
* --print-mem,-m Print memory dump. Used only with "info_corefile".
* <prog> Path to program ELF file.
* <prog> Path to program ELF file.