]> git.cworth.org Git - apitrace/commitdiff
First stab at binary trace and retracing.
authorJosé Fonseca <jfonseca@vmware.com>
Fri, 19 Nov 2010 17:05:18 +0000 (17:05 +0000)
committerJosé Fonseca <jfonseca@vmware.com>
Fri, 19 Nov 2010 17:05:18 +0000 (17:05 +0000)
It's enough to retrace trivial/tri Mesa demo.

13 files changed:
.gitignore
CMakeLists.txt
apitrace.xsl [deleted file]
base.py
dump.cpp [new file with mode: 0644]
glretrace.py [new file with mode: 0644]
log.cpp
log.hpp
trace_format.hpp [new file with mode: 0644]
trace_model.cpp [new file with mode: 0644]
trace_model.hpp [new file with mode: 0644]
trace_parser.hpp [new file with mode: 0644]
xml2txt.py [deleted file]

index 7fac701286dc7d08693a9b8ce98be39df84349b1..32ddb972723bec06dee86a28a9039005094a30dd 100644 (file)
@@ -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
index 9ae07409de8c3cfd9e1f1455d3b5403f4b170808..41f896bdcc073bed0f8b27f2156ee3b1af3c4ae5 100644 (file)
@@ -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 (file)
index ccb4d80..0000000
+++ /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 e672a3ced1ebd22551109eaeffb340de509529b2..3c93c424dd16a7f74601b1f6af217fb93cbdd677 100644 (file)
--- 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 (file)
index 0000000..09d74c4
--- /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 (file)
index 0000000..82cd713
--- /dev/null
@@ -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 a7128f802272d3be25c00c96a4e322170274b44d..a78ba5358e627dc1d3b44fa296c68a0f56f77ad6 100644 (file)
--- 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 b05541b5a7acef114f1581a29f0f80766979d434..fa1f91e2b7a08afca932bd28f60a7aada064724e 100644 (file)
--- 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 (file)
index 0000000..fe37a80
--- /dev/null
@@ -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 (file)
index 0000000..1d33ba6
--- /dev/null
@@ -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 (file)
index 0000000..9bb3e1d
--- /dev/null
@@ -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 (file)
index 0000000..50f315c
--- /dev/null
@@ -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 (executable)
index e0c5efd..0000000
+++ /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()
-