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