--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tracesrv/tracecore/btrace_handler/test/tracedataparser/src/tracedataparser.cpp Fri Oct 08 14:56:39 2010 +0300
@@ -0,0 +1,2403 @@
+// Copyright (c) 2005-2010 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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:
+// Trace Data parser
+//
+
+#include <e32svr.h>
+#include <e32def.h>
+#include <e32def_private.h>
+#include <e32btrace.h>
+
+#include "tracedataparser.h"
+#include "testdatawriternotifier.h"
+#include "tracecoreconstants.h"
+#include "d32tracebuffer.h"
+
+
+EXPORT_C TUint32 TTraceDataParser::Swap(TUint32 x)
+ {
+ return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24);
+ }
+
+EXPORT_C TUint32 TTraceDataParser::ReadUint32FromBuf(TUint8*& aBuf, TBool aFromTestWriter)
+ {
+#ifdef __WINS__
+ aFromTestWriter = EFalse;
+#endif
+ // reads a 4 byte integer of expected endianess
+ TUint32 n;
+ if (!aFromTestWriter)
+ {
+ n = *(aBuf+3) + (*(aBuf+2) << 8) + (*(aBuf+1) << 16) + (*aBuf << 24);
+ }
+ else
+ {
+ // endianess order is reversed for TestWriter on hw
+ n = (*aBuf) + (*(aBuf+1) << 8) + (*(aBuf+2) << 16) + (*(aBuf+3) << 24);
+ }
+ aBuf += sizeof(TUint32);
+ return n;
+ }
+
+EXPORT_C TUint16 TTraceDataParser::ReadUint16FromBuf(TUint8*& aBuf)
+ {
+ // reads a 2 byte integer of expected endianess
+ TUint16 n = (*aBuf << 8)+ (*(aBuf+1));
+ aBuf += sizeof(TUint16);
+ return n;
+ }
+
+TPtr8 TTraceDataParser::ReadTracePrintf(TUint8* aData, TInt aSize)
+ {
+ TPtr8 printfString(aData, aSize, aSize);
+ TInt endPosition = printfString.Locate(TChar(0));
+ if (endPosition >= 0)
+ {
+ printfString = printfString.Left(endPosition);
+ }
+ else
+ {
+ printfString.Trim();
+ }
+ return printfString;
+ }
+
+TBool TTraceDataParser::StringsMatch(const TDesC8& aString1, const TDesC8& aString2)
+ {
+ TInt compareLength = (aString1.Length() > aString2.Length()) ? aString2.Length() : aString1.Length();
+ if ( (aString2.Left(compareLength).Compare(aString1) == 0) ||
+ (aString1.Left(compareLength).Compare(aString2) == 0) )
+ {
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+/**
+ * Function to string for a number
+ * @param aBuffer Trace data descriptor
+ * @param aFindStringPattern Pattern that indicates where in the string the number will be, using an asterisk
+ * @param aNumberFound If found, the number in the string
+ * @return Symbian error code
+ */
+TInt TTraceDataParser::ParseStringForNumber(const TDesC8& aBuffer, const TDesC8& aFindStringPattern, TInt& aNumberFound)
+ {
+ TInt err = KErrNotFound;
+ TInt posOfNum = aFindStringPattern.Locate('*');
+ TInt lengthOfNum = 1 + aBuffer.Length() - aFindStringPattern.Length();
+ if (posOfNum >= 0 && lengthOfNum >= 1)
+ {
+ TBuf<KMaxNumberBufferLength> numberBuffer;
+ numberBuffer.Copy(aBuffer.Mid(posOfNum, lengthOfNum));
+ TLex lex(numberBuffer);
+ err = lex.Val(aNumberFound);
+ }
+ return err;
+ }
+
+/*
+ * Validate the trace data in buffer
+ *
+ * @param aBuffer the buffer containing the trace data
+ * @param aExpectedNum expected number of traces
+ * @param aComponentID component ID of traces
+ * @param aGroupID group ID of traces
+ * @param aData first expected trace data
+ * @param aTraceWord trace word of traces
+ * @param aIdentical indicates that the payload of each trace packet should be identical
+ * @param aBufferMode The mode of the trace buffer.. 0=straight, 1=circular.
+ * @param aOrdinalData indicates whether the payload data reflects its position in the stream of trace packets
+ * @param aNumTraces number of traces written to circular buffer
+ * @param aMaxTraces maximum number of traces circular buffer can hold
+ * @return Standard Symbian error code
+ */
+EXPORT_C TInt TTraceDataParser::ValidatePayload(TDesC8& aBuffer,
+ TInt aExpectedNum,
+ TComponentId aComponentID,
+ TGroupId aGroupID,
+ TUint32 aData,
+ TUint32 aTraceWord,
+ TBool aIdentical,
+ TInt aBufferMode,
+ TBool aOrdinalData,
+ TInt aNumTraces,
+ TInt aMaxTraces)
+ {
+ if ((aBuffer.Length() == 0) && (aExpectedNum <= 0)) // size is zero and there should be no traces
+ {
+ return KErrNone;
+ }
+ if ((aBuffer.Length() == 0) && (aExpectedNum > 0)) // size is zero and there should be traces
+ {
+ return KErrCorrupt;
+ }
+ if (aBuffer.Length() != 0 && (aExpectedNum <= 0)) // size is non-zero and there should be no traces
+ {
+ return KErrCorrupt;
+ }
+
+ TUint32 lastData = aData;
+ TBool firstInStream = ETrue;
+
+ // get the current position on the stream of traces so we can determine what the payload value should be.
+ TInt overwrites = 0;
+ if (aBufferMode == RTraceBuffer::EFreeRunning)
+ {
+ TInt overwrittenTraces = aNumTraces; // initialise to number of traces we wrote to the buffer for circular test
+ while (overwrittenTraces > aMaxTraces)
+ {
+ overwrittenTraces = overwrittenTraces - aMaxTraces; // aMaxTraces is the max the buffer can hold
+ overwrites++;
+ }
+ lastData = (aMaxTraces * (overwrites - 1)) + overwrittenTraces + 1; // get where we are in the buffer
+ }
+
+ TInt numberOSTtraces = 0;
+ TUint8* data = (TUint8*) aBuffer.Ptr();
+ TUint8* endOfData = data + aBuffer.Size();
+ TUint8 testGID = aGroupID;
+ TUint32 testCID = aComponentID;
+ TUint32 testTraceWord = 0;
+
+ TTraceHeaderSettings traceHeaderSettings;
+
+ // Loop through all traces
+ while (data < endOfData)
+ {
+ // Get trace info from header
+ TInt err = ParseHeader(data, endOfData-data, traceHeaderSettings);
+
+ if (err != KErrNone)
+ {
+ return err;
+ }
+
+ //check the missing flag if we expect it
+ if ((firstInStream&&(overwrites>0)))
+ {
+ if(!(traceHeaderSettings.iHeaderFlags & BTrace::EMissingRecord))
+ {
+ return KErrCorrupt;
+ }
+ }
+
+ if (!traceHeaderSettings.iPrintfTrace)
+ {
+ testTraceWord = ((TUint32) (testGID << GROUPIDSHIFT)) + 1;
+
+ // check group ID
+ if (traceHeaderSettings.iCategory != testGID)
+ {
+ return KErrCorrupt;
+ }
+ // check component ID
+ if (traceHeaderSettings.iComponentID != testCID)
+ {
+ return KErrCorrupt;
+ }
+ // check trace word
+ if (traceHeaderSettings.iTraceWord != testTraceWord)
+ {
+ return KErrCorrupt;
+ }
+
+ TBool lastTrace = EFalse;
+ if ( (traceHeaderSettings.iMultiPartType == BTrace::EMultipartLast) || (!traceHeaderSettings.iMultiPartType) )
+ {
+ lastTrace = ETrue;
+ }
+
+ // check trace payload
+ for (TInt i=0; traceHeaderSettings.iLengthOfPayload>0; i++)
+ {
+ TUint32 param = Swap(ReadUint32FromBuf(data, traceHeaderSettings.iFromTestWriter));
+ // For circular case, we try to estimate to within +/- 2 where we are in payload
+ // for straight case we should get it exactly correct.
+ if ( ((param != lastData) && (aBufferMode == 0)) ||
+ ( ((param > lastData + 2) || (param < lastData - 2)) && (aBufferMode == RTraceBuffer::EFreeRunning) ) )
+ {
+ return KErrCorrupt;
+ }
+ lastData = param; // in case we weren't accurate in circular case.
+ traceHeaderSettings.iLengthOfPayload -= 4;
+ lastData++;
+ }
+ lastData = (!aOrdinalData)? aData : lastData;
+ if (!aOrdinalData)
+ {
+ lastData = (lastTrace || aIdentical) ? aData : lastData;
+ }
+
+ if (traceHeaderSettings.iMultiPartType || aIdentical || aOrdinalData)
+ {
+ testGID = aGroupID;
+ testCID = aComponentID;
+ testTraceWord = aTraceWord;
+ }
+ else
+ {
+ testGID++;
+ testCID++;
+ testTraceWord += (1 << GROUPIDSHIFT);
+ }
+ numberOSTtraces++;
+ }
+ else
+ {
+ // Go to the next trace
+ data += traceHeaderSettings.iLengthOfPayload;
+ }
+ firstInStream = EFalse; //after this, it's defnitely not the first trace in the stream.
+ }
+
+ // Check that we're getting the correct number of traces
+ //or approximate ammount (+/-1) for circular buffer because
+ //the arithmetic to overwrite traces sometimes also skips one
+ //extra trace
+
+ if (numberOSTtraces != aExpectedNum)
+ {
+ if ((aBufferMode==RTraceBuffer::EFreeRunning)
+ &&((numberOSTtraces>=aExpectedNum-1)||(numberOSTtraces<=aExpectedNum+1)))
+ {
+ return KErrNone;
+ }
+ return KErrCorrupt;
+ }
+
+ return KErrNone;
+ }
+
+/*
+ * Validate the single trace data in buffer
+ *
+ * @param aBuffer the buffer containing the trace data
+ * @param aTracePresent determines if trace data should be present or not
+ * @param aGroupID expected GID
+ * @param aComponentID expected CID
+ * @param aData expected trace data
+ * @param aPrintfTrace determines if trace data should be printf data or not
+ * @param aMissingTrace determines if trace data should indicate missing data or not
+ * @param aExpectedPrintfTrace expected printf trace data
+ * @return Standard Symbian error code
+ */
+EXPORT_C TInt TTraceDataParser::ValidatePayload(TDesC8& aBuffer,
+ TBool aTracePresent,
+ TGroupId aGroupID,
+ TComponentId aComponentID,
+ TUint32 aData,
+ TBool aPrintfTrace,
+ TBool aMissingTrace,
+ TDesC8* aExpectedPrintfTrace)
+ {
+ if ((aBuffer.Length() == 0) && (!aTracePresent)) // size is zero and there should be no traces
+ {
+ return KErrNone;
+ }
+ if ((aBuffer.Length() == 0) && (aTracePresent)) // size is zero and there should be traces
+ {
+ return KErrCorrupt;
+ }
+ if (aBuffer.Length() != 0 && (!aTracePresent)) // size is non-zero and there should be no traces
+ {
+ return KErrCorrupt;
+ }
+
+ TUint8* data = (TUint8*) aBuffer.Ptr();
+ TUint8* endOfData = data + aBuffer.Size();
+
+ TTraceHeaderSettings traceHeaderSettings;
+
+ // Get trace info from header
+ TInt err = ParseHeader(data, endOfData-data, traceHeaderSettings);
+
+ if (err != KErrNone)
+ {
+ return err;
+ }
+
+ // check trace type
+ if (traceHeaderSettings.iPrintfTrace != aPrintfTrace)
+ {
+ return KErrCorrupt;
+ }
+
+ if (!traceHeaderSettings.iPrintfTrace)
+ {
+ TUint32 testTraceWord = ((TUint32) (aGroupID << GROUPIDSHIFT)) + 1;
+
+ // check group ID
+ if (traceHeaderSettings.iCategory != aGroupID)
+ {
+ return KErrCorrupt;
+ }
+ // check component ID
+ if (traceHeaderSettings.iComponentID != aComponentID)
+ {
+ return KErrCorrupt;
+ }
+ // check trace word
+ if (traceHeaderSettings.iTraceWord != testTraceWord)
+ {
+ return KErrCorrupt;
+ }
+
+ if (aMissingTrace)
+ {
+ // check missing flag
+ if (!(traceHeaderSettings.iHeaderFlags & BTrace::EMissingRecord))
+ {
+ return KErrCorrupt;
+ }
+ }
+
+ TInt i = 0;
+ while (data < endOfData)
+ {
+ TUint32 param = Swap(ReadUint32FromBuf(data, traceHeaderSettings.iFromTestWriter));
+ if (param != aData + i)
+ {
+ return KErrCorrupt;
+ }
+ i++;
+ }
+ }
+ else if (!aExpectedPrintfTrace)
+ {
+ return KErrArgument;
+ }
+ else
+ {
+ TBuf8<KExpectedPrintfMaxLength> expectedPrintf;
+
+ // In the case of an expected dropped trace, we only check for "* Dropped Trace" because
+ // the test writer has completed the request for data when it writes that bit first (right
+ // before the next trace), and when it goes to write the actual trace, it doesn't.
+ // If we change this, the "* Dropped Trace" will be overwritten by the actual trace before
+ // the test can check it, since the test writer doesn't buffer trace data.
+ if (aMissingTrace)
+ {
+ // check that "* Dropped Trace" is in the buffer
+ expectedPrintf = KDroppedTrace;
+ }
+ else
+ {
+ // check that "Test Printf Trace" is in the buffer"
+ expectedPrintf = *aExpectedPrintfTrace;
+ }
+
+ expectedPrintf.Append(TChar(0)); // printf handler appends null at the end.
+
+ TPtrC8 actualprintf(data, traceHeaderSettings.iLengthOfPayload);
+
+ // Need to fix endianess for hw
+#ifndef __WINS__
+ TInt bufpos = 0;
+ while (bufpos < (actualprintf.Length()-4))
+ {
+ // reads a 4 byte integer of expected endianess
+ TUint32 n = actualprintf[bufpos] + (actualprintf[bufpos+1] << 8) + (actualprintf[bufpos+2] << 16) + (actualprintf[bufpos+3] << 24);
+ bufpos += sizeof(TUint32);
+ TUint32 tempData = Swap(n);
+ memcpy((TAny*)(actualprintf.Ptr()+bufpos-4),(TAny*)&tempData, sizeof(TUint32));
+ }
+#endif //__WINS__
+
+ if (expectedPrintf.Compare(actualprintf) != 0)
+ {
+ return KErrCorrupt;
+ }
+
+ // Check if there is another trace to follow
+ data += traceHeaderSettings.iLengthOfPayload;
+ if (data != endOfData)
+ {
+ TPtrC8 buffer(data, endOfData - data);
+
+ return ValidatePayload(buffer,
+ aTracePresent,
+ aGroupID,
+ aComponentID,
+ aData,
+ aPrintfTrace,
+ EFalse,
+ aExpectedPrintfTrace);
+ }
+ }
+ return KErrNone;
+ }
+
+/*
+ * Verify the priming data contains all the expected values
+ *
+ * @param aBuffer Buffer containing the trace data
+ * @param aSize Size of the trace buffer
+ * @param aCategory BTrace category of the trace data
+ * @param aSubCategory BTrace subcategory of the trace data
+ * @param aElementsFound Parameter to hold current state of expected data found so far
+ * @param aVerificationData1 Optional input value - used differently for different categories
+ * @param aVerificationData2 Optional input value - used differently for different categories
+ * @return Standard Symbian error code
+ */
+TInt TTraceDataParser::VerifyPrimingData(TUint8* aBuffer,
+ TInt aSize,
+ TUint8 aCategory,
+ TUint8 aSubCategory,
+ TInt& aElementsFound,
+ TBool aFromTestWriter,
+ TUint32 aVerificationData1,
+ TUint32 aVerificationData2)
+ {
+ TInt err = KErrNotSupported;
+ switch(aCategory)
+ {
+ case BTrace::EThreadIdentification:
+ err = VerifyThreadPrimingData(aBuffer, aSize, aSubCategory, aElementsFound, aFromTestWriter, aVerificationData1, aVerificationData2);
+ break;
+ case BTrace::EFastMutex:
+ err = VerifyFastMutexPrimingData(aBuffer, aSize, aSubCategory, aElementsFound, aFromTestWriter);
+ break;
+ case BTrace::ECodeSegs:
+ err = VerifyCodeSegsPrimingData(aBuffer, aSize, aSubCategory, aElementsFound, aFromTestWriter, aVerificationData1, aVerificationData2);
+ break;
+ default:
+ break;
+ }
+ return err;
+ }
+
+/*
+ * Verify the EThreadIdentification priming data contains all the expected values
+ *
+ * @param aBuffer Buffer containing the trace data
+ * @param aSize Size of the trace buffer
+ * @param aSubCategory BTrace subcategory of the trace data
+ * @param aElementsFound Parameter to hold current state of expected data found so far
+ * @param aThreadAddr The address of the thread to search for
+ * @param aProcessAddr The address of the process to search for
+ * @return Standard Symbian error code
+ */
+TInt TTraceDataParser::VerifyThreadPrimingData(TUint8* aBuffer,
+ TInt aSize,
+ TUint8 aSubCategory,
+ TInt& aElementsFound,
+ TBool aFromTestWriter,
+ TUint32 aThreadAddr,
+ TUint32 aProcessAddr)
+ {
+ RThread currentThread;
+ RProcess currentProcess;
+
+ TUint32 tempThreadAddr;
+ TUint32 tempProcessAddr;
+
+ switch(aSubCategory)
+ {
+ case BTrace::EProcessCreate:
+ {
+ tempProcessAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter));
+ if (tempProcessAddr == aProcessAddr)
+ {
+ aElementsFound |= 0x000000ff;
+ }
+ }
+ break;
+
+ case BTrace::EProcessName:
+ {
+ tempThreadAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter));
+ tempProcessAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter));
+ if ( (tempThreadAddr == aThreadAddr) && (tempProcessAddr == aProcessAddr) )
+ {
+ TBuf8<KMaxName> currentProcessName;
+ currentProcessName.Copy(currentProcess.Name());
+ TPtr8 processName(aBuffer,(aSize-8),(aSize-8)); //should be name of the process
+ processName.Trim();
+ if (StringsMatch(currentProcessName, processName))
+ {
+ aElementsFound |= 0x0000ff00;
+ }
+ }
+ }
+ break;
+
+ case BTrace::EThreadName:
+ {
+ tempThreadAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter));
+ tempProcessAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter));
+ if ( (tempThreadAddr == aThreadAddr) && (tempProcessAddr == aProcessAddr) )
+ {
+ TBuf8<KMaxName> currentThreadName;
+ currentThreadName.Copy(currentThread.Name());
+ TPtr8 threadName(aBuffer,(aSize-8),(aSize-8)); //should be name of the thread
+ threadName.Trim();
+ if (StringsMatch(currentThreadName, threadName))
+ {
+ aElementsFound |= 0x00ff0000;
+ }
+ }
+ }
+ break;
+
+ case BTrace::EThreadId:
+ {
+ tempThreadAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter));
+ tempProcessAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter));
+ if ( (tempThreadAddr == aThreadAddr) && (tempProcessAddr == aProcessAddr) )
+ {
+ TThreadId threadId = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter));
+ if (currentThread.Id() == threadId)
+ {
+ aElementsFound |= 0xff000000;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ TInt err = KErrNotFound;
+ if (aElementsFound == 0xffffffff)
+ {
+ err = KErrNone;
+ }
+ return err;
+ }
+
+/*
+ * Verify the EFastMutex priming data contains all the expected values
+ *
+ * @param aBuffer Buffer containing the trace data
+ * @param aSize Size of the trace buffer
+ * @param aSubCategory BTrace subcategory of the trace data
+ * @param aElementsFound Parameter to hold current state of expected data found so far
+ * @return Standard Symbian error code
+ */
+TInt TTraceDataParser::VerifyFastMutexPrimingData(TUint8* aBuffer,
+ TInt aSize,
+ TUint8 aSubCategory,
+ TInt& aElementsFound,
+ TBool aFromTestWriter)
+ {
+ if (aSubCategory == BTrace::EFastMutexName)
+ {
+ TUint32 fastMutexId = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter));
+ TUint32 unspecified = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter));
+ if (fastMutexId && !unspecified)
+ {
+ TPtr8 fastMutexName(aBuffer,(aSize-8),(aSize-8)); //should be name of the fast mutex
+ fastMutexName.Trim();
+ if (StringsMatch(KFastMutexNameSystemLock(), fastMutexName))
+ {
+ aElementsFound |= 0x000000ff;
+ }
+ else if (StringsMatch(KFastMutexNameMsgLock(), fastMutexName))
+ {
+ aElementsFound |= 0x0000ff00;
+ }
+ else if (StringsMatch(KFastMutexNameObjLock(), fastMutexName))
+ {
+ aElementsFound |= 0x00ff0000;
+ }
+ else if (StringsMatch(KFastMutexNameLogonLock(), fastMutexName))
+ {
+ aElementsFound |= 0xff000000;
+ }
+ }
+ }
+
+ TInt err = KErrNotFound;
+ if (aElementsFound == 0xffffffff)
+ {
+ err = KErrNone;
+ }
+ return err;
+ }
+
+/*
+ * Verify the ECodeSegs priming data contains all the expected values
+ *
+ * @param aBuffer Buffer containing the trace data
+ * @param aSize Size of the trace buffer
+ * @param aSubCategory BTrace subcategory of the trace data
+ * @param aElementsFound Parameter to hold current state of expected data found so far
+ * @param aSegAddr1 The address of the first code seg to search for
+ * @param aSegAddr2 The address of the second code seg to search for
+ * @return Standard Symbian error code
+ */
+TInt TTraceDataParser::VerifyCodeSegsPrimingData(TUint8* aBuffer,
+ TInt aSize,
+ TUint8 aSubCategory,
+ TInt& aElementsFound,
+ TBool aFromTestWriter,
+ TUint32 aSegAddr1,
+ TUint32 aSegAddr2)
+ {
+ TUint32 codeSegAddr;
+ if (aSubCategory == BTrace::ECodeSegCreated)
+ {
+ codeSegAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter));
+ if (codeSegAddr == aSegAddr1 || codeSegAddr == aSegAddr2)
+ {
+ TPtr8 codeSegName(aBuffer,(aSize-4),(aSize-4)); //should be name of the code seg
+ codeSegName.Trim();
+ if (codeSegAddr == aSegAddr1 && StringsMatch(KCodeSegsName1(), codeSegName))
+ {
+ aElementsFound |= 0x000000ff;
+ }
+ else if (codeSegAddr == aSegAddr2 && StringsMatch(KCodeSegsName2(), codeSegName))
+ {
+ aElementsFound |= 0x0000ff00;
+ }
+ }
+ }
+ else if (aSubCategory == BTrace::ECodeSegInfo)
+ {
+ codeSegAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter));
+ if (codeSegAddr == aSegAddr1)
+ {
+ aElementsFound |= 0x00ff0000;
+ }
+ else if (codeSegAddr == aSegAddr2)
+ {
+ aElementsFound |= 0xff000000;
+ }
+ }
+
+ TInt err = KErrNotFound;
+ if (aElementsFound == 0xffffffff)
+ {
+ err = KErrNone;
+ }
+ return err;
+ }
+
+/*
+ * Work out if a trace point is potentially kernel priming data based on category and subcategory
+ *
+ * @param aCategory BTrace category of the trace data
+ * @param aSubCategory BTrace subcategory of the trace data
+ * @param aIsPotentialPrimingTrace Output value set if there is no error
+ * @return Standard Symbian error code
+ */
+TBool TTraceDataParser::IsPotentialPrimingTrace(TUint8 aCategory, TUint8 aSubCategory, TBool& aIsPotentialPrimingTrace)
+ {
+ TInt err = KErrNone;
+
+ switch(aCategory)
+ {
+ case BTrace::EThreadIdentification:
+ {
+ switch(aSubCategory)
+ {
+ case BTrace::EProcessCreate:
+ case BTrace::EProcessName:
+ case BTrace::EThreadName:
+ case BTrace::EThreadId:
+ aIsPotentialPrimingTrace = ETrue;
+ break;
+ default:
+ aIsPotentialPrimingTrace = EFalse;
+ break;
+ }
+ }
+ break;
+ case BTrace::ECpuUsage:
+ {
+ switch(aSubCategory)
+ {
+ case BTrace::ENewThreadContext:
+ aIsPotentialPrimingTrace = ETrue;
+ break;
+ default:
+ aIsPotentialPrimingTrace = EFalse;
+ break;
+ }
+ }
+ break;
+ case BTrace::EChunks:
+ {
+ switch(aSubCategory)
+ {
+ case BTrace::EChunkCreated:
+ case BTrace::EChunkOwner:
+ case BTrace::EChunkInfo:
+ aIsPotentialPrimingTrace = ETrue;
+ break;
+ default:
+ aIsPotentialPrimingTrace = EFalse;
+ break;
+ }
+ }
+ break;
+ case BTrace::ECodeSegs:
+ {
+ switch(aSubCategory)
+ {
+ case BTrace::ECodeSegCreated:
+ case BTrace::ECodeSegInfo:
+ aIsPotentialPrimingTrace = ETrue;
+ break;
+ default:
+ aIsPotentialPrimingTrace = EFalse;
+ break;
+ }
+ }
+ break;
+ case BTrace::EPaging:
+ {
+ switch(aSubCategory)
+ {
+ case BTrace::EPagingMemoryModel:
+ aIsPotentialPrimingTrace = ETrue;
+ break;
+ default:
+ aIsPotentialPrimingTrace = EFalse;
+ break;
+ }
+ }
+ break;
+ case BTrace::EThreadPriority:
+ {
+ switch(aSubCategory)
+ {
+ case BTrace::EProcessPriority:
+ case BTrace::EDThreadPriority:
+ case BTrace::ENThreadPriority:
+ aIsPotentialPrimingTrace = ETrue;
+ break;
+ default:
+ aIsPotentialPrimingTrace = EFalse;
+ break;
+ }
+ }
+ break;
+ case BTrace::EFastMutex:
+ {
+ switch(aSubCategory)
+ {
+ case BTrace::EFastMutexName:
+ aIsPotentialPrimingTrace = ETrue;
+ break;
+ default:
+ aIsPotentialPrimingTrace = EFalse;
+ break;
+ }
+ }
+ break;
+ case BTrace::ESymbianKernelSync:
+ {
+ switch(aSubCategory)
+ {
+ case BTrace::EMutexCreate:
+ case BTrace::ESemaphoreCreate:
+ case BTrace::ECondVarCreate:
+ aIsPotentialPrimingTrace = ETrue;
+ break;
+ default:
+ aIsPotentialPrimingTrace = EFalse;
+ break;
+ }
+ }
+ break;
+ case BTrace::EClientServer:
+ {
+ switch(aSubCategory)
+ {
+ case BTrace::EServerCreate:
+ case BTrace::ESessionAttach:
+ aIsPotentialPrimingTrace = ETrue;
+ break;
+ default:
+ aIsPotentialPrimingTrace = EFalse;
+ break;
+ }
+ }
+ break;
+ default:
+ err = KErrNotSupported;
+ break;
+ }
+
+ return err;
+ }
+
+/*
+ * If the next trace is a meta trace true is returned if it is the start of priming data for a given group ID
+ *
+ * @param aBuffer Buffer containing the trace data
+ * @param aGroupId Group ID of kernel priming data
+ * @param aCategory BTrace category of the current trace
+ * @param aSubCategory BTrace subcategory of the current trace
+ * @return True if start of priming data for given group ID, false otherwise
+ */
+TBool TTraceDataParser::IsStartOfKernelPrimingBatch(TUint8* aBuffer, TGroupId aGroupId, TUint8 aCategory, TUint8 aSubCategory)
+ {
+ TBool startOfBatch = EFalse;
+ if (aCategory == BTrace::EMetaTrace)
+ {
+ if (aSubCategory == BTrace::EMetaTraceFilterChange)
+ {
+ TUint8 metaCategory = aBuffer[0];
+ TUint8 isActive = aBuffer[1];
+ if (metaCategory == aGroupId && isActive)
+ {
+ startOfBatch = ETrue;
+ }
+ }
+ }
+ return startOfBatch;
+ }
+
+/*
+ * Use heuristics to work out if current trace is part of kernel priming data
+ *
+ * @param aCategory BTrace category of the trace data
+ * @param aSubCategory BTrace subcategory of the trace data
+ * @param aTimeDifference Time difference (in microseconds) since last trace for given category
+ * @param aIsInPrimingBatch Output parameter set to true if in priming data
+ * @param aFirstTrace Boolean used to indicate if this is first trace (so there is no valid time difference)
+ * @param aStartOfBatch Output parameter set to true if start of batch of kernel priming data
+ * @return Standard Symbian error code
+ */
+TInt TTraceDataParser::IsInPrimingBatch(TUint8 aCategory,
+ TUint8 aSubCategory,
+ TUint32 aTimeDifference,
+ TBool& aIsInPrimingBatch,
+ TBool& aFirstTrace,
+ TBool& aStartOfBatch)
+ {
+ TBool isPotentialPrimingTrace = EFalse;
+ TInt err = IsPotentialPrimingTrace(aCategory, aSubCategory, isPotentialPrimingTrace);
+
+ // Look at timestamp to see if this is a new batch of traces
+ if (aFirstTrace)
+ {
+ aFirstTrace = EFalse;
+ }
+ else if (aTimeDifference > KMinMilliSecondsBatchGap * 1000)
+ {
+ aStartOfBatch = ETrue;
+ aIsInPrimingBatch = EFalse;
+ }
+ else
+ {
+ aStartOfBatch = EFalse;
+ }
+
+ if (isPotentialPrimingTrace && aStartOfBatch)
+ {
+ aIsInPrimingBatch = ETrue;
+ aStartOfBatch = EFalse;
+ }
+ else if (!isPotentialPrimingTrace)
+ {
+ aIsInPrimingBatch = EFalse;
+ }
+
+ return err;
+ }
+
+/*
+ * Parse the trace data header
+ *
+ * The following trace types are supported:
+ * OST traces (ascii and binary)
+ * XTIv3 traces (ascii and binary)
+ * Traces from the Test Writer (ascii and binary)
+ *
+ * @param aData Buffer containing the trace data
+ * @param aSize Size of trace data buffer
+ * @param aTraceHeaderSettings Output parameters set to header settings of the trace data
+ * @return Standard Symbian error code
+ */
+TInt TTraceDataParser::ParseHeader(TUint8*& aData,
+ TInt aSize,
+ TTraceHeaderSettings& aTraceHeaderSettings)
+ {
+ // Check buffer is large enough to contain header
+ aSize--;
+ if (aSize < 0)
+ {
+ return KErrOverflow;
+ }
+
+ TInt err = KErrNone;
+ TUint8* startOfData = aData;
+ aTraceHeaderSettings.iMultiPartType = 0;
+ aTraceHeaderSettings.iMultiPartTraceID = 0;
+ aTraceHeaderSettings.iPrintfTrace = EFalse;
+ aTraceHeaderSettings.iHeaderFlags = EFalse;
+ aTraceHeaderSettings.iFromTestWriter = EFalse;
+ TBool xtiTrace = EFalse;
+ TUint8 version = aData[0]; // Version (1 byte)
+ aData++;
+
+ if (version == KXtiHeaderVersion)
+ {
+ // Check buffer is large enough to contain header
+ aSize -= KMinSizeXtiHeader;
+ if (aSize < 0)
+ {
+ aData = startOfData;
+ return KErrOverflow;
+ }
+ xtiTrace = ETrue;
+ TUint8 xtiTraceType = aData[KXtiTraceTypeIndex-1];
+ if (xtiTraceType != KXtiProtocolIdSimpleTrace)
+ {
+ aTraceHeaderSettings.iPrintfTrace = ETrue;
+ aTraceHeaderSettings.iLengthOfPayload = aData[KXtiLengthIndex-1] - 15;
+ aData += KMinSizeXtiHeader;
+ }
+ else
+ {
+ // Check buffer is large enough to contain header
+ aSize -= 1;
+ if (aSize < 0)
+ {
+ aData = startOfData;
+ return KErrOverflow;
+ }
+ // Jump to start of OST buffer
+ aData += KMinSizeXtiHeader + 1;
+ version = aData[0];
+ aData++;
+ }
+ }
+
+ if (version == KHeaderVersion) // Ost header version byte is correct
+ {
+ // Check buffer is large enough to contain header
+ aSize -= KMinSizeOstHeader;
+ if (aSize < 0)
+ {
+ aData = startOfData;
+ return KErrOverflow;
+ }
+ const TUint8 protocolId = aData[0]; // Protocol ID (1 byte)
+ aData++;
+ if (xtiTrace)
+ {
+ aTraceHeaderSettings.iLengthOfPayload = aData[0];
+ aData++;
+ aSize++;
+ }
+ else
+ {
+ aTraceHeaderSettings.iLengthOfPayload = ReadUint16FromBuf(aData); // Size (2 bytes)
+ }
+
+ if (protocolId == KProtocolIdSimpleTrace) // Normal binary data
+ {
+ // Check buffer is large enough to contain header
+ aSize -= KMinSizeOstBinaryHeader;
+ if (aSize < 0)
+ {
+ aData = startOfData;
+ return KErrOverflow;
+ }
+ ReadUint32FromBuf(aData); // Timestamp 1 (4 bytes)
+ aTraceHeaderSettings.iTimestamp = ReadUint32FromBuf(aData); // Timestamp 2 (4 bytes)
+ }
+ else if (protocolId == KProtocolIdAscii) // Ascii Printf data
+ {
+ aTraceHeaderSettings.iPrintfTrace = ETrue;
+ // Check buffer is large enough to contain header
+ aSize -= KMinSizeOstAsciiHeader;
+ if (aSize < 0)
+ {
+ aData = startOfData;
+ return KErrOverflow;
+ }
+ aData += 8;
+ aTraceHeaderSettings.iLengthOfPayload -= 8;
+ }
+ else // Protocol ID is incorrect
+ {
+ err = KErrCorrupt;
+ }
+ }
+ else if (version == SYMBIAN_TRACE) // Trace data is binary data from Test Writer
+ {
+ aTraceHeaderSettings.iFromTestWriter = ETrue;
+ }
+ else if (version == PRINTF_TRACE) // Trace data is ascii data from Test Writer
+ {
+ aTraceHeaderSettings.iFromTestWriter = ETrue;
+ aTraceHeaderSettings.iPrintfTrace = ETrue;
+ // The end of the printf trace data will have null char, so use that to find end of payload
+ TPtr8 printfString(aData, aSize, aSize);
+ aTraceHeaderSettings.iLengthOfPayload = printfString.Locate(TChar(0));
+ if (aTraceHeaderSettings.iLengthOfPayload >= 0)
+ {
+ aTraceHeaderSettings.iLengthOfPayload++;
+ }
+ else
+ {
+ err = KErrCorrupt;
+ }
+ }
+ else if (version != KXtiHeaderVersion)
+ {
+ err = KErrCorrupt;
+
+ if(aTraceHeaderSettings.iLengthOfPayload < 0 )
+ {
+ err = KErrOverflow;
+ }
+ }
+
+ if (aTraceHeaderSettings.iPrintfTrace)
+ {
+ aTraceHeaderSettings.iTimestamp = 0;
+ aTraceHeaderSettings.iComponentID = 0;
+ aTraceHeaderSettings.iCategory = 0;
+ aTraceHeaderSettings.iSubCategory = 0;
+ aTraceHeaderSettings.iTraceWord = 0;
+ }
+ else if (err == KErrNone)
+ {
+ // Check buffer is large enough to contain header
+ aSize -= KMinSizeBinaryHeader;
+ if (aSize < 0)
+ {
+ aData = startOfData;
+ return KErrOverflow;
+ }
+ aTraceHeaderSettings.iComponentID = ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter); // ComponentId (4 bytes)
+ aTraceHeaderSettings.iTraceWord = ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter); // GroupId (2 bytes). TraceId (2 bytes)
+
+ TUint8* startOfPayload = aData;
+ TUint8 size;
+
+ TBool testWriterHwData = EFalse;
+#ifndef __WINS__
+ testWriterHwData = aTraceHeaderSettings.iFromTestWriter;
+#endif
+
+ // now look at BTrace header and payload.
+ if (!testWriterHwData)
+ {
+ size = aData[BTrace::ESizeIndex];
+ aTraceHeaderSettings.iHeaderFlags = aData[BTrace::EFlagsIndex];
+ aTraceHeaderSettings.iCategory = aData[BTrace::ECategoryIndex];
+ aTraceHeaderSettings.iSubCategory = aData[BTrace::ESubCategoryIndex];
+ }
+ else
+ {
+ // endianess order is reversed for TestWriter on hw
+ aTraceHeaderSettings.iSubCategory = aData[BTrace::ESizeIndex];
+ aTraceHeaderSettings.iCategory = aData[BTrace::EFlagsIndex];
+ aTraceHeaderSettings.iHeaderFlags = aData[BTrace::ECategoryIndex];
+ size = aData[BTrace::ESubCategoryIndex];
+ }
+
+ aData+=4;
+
+ //read header extensions
+ if(aTraceHeaderSettings.iHeaderFlags & BTrace::EHeader2Present)
+ {
+ // Check buffer is large enough to contain header
+ aSize -= 4;
+ if (aSize < 0)
+ {
+ aData = startOfData;
+ return KErrOverflow;
+ }
+ TUint32 header2 = Swap(ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter));
+ aTraceHeaderSettings.iMultiPartType = header2 & BTrace::EMultipartFlagMask;
+ }
+ if(aTraceHeaderSettings.iHeaderFlags & BTrace::ETimestampPresent)
+ {
+ // Check buffer is large enough to contain header
+ aSize -= 4;
+ if (aSize < 0)
+ {
+ aData = startOfData;
+ return KErrOverflow;
+ }
+ ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter);
+ }
+ if(aTraceHeaderSettings.iHeaderFlags & BTrace::ETimestamp2Present)
+ {
+ // Check buffer is large enough to contain header
+ aSize -= 4;
+ if (aSize < 0)
+ {
+ aData = startOfData;
+ return KErrOverflow;
+ }
+ ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter);
+ }
+ if(aTraceHeaderSettings.iHeaderFlags & BTrace::EContextIdPresent)
+ {
+ // Check buffer is large enough to contain header
+ aSize -= 4;
+ if (aSize < 0)
+ {
+ aData = startOfData;
+ return KErrOverflow;
+ }
+ ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter);
+ }
+ if(aTraceHeaderSettings.iHeaderFlags & BTrace::EPcPresent)
+ {
+ // Check buffer is large enough to contain header
+ aSize -= 4;
+ if (aSize < 0)
+ {
+ aData = startOfData;
+ return KErrOverflow;
+ }
+ ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter);
+ }
+ if(aTraceHeaderSettings.iHeaderFlags & BTrace::EExtraPresent)
+ {
+ // Check buffer is large enough to contain header
+ aSize -=4 ;
+ if (aSize < 0)
+ {
+ aData = startOfData;
+ return KErrOverflow;
+ }
+ aTraceHeaderSettings.iMultiPartTraceID = Swap(ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter));
+ }
+
+ if (!xtiTrace)
+ {
+ size = (size+3)&~3; // make it 4 byte aligned
+ }
+ if (size == 0)
+ {
+ // This happens when the trace is larger than maximum size, and we can't use the BTrace size field
+ // Instead calculate payload length based on size in OST header
+ aTraceHeaderSettings.iLengthOfPayload -= (aData-startOfPayload)+16; // size of rest of payload
+ }
+ else
+ {
+ aTraceHeaderSettings.iLengthOfPayload = size-(aData-startOfPayload); // size of rest of payload
+ }
+ }
+
+
+ // Check buffer is large enough to contain payload
+ aSize -= aTraceHeaderSettings.iLengthOfPayload;
+ if (aSize < 0)
+ {
+ aData = startOfData;
+ err = KErrOverflow;
+ }
+
+ return err;
+ }
+
+/*
+ * Get the data required to verify kernel priming traces for EThreadIdentification
+ *
+ * @param aBuffer Buffer containing the trace data
+ * @param aSize Size of the trace buffer
+ * @param aThreadAddr Output parameter set to address of current thread
+ * @param aProcessAddr Output parameter set to address of current process
+ * @return Standard Symbian error code
+ */
+TInt TTraceDataParser::GetThreadPrimingVerificationDataL(TUint8* aBuffer,
+ TInt aSize,
+ TUint32& aThreadAddr,
+ TUint32& aProcessAddr,
+ RFile* aFile)
+ {
+ TInt err = KErrNone;
+ TInt filePos = 0;
+ TUint8* data = NULL;
+ TUint8* startOfData = NULL;
+ TUint8* endOfData = NULL;
+ RBuf8 fileBuffer;
+
+ if (aFile)
+ {
+ // Create file buffer and read first chunk from file
+ err = CreateFileBuffer(fileBuffer, *aFile);
+ if (err != KErrNone)
+ {
+ return err;
+ }
+ fileBuffer.CleanupClosePushL();
+ err = ReadNextChunkFromFile(fileBuffer, *aFile, filePos, data, startOfData, endOfData);
+ if (err != KErrNone)
+ {
+ CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer
+ return err;
+ }
+ }
+ else
+ {
+ data = aBuffer;
+ startOfData = data;
+ endOfData = data + aSize;
+ }
+
+ TInt headerErr = KErrNone;
+ RThread currentThread;
+ TUint32 tempThreadAddr;
+ TUint32 tempProcessAddr;
+ TThreadId threadid = 0;
+
+ TTraceHeaderSettings traceHeaderSettings;
+
+ err = KErrGeneral;
+
+ while(data < endOfData)
+ {
+ headerErr = ParseHeader(data, endOfData-data, traceHeaderSettings);
+
+ if (aFile && headerErr == KErrOverflow)
+ {
+ // We don't have all the trace data, so read next chunk from file
+ headerErr = ReadNextChunkFromFile(fileBuffer, *aFile, filePos, data, startOfData, endOfData);
+ if (headerErr == KErrNone)
+ {
+ continue;
+ }
+ }
+ if (headerErr != KErrNone)
+ {
+ err = headerErr;
+ break;
+ }
+ if ( (traceHeaderSettings.iCategory == BTrace::EThreadIdentification) && (traceHeaderSettings.iSubCategory == BTrace::EThreadId) )
+ {
+ tempThreadAddr = Swap(ReadUint32FromBuf(data, traceHeaderSettings.iFromTestWriter));
+ tempProcessAddr = Swap(ReadUint32FromBuf(data, traceHeaderSettings.iFromTestWriter));
+ threadid = Swap(ReadUint32FromBuf(data, traceHeaderSettings.iFromTestWriter));
+ if (currentThread.Id() == threadid)
+ {
+ aThreadAddr = tempThreadAddr;
+ aProcessAddr = tempProcessAddr;
+ err = KErrNone;
+ break;
+ }
+ }
+ else
+ {
+ data += traceHeaderSettings.iLengthOfPayload; //go to next trace
+ }
+
+ if (aFile && data == endOfData)
+ {
+ // We might not have all the trace data, so read next chunk from file
+ headerErr = ReadNextChunkFromFile(fileBuffer, *aFile, filePos, data, startOfData, endOfData);
+ if (headerErr != KErrNone)
+ {
+ err = headerErr;
+ break;
+ }
+ }
+ }
+
+ if (aFile)
+ {
+ CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer
+ }
+
+ return err;
+ }
+
+
+/*
+ * Get the data required to verify kernel priming traces for ECodeSegs
+ *
+ * @param aBuffer Buffer containing the trace data
+ * @param aSize Size of the trace buffer
+ * @param aSegAddr1 Output parameter set to address of first code seg
+ * @param aSegAddr2 Output parameter set to address of second code seg
+ * @return Standard Symbian error code
+ */
+TInt TTraceDataParser::GetCodeSegsVerificationDataL(TUint8* aBuffer,
+ TInt aSize,
+ TUint32& aSegAddr1,
+ TUint32& aSegAddr2,
+ RFile* aFile)
+ {
+ TInt err = KErrNone;
+ TInt filePos = 0;
+ TUint8* data = NULL;
+ TUint8* startOfData = NULL;
+ TUint8* endOfData = NULL;
+ RBuf8 fileBuffer;
+
+ if (aFile)
+ {
+ // Create file buffer and read first chunk from file
+ err = CreateFileBuffer(fileBuffer, *aFile);
+ if (err != KErrNone)
+ {
+ return err;
+ }
+ fileBuffer.CleanupClosePushL();
+ err = ReadNextChunkFromFile(fileBuffer, *aFile, filePos, data, startOfData, endOfData);
+ if (err != KErrNone)
+ {
+ CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer
+ return err;
+ }
+ }
+ else
+ {
+ data = aBuffer;
+ startOfData = data;
+ endOfData = data + aSize;
+ }
+
+ TInt headerErr = KErrNone;
+ TUint32 tempSegAddr;
+
+ TTraceHeaderSettings traceHeaderSettings;
+
+ err = KErrGeneral;
+
+ while(data < endOfData)
+ {
+ headerErr = ParseHeader(data, endOfData-data, traceHeaderSettings);
+
+ if (aFile && headerErr == KErrOverflow)
+ {
+ // We don't have all the trace data, so read next chunk from file
+ headerErr = ReadNextChunkFromFile(fileBuffer, *aFile, filePos, data, startOfData, endOfData);
+ if (headerErr == KErrNone)
+ {
+ continue;
+ }
+ }
+ if (headerErr != KErrNone)
+ {
+ err = headerErr;
+ break;
+ }
+ if ( (traceHeaderSettings.iCategory == BTrace::ECodeSegs) && (traceHeaderSettings.iSubCategory == BTrace::ECodeSegCreated) )
+ {
+ tempSegAddr = Swap(ReadUint32FromBuf(data, traceHeaderSettings.iFromTestWriter));
+ traceHeaderSettings.iLengthOfPayload -= 4;
+ TPtr8 codeSegName(data,traceHeaderSettings.iLengthOfPayload,traceHeaderSettings.iLengthOfPayload); //should be name of the code seg
+ codeSegName.Trim();
+ if (StringsMatch(KCodeSegsName1(), codeSegName))
+ {
+ aSegAddr1 = tempSegAddr;
+ }
+ if (StringsMatch(KCodeSegsName2(), codeSegName))
+ {
+ aSegAddr2 = tempSegAddr;
+ }
+ if (aSegAddr1 != 0 && aSegAddr2 != 0)
+ {
+ err = KErrNone;
+ break;
+ }
+ }
+
+ data += traceHeaderSettings.iLengthOfPayload; //go to next trace
+
+ if (aFile && data == endOfData)
+ {
+ // We might not have all the trace data, so read next chunk from file
+ headerErr = ReadNextChunkFromFile(fileBuffer, *aFile, filePos, data, startOfData, endOfData);
+ if (headerErr != KErrNone)
+ {
+ err = headerErr;
+ break;
+ }
+ }
+ }
+
+ if (aFile)
+ {
+ CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer
+ }
+
+ return err;
+ }
+
+/*
+ * Get the data required to verify kernel priming traces
+ *
+ * @param aBuffer Buffer containing the trace data
+ * @param aSize Size of the trace buffer
+ * @param aGroupId Group ID of traces
+ * @param aVerificationData1 Output parameter set to first data required
+ * @param aVerificationData2 Output parameter set to second data required
+ * @return Standard Symbian error code
+ */
+TInt TTraceDataParser::GetPrimingVerificationDataL(TUint8* aBuffer,
+ TInt aSize,
+ TGroupId aGroupId,
+ TUint32& aVerificationData1,
+ TUint32& aVerificationData2,
+ RFile* aFile)
+ {
+ TInt err = KErrNone;
+ switch(aGroupId)
+ {
+ case BTrace::EThreadIdentification:
+ err = GetThreadPrimingVerificationDataL(aBuffer, aSize, aVerificationData1, aVerificationData2, aFile);
+ break;
+ case BTrace::ECodeSegs:
+ err = GetCodeSegsVerificationDataL(aBuffer, aSize, aVerificationData1, aVerificationData2, aFile);
+ break;
+ default:
+ break;
+ }
+ return err;
+ }
+
+/*
+ * Parse trace data for kernel priming data
+ *
+ * Note that this function can only verify priming data if the group ID is EThreadIdentification or EFastMutex,
+ * otherwise KErrNotSupported is returned if aVerifyData is ETrue
+ *
+ * @param aBuffer Buffer containing the trace data
+ * @param aGroupId Group ID of traces to parse
+ * @param aNumPrimingTraces Output parameter set to number of priming traces found for given group ID
+ * @param aNumTraces Output parameter set to total number of traces found for given group ID
+ * @param aVerifyData Flag indicating if priming data should be verified
+ * @param aVerificationData1 Optional first data required for verifying priming data
+ * @param aVerificationData1 Optional second data required for verifying priming data
+ * @return Standard Symbian error code
+ */
+EXPORT_C TInt TTraceDataParser::ParsePrimingDataL(TDesC8& aBuffer,
+ TGroupId aGroupId,
+ TInt& aNumPrimingTraces,
+ TInt& aNumTraces,
+ TBool aVerifyData,
+ TUint32 aVerificationData1,
+ TUint32 aVerificationData2)
+ {
+ aNumPrimingTraces = 0;
+ aNumTraces = 0;
+
+ TUint8* data = (TUint8*) aBuffer.Ptr();
+ TUint8* endOfData = data + aBuffer.Size();
+
+ // If the output data is to be verified but no verification data provided, try getting it automatically
+ if (aVerifyData && aVerificationData1 == 0 && aVerificationData2 == 0)
+ {
+ TInt err = GetPrimingVerificationDataL(data, endOfData-data, aGroupId, aVerificationData1, aVerificationData2);
+ if (err != KErrNone)
+ {
+ return err;
+ }
+ }
+
+ TInt returnErr = KErrNone;
+ TInt dataVerificationErr = KErrNone;
+ TInt generalErr = KErrNone;
+ TBool firstTrace = ETrue;
+ TBool startOfBatch = ETrue;
+ TBool inPrimingData = EFalse;
+ TBool useMetaTraces = EFalse;
+ TInt numPotentialPrimingTraces = 0;
+ TUint32 lastTimestamp = 0;
+ TInt elementsFound = 0;
+
+ TTraceHeaderSettings traceHeaderSettings;
+
+ // Loop through all traces
+ while (data < endOfData)
+ {
+ // Get trace info from header
+ generalErr = ParseHeader(data, endOfData-data, traceHeaderSettings);
+
+ if (generalErr != KErrNone)
+ {
+ if (returnErr == KErrNone)
+ {
+ // Set error to return, if this is first error so far
+ returnErr = generalErr;
+ }
+ break;
+ }
+
+ // If this is a meta trace, work out if it signifies start of kernel priming data for GID of interest
+ if (traceHeaderSettings.iCategory == BTrace::EMetaTrace)
+ {
+ useMetaTraces = ETrue;
+ startOfBatch = IsStartOfKernelPrimingBatch(data, aGroupId, traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory);
+ }
+
+ // This is a trace of the correct GID/CID
+ if ( (traceHeaderSettings.iComponentID == KKernelHooksOSTComponentUID) && (traceHeaderSettings.iCategory == aGroupId) )
+ {
+ // Increase the number of traces for this GID
+ aNumTraces++;
+
+ if (useMetaTraces)
+ {
+ // If data contains meta traces, work out if this is a priming trace
+ if (startOfBatch)
+ {
+ // This is the start of a batch of priming traces
+ inPrimingData = ETrue;
+ startOfBatch = EFalse;
+ }
+ if (inPrimingData)
+ {
+ // This is a priming trace, so increase number found for this GID
+ aNumPrimingTraces++;
+ // If data is to be verified, attempt the verification
+ if (aVerifyData)
+ {
+ dataVerificationErr = VerifyPrimingData(data, traceHeaderSettings.iLengthOfPayload, traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory, elementsFound, traceHeaderSettings.iFromTestWriter, aVerificationData1, aVerificationData2);
+ }
+ }
+ }
+ else
+ {
+ // If data contains no meta traces, work out if this is a priming trace using heuristics
+ generalErr = IsInPrimingBatch(traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory, traceHeaderSettings.iTimestamp-lastTimestamp, inPrimingData, firstTrace, startOfBatch);
+ if ( (generalErr != KErrNone) && (returnErr == KErrNone) )
+ {
+ // Set error to return, if this is first error so far
+ returnErr = generalErr;
+ }
+ lastTimestamp = traceHeaderSettings.iTimestamp;
+ if (inPrimingData)
+ {
+ // This is possibly a priming trace, so increase potential number found for this GID
+ numPotentialPrimingTraces++;
+ // If data is to be verified, attempt the verification
+ if (aVerifyData)
+ {
+ dataVerificationErr = VerifyPrimingData(data, traceHeaderSettings.iLengthOfPayload, traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory, elementsFound, traceHeaderSettings.iFromTestWriter, aVerificationData1, aVerificationData2);
+ }
+ }
+ else
+ {
+ // If we have enough potential priming traces, assume they are priming traces
+ if (numPotentialPrimingTraces >= KMinimumPrimingTracesInBatch)
+ {
+ aNumPrimingTraces += numPotentialPrimingTraces;
+ }
+ numPotentialPrimingTraces = 0;
+ }
+ }
+ }
+ else
+ {
+ // This is not a trace of the correct GID/CID
+ inPrimingData = EFalse;
+ }
+
+ // Go to the next trace
+ data+=traceHeaderSettings.iLengthOfPayload;
+ }
+
+ if (!useMetaTraces)
+ {
+ // If we have enough potential priming traces left over, assume they are priming traces
+ if (numPotentialPrimingTraces >= KMinimumPrimingTracesInBatch)
+ {
+ aNumPrimingTraces += numPotentialPrimingTraces;
+ }
+ }
+
+ if ( (dataVerificationErr != KErrNone) && (returnErr == KErrNone) )
+ {
+ // Set error to return, if this is first error so far
+ returnErr = dataVerificationErr;
+ }
+ return returnErr;
+ }
+
+/*
+ * Parse trace data for kernel priming data
+ *
+ * Note that this function can only verify priming data if the group ID is EThreadIdentification or EFastMutex,
+ * otherwise KErrNotSupported is returned if aVerifyData is ETrue
+ *
+ * @param aFilePath Full path of file containing the trace data
+ * @param aFs File system object
+ * @param aGroupId Group ID of traces to parse
+ * @param aNumPrimingTraces Output parameter set to number of priming traces found for given group ID
+ * @param aNumTraces Output parameter set to total number of traces found for given group ID
+ * @param aVerifyData Flag indicating if priming data should be verified
+ * @param aVerificationData1 Optional first data required for verifying priming data
+ * @param aVerificationData1 Optional second data required for verifying priming data
+ * @return Standard Symbian error code
+ */
+EXPORT_C TInt TTraceDataParser::ParsePrimingDataL(const TDesC& aFilePath,
+ RFs& aFs,
+ TGroupId aGroupId,
+ TInt& aNumPrimingTraces,
+ TInt& aNumTraces,
+ TBool aVerifyData,
+ TUint32 aVerificationData1,
+ TUint32 aVerificationData2)
+ {
+ aNumPrimingTraces = 0;
+ aNumTraces = 0;
+
+ RFile file;
+
+ // Open file with trace data
+ TInt err = file.Open(aFs, aFilePath, EFileRead|EFileShareAny);
+ if (err != KErrNone)
+ {
+ return err;
+ }
+ CleanupClosePushL(file);
+
+ // If the output data is to be verified but no verification data provided, try getting it automatically
+ if (aVerifyData && aVerificationData1 == 0 && aVerificationData2 == 0)
+ {
+ err = GetPrimingVerificationDataL(NULL, 0, aGroupId, aVerificationData1, aVerificationData2, &file);
+ if (err != KErrNone)
+ {
+ CleanupStack::PopAndDestroy(&file); // close file
+ return err;
+ }
+ }
+
+ RBuf8 fileBuffer;
+ TInt filePos = 0;
+
+ // Create file buffer and read first chunk from file
+ err = CreateFileBuffer(fileBuffer, file);
+ if (err != KErrNone)
+ {
+ CleanupStack::PopAndDestroy(&file); // close file
+ return err;
+ }
+ fileBuffer.CleanupClosePushL();
+
+ TUint8* data = NULL;
+ TUint8* startOfData = NULL;
+ TUint8* endOfData = NULL;
+
+ err = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData);
+ if (err != KErrNone)
+ {
+ CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer
+ CleanupStack::PopAndDestroy(&file); // close file
+ return err;
+ }
+
+ TInt dataVerificationErr = KErrNone;
+ TInt generalErr = KErrNone;
+ TBool firstTrace = ETrue;
+ TBool startOfBatch = ETrue;
+ TBool inPrimingData = EFalse;
+ TBool useMetaTraces = EFalse;
+ TInt numPotentialPrimingTraces = 0;
+ TUint32 lastTimestamp = 0;
+ TInt elementsFound = 0;
+
+ TTraceHeaderSettings traceHeaderSettings;
+
+ // Loop through all traces
+ while (data < endOfData)
+ {
+ // Get trace info from header
+ generalErr = ParseHeader(data, endOfData-data, traceHeaderSettings);
+
+ if (generalErr == KErrOverflow)
+ {
+ // We don't have all the trace data, so read next chunk from file
+ generalErr = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData);
+ if (generalErr == KErrNone)
+ {
+ continue;
+ }
+ }
+ if (generalErr != KErrNone)
+ {
+ if (err == KErrNone)
+ {
+ // Set error to return, if this is first error so far
+ err = generalErr;
+ }
+ break;
+ }
+
+ // If this is a meta trace, work out if it signifies start of kernel priming data for GID of interest
+ if (traceHeaderSettings.iCategory == BTrace::EMetaTrace)
+ {
+ useMetaTraces = ETrue;
+ startOfBatch = IsStartOfKernelPrimingBatch(data, aGroupId, traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory);
+ }
+
+ // This is a trace of the correct GID/CID
+ if ( (traceHeaderSettings.iComponentID == KKernelHooksOSTComponentUID) && (traceHeaderSettings.iCategory == aGroupId) )
+ {
+ // Increase the number of traces for this GID
+ aNumTraces++;
+
+ if (useMetaTraces)
+ {
+ // If data contains meta traces, work out if this is a priming trace
+ if (startOfBatch)
+ {
+ // This is the start of a batch of priming traces
+ inPrimingData = ETrue;
+ startOfBatch = EFalse;
+ }
+ if (inPrimingData)
+ {
+ // This is a priming trace, so increase number found for this GID
+ aNumPrimingTraces++;
+ // If data is to be verified, attempt the verification
+ if (aVerifyData)
+ {
+ dataVerificationErr = VerifyPrimingData(data, traceHeaderSettings.iLengthOfPayload, traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory, elementsFound, traceHeaderSettings.iFromTestWriter, aVerificationData1, aVerificationData2);
+ }
+ }
+ }
+ else
+ {
+ // If data contains no meta traces, work out if this is a priming trace using heuristics
+ generalErr = IsInPrimingBatch(traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory, traceHeaderSettings.iTimestamp-lastTimestamp, inPrimingData, firstTrace, startOfBatch);
+ if ( (generalErr != KErrNone) && (err == KErrNone) )
+ {
+ // Set error to return, if this is first error so far
+ err = generalErr;
+ }
+ lastTimestamp = traceHeaderSettings.iTimestamp;
+ if (inPrimingData)
+ {
+ // This is possibly a priming trace, so increase potential number found for this GID
+ numPotentialPrimingTraces++;
+ // If data is to be verified, attempt the verification
+ if (aVerifyData)
+ {
+ dataVerificationErr = VerifyPrimingData(data, traceHeaderSettings.iLengthOfPayload, traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory, elementsFound, traceHeaderSettings.iFromTestWriter, aVerificationData1, aVerificationData2);
+ }
+ }
+ else
+ {
+ // If we have enough potential priming traces, assume they are priming traces
+ if (numPotentialPrimingTraces >= KMinimumPrimingTracesInBatch)
+ {
+ aNumPrimingTraces += numPotentialPrimingTraces;
+ }
+ numPotentialPrimingTraces = 0;
+ }
+ }
+ }
+ else
+ {
+ // This is not a trace of the correct GID/CID
+ inPrimingData = EFalse;
+ }
+
+ // Go to the next trace
+ data+=traceHeaderSettings.iLengthOfPayload;
+
+ if (data == endOfData)
+ {
+ // We might not have all the trace data, so read next chunk from file
+ generalErr = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData);
+ if (generalErr != KErrNone)
+ {
+ if (err == KErrNone)
+ {
+ // Set error to return, if this is first error so far
+ err = generalErr;
+ }
+ break;
+ }
+ }
+ }
+
+ if (!useMetaTraces)
+ {
+ // If we have enough potential priming traces left over, assume they are priming traces
+ if (numPotentialPrimingTraces >= KMinimumPrimingTracesInBatch)
+ {
+ aNumPrimingTraces += numPotentialPrimingTraces;
+ }
+ }
+
+ if ( (dataVerificationErr != KErrNone) && (err == KErrNone) )
+ {
+ // Set error to return, if this is first error so far
+ err = dataVerificationErr;
+ }
+
+ CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer
+ CleanupStack::PopAndDestroy(&file); // close file
+
+ return err;
+ }
+
+TInt TTraceDataParser::CreateFileBuffer(RBuf8& aFileBuffer,
+ RFile& aFile)
+ {
+ TInt fileSize;
+ TInt err = aFile.Size(fileSize);
+ if (err == KErrNone)
+ {
+ if (fileSize < KFileBufferSize)
+ {
+ err = aFileBuffer.Create(fileSize);
+ }
+ else
+ {
+ err = aFileBuffer.Create(KFileBufferSize);
+ }
+ }
+ return err;
+ }
+
+TInt TTraceDataParser::ReadNextChunkFromFile(TDes8& aFileBuffer,
+ RFile& aFile,
+ TInt& aFilePosition,
+ TUint8*& aData,
+ TUint8*& aStartOfData,
+ TUint8*& aEndOfData)
+ {
+ aFilePosition += aData-aStartOfData;
+ TInt err = aFile.Read(aFilePosition, aFileBuffer);
+ if (err == KErrNone)
+ {
+ aData = (TUint8*) aFileBuffer.Ptr();
+ aStartOfData = aData;
+ aEndOfData = aData + aFileBuffer.Size();
+ }
+ return err;
+ }
+
+/*
+ * Parse trace data for Printf data, returning the number of occurances of a given string
+ *
+ * @param aBuffer Buffer containing the trace data
+ * @param aFindString String to search for
+ * @param aNumFound Output parameter set to number of occurances of given string
+ * @return Standard Symbian error code
+ */
+EXPORT_C TInt TTraceDataParser::DataHasPrintfString(TDesC8& aBuffer,
+ const TDesC8& aFindString,
+ TInt& aNumFound)
+ {
+ aNumFound = 0;
+
+ TInt err = KErrNone;
+ TUint8* data = (TUint8*) aBuffer.Ptr();
+ TUint8* endOfData = data + aBuffer.Size();
+
+ TTraceHeaderSettings traceHeaderSettings;
+
+ while(data < endOfData)
+ {
+ err = ParseHeader(data, endOfData-data, traceHeaderSettings);
+
+ if (err != KErrNone)
+ {
+ break;
+ }
+ if (traceHeaderSettings.iPrintfTrace)
+ {
+ TPtr8 printfString = ReadTracePrintf(data, traceHeaderSettings.iLengthOfPayload);
+ if (StringsMatch(aFindString, printfString))
+ {
+ aNumFound++;
+ }
+ }
+ data += traceHeaderSettings.iLengthOfPayload; //go to next trace
+ }
+
+ return err;
+ }
+
+/*
+ * Parse trace data file for Printf data, returning the number of occurances of a given string
+ *
+ * @param aFilePath Full path of file containing the trace data
+ * @param aFs File system object
+ * @param aFindString String to search for
+ * @param aNumFound Output parameter set to number of occurances of given string
+ * @return Standard Symbian error code
+ */
+EXPORT_C TInt TTraceDataParser::DataHasPrintfStringL(const TDesC& aFilePath,
+ RFs& aFs,
+ const TDesC8& aFindString,
+ TInt& aNumFound)
+ {
+ aNumFound = 0;
+
+ RFile file;
+
+ // Open file with trace data
+ TInt err = file.Open(aFs, aFilePath, EFileRead|EFileShareAny);
+ if (err != KErrNone)
+ {
+ return err;
+ }
+ CleanupClosePushL(file);
+
+ RBuf8 fileBuffer;
+ TInt filePos = 0;
+
+ // Create file buffer and read first chunk from file
+ err = CreateFileBuffer(fileBuffer, file);
+ if (err != KErrNone)
+ {
+ CleanupStack::PopAndDestroy(&file); // close file
+ return err;
+ }
+ fileBuffer.CleanupClosePushL();
+
+ TUint8* data = NULL;
+ TUint8* startOfData = NULL;
+ TUint8* endOfData = NULL;
+
+ err = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData);
+ if (err != KErrNone)
+ {
+ CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer
+ CleanupStack::PopAndDestroy(&file); // close file
+ return err;
+ }
+
+ TTraceHeaderSettings traceHeaderSettings;
+
+ while(data < endOfData)
+ {
+ err = ParseHeader(data, endOfData-data, traceHeaderSettings);
+
+ if (err == KErrOverflow)
+ {
+ // We don't have all the trace data, so read next chunk from file
+ err = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData);
+ if (err == KErrNone)
+ {
+ continue;
+ }
+ }
+ if (err != KErrNone)
+ {
+ break;
+ }
+ if (traceHeaderSettings.iPrintfTrace)
+ {
+ TPtr8 printfString = ReadTracePrintf(data, traceHeaderSettings.iLengthOfPayload);
+ if (StringsMatch(aFindString, printfString))
+ {
+ aNumFound++;
+ }
+ }
+ data += traceHeaderSettings.iLengthOfPayload; //go to next trace
+
+ if (data == endOfData)
+ {
+ // We might not have all the trace data, so read next chunk from file
+ err = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData);
+ if (err != KErrNone)
+ {
+ break;
+ }
+ }
+ }
+
+ CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer
+ CleanupStack::PopAndDestroy(&file); // close file
+
+ return err;
+ }
+
+/*
+ * Parse trace data file for a sequence of traces
+ *
+ * @param aFilePath Full path of file containing the trace data
+ * @param aFs File system object
+ * @param aLastNumberFound Output parameter set to number in last occurances of given string
+ * @param aNumDroppedTraces Output parameter set to number of dropped traces
+ * @param aFindPrintfPattern Pattern that indicates where in the printf string the number will be, using an asterisk
+ * This is only used if aGroupId = BTrace::ERDebugPrintf
+ * @param aGroupId Group ID of traces to parse
+ * @param aComponentID Component ID of traces to parse
+ * @return Standard Symbian error code
+ */
+EXPORT_C TInt TTraceDataParser::DataHasTraceSequenceL(const TDesC& aFilePath,
+ RFs& aFs,
+ TInt& aLastNumberFound,
+ TInt& aNumDroppedTraces,
+ TDesC8* aFindPrintfPattern,
+ TGroupId aGroupId,
+ TComponentId aComponentID)
+ {
+ aLastNumberFound = 0;
+ aNumDroppedTraces = 0;
+
+ RFile file;
+
+ // Open file with trace data
+ TInt err = file.Open(aFs, aFilePath, EFileRead|EFileShareAny);
+ if (err != KErrNone)
+ {
+ return err;
+ }
+ CleanupClosePushL(file);
+
+ RBuf8 fileBuffer;
+ TInt filePos = 0;
+
+ // Create file buffer and read first chunk from file
+ err = CreateFileBuffer(fileBuffer, file);
+ if (err != KErrNone)
+ {
+ CleanupStack::PopAndDestroy(&file); // close file
+ return err;
+ }
+ fileBuffer.CleanupClosePushL();
+
+ TUint8* data = NULL;
+ TUint8* startOfData = NULL;
+ TUint8* endOfData = NULL;
+
+ err = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData);
+ if (err != KErrNone)
+ {
+ CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer
+ CleanupStack::PopAndDestroy(&file); // close file
+ return err;
+ }
+
+ TInt currentNumber = 0;
+ TInt expectedNumber = 1;
+ TBool gotNumberFromTrace = EFalse;
+ TBool isDroppedTrace = EFalse;
+
+ TTraceHeaderSettings traceHeaderSettings;
+
+ while(data < endOfData)
+ {
+ err = ParseHeader(data, endOfData-data, traceHeaderSettings);
+
+ if (err == KErrOverflow)
+ {
+ // We don't have all the trace data, so read next chunk from file
+ err = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData);
+ if (err == KErrNone)
+ {
+ continue;
+ }
+ }
+ if (err != KErrNone)
+ {
+ break;
+ }
+
+ gotNumberFromTrace = EFalse;
+
+ if (traceHeaderSettings.iPrintfTrace && aGroupId == BTrace::ERDebugPrintf)
+ {
+ TPtr8 printfString = ReadTracePrintf(data, traceHeaderSettings.iLengthOfPayload);
+ // See if this is a printf that matches given string
+ if (!aFindPrintfPattern)
+ {
+ err = KErrArgument;
+ break;
+ }
+ else if (printfString.Match(*aFindPrintfPattern) != KErrNotFound)
+ {
+ // Get the line number from the string
+ err = ParseStringForNumber(printfString, *aFindPrintfPattern, currentNumber);
+ if (err != KErrNone)
+ {
+ // Could not extract number from printf, so stop and fail
+ break;
+ }
+ gotNumberFromTrace = ETrue;
+ }
+ // See if this is a dropped trace
+ else if (printfString.Compare(KDroppedTrace()) == 0)
+ {
+ // If we get 2 dropped trace notifications in a row, return an error
+ if (isDroppedTrace)
+ {
+ err = KErrGeneral;
+ break;
+ }
+ isDroppedTrace = ETrue;
+ }
+ else
+ {
+ isDroppedTrace = EFalse;
+ }
+ }
+ else if (!traceHeaderSettings.iPrintfTrace && traceHeaderSettings.iCategory == aGroupId && traceHeaderSettings.iComponentID == aComponentID)
+ {
+ // check dropped trace flag
+ if (traceHeaderSettings.iHeaderFlags & BTrace::EMissingRecord)
+ {
+ // If we get 2 dropped trace notifications in a row, return an error
+ if (isDroppedTrace)
+ {
+ err = KErrGeneral;
+ break;
+ }
+ isDroppedTrace = ETrue;
+ }
+ else
+ {
+ isDroppedTrace = EFalse;
+ }
+
+ if (traceHeaderSettings.iLengthOfPayload >= 4)
+ {
+ currentNumber = (TInt) Swap(ReadUint32FromBuf(data, traceHeaderSettings.iFromTestWriter));
+ traceHeaderSettings.iLengthOfPayload -= 4;
+ gotNumberFromTrace = ETrue;
+ }
+ else
+ {
+ // Could not get number from trace, so stop and fail
+ err = KErrGeneral;
+ break;
+ }
+ }
+
+ if (gotNumberFromTrace)
+ {
+ if (currentNumber < expectedNumber)
+ {
+ // Start of a new sequence, so stop
+ break;
+ }
+ aLastNumberFound = currentNumber;
+ if (aLastNumberFound != expectedNumber && !isDroppedTrace)
+ {
+ // A printf has been missed out with no notification, so stop and fail
+ err = KErrGeneral;
+ break;
+ }
+ else if (aLastNumberFound == expectedNumber && isDroppedTrace)
+ {
+ // A printf hasn't been missed out despite notification, so stop and fail
+ err = KErrGeneral;
+ break;
+ }
+
+ aNumDroppedTraces += (aLastNumberFound - expectedNumber);
+ expectedNumber = aLastNumberFound + 1;
+
+ if (traceHeaderSettings.iPrintfTrace)
+ {
+ isDroppedTrace = EFalse;
+ }
+ }
+
+ data += traceHeaderSettings.iLengthOfPayload; //go to next trace
+
+ if (data == endOfData)
+ {
+ // We might not have all the trace data, so read next chunk from file
+ err = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData);
+ if (err != KErrNone)
+ {
+ break;
+ }
+ }
+ }
+
+ CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer
+ CleanupStack::PopAndDestroy(&file); // close file
+
+ return err;
+ }
+
+/*
+ * Get Printf string from single trace data
+ *
+ * @param aBuffer Buffer containing the trace data
+ * @param aPrintfString Output parameter set to the print string in the trace data
+ * @return Standard Symbian error code
+ */
+EXPORT_C TInt TTraceDataParser::GetPrintfFromTrace(TDesC8& aBuffer, TDes8& aPrintfString)
+ {
+ TUint8* data = (TUint8*) aBuffer.Ptr();
+
+ TTraceHeaderSettings traceHeaderSettings;
+
+ TInt err = ParseHeader(data, aBuffer.Size(), traceHeaderSettings);
+
+ if (err == KErrNone && traceHeaderSettings.iPrintfTrace)
+ {
+ aPrintfString.Copy(ReadTracePrintf(data, traceHeaderSettings.iLengthOfPayload));
+ }
+
+ return err;
+ }
+
+/*
+ * Parse trace data for multipart data, returning the number of traces found and total size of trace data.
+ * The data is expected to contain a sequence of integers, starting at 0
+ *
+ * @param aBuffer Buffer containing the trace data
+ * @param aGroupId Group ID of traces to parse
+ * @param aComponentID Component ID of traces to parse
+ * @param aMultipartDataSize Output parameter set to total size of data in multipart trace
+ * @param aNumMultipartTraces Output parameter set to number of traces that make up multipart trace
+ * @return Standard Symbian error code
+ */
+EXPORT_C TInt TTraceDataParser::ValidateMultipartTraces(TDesC8& aBuffer,
+ TGroupId aGroupID,
+ TComponentId aComponentID,
+ TInt& aMultipartDataSize,
+ TInt& aNumMultipartTraces)
+ {
+ aMultipartDataSize = 0;
+ aNumMultipartTraces = 0;
+
+ TInt err = KErrNone;
+ TUint8* data = (TUint8*) aBuffer.Ptr();
+ TUint8* endOfData = data + aBuffer.Size();
+ TUint8 currentNumber = 0;
+ TUint8 expectedNumber = 0;
+ TUint32 expectedMultiPartTraceID = 0;
+ TBool foundStartOfMultipart = EFalse;
+ TBool foundEndOfMultipart = EFalse;
+ TBool isMultipartTrace = EFalse;
+
+ TTraceHeaderSettings traceHeaderSettings;
+
+ while(data < endOfData)
+ {
+ err = ParseHeader(data, endOfData-data, traceHeaderSettings);
+ if (err != KErrNone)
+ {
+ return err;
+ }
+
+ // Only look at traces with correct group ID / component ID
+ if (traceHeaderSettings.iCategory == aGroupID && traceHeaderSettings.iComponentID == aComponentID)
+ {
+ isMultipartTrace = EFalse;
+ if (traceHeaderSettings.iMultiPartType == BTrace::EMultipartFirst ||
+ traceHeaderSettings.iMultiPartType == BTrace::EMultipartMiddle ||
+ traceHeaderSettings.iMultiPartType == BTrace::EMultipartLast)
+ {
+ isMultipartTrace = ETrue;
+ }
+
+ if (!isMultipartTrace)
+ {
+ // If not a multipart trace, then this one trace should contain all data
+ aNumMultipartTraces = 1;
+ aMultipartDataSize = traceHeaderSettings.iLengthOfPayload;
+ // If already found some of the data then we shouldn't have this trace
+ if (foundStartOfMultipart || foundEndOfMultipart)
+ {
+ return KErrCorrupt;
+ }
+ foundStartOfMultipart = ETrue;
+ foundEndOfMultipart = ETrue;
+
+ // Validate payload
+ while (traceHeaderSettings.iLengthOfPayload > 0)
+ {
+ currentNumber = (TInt) data[0];
+ data++;
+ // Adjust length of payload remaining
+ traceHeaderSettings.iLengthOfPayload -= 1;
+ if (currentNumber != expectedNumber)
+ {
+ if (traceHeaderSettings.iLengthOfPayload >= 4 || currentNumber != 0)
+ {
+ // Data is 4-byte aligned, so it's ok to have up to 3 zeros at the end of payload
+ return KErrCorrupt;
+ }
+ // This byte is zero padding, so not part of data
+ aMultipartDataSize--;
+ }
+ expectedNumber++;
+ }
+ }
+ // Only look at multipart traces with correct multipart trace ID
+ else if (traceHeaderSettings.iMultiPartTraceID == expectedMultiPartTraceID || expectedMultiPartTraceID == 0)
+ {
+ aNumMultipartTraces++;
+
+ // If already found all data then we shouldn't get another trace with this ID
+ if (foundEndOfMultipart)
+ {
+ return KErrCorrupt;
+ }
+
+ // Trace is start of multipart
+ if (traceHeaderSettings.iMultiPartType == BTrace::EMultipartFirst)
+ {
+ // If already found start of data then we shouldn't get this part
+ if (foundStartOfMultipart)
+ {
+ return KErrCorrupt;
+ }
+ foundStartOfMultipart = ETrue;
+ aMultipartDataSize = 0;
+
+ // Set the expected multipart trace ID
+ expectedMultiPartTraceID = traceHeaderSettings.iMultiPartTraceID;
+ }
+ else if (traceHeaderSettings.iMultiPartType == BTrace::EMultipartMiddle ||
+ traceHeaderSettings.iMultiPartType == BTrace::EMultipartLast)
+ {
+ // If not yet found start of data then we shouldn't get this part
+ if (!foundStartOfMultipart)
+ {
+ return KErrCorrupt;
+ }
+ }
+
+ // Add length of payload to size of total data found
+ aMultipartDataSize += traceHeaderSettings.iLengthOfPayload;
+
+ while (traceHeaderSettings.iLengthOfPayload > 0)
+ {
+ // Validate the next part of payload
+ currentNumber = (TInt) data[0];
+ data++;
+ // Adjust length of payload remaining
+ traceHeaderSettings.iLengthOfPayload -= 1;
+ if (currentNumber != expectedNumber)
+ {
+ if (traceHeaderSettings.iLengthOfPayload >= 4 || currentNumber != 0)
+ {
+ // Data is 4-byte aligned, so it's ok to have up to 3 zeros at the end of payload
+ return KErrCorrupt;
+ }
+ // This byte is zero padding, so not part of data
+ aMultipartDataSize--;
+ }
+ expectedNumber++;
+ }
+
+ if (traceHeaderSettings.iMultiPartType == BTrace::EMultipartLast)
+ {
+ // Found end of trace data
+ foundEndOfMultipart = ETrue;
+ }
+ }
+ }
+
+ data += traceHeaderSettings.iLengthOfPayload; //go to next trace
+ }
+
+ if (!foundEndOfMultipart)
+ {
+ // Did not find end of trace data, so return KErrNotFound
+ err = KErrNotFound;
+ }
+ return err;
+ }