1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - OS
3   File:     os_callTrace.c
4 
5   Copyright 2003-2008 Nintendo.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2009-06-19#$
14   $Rev: 10786 $
15   $Author: okajima_manabu $
16  *---------------------------------------------------------------------------*/
17 #include <nitro/os.h>
18 
19 #if defined(OS_PROFILE_AVAILABLE) && defined(OS_PROFILE_CALL_TRACE)
20 
21 #ifdef OS_NO_CALLTRACE
22 //---- dummy function
__PROFILE_ENTRY(void)23 SDK_WEAK_SYMBOL asm void __PROFILE_ENTRY( void ){  bx   lr }
__PROFILE_EXIT(void)24 SDK_WEAK_SYMBOL asm void __PROFILE_EXIT( void ){   bx   lr }
OS_DumpThreadCallTrace(const OSThread *)25 void OS_DumpThreadCallTrace(const OSThread *)
26 {
27 }
28 #else  // ifdef OS_NO_CALLTRACE
29 
30 //---- function prototype declaration
31 OSCallTraceInfo *OSi_GetCallTraceInfo(void);
32 void    OSi_DumpCurrentLr(u32 lr, int strIndex);
33 void    OSi_DumpOneInfo(OSCallTrace *p);
34 void    OSi_DumpFullInfo(OSCallTraceInfo *info);
35 void    OSi_DumpCallTrace_core(u32 returnAddress);
36 void    OSi_DumpThreadCallTrace_core(const OSThread *thread, u32 returnAddress);
37 void    OSi_Abort_CallTraceFull(u32 name, u32 returnAddress, u32 r0, u32 sp);
38 void    OSi_Abort_CallTraceLess(u32 returnAddress);
39 
40 //---- pointer to callTraceInfo at not using threadSystem
41 static OSCallTraceInfo *OSi_DefaultCallTraceInfo;
42 
43 #define OSi_STR_DUMPCALLTRACE          0
44 #define OSi_STR_DUMPTHREADCALLTRACE    1
45 
46 extern BOOL OSi_IsThreadInitialized;
47 
48 //================================================================================
49 //              ENABLE/DISABLE
50 //================================================================================
51 /*---------------------------------------------------------------------------*
52   Name:         OS_EnableCallTrace
53 
54   Description:  enable callTrace
55 
56   Arguments:    None
57 
58   Returns:      previous status. TRUE if enable
59  *---------------------------------------------------------------------------*/
60 #include <nitro/code32.h>
OS_EnableCallTrace(void)61 asm BOOL OS_EnableCallTrace( void )
62 {
63     //---- check if callTrace not available
64     stmfd   sp!, {lr}
65     bl      OSi_GetCallTraceInfo
66     ldmfd   sp!, {lr}
67     cmp     r0, #0
68     bxeq    lr
69 
70     mov     r2, r0
71     ldrh    r0, [ r2, #OSCallTraceInfo.enable ]
72     mov     r1, #1
73     strh    r1, [ r2, #OSCallTraceInfo.enable ]
74 
75     bx      lr
76 }
77 #include <nitro/codereset.h>
78 
79 /*---------------------------------------------------------------------------*
80   Name:         OS_DisableCallTrace
81 
82   Description:  disble callTrace
83 
84   Arguments:    None
85 
86   Returns:      previous status. TRUE if enable
87  *---------------------------------------------------------------------------*/
88 #include <nitro/code32.h>
OS_DisableCallTrace(void)89 asm BOOL OS_DisableCallTrace( void )
90 {
91     //---- check if callTrace not available
92     stmfd   sp!, {lr}
93     bl      OSi_GetCallTraceInfo
94     ldmfd   sp!, {lr}
95     cmp     r0, #0
96     bxeq    lr
97 
98     mov     r2, r0
99     ldrh    r0, [ r2, #OSCallTraceInfo.enable ]
100     mov     r1, #0
101     strh    r1, [ r2, #OSCallTraceInfo.enable ]
102 
103     bx      lr
104 }
105 #include <nitro/codereset.h>
106 
107 /*---------------------------------------------------------------------------*
108   Name:         OS_RestoreCallTrace
109 
110   Description:  set status of callTrace
111 
112   Arguments:    enable :  TRUE if set to be enable, FALSE if not
113 
114   Returns:      previous status. TRUE if enable
115  *---------------------------------------------------------------------------*/
116 #include <nitro/code32.h>
OS_RestoreCallTrace(BOOL)117 asm BOOL OS_RestoreCallTrace( BOOL )
118 {
119     //---- check if callTrace not available
120     stmfd   sp!, {r0, lr}
121     bl      OSi_GetCallTraceInfo
122     mov     r1, r0
123     ldmfd   sp!, {r0, lr}
124     cmp     r1, #0
125     bxeq    lr
126 
127     ldrh    r2, [ r1, #OSCallTraceInfo.enable ]
128     strh    r0, [ r1, #OSCallTraceInfo.enable ]
129     mov     r0, r2
130 
131     bx      lr
132 }
133 #include <nitro/codereset.h>
134 
135 
136 //================================================================================
137 //              SETTING
138 //================================================================================
139 /*---------------------------------------------------------------------------*
140   Name:         OS_InitCallTrace
141 
142   Description:  Initialize callTrace stack,
143                 and start recording trace.
144 
145   Arguments:    buf     address to record trace infomation
146                 size    size of buffer (by byte)
147 
148   Returns:      None
149  *---------------------------------------------------------------------------*/
150 #pragma profile off
OS_InitCallTrace(void * buf,u32 size,OSCallTraceMode mode)151 void OS_InitCallTrace(void *buf, u32 size, OSCallTraceMode mode)
152 {
153     OSCallTraceInfo **infoPtr;
154 
155     SDK_TASSERTMSG(((u32)buf & 3) == 0, "CallTrace buffer must be aligned by 4");
156     SDK_TASSERTMSG((size >= OSi_TRACEINFO_SIZEOF_HEADERPART + sizeof(OSCallTrace)),
157                   "to small CallTrace buffer");
158 
159 #ifdef SDK_NO_THREAD
160     //---- pointer to callTraceInfo is in static valiable
161     infoPtr = &OSi_DefaultCallTraceInfo;
162 #else
163     SDK_TASSERTMSG(OS_IsThreadAvailable(), "CallTrace need thread system.");
164     //---- pointer to callTraceInfo is in OSThread structure
165     infoPtr = (OSCallTraceInfo **)&(OS_GetCurrentThread()->profiler);
166 #endif
167 
168     *infoPtr = (OSCallTraceInfo *)buf;
169     (*infoPtr)->current = (*infoPtr)->array;
170     (*infoPtr)->limit = (OSCallTrace *)((u32)buf
171                                         + OSi_TRACEINFO_SIZEOF_HEADERPART
172                                         + OS_CalcCallTraceLines(size) * sizeof(OSCallTrace));
173     (*infoPtr)->enable = (u16)TRUE;
174     (*infoPtr)->circular = (u16)mode;
175 #ifdef OS_CALLTRACE_LEVEL_AVAILABLE
176     (*infoPtr)->level = 0;
177 #endif
178 
179     //---- clear buffer if used for logging
180     if (mode == OS_CALLTRACE_LOG)
181     {
182         OS_ClearCallTraceBuffer();
183     }
184 }
185 
186 #pragma profile reset
187 
188 //================================================================================
189 //              UTILITY
190 //================================================================================
191 /*---------------------------------------------------------------------------*
192   Name:         OS_CalcCallTraceLines
193 
194   Description:  calculate number of lines to be able to be allocated
195 
196   Arguments:    size :    CallTrace buffer size
197                           same as argument of OS_InitCallTrace()'s size
198 
199   Returns:      number of lines to be able to allocate in 'size' byte
200  *---------------------------------------------------------------------------*/
OS_CalcCallTraceLines(u32 size)201 int OS_CalcCallTraceLines(u32 size)
202 {
203     int     n = (int)((size - OSi_TRACEINFO_SIZEOF_HEADERPART) / sizeof(OSCallTrace));
204 
205     return (n < 0) ? 0 : n;
206 }
207 
208 /*---------------------------------------------------------------------------*
209   Name:         OS_CalcCallTraceBufferSize
210 
211   Description:  calculate buffer size to allocate specified lines
212 
213   Arguments:    lines :   lines to want to allocate
214 
215   Returns:      buffer size to need
216  *---------------------------------------------------------------------------*/
OS_CalcCallTraceBufferSize(int lines)217 u32 OS_CalcCallTraceBufferSize(int lines)
218 {
219     SDK_ASSERT(lines >= 0);
220     return OSi_TRACEINFO_SIZEOF_HEADERPART + lines * sizeof(OSCallTrace);
221 }
222 
223 /*---------------------------------------------------------------------------*
224   Name:         OS_ClearCallTraceBuffer
225 
226   Description:  clear buffer if used for logging
227 
228   Arguments:    None
229 
230   Returns:      None
231  *---------------------------------------------------------------------------*/
232 #pragma profile off
OS_ClearCallTraceBuffer(void)233 void OS_ClearCallTraceBuffer(void)
234 {
235 
236     OSCallTraceInfo *info = OSi_GetCallTraceInfo();
237 
238     if (info && info->circular)
239     {
240         OSCallTrace *p;
241 
242         info->current = info->array;
243         for (p = info->current; p < info->limit; p++)
244         {
245             p->name = (u32)NULL;
246         }
247     }
248 }
249 
250 #pragma profile reset
251 
252 /*---------------------------------------------------------------------------*
253   Name:         OSi_SetCallTraceEntry
254 
255   Description:  store dummy string pointer
256 
257   Arguments:    name  : pointer to string to be stored as function name
258                 lr    : value to be stored as lr
259 
260   Returns:      None
261  *---------------------------------------------------------------------------*/
262 #pragma profile off
OSi_SetCallTraceEntry(const char * name,u32 lr)263 void OSi_SetCallTraceEntry(const char *name, u32 lr)
264 {
265 
266     OSCallTraceInfo *info = OSi_GetCallTraceInfo();
267 
268     if (info && info->circular)
269     {
270         OSCallTrace *p = info->current;
271 
272         p->name = (u32)name;
273         p->returnAddress = lr;
274 
275 #ifdef OS_CALLTRACE_RECORD_R0
276         p->r0 = 0;
277 #endif
278 #ifdef OS_CALLTRACE_RECORD_R1
279         p->r1 = 0;
280 #endif
281 #ifdef OS_CALLTRACE_RECORD_R2
282         p->r2 = 0;
283 #endif
284 #ifdef OS_CALLTRACE_RECORD_R3
285         p->r3 = 0;
286 #endif
287         p++;
288 
289         if ((u32)p >= (u32)info->limit)
290         {
291             p = info->array;
292         }
293 
294         info->current = p;
295     }
296 }
297 
298 #pragma profile reset
299 
300 /*---------------------------------------------------------------------------*
301   Name:         OSi_GetCallTraceInfo
302 
303   Description:  get pointer to callTraceInfo structure
304 
305   Arguments:    None
306 
307   Returns:      pointer.
308                 NULL if not callTrace initialized
309  *---------------------------------------------------------------------------*/
310 #include <nitro/code32.h>
OSi_GetCallTraceInfo(void)311 asm OSCallTraceInfo* OSi_GetCallTraceInfo( void )
312 {
313 #ifdef SDK_NO_THREAD
314     ldr     r0, =OSi_DefaultCallTraceInfo
315     ldr     r0, [ r0, #0 ]
316     bx      lr
317 #else
318     ldr     r0, =OSi_ThreadInfo
319     ldr     r0, [ r0, #OSThreadInfo.current ]         // r0 = currentThread. 0 if no currentThread
320     cmp     r0, #0
321     ldrne   r0, [ r0, #OSThread.profiler ]            // r0 = callTraceInfo
322     bx      lr
323 #endif
324 }
325 #include <nitro/codereset.h>
326 
327 //================================================================================
328 //              PROFILE
329 //================================================================================
330 /*---------------------------------------------------------------------------*
331   Name:         __PROFILE_ENTRY
332 
333   Description:  entry of function in profiler
334 
335   Arguments:    None
336 
337   Returns:      None
338  *---------------------------------------------------------------------------*/
339 #include <nitro/code32.h>
__PROFILE_ENTRY(void)340 asm void __PROFILE_ENTRY( void )
341 {
342 #ifndef SDK_NO_THREAD
343     stmfd  sp!, {r0}
344     ldr    r0, =OSi_IsThreadInitialized
345     ldr    r0, [ r0, #0 ]
346     cmp    r0, #0
347     ldmfd  sp!, {r0}
348     bxeq   lr
349 #endif
350 
351     stmfd  sp!, {r1-r3}
352 
353     //---- check if callTrace not available
354     stmfd  sp!, {r0, lr}
355     bl     OSi_GetCallTraceInfo
356     mov    r1, r0                                // r1 = callTraceInfo
357     ldmfd  sp!, {r0, lr}
358     cmp    r1, #0
359     beq    _exit
360 
361     //---- check if callTrace master enable
362     ldrh    r2, [ r1, #OSCallTraceInfo.enable ]
363     cmp     r2, #0
364     beq    _exit
365 
366     //---- get currentPtr of CallTrace
367     ldr    r2, [ r1, #OSCallTraceInfo.current ]  // r2 = currentPtr of trace
368     cmp    r2, #0
369     beq    _exit
370 
371     //---- if circular
372     ldrh    r3, [ r1, #OSCallTraceInfo.circular ]
373     cmp     r3, #0
374     bne     _circular_skip_overcheck
375 
376     //---- check if trace buffer is over limit
377 #ifdef OS_CALLTRACE_CHECK_OVERSTACK
378     ldr    r3, [ r1, #OSCallTraceInfo.limit ]
379     cmp    r2, r3
380     ldrpl  r1, [ sp, #16 ] // lr
381     ldrpl  r2, [ sp, #12 ] // r0
382     movpl  r3, sp          // sp ( r1,r2,r3 stored )
383     bpl    OSi_Abort_CallTraceFull
384 #endif
385 
386 _circular_skip_overcheck:
387     //---- store pointer to function name string
388     str    r0, [ r2, #OSCallTrace.name ]
389 
390     //---- store lr register
391     ldr    r0, [ sp, #16 ]
392     str    r0, [ r2, #OSCallTrace.returnAddress ]
393 
394 #ifdef OS_CALLTRACE_RECORD_R0
395     //---- store r0 register
396     ldr    r0, [ sp, #12 ]
397     str    r0, [ r2, #OSCallTrace.r0 ]
398 #endif
399 
400 #ifdef OS_CALLTRACE_RECORD_R1
401     //---- store r1 register
402     ldr    r0, [ sp, #0 ]
403     str    r0, [ r2, #OSCallTrace.r1 ]
404 #endif
405 
406 #ifdef OS_CALLTRACE_RECORD_R2
407     //---- store r2 register
408     ldr    r0, [ sp, #4 ]
409     str    r0, [ r2, #OSCallTrace.r2 ]
410 #endif
411 
412 #ifdef OS_CALLTRACE_RECORD_R3
413     //---- store r3 register
414     ldr    r0, [ sp, #8 ]
415     str    r0, [ r2, #OSCallTrace.r3 ]
416 #endif
417 
418 #ifdef OS_CALLTRACE_LEVEL_AVAILABLE
419     //---- store call level
420     ldr    r0, [ r1, #OSCallTraceInfo.level ]
421     str    r0, [ r2, #OSCallTrace.level ]
422     add    r0, r0, #1
423     str    r0, [ r1, #OSCallTraceInfo.level ]
424 #endif
425 
426     //---- increment pointer
427     add    r2, r2, #OSi_SIZEOF_CALLTRACE
428 
429     //---- if circular then buffer is ring-buf
430     ldrh   r3, [ r1, #OSCallTraceInfo.circular ]
431     cmp    r3, #0
432     beq    _notcircular_skip_ring
433     ldr    r3, [ r1, #OSCallTraceInfo.limit ]
434     cmp    r2, r3
435     bmi    _store_current
436     add    r2, r1, #OSCallTraceInfo.array
437 
438 _notcircular_skip_ring:
439 _store_current:
440     str    r2, [ r1, #OSCallTraceInfo.current ]
441 
442 _exit:
443     ldmfd  sp!, {r1-r3}
444     bx     lr
445 }
446 #include <nitro/codereset.h>
447 
448 /*---------------------------------------------------------------------------*
449   Name:         __PROFILE_EXIT
450 
451   Description:  exit of function in profiler
452 
453   Arguments:    None
454 
455   Returns:      None
456  *---------------------------------------------------------------------------*/
457 #include <nitro/code32.h>
__PROFILE_EXIT(void)458 asm void __PROFILE_EXIT( void )
459 {
460 #ifdef OS_CALLTRACE_CHECK_OVERSTACK
461     stmfd  sp!, {r0-r2, lr}
462 #else
463     stmfd  sp!, {r0-r1, lr}
464 #endif
465 
466 #ifndef SDK_NO_THREAD
467     ldr    r0, =OSi_IsThreadInitialized
468     ldr    r0, [ r0, #0 ]
469     cmp    r0, #0
470     beq    _exit
471 #endif
472 
473     //---- check if callTrace not available
474     bl     OSi_GetCallTraceInfo
475     cmp    r0, #0
476     beq    _exit
477 
478     //---- check if callTrace master enable
479     ldrh    r1, [ r0, #OSCallTraceInfo.enable ]
480     cmp     r1, #0
481     beq     _exit
482 
483 #ifdef OS_CALLTRACE_LEVEL_AVAILABLE
484     //---- decrement level
485     ldr     r1, [ r0, #OSCallTraceInfo.level ]
486     sub     r1, r1, #1
487     movmi   r1, #0
488     str     r1, [ r0, #OSCallTraceInfo.level ]
489 #endif
490 
491     //---- if circular then do nothing
492     ldrh    r1, [ r0, #OSCallTraceInfo.circular ]
493     cmp     r1, #0
494     bne     _exit
495 
496     //---- decrement current pointer
497     ldr    r1, [ r0, #OSCallTraceInfo.current ]        // r1 = current
498     sub    r1, r1, #OSi_SIZEOF_CALLTRACE
499 
500     //---- check if trace buffer is over limit
501 #ifdef OS_CALLTRACE_CHECK_OVERSTACK
502     add    r2, r0, #OSCallTraceInfo.array
503 
504     cmp    r1, r2
505     ldrmi  r0, [ sp, #12 ] // lr
506     bmi    OSi_Abort_CallTraceLess
507 #endif
508 
509     //---- store current pointer
510     str    r1, [ r0, #OSCallTraceInfo.current ]
511 
512 _exit:
513 #ifdef OS_CALLTRACE_CHECK_OVERSTACK
514     ldmfd  sp!, {r0-r2, lr}
515 #else
516     ldmfd  sp!, {r0-r1, lr}
517 #endif
518     bx     lr
519 }
520 #include <nitro/codereset.h>
521 
522 //================================================================================
523 //              DUMP
524 //================================================================================
525 /*---------------------------------------------------------------------------*
526   Name:         OSi_DumpCurrentLr
527 
528   Description:  dump current lr register
529 
530   Arguments:    lr     value of lr register
531 
532   Returns:      None
533  *---------------------------------------------------------------------------*/
534 const char *OSi_DumpCurrentLr_str[] = {
535     "OS_DumpCallTrace", "OS_DumpThreadCallTrace",
536 };
537 #pragma profile off
OSi_DumpCurrentLr(u32 lr,int strIndex)538 void OSi_DumpCurrentLr(u32 lr, int strIndex)
539 {
540     BOOL    e = OS_DisableCallTrace();
541     OS_TPrintf("%s: lr=%08x\n", OSi_DumpCurrentLr_str[strIndex], lr);
542     (void)OS_RestoreCallTrace(e);
543 }
544 
545 #pragma profile reset
546 
547 /*---------------------------------------------------------------------------*
548   Name:         OSi_DumpOneInfo
549 
550   Description:  dump one OSCallTrace line
551                 normaly, only call from OSi_DumpFullInfo
552 
553   Arguments:    p    OSCallTrace pointer
554 
555   Returns:      None
556  *---------------------------------------------------------------------------*/
557 #pragma profile off
558 #define OSi_CALLTRACE_MAX_INDENT 10
OSi_DumpOneInfo(OSCallTrace * p)559 void OSi_DumpOneInfo(OSCallTrace *p)
560 {
561 
562 #ifdef OS_CALLTRACE_LEVEL_AVAILABLE
563     {
564         int     n = (int)p->level;
565         if (n > OSi_CALLTRACE_MAX_INDENT)
566         {
567             n = OSi_CALLTRACE_MAX_INDENT;
568         }
569 
570         while (n)
571         {
572             int     space = n;
573             if (space >= 10)
574             {
575                 space = 10;
576             }
577             OS_TPrintf("%s", &("          \0"[10 - space]));
578             n -= space;
579         }
580     }
581 #endif
582 
583     OS_TPrintf("%s: lr=%08x"
584 #ifdef OS_CALLTRACE_RECORD_R0
585               ", r0=%08x"
586 #endif
587 #ifdef OS_CALLTRACE_RECORD_R1
588               ", r1=%08x"
589 #endif
590 #ifdef OS_CALLTRACE_RECORD_R2
591               ", r2=%08x"
592 #endif
593 #ifdef OS_CALLTRACE_RECORD_R3
594               ", r3=%08x"
595 #endif
596               "\n", (char *)(p->name), p->returnAddress
597 #ifdef OS_CALLTRACE_RECORD_R0
598               , p->r0
599 #endif
600 #ifdef OS_CALLTRACE_RECORD_R1
601               , p->r1
602 #endif
603 #ifdef OS_CALLTRACE_RECORD_R2
604               , p->r2
605 #endif
606 #ifdef OS_CALLTRACE_RECORD_R3
607               , p->r3
608 #endif
609         );
610 }
611 
612 #pragma profile reset
613 
614 /*---------------------------------------------------------------------------*
615   Name:         OSi_DumpFullInfo
616 
617   Description:  dump one OSCallTrace line
618                 normaly, only call from OSi_DumpCallTrace_core and OSi_DumpThreadCallTrace_core
619 
620   Arguments:    info    OSCallTraceInfo pointer
621 
622   Returns:      None
623  *---------------------------------------------------------------------------*/
624 #pragma profile off
OSi_DumpFullInfo(OSCallTraceInfo * info)625 void OSi_DumpFullInfo(OSCallTraceInfo *info)
626 {
627     if (info && info->current)
628     {
629         OSCallTrace *p = info->current - 1;
630 
631         while (1)
632         {
633             if (info->circular && (u32)p < (u32)info->array)
634             {
635                 p = info->limit - 1;
636             }
637 
638             if ((u32)p < (u32)info->array
639                 || 0x2000000 > (u32)(p->name) || 0x2400000 < (u32)(p->name))
640             {
641                 break;
642             }
643 
644             OSi_DumpOneInfo(p);
645 
646             if ((u32)p == (u32)(info->current))
647             {
648                 break;
649             }
650 
651             p--;
652         }
653     }
654 }
655 
656 #pragma profile reset
657 
658 
659 /*---------------------------------------------------------------------------*
660   Name:         OS_DumpCallTrace
661 
662   Description:  dump callStack
663 
664   Arguments:    None
665 
666   Returns:      None
667  *---------------------------------------------------------------------------*/
668 #include <nitro/code32.h>
OS_DumpCallTrace(void)669 asm void OS_DumpCallTrace( void )
670 {
671     mov    r0, lr
672     b      OSi_DumpCallTrace_core
673 
674     // no 'bx lr'
675 }
676 #include <nitro/codereset.h>
677 
678 /*---------------------------------------------------------------------------*
679   Name:         OSi_DumpCallTrace_core
680 
681   Description:  dump callTrace (core function)
682 
683   Arguments:    returnAddress :  lr (for display)
684 
685   Returns:      None
686  *---------------------------------------------------------------------------*/
687 #pragma profile off
OSi_DumpCallTrace_core(u32 returnAddress)688 void OSi_DumpCallTrace_core(u32 returnAddress)
689 {
690     BOOL    e = OS_DisableCallTrace();
691 
692     OSCallTraceInfo *info = OSi_GetCallTraceInfo();
693     SDK_TASSERTMSG(info && info->current, "Not Initialize functionTrace");
694 
695     if (returnAddress)
696     {
697         OSi_DumpCurrentLr(returnAddress, OSi_STR_DUMPCALLTRACE);
698     }
699     OSi_DumpFullInfo(info);
700 
701     (void)OS_RestoreCallTrace(e);
702 }
703 
704 #pragma profile reset
705 
706 /*---------------------------------------------------------------------------*
707   Name:         OS_DumpThreadCallTrace
708 
709   Description:  dump callTrace of thread
710 
711   Arguments:    thread :    thread
712 
713   Returns:      None
714  *---------------------------------------------------------------------------*/
715 #include <nitro/code32.h>
OS_DumpThreadCallTrace(const OSThread * thread)716 asm void OS_DumpThreadCallTrace( const OSThread* thread )
717 {
718     mov   r1, lr
719     b     OSi_DumpThreadCallTrace_core
720 
721     // no 'bx lr'
722 }
723 #include <nitro/codereset.h>
724 
725 /*---------------------------------------------------------------------------*
726   Name:         OSi_DumpThreadCallTrace_core
727 
728   Description:  dump callTrace of thread
729 
730   Arguments:    thread :         thread
731                 returnAddress :  lr (for display)
732 
733   Returns:      None
734  *---------------------------------------------------------------------------*/
OSi_DumpThreadCallTrace_core(const OSThread * thread,u32 returnAddress)735 void OSi_DumpThreadCallTrace_core(const OSThread *thread, u32 returnAddress)
736 {
737     OSCallTraceInfo *info;
738     BOOL    e;
739 
740 #ifdef SDK_NO_THREAD
741     return;
742 #endif
743 
744     //---- null means current thread
745     if (!thread)
746     {
747         thread = OS_GetCurrentThread();
748     }
749 
750     //---- get callTraceInfo
751     if (thread)
752     {
753         info = (OSCallTraceInfo *)thread->profiler;
754     }
755 
756     //---- check callTraceInfo available
757     if (!thread || !info || !info->current)
758     {
759         return;
760     }
761 
762     //---- arrange returnAddress
763     if (thread != OS_GetCurrentThread())
764     {
765         returnAddress = thread->context.r[14];
766     }
767 
768     e = OS_DisableCallTrace();
769 
770     if (returnAddress)
771     {
772         OSi_DumpCurrentLr(returnAddress, OSi_STR_DUMPTHREADCALLTRACE);
773     }
774     OSi_DumpFullInfo(info);
775 
776     (void)OS_RestoreCallTrace(e);
777 }
778 
779 //================================================================================
780 //              ERROR ABORT
781 //================================================================================
782 /*---------------------------------------------------------------------------*
783   Name:         OSi_Abort_CallTraceFull
784 
785   Description:  display error in stack overflow
786 
787   Arguments:    name            function name pointer
788                 returnAddress   lr
789                 r0              r0 (if use)
790 
791   Returns:      None
792  *---------------------------------------------------------------------------*/
793 #pragma profile off
OSi_Abort_CallTraceFull(u32 name,u32 returnAddress,u32 r0,u32 sp)794 void OSi_Abort_CallTraceFull(u32 name, u32 returnAddress, u32 r0, u32 sp)
795 {
796 #pragma unused( r0 )
797 
798     BOOL    e = OS_DisableCallTrace(); // not restore status in this function.
799 
800     OS_TPrintf("***Error: CallTrace stack overflow");
801     OS_TPrintf(" in %s: lr=%08x"
802 #ifdef OS_CALLTRACE_RECORD_R0
803               ", r0=%08x"
804 #endif
805 #ifdef OS_CALLTRACE_RECORD_R1
806               ", r1=%08x"
807 #endif
808 #ifdef OS_CALLTRACE_RECORD_R2
809               ", r2=%08x"
810 #endif
811 #ifdef OS_CALLTRACE_RECORD_R3
812               ", r3=%08x"
813 #endif
814               "\n", (char *)(name), returnAddress
815 #ifdef OS_CALLTRACE_RECORD_R0
816               , r0
817 #endif
818 #ifdef OS_CALLTRACE_RECORD_R1
819               , *((u32 *)sp)
820 #endif
821 #ifdef OS_CALLTRACE_RECORD_R2
822               , *((u32 *)sp + 1)
823 #endif
824 #ifdef OS_CALLTRACE_RECORD_R3
825               , *((u32 *)sp + 2)
826 #endif
827         );
828 
829 #ifdef SDK_NO_THREAD
830     OSi_DumpCallTrace_core(0);
831 #else
832     OSi_DumpThreadCallTrace_core(NULL, 0);
833 #endif
834 
835     OS_Terminate();
836 }
837 
838 #pragma profile reset
839 
840 /*---------------------------------------------------------------------------*
841   Name:         OSi_Abort_CallTraceLess
842 
843   Description:  display error in stack underflow
844 
845   Arguments:    returnAddress   lr
846 
847   Returns:      None
848  *---------------------------------------------------------------------------*/
849 #pragma profile off
OSi_Abort_CallTraceLess(u32 returnAddress)850 void OSi_Abort_CallTraceLess(u32 returnAddress)
851 {
852     BOOL    e = OS_DisableCallTrace(); // not restore status in this function.
853 
854     OS_TPrintf("***Error: CallTrace stack underflow.");
855     OS_TPrintf(" (lr=%08x)\n", returnAddress);
856 
857     OS_Terminate();
858 }
859 
860 #pragma profile reset
861 
862 #endif // ifdef OS_NO_CALLTRACE
863 #endif // defined(OS_PROFILE_AVAILABLE) && defined(OS_PROFILE_CALL_TRACE)
864