Skip to content

Commit

Permalink
up_backtrace: fix maybe backtrace the exiting thread
Browse files Browse the repository at this point in the history
Signed-off-by: buxiasen <[email protected]>
  • Loading branch information
jasonbu committed Jul 24, 2024
1 parent f640030 commit 12ff7e5
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 39 deletions.
13 changes: 8 additions & 5 deletions arch/arm/src/common/arm_backtrace_fp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
13 changes: 8 additions & 5 deletions arch/arm/src/common/arm_backtrace_sp.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,14 +230,21 @@ 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;
unsigned long sp;
int ret;

Expand Down Expand Up @@ -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];
Expand All @@ -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;
Expand Down
13 changes: 8 additions & 5 deletions arch/arm/src/common/arm_backtrace_unwind.c
Original file line number Diff line number Diff line change
Expand Up @@ -698,14 +698,21 @@ static int backtrace_unwind(struct unwind_frame_s *frame,
* 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();
struct unwind_frame_s frame;
irqstate_t flags;
int ret;

if (size <= 0 || !buffer)
Expand Down Expand Up @@ -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];
Expand All @@ -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;
Expand Down
13 changes: 8 additions & 5 deletions arch/arm/src/tlsr82/tc32/tc32_backtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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];
Expand All @@ -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;
Expand Down
12 changes: 8 additions & 4 deletions arch/arm64/src/common/arm64_backtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,21 @@ 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 = (struct tcb_s *)arch_get_current_tcb();
struct regs_context * p_regs;
irqstate_t flags;
int ret;

if (rtcb == NULL)
Expand Down Expand Up @@ -158,16 +165,13 @@ 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,
tcb->stack_base_ptr + tcb->adj_stack_size,
(void *)p_regs->regs[REG_X29],
(void *)p_regs->elr,
buffer, size, &skip);

leave_critical_section(flags);
}

return ret;
Expand Down
13 changes: 8 additions & 5 deletions arch/risc-v/src/common/riscv_backtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
Expand Down
13 changes: 8 additions & 5 deletions arch/xtensa/src/common/xtensa_backtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
8 changes: 8 additions & 0 deletions include/nuttx/arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
15 changes: 10 additions & 5 deletions sched/sched/sched_backtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,21 @@
int sched_backtrace(pid_t tid, FAR void **buffer, int size, int skip)
{
FAR struct tcb_s *rtcb = NULL;
irqstate_t flags;
int ret = 0;

flags = enter_critical_section();
if (tid >= 0)
{
rtcb = nxsched_get_tcb(tid);
if (rtcb == NULL)
{
return 0;
}
}

return up_backtrace(rtcb, buffer, size, skip);
if (rtcb != NULL)
{
ret = up_backtrace(rtcb, buffer, size, skip);
}

leave_critical_section(flags);
return ret;
}
#endif

0 comments on commit 12ff7e5

Please sign in to comment.