]> git.cworth.org Git - apitrace/blobdiff - trace_parser.hpp
More efficient enum representation.
[apitrace] / trace_parser.hpp
index 565ccaa8f830d7cce0bd806755ef1cec50ffc3f9..254141c1bb6f66b4b4f4a9a830c5b8b10db4bff8 100644 (file)
@@ -30,6 +30,8 @@
 #include <cassert>
 
 #include <iostream>
+#include <map>
+#include <string>
 
 #include <zlib.h>
 
@@ -37,6 +39,9 @@
 #include "trace_model.hpp"
 
 
+#define TRACE_VERBOSE 0
+
+
 namespace Trace {
 
 
@@ -44,12 +49,35 @@ class Parser
 {
 protected:
    gzFile file;
+
+   typedef std::map<size_t, std::string> namemap;
+   namemap names;
+
+   typedef std::map<unsigned, Call *> callmap;
+   callmap calls;
+
+   typedef std::map<size_t, Call::Signature *> FunctionMap;
+   FunctionMap functions;
+
+   typedef std::map<size_t, Enum *> EnumMap;
+   EnumMap enums;
+
+   typedef std::map<size_t, Bitmask::Signature *> BitmaskMap;
+   BitmaskMap bitmasks;
+
+   unsigned next_call_no;
+
 public:
    Parser() {
       file = NULL;
+      next_call_no = 0;
    }
 
-   bool parse(const char *filename) {
+   ~Parser() {
+      close();
+   }
+
+   bool open(const char *filename) {
       unsigned long long version;
 
       file = gzopen(filename, "rb");
@@ -63,54 +91,111 @@ public:
          return false;
       }
 
-      while (!gzeof(file)) {
-         parse_call();
-      }
-
       return true;
    }
 
-   void parse_call(void) {
-      Call call;
-      call.name = read_string();
-      int c;
+   void close(void) {
+      if (file) {
+         gzclose(file);
+         file = NULL;
+      }
+   }
+
+   Call *parse_call(void) {
       do {
-         c = gzgetc(file);
-         if (c == Trace::CALL_END || c == -1) {
+         int c = read_byte();
+         switch(c) {
+         case Trace::EVENT_ENTER:
+            parse_enter();
             break;
+         case Trace::EVENT_LEAVE:
+            return parse_leave();
+         case Trace::EVENT_MESSAGE:
+            std::cerr << "message: " << read_string() << "\n";
+            break;
+         default:
+            std::cerr << "error: unknown call detail " << c << "\n";
+            assert(0);
+            /* fallthrough */
+         case -1:
+            return NULL;
          }
+      } while(true);
+   }
+   
+   void parse_enter(void) {
+      size_t id = read_uint();
+
+      Call::Signature *sig;
+      FunctionMap::const_iterator it = functions.find(id);
+      if (it == functions.end()) {
+          sig = new Call::Signature;
+          sig->name = read_string();
+          unsigned size = read_uint();
+          for (unsigned i = 0; i < size; ++i) {
+              sig->arg_names.push_back(read_string());
+          }
+          functions[id] = sig;
+      } else {
+          sig = it->second;
+      }
+      assert(sig);
+
+      Call *call = new Call(sig);
+      call->no = next_call_no++;
+
+      parse_call_details(call);
+      calls[call->no] = call;
+   }
+   
+   Call *parse_leave(void) {
+      unsigned call_no = read_uint();
+      Call *call = calls[call_no];
+      assert(call);
+      if (!call) {
+          return NULL;
+      }
+      parse_call_details(call);
+      return call;
+   }
+   
+   void parse_call_details(Call *call) {
+      do {
+         int c = read_byte();
          switch(c) {
          case Trace::CALL_END:
             return;
          case Trace::CALL_ARG:
-            call.args.push_back(parse_arg());
+            parse_arg(call);
             break;
          case Trace::CALL_RET:
-            call.ret = parse_value();
+            call->ret = parse_value();
             break;
          default:
             std::cerr << "error: unknown call detail " << c << "\n";
             assert(0);
-            break;
+            /* fallthrough */
+         case -1:
+            return;
          }
       } while(true);
-      handle_call(call);
    }
    
-   virtual void handle_call(Call &call) {
-      std::cout << call;
-   }
-
-   Arg parse_arg(void) {
-      std::string name = read_string();
+   void parse_arg(Call *call) {
+      unsigned index = read_uint();
       Value *value = parse_value();
-      return Arg(name, value);
+      if (index >= call->args.size()) {
+          call->args.resize(index + 1);
+      }
+      call->args[index] = value;
    }
    
    Value *parse_value(void) {
       int c;
-      c = gzgetc(file);
+      c = read_byte();
       switch(c) {
+      case Trace::TYPE_NULL:
+         return new Null;
       case Trace::TYPE_FALSE:
          return new Bool(false);
       case Trace::TYPE_TRUE:
@@ -125,18 +210,18 @@ public:
          return parse_double();
       case Trace::TYPE_STRING:
          return parse_string();
-      case Trace::TYPE_CONST:
-         return parse_const();
+      case Trace::TYPE_ENUM:
+         return parse_enum();
       case Trace::TYPE_BITMASK:
          return parse_bitmask();
       case Trace::TYPE_ARRAY:
          return parse_array();
+      case Trace::TYPE_STRUCT:
+         return parse_struct();
       case Trace::TYPE_BLOB:
          return parse_blob();
-      case Trace::TYPE_POINTER:
-         return parse_pointer();
-      case Trace::TYPE_NULL:
-         return new Null;
+      case Trace::TYPE_OPAQUE:
+         return parse_opaque();
       default:
          std::cerr << "error: unknown type " << c << "\n";
          assert(0);
@@ -144,14 +229,8 @@ public:
       }
    }
 
-   Value *parse_bool() {
-      int c;
-      c = gzgetc(file);
-      return new Bool(c);
-   }
-   
    Value *parse_sint() {
-      return new SInt(-read_uint());
+      return new SInt(-(signed long long)read_uint());
    }
    
    Value *parse_uint() {
@@ -174,37 +253,43 @@ public:
       return new String(read_string());
    }
    
-   Value *parse_const() {
-      std::string name = read_string();
-      Value *value = parse_value();
-      return new Const(name, value);
+   Value *parse_enum() {
+      size_t id = read_uint();
+      Enum *sig;
+      EnumMap::const_iterator it = enums.find(id);
+      if (it == enums.end()) {
+          std::string name = read_string();
+          Value *value = parse_value();
+          sig = new Enum(name, value);
+          enums[id] = sig;
+      } else {
+          sig = it->second;
+      }
+      assert(sig);
+      return sig;
    }
    
    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_NULL:
-            goto done;
-         default:
-            std::cerr << "error: uexpected type " << c << "\n";
-            assert(0);
-            return NULL;
-         }
-      } while(true);
-done:
-      return new UInt(value);
+      size_t id = read_uint();
+      Bitmask::Signature *sig;
+      BitmaskMap::const_iterator it = bitmasks.find(id);
+      if (it == bitmasks.end()) {
+          size_t size = read_uint();
+          sig = new Bitmask::Signature(size);
+          for (Bitmask::Signature::iterator it = sig->begin(); it != sig->end(); ++it) {
+              it->first = read_string();
+              it->second = read_uint();
+              assert(it->second);
+          }
+          bitmasks[id] = sig;
+      } else {
+          sig = it->second;
+      }
+      assert(sig);
+
+      unsigned long long value = read_uint();
+
+      return new Bitmask(sig, value);
    }
 
    Value *parse_array(void) {
@@ -225,22 +310,53 @@ done:
       return blob;
    }
    
-   Value *parse_pointer() {
+   Value *parse_struct() {
+      size_t length = read_uint();
+      /* XXX */
+      for (size_t i = 0; i < length; ++i) {
+         std::string name = read_name();
+         Value *value = parse_value();
+         std::cout << "  " << name << " = " << value << "\n";
+      }
+      return NULL;
+   }
+   
+   Value *parse_opaque() {
       unsigned long long addr;
-      Value *value;
       addr = read_uint();
-      value = parse_value();
-      if (!value)
-         value = new UInt(addr);
-      return value;
+      /* XXX */
+      return new UInt(addr);
+   }
+
+   std::string read_name(void) {
+       std::string name;
+       size_t id = read_uint();
+       if (id >= names.size()) {
+           assert(id == names.size());
+           name = read_string();
+           names[id] = name;
+           return name;
+       } else {
+           name = names[id];
+       }
+#if TRACE_VERBOSE
+       std::cerr << "\tNAME " << id << " " << name << "\n";
+#endif
+       return name;
    }
    
    std::string read_string(void) {
       size_t len = read_uint();
+      if (!len) {
+         return std::string();
+      }
       char * buf = new char[len];
       gzread(file, buf, len);
       std::string value(buf, len);
       delete [] buf;
+#if TRACE_VERBOSE
+      std::cerr << "\tSTRING \"" << value << "\"\n";
+#endif
       return value;
    }
 
@@ -256,8 +372,22 @@ done:
          value |= (unsigned long long)(c & 0x7f) << shift;
          shift += 7;
       } while(c & 0x80);
+#if TRACE_VERBOSE
+      std::cerr << "\tUINT " << value << "\n";
+#endif
       return value;
    }
+
+   int read_byte(void) {
+      int c = gzgetc(file);
+#if TRACE_VERBOSE
+      if (c < 0)
+         std::cerr << "\tEOF" << "\n";
+      else
+         std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
+#endif
+      return c;
+   }
 };