Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h)
Have multiple extension sections in the bld.inf, one for each version
of the compiler. The RVCT version building the tools will build the
runtime libraries for its version, but make sure we extract all the other
versions from zip archives. Also add the archive for RVCT4.
// 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:
//
#include <e32base.h>
#include <e32base_private.h>
#include <e32cmn.h>
#include <e32cmn_private.h>
#include <e32debug.h>
#include <e32property.h>
#include "t_rmdebug_app.h"
IMPORT_C extern void RMDebug_BranchTst2();
LOCAL_C void ParseCommandLineL(TInt32& aFunctionType, TUint& aDelay, TUint& aExtraThreads)
{
// get the length of the command line arguments
TInt argc = User::CommandLineLength();
// allocate a buffer for the command line arguments and extract the data to it
HBufC* commandLine = HBufC::NewLC(argc);
TPtr commandLineBuffer = commandLine->Des();
User::CommandLine(commandLineBuffer);
// create a lexer and read through the command line
TLex lex(*commandLine);
while (!lex.Eos())
{
// expecting the first character to be a '-'
if (lex.Get() == '-')
{
TChar arg = lex.Get();
switch (arg)
{
case 'f':
// the digits following '-f' give the function type
User::LeaveIfError(lex.Val(aFunctionType));
break;
case 'd':
// the digits following '-d' give the delay
User::LeaveIfError(lex.Val(aDelay));
break;
case 'e':
// the digits following '-e' give the number of extra threads to launch
User::LeaveIfError(lex.Val(aExtraThreads));
break;
default:
// unknown argument so leave
User::Leave(KErrArgument);
}
lex.SkipSpace();
}
else
{
// unknown argument so leave
User::Leave(KErrArgument);
}
}
// do clean up
CleanupStack::PopAndDestroy(commandLine);
}
typedef void (*TPfun)();
// test function to call corresponding to EPrefetchAbortFunction
void PrefetchAbort()
{
TPfun f = NULL;
f();
}
// test function to call corresponding to EUserPanicFunction
void UserPanic()
{
User::Panic(KUserPanic, KUserPanicCode);
}
// calls self repeatedly until stack is used up. Slightly convoluted to prevent UREL optimising this out...
TUint32 StackOverFlowFunction(TUint32 aInt=0)
{
TUint32 unusedArray[150];
for(TInt i=0; i<150; i++)
{
unusedArray[i] = StackOverFlowFunction(i);
}
return unusedArray[0];
}
void DataAbort()
{
TInt* r = (TInt*) 0x1000;
*r = 0x42;
}
void UndefInstruction()
{
TUint32 undef = 0xE6000010;
TPfun f = (TPfun) &undef;
f();
}
TInt DataRead()
{
TInt* r = (TInt*) 0x1000;
TInt rr = (TInt)*r;
//include the following line to ensure that rr doesn't get optimised out
RDebug::Printf("Shouldn't see this being printed out: %d", rr);
// Stop compilation warning. Should not get here anyway.
rr++;
return rr;
}
void DataWrite()
{
TInt* r = (TInt*) 0x1000;
*r = 0x42;
}
void UserException()
{
User::RaiseException(EExcGeneral);
}
void SpinForeverWithBreakPoint()
{
// finding the process t_rmdebug2/t_rmdebug2_oem/t_rmdebug2_oem2
// we find the process.SID to attach to the property
_LIT(KThreadWildCard, "t_rmdebug2*");
TInt err = KErrNone;
TUid propertySid = KNullUid;
TFindThread find(KThreadWildCard);
TFullName name;
TBool found = EFalse;
while(find.Next(name)==KErrNone && !found)
{
RThread thread;
err = thread.Open(find);
if (err == KErrNone)
{
RProcess process;
thread.Process(process);
TFullName fullname = thread.FullName();
//RDebug::Printf("SID Search Match Found Name %lS Process ID%ld Thread Id %ld", &fullname, process.Id().Id(), thread.Id().Id());
found = ETrue;
//SID saved so that the property can be attached to
propertySid = process.SecureId();
process.Close();
}
thread.Close();
}
//attach to the property to publish the address of the RMDebug_BranchTst2 with the correct SID value
RProperty integerProperty;
err = integerProperty.Attach(propertySid, EMyPropertyInteger, EOwnerThread);
if(KErrNone != err)
RDebug::Printf("Error Attach to the property %d", err);
TInt address = (TInt)&RMDebug_BranchTst2;
// publish the address where the breakpoint would be set
err = integerProperty.Set(address);
if(KErrNone != err)
RDebug::Printf("Error Set of the property %d", err);
integerProperty.Close();
//open semaphore to signal the fact we have reached the point where we have to set the property
RSemaphore globsem;
globsem.OpenGlobal(_L("RMDebugGlobSem"));
globsem.Signal();
globsem.Close();
RProcess thisProcess;
TFileName thisProcessName = thisProcess.FileName();
RDebug::Printf("App Process Name %lS process id %ld thread id %ld", &thisProcessName, thisProcess.Id().Id(), RThread().Id().Id());
TInt i=0;
RThread::Rendezvous(KErrNone);
while(i<0xffffffff)
{
RMDebug_BranchTst2();
User::After(10000);
}
}
void SpinForever()
{
TInt i=0;
RThread::Rendezvous(KErrNone);
while(i<0xffffffff)
{
User::After(10000);
}
}
void LaunchThreads(TUint aNumber)
{
_LIT(KDebugThreadName, "DebugThread");
const TUint KDebugThreadDefaultHeapSize=0x10000;
for(TInt i=0; i<aNumber; i++)
{
RThread thread;
RBuf threadName;
threadName.Create(KDebugThreadName().Length()+10); // the 10 is for appending i to the end of the name
threadName.Append(KDebugThreadName());
threadName.AppendNum(i);
TInt err = thread.Create(threadName, (TThreadFunction)SpinForever, KDefaultStackSize, KDebugThreadDefaultHeapSize, KDebugThreadDefaultHeapSize, NULL);
if(err != KErrNone)
{
RDebug::Printf("Couldn't create thread %d", err);
threadName.Close();
thread.Close();
break;
}
thread.SetPriority(EPriorityNormal);
TRequestStatus status;
thread.Rendezvous(status);
thread.Resume();
User::WaitForRequest(status);
thread.Close();
threadName.Close();
}
}
void WaitFiveSecondsThenExit(void)
{
// wait for 5 seconds
User::After(5000000);
}
// call the function corresponding to aFunctionType
LOCAL_C void CallFunction(TDebugFunctionType aFunctionType, TUint aDelay, TUint aExtraThreads)
{
// pause for aDelay microseconds
User::After(aDelay);
// launch the extra threads
LaunchThreads(aExtraThreads);
// call appropriate function
switch( aFunctionType )
{
case EPrefetchAbortFunction:
PrefetchAbort();
break;
case EUserPanicFunction:
UserPanic();
break;
case EStackOverflowFunction:
StackOverFlowFunction();
break;
case EDataAbortFunction:
DataAbort();
break;
case EUndefInstructionFunction:
UndefInstruction();
break;
case EDataReadErrorFunction:
DataRead();
break;
case EDataWriteErrorFunction:
DataWrite();
break;
case EUserExceptionFunction:
UserException();
break;
case EWaitFiveSecondsThenExit:
WaitFiveSecondsThenExit();
break;
case ESpinForever:
SpinForever();
break;
case ESpinForeverWithBreakPoint:
SpinForeverWithBreakPoint();
break;
case EDefaultDebugFunction:
default:
break;
}
}
void PrintHelp()
{
RDebug::Printf("Invoke with arguments:\n");
RDebug::Printf("\t-d<delay>\n\t: delay in microseconds before calling target function\n");
RDebug::Printf("\t-f<function-number>\n\t: enumerator from TDebugFunctionType representing function to call\n");
RDebug::Printf("\t-e<number>\n\t: number of extra threads to launch, these threads run endlessly\n");
}
TInt E32Main()
{
// setup heap checking and clean up trap
__UHEAP_MARK;
CTrapCleanup* cleanup=CTrapCleanup::New();
RThread().SetPriority(EPriorityNormal);
RProcess::Rendezvous(KErrNone);
// read arguments from command line
TUint delay = 0;
TInt32 functionTypeAsTInt32 = (TInt32)EDefaultDebugFunction;
TUint extraThreads = 0;
TRAPD(err, ParseCommandLineL(functionTypeAsTInt32, delay, extraThreads));
if(KErrNone == err)
{
// if the command line arguments were successfully read then call the appropriate function
CallFunction((TDebugFunctionType)functionTypeAsTInt32, delay, extraThreads);
}
// perform clean up and return any error which was recorded
delete cleanup;
__UHEAP_MARKEND;
return err;
}