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