Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h)
Have multiple extension sections in the bld.inf, one for each version
of the compiler. The RVCT version building the tools will build the
runtime libraries for its version, but make sure we extract all the other
versions from zip archives. Also add the archive for RVCT4.
// 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