--- /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;
+ }
+