kerneltest/e32test/nkernsa/kprintf.cpp
changeset 0 a41df078684a
child 90 947f0dc9f7a8
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32test\nkernsa\kprintf.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #define __E32CMN_H__
       
    19 #include <nktest/utils.h>
       
    20 #include "nk_priv.h"
       
    21 
       
    22 #undef EXPORT_C
       
    23 #define EXPORT_C /* */
       
    24 
       
    25 class TVersion
       
    26 	{
       
    27 public:
       
    28 	TInt8 iMajor;
       
    29 	TInt8 iMinor;
       
    30 	TInt16 iBuild;
       
    31 	};
       
    32 
       
    33 class TDesC;
       
    34 
       
    35 #include <e32rom.h>
       
    36 
       
    37 extern void DebugPrint(const char*, int);
       
    38 
       
    39 /**
       
    40 Returns the active debug mask obtained by logically ANDing the global debug mask
       
    41 in the super page with the per-thread debug mask in the current DThread object.
       
    42 
       
    43 If the current thread is not a symbian OS thread the global debug mask is used.
       
    44 
       
    45 Only supports the first 32 global debug trace bits.
       
    46 
       
    47 @return The debug mask.
       
    48 */
       
    49 extern "C" {
       
    50 extern TLinAddr RomHeaderAddress;
       
    51 }
       
    52 EXPORT_C TInt KDebugMask()
       
    53 	{
       
    54 	const TRomHeader& rh = *(const TRomHeader*)RomHeaderAddress;
       
    55 	return rh.iTraceMask[0];
       
    56 	}
       
    57 
       
    58 
       
    59 
       
    60 /**
       
    61 Returns the state (ETrue or EFalse) of given bit in the active debug mask
       
    62 which is obtained by logically ANDing the global debug mask in the super page 
       
    63 with the per-thread debug mask in the current DThread object.
       
    64 
       
    65 If the current thread is not a symbian OS thread the global debug mask is used.
       
    66 
       
    67 @return The state of the debug mask bit number.
       
    68 */
       
    69 
       
    70 EXPORT_C TBool KDebugNum(TInt aBitNum)
       
    71 	{
       
    72 #if 1
       
    73 	const TRomHeader& rh = *(const TRomHeader*)RomHeaderAddress;
       
    74 	TInt m = 0;
       
    75 
       
    76 	// special case for KALWAYS
       
    77 	if (aBitNum == KALWAYS)
       
    78 		{
       
    79 		m = rh.iTraceMask[0] ||
       
    80 			rh.iTraceMask[1] ||
       
    81 			rh.iTraceMask[2] ||
       
    82 			rh.iTraceMask[3] ||
       
    83 			rh.iTraceMask[4] ||
       
    84 			rh.iTraceMask[5] ||
       
    85 			rh.iTraceMask[6] ||
       
    86 		    rh.iTraceMask[7];
       
    87 		}
       
    88 	else if  ( (aBitNum > KMAXTRACE) || (aBitNum < 0) )
       
    89 		m = 0;
       
    90 	else
       
    91 		{
       
    92 		TInt index = aBitNum >> 5;
       
    93 		m = rh.iTraceMask[index];
       
    94 		m &= 1 << (aBitNum & 31);
       
    95 		}
       
    96 
       
    97 	return (m != 0);
       
    98 #else
       
    99 	return 1;
       
   100 #endif
       
   101 	}
       
   102 
       
   103 extern "C" unsigned int strlen(const char* s)
       
   104 	{
       
   105 	const char* s0 = s;
       
   106 	while(*s++) {}
       
   107 	return s - s0 - 1;
       
   108 	}
       
   109 
       
   110 int appendstr(char* out, int outlen, const char* s)
       
   111 	{
       
   112 	if (!s)
       
   113 		s = "NULL";
       
   114 	char* d = out + outlen;
       
   115 	while(*s)
       
   116 		*d++ = *s++;
       
   117 	return d - out;
       
   118 	}
       
   119 
       
   120 int AppendNumBase10U(char* out, unsigned int val, int width, int fill)
       
   121 	{
       
   122 	int len = 10;
       
   123 	if (val < 10)
       
   124 		len = 1;
       
   125 	else if (val < 100)
       
   126 		len = 2;
       
   127 	else if (val < 1000)
       
   128 		len = 3;
       
   129 	else if (val < 10000)
       
   130 		len = 4;
       
   131 	else if (val < 100000)
       
   132 		len = 5;
       
   133 	else if (val < 1000000)
       
   134 		len = 6;
       
   135 	else if (val < 10000000)
       
   136 		len = 7;
       
   137 	else if (val < 100000000)
       
   138 		len = 8;
       
   139 	else if (val < 1000000000)
       
   140 		len = 9;
       
   141 	int w = (len < width) ? width : len;
       
   142 	char* d = out + w;
       
   143 	do	{
       
   144 		*--d = (char)(48 + val%10);
       
   145 		val /= 10;
       
   146 		} while(val);
       
   147 	for (; d > out; *--d = (char)fill ) {}
       
   148 	return w;
       
   149 	}
       
   150 
       
   151 int AppendNumBase10S(char* out, int sval, int width, int fill)
       
   152 	{
       
   153 	int sign = (sval<0) ? 1 : 0;
       
   154 	unsigned val = sign ? unsigned(-sval) : unsigned(sval);
       
   155 	int len = 10;
       
   156 	if (val < 10)
       
   157 		len = 1;
       
   158 	else if (val < 100)
       
   159 		len = 2;
       
   160 	else if (val < 1000)
       
   161 		len = 3;
       
   162 	else if (val < 10000)
       
   163 		len = 4;
       
   164 	else if (val < 100000)
       
   165 		len = 5;
       
   166 	else if (val < 1000000)
       
   167 		len = 6;
       
   168 	else if (val < 10000000)
       
   169 		len = 7;
       
   170 	else if (val < 100000000)
       
   171 		len = 8;
       
   172 	else if (val < 1000000000)
       
   173 		len = 9;
       
   174 	if (sign) ++len;
       
   175 	int w = (len < width) ? width : len;
       
   176 	char* d = out + w;
       
   177 	do	{
       
   178 		*--d = (char)(48 + val%10);
       
   179 		val /= 10;
       
   180 		} while(val);
       
   181 	if (sign) *--d = '-';
       
   182 	for (; d > out; *--d = (char)fill ) {}
       
   183 	return w;
       
   184 	}
       
   185 
       
   186 int AppendNumBase16(char* out, unsigned int val, int width, int fill)
       
   187 	{
       
   188 	int len = 8;
       
   189 	if (val < 0x10)
       
   190 		len = 1;
       
   191 	else if (val < 0x100)
       
   192 		len = 2;
       
   193 	else if (val < 0x1000)
       
   194 		len = 3;
       
   195 	else if (val < 0x10000)
       
   196 		len = 4;
       
   197 	else if (val < 0x100000)
       
   198 		len = 5;
       
   199 	else if (val < 0x1000000)
       
   200 		len = 6;
       
   201 	else if (val < 0x10000000)
       
   202 		len = 7;
       
   203 	int w = (len < width) ? width : len;
       
   204 	char* d = out + w;
       
   205 	do	{
       
   206 		char c = (char)(48 + (val&15));
       
   207 		if (c>'9') c+=0x07;
       
   208 		*--d = c;
       
   209 		val >>= 4;
       
   210 		} while(val);
       
   211 	for (; d > out; *--d = (char)fill ) {}
       
   212 	return w;
       
   213 	}
       
   214 
       
   215 int AppendNumBase16L(char* out, Uint64 val, int width, int fill)
       
   216 	{
       
   217 	TUint vl = (TUint)val;
       
   218 	TUint vh = (TUint)(val>>32);
       
   219 	TInt l = 0;
       
   220 	if (vh)
       
   221 		{
       
   222 		l = AppendNumBase16(out, vh, width-8, fill);
       
   223 		l += AppendNumBase16(out+l, vl, 8, fill);
       
   224 		}
       
   225 	else
       
   226 		l = AppendNumBase16(out, vl, width, fill);
       
   227 	return l;
       
   228 	}
       
   229 
       
   230 
       
   231 
       
   232 /**
       
   233 Formats and appends text to the specified narrow descriptor without making any
       
   234 executive calls.
       
   235 
       
   236 The function takes a format string and a variable number of arguments. The
       
   237 format specifiers in the format string are used to interpret and the arguments.
       
   238 
       
   239 Format directives have the following syntax:
       
   240 @code
       
   241 <format-directive> ::= 
       
   242 	"%" [<padding-character>] [<field-width>] [<long-flag>] <conversion-specifier>
       
   243 @endcode
       
   244 
       
   245 If a field width is specified and the width of the formatted field is less
       
   246 than this width, then the field is padded with the padding character.
       
   247 The only supported padding characters are ' ' (default) and '0'.
       
   248 
       
   249 The long flag specifier ('l') modifies the semantic of the conversion
       
   250 specifier as explained below.
       
   251 
       
   252 The possible values for the conversion specifiers, the long flag and the way in
       
   253 which arguments are interpreted, are as follows:
       
   254 @code
       
   255 d	Interpret the argument as a TInt decimal representation
       
   256 ld	NOT SUPPORTED - use lx instead
       
   257 u	Interpret the argument as a TUint decimal representation
       
   258 lu	NOT SUPPORTED - use lx instead
       
   259 x	Interpret the argument as a TUint hexadecimal representation
       
   260 X	As above
       
   261 lx	Interpret the argument as a Uint64 hexadecimal representation
       
   262 lX	As above
       
   263 c	Interpret the argument as a character
       
   264 s	Interpret the argument as a pointer to narrow C string
       
   265 ls	Interpret the argument as a pointer to narrow C string
       
   266 S 	Interpret the argument as a pointer to narrow descriptor or NULL
       
   267 lS	NOT SUPPORTED - use S instead
       
   268 O	Interpret the argument as a pointer to DObject or NULL 
       
   269 	Generates the object full name or 'NULL'
       
   270 o	Interpret the argument as a pointer to DObject or NULL
       
   271 	Generates the object name or 'NULL'
       
   272 M	Interpret the argument as a pointer to a fast mutex or NULL
       
   273 	Generates the name, if this is a well-known fast mutex, address otherwise
       
   274 m	Interpret the argument as a pointer to a fast semaphore or NULL
       
   275 	Generates the owning thread name, if this is a well-known fast semaphore, address otherwise
       
   276 T	Interpret the argument as a pointer to a nanothread or NULL 
       
   277 	Generates the full name, if this is a Symbian OS thread, address otherwise
       
   278 C	Interpret the argument as a pointer to a DCodeSeg or NULL
       
   279 	Generates the filename and module version number
       
   280 @endcode
       
   281 
       
   282 The function can be called from the interrupt context, but extreme caution is advised as it
       
   283 may require a lot of stack space and interrupt stacks are very small.
       
   284 
       
   285 @param aDes 	Narrow descriptor that must be big-enough to hold result
       
   286 @param aFmt 	The format string
       
   287 @param aList 	A variable number of arguments to be converted to text as dictated by the format string
       
   288 
       
   289 @pre Calling thread can be either in a critical section or not.
       
   290 @pre Interrupts must be enabled.
       
   291 @pre Kernel must be unlocked
       
   292 @pre No fast mutex can be held.
       
   293 @pre Call in any context.
       
   294 @pre Suitable for use in a device driver
       
   295 
       
   296 @panic The set of panics that can be raised when appending data to descriptors.
       
   297 
       
   298 @see   TDes8
       
   299 */
       
   300 EXPORT_C TInt AppendFormat(char* aOut, const char* aFmt, VA_LIST aList)
       
   301 	{
       
   302 #define NEXT_FMT(c,p) if (((c)=*(p)++)==0) return outLen;
       
   303 
       
   304 	TInt outLen = 0;
       
   305 	FOREVER
       
   306 		{
       
   307 		char c;
       
   308 		NEXT_FMT(c,aFmt);
       
   309 		if (c=='%')
       
   310 			{
       
   311 			char fill=' ';
       
   312 			TInt width=0;
       
   313 			TBool long_arg=EFalse;
       
   314 			TBool ok=ETrue;
       
   315 			NEXT_FMT(c,aFmt);
       
   316 			if (c=='0')
       
   317 				{
       
   318 				fill='0';
       
   319 				NEXT_FMT(c,aFmt);
       
   320 				}
       
   321 			while(c>='0' && c<='9')
       
   322 				{
       
   323 				width=width*10+c-'0';
       
   324 				NEXT_FMT(c,aFmt);
       
   325 				}
       
   326 			if (c=='l')
       
   327 				{
       
   328 				long_arg=ETrue;
       
   329 				NEXT_FMT(c,aFmt);
       
   330 				}
       
   331 			switch(c)
       
   332 				{
       
   333 				case 'd':
       
   334 					{
       
   335 					if (long_arg)
       
   336 						ok=EFalse;
       
   337 					else
       
   338 						{
       
   339 						TInt val=VA_ARG(aList,TInt);
       
   340 						char* d = aOut + outLen;
       
   341 						outLen += AppendNumBase10S(d, val, width, fill);
       
   342 						}
       
   343 					break;
       
   344 					}
       
   345 				case 'u':
       
   346 					{
       
   347 					if (long_arg)
       
   348 						ok=EFalse;
       
   349 					else
       
   350 						{
       
   351 						TUint val=VA_ARG(aList,TUint);
       
   352 						char* d = aOut + outLen;
       
   353 						outLen += AppendNumBase10U(d, val, width, fill);
       
   354 						}
       
   355 					break;
       
   356 					}
       
   357 				case 'x':
       
   358 				case 'X':
       
   359 					{
       
   360 					if (long_arg)
       
   361 						{
       
   362 						Uint64 val=VA_ARG(aList,Uint64);
       
   363 						char* d = aOut + outLen;
       
   364 						outLen += AppendNumBase16L(d, val, width, fill);
       
   365 						}
       
   366 					else
       
   367 						{
       
   368 						TUint val=VA_ARG(aList,TUint);
       
   369 						char* d = aOut + outLen;
       
   370 						outLen += AppendNumBase16(d, val, width, fill);
       
   371 						}
       
   372 					break;
       
   373 					}
       
   374 				case 's':
       
   375 					{
       
   376 					const char* s = VA_ARG(aList,const char*);
       
   377 					outLen = appendstr(aOut, outLen, s);
       
   378 					break;
       
   379 					}
       
   380 				case 'M':		// fast mutex
       
   381 					{
       
   382 					NFastMutex* pM=VA_ARG(aList,NFastMutex*);
       
   383 					outLen = appendstr(aOut, outLen, "M");
       
   384 					if (!pM)
       
   385 						outLen = appendstr(aOut, outLen, 0);
       
   386 					else if (pM==&TheScheduler.iLock)
       
   387 						outLen = appendstr(aOut, outLen, "SYSLOCK");
       
   388 					else
       
   389 						outLen += AppendNumBase16(aOut+outLen, (TUint)pM, 8, '0');
       
   390 					break;
       
   391 					}
       
   392 				case 'm':		// fast semaphore
       
   393 					{
       
   394 					NFastSemaphore* pS=VA_ARG(aList,NFastSemaphore*);
       
   395 					outLen = appendstr(aOut, outLen, "S");
       
   396 					if (!pS)
       
   397 						outLen = appendstr(aOut, outLen, 0);
       
   398 					else
       
   399 						outLen += AppendNumBase16(aOut+outLen, (TUint)pS, 8, '0');
       
   400 					break;
       
   401 					}
       
   402 				case 'T':		// NKERN thread
       
   403 					{
       
   404 					NThread* pN=VA_ARG(aList,NThread*);
       
   405 #ifdef __SMP__
       
   406 					if (pN && pN->iNThreadBaseSpare8)
       
   407 						outLen = appendstr(aOut, outLen, (const char*)pN->iNThreadBaseSpare8);
       
   408 #else
       
   409 					if (pN && pN->iSpare8)
       
   410 						outLen = appendstr(aOut, outLen, (const char*)pN->iSpare8);
       
   411 #endif
       
   412 					else
       
   413 						{
       
   414 						outLen = appendstr(aOut, outLen, "T");
       
   415 						if (!pN)
       
   416 							outLen = appendstr(aOut, outLen, 0);
       
   417 						else
       
   418 							outLen += AppendNumBase16(aOut+outLen, (TUint)pN, 8, '0');
       
   419 						}
       
   420 					break;
       
   421 					}
       
   422 #ifdef __SMP__
       
   423 				case 'G':		// NKERN thread group
       
   424 					{
       
   425 					NThreadGroup* pG=VA_ARG(aList,NThreadGroup*);
       
   426 //					if (pG && pG->iNThreadBaseSpare8)
       
   427 //						outLen = appendstr(aOut, outLen, (const char*)pG->iNThreadBaseSpare8);
       
   428 //					else
       
   429 						{
       
   430 						outLen = appendstr(aOut, outLen, "G");
       
   431 						if (!pG)
       
   432 							outLen = appendstr(aOut, outLen, 0);
       
   433 						else
       
   434 							outLen += AppendNumBase16(aOut+outLen, (TUint)pG, 8, '0');
       
   435 						}
       
   436 					break;
       
   437 					}
       
   438 #endif
       
   439 				case 'c':
       
   440 					c=(char)VA_ARG(aList,TUint);
       
   441 					// fall through
       
   442 				default:
       
   443 					ok=EFalse;
       
   444 					break;
       
   445 				}
       
   446 				if (ok)
       
   447 					continue;
       
   448 			}
       
   449 		aOut[outLen++]=c;
       
   450 		}
       
   451 	return outLen;
       
   452 	}
       
   453 
       
   454 
       
   455 /**
       
   456 Prints a formatted string on the debug port.
       
   457 
       
   458 The function uses Kern::AppendFormat() to do the formatting.
       
   459 
       
   460 Although it is safe to call this function from an ISR, it polls the output
       
   461 serial port and may take a long time to complete, invalidating any
       
   462 real-time guarantee.
       
   463 
       
   464 If called from an ISR, it is possible for output text to be intermingled
       
   465 with other output text if one set of output interrupts or preempts another.
       
   466 
       
   467 Some of the formatting options may not work inside an ISR.
       
   468 
       
   469 Be careful not to use a string that is too long to fit onto the stack.
       
   470 
       
   471 @param aFmt The format string. This must not be longer than 256 characters.
       
   472 @param ...	A variable number of arguments to be converted to text as dictated
       
   473             by the format string.
       
   474 
       
   475 @pre Calling thread can either be in a critical section or not.
       
   476 @pre Interrupts must be enabled.
       
   477 @pre Kernel must be unlocked
       
   478 @pre No fast mutex can be held.
       
   479 @pre Call in any context.
       
   480 @pre Suitable for use in a device driver
       
   481 
       
   482 @see Kern::AppendFormat()
       
   483 */
       
   484 extern "C" void puts(const char* s);
       
   485 extern "C" void prthex8(TUint);
       
   486 EXPORT_C void KPrintf(const char* aFmt, ...)
       
   487 	{
       
   488 	extern TUint32 __tr();
       
   489 
       
   490 	char printBuf[256];
       
   491 	VA_LIST list;
       
   492 	VA_START(list,aFmt);
       
   493 	int c = AppendFormat(printBuf+2,aFmt,list) + 2;
       
   494 	printBuf[c++] = 13;
       
   495 	printBuf[c++] = 10;
       
   496 	printBuf[0] = __trace_cpu_num()+48;
       
   497 	printBuf[1] = 58;
       
   498 
       
   499 	if (NKern::Crashed())
       
   500 		{
       
   501 		DebugPrint(printBuf,c);
       
   502 		return;
       
   503 		}
       
   504 
       
   505 	// Handle BTrace first...
       
   506 	TUint category = BTrace::EKernPrintf;
       
   507 	TInt result = BTraceContextBig(category,0,0,printBuf,c);
       
   508 
       
   509 	NThread* csThread = 0;
       
   510 	NThread* curr = NKern::CurrentThread();
       
   511 	if (curr && NKern::CurrentContext() == NKern::EThread && !NKern::KernelLocked())
       
   512 		{
       
   513 		csThread = curr;
       
   514 		NKern::_ThreadEnterCS();
       
   515 		}
       
   516 	if (!result)
       
   517 		{
       
   518 		DebugPrint(printBuf,c);
       
   519 		}
       
   520 	if (csThread)
       
   521 		{
       
   522 		NKern::_ThreadLeaveCS();
       
   523 		}
       
   524 	}
       
   525 
       
   526 
       
   527 
       
   528 /******************************************************************************
       
   529  * BTRACE SUPPORT
       
   530  ******************************************************************************/
       
   531 
       
   532 #define BTRACE_INCLUDE_TIMESTAMPS
       
   533 
       
   534 TAny* BTraceBufferBase[KMaxCpus];
       
   535 TAny* BTraceBufferEnd[KMaxCpus];
       
   536 TAny* BTraceBufferPtr[KMaxCpus];	// next free position
       
   537 TBool BTraceBufferWrap[KMaxCpus];
       
   538 TBool BTraceActive;
       
   539 
       
   540 //const TUint KBTraceBufferSize = 16 * 1024 * 1024;
       
   541 const TUint KBTraceBufferSize = 1 * 1024 * 1024;
       
   542 const TUint KBTraceSlotSize = 128;
       
   543 
       
   544 __ASSERT_COMPILE(KBTraceSlotSize >= (TUint)KMaxBTraceRecordSize);
       
   545 
       
   546 TBool HandleBTrace(TUint32 aHeader,TUint32 aHeader2,const TUint32 aContext,const TUint32 a1,const TUint32 a2,const TUint32 a3,const TUint32 aExtra,const TUint32 aPc)
       
   547 	{
       
   548 #ifdef __SMP__
       
   549 	// Header 2 always present and contains CPU number
       
   550 	// If Header2 not originally there, add 4 to size
       
   551 	TInt cpu = NKern::CurrentCpu();
       
   552 	if (!(aHeader&(BTrace::EHeader2Present<<BTrace::EFlagsIndex*8)))
       
   553 		aHeader += (4<<BTrace::ESizeIndex*8) + (BTrace::EHeader2Present<<BTrace::EFlagsIndex*8), aHeader2=0;
       
   554 	aHeader2 = (aHeader2 &~ BTrace::ECpuIdMask) | (cpu<<20);
       
   555 #else
       
   556 	TInt cpu = 0;
       
   557 #endif
       
   558 #ifdef BTRACE_INCLUDE_TIMESTAMPS
       
   559 	// Add timestamp to trace...
       
   560 #if defined(__EPOC32__) && defined(__CPU_X86)
       
   561 	aHeader += 8<<BTrace::ESizeIndex*8;
       
   562 	aHeader |= BTrace::ETimestampPresent<<BTrace::EFlagsIndex*8 | BTrace::ETimestamp2Present<<BTrace::EFlagsIndex*8;
       
   563 	TUint64 timeStamp = fast_counter();
       
   564 #else
       
   565 	aHeader += 4<<BTrace::ESizeIndex*8;
       
   566 	aHeader |= BTrace::ETimestampPresent<<BTrace::EFlagsIndex*8;
       
   567 	TUint32 timeStamp = NKern::FastCounter();
       
   568 #endif
       
   569 #endif
       
   570 	TUint size = (aHeader+3)&0xfc;
       
   571 
       
   572 #if !defined(__SMP__) || !defined(__USE_BTRACE_LOCK__)
       
   573 	TInt irq = NKern::DisableAllInterrupts();
       
   574 #endif
       
   575 
       
   576 	TUint32* src;
       
   577 	TUint32* dst = (TUint32*)BTraceBufferPtr[cpu];
       
   578 
       
   579 	if (!BTraceActive)
       
   580 		goto trace_off;
       
   581 
       
   582 	BTraceBufferPtr[cpu] = ((TUint8*)BTraceBufferPtr[cpu]) + KBTraceSlotSize;
       
   583 	if (BTraceBufferPtr[cpu] >= BTraceBufferEnd[cpu])
       
   584 		{
       
   585 		BTraceBufferPtr[cpu] = BTraceBufferBase[cpu];
       
   586 		BTraceBufferWrap[cpu] = TRUE;
       
   587 		}
       
   588 
       
   589 	size >>= 2; // we are now counting words, not bytes
       
   590 
       
   591 	if (dst+size > (TUint32*)BTraceBufferEnd[cpu])
       
   592 		goto trace_dropped;
       
   593 
       
   594 	{
       
   595 	// store first word of trace...
       
   596 	TUint w = aHeader;
       
   597 	--size;
       
   598 	*dst++ = w;
       
   599 
       
   600 #ifndef __SMP__
       
   601 	if (aHeader&(BTrace::EHeader2Present<<(BTrace::EFlagsIndex*8)))
       
   602 #endif
       
   603 		{
       
   604 		w = aHeader2;
       
   605 		--size;
       
   606 		*dst++ = w;
       
   607 		}
       
   608 
       
   609 #ifdef BTRACE_INCLUDE_TIMESTAMPS
       
   610 	// store timestamp...
       
   611 #if defined(__EPOC32__) && defined(__CPU_X86)
       
   612 	--size;
       
   613 	*dst++ = TUint32(timeStamp);
       
   614 	--size;
       
   615 	*dst++ = TUint32(timeStamp>>32);
       
   616 #else
       
   617 	--size;
       
   618 	*dst++ = timeStamp;
       
   619 #endif
       
   620 #endif
       
   621 
       
   622 	if(aHeader&(BTrace::EContextIdPresent<<(BTrace::EFlagsIndex*8)))
       
   623 		{
       
   624 		w = aContext;
       
   625 		--size;
       
   626 		*dst++ = w;
       
   627 		}
       
   628 
       
   629 	if(aHeader&(BTrace::EPcPresent<<(BTrace::EFlagsIndex*8)))
       
   630 		{
       
   631 		w = aPc;
       
   632 		--size;
       
   633 		*dst++ = w;
       
   634 		}
       
   635 
       
   636 	if(aHeader&(BTrace::EExtraPresent<<(BTrace::EFlagsIndex*8)))
       
   637 		{
       
   638 		w = aExtra;
       
   639 		--size;
       
   640 		*dst++ = w;
       
   641 		}
       
   642 
       
   643 	// store remaining words of trace...
       
   644 	if(size)
       
   645 		{
       
   646 		w = a1;
       
   647 		--size;
       
   648 		*dst++ = w;
       
   649 		if(size)
       
   650 			{
       
   651 			w = a2;
       
   652 			--size;
       
   653 			*dst++ = w;
       
   654 			if(size)
       
   655 				{
       
   656 				if(size==1)
       
   657 					{
       
   658 					w = a3;
       
   659 					*dst++ = w;
       
   660 					}
       
   661 				else
       
   662 					{
       
   663 					src = (TUint32*)a3;
       
   664 					do
       
   665 						{
       
   666 						w = *src++;
       
   667 						--size;
       
   668 						*dst++ = w;
       
   669 						}
       
   670 					while(size);
       
   671 					}
       
   672 				}
       
   673 			}
       
   674 		}
       
   675 	}
       
   676 
       
   677 #if !defined(__SMP__) || !defined(__USE_BTRACE_LOCK__)
       
   678 	NKern::RestoreInterrupts(irq);
       
   679 #endif
       
   680 	return ETrue;
       
   681 
       
   682 
       
   683 trace_dropped:
       
   684 #if !defined(__SMP__) || !defined(__USE_BTRACE_LOCK__)
       
   685 	NKern::RestoreInterrupts(irq);
       
   686 #endif
       
   687 	return ETrue;
       
   688 
       
   689 trace_off:
       
   690 #if !defined(__SMP__) || !defined(__USE_BTRACE_LOCK__)
       
   691 	NKern::RestoreInterrupts(irq);
       
   692 #endif
       
   693 	return ETrue;
       
   694 //	return EFalse;
       
   695 	}
       
   696 
       
   697 
       
   698 TBool SBTraceData::CheckFilter2(TUint32)
       
   699 	{
       
   700 	return TRUE;
       
   701 	}
       
   702 
       
   703 void InitBTraceHandler()
       
   704 	{
       
   705 	TInt cpu;
       
   706 #ifdef __SMP__
       
   707 	TInt ncpus = NKern::NumberOfCpus();
       
   708 #else
       
   709 	TInt ncpus = 1;
       
   710 #endif
       
   711 	for (cpu=0; cpu<ncpus; ++cpu)
       
   712 		{
       
   713 		BTraceBufferBase[cpu] = malloc(KBTraceBufferSize);
       
   714 		TEST_OOM(BTraceBufferBase[cpu]);
       
   715 		BTraceBufferEnd[cpu] = ((TUint8*)BTraceBufferBase[cpu]) + KBTraceBufferSize;
       
   716 
       
   717 		TUint8* p = (TUint8*)BTraceBufferBase[cpu];
       
   718 
       
   719 		BTraceBufferPtr[cpu] = p;
       
   720 		BTraceBufferWrap[cpu] = FALSE;
       
   721 
       
   722 		TEST_PRINT2("BTraceBufferBase[%d] = %08x", cpu, BTraceBufferBase[cpu]);
       
   723 		TEST_PRINT2("BTraceBufferEnd[%d]  = %08x", cpu, BTraceBufferEnd[cpu]);
       
   724 		TEST_PRINT2("BTraceBufferPtr[%d]  = %08x", cpu, BTraceBufferPtr[cpu]);
       
   725 		}
       
   726 
       
   727 	SBTraceData& traceData = BTraceData;
       
   728 	traceData.iHandler = &HandleBTrace;
       
   729 //	traceData.iFilter[BTrace::EKernPrintf] = 1;
       
   730 	traceData.iFilter[BTrace::EThreadIdentification] = 1;
       
   731 	traceData.iFilter[BTrace::ECpuUsage] = 1;
       
   732 	traceData.iFilter[0xdd] = 1;
       
   733 //	memset(traceData.iFilter, 1, sizeof(traceData.iFilter));
       
   734 	}
       
   735 
       
   736 void DumpBTraceBuffer()
       
   737 	{
       
   738 	BTraceActive = FALSE;
       
   739 
       
   740 	TInt cpu;
       
   741 #ifdef __SMP__
       
   742 	TInt ncpus = NKern::NumberOfCpus();
       
   743 #else
       
   744 	TInt ncpus = 1;
       
   745 #endif
       
   746 	char x[64];
       
   747 	for (cpu=0; cpu<=ncpus; ++cpu)
       
   748 		{
       
   749 		memset(x, cpu+0xc0, sizeof(x));
       
   750 		DebugPrint(x, sizeof(x));
       
   751 		if (cpu == ncpus)
       
   752 			break;
       
   753 		const char* b = (const char*)BTraceBufferBase[cpu];
       
   754 		const char* e = (const char*)BTraceBufferEnd[cpu];
       
   755 		const char* f = (const char*)BTraceBufferPtr[cpu];
       
   756 		const char* p = BTraceBufferWrap[cpu] ? f : b;
       
   757 		if (!p || (!BTraceBufferWrap[cpu] && p==f))
       
   758 			continue;
       
   759 		do	{
       
   760 			TInt size = *(const TUint8*)p;
       
   761 			size = (size + 3) &~ 3;
       
   762 			DebugPrint(p, size);
       
   763 			p+=KBTraceSlotSize;
       
   764 			if (p==e)
       
   765 				p = b;
       
   766 			} while (p!=f);
       
   767 		}
       
   768 
       
   769 	SBTraceData& traceData = BTraceData;
       
   770 	memset(traceData.iFilter, 0, sizeof(traceData.iFilter));
       
   771 	traceData.iHandler = 0;
       
   772 	TEST_PRINT("\r\n\nBTrace Dump Complete");
       
   773 	}
       
   774 
       
   775 void StartBTrace()
       
   776 	{
       
   777 	BTraceActive = TRUE;
       
   778 	}
       
   779 
       
   780 void StopBTrace()
       
   781 	{
       
   782 	BTraceActive = FALSE;
       
   783 	}
       
   784 
       
   785 TInt KCrazySchedulerEnabled()
       
   786 	{
       
   787 	return 0;
       
   788 	}