commsfwtools/commstools/utracedecoder/src/utraceframe.cpp
changeset 0 dfb7c4ff071f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commsfwtools/commstools/utracedecoder/src/utraceframe.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,591 @@
+// Copyright (c) 2007-2009 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:
+//
+
+#include <cassert>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+
+#include "utraceframe.h"
+#include "e32btrace.h"
+#include "util.h"
+
+CUTraceFrame::CUTraceFrame(const unsigned char* aFrameData, unsigned int aEntryNumber)
+    {
+    SetFrameBuffer(aFrameData);
+    iEventEntryNumber = aEntryNumber;
+    }
+
+CUTraceFrame::~CUTraceFrame()
+    {
+    delete [] iFrameBuffer;
+    }
+
+
+void CUTraceFrame::SetFrameBuffer(const unsigned char *aData)
+    {
+	int length = aData[0];
+	iFrameBuffer = new unsigned char[length + 4];
+	memset(iFrameBuffer, 0, length + 4); //need to do this so payload() doesnt blow out when used as string
+	memcpy((char *)iFrameBuffer, (const char*)aData, length);
+    }
+
+
+unsigned char* CUTraceFrame::Data() const
+    {
+    // Get a pointer to the data after the header
+	unsigned char *p = (unsigned char*)(iFrameBuffer + CalculateEntryOffset(0));
+
+    // Make adjustments for any extra fields such as multipart information
+    // and the arg1 value
+    if (IsMultiPart())
+        {
+        /*
+	    The structure of the data part of each trace record in a multipart trace is described
+	    below. In this description, the following labels are used.
+	    -	A is the initial 4 bytes of data; the a1 argument of BTraceBig.
+	    -	D is the array of bytes of additional data; the aData argument of BTraceBig.
+	    -	N is the size of D; the aDataSize argument of BTraceBig
+	    -	X is the maximum number of additional bytes which will fit into a trace record. 
+		    This is usually KMaxBTraceDataArray but this should not be assumed, instead
+		    the size and other information present in each trace record should be examined.
+
+	    For the first part of a multipart trace, the data in a trace record has the following
+	    structure:
+	    -	4 bytes containing N.
+	    -	4 bytes containing A.
+	    -	X bytes containing D[0..X-1]
+    
+	    If the parts are numbered 0 through to 'j', then a middle part of a multipart trace
+	    is numbered 'i' where 0<i<j. The data in these parts has the structure:
+	    -	4 bytes containing N.
+	    -	4 bytes containing X*i. I.e. the offset within D for the data in this trace record.
+	    -	X bytes containing D[X*i..X*i+X-1]
+	
+	    For the last part of a multipart trace, the data has the structure:
+	    -	4 bytes containing N.
+	    -	4 bytes containing X*j. I.e. the offset within D for the data in this trace record.
+	    -	N modulo X bytes containing D[X*j..N-1]. I.e. the final bytes of the trace data.*/
+        
+        p += 8; // trace arg1 and the offset to where this piece of data should go
+        }
+    else
+        {
+        p += 4; // trace arg1
+        }
+
+    return p;
+    }
+
+
+unsigned int CUTraceFrame::EventEntryNumber() const
+    {
+    return iEventEntryNumber;
+    }
+
+unsigned int CUTraceFrame::DataLength() const
+    {
+    unsigned char* data = Data();
+    unsigned int dataLength = (unsigned int)((iFrameBuffer + FrameLength()) - data);
+    return dataLength;
+    }
+
+unsigned int CUTraceFrame::DataFullLength() const
+    {
+    if (MultiPartType() == BTrace::EMultiPartFirst)
+        {
+	    unsigned char* p = (unsigned char*)(iFrameBuffer + CalculateEntryOffset(0));
+        return *((unsigned int*)(p));
+        }
+    else if (MultiPartType() == BTrace::ENotMultiPart)
+        {
+        return DataLength();
+        }
+
+#ifdef _DEBUG
+    assert(0); // called out of context
+#endif
+    std::cerr << "Error: CUTraceFrame::DataFullLength() called out of context" << std::endl;
+    return 0;
+    }
+
+
+unsigned int CUTraceFrame::FrameLength() const
+    {
+    return unsigned int(iFrameBuffer[BTrace::ESizeIndex]);
+    }
+
+
+unsigned int CUTraceFrame::Flags() const
+    {
+    return int(iFrameBuffer[BTrace::EFlagsIndex]);
+    }
+
+
+unsigned int CUTraceFrame::PrimaryFilter() const
+    {
+    return int(iFrameBuffer[BTrace::ECategoryIndex]);
+    }
+
+
+unsigned int CUTraceFrame::SecondaryFilter() const
+    {
+    // TODO:
+    std::cerr << "Error: CUTraceFrame::SecondaryFilter() not implemented" << std::endl;
+    assert(0);
+	return 0;
+    }
+
+
+unsigned int CUTraceFrame::SubCategory() const
+    {
+    return iFrameBuffer[BTrace::ESubCategoryIndex];
+    }
+
+
+bool CUTraceFrame::Header2Present() const
+    {
+    return iFrameBuffer[BTrace::EFlagsIndex] & BTrace::EHeader2Present;
+    }
+
+bool CUTraceFrame::Timestamp1Present() const
+    {
+    return (iFrameBuffer[BTrace::EFlagsIndex] & BTrace::ETimestampPresent) == BTrace::ETimestampPresent;
+    }
+
+bool CUTraceFrame::Timestamp2Present() const
+    {
+    return (iFrameBuffer[BTrace::EFlagsIndex] & BTrace::ETimestamp2Present) == BTrace::ETimestamp2Present;
+    }
+
+bool CUTraceFrame::ContextIdPresent() const
+    {
+    return (iFrameBuffer[BTrace::EFlagsIndex] & BTrace::EContextIdPresent) == BTrace::EContextIdPresent;
+    }
+
+bool CUTraceFrame::PcPresent() const
+    {
+    return (iFrameBuffer[BTrace::EFlagsIndex] & BTrace::EPcPresent) == BTrace::EPcPresent;
+    }
+
+bool CUTraceFrame::ExtraPresent() const
+    {
+    return (iFrameBuffer[BTrace::EFlagsIndex] & BTrace::EExtraPresent) == BTrace::EExtraPresent;
+    }
+
+bool CUTraceFrame::RecordTruncated() const
+    {
+    return (iFrameBuffer[BTrace::EFlagsIndex] & BTrace::ERecordTruncated) == BTrace::ERecordTruncated;
+    }
+
+bool CUTraceFrame::MissingRecord() const
+    {
+    return (iFrameBuffer[BTrace::EFlagsIndex] & BTrace::EMissingRecord) == BTrace::EMissingRecord;
+    }
+
+
+unsigned int CUTraceFrame::Header2() const
+    {
+    if (Header2Present())
+        {
+        return BytesToInt(iFrameBuffer + CalculateEntryOffset(BTrace::EHeader2Present));
+	    }
+
+#ifdef _DEBUG
+    assert(0); // Test for presence
+#endif
+    std::cerr << "Error: CUTraceFrame::Header2() called out of context" << std::endl;
+    return 0;
+    }
+
+
+unsigned int CUTraceFrame::Timestamp1() const
+    {
+	if (Timestamp1Present())
+        {
+        return BytesToInt(iFrameBuffer  + CalculateEntryOffset(BTrace::ETimestampPresent));
+	    }
+
+#ifdef _DEBUG
+    assert(0); // Test for presence
+#endif
+    std::cerr << "Error: CUTraceFrame::Timestamp1() called out of context" << std::endl;
+    return 0;
+    }
+
+
+unsigned int CUTraceFrame::Timestamp2() const
+    {
+    if (Timestamp2Present())
+	    {
+        return BytesToInt(iFrameBuffer  + CalculateEntryOffset(BTrace::ETimestamp2Present));
+	    }
+
+#ifdef _DEBUG
+    assert(0); // Test for presence
+#endif
+    std::cerr << "Error: CUTraceFrame::Timestamp2() called out of context" << std::endl;
+    return 0;
+    }
+
+
+unsigned int CUTraceFrame::ContextType() const
+    {
+    if (ContextIdPresent())
+        {
+        return BytesToInt(iFrameBuffer  + CalculateEntryOffset(BTrace::EContextIdPresent)) & (3UL);
+        }
+
+    #ifdef _DEBUG
+    assert(0); // Test for presence
+#endif
+    std::cerr << "Error: CUTraceFrame::ContextType() called out of context" << std::endl;
+    return 0;
+    }
+
+
+unsigned int CUTraceFrame::ContextId() const
+    {
+    if (ContextIdPresent())
+	    {
+        return BytesToInt(iFrameBuffer  + CalculateEntryOffset(BTrace::EContextIdPresent)) & (~3UL);
+	    }
+
+#ifdef _DEBUG
+    assert(0); // Test for presence
+#endif
+    std::cerr << "Error: CUTraceFrame::ContextId() called out of context" << std::endl;
+    return 0;
+    }
+
+
+unsigned int CUTraceFrame::ProgramCounter() const
+    {
+    if (PcPresent())
+        {
+        return BytesToInt(iFrameBuffer  + CalculateEntryOffset(BTrace::EPcPresent));
+	    }
+
+#ifdef _DEBUG
+    assert(0); // Test for presence
+#endif
+    std::cerr << "Error: CUTraceFrame::ProgramCounter() called out of context" << std::endl;
+    return 0;
+    }
+
+
+unsigned int CUTraceFrame::Extra() const
+    {
+    if (ExtraPresent())
+	    {
+        return BytesToInt(iFrameBuffer  + CalculateEntryOffset(BTrace::EExtraPresent));
+	    }
+
+#ifdef _DEBUG
+    assert(0); // Test for presence
+#endif
+    std::cerr << "Error: CUTraceFrame::Extra() called out of context" << std::endl;
+    return 0;
+    }
+
+
+BTrace::TMultiPart CUTraceFrame::MultiPartType() const
+    {
+    if (Header2Present())
+        {
+        return (BTrace::TMultiPart)(Header2() & BTrace::EMultiPartFlagMask);
+        }
+
+    return BTrace::ENotMultiPart;
+    }
+
+
+unsigned int CUTraceFrame::MultiPartSequenceNumber() const
+    {
+    if (MultiPartType() == BTrace::ENotMultiPart)
+        {
+#ifdef _DEBUG
+        assert(0); // called out of context
+#endif
+        std::cerr << "Error: CUTraceFrame::MultiPartSequenceNumber() called out of context" << std::endl;
+        return 0;
+        }
+
+    return Extra();
+    }
+
+
+unsigned int CUTraceFrame::Arg1() const
+    {
+    BTrace::TMultiPart partType = MultiPartType();
+
+    assert(partType == BTrace::ENotMultiPart || partType ==  BTrace::EMultiPartFirst);
+    return *((unsigned int*)(Data() - 4)); // Arg1 always 4 bytes before the start of the data
+    }
+
+
+unsigned int CUTraceFrame::Truncated() const
+    {
+    if (RecordTruncated())
+        {
+		return BytesToInt(iFrameBuffer  + CalculateEntryOffset(BTrace::ERecordTruncated));
+	    }
+
+#ifdef _DEBUG
+    assert(0); // Test for presence
+#endif
+    return 0;
+    }
+
+
+unsigned int CUTraceFrame::Missing() const
+    {
+    if (MissingRecord())
+        {
+    	return BytesToInt(iFrameBuffer  + CalculateEntryOffset(BTrace::EMissingRecord));
+	    }
+    
+#ifdef _DEBUG
+    assert(0); // Test for presence
+#endif
+    return 0;
+    }
+
+
+/**
+Calculates the offset from the start of the frame to either the data after the header,
+or to the data for the specified flag.
+
+@param aEntry - Either a value from BTrace::TFlags or zero to retrieve the offset to the data after the header.
+The requested flag must be set in the flags field of the frame.
+The requested flag must not be BTrace::ERecordTruncated or BTrace::EMissingRecord which have no associated data
+*/
+unsigned int CUTraceFrame::CalculateEntryOffset(unsigned char aEntry) const
+    {
+	assert(aEntry == 0 || (aEntry & Flags()) > 0);
+	assert(aEntry != BTrace::ERecordTruncated);
+	assert(aEntry != BTrace::EMissingRecord);
+
+    int offset = 4; // size, flags, 1ry category, subcategory
+    unsigned char mask = aEntry - 1;
+	mask &= ~(BTrace::ERecordTruncated | BTrace::EMissingRecord);
+
+    unsigned char n = Flags() & mask;    
+	while (n)
+	    {
+		offset += ((n & 1UL) * 4) ;
+		n >>= 1 ;
+	    }
+
+	return offset;
+    }
+
+
+void CUTraceFrame::DumpFlags(std::ostream& aStream) const
+    {
+    if (Flags() & BTrace::EHeader2Present)
+        {
+        aStream << "Header2Present ";
+        }
+
+    if (Flags() & BTrace::ETimestampPresent)
+        {
+        aStream << "TimestampPresent ";
+        }
+
+    if (Flags() & BTrace::ETimestamp2Present)
+        {
+        aStream << "Timestamp2Present ";
+        }
+
+    if (Flags() & BTrace::EContextIdPresent)
+        {
+        aStream << "ContextIdPresent ";
+        }
+
+    if (Flags() & BTrace::EPcPresent)
+        {
+        aStream << "PcPresent ";
+        }
+
+    if (Flags() & BTrace::EExtraPresent)
+        {
+        aStream << "ExtraPresent ";
+        }
+
+    if (Flags() & BTrace::ERecordTruncated)
+        {
+        aStream << "RecordTruncated ";
+        }
+
+    if (Flags() & BTrace::EMissingRecord)
+        {
+        aStream << "MissingRecord ";
+        }
+    }
+
+void CUTraceFrame::DumpFrame(std::ostream& aStream) const
+    {
+    aStream
+        << "Size: " << std::dec << FrameLength() << std::endl
+        << "Flags: 0x" << std::noshowbase << std::setw(2)
+        << std::setfill('0') << std::nouppercase << std::hex
+        << Flags() << " (";
+
+    DumpFlags(aStream);
+
+    aStream << ")" << std::endl
+        << "Primary Filter: 0x" << std::noshowbase << std::setw(2)
+        << std::setfill('0') << std::nouppercase << std::hex
+        << PrimaryFilter() << std::endl
+        << "Subcategory: 0x" << std::noshowbase << std::setw(2)
+        << std::setfill('0') << std::nouppercase << std::hex
+        << SubCategory() << std::endl;
+
+    if (Header2Present())
+        {
+        aStream << "Header2: 0x" << std::noshowbase << std::setw(8)
+            << std::setfill('0') << std::nouppercase << std::hex
+            << Header2() << std::endl;
+        }
+
+    if (Timestamp1Present())
+        {
+        aStream << "Timestamp1: " << std::noshowbase << std::dec
+            << Timestamp1() << std::endl;
+        }
+
+    if (Timestamp2Present())
+        {
+        aStream << "Timestamp2: " << std::noshowbase << std::dec
+            << Timestamp2() << std::endl;
+        }
+    if (ContextIdPresent())
+        {
+        aStream << "Context Type: ";
+        switch (ContextType())
+            {
+            case 0:
+                aStream << "NThread" << std::endl;
+                aStream << "Context ID: 0x" << std::noshowbase << std::hex << std::nouppercase
+                    << std::setw(8) << std::setfill('0') << ContextId() << std::endl;
+                break;
+
+            case 1:
+                aStream << "Fast Interrupt (FIQ)" << std::endl;
+                break;
+
+            case 2:
+                aStream << "Interrupt (IRQ)" << std::endl;                    
+                break;
+
+            case 3:
+                aStream << "Immediate Delayed Function Call (IDFC)" << std::endl;
+                break;
+            }
+        }
+
+    if (PcPresent())
+        {
+        aStream << "PC: 0x" << std::noshowbase << std::setw(8)
+            << std::setfill('0') << std::nouppercase << std::hex
+            << ProgramCounter() << std::endl;
+        }
+
+    if (IsMultiPart())
+        {
+        aStream << "Multipart Frame: ";
+        switch (Header2() & BTrace::EMultiPartFlagMask)
+            {
+            case 1:
+                aStream << "EMultiPartFirst";
+                break;
+
+            case 2:
+                aStream << "EMultiPartMiddle";
+                break;
+
+            case 3:
+                aStream << "EMultiPartLast";
+                break;
+            }
+        aStream << std::endl;
+        }
+
+    if (ExtraPresent())
+        {
+        if (IsMultiPart())
+            {
+            aStream << "MultiPart Event Id: 0x";
+            }
+        else
+            {
+            aStream << "Extra: 0x";
+            }
+
+        aStream << std::noshowbase << std::setw(8)
+            << std::setfill('0') << std::nouppercase << std::hex
+            << Extra() << std::endl;
+        }
+
+    if (!IsMultiPart() || MultiPartType() == BTrace::EMultiPartFirst)
+        {
+        aStream << "Arg1: 0x" << std::noshowbase << std::setw(8)
+            << std::setfill('0') << std::nouppercase << std::hex
+            << Arg1() << std::endl;
+        }
+
+    unsigned int zones[1] = { (unsigned int)(Data() - iFrameBuffer) };
+    DumpBytes(aStream, iFrameBuffer, FrameLength(), zones, 1);
+    aStream << std::endl;
+    aStream.flush();
+    }
+
+
+void CUTraceFrame::DumpFrame(std::string& aOutput) const
+    {
+    std::ostringstream ss;
+    DumpFrame(ss);
+    aOutput += ss.str();
+    }
+
+
+CMultiPartFrameCollection::CMultiPartFrameCollection(CUTraceFrame* aFrame)
+    {
+    assert(aFrame->IsMultiPart());
+    push_back(aFrame);
+    }
+
+CMultiPartFrameCollection::~CMultiPartFrameCollection()
+    {
+    while (!empty())
+        {
+        CUTraceFrame* frame = this->back();
+        this->pop_back();
+        delete frame;
+        }
+    }
+
+void CMultiPartFrameCollection::AddFrame(CUTraceFrame* aFrame)
+    {
+    assert(aFrame->IsMultiPart() && aFrame->MultiPartSequenceNumber() == MultiPartId());
+    push_back(aFrame);
+    }
+
+unsigned int CMultiPartFrameCollection::MultiPartId() const
+    {
+    return at(0)->MultiPartSequenceNumber();
+    }
+