up_backtrace: fix maybe backtrace the exiting thread
when the thread to backtrace is exiting, get_tcb and up_backtrace in different critical section may cause try to dump invalid pointer, have to ensure the nxsched_get_tcb and up_backtrace inside same critical section procedure. Signed-off-by: buxiasen <buxiasen@xiaomi.com>
This commit is contained in:
parent
4038abd3ab
commit
f5021021ae
9 changed files with 74 additions and 40 deletions
|
@ -99,13 +99,20 @@ static int backtrace(uintptr_t *base, uintptr_t *limit,
|
|||
* Returned Value:
|
||||
* up_backtrace() returns the number of addresses returned in buffer
|
||||
*
|
||||
* Assumptions:
|
||||
* Have to make sure tcb keep safe during function executing, it means
|
||||
* 1. Tcb have to be self or not-running. In SMP case, the running task
|
||||
* PC & SP cannot be backtrace, as whose get from tcb is not the newest.
|
||||
* 2. Tcb have to keep not be freed. In task exiting case, have to
|
||||
* make sure the tcb get from pid and up_backtrace in one critical
|
||||
* section procedure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_backtrace(struct tcb_s *tcb,
|
||||
void **buffer, int size, int skip)
|
||||
{
|
||||
struct tcb_s *rtcb = running_task();
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
|
||||
if (size <= 0 || !buffer)
|
||||
|
@ -149,15 +156,11 @@ int up_backtrace(struct tcb_s *tcb,
|
|||
}
|
||||
else
|
||||
{
|
||||
flags = enter_critical_section();
|
||||
|
||||
ret = backtrace(tcb->stack_base_ptr,
|
||||
tcb->stack_base_ptr + tcb->adj_stack_size,
|
||||
(void *)tcb->xcp.regs[REG_FP],
|
||||
(void *)tcb->xcp.regs[REG_PC],
|
||||
buffer, size, &skip);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -230,6 +230,14 @@ void up_backtrace_init_code_regions(void **regions)
|
|||
* Returned Value:
|
||||
* up_backtrace() returns the number of addresses returned in buffer
|
||||
*
|
||||
* Assumptions:
|
||||
* Have to make sure tcb keep safe during function executing, it means
|
||||
* 1. Tcb have to be self or not-running. In SMP case, the running task
|
||||
* PC & SP cannot be backtrace, as whose get from tcb is not the newest.
|
||||
* 2. Tcb have to keep not be freed. In task exiting case, have to
|
||||
* make sure the tcb get from pid and up_backtrace in one critical
|
||||
* section procedure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
nosanitize_address
|
||||
|
@ -237,7 +245,6 @@ int up_backtrace(struct tcb_s *tcb,
|
|||
void **buffer, int size, int skip)
|
||||
{
|
||||
struct tcb_s *rtcb = running_task();
|
||||
irqstate_t flags;
|
||||
unsigned long sp;
|
||||
int ret;
|
||||
|
||||
|
@ -287,8 +294,6 @@ int up_backtrace(struct tcb_s *tcb,
|
|||
{
|
||||
ret = 0;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
if (tcb->xcp.regs[REG_PC] && skip-- <= 0)
|
||||
{
|
||||
buffer[ret++] = (void *)tcb->xcp.regs[REG_PC];
|
||||
|
@ -299,8 +304,6 @@ int up_backtrace(struct tcb_s *tcb,
|
|||
tcb->stack_base_ptr +
|
||||
tcb->adj_stack_size, sp,
|
||||
&buffer[ret], size - ret, &skip);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -698,6 +698,14 @@ again:
|
|||
* Returned Value:
|
||||
* up_backtrace() returns the number of addresses returned in buffer
|
||||
*
|
||||
* Assumptions:
|
||||
* Have to make sure tcb keep safe during function executing, it means
|
||||
* 1. Tcb have to be self or not-running. In SMP case, the running task
|
||||
* PC & SP cannot be backtrace, as whose get from tcb is not the newest.
|
||||
* 2. Tcb have to keep not be freed. In task exiting case, have to
|
||||
* make sure the tcb get from pid and up_backtrace in one critical
|
||||
* section procedure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_backtrace(struct tcb_s *tcb,
|
||||
|
@ -705,7 +713,6 @@ int up_backtrace(struct tcb_s *tcb,
|
|||
{
|
||||
struct tcb_s *rtcb = running_task();
|
||||
struct unwind_frame_s frame;
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
|
||||
if (size <= 0 || !buffer)
|
||||
|
@ -748,8 +755,6 @@ int up_backtrace(struct tcb_s *tcb,
|
|||
}
|
||||
else
|
||||
{
|
||||
flags = enter_critical_section();
|
||||
|
||||
frame.fp = tcb->xcp.regs[REG_FP];
|
||||
frame.sp = tcb->xcp.regs[REG_SP];
|
||||
frame.lr = tcb->xcp.regs[REG_LR];
|
||||
|
@ -758,8 +763,6 @@ int up_backtrace(struct tcb_s *tcb,
|
|||
tcb->adj_stack_size;
|
||||
|
||||
ret = backtrace_unwind(&frame, buffer, size, &skip);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -448,13 +448,20 @@ void up_backtrace_init_code_regions(void **regions)
|
|||
* Returned Value:
|
||||
* up_backtrace() returns the number of addresses returned in buffer
|
||||
*
|
||||
* Assumptions:
|
||||
* Have to make sure tcb keep safe during function executing, it means
|
||||
* 1. Tcb have to be self or not-running. In SMP case, the running task
|
||||
* PC & SP cannot be backtrace, as whose get from tcb is not the newest.
|
||||
* 2. Tcb have to keep not be freed. In task exiting case, have to
|
||||
* make sure the tcb get from pid and up_backtrace in one critical
|
||||
* section procedure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
nosanitize_address
|
||||
int up_backtrace(struct tcb_s *tcb, void **buffer, int size, int skip)
|
||||
{
|
||||
struct tcb_s *rtcb = running_task();
|
||||
irqstate_t flags;
|
||||
void *sp;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -511,8 +518,6 @@ int up_backtrace(struct tcb_s *tcb, void **buffer, int size, int skip)
|
|||
}
|
||||
else
|
||||
{
|
||||
flags = enter_critical_section();
|
||||
|
||||
if (skip-- <= 0)
|
||||
{
|
||||
buffer[ret++] = (void *)tcb->xcp.regs[REG_PC];
|
||||
|
@ -533,8 +538,6 @@ int up_backtrace(struct tcb_s *tcb, void **buffer, int size, int skip)
|
|||
&buffer[ret], size - ret, &skip);
|
||||
}
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -102,6 +102,14 @@ static int backtrace(uintptr_t *base, uintptr_t *limit,
|
|||
* Returned Value:
|
||||
* up_backtrace() returns the number of addresses returned in buffer
|
||||
*
|
||||
* Assumptions:
|
||||
* Have to make sure tcb keep safe during function executing, it means
|
||||
* 1. Tcb have to be self or not-running. In SMP case, the running task
|
||||
* PC & SP cannot be backtrace, as whose get from tcb is not the newest.
|
||||
* 2. Tcb have to keep not be freed. In task exiting case, have to
|
||||
* make sure the tcb get from pid and up_backtrace in one critical
|
||||
* section procedure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_backtrace(struct tcb_s *tcb,
|
||||
|
@ -109,7 +117,6 @@ int up_backtrace(struct tcb_s *tcb,
|
|||
{
|
||||
struct tcb_s *rtcb = (struct tcb_s *)arch_get_current_tcb();
|
||||
struct regs_context * p_regs;
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
|
||||
if (rtcb == NULL)
|
||||
|
@ -158,7 +165,6 @@ int up_backtrace(struct tcb_s *tcb,
|
|||
}
|
||||
else
|
||||
{
|
||||
flags = enter_critical_section();
|
||||
p_regs = (struct regs_context *)tcb->xcp.regs;
|
||||
|
||||
ret = backtrace(tcb->stack_base_ptr,
|
||||
|
@ -166,8 +172,6 @@ int up_backtrace(struct tcb_s *tcb,
|
|||
(void *)p_regs->regs[REG_X29],
|
||||
(void *)p_regs->elr,
|
||||
buffer, size, &skip);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -124,12 +124,19 @@ static int backtrace(uintptr_t *base, uintptr_t *limit,
|
|||
* Returned Value:
|
||||
* up_backtrace() returns the number of addresses returned in buffer
|
||||
*
|
||||
* Assumptions:
|
||||
* Have to make sure tcb keep safe during function executing, it means
|
||||
* 1. Tcb have to be self or not-running. In SMP case, the running task
|
||||
* PC & SP cannot be backtrace, as whose get from tcb is not the newest.
|
||||
* 2. Tcb have to keep not be freed. In task exiting case, have to
|
||||
* make sure the tcb get from pid and up_backtrace in one critical
|
||||
* section procedure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_backtrace(struct tcb_s *tcb, void **buffer, int size, int skip)
|
||||
{
|
||||
struct tcb_s *rtcb = running_task();
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
|
||||
if (size <= 0 || !buffer)
|
||||
|
@ -181,8 +188,6 @@ int up_backtrace(struct tcb_s *tcb, void **buffer, int size, int skip)
|
|||
}
|
||||
else
|
||||
{
|
||||
flags = enter_critical_section();
|
||||
|
||||
#ifdef CONFIG_ARCH_KERNEL_STACK
|
||||
if (tcb->xcp.ustkptr != NULL)
|
||||
{
|
||||
|
@ -200,8 +205,6 @@ int up_backtrace(struct tcb_s *tcb, void **buffer, int size, int skip)
|
|||
(void *)tcb->xcp.regs[REG_EPC],
|
||||
buffer, size, &skip);
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -217,12 +217,19 @@ static int backtrace_stack(uintptr_t *base, uintptr_t *limit,
|
|||
* Returned Value:
|
||||
* up_backtrace() returns the number of addresses returned in buffer
|
||||
*
|
||||
* Assumptions:
|
||||
* Have to make sure tcb keep safe during function executing, it means
|
||||
* 1. Tcb have to be self or not-running. In SMP case, the running task
|
||||
* PC & SP cannot be backtrace, as whose get from tcb is not the newest.
|
||||
* 2. Tcb have to keep not be freed. In task exiting case, have to
|
||||
* make sure the tcb get from pid and up_backtrace in one critical
|
||||
* section procedure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_backtrace(struct tcb_s *tcb, void **buffer, int size, int skip)
|
||||
{
|
||||
struct tcb_s *rtcb = running_task();
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
|
||||
if (size <= 0 || !buffer)
|
||||
|
@ -285,15 +292,11 @@ int up_backtrace(struct tcb_s *tcb, void **buffer, int size, int skip)
|
|||
{
|
||||
/* For non-current task, only check in stack. */
|
||||
|
||||
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, &skip);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -495,6 +495,14 @@ void up_dump_register(FAR void *regs);
|
|||
* Returned Value:
|
||||
* up_backtrace() returns the number of addresses returned in buffer
|
||||
*
|
||||
* Assumptions:
|
||||
* Have to make sure tcb keep safe during function executing, it means
|
||||
* 1. Tcb have to be self or not-running. In SMP case, the running task
|
||||
* PC & SP cannot be backtrace, as whose get from tcb is not the newest.
|
||||
* 2. Tcb have to keep not be freed. In task exiting case, have to
|
||||
* make sure the tcb get from pid and up_backtrace in one critical
|
||||
* section procedure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_backtrace(FAR struct tcb_s *tcb,
|
||||
|
|
|
@ -43,17 +43,21 @@
|
|||
#ifdef CONFIG_ARCH_HAVE_BACKTRACE
|
||||
int sched_backtrace(pid_t tid, FAR void **buffer, int size, int skip)
|
||||
{
|
||||
FAR struct tcb_s *rtcb = NULL;
|
||||
|
||||
FAR struct tcb_s *rtcb;
|
||||
irqstate_t flags;
|
||||
int ret = 0;
|
||||
if (tid >= 0)
|
||||
{
|
||||
rtcb = nxsched_get_tcb(tid);
|
||||
if (rtcb == NULL)
|
||||
flags = enter_critical_section();
|
||||
rtcb = nxsched_get_tcb(tid);
|
||||
if (rtcb != NULL)
|
||||
{
|
||||
return 0;
|
||||
ret = up_backtrace(rtcb, buffer, size, skip);
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
return up_backtrace(rtcb, buffer, size, skip);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue