--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/debug/crashMonitor/src/crashlogwalker.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,535 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32\debug\crashMonitor\src\crashlogwalker.cpp
+// Class to allow us to traverse the crash log generated by System Crash Monitor
+//
+//
+
+/**
+ @file
+ @internalTechnology
+*/
+
+#ifndef __KERNEL_MODE__
+#include <e32std.h>
+#include <e32std_private.h>
+#include <e32base.h>
+#include <e32base_private.h>
+#endif
+
+#include "scmtrace.h"
+#include "crashlogwalker.h"
+
+namespace Debug
+ {
+ /**
+ * Constructor for log walker
+ * @param aBuffer The buffer containing the crash data
+ */
+ TCrashLogWalker::TCrashLogWalker(TDesC8& aBuffer) :
+ iBuffer(aBuffer),
+ iReader(const_cast<TUint8*>(iBuffer.Ptr()))
+ {
+ }
+
+ /**
+ * This reads in the crash header from the buffer from the given start point
+ * @param aStartPoint Point to begin reading in buffer
+ * @return One of the OS wide codes
+ */
+ TInt TCrashLogWalker::ReadLogHeader(const TInt aStartPoint)
+ {
+ iReader.SetPosition(aStartPoint);
+
+ TInt err = iCrashHeader.Deserialize(iReader);
+ if(err != KErrNone)
+ {
+ CLTRACE("(TCrashLogWalker::ReadLogHeader) - failed to read crash header");
+ return KErrCorrupt;
+ }
+
+ err = iOffsets.Deserialize(iReader);
+ if(err != KErrNone)
+ {
+ CLTRACE("(TCrashLogWalker::ReadLogHeader) - failed to read offsets");
+ return KErrCorrupt;
+ }
+
+ TRegisterSet set;
+ err = set.Deserialize(iReader);
+ if(err != KErrNone)
+ {
+ CLTRACE("(TCrashLogWalker::ReadLogHeader) - failed to read register set");
+ return KErrCorrupt;
+ }
+
+ for(TInt cnt = 0; cnt < set.iNumRegisters; cnt++)
+ {
+ TRegisterValue val;
+ err = val.Deserialize(iReader);
+ if(err != KErrNone)
+ {
+ CLTRACE1("(TCrashLogWalker::ReadLogHeader) - failed to read TRegisterValue cnt = %d", cnt);
+ return KErrCorrupt;
+ }
+
+ HelpAssignRegisterToContext(val);
+ }
+
+ return VerifyHeader();
+ }
+
+ /**
+ * Getter for the crash context - This is the CPU register set at the time of crash
+ * @return Crash Context
+ */
+ const TRmdArmExcInfo& TCrashLogWalker::GetCrashContext() const
+ {
+ return iContext;
+ }
+
+ /**
+ * Returns the crash size for the crash that has just been read, provided the
+ * reading of the header was succesful.
+ * @see ReadLogHeader
+ * @return Crash Log size
+ */
+ TInt TCrashLogWalker::GetCrashSize() const
+ {
+ return iCrashHeader.iLogSize;
+ }
+
+ /**
+ * Returns the crash ID for the crash that has just been read, provided the
+ * reading of the header was succesful.
+ * @see ReadLogHeader
+ * @return Crash Log ID
+ */
+ TInt TCrashLogWalker::GetCrashId() const
+ {
+ return iCrashHeader.iCrashId;
+ }
+
+ /**
+ * Looks at the member crash log header and checks that it is valid.
+ * @see ReadLogHeader
+ * @return one of the OS wide codes
+ */
+ TInt TCrashLogWalker::VerifyHeader()
+ {
+ if(iCrashHeader.iId == ESCMTCrashInfo)
+ {
+ CLTRACE("TCrashLogWalker::VerifyHeader() OK");
+ return KErrNone;
+ }
+ else
+ {
+ CLTRACE("TCrashLogWalker::VerifyHeader() FAILED");
+ return KErrCorrupt;
+ }
+ }
+
+ /**
+ * Updates the buffer being used by the crash walker and resets reader to use
+ * the beginning of this
+ * @param aBuffer New buffer
+ */
+ void TCrashLogWalker::UpdateBuffer(TDesC8& aBuffer)
+ {
+ iBuffer = aBuffer;
+
+ //Read from start of this buffer
+ iReader = TByteStreamReader(const_cast<TUint8*>(aBuffer.Ptr()));
+ }
+
+#ifndef __KERNEL_MODE__
+ /**
+ * Gets the next data type from the buffer. If this is NULL it means the buffer was too small.
+ * Call again with a larger buffer. It assumes the buffer contains valid data and leaves with KErrCorrupt
+ * 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
+ * correct position. If you just want to skip a raw data type, move the buffer along the size of (contained in the returned struct)
+ *
+ * @see GetRawDataTypeL
+ * @see UpdateBuffer
+ * @param aPos Next position that will be read. If we return NULL, this is the position the next buffer should
+ * begin from
+ * @param aId ID of the MByteStreamSerializable returned
+ * @param buffer size to be used the next time. Unchanged if the current buffer is ok
+ * @return MByteStreamSerializable pointer. Ownership is passed to caller. NULL if failed
+ * @leave KErrCorrupt if the buffer cant be read
+ */
+ MByteStreamSerializable* TCrashLogWalker::GetNextDataTypeL(TInt& aPos, SCMStructId& aId, TInt& aBufferSize)
+ {
+ MByteStreamSerializable* data = NULL;
+
+ TInt roomInBuffer = iBuffer.Length() - iReader.CurrentPosition();
+ //make sure we have at LEAST 4 bytes in the buffer
+ if(roomInBuffer < (TInt)(sizeof(TInt)))
+ {
+ aBufferSize = sizeof(TInt);
+ return NULL;
+ }
+
+ //this stores the required size in which to deserialize a structure - to make sure
+ //there is room in the buffer
+ TInt maxSize = 0;
+ aPos = iReader.CurrentPosition();
+ aBufferSize = iBuffer.Length();
+
+ //all these data types are defined by their first byte
+ aId = (SCMStructId)iBuffer.Ptr()[iReader.CurrentPosition()];
+
+ //ensure we have a valid structure found
+ if(aId <= 0 || aId >= ESCMLast)
+ {
+ //oddness is afoot and the mist of corruption reigns thick
+ User::Leave(KErrCorrupt);
+ }
+
+ switch(aId)
+ {
+ case ESCMOffsetsHeader:
+ {
+ data = new TCrashOffsetsHeader();
+ maxSize = TCrashOffsetsHeader::KSCMCrashOffsetsMaxSize;
+ break;
+ }
+ case ESCMTCrashInfo:
+ {
+ data = new TCrashInfoHeader();
+ maxSize = TCrashInfoHeader::KSCMCrashInfoMaxSize;
+ break;
+ }
+ case ESCMProcessData:
+ {
+ data = new TProcessData();
+ maxSize = TProcessData::KSCMProcessDataMaxSize;
+ break;
+ }
+ case ESCMThreadData:
+ {
+ data = new TThreadData();
+ maxSize = TThreadData::KSCMThreadDataMaxSize;
+ break;
+ }
+ case ESCMThreadStack:
+ {
+ data = new TThreadStack();
+ maxSize = TThreadStack::KSCMThreadStackMaxSize;
+ break;
+ }
+ case ESCMRegisterValue:
+ {
+ data = new TRegisterValue();
+ maxSize = TRegisterValue::KSCMRegisterValueMaxSize;
+ break;
+ }
+ case ESCMRegisterSet:
+ {
+ data = new TRegisterSet();
+ maxSize = TRegisterSet::KSCMRegisterSetMaxSize;
+ break;
+ }
+ case ESCMMemory:
+ {
+ data = new TMemoryDump();
+ maxSize = TMemoryDump::KSCMMemDumpMaxSize;
+ break;
+ }
+ case ESCMCodeSegSet:
+ {
+ data = new TCodeSegmentSet();
+ maxSize = TCodeSegmentSet::KSCMCodeSegSetMaxSize;
+ break;
+ }
+ case ESCMCodeSeg:
+ {
+ data = new TCodeSegment();
+ maxSize = TCodeSegment::KMaxSegmentNameSize;
+ break;
+ }
+ case ESCMLocks:
+ {
+ data = new TSCMLockData();
+ maxSize = TSCMLockData::KSCMLockDataMaxSize;
+ break;
+ }
+ case ESCMVariantData:
+ {
+ data = new TVariantSpecificData();
+ maxSize = TVariantSpecificData::KSCMVarSpecMaxSize;
+ break;
+ }
+ case ESCMRomHeader:
+ {
+ data = new TRomHeaderData();
+ maxSize = TRomHeaderData::KSCMRomHdrMaxSize;
+ break;
+ }
+ case ESCMRawData:
+ {
+ data = new TRawData();
+
+ //This is a special case. The data in here can be any length, so we need to deserialise it
+ //to find this length out. The MAX_SIZE of this class is the max size minus data
+ //which is fine if we dont assign the TPtr8.
+ if(TRawData::KSCMRawDataMaxSize > roomInBuffer )
+ {
+ aBufferSize = (maxSize > aBufferSize) ? maxSize : aBufferSize;
+
+ if(data)
+ delete data;
+
+ return NULL;
+ }
+ else
+ {
+ data->Deserialize(iReader);
+ maxSize = data->GetSize();
+
+ aPos = iReader.CurrentPosition();
+ return data;
+ }
+ }
+ case ESCMTraceData:
+ {
+ data = new TTraceDump();
+ maxSize = TTraceDump::KSCMTraceDumpMaxSize;
+ break;
+ }
+ default :
+ {
+ User::Panic(_L("Unexpected Null. Unrecognised Data type from crash log."), KErrGeneral); //Programming error
+ }
+ }
+
+ __ASSERT_ALWAYS((data != NULL), User::Panic(_L("Unexpected Null"), KErrGeneral));
+
+ if(maxSize > roomInBuffer )
+ {
+ //Not enough room in buffer to read this. Tell caller where in the current buffer
+ //we were via aPos, and what minimum size buffer should be used next time to allow reading
+ aBufferSize = maxSize;
+ if(data)
+ {
+ delete data;
+ }
+
+ return NULL;
+ }
+
+ if(!data)
+ {
+ CLTRACE("Unable to create data structure");
+ User::Leave(KErrAbort);
+ }
+
+ data->Deserialize(iReader);
+ aPos = iReader.CurrentPosition();
+
+ return data;
+ }
+
+ /**
+ * Assuming the next type in the buffer is a TRawData type, this will return the TRawData
+ * types data pointer pointing to the buffer passed via aRawBuf.
+ *
+ * The difference between this call and GetNextDataTypeL is that GetNextDataTypeL only lets you move along the buffer
+ * it doesnt allow you to specify a buffer in which to store the raw data.
+ *
+ * @see GetNextDataTypeL
+ * @return TRawData* This is the TRawData object that holds the data via the buffer passed in. Ownership is passed to the caller
+ * @param aPos position in buffer its been found. If we return NULL, this is the position the next buffer should
+ * begin from
+ * @param aBufferSize Should we return NULL, that means the descriptor passed in was not big enough and should be of at least aBufferSize bytes
+ * @param aRawBuf The buffer to store the data refered to by the TRawData returned
+ * @param aStartRawPosition The point in the raw data at which we will start to put it into the buffer
+ * @leave One of the OS wide codes
+ */
+ TRawData* TCrashLogWalker::GetRawDataTypeL(TInt& aPos, TInt& aBufferSize, TDes8& aRawBuf, TInt aStartRawPosition)
+ {
+ //make sure we have at LEAST the size of the struct in the buffer
+ if(iBuffer.Length() < TRawData::KSCMRawDataMaxSize)
+ {
+ aBufferSize = TRawData::KSCMRawDataMaxSize;
+ return NULL;
+ }
+
+ //this stores the required size in which to deserialize a structure - to make sure
+ //there is room in the buffer
+ aPos = iReader.CurrentPosition();
+ aBufferSize = iBuffer.Length();
+
+ //all these data types are defined by their first byte
+ TInt id = (SCMStructId)iBuffer.Ptr()[iReader.CurrentPosition()];
+ if(id != ESCMRawData)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ //Deserialise once to get the length (this will ignore the data in the absence of a Tptr)
+ TRawData* data = new TRawData();
+ data->Deserialize(iReader);
+
+ //reset reader to where the raw data starts again
+ iReader.SetPosition(aPos);
+
+ //now we know we have room, deserialize into this descriptor
+ aRawBuf.SetMax();
+ data->iData.Set(aRawBuf.MidTPtr(0));
+ User::LeaveIfError(data->Deserialize(aStartRawPosition, iReader));
+
+ return data;
+ }
+
+#endif
+
+ /**
+ * This is a helper function to convert between the two formats of register
+ * @param aRegVal Resulting register values
+ */
+ void TCrashLogWalker::HelpAssignRegisterToContext(const TRegisterValue& aRegVal)
+ {
+ //only interested in core registers at the moment
+ if(aRegVal.iClass != 0 || aRegVal.iSize != 2)
+ {
+ return;
+ }
+
+ //Is there a cleverer way to do this with bitmasks and FOFF ?
+ switch(aRegVal.iType)
+ {
+ case 0x0 :
+ {
+ iContext.iR0 = aRegVal.iValue32;
+ break;
+ }
+ case 0x100 :
+ {
+ iContext.iR1 = aRegVal.iValue32;
+ break;
+ }
+ case 0x200 :
+ {
+ iContext.iR2 = aRegVal.iValue32;
+ break;
+ }
+ case 0x300 :
+ {
+ iContext.iR3 = aRegVal.iValue32;
+ break;
+ }
+ case 0x400 :
+ {
+ iContext.iR4 = aRegVal.iValue32;
+ break;
+ }
+ case 0x500 :
+ {
+ iContext.iR5 = aRegVal.iValue32;
+ break;
+ }
+ case 0x600 :
+ {
+ iContext.iR6 = aRegVal.iValue32;
+ break;
+ }
+ case 0x700 :
+ {
+ iContext.iR7 = aRegVal.iValue32;
+ break;
+ }
+ case 0x800 :
+ {
+ iContext.iR8 = aRegVal.iValue32;
+ break;
+ }
+ case 0x900 :
+ {
+ iContext.iR9 = aRegVal.iValue32;
+ break;
+ }
+ case 0xa00 :
+ {
+ iContext.iR10 = aRegVal.iValue32;
+ break;
+ }
+ case 0xb00 :
+ {
+ iContext.iR11 = aRegVal.iValue32;
+ break;
+ }
+ case 0xc00 :
+ {
+ iContext.iR12 = aRegVal.iValue32;
+ break;
+ }
+ case 0xd00 :
+ {
+ iContext.iR13 = aRegVal.iValue32;
+ break;
+ }
+ case 0xe00 :
+ {
+ iContext.iR14 = aRegVal.iValue32;
+ break;
+ }
+ case 0xf00 :
+ {
+ iContext.iR15 = aRegVal.iValue32;
+ break;
+ }
+ case 0x1000 :
+ {
+ iContext.iCpsr = aRegVal.iValue32;
+ break;
+ }
+ case 0x1100 :
+ {
+ iContext.iR13Svc = aRegVal.iValue32;
+ break;
+ }
+ case 0x1200 :
+ {
+ iContext.iR14Svc = aRegVal.iValue32;
+ break;
+ }
+ default :
+ {
+ return;
+ }
+ }
+ }
+
+ /**
+ * Getter for crash header
+ * @return header
+ */
+ const TCrashInfoHeader& TCrashLogWalker::GetCrashHeader() const
+ {
+ return iCrashHeader;
+ }
+
+ /**
+ * Getter for crash offsets header
+ * @return header
+ */
+ const TCrashOffsetsHeader& TCrashLogWalker::GetOffsetsHeader() const
+ {
+ return iOffsets;
+ }
+
+ }
+//eof
+