]> git.cworth.org Git - apitrace/blob - trace_parser.hpp
Standardize on 4 spaces.
[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_ */