1 //==========================================================================
5 // Memory buffered trace and assert functions
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
44 // Contributors: nickg
46 // Purpose: Buffered Trace and assert functions
47 // Description: The functions in this file are a buffered implementation
48 // of the standard trace and assert functions. These store
49 // trace messages in a memory buffer and emit them when an
50 // assert is hit, or when requested to.
52 //####DESCRIPTIONEND####
54 //==========================================================================
56 #include <pkgconf/system.h>
57 #include <pkgconf/infra.h>
59 #ifdef CYGDBG_INFRA_DEBUG_TRACE_ASSERT_BUFFER
61 #include <cyg/infra/cyg_type.h> // base types
62 #include <cyg/infra/cyg_trac.h> // tracing macros
63 #include <cyg/infra/cyg_ass.h> // assertion macros
65 #include <pkgconf/hal.h> // HAL configury
66 #include <cyg/infra/diag.h> // HAL polled output
67 #include <cyg/hal/hal_arch.h> // architectural stuff for...
68 #include <cyg/hal/hal_intr.h> // interrupt control
71 #include <pkgconf/kernel.h> // kernel configury
72 #include <cyg/kernel/thread.hxx> // thread id to print
73 #include <cyg/kernel/sched.hxx> // ancillaries for above
74 #include <cyg/kernel/thread.inl> // ancillaries for above
77 // -------------------------------------------------------------------------
78 // Local Configuration: hack me!
80 // these are generally:
81 // if 0, feature is disabled
82 // if 1, feature is enabled, printing is default width
83 // if >1, field is padded up to that width if necessary
84 // (not truncated ever)
86 #define CYG_FILENAME 20
87 #define CYG_THREADID 1
89 #define CYG_FUNCNAME 100
90 #define CYG_DIAG_PRINTF 1
91 #define CYG_FUNC_INDENT 2
95 # define CYG_THREADID 0
99 #define CYG_FBUF_SIZE 100
101 #define CYG_FBUF_SIZE (CYG_FUNCNAME+20)
104 // -------------------------------------------------------------------------
107 #ifdef CYGDBG_USE_TRACING
109 struct Cyg_TraceRecord
113 const char *function;
121 Cyg_TraceRecord cyg_infra_trace_buffer[CYGDBG_INFRA_DEBUG_TRACE_BUFFER_SIZE];
123 static cyg_uint32 cyg_infra_trace_buffer_pos = 0;
125 static cyg_bool cyg_infra_trace_buffer_enable = true;
127 static cyg_bool cyg_infra_trace_buffer_wrap = false;
129 // -------------------------------------------------------------------------
130 // Functions to trim file names and function names down to printable lengths
131 // (these are shared between trace and assert functions)
134 static char * tracepremsgs[] = {
143 static char * tracepremsgs[] = {
151 static char * tracepostmsgs[] = {
160 write_whattrace( cyg_uint32 what )
163 static cyg_int32 cyg_indent = 0;
165 cyg_indent -= CYG_FUNC_INDENT;
166 cyg_int32 i = cyg_indent;
168 diag_write_string( " " );
169 #endif // CYG_FUNC_INDENT
170 diag_write_string( tracepremsgs[ what > 4 ? 4 : what ] );
173 cyg_indent += CYG_FUNC_INDENT;
174 #endif // CYG_FUNC_INDENT
178 write_whattracepost( cyg_uint32 what )
180 diag_write_string( tracepostmsgs[ what > 4 ? 4 : what ] );
184 #endif // CYGDBG_USE_TRACING
186 // -------------------------------------------------------------------------
188 #if defined(CYGDBG_USE_TRACING) || defined(CYGDBG_USE_ASSERTS)
190 static const char *trim_file(const char *file)
196 #if 1 == CYG_FILENAME
197 const char *f = file;
199 while( *f != '/' && f != file ) f--;
200 return f==file?f:(f+1);
202 static char fbuf2[100];
203 const char *f = file;
206 while( *f != '/' && f != file ) f--;
208 while( *f ) *g++ = *f++;
209 while( CYG_FILENAME > (g - fbuf2) ) *g++ = ' ';
218 static const char *trim_func(const char *func)
221 static char fbuf[CYG_FBUF_SIZE];
227 for( i = 0; func[i] && func[i] != '(' && i < CYG_FBUF_SIZE-4 ; i++ )
234 #if 1 == CYG_FUNCNAME
239 while ( CYG_FUNCNAME > (p - (&fbuf[i])) ) *p++ = ' ';
248 static void write_lnum( cyg_uint32 lnum)
251 diag_write_char('[');
254 for ( i = 2, j = 100; i < CYG_LINENUM ; i++, j *= 10 )
256 diag_write_char(' ');
258 diag_write_dec(lnum);
259 diag_write_char(']');
260 diag_write_char(' ');
264 #endif // defined(CYGDBG_USE_TRACING) || defined(CYGDBG_USE_ASSERTS)
266 // -------------------------------------------------------------------------
268 #if defined(CYGDBG_USE_TRACING) || defined(CYGDBG_USE_ASSERTS)
271 static cyg_uint32 get_tid(void)
274 Cyg_Thread *t = Cyg_Thread::self();
275 cyg_uint16 tid = 0xFFFF;
277 if( t != NULL ) tid = t->get_unique_id();
282 # define get_tid() (0xFFFF)
285 #endif // defined(CYGDBG_USE_TRACING) || defined(CYGDBG_USE_ASSERTS)
287 #ifdef CYGDBG_USE_ASSERTS
288 static void write_thread_id()
291 cyg_uint16 tid = get_tid();
293 diag_write_char('<');
295 diag_write_char('>');
300 // -------------------------------------------------------------------------
303 #ifdef CYGDBG_USE_TRACING
305 static void print_trace_buffer(void)
307 cyg_count32 start = cyg_infra_trace_buffer_pos;
308 cyg_count32 end = start;
311 // If the buffer has wrapped we want to display the records from
312 // the current pos and around back to the same place. If the buffer
313 // has not wrapped, we want to display from the start to pos.
315 if( !cyg_infra_trace_buffer_wrap )
321 Cyg_TraceRecord *rec = &cyg_infra_trace_buffer[i];
324 const char *psz_msg = rec->message;
327 HAL_DISABLE_INTERRUPTS(old_ints);
328 DIAG_DEVICE_START_SYNC();
330 if ( NULL == psz_msg )
333 diag_write_string( "TRACE: " );
335 diag_write_char('<');
336 diag_write_hex(rec->tid);
337 diag_write_char('>');
339 diag_write_string(trim_file(rec->file));
340 write_lnum(rec->line);
341 diag_write_string(trim_func(rec->function));
342 diag_write_char(' ');
343 write_whattrace( rec->what );
345 diag_printf( psz_msg,
346 rec->arg[0], rec->arg[1],
347 rec->arg[2], rec->arg[3],
348 rec->arg[4], rec->arg[5],
349 rec->arg[6], rec->arg[7] );
351 diag_write_string(psz_msg);
352 diag_write_char(' ');
354 for( cyg_count8 j = 0; j < rec->narg ; j++ )
356 diag_write_hex(rec->arg[j]);
357 diag_write_char(' ');
360 write_whattracepost( rec->what );
361 diag_write_char('\n');
363 DIAG_DEVICE_END_SYNC();
364 HAL_RESTORE_INTERRUPTS(old_ints);
367 if( i == CYGDBG_INFRA_DEBUG_TRACE_BUFFER_SIZE )
374 static void increment_buffer_pos()
376 cyg_infra_trace_buffer_pos++;
378 if( cyg_infra_trace_buffer_pos == CYGDBG_INFRA_DEBUG_TRACE_BUFFER_SIZE )
380 #if defined(CYGDBG_INFRA_DEBUG_TRACE_BUFFER_WRAP)
381 cyg_infra_trace_buffer_pos = 0;
382 cyg_infra_trace_buffer_wrap = true;
383 #elif defined(CYGDBG_INFRA_DEBUG_TRACE_BUFFER_HALT)
384 cyg_infra_trace_buffer_enable = false;
385 #elif defined(CYGDBG_INFRA_DEBUG_TRACE_BUFFER_PRINT)
386 cyg_infra_trace_buffer_pos = 0;
387 print_trace_buffer();
389 #error No trace buffer full mode set
395 // -------------------------------------------------------------------------
398 cyg_tracenomsg( const char *psz_func, const char *psz_file, cyg_uint32 linenum )
402 if( !cyg_infra_trace_buffer_enable ) return;
404 HAL_DISABLE_INTERRUPTS(old_ints);
406 Cyg_TraceRecord *rec = &cyg_infra_trace_buffer[cyg_infra_trace_buffer_pos];
409 rec->tid = get_tid();
410 rec->function = psz_func;
411 rec->file = psz_file;
416 increment_buffer_pos();
418 HAL_RESTORE_INTERRUPTS(old_ints);
422 // provide every other one of these as a space/caller bloat compromise.
425 cyg_tracemsg( cyg_uint32 what,
426 const char *psz_func, const char *psz_file, cyg_uint32 linenum,
427 const char *psz_msg )
431 if( !cyg_infra_trace_buffer_enable ) return;
433 HAL_DISABLE_INTERRUPTS(old_ints);
435 Cyg_TraceRecord *rec = &cyg_infra_trace_buffer[cyg_infra_trace_buffer_pos];
438 rec->tid = get_tid();
439 rec->function = psz_func;
440 rec->file = psz_file;
442 rec->message = psz_msg;
445 increment_buffer_pos();
447 HAL_RESTORE_INTERRUPTS(old_ints);
452 cyg_tracemsg2( cyg_uint32 what,
453 const char *psz_func, const char *psz_file, cyg_uint32 linenum,
455 CYG_ADDRWORD arg0, CYG_ADDRWORD arg1 )
459 if( !cyg_infra_trace_buffer_enable ) return;
461 HAL_DISABLE_INTERRUPTS(old_ints);
463 Cyg_TraceRecord *rec = &cyg_infra_trace_buffer[cyg_infra_trace_buffer_pos];
466 rec->tid = get_tid();
467 rec->function = psz_func;
468 rec->file = psz_file;
470 rec->message = psz_msg;
476 increment_buffer_pos();
478 HAL_RESTORE_INTERRUPTS(old_ints);
482 cyg_tracemsg4( cyg_uint32 what,
483 const char *psz_func, const char *psz_file, cyg_uint32 linenum,
485 CYG_ADDRWORD arg0, CYG_ADDRWORD arg1,
486 CYG_ADDRWORD arg2, CYG_ADDRWORD arg3 )
490 if( !cyg_infra_trace_buffer_enable ) return;
492 HAL_DISABLE_INTERRUPTS(old_ints);
494 Cyg_TraceRecord *rec = &cyg_infra_trace_buffer[cyg_infra_trace_buffer_pos];
497 rec->tid = get_tid();
498 rec->function = psz_func;
499 rec->file = psz_file;
501 rec->message = psz_msg;
509 increment_buffer_pos();
511 HAL_RESTORE_INTERRUPTS(old_ints);
515 cyg_tracemsg6( cyg_uint32 what,
516 const char *psz_func, const char *psz_file, cyg_uint32 linenum,
518 CYG_ADDRWORD arg0, CYG_ADDRWORD arg1,
519 CYG_ADDRWORD arg2, CYG_ADDRWORD arg3,
520 CYG_ADDRWORD arg4, CYG_ADDRWORD arg5 )
524 if( !cyg_infra_trace_buffer_enable ) return;
526 HAL_DISABLE_INTERRUPTS(old_ints);
528 Cyg_TraceRecord *rec = &cyg_infra_trace_buffer[cyg_infra_trace_buffer_pos];
531 rec->tid = get_tid();
532 rec->function = psz_func;
533 rec->file = psz_file;
535 rec->message = psz_msg;
545 increment_buffer_pos();
547 HAL_RESTORE_INTERRUPTS(old_ints);
551 cyg_tracemsg8( cyg_uint32 what,
552 const char *psz_func, const char *psz_file, cyg_uint32 linenum,
554 CYG_ADDRWORD arg0, CYG_ADDRWORD arg1,
555 CYG_ADDRWORD arg2, CYG_ADDRWORD arg3,
556 CYG_ADDRWORD arg4, CYG_ADDRWORD arg5,
557 CYG_ADDRWORD arg6, CYG_ADDRWORD arg7 )
561 if( !cyg_infra_trace_buffer_enable ) return;
563 HAL_DISABLE_INTERRUPTS(old_ints);
565 Cyg_TraceRecord *rec = &cyg_infra_trace_buffer[cyg_infra_trace_buffer_pos];
568 rec->tid = get_tid();
569 rec->function = psz_func;
570 rec->file = psz_file;
572 rec->message = psz_msg;
584 increment_buffer_pos();
586 HAL_RESTORE_INTERRUPTS(old_ints);
589 // -------------------------------------------------------------------------
592 cyg_trace_print(void)
594 cyg_bool old_enable = cyg_infra_trace_buffer_enable;
595 cyg_infra_trace_buffer_enable = false;
596 print_trace_buffer();
597 cyg_infra_trace_buffer_pos = 0;
598 cyg_infra_trace_buffer_wrap = false;
599 cyg_infra_trace_buffer_enable = old_enable;
603 // -------------------------------------------------------------------------
608 #if defined(CYGPKG_KERNEL) && defined(CYG_DIAG_PRINTF)
611 diag_printf("\nScheduler:\n\n");
613 Cyg_Scheduler *sched = &Cyg_Scheduler::scheduler;
615 diag_printf("Lock: %d\n",sched->get_sched_lock() );
617 # ifdef CYGVAR_KERNEL_THREADS_NAME
619 diag_printf("Current Thread: %s\n",sched->get_current_thread()->get_name());
623 diag_printf("Current Thread: %d\n",sched->get_current_thread()->get_unique_id());
629 # ifdef CYGVAR_KERNEL_THREADS_LIST
632 Cyg_Thread *t = Cyg_Thread::get_list_head();
634 diag_printf("\nThreads:\n\n");
638 cyg_uint32 state = t->get_state();
640 char *tstate1 = "SCUKX";
641 static char *(reasons[8]) =
643 "NONE", // No recorded reason
644 "WAIT", // Wait with no timeout
645 "DELAY", // Simple time delay
646 "TIMEOUT", // Wait with timeout/timeout expired
647 "BREAK", // forced break out of sleep
648 "DESTRUCT", // wait object destroyed[note]
649 "EXIT", // forced termination
650 "DONE" // Wait/delay complete
655 // Knock out chars that do not correspond to set bits.
656 for( int i = 0; i < 6 ; i++ )
657 if( 0 == (state & (1<<i)) )
659 else tstate[i] = tstate1[i];
662 else tstate[0] = 'R', tstate[1] = 0;
664 # ifdef CYGVAR_KERNEL_THREADS_NAME
666 diag_printf( "%20s pri = %3d state = %6s id = %3d\n",
674 diag_printf( "Thread %3d pri = %3d state = %6s\n",
681 diag_printf( "%20s stack base = %08x ptr = %08x size = %08x\n",
684 #ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
685 t->get_saved_context(),
692 diag_printf( "%20s sleep reason %8s wake reason %8s\n",
694 reasons[t->get_sleep_reason()],
695 reasons[t->get_wake_reason()]
698 diag_printf( "%20s queue = %08x wait info = %08x\n",
700 t->get_current_queue(),
705 t = t->get_list_next();
709 # endif // CYGVAR_KERNEL_THREADS_LIST
711 #endif // CYG_DIAG_PRINTF
714 #endif // CYGDBG_USE_TRACING
716 // -------------------------------------------------------------------------
719 #ifdef CYGDBG_USE_ASSERTS
722 cyg_assert_fail( const char *psz_func, const char *psz_file,
723 cyg_uint32 linenum, const char *psz_msg ) __THROW
727 HAL_DISABLE_INTERRUPTS(old_ints);
728 DIAG_DEVICE_START_SYNC();
730 diag_write_string("ASSERT FAIL: ");
732 diag_write_string(trim_file(psz_file));
734 diag_write_string(trim_func(psz_func));
735 diag_write_char(' ');
736 diag_write_string(psz_msg);
737 diag_write_char('\n');
739 #ifdef CYGDBG_INFRA_DEBUG_TRACE_BUFFER_PRINT_ON_ASSERT
746 #ifdef CYGHWR_TEST_PROGRAM_EXIT
747 CYGHWR_TEST_PROGRAM_EXIT();
751 // DIAG_DEVICE_END_SYNC();
752 // HAL_RESTORE_INTERRUPTS(old_ints);
757 extern unsigned long _stext;
758 extern unsigned long _etext;
760 unsigned long stext_addr = (unsigned long)&_stext;
761 unsigned long etext_addr = (unsigned long)&_etext;
764 externC cyg_bool cyg_check_data_ptr(const void *ptr)
766 unsigned long p = (unsigned long)ptr;
768 if( p == 0 ) return false;
770 if( p > stext_addr && p < etext_addr ) return false;
775 externC cyg_bool cyg_check_func_ptr(void (*ptr)(void))
777 unsigned long p = (unsigned long)ptr;
779 if( p == 0 ) return false;
781 if( p < stext_addr && p > etext_addr ) return false;
786 #endif // CYGDBG_USE_ASSERTS
788 #endif // CYGDBG_INFRA_DEBUG_TRACE_ASSERT_BUFFER
790 // -------------------------------------------------------------------------