commsfwtools/commstools/utracedecoder/src/utracedecoderapp.cpp
changeset 0 dfb7c4ff071f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commsfwtools/commstools/utracedecoder/src/utracedecoderapp.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,438 @@
+// 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 <iostream>
+#include <sstream>
+#include <string>
+
+#include <windows.h>
+
+#include "utracedecoderapp.h"
+#include "utraceframe.h"
+#include "framesorter.h"
+#include "util.h"
+#include "logevents\traceeventbase.h"
+#include "version.h"
+
+const int KLogBufferSize = 16384;
+
+Parser::CDefinitionParser* gMsgDefParser;
+bool gQuiet;
+
+bool CUTraceDecoderApp::iUseTimes = false;
+CUTraceDecoderApp::TTimestampPeriod CUTraceDecoderApp::iPeriodType = CUTraceDecoderApp::EUnknown;
+double CUTraceDecoderApp::iPeriod1;
+double CUTraceDecoderApp::iPeriod2;
+
+CUTraceDecoderApp::CUTraceDecoderApp()
+    {
+    iFrameSorter = new CFrameSorter(*this);
+
+    iDumpIdentifiers = false;
+    iTesting = false;
+    SetShowContextInfo(true);
+    iCurrentFrame = 0;
+    iUseQuotes = false;
+    iTail = false;
+
+    iInputBuffer = new unsigned char[KLogBufferSize];
+    iBufferOffset = 0;
+    iBufferSize = 0;
+    iBufferValid = false;
+
+    // There will only ever be one CUTraceDecoderApp so this isn't so bad
+    // Needs refactoring though. gMsgDefParser is used by the Node Message Event
+    ::gMsgDefParser = new Parser::CDefinitionParser();
+	::gQuiet = false;
+    }
+
+
+CUTraceDecoderApp::~CUTraceDecoderApp()
+    {
+    delete iInputBuffer;
+    }
+
+
+bool CUTraceDecoderApp::Initialise(int aArgc, char **aArgv) 
+    {
+    if (aArgc < 2)
+	    {
+	    return false;
+	    }
+    
+    // defaults
+    SetShowContextInfo(true);
+    SetNewLineEnabled(true);
+    
+    int currentArg = 1;
+    while (currentArg < aArgc)
+        {
+        if (aArgv[currentArg][0] == '-' && aArgv[currentArg][1] == '-')
+            {
+            if (!_strcmpi(&aArgv[currentArg][2], "payload-only"))
+                {
+                SetShowContextInfo(false);
+                }
+            else if (!_strcmpi(&aArgv[currentArg][2], "use-quotes"))
+                {
+                iUseQuotes = true;
+                }
+            else if (!_strcmpi(&aArgv[currentArg][2], "use-times"))
+                {
+                iUseTimes = true;
+                }
+            else if (!_strcmpi(&aArgv[currentArg][2], "tail"))
+                {
+                // EXPERIMENTAL: This is an experimental feature at the moment
+                iTail = true;
+                }
+			else if (!_strcmpi(&aArgv[currentArg][2], "quiet"))
+				{
+				::gQuiet = true;
+				}
+            else if (!_strcmpi(&aArgv[currentArg][2], "message-def"))
+                {
+                currentArg++;
+                iMsgDefFile = aArgv[currentArg];
+                }
+            else if (!_strcmpi(&aArgv[currentArg][2], "dump-frame"))
+                {
+                currentArg++;
+                char* startFrame = aArgv[currentArg];
+
+                char* endFrame = startFrame;
+                while (*endFrame != ',' && *endFrame != 0)
+                    {
+                    if (*endFrame < '0' || *endFrame > '9')
+                        {
+                        return false;
+                        }
+                    ++endFrame;
+                    }
+                if (*endFrame == 0)
+                    {
+                    return false;
+                    }
+                *endFrame = 0;
+                if (*startFrame == 0)
+                    {
+                    return false;
+                    }
+                ++endFrame;
+                
+                char* tmp = endFrame;
+                while (*tmp != 0)
+                    {
+                    if (*tmp < '0' || *tmp > '9')
+                        {
+                        return false;
+                        }
+                    ++tmp;
+                    }
+
+                iFrameSorter->SetDumpFrameRange(atol(startFrame), atol(endFrame));
+                }
+            else if (!_strcmpi(&aArgv[currentArg][2], "dump-event"))
+                {
+                currentArg++;
+                char* startEvent = aArgv[currentArg];
+
+                char* endEvent = startEvent;
+                while (*endEvent != ',' && *endEvent != 0)
+                    {
+                    if (*endEvent < '0' || *endEvent > '9')
+                        {
+                        return false;
+                        }
+                    ++endEvent;
+                    }
+                if (*endEvent == 0)
+                    {
+                    return false;
+                    }
+                *endEvent = 0;
+                if (*startEvent == 0)
+                    {
+                    return false;
+                    }
+                ++endEvent;
+                
+                char* tmp = endEvent;
+                while (*tmp != 0)
+                    {
+                    if (*tmp < '0' || *tmp > '9')
+                        {
+                        return false;
+                        }
+                    ++tmp;
+                    }
+
+                iFrameSorter->SetDumpEventRange(atol(startEvent), atol(endEvent));
+                }
+            else if (!_strcmpi(&aArgv[currentArg][2], "dump-message-def"))
+                {
+                iDumpIdentifiers = true;
+                }
+            else if (!_strcmpi(&aArgv[currentArg][2], "test-message-def"))
+                {
+                iTesting = true;
+                }
+            }
+        else
+            {
+            if (iLogFile.length() > 0)
+                {
+                return false;
+                }
+            iLogFile = aArgv[currentArg];
+            }
+
+        currentArg++;
+        }
+
+    if (iMsgDefFile.length() > 0)
+        {
+        if (iTesting)
+            {
+            gMsgDefParser->SetTestMode();
+            }
+
+        if (gMsgDefParser->ParseDefinitionFile(iMsgDefFile.c_str()) != Parser::ENoError)
+            {
+//            std::cerr << "Error in message definition file" << std::endl;
+            return false;
+            }
+        }
+
+    if (iDumpIdentifiers)
+        {
+        gMsgDefParser->DumpIdentifiers();
+        }
+    
+    if (iTesting)
+        {
+        if (iMsgDefFile.length() == 0)
+            {
+            std::cerr << "No message definition file specifed to check" << std::endl;
+            }
+        return true;
+        }
+
+    if (iLogFile.length() == 0)
+        {
+        return false;
+        }
+        
+    return true;
+    }
+
+
+void CUTraceDecoderApp::ProcessLog()
+    {
+    // csv header
+    if (ShowContextInfo())
+        {
+        std::cout << "Sequence,Primary Filter,Sub Category,Time Stamp1,Time Stamp2,Context ID,Description" << std::endl;
+        } 
+
+    // Open the log file and fill the buffer
+    if(!LoadUTraceLog()) 
+        { // file couldn't be opened
+        std::cerr << "Error: file " << iLogFile.c_str() << " could not be opened." << std::endl;
+        return;
+        }
+
+    while (iBufferValid)
+        {
+        while (iBufferOffset < iBufferSize)
+            {
+            //grab a hunk of log
+            int length = iInputBuffer[iBufferOffset];
+            length = (length + 3) & ~3;
+
+            // Minimum length is actually 4, but this would mean only the header was
+            // present, so why was it logged
+            if (length < 8 || length > KMaxBTraceRecordSize)
+                {
+                if (!iInputFile.eof())
+                    {
+                    std::cerr << "Error: Frame " << iCurrentFrame << " is corrupt - size is out of range (8-116)" << std::endl;
+                    
+                    // Dump what we have in the buffer, up to the max size of a frame
+                    DumpBytes(std::cerr, &iInputBuffer[iBufferOffset], (KMaxBTraceRecordSize < (iBufferSize - iBufferOffset)) ? KMaxBTraceRecordSize : (iBufferSize - iBufferOffset));
+                    }
+                return;
+                }
+
+            if (length + iBufferOffset > iBufferSize)
+                {
+                break;
+                }
+	   		
+            CUTraceFrame* frame = new CUTraceFrame(&iInputBuffer[iBufferOffset], iCurrentFrame);
+            if (frame)
+                {
+                iFrameSorter->ProcessFrame(frame);
+                frame = NULL;
+                iCurrentFrame++;
+                }
+            else
+                {
+                std::cerr << "Failed to create frame instance" << std::endl;
+                }
+	   		
+            iBufferOffset += length;
+            }
+		   
+        RefillUTraceBuffer();
+        }
+    
+    iInputFile.close();
+	
+	std::cerr << "Processed " << iCurrentFrame << " frames" << std::endl;
+    }
+
+
+unsigned int CUTraceDecoderApp::CurrentFrame() const
+    {
+    return iCurrentFrame;
+    }
+
+
+void CUTraceDecoderApp::WriteEvent(const CTraceEventBase& aEvent) const
+    {
+    if (NewLineEnabled())
+        {
+        if (ShowContextInfo())
+            {
+            aEvent.WriteContextInfo(std::cout);
+            }
+
+        if (iUseQuotes)
+            {
+            std::cout << "\"";
+            }
+        aEvent.WriteEventPrefix(std::cout);
+        }
+
+    if (iUseQuotes)
+        {
+        std::stringstream ss;
+        aEvent.Describe(ss);
+        std::string s = ss.str();
+        // todo: replace " with ""
+        std::cout << s;
+        }
+    else
+        {
+        aEvent.Describe(std::cout);
+        }
+
+    if (NewLineEnabled())
+        {
+        if (iUseQuotes)
+            {
+            std::cout << "\"";
+            }
+        std::cout << std::endl;
+        }
+    else
+        {
+        std::cout << " ";
+        }
+    };
+
+
+bool CUTraceDecoderApp::LoadUTraceLog()
+    {
+    iInputFile.open(iLogFile.c_str(), std::ios::in | std::ios::binary);
+    if (iInputFile.is_open())
+        {
+        RefillUTraceBuffer();
+        return true;
+        }
+
+    return false;
+    }
+
+
+void CUTraceDecoderApp::RefillUTraceBuffer()
+    {
+    int bufferSpace = KLogBufferSize;
+    int bufferInUse = 0;
+
+    if (iBufferOffset)
+        {
+        bufferInUse = iBufferSize - iBufferOffset;
+        bufferSpace = KLogBufferSize - bufferInUse;
+        memcpy(iInputBuffer, &iInputBuffer[iBufferOffset], bufferInUse);
+        }
+
+    memset(&iInputBuffer[bufferInUse], 0, bufferSpace);
+    iInputFile.read((char*)&iInputBuffer[bufferInUse], bufferSpace);
+    iBufferSize = iInputFile.gcount();
+
+#ifdef _DEBUG
+    std::cerr << std::dec << std::noshowbase << iBufferSize << " bytes read from log file" << std::endl;
+#endif
+    iBufferValid = (iBufferSize > 0);
+
+    if (!iBufferValid && iTail)
+        {
+        // EXPERIMENTAL: This is an experimental feature at the moment
+        HANDLE fileChangeHandle;
+        fileChangeHandle = FindFirstChangeNotificationA(iLogFile.c_str(), FALSE, FILE_NOTIFY_CHANGE_SIZE);
+        if (fileChangeHandle != INVALID_HANDLE_VALUE)
+            {
+            iInputFile.read((char*)&iInputBuffer[bufferInUse], bufferSpace);
+            iBufferSize = iInputFile.gcount();
+
+            std::cerr << std::dec << std::noshowbase << iBufferSize << " bytes read from log file" << std::endl;
+            iBufferValid = (iBufferSize > 0);
+            FindCloseChangeNotification(fileChangeHandle);
+            }
+        }
+
+    iBufferSize += bufferInUse;
+    iBufferOffset = 0;
+    }
+
+
+void CUTraceDecoderApp::ShowUsage()
+    {
+	std::cerr
+        << "utracedecoder " APPVERSION ":" << std::endl
+	    << "Log parser for utrace logs, converts a utrace generated log file into human readable and perl processable csv format" << std::endl
+	    << "utracedecoder [options] <path_to_log>" << std::endl
+        << "    --payload-only                 Show only the message part of the trace" << std::endl
+        << "    --use-quotes                   Wrap the description in quotes" << std::endl
+        << "    --use-times                    \"time-in-seconds,0\" substituted for \"timestamp1,timestamp\" pair" << std::endl
+        << "    --message-def <message_definition_file>  The file from which to load message and signature definition" << std::endl
+        << "    --test-message-def             Tests the message definition file showing all errors then exits" << std::endl
+        << std::endl << "Debugging options" << std::endl 
+        << "    --dump-message-def             Dumps the parsed definition file details" << std::endl
+        << "    --dump-frame <start_frame>,<end_frame>  Dumps the frames in the given range to stderr" << std::endl
+        << "    --dump-event <first_event>,<last_event>  Dumps the events in the given range to stderr" << std::endl
+		<< "    --quiet                        Only output urgent warnings" << std::endl
+        << std::endl;
+    }
+
+void CUTraceDecoderApp::SetTimestampPeriod(CUTraceDecoderApp::TTimestampPeriod aType, double aPeriod1, double aPeriod2)
+	{
+	iPeriodType = aType;
+	iPeriod1 = aPeriod1;
+	iPeriod2 = aPeriod2;
+	}
+