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