assert: cleanup assert handler
1. extract dump from assert main flow 2. use OSINIT_PANIC for fatal error. 3. fix the method to judge kernel thread. Signed-off-by: xuxingliang <xuxingliang@xiaomi.com>
This commit is contained in:
parent
9da6761453
commit
e65b03edd2
@ -69,7 +69,8 @@ enum nx_initstate_e
|
|||||||
* initialization. */
|
* initialization. */
|
||||||
OSINIT_OSREADY = 5, /* The OS is fully initialized and multi-tasking is
|
OSINIT_OSREADY = 5, /* The OS is fully initialized and multi-tasking is
|
||||||
* active. */
|
* active. */
|
||||||
OSINIT_IDLELOOP = 6 /* The OS enter idle loop */
|
OSINIT_IDLELOOP = 6, /* The OS enter idle loop. */
|
||||||
|
OSINIT_PANIC = 7 /* Fatal error happened. */
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -29,9 +29,9 @@
|
|||||||
#include <nuttx/arch.h>
|
#include <nuttx/arch.h>
|
||||||
#include <nuttx/board.h>
|
#include <nuttx/board.h>
|
||||||
#include <nuttx/coredump.h>
|
#include <nuttx/coredump.h>
|
||||||
#include <nuttx/fs/fs.h>
|
|
||||||
#include <nuttx/init.h>
|
#include <nuttx/init.h>
|
||||||
#include <nuttx/irq.h>
|
#include <nuttx/irq.h>
|
||||||
|
#include <nuttx/fs/fs.h>
|
||||||
#include <nuttx/tls.h>
|
#include <nuttx/tls.h>
|
||||||
#include <nuttx/signal.h>
|
#include <nuttx/signal.h>
|
||||||
#ifdef CONFIG_ARCH_LEDS
|
#ifdef CONFIG_ARCH_LEDS
|
||||||
@ -94,8 +94,9 @@
|
|||||||
* Private Data
|
* Private Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static uintptr_t
|
static uintptr_t g_last_regs[XCPTCONTEXT_REGS]
|
||||||
g_last_regs[XCPTCONTEXT_REGS] aligned_data(XCPTCONTEXT_ALIGN);
|
aligned_data(XCPTCONTEXT_ALIGN);
|
||||||
|
|
||||||
static FAR const char * const g_policy[4] =
|
static FAR const char * const g_policy[4] =
|
||||||
{
|
{
|
||||||
"FIFO", "RR", "SPORADIC"
|
"FIFO", "RR", "SPORADIC"
|
||||||
@ -109,8 +110,6 @@ static FAR const char * const g_ttypenames[4] =
|
|||||||
"Invalid"
|
"Invalid"
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool g_fatal_assert = false;
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -213,8 +212,14 @@ static void dump_stack(FAR const char *tag, uintptr_t sp,
|
|||||||
|
|
||||||
static void dump_stacks(FAR struct tcb_s *rtcb, uintptr_t sp)
|
static void dump_stacks(FAR struct tcb_s *rtcb, uintptr_t sp)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
int cpu = rtcb->cpu;
|
||||||
|
#else
|
||||||
|
int cpu = this_cpu();
|
||||||
|
UNUSED(cpu);
|
||||||
|
#endif
|
||||||
#if CONFIG_ARCH_INTERRUPTSTACK > 0
|
#if CONFIG_ARCH_INTERRUPTSTACK > 0
|
||||||
uintptr_t intstack_base = up_get_intstackbase(this_cpu());
|
uintptr_t intstack_base = up_get_intstackbase(cpu);
|
||||||
size_t intstack_size = CONFIG_ARCH_INTERRUPTSTACK;
|
size_t intstack_size = CONFIG_ARCH_INTERRUPTSTACK;
|
||||||
uintptr_t intstack_top = intstack_base + intstack_size;
|
uintptr_t intstack_top = intstack_base + intstack_size;
|
||||||
uintptr_t intstack_sp = 0;
|
uintptr_t intstack_sp = 0;
|
||||||
@ -263,13 +268,16 @@ static void dump_stacks(FAR struct tcb_s *rtcb, uintptr_t sp)
|
|||||||
intstack_base,
|
intstack_base,
|
||||||
intstack_size,
|
intstack_size,
|
||||||
#ifdef CONFIG_STACK_COLORATION
|
#ifdef CONFIG_STACK_COLORATION
|
||||||
up_check_intstack(this_cpu())
|
up_check_intstack(cpu)
|
||||||
#else
|
#else
|
||||||
0
|
0
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
tcbstack_sp = up_getusrsp((FAR void *)up_current_regs());
|
/* Try to restore SP from current_regs if assert from interrupt. */
|
||||||
|
|
||||||
|
tcbstack_sp = up_interrupt_context() ?
|
||||||
|
up_getusrsp((FAR void *)up_current_regs()) : 0;
|
||||||
if (tcbstack_sp < tcbstack_base || tcbstack_sp >= tcbstack_top)
|
if (tcbstack_sp < tcbstack_base || tcbstack_sp >= tcbstack_top)
|
||||||
{
|
{
|
||||||
tcbstack_sp = 0;
|
tcbstack_sp = 0;
|
||||||
@ -364,7 +372,7 @@ static void dump_task(FAR struct tcb_s *tcb, FAR void *arg)
|
|||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
" %4d"
|
" %4d"
|
||||||
#endif
|
#endif
|
||||||
" %3d %-8s %-7s %c"
|
" %3d %-8s %-7s %-3c"
|
||||||
" %-18s"
|
" %-18s"
|
||||||
" " SIGSET_FMT
|
" " SIGSET_FMT
|
||||||
" %p"
|
" %p"
|
||||||
@ -562,95 +570,47 @@ static void pause_all_cpu(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
static void dump_running_task(FAR struct tcb_s *rtcb, FAR void *regs)
|
||||||
* Public Functions
|
{
|
||||||
****************************************************************************/
|
/* Register dump */
|
||||||
|
|
||||||
/****************************************************************************
|
up_dump_register(regs);
|
||||||
* Name: _assert
|
|
||||||
****************************************************************************/
|
#ifdef CONFIG_ARCH_STACKDUMP
|
||||||
|
dump_stacks(rtcb, up_getusrsp(regs));
|
||||||
void _assert(FAR const char *filename, int linenum,
|
#endif
|
||||||
FAR const char *msg, FAR void *regs)
|
|
||||||
|
/* Show back trace */
|
||||||
|
|
||||||
|
#ifdef CONFIG_SCHED_BACKTRACE
|
||||||
|
sched_dumpstack(rtcb->pid);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: dump_assert_info
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Dump basic information of assertion
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void dump_assert_info(FAR struct tcb_s *rtcb,
|
||||||
|
FAR const char *filename, int linenum,
|
||||||
|
FAR const char *msg, FAR void *regs)
|
||||||
{
|
{
|
||||||
const bool os_ready = OSINIT_OS_READY();
|
|
||||||
FAR struct tcb_s *rtcb = running_task();
|
|
||||||
#if CONFIG_TASK_NAME_SIZE > 0
|
#if CONFIG_TASK_NAME_SIZE > 0
|
||||||
FAR struct tcb_s *ptcb = NULL;
|
FAR struct tcb_s *ptcb = NULL;
|
||||||
#endif
|
#endif
|
||||||
struct panic_notifier_s notifier_data;
|
|
||||||
struct utsname name;
|
struct utsname name;
|
||||||
irqstate_t flags;
|
|
||||||
bool fatal = true;
|
|
||||||
|
|
||||||
#if CONFIG_TASK_NAME_SIZE > 0
|
#if CONFIG_TASK_NAME_SIZE > 0
|
||||||
if (rtcb->group && !(rtcb->flags & TCB_FLAG_TTYPE_KERNEL))
|
if (rtcb->group &&
|
||||||
|
(rtcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL)
|
||||||
{
|
{
|
||||||
ptcb = nxsched_get_tcb(rtcb->group->tg_pid);
|
ptcb = nxsched_get_tcb(rtcb->group->tg_pid);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
flags = 0; /* suppress GCC warning */
|
|
||||||
if (os_ready)
|
|
||||||
{
|
|
||||||
flags = enter_critical_section();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_fatal_assert)
|
|
||||||
{
|
|
||||||
goto reset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (os_ready && fatal)
|
|
||||||
{
|
|
||||||
/* Disable KASAN to avoid false positive */
|
|
||||||
|
|
||||||
kasan_stop();
|
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
pause_all_cpu();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* try to save current context if regs is null */
|
|
||||||
|
|
||||||
if (regs == NULL)
|
|
||||||
{
|
|
||||||
up_saveusercontext(g_last_regs);
|
|
||||||
regs = g_last_regs;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(g_last_regs, regs, sizeof(g_last_regs));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CONFIG_BOARD_RESET_ON_ASSERT < 2
|
|
||||||
if (!up_interrupt_context() &&
|
|
||||||
(rtcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL)
|
|
||||||
{
|
|
||||||
fatal = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
g_fatal_assert = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
notifier_data.rtcb = rtcb;
|
|
||||||
notifier_data.regs = regs;
|
|
||||||
notifier_data.filename = filename;
|
|
||||||
notifier_data.linenum = linenum;
|
|
||||||
notifier_data.msg = msg;
|
|
||||||
panic_notifier_call_chain(fatal ? PANIC_KERNEL : PANIC_TASK,
|
|
||||||
¬ifier_data);
|
|
||||||
#ifdef CONFIG_ARCH_LEDS
|
|
||||||
board_autoled_on(LED_ASSERTION);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Flush any buffered SYSLOG data (from prior to the assertion) */
|
|
||||||
|
|
||||||
syslog_flush();
|
|
||||||
|
|
||||||
uname(&name);
|
uname(&name);
|
||||||
_alert("Current Version: %s %s %s %s %s\n",
|
_alert("Current Version: %s %s %s %s %s\n",
|
||||||
name.sysname, name.nodename,
|
name.sysname, name.nodename,
|
||||||
@ -677,42 +637,41 @@ void _assert(FAR const char *filename, int linenum,
|
|||||||
#endif
|
#endif
|
||||||
rtcb->entry.main);
|
rtcb->entry.main);
|
||||||
|
|
||||||
/* Register dump */
|
/* Dump current CPU registers, running task stack and backtrace. */
|
||||||
|
|
||||||
up_dump_register(regs);
|
dump_running_task(rtcb, regs);
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_STACKDUMP
|
|
||||||
dump_stacks(rtcb, up_getusrsp(regs));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Show back trace */
|
|
||||||
|
|
||||||
#ifdef CONFIG_SCHED_BACKTRACE
|
|
||||||
sched_dumpstack(rtcb->pid);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Flush any buffered SYSLOG data */
|
/* Flush any buffered SYSLOG data */
|
||||||
|
|
||||||
syslog_flush();
|
syslog_flush();
|
||||||
|
}
|
||||||
|
|
||||||
if (fatal)
|
/****************************************************************************
|
||||||
{
|
* Name: dump_fatal_info
|
||||||
dump_tasks();
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void dump_fatal_info(FAR struct tcb_s *rtcb,
|
||||||
|
FAR const char *filename, int linenum,
|
||||||
|
FAR const char *msg, FAR void *regs)
|
||||||
|
{
|
||||||
|
/* Dump backtrace of other tasks. */
|
||||||
|
|
||||||
|
dump_tasks();
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_DEADLOCKDUMP
|
#ifdef CONFIG_ARCH_DEADLOCKDUMP
|
||||||
/* Deadlock Dump */
|
/* Deadlock Dump */
|
||||||
|
|
||||||
dump_deadlock();
|
dump_deadlock();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_USBDUMP
|
#ifdef CONFIG_ARCH_USBDUMP
|
||||||
/* Dump USB trace data */
|
/* Dump USB trace data */
|
||||||
|
|
||||||
usbtrace_enumerate(assert_tracecallback, NULL);
|
usbtrace_enumerate(assert_tracecallback, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_BOARD_CRASHDUMP
|
#ifdef CONFIG_BOARD_CRASHDUMP
|
||||||
board_crashdump(up_getsp(), rtcb, filename, linenum, msg, regs);
|
board_crashdump(up_getsp(), rtcb, filename, linenum, msg, regs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_BOARD_COREDUMP_SYSLOG) || \
|
#if defined(CONFIG_BOARD_COREDUMP_SYSLOG) || \
|
||||||
@ -720,35 +679,136 @@ void _assert(FAR const char *filename, int linenum,
|
|||||||
/* Dump core information */
|
/* Dump core information */
|
||||||
|
|
||||||
# ifdef CONFIG_BOARD_COREDUMP_FULL
|
# ifdef CONFIG_BOARD_COREDUMP_FULL
|
||||||
coredump_dump(INVALID_PROCESS_ID);
|
coredump_dump(INVALID_PROCESS_ID);
|
||||||
# else
|
# else
|
||||||
coredump_dump(rtcb->pid);
|
coredump_dump(rtcb->pid);
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Flush any buffered SYSLOG data */
|
/* Flush any buffered SYSLOG data */
|
||||||
|
|
||||||
|
syslog_flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: reset_board
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Reset board or stuck here to flash LED. It should never return.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void reset_board(void)
|
||||||
|
{
|
||||||
|
#if CONFIG_BOARD_RESET_ON_ASSERT >= 1
|
||||||
|
board_reset(CONFIG_BOARD_ASSERT_RESET_VALUE);
|
||||||
|
#else
|
||||||
|
for (; ; )
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_ARCH_LEDS
|
||||||
|
/* FLASH LEDs a 2Hz */
|
||||||
|
|
||||||
|
board_autoled_on(LED_PANIC);
|
||||||
|
up_mdelay(250);
|
||||||
|
board_autoled_off(LED_PANIC);
|
||||||
|
#endif
|
||||||
|
up_mdelay(250);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: _assert
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void _assert(FAR const char *filename, int linenum,
|
||||||
|
FAR const char *msg, FAR void *regs)
|
||||||
|
{
|
||||||
|
const bool os_ready = OSINIT_OS_READY();
|
||||||
|
FAR struct tcb_s *rtcb = running_task();
|
||||||
|
struct panic_notifier_s notifier_data;
|
||||||
|
irqstate_t flags;
|
||||||
|
|
||||||
|
if (g_nx_initstate == OSINIT_PANIC)
|
||||||
|
{
|
||||||
|
/* Already in fatal state, reset board directly. */
|
||||||
|
|
||||||
|
reset_board(); /* Should not return. */
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = 0; /* suppress GCC warning */
|
||||||
|
if (os_ready)
|
||||||
|
{
|
||||||
|
flags = enter_critical_section();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_BOARD_RESET_ON_ASSERT < 2
|
||||||
|
if (up_interrupt_context() ||
|
||||||
|
(rtcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_KERNEL)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* Fatal error, enter panic state. */
|
||||||
|
|
||||||
|
g_nx_initstate = OSINIT_PANIC;
|
||||||
|
|
||||||
|
/* Disable KASAN to avoid false positive */
|
||||||
|
|
||||||
|
kasan_stop();
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
if (os_ready)
|
||||||
|
{
|
||||||
|
pause_all_cpu();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to save current context if regs is null */
|
||||||
|
|
||||||
|
if (regs == NULL)
|
||||||
|
{
|
||||||
|
up_saveusercontext(g_last_regs);
|
||||||
|
regs = g_last_regs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(g_last_regs, regs, sizeof(g_last_regs));
|
||||||
|
}
|
||||||
|
|
||||||
|
notifier_data.rtcb = rtcb;
|
||||||
|
notifier_data.regs = regs;
|
||||||
|
notifier_data.filename = filename;
|
||||||
|
notifier_data.linenum = linenum;
|
||||||
|
notifier_data.msg = msg;
|
||||||
|
panic_notifier_call_chain(g_nx_initstate == OSINIT_PANIC
|
||||||
|
? PANIC_KERNEL : PANIC_TASK,
|
||||||
|
¬ifier_data);
|
||||||
|
#ifdef CONFIG_ARCH_LEDS
|
||||||
|
board_autoled_on(LED_ASSERTION);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Flush any buffered SYSLOG data (from prior to the assertion) */
|
||||||
|
|
||||||
|
syslog_flush();
|
||||||
|
|
||||||
|
/* Dump basic info of assertion. */
|
||||||
|
|
||||||
|
dump_assert_info(rtcb, filename, linenum, msg, regs);
|
||||||
|
|
||||||
|
if (g_nx_initstate == OSINIT_PANIC)
|
||||||
|
{
|
||||||
|
/* Dump fatal info of assertion. */
|
||||||
|
|
||||||
|
dump_fatal_info(rtcb, filename, linenum, msg, regs);
|
||||||
|
|
||||||
syslog_flush();
|
|
||||||
panic_notifier_call_chain(PANIC_KERNEL_FINAL, ¬ifier_data);
|
panic_notifier_call_chain(PANIC_KERNEL_FINAL, ¬ifier_data);
|
||||||
|
|
||||||
reboot_notifier_call_chain(SYS_HALT, NULL);
|
reboot_notifier_call_chain(SYS_HALT, NULL);
|
||||||
|
|
||||||
reset:
|
reset_board(); /* Should not return. */
|
||||||
#if CONFIG_BOARD_RESET_ON_ASSERT >= 1
|
|
||||||
board_reset(CONFIG_BOARD_ASSERT_RESET_VALUE);
|
|
||||||
#else
|
|
||||||
for (; ; )
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_ARCH_LEDS
|
|
||||||
/* FLASH LEDs a 2Hz */
|
|
||||||
|
|
||||||
board_autoled_on(LED_PANIC);
|
|
||||||
up_mdelay(250);
|
|
||||||
board_autoled_off(LED_PANIC);
|
|
||||||
#endif
|
|
||||||
up_mdelay(250);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (os_ready)
|
if (os_ready)
|
||||||
|
Loading…
Reference in New Issue
Block a user