sched/backtrace: Dump the complete stack regardless the depth

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
This commit is contained in:
Xiang Xiao 2021-12-24 15:38:14 +08:00 committed by archer
parent 9eecd4c5e2
commit dd942f0b04
12 changed files with 162 additions and 104 deletions

View File

@ -49,13 +49,17 @@ __attribute__((no_sanitize_address))
#endif
static int backtrace(FAR uintptr_t *base, FAR uintptr_t *limit,
FAR uintptr_t *fp, FAR uintptr_t *pc,
FAR void **buffer, int size)
FAR void **buffer, int size, FAR int *skip)
{
int i = 0;
if (pc)
{
buffer[i++] = pc;
i++;
if (*skip-- <= 0)
{
*buffer++ = pc;
}
}
for (; i < size; fp = (FAR uintptr_t *)*(fp - 1), i++)
@ -65,7 +69,10 @@ static int backtrace(FAR uintptr_t *base, FAR uintptr_t *limit,
break;
}
buffer[i] = (FAR void *)*fp;
if (*skip-- <= 0)
{
*buffer++ = (FAR void *)*fp;
}
}
return i;
@ -93,6 +100,7 @@ static int backtrace(FAR uintptr_t *base, FAR uintptr_t *limit,
* tcb - Address of the task's TCB
* buffer - Return address from the corresponding stack frame
* size - Maximum number of addresses that can be stored in buffer
* skip - number of addresses to be skipped
*
* Returned Value:
* up_backtrace() returns the number of addresses returned in buffer
@ -102,7 +110,8 @@ static int backtrace(FAR uintptr_t *base, FAR uintptr_t *limit,
#ifdef CONFIG_MM_KASAN
__attribute__((no_sanitize_address))
#endif
int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size)
int up_backtrace(FAR struct tcb_s *tcb,
FAR void **buffer, int size, int skip)
{
FAR struct tcb_s *rtcb = running_task();
#if CONFIG_ARCH_INTERRUPTSTACK > 7
@ -129,12 +138,12 @@ int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size)
ret = backtrace(istacklimit - (CONFIG_ARCH_INTERRUPTSTACK & ~7),
istacklimit,
(FAR void *)__builtin_frame_address(0),
NULL, buffer, size);
NULL, buffer, size, &skip);
#else
ret = backtrace(rtcb->stack_base_ptr,
rtcb->stack_base_ptr + rtcb->adj_stack_size,
(FAR void *)__builtin_frame_address(0),
NULL, buffer, size);
NULL, buffer, size, &skip);
#endif /* CONFIG_ARCH_INTERRUPTSTACK > 7 */
if (ret < size)
{
@ -142,7 +151,7 @@ int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size)
rtcb->stack_base_ptr + rtcb->adj_stack_size,
(FAR void *)CURRENT_REGS[REG_FP],
(FAR void *)CURRENT_REGS[REG_PC],
&buffer[ret], size - ret);
&buffer[ret], size - ret, &skip);
}
}
else
@ -150,7 +159,7 @@ int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size)
ret = backtrace(rtcb->stack_base_ptr,
rtcb->stack_base_ptr + rtcb->adj_stack_size,
(FAR void *)__builtin_frame_address(0),
NULL, buffer, size);
NULL, buffer, size, &skip);
}
}
else
@ -161,7 +170,7 @@ int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size)
tcb->stack_base_ptr + tcb->adj_stack_size,
(FAR void *)tcb->xcp.regs[REG_FP],
(FAR void *)tcb->xcp.regs[REG_PC],
buffer, size);
buffer, size, &skip);
leave_critical_section(flags);
}

View File

