]> git.cworth.org Git - apitrace/blob - trace_parser.hpp
2c5503751ee9c1c03247fd325a22825e1517cb76
[apitrace] / trace_parser.hpp
1 /**************************************************************************
2  *
3  * Copyright 2010 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 #ifndef _TRACE_PARSER_HPP_
27 #define _TRACE_PARSER_HPP_
28
29
30 #include <cassert>
31
32 #include <iostream>
33
34 #include <zlib.h>
35
36 #include "trace_format.hpp"
37 #include "trace_model.hpp"
38
39
40 namespace Trace {
41
42
43 class Parser
44 {
45 protected:
46    gzFile file;
47 public:
48    Parser() {
49       file = NULL;
50    }
51
52    ~Parser() {
53       close();
54    }
55
56    bool open(const char *filename) {
57       unsigned long long version;
58
59       file = gzopen(filename, "rb");
60       if (!file) {
61          return false;
62       }
63
64       version = read_uint();
65       if (version != TRACE_VERSION) {
66          std::cerr << "error: unsupported format version" << version << "\n";
67          return false;
68       }
69
70       return true;
71    }
72
73    void close(void) {
74       if (file) {
75          gzclose(file);
76          file = NULL;
77       }
78    }
79
80    Call *parse_call(void) {
81       Call *call = new Call;
82       call->name = read_string();
83       do {
84          int c = read_byte();
85          switch(c) {
86          case Trace::CALL_END:
87             return call;
88          case Trace::CALL_ARG:
89             call->args.push_back(parse_arg());
90             break;
91          case Trace::CALL_RET:
92             call->ret = parse_value();
93             break;
94          default:
95             std::cerr << "error: unknown call detail " << c << "\n";
96             assert(0);
97             /* fallthrough */
98          case -1:
99             delete call;
100             return NULL;
101          }
102       } while(true);
103    }
104    
105    Arg parse_arg(void) {
106       std::string name = read_string();
107       Value *value = parse_value();
108       return Arg(name, value);
109    }
110    
111    Value *parse_value(void) {
112       int c;
113       c = read_byte();
114       switch(c) {
115       case Trace::TYPE_NULL:
116          return new Null;
117       case Trace::TYPE_FALSE:
118          return new Bool(false);
119       case Trace::TYPE_TRUE:
120          return new Bool(true);
121       case Trace::TYPE_SINT:
122          return parse_sint();
123       case Trace::TYPE_UINT:
124          return parse_uint();
125       case Trace::TYPE_FLOAT:
126          return parse_float();
127       case Trace::TYPE_DOUBLE:
128          return parse_double();
129       case Trace::TYPE_STRING:
130          return parse_string();
131       case Trace::TYPE_CONST:
132          return parse_const();
133       case Trace::TYPE_BITMASK:
134          return parse_bitmask();
135       case Trace::TYPE_ARRAY:
136          return parse_array();
137       case Trace::TYPE_STRUCT:
138          return parse_struct();
139       case Trace::TYPE_BLOB:
140          return parse_blob();
141       case Trace::TYPE_OPAQUE:
142          return parse_opaque();
143       default:
144          std::cerr << "error: unknown type " << c << "\n";
145          assert(0);
146          return NULL;
147       }
148    }
149
150    Value *parse_sint() {
151       return new SInt(-read_uint());
152    }
153    
154    Value *parse_uint() {
155       return new UInt(read_uint());
156    }
157    
158    Value *parse_float() {
159       float value;
160       gzread(file, &value, sizeof value);
161       return new Float(value);
162    }
163    
164    Value *parse_double() {
165       double value;
166       gzread(file, &value, sizeof value);
167       return new Float(value);
168    }
169    
170    Value *parse_string() {
171       return new String(read_string());
172    }
173    
174    Value *parse_const() {
175       std::string name = read_string();
176       Value *value = parse_value();
177       return new Const(name, value);
178    }
179    
180    Value *parse_bitmask() {
181       unsigned long long value = 0;
182       int c;
183       do {
184          c = read_byte();
185          switch(c) {
186          case Trace::TYPE_SINT:
187             value |= -read_uint();
188             break;
189          case Trace::TYPE_UINT:
190             value |= read_uint();
191             break;
192          case Trace::TYPE_CONST:
193             read_string();
194             break;
195          case Trace::TYPE_NULL:
196             goto done;
197          default:
198             std::cerr << "error: uexpected type " << c << "\n";
199             assert(0);
200             return NULL;
201          }
202       } while(true);
203 done:
204       return new UInt(value);
205    }
206
207    Value *parse_array(void) {
208       size_t len = read_uint();
209       Array *array = new Array(len);
210       for (size_t i = 0; i < len; ++i) {
211          array->values[i] = parse_value();
212       }
213       return array;
214    }
215    
216    Value *parse_blob(void) {
217       size_t size = read_uint();
218       Blob *blob = new Blob(size);
219       if (size) {
220           gzread(file, blob->buf, size);
221       }
222       return blob;
223    }
224    
225    Value *parse_struct() {
226       std::string name;
227       /* XXX */
228       name = read_string();
229       while(name.length()) {
230          Value *value = parse_value();
231          std::cout << "  " << name << " = " << value << "\n";
232          name = read_string();
233       }
234       return NULL;
235    }
236    
237    Value *parse_opaque() {
238       unsigned long long addr;
239       addr = read_uint();
240       /* XXX */
241       return new UInt(addr);
242    }
243    
244    std::string read_string(void) {
245       size_t len = read_uint();
246       if (!len) {
247          return std::string();
248       }
249       char * buf = new char[len];
250       gzread(file, buf, len);
251       std::string value(buf, len);
252       delete [] buf;
253 #ifdef TRACE_VERBOSE
254       std::cerr << '"' << value << '"' << "\n";
255 #endif
256       return value;
257    }
258
259    unsigned long long read_uint(void) {
260       unsigned long long value = 0;
261       int c;
262       unsigned shift = 0;
263       do {
264          c = gzgetc(file);
265          if (c == -1) {
266             break;
267          }
268          value |= (unsigned long long)(c & 0x7f) << shift;
269          shift += 7;
270       } while(c & 0x80);
271 #ifdef TRACE_VERBOSE
272       std::cerr << value << "\n";
273 #endif
274       return value;
275    }
276
277    int read_byte(void) {
278       int c = gzgetc(file);
279 #ifdef TRACE_VERBOSE
280       if (c < 0)
281          std::cerr << "EOF" << "\n";
282       else
283          std::cerr << "0x" << std::hex << c << "\n";
284 #endif
285       return c;
286    }
287 };
288
289
290 } /* namespace Trace */
291
292 #endif /* _TRACE_PARSER_HPP_ */