From b797f05558f5c902f40ea4b9f24e31e1ffdf8106 Mon Sep 17 00:00:00 2001 From: X-Ryl669 Date: Tue, 11 Dec 2018 23:14:15 +0100 Subject: [PATCH 1/2] Add support for listing tasks to gdb in gdbstub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …and changing the active task and fetching each task's stack Merges https://github.com/espressif/esp-idf/pull/2828 --- components/esp32/gdbstub.c | 239 ++++++++++++++++++++++++++++++++----- 1 file changed, 208 insertions(+), 31 deletions(-) diff --git a/components/esp32/gdbstub.c b/components/esp32/gdbstub.c index df04c9199..500ecca15 100644 --- a/components/esp32/gdbstub.c +++ b/components/esp32/gdbstub.c @@ -13,16 +13,19 @@ // limitations under the License. /****************************************************************************** - * Description: A stub to make the ESP32 debuggable by GDB over the serial + * Description: A stub to make the ESP32 debuggable by GDB over the serial * port, at least enough to do a backtrace on panic. This gdbstub is read-only: - * it allows inspecting the ESP32 state + * it allows inspecting the ESP32 state *******************************************************************************/ #include "rom/ets_sys.h" #include "soc/uart_reg.h" #include "soc/io_mux_reg.h" #include "esp_gdbstub.h" +#include "esp_panic.h" #include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" //Length of buffer used to reserve GDB commands. Has to be at least able to fit the G command, which //implies a minimum size of about 320 bytes. @@ -33,6 +36,15 @@ static char chsum; //Running checksum of the output packet #define ATTR_GDBFN +//If you want more than (default) 32 tasks to be dumped, you'll need to enable the coredump feature and specify +//here your amount. +#ifdef CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM + #define STUB_TASKS_NUM CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM +#else + #define STUB_TASKS_NUM 32 +#endif + + //Receive a char from the uart. Uses polling and feeds the watchdog. static int ATTR_GDBFN gdbRecvChar() { int i; @@ -187,7 +199,7 @@ typedef struct { GdbRegFile gdbRegFile; -/* +/* //Register format as the Xtensa HAL has it: STRUCT_FIELD (long, 4, XT_STK_EXIT, exit) STRUCT_FIELD (long, 4, XT_STK_PC, pc) @@ -201,7 +213,7 @@ STRUCT_FIELD (long, 4, XT_STK_EXCVADDR, excvaddr) STRUCT_FIELD (long, 4, XT_STK_LBEG, lbeg) STRUCT_FIELD (long, 4, XT_STK_LEND, lend) STRUCT_FIELD (long, 4, XT_STK_LCOUNT, lcount) -// Temporary space for saving stuff during window spill +// Temporary space for saving stuff during window spill STRUCT_FIELD (long, 4, XT_STK_TMP0, tmp0) STRUCT_FIELD (long, 4, XT_STK_TMP1, tmp1) STRUCT_FIELD (long, 4, XT_STK_TMP2, tmp2) @@ -212,23 +224,16 @@ STRUCT_END(XtExcFrame) */ -static void dumpHwToRegfile(XtExcFrame *frame) { - int i; - long *frameAregs=&frame->a0; - gdbRegFile.pc=frame->pc; - for (i=0; i<16; i++) gdbRegFile.a[i]=frameAregs[i]; - for (i=16; i<64; i++) gdbRegFile.a[i]=0xDEADBEEF; - gdbRegFile.lbeg=frame->lbeg; - gdbRegFile.lend=frame->lend; - gdbRegFile.lcount=frame->lcount; - gdbRegFile.sar=frame->sar; - //All windows have been spilled to the stack by the ISR routines. The following values should indicate that. - gdbRegFile.sar=frame->sar; +//Remember the exception frame that caused panic since it's not saved in TCB +static XtExcFrame paniced_frame; + +static void commonRegfile() { + if (gdbRegFile.a[0] & 0x8000000U) gdbRegFile.a[0] = (gdbRegFile.a[0] & 0x3fffffffU) | 0x40000000U; + if (!esp_stack_ptr_is_sane(gdbRegFile.a[1])) gdbRegFile.a[1] = 0xDEADBEEF; gdbRegFile.windowbase=0; //0 gdbRegFile.windowstart=0x1; //1 gdbRegFile.configid0=0xdeadbeef; //ToDo gdbRegFile.configid1=0xdeadbeef; //ToDo - gdbRegFile.ps=frame->ps-PS_EXCM_MASK; gdbRegFile.threadptr=0xdeadbeef; //ToDo gdbRegFile.br=0xdeadbeef; //ToDo gdbRegFile.scompare1=0xdeadbeef; //ToDo @@ -238,9 +243,23 @@ static void dumpHwToRegfile(XtExcFrame *frame) { gdbRegFile.m1=0xdeadbeef; //ToDo gdbRegFile.m2=0xdeadbeef; //ToDo gdbRegFile.m3=0xdeadbeef; //ToDo - gdbRegFile.expstate=frame->exccause; //ToDo } +static void dumpHwToRegfile(XtExcFrame *frame) { + int i; + long *frameAregs=&frame->a0; + gdbRegFile.pc=(frame->pc & 0x3fffffffU)|0x40000000U; + for (i=0; i<16; i++) gdbRegFile.a[i]=frameAregs[i]; + for (i=16; i<64; i++) gdbRegFile.a[i]=0xDEADBEEF; + gdbRegFile.lbeg=frame->lbeg; + gdbRegFile.lend=frame->lend; + gdbRegFile.lcount=frame->lcount; + gdbRegFile.ps=(frame->ps & PS_UM) ? (frame->ps & ~PS_EXCM) : frame->ps; + //All windows have been spilled to the stack by the ISR routines. The following values should indicate that. + gdbRegFile.sar=frame->sar; + commonRegfile(); + gdbRegFile.expstate=frame->exccause; //ToDo +} //Send the reason execution is stopped to GDB. static void sendReason() { @@ -251,13 +270,90 @@ static void sendReason() { gdbPacketChar('T'); i=gdbRegFile.expstate&0x7f; if (ia0; + gdbRegFile.pc=(frame->pc & 0x3fffffffU)|0x40000000U; + for (i=0; i<4; i++) gdbRegFile.a[i]=frameAregs[i]; + for (i=4; i<64; i++) gdbRegFile.a[i]=0xDEADBEEF; + gdbRegFile.lbeg=0; + gdbRegFile.lend=0; + gdbRegFile.lcount=0; + gdbRegFile.ps=(frame->ps & PS_UM) ? (frame->ps & ~PS_EXCM) : frame->ps; + //All windows have been spilled to the stack by the ISR routines. The following values should indicate that. + gdbRegFile.sar=0; + commonRegfile(); + gdbRegFile.expstate=0; //ToDo +} + +//Fetch the task status +static unsigned getAllTasksHandle(unsigned index, unsigned * handle, const char ** name, unsigned * coreId) { + static unsigned taskCount = 0; + static TaskSnapshot_t tasks[STUB_TASKS_NUM]; + + if (!taskCount) { + unsigned tcbSize = 0; + taskCount = uxTaskGetSnapshotAll(tasks, STUB_TASKS_NUM, &tcbSize); + } + if (index < taskCount) { + TaskHandle_t h = (TaskHandle_t)tasks[index].pxTCB; + if (handle) *handle = (unsigned)h; + if (name) *name = pcTaskGetTaskName(h); + if (coreId) *coreId = xTaskGetAffinity(h); + } + return taskCount; +} + +typedef struct +{ + uint8_t * topOfStack; +} DumpTCB; + + +static void dumpTCBToRegFile(unsigned handle) { + // A task handle is a pointer to a TCB in FreeRTOS + DumpTCB * tcb = (DumpTCB*)handle; + uint8_t * pxTopOfStack = tcb->topOfStack; + + //Deduced from coredump code + XtExcFrame * frame = (XtExcFrame*)pxTopOfStack; + if (frame->exit) { + // It's an exception frame + dumpHwToRegfile(frame); + } else { + XtSolFrame * taskFrame = (XtSolFrame*)pxTopOfStack; + dumpTaskToRegfile(taskFrame); + } +} + +static int findCurrentTaskIndex() { + static int curTaskIndex = -2; + if (curTaskIndex == -2) { + unsigned curHandle = (unsigned)xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID()), handle, count = getAllTasksHandle(0, 0, 0, 0); + for(int k=0; k<(int)count; k++) { + if (getAllTasksHandle(k, &handle, 0, 0) && curHandle == handle) + return curTaskIndex = k; + } + curTaskIndex = -1; + } + return curTaskIndex; +} + //Handle a command as received from GDB. static int gdbHandleCommand(unsigned char *cmd, int len) { //Handle a command @@ -270,10 +366,8 @@ static int gdbHandleCommand(unsigned char *cmd, int len) { gdbPacketEnd(); } else if (cmd[0]=='G') { //receive content for all registers from gdb int *p=(int*)&gdbRegFile; - for (i=0; i 16 && cmd[1] == 'T' && cmd[2] == 'h' && cmd[3] == 'r' && cmd[7] == 'E' && cmd[12] == 'I' && cmd[16] == ',') { + data=&cmd[17]; + i=gdbGetHexVal(&data, -1); + + unsigned handle = 0, coreId = 3; + const char * name = 0; + // Extract the task name and CPU from freeRTOS + unsigned tCount = getAllTasksHandle(i, &handle, &name, &coreId); + if (i < tCount) { + gdbPacketStart(); + for(k=0; name[k]; k++) gdbPacketHex(name[k], 8); + gdbPacketStr("20435055"); // CPU + gdbPacketStr(coreId == 0 ? "30": coreId == 1 ? "31" : "78"); // 0 or 1 or x + gdbPacketEnd(); + return ST_OK; + } + } else if (len >= 12 && (cmd[1] == 'f' || cmd[1] == 's') && (cmd[2] == 'T' && cmd[3] == 'h' && cmd[4] == 'r' && cmd[5] == 'e' && cmd[6] == 'a' && cmd[7] == 'd' && cmd[8] == 'I')) { + // Only react to qfThreadInfo and qsThreadInfo, not using strcmp here since it can be in ROM + // Extract the number of task from freeRTOS + static int taskIndex = 0; + unsigned tCount = 0; + if (cmd[1] == 'f') { + taskIndex = 0; + reenteredHandler = 1; //It seems it's the first request GDB is sending + } + tCount = getAllTasksHandle(0, 0, 0, 0); + if (taskIndex < tCount) { + gdbPacketStart(); + gdbPacketStr("m"); + gdbPacketHex(taskIndex, 32); + gdbPacketEnd(); + taskIndex++; + } else return sendPacket("l"); + } else if (len >= 2 && cmd[1] == 'C') { + // Get current task id + gdbPacketStart(); + k = findCurrentTaskIndex(); + if (k != -1) { + gdbPacketStr("QC"); + gdbPacketHex(k, 32); + } else gdbPacketStr("bad"); + gdbPacketEnd(); + return ST_OK; + } + return sendPacket(0); + } + } else //We don't recognize or support whatever GDB just sent us. - gdbPacketStart(); - gdbPacketEnd(); - return ST_ERR; - } + return sendPacket(0); return ST_OK; } //Lower layer: grab a command packet and check the checksum //Calls gdbHandleCommand on the packet if the checksum is OK -//Returns ST_OK on success, ST_ERR when checksum fails, a +//Returns ST_OK on success, ST_ERR when checksum fails, a //character if it is received instead of the GDB packet //start char. static int gdbReadCommand() { @@ -346,7 +512,19 @@ static int gdbReadCommand() { void esp_gdbstub_panic_handler(XtExcFrame *frame) { - dumpHwToRegfile(frame); + if (reenteredHandler == 1) { + //Prevent using advanced FreeRTOS features since they seems to crash + gdbPacketEnd(); // Ends up any pending GDB packet (this creates a garbage value) + reenteredHandler = -1; + } else { + //Need to remember the frame that panic'd since gdb will ask for all thread before ours + uint8_t * pf = (uint8_t*)&paniced_frame, *f = (uint8_t*)frame; + //Could not use memcpy here + for(int i = 0; i < sizeof(*frame); i++) pf[i] = f[i]; + } + //Let's start from something + dumpHwToRegfile(&paniced_frame); + //Make sure txd/rxd are enabled gpio_pullup_dis(1); PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD); @@ -356,4 +534,3 @@ void esp_gdbstub_panic_handler(XtExcFrame *frame) { while(gdbReadCommand()!=ST_CONT); while(1); } - From c22e572ad02f0994d12593c2a13d82327896281b Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 27 Feb 2019 12:23:56 +0800 Subject: [PATCH 2/2] gdbstub: minor cleanup 1. Add Kconfig options to control task listing support. 2. Convert magic values (-1, -2) to named constants. 3. Convert spaces to tabs to match the rest of the file. 4. Rename getAllTasksHandle to getTaskInfo to reflect its purpose. 5. Add some curly braces for single line statements. --- components/esp32/Kconfig | 17 ++++++ components/esp32/gdbstub.c | 121 ++++++++++++++++++++++--------------- 2 files changed, 88 insertions(+), 50 deletions(-) diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 1952e2feb..c697a7827 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -544,6 +544,23 @@ menu "ESP32-specific" of the crash. endchoice + config GDBSTUB_SUPPORT_TASKS + bool "GDBStub: enable listing FreeRTOS tasks" + default y + depends on ESP32_PANIC_GDBSTUB + help + If enabled, GDBStub can supply the list of FreeRTOS tasks to GDB. + Thread list can be queried from GDB using 'info threads' command. + Note that if GDB task lists were corrupted, this feature may not work. + If GDBStub fails, try disabling this feature. + + config GDBSTUB_MAX_TASKS + int "GDBStub: maximum number of tasks supported" + default 32 + depends on GDBSTUB_SUPPORT_TASKS + help + Set the number of tasks which GDB Stub will support. + config ESP32_DEBUG_OCDAWARE bool "Make exception and panic handlers JTAG/OCD aware" default y diff --git a/components/esp32/gdbstub.c b/components/esp32/gdbstub.c index 500ecca15..a93b45992 100644 --- a/components/esp32/gdbstub.c +++ b/components/esp32/gdbstub.c @@ -18,6 +18,7 @@ * it allows inspecting the ESP32 state *******************************************************************************/ +#include #include "rom/ets_sys.h" #include "soc/uart_reg.h" #include "soc/io_mux_reg.h" @@ -26,6 +27,7 @@ #include "driver/gpio.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "sdkconfig.h" //Length of buffer used to reserve GDB commands. Has to be at least able to fit the G command, which //implies a minimum size of about 320 bytes. @@ -36,15 +38,6 @@ static char chsum; //Running checksum of the output packet #define ATTR_GDBFN -//If you want more than (default) 32 tasks to be dumped, you'll need to enable the coredump feature and specify -//here your amount. -#ifdef CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM - #define STUB_TASKS_NUM CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM -#else - #define STUB_TASKS_NUM 32 -#endif - - //Receive a char from the uart. Uses polling and feeds the watchdog. static int ATTR_GDBFN gdbRecvChar() { int i; @@ -223,10 +216,6 @@ STRUCT_FIELD (long, 4, XT_STK_OVLY, ovly) STRUCT_END(XtExcFrame) */ - -//Remember the exception frame that caused panic since it's not saved in TCB -static XtExcFrame paniced_frame; - static void commonRegfile() { if (gdbRegFile.a[0] & 0x8000000U) gdbRegFile.a[0] = (gdbRegFile.a[0] & 0x3fffffffU) | 0x40000000U; if (!esp_stack_ptr_is_sane(gdbRegFile.a[1])) gdbRegFile.a[1] = 0xDEADBEEF; @@ -277,7 +266,6 @@ static void sendReason() { gdbPacketEnd(); } -static int reenteredHandler = 0; static int sendPacket(const char * text) { gdbPacketStart(); if (text != NULL) gdbPacketStr(text); @@ -285,6 +273,21 @@ static int sendPacket(const char * text) { return ST_OK; } +#if CONFIG_GDBSTUB_SUPPORT_TASKS + +#define STUB_TASKS_NUM CONFIG_GDBSTUB_MAX_TASKS + +//Remember the exception frame that caused panic since it's not saved in TCB +static XtExcFrame paniced_frame; + +//Allows GDBStub to disable task support after a crash +//(e.g. if GDBStub crashes while trying to get task list, e.g. due to corrupted list structures) +static enum { + HANDLER_NOT_STARTED, + HANDLER_STARTED, + HANDLER_TASK_SUPPORT_DISABLED +} handlerState; + static void dumpTaskToRegfile(XtSolFrame *frame) { int i; long *frameAregs=&frame->a0; @@ -301,21 +304,21 @@ static void dumpTaskToRegfile(XtSolFrame *frame) { gdbRegFile.expstate=0; //ToDo } -//Fetch the task status -static unsigned getAllTasksHandle(unsigned index, unsigned * handle, const char ** name, unsigned * coreId) { +// Fetch the task status. Returns the total number of tasks. +static unsigned getTaskInfo(unsigned index, unsigned * handle, const char ** name, unsigned * coreId) { static unsigned taskCount = 0; static TaskSnapshot_t tasks[STUB_TASKS_NUM]; - if (!taskCount) { + if (!taskCount) { unsigned tcbSize = 0; taskCount = uxTaskGetSnapshotAll(tasks, STUB_TASKS_NUM, &tcbSize); - } + } if (index < taskCount) { TaskHandle_t h = (TaskHandle_t)tasks[index].pxTCB; if (handle) *handle = (unsigned)h; if (name) *name = pcTaskGetTaskName(h); if (coreId) *coreId = xTaskGetAffinity(h); - } + } return taskCount; } @@ -341,19 +344,29 @@ static void dumpTCBToRegFile(unsigned handle) { } } +#define CUR_TASK_INDEX_NOT_SET -2 +#define CUR_TASK_INDEX_UNKNOWN -1 + +// Get the index of the task currently running on the current CPU, and cache the result static int findCurrentTaskIndex() { - static int curTaskIndex = -2; - if (curTaskIndex == -2) { - unsigned curHandle = (unsigned)xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID()), handle, count = getAllTasksHandle(0, 0, 0, 0); + static int curTaskIndex = CUR_TASK_INDEX_NOT_SET; + if (curTaskIndex == CUR_TASK_INDEX_NOT_SET) { + unsigned curHandle = (unsigned)xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID()); + unsigned handle; + unsigned count = getTaskInfo(0, 0, 0, 0); for(int k=0; k<(int)count; k++) { - if (getAllTasksHandle(k, &handle, 0, 0) && curHandle == handle) - return curTaskIndex = k; + if (getTaskInfo(k, &handle, 0, 0) && curHandle == handle) { + curTaskIndex = k; + return curTaskIndex; + } } - curTaskIndex = -1; + curTaskIndex = CUR_TASK_INDEX_UNKNOWN; } return curTaskIndex; } +#endif // CONFIG_GDBSTUB_SUPPORT_TASKS + //Handle a command as received from GDB. static int gdbHandleCommand(unsigned char *cmd, int len) { //Handle a command @@ -379,20 +392,26 @@ static int gdbHandleCommand(unsigned char *cmd, int len) { gdbPacketEnd(); } else if (cmd[0]=='?') { //Reply with stop reason sendReason(); - } else if (reenteredHandler != -1) { +#if CONFIG_GDBSTUB_SUPPORT_TASKS + } else if (handlerState != HANDLER_TASK_SUPPORT_DISABLED) { if (cmd[0]=='H') { //Continue with task if (cmd[1]=='g' || cmd[1]=='c') { const char * ret = "OK"; data++; i=gdbGetHexVal(&data, -1); - reenteredHandler = 1; //Hg0 is the first packet received after connect + handlerState = HANDLER_STARTED; //Hg0 is the first packet received after connect j = findCurrentTaskIndex(); - if (i == j || (j == -1 && !i)) { //The first task requested must be the one that crashed and it does not have a valid TCB anyway since it's not saved yet + if (i == j || (j == CUR_TASK_INDEX_UNKNOWN && i == 0)) { + //GDB has asked us for the current task on this CPU. + //This task either was executing when we have entered the panic handler, + //or was already switched out and we have paniced during the context switch. + //Either way we are interested in the stack frame where panic has happened, + //so obtain the state from the exception frame rather than the TCB. dumpHwToRegfile(&paniced_frame); } else { unsigned handle, count; //Get the handle for that task - count = getAllTasksHandle(i, &handle, 0, 0); + count = getTaskInfo(i, &handle, 0, 0); //Then extract TCB and gdbRegFile from it if (i < count) dumpTCBToRegFile(handle); else ret = "E00"; @@ -404,7 +423,7 @@ static int gdbHandleCommand(unsigned char *cmd, int len) { unsigned count; data++; i=gdbGetHexVal(&data, -1); - count = getAllTasksHandle(i, 0, 0, 0); + count = getTaskInfo(i, 0, 0, 0); return sendPacket(i < count ? "OK": "E00"); } else if (cmd[0]=='q') { //Extended query // React to qThreadExtraInfo or qfThreadInfo or qsThreadInfo or qC, without using strcmp @@ -415,7 +434,7 @@ static int gdbHandleCommand(unsigned char *cmd, int len) { unsigned handle = 0, coreId = 3; const char * name = 0; // Extract the task name and CPU from freeRTOS - unsigned tCount = getAllTasksHandle(i, &handle, &name, &coreId); + unsigned tCount = getTaskInfo(i, &handle, &name, &coreId); if (i < tCount) { gdbPacketStart(); for(k=0; name[k]; k++) gdbPacketHex(name[k], 8); @@ -429,34 +448,36 @@ static int gdbHandleCommand(unsigned char *cmd, int len) { // Extract the number of task from freeRTOS static int taskIndex = 0; unsigned tCount = 0; - if (cmd[1] == 'f') { + if (cmd[1] == 'f') { taskIndex = 0; - reenteredHandler = 1; //It seems it's the first request GDB is sending + handlerState = HANDLER_STARTED; //It seems it's the first request GDB is sending } - tCount = getAllTasksHandle(0, 0, 0, 0); + tCount = getTaskInfo(0, 0, 0, 0); if (taskIndex < tCount) { gdbPacketStart(); gdbPacketStr("m"); gdbPacketHex(taskIndex, 32); gdbPacketEnd(); - taskIndex++; + taskIndex++; } else return sendPacket("l"); } else if (len >= 2 && cmd[1] == 'C') { // Get current task id gdbPacketStart(); k = findCurrentTaskIndex(); - if (k != -1) { + if (k != CUR_TASK_INDEX_UNKNOWN) { gdbPacketStr("QC"); gdbPacketHex(k, 32); } else gdbPacketStr("bad"); gdbPacketEnd(); return ST_OK; } - return sendPacket(0); + return sendPacket(NULL); } - } else +#endif // CONFIG_GDBSTUB_SUPPORT_TASKS + } else { //We don't recognize or support whatever GDB just sent us. - return sendPacket(0); + return sendPacket(NULL); + } return ST_OK; } @@ -510,20 +531,20 @@ static int gdbReadCommand() { } - void esp_gdbstub_panic_handler(XtExcFrame *frame) { - if (reenteredHandler == 1) { - //Prevent using advanced FreeRTOS features since they seems to crash +#if CONFIG_GDBSTUB_SUPPORT_TASKS + if (handlerState == HANDLER_STARTED) { + //We have re-entered GDB Stub. Try disabling task support. + handlerState = HANDLER_TASK_SUPPORT_DISABLED; gdbPacketEnd(); // Ends up any pending GDB packet (this creates a garbage value) - reenteredHandler = -1; - } else { - //Need to remember the frame that panic'd since gdb will ask for all thread before ours - uint8_t * pf = (uint8_t*)&paniced_frame, *f = (uint8_t*)frame; - //Could not use memcpy here - for(int i = 0; i < sizeof(*frame); i++) pf[i] = f[i]; + } else if (handlerState == HANDLER_NOT_STARTED) { + //Need to remember the frame that panic'd since gdb will ask for all threads before ours + memcpy(&paniced_frame, frame, sizeof(paniced_frame)); + dumpHwToRegfile(&paniced_frame); } - //Let's start from something - dumpHwToRegfile(&paniced_frame); +#else // CONFIG_GDBSTUB_SUPPORT_TASKS + dumpHwToRegfile(frame); +#endif // CONFIG_GDBSTUB_SUPPORT_TASKS //Make sure txd/rxd are enabled gpio_pullup_dis(1);