@ -316,10 +316,10 @@ static FAR void *backtrace_push_internal(FAR void **psp,
#ifdef CONFIG_MM_KASAN
__attribute__((no_sanitize_address))
#endif
static int backtrace_push(FAR void *limit, FAR void **sp,
FAR void *pc, FAR void **buffer, int size)
static int backtrace_push(FAR void *limit, FAR void **sp, FAR void *pc,
FAR void **buffer, int size, FAR int *skip)
{
int i = 0;
int i = 1;
if (!in_code_region(pc))
{
@ -328,7 +328,10 @@ static int backtrace_push(FAR void *limit, FAR void **sp,
pc = (uintptr_t)pc & 0xfffffffe;
buffer[i++] = pc;
if (*skip-- <= 0)
{
*buffer++ = pc;
}
for (; i < size; i++)
{
@ -337,11 +340,21 @@ static int backtrace_push(FAR void *limit, FAR void **sp,
break;
}
buffer[i] = backtrace_push_internal(sp, &pc);
if (!buffer[i])
pc = backtrace_push_internal(sp, &pc);
if (!pc)
{
break;
}
if (*skip-- <= 0)
{
*buffer++ = pc;
}
if (ip)
{
ip = NULL;
}
}
return i;
@ -359,7 +372,7 @@ static int backtrace_push(FAR void *limit, FAR void **sp,
__attribute__((no_sanitize_address))
#endif
static int backtrace_branch(FAR void *limit, FAR void *sp,
FAR void **buffer, int size)
FAR void **buffer, int size, FAR int *skip)
{
uint16_t ins16;
uint32_t addr;
@ -377,7 +390,11 @@ static int backtrace_branch(FAR void *limit, FAR void *sp,
ins16 = *(FAR uint16_t *)addr;
if (INSTR_IS(ins16, T_BLX))
{
buffer[i++] = addr;
i++;
if (*skip-- <= 0)
{
*buffer++ = addr;
}
}
/* BL Instruction
@ -393,7 +410,11 @@ static int backtrace_branch(FAR void *limit, FAR void *sp,
ins16 = *(FAR uint16_t *)addr;
if (INSTR_IS(ins16, T_BL))
{
buffer[i++] = addr;
i++;
if (*skip-- <= 0)
{
*buffer++ = addr;
}
}
}
}
@ -468,7 +489,8 @@ void up_backtrace_init_code_regions(FAR void **regions)
#ifdef CONFIG_MM_KASAN
__attribute__((no_sanitize_address))
#endif
int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size)
int up_backtrace(FAR struct tcb_s *tcb,
FAR void **buffer, int size, FAR int skip)
{
FAR struct tcb_s *rtcb = running_task();
irqstate_t flags;
@ -504,7 +526,7 @@ int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size)
ret = backtrace_push(rtcb->stack_base_ptr +
rtcb->adj_stack_size,
&sp, (FAR void *)up_backtrace + 10,
buffer, size);
buffer, size, &skip);
#endif
if (ret < size)
{
@ -512,7 +534,7 @@ int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size)
ret += backtrace_push(rtcb->stack_base_ptr +
rtcb->adj_stack_size, &sp,
(FAR void *)CURRENT_REGS[REG_PC],
&buffer[ret], size - ret);
&buffer[ret], size - ret, &skip);
}
}
else
@ -520,14 +542,14 @@ int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size)
ret = backtrace_push(rtcb->stack_base_ptr +
rtcb->adj_stack_size, &sp,
(FAR void *)up_backtrace + 10,
buffer, size);
buffer, size, &skip);
}
if (ret < size)
{
ret += backtrace_branch(rtcb->stack_base_ptr +
rtcb->adj_stack_size, sp,
&buffer[ret], size - ret);
&buffer[ret], size - ret, &skip);
}
}
else
@ -544,13 +566,13 @@ int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size)
ret += backtrace_push(tcb->stack_base_ptr +
tcb->adj_stack_size, &sp,
(FAR void *)tcb->xcp.regs[REG_LR],
&buffer[ret], size - ret);
&buffer[ret], size - ret, &skip);
if (ret < size)
{
ret += backtrace_branch(tcb->stack_base_ptr +
tcb->adj_stack_size, sp,
&buffer[ret], size - ret);
&buffer[ret], size - ret, &skip);
}
}

View File

@ -63,13 +63,17 @@ static inline uintptr_t getfp(void)
static int backtrace(uintptr_t *base, uintptr_t *limit,
uintptr_t *fp, uintptr_t *ra,
void **buffer, int size)
void **buffer, int size, int *skip)
{
int i = 0;
if (ra)
{
buffer[i++] = ra;
i++;
if (*skip-- <= 0)
{
*buffer++ = ra;
}
}
for (; i < size; fp = (uintptr_t *)*(fp - 2), i++)
@ -85,7 +89,10 @@ static int backtrace(uintptr_t *base, uintptr_t *limit,
break;
}
buffer[i] = ra;
if (*skip-- <= 0)
{
*buffer++ = ra;
}
}
return i;
@ -113,13 +120,14 @@ static int backtrace(uintptr_t *base, uintptr_t *limit,
* tcb - Address of the task's TCB
* buffer - Return address from the corresponding stack frame
* size - Maximum number of addresses that can be stored in buffer
* skip - number of addresses to be skipped
*
* Returned Value:
* up_backtrace() returns the number of addresses returned in buffer
*
****************************************************************************/
int up_backtrace(struct tcb_s *tcb, void **buffer, int size)
int up_backtrace(struct tcb_s *tcb, void **buffer, int size, int skip)
{
struct tcb_s *rtcb = running_task();
irqstate_t flags;
@ -137,28 +145,27 @@ int up_backtrace(struct tcb_s *tcb, void **buffer, int size)
#if CONFIG_ARCH_INTERRUPTSTACK > 15
ret = backtrace((void *)&g_intstackalloc,
(void *)((uint32_t)&g_intstackalloc +
CONFIG_ARCH_INTERRUPTSTACK),
(void *)getfp(), NULL, buffer, size);
CONFIG_ARCH_INTERRUPTSTACK),
(void *)getfp(), NULL, buffer, size, &skip);
#else
ret = backtrace(rtcb->stack_base_ptr,
rtcb->stack_base_ptr + rtcb->adj_stack_size,
(void *)getfp(), NULL, buffer, size);
(void *)getfp(), NULL, buffer, size, &skip);
#endif
if (ret < size)
{
ret += backtrace(rtcb->stack_base_ptr,
rtcb->stack_base_ptr +
rtcb->adj_stack_size,
rtcb->stack_base_ptr + rtcb->adj_stack_size,
(void *)CURRENT_REGS[REG_FP],
(void *)CURRENT_REGS[REG_EPC],
&buffer[ret], size - ret);
&buffer[ret], size - ret, &skip);
}
}
else
{
ret = backtrace(rtcb->stack_base_ptr,
rtcb->stack_base_ptr + rtcb->adj_stack_size,
(void *)getfp(), NULL, buffer, size);
(void *)getfp(), NULL, buffer, size, &skip);
}
}
else
@ -169,7 +176,7 @@ int up_backtrace(struct tcb_s *tcb, void **buffer, int size)
tcb->stack_base_ptr + tcb->adj_stack_size,
(void *)tcb->xcp.regs[REG_FP],
(void *)tcb->xcp.regs[REG_EPC],
buffer, size);
buffer, size, &skip);
leave_critical_section(flags);
}

