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