os/kernelhwsrv/kernel/eka/kernel/smondebug.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2007-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 // e32\kernel\smondebug.cpp
    15 // interactive crash debugger -- crash debugger code specific to the interactive
    16 // instance
    17 // 
    18 //
    19 
    20 #include <kernel/monitor.h>
    21 #include "crashdebug_gzip.h"
    22 
    23 GLDEF_D TCrashDebugGzip gDebugGzip;
    24 GLDEF_D CrashDebugger TheCrashDebugger;
    25 
    26 const char* InitialInputPtr;
    27 
    28 #if 1 /*#ifndef __X86__*/
    29 const char* InitialInput="";
    30 #else
    31 const char* InitialInput="replacement\rf\ri\rr\rc0\rc1\rc2\rc3\rc4\rc5\rc6\rc7\rc8\rc9\rca\rcb\rcc\rcd\rce\rcf\r";
    32 #endif
    33 
    34 CrashDebugger::CrashDebugger() 
    35 	: iEncoder(&gDebugGzip) {}
    36 
    37 
    38 void CrashDebugger::Print(const TDesC8& aDes)
    39 	{
    40 	const TUint8* p=aDes.Ptr();
    41 	TInt l=aDes.Length();
    42 	for (; l; --l)
    43 		UartOut(*p++);
    44 	}
    45 
    46 void CrashDebugger::Pause(TBool aPause)
    47 	{
    48 	if (aPause && *InitialInputPtr)
    49 		{
    50 		UartIn();
    51 		}
    52 	}
    53 
    54 void CrashDebugger::UnknownCommand()
    55 	{
    56 	Print(_L8("Unknown command - type h for help\r\n"));
    57 	}
    58 
    59 void CrashDebugger::SyntaxError()
    60 	{
    61 	Print(_L8("Syntax error - type h for help\r\n"));
    62 	}
    63 
    64 void CrashDebugger::ProcessDumpObjectContainer(const TDesC8& aDes, TInt& i, TBool aPause)
    65 	{
    66 	TUint index;
    67 	TInt r=ReadHex(aDes,i,index);
    68 	if(r!=KErrNone)
    69 		{
    70 		SyntaxError();
    71 		return;
    72 		}
    73 	DumpObjectContainer(index,aPause);
    74 	}
    75 
    76 TInt CrashDebugger::ReadHex(const TDesC8& in, TInt& i, TUint& r)
    77 	{
    78 	r=0;
    79 	TInt l=in.Length();
    80 	SkipSpaces(in,i);
    81 	if (i==l)
    82 		return KErrGeneral;
    83 	TInt j=i;
    84 	while(i<l)
    85 		{
    86 		char c=(char)in[i];
    87 		if (c>='a' && c<='z')
    88 			c&=0xdf;
    89 		if (c>='0' && c<='9')
    90 			c-='0';
    91 		else if (c>='A' && c<='F')
    92 			c-=('A'-10);
    93 		else break;
    94 		r=(r<<4)+(TUint)c;
    95 		i++;
    96 		}
    97 	if (i==j)
    98 		return KErrGeneral;
    99 	return KErrNone;
   100 	}
   101 
   102 void CrashDebugger::SkipSpaces(const TDesC8& in, TInt& i)
   103 	{
   104 	TInt l=in.Length();
   105 	while(i<l && (in[i]==' ' || in[i]=='\t')) i++;
   106 	}
   107 
   108 void CrashDebugger::ProcessMemDumpCommand(const TDesC8& aDes, TInt& i, TBool aDiscontiguous)
   109 	{
   110 	TUint start;
   111 	TUint end;
   112 	TInt length=0;
   113 	TBool add=EFalse;
   114 	TUint readSize;
   115 	TInt r=ReadHex(aDes,i,start);
   116 	if (r==KErrNone)
   117 		{
   118 		SkipSpaces(aDes,i);
   119 		if (i==aDes.Length())
   120 			end=start;
   121 		else
   122 			{
   123 			if (i<aDes.Length() && aDes[i]=='+')
   124 				i++, add=ETrue;
   125 			r=ReadHex(aDes,i,end);
   126 			}
   127 		}
   128 	if (r==KErrNone)
   129 		{
   130 		if (add)
   131 			length=(TInt)end;
   132 		else
   133 			length=(TInt)(end-start+1);
   134 		if (length<0)
   135 			r=KErrGeneral;
   136 		}
   137 	if (r!=KErrNone)
   138 		{
   139 		SyntaxError();
   140 		return;
   141 		}
   142 
   143 	SkipSpaces(aDes,i);
   144 	if(i==aDes.Length())
   145 		{
   146 		if (aDiscontiguous)
   147  			{
   148    			DoDiscontiguousMemoryDumpL(start,length);		
   149  			}
   150  		else
   151  		    {
   152   		    DoMemoryDumpL(start,length);	
   153  		    }			
   154 		}
   155 	 else
   156   	 	{
   157   	    readSize=(TUint)aDes[i];
   158 		TInt r=ReadHex(aDes,i,readSize);
   159 		if (r!=KErrNone)
   160 			{
   161 			SyntaxError();
   162 			return;
   163 			}		
   164 		if(readSize == 0x0 || readSize == 0x3 || readSize >= 0x5)
   165 		 	{
   166 		 	UnknownCommand();	
   167 		 	}
   168  	   	if(aDiscontiguous)
   169 			{
   170  			DoDiscontiguousMemoryDumpL(start,length,readSize);	
   171 			}
   172 		else
   173 			{
   174 			DoMemoryDumpL(start,length,readSize);	
   175 			}
   176 			
   177  		}
   178 	}
   179 
   180 void CrashDebugger::ProcessNThreadDumpCommand(const TDesC8& aDes, TInt& i)
   181 	{
   182 	TUint addr;
   183 	TInt r=ReadHex(aDes,i,addr);
   184 	if (r!=KErrNone)
   185 		{
   186 		SyntaxError();
   187 		return;
   188 		}
   189 	DisplayNThreadInfo((NThread*)addr);
   190 	}
   191 
   192 void CrashDebugger::ProcessObjectDumpCommand(const TDesC8& aDes, TInt& i)
   193 	{
   194 	TUint addr;
   195 	TInt r=ReadHex(aDes,i,addr);
   196 	if (r!=KErrNone)
   197 		{
   198 		SyntaxError();
   199 		return;
   200 		}
   201 	ObjectDump(addr);
   202 	}
   203 
   204 void CrashDebugger::ProcessObjectFullDumpCommand(const TDesC8& aDes, TInt& i)
   205 	{
   206 	TUint addr;
   207 	TInt r=ReadHex(aDes,i,addr);
   208 	if (r!=KErrNone)
   209 		{
   210 		SyntaxError();
   211 		return;
   212 		}
   213 	ObjectFullDump(addr);
   214 	}
   215 
   216 void CrashDebugger::ProcessAddressSpaceSwitchCommand(const TDesC8& aDes, TInt& i, TBool aForce)
   217 	{
   218 	TUint addr;
   219 	TInt r=ReadHex(aDes,i,addr);
   220 	if (r!=KErrNone)
   221 		{
   222 		SyntaxError();
   223 		return;
   224 		}
   225 	r = SwitchAddressSpace((DProcess*)addr, aForce);
   226 	switch (r)
   227 		{
   228 		case KErrArgument:
   229 			Print(_L8("Invalid process address\r\n")); break;
   230 		case KErrCorrupt:
   231 			Print(_L8("Process is corrupt\r\n")); break;
   232 		case KErrNone:
   233 			break;
   234 		default:
   235 			Print(_L8("Unknown error\r\n")); break;
   236 		}
   237 	}
   238 
   239 void CrashDebugger::Input(TDes8& aDes, const char* aPrompt)
   240 	{
   241 	TInt m=aDes.MaxLength();
   242 	TUint8* p=(TUint8*)aDes.Ptr();
   243 	TUint8* q=p;
   244 	TUint8* e=p+m;
   245 	Monitor::Print(aPrompt);
   246 	TUint c=0xffffffff;
   247 	FOREVER
   248 		{
   249 		do
   250 			{
   251 			c = *InitialInputPtr;
   252 			if (c)
   253 				++InitialInputPtr;
   254 			else
   255 				c=UartIn();
   256 			} while(c==0x0a);	// ignore LF's
   257 		if (c==0x0d)
   258 			{
   259 			NewLine();
   260 			break;
   261 			}
   262 		else if (c==0x08)
   263 			{
   264 			if (q>p)
   265 				--q;
   266 			}
   267 		else if (q<e)
   268 			*q++=(TUint8)c;
   269 		UartOut(c);
   270 		}
   271 	aDes.SetLength(q-p);
   272 	}
   273 	
   274 _LIT8(KAllCommand, "all");	
   275 void CrashDebugger::DisplayCodeSegCommand(const TDesC8& aDes, TInt& ai, TBool aFull)
   276 	{
   277 	TInt r;
   278 	TUint addr;
   279 	SkipSpaces(aDes,ai);
   280 	if (aDes.Mid(ai)==KAllCommand)
   281 		{
   282 		MTRAP(r,DisplayCodeSeg(aFull));
   283 		if (r!=KErrNone)
   284 			ProcessError(r);
   285 		}
   286 	else if (ReadHex(aDes,ai,addr)==KErrNone)
   287 		{
   288 		MTRAP(r,DisplayCodeSeg((DCodeSeg*) addr,aFull));
   289 		if (r!=KErrNone)
   290 			ProcessError(r);
   291 		}
   292 	else
   293 		SyntaxError();
   294 	}
   295 
   296 
   297 _LIT8(KWaitCommand, "wait");
   298 _LIT8(KNowaitCommand, "nowait");
   299 _LIT8(KZipCommand, "zip");
   300 void CrashDebugger::ProcessBTrace(const TDesC8& aDes, TInt& ai)
   301 	{
   302 	TBool zip = EFalse;
   303 	TBool wait;
   304 	TInt lenZipCommand = ((TDesC8)KZipCommand).Length(); 
   305 	
   306 	if (aDes.Mid(ai, lenZipCommand)==KZipCommand)
   307 		{
   308 		zip = ETrue;
   309 		ai += lenZipCommand;
   310 		SkipSpaces(aDes, ai);
   311 		}
   312 
   313 	if (aDes.Mid(ai)==KWaitCommand)
   314 		wait = ETrue;
   315 	else if (aDes.Mid(ai)==KNowaitCommand)
   316 		wait = EFalse;
   317 	else
   318 		{
   319 		SyntaxError();
   320 		return;
   321 		}
   322 
   323 	if (zip)
   324 		iEncoder->SetOutput(this);
   325 
   326 	TUint8* data;
   327 	TUint size;
   328 	TInt r = BTrace::Control(BTrace::ECtrlCrashReadFirst,&data,&size);
   329 	if(r==KErrNone)
   330 		{
   331 		if(size==0)
   332 			{
   333 			Print(_L8("BTrace Dump: Buffer is empty.\r\n"));
   334 			return;
   335 			}
   336 
   337 		if(wait)
   338 			{
   339 			Print(_L8("BTrace Dump: Press any key to start...\r\n"));
   340 			UartIn();
   341 			}
   342 
   343 		do
   344 			{
   345 			if (zip)
   346 				{
   347 				TPtrC8 ptr(data, size);
   348 				iEncoder->Write(ptr);
   349 				size = 0;
   350 				}
   351 			else
   352 				{
   353 				do UartOut(*data++);
   354 				while(--size);
   355 				}
   356 			r = BTrace::Control(BTrace::ECtrlCrashReadNext,&data,&size);
   357 			}
   358 		while(size && r==KErrNone);
   359 
   360 		if(wait)
   361 			{
   362 			// this is also a valid BTrace 'EKernPrintf' trace...
   363 			_LIT(dumpEndText,"\060\000\001\001\377\377\377\377\r\nBTrace Dump: Done - press any key...\r\n");
   364 			if (zip)
   365 				{
   366 				iEncoder->FlushEnd();
   367 				}
   368 			else
   369 				Print(dumpEndText);
   370 			UartIn();
   371 			}
   372 		else if (zip)
   373 			iEncoder->FlushEnd();
   374 
   375 		}
   376 	
   377 	if(r!=KErrNone)
   378 		Print(_L("BTrace Dump: Handler returned error.\r\n"));
   379 	}
   380 
   381 _LIT8(KPassword, "replacement");
   382 void CrashDebugger::WaitForSensibleInput()
   383 	{
   384 	TBuf8<80> buf;
   385 	while (buf!=KPassword)
   386 		Input(buf, "Password: ");
   387 	}
   388 
   389 void CrashDebugger::DisplayHelp()
   390 	{
   391 	//              1234567890123456789012345678901234567890123456789012345678901234567890123456890
   392 	Monitor::Print("The following commands are available:\r\n");
   393 	Monitor::Print("\r\n");
   394 	Monitor::Print("  c NUM       Display the contents of container NUM (defined by TObjectType)\r\n");
   395 	Monitor::Print("  C NUM       Display the contents of a container, pausing after each screen\r\n");
   396 	Monitor::Print("  f           Display fault information\r\n");
   397 	Monitor::Print("  h           Display this help message\r\n");
   398 	Monitor::Print("  i           Display info about the kernel and the current thread and process\r\n");
   399 	Monitor::Print("  m STRT  END READSIZE  Dump memory between STRT and END\r\n");
   400 	Monitor::Print("	Where READSIZE is 4 for 4byte,2 for 2byte,and 1 for default byte read\r\n");
   401  	Monitor::Print("  m STRT +LEN READSIZE 	Dump memory between STRT and STRT +LEN\r\n"); 
   402  	Monitor::Print("	Where READSIZE is 4 for 4byte,2 for 2byte,and 1 for default byte read\r\n");
   403 	Monitor::Print("  n ADDR      Display full information about NThread/NSchedulable at address ADDR\r\n");
   404  	Monitor::Print("  o ADDR    Display short information about the object at address ADDR\r\n");
   405 	Monitor::Print("  O ADDR    Display full information about the object at address ADDR\r\n");
   406 	Monitor::Print("  p ADDR|all  Display short information about given or all code segments\r\n");
   407 	Monitor::Print("  P ADDR|all  Display full information about given or all code segments\r\n");
   408 	Monitor::Print("  r           Display the contents of the CPU registers\r\n");
   409 	Monitor::Print("  S           Dump the contents all thread stacks and \r\n");
   410     Monitor::Print("              Dump IRQ and FIQ exception stacks \r\n");
   411 	Monitor::Print("  x           Perform a soft reset\r\n");
   412 	Monitor::Print("  X           Perform a hard reset\r\n");
   413 	Monitor::Print("  z STRT  END READSIZE	Dump memory between STRT and END ignoring access faults\r\n"); 
   414 	Monitor::Print("	Where READSIZE is 4 for 4byte,2 for 2byte,and 1 for default byte read\r\n");
   415 	Monitor::Print("  z STRT +LEN READSIZE	Dump memory between STRT and STRT+LEN ignoring access faults\r\n");
   416 	Monitor::Print("	Where READSIZE is 4 for 4byte,2 for 2byte,and 1 for default byte read\r\n");
   417 	Monitor::Print("  a ADDR       Switch address space to the process at address ADDR\r\n");
   418 	Monitor::Print("  A ADDR       Switch address space to the process at address ADDR (fix PD)\r\n");
   419 	Monitor::Print("  B [zip] [no]wait  Dump contents of BTrace buffer in raw binary form.\r\n");
   420 	Monitor::Print("  h            Display this help message\r\n");
   421 	Monitor::Print("  ?            Display this help message\r\n");
   422 	Monitor::Print("\r\n");
   423 	Monitor::Print("All numbers should be given in hex.\r\n");
   424 	}
   425 
   426 TInt CrashDebugger::DoCommandL()
   427 	{
   428 	TBuf8<80> in;
   429 	Input(in, ".");
   430 	TInt i=0;
   431 	SkipSpaces(in,i);
   432 	TInt l=in.Length();
   433 	if (i<l)
   434 		{
   435 		char c=(char)in[i++];
   436 		SkipSpaces(in,i);
   437 		switch (c)
   438 			{
   439 			case 'm': ProcessMemDumpCommand(in,i,EFalse); break;
   440 			case 'z': ProcessMemDumpCommand(in,i,ETrue); break;
   441 			case 'i': ProcessInfoCommand(in,i); break;
   442 			case 'n': ProcessNThreadDumpCommand(in,i); break;
   443 			case 'o': ProcessObjectDumpCommand(in,i); break;
   444 			case 'O':
   445 			case 'q': ProcessObjectFullDumpCommand(in,i); break;
   446 			case 'p': DisplayCodeSegCommand(in,i,EFalse); break;
   447 			case 'P': DisplayCodeSegCommand(in,i,ETrue); break;
   448 			case 'f': DisplayFaultInfo(); break;
   449 			case 'C': ProcessDumpObjectContainer(in,i,ETrue); break;
   450 			case 'c': ProcessDumpObjectContainer(in,i,EFalse); break;
   451 			case 'r': DumpCpuRegisters(); break;
   452 			case 'S': DumpThreadStacks(ETrue); DumpExceptionStacks(); break;
   453 			case 'x': return ESoftRestart; 
   454 			case 'X': return EHardRestart;
   455 			case 'a': ProcessAddressSpaceSwitchCommand(in, i, EFalse); break;
   456 			case 'A': ProcessAddressSpaceSwitchCommand(in, i, ETrue); break;
   457 			case 'B': ProcessBTrace(in, i); break;
   458 			case '?':
   459 			case 'h': DisplayHelp(); break;
   460 			default:  UnknownCommand(); break;
   461 			}
   462 		}
   463 	return KErrNone;
   464 	}
   465 
   466 TInt CrashDebugger::Init2(TAny* aCategory, TInt aReason)
   467 	{
   468 	if(KDebugNum(KDEBUGMONITORDISABLE))
   469 		{
   470 		return KErrNone;
   471 		}	
   472 	iFrame=NULL;
   473 	iFaultCategory=*(const TDesC8*)aCategory;
   474 	iFaultReason=aReason;
   475 	Epoc::SetMonitorExceptionHandler((TLinAddr)HandleException);
   476 	CpuInit();
   477 	QuadrupleBeepAndPowerDown();
   478 
   479 	InitUart();
   480 	InitialInputPtr = InitialInput;
   481 	WaitForSensibleInput();
   482 	NewLine();
   483 	Monitor::Print("*** DEBUG MONITOR v2 ***\r\n");
   484 	Monitor::Print("Type h for help\r\n\r\n");
   485 	FOREVER
   486 		{
   487 		TInt restartType=0;
   488 		MTRAPD(trap,restartType=DoCommandL())
   489 		if (trap!=KErrNone)
   490 			ProcessError(trap);
   491 		if (restartType)
   492 			return restartType;
   493 		}
   494 	}
   495 
   496 GLDEF_C TInt KernelModuleEntry(TInt aReason)
   497 	{
   498 	if(aReason==KModuleEntryReasonVariantInit0)
   499 		{
   500 		__KTRACE_OPT(KALWAYS,Kern::Printf("Installing crash debugger extension"));
   501 		new(&gDebugGzip) TCrashDebugGzip;
   502 		new(&TheCrashDebugger) CrashDebugger;
   503 		Monitor::RegisterMonitorImpl(&TheCrashDebugger);
   504 		return KErrNone;
   505 		}
   506 	else if(aReason==KModuleEntryReasonExtensionInit0)
   507 		{
   508 		// Returning an error here ensures that we aren't called a third time
   509 		// with aReason == KModuleEntryReasonExtensionInit1
   510 		return KErrGeneral;
   511 		}
   512 	return KErrArgument;
   513 	}
   514