View File

@ -106,8 +106,8 @@ static void get_window_regs(struct xtensa_windowregs_s *frame)
#ifndef __XTENSA_CALL0_ABI__
static int backtrace_window(uintptr_t *base, uintptr_t *limit,
struct xtensa_windowregs_s *frame,
void **buffer, int size)
struct xtensa_windowregs_s *frame,
void **buffer, int size, int *skip)
{
uint32_t windowstart;
uint32_t ra;
@ -136,7 +136,11 @@ static int backtrace_window(uintptr_t *base, uintptr_t *limit,
continue;
}
buffer[i++] = MAKE_PC_FROM_RA(ra);
i++;
if (*skip-- <= 0)
{
*buffer++ = MAKE_PC_FROM_RA(ra);
}
}
}
@ -153,14 +157,18 @@ static int backtrace_window(uintptr_t *base, uintptr_t *limit,
****************************************************************************/
static int backtrace_stack(uintptr_t *base, uintptr_t *limit,
uintptr_t *sp, uintptr_t *ra,
void **buffer, int size)
uintptr_t *sp, uintptr_t *ra,
void **buffer, int size, int *skip)
{
int i = 0;
if (ra)
{
buffer[i++] = MAKE_PC_FROM_RA((uintptr_t)ra);
i++;
if (*skip-- <= 0)
{
*buffer++ = MAKE_PC_FROM_RA((uintptr_t)ra);
}
}
for (; i < size; sp = (uintptr_t *)*(sp - 3), i++)
@ -176,7 +184,10 @@ static int backtrace_stack(uintptr_t *base, uintptr_t *limit,
break;
}
buffer[i] = MAKE_PC_FROM_RA((uintptr_t)ra);
if (*skip-- <= 0)
{
*buffer++ = MAKE_PC_FROM_RA((uintptr_t)ra);
}
}
return i;
@ -204,13 +215,14 @@ static int backtrace_stack(uintptr_t *base, uintptr_t *limit,
* tcb - Address of the task's TCB
* buffer - Return address from the corresponding stack frame
* size - Maximum number of addresses that can be stored in buffer
* skip - number of addresses to be skipped
*
* Returned Value:
* up_backtrace() returns the number of addresses returned in buffer
*
****************************************************************************/
int up_backtrace(struct tcb_s *tcb, void **buffer, int size)
int up_backtrace(struct tcb_s *tcb, void **buffer, int size, int skip)
{
struct tcb_s *rtcb = running_task();
irqstate_t flags;
@ -235,20 +247,21 @@ int up_backtrace(struct tcb_s *tcb, void **buffer, int size)
xtensa_window_spill();
ret = backtrace_stack((void *)istackbase,
(void *)(istackbase +
CONFIG_ARCH_INTERRUPTSTACK),
(void *)up_getsp(), NULL, buffer, size);
(void *)(istackbase +
CONFIG_ARCH_INTERRUPTSTACK),
(void *)up_getsp(), NULL,
buffer, size, &skip);
#else
ret = backtrace_stack(rtcb->stack_base_ptr,
rtcb->stack_base_ptr + rtcb->adj_stack_size,
(void *)up_getsp(), NULL, buffer, size);
rtcb->stack_base_ptr + rtcb->adj_stack_size,
(void *)up_getsp(), NULL,
buffer, size, &skip);
#endif
ret += backtrace_stack(rtcb->stack_base_ptr,
rtcb->stack_base_ptr +
rtcb->adj_stack_size,
(void *)CURRENT_REGS[REG_A1],
(void *)CURRENT_REGS[REG_A0],
&buffer[ret], size - ret);
rtcb->stack_base_ptr + rtcb->adj_stack_size,
(void *)CURRENT_REGS[REG_A1],
(void *)CURRENT_REGS[REG_A0],
&buffer[ret], size - ret, &skip);
}
else
{
@ -268,12 +281,13 @@ int up_backtrace(struct tcb_s *tcb, void **buffer, int size)
get_window_regs(&frame);
ret = backtrace_window(rtcb->stack_base_ptr,
rtcb->stack_base_ptr + rtcb->adj_stack_size,
&frame, buffer, size);
rtcb->stack_base_ptr + rtcb->adj_stack_size,
&frame, buffer, size, &skip);
#endif
ret += backtrace_stack(rtcb->stack_base_ptr,
rtcb->stack_base_ptr + rtcb->adj_stack_size,
(void *)up_getsp(), NULL, buffer, size - ret);
rtcb->stack_base_ptr + rtcb->adj_stack_size,
(void *)up_getsp(), NULL,
buffer, size - ret, &skip);
}
}
else
@ -283,10 +297,10 @@ int up_backtrace(struct tcb_s *tcb, void **buffer, int size)
flags = enter_critical_section();
ret = backtrace_stack(tcb->stack_base_ptr,
tcb->stack_base_ptr + tcb->adj_stack_size,
(void *)tcb->xcp.regs[REG_A1],
(void *)tcb->xcp.regs[REG_A0],
buffer, size);
tcb->stack_base_ptr + tcb->adj_stack_size,
(void *)tcb->xcp.regs[REG_A1],
(void *)tcb->xcp.regs[REG_A0],
buffer, size, &skip);
leave_critical_section(flags);
}

