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
 | ||
|  | 
 |