Add documentation to panic handler functions, move watchpoint stuff from tasks.c to port.c, account for non-32-bytes-aligned stacks when setting watchpoint, add debug reason explanation to panic handler
This commit is contained in:
parent
ca57a86f20
commit
881157e1ed
5 changed files with 89 additions and 7 deletions
|
@ -16,13 +16,44 @@
|
||||||
|
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief If an OCD is connected over JTAG. set breakpoint 0 to the given function
|
||||||
|
* address. Do nothing otherwise.
|
||||||
|
* @param data Pointer to the target breakpoint position
|
||||||
|
*/
|
||||||
|
|
||||||
void esp_set_breakpoint_if_jtag(void *fn);
|
void esp_set_breakpoint_if_jtag(void *fn);
|
||||||
|
|
||||||
#define ESP_WATCHPOINT_LOAD 0x40000000
|
#define ESP_WATCHPOINT_LOAD 0x40000000
|
||||||
#define ESP_WATCHPOINT_STORE 0x80000000
|
#define ESP_WATCHPOINT_STORE 0x80000000
|
||||||
#define ESP_WATCHPOINT_ACCESS 0xC0000000
|
#define ESP_WATCHPOINT_ACCESS 0xC0000000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set a watchpoint to break/panic when a certain memory range is accessed.
|
||||||
|
*
|
||||||
|
* @param no Watchpoint number. On the ESP32, this can be 0 or 1.
|
||||||
|
* @param adr Base address to watch
|
||||||
|
* @param size Size of the region, starting at the base address, to watch. Must
|
||||||
|
* be one of 2^n, with n in [0..6].
|
||||||
|
* @param flags One of ESP_WATCHPOINT_* flags
|
||||||
|
*
|
||||||
|
* @return ESP_ERR_INVALID_ARG on invalid arg, ESP_OK otherwise
|
||||||
|
*
|
||||||
|
* @warning The ESP32 watchpoint hardware watches a region of bytes by effectively
|
||||||
|
* masking away the lower n bits for a region with size 2^n. If adr does
|
||||||
|
* not have zero for these lower n bits, you may not be watching the
|
||||||
|
* region you intended.
|
||||||
|
*/
|
||||||
esp_err_t esp_set_watchpoint(int no, void *adr, int size, int flags);
|
esp_err_t esp_set_watchpoint(int no, void *adr, int size, int flags);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear a watchpoint
|
||||||
|
*
|
||||||
|
* @param no Watchpoint to clear
|
||||||
|
*
|
||||||
|
*/
|
||||||
void esp_clear_watchpoint(int no);
|
void esp_clear_watchpoint(int no);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -164,8 +164,37 @@ void panicHandler(XtExcFrame *frame)
|
||||||
panicPutStr("Guru Meditation Error: Core ");
|
panicPutStr("Guru Meditation Error: Core ");
|
||||||
panicPutDec(xPortGetCoreID());
|
panicPutDec(xPortGetCoreID());
|
||||||
panicPutStr(" panic'ed (");
|
panicPutStr(" panic'ed (");
|
||||||
|
if (!abort_called) {
|
||||||
panicPutStr(reason);
|
panicPutStr(reason);
|
||||||
panicPutStr(")\r\n");
|
panicPutStr(")\r\n");
|
||||||
|
if (regs[20]==PANIC_RSN_DEBUGEXCEPTION) {
|
||||||
|
int debugRsn;
|
||||||
|
asm("rsr.debugcause %0":"=r"(debugRsn));
|
||||||
|
panicPutStr("Debug exception reason: ");
|
||||||
|
if (debugRsn&XCHAL_DEBUGCAUSE_ICOUNT_MASK) panicPutStr("SingleStep ");
|
||||||
|
if (debugRsn&XCHAL_DEBUGCAUSE_IBREAK_MASK) panicPutStr("HwBreakpoint ");
|
||||||
|
if (debugRsn&XCHAL_DEBUGCAUSE_DBREAK_MASK) {
|
||||||
|
//Unlike what the ISA manual says, this core seemingly distinguishes from a DBREAK
|
||||||
|
//reason caused by watchdog 0 and one caused by watchdog 1 by setting bit 8 of the
|
||||||
|
//debugcause if the cause is watchdog 1 and clearing it if it's watchdog 0.
|
||||||
|
if (debugRsn&(1<<8)) {
|
||||||
|
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
|
||||||
|
panicPutStr("Stack canary watchpoint triggered ");
|
||||||
|
#else
|
||||||
|
panicPutStr("Watchpoint 1 triggered ");
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
panicPutStr("Watchpoint 0 triggered ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (debugRsn&XCHAL_DEBUGCAUSE_BREAK_MASK) panicPutStr("BREAK instr ");
|
||||||
|
if (debugRsn&XCHAL_DEBUGCAUSE_BREAKN_MASK) panicPutStr("BREAKN instr ");
|
||||||
|
if (debugRsn&XCHAL_DEBUGCAUSE_DEBUGINT_MASK) panicPutStr("DebugIntr ");
|
||||||
|
panicPutStr("\r\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panicPutStr("abort)\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (esp_cpu_in_ocd_debug_mode()) {
|
if (esp_cpu_in_ocd_debug_mode()) {
|
||||||
asm("break.n 1");
|
asm("break.n 1");
|
||||||
|
@ -363,11 +392,11 @@ esp_err_t esp_set_watchpoint(int no, void *adr, int size, int flags)
|
||||||
if (flags&(~0xC0000000)) return ESP_ERR_INVALID_ARG;
|
if (flags&(~0xC0000000)) return ESP_ERR_INVALID_ARG;
|
||||||
int dbreakc=0x3F;
|
int dbreakc=0x3F;
|
||||||
//We support watching 2^n byte values, from 1 to 64. Calculate the mask for that.
|
//We support watching 2^n byte values, from 1 to 64. Calculate the mask for that.
|
||||||
for (x=0; x<6; x++) {
|
for (x=0; x<7; x++) {
|
||||||
if (size==(1<<x)) break;
|
if (size==(1<<x)) break;
|
||||||
dbreakc<<=1;
|
dbreakc<<=1;
|
||||||
}
|
}
|
||||||
if (x==6) return ESP_ERR_INVALID_ARG;
|
if (x==7) return ESP_ERR_INVALID_ARG;
|
||||||
//Mask mask and add in flags.
|
//Mask mask and add in flags.
|
||||||
dbreakc=(dbreakc&0x3f)|flags;
|
dbreakc=(dbreakc&0x3f)|flags;
|
||||||
|
|
||||||
|
|
|
@ -187,6 +187,13 @@ void vPortEndScheduler( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
void vPortYieldOtherCore( BaseType_t coreid) PRIVILEGED_FUNCTION;
|
void vPortYieldOtherCore( BaseType_t coreid) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Callback to set a watchpoint on the end of the stack. Called every context switch to change the stack
|
||||||
|
watchpoint around.
|
||||||
|
*/
|
||||||
|
void vPortSetStackWatchpoint( void* pxStackStart );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The structures and methods of manipulating the MPU are contained within the
|
* The structures and methods of manipulating the MPU are contained within the
|
||||||
* port layer.
|
* port layer.
|
||||||
|
|
|
@ -394,3 +394,19 @@ void vPortFirstTaskHook(TaskFunction_t function) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void vPortSetStackWatchpoint( void* pxStackStart ) {
|
||||||
|
//Set watchpoint 1 to watch the last 32 bytes of the stack.
|
||||||
|
//Unfortunately, the Xtensa watchpoints can't set a watchpoint on a random [base - base+n] region because
|
||||||
|
//the size works by masking off the lowest address bits. For that reason, we futz a bit and watch the lowest 32
|
||||||
|
//bytes of the stack we can actually watch. In general, this can cause the watchpoint to be triggered at most
|
||||||
|
//28 bytes early. The value 32 is chosen because it's larger than the stack canary, which in FreeRTOS is 20 bytes.
|
||||||
|
//This way, we make sure we trigger before/when the stack canary is corrupted, not after.
|
||||||
|
int addr=(int)pxStackStart;
|
||||||
|
addr=(addr+31)&(~31);
|
||||||
|
esp_set_watchpoint(1, (char*)addr, 32, ESP_WATCHPOINT_STORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2811,8 +2811,7 @@ void vTaskSwitchContext( void )
|
||||||
traceTASK_SWITCHED_IN();
|
traceTASK_SWITCHED_IN();
|
||||||
|
|
||||||
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
|
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
|
||||||
//Set watchpoint 1 to watch the last 32 bytes of the stack.
|
vPortSetStackWatchpoint(pxCurrentTCB[xPortGetCoreID()]->pxStack);
|
||||||
esp_set_watchpoint(1, pxCurrentTCB[xPortGetCoreID()]->pxStack, 32, ESP_WATCHPOINT_STORE);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue