]> git.cworth.org Git - apitrace/blob - trace_parser.cpp
Ok, when != -1
[apitrace] / trace_parser.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
4  * Copyright 2010 VMware, Inc.
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  *
25  **************************************************************************/
26
27
28 #include <assert.h>
29 #include <stdlib.h>
30
31 #include "trace_file.hpp"
32 #include "trace_parser.hpp"
33
34
35 #define TRACE_VERBOSE 0
36
37
38 namespace Trace {
39
40
41 Parser::Parser() {
42     file = new Trace::ZLibFile;
43     next_call_no = 0;
44     version = 0;
45 }
46
47
48 Parser::~Parser() {
49     close();
50     delete file;
51 }
52
53
54 bool Parser::open(const char *filename) {
55     if (!file->open(filename, File::Read)) {
56         return false;
57     }
58
59     version = read_uint();
60     if (version > TRACE_VERSION) {
61         std::cerr << "error: unsupported trace format version " << version << "\n";
62         return false;
63     }
64
65     return true;
66 }
67
68 template <typename Iter>
69 inline void
70 deleteAll(Iter begin, Iter end)
71 {
72     while (begin != end) {
73         delete *begin;
74         ++begin;
75     }
76 }
77
78 template <typename Container>
79 inline void
80 deleteAll(const Container &c)
81 {
82     deleteAll(c.begin(), c.end());
83 }
84
85 void Parser::close(void) {
86     file->close();
87
88     deleteAll(calls);
89     deleteAll(functions);
90     deleteAll(structs);
91     deleteAll(enums);
92     deleteAll(bitmasks);
93 }
94
95
96 Call *Parser::parse_call(void) {
97     do {
98         int c = read_byte();
99         switch(c) {
100         case Trace::EVENT_ENTER:
101             parse_enter();
102             break;
103         case Trace::EVENT_LEAVE:
104             return parse_leave();
105         default:
106             std::cerr << "error: unknown event " << c << "\n";
107             exit(1);
108         case -1:
109             for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
110                 std::cerr << "warning: incomplete call " << (*it)->name() << "\n";
111                 std::cerr << **it << "\n";
112             }
113             return NULL;
114         }
115     } while(true);
116 }
117
118
119 /**
120  * Helper function to lookup an ID in a vector, resizing the vector if it doesn't fit.
121  */
122 template<class T>
123 T *lookup(std::vector<T *> &map, size_t index) {
124     if (index >= map.size()) {
125         map.resize(index + 1);
126         return NULL;
127     } else {
128         return map[index];
129     }
130 }
131
132
133 void Parser::parse_enter(void) {
134     size_t id = read_uint();
135
136     FunctionSig *sig = lookup(functions, id);
137     if (!sig) {
138         sig = new FunctionSig;
139         sig->id = id;
140         sig->name = read_string();
141         sig->num_args = read_uint();
142         const char **arg_names = new const char *[sig->num_args];
143         for (unsigned i = 0; i < sig->num_args; ++i) {
144             arg_names[i] = read_string();
145         }
146         sig->arg_names = arg_names;
147         functions[id] = sig;
148     }
149     assert(sig);
150
151     Call *call = new Call(sig);
152     call->no = next_call_no++;
153
154     if (parse_call_details(call)) {
155         calls.push_back(call);
156     } else {
157         delete call;
158     }
159 }
160
161
162 Call *Parser::parse_leave(void) {
163     unsigned call_no = read_uint();
164     Call *call = NULL;
165     for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
166         if ((*it)->no == call_no) {
167             call = *it;
168             calls.erase(it);
169             break;
170         }
171     }
172     if (!call) {
173         return NULL;
174     }
175
176     if (parse_call_details(call)) {
177         return call;
178     } else {
179         delete call;
180         return NULL;
181     }
182 }
183
184
185 bool Parser::parse_call_details(Call *call) {
186     do {
187         int c = read_byte();
188         switch(c) {
189         case Trace::CALL_END:
190             return true;
191         case Trace::CALL_ARG:
192             parse_arg(call);
193             break;
194         case Trace::CALL_RET:
195             call->ret = parse_value();
196             break;
197         default:
198             std::cerr << "error: ("<<call->name()<< ") unknown call detail "
199                       << c << "\n";
200             exit(1);
201         case -1:
202             return false;
203         }
204     } while(true);
205 }
206
207
208 void Parser::parse_arg(Call *call) {
209     unsigned index = read_uint();
210     Value *value = parse_value();
211     if (index >= call->args.size()) {
212         call->args.resize(index + 1);
213     }
214     call->args[index] = value;
215 }
216
217
218 Value *Parser::parse_value(void) {
219     int c;
220     Value *value;
221     c = read_byte();
222     switch(c) {
223     case Trace::TYPE_NULL:
224         value = new Null;
225         break;
226     case Trace::TYPE_FALSE:
227         value = new Bool(false);
228         break;
229     case Trace::TYPE_TRUE:
230         value = new Bool(true);
231         break;
232     case Trace::TYPE_SINT:
233         value = parse_sint();
234         break;
235     case Trace::TYPE_UINT:
236         value = parse_uint();
237         break;
238     case Trace::TYPE_FLOAT:
239         value = parse_float();
240         break;
241     case Trace::TYPE_DOUBLE:
242         value = parse_double();
243         break;
244     case Trace::TYPE_STRING:
245         value = parse_string();
246         break;
247     case Trace::TYPE_ENUM:
248         value = parse_enum();
249         break;
250     case Trace::TYPE_BITMASK:
251         value = parse_bitmask();
252         break;
253     case Trace::TYPE_ARRAY:
254         value = parse_array();
255         break;
256     case Trace::TYPE_STRUCT:
257         value = parse_struct();
258         break;
259     case Trace::TYPE_BLOB:
260         value = parse_blob();
261         break;
262     case Trace::TYPE_OPAQUE:
263         value = parse_opaque();
264         break;
265     default:
266         std::cerr << "error: unknown type " << c << "\n";
267         exit(1);
268     case -1:
269         value = NULL;
270         break;
271     }
272 #if TRACE_VERBOSE
273     if (value) {
274         std::cerr << "\tVALUE " << value << "\n";
275     }
276 #endif
277     return value;
278 }
279
280
281 Value *Parser::parse_sint() {
282     return new SInt(-(signed long long)read_uint());
283 }
284
285
286 Value *Parser::parse_uint() {
287     return new UInt(read_uint());
288 }
289
290
291 Value *Parser::parse_float() {
292     float value;
293     file->read(&value, sizeof value);
294     return new Float(value);
295 }
296
297
298 Value *Parser::parse_double() {
299     double value;
300     file->read(&value, sizeof value);
301     return new Float(value);
302 }
303
304
305 Value *Parser::parse_string() {
306     return new String(read_string());
307 }
308
309
310 Value *Parser::parse_enum() {
311     size_t id = read_uint();
312     EnumSig *sig = lookup(enums, id);
313     if (!sig) {
314         sig = new EnumSig;
315         sig->id = id;
316         sig->name = read_string();
317         Value *value = parse_value();
318         sig->value = value->toSInt();
319         delete value;
320         enums[id] = sig;
321     }
322     assert(sig);
323     return new Enum(sig);
324 }
325
326
327 Value *Parser::parse_bitmask() {
328     size_t id = read_uint();
329     BitmaskSig *sig = lookup(bitmasks, id);
330     if (!sig) {
331         sig = new BitmaskSig;
332         sig->id = id;
333         sig->num_flags = read_uint();
334         BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
335         for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
336             it->name = read_string();
337             it->value = read_uint();
338             if (it->value == 0 && it != flags) {
339                 std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
340             }
341         }
342         sig->flags = flags;
343         bitmasks[id] = sig;
344     }
345     assert(sig);
346
347     unsigned long long value = read_uint();
348
349     return new Bitmask(sig, value);
350 }
351
352
353 Value *Parser::parse_array(void) {
354     size_t len = read_uint();
355     Array *array = new Array(len);
356     for (size_t i = 0; i < len; ++i) {
357         array->values[i] = parse_value();
358     }
359     return array;
360 }
361
362
363 Value *Parser::parse_blob(void) {
364     size_t size = read_uint();
365     Blob *blob = new Blob(size);
366     if (size) {
367         file->read(blob->buf, (unsigned)size);
368     }
369     return blob;
370 }
371
372
373 Value *Parser::parse_struct() {
374     size_t id = read_uint();
375
376     StructSig *sig = lookup(structs, id);
377     if (!sig) {
378         sig = new StructSig;
379         sig->id = id;
380         sig->name = read_string();
381         sig->num_members = read_uint();
382         const char **member_names = new const char *[sig->num_members];
383         for (unsigned i = 0; i < sig->num_members; ++i) {
384             member_names[i] = read_string();
385         }
386         sig->member_names = member_names;
387         structs[id] = sig;
388     }
389     assert(sig);
390
391     Struct *value = new Struct(sig);
392
393     for (size_t i = 0; i < sig->num_members; ++i) {
394         value->members[i] = parse_value();
395     }
396
397     return value;
398 }
399
400
401 Value *Parser::parse_opaque() {
402     unsigned long long addr;
403     addr = read_uint();
404     return new Pointer(addr);
405 }
406
407
408 const char * Parser::read_string(void) {
409     size_t len = read_uint();
410     char * value = new char[len + 1];
411     if (len) {
412         file->read(value, (unsigned)len);
413     }
414     value[len] = 0;
415 #if TRACE_VERBOSE
416     std::cerr << "\tSTRING \"" << value << "\"\n";
417 #endif
418     return value;
419 }
420
421
422 unsigned long long Parser::read_uint(void) {
423     unsigned long long value = 0;
424     int c;
425     unsigned shift = 0;
426     do {
427         c = file->getc();
428         if (c == -1) {
429             break;
430         }
431         value |= (unsigned long long)(c & 0x7f) << shift;
432         shift += 7;
433     } while(c & 0x80);
434 #if TRACE_VERBOSE
435     std::cerr << "\tUINT " << value << "\n";
436 #endif
437     return value;
438 }
439
440
441 inline int Parser::read_byte(void) {
442     int c = file->getc();
443 #if TRACE_VERBOSE
444     if (c < 0)
445         std::cerr << "\tEOF" << "\n";
446     else
447         std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
448 #endif
449     return c;
450 }
451
452
453 } /* namespace Trace */