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