738 lines
21 KiB
C
738 lines
21 KiB
C
/*
|
|
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
|
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
* conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
|
* provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
|
|
* to endorse or promote products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "los_backtrace.h"
|
|
#include "los_task.h"
|
|
#include "los_debug.h"
|
|
#include "los_arch.h"
|
|
#if (LOSCFG_BACKTRACE_TYPE == 4)
|
|
#include "los_arch_regs.h"
|
|
#endif
|
|
|
|
#if (LOSCFG_BACKTRACE_TYPE != 0)
|
|
/* This function is used to judge whether the data in the stack is a code section address.
|
|
The default code section is only one, but there may be more than one. Modify the
|
|
judgment condition to support multiple code sections. */
|
|
WEAK BOOL OsStackDataIsCodeAddr(UINTPTR value)
|
|
{
|
|
if ((value > CODE_START_ADDR) && (value < CODE_END_ADDR)) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
#if (LOSCFG_BACKTRACE_TYPE == 1)
|
|
#define OS_BACKTRACE_START 2
|
|
/* Thumb instruction, so the pc must be an odd number */
|
|
#define OS_IS_THUMB_INSTRUCTION(pc) ((pc & 0x1) == 1)
|
|
|
|
/* BL or BLX instruction flag. */
|
|
#define OS_BL_INS_MASK 0xF800
|
|
#define OS_BL_INS_HIGH 0xF800
|
|
#define OS_BL_INS_LOW 0xF000
|
|
#define OS_BLX_INX_MASK 0xFF00
|
|
#define OS_BLX_INX 0x4700
|
|
|
|
STATIC INLINE BOOL OsInsIsBlOrBlx(UINTPTR addr)
|
|
{
|
|
UINT16 ins1 = *((UINT16 *)addr);
|
|
UINT16 ins2 = *((UINT16 *)(addr + 2)); /* 2: Thumb instruction is two bytes. */
|
|
|
|
if (((ins2 & OS_BL_INS_MASK) == OS_BL_INS_HIGH) &&
|
|
((ins1 & OS_BL_INS_MASK) == OS_BL_INS_LOW)) {
|
|
return TRUE;
|
|
} else if ((ins2 & OS_BLX_INX_MASK) == OS_BLX_INX) {
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
STATIC INLINE UINT32 OsStackAddrGet(UINTPTR *stackStart, UINTPTR *stackEnd, UINTPTR SP)
|
|
{
|
|
if (SP != 0) {
|
|
*stackStart = SP;
|
|
if ((SP >= CSTACK_START_ADDR) && (SP < CSTACK_END_ADDR)) {
|
|
*stackEnd = CSTACK_END_ADDR;
|
|
} else {
|
|
UINT32 taskID = LOS_CurTaskIDGet();
|
|
LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
|
|
*stackEnd = (UINTPTR)taskCB->topOfStack + taskCB->stackSize;
|
|
if ((SP < (UINTPTR)taskCB->topOfStack) || (SP >= *stackEnd)) {
|
|
PRINT_ERR("msp statck [0x%x, 0x%x], cur task stack [0x%x, 0x%x], cur sp(0x%x) is overflow!\n",
|
|
CSTACK_START_ADDR, CSTACK_END_ADDR, (UINTPTR)taskCB->topOfStack, *stackEnd, SP);
|
|
return LOS_NOK;
|
|
}
|
|
}
|
|
} else {
|
|
if (ArchSpGet() != ArchPspGet()) {
|
|
*stackStart = ArchMspGet();
|
|
*stackEnd = CSTACK_END_ADDR;
|
|
if ((*stackStart < CSTACK_START_ADDR) || (*stackStart >= CSTACK_END_ADDR)) {
|
|
PRINT_ERR("msp stack [0x%x, 0x%x], cur sp(0x%x) is overflow!\n",
|
|
CSTACK_START_ADDR, CSTACK_END_ADDR, *stackStart);
|
|
return LOS_NOK;
|
|
}
|
|
PRINTK("msp, start = %x, end = %x\n", *stackStart, *stackEnd);
|
|
} else {
|
|
*stackStart = ArchPspGet();
|
|
UINT32 taskID = LOS_CurTaskIDGet();
|
|
LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
|
|
*stackEnd = (UINTPTR)taskCB->topOfStack + taskCB->stackSize;
|
|
if ((*stackStart < (UINTPTR)taskCB->topOfStack) || (*stackStart >= *stackEnd)) {
|
|
PRINT_ERR("psp stack [0x%x, 0x%x], cur sp(0x%x) is overflow, cur task id is %d!\n",
|
|
taskCB->topOfStack, *stackEnd, *stackStart, taskID);
|
|
return LOS_NOK;
|
|
}
|
|
PRINTK("psp, start = %x, end = %x\n", *stackStart, *stackEnd);
|
|
}
|
|
}
|
|
|
|
return LOS_OK;
|
|
}
|
|
|
|
STATIC INLINE UINTPTR OsAddrIsValid(UINTPTR sp)
|
|
{
|
|
UINTPTR pc;
|
|
BOOL ret;
|
|
|
|
/* The stack space pointed to by the current SP may store the LR,
|
|
so need decrease a word to PC. */
|
|
pc = *((UINTPTR *)sp) - sizeof(UINTPTR);
|
|
|
|
if (!OS_IS_THUMB_INSTRUCTION(pc)) {
|
|
return 0;
|
|
}
|
|
|
|
/* PC in thumb mode is an odd number, fix the PC address by decreasing one byte. */
|
|
pc = *((UINTPTR *)sp) - 1;
|
|
|
|
ret = OsStackDataIsCodeAddr(pc);
|
|
if (ret == FALSE) {
|
|
return 0;
|
|
}
|
|
|
|
ret = OsInsIsBlOrBlx(pc - sizeof(UINTPTR));
|
|
if (ret == FALSE) {
|
|
return 0;
|
|
}
|
|
|
|
return pc;
|
|
}
|
|
#elif (LOSCFG_BACKTRACE_TYPE == 2)
|
|
#define OS_BACKTRACE_START 1
|
|
#define OS_RA_OFFSET 4
|
|
#define OS_FP_OFFSET 8
|
|
#define OS_FP_ALIGN(value) (((UINT32)(value) & (UINT32)(LOSCFG_STACK_POINT_ALIGN_SIZE - 1)) == 0)
|
|
|
|
STATIC INLINE UINTPTR OsFpGet(VOID)
|
|
{
|
|
UINTPTR fp = 0;
|
|
__asm volatile("mv %0, s0" : "=r"(fp));
|
|
dsb();
|
|
return fp;
|
|
}
|
|
|
|
WEAK BOOL IsValidFP(UINTPTR fp)
|
|
{
|
|
LosTaskCB *taskCB = NULL;
|
|
UINTPTR stackTop, stackBottom;
|
|
UINTPTR irqStackTop, irqStackBottom;
|
|
|
|
if ((fp == FP_INIT_VALUE) || !OS_FP_ALIGN(fp)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (LOS_TaskIsRunning()) {
|
|
taskCB = OS_TCB_FROM_TID(LOS_CurTaskIDGet());
|
|
stackTop = taskCB->topOfStack;
|
|
stackBottom = taskCB->topOfStack + taskCB->stackSize;
|
|
irqStackTop = (UINTPTR)CSTACK_START_ADDR;
|
|
irqStackBottom = (UINTPTR)CSTACK_SECTION_END;
|
|
} else {
|
|
stackTop = 0;
|
|
stackBottom = 0;
|
|
irqStackTop = (UINTPTR)CSTACK_START_ADDR;
|
|
irqStackBottom = (UINTPTR)CSTACK_SECTION_END;
|
|
}
|
|
|
|
if (((fp > stackTop) && (fp <= stackBottom)) || ((fp > irqStackTop) && (fp <= irqStackBottom))) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID LOS_RecordLR(UINTPTR *LR, UINT32 LRSize, UINT32 jumpCount, UINTPTR SP)
|
|
{
|
|
UINTPTR backFp;
|
|
UINTPTR tmpFp;
|
|
UINTPTR backRa;
|
|
UINT32 count = 0;
|
|
UINT32 index = 0;
|
|
|
|
if (LR == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (SP != 0) {
|
|
backFp = SP;
|
|
} else {
|
|
backFp = OsFpGet();
|
|
}
|
|
|
|
if (!IsValidFP(backFp)) {
|
|
PRINT_ERR("BackTrace failed! Invalid fp 0x%x\n", backFp);
|
|
return;
|
|
}
|
|
|
|
do {
|
|
tmpFp = backFp;
|
|
backRa = *((UINTPTR *)(UINTPTR)(tmpFp - OS_RA_OFFSET));
|
|
backFp = *((UINTPTR *)(UINTPTR)(tmpFp - OS_FP_OFFSET));
|
|
if (index++ < jumpCount) {
|
|
continue;
|
|
}
|
|
|
|
LR[count] = backRa;
|
|
count++;
|
|
if ((count == LRSize) || (backFp == tmpFp)) {
|
|
break;
|
|
}
|
|
} while (IsValidFP(backFp));
|
|
|
|
if (count < LRSize) {
|
|
LR[count] = 0;
|
|
}
|
|
}
|
|
#elif (LOSCFG_BACKTRACE_TYPE == 3)
|
|
#define OS_BACKTRACE_START 1
|
|
#define OS_JALX_INS_MASK 0x7F
|
|
#define OS_JAL_INS_LOW 0x6F
|
|
#define OS_JAL_16_INS_MASK 0x2001
|
|
#define OS_JALR_INS_LOW 0x67
|
|
#define OS_JALR_16_INS_MASK 0x9002
|
|
#define OS_JR_16_INS_MASK 0x8002
|
|
#define OS_J_16_INS_MASK 0xA001
|
|
|
|
STATIC INLINE BOOL OsInsIsJump(UINTPTR addr)
|
|
{
|
|
UINT16 ins1 = *((UINT16 *)addr);
|
|
UINT16 ins2 = *((UINT16 *)(addr + 2)); // 2, for the mask
|
|
|
|
/* Jal ins */
|
|
if (((ins1 & OS_JALX_INS_MASK) == OS_JAL_INS_LOW) ||
|
|
((ins1 & OS_JAL_16_INS_MASK) == OS_JAL_16_INS_MASK) ||
|
|
((ins2 & OS_JAL_16_INS_MASK) == OS_JAL_16_INS_MASK)) {
|
|
return TRUE;
|
|
}
|
|
|
|
/* Jalr ins */
|
|
if (((ins1 & OS_JALX_INS_MASK) == OS_JALR_INS_LOW) ||
|
|
((ins1 & OS_JALR_16_INS_MASK) == OS_JALR_16_INS_MASK) ||
|
|
((ins2 & OS_JALR_16_INS_MASK) == OS_JALR_16_INS_MASK)) {
|
|
return TRUE;
|
|
}
|
|
|
|
/* Jr ins */
|
|
if (((ins1 & OS_JR_16_INS_MASK) == OS_JR_16_INS_MASK) ||
|
|
((ins2 & OS_JR_16_INS_MASK) == OS_JR_16_INS_MASK)) {
|
|
return TRUE;
|
|
}
|
|
|
|
/* J ins */
|
|
if (((ins1 & OS_J_16_INS_MASK) == OS_J_16_INS_MASK) ||
|
|
((ins2 & OS_J_16_INS_MASK) == OS_J_16_INS_MASK)) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
STATIC INLINE UINTPTR OsSpGet(VOID)
|
|
{
|
|
UINTPTR sp = 0;
|
|
__asm volatile("mv %0, sp" : "=r"(sp));
|
|
dsb();
|
|
return sp;
|
|
}
|
|
|
|
STATIC INLINE UINT32 OsStackAddrGet(UINTPTR *stackStart, UINTPTR *stackEnd, UINTPTR SP)
|
|
{
|
|
if (SP != 0) {
|
|
*stackStart = SP;
|
|
if ((SP >= CSTACK_START_ADDR) && (SP < CSTACK_END_ADDR)) {
|
|
*stackEnd = CSTACK_END_ADDR;
|
|
} else {
|
|
UINT32 taskID = LOS_CurTaskIDGet();
|
|
LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
|
|
*stackEnd = (UINTPTR)taskCB->topOfStack + taskCB->stackSize;
|
|
if ((SP < (UINTPTR)taskCB->topOfStack) || (SP >= *stackEnd)) {
|
|
PRINT_ERR("msp statck [0x%x, 0x%x], cur task stack [0x%x, 0x%x], cur sp(0x%x) is overflow!\n",
|
|
CSTACK_START_ADDR, CSTACK_END_ADDR, (UINTPTR)taskCB->topOfStack, *stackEnd, SP);
|
|
return LOS_NOK;
|
|
}
|
|
}
|
|
} else {
|
|
if (!LOS_TaskIsRunning()) {
|
|
*stackStart = OsSpGet();
|
|
*stackEnd = CSTACK_END_ADDR;
|
|
if ((*stackStart < CSTACK_START_ADDR) || (*stackStart >= CSTACK_END_ADDR)) {
|
|
PRINT_ERR("msp stack [0x%x, 0x%x], cur sp(0x%x) is overflow!\n",
|
|
CSTACK_START_ADDR, CSTACK_END_ADDR, *stackStart);
|
|
return LOS_NOK;
|
|
}
|
|
} else {
|
|
*stackStart = OsSpGet();
|
|
UINT32 taskID = LOS_CurTaskIDGet();
|
|
LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
|
|
*stackEnd = (UINTPTR)taskCB->topOfStack + taskCB->stackSize;
|
|
if ((*stackStart < (UINTPTR)taskCB->topOfStack) || (*stackStart >= *stackEnd)) {
|
|
PRINT_ERR("psp stack [0x%x, 0x%x], cur sp(0x%x) is overflow, cur task id is %d!\n",
|
|
taskCB->topOfStack, *stackEnd, *stackStart, taskID);
|
|
return LOS_NOK;
|
|
}
|
|
}
|
|
}
|
|
|
|
return LOS_OK;
|
|
}
|
|
|
|
STATIC INLINE UINTPTR OsAddrIsValid(UINTPTR sp)
|
|
{
|
|
UINTPTR pc;
|
|
BOOL ret;
|
|
|
|
pc = *((UINTPTR *)sp);
|
|
|
|
ret = OsStackDataIsCodeAddr(pc);
|
|
if (ret == FALSE) {
|
|
return 0;
|
|
}
|
|
|
|
ret = OsInsIsJump(pc - sizeof(UINTPTR));
|
|
if (ret == FALSE) {
|
|
return 0;
|
|
}
|
|
|
|
return pc;
|
|
}
|
|
|
|
#elif (LOSCFG_BACKTRACE_TYPE == 4)
|
|
#define OS_BACKTRACE_START 0
|
|
#define ALIGN_MASK (4 - 1)
|
|
#define OS_REG_LR_OFFSET (CONTEXT_SIZE - 8)
|
|
|
|
UINT32 IsSpAligned(UINT32 value)
|
|
{
|
|
return (value & (UINT32)(ALIGN_MASK)) == 0;
|
|
}
|
|
|
|
STATIC INLINE UINTPTR HalGetLr(VOID)
|
|
{
|
|
UINTPTR regLr;
|
|
|
|
__asm__ __volatile__("mov %0, a0" : "=r"(regLr));
|
|
|
|
return regLr;
|
|
}
|
|
|
|
/* This function is used to check sp address. */
|
|
BOOL IsValidSP(UINTPTR regSP, UINTPTR start, UINTPTR end)
|
|
{
|
|
return (regSP >= start) && (regSP <= end) && IsSpAligned(regSP);
|
|
}
|
|
|
|
/* This function is used to check return address. */
|
|
BOOL IsValidRa(UINTPTR regRA)
|
|
{
|
|
regRA &= ~VIR_TEXT_ADDR_MASK;
|
|
regRA |= TEXT_ADDR_MASK;
|
|
|
|
return OsStackDataIsCodeAddr(regRA);
|
|
}
|
|
|
|
BOOL FindSuitableStack(UINTPTR regSP, UINTPTR *start, UINTPTR *end)
|
|
{
|
|
UINT32 stackStart;
|
|
UINT32 stackEnd;
|
|
BOOL found = FALSE;
|
|
|
|
if (LOS_TaskIsRunning()) {
|
|
UINT32 taskID = LOS_CurTaskIDGet();
|
|
LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
|
|
stackStart = taskCB->topOfStack;
|
|
stackEnd = taskCB->topOfStack + taskCB->stackSize;
|
|
if (IsValidSP(regSP, stackStart, stackEnd)) {
|
|
found = TRUE;
|
|
goto FOUND;
|
|
}
|
|
}
|
|
|
|
if (IsValidSP(regSP, CSTACK_START_ADDR, CSTACK_END_ADDR)) {
|
|
stackStart = CSTACK_START_ADDR;
|
|
stackEnd = CSTACK_END_ADDR;
|
|
found = TRUE;
|
|
goto FOUND;
|
|
}
|
|
|
|
FOUND:
|
|
if (found == TRUE) {
|
|
*start = stackStart;
|
|
*end = stackEnd;
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
UINT32 HalBackTraceGet(UINTPTR sp, UINT32 retAddr, UINTPTR *callChain, UINT32 maxDepth, UINT32 jumpCount)
|
|
{
|
|
UINTPTR tmpSp;
|
|
UINT32 tmpRa;
|
|
UINTPTR backRa = retAddr;
|
|
UINTPTR backSp = sp;
|
|
UINTPTR stackStart;
|
|
UINT32 stackEnd;
|
|
UINT32 count = 0;
|
|
UINT32 index = 0;
|
|
|
|
if (FindSuitableStack(sp, &stackStart, &stackEnd) == FALSE) {
|
|
PRINTK("sp:0x%x error, backtrace failed!\n", sp);
|
|
return 0;
|
|
}
|
|
|
|
while (IsValidSP(backSp, stackStart, stackEnd)) {
|
|
if (callChain == NULL) {
|
|
PRINTK("trace%u ra:0x%x sp:0x%x\n", count, (backRa << WINDOW_INCREMENT_SHIFT) >>
|
|
WINDOW_INCREMENT_SHIFT, backSp);
|
|
} else {
|
|
if (index++ < jumpCount) {
|
|
continue;
|
|
}
|
|
backRa &= ~VIR_TEXT_ADDR_MASK;
|
|
backRa |= TEXT_ADDR_MASK;
|
|
callChain[count++] = backRa;
|
|
}
|
|
|
|
tmpRa = backRa;
|
|
tmpSp = backSp;
|
|
backRa = *((UINT32 *)(UINTPTR)(tmpSp - RA_OFFSET));
|
|
backSp = *((UINT32 *)(UINTPTR)(tmpSp - SP_OFFSET));
|
|
|
|
if ((tmpRa == backRa) || (backSp == tmpSp) || (count == maxDepth) || !IsValidRa(backRa)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
VOID LOS_RecordLR(UINTPTR *LR, UINT32 LRSize, UINT32 jumpCount, UINTPTR SP)
|
|
{
|
|
UINTPTR reglr;
|
|
if (LR == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (SP == 0) {
|
|
__asm__ __volatile__("mov %0, sp" : "=a"(SP) : :);
|
|
__asm__ __volatile__("mov %0, a0" : "=a"(reglr) : :);
|
|
} else {
|
|
reglr = *(UINT32 *)(SP - OS_REG_LR_OFFSET);
|
|
}
|
|
HakSpillWindow();
|
|
HalBackTraceGet(SP, reglr, LR, LRSize, jumpCount);
|
|
}
|
|
#elif (LOSCFG_BACKTRACE_TYPE == 5)
|
|
#define OS_BACKTRACE_START 0
|
|
|
|
UINT32 IsAligned(UINT32 val, UINT32 align)
|
|
{
|
|
return ((val & (align - 1)) == 0);
|
|
}
|
|
|
|
STATIC INLINE UINTPTR OsSpGet(VOID)
|
|
{
|
|
UINTPTR regSp;
|
|
|
|
__asm__ __volatile__("mov %0, sp" : "=r"(regSp));
|
|
|
|
return regSp;
|
|
}
|
|
|
|
/* This function is used to check sp. */
|
|
BOOL IsValidSP(UINTPTR regSP, UINTPTR start, UINTPTR end)
|
|
{
|
|
return (regSP >= start) && (regSP <= end);
|
|
}
|
|
|
|
BOOL FindSuitableStack(UINTPTR regSP, UINTPTR *start, UINTPTR *end)
|
|
{
|
|
UINT32 stackStart;
|
|
UINT32 stackEnd;
|
|
BOOL found = FALSE;
|
|
|
|
if (LOS_TaskIsRunning()) {
|
|
UINT32 taskID = LOS_CurTaskIDGet();
|
|
LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
|
|
stackStart = taskCB->topOfStack;
|
|
stackEnd = taskCB->topOfStack + taskCB->stackSize;
|
|
if (IsValidSP(regSP, stackStart, stackEnd)) {
|
|
found = TRUE;
|
|
goto FOUND;
|
|
}
|
|
}
|
|
|
|
if (IsValidSP(regSP, CSTACK_START_ADDR, CSTACK_END_ADDR)) {
|
|
stackStart = CSTACK_START_ADDR;
|
|
stackEnd = CSTACK_END_ADDR;
|
|
found = TRUE;
|
|
goto FOUND;
|
|
}
|
|
|
|
FOUND:
|
|
if (found == TRUE) {
|
|
*start = stackStart;
|
|
*end = stackEnd;
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
VOID LOS_RecordLR(UINTPTR *LR, UINT32 LRSize, UINT32 jumpCount, UINTPTR SP)
|
|
{
|
|
UINTPTR stackPointer;
|
|
UINTPTR topOfStack;
|
|
UINTPTR tmpStack = 0;
|
|
UINTPTR stackBottom;
|
|
UINTPTR checkBL;
|
|
UINT32 count = 0;
|
|
UINT32 index = 0;
|
|
|
|
if (LR == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (SP == 0) {
|
|
SP = OsSpGet();
|
|
}
|
|
|
|
stackPointer = SP;
|
|
|
|
if (FindSuitableStack(stackPointer, &topOfStack, &stackBottom) == FALSE) {
|
|
return;
|
|
}
|
|
|
|
while ((stackPointer < stackBottom) && (count < LRSize)) {
|
|
if (IsValidSP(*(UINT32 *)stackPointer, topOfStack, stackBottom)
|
|
&& OsStackDataIsCodeAddr(*(UINT32 *)(stackPointer + STACK_OFFSET))
|
|
&& IsAligned(*(UINT32 *)stackPointer, ALGIN_CODE)) {
|
|
if (tmpStack == *(UINT32 *)stackPointer) {
|
|
break;
|
|
}
|
|
tmpStack = *(UINT32 *)stackPointer;
|
|
checkBL = *(UINT32 *)(stackPointer + STACK_OFFSET);
|
|
if (count++ < jumpCount) {
|
|
continue;
|
|
}
|
|
stackPointer = tmpStack;
|
|
LR[index++] = checkBL;
|
|
continue;
|
|
}
|
|
stackPointer += STACK_OFFSET;
|
|
}
|
|
|
|
if (index < LRSize) {
|
|
LR[index] = 0;
|
|
}
|
|
}
|
|
#elif (LOSCFG_BACKTRACE_TYPE == 6)
|
|
#define OS_BACKTRACE_START 1
|
|
#define STACK_OFFSET 4
|
|
#define THUMB_OFFSET 2
|
|
#define THUMB_BIT 16
|
|
#define ARM_ALIGN_CODE 4
|
|
#define THUMB_ALIGN_CODE 2
|
|
#define BL_CMD_OFFSET 4
|
|
#define ARM_BL_MASK 0xEB000000
|
|
#define THUMB_BL_MASK 0xF000F000
|
|
#define CLEAR_LOW_BIT_MASK 0xFFFFFFFE
|
|
|
|
STATIC INLINE BOOL IsAligned(UINT32 val, UINT32 align)
|
|
{
|
|
return ((val & (align - 1)) == 0);
|
|
}
|
|
|
|
STATIC INLINE UINTPTR OsSpGet(VOID)
|
|
{
|
|
UINTPTR SP;
|
|
__asm volatile("mov %0, sp" : "=r"(SP));
|
|
return SP;
|
|
}
|
|
|
|
STATIC INLINE BOOL IsArmValidLr(UINTPTR lr)
|
|
{
|
|
return ((*(UINT32 *)(lr - BL_CMD_OFFSET) & ARM_BL_MASK) == ARM_BL_MASK);
|
|
}
|
|
|
|
STATIC INLINE BOOL IsThumbValidLr(UINTPTR lr)
|
|
{
|
|
lr = (*(UINT16 *)(lr - BL_CMD_OFFSET) << THUMB_BIT) + *(UINT16 *)(lr - THUMB_OFFSET);
|
|
return ((lr & THUMB_BL_MASK) == THUMB_BL_MASK);
|
|
}
|
|
|
|
VOID LOS_RecordLR(UINTPTR *LR, UINT32 LRSize, UINT32 jumpCount, UINTPTR SP)
|
|
{
|
|
UINT32 count = 0;
|
|
UINT32 index = 0;
|
|
LosTaskCB *taskCB = NULL;
|
|
UINT32 taskID;
|
|
UINT32 stackStart, stackEnd;
|
|
UINTPTR framePtr, tmpFramePtr, linkReg;
|
|
|
|
if (LR == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (SP == 0) {
|
|
SP = OsSpGet();
|
|
}
|
|
|
|
if (LOS_TaskIsRunning()) {
|
|
taskID = LOS_CurTaskIDGet();
|
|
taskCB = OS_TCB_FROM_TID(taskID);
|
|
stackStart = taskCB->topOfStack;
|
|
stackEnd = stackStart + taskCB->stackSize;
|
|
} else {
|
|
stackStart = CSTACK_START_ADDR;
|
|
stackEnd = CSTACK_END_ADDR;
|
|
}
|
|
|
|
while ((SP > stackStart) && (SP < stackEnd)) {
|
|
linkReg = *(UINTPTR *)SP;
|
|
if (!OsStackDataIsCodeAddr(linkReg)) {
|
|
SP += STACK_OFFSET;
|
|
continue;
|
|
}
|
|
if (((!IsAligned(linkReg, ARM_ALIGN_CODE)) || !IsArmValidLr(linkReg)) &&
|
|
((!IsAligned(linkReg - 1, THUMB_ALIGN_CODE)) || !IsThumbValidLr(linkReg - 1))) {
|
|
SP += STACK_OFFSET;
|
|
continue;
|
|
}
|
|
if (index >= jumpCount) {
|
|
LR[count++] = linkReg & CLEAR_LOW_BIT_MASK;
|
|
if (count == LRSize) {
|
|
break;
|
|
}
|
|
}
|
|
++index;
|
|
SP += STACK_OFFSET;
|
|
}
|
|
|
|
/* if linkReg is not enough,clean up the last of the effective LR as the end. */
|
|
if (count < LRSize) {
|
|
LR[count] = 0;
|
|
}
|
|
}
|
|
#else
|
|
#error Unknown backtrace type.
|
|
#endif
|
|
|
|
#if (LOSCFG_BACKTRACE_TYPE == 1) || (LOSCFG_BACKTRACE_TYPE == 3)
|
|
VOID LOS_RecordLR(UINTPTR *LR, UINT32 LRSize, UINT32 jumpCount, UINTPTR SP)
|
|
{
|
|
if (LR == NULL) {
|
|
return;
|
|
}
|
|
|
|
UINTPTR stackStart;
|
|
UINTPTR stackEnd;
|
|
UINT32 count = 0;
|
|
UINT32 index = 0;
|
|
UINTPTR sp;
|
|
UINTPTR pc;
|
|
UINT32 ret;
|
|
|
|
ret = OsStackAddrGet(&stackStart, &stackEnd, SP);
|
|
if (ret != LOS_OK) {
|
|
return;
|
|
}
|
|
|
|
/* Traverse the stack space and find the LR address. */
|
|
for (sp = stackStart; sp < stackEnd; sp += sizeof(UINTPTR)) {
|
|
pc = OsAddrIsValid(sp);
|
|
if ((pc != 0) && (count < LRSize)) {
|
|
if (index++ < jumpCount) {
|
|
continue;
|
|
}
|
|
LR[count] = pc;
|
|
count++;
|
|
if (count == LRSize) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (count < LRSize) {
|
|
LR[count] = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
VOID LOS_BackTrace(VOID)
|
|
{
|
|
UINTPTR LR[BACKTRACE_MAX_DEPTH] = {0};
|
|
UINT32 index;
|
|
|
|
LOS_RecordLR(LR, BACKTRACE_MAX_DEPTH, OS_BACKTRACE_START, 0);
|
|
|
|
if (LOS_TaskIsRunning()) {
|
|
PRINTK("taskName = %s\n", g_losTask.runTask->taskName);
|
|
PRINTK("taskID = %u\n", g_losTask.runTask->taskID);
|
|
}
|
|
|
|
PRINTK("----- traceback start -----\r\n");
|
|
for (index = 0; index < BACKTRACE_MAX_DEPTH; index++) {
|
|
if (LR[index] == 0) {
|
|
break;
|
|
}
|
|
PRINTK("traceback %d -- lr = 0x%x\r\n", index, LR[index]);
|
|
}
|
|
PRINTK("----- traceback end -----\r\n");
|
|
}
|
|
|
|
VOID OsBackTraceInit(VOID)
|
|
{
|
|
OsBackTraceHookSet(LOS_RecordLR);
|
|
}
|
|
#endif
|
|
|