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
components
esp8266
include/driver
source
freertos

@ -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

@ -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;

@ -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

@ -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

@ -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

@ -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);

@ -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.