os/kernelhwsrv/kernel/eka/debug/crashMonitor/src/crashlogwalker.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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