tracesrv/tracecore/btrace_handler/test/tracedataparser/src/tracedataparser.cpp
changeset 56 aa2539c91954
--- /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;
+    }