mirror of
https://github.com/apache/nuttx.git
synced 2026-05-30 13:27:01 +08:00
cortex-m/backtrace: remove the push process to simplify backtrace
Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
@@ -42,38 +42,12 @@
|
|||||||
|
|
||||||
#define INSTR_IS(i, o) (((i) & (IMASK_##o)) == (IOP_##o))
|
#define INSTR_IS(i, o) (((i) & (IMASK_##o)) == (IOP_##o))
|
||||||
|
|
||||||
#define IMASK_T_STMDB 0xfffff000 /* stmdb sp!,{..lr} */
|
|
||||||
#define IOP_T_STMDB 0xe92d4000
|
|
||||||
|
|
||||||
#define IMASK_T_PUSH_LO 0xff00 /* push {reglist} (not LR) */
|
|
||||||
#define IOP_T_PUSH_LO 0xb400
|
|
||||||
|
|
||||||
#define IMASK_T_PUSH 0xff00 /* push {reglist} (inc LR) */
|
|
||||||
#define IOP_T_PUSH 0xb500
|
|
||||||
|
|
||||||
#define IMASK_T_VPUSH_16 0xffbf8f00 /* vpush d */
|
|
||||||
#define IOP_T_VPUSH_16 0xed2d8b00
|
|
||||||
|
|
||||||
#define IMASK_T_VPUSH_8 0xffbf8f00 /* vpush s */
|
|
||||||
#define IOP_T_VPUSH_8 0xed2d8a00
|
|
||||||
|
|
||||||
#define IMASK_T_SUB_SP_16 0xff80 /* sub sp, # */
|
|
||||||
#define IOP_T_SUB_SP_16 0xb080
|
|
||||||
|
|
||||||
#define IMASK_T_SUB_SP_32 0xf2ff8f00 /* subw sp, sp, # */
|
|
||||||
#define IOP_T_SUB_SP_32 0xf2ad0d00
|
|
||||||
|
|
||||||
#define IMASK_T_SUB_W_SP_32 0xfbff8f00 /* sub.w sp, sp, # */
|
|
||||||
#define IOP_T_SUB_W_SP_32 0xf1ad0d00
|
|
||||||
|
|
||||||
#define IMASK_T_BLX 0xff80 /* blx */
|
#define IMASK_T_BLX 0xff80 /* blx */
|
||||||
#define IOP_T_BLX 0x4780
|
#define IOP_T_BLX 0x4780
|
||||||
|
|
||||||
#define IMASK_T_BL 0xf800 /* blx */
|
#define IMASK_T_BL 0xf800 /* blx */
|
||||||
#define IOP_T_BL 0xf000
|
#define IOP_T_BL 0xf000
|
||||||
|
|
||||||
#define INSTR_LIMIT 0x2000
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -84,32 +58,6 @@ static FAR void **g_backtrace_code_regions;
|
|||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: getlroffset
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* getlroffset() returns the currect link address offset.
|
|
||||||
*
|
|
||||||
* Input Parameters:
|
|
||||||
* lr - Link register address
|
|
||||||
*
|
|
||||||
* Returned Value:
|
|
||||||
* Link address offset, 0 is returned if the lr is invalid.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static int getlroffset(FAR uint8_t *lr)
|
|
||||||
{
|
|
||||||
lr = (FAR uint8_t *)((uintptr_t)lr & 0xfffffffe);
|
|
||||||
|
|
||||||
if (((uintptr_t)lr & 0xffffffe0) == 0xffffffe0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (*(FAR uint16_t *)(lr - 4) & 0xf000) == 0xf000 ? 5 : 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: in_code_region
|
* Name: in_code_region
|
||||||
*
|
*
|
||||||
@@ -155,178 +103,6 @@ static bool in_code_region(FAR void *pc)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: backtrace_push_internal
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* backtrace_push_internal() returns the currect link address from
|
|
||||||
* program counter and stack pointer
|
|
||||||
*
|
|
||||||
* Input Parameters:
|
|
||||||
* psp - Double poninter to the SP, this parameter will be changed if
|
|
||||||
* the corresponding LR address is successfully found.
|
|
||||||
* ppc - Double poninter to the PC, this parameter will be changed if
|
|
||||||
* the corresponding LR address is successfully found.
|
|
||||||
*
|
|
||||||
* Returned Value:
|
|
||||||
* Link address should be returned if successful
|
|
||||||
* Otherwise, NULL is returned
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static FAR void *backtrace_push_internal(FAR void **psp, FAR void **ppc)
|
|
||||||
{
|
|
||||||
FAR uint8_t *sp = *psp;
|
|
||||||
FAR uint8_t *pc = *ppc;
|
|
||||||
FAR uint8_t *base;
|
|
||||||
FAR uint8_t *lr;
|
|
||||||
uint32_t ins32;
|
|
||||||
uint16_t ins16;
|
|
||||||
int offset = 1;
|
|
||||||
int frame;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < INSTR_LIMIT; i += 2)
|
|
||||||
{
|
|
||||||
ins16 = *(FAR uint16_t *)(pc - i);
|
|
||||||
if (INSTR_IS(ins16, T_PUSH))
|
|
||||||
{
|
|
||||||
frame = __builtin_popcount(ins16 & 0xff) + 1;
|
|
||||||
ins16 = *(FAR uint16_t *)(pc - i - 2);
|
|
||||||
if (INSTR_IS(ins16, T_PUSH_LO))
|
|
||||||
{
|
|
||||||
offset += __builtin_popcount(ins16 & 0xff);
|
|
||||||
frame += offset - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ins32 = ins16 << 16;
|
|
||||||
ins32 |= *(FAR uint16_t *)(pc - i + 2);
|
|
||||||
if (INSTR_IS(ins32, T_STMDB))
|
|
||||||
{
|
|
||||||
frame = __builtin_popcount(ins32 & 0xfff) + 1;
|
|
||||||
ins16 = *(FAR uint16_t *)(pc - i - 2);
|
|
||||||
if (INSTR_IS(ins16, T_PUSH_LO))
|
|
||||||
{
|
|
||||||
offset += __builtin_popcount(ins16 & 0xff);
|
|
||||||
frame += offset - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i >= INSTR_LIMIT)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
base = pc - i;
|
|
||||||
|
|
||||||
for (i = 0; i < INSTR_LIMIT && base + i < pc; )
|
|
||||||
{
|
|
||||||
ins16 = *(FAR uint16_t *)(base + i);
|
|
||||||
if (INSTR_IS(ins16, T_SUB_SP_16))
|
|
||||||
{
|
|
||||||
frame += (ins16 & 0x7f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ins32 = ins16 << 16;
|
|
||||||
ins32 |= *(FAR uint16_t *)(base + i + 2);
|
|
||||||
if (INSTR_IS(ins32, T_SUB_SP_32))
|
|
||||||
{
|
|
||||||
uint32_t shift = ins32 >> 24 & 0x4;
|
|
||||||
uint32_t sub = 0;
|
|
||||||
|
|
||||||
if (shift)
|
|
||||||
{
|
|
||||||
sub = 1 << (shift - 1 + 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
frame += (sub + (ins32 & 0xff) +
|
|
||||||
((ins32 & 0x7000) >> 4)) / sizeof(uint32_t);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (INSTR_IS(ins32, T_SUB_W_SP_32))
|
|
||||||
{
|
|
||||||
uint32_t shift;
|
|
||||||
uint32_t sub;
|
|
||||||
|
|
||||||
sub = (ins32 & 0x7f) + 0x80;
|
|
||||||
shift = (ins32 >> 7) & 0x1;
|
|
||||||
shift += ((ins32 >> 12) & 0x7) << 1;
|
|
||||||
shift += ((ins32 >> 26) & 0x1) << 4;
|
|
||||||
|
|
||||||
frame += sub << (30 - shift);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (INSTR_IS(ins32, T_VPUSH_16))
|
|
||||||
{
|
|
||||||
frame += (ins32 & 0xff);
|
|
||||||
}
|
|
||||||
else if (INSTR_IS(ins32, T_VPUSH_8))
|
|
||||||
{
|
|
||||||
frame += (ins32 & 0xff) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
i += ((ins16 & 0xf800) >= 0xe800) ? 4 : 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
lr = (FAR uint8_t *)*((FAR uint32_t *)sp + frame - offset);
|
|
||||||
if (!in_code_region(lr))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = getlroffset(lr);
|
|
||||||
if (offset == 0)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*psp = (FAR uint32_t *)sp + frame;
|
|
||||||
*ppc = lr - offset;
|
|
||||||
|
|
||||||
return *ppc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: backtrace_push
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* backtrace_push() parsing the return address through instruction
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static int backtrace_push(FAR void *limit, FAR void **sp,
|
|
||||||
FAR void *pc, FAR void **buffer, int size)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
pc = (uintptr_t)pc & 0xfffffffe;
|
|
||||||
|
|
||||||
buffer[i++] = pc;
|
|
||||||
|
|
||||||
for (; i < size; i++)
|
|
||||||
{
|
|
||||||
if (*sp >= limit)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[i] = backtrace_push_internal(sp, &pc);
|
|
||||||
if (!buffer[i])
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: backtrace_branch
|
* Name: backtrace_branch
|
||||||
*
|
*
|
||||||
@@ -458,54 +234,47 @@ int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size)
|
|||||||
|
|
||||||
if (tcb == rtcb)
|
if (tcb == rtcb)
|
||||||
{
|
{
|
||||||
|
sp = (FAR void *)up_getsp();
|
||||||
if (up_interrupt_context())
|
if (up_interrupt_context())
|
||||||
{
|
{
|
||||||
sp = (FAR void *)up_getsp();
|
#if CONFIG_ARCH_INTERRUPTSTACK > 7
|
||||||
|
ret = backtrace_branch(
|
||||||
ret = backtrace_push(rtcb->stack_base_ptr +
|
# ifdef CONFIG_SMP
|
||||||
rtcb->adj_stack_size,
|
(uint32_t)arm_intstack_alloc()
|
||||||
&sp, (FAR void *)up_backtrace + 10,
|
# else
|
||||||
buffer, size);
|
(uint32_t)&g_intstackalloc
|
||||||
|
# endif
|
||||||
|
+ (CONFIG_ARCH_INTERRUPTSTACK & ~7), sp,
|
||||||
|
buffer, size);
|
||||||
if (ret < size)
|
if (ret < size)
|
||||||
{
|
{
|
||||||
sp = (FAR void *)CURRENT_REGS[REG_SP];
|
sp = (FAR void *)CURRENT_REGS[REG_SP];
|
||||||
ret += backtrace_push(rtcb->stack_base_ptr +
|
ret += backtrace_branch(rtcb->stack_base_ptr +
|
||||||
rtcb->adj_stack_size, &sp,
|
rtcb->adj_stack_size, sp,
|
||||||
(FAR void *)CURRENT_REGS[REG_PC],
|
&buffer[ret], size - ret);
|
||||||
&buffer[ret], size - ret);
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
sp = (FAR void *)CURRENT_REGS[REG_SP];
|
||||||
|
ret = backtrace_branch(rtcb->stack_base_ptr +
|
||||||
|
rtcb->adj_stack_size, sp,
|
||||||
|
buffer, size);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sp = (FAR void *)up_getsp();
|
ret = backtrace_branch(rtcb->stack_base_ptr +
|
||||||
ret = backtrace_push(rtcb->stack_base_ptr +
|
rtcb->adj_stack_size, sp,
|
||||||
rtcb->adj_stack_size, &sp,
|
buffer, size);
|
||||||
(FAR void *)up_backtrace + 10,
|
|
||||||
buffer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < size)
|
|
||||||
{
|
|
||||||
ret += backtrace_branch(rtcb->stack_base_ptr +
|
|
||||||
rtcb->adj_stack_size, sp,
|
|
||||||
&buffer[ret], size - ret);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
flags = enter_critical_section();
|
flags = enter_critical_section();
|
||||||
|
|
||||||
sp = (FAR void *)tcb->xcp.regs[REG_SP];
|
ret = backtrace_branch(tcb->stack_base_ptr +
|
||||||
ret = backtrace_push(tcb->stack_base_ptr +
|
tcb->adj_stack_size,
|
||||||
tcb->adj_stack_size, &sp,
|
(FAR void *)tcb->xcp.regs[REG_SP],
|
||||||
(FAR void *)tcb->xcp.regs[REG_PC],
|
buffer, size);
|
||||||
buffer, size);
|
|
||||||
if (ret < size)
|
|
||||||
{
|
|
||||||
ret += backtrace_branch(tcb->stack_base_ptr +
|
|
||||||
tcb->adj_stack_size, sp,
|
|
||||||
&buffer[ret], size - ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
leave_critical_section(flags);
|
leave_critical_section(flags);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,38 +42,12 @@
|
|||||||
|
|
||||||
#define INSTR_IS(i, o) (((i) & (IMASK_##o)) == (IOP_##o))
|
#define INSTR_IS(i, o) (((i) & (IMASK_##o)) == (IOP_##o))
|
||||||
|
|
||||||
#define IMASK_T_STMDB 0xfffff000 /* stmdb sp!,{..lr} */
|
|
||||||
#define IOP_T_STMDB 0xe92d4000
|
|
||||||
|
|
||||||
#define IMASK_T_PUSH_LO 0xff00 /* push {reglist} (not LR) */
|
|
||||||
#define IOP_T_PUSH_LO 0xb400
|
|
||||||
|
|
||||||
#define IMASK_T_PUSH 0xff00 /* push {reglist} (inc LR) */
|
|
||||||
#define IOP_T_PUSH 0xb500
|
|
||||||
|
|
||||||
#define IMASK_T_VPUSH_16 0xffbf8f00 /* vpush d */
|
|
||||||
#define IOP_T_VPUSH_16 0xed2d8b00
|
|
||||||
|
|
||||||
#define IMASK_T_VPUSH_8 0xffbf8f00 /* vpush s */
|
|
||||||
#define IOP_T_VPUSH_8 0xed2d8a00
|
|
||||||
|
|
||||||
#define IMASK_T_SUB_SP_16 0xff80 /* sub sp, # */
|
|
||||||
#define IOP_T_SUB_SP_16 0xb080
|
|
||||||
|
|
||||||
#define IMASK_T_SUB_SP_32 0xf2ff8f00 /* subw sp, sp, # */
|
|
||||||
#define IOP_T_SUB_SP_32 0xf2ad0d00
|
|
||||||
|
|
||||||
#define IMASK_T_SUB_W_SP_32 0xfbff8f00 /* sub.w sp, sp, # */
|
|
||||||
#define IOP_T_SUB_W_SP_32 0xf1ad0d00
|
|
||||||
|
|
||||||
#define IMASK_T_BLX 0xff80 /* blx */
|
#define IMASK_T_BLX 0xff80 /* blx */
|
||||||
#define IOP_T_BLX 0x4780
|
#define IOP_T_BLX 0x4780
|
||||||
|
|
||||||
#define IMASK_T_BL 0xf800 /* blx */
|
#define IMASK_T_BL 0xf800 /* blx */
|
||||||
#define IOP_T_BL 0xf000
|
#define IOP_T_BL 0xf000
|
||||||
|
|
||||||
#define INSTR_LIMIT 0x2000
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -84,32 +58,6 @@ static FAR void **g_backtrace_code_regions;
|
|||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: getlroffset
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* getlroffset() returns the currect link address offset.
|
|
||||||
*
|
|
||||||
* Input Parameters:
|
|
||||||
* lr - Link register address
|
|
||||||
*
|
|
||||||
* Returned Value:
|
|
||||||
* Link address offset, 0 is returned if the lr is invalid.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static int getlroffset(FAR uint8_t *lr)
|
|
||||||
{
|
|
||||||
lr = (FAR uint8_t *)((uintptr_t)lr & 0xfffffffe);
|
|
||||||
|
|
||||||
if (((uintptr_t)lr & 0xffffffe0) == 0xffffffe0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (*(FAR uint16_t *)(lr - 4) & 0xf000) == 0xf000 ? 5 : 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: in_code_region
|
* Name: in_code_region
|
||||||
*
|
*
|
||||||
@@ -155,178 +103,6 @@ static bool in_code_region(FAR void *pc)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: backtrace_push_internal
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* backtrace_push_internal() returns the currect link address from
|
|
||||||
* program counter and stack pointer
|
|
||||||
*
|
|
||||||
* Input Parameters:
|
|
||||||
* psp - Double poninter to the SP, this parameter will be changed if
|
|
||||||
* the corresponding LR address is successfully found.
|
|
||||||
* ppc - Double poninter to the PC, this parameter will be changed if
|
|
||||||
* the corresponding LR address is successfully found.
|
|
||||||
*
|
|
||||||
* Returned Value:
|
|
||||||
* Link address should be returned if successful
|
|
||||||
* Otherwise, NULL is returned
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static FAR void *backtrace_push_internal(FAR void **psp, FAR void **ppc)
|
|
||||||
{
|
|
||||||
FAR uint8_t *sp = *psp;
|
|
||||||
FAR uint8_t *pc = *ppc;
|
|
||||||
FAR uint8_t *base;
|
|
||||||
FAR uint8_t *lr;
|
|
||||||
uint32_t ins32;
|
|
||||||
uint16_t ins16;
|
|
||||||
int offset = 1;
|
|
||||||
int frame;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < INSTR_LIMIT; i += 2)
|
|
||||||
{
|
|
||||||
ins16 = *(FAR uint16_t *)(pc - i);
|
|
||||||
if (INSTR_IS(ins16, T_PUSH))
|
|
||||||
{
|
|
||||||
frame = __builtin_popcount(ins16 & 0xff) + 1;
|
|
||||||
ins16 = *(FAR uint16_t *)(pc - i - 2);
|
|
||||||
if (INSTR_IS(ins16, T_PUSH_LO))
|
|
||||||
{
|
|
||||||
offset += __builtin_popcount(ins16 & 0xff);
|
|
||||||
frame += offset - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ins32 = ins16 << 16;
|
|
||||||
ins32 |= *(FAR uint16_t *)(pc - i + 2);
|
|
||||||
if (INSTR_IS(ins32, T_STMDB))
|
|
||||||
{
|
|
||||||
frame = __builtin_popcount(ins32 & 0xfff) + 1;
|
|
||||||
ins16 = *(FAR uint16_t *)(pc - i - 2);
|
|
||||||
if (INSTR_IS(ins16, T_PUSH_LO))
|
|
||||||
{
|
|
||||||
offset += __builtin_popcount(ins16 & 0xff);
|
|
||||||
frame += offset - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i >= INSTR_LIMIT)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
base = pc - i;
|
|
||||||
|
|
||||||
for (i = 0; i < INSTR_LIMIT && base + i < pc; )
|
|
||||||
{
|
|
||||||
ins16 = *(FAR uint16_t *)(base + i);
|
|
||||||
if (INSTR_IS(ins16, T_SUB_SP_16))
|
|
||||||
{
|
|
||||||
frame += (ins16 & 0x7f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ins32 = ins16 << 16;
|
|
||||||
ins32 |= *(FAR uint16_t *)(base + i + 2);
|
|
||||||
if (INSTR_IS(ins32, T_SUB_SP_32))
|
|
||||||
{
|
|
||||||
uint32_t shift = ins32 >> 24 & 0x4;
|
|
||||||
uint32_t sub = 0;
|
|
||||||
|
|
||||||
if (shift)
|
|
||||||
{
|
|
||||||
sub = 1 << (shift - 1 + 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
frame += (sub + (ins32 & 0xff) +
|
|
||||||
((ins32 & 0x7000) >> 4)) / sizeof(uint32_t);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (INSTR_IS(ins32, T_SUB_W_SP_32))
|
|
||||||
{
|
|
||||||
uint32_t shift;
|
|
||||||
uint32_t sub;
|
|
||||||
|
|
||||||
sub = (ins32 & 0x7f) + 0x80;
|
|
||||||
shift = (ins32 >> 7) & 0x1;
|
|
||||||
shift += ((ins32 >> 12) & 0x7) << 1;
|
|
||||||
shift += ((ins32 >> 26) & 0x1) << 4;
|
|
||||||
|
|
||||||
frame += sub << (30 - shift);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (INSTR_IS(ins32, T_VPUSH_16))
|
|
||||||
{
|
|
||||||
frame += (ins32 & 0xff);
|
|
||||||
}
|
|
||||||
else if (INSTR_IS(ins32, T_VPUSH_8))
|
|
||||||
{
|
|
||||||
frame += (ins32 & 0xff) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
i += ((ins16 & 0xf800) >= 0xe800) ? 4 : 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
lr = (FAR uint8_t *)*((FAR uint32_t *)sp + frame - offset);
|
|
||||||
if (!in_code_region(lr))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = getlroffset(lr);
|
|
||||||
if (offset == 0)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*psp = (FAR uint32_t *)sp + frame;
|
|
||||||
*ppc = lr - offset;
|
|
||||||
|
|
||||||
return *ppc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: backtrace_push
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* backtrace_push() parsing the return address through instruction
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static int backtrace_push(FAR void *limit, FAR void **sp,
|
|
||||||
FAR void *pc, FAR void **buffer, int size)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
pc = (uintptr_t)pc & 0xfffffffe;
|
|
||||||
|
|
||||||
buffer[i++] = pc;
|
|
||||||
|
|
||||||
for (; i < size; i++)
|
|
||||||
{
|
|
||||||
if (*sp >= limit)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[i] = backtrace_push_internal(sp, &pc);
|
|
||||||
if (!buffer[i])
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: backtrace_branch
|
* Name: backtrace_branch
|
||||||
*
|
*
|
||||||
@@ -458,54 +234,47 @@ int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size)
|
|||||||
|
|
||||||
if (tcb == rtcb)
|
if (tcb == rtcb)
|
||||||
{
|
{
|
||||||
|
sp = (FAR void *)up_getsp();
|
||||||
if (up_interrupt_context())
|
if (up_interrupt_context())
|
||||||
{
|
{
|
||||||
sp = (FAR void *)up_getsp();
|
#if CONFIG_ARCH_INTERRUPTSTACK > 7
|
||||||
|
ret = backtrace_branch(
|
||||||
ret = backtrace_push(rtcb->stack_base_ptr +
|
# ifdef CONFIG_SMP
|
||||||
rtcb->adj_stack_size,
|
(uint32_t)arm_intstack_alloc()
|
||||||
&sp, (FAR void *)up_backtrace + 10,
|
# else
|
||||||
buffer, size);
|
(uint32_t)&g_intstackalloc
|
||||||
|
# endif
|
||||||
|
+ (CONFIG_ARCH_INTERRUPTSTACK & ~7), sp,
|
||||||
|
buffer, size);
|
||||||
if (ret < size)
|
if (ret < size)
|
||||||
{
|
{
|
||||||
sp = (FAR void *)CURRENT_REGS[REG_SP];
|
sp = (FAR void *)CURRENT_REGS[REG_SP];
|
||||||
ret += backtrace_push(rtcb->stack_base_ptr +
|
ret += backtrace_branch(rtcb->stack_base_ptr +
|
||||||
rtcb->adj_stack_size, &sp,
|
rtcb->adj_stack_size, sp,
|
||||||
(FAR void *)CURRENT_REGS[REG_PC],
|
&buffer[ret], size - ret);
|
||||||
&buffer[ret], size - ret);
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
sp = (FAR void *)CURRENT_REGS[REG_SP];
|
||||||
|
ret = backtrace_branch(rtcb->stack_base_ptr +
|
||||||
|
rtcb->adj_stack_size, sp,
|
||||||
|
buffer, size);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sp = (FAR void *)up_getsp();
|
ret = backtrace_branch(rtcb->stack_base_ptr +
|
||||||
ret = backtrace_push(rtcb->stack_base_ptr +
|
rtcb->adj_stack_size, sp,
|
||||||
rtcb->adj_stack_size, &sp,
|
buffer, size);
|
||||||
(FAR void *)up_backtrace + 10,
|
|
||||||
buffer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < size)
|
|
||||||
{
|
|
||||||
ret += backtrace_branch(rtcb->stack_base_ptr +
|
|
||||||
rtcb->adj_stack_size, sp,
|
|
||||||
&buffer[ret], size - ret);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
flags = enter_critical_section();
|
flags = enter_critical_section();
|
||||||
|
|
||||||
sp = (FAR void *)tcb->xcp.regs[REG_SP];
|
ret = backtrace_branch(tcb->stack_base_ptr +
|
||||||
ret = backtrace_push(tcb->stack_base_ptr +
|
tcb->adj_stack_size,
|
||||||
tcb->adj_stack_size, &sp,
|
(FAR void *)tcb->xcp.regs[REG_SP],
|
||||||
(FAR void *)tcb->xcp.regs[REG_PC],
|
buffer, size);
|
||||||
buffer, size);
|
|
||||||
if (ret < size)
|
|
||||||
{
|
|
||||||
ret += backtrace_branch(tcb->stack_base_ptr +
|
|
||||||
tcb->adj_stack_size, sp,
|
|
||||||
&buffer[ret], size - ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
leave_critical_section(flags);
|
leave_critical_section(flags);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,38 +42,12 @@
|
|||||||
|
|
||||||
#define INSTR_IS(i, o) (((i) & (IMASK_##o)) == (IOP_##o))
|
#define INSTR_IS(i, o) (((i) & (IMASK_##o)) == (IOP_##o))
|
||||||
|
|
||||||
#define IMASK_T_STMDB 0xfffff000 /* stmdb sp!,{..lr} */
|
|
||||||
#define IOP_T_STMDB 0xe92d4000
|
|
||||||
|
|
||||||
#define IMASK_T_PUSH_LO 0xff00 /* push {reglist} (not LR) */
|
|
||||||
#define IOP_T_PUSH_LO 0xb400
|
|
||||||
|
|
||||||
#define IMASK_T_PUSH 0xff00 /* push {reglist} (inc LR) */
|
|
||||||
#define IOP_T_PUSH 0xb500
|
|
||||||
|
|
||||||
#define IMASK_T_VPUSH_16 0xffbf8f00 /* vpush d */
|
|
||||||
#define IOP_T_VPUSH_16 0xed2d8b00
|
|
||||||
|
|
||||||
#define IMASK_T_VPUSH_8 0xffbf8f00 /* vpush s */
|
|
||||||
#define IOP_T_VPUSH_8 0xed2d8a00
|
|
||||||
|
|
||||||
#define IMASK_T_SUB_SP_16 0xff80 /* sub sp, # */
|
|
||||||
#define IOP_T_SUB_SP_16 0xb080
|
|
||||||
|
|
||||||
#define IMASK_T_SUB_SP_32 0xf2ff8f00 /* subw sp, sp, # */
|
|
||||||
#define IOP_T_SUB_SP_32 0xf2ad0d00
|
|
||||||
|
|
||||||
#define IMASK_T_SUB_W_SP_32 0xfbff8f00 /* sub.w sp, sp, # */
|
|
||||||
#define IOP_T_SUB_W_SP_32 0xf1ad0d00
|
|
||||||
|
|
||||||
#define IMASK_T_BLX 0xff80 /* blx */
|
#define IMASK_T_BLX 0xff80 /* blx */
|
||||||
#define IOP_T_BLX 0x4780
|
#define IOP_T_BLX 0x4780
|
||||||
|
|
||||||
#define IMASK_T_BL 0xf800 /* blx */
|
#define IMASK_T_BL 0xf800 /* blx */
|
||||||
#define IOP_T_BL 0xf000
|
#define IOP_T_BL 0xf000
|
||||||
|
|
||||||
#define INSTR_LIMIT 0x2000
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -84,32 +58,6 @@ static FAR void **g_backtrace_code_regions;
|
|||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: getlroffset
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* getlroffset() returns the currect link address offset.
|
|
||||||
*
|
|
||||||
* Input Parameters:
|
|
||||||
* lr - Link register address
|
|
||||||
*
|
|
||||||
* Returned Value:
|
|
||||||
* Link address offset, 0 is returned if the lr is invalid.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static int getlroffset(FAR uint8_t *lr)
|
|
||||||
{
|
|
||||||
lr = (FAR uint8_t *)((uintptr_t)lr & 0xfffffffe);
|
|
||||||
|
|
||||||
if (((uintptr_t)lr & 0xffffffe0) == 0xffffffe0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (*(FAR uint16_t *)(lr - 4) & 0xf000) == 0xf000 ? 5 : 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: in_code_region
|
* Name: in_code_region
|
||||||
*
|
*
|
||||||
@@ -155,178 +103,6 @@ static bool in_code_region(FAR void *pc)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: backtrace_push_internal
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* backtrace_push_internal() returns the currect link address from
|
|
||||||
* program counter and stack pointer
|
|
||||||
*
|
|
||||||
* Input Parameters:
|
|
||||||
* psp - Double poninter to the SP, this parameter will be changed if
|
|
||||||
* the corresponding LR address is successfully found.
|
|
||||||
* ppc - Double poninter to the PC, this parameter will be changed if
|
|
||||||
* the corresponding LR address is successfully found.
|
|
||||||
*
|
|
||||||
* Returned Value:
|
|
||||||
* Link address should be returned if successful
|
|
||||||
* Otherwise, NULL is returned
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static FAR void *backtrace_push_internal(FAR void **psp, FAR void **ppc)
|
|
||||||
{
|
|
||||||
FAR uint8_t *sp = *psp;
|
|
||||||
FAR uint8_t *pc = *ppc;
|
|
||||||
FAR uint8_t *base;
|
|
||||||
FAR uint8_t *lr;
|
|
||||||
uint32_t ins32;
|
|
||||||
uint16_t ins16;
|
|
||||||
int offset = 1;
|
|
||||||
int frame;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < INSTR_LIMIT; i += 2)
|
|
||||||
{
|
|
||||||
ins16 = *(FAR uint16_t *)(pc - i);
|
|
||||||
if (INSTR_IS(ins16, T_PUSH))
|
|
||||||
{
|
|
||||||
frame = __builtin_popcount(ins16 & 0xff) + 1;
|
|
||||||
ins16 = *(FAR uint16_t *)(pc - i - 2);
|
|
||||||
if (INSTR_IS(ins16, T_PUSH_LO))
|
|
||||||
{
|
|
||||||
offset += __builtin_popcount(ins16 & 0xff);
|
|
||||||
frame += offset - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ins32 = ins16 << 16;
|
|
||||||
ins32 |= *(FAR uint16_t *)(pc - i + 2);
|
|
||||||
if (INSTR_IS(ins32, T_STMDB))
|
|
||||||
{
|
|
||||||
frame = __builtin_popcount(ins32 & 0xfff) + 1;
|
|
||||||
ins16 = *(FAR uint16_t *)(pc - i - 2);
|
|
||||||
if (INSTR_IS(ins16, T_PUSH_LO))
|
|
||||||
{
|
|
||||||
offset += __builtin_popcount(ins16 & 0xff);
|
|
||||||
frame += offset - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i >= INSTR_LIMIT)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
base = pc - i;
|
|
||||||
|
|
||||||
for (i = 0; i < INSTR_LIMIT && base + i < pc; )
|
|
||||||
{
|
|
||||||
ins16 = *(FAR uint16_t *)(base + i);
|
|
||||||
if (INSTR_IS(ins16, T_SUB_SP_16))
|
|
||||||
{
|
|
||||||
frame += (ins16 & 0x7f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ins32 = ins16 << 16;
|
|
||||||
ins32 |= *(FAR uint16_t *)(base + i + 2);
|
|
||||||
if (INSTR_IS(ins32, T_SUB_SP_32))
|
|
||||||
{
|
|
||||||
uint32_t shift = ins32 >> 24 & 0x4;
|
|
||||||
uint32_t sub = 0;
|
|
||||||
|
|
||||||
if (shift)
|
|
||||||
{
|
|
||||||
sub = 1 << (shift - 1 + 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
frame += (sub + (ins32 & 0xff) +
|
|
||||||
((ins32 & 0x7000) >> 4)) / sizeof(uint32_t);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (INSTR_IS(ins32, T_SUB_W_SP_32))
|
|
||||||
{
|
|
||||||
uint32_t shift;
|
|
||||||
uint32_t sub;
|
|
||||||
|
|
||||||
sub = (ins32 & 0x7f) + 0x80;
|
|
||||||
shift = (ins32 >> 7) & 0x1;
|
|
||||||
shift += ((ins32 >> 12) & 0x7) << 1;
|
|
||||||
shift += ((ins32 >> 26) & 0x1) << 4;
|
|
||||||
|
|
||||||
frame += sub << (30 - shift);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (INSTR_IS(ins32, T_VPUSH_16))
|
|
||||||
{
|
|
||||||
frame += (ins32 & 0xff);
|
|
||||||
}
|
|
||||||
else if (INSTR_IS(ins32, T_VPUSH_8))
|
|
||||||
{
|
|
||||||
frame += (ins32 & 0xff) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
i += ((ins16 & 0xf800) >= 0xe800) ? 4 : 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
lr = (FAR uint8_t *)*((FAR uint32_t *)sp + frame - offset);
|
|
||||||
if (!in_code_region(lr))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = getlroffset(lr);
|
|
||||||
if (offset == 0)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*psp = (FAR uint32_t *)sp + frame;
|
|
||||||
*ppc = lr - offset;
|
|
||||||
|
|
||||||
return *ppc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: backtrace_push
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* backtrace_push() parsing the return address through instruction
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static int backtrace_push(FAR void *limit, FAR void **sp,
|
|
||||||
FAR void *pc, FAR void **buffer, int size)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
pc = (uintptr_t)pc & 0xfffffffe;
|
|
||||||
|
|
||||||
buffer[i++] = pc;
|
|
||||||
|
|
||||||
for (; i < size; i++)
|
|
||||||
{
|
|
||||||
if (*sp >= limit)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[i] = backtrace_push_internal(sp, &pc);
|
|
||||||
if (!buffer[i])
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: backtrace_branch
|
* Name: backtrace_branch
|
||||||
*
|
*
|
||||||
@@ -458,54 +234,47 @@ int up_backtrace(FAR struct tcb_s *tcb, FAR void **buffer, int size)
|
|||||||
|
|
||||||
if (tcb == rtcb)
|
if (tcb == rtcb)
|
||||||
{
|
{
|
||||||
|
sp = (FAR void *)up_getsp();
|
||||||
if (up_interrupt_context())
|
if (up_interrupt_context())
|
||||||
{
|
{
|
||||||
sp = (FAR void *)up_getsp();
|
#if CONFIG_ARCH_INTERRUPTSTACK > 7
|
||||||
|
ret = backtrace_branch(
|
||||||
ret = backtrace_push(rtcb->stack_base_ptr +
|
# ifdef CONFIG_SMP
|
||||||
rtcb->adj_stack_size,
|
(uint32_t)arm_intstack_alloc()
|
||||||
&sp, (FAR void *)up_backtrace + 10,
|
# else
|
||||||
buffer, size);
|
(uint32_t)&g_intstackalloc
|
||||||
|
# endif
|
||||||
|
+ (CONFIG_ARCH_INTERRUPTSTACK & ~7), sp,
|
||||||
|
buffer, size);
|
||||||
if (ret < size)
|
if (ret < size)
|
||||||
{
|
{
|
||||||
sp = (FAR void *)CURRENT_REGS[REG_SP];
|
sp = (FAR void *)CURRENT_REGS[REG_SP];
|
||||||
ret += backtrace_push(rtcb->stack_base_ptr +
|
ret += backtrace_branch(rtcb->stack_base_ptr +
|
||||||
rtcb->adj_stack_size, &sp,
|
rtcb->adj_stack_size, sp,
|
||||||
(FAR void *)CURRENT_REGS[REG_PC],
|
&buffer[ret], size - ret);
|
||||||
&buffer[ret], size - ret);
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
sp = (FAR void *)CURRENT_REGS[REG_SP];
|
||||||
|
ret = backtrace_branch(rtcb->stack_base_ptr +
|
||||||
|
rtcb->adj_stack_size, sp,
|
||||||
|
buffer, size);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sp = (FAR void *)up_getsp();
|
ret = backtrace_branch(rtcb->stack_base_ptr +
|
||||||
ret = backtrace_push(rtcb->stack_base_ptr +
|
rtcb->adj_stack_size, sp,
|
||||||
rtcb->adj_stack_size, &sp,
|
buffer, size);
|
||||||
(FAR void *)up_backtrace + 10,
|
|
||||||
buffer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < size)
|
|
||||||
{
|
|
||||||
ret += backtrace_branch(rtcb->stack_base_ptr +
|
|
||||||
rtcb->adj_stack_size, sp,
|
|
||||||
&buffer[ret], size - ret);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
flags = enter_critical_section();
|
flags = enter_critical_section();
|
||||||
|
|
||||||
sp = (FAR void *)tcb->xcp.regs[REG_SP];
|
ret = backtrace_branch(tcb->stack_base_ptr +
|
||||||
ret = backtrace_push(tcb->stack_base_ptr +
|
tcb->adj_stack_size,
|
||||||
tcb->adj_stack_size, &sp,
|
(FAR void *)tcb->xcp.regs[REG_SP],
|
||||||
(FAR void *)tcb->xcp.regs[REG_PC],
|
buffer, size);
|
||||||
buffer, size);
|
|
||||||
if (ret < size)
|
|
||||||
{
|
|
||||||
ret += backtrace_branch(tcb->stack_base_ptr +
|
|
||||||
tcb->adj_stack_size, sp,
|
|
||||||
&buffer[ret], size - ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
leave_critical_section(flags);
|
leave_critical_section(flags);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user