]> git.cworth.org Git - apitrace/blob - trace_parser.cpp
Bundle Snappy source 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 = NULL;
43     next_call_no = 0;
44     version = 0;
45 }
46
47
48 Parser::~Parser() {
49     close();
50 }
51
52
53 bool Parser::open(const char *filename) {
54     assert(!file);
55     if (File::isZLibCompressed(filename)) {
56         file = new ZLibFile;
57     } else {
58         file = new SnappyFile;
59     }
60
61     if (!file->open(filename, File::Read)) {
62         return false;
63     }
64
65     version = read_uint();
66     if (version > TRACE_VERSION) {
67         std::cerr << "error: unsupported trace format version " << version << "\n";
68         return false;
69     }
70
71     return true;
72 }
73
74 template <typename Iter>
75 inline void
76 deleteAll(Iter begin, Iter end)
77 {
78     while (begin != end) {
79         delete *begin;
80         ++begin;
81     }
82 }
83
84 template <typename Container>
85 inline void
86 deleteAll(const Container &c)
87 {
88     deleteAll(c.begin(), c.end());
89 }
90
91 void Parser::close(void) {
92     file->close();
93     delete file;
94     file = NULL;
95
96     deleteAll(calls);
97     deleteAll(functions);
98     deleteAll(structs);
99     deleteAll(enums);
100     deleteAll(bitmasks);
101 }
102
103
104 Call *Parser::parse_call(void) {
105     do {
106         int c = read_byte();
107         switch(c) {
108         case Trace::EVENT_ENTER:
109             parse_enter();
110             break;
111         case Trace::EVENT_LEAVE:
112             return parse_leave();
113         default:
114             std::cerr << "error: unknown event " << c << "\n";
115             exit(1);
116         case -1:
117             for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
118                 std::cerr << "warning: incomplete call " << (*it)->name() << "\n";
119                 std::cerr << **it << "\n";
120             }
121             return NULL;
122         }
123     } while(true);
124 }
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
141 void Parser::parse_enter(void) {
142     size_t id = read_uint();
143
144     FunctionSig *sig = lookup(functions, id);
145     if (!sig) {
146         sig = new FunctionSig;
147         sig->id = id;
148         sig->name = read_string();
149         sig->num_args = read_uint();
150         const char **arg_names = new const char *[sig->num_args];
151         for (unsigned i = 0; i < sig->num_args; ++i) {
152             arg_names[i] = read_string();
153         }
154         sig->arg_names = arg_names;
155         functions[id] = sig;
156     }
157     assert(sig);
158
159     Call *call = new Call(sig);
160     call->no = next_call_no++;
161
162     if (parse_call_details(call)) {
163         calls.push_back(call);
164     } else {
165         delete call;
166     }
167 }
168
169
170 Call *Parser::parse_leave(void) {
171     unsigned call_no = read_uint();
172     Call *call = NULL;
173     for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
174         if ((*it)->no == call_no) {
175             call = *it;
176             calls.erase(it);
177             break;
178         }
179     }
180     if (!call) {
181         return NULL;
182     }
183
184     if (parse_call_details(call)) {
185         return call;
186     } else {
187         delete call;
188         return NULL;
189     }
190 }
191
192
193 bool Parser::parse_call_details(Call *call) {
194     do {
195         int c = read_byte();
196         switch(c) {
197         case Trace::CALL_END:
198             return true;
199         case Trace::CALL_ARG:
200             parse_arg(call);
201             break;
202         case Trace::CALL_RET:
203             call->ret = parse_value();
204             break;
205         default:
206             std::cerr << "error: ("<<call->name()<< ") unknown call detail "
207                       << c << "\n";
208             exit(1);
209         case -1:
210             return false;
211         }
212     } while(true);
213 }
214
215
216 void Parser::parse_arg(Call *call) {
217     unsigned index = read_uint();
218     Value *value = parse_value();
219     if (index >= call->args.size()) {
220         call->args.resize(index + 1);
221     }
222     call->args[index] = value;
223 }
224
225
226 Value *Parser::parse_value(void) {
227     int c;
228     Value *value;
229     c = read_byte();
230     switch(c) {
231     case Trace::TYPE_NULL:
232         value = new Null;
233         break;
234     case Trace::TYPE_FALSE:
235         value = new Bool(false);
236         break;
237     case Trace::TYPE_TRUE:
238         value = new Bool(true);
239         break;
240     case Trace::TYPE_SINT:
241         value = parse_sint();
242         break;
243     case Trace::TYPE_UINT:
244         value = parse_uint();
245         break;
246     case Trace::TYPE_FLOAT:
247         value = parse_float();
248         break;
249     case Trace::TYPE_DOUBLE:
250         value = parse_double();
251         break;
252     case Trace::TYPE_STRING:
253         value = parse_string();
254         break;
255     case Trace::TYPE_ENUM:
256         value = parse_enum();
257         break;
258     case Trace::TYPE_BITMASK:
259         value = parse_bitmask();
260         break;
261     case Trace::TYPE_ARRAY:
262         value = parse_array();
263         break;
264     case Trace::TYPE_STRUCT:
265         value = parse_struct();
266         break;
267     case Trace::TYPE_BLOB:
268         value = parse_blob();
269         break;
270     case Trace::TYPE_OPAQUE:
271         value = parse_opaque();
272         break;
273     default:
274         std::cerr << "error: unknown type " << c << "\n";
275         exit(1);
276     case -1:
277         value = NULL;
278         break;
279     }
280 #if TRACE_VERBOSE
281     if (value) {
282         std::cerr << "\tVALUE " << value << "\n";
283     }
284 #endif
285     return value;
286 }
287
288
289 Value *Parser::parse_sint() {
290     return new SInt(-(signed long long)read_uint());
291 }
292
293
294 Value *Parser::parse_uint() {
295     return new UInt(read_uint());
296 }
297
298
299 Value *Parser::parse_float() {
300     float value;
301     file->read(&value, sizeof value);
302     return new Float(value);
303 }
304
305
306 Value *Parser::parse_double() {
307     double value;
308     file->read(&value, sizeof value);
309     return new Float(value);
310 }
311
312
313 Value *Parser::parse_string() {
314     return new String(read_string());
315 }
316
317
318 Value *Parser::parse_enum() {
319     size_t id = read_uint();
320     EnumSig *sig = lookup(enums, id);
321     if (!sig) {
322         sig = new EnumSig;
323         sig->id = id;
324         sig->name = read_string();
325         Value *value = parse_value();
326         sig->value = value->toSInt();
327         delete value;
328         enums[id] = sig;
329     }
330     assert(sig);
331     return new Enum(sig);
332 }
333
334
335 Value *Parser::parse_bitmask() {
336     size_t id = read_uint();
337     BitmaskSig *sig = lookup(bitmasks, id);
338     if (!sig) {
339         sig = new BitmaskSig;
340         sig->id = id;
341         sig->num_flags = read_uint();
342         BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
343         for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
344             it->name = read_string();
345             it->value = read_uint();
346             if (it->value == 0 && it != flags) {
347                 std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
348             }
349         }
350         sig->flags = flags;
351         bitmasks[id] = sig;
352     }
353     assert(sig);
354
355     unsigned long long value = read_uint();
356
357     return new Bitmask(sig, value);
358 }
359
360
361 Value *Parser::parse_array(void) {
362     size_t len = read_uint();
363     Array *array = new Array(len);
364     for (size_t i = 0; i < len; ++i) {
365         array->values[i] = parse_value();
366     }
367     return array;
368 }
369
370
371 Value *Parser::parse_blob(void) {
372     size_t size = read_uint();
373     Blob *blob = new Blob(size);
374     if (size) {
375         file->read(blob->buf, (unsigned)size);
376     }
377     return blob;
378 }
379
380
381 Value *Parser::parse_struct() {
382     size_t id = read_uint();
383
384     StructSig *sig = lookup(structs, id);
385     if (!sig) {
386         sig = new StructSig;
387         sig->id = id;
388         sig->name = read_string();
389         sig->num_members = read_uint();
390         const char **member_names = new const char *[sig->num_members];
391         for (unsigned i = 0; i < sig->num_members; ++i) {
392             member_names[i] = read_string();
393         }
394         sig->member_names = member_names;
395         structs[id] = sig;
396     }
397     assert(sig);
398
399     Struct *value = new Struct(sig);
400
401     for (size_t i = 0; i < sig->num_members; ++i) {
402         value->members[i] = parse_value();
403     }
404
405     return value;
406 }
407
408
409 Value *Parser::parse_opaque() {
410     unsigned long long addr;
411     addr = read_uint();
412     return new Pointer(addr);
413 }
414
415
416 const char * Parser::read_string(void) {
417     size_t len = read_uint();
418     char * value = new char[len + 1];
419     if (len) {
420         file->read(value, (unsigned)len);
421     }
422     value[len] = 0;
423 #if TRACE_VERBOSE
424     std::cerr << "\tSTRING \"" << value << "\"\n";
425 #endif
426     return value;
427 }
428
429
430 unsigned long long Parser::read_uint(void) {
431     unsigned long long value = 0;
432     int c;
433     unsigned shift = 0;
434     do {
435         c = file->getc();
436         if (c == -1) {
437             break;
438         }
439         value |= (unsigned long long)(c & 0x7f) << shift;
440         shift += 7;
441     } while(c & 0x80);
442 #if TRACE_VERBOSE
443     std::cerr << "\tUINT " << value << "\n";
444 #endif
445     return value;
446 }
447
448
449 inline int Parser::read_byte(void) {
450     int c = file->getc();
451 #if TRACE_VERBOSE
452     if (c < 0)
453         std::cerr << "\tEOF" << "\n";
454     else
455         std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
456 #endif
457     return c;
458 }
459
460
461 } /* namespace Trace */