View File

@ -38,8 +38,8 @@
* ARRAY and return the exact number of values stored.
*/
#define backtrace(buffer, size) sched_backtrace(gettid(), buffer, size)
#define dump_stack() sched_dumpstack(gettid())
# define backtrace(buffer, size) sched_backtrace(gettid(), buffer, size, 0)
# define dump_stack() sched_dumpstack(gettid())
#else
# define backtrace(buffer, size) 0

View File

@ -513,13 +513,15 @@ void up_assert(FAR const char *filename, int linenum);
* tcb - Address of the task's TCB, NULL means dump the running task
* buffer - Return address from the corresponding stack frame
* size - Maximum number of addresses that can be stored in buffer
* skip - number of addresses to be skipped
*
* Returned Value:
* up_backtrace() returns the number of addresses returned in buffer
*
****************************************************************************/
int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size);
int up_backtrace(FAR struct tcb_s *tcb,
FAR void **buffer, int size, int skip);
#endif /* CONFIG_ARCH_HAVE_BACKTRACE */
/****************************************************************************

View File

@ -264,7 +264,7 @@ bool sched_idletask(void);
/* Task Backtrace */
int sched_backtrace(pid_t tid, FAR void **buffer, int size);
int sched_backtrace(pid_t tid, FAR void **buffer, int size, int skip);
void sched_dumpstack(pid_t tid);
#undef EXTERN

