dbgsrv/coredumpserver/test/crashapps/src/d_crashdriver_ldd.cpp
changeset 0 c6b0df440bee
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dbgsrv/coredumpserver/test/crashapps/src/d_crashdriver_ldd.cpp	Tue Mar 02 10:33:16 2010 +0530
@@ -0,0 +1,593 @@
+// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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 "t_crashdriver_drv.h"
+#include "d_crashdriver_ldd.h"
+#include "crash.h"
+#include <arm_types.h>
+//#include <scmonitor.h>
+
+/**
+ * Utility method to append a string to a kernel side descriptor
+ */
+void AppendString(TDes8& aDes, const char* aFmt, ...)
+	{
+	VA_LIST list;
+	VA_START(list,aFmt);
+	Kern::AppendFormat(aDes,aFmt,list);
+	}
+
+/**
+ * DCrashDriverFactory
+ * Standard export function for LDDs. This creates a DLogicalDevice derived object,
+ * in this case, our DCrashDriverFactory
+ */
+DECLARE_STANDARD_LDD()
+    {
+    return new DCrashDriverFactory;
+    }
+
+/**
+ * Constructor
+ */
+DCrashDriverFactory::DCrashDriverFactory()
+    {
+    // Set version number for this device
+    iVersion=RKernelCrashDrv::VersionRequired();
+    }
+     
+     
+/**
+  Destructor
+*/
+DCrashDriverFactory::~DCrashDriverFactory()
+    {
+    }
+
+/**
+  Second stage constructor for DKernelCrashAppFactory.
+  This must at least set a name for the driver object.
+
+  @return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DCrashDriverFactory::Install()
+    {
+    return SetName(&RKernelCrashDrv::Name());
+    }
+
+/**
+  Return the drivers capabilities.
+  Called in the response to an RDevice::GetCaps() request.
+
+  @param aDes Descriptor into which capabilities information is to be written.
+*/
+void DCrashDriverFactory::GetCaps(TDes8& aDes) const
+    {
+    // Create a capabilities object
+    RKernelCrashDrv::TCaps caps;
+    caps.iVersion = iVersion;
+    // Write it back to user memory
+    Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps));
+    }
+
+
+/**
+  Called by the kernel's device driver framework to create a Logical Channel.
+  This is called in the context of the user thread (client) which requested the creation
+  of the Logical Channel (e.g. through a call to RBusLogicalChannel::DoCreate).
+  The thread is in a critical section.
+
+  @param aChannel Set to point to the created Logical Channel
+
+  @return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DCrashDriverFactory::Create(DLogicalChannelBase*& aChannel)
+    {
+    aChannel=new DCrashDriverChannel;
+    if(!aChannel)
+        return KErrNoMemory;
+
+    return KErrNone;
+    }
+
+
+//
+// Logical Channel
+//
+
+/**
+  Constructor
+*/
+DCrashDriverChannel::DCrashDriverChannel() :
+	iDfcQ(NULL)
+    {
+    // Get pointer to client thread's DThread object
+    iClient=&Kern::CurrentThread();
+
+    // Open a reference on client thread so its control block can't disappear until
+    // this driver has finished with it.
+    // Note, this call to Open() can't fail since it is the thread we are currently running in.
+    iClient->Open();
+    recurseCount = 0;
+    }
+
+
+/**
+  Destructor
+*/
+DCrashDriverChannel::~DCrashDriverChannel()
+    {
+    if(iDfcQ)
+    	iDfcQ->Destroy();
+    
+    // Cancel all processing that we may be doing
+    //DoCancel(RKernelCrashApp::EAllRequests); not needed as of now check while debugging - praveenc
+    //Close our reference on the client thread
+    Kern::SafeClose((DObject*&)iClient,NULL);
+    }
+
+
+/**
+  Second stage constructor called by the kernel's device driver framework.
+  This is called in the context of the user thread (client) which requested the creation
+  of the Logical Channel (e.g. through a call to RBusLogicalChannel::DoCreate())
+  The thread is in a critical section.
+
+  @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate()
+  @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate()
+  @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate()
+
+  @return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DCrashDriverChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
+    {
+    if(!Kern::CurrentThreadHasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by crashdriver")))
+        return KErrPermissionDenied;
+     
+    // Check version
+    if (!Kern::QueryVersionSupported(RKernelCrashDrv::VersionRequired(),aVer))
+        return KErrNotSupported;
+    
+    // Setup LDD for receiving client messages.
+	TInt err = Kern::DynamicDfcQCreate(iDfcQ, 25, RKernelCrashDrv::Name());
+	if(err != KErrNone)
+		{
+		Kern::Printf("Creating Dfc queue failed.");  	
+		}
+	SetDfcQ(iDfcQ);       
+    iMsgQ.Receive();
+
+    return KErrNone;    
+    }
+
+
+/**
+  Called when a user thread requests a handle to this channel.
+*/
+TInt DCrashDriverChannel::RequestUserHandle(DThread* aThread, TOwnerType aType)
+    {
+    // Make sure that only our client can get a handle
+    if (aType!=EOwnerThread || aThread!=iClient)
+    	{    
+        return KErrAccessDenied;
+    	}
+    return KErrNone;    
+    }
+
+
+/**
+  Process a message for this logical channel.
+  This function is called in the context of a DFC thread.
+
+  @param aMessage The message to process.
+                  The iValue member of this distinguishes the message type:
+                  iValue==ECloseMsg, channel close message
+                  iValue==KMaxTInt, a 'DoCancel' message
+                  iValue>=0, a 'DoControl' message with function number equal to iValue
+                  iValue<0, a 'DoRequest' message with function number equal to ~iValue
+*/
+void DCrashDriverChannel::HandleMsg(TMessageBase* aMsg)
+    {    
+    TThreadMessage& m=*(TThreadMessage*)aMsg;//needs checking -praveenc
+
+    // Get message type
+    TInt id=m.iValue;
+
+    // Decode the message type and dispatch it to the relevent handler function...    
+    if (id==(TInt)ECloseMsg) //check later praveenc
+        {
+        // Channel Close        
+        m.Complete(KErrNone, EFalse);
+        return;
+        }   
+
+    if (id<0)
+        {
+        TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
+        TInt r=DoRequest(~id,pS,m.Ptr1(), m.Ptr2());
+        if (r==KErrNone)
+            Kern::RequestComplete(iClient,pS,r);
+        m.Complete(KErrNone,ETrue);
+        }
+    }
+
+/**
+ * Loop thread - infinite loop so we have a thread in a known state
+ * @param aPtr
+ * @return One of the symbian wide return codes
+ */
+TInt Loop(TAny* aPtr)
+	{    
+    TInt32 array[3];
+	array[0] = 0xDEADDEAD;
+	array[1] = 0xF000BEEF;
+	array[2] = 0xBEEBEE00;
+	
+	//set registers for known state for testing
+	SetRegs();
+	
+	//go into infinite loop
+	InfLoop();
+	
+	return array[0]; //to avoid warning - will never get here anyway
+	}
+
+TInt StartInfLoop()
+	{
+    //set registers for known state for testing
+    SetUpperRegs();
+	
+    //Launch another kernel thread
+    SThreadCreateInfo info;
+    info.iType = EThreadSupervisor;
+    info.iFunction = Loop; 
+    info.iPtr = NULL;
+    info.iSupervisorStack=NULL;
+    info.iSupervisorStackSize=0;    // zero means use default value
+    info.iInitialThreadPriority= 25;
+    info.iName.Set(_L("cdsknownthread"));
+    info.iTotalSize = sizeof(info);
+    
+    NKern::ThreadEnterCS();
+    TInt err = Kern::ThreadCreate(info);
+    NKern::ThreadLeaveCS();
+    
+    if(err != KErrNone)
+    	return err;
+    
+    DThread* kernTh = (DThread*)info.iHandle;
+    Kern::ThreadResume(*kernTh);
+    
+    NKern::Sleep(NKern::TimerTicks(3000)); //wait 3 seconds to ensure our other thread has been scheduled
+    
+    return KErrNone;
+	}
+
+/**
+  Process asynchronous requests
+*/
+TInt DCrashDriverChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
+    {               
+    
+    
+	Kern::Printf("DCrashDriverChannel::DoRequest");
+
+    TInt err = KErrNone;   
+    
+    switch(aReqNo)
+        {      
+        case RKernelCrashDrv::EPrefetchAbort:
+        	{    
+        	err = StartInfLoop();  
+        	if(err != KErrNone)
+        		return err;
+        	PrefetchAbort();
+        	break;
+        	}            
+        case RKernelCrashDrv::EDataRead:
+        	{
+        	err = StartInfLoop();  
+        	if(err != KErrNone)
+        		return err;
+        	DataRead();
+            break;
+        	}
+        case RKernelCrashDrv::EDataWrite:
+        	{
+        	err = StartInfLoop();  
+        	if(err != KErrNone)
+        		return err;
+        	DataWrite();
+            break;
+        	}         
+        case RKernelCrashDrv::EUndefInst:
+        	{
+        	err = StartInfLoop();  
+        	if(err != KErrNone)
+        		return err;
+        	UndefinedInst();
+            break;
+        	}            
+        case RKernelCrashDrv::EDivByZero:
+        	{
+        	err = StartInfLoop();  
+        	if(err != KErrNone)
+        		return err;
+        	DivByZero();
+        	break;
+        	}        	
+        case RKernelCrashDrv::EStackOverflow:
+        	{
+        	err = StartInfLoop();  
+        	if(err != KErrNone)
+        		return err;
+        	StackOverFlow();
+            break;
+        	}
+        case RKernelCrashDrv::ETestSCMConfigInsertMethod:
+        	{
+        	//read the argmuents
+        	HBuf8* tmp = HBuf8::New(KMaxBufferSize);
+        	
+        	TInt err = Kern::ThreadDesRead(iClient, a2, *tmp, 0, 0 );
+			if (err != KErrNone || tmp->MaxLength() < KMaxBufferSize)
+			{				
+				Kern::Printf("Unable to read argument or buffer too small");
+
+				// We could not read information from the user, so the a2 argument is probably wrong
+				Kern::RequestComplete(iClient, aStatus, KErrArgument);
+				return KErrArgument;
+			}
+        	
+			//run the test and gather the results
+			TBool pass;
+			
+			//run test
+        	//TestConfigInsertL(pass, *tmp);
+        	
+        	//write the results back to client thread
+        	err = Kern::ThreadRawWrite(iClient, a1, (TUint8*)&pass, sizeof(TBool), iClient);
+        	if(err != KErrNone)
+        		{
+				Kern::Printf("Unable to write data back to client");
+
+				// We could not read information from the user, so the a2 argument is probably wrong
+				Kern::RequestComplete(iClient, aStatus, KErrArgument);
+				return err;
+        		}
+        	
+        	//and write the buffer back...
+        	err = Kern::ThreadDesWrite(iClient, a2, *tmp, 0, 0, iClient);
+        	if(err != KErrNone)
+        		{
+        		Kern::Printf("Unable to write data back to client");
+        		
+				// We could not read information from the user, so the a2 argument is probably wrong
+				Kern::RequestComplete(iClient, aStatus, KErrArgument);
+				return err;
+        		}
+        	
+        	break;
+        	}
+        default:
+        	{        	
+            err=KErrNotSupported;
+            break;
+        	}
+        }
+
+    return err;
+    }
+
+
+/**
+  Process cancelling of asynchronous requests //need later -praveenc
+*/
+void DCrashDriverChannel::DoCancel(TUint aMask)
+    {
+    //give definition later - praveenc
+    //if(aMask&(1<<RKernelCrashApp::ESendData))
+      //  SendDataCancel();
+    //if(aMask&(1<<RKernelCrashApp::EReceiveData))
+      //  ReceiveDataCancel();
+    }
+
+/**
+ * Method to cause board to crash with a prefetch abort
+ */
+void DCrashDriverChannel::PrefetchAbort()
+	{
+    Tfunc f = NULL;
+    f();
+	}
+
+/**
+ * Method to cause board to read from a location we arent allowed
+ */
+void DCrashDriverChannel::DataRead()
+	{
+	Kern::Printf("Causing a data read crash");
+	TInt* r = (TInt*) 0x1000;
+   	TInt rr = (TInt)*r;
+
+	// Stop compilation warning. Should not get here anyway.
+	rr++;	
+	
+	}
+
+/**
+ * Method to cause board to crash from writing to a location we are not allowed
+ */
+void DCrashDriverChannel::DataWrite()
+	{
+	Kern::Printf("Causing a data write crash");
+  	TInt* r = (TInt*) 0x1000;
+   	*r = 0x42;
+	}
+
+/**
+ * Method to cause board to crash from executing an undefined instruction
+ */
+void DCrashDriverChannel::UndefinedInst()
+	{
+	Kern::Printf("Executing an undefined instruction");
+   	TUint32 undef = 0xE6000010;
+   	Tfunc f = (Tfunc) &undef;
+   	f();
+	}
+
+/**
+ * Method to cause board to crash with a division by zero
+ */
+void DCrashDriverChannel::DivByZero()
+	{
+	Kern::Printf("\tDivision By zero crash...");
+	int x = 5;
+	int y = 5;
+	for(y = 5; y>0; --y)
+		{
+		//this is to avoid compiler errors
+		}
+	x = x/y;
+	}
+
+/**
+ * Method to cause board to crash with a stack overflow
+ */
+void DCrashDriverChannel::StackOverFlow()
+	{
+	Kern::Printf("\tAbout to cause a stackoverflow");
+	TUint32 array[128];
+	array[0] = ++recurseCount;
+	StackOverFlow();
+	TUint warnRem = array[0];
+	array[0] = warnRem;
+	}
+
+// Testing methods for SCMConfig //
+
+/**
+ * This tests we can succesfully enter and retrieve items from our config class
+ *//*
+void DCrashDriverChannel::TestConfigInsertL(TBool& aPass, TDes8& aResult)
+	{	
+	//create our config object (We want a fresh one every time)
+	SCMConfiguration* config = new SCMConfiguration();
+	
+	TInt32 highPriority = 200;
+	TInt32 highishPriority = 150;
+	TInt32 mediumPriority = 100;
+	TInt32 lowishPriority = 50;
+	TInt32 lowPriority = 10;
+	
+	TUint8 numbytes1 = 20;
+	TUint8 numbytes2 = 30;
+	TUint8 numbytes3 = 40;
+	TUint8 numbytes4 = 50;
+	TUint8 numbytes5 = 60;
+	TUint8 numbytes6 = 10;
+	
+	config->SetConfigItem(SCMConfiguration::ECrashedProcessMetaData, highishPriority, numbytes2);
+	config->SetConfigItem(SCMConfiguration::ECrashedThreadMetaData, lowPriority, numbytes5);
+	config->SetConfigItem(SCMConfiguration::ECrashedThreadUsrRegisters, highPriority, numbytes1);
+	config->SetConfigItem(SCMConfiguration::EExceptionStacks, mediumPriority, numbytes3);
+	config->SetConfigItem(SCMConfiguration::EThreadsSvrStack, lowishPriority, numbytes4);
+	config->SetConfigItem(SCMConfiguration::EProcessMetaData, lowishPriority, numbytes6);
+	
+	//now we make sure they come back in the right order
+	TInt32 size = 0;
+	SCMConfiguration::TSCMDataType type;
+	
+	//for each item, ensure that the expected size and type is correct
+	type = config->GetNextItemToDump(size);
+	aPass = (type == SCMConfiguration::ECrashedThreadUsrRegisters ) && (size == numbytes1);
+		
+	if(!aPass)
+		{
+		delete config;
+		AppendString(aResult, "Expected ECrashedThreadUsrRegisters but got %d and expected size to be %d but got %d", type, numbytes1, size );
+		return;
+		}
+	
+	type = config->GetNextItemToDump(size);
+	aPass = (type == SCMConfiguration::ECrashedProcessMetaData ) && (size == numbytes2);
+	
+	if(!aPass)
+		{
+		delete config;
+		AppendString(aResult, "Expected ECrashedProcessMetaData but got %d and expected size to be %d but got %d", type, numbytes2, size );
+		return;
+		}
+	
+	type = config->GetNextItemToDump(size);
+	aPass = (type == SCMConfiguration::EExceptionStacks ) && (size == numbytes3);
+	
+	if(!aPass)
+		{
+		delete config;
+		AppendString(aResult, "Expected EExceptionStacks but got %d and expected size to be %d but got %d", type, numbytes3, size);
+		return;
+		}
+	
+	//these next 2 went in at the same priority but the last one that goes in will be retrieved first
+	type = config->GetNextItemToDump(size);
+	aPass = (type == SCMConfiguration::EProcessMetaData ) && (size == numbytes6);
+	
+	if(!aPass)
+		{
+		delete config;
+		AppendString(aResult, "Expected EProcessMetaData but got %d and expected size to be %d but got %d", type, numbytes6, size);
+		return;
+		}
+	
+	type = config->GetNextItemToDump(size);
+	aPass = (type == SCMConfiguration::EThreadsSvrStack ) && (size == numbytes4);
+	
+	if(!aPass)
+		{
+		delete config;
+		AppendString(aResult, "Expected EThreadsSvrStack but got %d and expected size to be %d but got %d", type, numbytes4, size);
+		return;
+		}
+	
+	type = config->GetNextItemToDump(size);
+	aPass = (type == SCMConfiguration::ECrashedThreadMetaData ) && (size == numbytes5);
+	
+	if(!aPass)
+		{
+		delete config;
+		AppendString(aResult, "Expected ECrashedThreadMetaData but got %d and expected size to be %d but got %d", type, numbytes5, size);
+		return;
+		}
+	
+	//if we get here, test has passed
+	aResult.Zero();
+	aResult.SetLength(50);
+	AppendString(aResult, "TestConfigInsertL passed");
+	aPass = ETrue;
+	
+	
+	delete config;
+	}*/
+
+//eof d_crashdriver_ldd.cpp
+
+
+
+
+
+
+
+