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