1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/debug/crashMonitor/src/scmonitor.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1032 @@
1.4 +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32\debug\crashMonitor\src\scmonitor.cpp
1.18 +// Core dump server - Kernel side crash monitor
1.19 +//
1.20 +//
1.21 +
1.22 +/**
1.23 + @file
1.24 + @internalTechnology
1.25 +*/
1.26 +
1.27 +#include <scmonitor.h>
1.28 +#include <kernel/monitor.h>
1.29 +#include <assp.h>
1.30 +#include <drivers/crashflash.h>
1.31 +#include <kernel/klib.h>
1.32 +#include <crashlogwalker.h>
1.33 +#include <scmconfigitem.h>
1.34 +
1.35 +#include "scmdatasave.h"
1.36 +
1.37 +GLDEF_D SCMonitor TheSCMonitor; //global definition of SCMonitor
1.38 +
1.39 +//keep things 4 byte aligned
1.40 +const TInt KRestartType = SCMonitor::ESoftRestart;
1.41 +
1.42 +/**
1.43 +SCMonitor constructor
1.44 +*/
1.45 +SCMonitor::SCMonitor()
1.46 + : iMultiCrashInfo(NULL)
1.47 + {
1.48 + }
1.49 +
1.50 +SCMonitor::~SCMonitor()
1.51 + {
1.52 + delete iMultiCrashInfo;
1.53 + }
1.54 +
1.55 +/**
1.56 + Print data to the corresponding output channel. Derived from monitor
1.57 + @param aDes the buffer containing the data
1.58 + */
1.59 +void SCMonitor::Print (const TDesC8& aDes )
1.60 + {
1.61 + //intended to do nothing
1.62 + }
1.63 +
1.64 +/**
1.65 + * Allocates resources for SCMonitor
1.66 + * cant fully construct in constructor as we are a kernel extension and resources are limited when we are created
1.67 + */
1.68 +void SCMonitor::StableConstruction()
1.69 + {
1.70 + LOG_CONTEXT
1.71 + iDataSave = new SCMDataSave(this, TheSCMonitor.iFlash);
1.72 +
1.73 + //Configuration object for use upon crash
1.74 + iScmConfig = new SCMConfiguration();
1.75 + TInt err = iScmConfig->SetDefaultConfig();
1.76 + if(KErrNone != err)
1.77 + {
1.78 + CLTRACE1("SCMonitor::StableConstruction - Unable to set default config err = %d", err);
1.79 + }
1.80 +
1.81 +
1.82 +#ifdef NO_MULTICRASHINFO
1.83 + iMultiCrashInfo = NULL;
1.84 +#else
1.85 +
1.86 + //We need to take a look at the flash map from variant_norflash_layout.h
1.87 + iMultiCrashInfo = new SCMMultiCrashInfo();
1.88 +
1.89 + TUint numberBlocks = KCrashLogSize / KCrashLogBlockSize;
1.90 + for(TUint32 cnt = 0; cnt < numberBlocks; cnt++)
1.91 + {
1.92 + iMultiCrashInfo->AddBlock(new SCMCrashBlockEntry(cnt, cnt * KCrashLogBlockSize, KCrashLogBlockSize));
1.93 + }
1.94 +#endif
1.95 + }
1.96 +
1.97 +/**
1.98 + * Start a secondary DFC queue for the Flash and Init the flash in the variant(h4)
1.99 + * @param aAny
1.100 + */
1.101 +void StartSecondary (TAny* )
1.102 + {
1.103 + LOG_CONTEXT
1.104 + //InitFlash is implemented in the variant as it creates a variant
1.105 + //specific derived CrashFlash
1.106 + TheSCMonitor.InitFlash ( );
1.107 + TheSCMonitor.StableConstruction();
1.108 + }
1.109 +
1.110 +/**
1.111 + * Global method to create a dfc queue
1.112 + * @param Method to intialise the flash.
1.113 + * @param Null
1.114 + * @param Gets the address of the supervisor thread DFC queue
1.115 + * @param TDfcQ priority number
1.116 + * @return a DFC object
1.117 + */
1.118 +GLDEF_C TDfc StartSecondaryDfc(&StartSecondary, NULL, Kern::SvMsgQue(), KMaxDfcPriority-1);
1.119 +
1.120 +/**
1.121 + * Kernel Main module entry - Own implementation( similar to crash logger)
1.122 + * @param aReason reason to enter to the method
1.123 + * @return One of the system wide codes
1.124 + */
1.125 +GLDEF_C TInt KernelModuleEntry(TInt aReason)
1.126 + {
1.127 + if(aReason==KModuleEntryReasonVariantInit0)
1.128 + {
1.129 + new(&TheSCMonitor) SCMonitor;
1.130 + // We are going to register the system Crash monitor here so that the order
1.131 + // the monitor modules are placed in rom is preserved.
1.132 + // The monitor is not fully intialised here.
1.133 + //the variant target is missing as we still have to finalise on the crash flash
1.134 + //implementation. H2 & H4 doesnt support currently.
1.135 + LOG_CONTEXT
1.136 + CLTRACE("Installing System Crash Monitor");
1.137 + Monitor::RegisterMonitorImpl (&TheSCMonitor );
1.138 + return KErrNone;
1.139 + }
1.140 + else if (aReason==KModuleEntryReasonExtensionInit0 )
1.141 + {
1.142 + return KErrNone;
1.143 + }
1.144 + else if (aReason==KModuleEntryReasonExtensionInit1 )
1.145 + {
1.146 + LOG_CONTEXT
1.147 + CLTRACE("Enqueing dfc to init crash flash for System Crash Monitor after all modules loaded");
1.148 + StartSecondaryDfc.Enque ( );
1.149 + return KErrNone;
1.150 + }
1.151 + return KErrArgument;
1.152 + }
1.153 +
1.154 +/**
1.155 + Method to intialize the system crash monitor
1.156 + @param aCategory the fault category type
1.157 + @param aReason the reason for crash
1.158 + @return restart type
1.159 + */
1.160 +TInt SCMonitor::Init2 (TAny* aCategory, TInt aReason )
1.161 + {
1.162 + LOG_CONTEXT
1.163 + __KTRACE_OPT(KALWAYS, Kern::Printf("\n\nSystem Crash Monitor Launched: To Analyse Crash Produced Use Core Dump Server\n"));
1.164 +
1.165 + //Start logging the data:
1.166 + //Need to lock kernel to access object containers (it technically is anyway, but flag isnt set)
1.167 + NKern::Lock();
1.168 + DoCrash(aCategory, aReason);
1.169 + NKern::Unlock();
1.170 +
1.171 + __KTRACE_OPT(KALWAYS, Kern::Printf("System Crash Monitor Finished: Log Size = [%d]\n", iDataSave->iCrashInf.iLogSize));
1.172 +
1.173 + return KRestartType;
1.174 + }
1.175 +
1.176 +/**
1.177 + * This is responsible for setting up any structures required for processing of the crash
1.178 + * @param aCategory the fault category type
1.179 + * @param aReason
1.180 + */
1.181 +void SCMonitor::DoCrash(TAny* aCategory, TInt aReason )
1.182 + {
1.183 + // get debug mask
1.184 + TInt dbgMask = Kern::SuperPage().iDebugMask[0];
1.185 +
1.186 + // if we are writing to the comm port then we need to turn off other debug messages
1.187 + if( iDataSave->GetWriteSelect() == SCMDataSave::EWriteComm)
1.188 + {
1.189 + Kern::SuperPage().iDebugMask[0] = 0;
1.190 + }
1.191 +
1.192 + if(!aCategory)
1.193 + {
1.194 + CLTRACE("\tNULL category retrieved and returning");
1.195 + TheSCMonitor.iFlash->EndTransaction();
1.196 + return;
1.197 + }
1.198 +
1.199 + iFrame = NULL;
1.200 +
1.201 + CLTRACE("\tAbout to set category -- note: can occasionaly crash board");
1.202 + iFaultCategory = *(const TDesC8*)aCategory; // this crashes the board sometimes
1.203 + iFaultReason = aReason;
1.204 + Epoc::SetMonitorExceptionHandler ((TLinAddr)HandleException );
1.205 +
1.206 + // get the first start block
1.207 + // will retieve start of flash by default
1.208 + SCMCrashBlockEntry block;
1.209 + TInt err = GetNextCrashStartPoint(block); // will also attempt to read iScmConfig
1.210 +
1.211 + if(KErrNone == err)
1.212 + {
1.213 + CLTRACE2("SCMonitor::DoCrash next crash will be written at blocknumber = %d offset %d"
1.214 + , block.iBlockNumber, block.iBlockOffset);
1.215 + }
1.216 + else
1.217 + {
1.218 + CLTRACE1("SCMonitor::DoCrash Failed to find a valid block to write to, can not continue. err = [%d]", err);
1.219 + return;
1.220 + }
1.221 +
1.222 + TUint crashId = block.iBlockNumber;
1.223 + iDataSave->iWriter->ResetBytesWritten();
1.224 +
1.225 + //Write the crash (1st pass is to gather header data)
1.226 + TInt spaceRequired = ProcessCrash(block, crashId, EFalse);
1.227 +
1.228 + // now do the real write
1.229 + // prepare flash for data
1.230 + TheSCMonitor.iFlash->StartTransaction();
1.231 + TheSCMonitor.iFlash->SetWritePos(block.iBlockOffset);
1.232 +
1.233 + //write the crash this time
1.234 + ProcessCrash(block, crashId, ETrue);
1.235 +
1.236 + TheSCMonitor.iFlash->EndTransaction();
1.237 +
1.238 + // restore debug mask
1.239 + Kern::SuperPage().iDebugMask[0] = dbgMask;
1.240 + }
1.241 +
1.242 +
1.243 +/**
1.244 + * This walks the existing crash log and finds out where current crashes finish
1.245 + * @param aBlockEntry Block to use. Only valid if KErrNone is returned.
1.246 + * @return One of the OS wide codes
1.247 + */
1.248 +TInt SCMonitor::GetNextCrashStartPoint(SCMCrashBlockEntry& aBlockEntry)
1.249 + {
1.250 + LOG_CONTEXT
1.251 +
1.252 + //First thing is to try and read the config
1.253 + TBool configFound = (iDataSave->ReadConfig(*iScmConfig) == KErrNone);
1.254 +
1.255 + if( iMultiCrashInfo)
1.256 + {
1.257 + /**
1.258 + * data save has been configured to use multicrash info to find the next block we are on we need to scan each
1.259 + * block to see if it contains a valid header. if we find an empty block in our block list then that is the
1.260 + * one we will use if we find no empty blocks then we have no room left
1.261 + */
1.262 + iMultiCrashInfo->Reset();
1.263 + SCMCrashBlockEntry* block = iMultiCrashInfo->GetNextBlock();
1.264 + TBool blockFound = EFalse;
1.265 +
1.266 + //For any crashes in flash, we need to record where they end, so that we can then go to the next
1.267 + //block after the one in which it ends
1.268 + TInt crashEndPoint = 0;
1.269 +
1.270 + while(block)
1.271 + {
1.272 + CLTRACE1("SCMonitor::GetNextCrashStartPoint Processing block number %d", block->iBlockNumber );
1.273 +
1.274 + //If we have already found our block, we should erase subsequent ones for use
1.275 + if(blockFound)
1.276 + {
1.277 + TInt err = EraseFlashBlock(*block);
1.278 + if(err != KErrNone)
1.279 + {
1.280 + return err;
1.281 + }
1.282 +
1.283 + block = iMultiCrashInfo->GetNextBlock();
1.284 + continue;
1.285 + }
1.286 +
1.287 + //is this block before a crash end? if it is, we cant use it as a crash can span multiple blocks
1.288 + if(block->iBlockOffset >= crashEndPoint)
1.289 + {
1.290 + //special condition if we have a config
1.291 + TUint startPos = block->iBlockOffset;
1.292 + TUint skipBytes = 0;
1.293 + if(configFound && block->iBlockOffset == 0)
1.294 + {
1.295 + startPos+=iScmConfig->GetSize();
1.296 +
1.297 + //must align to flash for read
1.298 + skipBytes = startPos % KFlashAlignment;
1.299 + startPos -= skipBytes;
1.300 + }
1.301 +
1.302 + // try and read an info header at these flash coords
1.303 + TBuf8<TCrashInfoHeader::KSCMCrashInfoMaxSize + KFlashAlignment> buf;
1.304 + buf.SetLength(TCrashInfoHeader::KSCMCrashInfoMaxSize + KFlashAlignment);
1.305 +
1.306 + CLTRACE1("(SCMonitor::GetNextCrashStartPoint) reading at offset %d", block->iBlockOffset);
1.307 +
1.308 + TheSCMonitor.iFlash->SetReadPos(startPos);
1.309 + TheSCMonitor.iFlash->Read(buf);
1.310 +
1.311 + // create the buffer applying the offset of bytes skipped
1.312 + TByteStreamReader reader(const_cast<TUint8*> (buf.Ptr() + skipBytes));
1.313 +
1.314 + TCrashInfoHeader header;
1.315 + TInt err = header.Deserialize(reader);
1.316 +
1.317 + if(err == KErrCorrupt)
1.318 + {
1.319 + CLTRACE2("(SCMonitor::GetNextCrashStartPoint) Found empty block blocknumber %d blockoffset = %d"
1.320 + , block->iBlockNumber, block->iBlockOffset);
1.321 +
1.322 + blockFound = ETrue;
1.323 + aBlockEntry = *block;
1.324 +
1.325 + continue; //Dont get next block, as next run will erase this current block for use
1.326 + }
1.327 + else
1.328 + {
1.329 + crashEndPoint = header.iLogSize + startPos;
1.330 + CLTRACE3("(SCMonitor::GetNextCrashStartPoint) In block [%d] we found a valid crash header. This crash finishes at [%d] [0x%X]", block->iBlockNumber, crashEndPoint, crashEndPoint);
1.331 + }
1.332 + }
1.333 +
1.334 + block = iMultiCrashInfo->GetNextBlock();
1.335 + }
1.336 +
1.337 + if(blockFound)
1.338 + {
1.339 + return KErrNone;
1.340 + }
1.341 + else
1.342 + {
1.343 + //CLTRACE("(SCMonitor::GetNextCrashStartPoint) No available blocks TREATING as NO MULTICRASH INFO will write to default block");
1.344 + //In this case should we just overwrite old crashes and return the first block as the comment above suggests
1.345 + //return blockFound;
1.346 + }
1.347 + }
1.348 +
1.349 + // no multi crash info supplied - use default first block settings
1.350 + TInt err = EraseEntireFlashPartition();
1.351 + if(err != KErrNone)
1.352 + {
1.353 + CLTRACE1("Unable to delete area required to log to flash. Aborting. Error - [%d]", err);
1.354 + return err;
1.355 + }
1.356 +
1.357 + aBlockEntry = SCMCrashBlockEntry(0,0,0);
1.358 + return KErrNone;
1.359 + }
1.360 +
1.361 +/**
1.362 + * Handles the processing of the crash
1.363 + * @return The size of the crash log (including header) that has been/will be written
1.364 + */
1.365 +TInt SCMonitor::ProcessCrash(const SCMCrashBlockEntry& aBlock, TUint aCrashId, TBool aCommit)
1.366 + {
1.367 + LOG_CONTEXT
1.368 + CLTRACE5("aBlock.iBlockOffset = [%d] [0x%X] aBlock.iBlockNumber = %d aBlock.iBlockSize = [%d] [0x%X]",
1.369 + aBlock.iBlockOffset, aBlock.iBlockOffset, aBlock.iBlockNumber, aBlock.iBlockSize, aBlock.iBlockSize);
1.370 +
1.371 + // reset writer for start of each crash
1.372 + iDataSave->iWriter->ResetBytesWritten();
1.373 + TInt logLevel = 0;
1.374 +
1.375 + if(aCommit)
1.376 + {
1.377 + logLevel = KALWAYS;
1.378 + iDataSave->iWriter->EnablePhysicalWriting();
1.379 + }
1.380 + else
1.381 + {
1.382 +#if defined(_DEBUG)
1.383 + logLevel = KDEBUGGER;
1.384 +#else
1.385 + logLevel = KALWAYS; //Doesnt matter, KTRACE OPT is empty for rel builds
1.386 + if(logLevel != KALWAYS)
1.387 + {
1.388 + //This is to avoid warning
1.389 + }
1.390 +#endif
1.391 +
1.392 + iDataSave->iWriter->DisablePhysicalWriting();
1.393 + }
1.394 +
1.395 + iDataSave->SetByteCount(aBlock.iBlockOffset);
1.396 + if(aBlock.iBlockOffset == 0 && aBlock.iBlockNumber == 0)
1.397 + {
1.398 + // this is the first crash - we need to save the config here first
1.399 + CLTRACE("(SCMonitor::ProcessCrash) - this is block 0 - WRITING CONFIG");
1.400 + iDataSave->LogConfig(*iScmConfig);
1.401 +
1.402 + //Config is not part of crash so reset bytes written
1.403 + iDataSave->SetCrashStartingPoint(iDataSave->iWriter->GetBytesWritten());
1.404 + }
1.405 + else
1.406 + {
1.407 + iDataSave->SetCrashStartingPoint(aBlock.iBlockOffset);
1.408 + }
1.409 +
1.410 + iDataSave->iWriter->ResetBytesWritten();
1.411 +
1.412 + TUint32 logSize = 0;
1.413 + TUint sizeOfObjectDumped = 0;
1.414 +
1.415 + TInt err = iDataSave->LogCrashHeader(iFaultCategory, iFaultReason, aCrashId, sizeOfObjectDumped);
1.416 + if(KErrNone != err)
1.417 + {
1.418 + CLTRACE("System Crash Monitor: Failed to create crash info header - (TCrashInfo)");
1.419 + return KRestartType;
1.420 + }
1.421 +
1.422 + logSize += sizeOfObjectDumped;
1.423 +
1.424 + //Now we must read the configuration to use. This is held at the start of our flash partition
1.425 + //and managed by the iConfig object
1.426 + iScmConfig->ResetToHighestPriority();
1.427 +
1.428 + //Always want the crash context
1.429 + iDataSave->iHdr.iCTFullRegOffset = logSize + iDataSave->GetCrashStartingPoint();
1.430 +
1.431 + err = iDataSave->LogCPURegisters(sizeOfObjectDumped);
1.432 + if(KErrNone != err)
1.433 + {
1.434 + CLTRACE1("\tError logging full registers = %d", err);
1.435 + }
1.436 +
1.437 + logSize += sizeOfObjectDumped;
1.438 +
1.439 + CLTRACE("\tAbout to enter processing loop");
1.440 + SCMDataSave::TDataToDump dump;
1.441 +
1.442 + for(;;)
1.443 + {
1.444 + //now we get each item by priority from the configuration
1.445 + TConfigItem* configItem = iScmConfig->GetNextItem();
1.446 +
1.447 + if(!configItem)
1.448 + {
1.449 + // end of list
1.450 + break;
1.451 + }
1.452 +
1.453 + CLTRACE1("\nLooking at item type [%d]", configItem->GetDataType());
1.454 + if(configItem->GetSpaceRequired() > iDataSave->SpaceRemaining())
1.455 + {
1.456 + __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()));
1.457 + continue;
1.458 + }
1.459 + else
1.460 + {
1.461 + CLTRACE1("Will require [%d] bytes for this item", configItem->GetSpaceRequired());
1.462 + }
1.463 +
1.464 + // only interested in logging items with priority > 0
1.465 + if( configItem->GetPriority() <= 0)
1.466 + {
1.467 + CLTRACE1("\tIgnored config item type %d priority 0", configItem->GetDataType());
1.468 + continue;
1.469 + }
1.470 +
1.471 + //there are a lot of TUints in the hdr to record where we wrote this item.
1.472 + //This will point to the one of interest for this configItem
1.473 + TUint32* offsetPointer = NULL;
1.474 +
1.475 + //now we check the type of data we wish to dump
1.476 + switch(configItem->GetDataType())
1.477 + {
1.478 + case TConfigItem::ECrashedThreadMetaData:
1.479 + {
1.480 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ECrashedThreadMetaData at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.481 +
1.482 + err = LogThreadMetaData(SCMDataSave::EThreadSpecific, sizeOfObjectDumped);
1.483 + offsetPointer = &(iDataSave->iHdr.iCTMetaOffset);
1.484 +
1.485 + break;
1.486 + }
1.487 + case TConfigItem::EThreadsMetaData:
1.488 + {
1.489 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EThreadsMetaData at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.490 +
1.491 + //record location we are writing to in the header
1.492 + iDataSave->iHdr.iTLstOffset = iDataSave->iWriter->GetBytesWritten();
1.493 + err = LogThreadMetaData(SCMDataSave::ESystemWide, sizeOfObjectDumped);
1.494 + offsetPointer = &(iDataSave->iHdr.iTLstOffset);
1.495 +
1.496 + break;
1.497 + }
1.498 + case TConfigItem::ECrashedProcessMetaData:
1.499 + {
1.500 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ECrashedProcessMetaData at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.501 +
1.502 + err = LogProcessMetaData(SCMDataSave::EProcessSpecific, sizeOfObjectDumped);
1.503 + offsetPointer = &(iDataSave->iHdr.iCPMetaOffset);
1.504 +
1.505 + break;
1.506 + }
1.507 + case TConfigItem::EProcessMetaData:
1.508 + {
1.509 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EProcessMetaData at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.510 +
1.511 + err = LogProcessMetaData(SCMDataSave::ESystemWide, sizeOfObjectDumped);
1.512 + offsetPointer = &(iDataSave->iHdr.iPLstOffset);
1.513 +
1.514 + break;
1.515 + }
1.516 + case TConfigItem::ECrashedProcessUsrStacks:
1.517 + {
1.518 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ECrashedProcessUsrStacks at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.519 +
1.520 + //define what we wish to dump
1.521 + dump.iMetaData = EFalse;
1.522 + dump.iCodeSegs = EFalse;
1.523 + dump.iStk = SCMDataSave::EUsrStack;
1.524 + dump.iReg = SCMDataSave::ERegSetNone;
1.525 + err = LogObjectContainers(EThread, SCMDataSave::EProcessSpecific, dump, sizeOfObjectDumped);
1.526 + offsetPointer = &(iDataSave->iHdr.iCTUsrStkOffset);
1.527 +
1.528 + break;
1.529 + }
1.530 + case TConfigItem::EThreadsUsrStack:
1.531 + {
1.532 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EThreadsUsrStack at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.533 +
1.534 + //define what we wish to dump
1.535 + dump.iMetaData = EFalse;
1.536 + dump.iCodeSegs = EFalse;
1.537 + dump.iStk = SCMDataSave::EUsrStack;
1.538 + dump.iReg = SCMDataSave::ERegSetNone;
1.539 +
1.540 + err = LogObjectContainers(EThread, SCMDataSave::ESystemWide, dump, sizeOfObjectDumped);
1.541 + offsetPointer = &(iDataSave->iHdr.iSysSvrStkOffset);
1.542 +
1.543 + break;
1.544 + }
1.545 + case TConfigItem::ECrashedProcessSvrStacks:
1.546 + {
1.547 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ECrashedProcessSvrStacks at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.548 +
1.549 + //define what we wish to dump
1.550 + dump.iMetaData = EFalse;
1.551 + dump.iCodeSegs = EFalse;
1.552 + dump.iStk = SCMDataSave::ESvrStack;
1.553 + dump.iReg = SCMDataSave::ERegSetNone;
1.554 +
1.555 + err = LogObjectContainers(EThread, SCMDataSave::EProcessSpecific, dump, sizeOfObjectDumped);
1.556 + offsetPointer = &(iDataSave->iHdr.iCTSvrStkOffset);
1.557 +
1.558 + break;
1.559 + }
1.560 + case TConfigItem::EThreadsSvrStack:
1.561 + {
1.562 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EThreadsSvrStack at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.563 +
1.564 + //define what we wish to dump
1.565 + dump.iMetaData = EFalse;
1.566 + dump.iCodeSegs = EFalse;
1.567 + dump.iStk = SCMDataSave::ESvrStack;
1.568 + dump.iReg = SCMDataSave::ERegSetNone;
1.569 +
1.570 + err = LogObjectContainers(EThread, SCMDataSave::ESystemWide, dump, sizeOfObjectDumped);
1.571 + offsetPointer = &(iDataSave->iHdr.iSysSvrStkOffset);
1.572 +
1.573 + break;
1.574 + }
1.575 + case TConfigItem::EThreadsUsrRegisters:
1.576 + {
1.577 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EThreadsUsrRegisters at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.578 +
1.579 + //define what we wish to dump
1.580 + dump.iMetaData = EFalse;
1.581 + dump.iCodeSegs = EFalse;
1.582 + dump.iStk = SCMDataSave::EStackTypeNone;
1.583 + dump.iReg = SCMDataSave::EUserRegisters;
1.584 +
1.585 + err = LogObjectContainers(EThread, SCMDataSave::ESystemWide, dump, sizeOfObjectDumped);
1.586 + offsetPointer = &(iDataSave->iHdr.iSysUsrRegOffset);
1.587 +
1.588 + break;
1.589 + }
1.590 + case TConfigItem::EThreadsSvrRegisters:
1.591 + {
1.592 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EThreadsSvrRegisters at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.593 +
1.594 + //define what we wish to dump
1.595 + dump.iMetaData = EFalse;
1.596 + dump.iCodeSegs = EFalse;
1.597 + dump.iStk = SCMDataSave::EStackTypeNone;
1.598 + dump.iReg = SCMDataSave::ESupervisorRegisters;
1.599 +
1.600 + err = LogObjectContainers(EThread, SCMDataSave::ESystemWide, dump, sizeOfObjectDumped);
1.601 + offsetPointer = &(iDataSave->iHdr.iSysSvrRegOffset);
1.602 +
1.603 + break;
1.604 + }
1.605 + case TConfigItem::EExceptionStacks:
1.606 + {
1.607 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EExceptionStacks at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.608 +
1.609 + err = iDataSave->LogExceptionStacks(sizeOfObjectDumped);
1.610 + offsetPointer = &(iDataSave->iHdr.iExcStkOffset);
1.611 +
1.612 + break;
1.613 + }
1.614 + case TConfigItem::ECrashedProcessCodeSegs:
1.615 + {
1.616 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ECrashedProcessCodeSegs at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.617 +
1.618 + //define what we wish to dump
1.619 + dump.iMetaData = EFalse;
1.620 + dump.iCodeSegs = ETrue;
1.621 + dump.iStk = SCMDataSave::EStackTypeNone;
1.622 + dump.iReg = SCMDataSave::ERegSetNone;
1.623 +
1.624 + err = LogObjectContainers(EProcess, SCMDataSave::EProcessSpecific, dump, sizeOfObjectDumped);
1.625 + offsetPointer = &(iDataSave->iHdr.iCPCodeSegOffset);
1.626 +
1.627 + break;
1.628 + }
1.629 + case TConfigItem::EProcessCodeSegs:
1.630 + {
1.631 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EProcessCodeSegs at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.632 +
1.633 + //define what we wish to dump
1.634 + dump.iMetaData = EFalse;
1.635 + dump.iCodeSegs = ETrue;
1.636 + dump.iStk = SCMDataSave::EStackTypeNone;
1.637 + dump.iReg = SCMDataSave::ERegSetNone;
1.638 + err = LogObjectContainers(EProcess, SCMDataSave::ESystemWide, dump, sizeOfObjectDumped);
1.639 + offsetPointer = &(iDataSave->iHdr.iSysCodeSegOffset);
1.640 +
1.641 + break;
1.642 + }
1.643 + case TConfigItem::ETraceData:
1.644 + {
1.645 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ETraceData at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.646 +
1.647 + err = iDataSave->LogTraceBuffer(configItem->GetSizeToDump(), sizeOfObjectDumped);
1.648 + offsetPointer = &(iDataSave->iHdr.iTraceOffset);
1.649 +
1.650 + break;
1.651 + }
1.652 + case TConfigItem::ELocks:
1.653 + {
1.654 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ELocks at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.655 +
1.656 + err = iDataSave->LogLocks(sizeOfObjectDumped);
1.657 + offsetPointer = &(iDataSave->iHdr.iScmLocksOffset);
1.658 +
1.659 + break;
1.660 + }
1.661 + case TConfigItem::EKernelHeap:
1.662 + {
1.663 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EKernelHeap at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.664 +
1.665 + err = iDataSave->LogKernelHeap(sizeOfObjectDumped);
1.666 + offsetPointer = &(iDataSave->iHdr.iKernelHeapOffset);
1.667 +
1.668 + break;
1.669 + }
1.670 + case TConfigItem::EVariantSpecificData:
1.671 + {
1.672 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: EVariantSpecificData at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.673 +
1.674 + err = iDataSave->LogVariantSpecificData(sizeOfObjectDumped);
1.675 + offsetPointer = &(iDataSave->iHdr.iVarSpecInfOffset);
1.676 +
1.677 + break;
1.678 + }
1.679 + case TConfigItem::ERomInfo:
1.680 + {
1.681 + __KTRACE_OPT(logLevel, Kern::Printf("\tDoing: ERomInfo at [%d] offset from [%d]", iDataSave->iWriter->GetBytesWritten(), iDataSave->GetCrashStartingPoint()));
1.682 +
1.683 + err = iDataSave->LogRomInfo(sizeOfObjectDumped);
1.684 + offsetPointer = &(iDataSave->iHdr.iRomInfoOffset);
1.685 +
1.686 + break;
1.687 + }
1.688 + //unknown configuration type - something bad is going on
1.689 + default: return 0;
1.690 + }
1.691 +
1.692 + if(KErrNone != err)
1.693 + {
1.694 + __KTRACE_OPT(logLevel, Kern::Printf("\tError logging data: [%d] Type = [%d]", err, aBlock.iBlockOffset));
1.695 + continue;
1.696 + }
1.697 +
1.698 + //Set the space required so next time around we will know in advance how much space we need
1.699 + configItem->SetSpaceRequired(sizeOfObjectDumped);
1.700 +
1.701 + //Note: the following steps are only required for the first time we call process crash. The second time,
1.702 + //when physical writing is enabled, these will have been written already and so they dont matter
1.703 +
1.704 + //update the offset and logsize if we are going to dump this item
1.705 + TUint32 absoluteLogPos = logSize + iDataSave->GetCrashStartingPoint();
1.706 + if(absoluteLogPos+sizeOfObjectDumped < iDataSave->MaxLogSize())
1.707 + {
1.708 + //now, we must record where in the crash log this item will be dumped
1.709 + *offsetPointer = absoluteLogPos;
1.710 + logSize += sizeOfObjectDumped;
1.711 + }
1.712 + }
1.713 +
1.714 + iDataSave->iCrashInf.iLogSize = logSize;
1.715 + iDataSave->iWriter->FlushCache();
1.716 +
1.717 + return iDataSave->iCrashInf.iLogSize;
1.718 + }
1.719 +
1.720 +/**
1.721 + * Logs the meta data for processes
1.722 + * @param aCurrentProcess - scope to dump
1.723 + * @return one of the OS wide codes
1.724 + */
1.725 +TInt SCMonitor::LogProcessMetaData(SCMDataSave::TDumpScope aScope, TUint& aSizeDumped) const
1.726 + {
1.727 + LOG_CONTEXT
1.728 +
1.729 + SCMDataSave::TDataToDump dump;
1.730 + dump.iMetaData = ETrue;
1.731 +
1.732 + return LogObjectContainers(EProcess, aScope, dump, aSizeDumped);
1.733 + }
1.734 +
1.735 +/**
1.736 + *
1.737 + * @param aCurrentThread - to only do the current (crashed thread) or to do all the others
1.738 + * @return one of the OS wide codes
1.739 + */
1.740 +TInt SCMonitor::LogThreadMetaData(SCMDataSave::TDumpScope aScope, TUint& aSizeDumped) const
1.741 + {
1.742 + LOG_CONTEXT
1.743 +
1.744 + SCMDataSave::TDataToDump dump;
1.745 + dump.iMetaData = ETrue;
1.746 +
1.747 + return LogObjectContainers(EThread, aScope, dump, aSizeDumped);
1.748 + }
1.749 +
1.750 +/**
1.751 + * Generic method that looks at all kernel objects of aObjectType
1.752 + * @param aObjectType
1.753 + * @param aDumpScope - if you wish to dump for the the current process, current thread or entire system
1.754 + * @param aDataToDump - data you wish to dump
1.755 + * @param aSizeDumped - records how much was dumped
1.756 + * @return
1.757 + */
1.758 +TInt SCMonitor::LogObjectContainers(TObjectType aObjectType, SCMDataSave::TDumpScope aDumpScope, const SCMDataSave::TDataToDump& aDataToDump, TUint& aSizeDumped) const
1.759 + {
1.760 + aSizeDumped = 0;
1.761 +
1.762 + if(aObjectType >= ENumObjectTypes)
1.763 + {
1.764 + return KErrArgument;
1.765 + }
1.766 +
1.767 + //Get the object container for the given object type
1.768 + DObjectCon* objectContainer = Kern::Containers()[aObjectType];
1.769 + if(objectContainer == NULL)
1.770 + {
1.771 + CLTRACE("tFailed to get object container");
1.772 + return KErrNotFound;
1.773 + }
1.774 +
1.775 + //Must check the mutex on this is ok otherwise the data will be in an inconsistent state
1.776 + if(objectContainer->iMutex->iHoldCount)
1.777 + {
1.778 + CLTRACE("\tObject Container is in an inconsistant state");
1.779 + return KErrCorrupt;
1.780 + }
1.781 +
1.782 + TInt numObjects = objectContainer->Count();
1.783 + TInt err = KErrNone;
1.784 +
1.785 + for(TInt cnt = 0; cnt< numObjects; cnt ++)
1.786 + {
1.787 + DObject* object = (*objectContainer)[cnt];
1.788 +
1.789 + //Are we interested in the object? scope only relevant for thread and process objects, for others, the scope is implicit
1.790 + if(aObjectType == EThread)
1.791 + {
1.792 + switch(aDumpScope)
1.793 + {
1.794 + case SCMDataSave::EThreadSpecific :
1.795 + {
1.796 + //if we are interested in the current thread and this is not it, continue
1.797 + if(((DThread*)object) != &Kern::CurrentThread())
1.798 + continue;
1.799 + break;
1.800 + }
1.801 + case SCMDataSave::EProcessSpecific :
1.802 + {
1.803 + //if we are interested in the current proc and this is not it, continue
1.804 + if(((DThread*)object)->iOwningProcess != &Kern::CurrentProcess())
1.805 + continue;
1.806 + break;
1.807 + }
1.808 + case SCMDataSave::ESystemWide :
1.809 + default:
1.810 + break;
1.811 + }
1.812 + }
1.813 + else if(aObjectType == EProcess)
1.814 + {
1.815 + switch(aDumpScope)
1.816 + {
1.817 + case SCMDataSave::EProcessSpecific :
1.818 + {
1.819 + if((DProcess*)object != &Kern::CurrentProcess())
1.820 + continue;
1.821 + break;
1.822 + }
1.823 + case SCMDataSave::EThreadSpecific : //thread specific process doesnt make sense
1.824 + return KErrArgument;
1.825 + case SCMDataSave::ESystemWide :
1.826 + default:
1.827 + break;
1.828 + }
1.829 + }
1.830 +
1.831 + //Now we look at the data we have been asked to dump
1.832 + if(aDataToDump.iMetaData)
1.833 + {
1.834 + TUint dumped = 0;
1.835 + err = HelpDumpMetaData(object, aObjectType, dumped);
1.836 + if(KErrNone != err)
1.837 + {
1.838 + CLTRACE1("Failed to meta data: [%d]", err);
1.839 + return err;
1.840 + }
1.841 + aSizeDumped += dumped;
1.842 + }
1.843 +
1.844 + if(aDataToDump.iCodeSegs)
1.845 + {
1.846 + if(aObjectType != EProcess)
1.847 + {
1.848 + return KErrArgument;
1.849 + }
1.850 +
1.851 + TUint dumped = 0;
1.852 + err = iDataSave->LogCodeSegments((DProcess*)object, dumped);
1.853 + if(KErrNone != err)
1.854 + {
1.855 + CLTRACE1("Failed to log code segments: [%d]", err);
1.856 + return err;
1.857 + }
1.858 + aSizeDumped += dumped;
1.859 + }
1.860 +
1.861 + if(aDataToDump.iStk != SCMDataSave::EStackTypeNone)
1.862 + {
1.863 + TUint dumped = 0;
1.864 + err = HelpDumpStacks(object, aObjectType, dumped, aDataToDump.iStk);
1.865 + if(KErrNone != err)
1.866 + {
1.867 + CLTRACE1("Failed to log stacks: [%d]", err);
1.868 + return err;
1.869 + }
1.870 + aSizeDumped += dumped;
1.871 + }
1.872 +
1.873 + if(aDataToDump.iReg != SCMDataSave::ERegSetNone)
1.874 + {
1.875 + if(aObjectType != EThread)
1.876 + {
1.877 + return KErrArgument;
1.878 + }
1.879 + TUint dumped = 0;
1.880 + err = iDataSave->LogRegisters((DThread*)object, aDataToDump.iReg, dumped);
1.881 + 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
1.882 + {
1.883 + CLTRACE1("Failed to log registers: [%d]", err);
1.884 + return err;
1.885 + }
1.886 + aSizeDumped += dumped;
1.887 + }
1.888 + }
1.889 +
1.890 + return KErrNone;
1.891 + }
1.892 +
1.893 +/**
1.894 + * Helper method for dumping stacks. Looks to see what type of stack we want and then calls
1.895 + * appropriate method
1.896 + * @param aObject The DThread object whose stack we want
1.897 + * @param aObjectType The object type of this aObject. Anything other than EThread will give KErrArgument
1.898 + * @param aSizeDumped Holds the size of the stack dumped after processing
1.899 + * @param aStkType The type of stack to be dumped
1.900 + * @see TObjectType
1.901 + * @see SCMDataSave::TStackType
1.902 + * @return One of the system wide codes
1.903 + */
1.904 +TInt SCMonitor::HelpDumpStacks(DObject* aObject, TObjectType aObjectType, TUint& aSizeDumped, SCMDataSave::TStackType aStkType) const
1.905 + {
1.906 + //verify args
1.907 + if(aObjectType != EThread)
1.908 + {
1.909 + return KErrArgument;
1.910 + }
1.911 +
1.912 + switch(aStkType)
1.913 + {
1.914 + case SCMDataSave::EUsrStack:
1.915 + {
1.916 + return iDataSave->LogThreadUserStack((DThread*)aObject, ETrue, aSizeDumped);
1.917 + }
1.918 + case SCMDataSave::ESvrStack:
1.919 + {
1.920 + return iDataSave->LogThreadSupervisorStack((DThread*)aObject, ETrue, aSizeDumped);
1.921 + }
1.922 + default: return KErrArgument;
1.923 + }
1.924 + }
1.925 +
1.926 +/**
1.927 + * Helper method to dump meta data about a DThread or a DProcess object
1.928 + * @param aObject DObject to use
1.929 + * @param aObjectType Type of DObject. Must be EThread or EProcess
1.930 + * @param aSizeDumped Holds the size of the stack dumped after processing
1.931 + * @return
1.932 + */
1.933 +TInt SCMonitor::HelpDumpMetaData(DObject* aObject, TObjectType aObjectType, TUint& aSizeDumped) const
1.934 + {
1.935 + aSizeDumped = 0;
1.936 +
1.937 + switch(aObjectType)
1.938 + {
1.939 + case EThread:
1.940 + {
1.941 + return iDataSave->LogThreadData((DThread*)aObject, aSizeDumped);
1.942 + }
1.943 + case EProcess:
1.944 + {
1.945 + return iDataSave->LogProcessData((DProcess*)aObject, aSizeDumped);
1.946 + }
1.947 + default: return KErrArgument;
1.948 + }
1.949 + }
1.950 +
1.951 +/**
1.952 + * Wrapper method around the flash erase block fundtion to determine if the erase was succesful.
1.953 + * If the erase was not succesful we can't continue as we cannot write.
1.954 + * @param aBlockOffset Block to erase
1.955 + * @return One of the OS wide codes
1.956 + */
1.957 +TInt SCMonitor::EraseFlashBlock(const SCMCrashBlockEntry& aBlock)
1.958 + {
1.959 + iFlash->StartTransaction();
1.960 +
1.961 + TInt numAttempts = 0;
1.962 + while(numAttempts < KFlashEraseAttempts)
1.963 + {
1.964 + iFlash->SetWritePos(aBlock.iBlockOffset);
1.965 + iFlash->EraseFlashBlock(aBlock.iBlockOffset);
1.966 +
1.967 + //we will read the flash to make sure that it set the block to all 1's (well not all, just the start)
1.968 + TBuf8<sizeof(TUint32)> buf;
1.969 + buf.SetLength(sizeof(TUint32));
1.970 +
1.971 + iFlash->SetReadPos(aBlock.iBlockOffset);
1.972 + iFlash->Read(buf);
1.973 +
1.974 + volatile TUint32* result = (TUint32*)buf.Ptr();
1.975 + if(*result == 0xFFFFFFFF)
1.976 + {
1.977 + __KTRACE_OPT(KALWAYS, Kern::Printf("Erase of block [0x%X] succesful after [%d] attempts", aBlock.iBlockOffset, numAttempts+1))
1.978 + iFlash->EndTransaction();
1.979 + return KErrNone;
1.980 + }
1.981 +
1.982 + numAttempts++;
1.983 +
1.984 + //Sometimes a write to the block helps the next erase
1.985 + TUint32 bytesWritten = 0;
1.986 + while(bytesWritten < aBlock.iBlockSize)
1.987 + {
1.988 + TBuf8<sizeof(TUint8)> num;
1.989 + num.Append(0x0);
1.990 + iFlash->Write(num);
1.991 + bytesWritten++;
1.992 + }
1.993 + }
1.994 +
1.995 + __KTRACE_OPT(KALWAYS, Kern::Printf("After %d attempts, we were unable to erase the flash block at [0x%X]. This could be because "
1.996 + "the driver is defective or because the flash has gone past its lifetime. Whatever it is though, "
1.997 + "we cannot continue.", KFlashEraseAttempts, aBlock.iBlockOffset));
1.998 +
1.999 + iFlash->EndTransaction();
1.1000 + return KErrAbort;
1.1001 + }
1.1002 +
1.1003 +/**
1.1004 + * This erases each block in the flash partition
1.1005 + * @return One of the system wide codes
1.1006 + */
1.1007 +TInt SCMonitor::EraseEntireFlashPartition()
1.1008 + {
1.1009 + if(iMultiCrashInfo)
1.1010 + {
1.1011 + iMultiCrashInfo->Reset();
1.1012 +
1.1013 + SCMCrashBlockEntry* block = iMultiCrashInfo->GetNextBlock();
1.1014 + while(block)
1.1015 + {
1.1016 + TInt err = EraseFlashBlock(*block);
1.1017 + if(KErrNone != err)
1.1018 + {
1.1019 + return err;
1.1020 + }
1.1021 +
1.1022 + block = iMultiCrashInfo->GetNextBlock();
1.1023 + }
1.1024 +
1.1025 + return KErrNone;
1.1026 + }
1.1027 +
1.1028 + CLTRACE("SCMonitor::EraseEntireFlashPartition() -- No Flash MAP available, trying to use the raw driver to delete.");
1.1029 + TheSCMonitor.iFlash->EraseLogArea();
1.1030 +
1.1031 + return KErrNone;
1.1032 + }
1.1033 +
1.1034 +//eof scmonitor.cpp
1.1035 +