--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/debug/crashMonitor/src/scmdatasave.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1240 @@
+// Copyright (c) 2008-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\debug\crashMonitor\src\scmdatasave.cpp
+//
+//
+
+#define __INCLUDE_REG_OFFSETS__ // for SP_R13U in nk_plat.h
+
+#include <omap_dbg.h>
+#include "arm_mem.h"
+#include "nk_plat.h"
+#include <omap_assp.h>
+#include <scmonitor.h>
+#include <scmdatasave.h>
+
+/**
+ * @file
+ * @internal technology
+ */
+
+/**
+ * SCMDataSave constructor
+ * @param aMonitor - the monitor which has caught the syetem crash this object is saving data for
+ * @param aFlash - the flash memory data will be written to, note the CrashFlash interface is
+ * rather limited and does not support partial block writes
+ * @param aFlashInfo - data describing the structure of the flash data
+ */
+EXPORT_C SCMDataSave::SCMDataSave(Monitor* aMonitor, CrashFlash* aFlash)
+ : iMonitor(aMonitor)
+ ,iFlash(aFlash)
+ ,iByteCount(0)
+#ifdef SCM_COMM_OUTPUT
+ ,iWriteSelect(EWriteComm) // write data to debug port
+#else
+ ,iWriteSelect(EWriteFlash) // write data to flash
+#endif
+ ,iPerformChecksum(ETrue) // checksum data
+ ,iStartingPointForCrash(0)
+ {
+ const TInt KCacheSize = 128;
+ iFlashCache = HBuf8::New(KCacheSize);
+ CLTRACE1("(SCMDataSave) Creating writer with cache size = %d", KCacheSize);
+ iWriter = new TCachedByteStreamWriter(const_cast<TUint8*>(iFlashCache->Ptr()), KCacheSize);
+ iWriter->SetWriterImpl(this);
+ }
+
+/**
+ * Destructor
+ */
+SCMDataSave::~SCMDataSave()
+ {
+ delete iFlashCache;
+ }
+
+/**
+ * Getter for the current byte count. This is the amount of data that has currently
+ * been written to given media for this crash log
+ * @return The number of bytes written already to given media
+ */
+TInt SCMDataSave::GetByteCount()
+ {
+ return iByteCount;
+ }
+
+/**
+ * Logs the user stack for a given DThread object if it is available
+ * @param aThread - thread whose stack we wish to log
+ * @param aSizeDumped Holds the size of the data dumped
+ * @return one of the OS codes
+ */
+TInt SCMDataSave::LogThreadUserStack(DThread* aThread, TBool aFullStack, TUint& aSizeDumped)
+ {
+ LOG_CONTEXT
+ aSizeDumped = 0;
+ TUint memDumped = 0;
+
+ TUint svSp, usrSp;
+ iMonitor->GetStackPointers(&(aThread->iNThread), svSp, usrSp );
+
+ //first we check for a user stack...
+ if (aThread->iUserStackRunAddress && aThread->iUserStackSize)
+ {
+ //Get data together
+ TThreadStack usrStack;
+ usrStack.iStackType = TThreadStack::EUsrStack;
+ usrStack.iThreadId = (TUint64)aThread->iId;
+
+ //map in the user stack
+ TUint8* usrStart = (TUint8*)iMonitor->MapAndLocateUserStack(aThread); //What about Demand paging??
+ TUint8* usrEnd = (TUint8*)(usrStart + aThread->iUserStackSize);
+ if(usrStart)
+ {
+ TUint8* stackPointer = (TUint8*)usrSp;
+
+ //check the stack pointer is in the range of the stack...
+ if (stackPointer < usrStart || stackPointer >= usrEnd)
+ {
+ stackPointer = usrStart;
+ }
+
+ //log the size of the stack we are dumping
+ usrStack.iStackSize = aFullStack || (stackPointer == usrStart) ? usrEnd - usrStart : usrEnd - stackPointer;
+ TUint8* dumpFrom = aFullStack ? usrStart : stackPointer;
+
+ //write the stack
+ aSizeDumped+= usrStack.GetSize();
+ usrStack.Serialize(*iWriter);
+
+ //now we dump the actual stack
+ //if there is a memErr when we read, there isnt much we can do - possibly a bit in the struct to say available/not available?
+ //-1 because we dont want to write the byte at usrEnd
+ MTRAPD(memErr, LogMemory(dumpFrom, usrStack.iStackSize, aThread, memDumped));
+ if(KErrNone != memErr)
+ {
+ CLTRACE("Failed to log usr stack");
+ }
+
+ aSizeDumped+= memDumped;
+ }
+ else
+ {
+ //write the struct
+ aSizeDumped+=usrStack.GetSize();
+ usrStack.Serialize(*iWriter);
+ }
+ }
+ return KErrNone;
+ }
+
+/**
+ * Logs the supervisor stack for a given DThread object
+ * @param aThread - thread whose stack we wish to log
+ * @param aSizeDumped Holds the size of the data dumped
+ * @return one of the system wide codes
+ */
+TInt SCMDataSave::LogThreadSupervisorStack(DThread* aThread, TBool aFullStack, TUint& aSizeDumped)
+ {
+ LOG_CONTEXT
+ aSizeDumped = 0;
+ TUint memDumped;
+
+ TUint svSp, usrSp;
+ iMonitor->GetStackPointers(&(aThread->iNThread), svSp, usrSp );
+
+ //now we dump the supervisor stack
+ TThreadStack svrStack;
+ svrStack.iStackType = TThreadStack::ESvrStack;
+ svrStack.iThreadId = (TUint64)aThread->iId;
+
+ if (aThread->iSupervisorStack && aThread->iSupervisorStackSize)
+ {
+ TUint8* svrStart = (TUint8*)aThread->iSupervisorStack;
+ TUint8* svrEnd = (TUint8*)(svrStart + aThread->iSupervisorStackSize);
+ TUint8* svrStackPointer = (TUint8*)svSp;
+
+ //size of stack we are to dump
+ svrStack.iStackSize = aFullStack || (svrStackPointer == svrStart) ? svrEnd - svrStart : svrEnd - svrStackPointer;
+
+ if(svrStart)
+ {
+ //check the stack pointer is in the range of the stack...
+ if (svrStackPointer < svrStart || svrStackPointer >= svrEnd)
+ {
+ svrStackPointer = svrStart;
+ }
+
+ //write struct to flash
+ aSizeDumped+=svrStack.GetSize();
+ svrStack.Serialize(*iWriter);
+
+ //now we dump the actual stack
+ //if there is a memErr when we read, there isnt much we can do - possibly a bit in the struct to say available/not available?
+ MTRAPD(memErr, LogMemory(svrStart, svrStack.iStackSize, aThread, memDumped));
+ aSizeDumped+=memDumped;
+
+ if(KErrNone != memErr)
+ {
+ CLTRACE("Failed to log supervisor stack");
+ }
+ }
+ else
+ {
+ //write the struct
+ aSizeDumped+=svrStack.GetSize();
+ svrStack.Serialize(*iWriter);
+ }
+ }
+
+ return KErrNone;
+ }
+
+/**
+ * Takes a DProcess kernel object and logs its corrosponding code segments
+ * @param aProcess
+ * @param aSizeDumped Holds the size of the data dumped
+ * @return one of the OS wide error codes
+ */
+TInt SCMDataSave::LogCodeSegments(DProcess* aProc, TUint& aSizeDumped)
+ {
+ LOG_CONTEXT
+ aSizeDumped = 0;
+
+ //the code segment set for this process
+ TCodeSegmentSet segSet;
+ segSet.iPid = (TUint64)aProc->iId;
+
+ //make sure list mutex is ok
+ if(Kern::CodeSegLock()->iHoldCount)
+ {
+ return KErrCorrupt;
+ }
+
+ //get code seg list
+ SDblQue queue;
+ aProc->TraverseCodeSegs(&queue, NULL, DCodeSeg::EMarkDebug, DProcess::ETraverseFlagAdd);
+
+ //iterate through the list
+ TInt codeSegCnt = 0;
+ for(SDblQueLink* codeSegPtr= queue.First(); codeSegPtr!=(SDblQueLink*) (&queue); codeSegPtr=codeSegPtr->iNext)
+ {
+ //get the code seg
+ DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr,DCodeSeg, iTempLink);
+
+ if(codeSeg)
+ {
+ codeSegCnt++;
+ }
+ }
+
+ if(codeSegCnt == 0)
+ {
+ return KErrNone;
+ }
+
+ segSet.iNumSegs = codeSegCnt;
+ segSet.Serialize(*iWriter);
+ aSizeDumped+=segSet.GetSize();
+
+ TModuleMemoryInfo memoryInfo;
+
+ //now we write each code segment
+ for(SDblQueLink* codeSegPtr= queue.First(); codeSegPtr!=(SDblQueLink*) (&queue); codeSegPtr=codeSegPtr->iNext)
+ {
+ //get the code seg
+ DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr,DCodeSeg, iTempLink);
+
+ if(codeSeg)
+ {
+ TCodeSegment seg;
+ seg.iXip = (codeSeg->iXIP) ? ETrue : EFalse;
+
+ //Get the code seg type
+ if(codeSeg->IsExe())
+ {
+ seg.iCodeSegType = EExeCodeSegType;
+ }
+ else if(codeSeg->IsDll())
+ {
+ seg.iCodeSegType = EDllCodeSegType;
+ }
+
+ TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL);
+ if(KErrNone == err)
+ {
+ seg.iCodeSegMemInfo = memoryInfo;
+ }
+ else
+ {
+ seg.iCodeSegMemInfo.iCodeSize = 0;
+
+ // Still need to indicate it wasnt available somehow
+ }
+
+ //Get filename
+ seg.iNameLength = codeSeg->iFileName->Length();
+ seg.iName = *(codeSeg->iFileName);
+
+ aSizeDumped+=seg.GetSize();
+ seg.Serialize(*iWriter);
+ }
+ }
+
+ //Empty this queue and clear marks
+ DCodeSeg::EmptyQueue(queue, DCodeSeg::EMarkDebug);
+
+ return KErrNone;
+ }
+
+/**
+ * This logs the rom version and header information to the crash media
+ * @param aSizeDumped amount of data occupied
+ * @return one of the OS wide codes
+ */
+TInt SCMDataSave::LogRomInfo(TUint& aSizeDumped)
+ {
+ aSizeDumped = 0;
+
+ TRomHeaderData romData;
+
+ TRomHeader rHdr = Epoc::RomHeader();
+
+ romData.iMajorVersion = rHdr.iVersion.iMajor;
+ romData.iMinorVersion = rHdr.iVersion.iMinor;
+ romData.iBuildNumber = rHdr.iVersion.iBuild;
+ romData.iTime = rHdr.iTime;
+
+ TInt err = romData.Serialize(*iWriter);
+ if(KErrNone != err)
+ {
+ return err;
+ }
+
+ aSizeDumped += romData.GetSize();
+
+ return KErrNone;
+ }
+
+/**
+ * Takes a DProcess kernel object and logs to flash
+ * @param aProc
+ * @param aSizeDumped Holds the size of the data dumped
+ * @return one of the OS wide error codes
+ */
+TInt SCMDataSave::LogProcessData(DProcess* aProc, TUint& aSizeDumped)
+ {
+ LOG_CONTEXT
+ aSizeDumped = 0;
+
+ TProcessData procData;
+ DCodeSeg* codeSeg = aProc->iCodeSeg;
+
+ procData.iPriority = aProc->iPriority;
+ procData.iPid = (TUint64)aProc->iId;
+
+ //the code segment is not always available
+ if(codeSeg)
+ {
+ procData.iNamesize = codeSeg->iFileName->Length();
+ procData.iName = *(codeSeg->iFileName);
+ }
+
+ aSizeDumped += procData.GetSize();
+ procData.Serialize(*iWriter);
+
+ return KErrNone;
+ }
+
+/**
+ * Creates meta data about the crash such as time of crash, exit reason etc. to be logged
+ * later on when we have log size.
+ * @param aCategory - crash category
+ * @param aReason - crash reason
+ * @param aSizeDumped Holds the size of the data dumped
+ * @return one of the OS wide codes
+ */
+TInt SCMDataSave::LogCrashHeader(const TDesC8& aCategory, TInt aReason, TInt aCrashId, TUint& aSizeDumped)
+ {
+ LOG_CONTEXT
+ aSizeDumped = 0;
+
+ //the thread that crashed is the context in which we are running
+ DThread* crashedThread = &Kern::CurrentThread();
+
+ iCrashInf.iPid = crashedThread->iOwningProcess->iId;
+ iCrashInf.iTid = crashedThread->iId;
+ iCrashInf.iCrashTime = CrashTime();
+ iCrashInf.iExitType = 0; // Not yet done: Exception or Fault - should be in category
+ iCrashInf.iExitReason = aReason;
+ iCrashInf.iFlashAlign = KFlashAlignment; //record the flash alignment (word aligned for now)
+ iCrashInf.iCachedWriterSize = iWriter->GetCacheSize();
+
+ iCrashInf.iCategorySize = aCategory.Length();
+ iCrashInf.iCategory = aCategory;
+ iCrashInf.iCrashId = aCrashId;
+
+ iCrashInf.iFlashBlockSize = KCrashLogBlockSize;;
+ iCrashInf.iFlashPartitionSize = KCrashLogSize;;
+
+ TSuperPage& sp=Kern::SuperPage();
+ iCrashInf.iExcCode = sp.iKernelExcId;
+
+ //These will be updated with more info at end of crash
+ aSizeDumped+=iCrashInf.GetSize();
+ iCrashInf.Serialize(*iWriter);
+
+ aSizeDumped+=iHdr.GetSize();
+ iHdr.Serialize(*iWriter);
+
+ CLTRACE1("(SCMDataSave::LogCrashHeader) finished bytes written= %d", iWriter->GetBytesWritten());
+ return KErrNone;
+ }
+
+/**
+ * Logs meta data about a given DThread object
+ * @param aThread Thread to dump
+ * @param aSizeDumped Holds the size of the data dumped
+ * @return
+ */
+TInt SCMDataSave::LogThreadData(DThread* aThread, TUint& aSizeDumped)
+ {
+ LOG_CONTEXT
+ aSizeDumped = 0;
+
+ //struct to hold data that gets written to flash
+ TThreadData threadData;
+
+ threadData.iTid = (TUint64)aThread->iId;
+ threadData.iOwnerId = (TUint64)aThread->iOwningProcess->iId;
+ threadData.iPriority = aThread->iThreadPriority;
+
+ //Get the stack pointers
+ TUint svSp, usrSp;
+ iMonitor->GetStackPointers(&(aThread->iNThread), svSp, usrSp );
+ threadData.iUsrSP = usrSp;
+ threadData.iSvcSP = svSp;
+
+ //supervisor and user stack details
+ threadData.iSvcStack = (TInt32)aThread->iSupervisorStack;
+ threadData.iSvcStacksize = aThread->iSupervisorStackSize;
+ threadData.iUsrStack = aThread->iUserStackRunAddress;
+ threadData.iUsrStacksize = aThread->iUserStackSize;
+
+ //currently we can only get the kernels heap
+ if(aThread == &Kern::CurrentThread())
+ {
+ TInt32 heapLoc = 0;
+ TInt32 heapSz = 0;
+ TInt err = FindKernelHeap(heapLoc,heapSz);
+ if(KErrNone == err)
+ {
+ threadData.iSvcHeap = heapLoc;
+ threadData.iSvcHeapSize = heapSz;
+ }
+ else
+ {
+ CLTRACE("\tError: Unable to get kernel heap");
+ }
+ }
+
+ //get filename
+ TFileName filename;
+ aThread->TraceAppendFullName(filename, EFalse);
+
+ threadData.iName.Copy(filename);
+ threadData.iNamesize = threadData.iName.Length();
+
+
+#ifdef __INCLUDE_NTHREADBASE_DEFINES__
+ threadData.iLastCpu = aThread->iNThread.iLastCpu;
+#else
+ threadData.iLastCpu = aThread->iNThread.iSpare3;
+#endif
+
+ threadData.Serialize(*iWriter);
+ aSizeDumped+=threadData.GetSize();
+
+ return KErrNone;
+ }
+
+/**
+ * Logs the arm exception stacks
+ * @param aSizeDumped Holds the size of the data dumped
+ * @return one of the OS wide codes
+ */
+TInt SCMDataSave::LogExceptionStacks(TUint& aSizeDumped)
+ {
+ LOG_CONTEXT
+ aSizeDumped = 0;
+ TUint memDumped = 0;
+
+ #if defined(__EPOC32__) && !defined(__CPU_X86)
+
+ TStackInfo& stackInfo = Kern::SuperPage().iStackInfo;
+
+ TThreadStack irqStack;
+ irqStack.iStackType = TThreadStack::EIRQStack;
+ irqStack.iStackSize = stackInfo.iIrqStackSize;
+
+ aSizeDumped+=irqStack.GetSize();
+ irqStack.Serialize(*iWriter);
+
+ //now dump the IRQ memory - not much we can do in the event of an error
+ MTRAPD(irqErr, LogMemory((TUint8*)stackInfo.iIrqStackBase, stackInfo.iIrqStackSize, &Kern::CurrentThread(), memDumped));
+
+ if(KErrNone != irqErr)
+ {
+ CLTRACE("*****Failed to log IRQ stack");
+ }
+ aSizeDumped+=memDumped;
+
+ //Next, we do the FIQ stack
+ TThreadStack fiqStack;
+ fiqStack.iStackType = TThreadStack::EFIQStack;
+ fiqStack.iStackSize = stackInfo.iFiqStackSize;
+
+ aSizeDumped+=fiqStack.GetSize();
+ fiqStack.Serialize(*iWriter);
+
+ //Now dump the stack itself
+ MTRAPD(fiqErr, LogMemory((TUint8*)stackInfo.iFiqStackBase, stackInfo.iFiqStackSize, &Kern::CurrentThread(), memDumped));
+
+ if(KErrNone != fiqErr )
+ {
+ CLTRACE("*****Failed to log FIQ stack");
+ }
+ aSizeDumped+=memDumped;
+
+ #endif
+
+ return KErrNone;
+ }
+
+/**
+ * Logs the CPU Registers at the time of crash
+ * @param aSizeDumped Holds the size of the data dumped
+ * @return system wide OS code
+ */
+TInt SCMDataSave::LogCPURegisters(TUint& aSizeDumped)
+ {
+ LOG_CONTEXT
+ aSizeDumped = 0;
+
+ TInt32 fullSet = 37;
+
+ //meta data about the thread set
+ TRegisterSet threadSet;
+ threadSet.iNumRegisters = fullSet;
+
+ aSizeDumped+=threadSet.GetSize();
+ threadSet.Serialize(*iWriter);
+
+ SFullArmRegSet regSet;
+ ReadCPURegisters(regSet);
+ TArmReg* regs = (TArmReg*)®Set;
+
+ TInt32 cnt = 0;
+ for(cnt = 0; cnt < fullSet; cnt++)
+ {
+ //this is the struct to store the register value in
+ TRegisterValue regVal;
+ regVal.iType = cnt * 0x100;
+ regVal.iValue32 = regs[cnt];
+ regVal.iOwnId = Kern::CurrentThread().iId;
+
+ aSizeDumped+=regVal.GetSize();
+ regVal.Serialize(*iWriter);
+ }
+
+ return KErrNone;
+ }
+
+/**
+ * This logs the registers for a given thread to the flash memory
+ * @param aThread - thread whose registers we want
+ * @param aRegType - type of register set required such as user, supervisor etc
+ * @param aSizeDumped Holds the size of the data dumped
+ * @return one of the OS return codes
+ */
+TInt SCMDataSave::LogRegisters(DThread* aThread, const TRegisterSetType& aRegType, TUint& aSizeDumped)
+ {
+ LOG_CONTEXT
+ aSizeDumped = 0;
+
+ TArmRegSet regs;
+ TUint32 availableRegs;
+ TInt err;
+
+ //for the current thread we do things differently
+ if(aThread == &Kern::CurrentThread() && aRegType == EFullCPURegisters)
+ {
+ err = LogCPURegisters(aSizeDumped);
+ return err;
+ }
+ else if(aThread == &Kern::CurrentThread())
+ {
+ //only do full cpu reg for the current thread
+ return KErrNotSupported;
+ }
+
+ //Read the appropriate registers
+ switch(aRegType)
+ {
+ case EUserRegisters :
+ {
+ err = ReadUserRegisters(aThread, regs, availableRegs);
+ break;
+ }
+ case ESupervisorRegisters :
+ {
+ err = ReadSystemRegisters(aThread, regs, availableRegs);
+ break;
+ }
+ default : return KErrNotSupported;
+ }
+
+ if(err != KErrNone)
+ {
+ return err;
+ }
+
+ //meta data about the thread set
+ TRegisterSet threadSet;
+
+ //to get the number of registers in advance, we need to count the number of times 1 is set in the bit field of availableRegs
+ TUint numR = 0;
+ for(TInt cnt =0; cnt< 8*sizeof(availableRegs); cnt++) //cycle through 1 bit at a time
+ {
+ if(0x1 & (availableRegs>>cnt))
+ numR++;
+ }
+
+ threadSet.iNumRegisters = numR;
+
+ if(numR == 0)
+ return KErrNone;
+
+ threadSet.Serialize(*iWriter);
+ aSizeDumped += threadSet.GetSize();
+
+ TInt32 currentRegister = 1;
+ TArmReg* reg = (TArmReg*)(®s);
+
+ for(TInt32 cnt = 0; cnt < KArmRegisterCount; cnt++)
+ {
+ //look at the unavailable bitmask to see current register is available
+ //only write the registers we have values for
+ if(currentRegister & availableRegs)
+ {
+ //this is the struct to store the register value in
+ TRegisterValue regVal;
+
+ //get register type as per symbian elf docs
+ TUint32 registerType;
+ err = GetRegisterType(aRegType, cnt, registerType);
+ if(err != KErrNone)
+ {
+ continue;
+ }
+ regVal.iType = registerType;
+ regVal.iOwnId = aThread->iId;
+
+ //set value
+ regVal.iValue32 = reg[cnt];
+
+ aSizeDumped+=regVal.GetSize();
+ regVal.Serialize(*iWriter);
+ }
+
+ currentRegister<<=1;
+ }
+
+ return KErrNone;
+ }
+
+/**
+ * This logs memory in the specified area
+ * @param aStartAddress - address to start from
+ * @param aEndAddress - address to finish
+ * @param aThread - process whose memory this is in
+ * @param aSizeDumped Holds the size of the data dumped
+ * @return one of the system wide codes
+ */
+TInt SCMDataSave::LogMemory(const TUint8* aStartAddress, TInt aLength, const DThread* aThread, TUint& aSizeDumped)
+ {
+ LOG_CONTEXT
+ aSizeDumped = 0;
+
+ if(aThread->iOwningProcess != &Kern::CurrentProcess())
+ {
+ TInt err = iMonitor->SwitchAddressSpace(aThread->iOwningProcess, ETrue);
+ if(KErrNone != err)
+ {
+ return err;
+ }
+ }
+
+ TMemoryDump memDump;
+ memDump.iStartAddress = (TUint32)aStartAddress;
+ memDump.iLength = aLength;
+ memDump.iPid = aThread->iOwningProcess->iId;
+
+ aSizeDumped+=memDump.GetSize();
+ memDump.Serialize(*iWriter);
+
+ if(!aStartAddress)
+ {
+ return KErrArgument;
+ }
+
+ TRawData theMemory;
+ theMemory.iData.Set(const_cast<TUint8*>(aStartAddress), aLength, aLength);
+
+ theMemory.Serialize(*iWriter);
+ aSizeDumped+=theMemory.GetSize();
+
+ return KErrNone;
+ }
+
+/**
+ * This logs the locks held by system at time of crash
+ * @param aSizeDumped Holds the size of the data dumped
+ * @return one of the system wide codes
+ */
+TInt SCMDataSave::LogLocks(TUint& aSizeDumped)
+ {
+ LOG_CONTEXT
+ aSizeDumped = 0;
+
+ // get the mutex logs & waits & log via a TLockData object
+ TSCMLockData lockData;
+
+ const TInt KMaxLockCheck = 20; // so no possibility of infinite loop
+
+ TInt lockCount = 0;
+ // check for kernel locks -
+ for(TInt i=0;i<KMaxLockCheck;i++)
+ {
+ TBool locked = NKern::KernelLocked(i);
+ if(!locked)
+ {
+ lockData.SetLockCount(lockCount);
+ break;
+ }
+ // found a valid lock for value i increment the clock counter
+ lockCount++;
+ }
+
+ // now mutexes
+ DMutex* mutex = Kern::CodeSegLock();
+ if(mutex)
+ {
+ lockData.SetMutexHoldCount(mutex->iHoldCount);
+ lockData.SetMutexThreadWaitCount(mutex->iWaitCount);
+ }
+ else
+ {
+ // no mutex held set to -1
+ lockData.SetMutexHoldCount(0);
+ lockData.SetMutexThreadWaitCount(0);
+ }
+
+ aSizeDumped+=lockData.GetSize();
+ TInt err = lockData.Serialize(*iWriter);
+
+ return err;
+ }
+
+/**
+ * Writes the SCM Configuration to the start of the media
+ * @param aScmConfig Configuration to write
+ * @return one of the system wide codes
+ */
+TInt SCMDataSave::LogConfig(SCMConfiguration& aScmConfig)
+ {
+ iWriter->SetPosition(0);
+
+ TInt err = aScmConfig.Serialize(*iWriter);
+
+ if( err != KErrNone)
+ {
+ CLTRACE1("SCMDataSave::LogConfig failed err = %d", err);
+ }
+
+ return err;
+ }
+
+/**
+ * Reads the SCM Configuration from the media
+ * @param aScmConfig
+ * @return one of the system wide codes
+ */
+TInt SCMDataSave::ReadConfig(SCMConfiguration& aScmConfig)
+ {
+ const TInt KBufSize = 135; //Not yet done: Put in header, beside config defn
+
+ if( KBufSize < aScmConfig.GetSize())
+ {
+ CLTRACE2("(SCMDataSave::ReadConfig) ** ERROR Inadequate buffer actual = %d req = %d"
+ , KBufSize, aScmConfig.GetSize());
+ }
+
+ // try and read the configuration
+ TBuf8<KBufSize> buf;
+ buf.SetLength(KBufSize);
+
+ iFlash->SetReadPos(0); // config always at 0
+ iFlash->Read(buf);
+
+ TByteStreamReader reader(const_cast<TUint8*>(buf.Ptr()));
+ TInt err = aScmConfig.Deserialize(reader);
+ if(err == KErrNotReady)
+ {
+ CLTRACE("(SCMDataSave::ReadConfig) no config saved - use default");
+ }
+ else if(err == KErrNone)
+ {
+ CLTRACE("(SCMDataSave::ReadConfig) Config read ok");
+ }
+ else
+ {
+ CLTRACE1("(SCMDataSave::ReadConfig) error reading config err = %d", err);
+ }
+
+ return err;
+ }
+
+/**
+ * This is a look up table to map the register type and number to the symbian elf definition
+ * of register type
+ * @param aSetType this is the register set type - user, supervisor etc
+ * @param aRegNumber this is the number of the register as per TArmRegisters in arm_types.h
+ * @param aSizeDumped Holds the size of the data dumped
+ * @return One of the OS wide codes
+ */
+TInt SCMDataSave::GetRegisterType(const TRegisterSetType& aSetType, TInt32& aRegNumber, TUint32& aRegisterType)
+ {
+ //validate arguments
+ if(aRegNumber < EArmR0 || aRegNumber > EArmFlags)
+ {
+ return KErrArgument;
+ }
+
+ //look at what type we are using
+ switch(aSetType)
+ {
+ case EUserRegisters :
+ {
+ aRegisterType = aRegNumber * 0x100; //for R0 to R16 (CPSR) it just increments in 0x100 from 0x0 to 0x1000
+ break;
+ }
+ case ESupervisorRegisters :
+ {
+ //same as EUserRegisters except R13 and R14 are different
+ if(aRegNumber == EArmSp)
+ {
+ aRegisterType = 0x1100;
+ break;
+ }
+ else if(aRegNumber == EArmLr)
+ {
+ aRegisterType = 0x1200;
+ break;
+ }
+ else
+ {
+ aRegisterType = aRegNumber * 0x100;
+ break;
+ }
+ }
+ default : return KErrNotSupported;
+ }
+
+ return KErrNone;
+ }
+
+/**
+ * Writes the trace buffer to the crash log.
+ * @param aSizeToDump Number of bytes to dump. If this is zero we attempt to write the entire buffer
+ * @param aSizeDumped Holds the size of the data dumped
+ * @return One of the OS wide codes
+ */
+TInt SCMDataSave::LogTraceBuffer(TInt aSizeToDump, TUint& aSizeDumped)
+ {
+ LOG_CONTEXT
+ aSizeDumped = 0;
+ TUint memDumped = 0;
+
+ TBool dumpAll = (aSizeToDump == 0) ? ETrue : EFalse;
+
+ //Because the btrace buffer is a circular one, we need to save it in two parts
+ //this corrosponds to how we read it
+ TUint8* data;
+ TUint sizeOfPartRead;
+ TInt spaceRemaining = aSizeToDump;
+
+ //This structure will be filled after the first pass and cached so by the time we ARE writing it will
+ //contain the data we want
+ aSizeDumped+=iTrace.GetSize();
+ iTrace.Serialize(*iWriter);
+
+ //read first part
+ TInt err = BTrace::Control(BTrace::ECtrlCrashReadFirst,&data,&sizeOfPartRead);
+
+ while(KErrNone == err && sizeOfPartRead > 0)
+ {
+ TUint rawSize = 0; //how much of this read data want we to dump
+
+ if(dumpAll)
+ {
+ rawSize = sizeOfPartRead;
+ }
+ else //Otherwise see what room is left for dumpage
+ {
+ rawSize = ((sizeOfPartRead + iTrace.iSizeOfMemory) > aSizeToDump) ? spaceRemaining : sizeOfPartRead;
+ }
+
+ //Only relevant if restricting the dump
+ if(spaceRemaining <= 0 && !dumpAll)
+ break;
+
+ TPtrC8 ptr(data, rawSize);
+ err = LogRawData(ptr, memDumped);
+ if(KErrNone != err)
+ {
+ CLTRACE1("Logging Raw data failed - [%d]", err);
+ err = BTrace::Control(BTrace::ECtrlCrashReadNext,&data,&sizeOfPartRead);
+ continue;
+ }
+
+ aSizeDumped+=memDumped;
+
+ iTrace.iSizeOfMemory += rawSize;
+ iTrace.iNumberOfParts++;
+ spaceRemaining -= rawSize;
+
+ err = BTrace::Control(BTrace::ECtrlCrashReadNext,&data,&sizeOfPartRead);
+ }
+
+ return KErrNone;
+ }
+
+/**
+ * Logs the data in a TRawData struct
+ * @param aData
+ * @param aSizeDumped Holds the size of the data dumped
+ * @return One of the OS wide codes
+ */
+TInt SCMDataSave::LogRawData(const TDesC8& aData, TUint& aSizeDumped)
+ {
+ TRawData theData;
+ theData.iLength = aData.Length();
+ theData.iData.Set(const_cast<TUint8*>(aData.Ptr()), aData.Length(), aData.Length());
+
+ aSizeDumped+=theData.GetSize();
+ return theData.Serialize(*iWriter);
+ }
+
+
+/**
+ * Logs the kernels heap and returns the size dumped via aSizeDumped
+ * @param aSizeDumped Holds the size of the data dumped
+ * @return
+ */
+TInt SCMDataSave::LogKernelHeap(TUint& aSizeDumped)
+ {
+ LOG_CONTEXT
+
+ TInt32 heapLoc = 0;
+ TInt32 heapSize = 0;
+ TInt32 err = FindKernelHeap(heapLoc, heapSize);
+ if(KErrNone == err)
+ {
+ return LogMemory((TUint8*)heapLoc, heapSize, &Kern::CurrentThread(), aSizeDumped);
+ }
+
+ CLTRACE1("\tCouldnt find the kernel heap: [%d]", err);
+ return err;
+ }
+
+/**
+ * Iterates the object containers and finds the kernel heap
+ * @param aHeapLocation Contains the memory location of the kernel heap
+ * @param aHeapSize Contains the size of the Heap
+ * @return One of the OS wide codes
+ */
+TInt SCMDataSave::FindKernelHeap(TInt32& aHeapLocation, TInt32& aHeapSize)
+ {
+ LOG_CONTEXT
+
+ //Get Chunk object container
+ DObjectCon* objectContainer = Kern::Containers()[EChunk];
+ if(objectContainer == NULL)
+ {
+ CLTRACE("\tFailed to get object container for the chunks");
+ return KErrNotFound;
+ }
+
+ //Must check the mutex on this is ok otherwise the data will be in an inconsistent state
+ if(objectContainer->Lock()->iHoldCount)
+ {
+ CLTRACE("\tChunk Container is in an inconsistant state");
+ return KErrCorrupt;
+ }
+
+ TInt numObjects = objectContainer->Count();
+
+ for(TInt cnt = 0; cnt< numObjects; cnt ++)
+ {
+ DChunk* candidateHeapChunk = (DChunk*)(*objectContainer)[cnt];
+
+ //Get the objects name
+ TBuf8<KMaxKernelName> name;
+ candidateHeapChunk->TraceAppendFullName(name,EFalse);
+
+ if(name == KKernelHeapChunkName)
+ {
+ #ifndef __MEMMODEL_FLEXIBLE__
+ aHeapLocation = (TInt32)candidateHeapChunk->iBase;
+ #else
+ aHeapLocation = (TInt32)candidateHeapChunk->iFixedBase;
+ #endif
+
+ aHeapSize = candidateHeapChunk->iSize;
+
+ return KErrNone;
+ }
+ }
+
+ return KErrNotFound;
+ }
+
+/**
+ * This logs the variant specific descriptor data to the crash log
+ * @param aSizeDumped records how much was dumped by this function
+ * @return one of the OS wide codes
+ */
+TInt SCMDataSave::LogVariantSpecificData(TUint& aSizeDumped)
+ {
+ LOG_CONTEXT
+
+ aSizeDumped = 0;
+
+ //Change this descriptor as required for your needs
+ _LIT(KVariantSpecificData, "This is the variant specific data. Put your own here");
+
+ TVariantSpecificData varData;
+ varData.iSize = KVariantSpecificData().Size();
+
+ TInt err = varData.Serialize(*iWriter);
+ if(KErrNone != err)
+ {
+ CLTRACE1("\tLogging variant specific data failed with code [%d]", err);
+ return err;
+ }
+ aSizeDumped+=varData.GetSize();
+
+ TUint rawDataSize = 0;
+ err = LogRawData(KVariantSpecificData(), rawDataSize);
+ if(KErrNone != err)
+ {
+ CLTRACE1("\tLogging variant specific data failed with code [%d]", err);
+ return err;
+ }
+
+ aSizeDumped+=rawDataSize;
+
+ return KErrNone;
+ }
+
+
+/**
+ * This method is the callback used by MPhysicalWriterImpl interface
+ * if the TCachedByteStreamWriter is configured to use this interface
+ * the callback avoids the need for temp buffers & can interface directly with the
+ * flash writer methods
+ * @param aData - data to write
+ * @param aLen - length of data to write
+ * @param aPos - writers internal position
+ */
+void SCMDataSave::DoPhysicalWrite(TAny* aData, TInt aPos, TInt aLen)
+ {
+ if(iPerformChecksum)
+ {
+ iChecksum.ChecksumBlock((TUint8*)aData, aLen);
+ }
+
+ if( this->iWriteSelect == EWriteComm)
+ {
+ WriteUart((TUint8*)aData, aLen);
+ }
+ else // EWriteFlash
+ {
+ Write(aData, aLen);
+ }
+ }
+
+/**
+ * Writes data to Flash
+ * @param aSomething Pointer to the data
+ * @param aSize Size of the data
+ */
+void SCMDataSave::Write(const TAny* aSomething, TInt aSize)
+ {
+ TPtrC8 data((const TUint8 *)aSomething, aSize);
+
+ TInt written = 0;
+
+ WriteCrashFlash(iByteCount, written, data);
+ iByteCount+= written;
+ }
+
+/**
+ * Writes a descriptor to the crash flash
+ * @param aPos Position in flash to write
+ * @param aSize Holds the size of the data written after the call
+ * @param aBuffer Descriptor to write
+ */
+void SCMDataSave::WriteCrashFlash(TInt aPos, TInt& aSize, const TDesC8& aBuffer)
+ {
+ //Set write position in the flash
+ iFlash->SetWritePos(aPos);
+ iFlash->Write(aBuffer);
+
+ //get bytes written
+ aSize += iFlash->BytesWritten();
+
+ if(aSize != aBuffer.Length())
+ {
+ CLTRACE2("(SCMDataSave::WriteCrashFlash) Over the limit aSize = %d aBuffer.Length() = %d",
+ aSize, aBuffer.Length());
+ }
+ }
+
+/**
+ * Writes a descriptor via serial
+ * @param aDes Descriptor to write
+ */
+void SCMDataSave::WriteUart(const TDesC8& aDes)
+ {
+ WriteUart(aDes.Ptr(), aDes.Length());
+ }
+
+/**
+ * Writes data via serial
+ * @param aData Data to write
+ * @param aSize Size of data to write
+ */
+void SCMDataSave::WriteUart(const TUint8* aData, TInt aSize)
+ {
+ OMAP* assp = ((OMAP*)Arch::TheAsic());
+ TOmapDbgPrt* dbg = assp->DebugPort();
+
+ if (dbg)
+ {
+ for(TInt i=0;i<aSize;i++)
+ {
+ dbg->DebugOutput(*(aData+i));
+ }
+ }
+ else
+ {
+ CLTRACE("SCMDataSave::WriteUart ERROR - dbg was null");
+ }
+ }
+
+/**
+ * Setter for the current number of bytes written for this crash log
+ * If aByte is not word aligned, it will be rounded up to be so
+ * @param aByte Current bytes written
+ */
+void SCMDataSave::SetByteCount(TInt aByte)
+ {
+ //ensure aligned
+ if(aByte % iWriter->GetCacheSize() == 0)
+ {
+ iByteCount = aByte;
+ }
+ else
+ {
+ iByteCount = aByte + (iWriter->GetCacheSize() - (aByte % iWriter->GetCacheSize()));
+ }
+ }
+
+/**
+ * Gets the output target selection
+ * @return TScmWriteSelect output target selection
+ * @param void
+ */
+SCMDataSave::TWriteSelect SCMDataSave::GetWriteSelect()
+ {
+ return iWriteSelect;
+ }
+
+/**
+ * Sets the output target selection
+ * @return void
+ * @param TScmWriteSelect aWriteSelect output target selection
+ */
+void SCMDataSave::SetWriteSelect(SCMDataSave::TWriteSelect aWriteSelect)
+ {
+ iWriteSelect = aWriteSelect;
+ }
+
+/**
+ * Gets the amount of space remaining for the media of choice
+ * @return
+ */
+TUint SCMDataSave::SpaceRemaining()
+ {
+ TInt currentPosition = iWriter->GetBytesWritten() + iStartingPointForCrash;
+
+ return MaxLogSize() - currentPosition;
+ }
+
+/**
+ * To find the max size of a log for a given media
+ * @return the max size of a log for a given media
+ */
+TUint SCMDataSave::MaxLogSize()
+ {
+ //see what write media is being used
+ switch(GetWriteSelect())
+ {
+ case EWriteFlash:
+ {
+ return KMaxCrashLogSize;
+ }
+ case EWriteComm:
+ {
+ return 0xFFFFFFFF;
+ }
+ default:
+ {
+ return 0;
+ }
+ }
+ }
+
+/**
+ * Records the offset in the flash partition where this crash begins
+ * @param aStart Offset in flash
+ */
+void SCMDataSave::SetCrashStartingPoint(TUint32 aStart)
+ {
+ iStartingPointForCrash = aStart;
+ }
+
+//eof
+