feat(esp8266): hardware check task stack overflow

This commit is contained in:
Dong Heng
2019-12-24 18:56:45 +08:00
parent a3537856b2
commit 53e4e1687c
7 changed files with 99 additions and 13 deletions

View File

@ -134,6 +134,21 @@ static inline void soc_wait_int(void)
); );
} }
static inline uint32_t soc_debug_reason(void)
{
uint32_t tmp;
__asm__ __volatile__(
"movi %0, 0\n"
"wsr %0, dbreakc0\n"
"rsr.debugcause %0\n"
: "=r"(tmp)
:
: "memory");
return tmp;
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -57,7 +57,12 @@ int xt_retaddr_callee(const void *i_pc, const void *i_sp, const void *i_lr, void
} }
sp -= stk_size; sp -= stk_size;
pc = *(uint32_t *)(sp - 4);
if (off <= 3) {
pc = lr;
} else {
pc = *(uint32_t *)(sp - 4);
}
*o_sp = (void *)sp; *o_sp = (void *)sp;
*o_pc = (void *)pc; *o_pc = (void *)pc;

View File

@ -173,4 +173,19 @@ config FREERTOS_RUN_TIME_STATS_USING_CPU_CLK
endchoice endchoice
config FREERTOS_WATCHPOINT_END_OF_STACK
bool "Set a debug watchpoint as a stack overflow check"
default y
help
FreeRTOS can check if a stack has overflown its bounds by checking either the value of
the stack pointer or by checking the integrity of canary bytes. (See FREERTOS_CHECK_STACKOVERFLOW
for more information.) These checks only happen on a context switch, and the situation that caused
the stack overflow may already be long gone by then. This option will use the debug memory
watchpoint 0 to allow breaking into the debugger (or panic'ing) as soon as any
of the last 16 bytes on the stack of a task are overwritten.
This check only triggers if the stack overflow writes within 4 bytes of the end of the stack, rather than
overshooting further, so it is worth combining this approach with one of the other stack overflow check
methods.
endmenu endmenu

View File

@ -72,7 +72,10 @@
#define INCLUDE_xTaskGetIdleTaskHandle 1 #define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1 #define INCLUDE_xTimerGetTimerDaemonTaskHandle 1
#ifndef CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
#define configCHECK_FOR_STACK_OVERFLOW 2 #define configCHECK_FOR_STACK_OVERFLOW 2
#endif
#define configUSE_MUTEXES 1 #define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1 #define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1 #define configUSE_COUNTING_SEMAPHORES 1

View File

@ -97,6 +97,18 @@ _xt_int_exit:
l32i sp, sp, 0 l32i sp, sp, 0
l32i sp, sp, 0 l32i sp, sp, 0
#ifdef CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
movi a2, pxCurrentTCB
l32i a2, a2, 0
l32i a2, a2, 48
movi a4, ~(0xf)
and a4, a4, a2
wsr a4, dbreaka0
movi a3, 0xc0000030
wsr a3, dbreakc0
#endif
/* /*
We come here only if there was no context switch, that is if this We come here only if there was no context switch, that is if this
is a nested interrupt or the interrupted task was not preempted. is a nested interrupt or the interrupted task was not preempted.
@ -229,6 +241,18 @@ _xt_enter_first_task:
l32i sp, sp, 0 l32i sp, sp, 0
l32i sp, sp, 0 l32i sp, sp, 0
#ifdef CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
movi a2, pxCurrentTCB
l32i a2, a2, 0
l32i a2, a2, 48
movi a4, ~(0xf)
and a4, a4, a2
wsr a4, dbreaka0
movi a3, 0xc0000030
wsr a3, dbreakc0
#endif
movi a14, pxCurrentTCB movi a14, pxCurrentTCB
l32i a14, a14, 0 l32i a14, a14, 0
addi a15, sp, XT_STK_FRMSZ addi a15, sp, XT_STK_FRMSZ

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
#include "stdlib.h" #include "stdlib.h"
#include <string.h>
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_libc.h" #include "esp_libc.h"
#include "esp_system.h" #include "esp_system.h"
@ -27,6 +27,7 @@
#include "esp_err.h" #include "esp_err.h"
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h"
#include "freertos/xtensa_context.h" #include "freertos/xtensa_context.h"
#define PANIC(_fmt, ...) ets_printf(_fmt, ##__VA_ARGS__) #define PANIC(_fmt, ...) ets_printf(_fmt, ##__VA_ARGS__)
@ -77,17 +78,31 @@ static inline void panic_frame(XtExcFrame *frame)
void *o_pc; void *o_pc;
void *o_sp; void *o_sp;
const char *reason = frame->exccause < 30 ? edesc[frame->exccause] : "unknown"; #ifdef CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
const uint32_t *regs = (const uint32_t *)frame; if (frame->exccause == 1) {
uint32_t reason = soc_debug_reason();
PANIC("Guru Meditation Error: Core 0 panic'ed (%s). Exception was unhandled.\r\n", reason); if (reason & XCHAL_DEBUGCAUSE_DBREAK_MASK) {
PANIC("Core 0 register dump:\n"); char name[configMAX_TASK_NAME_LEN];
for (int i = 0; i < 20; i += 4) { strncpy(name, pcTaskGetTaskName(NULL), configMAX_TASK_NAME_LEN);
for (int j = 0; j < 4; j++) { ets_printf("Stack canary watchpoint triggered (%s)\n", name);
PANIC("%-8s: 0x%08x ", sdesc[i + j], regs[i + j + 1]); }
} else
#endif
{
const char *reason = frame->exccause < 30 ? edesc[frame->exccause] : "unknown";
const uint32_t *regs = (const uint32_t *)frame;
PANIC("Guru Meditation Error: Core 0 panic'ed (%s). Exception was unhandled.\r\n", reason);
PANIC("Core 0 register dump:\n");
for (int i = 0; i < 20; i += 4) {
for (int j = 0; j < 4; j++) {
PANIC("%-8s: 0x%08x ", sdesc[i + j], regs[i + j + 1]);
}
PANIC("\r\n");
} }
PANIC("\r\n");
} }
PANIC("\r\nBacktrace: %p:%p ", i_pc, i_sp); PANIC("\r\nBacktrace: %p:%p ", i_pc, i_sp);

View File

@ -107,6 +107,7 @@ STRUCT_END(HighPriFrame)
.align 16 .align 16
_chip_nmi_stk: .space PRI_N_STACK_SIZE + HESF_TOTALSIZE + PRI_N_STACK_SIZE2 + HESF_TOTALSIZE _chip_nmi_stk: .space PRI_N_STACK_SIZE + HESF_TOTALSIZE + PRI_N_STACK_SIZE2 + HESF_TOTALSIZE
.global LoadStoreErrorHandlerStack .global LoadStoreErrorHandlerStack
.balign 16 .balign 16
LoadStoreErrorHandlerStack: LoadStoreErrorHandlerStack:
@ -559,15 +560,23 @@ Debug Exception.
.align 4 .align 4
.literal_position .literal_position
_DebugExceptionVector: _DebugExceptionVector:
wsr a0, EXCSAVE + XCHAL_DEBUGLEVEL /* save original a0 somewhere */
wsr a0, EXCSAVE_1 wsr a0, EXCSAVE_1
wsr a1, EXCSAVE_2 wsr a1, EXCSAVE_2
call0 _xt_ext_panic /* does not return */ movi a0, 1
rfi XCHAL_DEBUGLEVEL /* make a0 point here not later */ wsr a0, EXCCAUSE
call0 _xt_debug_exc
.end literal_prefix .end literal_prefix
.section .text
.type _xt_user_exc,@function
.align 4
_xt_debug_exc:
rsr a0, (EPC + XCHAL_DEBUGLEVEL)
wsr a0, EPC1
call0 _xt_ext_panic /* does not return */
/* /*
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
Double Exception. Double Exception.