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