os/kernelhwsrv/kernel/eka/debug/crashMonitor/src/scmdatasave.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32\debug\crashMonitor\src\scmdatasave.cpp
    15 // 
    16 //
    17 
    18 #define __INCLUDE_REG_OFFSETS__  // for SP_R13U in nk_plat.h
    19 
    20 #include <omap_dbg.h>
    21 #include "arm_mem.h"
    22 #include "nk_plat.h"
    23 #include <omap_assp.h>
    24 #include <scmonitor.h>
    25 #include <scmdatasave.h> 
    26 
    27 /**
    28  * @file
    29  * @internal technology
    30  */
    31 
    32 /**
    33  * SCMDataSave constructor
    34  * @param aMonitor - the monitor which has caught the syetem crash this object is saving data for 
    35  * @param aFlash - the flash memory data will be written to, note the CrashFlash interface is
    36  * 				   rather limited and does not support partial block writes
    37  * @param aFlashInfo - data describing the structure of the flash data
    38  */
    39 EXPORT_C SCMDataSave::SCMDataSave(Monitor* aMonitor, CrashFlash* aFlash)
    40 	: iMonitor(aMonitor)
    41 		,iFlash(aFlash)
    42 		,iByteCount(0)	
    43 #ifdef SCM_COMM_OUTPUT	
    44 		,iWriteSelect(EWriteComm)  // write data to debug port	
    45 #else	
    46 		,iWriteSelect(EWriteFlash)  // write data to flash
    47 #endif
    48 		,iPerformChecksum(ETrue)			 // checksum data 
    49 		,iStartingPointForCrash(0)
    50 	{  		
    51 	const TInt KCacheSize = 128;
    52 	iFlashCache = HBuf8::New(KCacheSize);
    53 	CLTRACE1("(SCMDataSave) Creating writer with cache size = %d", KCacheSize);
    54 	iWriter = new TCachedByteStreamWriter(const_cast<TUint8*>(iFlashCache->Ptr()), KCacheSize);
    55 	iWriter->SetWriterImpl(this);
    56 	}
    57 
    58 /**
    59  * Destructor
    60  */
    61 SCMDataSave::~SCMDataSave()
    62 	{
    63 	delete iFlashCache;
    64 	}
    65 
    66 /**
    67  * Getter for the current byte count. This is the amount of data that has currently 
    68  * been written to given media for this crash log
    69  * @return The number of bytes written already to given media
    70  */
    71 TInt SCMDataSave::GetByteCount()
    72 	{
    73 	return iByteCount;
    74 	}
    75 
    76 /**
    77  * Logs the user stack for a given DThread object if it is available
    78  * @param aThread - thread whose stack we wish to log
    79  * @param aSizeDumped Holds the size of the data dumped
    80  * @return one of the OS codes
    81  */
    82 TInt SCMDataSave::LogThreadUserStack(DThread* aThread, TBool aFullStack, TUint& aSizeDumped)
    83 	{
    84 	LOG_CONTEXT
    85 	aSizeDumped = 0;
    86 	TUint memDumped = 0;	
    87 	
    88 	TUint svSp, usrSp;
    89 	iMonitor->GetStackPointers(&(aThread->iNThread), svSp, usrSp );	
    90 	
    91 	//first we check for a user stack...
    92 	if (aThread->iUserStackRunAddress && aThread->iUserStackSize)
    93 		{		
    94 		//Get data together
    95 		TThreadStack usrStack;
    96 		usrStack.iStackType = TThreadStack::EUsrStack;
    97 		usrStack.iThreadId = (TUint64)aThread->iId;					
    98 				
    99 		//map in the user stack
   100 		TUint8* usrStart = (TUint8*)iMonitor->MapAndLocateUserStack(aThread); //What about Demand paging??
   101 		TUint8* usrEnd = (TUint8*)(usrStart + aThread->iUserStackSize);
   102 		if(usrStart) 
   103 			{
   104 			TUint8* stackPointer = (TUint8*)usrSp;			
   105 			
   106 			//check the stack pointer is in the range of the stack...
   107 			if (stackPointer < usrStart || stackPointer >= usrEnd)
   108 				{
   109 				stackPointer = usrStart;
   110 				}
   111 			
   112 			//log the size of the stack we are dumping
   113 			usrStack.iStackSize = aFullStack || (stackPointer == usrStart) ? usrEnd - usrStart : usrEnd - stackPointer;
   114 			TUint8* dumpFrom = aFullStack ? usrStart : stackPointer;
   115 			
   116 			//write the stack
   117 			aSizeDumped+= usrStack.GetSize();
   118 			usrStack.Serialize(*iWriter);					
   119 			
   120 			//now we dump the actual stack
   121 			//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?
   122 			//-1 because we dont want to write the byte at usrEnd			
   123 			MTRAPD(memErr, LogMemory(dumpFrom, usrStack.iStackSize, aThread, memDumped));			
   124 			if(KErrNone != memErr)
   125 				{
   126 				CLTRACE("Failed to log usr stack");
   127 				}
   128 			
   129 			aSizeDumped+= memDumped;					
   130 			}
   131 		else
   132 			{
   133 			//write the struct
   134 			aSizeDumped+=usrStack.GetSize();
   135 			usrStack.Serialize(*iWriter);
   136 			}
   137 		}	
   138 	return KErrNone;
   139 	}
   140 
   141 /**
   142  * Logs the supervisor stack for a given DThread object
   143  * @param aThread - thread whose stack we wish to log
   144  * @param aSizeDumped Holds the size of the data dumped
   145  * @return one of the system wide codes
   146  */
   147 TInt SCMDataSave::LogThreadSupervisorStack(DThread* aThread, TBool aFullStack, TUint& aSizeDumped)
   148 	{	
   149 	LOG_CONTEXT
   150 	aSizeDumped = 0;
   151 	TUint memDumped;	
   152 	
   153 	TUint svSp, usrSp;
   154 	iMonitor->GetStackPointers(&(aThread->iNThread), svSp, usrSp );
   155 	
   156 	//now we dump the supervisor stack
   157 	TThreadStack svrStack;
   158 	svrStack.iStackType = TThreadStack::ESvrStack;
   159 	svrStack.iThreadId = (TUint64)aThread->iId;
   160 	
   161 	if (aThread->iSupervisorStack && aThread->iSupervisorStackSize)
   162 		{
   163 		TUint8* svrStart = (TUint8*)aThread->iSupervisorStack;
   164 		TUint8* svrEnd = (TUint8*)(svrStart + aThread->iSupervisorStackSize);
   165 		TUint8* svrStackPointer = (TUint8*)svSp;
   166 		
   167 		//size of stack we are to dump
   168 		svrStack.iStackSize = aFullStack || (svrStackPointer == svrStart) ? svrEnd - svrStart  : svrEnd - svrStackPointer;					
   169 		
   170 		if(svrStart)
   171 			{
   172 			//check the stack pointer is in the range of the stack...
   173 			if (svrStackPointer < svrStart || svrStackPointer >= svrEnd)
   174 				{
   175 				svrStackPointer = svrStart;
   176 				}
   177 
   178 			//write struct to flash
   179 			aSizeDumped+=svrStack.GetSize();
   180 			svrStack.Serialize(*iWriter);
   181 			
   182 			//now we dump the actual stack
   183 			//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?
   184 			MTRAPD(memErr, LogMemory(svrStart, svrStack.iStackSize, aThread, memDumped));
   185 			aSizeDumped+=memDumped;
   186 			
   187 			if(KErrNone != memErr)
   188 				{
   189 				CLTRACE("Failed to log supervisor stack");
   190 				}						
   191 			}
   192 		else
   193 			{
   194 			//write the struct
   195 			aSizeDumped+=svrStack.GetSize();
   196 			svrStack.Serialize(*iWriter);
   197 			}
   198 		}
   199 	
   200 	return KErrNone;
   201 	}
   202 
   203 /**
   204  * Takes a DProcess kernel object and logs its corrosponding code segments
   205  * @param aProcess
   206  * @param aSizeDumped Holds the size of the data dumped
   207  * @return one of the OS wide error codes
   208  */
   209 TInt SCMDataSave::LogCodeSegments(DProcess* aProc, TUint& aSizeDumped)
   210 	{	
   211 	LOG_CONTEXT
   212 	aSizeDumped = 0;	
   213 	
   214 	//the code segment set for this process
   215 	TCodeSegmentSet segSet;
   216 	segSet.iPid = (TUint64)aProc->iId;
   217 	
   218 	//make sure list mutex is ok
   219 	if(Kern::CodeSegLock()->iHoldCount)
   220 		{
   221 		return KErrCorrupt;
   222 		}
   223 	
   224 	//get code seg list
   225 	SDblQue queue;		
   226 	aProc->TraverseCodeSegs(&queue, NULL, DCodeSeg::EMarkDebug, DProcess::ETraverseFlagAdd);
   227 	
   228 	//iterate through the list
   229 	TInt codeSegCnt = 0;
   230 	for(SDblQueLink* codeSegPtr= queue.First(); codeSegPtr!=(SDblQueLink*) (&queue); codeSegPtr=codeSegPtr->iNext)
   231 		{
   232 		//get the code seg
   233 		DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr,DCodeSeg, iTempLink);
   234 		
   235 		if(codeSeg)
   236 			{
   237 			codeSegCnt++;
   238 			}
   239 		}
   240 	
   241 	if(codeSegCnt == 0)
   242 		{
   243 		return KErrNone;
   244 		}	
   245 	
   246 	segSet.iNumSegs = codeSegCnt;
   247 	segSet.Serialize(*iWriter);	
   248 	aSizeDumped+=segSet.GetSize();
   249 	
   250 	TModuleMemoryInfo memoryInfo;
   251 	
   252 	//now we write each code segment
   253 	for(SDblQueLink* codeSegPtr= queue.First(); codeSegPtr!=(SDblQueLink*) (&queue); codeSegPtr=codeSegPtr->iNext)
   254 		{
   255 		//get the code seg
   256 		DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr,DCodeSeg, iTempLink);
   257 		
   258 		if(codeSeg)
   259 			{			
   260 			TCodeSegment seg;									
   261 			seg.iXip = (codeSeg->iXIP) ? ETrue : EFalse;
   262 			
   263 			//Get the code seg type
   264 			if(codeSeg->IsExe())
   265 				{
   266 				seg.iCodeSegType = EExeCodeSegType;
   267 				}
   268 			else if(codeSeg->IsDll())
   269 				{
   270 				seg.iCodeSegType = EDllCodeSegType;
   271 				}
   272 			
   273 			TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL);
   274 			if(KErrNone == err)
   275 				{
   276 				seg.iCodeSegMemInfo = memoryInfo;
   277 				}
   278 			else
   279 				{
   280 				seg.iCodeSegMemInfo.iCodeSize = 0; 
   281 
   282 				// Still need to indicate it wasnt available somehow
   283 				}
   284 			
   285 			//Get filename			
   286 			seg.iNameLength = codeSeg->iFileName->Length();
   287 			seg.iName = *(codeSeg->iFileName);
   288 			
   289 			aSizeDumped+=seg.GetSize();
   290 			seg.Serialize(*iWriter);						
   291 			}
   292 		}
   293 	
   294 	//Empty this queue and clear marks
   295 	DCodeSeg::EmptyQueue(queue, DCodeSeg::EMarkDebug);
   296 	
   297 	return KErrNone;
   298 	}
   299 
   300 /**
   301  * This logs the rom version and header information to the crash media
   302  * @param aSizeDumped amount of data occupied
   303  * @return one of the OS wide codes
   304  */
   305 TInt SCMDataSave::LogRomInfo(TUint& aSizeDumped)	
   306 	{
   307 	aSizeDumped = 0;
   308 	
   309 	TRomHeaderData romData;
   310 	
   311 	TRomHeader rHdr = Epoc::RomHeader();
   312 	
   313 	romData.iMajorVersion = rHdr.iVersion.iMajor;
   314 	romData.iMinorVersion = rHdr.iVersion.iMinor;
   315 	romData.iBuildNumber = rHdr.iVersion.iBuild;
   316 	romData.iTime = rHdr.iTime;
   317 	
   318 	TInt err = romData.Serialize(*iWriter);
   319 	if(KErrNone != err)
   320 		{
   321 		return err;
   322 		}
   323 	
   324 	aSizeDumped += romData.GetSize();
   325 	
   326 	return KErrNone;
   327 	}
   328 
   329 /**
   330  * Takes a DProcess kernel object and logs to flash
   331  * @param aProc
   332  * @param aSizeDumped Holds the size of the data dumped
   333  * @return one of the OS wide error codes
   334  */
   335 TInt SCMDataSave::LogProcessData(DProcess* aProc, TUint& aSizeDumped)
   336 	{	
   337 	LOG_CONTEXT
   338 	aSizeDumped = 0;	
   339 	
   340 	TProcessData procData;
   341 	DCodeSeg* codeSeg = aProc->iCodeSeg;
   342 
   343 	procData.iPriority = aProc->iPriority;
   344 	procData.iPid = (TUint64)aProc->iId;
   345 	
   346 	//the code segment is not always available
   347 	if(codeSeg)
   348 		{
   349 		procData.iNamesize = codeSeg->iFileName->Length();
   350 		procData.iName = *(codeSeg->iFileName);
   351 		}
   352 	
   353 	aSizeDumped += procData.GetSize();
   354 	procData.Serialize(*iWriter);
   355 	
   356 	return KErrNone;
   357 	}
   358 
   359 /**
   360  * Creates meta data about the crash such as time of crash, exit reason etc. to be logged
   361  * later on when we have log size.
   362  * @param aCategory - crash category
   363  * @param aReason - crash reason
   364  * @param aSizeDumped Holds the size of the data dumped
   365  * @return one of the OS wide codes
   366  */
   367 TInt SCMDataSave::LogCrashHeader(const TDesC8& aCategory, TInt aReason, TInt aCrashId, TUint& aSizeDumped)
   368 	{
   369 	LOG_CONTEXT
   370 	aSizeDumped = 0;
   371 	
   372 	//the thread that crashed is the context in which we are running
   373 	DThread* crashedThread = &Kern::CurrentThread();
   374 	
   375 	iCrashInf.iPid = crashedThread->iOwningProcess->iId; 
   376 	iCrashInf.iTid = crashedThread->iId;
   377 	iCrashInf.iCrashTime = CrashTime();
   378 	iCrashInf.iExitType = 0; // Not yet done: Exception or Fault - should be in category
   379 	iCrashInf.iExitReason = aReason;
   380 	iCrashInf.iFlashAlign = KFlashAlignment; //record the flash alignment (word aligned for now)
   381 	iCrashInf.iCachedWriterSize = iWriter->GetCacheSize();
   382 	
   383 	iCrashInf.iCategorySize = aCategory.Length();
   384 	iCrashInf.iCategory = aCategory;	
   385 	iCrashInf.iCrashId = aCrashId;
   386 	
   387 	iCrashInf.iFlashBlockSize = KCrashLogBlockSize;;
   388 	iCrashInf.iFlashPartitionSize = KCrashLogSize;;
   389 	
   390 	TSuperPage& sp=Kern::SuperPage();
   391 	iCrashInf.iExcCode = sp.iKernelExcId;
   392 
   393 	//These will be updated with more info at end of crash
   394 	aSizeDumped+=iCrashInf.GetSize();
   395 	iCrashInf.Serialize(*iWriter);
   396 	
   397 	aSizeDumped+=iHdr.GetSize();
   398 	iHdr.Serialize(*iWriter);		
   399 
   400 	CLTRACE1("(SCMDataSave::LogCrashHeader) finished bytes written= %d", iWriter->GetBytesWritten());
   401 	return KErrNone;
   402 	}
   403 
   404 /**
   405  * Logs meta data about a given DThread object
   406  * @param aThread Thread to dump
   407  * @param aSizeDumped Holds the size of the data dumped
   408  * @return
   409  */
   410 TInt SCMDataSave::LogThreadData(DThread* aThread, TUint& aSizeDumped)
   411 	{
   412 	LOG_CONTEXT
   413 	aSizeDumped = 0;	
   414 	
   415 	//struct to hold data that gets written to flash
   416 	TThreadData threadData;
   417 	
   418 	threadData.iTid = (TUint64)aThread->iId;
   419 	threadData.iOwnerId = (TUint64)aThread->iOwningProcess->iId;
   420 	threadData.iPriority = aThread->iThreadPriority;
   421 	
   422 	//Get the stack pointers	
   423 	TUint svSp, usrSp;
   424 	iMonitor->GetStackPointers(&(aThread->iNThread), svSp, usrSp );
   425 	threadData.iUsrSP = usrSp;
   426 	threadData.iSvcSP = svSp;
   427 		
   428 	//supervisor and user stack details
   429 	threadData.iSvcStack = (TInt32)aThread->iSupervisorStack;
   430 	threadData.iSvcStacksize = aThread->iSupervisorStackSize;
   431 	threadData.iUsrStack = aThread->iUserStackRunAddress;
   432 	threadData.iUsrStacksize = aThread->iUserStackSize;	
   433 	
   434 	//currently we can only get the kernels heap
   435 	if(aThread == &Kern::CurrentThread())
   436 		{
   437 		TInt32 heapLoc = 0;
   438 		TInt32 heapSz = 0;
   439 		TInt err = FindKernelHeap(heapLoc,heapSz);
   440 		if(KErrNone == err)
   441 			{
   442 			threadData.iSvcHeap = heapLoc;
   443 			threadData.iSvcHeapSize = heapSz;
   444 			}
   445 		else
   446 			{
   447 			CLTRACE("\tError: Unable to get kernel heap");
   448 			}
   449 		}	
   450 	
   451 	//get filename	
   452 	TFileName filename;
   453 	aThread->TraceAppendFullName(filename, EFalse);
   454 	
   455 	threadData.iName.Copy(filename);
   456 	threadData.iNamesize = threadData.iName.Length();
   457 	
   458 		
   459 #ifdef __INCLUDE_NTHREADBASE_DEFINES__
   460 	threadData.iLastCpu = aThread->iNThread.iLastCpu;
   461 #else	
   462 	threadData.iLastCpu = aThread->iNThread.iSpare3;	
   463 #endif	
   464 	
   465 	threadData.Serialize(*iWriter);
   466 	aSizeDumped+=threadData.GetSize();
   467 	
   468 	return KErrNone;
   469 	}
   470 
   471 /**
   472  * Logs the arm exception stacks 
   473  * @param aSizeDumped Holds the size of the data dumped 
   474  * @return one of the OS wide codes
   475  */
   476 TInt SCMDataSave::LogExceptionStacks(TUint& aSizeDumped)
   477 	{
   478 	LOG_CONTEXT
   479 	aSizeDumped = 0;
   480 	TUint memDumped = 0;
   481 	
   482 	#if defined(__EPOC32__) && !defined(__CPU_X86)
   483 
   484 	TStackInfo& stackInfo = Kern::SuperPage().iStackInfo;
   485 
   486 	TThreadStack irqStack;
   487 	irqStack.iStackType = TThreadStack::EIRQStack;
   488 	irqStack.iStackSize = stackInfo.iIrqStackSize;
   489 	
   490 	aSizeDumped+=irqStack.GetSize();
   491 	irqStack.Serialize(*iWriter);
   492 	
   493 	//now dump the IRQ memory - not much we can do in the event of an error
   494 	MTRAPD(irqErr, LogMemory((TUint8*)stackInfo.iIrqStackBase, stackInfo.iIrqStackSize, &Kern::CurrentThread(), memDumped));	
   495 	
   496 	if(KErrNone != irqErr)
   497 		{
   498 		CLTRACE("*****Failed to log IRQ stack");
   499 		}
   500 	aSizeDumped+=memDumped;
   501 	
   502 	//Next, we do the FIQ stack
   503 	TThreadStack fiqStack;
   504 	fiqStack.iStackType = TThreadStack::EFIQStack;
   505 	fiqStack.iStackSize = stackInfo.iFiqStackSize;
   506 	
   507 	aSizeDumped+=fiqStack.GetSize();
   508 	fiqStack.Serialize(*iWriter);
   509 	
   510 	//Now dump the stack itself
   511 	MTRAPD(fiqErr, LogMemory((TUint8*)stackInfo.iFiqStackBase, stackInfo.iFiqStackSize, &Kern::CurrentThread(), memDumped));
   512 	
   513 	if(KErrNone != fiqErr )
   514 		{
   515 		CLTRACE("*****Failed to log FIQ stack");
   516 		}
   517 	aSizeDumped+=memDumped;
   518 
   519 	#endif
   520 	
   521 	return KErrNone;
   522 	}
   523 
   524 /**
   525  * Logs the CPU Registers at the time of crash
   526  * @param aSizeDumped Holds the size of the data dumped
   527  * @return system wide OS code
   528  */
   529 TInt SCMDataSave::LogCPURegisters(TUint& aSizeDumped)
   530 	{
   531 	LOG_CONTEXT
   532 	aSizeDumped = 0;
   533 	
   534 	TInt32 fullSet = 37;
   535 	
   536 	//meta data about the thread set
   537 	TRegisterSet threadSet;
   538 	threadSet.iNumRegisters = fullSet;
   539 	
   540 	aSizeDumped+=threadSet.GetSize();
   541 	threadSet.Serialize(*iWriter);
   542 		
   543 	SFullArmRegSet regSet;
   544 	ReadCPURegisters(regSet);
   545 	TArmReg* regs = (TArmReg*)&regSet;
   546 		
   547 	TInt32 cnt = 0;
   548 	for(cnt = 0; cnt < fullSet; cnt++)
   549 		{			
   550 		//this is the struct to store the register value in
   551 		TRegisterValue regVal;
   552 		regVal.iType = cnt * 0x100;
   553 		regVal.iValue32 = regs[cnt];
   554 		regVal.iOwnId = Kern::CurrentThread().iId;
   555 		
   556 		aSizeDumped+=regVal.GetSize();
   557 		regVal.Serialize(*iWriter);
   558 		}
   559 
   560 	return KErrNone;	
   561 	}
   562 
   563 /**
   564  * This logs the registers for a given thread to the flash memory
   565  * @param aThread - thread whose registers we want
   566  * @param aRegType - type of register set required such as user, supervisor etc
   567  * @param aSizeDumped Holds the size of the data dumped
   568  * @return one of the OS return codes
   569  */
   570 TInt SCMDataSave::LogRegisters(DThread* aThread, const TRegisterSetType& aRegType, TUint& aSizeDumped)
   571 	{
   572 	LOG_CONTEXT
   573 	aSizeDumped = 0;
   574 	
   575 	TArmRegSet regs;
   576 	TUint32 availableRegs;
   577 	TInt err;
   578 	
   579 	//for the current thread we do things differently
   580 	if(aThread == &Kern::CurrentThread() && aRegType == EFullCPURegisters)
   581 		{
   582 		err = LogCPURegisters(aSizeDumped);
   583 		return err;
   584 		} 
   585 	else if(aThread == &Kern::CurrentThread())
   586 		{
   587 		//only do full cpu reg for the current thread
   588 		return KErrNotSupported;
   589 		}
   590 	
   591 	//Read the appropriate registers
   592 	switch(aRegType)
   593 		{
   594 		case EUserRegisters :
   595 			{
   596 			err = ReadUserRegisters(aThread, regs, availableRegs);
   597 			break;
   598 			}
   599 		case ESupervisorRegisters :
   600 			{
   601 			err = ReadSystemRegisters(aThread, regs, availableRegs);
   602 			break;			
   603 			}
   604 		default : return KErrNotSupported;
   605 		}
   606 	
   607 	if(err != KErrNone)
   608 		{
   609 		return err;
   610 		}	
   611 		
   612 	//meta data about the thread set
   613 	TRegisterSet threadSet;
   614 	
   615 	//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
   616 	TUint numR = 0;
   617 	for(TInt cnt =0; cnt< 8*sizeof(availableRegs); cnt++) //cycle through 1 bit at a time
   618 		{
   619 		if(0x1 & (availableRegs>>cnt))
   620 			numR++;
   621 		}
   622 	
   623 	threadSet.iNumRegisters = numR;
   624 	
   625 	if(numR == 0)
   626 		return KErrNone;
   627 	
   628 	threadSet.Serialize(*iWriter);
   629 	aSizeDumped += threadSet.GetSize();
   630 	
   631 	TInt32 currentRegister = 1;
   632 	TArmReg* reg = (TArmReg*)(&regs);	
   633 	
   634 	for(TInt32 cnt = 0; cnt < KArmRegisterCount; cnt++)
   635 		{		
   636 		//look at the unavailable bitmask to see current register is available
   637 		//only write the registers we have values for
   638 		if(currentRegister & availableRegs)
   639 			{
   640 			//this is the struct to store the register value in
   641 			TRegisterValue regVal;
   642 						
   643 			//get register type as per symbian elf docs
   644 			TUint32 registerType;
   645 			err = GetRegisterType(aRegType, cnt, registerType);
   646 			if(err != KErrNone)
   647 				{
   648 				continue;
   649 				}
   650 			regVal.iType = registerType;
   651 			regVal.iOwnId = aThread->iId;
   652 			
   653 			//set value
   654 			regVal.iValue32 = reg[cnt];
   655 			
   656 			aSizeDumped+=regVal.GetSize();
   657 			regVal.Serialize(*iWriter);
   658 			}
   659 		
   660 		currentRegister<<=1; 
   661 		}
   662 	
   663 	return KErrNone;
   664 	}
   665 
   666 /**
   667  * This logs memory in the specified area
   668  * @param aStartAddress - address to start from
   669  * @param aEndAddress - address to finish
   670  * @param aThread - process whose memory this is in
   671  * @param aSizeDumped Holds the size of the data dumped
   672  * @return one of the system wide codes
   673  */
   674 TInt SCMDataSave::LogMemory(const TUint8* aStartAddress, TInt aLength, const DThread* aThread, TUint& aSizeDumped)
   675 	{
   676 	LOG_CONTEXT
   677 	aSizeDumped = 0;	
   678 	
   679 	if(aThread->iOwningProcess != &Kern::CurrentProcess())
   680 		{
   681 		TInt err = iMonitor->SwitchAddressSpace(aThread->iOwningProcess, ETrue);
   682 		if(KErrNone != err)
   683 			{
   684 			return err;
   685 			}
   686 		}
   687 	
   688 	TMemoryDump memDump;
   689 	memDump.iStartAddress = (TUint32)aStartAddress;
   690 	memDump.iLength = aLength;
   691 	memDump.iPid = aThread->iOwningProcess->iId;
   692 	
   693 	aSizeDumped+=memDump.GetSize();
   694 	memDump.Serialize(*iWriter);	
   695 	
   696 	if(!aStartAddress)
   697 		{
   698 		return KErrArgument;
   699 		}
   700 	
   701 	TRawData theMemory;
   702 	theMemory.iData.Set(const_cast<TUint8*>(aStartAddress), aLength, aLength);
   703 	
   704 	theMemory.Serialize(*iWriter);
   705 	aSizeDumped+=theMemory.GetSize();
   706 	
   707 	return KErrNone;	
   708 	}
   709 
   710 /**
   711  * This logs the locks held by system at time of crash
   712  * @param aSizeDumped Holds the size of the data dumped
   713  * @return one of the system wide codes
   714  */
   715 TInt SCMDataSave::LogLocks(TUint& aSizeDumped)
   716 	{
   717 	LOG_CONTEXT
   718 	aSizeDumped = 0;
   719 	
   720 	// get the mutex logs & waits & log via a TLockData object		
   721 	TSCMLockData lockData;
   722 
   723 	const TInt KMaxLockCheck = 20; // so no possibility of infinite loop
   724 		
   725 	TInt lockCount = 0;
   726 	// check for kernel locks - 	
   727 	for(TInt i=0;i<KMaxLockCheck;i++)
   728 		{		
   729 		TBool locked = NKern::KernelLocked(i);	
   730 		if(!locked)
   731 			{
   732 			lockData.SetLockCount(lockCount);
   733 			break;		
   734 			}
   735 		// found a valid lock for value i increment the clock counter
   736 		lockCount++;
   737 		}
   738 	
   739 	// now mutexes
   740 	DMutex* mutex = Kern::CodeSegLock();
   741 	if(mutex)
   742 		{
   743 		lockData.SetMutexHoldCount(mutex->iHoldCount);
   744 		lockData.SetMutexThreadWaitCount(mutex->iWaitCount);
   745 		}
   746 	else
   747 		{
   748 		// no mutex held set to -1
   749 		lockData.SetMutexHoldCount(0);
   750 		lockData.SetMutexThreadWaitCount(0);		
   751 		}
   752 
   753 	aSizeDumped+=lockData.GetSize();
   754 	TInt err = lockData.Serialize(*iWriter);
   755 	
   756 	return err;
   757 	}
   758 
   759 /**
   760  * Writes the SCM Configuration to the start of the media
   761  * @param aScmConfig Configuration to write
   762  * @return one of the system wide codes
   763  */
   764 TInt SCMDataSave::LogConfig(SCMConfiguration& aScmConfig)
   765 	{
   766 	iWriter->SetPosition(0);
   767 	
   768 	TInt err = aScmConfig.Serialize(*iWriter);
   769 	
   770 	if( err != KErrNone)
   771 		{
   772 		CLTRACE1("SCMDataSave::LogConfig failed err = %d", err);
   773 		}
   774 
   775 	return err;
   776 	}
   777 
   778 /**
   779  * Reads the SCM Configuration from the media
   780  * @param aScmConfig
   781  * @return one of the system wide codes
   782  */
   783 TInt SCMDataSave::ReadConfig(SCMConfiguration& aScmConfig)
   784 	{		
   785 	const TInt KBufSize = 135; //Not yet done: Put in header, beside config defn
   786 
   787 	if( KBufSize < aScmConfig.GetSize())
   788 		{
   789 		CLTRACE2("(SCMDataSave::ReadConfig) ** ERROR Inadequate buffer actual = %d req = %d"
   790 				, KBufSize,  aScmConfig.GetSize());	
   791 		}
   792 	
   793 	// try and read the configuration
   794 	TBuf8<KBufSize> buf;
   795 	buf.SetLength(KBufSize);
   796 		
   797 	iFlash->SetReadPos(0); // config always at 0
   798 	iFlash->Read(buf);
   799 	 
   800 	TByteStreamReader reader(const_cast<TUint8*>(buf.Ptr()));		
   801 	TInt err = aScmConfig.Deserialize(reader);	
   802 	if(err == KErrNotReady)
   803 		{
   804 		CLTRACE("(SCMDataSave::ReadConfig) no config saved - use default");
   805 		}	
   806 	else if(err == KErrNone)	
   807 		{
   808 		CLTRACE("(SCMDataSave::ReadConfig) Config read ok"); 		
   809 		}
   810 	else
   811 		{
   812 		CLTRACE1("(SCMDataSave::ReadConfig) error reading config err = %d", err); 
   813 		}
   814 	
   815 	return err;
   816 	}
   817 
   818 /**
   819  * This is a look up table to map the register type and number to the symbian elf definition 
   820  * of register type
   821  * @param aSetType this is the register set type - user, supervisor etc
   822  * @param aRegNumber this is the number of the register as per TArmRegisters in arm_types.h
   823  * @param aSizeDumped Holds the size of the data dumped
   824  * @return One of the OS wide codes
   825  */
   826 TInt SCMDataSave::GetRegisterType(const TRegisterSetType& aSetType, TInt32& aRegNumber, TUint32& aRegisterType)
   827 	{	
   828 	//validate arguments
   829 	if(aRegNumber < EArmR0 || aRegNumber > EArmFlags)
   830 		{
   831 		return KErrArgument;
   832 		}
   833 	
   834 	//look at what type we are using
   835 	switch(aSetType)
   836 		{
   837 		case EUserRegisters :
   838 			{
   839 			aRegisterType = aRegNumber * 0x100; //for R0 to R16 (CPSR) it just increments in 0x100 from 0x0 to 0x1000
   840 			break;
   841 			}
   842 		case ESupervisorRegisters :
   843 			{
   844 			//same as EUserRegisters except R13 and R14 are different
   845 			if(aRegNumber == EArmSp)
   846 				{
   847 				aRegisterType = 0x1100;
   848 				break;
   849 				}
   850 			else if(aRegNumber == EArmLr)
   851 				{
   852 				aRegisterType = 0x1200;
   853 				break;
   854 				}
   855 			else
   856 				{
   857 				aRegisterType = aRegNumber * 0x100;
   858 				break;
   859 				}		
   860 			}
   861 		default : return KErrNotSupported;
   862 		}
   863 	
   864 	return KErrNone;
   865 	}
   866 
   867 /**
   868  * Writes the trace buffer to the crash log. 
   869  * @param aSizeToDump Number of bytes to dump. If this is zero we attempt to write the entire buffer
   870  * @param aSizeDumped Holds the size of the data dumped
   871  * @return One of the OS wide codes
   872  */
   873 TInt SCMDataSave::LogTraceBuffer(TInt aSizeToDump, TUint& aSizeDumped)
   874 	{
   875 	LOG_CONTEXT
   876 	aSizeDumped = 0;
   877 	TUint memDumped = 0;
   878 	
   879 	TBool dumpAll = (aSizeToDump == 0) ? ETrue : EFalse;
   880 	
   881 	//Because the btrace buffer is a circular one, we need to save it in two parts
   882 	//this corrosponds to how we read it	
   883 	TUint8* data;
   884 	TUint sizeOfPartRead;
   885 	TInt spaceRemaining = aSizeToDump;
   886 	
   887 	//This structure will be filled after the first pass and cached so by the time we ARE writing it will
   888 	//contain the data we want 
   889 	aSizeDumped+=iTrace.GetSize();
   890 	iTrace.Serialize(*iWriter);
   891 	
   892 	//read first part
   893 	TInt err = BTrace::Control(BTrace::ECtrlCrashReadFirst,&data,&sizeOfPartRead);
   894 	
   895 	while(KErrNone == err && sizeOfPartRead > 0)
   896 		{
   897 		TUint rawSize = 0; //how much of this read data want we to dump
   898 		
   899 		if(dumpAll)
   900 			{
   901 			rawSize = sizeOfPartRead;
   902 			}
   903 		else	//Otherwise see what room is left for dumpage
   904 			{
   905 			rawSize  = ((sizeOfPartRead + iTrace.iSizeOfMemory) > aSizeToDump) ? spaceRemaining : sizeOfPartRead;
   906 			}		
   907 		
   908 		//Only relevant if restricting the dump
   909 		if(spaceRemaining <= 0 && !dumpAll)
   910 			break;
   911 		
   912 		TPtrC8 ptr(data, rawSize);
   913 		err = LogRawData(ptr, memDumped);
   914 		if(KErrNone != err)
   915 			{
   916 			CLTRACE1("Logging Raw data failed - [%d]", err);
   917 			err = BTrace::Control(BTrace::ECtrlCrashReadNext,&data,&sizeOfPartRead);
   918 			continue;
   919 			}
   920 		
   921 		aSizeDumped+=memDumped;
   922 		
   923 		iTrace.iSizeOfMemory += rawSize;
   924 		iTrace.iNumberOfParts++;
   925 		spaceRemaining -= rawSize;		
   926 		
   927 		err = BTrace::Control(BTrace::ECtrlCrashReadNext,&data,&sizeOfPartRead);
   928 		}
   929 	
   930 	return KErrNone;
   931 	}
   932 
   933 /**
   934  * Logs the data in a TRawData struct
   935  * @param aData 
   936  * @param aSizeDumped Holds the size of the data dumped
   937  * @return One of the OS wide codes
   938  */
   939 TInt SCMDataSave::LogRawData(const TDesC8& aData, TUint& aSizeDumped)
   940 	{
   941 	TRawData theData;
   942 	theData.iLength = aData.Length();
   943 	theData.iData.Set(const_cast<TUint8*>(aData.Ptr()), aData.Length(), aData.Length());
   944 	
   945 	aSizeDumped+=theData.GetSize();
   946 	return theData.Serialize(*iWriter);	
   947 	}
   948 
   949 
   950 /**
   951  * Logs the kernels heap and returns the size dumped via aSizeDumped
   952  * @param aSizeDumped Holds the size of the data dumped
   953  * @return
   954  */
   955 TInt SCMDataSave::LogKernelHeap(TUint& aSizeDumped)
   956 	{
   957 	LOG_CONTEXT
   958 	
   959 	TInt32 heapLoc = 0;
   960 	TInt32 heapSize = 0;
   961 	TInt32 err = FindKernelHeap(heapLoc, heapSize);
   962 	if(KErrNone == err)
   963 		{
   964 		return LogMemory((TUint8*)heapLoc, heapSize, &Kern::CurrentThread(), aSizeDumped);
   965 		}
   966 	
   967 	CLTRACE1("\tCouldnt find the kernel heap: [%d]", err);
   968 	return err;
   969 	}
   970 
   971 /**
   972  * Iterates the object containers and finds the kernel heap
   973  * @param aHeapLocation Contains the memory location of the kernel heap
   974  * @param aHeapSize Contains the size of the Heap
   975  * @return One of the OS wide codes
   976  */
   977 TInt SCMDataSave::FindKernelHeap(TInt32& aHeapLocation, TInt32& aHeapSize)
   978 	{
   979 	LOG_CONTEXT
   980 	
   981 	//Get Chunk object container
   982 	DObjectCon* objectContainer = Kern::Containers()[EChunk];
   983 	if(objectContainer == NULL)
   984 		{		
   985 		CLTRACE("\tFailed to get object container for the chunks");
   986 		return KErrNotFound;
   987 		}
   988 	
   989 	//Must check the mutex on this is ok otherwise the data will be in an inconsistent state
   990 	if(objectContainer->Lock()->iHoldCount)
   991 		{
   992 		CLTRACE("\tChunk Container is in an inconsistant state");
   993 		return KErrCorrupt;
   994 		}
   995 	
   996 	TInt numObjects = objectContainer->Count();	
   997 	
   998 	for(TInt cnt = 0; cnt< numObjects; cnt ++)
   999 		{		
  1000 		DChunk* candidateHeapChunk = (DChunk*)(*objectContainer)[cnt];
  1001 		
  1002 		//Get the objects name
  1003 		TBuf8<KMaxKernelName> name;
  1004 		candidateHeapChunk->TraceAppendFullName(name,EFalse);
  1005 		
  1006 		if(name == KKernelHeapChunkName)
  1007 			{
  1008 			#ifndef __MEMMODEL_FLEXIBLE__
  1009 				aHeapLocation = (TInt32)candidateHeapChunk->iBase;
  1010 			#else
  1011 				aHeapLocation = (TInt32)candidateHeapChunk->iFixedBase;
  1012 			#endif
  1013 				
  1014 				aHeapSize = candidateHeapChunk->iSize;
  1015 				
  1016 			return KErrNone;
  1017 			}
  1018 		}
  1019 	
  1020 	return KErrNotFound;
  1021 	}
  1022 
  1023 /**
  1024  * This logs the variant specific descriptor data to the crash log
  1025  * @param aSizeDumped records how much was dumped by this function
  1026  * @return one of the OS wide codes
  1027  */
  1028 TInt SCMDataSave::LogVariantSpecificData(TUint& aSizeDumped)
  1029 	{
  1030 	LOG_CONTEXT
  1031 	
  1032 	aSizeDumped = 0;
  1033 	
  1034 	//Change this descriptor as required for your needs
  1035 	_LIT(KVariantSpecificData, "This is the variant specific data. Put your own here");
  1036 	
  1037 	TVariantSpecificData varData;
  1038 	varData.iSize = KVariantSpecificData().Size(); 
  1039 	
  1040 	TInt err = varData.Serialize(*iWriter);
  1041 	if(KErrNone != err)
  1042 		{
  1043 		CLTRACE1("\tLogging variant specific data failed with code [%d]", err);
  1044 		return err;
  1045 		}
  1046 	aSizeDumped+=varData.GetSize();
  1047 	
  1048 	TUint rawDataSize = 0;
  1049 	err = LogRawData(KVariantSpecificData(), rawDataSize);
  1050 	if(KErrNone != err)
  1051 		{
  1052 		CLTRACE1("\tLogging variant specific data failed with code [%d]", err);
  1053 		return err;
  1054 		}
  1055 	
  1056 	aSizeDumped+=rawDataSize;
  1057 	
  1058 	return KErrNone;
  1059 	}
  1060 
  1061 
  1062 /**
  1063  * This method is the callback used by MPhysicalWriterImpl interface
  1064  * if the TCachedByteStreamWriter is configured to use this interface
  1065  * the callback avoids the need for temp buffers & can interface directly with the
  1066  * flash writer methods
  1067  * @param aData - data to write
  1068  * @param aLen	- length of data to write
  1069  * @param aPos  - writers internal position   
  1070  */
  1071 void SCMDataSave::DoPhysicalWrite(TAny* aData, TInt aPos, TInt aLen)
  1072 	{	
  1073 	if(iPerformChecksum)
  1074 		{
  1075 		iChecksum.ChecksumBlock((TUint8*)aData, aLen);
  1076 		}
  1077 	
  1078 	if( this->iWriteSelect == EWriteComm)
  1079 		{	
  1080 		WriteUart((TUint8*)aData, aLen);		
  1081 		}
  1082 	else  // EWriteFlash
  1083 		{			
  1084 		Write(aData, aLen);
  1085 		}
  1086 	}
  1087 
  1088 /**
  1089  * Writes data to Flash
  1090  * @param aSomething Pointer to the data
  1091  * @param aSize Size of the data
  1092  */
  1093 void SCMDataSave::Write(const TAny* aSomething, TInt aSize)
  1094 	{		
  1095 	TPtrC8 data((const TUint8 *)aSomething, aSize);
  1096 	
  1097 	TInt written = 0;
  1098 	
  1099 	WriteCrashFlash(iByteCount, written, data);
  1100 	iByteCount+= written;	
  1101 	}
  1102 
  1103 /**
  1104  * Writes a descriptor to the crash flash
  1105  * @param aPos Position in flash to write
  1106  * @param aSize Holds the size of the data written after the call
  1107  * @param aBuffer Descriptor to write
  1108  */
  1109 void SCMDataSave::WriteCrashFlash(TInt aPos, TInt& aSize, const TDesC8& aBuffer)
  1110 	{	
  1111 	//Set write position in the flash
  1112 	iFlash->SetWritePos(aPos);	
  1113 	iFlash->Write(aBuffer);
  1114 	
  1115 	//get bytes written
  1116 	aSize += iFlash->BytesWritten();
  1117 	
  1118 	if(aSize != aBuffer.Length())
  1119 		{
  1120 		CLTRACE2("(SCMDataSave::WriteCrashFlash) Over the limit aSize = %d aBuffer.Length() = %d",
  1121 				aSize,  aBuffer.Length());
  1122 		}
  1123 	}
  1124 	
  1125 /**
  1126  * Writes a descriptor via serial
  1127  * @param aDes Descriptor to write
  1128  */
  1129 void SCMDataSave::WriteUart(const TDesC8& aDes)
  1130 	{
  1131 	WriteUart(aDes.Ptr(), aDes.Length());	
  1132 	}
  1133 
  1134 /**
  1135  * Writes data via serial
  1136  * @param aData Data to write
  1137  * @param aSize Size of data to write
  1138  */
  1139 void SCMDataSave::WriteUart(const TUint8* aData, TInt aSize)
  1140 	{
  1141 	OMAP* assp = ((OMAP*)Arch::TheAsic());
  1142 	TOmapDbgPrt* dbg = assp->DebugPort();
  1143 		
  1144 	if (dbg)
  1145 		{
  1146 		for(TInt i=0;i<aSize;i++)
  1147 			{
  1148 			dbg->DebugOutput(*(aData+i));			
  1149 			}
  1150 		}
  1151 	else
  1152 		{
  1153 		CLTRACE("SCMDataSave::WriteUart ERROR - dbg was null");		
  1154 		}
  1155 	}
  1156 
  1157 /**
  1158  * Setter for the current number of bytes written for this crash log
  1159  * If aByte is not word aligned, it will be rounded up to be so
  1160  * @param aByte Current bytes written
  1161  */
  1162 void SCMDataSave::SetByteCount(TInt aByte)
  1163 	{
  1164 	//ensure aligned
  1165 	if(aByte % iWriter->GetCacheSize() == 0)
  1166 		{
  1167 		iByteCount = aByte;
  1168 		}
  1169 	else
  1170 		{
  1171 		iByteCount = aByte + (iWriter->GetCacheSize() - (aByte % iWriter->GetCacheSize()));
  1172 		}		
  1173 	}
  1174 
  1175 /**
  1176  * Gets the output target selection
  1177  * @return TScmWriteSelect output target selection
  1178  * @param void
  1179  */	
  1180 SCMDataSave::TWriteSelect SCMDataSave::GetWriteSelect()
  1181 	{
  1182 	return iWriteSelect;
  1183 	}
  1184 
  1185 /**
  1186  * Sets the output target selection
  1187  * @return void
  1188  * @param TScmWriteSelect aWriteSelect output target selection
  1189  */
  1190 void SCMDataSave::SetWriteSelect(SCMDataSave::TWriteSelect aWriteSelect)
  1191 	{
  1192 	iWriteSelect = aWriteSelect;
  1193 	}
  1194 
  1195 /**
  1196  * Gets the amount of space remaining for the media of choice
  1197  * @return
  1198  */
  1199 TUint SCMDataSave::SpaceRemaining()
  1200 	{
  1201 	TInt currentPosition = iWriter->GetBytesWritten() + iStartingPointForCrash;
  1202 	
  1203 	return MaxLogSize() - currentPosition; 
  1204 	}
  1205 
  1206 /**
  1207  * To find the max size of a log for a given media
  1208  * @return the max size of a log for a given media
  1209  */
  1210 TUint SCMDataSave::MaxLogSize()
  1211 	{
  1212 	//see what write media is being used
  1213 	switch(GetWriteSelect())
  1214 		{
  1215 		case EWriteFlash:
  1216 			{
  1217 			return KMaxCrashLogSize; 
  1218 			}
  1219 		case EWriteComm:
  1220 			{
  1221 			return 0xFFFFFFFF;
  1222 			}
  1223 		default:
  1224 			{
  1225 			return 0;
  1226 			}
  1227 		} 
  1228 	}
  1229 
  1230 /**
  1231  * Records the offset in the flash partition where this crash begins
  1232  * @param aStart Offset in flash
  1233  */
  1234 void SCMDataSave::SetCrashStartingPoint(TUint32 aStart)
  1235 	{
  1236 	iStartingPointForCrash = aStart;
  1237 	}
  1238 
  1239 //eof
  1240