908df725ad
reason: 1 On different architectures, we can utilize more optimized strategies to implement up_current_regs/up_set_current_regs. eg. use interrupt registersor percpu registers. code size before text data bss dec hex filename 262848 49985 63893 376726 5bf96 nuttx after text data bss dec hex filename 262844 49985 63893 376722 5bf92 nuttx size change -4 Configuring NuttX and compile: $ ./tools/configure.sh -l qemu-armv8a:nsh_smp $ make Running with qemu $ qemu-system-aarch64 -cpu cortex-a53 -smp 4 -nographic \ -machine virt,virtualization=on,gic-version=3 \ -net none -chardev stdio,id=con,mux=on -serial chardev:con \ -mon chardev=con,mode=readline -kernel ./nuttx Signed-off-by: hujun5 <hujun5@xiaomi.com>
754 lines
18 KiB
C
754 lines
18 KiB
C
/****************************************************************************
|
|
* sched/misc/assert.c
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <nuttx/arch.h>
|
|
#include <nuttx/board.h>
|
|
#include <nuttx/coredump.h>
|
|
#include <nuttx/fs/fs.h>
|
|
#include <nuttx/init.h>
|
|
#include <nuttx/irq.h>
|
|
#include <nuttx/tls.h>
|
|
#include <nuttx/signal.h>
|
|
#ifdef CONFIG_ARCH_LEDS
|
|
# include <arch/board/board.h>
|
|
#endif
|
|
#include <nuttx/panic_notifier.h>
|
|
#include <nuttx/reboot_notifier.h>
|
|
#include <nuttx/syslog/syslog.h>
|
|
#include <nuttx/usb/usbdev_trace.h>
|
|
|
|
#include <assert.h>
|
|
#include <debug.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <sys/utsname.h>
|
|
|
|
#include "irq/irq.h"
|
|
#include "sched/sched.h"
|
|
#include "group/group.h"
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
#define DEADLOCK_MAX 8
|
|
|
|
#ifndef CONFIG_BOARD_RESET_ON_ASSERT
|
|
# define CONFIG_BOARD_RESET_ON_ASSERT 0
|
|
#endif
|
|
|
|
/* Check if an interrupt stack size is configured */
|
|
|
|
#ifndef CONFIG_ARCH_INTERRUPTSTACK
|
|
# define CONFIG_ARCH_INTERRUPTSTACK 0
|
|
#endif
|
|
|
|
/* USB trace dumping */
|
|
|
|
#ifndef CONFIG_USBDEV_TRACE
|
|
# undef CONFIG_ARCH_USBDUMP
|
|
#endif
|
|
|
|
#define DUMP_PTR(p, x) ((uintptr_t)(&(p)[(x)]) < stack_top ? (p)[(x)] : 0)
|
|
#define DUMP_STRIDE (sizeof(FAR void *) * 8)
|
|
|
|
#if UINTPTR_MAX <= UINT32_MAX
|
|
# define DUMP_FORMAT " %08" PRIxPTR ""
|
|
#elif UINTPTR_MAX <= UINT64_MAX
|
|
# define DUMP_FORMAT " %016" PRIxPTR ""
|
|
#endif
|
|
|
|
/* Architecture can overwrite the default XCPTCONTEXT alignment */
|
|
|
|
#ifndef XCPTCONTEXT_ALIGN
|
|
# define XCPTCONTEXT_ALIGN 16
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
static uintptr_t
|
|
g_last_regs[XCPTCONTEXT_REGS] aligned_data(XCPTCONTEXT_ALIGN);
|
|
static FAR const char * const g_policy[4] =
|
|
{
|
|
"FIFO", "RR", "SPORADIC"
|
|
};
|
|
|
|
static FAR const char * const g_ttypenames[4] =
|
|
{
|
|
"Task",
|
|
"pthread",
|
|
"Kthread",
|
|
"Invalid"
|
|
};
|
|
|
|
static bool g_fatal_assert = false;
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: assert_tracecallback
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_ARCH_USBDUMP
|
|
static int usbtrace_syslog(FAR const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
/* Let vsyslog do the real work */
|
|
|
|
va_start(ap, fmt);
|
|
vsyslog(LOG_EMERG, fmt, ap);
|
|
va_end(ap);
|
|
return OK;
|
|
}
|
|
|
|
static int assert_tracecallback(FAR struct usbtrace_s *trace, FAR void *arg)
|
|
{
|
|
usbtrace_trprintf(usbtrace_syslog, trace->event, trace->value);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_ARCH_STACKDUMP
|
|
|
|
/****************************************************************************
|
|
* Name: stack_dump
|
|
****************************************************************************/
|
|
|
|
static void stack_dump(uintptr_t sp, uintptr_t stack_top)
|
|
{
|
|
uintptr_t stack;
|
|
|
|
for (stack = sp; stack <= stack_top; stack += DUMP_STRIDE)
|
|
{
|
|
FAR uintptr_t *ptr = (FAR uintptr_t *)stack;
|
|
|
|
_alert("%p:"DUMP_FORMAT DUMP_FORMAT DUMP_FORMAT DUMP_FORMAT
|
|
DUMP_FORMAT DUMP_FORMAT DUMP_FORMAT DUMP_FORMAT "\n",
|
|
(FAR void *)stack, DUMP_PTR(ptr, 0), DUMP_PTR(ptr , 1),
|
|
DUMP_PTR(ptr, 2), DUMP_PTR(ptr, 3), DUMP_PTR(ptr, 4),
|
|
DUMP_PTR(ptr, 5), DUMP_PTR(ptr , 6), DUMP_PTR(ptr, 7));
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: dump_stack
|
|
****************************************************************************/
|
|
|
|
static void dump_stack(FAR const char *tag, uintptr_t sp,
|
|
uintptr_t base, size_t size, size_t used)
|
|
{
|
|
uintptr_t top = base + size;
|
|
|
|
_alert("%s Stack:\n", tag);
|
|
_alert(" base: %p\n", (FAR void *)base);
|
|
_alert(" size: %08zu\n", size);
|
|
|
|
if (sp != 0)
|
|
{
|
|
_alert(" sp: %p\n", (FAR void *)sp);
|
|
|
|
/* Get more information */
|
|
|
|
if (sp - DUMP_STRIDE >= base)
|
|
{
|
|
sp -= DUMP_STRIDE;
|
|
}
|
|
|
|
stack_dump(sp, top);
|
|
}
|
|
else
|
|
{
|
|
#ifdef CONFIG_STACK_COLORATION
|
|
size_t remain = size - used;
|
|
|
|
base += remain;
|
|
size -= remain;
|
|
#endif
|
|
|
|
#if CONFIG_ARCH_STACKDUMP_MAX_LENGTH > 0
|
|
if (size > CONFIG_ARCH_STACKDUMP_MAX_LENGTH)
|
|
{
|
|
size = CONFIG_ARCH_STACKDUMP_MAX_LENGTH;
|
|
}
|
|
#endif
|
|
|
|
stack_dump(base, base + size);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: dump_stacks
|
|
****************************************************************************/
|
|
|
|
static void dump_stacks(FAR struct tcb_s *rtcb, uintptr_t sp)
|
|
{
|
|
#if CONFIG_ARCH_INTERRUPTSTACK > 0
|
|
uintptr_t intstack_base = up_get_intstackbase(this_cpu());
|
|
size_t intstack_size = CONFIG_ARCH_INTERRUPTSTACK;
|
|
uintptr_t intstack_top = intstack_base + intstack_size;
|
|
uintptr_t intstack_sp = 0;
|
|
#endif
|
|
#ifdef CONFIG_ARCH_KERNEL_STACK
|
|
uintptr_t kernelstack_base = (uintptr_t)rtcb->xcp.kstack;
|
|
size_t kernelstack_size = CONFIG_ARCH_KERNEL_STACKSIZE;
|
|
uintptr_t kernelstack_top = kernelstack_base + kernelstack_size;
|
|
uintptr_t kernelstack_sp = 0;
|
|
#endif
|
|
uintptr_t tcbstack_base = (uintptr_t)rtcb->stack_base_ptr;
|
|
size_t tcbstack_size = (size_t)rtcb->adj_stack_size;
|
|
uintptr_t tcbstack_top = tcbstack_base + tcbstack_size;
|
|
uintptr_t tcbstack_sp = 0;
|
|
bool force = false;
|
|
|
|
#if CONFIG_ARCH_INTERRUPTSTACK > 0
|
|
if (sp >= intstack_base && sp < intstack_top)
|
|
{
|
|
intstack_sp = sp;
|
|
}
|
|
else
|
|
#endif
|
|
#ifdef CONFIG_ARCH_KERNEL_STACK
|
|
if (sp >= kernelstack_base && sp < kernelstack_top)
|
|
{
|
|
kernelstack_sp = sp;
|
|
}
|
|
else
|
|
#endif
|
|
if (sp >= tcbstack_base && sp < tcbstack_top)
|
|
{
|
|
tcbstack_sp = sp;
|
|
}
|
|
else
|
|
{
|
|
force = true;
|
|
_alert("ERROR: Stack pointer is not within the stack\n");
|
|
}
|
|
|
|
#if CONFIG_ARCH_INTERRUPTSTACK > 0
|
|
if (intstack_sp != 0 || force)
|
|
{
|
|
dump_stack("IRQ",
|
|
intstack_sp,
|
|
intstack_base,
|
|
intstack_size,
|
|
#ifdef CONFIG_STACK_COLORATION
|
|
up_check_intstack(this_cpu())
|
|
#else
|
|
0
|
|
#endif
|
|
);
|
|
|
|
tcbstack_sp = up_getusrsp((FAR void *)up_current_regs());
|
|
if (tcbstack_sp < tcbstack_base || tcbstack_sp >= tcbstack_top)
|
|
{
|
|
tcbstack_sp = 0;
|
|
force = true;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_ARCH_KERNEL_STACK
|
|
if (kernelstack_sp != 0 || force)
|
|
{
|
|
dump_stack("Kernel",
|
|
kernelstack_sp,
|
|
kernelstack_base,
|
|
kernelstack_size,
|
|
0
|
|
);
|
|
}
|
|
#endif
|
|
|
|
if (tcbstack_sp != 0 || force)
|
|
{
|
|
dump_stack("User",
|
|
tcbstack_sp,
|
|
tcbstack_base,
|
|
tcbstack_size,
|
|
#ifdef CONFIG_STACK_COLORATION
|
|
up_check_tcbstack(rtcb)
|
|
#else
|
|
0
|
|
#endif
|
|
);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: dump_task
|
|
****************************************************************************/
|
|
|
|
static void dump_task(FAR struct tcb_s *tcb, FAR void *arg)
|
|
{
|
|
char args[64] = "";
|
|
char state[32];
|
|
FAR char *s;
|
|
#ifdef CONFIG_STACK_COLORATION
|
|
size_t stack_filled = 0;
|
|
size_t stack_used;
|
|
#endif
|
|
#ifndef CONFIG_SCHED_CPULOAD_NONE
|
|
struct cpuload_s cpuload;
|
|
size_t fracpart = 0;
|
|
size_t intpart = 0;
|
|
size_t tmp;
|
|
|
|
clock_cpuload(tcb->pid, &cpuload);
|
|
|
|
if (cpuload.total > 0)
|
|
{
|
|
tmp = (1000 * cpuload.active) / cpuload.total;
|
|
intpart = tmp / 10;
|
|
fracpart = tmp - 10 * intpart;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_STACK_COLORATION
|
|
stack_used = up_check_tcbstack(tcb);
|
|
if (tcb->adj_stack_size > 0 && stack_used > 0)
|
|
{
|
|
/* Use fixed-point math with one decimal place */
|
|
|
|
stack_filled = 10 * 100 * stack_used / tcb->adj_stack_size;
|
|
}
|
|
#endif
|
|
|
|
/* Stringify the argument vector */
|
|
|
|
group_argvstr(tcb, args, sizeof(args));
|
|
|
|
/* get the task_state */
|
|
|
|
nxsched_get_stateinfo(tcb, state, sizeof(state));
|
|
if ((s = strchr(state, ',')) != NULL)
|
|
{
|
|
*s = ' ';
|
|
}
|
|
|
|
/* Dump interesting properties of this task */
|
|
|
|
_alert(" %4d %5d"
|
|
#ifdef CONFIG_SMP
|
|
" %4d"
|
|
#endif
|
|
" %3d %-8s %-7s %c"
|
|
" %-18s"
|
|
" " SIGSET_FMT
|
|
" %p"
|
|
" %7zu"
|
|
#ifdef CONFIG_STACK_COLORATION
|
|
" %7zu %3zu.%1zu%%%c"
|
|
#endif
|
|
#ifndef CONFIG_SCHED_CPULOAD_NONE
|
|
" %3zu.%01zu%%"
|
|
#endif
|
|
" %s%s\n"
|
|
, tcb->pid
|
|
, tcb->group ? tcb->group->tg_pid : -1
|
|
#ifdef CONFIG_SMP
|
|
, tcb->cpu
|
|
#endif
|
|
, tcb->sched_priority
|
|
, g_policy[(tcb->flags & TCB_FLAG_POLICY_MASK) >>
|
|
TCB_FLAG_POLICY_SHIFT]
|
|
, g_ttypenames[(tcb->flags & TCB_FLAG_TTYPE_MASK)
|
|
>> TCB_FLAG_TTYPE_SHIFT]
|
|
, tcb->flags & TCB_FLAG_EXIT_PROCESSING ? 'P' : '-'
|
|
, state
|
|
, SIGSET_ELEM(&tcb->sigprocmask)
|
|
, tcb->stack_base_ptr
|
|
, tcb->adj_stack_size
|
|
#ifdef CONFIG_STACK_COLORATION
|
|
, up_check_tcbstack(tcb)
|
|
, stack_filled / 10, stack_filled % 10
|
|
, (stack_filled >= 10 * 80 ? '!' : ' ')
|
|
#endif
|
|
#ifndef CONFIG_SCHED_CPULOAD_NONE
|
|
, intpart, fracpart
|
|
#endif
|
|
#if CONFIG_TASK_NAME_SIZE > 0
|
|
, tcb->name
|
|
#else
|
|
, "<noname>"
|
|
#endif
|
|
, args
|
|
);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: dump_backtrace
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_SCHED_BACKTRACE
|
|
static void dump_backtrace(FAR struct tcb_s *tcb, FAR void *arg)
|
|
{
|
|
sched_dumpstack(tcb->pid);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: dump_filelist
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_SCHED_DUMP_ON_EXIT
|
|
static void dump_filelist(FAR struct tcb_s *tcb, FAR void *arg)
|
|
{
|
|
FAR struct filelist *filelist = &tcb->group->tg_filelist;
|
|
files_dumplist(filelist);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: dump_tasks
|
|
****************************************************************************/
|
|
|
|
static void dump_tasks(void)
|
|
{
|
|
#if CONFIG_ARCH_INTERRUPTSTACK > 0
|
|
int cpu;
|
|
#endif
|
|
|
|
/* Dump interesting properties of each task in the crash environment */
|
|
|
|
_alert(" PID GROUP"
|
|
#ifdef CONFIG_SMP
|
|
" CPU"
|
|
#endif
|
|
" PRI POLICY TYPE NPX"
|
|
" STATE EVENT"
|
|
" SIGMASK "
|
|
" STACKBASE"
|
|
" STACKSIZE"
|
|
#ifdef CONFIG_STACK_COLORATION
|
|
" USED FILLED "
|
|
#endif
|
|
#ifndef CONFIG_SCHED_CPULOAD_NONE
|
|
" CPU"
|
|
#endif
|
|
" COMMAND\n");
|
|
|
|
#if CONFIG_ARCH_INTERRUPTSTACK > 0
|
|
for (cpu = 0; cpu < CONFIG_SMP_NCPUS; cpu++)
|
|
{
|
|
# ifdef CONFIG_STACK_COLORATION
|
|
size_t stack_used = up_check_intstack(cpu);
|
|
size_t stack_filled = 0;
|
|
|
|
if (stack_used > 0)
|
|
{
|
|
/* Use fixed-point math with one decimal place */
|
|
|
|
stack_filled = 10 * 100 *
|
|
stack_used / CONFIG_ARCH_INTERRUPTSTACK;
|
|
}
|
|
# endif
|
|
|
|
_alert(" ---- ---"
|
|
# ifdef CONFIG_SMP
|
|
" %4d"
|
|
# endif
|
|
" --- --------"
|
|
" ------- ---"
|
|
" ------- ----------"
|
|
" ----------------"
|
|
" %p"
|
|
" %7u"
|
|
# ifdef CONFIG_STACK_COLORATION
|
|
" %7zu %3zu.%1zu%%%c"
|
|
# endif
|
|
# ifndef CONFIG_SCHED_CPULOAD_NONE
|
|
" ----"
|
|
# endif
|
|
" irq\n"
|
|
#ifdef CONFIG_SMP
|
|
, cpu
|
|
#endif
|
|
, (FAR void *)up_get_intstackbase(cpu)
|
|
, CONFIG_ARCH_INTERRUPTSTACK
|
|
# ifdef CONFIG_STACK_COLORATION
|
|
, stack_used
|
|
, stack_filled / 10, stack_filled % 10,
|
|
(stack_filled >= 10 * 80 ? '!' : ' ')
|
|
# endif
|
|
);
|
|
}
|
|
#endif
|
|
|
|
nxsched_foreach(dump_task, NULL);
|
|
|
|
#ifdef CONFIG_SCHED_BACKTRACE
|
|
nxsched_foreach(dump_backtrace, NULL);
|
|
#endif
|
|
|
|
#ifdef CONFIG_SCHED_DUMP_ON_EXIT
|
|
nxsched_foreach(dump_filelist, NULL);
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: dump_deadlock
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_ARCH_DEADLOCKDUMP
|
|
static void dump_deadlock(void)
|
|
{
|
|
pid_t deadlock[DEADLOCK_MAX];
|
|
size_t i = nxsched_collect_deadlock(deadlock, DEADLOCK_MAX);
|
|
|
|
if (i > 0)
|
|
{
|
|
_alert("Deadlock detected\n");
|
|
while (i-- > 0)
|
|
{
|
|
#ifdef CONFIG_SCHED_BACKTRACE
|
|
sched_dumpstack(deadlock[i]);
|
|
#else
|
|
_alert("deadlock pid: %d\n", deadlock[i]);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: pause_all_cpu
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_SMP
|
|
static void pause_all_cpu(void)
|
|
{
|
|
int cpu;
|
|
|
|
for (cpu = 0; cpu < CONFIG_SMP_NCPUS; cpu++)
|
|
{
|
|
if (cpu != this_cpu())
|
|
{
|
|
up_cpu_pause(cpu);
|
|
}
|
|
}
|
|
}
|
|
#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();
|
|
#if CONFIG_TASK_NAME_SIZE > 0
|
|
FAR struct tcb_s *ptcb = NULL;
|
|
#endif
|
|
struct panic_notifier_s notifier_data;
|
|
struct utsname name;
|
|
irqstate_t flags;
|
|
bool fatal = true;
|
|
|
|
#if CONFIG_TASK_NAME_SIZE > 0
|
|
if (rtcb->group && !(rtcb->flags & TCB_FLAG_TTYPE_KERNEL))
|
|
{
|
|
ptcb = nxsched_get_tcb(rtcb->group->tg_pid);
|
|
}
|
|
#endif
|
|
|
|
flags = 0; /* suppress GCC warning */
|
|
if (os_ready)
|
|
{
|
|
flags = enter_critical_section();
|
|
}
|
|
|
|
if (g_fatal_assert)
|
|
{
|
|
goto reset;
|
|
}
|
|
|
|
if (os_ready && fatal)
|
|
{
|
|
#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);
|
|
_alert("Current Version: %s %s %s %s %s\n",
|
|
name.sysname, name.nodename,
|
|
name.release, name.version, name.machine);
|
|
|
|
_alert("Assertion failed %s: at file: %s:%d task"
|
|
#ifdef CONFIG_SMP
|
|
"(CPU%d)"
|
|
#endif
|
|
": "
|
|
#if CONFIG_TASK_NAME_SIZE > 0
|
|
"%s "
|
|
"process: %s "
|
|
#endif
|
|
"%p\n",
|
|
msg ? msg : "",
|
|
filename ? filename : "", linenum,
|
|
#ifdef CONFIG_SMP
|
|
this_cpu(),
|
|
#endif
|
|
#if CONFIG_TASK_NAME_SIZE > 0
|
|
rtcb->name,
|
|
ptcb ? ptcb->name : "Kernel",
|
|
#endif
|
|
rtcb->entry.main);
|
|
|
|
/* Register dump */
|
|
|
|
up_dump_register(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 */
|
|
|
|
syslog_flush();
|
|
|
|
if (fatal)
|
|
{
|
|
dump_tasks();
|
|
|
|
#ifdef CONFIG_ARCH_DEADLOCKDUMP
|
|
/* Deadlock Dump */
|
|
|
|
dump_deadlock();
|
|
#endif
|
|
|
|
#ifdef CONFIG_ARCH_USBDUMP
|
|
/* Dump USB trace data */
|
|
|
|
usbtrace_enumerate(assert_tracecallback, NULL);
|
|
#endif
|
|
|
|
#ifdef CONFIG_BOARD_CRASHDUMP
|
|
board_crashdump(up_getsp(), rtcb, filename, linenum, msg, regs);
|
|
#endif
|
|
|
|
#if defined(CONFIG_BOARD_COREDUMP_SYSLOG) || \
|
|
defined(CONFIG_BOARD_COREDUMP_BLKDEV)
|
|
/* Dump core information */
|
|
|
|
# ifdef CONFIG_BOARD_COREDUMP_FULL
|
|
coredump_dump(INVALID_PROCESS_ID);
|
|
# else
|
|
coredump_dump(rtcb->pid);
|
|
# endif
|
|
#endif
|
|
|
|
/* Flush any buffered SYSLOG data */
|
|
|
|
syslog_flush();
|
|
panic_notifier_call_chain(PANIC_KERNEL_FINAL, ¬ifier_data);
|
|
|
|
reboot_notifier_call_chain(SYS_HALT, NULL);
|
|
|
|
reset:
|
|
#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)
|
|
{
|
|
leave_critical_section(flags);
|
|
}
|
|
}
|