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