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