sl@0: // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32\debug\crashMonitor\src\scmonitor.cpp sl@0: // Core dump server - Kernel side crash monitor sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: @internalTechnology sl@0: */ sl@0: sl@0: #include <scmonitor.h> sl@0: #include <kernel/monitor.h> sl@0: #include <assp.h> sl@0: #include <drivers/crashflash.h> sl@0: #include <kernel/klib.h> sl@0: #include <crashlogwalker.h> sl@0: #include <scmconfigitem.h> sl@0: sl@0: #include "scmdatasave.h" sl@0: sl@0: GLDEF_D SCMonitor TheSCMonitor; //global definition of SCMonitor sl@0: sl@0: //keep things 4 byte aligned sl@0: const TInt KRestartType = SCMonitor::ESoftRestart; sl@0: sl@0: /** sl@0: SCMonitor constructor sl@0: */ sl@0: SCMonitor::SCMonitor() sl@0: : iMultiCrashInfo(NULL) sl@0: { sl@0: } sl@0: sl@0: SCMonitor::~SCMonitor() sl@0: { sl@0: delete iMultiCrashInfo; sl@0: } sl@0: sl@0: /** sl@0: Print data to the corresponding output channel. Derived from monitor sl@0: @param aDes the buffer containing the data sl@0: */ sl@0: void SCMonitor::Print (const TDesC8& aDes ) sl@0: { sl@0: //intended to do nothing sl@0: } sl@0: sl@0: /** sl@0: * Allocates resources for SCMonitor sl@0: * cant fully construct in constructor as we are a kernel extension and resources are limited when we are created sl@0: */ sl@0: void SCMonitor::StableConstruction() sl@0: { sl@0: LOG_CONTEXT sl@0: iDataSave = new SCMDataSave(this, TheSCMonitor.iFlash); sl@0: sl@0: //Configuration object for use upon crash sl@0: iScmConfig = new SCMConfiguration(); sl@0: TInt err = iScmConfig->SetDefaultConfig(); sl@0: if(KErrNone != err) sl@0: { sl@0: CLTRACE1("SCMonitor::StableConstruction - Unable to set default config err = %d", err); sl@0: } sl@0: sl@0: sl@0: #ifdef NO_MULTICRASHINFO sl@0: iMultiCrashInfo = NULL; sl@0: #else sl@0: sl@0: //We need to take a look at the flash map from variant_norflash_layout.h sl@0: iMultiCrashInfo = new SCMMultiCrashInfo(); sl@0: sl@0: TUint numberBlocks = KCrashLogSize / KCrashLogBlockSize; sl@0: for(TUint32 cnt = 0; cnt < numberBlocks; cnt++) sl@0: { sl@0: iMultiCrashInfo->AddBlock(new SCMCrashBlockEntry(cnt, cnt * KCrashLogBlockSize, KCrashLogBlockSize)); sl@0: } sl@0: #endif sl@0: } sl@0: sl@0: /** sl@0: * Start a secondary DFC queue for the Flash and Init the flash in the variant(h4) sl@0: * @param aAny sl@0: */ sl@0: void StartSecondary (TAny* ) sl@0: { sl@0: LOG_CONTEXT sl@0: //InitFlash is implemented in the variant as it creates a variant sl@0: //specific derived CrashFlash sl@0: TheSCMonitor.InitFlash ( ); sl@0: TheSCMonitor.StableConstruction(); sl@0: } sl@0: sl@0: /** sl@0: * Global method to create a dfc queue sl@0: * @param Method to intialise the flash. sl@0: * @param Null sl@0: * @param Gets the address of the supervisor thread DFC queue sl@0: * @param TDfcQ priority number sl@0: * @return a DFC object sl@0: */ sl@0: GLDEF_C TDfc StartSecondaryDfc(&StartSecondary, NULL, Kern::SvMsgQue(), KMaxDfcPriority-1); sl@0: sl@0: /** sl@0: * Kernel Main module entry - Own implementation( similar to crash logger) sl@0: * @param aReason reason to enter to the method sl@0: * @return One of the system wide codes sl@0: */ sl@0: GLDEF_C TInt KernelModuleEntry(TInt aReason) sl@0: { sl@0: if(aReason==KModuleEntryReasonVariantInit0) sl@0: { sl@0: new(&TheSCMonitor) SCMonitor; sl@0: // We are going to register the system Crash monitor here so that the order sl@0: // the monitor modules are placed in rom is preserved. sl@0: // The monitor is not fully intialised here. sl@0: //the variant target is missing as we still have to finalise on the crash flash sl@0: //implementation. H2 & H4 doesnt support currently. sl@0: LOG_CONTEXT sl@0: CLTRACE("Installing System Crash Monitor"); sl@0: Monitor::RegisterMonitorImpl (&TheSCMonitor ); sl@0: return KErrNone; sl@0: } sl@0: else if (aReason==KModuleEntryReasonExtensionInit0 ) sl@0: { sl@0: return KErrNone; sl@0: } sl@0: else if (aReason==KModuleEntryReasonExtensionInit1 ) sl@0: { sl@0: LOG_CONTEXT sl@0: CLTRACE("Enqueing dfc to init crash flash for System Crash Monitor after all modules loaded"); sl@0: StartSecondaryDfc.Enque ( ); sl@0: return KErrNone; sl@0: } sl@0: return KErrArgument; sl@0: } sl@0: sl@0: /** sl@0: Method to intialize the system crash monitor sl@0: @param aCategory the fault category type sl@0: @param aReason the reason for crash sl@0: @return restart type sl@0: */ sl@0: TInt SCMonitor::Init2 (TAny* aCategory, TInt aReason ) sl@0: { sl@0: LOG_CONTEXT sl@0: __KTRACE_OPT(KALWAYS, Kern::Printf("\n\nSystem Crash Monitor Launched: To Analyse Crash Produced Use Core Dump Server\n")); sl@0: sl@0: //Start logging the data: sl@0: //Need to lock kernel to access object containers (it technically is anyway, but flag isnt set) sl@0: NKern::Lock(); sl@0: DoCrash(aCategory, aReason); sl@0: NKern::Unlock(); sl@0: sl@0: __KTRACE_OPT(KALWAYS, Kern::Printf("System Crash Monitor Finished: Log Size = [%d]\n", iDataSave->iCrashInf.iLogSize)); sl@0: sl@0: return KRestartType; sl@0: } sl@0: sl@0: /** sl@0: * This is responsible for setting up any structures required for processing of the crash sl@0: * @param aCategory the fault category type sl@0: * @param aReason sl@0: */ sl@0: void SCMonitor::DoCrash(TAny* aCategory, TInt aReason ) sl@0: { sl@0: // get debug mask sl@0: TInt dbgMask = Kern::SuperPage().iDebugMask[0]; sl@0: sl@0: // if we are writing to the comm port then we need to turn off other debug messages sl@0: if( iDataSave->GetWriteSelect() == SCMDataSave::EWriteComm) sl@0: { sl@0: Kern::SuperPage().iDebugMask[0] = 0; sl@0: } sl@0: sl@0: if(!aCategory) sl@0: { sl@0: CLTRACE("\tNULL category retrieved and returning"); sl@0: TheSCMonitor.iFlash->EndTransaction(); sl@0: return; sl@0: } sl@0: sl@0: iFrame = NULL; sl@0: sl@0: CLTRACE("\tAbout to set category -- note: can occasionaly crash board"); sl@0: iFaultCategory = *(const TDesC8*)aCategory; // this crashes the board sometimes sl@0: iFaultReason = aReason; sl@0: Epoc::SetMonitorExceptionHandler ((TLinAddr)HandleException ); sl@0: sl@0: // get the first start block sl@0: // will retieve start of flash by default sl@0: SCMCrashBlockEntry block; sl@0: TInt err = GetNextCrashStartPoint(block); // will also attempt to read iScmConfig sl@0: sl@0: if(KErrNone == err) sl@0: { sl@0: CLTRACE2("SCMonitor::DoCrash next crash will be written at blocknumber = %d offset %d" sl@0: , block.iBlockNumber, block.iBlockOffset); sl@0: } sl@0: else sl@0: { sl@0: CLTRACE1("SCMonitor::DoCrash Failed to find a valid block to write to, can not continue. err = [%d]", err); sl@0: return; sl@0: } sl@0: sl@0: TUint crashId = block.iBlockNumber; sl@0: iDataSave->iWriter->ResetBytesWritten(); sl@0: sl@0: //Write the crash (1st pass is to gather header data) sl@0: TInt spaceRequired = ProcessCrash(block, crashId, EFalse); sl@0: sl@0: // now do the real write sl@0: // prepare flash for data sl@0: TheSCMonitor.iFlash->StartTransaction(); sl@0: TheSCMonitor.iFlash->SetWritePos(block.iBlockOffset); sl@0: sl@0: //write the crash this time sl@0: ProcessCrash(block, crashId, ETrue); sl@0: sl@0: TheSCMonitor.iFlash->EndTransaction(); sl@0: sl@0: // restore debug mask sl@0: Kern::SuperPage().iDebugMask[0] = dbgMask; sl@0: } sl@0: sl@0: sl@0: /** sl@0: * This walks the existing crash log and finds out where current crashes finish sl@0: * @param aBlockEntry Block to use. Only valid if KErrNone is returned. sl@0: * @return One of the OS wide codes sl@0: */ sl@0: TInt SCMonitor::GetNextCrashStartPoint(SCMCrashBlockEntry& aBlockEntry) sl@0: { sl@0: LOG_CONTEXT sl@0: sl@0: //First thing is to try and read the config sl@0: TBool configFound = (iDataSave->ReadConfig(*iScmConfig) == KErrNone); sl@0: sl@0: if( iMultiCrashInfo) sl@0: { sl@0: /** sl@0: * data save has been configured to use multicrash info to find the next block we are on we need to scan each sl@0: * block to see if it contains a valid header. if we find an empty block in our block list then that is the sl@0: * one we will use if we find no empty blocks then we have no room left sl@0: */ sl@0: iMultiCrashInfo->Reset(); sl@0: SCMCrashBlockEntry* block = iMultiCrashInfo->GetNextBlock(); sl@0: TBool blockFound = EFalse; sl@0: sl@0: //For any crashes in flash, we need to record where they end, so that we can then go to the next sl@0: //block after the one in which it ends sl@0: TInt crashEndPoint = 0; sl@0: sl@0: while(block) sl@0: { sl@0: CLTRACE1("SCMonitor::GetNextCrashStartPoint Processing block number %d", block->iBlockNumber ); sl@0: sl@0: //If we have already found our block, we should erase subsequent ones for use sl@0: if(blockFound) sl@0: { sl@0: TInt err = EraseFlashBlock(*block); sl@0: if(err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: block = iMultiCrashInfo->GetNextBlock(); sl@0: continue; sl@0: } sl@0: sl@0: //is this block before a crash end? if it is, we cant use it as a crash can span multiple blocks sl@0: if(block->iBlockOffset >= crashEndPoint) sl@0: { sl@0: //special condition if we have a config sl@0: TUint startPos = block->iBlockOffset; sl@0: TUint skipBytes = 0; sl@0: if(configFound && block->iBlockOffset == 0) sl@0: { sl@0: startPos+=iScmConfig->GetSize(); sl@0: sl@0: //must align to flash for read sl@0: skipBytes = startPos % KFlashAlignment; sl@0: startPos -= skipBytes; sl@0: } sl@0: sl@0: // try and read an info header at these flash coords sl@0: TBuf8<TCrashInfoHeader::KSCMCrashInfoMaxSize + KFlashAlignment> buf; sl@0: buf.SetLength(TCrashInfoHeader::KSCMCrashInfoMaxSize + KFlashAlignment); sl@0: sl@0: CLTRACE1("(SCMonitor::GetNextCrashStartPoint) reading at offset %d", block->iBlockOffset); sl@0: sl@0: TheSCMonitor.iFlash->SetReadPos(startPos); sl@0: TheSCMonitor.iFlash->Read(buf); sl@0: sl@0: // create the buffer applying the offset of bytes skipped sl@0: TByteStreamReader reader(const_cast<TUint8*> (buf.Ptr() + skipBytes)); sl@0: sl@0: TCrashInfoHeader header; sl@0: TInt err = header.Deserialize(reader); sl@0: sl@0: if(err == KErrCorrupt) sl@0: { sl@0: CLTRACE2("(SCMonitor::GetNextCrashStartPoint) Found empty block blocknumber %d blockoffset = %d" sl@0: , block->iBlockNumber, block->iBlockOffset); sl@0: sl@0: blockFound = ETrue; sl@0: aBlockEntry = *block; sl@0: sl@0: continue; //Dont get next block, as next run will erase this current block for use sl@0: } sl@0: else sl@0: { sl@0: crashEndPoint = header.iLogSize + startPos; sl@0: CLTRACE3("(SCMonitor::GetNextCrashStartPoint) In block [%d] we found a valid crash header. This crash finishes at [%d] [0x%X]", block->iBlockNumber, crashEndPoint, crashEndPoint); sl@0: } sl@0: } sl@0: sl@0: block = iMultiCrashInfo->GetNextBlock(); sl@0: } sl@0: sl@0: if(blockFound) sl@0: { sl@0: return KErrNone; sl@0: } sl@0: else sl@0: { sl@0: //CLTRACE("(SCMonitor::GetNextCrashStartPoint) No available blocks TREATING as NO MULTICRASH INFO will write to default block"); sl@0: //In this case should we just overwrite old crashes and return the first block as the comment above suggests sl@0: //return blockFound; sl@0: } sl@0: } sl@0: sl@0: // no multi crash info supplied - use default first block settings sl@0: TInt err = EraseEntireFlashPartition(); sl@0: if(err != KErrNone) sl@0: { sl@0: CLTRACE1("Unable to delete area required to log to flash. Aborting. Error - [%d]", err); sl@0: return err; sl@0: } sl@0: sl@0: aBlockEntry = SCMCrashBlockEntry(0,0,0); sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: * Handles the processing of the crash sl@0: * @return The size of the crash log (including header) that has been/will be written sl@0: */ sl@0: TInt SCMonitor::ProcessCrash(const SCMCrashBlockEntry& aBlock, TUint aCrashId, TBool aCommit) sl@0: { sl@0: LOG_CONTEXT sl@0: CLTRACE5("aBlock.iBlockOffset = [%d] [0x%X] aBlock.iBlockNumber = %d aBlock.iBlockSize = [%d] [0x%X]", sl@0: aBlock.iBlockOffset, aBlock.iBlockOffset, aBlock.iBlockNumber, aBlock.iBlockSize, aBlock.iBlockSize); sl@0: sl@0: // reset writer for start of each crash sl@0: iDataSave->iWriter->ResetBytesWritten(); sl@0: TInt logLevel = 0; sl@0: sl@0: if(aCommit) sl@0: { sl@0: logLevel = KALWAYS; sl@0: iDataSave->iWriter->EnablePhysicalWriting(); sl@0: } sl@0: else sl@0: { sl@0: #if defined(_DEBUG) sl@0: logLevel = KDEBUGGER; sl@0: #else sl@0: logLevel = KALWAYS; //Doesnt matter, KTRACE OPT is empty for rel builds sl@0: if(logLevel != KALWAYS) sl@0: { sl@0: //This is to avoid warning sl@0: } sl@0: #endif sl@0: sl@0: iDataSave->iWriter->DisablePhysicalWriting(); sl@0: } sl@0: sl@0: iDataSave->SetByteCount(aBlock.iBlockOffset); sl@0: if(aBlock.iBlockOffset == 0 && aBlock.iBlockNumber == 0) sl@0: { sl@0: // this is the first crash - we need to save the config here first sl@0: CLTRACE("(SCMonitor::ProcessCrash) - this is block 0 - WRITING CONFIG"); sl@0: iDataSave->LogConfig(*iScmConfig); sl@0: sl@0: //Config is not part of crash so reset bytes written sl@0: iDataSave->SetCrashStartingPoint(iDataSave->iWriter->GetBytesWritten()); sl@0: } sl@0: else sl@0: { sl@0: iDataSave->SetCrashStartingPoint(aBlock.iBlockOffset); sl@0: } sl@0: sl@0: iDataSave->iWriter->ResetBytesWritten(); sl@0: sl@0: TUint32 logSize = 0; sl@0: TUint sizeOfObjectDumped = 0; sl@0: sl@0: TInt err = iDataSave->LogCrashHeader(iFaultCategory, iFaultReason, aCrashId, sizeOfObjectDumped); sl@0: if(KErrNone != err) sl@0: { sl@0: CLTRACE("System Crash Monitor: Failed to create crash info header - (TCrashInfo)"); sl@0: return KRestartType; sl@0: } sl@0: sl@0: logSize += sizeOfObjectDumped; sl@0: sl@0: //Now we must read the configuration to use. This is held at the start of our flash partition sl@0: //and managed by the iConfig object sl@0: iScmConfig->ResetToHighestPriority(); sl@0: sl@0: //Always want the crash context sl@0: iDataSave->iHdr.iCTFullRegOffset = logSize + iDataSave->GetCrashStartingPoint(); sl@0: sl@0: err = iDataSave->LogCPURegisters(sizeOfObjectDumped); sl@0: if(KErrNone != err) sl@0: { sl@0: CLTRACE1("\tError logging full registers = %d", err); sl@0: } sl@0: sl@0: logSize += sizeOfObjectDumped; sl@0: sl@0: CLTRACE("\tAbout to enter processing loop"); sl@0: SCMDataSave::TDataToDump dump; sl@0: sl@0: for(;;) sl@0: { sl@0: //now we get each item by priority from the configuration sl@0: TConfigItem* configItem = iScmConfig->GetNextItem(); sl@0: sl@0: if(!configItem) sl@0: { sl@0: // end of list sl@0: break; sl@0: } sl@0: sl@0: CLTRACE1("\nLooking at item type [%d]", configItem->GetDataType()); sl@0: if(configItem->GetSpaceRequired() > iDataSave->SpaceRemaining()) sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\t\tFor Item Type [%d]: Unable to log [0x%X] [%d] bytes because we only have [0x%X] [%d] bytes left", configItem->GetDataType(), configItem->GetSpaceRequired(), configItem->GetSpaceRequired(), iDataSave->SpaceRemaining(), iDataSave->SpaceRemaining())); sl@0: continue; sl@0: } sl@0: else sl@0: { sl@0: CLTRACE1("Will require [%d] bytes for this item", configItem->GetSpaceRequired()); sl@0: } sl@0: sl@0: // only interested in logging items with priority > 0 sl@0: if( configItem->GetPriority() <= 0) sl@0: { sl@0: CLTRACE1("\tIgnored config item type %d priority 0", configItem->GetDataType()); sl@0: continue; sl@0: } sl@0: sl@0: //there are a lot of TUints in the hdr to record where we wrote this item. sl@0: //This will point to the one of interest for this configItem sl@0: TUint32* offsetPointer = NULL; sl@0: sl@0: //now we check the type of data we wish to dump sl@0: switch(configItem->GetDataType()) sl@0: { sl@0: case TConfigItem::ECrashedThreadMetaData: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ECrashedThreadMetaData at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: err = LogThreadMetaData(SCMDataSave::EThreadSpecific, sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iCTMetaOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::EThreadsMetaData: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EThreadsMetaData at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: //record location we are writing to in the header sl@0: iDataSave->iHdr.iTLstOffset = iDataSave->iWriter->GetBytesWritten(); sl@0: err = LogThreadMetaData(SCMDataSave::ESystemWide, sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iTLstOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::ECrashedProcessMetaData: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ECrashedProcessMetaData at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: err = LogProcessMetaData(SCMDataSave::EProcessSpecific, sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iCPMetaOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::EProcessMetaData: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EProcessMetaData at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: err = LogProcessMetaData(SCMDataSave::ESystemWide, sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iPLstOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::ECrashedProcessUsrStacks: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ECrashedProcessUsrStacks at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: //define what we wish to dump sl@0: dump.iMetaData = EFalse; sl@0: dump.iCodeSegs = EFalse; sl@0: dump.iStk = SCMDataSave::EUsrStack; sl@0: dump.iReg = SCMDataSave::ERegSetNone; sl@0: err = LogObjectContainers(EThread, SCMDataSave::EProcessSpecific, dump, sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iCTUsrStkOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::EThreadsUsrStack: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EThreadsUsrStack at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: //define what we wish to dump sl@0: dump.iMetaData = EFalse; sl@0: dump.iCodeSegs = EFalse; sl@0: dump.iStk = SCMDataSave::EUsrStack; sl@0: dump.iReg = SCMDataSave::ERegSetNone; sl@0: sl@0: err = LogObjectContainers(EThread, SCMDataSave::ESystemWide, dump, sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iSysSvrStkOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::ECrashedProcessSvrStacks: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ECrashedProcessSvrStacks at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: //define what we wish to dump sl@0: dump.iMetaData = EFalse; sl@0: dump.iCodeSegs = EFalse; sl@0: dump.iStk = SCMDataSave::ESvrStack; sl@0: dump.iReg = SCMDataSave::ERegSetNone; sl@0: sl@0: err = LogObjectContainers(EThread, SCMDataSave::EProcessSpecific, dump, sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iCTSvrStkOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::EThreadsSvrStack: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EThreadsSvrStack at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: //define what we wish to dump sl@0: dump.iMetaData = EFalse; sl@0: dump.iCodeSegs = EFalse; sl@0: dump.iStk = SCMDataSave::ESvrStack; sl@0: dump.iReg = SCMDataSave::ERegSetNone; sl@0: sl@0: err = LogObjectContainers(EThread, SCMDataSave::ESystemWide, dump, sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iSysSvrStkOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::EThreadsUsrRegisters: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EThreadsUsrRegisters at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: //define what we wish to dump sl@0: dump.iMetaData = EFalse; sl@0: dump.iCodeSegs = EFalse; sl@0: dump.iStk = SCMDataSave::EStackTypeNone; sl@0: dump.iReg = SCMDataSave::EUserRegisters; sl@0: sl@0: err = LogObjectContainers(EThread, SCMDataSave::ESystemWide, dump, sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iSysUsrRegOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::EThreadsSvrRegisters: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EThreadsSvrRegisters at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: //define what we wish to dump sl@0: dump.iMetaData = EFalse; sl@0: dump.iCodeSegs = EFalse; sl@0: dump.iStk = SCMDataSave::EStackTypeNone; sl@0: dump.iReg = SCMDataSave::ESupervisorRegisters; sl@0: sl@0: err = LogObjectContainers(EThread, SCMDataSave::ESystemWide, dump, sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iSysSvrRegOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::EExceptionStacks: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EExceptionStacks at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: err = iDataSave->LogExceptionStacks(sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iExcStkOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::ECrashedProcessCodeSegs: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ECrashedProcessCodeSegs at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: //define what we wish to dump sl@0: dump.iMetaData = EFalse; sl@0: dump.iCodeSegs = ETrue; sl@0: dump.iStk = SCMDataSave::EStackTypeNone; sl@0: dump.iReg = SCMDataSave::ERegSetNone; sl@0: sl@0: err = LogObjectContainers(EProcess, SCMDataSave::EProcessSpecific, dump, sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iCPCodeSegOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::EProcessCodeSegs: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EProcessCodeSegs at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: //define what we wish to dump sl@0: dump.iMetaData = EFalse; sl@0: dump.iCodeSegs = ETrue; sl@0: dump.iStk = SCMDataSave::EStackTypeNone; sl@0: dump.iReg = SCMDataSave::ERegSetNone; sl@0: err = LogObjectContainers(EProcess, SCMDataSave::ESystemWide, dump, sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iSysCodeSegOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::ETraceData: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ETraceData at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: err = iDataSave->LogTraceBuffer(configItem->GetSizeToDump(), sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iTraceOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::ELocks: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ELocks at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: err = iDataSave->LogLocks(sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iScmLocksOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::EKernelHeap: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EKernelHeap at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: err = iDataSave->LogKernelHeap(sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iKernelHeapOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::EVariantSpecificData: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EVariantSpecificData at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: err = iDataSave->LogVariantSpecificData(sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iVarSpecInfOffset); sl@0: sl@0: break; sl@0: } sl@0: case TConfigItem::ERomInfo: sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ERomInfo at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint())); sl@0: sl@0: err = iDataSave->LogRomInfo(sizeOfObjectDumped); sl@0: offsetPointer = &(iDataSave->iHdr.iRomInfoOffset); sl@0: sl@0: break; sl@0: } sl@0: //unknown configuration type - something bad is going on sl@0: default: return 0; sl@0: } sl@0: sl@0: if(KErrNone != err) sl@0: { sl@0: __KTRACE_OPT(logLevel, Kern::Printf("\tError logging data: [%d] Type = [%d]", err, aBlock.iBlockOffset)); sl@0: continue; sl@0: } sl@0: sl@0: //Set the space required so next time around we will know in advance how much space we need sl@0: configItem->SetSpaceRequired(sizeOfObjectDumped); sl@0: sl@0: //Note: the following steps are only required for the first time we call process crash. The second time, sl@0: //when physical writing is enabled, these will have been written already and so they dont matter sl@0: sl@0: //update the offset and logsize if we are going to dump this item sl@0: TUint32 absoluteLogPos = logSize + iDataSave->GetCrashStartingPoint(); sl@0: if(absoluteLogPos+sizeOfObjectDumped < iDataSave->MaxLogSize()) sl@0: { sl@0: //now, we must record where in the crash log this item will be dumped sl@0: *offsetPointer = absoluteLogPos; sl@0: logSize += sizeOfObjectDumped; sl@0: } sl@0: } sl@0: sl@0: iDataSave->iCrashInf.iLogSize = logSize; sl@0: iDataSave->iWriter->FlushCache(); sl@0: sl@0: return iDataSave->iCrashInf.iLogSize; sl@0: } sl@0: sl@0: /** sl@0: * Logs the meta data for processes sl@0: * @param aCurrentProcess - scope to dump sl@0: * @return one of the OS wide codes sl@0: */ sl@0: TInt SCMonitor::LogProcessMetaData(SCMDataSave::TDumpScope aScope, TUint& aSizeDumped) const sl@0: { sl@0: LOG_CONTEXT sl@0: sl@0: SCMDataSave::TDataToDump dump; sl@0: dump.iMetaData = ETrue; sl@0: sl@0: return LogObjectContainers(EProcess, aScope, dump, aSizeDumped); sl@0: } sl@0: sl@0: /** sl@0: * sl@0: * @param aCurrentThread - to only do the current (crashed thread) or to do all the others sl@0: * @return one of the OS wide codes sl@0: */ sl@0: TInt SCMonitor::LogThreadMetaData(SCMDataSave::TDumpScope aScope, TUint& aSizeDumped) const sl@0: { sl@0: LOG_CONTEXT sl@0: sl@0: SCMDataSave::TDataToDump dump; sl@0: dump.iMetaData = ETrue; sl@0: sl@0: return LogObjectContainers(EThread, aScope, dump, aSizeDumped); sl@0: } sl@0: sl@0: /** sl@0: * Generic method that looks at all kernel objects of aObjectType sl@0: * @param aObjectType sl@0: * @param aDumpScope - if you wish to dump for the the current process, current thread or entire system sl@0: * @param aDataToDump - data you wish to dump sl@0: * @param aSizeDumped - records how much was dumped sl@0: * @return sl@0: */ sl@0: TInt SCMonitor::LogObjectContainers(TObjectType aObjectType, SCMDataSave::TDumpScope aDumpScope, const SCMDataSave::TDataToDump& aDataToDump, TUint& aSizeDumped) const sl@0: { sl@0: aSizeDumped = 0; sl@0: sl@0: if(aObjectType >= ENumObjectTypes) sl@0: { sl@0: return KErrArgument; sl@0: } sl@0: sl@0: //Get the object container for the given object type sl@0: DObjectCon* objectContainer = Kern::Containers()[aObjectType]; sl@0: if(objectContainer == NULL) sl@0: { sl@0: CLTRACE("tFailed to get object container"); sl@0: return KErrNotFound; sl@0: } sl@0: sl@0: //Must check the mutex on this is ok otherwise the data will be in an inconsistent state sl@0: if(objectContainer->iMutex->iHoldCount) sl@0: { sl@0: CLTRACE("\tObject Container is in an inconsistant state"); sl@0: return KErrCorrupt; sl@0: } sl@0: sl@0: TInt numObjects = objectContainer->Count(); sl@0: TInt err = KErrNone; sl@0: sl@0: for(TInt cnt = 0; cnt< numObjects; cnt ++) sl@0: { sl@0: DObject* object = (*objectContainer)[cnt]; sl@0: sl@0: //Are we interested in the object? scope only relevant for thread and process objects, for others, the scope is implicit sl@0: if(aObjectType == EThread) sl@0: { sl@0: switch(aDumpScope) sl@0: { sl@0: case SCMDataSave::EThreadSpecific : sl@0: { sl@0: //if we are interested in the current thread and this is not it, continue sl@0: if(((DThread*)object) != &Kern::CurrentThread()) sl@0: continue; sl@0: break; sl@0: } sl@0: case SCMDataSave::EProcessSpecific : sl@0: { sl@0: //if we are interested in the current proc and this is not it, continue sl@0: if(((DThread*)object)->iOwningProcess != &Kern::CurrentProcess()) sl@0: continue; sl@0: break; sl@0: } sl@0: case SCMDataSave::ESystemWide : sl@0: default: sl@0: break; sl@0: } sl@0: } sl@0: else if(aObjectType == EProcess) sl@0: { sl@0: switch(aDumpScope) sl@0: { sl@0: case SCMDataSave::EProcessSpecific : sl@0: { sl@0: if((DProcess*)object != &Kern::CurrentProcess()) sl@0: continue; sl@0: break; sl@0: } sl@0: case SCMDataSave::EThreadSpecific : //thread specific process doesnt make sense sl@0: return KErrArgument; sl@0: case SCMDataSave::ESystemWide : sl@0: default: sl@0: break; sl@0: } sl@0: } sl@0: sl@0: //Now we look at the data we have been asked to dump sl@0: if(aDataToDump.iMetaData) sl@0: { sl@0: TUint dumped = 0; sl@0: err = HelpDumpMetaData(object, aObjectType, dumped); sl@0: if(KErrNone != err) sl@0: { sl@0: CLTRACE1("Failed to meta data: [%d]", err); sl@0: return err; sl@0: } sl@0: aSizeDumped += dumped; sl@0: } sl@0: sl@0: if(aDataToDump.iCodeSegs) sl@0: { sl@0: if(aObjectType != EProcess) sl@0: { sl@0: return KErrArgument; sl@0: } sl@0: sl@0: TUint dumped = 0; sl@0: err = iDataSave->LogCodeSegments((DProcess*)object, dumped); sl@0: if(KErrNone != err) sl@0: { sl@0: CLTRACE1("Failed to log code segments: [%d]", err); sl@0: return err; sl@0: } sl@0: aSizeDumped += dumped; sl@0: } sl@0: sl@0: if(aDataToDump.iStk != SCMDataSave::EStackTypeNone) sl@0: { sl@0: TUint dumped = 0; sl@0: err = HelpDumpStacks(object, aObjectType, dumped, aDataToDump.iStk); sl@0: if(KErrNone != err) sl@0: { sl@0: CLTRACE1("Failed to log stacks: [%d]", err); sl@0: return err; sl@0: } sl@0: aSizeDumped += dumped; sl@0: } sl@0: sl@0: if(aDataToDump.iReg != SCMDataSave::ERegSetNone) sl@0: { sl@0: if(aObjectType != EThread) sl@0: { sl@0: return KErrArgument; sl@0: } sl@0: TUint dumped = 0; sl@0: err = iDataSave->LogRegisters((DThread*)object, aDataToDump.iReg, dumped); sl@0: if(KErrNone != err && KErrNotSupported !=err) //we expect to send down a KErrNotSupported when we ask for Full CPU set for the non crashed thread - thats fine sl@0: { sl@0: CLTRACE1("Failed to log registers: [%d]", err); sl@0: return err; sl@0: } sl@0: aSizeDumped += dumped; sl@0: } sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: * Helper method for dumping stacks. Looks to see what type of stack we want and then calls sl@0: * appropriate method sl@0: * @param aObject The DThread object whose stack we want sl@0: * @param aObjectType The object type of this aObject. Anything other than EThread will give KErrArgument sl@0: * @param aSizeDumped Holds the size of the stack dumped after processing sl@0: * @param aStkType The type of stack to be dumped sl@0: * @see TObjectType sl@0: * @see SCMDataSave::TStackType sl@0: * @return One of the system wide codes sl@0: */ sl@0: TInt SCMonitor::HelpDumpStacks(DObject* aObject, TObjectType aObjectType, TUint& aSizeDumped, SCMDataSave::TStackType aStkType) const sl@0: { sl@0: //verify args sl@0: if(aObjectType != EThread) sl@0: { sl@0: return KErrArgument; sl@0: } sl@0: sl@0: switch(aStkType) sl@0: { sl@0: case SCMDataSave::EUsrStack: sl@0: { sl@0: return iDataSave->LogThreadUserStack((DThread*)aObject, ETrue, aSizeDumped); sl@0: } sl@0: case SCMDataSave::ESvrStack: sl@0: { sl@0: return iDataSave->LogThreadSupervisorStack((DThread*)aObject, ETrue, aSizeDumped); sl@0: } sl@0: default: return KErrArgument; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: * Helper method to dump meta data about a DThread or a DProcess object sl@0: * @param aObject DObject to use sl@0: * @param aObjectType Type of DObject. Must be EThread or EProcess sl@0: * @param aSizeDumped Holds the size of the stack dumped after processing sl@0: * @return sl@0: */ sl@0: TInt SCMonitor::HelpDumpMetaData(DObject* aObject, TObjectType aObjectType, TUint& aSizeDumped) const sl@0: { sl@0: aSizeDumped = 0; sl@0: sl@0: switch(aObjectType) sl@0: { sl@0: case EThread: sl@0: { sl@0: return iDataSave->LogThreadData((DThread*)aObject, aSizeDumped); sl@0: } sl@0: case EProcess: sl@0: { sl@0: return iDataSave->LogProcessData((DProcess*)aObject, aSizeDumped); sl@0: } sl@0: default: return KErrArgument; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: * Wrapper method around the flash erase block fundtion to determine if the erase was succesful. sl@0: * If the erase was not succesful we can't continue as we cannot write. sl@0: * @param aBlockOffset Block to erase sl@0: * @return One of the OS wide codes sl@0: */ sl@0: TInt SCMonitor::EraseFlashBlock(const SCMCrashBlockEntry& aBlock) sl@0: { sl@0: iFlash->StartTransaction(); sl@0: sl@0: TInt numAttempts = 0; sl@0: while(numAttempts < KFlashEraseAttempts) sl@0: { sl@0: iFlash->SetWritePos(aBlock.iBlockOffset); sl@0: iFlash->EraseFlashBlock(aBlock.iBlockOffset); sl@0: sl@0: //we will read the flash to make sure that it set the block to all 1's (well not all, just the start) sl@0: TBuf8<sizeof(TUint32)> buf; sl@0: buf.SetLength(sizeof(TUint32)); sl@0: sl@0: iFlash->SetReadPos(aBlock.iBlockOffset); sl@0: iFlash->Read(buf); sl@0: sl@0: volatile TUint32* result = (TUint32*)buf.Ptr(); sl@0: if(*result == 0xFFFFFFFF) sl@0: { sl@0: __KTRACE_OPT(KALWAYS, Kern::Printf("Erase of block [0x%X] succesful after [%d] attempts", aBlock.iBlockOffset, numAttempts+1)) sl@0: iFlash->EndTransaction(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: numAttempts++; sl@0: sl@0: //Sometimes a write to the block helps the next erase sl@0: TUint32 bytesWritten = 0; sl@0: while(bytesWritten < aBlock.iBlockSize) sl@0: { sl@0: TBuf8<sizeof(TUint8)> num; sl@0: num.Append(0x0); sl@0: iFlash->Write(num); sl@0: bytesWritten++; sl@0: } sl@0: } sl@0: sl@0: __KTRACE_OPT(KALWAYS, Kern::Printf("After %d attempts, we were unable to erase the flash block at [0x%X]. This could be because " sl@0: "the driver is defective or because the flash has gone past its lifetime. Whatever it is though, " sl@0: "we cannot continue.", KFlashEraseAttempts, aBlock.iBlockOffset)); sl@0: sl@0: iFlash->EndTransaction(); sl@0: return KErrAbort; sl@0: } sl@0: sl@0: /** sl@0: * This erases each block in the flash partition sl@0: * @return One of the system wide codes sl@0: */ sl@0: TInt SCMonitor::EraseEntireFlashPartition() sl@0: { sl@0: if(iMultiCrashInfo) sl@0: { sl@0: iMultiCrashInfo->Reset(); sl@0: sl@0: SCMCrashBlockEntry* block = iMultiCrashInfo->GetNextBlock(); sl@0: while(block) sl@0: { sl@0: TInt err = EraseFlashBlock(*block); sl@0: if(KErrNone != err) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: block = iMultiCrashInfo->GetNextBlock(); sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: CLTRACE("SCMonitor::EraseEntireFlashPartition() -- No Flash MAP available, trying to use the raw driver to delete."); sl@0: TheSCMonitor.iFlash->EraseLogArea(); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: //eof scmonitor.cpp sl@0: