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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32\kernel\smondebug.cpp
15 // interactive crash debugger -- crash debugger code specific to the interactive
20 #include <kernel/monitor.h>
21 #include "crashdebug_gzip.h"
23 GLDEF_D TCrashDebugGzip gDebugGzip;
24 GLDEF_D CrashDebugger TheCrashDebugger;
26 const char* InitialInputPtr;
28 #if 1 /*#ifndef __X86__*/
29 const char* InitialInput="";
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";
34 CrashDebugger::CrashDebugger()
35 : iEncoder(&gDebugGzip) {}
38 void CrashDebugger::Print(const TDesC8& aDes)
40 const TUint8* p=aDes.Ptr();
46 void CrashDebugger::Pause(TBool aPause)
48 if (aPause && *InitialInputPtr)
54 void CrashDebugger::UnknownCommand()
56 Print(_L8("Unknown command - type h for help\r\n"));
59 void CrashDebugger::SyntaxError()
61 Print(_L8("Syntax error - type h for help\r\n"));
64 void CrashDebugger::ProcessDumpObjectContainer(const TDesC8& aDes, TInt& i, TBool aPause)
67 TInt r=ReadHex(aDes,i,index);
73 DumpObjectContainer(index,aPause);
76 TInt CrashDebugger::ReadHex(const TDesC8& in, TInt& i, TUint& r)
91 else if (c>='A' && c<='F')
102 void CrashDebugger::SkipSpaces(const TDesC8& in, TInt& i)
105 while(i<l && (in[i]==' ' || in[i]=='\t')) i++;
108 void CrashDebugger::ProcessMemDumpCommand(const TDesC8& aDes, TInt& i, TBool aDiscontiguous)
115 TInt r=ReadHex(aDes,i,start);
119 if (i==aDes.Length())
123 if (i<aDes.Length() && aDes[i]=='+')
125 r=ReadHex(aDes,i,end);
133 length=(TInt)(end-start+1);
148 DoDiscontiguousMemoryDumpL(start,length);
152 DoMemoryDumpL(start,length);
157 readSize=(TUint)aDes[i];
158 TInt r=ReadHex(aDes,i,readSize);
164 if(readSize == 0x0 || readSize == 0x3 || readSize >= 0x5)
170 DoDiscontiguousMemoryDumpL(start,length,readSize);
174 DoMemoryDumpL(start,length,readSize);
180 void CrashDebugger::ProcessNThreadDumpCommand(const TDesC8& aDes, TInt& i)
183 TInt r=ReadHex(aDes,i,addr);
189 DisplayNThreadInfo((NThread*)addr);
192 void CrashDebugger::ProcessObjectDumpCommand(const TDesC8& aDes, TInt& i)
195 TInt r=ReadHex(aDes,i,addr);
204 void CrashDebugger::ProcessObjectFullDumpCommand(const TDesC8& aDes, TInt& i)
207 TInt r=ReadHex(aDes,i,addr);
213 ObjectFullDump(addr);
216 void CrashDebugger::ProcessAddressSpaceSwitchCommand(const TDesC8& aDes, TInt& i, TBool aForce)
219 TInt r=ReadHex(aDes,i,addr);
225 r = SwitchAddressSpace((DProcess*)addr, aForce);
229 Print(_L8("Invalid process address\r\n")); break;
231 Print(_L8("Process is corrupt\r\n")); break;
235 Print(_L8("Unknown error\r\n")); break;
239 void CrashDebugger::Input(TDes8& aDes, const char* aPrompt)
241 TInt m=aDes.MaxLength();
242 TUint8* p=(TUint8*)aDes.Ptr();
245 Monitor::Print(aPrompt);
251 c = *InitialInputPtr;
256 } while(c==0x0a); // ignore LF's
274 _LIT8(KAllCommand, "all");
275 void CrashDebugger::DisplayCodeSegCommand(const TDesC8& aDes, TInt& ai, TBool aFull)
280 if (aDes.Mid(ai)==KAllCommand)
282 MTRAP(r,DisplayCodeSeg(aFull));
286 else if (ReadHex(aDes,ai,addr)==KErrNone)
288 MTRAP(r,DisplayCodeSeg((DCodeSeg*) addr,aFull));
297 _LIT8(KWaitCommand, "wait");
298 _LIT8(KNowaitCommand, "nowait");
299 _LIT8(KZipCommand, "zip");
300 void CrashDebugger::ProcessBTrace(const TDesC8& aDes, TInt& ai)
304 TInt lenZipCommand = ((TDesC8)KZipCommand).Length();
306 if (aDes.Mid(ai, lenZipCommand)==KZipCommand)
310 SkipSpaces(aDes, ai);
313 if (aDes.Mid(ai)==KWaitCommand)
315 else if (aDes.Mid(ai)==KNowaitCommand)
324 iEncoder->SetOutput(this);
328 TInt r = BTrace::Control(BTrace::ECtrlCrashReadFirst,&data,&size);
333 Print(_L8("BTrace Dump: Buffer is empty.\r\n"));
339 Print(_L8("BTrace Dump: Press any key to start...\r\n"));
347 TPtrC8 ptr(data, size);
348 iEncoder->Write(ptr);
356 r = BTrace::Control(BTrace::ECtrlCrashReadNext,&data,&size);
358 while(size && r==KErrNone);
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");
366 iEncoder->FlushEnd();
373 iEncoder->FlushEnd();
378 Print(_L("BTrace Dump: Handler returned error.\r\n"));
381 _LIT8(KPassword, "replacement");
382 void CrashDebugger::WaitForSensibleInput()
385 while (buf!=KPassword)
386 Input(buf, "Password: ");
389 void CrashDebugger::DisplayHelp()
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");
426 TInt CrashDebugger::DoCommandL()
435 char c=(char)in[i++];
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;
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;
459 case 'h': DisplayHelp(); break;
460 default: UnknownCommand(); break;
466 TInt CrashDebugger::Init2(TAny* aCategory, TInt aReason)
468 if(KDebugNum(KDEBUGMONITORDISABLE))
473 iFaultCategory=*(const TDesC8*)aCategory;
474 iFaultReason=aReason;
475 Epoc::SetMonitorExceptionHandler((TLinAddr)HandleException);
477 QuadrupleBeepAndPowerDown();
480 InitialInputPtr = InitialInput;
481 WaitForSensibleInput();
483 Monitor::Print("*** DEBUG MONITOR v2 ***\r\n");
484 Monitor::Print("Type h for help\r\n\r\n");
488 MTRAPD(trap,restartType=DoCommandL())
496 GLDEF_C TInt KernelModuleEntry(TInt aReason)
498 if(aReason==KModuleEntryReasonVariantInit0)
500 __KTRACE_OPT(KALWAYS,Kern::Printf("Installing crash debugger extension"));
501 new(&gDebugGzip) TCrashDebugGzip;
502 new(&TheCrashDebugger) CrashDebugger;
503 Monitor::RegisterMonitorImpl(&TheCrashDebugger);
506 else if(aReason==KModuleEntryReasonExtensionInit0)
508 // Returning an error here ensures that we aren't called a third time
509 // with aReason == KModuleEntryReasonExtensionInit1