1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/debug/crashMonitor/src/scmdatasave.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1240 @@
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\scmdatasave.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#define __INCLUDE_REG_OFFSETS__ // for SP_R13U in nk_plat.h
1.22 +
1.23 +#include <omap_dbg.h>
1.24 +#include "arm_mem.h"
1.25 +#include "nk_plat.h"
1.26 +#include <omap_assp.h>
1.27 +#include <scmonitor.h>
1.28 +#include <scmdatasave.h>
1.29 +
1.30 +/**
1.31 + * @file
1.32 + * @internal technology
1.33 + */
1.34 +
1.35 +/**
1.36 + * SCMDataSave constructor
1.37 + * @param aMonitor - the monitor which has caught the syetem crash this object is saving data for
1.38 + * @param aFlash - the flash memory data will be written to, note the CrashFlash interface is
1.39 + * rather limited and does not support partial block writes
1.40 + * @param aFlashInfo - data describing the structure of the flash data
1.41 + */
1.42 +EXPORT_C SCMDataSave::SCMDataSave(Monitor* aMonitor, CrashFlash* aFlash)
1.43 + : iMonitor(aMonitor)
1.44 + ,iFlash(aFlash)
1.45 + ,iByteCount(0)
1.46 +#ifdef SCM_COMM_OUTPUT
1.47 + ,iWriteSelect(EWriteComm) // write data to debug port
1.48 +#else
1.49 + ,iWriteSelect(EWriteFlash) // write data to flash
1.50 +#endif
1.51 + ,iPerformChecksum(ETrue) // checksum data
1.52 + ,iStartingPointForCrash(0)
1.53 + {
1.54 + const TInt KCacheSize = 128;
1.55 + iFlashCache = HBuf8::New(KCacheSize);
1.56 + CLTRACE1("(SCMDataSave) Creating writer with cache size = %d", KCacheSize);
1.57 + iWriter = new TCachedByteStreamWriter(const_cast<TUint8*>(iFlashCache->Ptr()), KCacheSize);
1.58 + iWriter->SetWriterImpl(this);
1.59 + }
1.60 +
1.61 +/**
1.62 + * Destructor
1.63 + */
1.64 +SCMDataSave::~SCMDataSave()
1.65 + {
1.66 + delete iFlashCache;
1.67 + }
1.68 +
1.69 +/**
1.70 + * Getter for the current byte count. This is the amount of data that has currently
1.71 + * been written to given media for this crash log
1.72 + * @return The number of bytes written already to given media
1.73 + */
1.74 +TInt SCMDataSave::GetByteCount()
1.75 + {
1.76 + return iByteCount;
1.77 + }
1.78 +
1.79 +/**
1.80 + * Logs the user stack for a given DThread object if it is available
1.81 + * @param aThread - thread whose stack we wish to log
1.82 + * @param aSizeDumped Holds the size of the data dumped
1.83 + * @return one of the OS codes
1.84 + */
1.85 +TInt SCMDataSave::LogThreadUserStack(DThread* aThread, TBool aFullStack, TUint& aSizeDumped)
1.86 + {
1.87 + LOG_CONTEXT
1.88 + aSizeDumped = 0;
1.89 + TUint memDumped = 0;
1.90 +
1.91 + TUint svSp, usrSp;
1.92 + iMonitor->GetStackPointers(&(aThread->iNThread), svSp, usrSp );
1.93 +
1.94 + //first we check for a user stack...
1.95 + if (aThread->iUserStackRunAddress && aThread->iUserStackSize)
1.96 + {
1.97 + //Get data together
1.98 + TThreadStack usrStack;
1.99 + usrStack.iStackType = TThreadStack::EUsrStack;
1.100 + usrStack.iThreadId = (TUint64)aThread->iId;
1.101 +
1.102 + //map in the user stack
1.103 + TUint8* usrStart = (TUint8*)iMonitor->MapAndLocateUserStack(aThread); //What about Demand paging??
1.104 + TUint8* usrEnd = (TUint8*)(usrStart + aThread->iUserStackSize);
1.105 + if(usrStart)
1.106 + {
1.107 + TUint8* stackPointer = (TUint8*)usrSp;
1.108 +
1.109 + //check the stack pointer is in the range of the stack...
1.110 + if (stackPointer < usrStart || stackPointer >= usrEnd)
1.111 + {
1.112 + stackPointer = usrStart;
1.113 + }
1.114 +
1.115 + //log the size of the stack we are dumping
1.116 + usrStack.iStackSize = aFullStack || (stackPointer == usrStart) ? usrEnd - usrStart : usrEnd - stackPointer;
1.117 + TUint8* dumpFrom = aFullStack ? usrStart : stackPointer;
1.118 +
1.119 + //write the stack
1.120 + aSizeDumped+= usrStack.GetSize();
1.121 + usrStack.Serialize(*iWriter);
1.122 +
1.123 + //now we dump the actual stack
1.124 + //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.125 + //-1 because we dont want to write the byte at usrEnd
1.126 + MTRAPD(memErr, LogMemory(dumpFrom, usrStack.iStackSize, aThread, memDumped));
1.127 + if(KErrNone != memErr)
1.128 + {
1.129 + CLTRACE("Failed to log usr stack");
1.130 + }
1.131 +
1.132 + aSizeDumped+= memDumped;
1.133 + }
1.134 + else
1.135 + {
1.136 + //write the struct
1.137 + aSizeDumped+=usrStack.GetSize();
1.138 + usrStack.Serialize(*iWriter);
1.139 + }
1.140 + }
1.141 + return KErrNone;
1.142 + }
1.143 +
1.144 +/**
1.145 + * Logs the supervisor stack for a given DThread object
1.146 + * @param aThread - thread whose stack we wish to log
1.147 + * @param aSizeDumped Holds the size of the data dumped
1.148 + * @return one of the system wide codes
1.149 + */
1.150 +TInt SCMDataSave::LogThreadSupervisorStack(DThread* aThread, TBool aFullStack, TUint& aSizeDumped)
1.151 + {
1.152 + LOG_CONTEXT
1.153 + aSizeDumped = 0;
1.154 + TUint memDumped;
1.155 +
1.156 + TUint svSp, usrSp;
1.157 + iMonitor->GetStackPointers(&(aThread->iNThread), svSp, usrSp );
1.158 +
1.159 + //now we dump the supervisor stack
1.160 + TThreadStack svrStack;
1.161 + svrStack.iStackType = TThreadStack::ESvrStack;
1.162 + svrStack.iThreadId = (TUint64)aThread->iId;
1.163 +
1.164 + if (aThread->iSupervisorStack && aThread->iSupervisorStackSize)
1.165 + {
1.166 + TUint8* svrStart = (TUint8*)aThread->iSupervisorStack;
1.167 + TUint8* svrEnd = (TUint8*)(svrStart + aThread->iSupervisorStackSize);
1.168 + TUint8* svrStackPointer = (TUint8*)svSp;
1.169 +
1.170 + //size of stack we are to dump
1.171 + svrStack.iStackSize = aFullStack || (svrStackPointer == svrStart) ? svrEnd - svrStart : svrEnd - svrStackPointer;
1.172 +
1.173 + if(svrStart)
1.174 + {
1.175 + //check the stack pointer is in the range of the stack...
1.176 + if (svrStackPointer < svrStart || svrStackPointer >= svrEnd)
1.177 + {
1.178 + svrStackPointer = svrStart;
1.179 + }
1.180 +
1.181 + //write struct to flash
1.182 + aSizeDumped+=svrStack.GetSize();
1.183 + svrStack.Serialize(*iWriter);
1.184 +
1.185 + //now we dump the actual stack
1.186 + //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.187 + MTRAPD(memErr, LogMemory(svrStart, svrStack.iStackSize, aThread, memDumped));
1.188 + aSizeDumped+=memDumped;
1.189 +
1.190 + if(KErrNone != memErr)
1.191 + {
1.192 + CLTRACE("Failed to log supervisor stack");
1.193 + }
1.194 + }
1.195 + else
1.196 + {
1.197 + //write the struct
1.198 + aSizeDumped+=svrStack.GetSize();
1.199 + svrStack.Serialize(*iWriter);
1.200 + }
1.201 + }
1.202 +
1.203 + return KErrNone;
1.204 + }
1.205 +
1.206 +/**
1.207 + * Takes a DProcess kernel object and logs its corrosponding code segments
1.208 + * @param aProcess
1.209 + * @param aSizeDumped Holds the size of the data dumped
1.210 + * @return one of the OS wide error codes
1.211 + */
1.212 +TInt SCMDataSave::LogCodeSegments(DProcess* aProc, TUint& aSizeDumped)
1.213 + {
1.214 + LOG_CONTEXT
1.215 + aSizeDumped = 0;
1.216 +
1.217 + //the code segment set for this process
1.218 + TCodeSegmentSet segSet;
1.219 + segSet.iPid = (TUint64)aProc->iId;
1.220 +
1.221 + //make sure list mutex is ok
1.222 + if(Kern::CodeSegLock()->iHoldCount)
1.223 + {
1.224 + return KErrCorrupt;
1.225 + }
1.226 +
1.227 + //get code seg list
1.228 + SDblQue queue;
1.229 + aProc->TraverseCodeSegs(&queue, NULL, DCodeSeg::EMarkDebug, DProcess::ETraverseFlagAdd);
1.230 +
1.231 + //iterate through the list
1.232 + TInt codeSegCnt = 0;
1.233 + for(SDblQueLink* codeSegPtr= queue.First(); codeSegPtr!=(SDblQueLink*) (&queue); codeSegPtr=codeSegPtr->iNext)
1.234 + {
1.235 + //get the code seg
1.236 + DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr,DCodeSeg, iTempLink);
1.237 +
1.238 + if(codeSeg)
1.239 + {
1.240 + codeSegCnt++;
1.241 + }
1.242 + }
1.243 +
1.244 + if(codeSegCnt == 0)
1.245 + {
1.246 + return KErrNone;
1.247 + }
1.248 +
1.249 + segSet.iNumSegs = codeSegCnt;
1.250 + segSet.Serialize(*iWriter);
1.251 + aSizeDumped+=segSet.GetSize();
1.252 +
1.253 + TModuleMemoryInfo memoryInfo;
1.254 +
1.255 + //now we write each code segment
1.256 + for(SDblQueLink* codeSegPtr= queue.First(); codeSegPtr!=(SDblQueLink*) (&queue); codeSegPtr=codeSegPtr->iNext)
1.257 + {
1.258 + //get the code seg
1.259 + DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr,DCodeSeg, iTempLink);
1.260 +
1.261 + if(codeSeg)
1.262 + {
1.263 + TCodeSegment seg;
1.264 + seg.iXip = (codeSeg->iXIP) ? ETrue : EFalse;
1.265 +
1.266 + //Get the code seg type
1.267 + if(codeSeg->IsExe())
1.268 + {
1.269 + seg.iCodeSegType = EExeCodeSegType;
1.270 + }
1.271 + else if(codeSeg->IsDll())
1.272 + {
1.273 + seg.iCodeSegType = EDllCodeSegType;
1.274 + }
1.275 +
1.276 + TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL);
1.277 + if(KErrNone == err)
1.278 + {
1.279 + seg.iCodeSegMemInfo = memoryInfo;
1.280 + }
1.281 + else
1.282 + {
1.283 + seg.iCodeSegMemInfo.iCodeSize = 0;
1.284 +
1.285 + // Still need to indicate it wasnt available somehow
1.286 + }
1.287 +
1.288 + //Get filename
1.289 + seg.iNameLength = codeSeg->iFileName->Length();
1.290 + seg.iName = *(codeSeg->iFileName);
1.291 +
1.292 + aSizeDumped+=seg.GetSize();
1.293 + seg.Serialize(*iWriter);
1.294 + }
1.295 + }
1.296 +
1.297 + //Empty this queue and clear marks
1.298 + DCodeSeg::EmptyQueue(queue, DCodeSeg::EMarkDebug);
1.299 +
1.300 + return KErrNone;
1.301 + }
1.302 +
1.303 +/**
1.304 + * This logs the rom version and header information to the crash media
1.305 + * @param aSizeDumped amount of data occupied
1.306 + * @return one of the OS wide codes
1.307 + */
1.308 +TInt SCMDataSave::LogRomInfo(TUint& aSizeDumped)
1.309 + {
1.310 + aSizeDumped = 0;
1.311 +
1.312 + TRomHeaderData romData;
1.313 +
1.314 + TRomHeader rHdr = Epoc::RomHeader();
1.315 +
1.316 + romData.iMajorVersion = rHdr.iVersion.iMajor;
1.317 + romData.iMinorVersion = rHdr.iVersion.iMinor;
1.318 + romData.iBuildNumber = rHdr.iVersion.iBuild;
1.319 + romData.iTime = rHdr.iTime;
1.320 +
1.321 + TInt err = romData.Serialize(*iWriter);
1.322 + if(KErrNone != err)
1.323 + {
1.324 + return err;
1.325 + }
1.326 +
1.327 + aSizeDumped += romData.GetSize();
1.328 +
1.329 + return KErrNone;
1.330 + }
1.331 +
1.332 +/**
1.333 + * Takes a DProcess kernel object and logs to flash
1.334 + * @param aProc
1.335 + * @param aSizeDumped Holds the size of the data dumped
1.336 + * @return one of the OS wide error codes
1.337 + */
1.338 +TInt SCMDataSave::LogProcessData(DProcess* aProc, TUint& aSizeDumped)
1.339 + {
1.340 + LOG_CONTEXT
1.341 + aSizeDumped = 0;
1.342 +
1.343 + TProcessData procData;
1.344 + DCodeSeg* codeSeg = aProc->iCodeSeg;
1.345 +
1.346 + procData.iPriority = aProc->iPriority;
1.347 + procData.iPid = (TUint64)aProc->iId;
1.348 +
1.349 + //the code segment is not always available
1.350 + if(codeSeg)
1.351 + {
1.352 + procData.iNamesize = codeSeg->iFileName->Length();
1.353 + procData.iName = *(codeSeg->iFileName);
1.354 + }
1.355 +
1.356 + aSizeDumped += procData.GetSize();
1.357 + procData.Serialize(*iWriter);
1.358 +
1.359 + return KErrNone;
1.360 + }
1.361 +
1.362 +/**
1.363 + * Creates meta data about the crash such as time of crash, exit reason etc. to be logged
1.364 + * later on when we have log size.
1.365 + * @param aCategory - crash category
1.366 + * @param aReason - crash reason
1.367 + * @param aSizeDumped Holds the size of the data dumped
1.368 + * @return one of the OS wide codes
1.369 + */
1.370 +TInt SCMDataSave::LogCrashHeader(const TDesC8& aCategory, TInt aReason, TInt aCrashId, TUint& aSizeDumped)
1.371 + {
1.372 + LOG_CONTEXT
1.373 + aSizeDumped = 0;
1.374 +
1.375 + //the thread that crashed is the context in which we are running
1.376 + DThread* crashedThread = &Kern::CurrentThread();
1.377 +
1.378 + iCrashInf.iPid = crashedThread->iOwningProcess->iId;
1.379 + iCrashInf.iTid = crashedThread->iId;
1.380 + iCrashInf.iCrashTime = CrashTime();
1.381 + iCrashInf.iExitType = 0; // Not yet done: Exception or Fault - should be in category
1.382 + iCrashInf.iExitReason = aReason;
1.383 + iCrashInf.iFlashAlign = KFlashAlignment; //record the flash alignment (word aligned for now)
1.384 + iCrashInf.iCachedWriterSize = iWriter->GetCacheSize();
1.385 +
1.386 + iCrashInf.iCategorySize = aCategory.Length();
1.387 + iCrashInf.iCategory = aCategory;
1.388 + iCrashInf.iCrashId = aCrashId;
1.389 +
1.390 + iCrashInf.iFlashBlockSize = KCrashLogBlockSize;;
1.391 + iCrashInf.iFlashPartitionSize = KCrashLogSize;;
1.392 +
1.393 + TSuperPage& sp=Kern::SuperPage();
1.394 + iCrashInf.iExcCode = sp.iKernelExcId;
1.395 +
1.396 + //These will be updated with more info at end of crash
1.397 + aSizeDumped+=iCrashInf.GetSize();
1.398 + iCrashInf.Serialize(*iWriter);
1.399 +
1.400 + aSizeDumped+=iHdr.GetSize();
1.401 + iHdr.Serialize(*iWriter);
1.402 +
1.403 + CLTRACE1("(SCMDataSave::LogCrashHeader) finished bytes written= %d", iWriter->GetBytesWritten());
1.404 + return KErrNone;
1.405 + }
1.406 +
1.407 +/**
1.408 + * Logs meta data about a given DThread object
1.409 + * @param aThread Thread to dump
1.410 + * @param aSizeDumped Holds the size of the data dumped
1.411 + * @return
1.412 + */
1.413 +TInt SCMDataSave::LogThreadData(DThread* aThread, TUint& aSizeDumped)
1.414 + {
1.415 + LOG_CONTEXT
1.416 + aSizeDumped = 0;
1.417 +
1.418 + //struct to hold data that gets written to flash
1.419 + TThreadData threadData;
1.420 +
1.421 + threadData.iTid = (TUint64)aThread->iId;
1.422 + threadData.iOwnerId = (TUint64)aThread->iOwningProcess->iId;
1.423 + threadData.iPriority = aThread->iThreadPriority;
1.424 +
1.425 + //Get the stack pointers
1.426 + TUint svSp, usrSp;
1.427 + iMonitor->GetStackPointers(&(aThread->iNThread), svSp, usrSp );
1.428 + threadData.iUsrSP = usrSp;
1.429 + threadData.iSvcSP = svSp;
1.430 +
1.431 + //supervisor and user stack details
1.432 + threadData.iSvcStack = (TInt32)aThread->iSupervisorStack;
1.433 + threadData.iSvcStacksize = aThread->iSupervisorStackSize;
1.434 + threadData.iUsrStack = aThread->iUserStackRunAddress;
1.435 + threadData.iUsrStacksize = aThread->iUserStackSize;
1.436 +
1.437 + //currently we can only get the kernels heap
1.438 + if(aThread == &Kern::CurrentThread())
1.439 + {
1.440 + TInt32 heapLoc = 0;
1.441 + TInt32 heapSz = 0;
1.442 + TInt err = FindKernelHeap(heapLoc,heapSz);
1.443 + if(KErrNone == err)
1.444 + {
1.445 + threadData.iSvcHeap = heapLoc;
1.446 + threadData.iSvcHeapSize = heapSz;
1.447 + }
1.448 + else
1.449 + {
1.450 + CLTRACE("\tError: Unable to get kernel heap");
1.451 + }
1.452 + }
1.453 +
1.454 + //get filename
1.455 + TFileName filename;
1.456 + aThread->TraceAppendFullName(filename, EFalse);
1.457 +
1.458 + threadData.iName.Copy(filename);
1.459 + threadData.iNamesize = threadData.iName.Length();
1.460 +
1.461 +
1.462 +#ifdef __INCLUDE_NTHREADBASE_DEFINES__
1.463 + threadData.iLastCpu = aThread->iNThread.iLastCpu;
1.464 +#else
1.465 + threadData.iLastCpu = aThread->iNThread.iSpare3;
1.466 +#endif
1.467 +
1.468 + threadData.Serialize(*iWriter);
1.469 + aSizeDumped+=threadData.GetSize();
1.470 +
1.471 + return KErrNone;
1.472 + }
1.473 +
1.474 +/**
1.475 + * Logs the arm exception stacks
1.476 + * @param aSizeDumped Holds the size of the data dumped
1.477 + * @return one of the OS wide codes
1.478 + */
1.479 +TInt SCMDataSave::LogExceptionStacks(TUint& aSizeDumped)
1.480 + {
1.481 + LOG_CONTEXT
1.482 + aSizeDumped = 0;
1.483 + TUint memDumped = 0;
1.484 +
1.485 + #if defined(__EPOC32__) && !defined(__CPU_X86)
1.486 +
1.487 + TStackInfo& stackInfo = Kern::SuperPage().iStackInfo;
1.488 +
1.489 + TThreadStack irqStack;
1.490 + irqStack.iStackType = TThreadStack::EIRQStack;
1.491 + irqStack.iStackSize = stackInfo.iIrqStackSize;
1.492 +
1.493 + aSizeDumped+=irqStack.GetSize();
1.494 + irqStack.Serialize(*iWriter);
1.495 +
1.496 + //now dump the IRQ memory - not much we can do in the event of an error
1.497 + MTRAPD(irqErr, LogMemory((TUint8*)stackInfo.iIrqStackBase, stackInfo.iIrqStackSize, &Kern::CurrentThread(), memDumped));
1.498 +
1.499 + if(KErrNone != irqErr)
1.500 + {
1.501 + CLTRACE("*****Failed to log IRQ stack");
1.502 + }
1.503 + aSizeDumped+=memDumped;
1.504 +
1.505 + //Next, we do the FIQ stack
1.506 + TThreadStack fiqStack;
1.507 + fiqStack.iStackType = TThreadStack::EFIQStack;
1.508 + fiqStack.iStackSize = stackInfo.iFiqStackSize;
1.509 +
1.510 + aSizeDumped+=fiqStack.GetSize();
1.511 + fiqStack.Serialize(*iWriter);
1.512 +
1.513 + //Now dump the stack itself
1.514 + MTRAPD(fiqErr, LogMemory((TUint8*)stackInfo.iFiqStackBase, stackInfo.iFiqStackSize, &Kern::CurrentThread(), memDumped));
1.515 +
1.516 + if(KErrNone != fiqErr )
1.517 + {
1.518 + CLTRACE("*****Failed to log FIQ stack");
1.519 + }
1.520 + aSizeDumped+=memDumped;
1.521 +
1.522 + #endif
1.523 +
1.524 + return KErrNone;
1.525 + }
1.526 +
1.527 +/**
1.528 + * Logs the CPU Registers at the time of crash
1.529 + * @param aSizeDumped Holds the size of the data dumped
1.530 + * @return system wide OS code
1.531 + */
1.532 +TInt SCMDataSave::LogCPURegisters(TUint& aSizeDumped)
1.533 + {
1.534 + LOG_CONTEXT
1.535 + aSizeDumped = 0;
1.536 +
1.537 + TInt32 fullSet = 37;
1.538 +
1.539 + //meta data about the thread set
1.540 + TRegisterSet threadSet;
1.541 + threadSet.iNumRegisters = fullSet;
1.542 +
1.543 + aSizeDumped+=threadSet.GetSize();
1.544 + threadSet.Serialize(*iWriter);
1.545 +
1.546 + SFullArmRegSet regSet;
1.547 + ReadCPURegisters(regSet);
1.548 + TArmReg* regs = (TArmReg*)®Set;
1.549 +
1.550 + TInt32 cnt = 0;
1.551 + for(cnt = 0; cnt < fullSet; cnt++)
1.552 + {
1.553 + //this is the struct to store the register value in
1.554 + TRegisterValue regVal;
1.555 + regVal.iType = cnt * 0x100;
1.556 + regVal.iValue32 = regs[cnt];
1.557 + regVal.iOwnId = Kern::CurrentThread().iId;
1.558 +
1.559 + aSizeDumped+=regVal.GetSize();
1.560 + regVal.Serialize(*iWriter);
1.561 + }
1.562 +
1.563 + return KErrNone;
1.564 + }
1.565 +
1.566 +/**
1.567 + * This logs the registers for a given thread to the flash memory
1.568 + * @param aThread - thread whose registers we want
1.569 + * @param aRegType - type of register set required such as user, supervisor etc
1.570 + * @param aSizeDumped Holds the size of the data dumped
1.571 + * @return one of the OS return codes
1.572 + */
1.573 +TInt SCMDataSave::LogRegisters(DThread* aThread, const TRegisterSetType& aRegType, TUint& aSizeDumped)
1.574 + {
1.575 + LOG_CONTEXT
1.576 + aSizeDumped = 0;
1.577 +
1.578 + TArmRegSet regs;
1.579 + TUint32 availableRegs;
1.580 + TInt err;
1.581 +
1.582 + //for the current thread we do things differently
1.583 + if(aThread == &Kern::CurrentThread() && aRegType == EFullCPURegisters)
1.584 + {
1.585 + err = LogCPURegisters(aSizeDumped);
1.586 + return err;
1.587 + }
1.588 + else if(aThread == &Kern::CurrentThread())
1.589 + {
1.590 + //only do full cpu reg for the current thread
1.591 + return KErrNotSupported;
1.592 + }
1.593 +
1.594 + //Read the appropriate registers
1.595 + switch(aRegType)
1.596 + {
1.597 + case EUserRegisters :
1.598 + {
1.599 + err = ReadUserRegisters(aThread, regs, availableRegs);
1.600 + break;
1.601 + }
1.602 + case ESupervisorRegisters :
1.603 + {
1.604 + err = ReadSystemRegisters(aThread, regs, availableRegs);
1.605 + break;
1.606 + }
1.607 + default : return KErrNotSupported;
1.608 + }
1.609 +
1.610 + if(err != KErrNone)
1.611 + {
1.612 + return err;
1.613 + }
1.614 +
1.615 + //meta data about the thread set
1.616 + TRegisterSet threadSet;
1.617 +
1.618 + //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
1.619 + TUint numR = 0;
1.620 + for(TInt cnt =0; cnt< 8*sizeof(availableRegs); cnt++) //cycle through 1 bit at a time
1.621 + {
1.622 + if(0x1 & (availableRegs>>cnt))
1.623 + numR++;
1.624 + }
1.625 +
1.626 + threadSet.iNumRegisters = numR;
1.627 +
1.628 + if(numR == 0)
1.629 + return KErrNone;
1.630 +
1.631 + threadSet.Serialize(*iWriter);
1.632 + aSizeDumped += threadSet.GetSize();
1.633 +
1.634 + TInt32 currentRegister = 1;
1.635 + TArmReg* reg = (TArmReg*)(®s);
1.636 +
1.637 + for(TInt32 cnt = 0; cnt < KArmRegisterCount; cnt++)
1.638 + {
1.639 + //look at the unavailable bitmask to see current register is available
1.640 + //only write the registers we have values for
1.641 + if(currentRegister & availableRegs)
1.642 + {
1.643 + //this is the struct to store the register value in
1.644 + TRegisterValue regVal;
1.645 +
1.646 + //get register type as per symbian elf docs
1.647 + TUint32 registerType;
1.648 + err = GetRegisterType(aRegType, cnt, registerType);
1.649 + if(err != KErrNone)
1.650 + {
1.651 + continue;
1.652 + }
1.653 + regVal.iType = registerType;
1.654 + regVal.iOwnId = aThread->iId;
1.655 +
1.656 + //set value
1.657 + regVal.iValue32 = reg[cnt];
1.658 +
1.659 + aSizeDumped+=regVal.GetSize();
1.660 + regVal.Serialize(*iWriter);
1.661 + }
1.662 +
1.663 + currentRegister<<=1;
1.664 + }
1.665 +
1.666 + return KErrNone;
1.667 + }
1.668 +
1.669 +/**
1.670 + * This logs memory in the specified area
1.671 + * @param aStartAddress - address to start from
1.672 + * @param aEndAddress - address to finish
1.673 + * @param aThread - process whose memory this is in
1.674 + * @param aSizeDumped Holds the size of the data dumped
1.675 + * @return one of the system wide codes
1.676 + */
1.677 +TInt SCMDataSave::LogMemory(const TUint8* aStartAddress, TInt aLength, const DThread* aThread, TUint& aSizeDumped)
1.678 + {
1.679 + LOG_CONTEXT
1.680 + aSizeDumped = 0;
1.681 +
1.682 + if(aThread->iOwningProcess != &Kern::CurrentProcess())
1.683 + {
1.684 + TInt err = iMonitor->SwitchAddressSpace(aThread->iOwningProcess, ETrue);
1.685 + if(KErrNone != err)
1.686 + {
1.687 + return err;
1.688 + }
1.689 + }
1.690 +
1.691 + TMemoryDump memDump;
1.692 + memDump.iStartAddress = (TUint32)aStartAddress;
1.693 + memDump.iLength = aLength;
1.694 + memDump.iPid = aThread->iOwningProcess->iId;
1.695 +
1.696 + aSizeDumped+=memDump.GetSize();
1.697 + memDump.Serialize(*iWriter);
1.698 +
1.699 + if(!aStartAddress)
1.700 + {
1.701 + return KErrArgument;
1.702 + }
1.703 +
1.704 + TRawData theMemory;
1.705 + theMemory.iData.Set(const_cast<TUint8*>(aStartAddress), aLength, aLength);
1.706 +
1.707 + theMemory.Serialize(*iWriter);
1.708 + aSizeDumped+=theMemory.GetSize();
1.709 +
1.710 + return KErrNone;
1.711 + }
1.712 +
1.713 +/**
1.714 + * This logs the locks held by system at time of crash
1.715 + * @param aSizeDumped Holds the size of the data dumped
1.716 + * @return one of the system wide codes
1.717 + */
1.718 +TInt SCMDataSave::LogLocks(TUint& aSizeDumped)
1.719 + {
1.720 + LOG_CONTEXT
1.721 + aSizeDumped = 0;
1.722 +
1.723 + // get the mutex logs & waits & log via a TLockData object
1.724 + TSCMLockData lockData;
1.725 +
1.726 + const TInt KMaxLockCheck = 20; // so no possibility of infinite loop
1.727 +
1.728 + TInt lockCount = 0;
1.729 + // check for kernel locks -
1.730 + for(TInt i=0;i<KMaxLockCheck;i++)
1.731 + {
1.732 + TBool locked = NKern::KernelLocked(i);
1.733 + if(!locked)
1.734 + {
1.735 + lockData.SetLockCount(lockCount);
1.736 + break;
1.737 + }
1.738 + // found a valid lock for value i increment the clock counter
1.739 + lockCount++;
1.740 + }
1.741 +
1.742 + // now mutexes
1.743 + DMutex* mutex = Kern::CodeSegLock();
1.744 + if(mutex)
1.745 + {
1.746 + lockData.SetMutexHoldCount(mutex->iHoldCount);
1.747 + lockData.SetMutexThreadWaitCount(mutex->iWaitCount);
1.748 + }
1.749 + else
1.750 + {
1.751 + // no mutex held set to -1
1.752 + lockData.SetMutexHoldCount(0);
1.753 + lockData.SetMutexThreadWaitCount(0);
1.754 + }
1.755 +
1.756 + aSizeDumped+=lockData.GetSize();
1.757 + TInt err = lockData.Serialize(*iWriter);
1.758 +
1.759 + return err;
1.760 + }
1.761 +
1.762 +/**
1.763 + * Writes the SCM Configuration to the start of the media
1.764 + * @param aScmConfig Configuration to write
1.765 + * @return one of the system wide codes
1.766 + */
1.767 +TInt SCMDataSave::LogConfig(SCMConfiguration& aScmConfig)
1.768 + {
1.769 + iWriter->SetPosition(0);
1.770 +
1.771 + TInt err = aScmConfig.Serialize(*iWriter);
1.772 +
1.773 + if( err != KErrNone)
1.774 + {
1.775 + CLTRACE1("SCMDataSave::LogConfig failed err = %d", err);
1.776 + }
1.777 +
1.778 + return err;
1.779 + }
1.780 +
1.781 +/**
1.782 + * Reads the SCM Configuration from the media
1.783 + * @param aScmConfig
1.784 + * @return one of the system wide codes
1.785 + */
1.786 +TInt SCMDataSave::ReadConfig(SCMConfiguration& aScmConfig)
1.787 + {
1.788 + const TInt KBufSize = 135; //Not yet done: Put in header, beside config defn
1.789 +
1.790 + if( KBufSize < aScmConfig.GetSize())
1.791 + {
1.792 + CLTRACE2("(SCMDataSave::ReadConfig) ** ERROR Inadequate buffer actual = %d req = %d"
1.793 + , KBufSize, aScmConfig.GetSize());
1.794 + }
1.795 +
1.796 + // try and read the configuration
1.797 + TBuf8<KBufSize> buf;
1.798 + buf.SetLength(KBufSize);
1.799 +
1.800 + iFlash->SetReadPos(0); // config always at 0
1.801 + iFlash->Read(buf);
1.802 +
1.803 + TByteStreamReader reader(const_cast<TUint8*>(buf.Ptr()));
1.804 + TInt err = aScmConfig.Deserialize(reader);
1.805 + if(err == KErrNotReady)
1.806 + {
1.807 + CLTRACE("(SCMDataSave::ReadConfig) no config saved - use default");
1.808 + }
1.809 + else if(err == KErrNone)
1.810 + {
1.811 + CLTRACE("(SCMDataSave::ReadConfig) Config read ok");
1.812 + }
1.813 + else
1.814 + {
1.815 + CLTRACE1("(SCMDataSave::ReadConfig) error reading config err = %d", err);
1.816 + }
1.817 +
1.818 + return err;
1.819 + }
1.820 +
1.821 +/**
1.822 + * This is a look up table to map the register type and number to the symbian elf definition
1.823 + * of register type
1.824 + * @param aSetType this is the register set type - user, supervisor etc
1.825 + * @param aRegNumber this is the number of the register as per TArmRegisters in arm_types.h
1.826 + * @param aSizeDumped Holds the size of the data dumped
1.827 + * @return One of the OS wide codes
1.828 + */
1.829 +TInt SCMDataSave::GetRegisterType(const TRegisterSetType& aSetType, TInt32& aRegNumber, TUint32& aRegisterType)
1.830 + {
1.831 + //validate arguments
1.832 + if(aRegNumber < EArmR0 || aRegNumber > EArmFlags)
1.833 + {
1.834 + return KErrArgument;
1.835 + }
1.836 +
1.837 + //look at what type we are using
1.838 + switch(aSetType)
1.839 + {
1.840 + case EUserRegisters :
1.841 + {
1.842 + aRegisterType = aRegNumber * 0x100; //for R0 to R16 (CPSR) it just increments in 0x100 from 0x0 to 0x1000
1.843 + break;
1.844 + }
1.845 + case ESupervisorRegisters :
1.846 + {
1.847 + //same as EUserRegisters except R13 and R14 are different
1.848 + if(aRegNumber == EArmSp)
1.849 + {
1.850 + aRegisterType = 0x1100;
1.851 + break;
1.852 + }
1.853 + else if(aRegNumber == EArmLr)
1.854 + {
1.855 + aRegisterType = 0x1200;
1.856 + break;
1.857 + }
1.858 + else
1.859 + {
1.860 + aRegisterType = aRegNumber * 0x100;
1.861 + break;
1.862 + }
1.863 + }
1.864 + default : return KErrNotSupported;
1.865 + }
1.866 +
1.867 + return KErrNone;
1.868 + }
1.869 +
1.870 +/**
1.871 + * Writes the trace buffer to the crash log.
1.872 + * @param aSizeToDump Number of bytes to dump. If this is zero we attempt to write the entire buffer
1.873 + * @param aSizeDumped Holds the size of the data dumped
1.874 + * @return One of the OS wide codes
1.875 + */
1.876 +TInt SCMDataSave::LogTraceBuffer(TInt aSizeToDump, TUint& aSizeDumped)
1.877 + {
1.878 + LOG_CONTEXT
1.879 + aSizeDumped = 0;
1.880 + TUint memDumped = 0;
1.881 +
1.882 + TBool dumpAll = (aSizeToDump == 0) ? ETrue : EFalse;
1.883 +
1.884 + //Because the btrace buffer is a circular one, we need to save it in two parts
1.885 + //this corrosponds to how we read it
1.886 + TUint8* data;
1.887 + TUint sizeOfPartRead;
1.888 + TInt spaceRemaining = aSizeToDump;
1.889 +
1.890 + //This structure will be filled after the first pass and cached so by the time we ARE writing it will
1.891 + //contain the data we want
1.892 + aSizeDumped+=iTrace.GetSize();
1.893 + iTrace.Serialize(*iWriter);
1.894 +
1.895 + //read first part
1.896 + TInt err = BTrace::Control(BTrace::ECtrlCrashReadFirst,&data,&sizeOfPartRead);
1.897 +
1.898 + while(KErrNone == err && sizeOfPartRead > 0)
1.899 + {
1.900 + TUint rawSize = 0; //how much of this read data want we to dump
1.901 +
1.902 + if(dumpAll)
1.903 + {
1.904 + rawSize = sizeOfPartRead;
1.905 + }
1.906 + else //Otherwise see what room is left for dumpage
1.907 + {
1.908 + rawSize = ((sizeOfPartRead + iTrace.iSizeOfMemory) > aSizeToDump) ? spaceRemaining : sizeOfPartRead;
1.909 + }
1.910 +
1.911 + //Only relevant if restricting the dump
1.912 + if(spaceRemaining <= 0 && !dumpAll)
1.913 + break;
1.914 +
1.915 + TPtrC8 ptr(data, rawSize);
1.916 + err = LogRawData(ptr, memDumped);
1.917 + if(KErrNone != err)
1.918 + {
1.919 + CLTRACE1("Logging Raw data failed - [%d]", err);
1.920 + err = BTrace::Control(BTrace::ECtrlCrashReadNext,&data,&sizeOfPartRead);
1.921 + continue;
1.922 + }
1.923 +
1.924 + aSizeDumped+=memDumped;
1.925 +
1.926 + iTrace.iSizeOfMemory += rawSize;
1.927 + iTrace.iNumberOfParts++;
1.928 + spaceRemaining -= rawSize;
1.929 +
1.930 + err = BTrace::Control(BTrace::ECtrlCrashReadNext,&data,&sizeOfPartRead);
1.931 + }
1.932 +
1.933 + return KErrNone;
1.934 + }
1.935 +
1.936 +/**
1.937 + * Logs the data in a TRawData struct
1.938 + * @param aData
1.939 + * @param aSizeDumped Holds the size of the data dumped
1.940 + * @return One of the OS wide codes
1.941 + */
1.942 +TInt SCMDataSave::LogRawData(const TDesC8& aData, TUint& aSizeDumped)
1.943 + {
1.944 + TRawData theData;
1.945 + theData.iLength = aData.Length();
1.946 + theData.iData.Set(const_cast<TUint8*>(aData.Ptr()), aData.Length(), aData.Length());
1.947 +
1.948 + aSizeDumped+=theData.GetSize();
1.949 + return theData.Serialize(*iWriter);
1.950 + }
1.951 +
1.952 +
1.953 +/**
1.954 + * Logs the kernels heap and returns the size dumped via aSizeDumped
1.955 + * @param aSizeDumped Holds the size of the data dumped
1.956 + * @return
1.957 + */
1.958 +TInt SCMDataSave::LogKernelHeap(TUint& aSizeDumped)
1.959 + {
1.960 + LOG_CONTEXT
1.961 +
1.962 + TInt32 heapLoc = 0;
1.963 + TInt32 heapSize = 0;
1.964 + TInt32 err = FindKernelHeap(heapLoc, heapSize);
1.965 + if(KErrNone == err)
1.966 + {
1.967 + return LogMemory((TUint8*)heapLoc, heapSize, &Kern::CurrentThread(), aSizeDumped);
1.968 + }
1.969 +
1.970 + CLTRACE1("\tCouldnt find the kernel heap: [%d]", err);
1.971 + return err;
1.972 + }
1.973 +
1.974 +/**
1.975 + * Iterates the object containers and finds the kernel heap
1.976 + * @param aHeapLocation Contains the memory location of the kernel heap
1.977 + * @param aHeapSize Contains the size of the Heap
1.978 + * @return One of the OS wide codes
1.979 + */
1.980 +TInt SCMDataSave::FindKernelHeap(TInt32& aHeapLocation, TInt32& aHeapSize)
1.981 + {
1.982 + LOG_CONTEXT
1.983 +
1.984 + //Get Chunk object container
1.985 + DObjectCon* objectContainer = Kern::Containers()[EChunk];
1.986 + if(objectContainer == NULL)
1.987 + {
1.988 + CLTRACE("\tFailed to get object container for the chunks");
1.989 + return KErrNotFound;
1.990 + }
1.991 +
1.992 + //Must check the mutex on this is ok otherwise the data will be in an inconsistent state
1.993 + if(objectContainer->Lock()->iHoldCount)
1.994 + {
1.995 + CLTRACE("\tChunk Container is in an inconsistant state");
1.996 + return KErrCorrupt;
1.997 + }
1.998 +
1.999 + TInt numObjects = objectContainer->Count();
1.1000 +
1.1001 + for(TInt cnt = 0; cnt< numObjects; cnt ++)
1.1002 + {
1.1003 + DChunk* candidateHeapChunk = (DChunk*)(*objectContainer)[cnt];
1.1004 +
1.1005 + //Get the objects name
1.1006 + TBuf8<KMaxKernelName> name;
1.1007 + candidateHeapChunk->TraceAppendFullName(name,EFalse);
1.1008 +
1.1009 + if(name == KKernelHeapChunkName)
1.1010 + {
1.1011 + #ifndef __MEMMODEL_FLEXIBLE__
1.1012 + aHeapLocation = (TInt32)candidateHeapChunk->iBase;
1.1013 + #else
1.1014 + aHeapLocation = (TInt32)candidateHeapChunk->iFixedBase;
1.1015 + #endif
1.1016 +
1.1017 + aHeapSize = candidateHeapChunk->iSize;
1.1018 +
1.1019 + return KErrNone;
1.1020 + }
1.1021 + }
1.1022 +
1.1023 + return KErrNotFound;
1.1024 + }
1.1025 +
1.1026 +/**
1.1027 + * This logs the variant specific descriptor data to the crash log
1.1028 + * @param aSizeDumped records how much was dumped by this function
1.1029 + * @return one of the OS wide codes
1.1030 + */
1.1031 +TInt SCMDataSave::LogVariantSpecificData(TUint& aSizeDumped)
1.1032 + {
1.1033 + LOG_CONTEXT
1.1034 +
1.1035 + aSizeDumped = 0;
1.1036 +
1.1037 + //Change this descriptor as required for your needs
1.1038 + _LIT(KVariantSpecificData, "This is the variant specific data. Put your own here");
1.1039 +
1.1040 + TVariantSpecificData varData;
1.1041 + varData.iSize = KVariantSpecificData().Size();
1.1042 +
1.1043 + TInt err = varData.Serialize(*iWriter);
1.1044 + if(KErrNone != err)
1.1045 + {
1.1046 + CLTRACE1("\tLogging variant specific data failed with code [%d]", err);
1.1047 + return err;
1.1048 + }
1.1049 + aSizeDumped+=varData.GetSize();
1.1050 +
1.1051 + TUint rawDataSize = 0;
1.1052 + err = LogRawData(KVariantSpecificData(), rawDataSize);
1.1053 + if(KErrNone != err)
1.1054 + {
1.1055 + CLTRACE1("\tLogging variant specific data failed with code [%d]", err);
1.1056 + return err;
1.1057 + }
1.1058 +
1.1059 + aSizeDumped+=rawDataSize;
1.1060 +
1.1061 + return KErrNone;
1.1062 + }
1.1063 +
1.1064 +
1.1065 +/**
1.1066 + * This method is the callback used by MPhysicalWriterImpl interface
1.1067 + * if the TCachedByteStreamWriter is configured to use this interface
1.1068 + * the callback avoids the need for temp buffers & can interface directly with the
1.1069 + * flash writer methods
1.1070 + * @param aData - data to write
1.1071 + * @param aLen - length of data to write
1.1072 + * @param aPos - writers internal position
1.1073 + */
1.1074 +void SCMDataSave::DoPhysicalWrite(TAny* aData, TInt aPos, TInt aLen)
1.1075 + {
1.1076 + if(iPerformChecksum)
1.1077 + {
1.1078 + iChecksum.ChecksumBlock((TUint8*)aData, aLen);
1.1079 + }
1.1080 +
1.1081 + if( this->iWriteSelect == EWriteComm)
1.1082 + {
1.1083 + WriteUart((TUint8*)aData, aLen);
1.1084 + }
1.1085 + else // EWriteFlash
1.1086 + {
1.1087 + Write(aData, aLen);
1.1088 + }
1.1089 + }
1.1090 +
1.1091 +/**
1.1092 + * Writes data to Flash
1.1093 + * @param aSomething Pointer to the data
1.1094 + * @param aSize Size of the data
1.1095 + */
1.1096 +void SCMDataSave::Write(const TAny* aSomething, TInt aSize)
1.1097 + {
1.1098 + TPtrC8 data((const TUint8 *)aSomething, aSize);
1.1099 +
1.1100 + TInt written = 0;
1.1101 +
1.1102 + WriteCrashFlash(iByteCount, written, data);
1.1103 + iByteCount+= written;
1.1104 + }
1.1105 +
1.1106 +/**
1.1107 + * Writes a descriptor to the crash flash
1.1108 + * @param aPos Position in flash to write
1.1109 + * @param aSize Holds the size of the data written after the call
1.1110 + * @param aBuffer Descriptor to write
1.1111 + */
1.1112 +void SCMDataSave::WriteCrashFlash(TInt aPos, TInt& aSize, const TDesC8& aBuffer)
1.1113 + {
1.1114 + //Set write position in the flash
1.1115 + iFlash->SetWritePos(aPos);
1.1116 + iFlash->Write(aBuffer);
1.1117 +
1.1118 + //get bytes written
1.1119 + aSize += iFlash->BytesWritten();
1.1120 +
1.1121 + if(aSize != aBuffer.Length())
1.1122 + {
1.1123 + CLTRACE2("(SCMDataSave::WriteCrashFlash) Over the limit aSize = %d aBuffer.Length() = %d",
1.1124 + aSize, aBuffer.Length());
1.1125 + }
1.1126 + }
1.1127 +
1.1128 +/**
1.1129 + * Writes a descriptor via serial
1.1130 + * @param aDes Descriptor to write
1.1131 + */
1.1132 +void SCMDataSave::WriteUart(const TDesC8& aDes)
1.1133 + {
1.1134 + WriteUart(aDes.Ptr(), aDes.Length());
1.1135 + }
1.1136 +
1.1137 +/**
1.1138 + * Writes data via serial
1.1139 + * @param aData Data to write
1.1140 + * @param aSize Size of data to write
1.1141 + */
1.1142 +void SCMDataSave::WriteUart(const TUint8* aData, TInt aSize)
1.1143 + {
1.1144 + OMAP* assp = ((OMAP*)Arch::TheAsic());
1.1145 + TOmapDbgPrt* dbg = assp->DebugPort();
1.1146 +
1.1147 + if (dbg)
1.1148 + {
1.1149 + for(TInt i=0;i<aSize;i++)
1.1150 + {
1.1151 + dbg->DebugOutput(*(aData+i));
1.1152 + }
1.1153 + }
1.1154 + else
1.1155 + {
1.1156 + CLTRACE("SCMDataSave::WriteUart ERROR - dbg was null");
1.1157 + }
1.1158 + }
1.1159 +
1.1160 +/**
1.1161 + * Setter for the current number of bytes written for this crash log
1.1162 + * If aByte is not word aligned, it will be rounded up to be so
1.1163 + * @param aByte Current bytes written
1.1164 + */
1.1165 +void SCMDataSave::SetByteCount(TInt aByte)
1.1166 + {
1.1167 + //ensure aligned
1.1168 + if(aByte % iWriter->GetCacheSize() == 0)
1.1169 + {
1.1170 + iByteCount = aByte;
1.1171 + }
1.1172 + else
1.1173 + {
1.1174 + iByteCount = aByte + (iWriter->GetCacheSize() - (aByte % iWriter->GetCacheSize()));
1.1175 + }
1.1176 + }
1.1177 +
1.1178 +/**
1.1179 + * Gets the output target selection
1.1180 + * @return TScmWriteSelect output target selection
1.1181 + * @param void
1.1182 + */
1.1183 +SCMDataSave::TWriteSelect SCMDataSave::GetWriteSelect()
1.1184 + {
1.1185 + return iWriteSelect;
1.1186 + }
1.1187 +
1.1188 +/**
1.1189 + * Sets the output target selection
1.1190 + * @return void
1.1191 + * @param TScmWriteSelect aWriteSelect output target selection
1.1192 + */
1.1193 +void SCMDataSave::SetWriteSelect(SCMDataSave::TWriteSelect aWriteSelect)
1.1194 + {
1.1195 + iWriteSelect = aWriteSelect;
1.1196 + }
1.1197 +
1.1198 +/**
1.1199 + * Gets the amount of space remaining for the media of choice
1.1200 + * @return
1.1201 + */
1.1202 +TUint SCMDataSave::SpaceRemaining()
1.1203 + {
1.1204 + TInt currentPosition = iWriter->GetBytesWritten() + iStartingPointForCrash;
1.1205 +
1.1206 + return MaxLogSize() - currentPosition;
1.1207 + }
1.1208 +
1.1209 +/**
1.1210 + * To find the max size of a log for a given media
1.1211 + * @return the max size of a log for a given media
1.1212 + */
1.1213 +TUint SCMDataSave::MaxLogSize()
1.1214 + {
1.1215 + //see what write media is being used
1.1216 + switch(GetWriteSelect())
1.1217 + {
1.1218 + case EWriteFlash:
1.1219 + {
1.1220 + return KMaxCrashLogSize;
1.1221 + }
1.1222 + case EWriteComm:
1.1223 + {
1.1224 + return 0xFFFFFFFF;
1.1225 + }
1.1226 + default:
1.1227 + {
1.1228 + return 0;
1.1229 + }
1.1230 + }
1.1231 + }
1.1232 +
1.1233 +/**
1.1234 + * Records the offset in the flash partition where this crash begins
1.1235 + * @param aStart Offset in flash
1.1236 + */
1.1237 +void SCMDataSave::SetCrashStartingPoint(TUint32 aStart)
1.1238 + {
1.1239 + iStartingPointForCrash = aStart;
1.1240 + }
1.1241 +
1.1242 +//eof
1.1243 +