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
}
#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;
pc = *(uint32_t *)(sp - 4);
if (off <= 3) {
pc = lr;
} else {
pc = *(uint32_t *)(sp - 4);
}
*o_sp = (void *)sp;
*o_pc = (void *)pc;

View File

@ -173,4 +173,19 @@ config FREERTOS_RUN_TIME_STATS_USING_CPU_CLK
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

View File

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

View File

@ -97,6 +97,18 @@ _xt_int_exit:
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
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
#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
l32i a14, a14, 0
addi a15, sp, XT_STK_FRMSZ

View File

@ -13,7 +13,7 @@
// limitations under the License.
#include "stdlib.h"
#include <string.h>
#include "esp_attr.h"
#include "esp_libc.h"
#include "esp_system.h"
@ -27,6 +27,7 @@
#include "esp_err.h"
#include "FreeRTOS.h"
#include "task.h"
#include "freertos/xtensa_context.h"
#define PANIC(_fmt, ...) ets_printf(_fmt, ##__VA_ARGS__)
@ -77,17 +78,31 @@ static inline void panic_frame(XtExcFrame *frame)
void *o_pc;
void *o_sp;
const char *reason = frame->exccause < 30 ? edesc[frame->exccause] : "unknown";
const uint32_t *regs = (const uint32_t *)frame;
#ifdef CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
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);
PANIC("Core 0 register dump:\n");
if (reason & XCHAL_DEBUGCAUSE_DBREAK_MASK) {
char name[configMAX_TASK_NAME_LEN];
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]);
strncpy(name, pcTaskGetTaskName(NULL), configMAX_TASK_NAME_LEN);
ets_printf("Stack canary watchpoint triggered (%s)\n", name);
}
} 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);

View File

@ -107,6 +107,7 @@ STRUCT_END(HighPriFrame)
.align 16
_chip_nmi_stk: .space PRI_N_STACK_SIZE + HESF_TOTALSIZE + PRI_N_STACK_SIZE2 + HESF_TOTALSIZE
.global LoadStoreErrorHandlerStack
.balign 16
LoadStoreErrorHandlerStack:
@ -559,15 +560,23 @@ Debug Exception.
.align 4
.literal_position
_DebugExceptionVector:
wsr a0, EXCSAVE + XCHAL_DEBUGLEVEL /* save original a0 somewhere */
wsr a0, EXCSAVE_1
wsr a1, EXCSAVE_2
call0 _xt_ext_panic /* does not return */
rfi XCHAL_DEBUGLEVEL /* make a0 point here not later */
movi a0, 1
wsr a0, EXCCAUSE
call0 _xt_debug_exc
.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.