Enhance the base/rom extension to generate the symbol file of the rom built.
The symbol file is placed in epoc32/rom/<baseport_name>, along with the rom log and final oby file.
// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// e32\kernel\smondebug.cpp
// interactive crash debugger -- crash debugger code specific to the interactive
// instance
//
//
#include <kernel/monitor.h>
#include "crashdebug_gzip.h"
GLDEF_D TCrashDebugGzip gDebugGzip;
GLDEF_D CrashDebugger TheCrashDebugger;
const char* InitialInputPtr;
#if 1 /*#ifndef __X86__*/
const char* InitialInput="";
#else
const char* InitialInput="replacement\rf\ri\rr\rc0\rc1\rc2\rc3\rc4\rc5\rc6\rc7\rc8\rc9\rca\rcb\rcc\rcd\rce\rcf\r";
#endif
CrashDebugger::CrashDebugger()
: iEncoder(&gDebugGzip) {}
void CrashDebugger::Print(const TDesC8& aDes)
{
const TUint8* p=aDes.Ptr();
TInt l=aDes.Length();
for (; l; --l)
UartOut(*p++);
}
void CrashDebugger::Pause(TBool aPause)
{
if (aPause && *InitialInputPtr)
{
UartIn();
}
}
void CrashDebugger::UnknownCommand()
{
Print(_L8("Unknown command - type h for help\r\n"));
}
void CrashDebugger::SyntaxError()
{
Print(_L8("Syntax error - type h for help\r\n"));
}
void CrashDebugger::ProcessDumpObjectContainer(const TDesC8& aDes, TInt& i, TBool aPause)
{
TUint index;
TInt r=ReadHex(aDes,i,index);
if(r!=KErrNone)
{
SyntaxError();
return;
}
DumpObjectContainer(index,aPause);
}
TInt CrashDebugger::ReadHex(const TDesC8& in, TInt& i, TUint& r)
{
r=0;
TInt l=in.Length();
SkipSpaces(in,i);
if (i==l)
return KErrGeneral;
TInt j=i;
while(i<l)
{
char c=(char)in[i];
if (c>='a' && c<='z')
c&=0xdf;
if (c>='0' && c<='9')
c-='0';
else if (c>='A' && c<='F')
c-=('A'-10);
else break;
r=(r<<4)+(TUint)c;
i++;
}
if (i==j)
return KErrGeneral;
return KErrNone;
}
void CrashDebugger::SkipSpaces(const TDesC8& in, TInt& i)
{
TInt l=in.Length();
while(i<l && (in[i]==' ' || in[i]=='\t')) i++;
}
void CrashDebugger::ProcessMemDumpCommand(const TDesC8& aDes, TInt& i, TBool aDiscontiguous)
{
TUint start;
TUint end;
TInt length=0;
TBool add=EFalse;
TUint readSize;
TInt r=ReadHex(aDes,i,start);
if (r==KErrNone)
{
SkipSpaces(aDes,i);
if (i==aDes.Length())
end=start;
else
{
if (i<aDes.Length() && aDes[i]=='+')
i++, add=ETrue;
r=ReadHex(aDes,i,end);
}
}
if (r==KErrNone)
{
if (add)
length=(TInt)end;
else
length=(TInt)(end-start+1);
if (length<0)
r=KErrGeneral;
}
if (r!=KErrNone)
{
SyntaxError();
return;
}
SkipSpaces(aDes,i);
if(i==aDes.Length())
{
if (aDiscontiguous)
{
DoDiscontiguousMemoryDumpL(start,length);
}
else
{
DoMemoryDumpL(start,length);
}
}
else
{
readSize=(TUint)aDes[i];
TInt r=ReadHex(aDes,i,readSize);
if (r!=KErrNone)
{
SyntaxError();
return;
}
if(readSize == 0x0 || readSize == 0x3 || readSize >= 0x5)
{
UnknownCommand();
}
if(aDiscontiguous)
{
DoDiscontiguousMemoryDumpL(start,length,readSize);
}
else
{
DoMemoryDumpL(start,length,readSize);
}
}
}
void CrashDebugger::ProcessNThreadDumpCommand(const TDesC8& aDes, TInt& i)
{
TUint addr;
TInt r=ReadHex(aDes,i,addr);
if (r!=KErrNone)
{
SyntaxError();
return;
}
DisplayNThreadInfo((NThread*)addr);
}
void CrashDebugger::ProcessObjectDumpCommand(const TDesC8& aDes, TInt& i)
{
TUint addr;
TInt r=ReadHex(aDes,i,addr);
if (r!=KErrNone)
{
SyntaxError();
return;
}
ObjectDump(addr);
}
void CrashDebugger::ProcessObjectFullDumpCommand(const TDesC8& aDes, TInt& i)
{
TUint addr;
TInt r=ReadHex(aDes,i,addr);
if (r!=KErrNone)
{
SyntaxError();
return;
}
ObjectFullDump(addr);
}
void CrashDebugger::ProcessAddressSpaceSwitchCommand(const TDesC8& aDes, TInt& i, TBool aForce)
{
TUint addr;
TInt r=ReadHex(aDes,i,addr);
if (r!=KErrNone)
{
SyntaxError();
return;
}
r = SwitchAddressSpace((DProcess*)addr, aForce);
switch (r)
{
case KErrArgument:
Print(_L8("Invalid process address\r\n")); break;
case KErrCorrupt:
Print(_L8("Process is corrupt\r\n")); break;
case KErrNone:
break;
default:
Print(_L8("Unknown error\r\n")); break;
}
}
void CrashDebugger::Input(TDes8& aDes, const char* aPrompt)
{
TInt m=aDes.MaxLength();
TUint8* p=(TUint8*)aDes.Ptr();
TUint8* q=p;
TUint8* e=p+m;
Monitor::Print(aPrompt);
TUint c=0xffffffff;
FOREVER
{
do
{
c = *InitialInputPtr;
if (c)
++InitialInputPtr;
else
c=UartIn();
} while(c==0x0a); // ignore LF's
if (c==0x0d)
{
NewLine();
break;
}
else if (c==0x08)
{
if (q>p)
--q;
}
else if (q<e)
*q++=(TUint8)c;
UartOut(c);
}
aDes.SetLength(q-p);
}
_LIT8(KAllCommand, "all");
void CrashDebugger::DisplayCodeSegCommand(const TDesC8& aDes, TInt& ai, TBool aFull)
{
TInt r;
TUint addr;
SkipSpaces(aDes,ai);
if (aDes.Mid(ai)==KAllCommand)
{
MTRAP(r,DisplayCodeSeg(aFull));
if (r!=KErrNone)
ProcessError(r);
}
else if (ReadHex(aDes,ai,addr)==KErrNone)
{
MTRAP(r,DisplayCodeSeg((DCodeSeg*) addr,aFull));
if (r!=KErrNone)
ProcessError(r);
}
else
SyntaxError();
}
_LIT8(KWaitCommand, "wait");
_LIT8(KNowaitCommand, "nowait");
_LIT8(KZipCommand, "zip");
void CrashDebugger::ProcessBTrace(const TDesC8& aDes, TInt& ai)
{
TBool zip = EFalse;
TBool wait;
TInt lenZipCommand = ((TDesC8)KZipCommand).Length();
if (aDes.Mid(ai, lenZipCommand)==KZipCommand)
{
zip = ETrue;
ai += lenZipCommand;
SkipSpaces(aDes, ai);
}
if (aDes.Mid(ai)==KWaitCommand)
wait = ETrue;
else if (aDes.Mid(ai)==KNowaitCommand)
wait = EFalse;
else
{
SyntaxError();
return;
}
if (zip)
iEncoder->SetOutput(this);
TUint8* data;
TUint size;
TInt r = BTrace::Control(BTrace::ECtrlCrashReadFirst,&data,&size);
if(r==KErrNone)
{
if(size==0)
{
Print(_L8("BTrace Dump: Buffer is empty.\r\n"));
return;
}
if(wait)
{
Print(_L8("BTrace Dump: Press any key to start...\r\n"));
UartIn();
}
do
{
if (zip)
{
TPtrC8 ptr(data, size);
iEncoder->Write(ptr);
size = 0;
}
else
{
do UartOut(*data++);
while(--size);
}
r = BTrace::Control(BTrace::ECtrlCrashReadNext,&data,&size);
}
while(size && r==KErrNone);
if(wait)
{
// this is also a valid BTrace 'EKernPrintf' trace...
_LIT(dumpEndText,"\060\000\001\001\377\377\377\377\r\nBTrace Dump: Done - press any key...\r\n");
if (zip)
{
iEncoder->FlushEnd();
}
else
Print(dumpEndText);
UartIn();
}
else if (zip)
iEncoder->FlushEnd();
}
if(r!=KErrNone)
Print(_L("BTrace Dump: Handler returned error.\r\n"));
}
_LIT8(KPassword, "replacement");
void CrashDebugger::WaitForSensibleInput()
{
TBuf8<80> buf;
while (buf!=KPassword)
Input(buf, "Password: ");
}
void CrashDebugger::DisplayHelp()
{
// 1234567890123456789012345678901234567890123456789012345678901234567890123456890
Monitor::Print("The following commands are available:\r\n");
Monitor::Print("\r\n");
Monitor::Print(" c NUM Display the contents of container NUM (defined by TObjectType)\r\n");
Monitor::Print(" C NUM Display the contents of a container, pausing after each screen\r\n");
Monitor::Print(" f Display fault information\r\n");
Monitor::Print(" h Display this help message\r\n");
Monitor::Print(" i Display info about the kernel and the current thread and process\r\n");
Monitor::Print(" m STRT END READSIZE Dump memory between STRT and END\r\n");
Monitor::Print(" Where READSIZE is 4 for 4byte,2 for 2byte,and 1 for default byte read\r\n");
Monitor::Print(" m STRT +LEN READSIZE Dump memory between STRT and STRT +LEN\r\n");
Monitor::Print(" Where READSIZE is 4 for 4byte,2 for 2byte,and 1 for default byte read\r\n");
Monitor::Print(" n ADDR Display full information about NThread/NSchedulable at address ADDR\r\n");
Monitor::Print(" o ADDR Display short information about the object at address ADDR\r\n");
Monitor::Print(" O ADDR Display full information about the object at address ADDR\r\n");
Monitor::Print(" p ADDR|all Display short information about given or all code segments\r\n");
Monitor::Print(" P ADDR|all Display full information about given or all code segments\r\n");
Monitor::Print(" r Display the contents of the CPU registers\r\n");
Monitor::Print(" S Dump the contents all thread stacks and \r\n");
Monitor::Print(" Dump IRQ and FIQ exception stacks \r\n");
Monitor::Print(" x Perform a soft reset\r\n");
Monitor::Print(" X Perform a hard reset\r\n");
Monitor::Print(" z STRT END READSIZE Dump memory between STRT and END ignoring access faults\r\n");
Monitor::Print(" Where READSIZE is 4 for 4byte,2 for 2byte,and 1 for default byte read\r\n");
Monitor::Print(" z STRT +LEN READSIZE Dump memory between STRT and STRT+LEN ignoring access faults\r\n");
Monitor::Print(" Where READSIZE is 4 for 4byte,2 for 2byte,and 1 for default byte read\r\n");
Monitor::Print(" a ADDR Switch address space to the process at address ADDR\r\n");
Monitor::Print(" A ADDR Switch address space to the process at address ADDR (fix PD)\r\n");
Monitor::Print(" B [zip] [no]wait Dump contents of BTrace buffer in raw binary form.\r\n");
Monitor::Print(" h Display this help message\r\n");
Monitor::Print(" ? Display this help message\r\n");
Monitor::Print("\r\n");
Monitor::Print("All numbers should be given in hex.\r\n");
}
TInt CrashDebugger::DoCommandL()
{
TBuf8<80> in;
Input(in, ".");
TInt i=0;
SkipSpaces(in,i);
TInt l=in.Length();
if (i<l)
{
char c=(char)in[i++];
SkipSpaces(in,i);
switch (c)
{
case 'm': ProcessMemDumpCommand(in,i,EFalse); break;
case 'z': ProcessMemDumpCommand(in,i,ETrue); break;
case 'i': ProcessInfoCommand(in,i); break;
case 'n': ProcessNThreadDumpCommand(in,i); break;
case 'o': ProcessObjectDumpCommand(in,i); break;
case 'O':
case 'q': ProcessObjectFullDumpCommand(in,i); break;
case 'p': DisplayCodeSegCommand(in,i,EFalse); break;
case 'P': DisplayCodeSegCommand(in,i,ETrue); break;
case 'f': DisplayFaultInfo(); break;
case 'C': ProcessDumpObjectContainer(in,i,ETrue); break;
case 'c': ProcessDumpObjectContainer(in,i,EFalse); break;
case 'r': DumpCpuRegisters(); break;
case 'S': DumpThreadStacks(ETrue); DumpExceptionStacks(); break;
case 'x': return ESoftRestart;
case 'X': return EHardRestart;
case 'a': ProcessAddressSpaceSwitchCommand(in, i, EFalse); break;
case 'A': ProcessAddressSpaceSwitchCommand(in, i, ETrue); break;
case 'B': ProcessBTrace(in, i); break;
case '?':
case 'h': DisplayHelp(); break;
default: UnknownCommand(); break;
}
}
return KErrNone;
}
TInt CrashDebugger::Init2(TAny* aCategory, TInt aReason)
{
if(KDebugNum(KDEBUGMONITORDISABLE))
{
return KErrNone;
}
iFrame=NULL;
iFaultCategory=*(const TDesC8*)aCategory;
iFaultReason=aReason;
Epoc::SetMonitorExceptionHandler((TLinAddr)HandleException);
CpuInit();
QuadrupleBeepAndPowerDown();
InitUart();
InitialInputPtr = InitialInput;
WaitForSensibleInput();
NewLine();
Monitor::Print("*** DEBUG MONITOR v2 ***\r\n");
Monitor::Print("Type h for help\r\n\r\n");
FOREVER
{
TInt restartType=0;
MTRAPD(trap,restartType=DoCommandL())
if (trap!=KErrNone)
ProcessError(trap);
if (restartType)
return restartType;
}
}
GLDEF_C TInt KernelModuleEntry(TInt aReason)
{
if(aReason==KModuleEntryReasonVariantInit0)
{
__KTRACE_OPT(KALWAYS,Kern::Printf("Installing crash debugger extension"));
new(&gDebugGzip) TCrashDebugGzip;
new(&TheCrashDebugger) CrashDebugger;
Monitor::RegisterMonitorImpl(&TheCrashDebugger);
return KErrNone;
}
else if(aReason==KModuleEntryReasonExtensionInit0)
{
// Returning an error here ensures that we aren't called a third time
// with aReason == KModuleEntryReasonExtensionInit1
return KErrGeneral;
}
return KErrArgument;
}