View File

@ -45,7 +45,7 @@ SYSCALL_LOOKUP(sched_yield, 0)
SYSCALL_LOOKUP(nxsched_get_stackinfo, 2)
#ifdef CONFIG_SCHED_BACKTRACE
SYSCALL_LOOKUP(sched_backtrace, 3)
SYSCALL_LOOKUP(sched_backtrace, 4)
#endif
#ifdef CONFIG_SMP

View File

@ -64,7 +64,7 @@ backtrace_helper(FAR struct _Unwind_Context *ctx, FAR void *a)
* Skip it.
*/
if (arg->cnt != -1)
if (arg->cnt >= 0)
{
arg->array[arg->cnt] = (FAR void *)_Unwind_GetIP(ctx);
if (arg->cnt > 0)
@ -88,7 +88,7 @@ backtrace_helper(FAR struct _Unwind_Context *ctx, FAR void *a)
arg->cfa = cfa;
}
if (++arg->cnt == arg->size)
if (++arg->cnt >= arg->size)
{
return _URC_END_OF_STACK;
}
@ -108,7 +108,7 @@ backtrace_helper(FAR struct _Unwind_Context *ctx, FAR void *a)
*
****************************************************************************/
int sched_backtrace(pid_t tid, FAR void **buffer, int size)
int sched_backtrace(pid_t tid, FAR void **buffer, int size, int skip)
{
struct trace_arg arg;
@ -120,7 +120,7 @@ int sched_backtrace(pid_t tid, FAR void **buffer, int size)
arg.array = buffer;
arg.cfa = 0;
arg.size = size;
arg.cnt = -1;
arg.cnt = -skip - 1;
if (size <= 0)
{
@ -138,7 +138,7 @@ int sched_backtrace(pid_t tid, FAR void **buffer, int size)
--arg.cnt;
}
return arg.cnt != -1 ? arg.cnt : 0;
return arg.cnt > 0 ? arg.cnt : 0;
}
#endif /* !CONFIG_ARCH_HAVE_BACKTRACE */

