summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--CMakeLists.txt38
-rw-r--r--apitrace.xsl228
-rw-r--r--base.py4
-rw-r--r--dump.cpp37
-rw-r--r--glretrace.py118
-rw-r--r--log.cpp453
-rw-r--r--log.hpp5
-rw-r--r--trace_format.hpp89
-rw-r--r--trace_model.cpp177
-rw-r--r--trace_model.hpp189
-rw-r--r--trace_parser.hpp253
-rwxr-xr-xxml2txt.py451
13 files changed, 1053 insertions, 995 deletions
diff --git a/.gitignore b/.gitignore
index 7fac7012..32ddb972 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,7 +6,7 @@
*.dll
*.exe
*.exp
-*.gz
+*.trace
*.ilk
*.lib
*.o
@@ -15,7 +15,6 @@
*.pyc
*.pyo
*.so
-*.xml
*.zip
CMakeFiles
CMakeCache.txt
@@ -29,5 +28,8 @@ d3d9.cpp
d3d10.cpp
d3d10_1.cpp
dxsdk
+dump
glx.cpp
+glretrace
+glretrace.cpp
opengl32.cpp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9ae07409..41f896bd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,9 +4,18 @@ project (apitrace)
find_package (PythonInterp REQUIRED)
find_package (OpenGL REQUIRED)
-
find_package (ZLIB)
+find_package (GLUT)
+
+find_library (GLEW_glew_LIBRARY GLEW
+ /usr/lib
+)
+
+find_path (GLEW_INCLUDE_DIR GL/glew.h
+ /usr/include/GL
+)
+
if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
# Nobody likes to include windows.h:
# - Microsoft's GL/gl.h header depends on windows.h but doesn't include it;
@@ -93,3 +102,30 @@ else ()
target_link_libraries (glxtrace dl)
endif ()
+add_executable (dump dump.cpp trace_model.cpp)
+
+
+if (GLEW_INCLUDE_DIR)
+ add_custom_command (
+ OUTPUT glretrace.cpp
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/glretrace.py > ${CMAKE_CURRENT_BINARY_DIR}/glretrace.cpp
+ DEPENDS glretrace.py glx.py gl.py dl.py base.py
+ )
+
+ include_directories (
+ ${OPENGL_INCLUDE_PATH}
+ ${GLUT_INCLUDE_DIR}
+ ${GLEW_INCLUDE_DIR}
+ )
+
+ add_executable (glretrace glretrace.cpp trace_model.cpp)
+
+ target_link_libraries (glretrace
+ ${OPENGL_gl_LIBRARY}
+ ${OPENGL_glu_LIBRARY}
+ ${GLUT_glut_LIBRARY}
+ ${GLEW_glew_LIBRARY}
+ )
+endif (GLEW_INCLUDE_DIR)
+
+
diff --git a/apitrace.xsl b/apitrace.xsl
deleted file mode 100644
index ccb4d80b..00000000
--- a/apitrace.xsl
+++ /dev/null
@@ -1,228 +0,0 @@
-<?xml version="1.0"?>
-
-<!--
-
-Copyright 2008-2009 VMware, Inc.
-All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
-!-->
-
-<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-
- <xsl:output method="html" />
-
- <xsl:strip-space elements="*" />
-
- <xsl:template match="/trace">
- <html>
- <head>
- <title>D3D Trace</title>
- </head>
- <style>
- body {
- font-family: verdana, sans-serif;
- font-size: 11px;
- font-weight: normal;
- text-align : left;
- }
-
- ul.calls {
- list-style: none;
- margin-left: 0px;
- padding-left: 0px;
- }
-
- ul.args {
- display:inline;
- list-style: none;
- margin-left: 0px;
- padding-left: 0px;
- }
-
- ul.args li {
- display:inline;
- }
-
- ul.elems {
- list-style: none;
- margin-left: 2em;
- padding-left: 0px;
- }
-
- ul.elems li {
- display:block;
- }
-
- .fun {
- font-weight: bold;
- }
-
- .var {
- font-style: italic;
- }
-
- .typ {
- display: none;
- }
-
- .lit {
- color: #0000ff;
- }
-
- .addr {
- color: #008000;
- }
-
- .ref {
- position: relative;
- cursor: help;
- }
-
- .def {
- display: none;
- position: absolute;
- top: 1.5em;
- left: 0;
- width: 32em;
- background: #f7f7f7;
- cursor: default;
- }
-
- .ref:hover .def {
- display: block;
- }
- </style>
- <body>
- <ul class="calls">
- <xsl:apply-templates/>
- </ul>
- </body>
- </html>
- </xsl:template>
-
- <xsl:template match="call">
- <li>
- <span class="fun">
- <xsl:value-of select="@name"/>
- </span>
- <xsl:text>(</xsl:text>
- <ul class="args">
- <xsl:apply-templates select="arg"/>
- </ul>
- <xsl:text>)</xsl:text>
- <xsl:apply-templates select="ret"/>
- </li>
- </xsl:template>
-
- <xsl:template match="arg|elem">
- <li>
- <xsl:apply-templates select="@type"/>
- <xsl:apply-templates select="@name"/>
- <xsl:text> = </xsl:text>
- <xsl:call-template name="compound"/>
- <xsl:if test="position() != last()">
- <xsl:text>, </xsl:text>
- </xsl:if>
- </li>
- </xsl:template>
-
- <xsl:template match="@type">
- <xsl:attribute name="title">
- <xsl:value-of select="."/>
- </xsl:attribute>
- </xsl:template>
-
- <xsl:template match="@name">
- <span class="var">
- <xsl:value-of select="."/>
- </span>
- </xsl:template>
-
- <xsl:template match="ret">
- <xsl:text> = </xsl:text>
- <xsl:call-template name="compound"/>
- </xsl:template>
-
- <xsl:template match="ref">
- <xsl:choose>
- <xsl:when test="elem">
- <span class="ref">
- <xsl:apply-templates select="@addr"/>
- <span class="def">
- <xsl:call-template name="compound"/>
- </span>
- </span>
- </xsl:when>
- <xsl:when test="*">
- <xsl:text>&amp;</xsl:text>
- <xsl:apply-templates />
- </xsl:when>
- <xsl:otherwise>
- <xsl:apply-templates select="@addr"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:template>
-
- <xsl:template match="@addr">
- <span class="addr">
- <xsl:value-of select="."/>
- </span>
- </xsl:template>
-
- <xsl:template match="text()">
- <span class="lit">
- <xsl:call-template name="break">
- <xsl:with-param name="text" select="."/>
- </xsl:call-template>
- </span>
- </xsl:template>
-
- <xsl:template name="compound">
- <xsl:choose>
- <xsl:when test="elem">
- <xsl:text>{</xsl:text>
- <ul class="elems">
- <xsl:apply-templates />
- </ul>
- <xsl:text>}</xsl:text>
- </xsl:when>
- <xsl:otherwise>
- <xsl:apply-templates />
- </xsl:otherwise>
- </xsl:choose>
- </xsl:template>
-
- <xsl:template name="break">
- <xsl:param name="text" select="."/>
- <xsl:choose>
- <xsl:when test="contains($text, '&#xa;')">
- <xsl:value-of select="substring-before($text, '&#xa;')"/>
- <br/>
- <xsl:call-template name="break">
- <xsl:with-param name="text" select="substring-after($text, '&#xa;')"/>
- </xsl:call-template>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$text"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:template>
-</xsl:transform>
diff --git a/base.py b/base.py
index e672a3ce..3c93c424 100644
--- a/base.py
+++ b/base.py
@@ -172,7 +172,7 @@ class Enum(Concrete):
print ' switch(%s) {' % instance
for value in self.values:
print ' case %s:' % value
- print ' Log::LiteralNamedConstant("%s");' % value
+ print ' Log::LiteralNamedConstant("%s", %s);' % (value, value)
print ' break;'
print ' default:'
print ' Log::LiteralSInt(%s);' % instance
@@ -199,7 +199,7 @@ class Flags(Concrete):
print ' Log::BeginBitmask("%s");' % (self.type,)
for value in self.values:
print ' if((l_Value & %s) == %s) {' % (value, value)
- print ' Log::LiteralNamedConstant("%s");' % value
+ print ' Log::LiteralNamedConstant("%s", %s);' % (value, value)
print ' l_Value &= ~%s;' % value
print ' }'
print ' if(l_Value) {'
diff --git a/dump.cpp b/dump.cpp
new file mode 100644
index 00000000..09d74c4e
--- /dev/null
+++ b/dump.cpp
@@ -0,0 +1,37 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include "trace_parser.hpp"
+
+
+int main(int argc, char **argv)
+{
+ for (int i = 1; i < argc; ++i) {
+ Trace::Parser p;
+ p.parse(argv[i]);
+ }
+ return 0;
+}
diff --git a/glretrace.py b/glretrace.py
new file mode 100644
index 00000000..82cd7131
--- /dev/null
+++ b/glretrace.py
@@ -0,0 +1,118 @@
+##########################################################################
+#
+# Copyright 2010 VMware, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+##########################################################################/
+
+
+import base
+from glx import libgl
+
+
+def is_arg_supported(arg_type):
+ if isinstance(arg_type, (base.Literal, base._String, base.Enum)):
+ return True
+ if isinstance(arg_type, (base.Alias, base.Flags)):
+ return is_arg_supported(arg_type.type)
+ return False
+
+
+def is_function_supported(function):
+ for arg_type, arg_name in function.args:
+ if not is_arg_supported(arg_type):
+ return False
+ return True
+
+
+def extract_value(arg_type, arg_value):
+ if isinstance(arg_type, base.Literal):
+ return 'Trace::as%s(%s)' % (arg_type.format, value)
+ if isinstance(arg_type, base.Enum):
+ return 'Trace::asSInt(%s)' % (value)
+ if isinstance(arg_type, (base.Alias, base.Flags)):
+ return extract_value(arg_type.type, value)
+ assert false
+ return '0'
+
+
+if __name__ == '__main__':
+ print
+ print '#include <stdlib.h>'
+ print '#include <string.h>'
+ print '#include <GL/glew.h>'
+ print '#include <GL/glut.h>'
+ print
+ print '#include "trace_parser.hpp"'
+ print
+
+ functions = filter(is_function_supported, libgl.functions)
+
+ for function in functions:
+ print 'static void retrace_%s(Trace::Call &call) {' % function.name
+ for arg_type, arg_name in function.args:
+ print ' %s %s;' % (arg_type, arg_name)
+ for arg_type, arg_name in function.args:
+ value = 'call.get_arg("%s")' % (arg_name,)
+ value = extract_value(arg_type, value)
+ print ' %s = static_cast<%s>(%s);' % (arg_name, arg_type, value)
+ arg_names = ", ".join([arg_name for arg_type, arg_name in function.args])
+ print ' %s(%s);' % (function.name, arg_names)
+ print '}'
+ print
+
+ print 'static bool retrace_call(Trace::Call &call) {'
+ for function in functions:
+ print ' if (call.name == "%s") {' % function.name
+ print ' retrace_%s(call);' % function.name
+ print ' return true;'
+ print ' }'
+ print ' std::cerr << "Unsupported call " << call.name << "\\n";'
+ print ' return false;'
+ print '}'
+ print '''
+
+class Retracer : public Trace::Parser
+{
+ void handle_call(Trace::Call &call) {
+ std::cout << call;
+ std::cout.flush();
+ retrace_call(call);
+ }
+};
+
+int main(int argc, char **argv)
+{
+ glutInit(&argc, argv);
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( 800, 600 );
+ glutInitDisplayMode( GLUT_DEPTH | GLUT_RGB | GLUT_SINGLE );
+ glutCreateWindow(argv[0]);
+ glewInit();
+ for (int i = 1; i < argc; ++i) {
+ Retracer p;
+ p.parse(argv[i]);
+ glutMainLoop();
+ }
+ return 0;
+}
+
+'''
diff --git a/log.cpp b/log.cpp
index a7128f80..a78ba535 100644
--- a/log.cpp
+++ b/log.cpp
@@ -24,6 +24,7 @@
**************************************************************************/
+#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -33,6 +34,7 @@
#include "os.hpp"
#include "log.hpp"
+#include "trace_format.hpp"
namespace Log {
@@ -40,397 +42,230 @@ namespace Log {
static gzFile g_gzFile = NULL;
static void _Close(void) {
- if(g_gzFile != NULL) {
- gzclose(g_gzFile);
- g_gzFile = NULL;
- }
+ if(g_gzFile != NULL) {
+ gzclose(g_gzFile);
+ g_gzFile = NULL;
+ }
}
static void _Open(const char *szName, const char *szExtension) {
- _Close();
-
- static unsigned dwCounter = 0;
-
- char szProcessName[PATH_MAX];
- char szFileName[PATH_MAX];
-
- OS::GetProcessName(szProcessName, PATH_MAX);
-
- for(;;) {
- FILE *file;
-
- if(dwCounter)
- snprintf(szFileName, PATH_MAX, "%s.%s.%u.%s.gz", szProcessName, szName, dwCounter, szExtension);
- else
- snprintf(szFileName, PATH_MAX, "%s.%s.%s.gz", szProcessName, szName, szExtension);
-
- file = fopen(szFileName, "rb");
- if(file == NULL)
- break;
-
- fclose(file);
-
- ++dwCounter;
- }
-
- fprintf(stderr, "Logging to %s\n", szFileName);
- g_gzFile = gzopen(szFileName, "wb");
+ _Close();
+
+ static unsigned dwCounter = 0;
+
+ char szProcessName[PATH_MAX];
+ char szFileName[PATH_MAX];
+
+ OS::GetProcessName(szProcessName, PATH_MAX);
+
+ for(;;) {
+ FILE *file;
+
+ if(dwCounter)
+ snprintf(szFileName, PATH_MAX, "%s.%s.%u.%s", szProcessName, szName, dwCounter, szExtension);
+ else
+ snprintf(szFileName, PATH_MAX, "%s.%s.%s", szProcessName, szName, szExtension);
+
+ file = fopen(szFileName, "rb");
+ if(file == NULL)
+ break;
+
+ fclose(file);
+
+ ++dwCounter;
+ }
+
+ fprintf(stderr, "Logging to %s\n", szFileName);
+ g_gzFile = gzopen(szFileName, "wb");
}
static inline void Write(const char *sBuffer, size_t dwBytesToWrite) {
- if(g_gzFile == NULL)
- return;
-
- gzwrite(g_gzFile, sBuffer, dwBytesToWrite);
-}
-
-static inline void Write(const char *szText) {
- Write(szText, strlen(szText));
-}
-
-static inline void Write(char c)
-{
- Write(&c, 1);
-}
-
-static inline void
-WriteF(const char *format, ...)
-{
- char szBuffer[4096];
- va_list ap;
- va_start(ap, format);
- vsnprintf(szBuffer, sizeof(szBuffer), format, ap);
- va_end(ap);
- Write(szBuffer);
+ if(g_gzFile == NULL)
+ return;
+
+ gzwrite(g_gzFile, sBuffer, dwBytesToWrite);
}
static inline void
-Escape(wchar_t c)
-{
- switch(c) {
- case '&':
- Write("&amp;");
- break;
- case '<':
- Write("&lt;");
- break;
- case '>':
- Write("&gt;");
- break;
- case '"':
- Write("&quot;");
- break;
- case '\'':
- Write("&apos;");
- break;
- case '\t':
- Write("&#09;");
- break;
- case '\r':
- Write("&#13;");
- break;
- case '\n':
- Write("&#10;");
- break;
- default:
- if (c >= 0x20 && c <= 0x7e) {
- Write((char)c);
- } else {
- Write('.');
- }
- }
+WriteByte(char c) {
+ Write(&c, 1);
}
-static inline void
-Escape(const char *s)
-{
- unsigned char c;
- while((c = *s++) != 0) {
- Escape(c);
- }
-}
+void inline
+WriteUInt(unsigned long long value) {
+ char buf[2 * sizeof value];
+ unsigned len;
-static inline void
-Escape(const wchar_t *s)
-{
- unsigned char c;
- while((c = *s++) != 0) {
- Escape(c);
- }
-}
+ len = 0;
+ do {
+ assert(len < sizeof buf);
+ buf[len] = 0x80 | (value & 0x7f);
+ value >>= 7;
+ ++len;
+ } while (value);
-static inline void
-EscapeF(const char *format, ...)
-{
- char szBuffer[4096];
- va_list ap;
- va_start(ap, format);
- vsnprintf(szBuffer, sizeof(szBuffer), format, ap);
- va_end(ap);
- Escape(szBuffer);
-}
-
-static inline void
-Indent(unsigned level) {
- for(unsigned i = 0; i < level; ++i)
- Write("\t");
-}
-
-static inline void
-NewLine(void) {
- Write("\r\n");
-}
+ assert(len);
+ buf[len - 1] &= 0x7f;
-static inline void
-Tag(const char *name) {
- Write("<");
- Write(name);
- Write("/>");
+ Write(buf, len);
}
static inline void
-BeginTag(const char *name) {
- Write("<");
- Write(name);
- Write(">");
+WriteFloat(float value) {
+ assert(sizeof value == 4);
+ Write((const char *)&value, sizeof value);
}
static inline void
-BeginTag(const char *name,
- const char *attr1, const char *value1) {
- Write("<");
- Write(name);
- Write(" ");
- Write(attr1);
- Write("=\"");
- Escape(value1);
- Write("\">");
+WriteDouble(double value) {
+ assert(sizeof value == 8);
+ Write((const char *)&value, sizeof value);
}
static inline void
-BeginTag(const char *name,
- const char *attr1, const char *value1,
- const char *attr2, const char *value2) {
- Write("<");
- Write(name);
- Write(" ");
- Write(attr1);
- Write("=\"");
- Escape(value1);
- Write("\" ");
- Write(attr2);
- Write("=\"");
- Escape(value2);
- Write("\">");
-}
-
-static inline void
-BeginTag(const char *name,
- const char *attr1, const char *value1,
- const char *attr2, const char *value2,
- const char *attr3, const char *value3) {
- Write("<");
- Write(name);
- Write(" ");
- Write(attr1);
- Write("=\"");
- Escape(value1);
- Write("\" ");
- Write(attr2);
- Write("=\"");
- Escape(value2);
- Write("\" ");
- Write(attr3);
- Write("=\"");
- Escape(value3);
- Write("\">");
-}
-
-static inline void
-EndTag(const char *name) {
- Write("</");
- Write(name);
- Write(">");
+WriteString(const char *str) {
+ size_t len = strlen(str);
+ WriteUInt(len);
+ Write(str, len);
}
void Open(const char *name) {
- _Open(name, "xml");
- Write("<?xml version='1.0' encoding='UTF-8'?>");
- NewLine();
- Write("<?xml-stylesheet type='text/xsl' href='apitrace.xsl'?>");
- NewLine();
- BeginTag("trace");
- NewLine();
+ _Open(name, "trace");
+ WriteUInt(TRACE_VERSION);
}
void Close(void) {
- EndTag("trace");
- NewLine();
- _Close();
+ _Close();
}
void BeginCall(const char *function) {
- OS::AcquireMutex();
- Indent(1);
- BeginTag("call", "name", function);
- NewLine();
+ OS::AcquireMutex();
+ WriteString(function);
}
void EndCall(void) {
- Indent(1);
- EndTag("call");
- NewLine();
- gzflush(g_gzFile, Z_SYNC_FLUSH);
- OS::ReleaseMutex();
+ WriteByte(Trace::CALL_END);
+ gzflush(g_gzFile, Z_SYNC_FLUSH);
+ OS::ReleaseMutex();
}
void BeginArg(const char *type, const char *name) {
- Indent(2);
- BeginTag("arg", "type", type, "name", name);
+ WriteByte(Trace::CALL_ARG);
+ WriteString(name);
}
-void EndArg(void) {
- EndTag("arg");
- NewLine();
-}
+void EndArg(void) { }
void BeginReturn(const char *type) {
- Indent(2);
- BeginTag("ret", "type", type);
+ WriteByte(Trace::CALL_RET);
}
-void EndReturn(void) {
- EndTag("ret");
- NewLine();
-}
+void EndReturn(void) { }
-void BeginArray(const char *type, size_t length)
-{
- BeginTag("array", "type", type);
+void BeginArray(const char *type, size_t length) {
+ WriteByte(Trace::TYPE_ARRAY);
+ WriteUInt(length);
}
-void EndArray(void)
-{
- EndTag("array");
-}
+void EndArray(void) { }
-void BeginElement(const char *type)
-{
- BeginTag("elem", "type", type);
-}
+void BeginElement(const char *type) { }
-void EndElement(void)
-{
- EndTag("elem");
-}
+void EndElement(void) { }
-void BeginStruct(const char *type)
-{
- BeginTag("struct", "type", type);
+void BeginStruct(const char *type) {
+ WriteByte(Trace::TYPE_STRUCT);
}
-void EndStruct(void)
-{
- EndTag("struct");
+void EndStruct(void) {
+ WriteString("");
}
-void BeginMember(const char *type, const char *name)
-{
- BeginTag("member", "type", type, "name", name);
+void BeginMember(const char *type, const char *name) {
+ WriteString(name);
}
-void EndMember(void)
-{
- EndTag("member");
-}
+void EndMember(void) { }
-void BeginBitmask(const char *type)
-{
- BeginTag("bitmask");
+void BeginBitmask(const char *type) {
+ WriteByte(Trace::TYPE_BITMASK);
}
-void EndBitmask(void)
-{
- EndTag("bitmask");
+void EndBitmask(void) {
+ WriteByte(Trace::TYPE_VOID);
}
void BeginPointer(const char *type, const void *addr)
{
- char saddr[256];
- snprintf(saddr, sizeof(saddr), "%p", addr);
- BeginTag("ref", "type", type, "addr", saddr);
+ WriteByte(Trace::TYPE_POINTER);
+ WriteUInt((size_t)addr);
}
-void EndPointer(void)
-{
- EndTag("ref");
+void EndPointer(void) { }
+
+void LiteralBool(bool value) {
+ WriteByte(Trace::TYPE_BOOL);
+ WriteByte(value ? 0 : 1);
}
-void LiteralBool(bool value)
-{
- BeginTag("bool");
- WriteF("%u", value ? 0 : 1);
- EndTag("bool");
+void LiteralSInt(signed long long value) {
+ if (value < 0) {
+ WriteByte(Trace::TYPE_SINT);
+ WriteUInt(-value);
+ } else {
+ WriteByte(Trace::TYPE_UINT);
+ WriteUInt(value);
+ }
}
-void LiteralSInt(signed long long value)
-{
- BeginTag("int");
- WriteF("%lli", value);
- EndTag("int");
+void LiteralUInt(unsigned long long value) {
+ WriteByte(Trace::TYPE_UINT);
+ WriteUInt(value);
}
-void LiteralUInt(unsigned long long value)
-{
- BeginTag("uint");
- WriteF("%llu", value);
- EndTag("uint");
+void LiteralFloat(float value) {
+ WriteByte(Trace::TYPE_FLOAT);
+ WriteFloat(value);
}
-void LiteralFloat(double value)
-{
- BeginTag("float");
- WriteF("%f", value);
- EndTag("float");
+void LiteralFloat(double value) {
+ WriteByte(Trace::TYPE_DOUBLE);
+ WriteDouble(value);
}
-void LiteralString(const char *str)
-{
- if (!str) {
- LiteralNull();
- return;
- }
- BeginTag("string");
- Escape(str);
- EndTag("string");
+void LiteralString(const char *str) {
+ if (!str) {
+ LiteralNull();
+ return;
+ }
+ WriteByte(Trace::TYPE_STRING);
+ WriteString(str);
}
-void LiteralWString(const wchar_t *str)
-{
- if (!str) {
- LiteralNull();
- return;
- }
- BeginTag("wstring");
- Escape(str);
- EndTag("wstring");
+void LiteralWString(const wchar_t *str) {
+
+ if (!str) {
+ LiteralNull();
+ return;
+ }
+ WriteByte(Trace::TYPE_STRING);
+ WriteString("<wide-string>");
}
-
-void LiteralNamedConstant(const char *str)
-{
- BeginTag("const");
- Escape(str);
- EndTag("const");
+
+void LiteralNamedConstant(const char *name, long long value) {
+ WriteByte(Trace::TYPE_CONST);
+ WriteString(name);
+ LiteralSInt(value);
}
-void LiteralNull(void)
-{
- Tag("null");
+void LiteralNull(void) {
+ WriteByte(Trace::TYPE_POINTER);
+ WriteUInt(0);
+ WriteByte(Trace::TYPE_OPAQUE);
}
-void LiteralOpaque(void)
-{
- Tag("opaque");
+void LiteralOpaque(void) {
+ WriteByte(Trace::TYPE_OPAQUE);
}
} /* namespace Log */
diff --git a/log.hpp b/log.hpp
index b05541b5..fa1f91e2 100644
--- a/log.hpp
+++ b/log.hpp
@@ -1,6 +1,6 @@
/**************************************************************************
*
- * Copyright 2007-2009 VMware, Inc.
+ * Copyright 2007-2010 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -61,10 +61,11 @@ namespace Log {
void LiteralBool(bool value);
void LiteralSInt(signed long long value);
void LiteralUInt(unsigned long long value);
+ void LiteralFloat(float value);
void LiteralFloat(double value);
void LiteralString(const char *str);
void LiteralWString(const wchar_t *str);
- void LiteralNamedConstant(const char *str);
+ void LiteralNamedConstant(const char *name, long long value);
void LiteralNull(void);
void LiteralOpaque(void);
}
diff --git a/trace_format.hpp b/trace_format.hpp
new file mode 100644
index 00000000..fe37a801
--- /dev/null
+++ b/trace_format.hpp
@@ -0,0 +1,89 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef _TRACE_FORMAT_HPP_
+#define _TRACE_FORMAT_HPP_
+
+namespace Trace {
+
+#define TRACE_VERSION 0
+
+enum CallDetail {
+ CALL_END = 0,
+ CALL_ARG,
+ CALL_RET,
+ CALL_THREAD,
+};
+
+enum Type {
+ TYPE_VOID = 0,
+ TYPE_BOOL,
+ TYPE_SINT,
+ TYPE_UINT,
+ TYPE_FLOAT,
+ TYPE_DOUBLE,
+ TYPE_STRING, // Null terminated, human readible string
+ TYPE_BLOB, // Block of bytes
+ TYPE_CONST,
+ TYPE_BITMASK,
+ TYPE_ARRAY,
+ TYPE_STRUCT,
+ TYPE_POINTER,
+ TYPE_OPAQUE,
+};
+
+/*
+ * trace = call* EOF
+ *
+ * call = name (detail)* END
+ *
+ * detail = ARG name value
+ * | RET value
+ * | ...
+ *
+ * value = VOID
+ * | BOOL BOOL_VALUE
+ * | SINT INT_VALUE
+ * | UINT INT_VALUE
+ * | FLOAT FLOAT_VALUE
+ * | STRING string
+ * | BLOB string
+ * | CONST name value
+ * | BITMASK value+
+ * | ARRAY length
+ *
+ * bool = 0 | 1
+ *
+ * name = string
+ *
+ * string = length (BYTE)*
+ *
+ * length = INT_VALUE
+ */
+
+
+} /* namespace Trace */
+
+#endif /* _TRACE_FORMAT_HPP_ */
diff --git a/trace_model.cpp b/trace_model.cpp
new file mode 100644
index 00000000..1d33ba69
--- /dev/null
+++ b/trace_model.cpp
@@ -0,0 +1,177 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include "trace_model.hpp"
+
+
+namespace Trace {
+
+
+void Void::visit(Visitor &visitor) {
+ visitor.visit(this);
+}
+
+void Bool::visit(Visitor &visitor) {
+ visitor.visit(this);
+}
+
+void SInt::visit(Visitor &visitor) {
+ visitor.visit(this);
+}
+
+void UInt::visit(Visitor &visitor) {
+ visitor.visit(this);
+}
+
+void Float::visit(Visitor &visitor) {
+ visitor.visit(this);
+}
+
+void String::visit(Visitor &visitor) {
+ visitor.visit(this);
+}
+
+void Const::visit(Visitor &visitor) {
+ visitor.visit(this);
+}
+
+void Array::visit(Visitor &visitor) {
+ visitor.visit(this);
+}
+
+
+class Dumper : public Visitor
+{
+public:
+ std::ostream &os;
+
+ Dumper() : os(std::cout) {}
+
+ Dumper(std::ostream &_os) : os(_os) {}
+
+ void visit(Void *node) {
+ }
+
+ void visit(Bool *node) {
+ os << (node->value ? "true" : "false");
+ }
+
+ void visit(SInt *node) {
+ os << node->value;
+ }
+
+ void visit(UInt *node) {
+ os << node->value;
+ }
+
+ void visit(Float *node) {
+ os << node->value;
+ }
+
+ void visit(String *node) {
+ os << '"' << node->value << '"';
+ }
+
+ void visit(Const *node) {
+ os << node->name;
+ }
+
+ void visit(Array *node) {
+ const char *sep = "";
+ os << "{";
+ for (std::vector<Value *>::iterator it = node->values.begin(); it != node->values.end(); ++it) {
+ os << sep;
+ (*it)->visit(*this);
+ sep = ", ";
+ }
+ os << "}";
+ }
+};
+
+
+std::ostream & operator <<(std::ostream &os, Value *value) {
+ Dumper d(os);
+ if (value) {
+ value->visit(d);
+ }
+ return os;
+}
+
+
+static const Value *unwrap(const Value *node) {
+ const Const *c = dynamic_cast<const Const *>(node);
+ if (c)
+ return c->value;
+ return node;
+}
+
+signed long long asSInt(const Value *node) {
+ node = unwrap(node);
+ const SInt *sint = dynamic_cast<const SInt *>(node);
+ if (sint)
+ return sint->value;
+ const UInt *uint = dynamic_cast<const UInt *>(node);
+ if (uint)
+ return uint->value;
+ assert(0);
+ return 0;
+}
+
+unsigned long long asUInt(const Value *node) {
+ node = unwrap(node);
+ const UInt *uint = dynamic_cast<const UInt *>(node);
+ if (uint)
+ return uint->value;
+ assert(0);
+ return 0;
+}
+
+
+double asFloat(const Value *node) {
+ node = unwrap(node);
+ const Float *fl = dynamic_cast<const Float *>(node);
+ assert(fl);
+ return fl->value;
+}
+
+
+std::ostream & operator <<(std::ostream &os, Call &call) {
+ const char *sep = "";
+ os << call.name << "(";
+ for (std::list<Arg>::iterator it = call.args.begin(); it != call.args.end(); ++it) {
+ os << sep << it->first << " = " << it->second;
+ sep = ", ";
+ }
+ os << ")";
+ if (call.ret) {
+ os << " = " << call.ret;
+ }
+ os << "\n";
+ return os;
+}
+
+
+} /* namespace Trace */
diff --git a/trace_model.hpp b/trace_model.hpp
new file mode 100644
index 00000000..9bb3e1d6
--- /dev/null
+++ b/trace_model.hpp
@@ -0,0 +1,189 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef _TRACE_MODEL_HPP_
+#define _TRACE_MODEL_HPP_
+
+
+#include <cassert>
+
+#include <string>
+#include <map>
+#include <list>
+#include <vector>
+#include <iostream>
+
+
+namespace Trace {
+
+
+class Visitor;
+class Dumper;
+class UInt;
+
+
+class Value
+{
+public:
+ virtual void visit(Visitor &visitor) = 0;
+};
+
+
+class Void : public Value
+{
+public:
+ void visit(Visitor &visitor);
+};
+
+
+class Bool : public Value
+{
+public:
+ Bool(bool _value) : value(_value) {}
+
+ void visit(Visitor &visitor);
+
+ bool value;
+};
+
+
+class SInt : public Value
+{
+public:
+ SInt(signed long long _value) : value(_value) {}
+
+ void visit(Visitor &visitor);
+
+ signed long long value;
+};
+
+
+class UInt : public Value
+{
+public:
+ UInt(unsigned long long _value) : value(_value) {}
+
+ void visit(Visitor &visitor);
+
+ unsigned long long value;
+};
+
+
+class Float : public Value
+{
+public:
+ Float(double _value) : value(_value) {}
+
+ void visit(Visitor &visitor);
+
+ double value;
+};
+
+
+class String : public Value
+{
+public:
+ String(std::string _value) : value(_value) {}
+
+ void visit(Visitor &visitor);
+
+ std::string value;
+};
+
+
+class Const : public Value
+{
+public:
+ Const(std::string _name, Value *_value) : name(_name), value(_value) {}
+
+ void visit(Visitor &visitor);
+
+ std::string name;
+ Value *value;
+};
+
+
+class Array : public Value
+{
+public:
+ Array(size_t len) : values(len) {}
+
+ void visit(Visitor &visitor);
+
+ std::vector<Value *> values;
+};
+
+
+class Visitor
+{
+public:
+ virtual void visit(Void *) {assert(0);}
+ virtual void visit(Bool *) {assert(0);}
+ virtual void visit(SInt *) {assert(0);}
+ virtual void visit(UInt *) {assert(0);}
+ virtual void visit(Float *) {assert(0);}
+ virtual void visit(String *) {assert(0);}
+ virtual void visit(Const *) {assert(0);}
+ virtual void visit(Array *) {assert(0);}
+};
+
+
+std::ostream & operator <<(std::ostream &os, Value *value);
+
+
+signed long long asSInt(const Value *node);
+unsigned long long asUInt(const Value *node);
+double asFloat(const Value *node);
+
+
+typedef std::pair<std::string, Value *> Arg;
+
+class Call
+{
+public:
+ std::string name;
+ std::list<Arg> args;
+ Value *ret;
+
+ Call() : ret(0) { }
+
+ Value * get_arg(const char *name) {
+ for (std::list<Arg>::iterator it = args.begin(); it != args.end(); ++it) {
+ if (it->first == name) {
+ return it->second;
+ }
+ }
+ return NULL;
+ }
+};
+
+
+
+std::ostream & operator <<(std::ostream &os, Call &call);
+
+
+} /* namespace Trace */
+
+#endif /* _TRACE_MODEL_HPP_ */
diff --git a/trace_parser.hpp b/trace_parser.hpp
new file mode 100644
index 00000000..50f315ca
--- /dev/null
+++ b/trace_parser.hpp
@@ -0,0 +1,253 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef _TRACE_PARSER_HPP_
+#define _TRACE_PARSER_HPP_
+
+
+#include <cassert>
+
+#include <iostream>
+
+#include <zlib.h>
+
+#include "trace_format.hpp"
+#include "trace_model.hpp"
+
+
+namespace Trace {
+
+
+class Parser
+{
+protected:
+ gzFile file;
+public:
+ Parser() {
+ file = NULL;
+ }
+
+ bool parse(const char *filename) {
+ unsigned long long version;
+
+ file = gzopen(filename, "rb");
+ if (!file) {
+ return false;
+ }
+
+ version = read_uint();
+ if (version != TRACE_VERSION) {
+ std::cerr << "Unsupported format version" << version << "\n";
+ return false;
+ }
+
+ while (!gzeof(file)) {
+ parse_call();
+ }
+
+ return true;
+ }
+
+ void parse_call(void) {
+ Call call;
+ call.name = read_string();
+ int c;
+ do {
+ c = gzgetc(file);
+ if (c == Trace::CALL_END || c == -1) {
+ break;
+ }
+ switch(c) {
+ case Trace::CALL_END:
+ return;
+ case Trace::CALL_ARG:
+ call.args.push_back(parse_arg());
+ break;
+ case Trace::CALL_RET:
+ call.ret = parse_value();
+ break;
+ default:
+ assert(0);
+ std::cerr << "Unknown call detail " << c << "\n";
+ break;
+ }
+ } while(true);
+ handle_call(call);
+ }
+
+ virtual void handle_call(Call &call) {
+ std::cout << call;
+ }
+
+ Arg parse_arg(void) {
+ std::string name = read_string();
+ Value *value = parse_value();
+ return Arg(name, value);
+ }
+
+ Value *parse_value(void) {
+ int c;
+ c = gzgetc(file);
+ switch(c) {
+ case Trace::TYPE_BOOL:
+ return parse_bool();
+ case Trace::TYPE_SINT:
+ return parse_sint();
+ case Trace::TYPE_UINT:
+ return parse_uint();
+ case Trace::TYPE_FLOAT:
+ return parse_float();
+ case Trace::TYPE_DOUBLE:
+ return parse_double();
+ case Trace::TYPE_STRING:
+ return parse_string();
+ case Trace::TYPE_CONST:
+ return parse_const();
+ case Trace::TYPE_BITMASK:
+ return parse_bitmask();
+ case Trace::TYPE_ARRAY:
+ return parse_array();
+ case Trace::TYPE_POINTER:
+ return parse_pointer();
+ case Trace::TYPE_VOID:
+ return NULL;
+ default:
+ std::cerr << "Unknown type " << c << "\n";
+ assert(0);
+ return NULL;
+ }
+ }
+
+ Value *parse_bool() {
+ int c;
+ c = gzgetc(file);
+ return new Bool(c);
+ }
+
+ Value *parse_sint() {
+ return new SInt(-read_uint());
+ }
+
+ Value *parse_uint() {
+ return new UInt(read_uint());
+ }
+
+ Value *parse_float() {
+ float value;
+ gzread(file, &value, sizeof value);
+ return new Float(value);
+ }
+
+ Value *parse_double() {
+ double value;
+ gzread(file, &value, sizeof value);
+ return new Float(value);
+ }
+
+ Value *parse_string() {
+ return new String(read_string());
+ }
+
+ Value *parse_const() {
+ std::string name = read_string();
+ Value *value = parse_value();
+ return new Const(name, value);
+ }
+
+ Value *parse_bitmask() {
+ unsigned long long value = 0;
+ int c;
+ do {
+ c = gzgetc(file);
+ switch(c) {
+ case Trace::TYPE_SINT:
+ value |= -read_uint();
+ break;
+ case Trace::TYPE_UINT:
+ value |= read_uint();
+ break;
+ case Trace::TYPE_CONST:
+ read_string();
+ break;
+ case Trace::TYPE_VOID:
+ goto done;
+ default:
+ std::cerr << "Unexpected type " << c << "\n";
+ assert(0);
+ return NULL;
+ }
+ } while(true);
+done:
+ return new UInt(value);
+ }
+
+ Value *parse_array() {
+ size_t len = read_uint();
+ Array *array = new Array(len);
+ for (size_t i = 0; i < len; ++i) {
+ array->values[i] = parse_value();
+ }
+ return array;
+ }
+
+ Value *parse_pointer() {
+ unsigned long long addr;
+ Value *value;
+ addr = read_uint();
+ value = parse_value();
+ if (!value)
+ value = new UInt(addr);
+ return value;
+ }
+
+ std::string read_string(void) {
+ size_t len = read_uint();
+ char * buf = new char[len];
+ gzread(file, buf, len);
+ std::string value(buf, len);
+ delete [] buf;
+ return value;
+ }
+
+ unsigned long long read_uint(void) {
+ unsigned long long value = 0;
+ int c;
+ unsigned shift = 0;
+ do {
+ c = gzgetc(file);
+ if (c == -1) {
+ break;
+ }
+ value |= (unsigned long long)(c & 0x7f) << shift;
+ shift += 7;
+ } while(c & 0x80);
+ return value;
+ }
+};
+
+
+} /* namespace Trace */
+
+#endif /* _TRACE_PARSER_HPP_ */
diff --git a/xml2txt.py b/xml2txt.py
deleted file mode 100755
index e0c5efde..00000000
--- a/xml2txt.py
+++ /dev/null
@@ -1,451 +0,0 @@
-#!/usr/bin/env python
-##########################################################################
-#
-# Copyright 2008-2009 VMware, Inc.
-# All Rights Reserved.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-##########################################################################/
-
-
-import sys
-import optparse
-import xml.parsers.expat
-import gzip
-
-from model import *
-
-
-ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF = range(4)
-
-
-class XmlToken:
-
- def __init__(self, type, name_or_data, attrs = None, line = None, column = None):
- assert type in (ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF)
- self.type = type
- self.name_or_data = name_or_data
- self.attrs = attrs
- self.line = line
- self.column = column
-
- def __str__(self):
- if self.type == ELEMENT_START:
- return '<' + self.name_or_data + ' ...>'
- if self.type == ELEMENT_END:
- return '</' + self.name_or_data + '>'
- if self.type == CHARACTER_DATA:
- return self.name_or_data
- if self.type == EOF:
- return 'end of file'
- assert 0
-
-
-class XmlTokenizer:
- """Expat based XML tokenizer."""
-
- def __init__(self, fp, skip_ws = True):
- self.fp = fp
- self.tokens = []
- self.index = 0
- self.final = False
- self.skip_ws = skip_ws
-
- self.character_pos = 0, 0
- self.character_data = ''
-
- self.parser = xml.parsers.expat.ParserCreate()
- self.parser.StartElementHandler = self.handle_element_start
- self.parser.EndElementHandler = self.handle_element_end
- self.parser.CharacterDataHandler = self.handle_character_data
-
- def handle_element_start(self, name, attributes):
- self.finish_character_data()
- line, column = self.pos()
- token = XmlToken(ELEMENT_START, name, attributes, line, column)
- self.tokens.append(token)
-
- def handle_element_end(self, name):
- self.finish_character_data()
- line, column = self.pos()
- token = XmlToken(ELEMENT_END, name, None, line, column)
- self.tokens.append(token)
-
- def handle_character_data(self, data):
- if not self.character_data:
- self.character_pos = self.pos()
- self.character_data += data
-
- def finish_character_data(self):
- if self.character_data:
- if not self.skip_ws or not self.character_data.isspace():
- line, column = self.character_pos
- token = XmlToken(CHARACTER_DATA, self.character_data, None, line, column)
- self.tokens.append(token)
- self.character_data = ''
-
- def next(self):
- size = 16*1024
- while self.index >= len(self.tokens) and not self.final:
- self.tokens = []
- self.index = 0
- data = self.fp.read(size)
- self.final = len(data) < size
- data = data.rstrip('\0')
- try:
- self.parser.Parse(data, self.final)
- except xml.parsers.expat.ExpatError, e:
- #if e.code == xml.parsers.expat.errors.XML_ERROR_NO_ELEMENTS:
- if e.code == 3:
- pass
- else:
- raise e
- if self.index >= len(self.tokens):
- line, column = self.pos()
- token = XmlToken(EOF, None, None, line, column)
- else:
- token = self.tokens[self.index]
- self.index += 1
- return token
-
- def pos(self):
- return self.parser.CurrentLineNumber, self.parser.CurrentColumnNumber
-
-
-class TokenMismatch(Exception):
-
- def __init__(self, expected, found):
- self.expected = expected
- self.found = found
-
- def __str__(self):
- return '%u:%u: %s expected, %s found' % (self.found.line, self.found.column, str(self.expected), str(self.found))
-
-
-
-class XmlParser:
- """Base XML document parser."""
-
- def __init__(self, fp):
- self.tokenizer = XmlTokenizer(fp)
- self.consume()
-
- def consume(self):
- self.token = self.tokenizer.next()
-
- def match_element_start(self, name):
- return self.token.type == ELEMENT_START and self.token.name_or_data == name
-
- def match_element_end(self, name):
- return self.token.type == ELEMENT_END and self.token.name_or_data == name
-
- def element_start(self, name):
- while self.token.type == CHARACTER_DATA:
- self.consume()
- if self.token.type != ELEMENT_START:
- raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token)
- if self.token.name_or_data != name:
- raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token)
- attrs = self.token.attrs
- self.consume()
- return attrs
-
- def element_end(self, name):
- while self.token.type == CHARACTER_DATA:
- self.consume()
- if self.token.type != ELEMENT_END:
- raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token)
- if self.token.name_or_data != name:
- raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token)
- self.consume()
-
- def character_data(self, strip = True):
- data = ''
- while self.token.type == CHARACTER_DATA:
- data += self.token.name_or_data
- self.consume()
- if strip:
- data = data.strip()
- return data
-
-
-class GzipFile(gzip.GzipFile):
-
- def _read_eof(self):
- # Ignore incomplete files
- try:
- gzip.GzipFile._read_eof(self)
- except IOError:
- pass
-
-
-class TraceParser(XmlParser):
-
- def __init__(self, stream):
- XmlParser.__init__(self, stream)
- self.call_no = 0
-
- def parse(self):
- self.element_start('trace')
- while self.token.type not in (ELEMENT_END, EOF):
- self.parse_call()
- if self.token.type != EOF:
- self.element_end('trace')
-
- def parse_call(self):
- attrs = self.element_start('call')
- name = attrs['name']
- args = []
- ret = None
- properties = {}
- while self.token.type == ELEMENT_START:
- if self.token.name_or_data == 'arg':
- arg = self.parse_arg()
- args.append(arg)
- elif self.token.name_or_data == 'ret':
- ret = self.parse_ret()
- elif self.token.name_or_data in ('duration', 'starttsc', 'endtsc'):
- property = self.token.name_or_data
- properties[property] = self.parse_hex(self.token.name_or_data)
- elif self.token.name_or_data == 'call':
- # ignore nested function calls
- self.parse_call()
- else:
- raise TokenMismatch("<arg ...> or <ret ...>", self.token)
- self.element_end('call')
-
- self.call_no += 1
-
- call = Call(self.call_no, name, args, ret, properties)
-
- self.handle_call(call)
-
- def parse_arg(self):
- attrs = self.element_start('arg')
- name = attrs['name']
- value = self.parse_value()
- self.element_end('arg')
-
- return name, value
-
- def parse_ret(self):
- attrs = self.element_start('ret')
- value = self.parse_value()
- self.element_end('ret')
-
- return value
-
- def parse_hex(self, token_name):
- attrs = self.element_start(token_name)
- value = int(self.character_data(), 16)
- self.element_end(token_name)
- return value
-
- def parse_value(self):
- if self.token.type == ELEMENT_START:
- if self.token.name_or_data == 'int':
- return self.parse_int()
- if self.token.name_or_data == 'uint':
- return self.parse_uint()
- if self.token.name_or_data == 'float':
- return self.parse_float()
- if self.token.name_or_data == 'string':
- return self.parse_string()
- if self.token.name_or_data == 'wstring':
- return self.parse_wstring()
- if self.token.name_or_data == 'const':
- return self.parse_const()
- if self.token.name_or_data == 'bitmask':
- return self.parse_bitmask()
- if self.token.name_or_data == 'ref':
- return self.parse_ref()
- raise TokenMismatch("<elem ...>, <ref ...>, or text", self.token)
-
- def parse_elems(self):
- elems = [self.parse_elem()]
- while self.token.type != ELEMENT_END:
- elems.append(self.parse_elem())
- return Struct("", elems)
-
- def parse_elem(self):
- attrs = self.element_start('elem')
- value = self.parse_value()
- self.element_end('elem')
-
- try:
- name = attrs['name']
- except KeyError:
- name = ""
-
- return name, value
-
- def parse_ref(self):
- attrs = self.element_start('ref')
- if self.token.type != ELEMENT_END:
- value = self.parse_value()
- else:
- value = None
- self.element_end('ref')
-
- return Pointer(attrs['addr'], value)
-
- def parse_bitmask(self):
- self.element_start('bitmask')
- elems = []
- while self.token.type != ELEMENT_END:
- elems.append(self.parse_value())
- self.element_end('bitmask')
- return Bitmask(elems)
-
- def parse_int(self):
- self.element_start('int')
- value = self.character_data()
- self.element_end('int')
- return Literal(int(value))
-
- def parse_uint(self):
- self.element_start('uint')
- value = self.character_data()
- self.element_end('uint')
- return Literal(int(value))
-
- def parse_float(self):
- self.element_start('float')
- value = self.character_data()
- self.element_end('float')
- return Literal(float(value))
-
- def parse_string(self):
- self.element_start('string')
- value = self.character_data()
- self.element_end('string')
- return Literal(value)
-
- def parse_wstring(self):
- self.element_start('wstring')
- value = self.character_data()
- self.element_end('wstring')
- return Literal(value)
-
- def parse_const(self):
- self.element_start('const')
- value = self.character_data()
- self.element_end('const')
- return NamedConstant(value)
-
- def handle_call(self, call):
- pass
-
-
-class DumpTraceParser(TraceParser):
-
- def __init__(self, stream, formatter):
- XmlParser.__init__(self, stream)
- self.formatter = formatter
- self.pretty_printer = PrettyPrinter(self.formatter)
- self.call_no = 0
-
- def handle_call(self, call):
- call.visit(self.pretty_printer)
- self.formatter.newline()
-
-
-class StatsTraceParser(TraceParser):
-
- def __init__(self, stream, formatter):
- TraceParser.__init__(self, stream, formatter)
- self.stats = {}
-
- def parse(self):
- TraceParser.parse(self)
-
- sys.stdout.write('%s\t%s\t%s\n' % ("name", "calls", "duration"))
- for name, (calls, duration) in self.stats.iteritems():
- sys.stdout.write('%s\t%u\t%f\n' % (name, calls, duration/1000000.0))
-
- def handle_call(self, name, args, ret, duration):
- try:
- nr_calls, total_duration = self.stats[name]
- except KeyError:
- nr_calls = 1
- total_duration = duration
- else:
- nr_calls += 1
- if duration is not None:
- total_duration += duration
- self.stats[name] = nr_calls, total_duration
-
-
-class Main:
-
- def __init__(self):
- pass
-
- def main(self):
- optparser = self.get_optparser()
- (options, args) = optparser.parse_args(sys.argv[1:])
-
- if args:
- for arg in args:
- if arg.endswith('.gz'):
- from gzip import GzipFile
- stream = GzipFile(arg, 'rb')
- elif arg.endswith('.bz2'):
- from bz2 import BZ2File
- stream = BZ2File(arg, 'rU')
- else:
- stream = open(arg, 'rt')
- self.process_arg(stream, options)
- else:
- self.process_arg(stream, options)
-
- def get_optparser(self):
- optparser = optparse.OptionParser(
- usage="\n\t%prog [options] [traces] ...")
- optparser.add_option(
- '-s', '--stats',
- action="store_true",
- dest="stats", default=False,
- help="generate statistics instead")
- optparser.add_option(
- '--color', '--colour',
- type="choice", choices=('never', 'always', 'auto'), metavar='WHEN',
- dest="color", default="always",
- help="coloring: never, always, or auto [default: %default]")
- return optparser
-
- def process_arg(self, stream, options):
- if options.color == 'always' or options.color == 'auto' and sys.stdout.isatty():
- formatter = format.DefaultFormatter(sys.stdout)
- else:
- formatter = format.Formatter(sys.stdout)
-
- if options.stats:
- factory = StatsTraceParser
- else:
- factory = DumpTraceParser
-
- parser = DumpTraceParser(stream, formatter)
- parser.parse()
-
-
-if __name__ == '__main__':
- Main().main()
-