kernel/eka/debug/crashMonitor/src/crashlogwalker.cpp
changeset 43 96e5fb8b040d
equal deleted inserted replaced
-1:000000000000 43:96e5fb8b040d
       
     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\crashlogwalker.cpp
       
    15 // Class to allow us to traverse the crash log generated by System Crash Monitor
       
    16 // 
       
    17 //
       
    18 
       
    19 /**
       
    20  @file
       
    21  @internalTechnology
       
    22 */
       
    23 
       
    24 #ifndef __KERNEL_MODE__
       
    25 #include <e32std.h>
       
    26 #include <e32std_private.h> 
       
    27 #include <e32base.h>
       
    28 #include <e32base_private.h> 
       
    29 #endif
       
    30 
       
    31 #include "scmtrace.h"
       
    32 #include "crashlogwalker.h"
       
    33 
       
    34 namespace Debug
       
    35 	{	
       
    36 	/**
       
    37 	 * Constructor for log walker
       
    38 	 * @param aBuffer The buffer containing the crash data
       
    39 	 */
       
    40 	TCrashLogWalker::TCrashLogWalker(TDesC8& aBuffer) : 
       
    41 		iBuffer(aBuffer),
       
    42 		iReader(const_cast<TUint8*>(iBuffer.Ptr()))
       
    43 		{
       
    44 		}
       
    45 	
       
    46 	/**
       
    47 	 * This reads in the crash header from the buffer from the given start point
       
    48 	 * @param aStartPoint Point to begin reading in buffer
       
    49 	 * @return One of the OS wide codes
       
    50 	 */
       
    51 	TInt TCrashLogWalker::ReadLogHeader(const TInt aStartPoint)
       
    52 		{		
       
    53 		iReader.SetPosition(aStartPoint);
       
    54 		
       
    55 		TInt err = iCrashHeader.Deserialize(iReader);
       
    56 		if(err != KErrNone)
       
    57 			{
       
    58 			CLTRACE("(TCrashLogWalker::ReadLogHeader) - failed to read crash header");
       
    59 			return KErrCorrupt;
       
    60 			}
       
    61 		
       
    62 		err = iOffsets.Deserialize(iReader);
       
    63 		if(err != KErrNone)
       
    64 			{
       
    65 			CLTRACE("(TCrashLogWalker::ReadLogHeader) - failed to read offsets");
       
    66 			return KErrCorrupt;
       
    67 			}
       
    68 		
       
    69 		TRegisterSet set;
       
    70 		err = set.Deserialize(iReader);
       
    71 		if(err != KErrNone)
       
    72 			{
       
    73 			CLTRACE("(TCrashLogWalker::ReadLogHeader) - failed to read register set");
       
    74 			return KErrCorrupt;
       
    75 			}
       
    76 		
       
    77 		for(TInt cnt = 0; cnt < set.iNumRegisters; cnt++)
       
    78 			{
       
    79 			TRegisterValue val;
       
    80 			err = val.Deserialize(iReader);
       
    81 			if(err != KErrNone)
       
    82 				{
       
    83 				CLTRACE1("(TCrashLogWalker::ReadLogHeader) - failed to read TRegisterValue cnt = %d", cnt);
       
    84 				return KErrCorrupt;
       
    85 				}
       
    86 						
       
    87 			HelpAssignRegisterToContext(val);
       
    88 			}
       
    89 		
       
    90 		return VerifyHeader();
       
    91 		}
       
    92 	
       
    93 	/**
       
    94 	 * Getter for the crash context - This is the CPU register set at the time of crash
       
    95 	 * @return Crash Context
       
    96 	 */
       
    97 	const TRmdArmExcInfo& TCrashLogWalker::GetCrashContext() const
       
    98 		{
       
    99 		return iContext;
       
   100 		}
       
   101 	
       
   102 	/**
       
   103 	 * Returns the crash size for the crash that has just been read, provided the
       
   104 	 * reading of the header was succesful. 
       
   105 	 * @see ReadLogHeader
       
   106 	 * @return Crash Log size
       
   107 	 */
       
   108 	TInt TCrashLogWalker::GetCrashSize() const
       
   109 		{
       
   110 		return iCrashHeader.iLogSize;
       
   111 		}
       
   112 	
       
   113 	/**
       
   114 	 * Returns the crash ID for the crash that has just been read, provided the
       
   115 	 * reading of the header was succesful. 
       
   116 	 * @see ReadLogHeader
       
   117 	 * @return Crash Log ID
       
   118 	 */
       
   119 	TInt TCrashLogWalker::GetCrashId() const
       
   120 		{
       
   121 		return iCrashHeader.iCrashId;
       
   122 		}
       
   123 	
       
   124 	/**
       
   125 	 * Looks at the member crash log header and checks that it is valid.
       
   126 	 * @see ReadLogHeader 
       
   127 	 * @return one of the OS wide codes
       
   128 	 */
       
   129 	TInt TCrashLogWalker::VerifyHeader()
       
   130 		{
       
   131 		if(iCrashHeader.iId == ESCMTCrashInfo)
       
   132 			{			
       
   133 			CLTRACE("TCrashLogWalker::VerifyHeader() OK");
       
   134 			return KErrNone;
       
   135 			}
       
   136 		else
       
   137 			{
       
   138 			CLTRACE("TCrashLogWalker::VerifyHeader() FAILED");
       
   139 			return KErrCorrupt;
       
   140 			}
       
   141 		}
       
   142 	
       
   143 	/**
       
   144 	 * Updates the buffer being used by the crash walker and resets reader to use 
       
   145 	 * the beginning of this
       
   146 	 * @param aBuffer New buffer
       
   147 	 */
       
   148 	void TCrashLogWalker::UpdateBuffer(TDesC8& aBuffer)
       
   149 		{
       
   150 		iBuffer = aBuffer;		
       
   151 		
       
   152 		//Read from start of this buffer		
       
   153 		iReader = TByteStreamReader(const_cast<TUint8*>(aBuffer.Ptr()));
       
   154 		}
       
   155 	
       
   156 #ifndef __KERNEL_MODE__
       
   157 	/**
       
   158 	 * Gets the next data type from the buffer. If this is NULL it means the buffer was too small.
       
   159 	 * Call again with a larger buffer. It assumes the buffer contains valid data and leaves with KErrCorrupt 
       
   160 	 * if it isnt. Note for raw data types, the data will be empty. This should be read with GetRawDataTypeL after reseting the reader to the 
       
   161 	 * correct position. If you just want to skip a raw data type, move the buffer along the size of (contained in the returned struct)
       
   162 	 * 
       
   163 	 * @see GetRawDataTypeL
       
   164 	 * @see UpdateBuffer
       
   165 	 * @param aPos Next position that will be read. If we return NULL, this is the position the next buffer should
       
   166 	 * 			begin from
       
   167 	 * @param aId ID of the MByteStreamSerializable returned	 
       
   168 	 * @param buffer size to be used the next time. Unchanged if the current buffer is ok
       
   169 	 * @return MByteStreamSerializable pointer. Ownership is passed to caller. NULL if failed
       
   170 	 * @leave KErrCorrupt if the buffer cant be read
       
   171 	 */
       
   172 	MByteStreamSerializable* TCrashLogWalker::GetNextDataTypeL(TInt& aPos, SCMStructId& aId, TInt& aBufferSize)
       
   173 		{
       
   174 		MByteStreamSerializable* data = NULL;
       
   175 		
       
   176 		TInt roomInBuffer = iBuffer.Length() - iReader.CurrentPosition();
       
   177 		//make sure we have at LEAST 4 bytes in the buffer
       
   178 		if(roomInBuffer < (TInt)(sizeof(TInt)))
       
   179 			{
       
   180 			aBufferSize = sizeof(TInt);
       
   181 			return NULL;
       
   182 			}
       
   183 		
       
   184 		//this stores the required size in which to deserialize a structure - to make sure 
       
   185 		//there is room in the buffer
       
   186 		TInt maxSize = 0;
       
   187 		aPos = iReader.CurrentPosition();
       
   188 		aBufferSize = iBuffer.Length();		
       
   189 		
       
   190 		//all these data types are defined by their first byte
       
   191 		aId = (SCMStructId)iBuffer.Ptr()[iReader.CurrentPosition()];		
       
   192 		
       
   193 		//ensure we have a valid structure found
       
   194 		if(aId <= 0 || aId >= ESCMLast)
       
   195 			{
       
   196 			//oddness is afoot and the mist of corruption reigns thick
       
   197 			User::Leave(KErrCorrupt);
       
   198 			}					
       
   199 		
       
   200 		switch(aId)
       
   201 			{
       
   202 			case ESCMOffsetsHeader:
       
   203 				{
       
   204 				data = new TCrashOffsetsHeader();	
       
   205 				maxSize = TCrashOffsetsHeader::KSCMCrashOffsetsMaxSize;
       
   206 				break;
       
   207 				}
       
   208 			case ESCMTCrashInfo:
       
   209 				{
       
   210 				data = new TCrashInfoHeader();
       
   211 				maxSize = TCrashInfoHeader::KSCMCrashInfoMaxSize;
       
   212 				break;
       
   213 				}
       
   214 			case ESCMProcessData:
       
   215 				{
       
   216 				data = new TProcessData();
       
   217 				maxSize = TProcessData::KSCMProcessDataMaxSize;
       
   218 				break;
       
   219 				}
       
   220 			case ESCMThreadData:
       
   221 				{
       
   222 				data = new TThreadData();
       
   223 				maxSize = TThreadData::KSCMThreadDataMaxSize;
       
   224 				break;
       
   225 				}
       
   226 			case ESCMThreadStack:
       
   227 				{
       
   228 				data = new TThreadStack();
       
   229 				maxSize = TThreadStack::KSCMThreadStackMaxSize;
       
   230 				break;
       
   231 				}
       
   232 			case ESCMRegisterValue:
       
   233 				{
       
   234 				data = new TRegisterValue();
       
   235 				maxSize = TRegisterValue::KSCMRegisterValueMaxSize;
       
   236 				break;
       
   237 				}
       
   238 			case ESCMRegisterSet:
       
   239 				{
       
   240 				data = new TRegisterSet();
       
   241 				maxSize = TRegisterSet::KSCMRegisterSetMaxSize;
       
   242 				break;
       
   243 				}
       
   244 			case ESCMMemory:
       
   245 				{
       
   246 				data = new TMemoryDump();
       
   247 				maxSize = TMemoryDump::KSCMMemDumpMaxSize;
       
   248 				break;
       
   249 				}
       
   250 			case ESCMCodeSegSet:
       
   251 				{
       
   252 				data = new TCodeSegmentSet();
       
   253 				maxSize = TCodeSegmentSet::KSCMCodeSegSetMaxSize;
       
   254 				break;
       
   255 				}
       
   256 			case ESCMCodeSeg:
       
   257 				{
       
   258 				data = new TCodeSegment();
       
   259 				maxSize = TCodeSegment::KMaxSegmentNameSize;
       
   260 				break;
       
   261 				}	
       
   262 			case ESCMLocks:
       
   263 				{
       
   264 				data = new TSCMLockData();
       
   265 				maxSize = TSCMLockData::KSCMLockDataMaxSize;	
       
   266 				break;
       
   267 				}
       
   268 			case ESCMVariantData:
       
   269 				{
       
   270 				data = new TVariantSpecificData();
       
   271 				maxSize = TVariantSpecificData::KSCMVarSpecMaxSize;	
       
   272 				break;
       
   273 				}				
       
   274 			case ESCMRomHeader:
       
   275 				{
       
   276 				data = new TRomHeaderData();
       
   277 				maxSize = TRomHeaderData::KSCMRomHdrMaxSize;	
       
   278 				break;
       
   279 				}				
       
   280 			case ESCMRawData:
       
   281 				{
       
   282 				data = new TRawData();
       
   283 				
       
   284 				//This is a special case. The data in here can be any length, so we need to deserialise it
       
   285 				//to find this length out. The MAX_SIZE of this class is the max size minus data
       
   286 				//which is fine if we dont assign the TPtr8.				
       
   287 				if(TRawData::KSCMRawDataMaxSize > roomInBuffer )
       
   288 					{					
       
   289 					aBufferSize = (maxSize > aBufferSize) ? maxSize : aBufferSize;
       
   290 					
       
   291 					if(data)
       
   292 						delete data;
       
   293 					
       
   294 					return NULL;
       
   295 					}
       
   296 				else
       
   297 					{
       
   298 					data->Deserialize(iReader);
       
   299 					maxSize = data->GetSize();
       
   300 					
       
   301 					aPos = iReader.CurrentPosition();
       
   302 					return data;
       
   303 					}
       
   304 				}
       
   305 			case ESCMTraceData:
       
   306 				{
       
   307 				data = new TTraceDump();
       
   308 				maxSize = TTraceDump::KSCMTraceDumpMaxSize;
       
   309 				break;
       
   310 				}
       
   311 			default :
       
   312 				{
       
   313 				User::Panic(_L("Unexpected Null. Unrecognised Data type from crash log."), KErrGeneral); //Programming error				
       
   314 				}							
       
   315 			}
       
   316 		
       
   317 		__ASSERT_ALWAYS((data != NULL), User::Panic(_L("Unexpected Null"), KErrGeneral));
       
   318 		
       
   319 		if(maxSize > roomInBuffer )
       
   320 			{
       
   321 			//Not enough room in buffer to read this. Tell caller where in the current buffer
       
   322 			//we were via aPos, and what minimum size buffer should be used next time to allow reading
       
   323 			aBufferSize = maxSize;
       
   324 			if(data)
       
   325 				{
       
   326 				delete data;
       
   327 				}
       
   328 			
       
   329 			return NULL;
       
   330 			}
       
   331 		
       
   332 		if(!data)
       
   333 			{
       
   334 			CLTRACE("Unable to create data structure");
       
   335 			User::Leave(KErrAbort);
       
   336 			}
       
   337 		
       
   338 		data->Deserialize(iReader);			
       
   339 		aPos = iReader.CurrentPosition();
       
   340 		
       
   341 		return data;
       
   342 		}
       
   343 	
       
   344 	/**
       
   345 	 * Assuming the next type in the buffer is a TRawData type, this will return the TRawData
       
   346 	 * types data pointer pointing to the buffer passed via aRawBuf.
       
   347 	 *  
       
   348 	 * The difference between this call and GetNextDataTypeL is that GetNextDataTypeL only lets you move along the buffer
       
   349 	 * it doesnt allow you to specify a buffer in which to store the raw data.
       
   350 	 * 
       
   351 	 * @see GetNextDataTypeL
       
   352 	 * @return TRawData* This is the TRawData object that holds the data via the buffer passed in. Ownership is passed to the caller
       
   353 	 * @param aPos position in buffer its been found. If we return NULL, this is the position the next buffer should
       
   354 	 * 			begin from
       
   355 	 * @param aBufferSize Should we return NULL, that means the descriptor passed in was not big enough and should be of at least aBufferSize bytes
       
   356 	 * @param aRawBuf The buffer to store the data refered to by the TRawData returned
       
   357 	 * @param aStartRawPosition The point in the raw data at which we will start to put it into the buffer
       
   358 	 * @leave One of the OS wide codes
       
   359 	 */
       
   360 	TRawData* TCrashLogWalker::GetRawDataTypeL(TInt& aPos, TInt& aBufferSize, TDes8& aRawBuf, TInt aStartRawPosition)
       
   361 		{								
       
   362 		//make sure we have at LEAST the size of the struct in the buffer
       
   363 		if(iBuffer.Length() < TRawData::KSCMRawDataMaxSize)
       
   364 			{
       
   365 			aBufferSize = TRawData::KSCMRawDataMaxSize;
       
   366 			return NULL;
       
   367 			}
       
   368 		
       
   369 		//this stores the required size in which to deserialize a structure - to make sure 
       
   370 		//there is room in the buffer
       
   371 		aPos = iReader.CurrentPosition();
       
   372 		aBufferSize = iBuffer.Length();
       
   373 		
       
   374 		//all these data types are defined by their first byte
       
   375 		TInt id = (SCMStructId)iBuffer.Ptr()[iReader.CurrentPosition()];
       
   376 		if(id != ESCMRawData)
       
   377 			{
       
   378 			User::Leave(KErrCorrupt);
       
   379 			}		
       
   380 		
       
   381 		//Deserialise once to get the length (this will ignore the data in the absence of a Tptr)
       
   382 		TRawData* data = new TRawData();
       
   383 		data->Deserialize(iReader);
       
   384 		
       
   385 		//reset reader to where the raw data starts again
       
   386 		iReader.SetPosition(aPos);
       
   387 		
       
   388 		//now we know we have room, deserialize into this descriptor	
       
   389 		aRawBuf.SetMax();	
       
   390 		data->iData.Set(aRawBuf.MidTPtr(0));
       
   391 		User::LeaveIfError(data->Deserialize(aStartRawPosition, iReader));
       
   392 		
       
   393 		return data;
       
   394 		}
       
   395 	
       
   396 #endif
       
   397 	
       
   398 	/**
       
   399 	 * This is a helper function to convert between the two formats of register
       
   400 	 * @param aRegVal Resulting register values
       
   401 	 */
       
   402 	void TCrashLogWalker::HelpAssignRegisterToContext(const TRegisterValue& aRegVal)
       
   403 		{
       
   404 		//only interested in core registers at the moment
       
   405 		if(aRegVal.iClass != 0 || aRegVal.iSize != 2)
       
   406 			{
       
   407 			return;
       
   408 			}
       
   409 		
       
   410 		//Is there a cleverer way to do this with bitmasks and FOFF ?
       
   411 		switch(aRegVal.iType)
       
   412 			{
       
   413 			case 0x0 :
       
   414 				{
       
   415 				iContext.iR0 = aRegVal.iValue32;
       
   416 				break;
       
   417 				}
       
   418 			case 0x100 :
       
   419 				{
       
   420 				iContext.iR1 = aRegVal.iValue32;
       
   421 				break;
       
   422 				}
       
   423 			case 0x200 :
       
   424 				{
       
   425 				iContext.iR2 = aRegVal.iValue32;
       
   426 				break;
       
   427 				}
       
   428 			case 0x300 :
       
   429 				{
       
   430 				iContext.iR3 = aRegVal.iValue32;
       
   431 				break;
       
   432 				}
       
   433 			case 0x400 :
       
   434 				{
       
   435 				iContext.iR4 = aRegVal.iValue32;
       
   436 				break;
       
   437 				}
       
   438 			case 0x500 :
       
   439 				{
       
   440 				iContext.iR5 = aRegVal.iValue32;
       
   441 				break;
       
   442 				}
       
   443 			case 0x600 :
       
   444 				{
       
   445 				iContext.iR6 = aRegVal.iValue32;
       
   446 				break;
       
   447 				}
       
   448 			case 0x700 :
       
   449 				{
       
   450 				iContext.iR7 = aRegVal.iValue32;
       
   451 				break;
       
   452 				}
       
   453 			case 0x800 :
       
   454 				{
       
   455 				iContext.iR8 = aRegVal.iValue32;
       
   456 				break;
       
   457 				}
       
   458 			case 0x900 :
       
   459 				{
       
   460 				iContext.iR9 = aRegVal.iValue32;
       
   461 				break;
       
   462 				}
       
   463 			case 0xa00 :
       
   464 				{
       
   465 				iContext.iR10 = aRegVal.iValue32;
       
   466 				break;
       
   467 				}
       
   468 			case 0xb00 :
       
   469 				{
       
   470 				iContext.iR11 = aRegVal.iValue32;
       
   471 				break;
       
   472 				}
       
   473 			case 0xc00 :
       
   474 				{
       
   475 				iContext.iR12 = aRegVal.iValue32;
       
   476 				break;
       
   477 				}
       
   478 			case 0xd00 :
       
   479 				{
       
   480 				iContext.iR13 = aRegVal.iValue32;				
       
   481 				break;
       
   482 				}
       
   483 			case 0xe00 :
       
   484 				{
       
   485 				iContext.iR14 = aRegVal.iValue32;
       
   486 				break;
       
   487 				}
       
   488 			case 0xf00 :
       
   489 				{
       
   490 				iContext.iR15 = aRegVal.iValue32;
       
   491 				break;
       
   492 				}
       
   493 			case 0x1000 :
       
   494 				{
       
   495 				iContext.iCpsr = aRegVal.iValue32;
       
   496 				break;
       
   497 				}
       
   498 			case 0x1100 :
       
   499 				{
       
   500 				iContext.iR13Svc = aRegVal.iValue32;
       
   501 				break;
       
   502 				}
       
   503 			case 0x1200 :
       
   504 				{
       
   505 				iContext.iR14Svc = aRegVal.iValue32;
       
   506 				break;
       
   507 				}
       
   508 			default :
       
   509 				{
       
   510 				return;
       
   511 				}				
       
   512 			}
       
   513 		}
       
   514 	
       
   515 	/**
       
   516 	 * Getter for crash header
       
   517 	 * @return header
       
   518 	 */
       
   519 	const TCrashInfoHeader& TCrashLogWalker::GetCrashHeader() const
       
   520 		{
       
   521 		return iCrashHeader;
       
   522 		}
       
   523 	
       
   524 	/**
       
   525 	 * Getter for crash offsets header
       
   526 	 * @return header
       
   527 	 */
       
   528 	const TCrashOffsetsHeader& TCrashLogWalker::GetOffsetsHeader() const
       
   529 		{
       
   530 		return iOffsets;
       
   531 		}			
       
   532 		
       
   533 	}
       
   534 //eof
       
   535