View File

@ -29,7 +29,6 @@
#include <stdio.h>
#include <syslog.h>
#include <execinfo.h>
/****************************************************************************
* Pre-processor Definitions
@ -54,38 +53,43 @@
void sched_dumpstack(pid_t tid)
{
FAR void *address[DUMP_DEPTH];
int size = DUMP_DEPTH;
int skip;
for (skip = 0; size == DUMP_DEPTH; skip += size)
{
FAR void *address[DUMP_DEPTH];
#ifndef CONFIG_ALLSYMS
const char *format = " %0*p";
char line[DUMP_LINESZ + 1];
int ret = 0;
const char *format = " %0*p";
char line[DUMP_LINESZ + 1];
int ret = 0;
#endif
int size;
int i;
int i;
size = sched_backtrace(tid, address, DUMP_DEPTH);
if (size <= 0)
{
return;
}
#ifndef CONFIG_ALLSYMS
for (i = 0; i < size; i++)
{
ret += snprintf(line + ret, sizeof(line) - ret,
format, DUMP_WIDTH, address[i]);
if (i == size - 1 || ret % DUMP_LINESZ == 0)
size = sched_backtrace(tid, address, DUMP_DEPTH, skip);
if (size <= 0)
{
syslog(LOG_EMERG, "backtrace|%2d:%s\n", tid, line);
ret = 0;
break;
}
#ifndef CONFIG_ALLSYMS
for (i = 0; i < size; i++)
{
ret += snprintf(line + ret, sizeof(line) - ret,
format, DUMP_WIDTH, address[i]);
if (i == size - 1 || ret % DUMP_LINESZ == 0)
{
syslog(LOG_EMERG, "backtrace|%2d:%s\n", tid, line);
ret = 0;
}
}
}
#else
syslog(LOG_EMERG, "backtrace:\n");
for (i = 0; i < size; i++)
{
syslog(LOG_EMERG, "[%2d] [<%p>] %pS\n",
tid, address[i], address[i]);
}
syslog(LOG_EMERG, "backtrace:\n");
for (i = 0; i < size; i++)
{
syslog(LOG_EMERG, "[%2d] [<%p>] %pS\n",
tid, address[i], address[i]);
}
#endif
}
}

View File

@ -40,7 +40,7 @@
*
****************************************************************************/
int sched_backtrace(pid_t tid, FAR void **buffer, int size)
int sched_backtrace(pid_t tid, FAR void **buffer, int size, int skip)
{
FAR struct tcb_s *rtcb = NULL;
@ -53,5 +53,5 @@ int sched_backtrace(pid_t tid, FAR void **buffer, int size)
}
}
return up_backtrace(rtcb, buffer, size);
return up_backtrace(rtcb, buffer, size, skip);
}

View File

@ -132,7 +132,7 @@
"sched_setscheduler","sched.h","","int","pid_t","int","const struct sched_param *"
"sched_unlock","sched.h","","int"
"sched_yield","sched.h","","int"
"sched_backtrace","sched.h","defined(CONFIG_SCHED_BACKTRACE)","int","pid_t","FAR void **","int"
"sched_backtrace","sched.h","defined(CONFIG_SCHED_BACKTRACE)","int","pid_t","FAR void **","int","int"
"seekdir","dirent.h","","void","FAR DIR *","off_t"
"select","sys/select.h","","int","int","FAR fd_set *","FAR fd_set *","FAR fd_set *","FAR struct timeval *"
"sem_clockwait","semaphore.h","","int","FAR sem_t *","clockid_t","FAR const struct timespec *"

Can't render this file because it has a wrong number of fields in line 2.