]> git.cworth.org Git - apitrace/blob - trace_parser.hpp
Tweaks.
[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 #include <map>
34 #include <string>
35
36 #include <zlib.h>
37
38 #include "trace_format.hpp"
39 #include "trace_model.hpp"
40
41
42 #define TRACE_VERBOSE 0
43
44
45 namespace Trace {
46
47
48 class Parser
49 {
50 protected:
51    gzFile file;
52
53    typedef std::map<size_t, std::string> namemap;
54    namemap names;
55
56    typedef std::map<unsigned, Call *> callmap;
57    callmap calls;
58
59    unsigned next_call_no;
60
61 public:
62    Parser() {
63       file = NULL;
64       next_call_no = 0;
65    }
66
67    ~Parser() {
68       close();
69    }
70
71    bool open(const char *filename) {
72       unsigned long long version;
73
74       file = gzopen(filename, "rb");
75       if (!file) {
76          return false;
77       }
78
79       version = read_uint();
80       if (version != TRACE_VERSION) {
81          std::cerr << "error: unsupported format version" << version << "\n";
82          return false;
83       }
84
85       return true;
86    }
87
88    void close(void) {
89       if (file) {
90          gzclose(file);
91          file = NULL;
92       }
93    }
94
95    Call *parse_call(void) {
96       do {
97          int c = read_byte();
98          switch(c) {
99          case Trace::EVENT_ENTER:
100             parse_enter();
101             break;
102          case Trace::EVENT_LEAVE:
103             return parse_leave();
104          case Trace::EVENT_MESSAGE:
105             std::cerr << "message: " << read_string() << "\n";
106             break;
107          default:
108             std::cerr << "error: unknown call detail " << c << "\n";
109             assert(0);
110             /* fallthrough */
111          case -1:
112             return NULL;
113          }
114       } while(true);
115    }
116    
117    void parse_enter(void) {
118       Call *call = new Call;
119       call->no = next_call_no++;
120       call->name = read_name();
121       parse_call_details(call);
122       calls[call->no] = call;
123    }
124    
125    Call *parse_leave(void) {
126       unsigned call_no = read_uint();
127       Call *call = calls[call_no];
128       assert(call);
129       if (!call) {
130           return NULL;
131       }
132       parse_call_details(call);
133       return call;
134    }
135    
136    void parse_call_details(Call *call) {
137       do {
138          int c = read_byte();
139          switch(c) {
140          case Trace::CALL_END:
141             return;
142          case Trace::CALL_ARG:
143             parse_arg(call);
144             break;
145          case Trace::CALL_RET:
146             call->ret = parse_value();
147             break;
148          default:
149             std::cerr << "error: unknown call detail " << c << "\n";
150             assert(0);
151             /* fallthrough */
152          case -1:
153             return;
154          }
155       } while(true);
156    }
157    
158    void parse_arg(Call *call) {
159       unsigned index = read_uint();
160       std::string name = read_name();
161       Value *value = parse_value();
162       if (index >= call->args.size()) {
163           call->args.resize(index + 1);
164       }
165       call->args[index] = Arg(name, value);
166    }
167    
168    Value *parse_value(void) {
169       int c;
170       c = read_byte();
171       switch(c) {
172       case Trace::TYPE_NULL:
173          return new Null;
174       case Trace::TYPE_FALSE:
175          return new Bool(false);
176       case Trace::TYPE_TRUE:
177          return new Bool(true);
178       case Trace::TYPE_SINT:
179          return parse_sint();
180       case Trace::TYPE_UINT:
181          return parse_uint();
182       case Trace::TYPE_FLOAT:
183          return parse_float();
184       case Trace::TYPE_DOUBLE:
185          return parse_double();
186       case Trace::TYPE_STRING:
187          return parse_string();
188       case Trace::TYPE_CONST:
189          return parse_const();
190       case Trace::TYPE_BITMASK:
191          return parse_bitmask();
192       case Trace::TYPE_ARRAY:
193          return parse_array();
194       case Trace::TYPE_STRUCT:
195          return parse_struct();
196       case Trace::TYPE_BLOB:
197          return parse_blob();
198       case Trace::TYPE_OPAQUE:
199          return parse_opaque();
200       default:
201          std::cerr << "error: unknown type " << c << "\n";
202          assert(0);
203          return NULL;
204       }
205    }
206
207    Value *parse_sint() {
208       return new SInt(-(signed long long)read_uint());
209    }
210    
211    Value *parse_uint() {
212       return new UInt(read_uint());
213    }
214    
215    Value *parse_float() {
216       float value;
217       gzread(file, &value, sizeof value);
218       return new Float(value);
219    }
220    
221    Value *parse_double() {
222       double value;
223       gzread(file, &value, sizeof value);
224       return new Float(value);
225    }
226    
227    Value *parse_string() {
228       return new String(read_string());
229    }
230    
231    Value *parse_const() {
232       std::string name = read_name();
233       Value *value = parse_value();
234       return new Const(name, value);
235    }
236    
237    Value *parse_bitmask() {
238       unsigned long long value = 0;
239       int c;
240       do {
241          c = read_byte();
242          switch(c) {
243          case Trace::TYPE_SINT:
244             value |= -(signed long long)read_uint();
245             break;
246          case Trace::TYPE_UINT:
247             value |= read_uint();
248             break;
249          case Trace::TYPE_CONST:
250             read_name();
251             break;
252          case Trace::TYPE_NULL:
253             goto done;
254          default:
255             std::cerr << "error: uexpected type " << c << "\n";
256             assert(0);
257             return NULL;
258          }
259       } while(true);
260 done:
261       return new UInt(value);
262    }
263
264    Value *parse_array(void) {
265       size_t len = read_uint();
266       Array *array = new Array(len);
267       for (size_t i = 0; i < len; ++i) {
268          array->values[i] = parse_value();
269       }
270       return array;
271    }
272    
273    Value *parse_blob(void) {
274       size_t size = read_uint();
275       Blob *blob = new Blob(size);
276       if (size) {
277           gzread(file, blob->buf, size);
278       }
279       return blob;
280    }
281    
282    Value *parse_struct() {
283       size_t length = read_uint();
284       /* XXX */
285       for (size_t i = 0; i < length; ++i) {
286          std::string name = read_name();
287          Value *value = parse_value();
288          std::cout << "  " << name << " = " << value << "\n";
289       }
290       return NULL;
291    }
292    
293    Value *parse_opaque() {
294       unsigned long long addr;
295       addr = read_uint();
296       /* XXX */
297       return new UInt(addr);
298    }
299
300    std::string read_name(void) {
301        std::string name;
302        size_t id = read_uint();
303        if (id >= names.size()) {
304            assert(id == names.size());
305            name = read_string();
306            names[id] = name;
307            return name;
308        } else {
309            name = names[id];
310        }
311 #if TRACE_VERBOSE
312        std::cerr << "\tNAME " << id << " " << name << "\n";
313 #endif
314        return name;
315    }
316    
317    std::string read_string(void) {
318       size_t len = read_uint();
319       if (!len) {
320          return std::string();
321       }
322       char * buf = new char[len];
323       gzread(file, buf, len);
324       std::string value(buf, len);
325       delete [] buf;
326 #if TRACE_VERBOSE
327       std::cerr << "\tSTRING \"" << value << "\"\n";
328 #endif
329       return value;
330    }
331
332    unsigned long long read_uint(void) {
333       unsigned long long value = 0;
334       int c;
335       unsigned shift = 0;
336       do {
337          c = gzgetc(file);
338          if (c == -1) {
339             break;
340          }
341          value |= (unsigned long long)(c & 0x7f) << shift;
342          shift += 7;
343       } while(c & 0x80);
344 #if TRACE_VERBOSE
345       std::cerr << "\tUINT " << value << "\n";
346 #endif
347       return value;
348    }
349
350    int read_byte(void) {
351       int c = gzgetc(file);
352 #if TRACE_VERBOSE
353       if (c < 0)
354          std::cerr << "\tEOF" << "\n";
355       else
356          std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
357 #endif
358       return c;
359    }
360 };
361
362
363 } /* namespace Trace */
364
365 #endif /* _TRACE_PARSER_HPP_ */