]> git.cworth.org Git - apitrace/blob - trace_parser.cpp
Add snappy compression/decompression code.
[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: unknown call detail " << c << "\n";
199             exit(1);
200         case -1:
201             return false;
202         }
203     } while(true);
204 }
205
206
207 void Parser::parse_arg(Call *call) {
208     unsigned index = read_uint();
209     Value *value = parse_value();
210     if (index >= call->args.size()) {
211         call->args.resize(index + 1);
212     }
213     call->args[index] = value;
214 }
215
216
217 Value *Parser::parse_value(void) {
218     int c;
219     Value *value;
220     c = read_byte();
221     switch(c) {
222     case Trace::TYPE_NULL:
223         value = new Null;
224         break;
225     case Trace::TYPE_FALSE:
226         value = new Bool(false);
227         break;
228     case Trace::TYPE_TRUE:
229         value = new Bool(true);
230         break;
231     case Trace::TYPE_SINT:
232         value = parse_sint();
233         break;
234     case Trace::TYPE_UINT:
235         value = parse_uint();
236         break;
237     case Trace::TYPE_FLOAT:
238         value = parse_float();
239         break;
240     case Trace::TYPE_DOUBLE:
241         value = parse_double();
242         break;
243     case Trace::TYPE_STRING:
244         value = parse_string();
245         break;
246     case Trace::TYPE_ENUM:
247         value = parse_enum();
248         break;
249     case Trace::TYPE_BITMASK:
250         value = parse_bitmask();
251         break;
252     case Trace::TYPE_ARRAY:
253         value = parse_array();
254         break;
255     case Trace::TYPE_STRUCT:
256         value = parse_struct();
257         break;
258     case Trace::TYPE_BLOB:
259         value = parse_blob();
260         break;
261     case Trace::TYPE_OPAQUE:
262         value = parse_opaque();
263         break;
264     default:
265         std::cerr << "error: unknown type " << c << "\n";
266         exit(1);
267     case -1:
268         value = NULL;
269         break;
270     }
271 #if TRACE_VERBOSE
272     if (value) {
273         std::cerr << "\tVALUE " << value << "\n";
274     }
275 #endif
276     return value;
277 }
278
279
280 Value *Parser::parse_sint() {
281     return new SInt(-(signed long long)read_uint());
282 }
283
284
285 Value *Parser::parse_uint() {
286     return new UInt(read_uint());
287 }
288
289
290 Value *Parser::parse_float() {
291     float value;
292     file->read(&value, sizeof value);
293     return new Float(value);
294 }
295
296
297 Value *Parser::parse_double() {
298     double value;
299     file->read(&value, sizeof value);
300     return new Float(value);
301 }
302
303
304 Value *Parser::parse_string() {
305     return new String(read_string());
306 }
307
308
309 Value *Parser::parse_enum() {
310     size_t id = read_uint();
311     EnumSig *sig = lookup(enums, id);
312     if (!sig) {
313         sig = new EnumSig;
314         sig->id = id;
315         sig->name = read_string();
316         Value *value = parse_value();
317         sig->value = value->toSInt();
318         delete value;
319         enums[id] = sig;
320     }
321     assert(sig);
322     return new Enum(sig);
323 }
324
325
326 Value *Parser::parse_bitmask() {
327     size_t id = read_uint();
328     BitmaskSig *sig = lookup(bitmasks, id);
329     if (!sig) {
330         sig = new BitmaskSig;
331         sig->id = id;
332         sig->num_flags = read_uint();
333         BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
334         for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
335             it->name = read_string();
336             it->value = read_uint();
337             if (it->value == 0 && it != flags) {
338                 std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
339             }
340         }
341         sig->flags = flags;
342         bitmasks[id] = sig;
343     }
344     assert(sig);
345
346     unsigned long long value = read_uint();
347
348     return new Bitmask(sig, value);
349 }
350
351
352 Value *Parser::parse_array(void) {
353     size_t len = read_uint();
354     Array *array = new Array(len);
355     for (size_t i = 0; i < len; ++i) {
356         array->values[i] = parse_value();
357     }
358     return array;
359 }
360
361
362 Value *Parser::parse_blob(void) {
363     size_t size = read_uint();
364     Blob *blob = new Blob(size);
365     if (size) {
366         file->read(blob->buf, (unsigned)size);
367     }
368     return blob;
369 }
370
371
372 Value *Parser::parse_struct() {
373     size_t id = read_uint();
374
375     StructSig *sig = lookup(structs, id);
376     if (!sig) {
377         sig = new StructSig;
378         sig->id = id;
379         sig->name = read_string();
380         sig->num_members = read_uint();
381         const char **member_names = new const char *[sig->num_members];
382         for (unsigned i = 0; i < sig->num_members; ++i) {
383             member_names[i] = read_string();
384         }
385         sig->member_names = member_names;
386         structs[id] = sig;
387     }
388     assert(sig);
389
390     Struct *value = new Struct(sig);
391
392     for (size_t i = 0; i < sig->num_members; ++i) {
393         value->members[i] = parse_value();
394     }
395
396     return value;
397 }
398
399
400 Value *Parser::parse_opaque() {
401     unsigned long long addr;
402     addr = read_uint();
403     return new Pointer(addr);
404 }
405
406
407 const char * Parser::read_string(void) {
408     size_t len = read_uint();
409     char * value = new char[len + 1];
410     if (len) {
411         file->read(value, (unsigned)len);
412     }
413     value[len] = 0;
414 #if TRACE_VERBOSE
415     std::cerr << "\tSTRING \"" << value << "\"\n";
416 #endif
417     return value;
418 }
419
420
421 unsigned long long Parser::read_uint(void) {
422     unsigned long long value = 0;
423     int c;
424     unsigned shift = 0;
425     do {
426         c = file->getc();
427         if (c == -1) {
428             break;
429         }
430         value |= (unsigned long long)(c & 0x7f) << shift;
431         shift += 7;
432     } while(c & 0x80);
433 #if TRACE_VERBOSE
434     std::cerr << "\tUINT " << value << "\n";
435 #endif
436     return value;
437 }
438
439
440 inline int Parser::read_byte(void) {
441     int c = file->getc();
442 #if TRACE_VERBOSE
443     if (c < 0)
444         std::cerr << "\tEOF" << "\n";
445     else
446         std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
447 #endif
448     return c;
449 }
450
451
452 } /* namespace Trace */