1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/debug/crashMonitor/src/crashlogwalker.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,535 @@
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\crashlogwalker.cpp
1.18 +// Class to allow us to traverse the crash log generated by System Crash Monitor
1.19 +//
1.20 +//
1.21 +
1.22 +/**
1.23 + @file
1.24 + @internalTechnology
1.25 +*/
1.26 +
1.27 +#ifndef __KERNEL_MODE__
1.28 +#include <e32std.h>
1.29 +#include <e32std_private.h>
1.30 +#include <e32base.h>
1.31 +#include <e32base_private.h>
1.32 +#endif
1.33 +
1.34 +#include "scmtrace.h"
1.35 +#include "crashlogwalker.h"
1.36 +
1.37 +namespace Debug
1.38 + {
1.39 + /**
1.40 + * Constructor for log walker
1.41 + * @param aBuffer The buffer containing the crash data
1.42 + */
1.43 + TCrashLogWalker::TCrashLogWalker(TDesC8& aBuffer) :
1.44 + iBuffer(aBuffer),
1.45 + iReader(const_cast<TUint8*>(iBuffer.Ptr()))
1.46 + {
1.47 + }
1.48 +
1.49 + /**
1.50 + * This reads in the crash header from the buffer from the given start point
1.51 + * @param aStartPoint Point to begin reading in buffer
1.52 + * @return One of the OS wide codes
1.53 + */
1.54 + TInt TCrashLogWalker::ReadLogHeader(const TInt aStartPoint)
1.55 + {
1.56 + iReader.SetPosition(aStartPoint);
1.57 +
1.58 + TInt err = iCrashHeader.Deserialize(iReader);
1.59 + if(err != KErrNone)
1.60 + {
1.61 + CLTRACE("(TCrashLogWalker::ReadLogHeader) - failed to read crash header");
1.62 + return KErrCorrupt;
1.63 + }
1.64 +
1.65 + err = iOffsets.Deserialize(iReader);
1.66 + if(err != KErrNone)
1.67 + {
1.68 + CLTRACE("(TCrashLogWalker::ReadLogHeader) - failed to read offsets");
1.69 + return KErrCorrupt;
1.70 + }
1.71 +
1.72 + TRegisterSet set;
1.73 + err = set.Deserialize(iReader);
1.74 + if(err != KErrNone)
1.75 + {
1.76 + CLTRACE("(TCrashLogWalker::ReadLogHeader) - failed to read register set");
1.77 + return KErrCorrupt;
1.78 + }
1.79 +
1.80 + for(TInt cnt = 0; cnt < set.iNumRegisters; cnt++)
1.81 + {
1.82 + TRegisterValue val;
1.83 + err = val.Deserialize(iReader);
1.84 + if(err != KErrNone)
1.85 + {
1.86 + CLTRACE1("(TCrashLogWalker::ReadLogHeader) - failed to read TRegisterValue cnt = %d", cnt);
1.87 + return KErrCorrupt;
1.88 + }
1.89 +
1.90 + HelpAssignRegisterToContext(val);
1.91 + }
1.92 +
1.93 + return VerifyHeader();
1.94 + }
1.95 +
1.96 + /**
1.97 + * Getter for the crash context - This is the CPU register set at the time of crash
1.98 + * @return Crash Context
1.99 + */
1.100 + const TRmdArmExcInfo& TCrashLogWalker::GetCrashContext() const
1.101 + {
1.102 + return iContext;
1.103 + }
1.104 +
1.105 + /**
1.106 + * Returns the crash size for the crash that has just been read, provided the
1.107 + * reading of the header was succesful.
1.108 + * @see ReadLogHeader
1.109 + * @return Crash Log size
1.110 + */
1.111 + TInt TCrashLogWalker::GetCrashSize() const
1.112 + {
1.113 + return iCrashHeader.iLogSize;
1.114 + }
1.115 +
1.116 + /**
1.117 + * Returns the crash ID for the crash that has just been read, provided the
1.118 + * reading of the header was succesful.
1.119 + * @see ReadLogHeader
1.120 + * @return Crash Log ID
1.121 + */
1.122 + TInt TCrashLogWalker::GetCrashId() const
1.123 + {
1.124 + return iCrashHeader.iCrashId;
1.125 + }
1.126 +
1.127 + /**
1.128 + * Looks at the member crash log header and checks that it is valid.
1.129 + * @see ReadLogHeader
1.130 + * @return one of the OS wide codes
1.131 + */
1.132 + TInt TCrashLogWalker::VerifyHeader()
1.133 + {
1.134 + if(iCrashHeader.iId == ESCMTCrashInfo)
1.135 + {
1.136 + CLTRACE("TCrashLogWalker::VerifyHeader() OK");
1.137 + return KErrNone;
1.138 + }
1.139 + else
1.140 + {
1.141 + CLTRACE("TCrashLogWalker::VerifyHeader() FAILED");
1.142 + return KErrCorrupt;
1.143 + }
1.144 + }
1.145 +
1.146 + /**
1.147 + * Updates the buffer being used by the crash walker and resets reader to use
1.148 + * the beginning of this
1.149 + * @param aBuffer New buffer
1.150 + */
1.151 + void TCrashLogWalker::UpdateBuffer(TDesC8& aBuffer)
1.152 + {
1.153 + iBuffer = aBuffer;
1.154 +
1.155 + //Read from start of this buffer
1.156 + iReader = TByteStreamReader(const_cast<TUint8*>(aBuffer.Ptr()));
1.157 + }
1.158 +
1.159 +#ifndef __KERNEL_MODE__
1.160 + /**
1.161 + * Gets the next data type from the buffer. If this is NULL it means the buffer was too small.
1.162 + * Call again with a larger buffer. It assumes the buffer contains valid data and leaves with KErrCorrupt
1.163 + * 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
1.164 + * correct position. If you just want to skip a raw data type, move the buffer along the size of (contained in the returned struct)
1.165 + *
1.166 + * @see GetRawDataTypeL
1.167 + * @see UpdateBuffer
1.168 + * @param aPos Next position that will be read. If we return NULL, this is the position the next buffer should
1.169 + * begin from
1.170 + * @param aId ID of the MByteStreamSerializable returned
1.171 + * @param buffer size to be used the next time. Unchanged if the current buffer is ok
1.172 + * @return MByteStreamSerializable pointer. Ownership is passed to caller. NULL if failed
1.173 + * @leave KErrCorrupt if the buffer cant be read
1.174 + */
1.175 + MByteStreamSerializable* TCrashLogWalker::GetNextDataTypeL(TInt& aPos, SCMStructId& aId, TInt& aBufferSize)
1.176 + {
1.177 + MByteStreamSerializable* data = NULL;
1.178 +
1.179 + TInt roomInBuffer = iBuffer.Length() - iReader.CurrentPosition();
1.180 + //make sure we have at LEAST 4 bytes in the buffer
1.181 + if(roomInBuffer < (TInt)(sizeof(TInt)))
1.182 + {
1.183 + aBufferSize = sizeof(TInt);
1.184 + return NULL;
1.185 + }
1.186 +
1.187 + //this stores the required size in which to deserialize a structure - to make sure
1.188 + //there is room in the buffer
1.189 + TInt maxSize = 0;
1.190 + aPos = iReader.CurrentPosition();
1.191 + aBufferSize = iBuffer.Length();
1.192 +
1.193 + //all these data types are defined by their first byte
1.194 + aId = (SCMStructId)iBuffer.Ptr()[iReader.CurrentPosition()];
1.195 +
1.196 + //ensure we have a valid structure found
1.197 + if(aId <= 0 || aId >= ESCMLast)
1.198 + {
1.199 + //oddness is afoot and the mist of corruption reigns thick
1.200 + User::Leave(KErrCorrupt);
1.201 + }
1.202 +
1.203 + switch(aId)
1.204 + {
1.205 + case ESCMOffsetsHeader:
1.206 + {
1.207 + data = new TCrashOffsetsHeader();
1.208 + maxSize = TCrashOffsetsHeader::KSCMCrashOffsetsMaxSize;
1.209 + break;
1.210 + }
1.211 + case ESCMTCrashInfo:
1.212 + {
1.213 + data = new TCrashInfoHeader();
1.214 + maxSize = TCrashInfoHeader::KSCMCrashInfoMaxSize;
1.215 + break;
1.216 + }
1.217 + case ESCMProcessData:
1.218 + {
1.219 + data = new TProcessData();
1.220 + maxSize = TProcessData::KSCMProcessDataMaxSize;
1.221 + break;
1.222 + }
1.223 + case ESCMThreadData:
1.224 + {
1.225 + data = new TThreadData();
1.226 + maxSize = TThreadData::KSCMThreadDataMaxSize;
1.227 + break;
1.228 + }
1.229 + case ESCMThreadStack:
1.230 + {
1.231 + data = new TThreadStack();
1.232 + maxSize = TThreadStack::KSCMThreadStackMaxSize;
1.233 + break;
1.234 + }
1.235 + case ESCMRegisterValue:
1.236 + {
1.237 + data = new TRegisterValue();
1.238 + maxSize = TRegisterValue::KSCMRegisterValueMaxSize;
1.239 + break;
1.240 + }
1.241 + case ESCMRegisterSet:
1.242 + {
1.243 + data = new TRegisterSet();
1.244 + maxSize = TRegisterSet::KSCMRegisterSetMaxSize;
1.245 + break;
1.246 + }
1.247 + case ESCMMemory:
1.248 + {
1.249 + data = new TMemoryDump();
1.250 + maxSize = TMemoryDump::KSCMMemDumpMaxSize;
1.251 + break;
1.252 + }
1.253 + case ESCMCodeSegSet:
1.254 + {
1.255 + data = new TCodeSegmentSet();
1.256 + maxSize = TCodeSegmentSet::KSCMCodeSegSetMaxSize;
1.257 + break;
1.258 + }
1.259 + case ESCMCodeSeg:
1.260 + {
1.261 + data = new TCodeSegment();
1.262 + maxSize = TCodeSegment::KMaxSegmentNameSize;
1.263 + break;
1.264 + }
1.265 + case ESCMLocks:
1.266 + {
1.267 + data = new TSCMLockData();
1.268 + maxSize = TSCMLockData::KSCMLockDataMaxSize;
1.269 + break;
1.270 + }
1.271 + case ESCMVariantData:
1.272 + {
1.273 + data = new TVariantSpecificData();
1.274 + maxSize = TVariantSpecificData::KSCMVarSpecMaxSize;
1.275 + break;
1.276 + }
1.277 + case ESCMRomHeader:
1.278 + {
1.279 + data = new TRomHeaderData();
1.280 + maxSize = TRomHeaderData::KSCMRomHdrMaxSize;
1.281 + break;
1.282 + }
1.283 + case ESCMRawData:
1.284 + {
1.285 + data = new TRawData();
1.286 +
1.287 + //This is a special case. The data in here can be any length, so we need to deserialise it
1.288 + //to find this length out. The MAX_SIZE of this class is the max size minus data
1.289 + //which is fine if we dont assign the TPtr8.
1.290 + if(TRawData::KSCMRawDataMaxSize > roomInBuffer )
1.291 + {
1.292 + aBufferSize = (maxSize > aBufferSize) ? maxSize : aBufferSize;
1.293 +
1.294 + if(data)
1.295 + delete data;
1.296 +
1.297 + return NULL;
1.298 + }
1.299 + else
1.300 + {
1.301 + data->Deserialize(iReader);
1.302 + maxSize = data->GetSize();
1.303 +
1.304 + aPos = iReader.CurrentPosition();
1.305 + return data;
1.306 + }
1.307 + }
1.308 + case ESCMTraceData:
1.309 + {
1.310 + data = new TTraceDump();
1.311 + maxSize = TTraceDump::KSCMTraceDumpMaxSize;
1.312 + break;
1.313 + }
1.314 + default :
1.315 + {
1.316 + User::Panic(_L("Unexpected Null. Unrecognised Data type from crash log."), KErrGeneral); //Programming error
1.317 + }
1.318 + }
1.319 +
1.320 + __ASSERT_ALWAYS((data != NULL), User::Panic(_L("Unexpected Null"), KErrGeneral));
1.321 +
1.322 + if(maxSize > roomInBuffer )
1.323 + {
1.324 + //Not enough room in buffer to read this. Tell caller where in the current buffer
1.325 + //we were via aPos, and what minimum size buffer should be used next time to allow reading
1.326 + aBufferSize = maxSize;
1.327 + if(data)
1.328 + {
1.329 + delete data;
1.330 + }
1.331 +
1.332 + return NULL;
1.333 + }
1.334 +
1.335 + if(!data)
1.336 + {
1.337 + CLTRACE("Unable to create data structure");
1.338 + User::Leave(KErrAbort);
1.339 + }
1.340 +
1.341 + data->Deserialize(iReader);
1.342 + aPos = iReader.CurrentPosition();
1.343 +
1.344 + return data;
1.345 + }
1.346 +
1.347 + /**
1.348 + * Assuming the next type in the buffer is a TRawData type, this will return the TRawData
1.349 + * types data pointer pointing to the buffer passed via aRawBuf.
1.350 + *
1.351 + * The difference between this call and GetNextDataTypeL is that GetNextDataTypeL only lets you move along the buffer
1.352 + * it doesnt allow you to specify a buffer in which to store the raw data.
1.353 + *
1.354 + * @see GetNextDataTypeL
1.355 + * @return TRawData* This is the TRawData object that holds the data via the buffer passed in. Ownership is passed to the caller
1.356 + * @param aPos position in buffer its been found. If we return NULL, this is the position the next buffer should
1.357 + * begin from
1.358 + * @param aBufferSize Should we return NULL, that means the descriptor passed in was not big enough and should be of at least aBufferSize bytes
1.359 + * @param aRawBuf The buffer to store the data refered to by the TRawData returned
1.360 + * @param aStartRawPosition The point in the raw data at which we will start to put it into the buffer
1.361 + * @leave One of the OS wide codes
1.362 + */
1.363 + TRawData* TCrashLogWalker::GetRawDataTypeL(TInt& aPos, TInt& aBufferSize, TDes8& aRawBuf, TInt aStartRawPosition)
1.364 + {
1.365 + //make sure we have at LEAST the size of the struct in the buffer
1.366 + if(iBuffer.Length() < TRawData::KSCMRawDataMaxSize)
1.367 + {
1.368 + aBufferSize = TRawData::KSCMRawDataMaxSize;
1.369 + return NULL;
1.370 + }
1.371 +
1.372 + //this stores the required size in which to deserialize a structure - to make sure
1.373 + //there is room in the buffer
1.374 + aPos = iReader.CurrentPosition();
1.375 + aBufferSize = iBuffer.Length();
1.376 +
1.377 + //all these data types are defined by their first byte
1.378 + TInt id = (SCMStructId)iBuffer.Ptr()[iReader.CurrentPosition()];
1.379 + if(id != ESCMRawData)
1.380 + {
1.381 + User::Leave(KErrCorrupt);
1.382 + }
1.383 +
1.384 + //Deserialise once to get the length (this will ignore the data in the absence of a Tptr)
1.385 + TRawData* data = new TRawData();
1.386 + data->Deserialize(iReader);
1.387 +
1.388 + //reset reader to where the raw data starts again
1.389 + iReader.SetPosition(aPos);
1.390 +
1.391 + //now we know we have room, deserialize into this descriptor
1.392 + aRawBuf.SetMax();
1.393 + data->iData.Set(aRawBuf.MidTPtr(0));
1.394 + User::LeaveIfError(data->Deserialize(aStartRawPosition, iReader));
1.395 +
1.396 + return data;
1.397 + }
1.398 +
1.399 +#endif
1.400 +
1.401 + /**
1.402 + * This is a helper function to convert between the two formats of register
1.403 + * @param aRegVal Resulting register values
1.404 + */
1.405 + void TCrashLogWalker::HelpAssignRegisterToContext(const TRegisterValue& aRegVal)
1.406 + {
1.407 + //only interested in core registers at the moment
1.408 + if(aRegVal.iClass != 0 || aRegVal.iSize != 2)
1.409 + {
1.410 + return;
1.411 + }
1.412 +
1.413 + //Is there a cleverer way to do this with bitmasks and FOFF ?
1.414 + switch(aRegVal.iType)
1.415 + {
1.416 + case 0x0 :
1.417 + {
1.418 + iContext.iR0 = aRegVal.iValue32;
1.419 + break;
1.420 + }
1.421 + case 0x100 :
1.422 + {
1.423 + iContext.iR1 = aRegVal.iValue32;
1.424 + break;
1.425 + }
1.426 + case 0x200 :
1.427 + {
1.428 + iContext.iR2 = aRegVal.iValue32;
1.429 + break;
1.430 + }
1.431 + case 0x300 :
1.432 + {
1.433 + iContext.iR3 = aRegVal.iValue32;
1.434 + break;
1.435 + }
1.436 + case 0x400 :
1.437 + {
1.438 + iContext.iR4 = aRegVal.iValue32;
1.439 + break;
1.440 + }
1.441 + case 0x500 :
1.442 + {
1.443 + iContext.iR5 = aRegVal.iValue32;
1.444 + break;
1.445 + }
1.446 + case 0x600 :
1.447 + {
1.448 + iContext.iR6 = aRegVal.iValue32;
1.449 + break;
1.450 + }
1.451 + case 0x700 :
1.452 + {
1.453 + iContext.iR7 = aRegVal.iValue32;
1.454 + break;
1.455 + }
1.456 + case 0x800 :
1.457 + {
1.458 + iContext.iR8 = aRegVal.iValue32;
1.459 + break;
1.460 + }
1.461 + case 0x900 :
1.462 + {
1.463 + iContext.iR9 = aRegVal.iValue32;
1.464 + break;
1.465 + }
1.466 + case 0xa00 :
1.467 + {
1.468 + iContext.iR10 = aRegVal.iValue32;
1.469 + break;
1.470 + }
1.471 + case 0xb00 :
1.472 + {
1.473 + iContext.iR11 = aRegVal.iValue32;
1.474 + break;
1.475 + }
1.476 + case 0xc00 :
1.477 + {
1.478 + iContext.iR12 = aRegVal.iValue32;
1.479 + break;
1.480 + }
1.481 + case 0xd00 :
1.482 + {
1.483 + iContext.iR13 = aRegVal.iValue32;
1.484 + break;
1.485 + }
1.486 + case 0xe00 :
1.487 + {
1.488 + iContext.iR14 = aRegVal.iValue32;
1.489 + break;
1.490 + }
1.491 + case 0xf00 :
1.492 + {
1.493 + iContext.iR15 = aRegVal.iValue32;
1.494 + break;
1.495 + }
1.496 + case 0x1000 :
1.497 + {
1.498 + iContext.iCpsr = aRegVal.iValue32;
1.499 + break;
1.500 + }
1.501 + case 0x1100 :
1.502 + {
1.503 + iContext.iR13Svc = aRegVal.iValue32;
1.504 + break;
1.505 + }
1.506 + case 0x1200 :
1.507 + {
1.508 + iContext.iR14Svc = aRegVal.iValue32;
1.509 + break;
1.510 + }
1.511 + default :
1.512 + {
1.513 + return;
1.514 + }
1.515 + }
1.516 + }
1.517 +
1.518 + /**
1.519 + * Getter for crash header
1.520 + * @return header
1.521 + */
1.522 + const TCrashInfoHeader& TCrashLogWalker::GetCrashHeader() const
1.523 + {
1.524 + return iCrashHeader;
1.525 + }
1.526 +
1.527 + /**
1.528 + * Getter for crash offsets header
1.529 + * @return header
1.530 + */
1.531 + const TCrashOffsetsHeader& TCrashLogWalker::GetOffsetsHeader() const
1.532 + {
1.533 + return iOffsets;
1.534 + }
1.535 +
1.536 + }
1.537 +//eof
1.538 +