diff -r 000000000000 -r 96e5fb8b040d kernel/eka/debug/crashMonitor/src/scmdatasave.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/debug/crashMonitor/src/scmdatasave.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -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 +#include "arm_mem.h" +#include "nk_plat.h" +#include +#include +#include + +/** + * @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(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(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;iiHoldCount); + 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 buf; + buf.SetLength(KBufSize); + + iFlash->SetReadPos(0); // config always at 0 + iFlash->Read(buf); + + TByteStreamReader reader(const_cast(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(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 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;iDebugOutput(*(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 +