• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  *    conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  *    of conditions and the following disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  *    to endorse or promote products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "los_backtrace.h"
33 #include "los_task.h"
34 #include "los_debug.h"
35 #include "los_arch.h"
36 #if (LOSCFG_BACKTRACE_TYPE == 4)
37 #include "los_arch_regs.h"
38 #endif
39 
40 #if (LOSCFG_BACKTRACE_TYPE != 0)
41 /* This function is used to judge whether the data in the stack is a code section address.
42    The default code section is only one, but there may be more than one. Modify the
43    judgment condition to support multiple code sections. */
OsStackDataIsCodeAddr(UINTPTR value)44 WEAK BOOL OsStackDataIsCodeAddr(UINTPTR value)
45 {
46     if ((value > CODE_START_ADDR) && (value < CODE_END_ADDR)) {
47         return TRUE;
48     }
49     return FALSE;
50 }
51 
52 #if (LOSCFG_BACKTRACE_TYPE == 1)
53 #define OS_BACKTRACE_START     2
54 /* Thumb instruction, so the pc must be an odd number */
55 #define OS_IS_THUMB_INSTRUCTION(pc)    ((pc & 0x1) == 1)
56 
57 /* BL or BLX instruction flag. */
58 #define OS_BL_INS_MASK     0xF800
59 #define OS_BL_INS_HIGH     0xF800
60 #define OS_BL_INS_LOW      0xF000
61 #define OS_BLX_INX_MASK    0xFF00
62 #define OS_BLX_INX         0x4700
63 
OsInsIsBlOrBlx(UINTPTR addr)64 STATIC INLINE BOOL OsInsIsBlOrBlx(UINTPTR addr)
65 {
66     UINT16 ins1 = *((UINT16 *)addr);
67     UINT16 ins2 = *((UINT16 *)(addr + 2)); /* 2: Thumb instruction is two bytes. */
68 
69     if (((ins2 & OS_BL_INS_MASK) == OS_BL_INS_HIGH) &&
70         ((ins1 & OS_BL_INS_MASK) == OS_BL_INS_LOW)) {
71         return TRUE;
72     } else if ((ins2 & OS_BLX_INX_MASK) == OS_BLX_INX) {
73         return TRUE;
74     } else {
75         return FALSE;
76     }
77 }
78 
OsStackAddrGet(UINTPTR * stackStart,UINTPTR * stackEnd,UINTPTR SP)79 STATIC INLINE UINT32 OsStackAddrGet(UINTPTR *stackStart, UINTPTR *stackEnd, UINTPTR SP)
80 {
81     if (SP != 0) {
82         *stackStart = SP;
83         if ((SP >= CSTACK_START_ADDR) && (SP < CSTACK_END_ADDR)) {
84             *stackEnd = CSTACK_END_ADDR;
85         } else {
86             UINT32 taskID = LOS_CurTaskIDGet();
87             LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
88             *stackEnd = (UINTPTR)taskCB->topOfStack + taskCB->stackSize;
89             if ((SP < (UINTPTR)taskCB->topOfStack) || (SP >= *stackEnd)) {
90                 PRINT_ERR("msp statck [0x%x, 0x%x], cur task stack [0x%x, 0x%x], cur sp(0x%x) is overflow!\n",
91                           CSTACK_START_ADDR, CSTACK_END_ADDR, (UINTPTR)taskCB->topOfStack, *stackEnd, SP);
92                 return LOS_NOK;
93             }
94         }
95     } else {
96         if (ArchSpGet() != ArchPspGet()) {
97             *stackStart = ArchMspGet();
98             *stackEnd = CSTACK_END_ADDR;
99             if ((*stackStart < CSTACK_START_ADDR) || (*stackStart >= CSTACK_END_ADDR)) {
100                 PRINT_ERR("msp stack [0x%x, 0x%x], cur sp(0x%x) is overflow!\n",
101                           CSTACK_START_ADDR, CSTACK_END_ADDR, *stackStart);
102                 return LOS_NOK;
103             }
104             PRINTK("msp, start = %x, end = %x\n", *stackStart, *stackEnd);
105         } else {
106             *stackStart = ArchPspGet();
107             UINT32 taskID = LOS_CurTaskIDGet();
108             LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
109             *stackEnd = (UINTPTR)taskCB->topOfStack + taskCB->stackSize;
110             if ((*stackStart < (UINTPTR)taskCB->topOfStack) || (*stackStart >= *stackEnd)) {
111                 PRINT_ERR("psp stack [0x%x, 0x%x], cur sp(0x%x) is overflow, cur task id is %d!\n",
112                           taskCB->topOfStack, *stackEnd, *stackStart, taskID);
113                 return LOS_NOK;
114             }
115             PRINTK("psp, start = %x, end = %x\n", *stackStart, *stackEnd);
116         }
117     }
118 
119     return LOS_OK;
120 }
121 
OsAddrIsValid(UINTPTR sp)122 STATIC INLINE UINTPTR OsAddrIsValid(UINTPTR sp)
123 {
124     UINTPTR pc;
125     BOOL ret;
126 
127     /* The stack space pointed to by the current SP may store the LR,
128        so need decrease a word to PC. */
129     pc = *((UINTPTR *)sp) - sizeof(UINTPTR);
130 
131     if (!OS_IS_THUMB_INSTRUCTION(pc)) {
132         return 0;
133     }
134 
135     /* PC in thumb mode is an odd number, fix the PC address by decreasing one byte. */
136     pc = *((UINTPTR *)sp) - 1;
137 
138     ret = OsStackDataIsCodeAddr(pc);
139     if (ret == FALSE) {
140         return 0;
141     }
142 
143     ret = OsInsIsBlOrBlx(pc - sizeof(UINTPTR));
144     if (ret == FALSE) {
145         return 0;
146     }
147 
148     return pc;
149 }
150 #elif (LOSCFG_BACKTRACE_TYPE == 2)
151 #define OS_BACKTRACE_START     1
152 #define OS_RA_OFFSET           4
153 #define OS_FP_OFFSET           8
154 #define OS_FP_ALIGN(value)     (((UINT32)(value) & (UINT32)(LOSCFG_STACK_POINT_ALIGN_SIZE - 1)) == 0)
155 
OsFpGet(VOID)156 STATIC INLINE UINTPTR OsFpGet(VOID)
157 {
158     UINTPTR fp = 0;
159     __asm volatile("mv %0, s0" : "=r"(fp));
160     dsb();
161     return fp;
162 }
163 
IsValidFP(UINTPTR fp)164 WEAK BOOL IsValidFP(UINTPTR fp)
165 {
166     LosTaskCB *taskCB = NULL;
167     UINTPTR stackTop, stackBottom;
168     UINTPTR irqStackTop, irqStackBottom;
169 
170     if ((fp == FP_INIT_VALUE) || !OS_FP_ALIGN(fp)) {
171         return FALSE;
172     }
173 
174     if (LOS_TaskIsRunning()) {
175         taskCB = OS_TCB_FROM_TID(LOS_CurTaskIDGet());
176         stackTop = taskCB->topOfStack;
177         stackBottom = taskCB->topOfStack + taskCB->stackSize;
178         irqStackTop = (UINTPTR)CSTACK_START_ADDR;
179         irqStackBottom = (UINTPTR)CSTACK_SECTION_END;
180     } else {
181         stackTop = 0;
182         stackBottom = 0;
183         irqStackTop = (UINTPTR)CSTACK_START_ADDR;
184         irqStackBottom = (UINTPTR)CSTACK_SECTION_END;
185     }
186 
187     if (((fp > stackTop) && (fp <= stackBottom)) || ((fp > irqStackTop) && (fp <= irqStackBottom))) {
188         return TRUE;
189     }
190 
191     return FALSE;
192 }
193 
LOS_RecordLR(UINTPTR * LR,UINT32 LRSize,UINT32 jumpCount,UINTPTR SP)194 VOID LOS_RecordLR(UINTPTR *LR, UINT32 LRSize, UINT32 jumpCount, UINTPTR SP)
195 {
196     UINTPTR backFp;
197     UINTPTR tmpFp;
198     UINTPTR backRa;
199     UINT32 count = 0;
200     UINT32 index = 0;
201 
202     if (LR == NULL) {
203         return;
204     }
205 
206     if (SP != 0) {
207         backFp = SP;
208     } else {
209         backFp = OsFpGet();
210     }
211 
212     if (!IsValidFP(backFp)) {
213         PRINT_ERR("BackTrace failed! Invalid fp 0x%x\n", backFp);
214         return;
215     }
216 
217     do {
218         tmpFp = backFp;
219         backRa = *((UINTPTR *)(UINTPTR)(tmpFp - OS_RA_OFFSET));
220         backFp = *((UINTPTR *)(UINTPTR)(tmpFp - OS_FP_OFFSET));
221         if (index++ < jumpCount) {
222             continue;
223         }
224 
225         LR[count] = backRa;
226         count++;
227         if ((count == LRSize) || (backFp == tmpFp)) {
228             break;
229         }
230     } while (IsValidFP(backFp));
231 
232     if (count < LRSize) {
233         LR[count] = 0;
234     }
235 }
236 #elif (LOSCFG_BACKTRACE_TYPE == 3)
237 #define OS_BACKTRACE_START  1
238 #define OS_JALX_INS_MASK    0x7F
239 #define OS_JAL_INS_LOW      0x6F
240 #define OS_JAL_16_INS_MASK  0x2001
241 #define OS_JALR_INS_LOW     0x67
242 #define OS_JALR_16_INS_MASK 0x9002
243 #define OS_JR_16_INS_MASK   0x8002
244 #define OS_J_16_INS_MASK    0xA001
245 
OsInsIsJump(UINTPTR addr)246 STATIC INLINE BOOL OsInsIsJump(UINTPTR addr)
247 {
248     UINT16 ins1 = *((UINT16 *)addr);
249     UINT16 ins2 = *((UINT16 *)(addr + 2)); // 2, for the mask
250 
251     /* Jal ins */
252     if (((ins1 & OS_JALX_INS_MASK) == OS_JAL_INS_LOW) ||
253         ((ins1 & OS_JAL_16_INS_MASK) == OS_JAL_16_INS_MASK) ||
254         ((ins2 & OS_JAL_16_INS_MASK) == OS_JAL_16_INS_MASK)) {
255         return TRUE;
256     }
257 
258     /* Jalr ins */
259     if (((ins1 & OS_JALX_INS_MASK) == OS_JALR_INS_LOW) ||
260         ((ins1 & OS_JALR_16_INS_MASK) == OS_JALR_16_INS_MASK) ||
261         ((ins2 & OS_JALR_16_INS_MASK) == OS_JALR_16_INS_MASK)) {
262         return TRUE;
263     }
264 
265     /* Jr ins */
266     if (((ins1 & OS_JR_16_INS_MASK) == OS_JR_16_INS_MASK) ||
267         ((ins2 & OS_JR_16_INS_MASK) == OS_JR_16_INS_MASK)) {
268         return TRUE;
269     }
270 
271     /* J ins */
272     if (((ins1 & OS_J_16_INS_MASK) == OS_J_16_INS_MASK) ||
273         ((ins2 & OS_J_16_INS_MASK) == OS_J_16_INS_MASK)) {
274         return TRUE;
275     }
276 
277     return FALSE;
278 }
279 
OsSpGet(VOID)280 STATIC INLINE UINTPTR OsSpGet(VOID)
281 {
282     UINTPTR sp = 0;
283     __asm volatile("mv %0, sp" : "=r"(sp));
284     dsb();
285     return sp;
286 }
287 
OsStackAddrGet(UINTPTR * stackStart,UINTPTR * stackEnd,UINTPTR SP)288 STATIC INLINE UINT32 OsStackAddrGet(UINTPTR *stackStart, UINTPTR *stackEnd, UINTPTR SP)
289 {
290     if (SP != 0) {
291         *stackStart = SP;
292         if ((SP >= CSTACK_START_ADDR) && (SP < CSTACK_END_ADDR)) {
293             *stackEnd = CSTACK_END_ADDR;
294         } else {
295             UINT32 taskID = LOS_CurTaskIDGet();
296             LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
297             *stackEnd = (UINTPTR)taskCB->topOfStack + taskCB->stackSize;
298             if ((SP < (UINTPTR)taskCB->topOfStack) || (SP >= *stackEnd)) {
299                 PRINT_ERR("msp statck [0x%x, 0x%x], cur task stack [0x%x, 0x%x], cur sp(0x%x) is overflow!\n",
300                           CSTACK_START_ADDR, CSTACK_END_ADDR, (UINTPTR)taskCB->topOfStack, *stackEnd, SP);
301                 return LOS_NOK;
302             }
303         }
304     } else {
305         if (!LOS_TaskIsRunning()) {
306             *stackStart = OsSpGet();
307             *stackEnd = CSTACK_END_ADDR;
308             if ((*stackStart < CSTACK_START_ADDR) || (*stackStart >= CSTACK_END_ADDR)) {
309                 PRINT_ERR("msp stack [0x%x, 0x%x], cur sp(0x%x) is overflow!\n",
310                           CSTACK_START_ADDR, CSTACK_END_ADDR, *stackStart);
311                 return LOS_NOK;
312             }
313         } else {
314             *stackStart = OsSpGet();
315             UINT32 taskID = LOS_CurTaskIDGet();
316             LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
317             *stackEnd = (UINTPTR)taskCB->topOfStack + taskCB->stackSize;
318             if ((*stackStart < (UINTPTR)taskCB->topOfStack) || (*stackStart >= *stackEnd)) {
319                 PRINT_ERR("psp stack [0x%x, 0x%x], cur sp(0x%x) is overflow, cur task id is %d!\n",
320                           taskCB->topOfStack, *stackEnd, *stackStart, taskID);
321                 return LOS_NOK;
322             }
323         }
324     }
325 
326     return LOS_OK;
327 }
328 
OsAddrIsValid(UINTPTR sp)329 STATIC INLINE UINTPTR OsAddrIsValid(UINTPTR sp)
330 {
331     UINTPTR pc;
332     BOOL ret;
333 
334     pc = *((UINTPTR *)sp);
335 
336     ret = OsStackDataIsCodeAddr(pc);
337     if (ret == FALSE) {
338         return 0;
339     }
340 
341     ret = OsInsIsJump(pc - sizeof(UINTPTR));
342     if (ret == FALSE) {
343         return 0;
344     }
345 
346     return pc;
347 }
348 
349 #elif (LOSCFG_BACKTRACE_TYPE == 4)
350 #define OS_BACKTRACE_START     0
351 #define ALIGN_MASK             (4 - 1)
352 #define OS_REG_LR_OFFSET       (CONTEXT_SIZE - 8)
353 
IsSpAligned(UINT32 value)354 UINT32 IsSpAligned(UINT32 value)
355 {
356     return (value & (UINT32)(ALIGN_MASK)) == 0;
357 }
358 
HalGetLr(VOID)359 STATIC INLINE UINTPTR HalGetLr(VOID)
360 {
361     UINTPTR regLr;
362 
363     __asm__ __volatile__("mov %0, a0" : "=r"(regLr));
364 
365     return regLr;
366 }
367 
368 /* This function is used to check sp address. */
IsValidSP(UINTPTR regSP,UINTPTR start,UINTPTR end)369 BOOL IsValidSP(UINTPTR regSP, UINTPTR start, UINTPTR end)
370 {
371     return (regSP >= start) && (regSP <= end) && IsSpAligned(regSP);
372 }
373 
374 /* This function is used to check return address. */
IsValidRa(UINTPTR regRA)375 BOOL IsValidRa(UINTPTR regRA)
376 {
377     regRA &= ~VIR_TEXT_ADDR_MASK;
378     regRA |= TEXT_ADDR_MASK;
379 
380     return OsStackDataIsCodeAddr(regRA);
381 }
382 
FindSuitableStack(UINTPTR regSP,UINTPTR * start,UINTPTR * end)383 BOOL FindSuitableStack(UINTPTR regSP, UINTPTR *start, UINTPTR *end)
384 {
385     UINT32 stackStart;
386     UINT32 stackEnd;
387     BOOL found = FALSE;
388 
389     if (LOS_TaskIsRunning()) {
390         UINT32 taskID = LOS_CurTaskIDGet();
391         LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
392         stackStart = taskCB->topOfStack;
393         stackEnd = taskCB->topOfStack + taskCB->stackSize;
394         if (IsValidSP(regSP, stackStart, stackEnd)) {
395             found = TRUE;
396             goto FOUND;
397         }
398     }
399 
400     if (IsValidSP(regSP, CSTACK_START_ADDR, CSTACK_END_ADDR)) {
401         stackStart = CSTACK_START_ADDR;
402         stackEnd = CSTACK_END_ADDR;
403         found = TRUE;
404         goto FOUND;
405     }
406 
407 FOUND:
408     if (found == TRUE) {
409         *start = stackStart;
410         *end = stackEnd;
411     }
412 
413     return found;
414 }
415 
HalBackTraceGet(UINTPTR sp,UINT32 retAddr,UINTPTR * callChain,UINT32 maxDepth,UINT32 jumpCount)416 UINT32 HalBackTraceGet(UINTPTR sp, UINT32 retAddr, UINTPTR *callChain, UINT32 maxDepth, UINT32 jumpCount)
417 {
418     UINTPTR tmpSp;
419     UINT32 tmpRa;
420     UINTPTR backRa = retAddr;
421     UINTPTR backSp = sp;
422     UINTPTR stackStart;
423     UINT32 stackEnd;
424     UINT32 count = 0;
425     UINT32 index = 0;
426 
427     if (FindSuitableStack(sp, &stackStart, &stackEnd) == FALSE) {
428         PRINTK("sp:0x%x error, backtrace failed!\n", sp);
429         return 0;
430     }
431 
432     while (IsValidSP(backSp, stackStart, stackEnd)) {
433         if (callChain == NULL) {
434             PRINTK("trace%u  ra:0x%x  sp:0x%x\n", count, (backRa << WINDOW_INCREMENT_SHIFT) >>
435                     WINDOW_INCREMENT_SHIFT, backSp);
436         } else {
437             if (index++ < jumpCount) {
438                 continue;
439             }
440             backRa &= ~VIR_TEXT_ADDR_MASK;
441             backRa |= TEXT_ADDR_MASK;
442             callChain[count++] = backRa;
443         }
444 
445         tmpRa = backRa;
446         tmpSp = backSp;
447         backRa = *((UINT32 *)(UINTPTR)(tmpSp - RA_OFFSET));
448         backSp = *((UINT32 *)(UINTPTR)(tmpSp - SP_OFFSET));
449 
450         if ((tmpRa == backRa) || (backSp == tmpSp) || (count == maxDepth) || !IsValidRa(backRa)) {
451             break;
452         }
453     }
454 
455     return count;
456 }
457 
LOS_RecordLR(UINTPTR * LR,UINT32 LRSize,UINT32 jumpCount,UINTPTR SP)458 VOID LOS_RecordLR(UINTPTR *LR, UINT32 LRSize, UINT32 jumpCount, UINTPTR SP)
459 {
460     UINTPTR reglr;
461     if (LR == NULL) {
462         return;
463     }
464 
465     if (SP == 0) {
466         __asm__ __volatile__("mov %0, sp" : "=a"(SP) : :);
467         __asm__ __volatile__("mov %0, a0" : "=a"(reglr) : :);
468     } else {
469         reglr = *(UINT32 *)(SP - OS_REG_LR_OFFSET);
470     }
471     HakSpillWindow();
472     HalBackTraceGet(SP, reglr, LR, LRSize, jumpCount);
473 }
474 #elif (LOSCFG_BACKTRACE_TYPE == 5)
475 #define OS_BACKTRACE_START     0
476 
IsAligned(UINT32 val,UINT32 align)477 UINT32 IsAligned(UINT32 val, UINT32 align)
478 {
479     return ((val & (align - 1)) == 0);
480 }
481 
OsSpGet(VOID)482 STATIC INLINE UINTPTR OsSpGet(VOID)
483 {
484     UINTPTR regSp;
485 
486     __asm__ __volatile__("mov %0, sp" : "=r"(regSp));
487 
488     return regSp;
489 }
490 
491 /* This function is used to check sp. */
IsValidSP(UINTPTR regSP,UINTPTR start,UINTPTR end)492 BOOL IsValidSP(UINTPTR regSP, UINTPTR start, UINTPTR end)
493 {
494     return (regSP >= start) && (regSP <= end);
495 }
496 
FindSuitableStack(UINTPTR regSP,UINTPTR * start,UINTPTR * end)497 BOOL FindSuitableStack(UINTPTR regSP, UINTPTR *start, UINTPTR *end)
498 {
499     UINT32 stackStart;
500     UINT32 stackEnd;
501     BOOL found = FALSE;
502 
503     if (LOS_TaskIsRunning()) {
504         UINT32 taskID = LOS_CurTaskIDGet();
505         LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
506         stackStart = taskCB->topOfStack;
507         stackEnd = taskCB->topOfStack + taskCB->stackSize;
508         if (IsValidSP(regSP, stackStart, stackEnd)) {
509             found = TRUE;
510             goto FOUND;
511         }
512     }
513 
514     if (IsValidSP(regSP, CSTACK_START_ADDR, CSTACK_END_ADDR)) {
515         stackStart = CSTACK_START_ADDR;
516         stackEnd = CSTACK_END_ADDR;
517         found = TRUE;
518         goto FOUND;
519     }
520 
521 FOUND:
522     if (found == TRUE) {
523         *start = stackStart;
524         *end = stackEnd;
525     }
526 
527     return found;
528 }
529 
LOS_RecordLR(UINTPTR * LR,UINT32 LRSize,UINT32 jumpCount,UINTPTR SP)530 VOID LOS_RecordLR(UINTPTR *LR, UINT32 LRSize, UINT32 jumpCount, UINTPTR SP)
531 {
532     UINTPTR stackPointer;
533     UINTPTR topOfStack;
534     UINTPTR tmpStack = 0;
535     UINTPTR stackBottom;
536     UINTPTR checkBL;
537     UINT32 count = 0;
538     UINT32 index = 0;
539 
540     if (LR == NULL) {
541         return;
542     }
543 
544     if (SP == 0) {
545         SP = OsSpGet();
546     }
547 
548     stackPointer = SP;
549 
550     if (FindSuitableStack(stackPointer, &topOfStack, &stackBottom) == FALSE) {
551         return;
552     }
553 
554     while ((stackPointer < stackBottom) && (count < LRSize)) {
555         if (IsValidSP(*(UINT32 *)stackPointer, topOfStack, stackBottom)
556             && OsStackDataIsCodeAddr(*(UINT32 *)(stackPointer + STACK_OFFSET))
557             && IsAligned(*(UINT32 *)stackPointer, ALGIN_CODE)) {
558             if (tmpStack == *(UINT32 *)stackPointer) {
559                 break;
560             }
561             tmpStack = *(UINT32 *)stackPointer;
562             checkBL = *(UINT32 *)(stackPointer + STACK_OFFSET);
563             if (count++ < jumpCount) {
564                 continue;
565             }
566             stackPointer = tmpStack;
567             LR[index++] =  checkBL;
568             continue;
569         }
570         stackPointer += STACK_OFFSET;
571     }
572 
573     if (index < LRSize) {
574         LR[index] = 0;
575     }
576 }
577 #elif (LOSCFG_BACKTRACE_TYPE == 6)
578 #define OS_BACKTRACE_START               1
579 #define STACK_OFFSET                     4
580 #define THUMB_OFFSET                     2
581 #define THUMB_BIT                        16
582 #define ARM_ALIGN_CODE                   4
583 #define THUMB_ALIGN_CODE                 2
584 #define BL_CMD_OFFSET                    4
585 #define ARM_BL_MASK                      0xEB000000
586 #define THUMB_BL_MASK                    0xF000F000
587 #define CLEAR_LOW_BIT_MASK               0xFFFFFFFE
588 
IsAligned(UINT32 val,UINT32 align)589 STATIC INLINE BOOL IsAligned(UINT32 val, UINT32 align)
590 {
591     return ((val & (align - 1)) == 0);
592 }
593 
OsSpGet(VOID)594 STATIC INLINE UINTPTR OsSpGet(VOID)
595 {
596     UINTPTR SP;
597     __asm volatile("mov %0, sp" : "=r"(SP));
598     return SP;
599 }
600 
IsArmValidLr(UINTPTR lr)601 STATIC INLINE BOOL IsArmValidLr(UINTPTR lr)
602 {
603     return ((*(UINT32 *)(lr - BL_CMD_OFFSET) & ARM_BL_MASK) == ARM_BL_MASK);
604 }
605 
IsThumbValidLr(UINTPTR lr)606 STATIC INLINE BOOL IsThumbValidLr(UINTPTR lr)
607 {
608     lr = (*(UINT16 *)(lr - BL_CMD_OFFSET) << THUMB_BIT) + *(UINT16 *)(lr - THUMB_OFFSET);
609     return ((lr & THUMB_BL_MASK) == THUMB_BL_MASK);
610 }
611 
LOS_RecordLR(UINTPTR * LR,UINT32 LRSize,UINT32 jumpCount,UINTPTR SP)612 VOID LOS_RecordLR(UINTPTR *LR, UINT32 LRSize, UINT32 jumpCount, UINTPTR SP)
613 {
614     UINT32 count = 0;
615     UINT32 index = 0;
616     LosTaskCB *taskCB = NULL;
617     UINT32 taskID;
618     UINT32 stackStart, stackEnd;
619     UINTPTR framePtr, tmpFramePtr, linkReg;
620 
621     if (LR == NULL) {
622         return;
623     }
624 
625     if (SP == 0) {
626         SP = OsSpGet();
627     }
628 
629     if (LOS_TaskIsRunning()) {
630         taskID = LOS_CurTaskIDGet();
631         taskCB = OS_TCB_FROM_TID(taskID);
632         stackStart = taskCB->topOfStack;
633         stackEnd = stackStart + taskCB->stackSize;
634     } else {
635         stackStart = CSTACK_START_ADDR;
636         stackEnd = CSTACK_END_ADDR;
637     }
638 
639     while ((SP > stackStart) && (SP < stackEnd)) {
640         linkReg = *(UINTPTR *)SP;
641         if (!OsStackDataIsCodeAddr(linkReg)) {
642             SP += STACK_OFFSET;
643             continue;
644         }
645         if (((!IsAligned(linkReg, ARM_ALIGN_CODE)) || !IsArmValidLr(linkReg)) &&
646             ((!IsAligned(linkReg - 1, THUMB_ALIGN_CODE)) || !IsThumbValidLr(linkReg - 1))) {
647             SP += STACK_OFFSET;
648             continue;
649         }
650         if (index >= jumpCount) {
651             LR[count++] = linkReg & CLEAR_LOW_BIT_MASK;
652             if (count == LRSize) {
653                 break;
654             }
655         }
656         ++index;
657         SP += STACK_OFFSET;
658     }
659 
660     /* if linkReg is not enough,clean up the last of the effective LR as the end. */
661     if (count < LRSize) {
662         LR[count] = 0;
663     }
664 }
665 #else
666 #error Unknown backtrace type.
667 #endif
668 
669 #if (LOSCFG_BACKTRACE_TYPE == 1) || (LOSCFG_BACKTRACE_TYPE == 3)
LOS_RecordLR(UINTPTR * LR,UINT32 LRSize,UINT32 jumpCount,UINTPTR SP)670 VOID LOS_RecordLR(UINTPTR *LR, UINT32 LRSize, UINT32 jumpCount, UINTPTR SP)
671 {
672     if (LR == NULL) {
673         return;
674     }
675 
676     UINTPTR stackStart;
677     UINTPTR stackEnd;
678     UINT32 count = 0;
679     UINT32 index = 0;
680     UINTPTR sp;
681     UINTPTR pc;
682     UINT32 ret;
683 
684     ret = OsStackAddrGet(&stackStart, &stackEnd, SP);
685     if (ret != LOS_OK) {
686         return;
687     }
688 
689     /* Traverse the stack space and find the LR address. */
690     for (sp = stackStart; sp < stackEnd; sp += sizeof(UINTPTR)) {
691         pc = OsAddrIsValid(sp);
692         if ((pc != 0) && (count < LRSize)) {
693             if (index++ < jumpCount) {
694                 continue;
695             }
696             LR[count] = pc;
697             count++;
698             if (count == LRSize) {
699                 break;
700             }
701         }
702     }
703 
704     if (count < LRSize) {
705         LR[count] = 0;
706     }
707 }
708 #endif
709 
LOS_BackTrace(VOID)710 VOID LOS_BackTrace(VOID)
711 {
712     UINTPTR LR[BACKTRACE_MAX_DEPTH] = {0};
713     UINT32 index;
714 
715     LOS_RecordLR(LR, BACKTRACE_MAX_DEPTH, OS_BACKTRACE_START, 0);
716 
717     if (LOS_TaskIsRunning()) {
718         PRINTK("taskName = %s\n", g_losTask.runTask->taskName);
719         PRINTK("taskID   = %u\n", g_losTask.runTask->taskID);
720     }
721 
722     PRINTK("----- traceback start -----\r\n");
723     for (index = 0; index < BACKTRACE_MAX_DEPTH; index++) {
724         if (LR[index] == 0) {
725             break;
726         }
727         PRINTK("traceback %d -- lr = 0x%x\r\n", index, LR[index]);
728     }
729     PRINTK("----- traceback end -----\r\n");
730 }
731 
OsBackTraceInit(VOID)732 VOID OsBackTraceInit(VOID)
733 {
734     OsBackTraceHookSet(LOS_RecordLR);
735 }
736 #endif
737 
738