]> git.cworth.org Git - apitrace/blobdiff - trace_parser.hpp
Update to-do list
[apitrace] / trace_parser.hpp
index ea6c746d9ee0f6cbe2d05be804b1301ebc73fc90..b4017414da646926737a0489ea9f987bd68d0b60 100644 (file)
@@ -30,6 +30,9 @@
 #include <cassert>
 
 #include <iostream>
+#include <map>
+#include <list>
+#include <string>
 
 #include <zlib.h>
 
 #include "trace_model.hpp"
 
 
+#define TRACE_VERBOSE 0
+
+
 namespace Trace {
 
 
 class Parser
 {
 protected:
-   gzFile file;
+    gzFile file;
+
+    typedef std::list<Call *> CallList;
+    CallList calls;
+
+    typedef std::vector<Call::Signature *> FunctionMap;
+    FunctionMap functions;
+
+    typedef std::vector<Struct::Signature *> StructMap;
+    StructMap structs;
+
+    typedef std::vector<Enum *> EnumMap;
+    EnumMap enums;
+
+    typedef std::vector<Bitmask::Signature *> BitmaskMap;
+    BitmaskMap bitmasks;
+
+    unsigned next_call_no;
+
 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 << "error: 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 = read_byte();
-         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:
-            std::cerr << "error: unknown call detail " << c << "\n";
-            assert(0);
-            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 = read_byte();
-      switch(c) {
-      case Trace::TYPE_NULL:
-         return new Null;
-      case Trace::TYPE_FALSE:
-         return new Bool(false);
-      case Trace::TYPE_TRUE:
-         return new Bool(true);
-      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_STRUCT:
-         return parse_struct();
-      case Trace::TYPE_BLOB:
-         return parse_blob();
-      case Trace::TYPE_POINTER:
-         return parse_pointer();
-      case Trace::TYPE_OPAQUE:
-         return parse_opaque();
-      default:
-         std::cerr << "error: unknown type " << c << "\n";
-         assert(0);
-         return NULL;
-      }
-   }
-
-   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 = read_byte();
-         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";
+    Parser() {
+        file = NULL;
+        next_call_no = 0;
+    }
+
+    ~Parser() {
+        close();
+    }
+
+    bool open(const char *filename) {
+        unsigned long long version;
+
+        file = gzopen(filename, "rb");
+        if (!file) {
+            return false;
+        }
+
+        version = read_uint();
+        if (version != TRACE_VERSION) {
+            std::cerr << "error: unsupported format version" << version << "\n";
+            return false;
+        }
+
+        return true;
+    }
+
+    void close(void) {
+        if (file) {
+            gzclose(file);
+            file = NULL;
+        }
+    }
+
+    Call *parse_call(void) {
+        do {
+            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);
+    }
+
+    /**
+     * Helper function to lookup an ID in a vector, resizing the vector if it doesn't fit.
+     */
+    template<class T>
+    T *lookup(std::vector<T *> &map, size_t index) {
+        if (index >= map.size()) {
+            map.resize(index + 1);
+            return NULL;
+        } else {
+            return map[index];
+        }
+    }
+
+    void parse_enter(void) {
+        size_t id = read_uint();
+
+        Call::Signature *sig = lookup(functions, id);
+        if (!sig) {
+            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;
+        }
+        assert(sig);
+
+        Call *call = new Call(sig);
+        call->no = next_call_no++;
+
+        parse_call_details(call);
+
+        calls.push_back(call);
+    }
+
+    Call *parse_leave(void) {
+        unsigned call_no = read_uint();
+
+        Call *call = NULL;
+        for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
+            if ((*it)->no == call_no) {
+                call = *it;
+                calls.erase(it);
+                break;
+            }
+        }
+        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:
+                parse_arg(call);
+                break;
+            case Trace::CALL_RET:
+                call->ret = parse_value();
+                break;
+            default:
+                std::cerr << "error: unknown call detail " << c << "\n";
+                assert(0);
+                /* fallthrough */
+            case -1:
+                return;
+            }
+        } while(true);
+    }
+
+    void parse_arg(Call *call) {
+        unsigned index = read_uint();
+        Value *value = parse_value();
+        if (index >= call->args.size()) {
+            call->args.resize(index + 1);
+        }
+        call->args[index] = value;
+    }
+
+    Value *parse_value(void) {
+        int c;
+        c = read_byte();
+        switch(c) {
+        case Trace::TYPE_NULL:
+            return new Null;
+        case Trace::TYPE_FALSE:
+            return new Bool(false);
+        case Trace::TYPE_TRUE:
+            return new Bool(true);
+        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_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_OPAQUE:
+            return parse_opaque();
+        default:
+            std::cerr << "error: unknown type " << c << "\n";
             assert(0);
             return NULL;
-         }
-      } while(true);
-done:
-      return new UInt(value);
-   }
-
-   Value *parse_array(void) {
-      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_blob(void) {
-      size_t size = read_uint();
-      Blob *blob = new Blob(size);
-      if (size) {
-          gzread(file, blob->buf, size);
-      }
-      return blob;
-   }
-   
-   Value *parse_pointer() {
-      unsigned long long addr;
-      Value *value;
-      addr = read_uint();
-      value = parse_value();
-      if (!value)
-         value = new UInt(addr);
-      return value;
-   }
-   
-   Value *parse_struct() {
-      std::string name;
-      /* XXX */
-      name = read_string();
-      while(name.length()) {
-         Value *value = parse_value();
-         std::cout << "  " << name << " = " << value << "\n";
-         name = read_string();
-      }
-      return NULL;
-   }
-   
-   Value *parse_opaque() {
-      unsigned long long addr;
-      addr = read_uint();
-      /* XXX */
-      return new UInt(addr);
-   }
-   
-   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;
-#ifdef TRACE_VERBOSE
-      std::cerr << '"' << value << '"' << "\n";
+        }
+    }
+
+    Value *parse_sint() {
+        return new SInt(-(signed long long)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_enum() {
+        size_t id = read_uint();
+        Enum *sig = lookup(enums, id);
+        if (!sig) {
+            std::string name = read_string();
+            Value *value = parse_value();
+            sig = new Enum(name, value);
+            enums[id] = sig;
+        }
+        assert(sig);
+        return sig;
+    }
+
+    Value *parse_bitmask() {
+        size_t id = read_uint();
+        Bitmask::Signature *sig = lookup(bitmasks, id);
+        if (!sig) {
+            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;
+        }
+        assert(sig);
+
+        unsigned long long value = read_uint();
+
+        return new Bitmask(sig, value);
+    }
+
+    Value *parse_array(void) {
+        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_blob(void) {
+        size_t size = read_uint();
+        Blob *blob = new Blob(size);
+        if (size) {
+            gzread(file, blob->buf, size);
+        }
+        return blob;
+    }
+
+    Value *parse_struct() {
+        size_t id = read_uint();
+
+        Struct::Signature *sig = lookup(structs, id);
+        if (!sig) {
+            sig = new Struct::Signature;
+            sig->name = read_string();
+            unsigned size = read_uint();
+            for (unsigned i = 0; i < size; ++i) {
+                sig->member_names.push_back(read_string());
+            }
+            structs[id] = sig;
+        }
+        assert(sig);
+
+        Struct *value = new Struct(sig);
+
+        for (size_t i = 0; i < sig->member_names.size(); ++i) {
+            value->members[i] = parse_value();
+        }
+
+        return value;
+    }
+
+    Value *parse_opaque() {
+        unsigned long long addr;
+        addr = read_uint();
+        return new Pointer(addr);
+    }
+
+    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;
-   }
-
-   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);
-#ifdef TRACE_VERBOSE
-      std::cerr << value << "\n";
+        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);
+#if TRACE_VERBOSE
+        std::cerr << "\tUINT " << value << "\n";
 #endif
-      return value;
-   }
-
-   int read_byte(void) {
-      int c = gzgetc(file);
-#ifdef TRACE_VERBOSE
-      if (c < 0)
-         std::cerr << "EOF" << "\n";
-      else
-         std::cerr << "0x" << std::hex << c << "\n";
+        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;
-   }
+        return c;
+    }
 };