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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32\debug\crashMonitor\src\crashlogwalker.cpp
15 // Class to allow us to traverse the crash log generated by System Crash Monitor
24 #ifndef __KERNEL_MODE__
26 #include <e32std_private.h>
28 #include <e32base_private.h>
32 #include "crashlogwalker.h"
37 * Constructor for log walker
38 * @param aBuffer The buffer containing the crash data
40 TCrashLogWalker::TCrashLogWalker(TDesC8& aBuffer) :
42 iReader(const_cast<TUint8*>(iBuffer.Ptr()))
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
51 TInt TCrashLogWalker::ReadLogHeader(const TInt aStartPoint)
53 iReader.SetPosition(aStartPoint);
55 TInt err = iCrashHeader.Deserialize(iReader);
58 CLTRACE("(TCrashLogWalker::ReadLogHeader) - failed to read crash header");
62 err = iOffsets.Deserialize(iReader);
65 CLTRACE("(TCrashLogWalker::ReadLogHeader) - failed to read offsets");
70 err = set.Deserialize(iReader);
73 CLTRACE("(TCrashLogWalker::ReadLogHeader) - failed to read register set");
77 for(TInt cnt = 0; cnt < set.iNumRegisters; cnt++)
80 err = val.Deserialize(iReader);
83 CLTRACE1("(TCrashLogWalker::ReadLogHeader) - failed to read TRegisterValue cnt = %d", cnt);
87 HelpAssignRegisterToContext(val);
90 return VerifyHeader();
94 * Getter for the crash context - This is the CPU register set at the time of crash
95 * @return Crash Context
97 const TRmdArmExcInfo& TCrashLogWalker::GetCrashContext() const
103 * Returns the crash size for the crash that has just been read, provided the
104 * reading of the header was succesful.
106 * @return Crash Log size
108 TInt TCrashLogWalker::GetCrashSize() const
110 return iCrashHeader.iLogSize;
114 * Returns the crash ID for the crash that has just been read, provided the
115 * reading of the header was succesful.
117 * @return Crash Log ID
119 TInt TCrashLogWalker::GetCrashId() const
121 return iCrashHeader.iCrashId;
125 * Looks at the member crash log header and checks that it is valid.
127 * @return one of the OS wide codes
129 TInt TCrashLogWalker::VerifyHeader()
131 if(iCrashHeader.iId == ESCMTCrashInfo)
133 CLTRACE("TCrashLogWalker::VerifyHeader() OK");
138 CLTRACE("TCrashLogWalker::VerifyHeader() FAILED");
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
148 void TCrashLogWalker::UpdateBuffer(TDesC8& aBuffer)
152 //Read from start of this buffer
153 iReader = TByteStreamReader(const_cast<TUint8*>(aBuffer.Ptr()));
156 #ifndef __KERNEL_MODE__
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)
163 * @see GetRawDataTypeL
165 * @param aPos Next position that will be read. If we return NULL, this is the position the next buffer should
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
172 MByteStreamSerializable* TCrashLogWalker::GetNextDataTypeL(TInt& aPos, SCMStructId& aId, TInt& aBufferSize)
174 MByteStreamSerializable* data = NULL;
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)))
180 aBufferSize = sizeof(TInt);
184 //this stores the required size in which to deserialize a structure - to make sure
185 //there is room in the buffer
187 aPos = iReader.CurrentPosition();
188 aBufferSize = iBuffer.Length();
190 //all these data types are defined by their first byte
191 aId = (SCMStructId)iBuffer.Ptr()[iReader.CurrentPosition()];
193 //ensure we have a valid structure found
194 if(aId <= 0 || aId >= ESCMLast)
196 //oddness is afoot and the mist of corruption reigns thick
197 User::Leave(KErrCorrupt);
202 case ESCMOffsetsHeader:
204 data = new TCrashOffsetsHeader();
205 maxSize = TCrashOffsetsHeader::KSCMCrashOffsetsMaxSize;
210 data = new TCrashInfoHeader();
211 maxSize = TCrashInfoHeader::KSCMCrashInfoMaxSize;
214 case ESCMProcessData:
216 data = new TProcessData();
217 maxSize = TProcessData::KSCMProcessDataMaxSize;
222 data = new TThreadData();
223 maxSize = TThreadData::KSCMThreadDataMaxSize;
226 case ESCMThreadStack:
228 data = new TThreadStack();
229 maxSize = TThreadStack::KSCMThreadStackMaxSize;
232 case ESCMRegisterValue:
234 data = new TRegisterValue();
235 maxSize = TRegisterValue::KSCMRegisterValueMaxSize;
238 case ESCMRegisterSet:
240 data = new TRegisterSet();
241 maxSize = TRegisterSet::KSCMRegisterSetMaxSize;
246 data = new TMemoryDump();
247 maxSize = TMemoryDump::KSCMMemDumpMaxSize;
252 data = new TCodeSegmentSet();
253 maxSize = TCodeSegmentSet::KSCMCodeSegSetMaxSize;
258 data = new TCodeSegment();
259 maxSize = TCodeSegment::KMaxSegmentNameSize;
264 data = new TSCMLockData();
265 maxSize = TSCMLockData::KSCMLockDataMaxSize;
268 case ESCMVariantData:
270 data = new TVariantSpecificData();
271 maxSize = TVariantSpecificData::KSCMVarSpecMaxSize;
276 data = new TRomHeaderData();
277 maxSize = TRomHeaderData::KSCMRomHdrMaxSize;
282 data = new TRawData();
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 )
289 aBufferSize = (maxSize > aBufferSize) ? maxSize : aBufferSize;
298 data->Deserialize(iReader);
299 maxSize = data->GetSize();
301 aPos = iReader.CurrentPosition();
307 data = new TTraceDump();
308 maxSize = TTraceDump::KSCMTraceDumpMaxSize;
313 User::Panic(_L("Unexpected Null. Unrecognised Data type from crash log."), KErrGeneral); //Programming error
317 __ASSERT_ALWAYS((data != NULL), User::Panic(_L("Unexpected Null"), KErrGeneral));
319 if(maxSize > roomInBuffer )
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;
334 CLTRACE("Unable to create data structure");
335 User::Leave(KErrAbort);
338 data->Deserialize(iReader);
339 aPos = iReader.CurrentPosition();
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.
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.
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
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
360 TRawData* TCrashLogWalker::GetRawDataTypeL(TInt& aPos, TInt& aBufferSize, TDes8& aRawBuf, TInt aStartRawPosition)
362 //make sure we have at LEAST the size of the struct in the buffer
363 if(iBuffer.Length() < TRawData::KSCMRawDataMaxSize)
365 aBufferSize = TRawData::KSCMRawDataMaxSize;
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();
374 //all these data types are defined by their first byte
375 TInt id = (SCMStructId)iBuffer.Ptr()[iReader.CurrentPosition()];
376 if(id != ESCMRawData)
378 User::Leave(KErrCorrupt);
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);
385 //reset reader to where the raw data starts again
386 iReader.SetPosition(aPos);
388 //now we know we have room, deserialize into this descriptor
390 data->iData.Set(aRawBuf.MidTPtr(0));
391 User::LeaveIfError(data->Deserialize(aStartRawPosition, iReader));
399 * This is a helper function to convert between the two formats of register
400 * @param aRegVal Resulting register values
402 void TCrashLogWalker::HelpAssignRegisterToContext(const TRegisterValue& aRegVal)
404 //only interested in core registers at the moment
405 if(aRegVal.iClass != 0 || aRegVal.iSize != 2)
410 //Is there a cleverer way to do this with bitmasks and FOFF ?
411 switch(aRegVal.iType)
415 iContext.iR0 = aRegVal.iValue32;
420 iContext.iR1 = aRegVal.iValue32;
425 iContext.iR2 = aRegVal.iValue32;
430 iContext.iR3 = aRegVal.iValue32;
435 iContext.iR4 = aRegVal.iValue32;
440 iContext.iR5 = aRegVal.iValue32;
445 iContext.iR6 = aRegVal.iValue32;
450 iContext.iR7 = aRegVal.iValue32;
455 iContext.iR8 = aRegVal.iValue32;
460 iContext.iR9 = aRegVal.iValue32;
465 iContext.iR10 = aRegVal.iValue32;
470 iContext.iR11 = aRegVal.iValue32;
475 iContext.iR12 = aRegVal.iValue32;
480 iContext.iR13 = aRegVal.iValue32;
485 iContext.iR14 = aRegVal.iValue32;
490 iContext.iR15 = aRegVal.iValue32;
495 iContext.iCpsr = aRegVal.iValue32;
500 iContext.iR13Svc = aRegVal.iValue32;
505 iContext.iR14Svc = aRegVal.iValue32;
516 * Getter for crash header
519 const TCrashInfoHeader& TCrashLogWalker::GetCrashHeader() const
525 * Getter for crash offsets header
528 const TCrashOffsetsHeader& TCrashLogWalker::GetOffsetsHeader() const