]> git.cworth.org Git - apitrace/blob - trace_parser.cpp
Parse the signatures only once.
[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_snappyfile.hpp"
33 #include "trace_parser.hpp"
34
35
36 #define TRACE_VERBOSE 0
37
38
39 namespace Trace {
40
41
42 Parser::Parser() {
43     file = NULL;
44     next_call_no = 0;
45     version = 0;
46     m_supportsSeeking = false;
47 }
48
49
50 Parser::~Parser() {
51     close();
52 }
53
54
55 bool Parser::open(const char *filename) {
56     assert(!file);
57     if (File::isZLibCompressed(filename)) {
58         file = new ZLibFile;
59     } else {
60         file = new SnappyFile;
61     }
62
63     if (!file->open(filename, File::Read)) {
64         return false;
65     }
66     m_supportsSeeking = file->supportsOffsets();
67
68     version = read_uint();
69     if (version > TRACE_VERSION) {
70         std::cerr << "error: unsupported trace format version " << version << "\n";
71         return false;
72     }
73
74     return true;
75 }
76
77 template <typename Iter>
78 inline void
79 deleteAll(Iter begin, Iter end)
80 {
81     while (begin != end) {
82         delete *begin;
83         ++begin;
84     }
85 }
86
87 template <typename Container>
88 inline void
89 deleteAll(Container &c)
90 {
91     deleteAll(c.begin(), c.end());
92     c.clear();
93 }
94
95 void Parser::close(void) {
96     if (file) {
97         file->close();
98         delete file;
99         file = NULL;
100     }
101
102     deleteAll(calls);
103     deleteAll(functions);
104     deleteAll(structs);
105     deleteAll(enums);
106     deleteAll(bitmasks);
107 }
108
109
110 Call *Parser::parse_call(void) {
111     do {
112         int c = read_byte();
113         switch(c) {
114         case Trace::EVENT_ENTER:
115             parse_enter();
116             break;
117         case Trace::EVENT_LEAVE:
118             return parse_leave();
119         default:
120             std::cerr << "error: unknown event " << c << "\n";
121             exit(1);
122         case -1:
123             for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
124                 std::cerr << "warning: incomplete call " << (*it)->name() << "\n";
125                 std::cerr << **it << "\n";
126             }
127             return NULL;
128         }
129     } while(true);
130 }
131
132
133 /**
134  * Helper function to lookup an ID in a vector, resizing the vector if it doesn't fit.
135  */
136 template<class T>
137 T *lookup(std::vector<T *> &map, size_t index) {
138     if (index >= map.size()) {
139         map.resize(index + 1);
140         return NULL;
141     } else {
142         return map[index];
143     }
144 }
145
146
147 FunctionSig *Parser::parse_function_sig(void) {
148     size_t id = read_uint();
149
150     FunctionSigState *sig = lookup(functions, id);
151
152     if (!sig) {
153         /* parse the signature */
154         sig = new FunctionSigState;
155         sig->id = id;
156         sig->name = read_string();
157         sig->num_args = read_uint();
158         const char **arg_names = new const char *[sig->num_args];
159         for (unsigned i = 0; i < sig->num_args; ++i) {
160             arg_names[i] = read_string();
161         }
162         sig->arg_names = arg_names;
163         if (m_supportsSeeking) {
164             sig->offset = file->currentOffset();
165         }
166         functions[id] = sig;
167     } else if (file->currentOffset() < sig->offset) {
168         /* skip over the signature */
169         skip_string(); /* name */
170         int num_args = read_uint();
171         for (unsigned i = 0; i < num_args; ++i) {
172              skip_string(); /*arg_name*/
173         }
174     }
175
176     assert(sig);
177     return sig;
178 }
179
180 void Parser::parse_enter(void) {
181     FunctionSig *sig = parse_function_sig();
182
183     Call *call = new Call(sig);
184
185     call->no = next_call_no++;
186
187     if (parse_call_details(call)) {
188         calls.push_back(call);
189     } else {
190         delete call;
191     }
192 }
193
194
195 Call *Parser::parse_leave(void) {
196     unsigned call_no = read_uint();
197     Call *call = NULL;
198     for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
199         if ((*it)->no == call_no) {
200             call = *it;
201             calls.erase(it);
202             break;
203         }
204     }
205     if (!call) {
206         return NULL;
207     }
208
209     if (parse_call_details(call)) {
210         return call;
211     } else {
212         delete call;
213         return NULL;
214     }
215 }
216
217
218 bool Parser::parse_call_details(Call *call) {
219     do {
220         int c = read_byte();
221         switch(c) {
222         case Trace::CALL_END:
223             return true;
224         case Trace::CALL_ARG:
225             parse_arg(call);
226             break;
227         case Trace::CALL_RET:
228             call->ret = parse_value();
229             break;
230         default:
231             std::cerr << "error: ("<<call->name()<< ") unknown call detail "
232                       << c << "\n";
233             exit(1);
234         case -1:
235             return false;
236         }
237     } while(true);
238 }
239
240
241 void Parser::parse_arg(Call *call) {
242     unsigned index = read_uint();
243     Value *value = parse_value();
244     if (index >= call->args.size()) {
245         call->args.resize(index + 1);
246     }
247     call->args[index] = value;
248 }
249
250
251 Value *Parser::parse_value(void) {
252     int c;
253     Value *value;
254     c = read_byte();
255     switch(c) {
256     case Trace::TYPE_NULL:
257         value = new Null;
258         break;
259     case Trace::TYPE_FALSE:
260         value = new Bool(false);
261         break;
262     case Trace::TYPE_TRUE:
263         value = new Bool(true);
264         break;
265     case Trace::TYPE_SINT:
266         value = parse_sint();
267         break;
268     case Trace::TYPE_UINT:
269         value = parse_uint();
270         break;
271     case Trace::TYPE_FLOAT:
272         value = parse_float();
273         break;
274     case Trace::TYPE_DOUBLE:
275         value = parse_double();
276         break;
277     case Trace::TYPE_STRING:
278         value = parse_string();
279         break;
280     case Trace::TYPE_ENUM:
281         value = parse_enum();
282         break;
283     case Trace::TYPE_BITMASK:
284         value = parse_bitmask();
285         break;
286     case Trace::TYPE_ARRAY:
287         value = parse_array();
288         break;
289     case Trace::TYPE_STRUCT:
290         value = parse_struct();
291         break;
292     case Trace::TYPE_BLOB:
293         value = parse_blob();
294         break;
295     case Trace::TYPE_OPAQUE:
296         value = parse_opaque();
297         break;
298     default:
299         std::cerr << "error: unknown type " << c << "\n";
300         exit(1);
301     case -1:
302         value = NULL;
303         break;
304     }
305 #if TRACE_VERBOSE
306     if (value) {
307         std::cerr << "\tVALUE " << value << "\n";
308     }
309 #endif
310     return value;
311 }
312
313
314 Value *Parser::parse_sint() {
315     return new SInt(-(signed long long)read_uint());
316 }
317
318
319 Value *Parser::parse_uint() {
320     return new UInt(read_uint());
321 }
322
323
324 Value *Parser::parse_float() {
325     float value;
326     file->read(&value, sizeof value);
327     return new Float(value);
328 }
329
330
331 Value *Parser::parse_double() {
332     double value;
333     file->read(&value, sizeof value);
334     return new Float(value);
335 }
336
337
338 Value *Parser::parse_string() {
339     return new String(read_string());
340 }
341
342
343 EnumSig *Parser::parse_enum_sig() {
344     size_t id = read_uint();
345
346     EnumSigState *sig = lookup(enums, id);
347
348     if (!sig) {
349         /* parse the signature */
350         sig = new EnumSigState;
351         sig->id = id;
352         sig->name = read_string();
353         Value *value = parse_value();
354         sig->value = value->toSInt();
355         delete value;
356         sig->offset = file->currentOffset();
357         enums[id] = sig;
358     } else if (file->currentOffset() < sig->offset) {
359         /* skip over the signature */
360         skip_string(); /*name*/
361         scan_value();
362     }
363
364     assert(sig);
365     return sig;
366 }
367
368 Value *Parser::parse_enum() {
369     EnumSig *sig = parse_enum_sig();
370     return new Enum(sig);
371 }
372
373
374 BitmaskSig *Parser::parse_bitmask_sig() {
375     size_t id = read_uint();
376
377     BitmaskSigState *sig = lookup(bitmasks, id);
378
379     if (!sig) {
380         /* parse the signature */
381         sig = new BitmaskSigState;
382         sig->id = id;
383         sig->num_flags = read_uint();
384         BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
385         for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
386             it->name = read_string();
387             it->value = read_uint();
388             if (it->value == 0 && it != flags) {
389                 std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
390             }
391         }
392         sig->flags = flags;
393         sig->offset = file->currentOffset();
394         bitmasks[id] = sig;
395     } else if (file->currentOffset() < sig->offset) {
396         /* skip over the signature */
397         int num_flags = read_uint();
398         for (int i = 0; i < num_flags; ++i) {
399             skip_string(); /*name */
400             skip_uint(); /* value */
401         }
402     }
403
404     assert(sig);
405     return sig;
406 }
407
408
409 Value *Parser::parse_bitmask() {
410     BitmaskSig *sig = parse_bitmask_sig();
411
412     unsigned long long value = read_uint();
413
414     return new Bitmask(sig, value);
415 }
416
417
418 Value *Parser::parse_array(void) {
419     size_t len = read_uint();
420     Array *array = new Array(len);
421     for (size_t i = 0; i < len; ++i) {
422         array->values[i] = parse_value();
423     }
424     return array;
425 }
426
427
428 Value *Parser::parse_blob(void) {
429     size_t size = read_uint();
430     Blob *blob = new Blob(size);
431     if (size) {
432         file->read(blob->buf, (unsigned)size);
433     }
434     return blob;
435 }
436
437
438 StructSig *Parser::parse_struct_sig() {
439     size_t id = read_uint();
440
441     StructSigState *sig = lookup(structs, id);
442
443     if (!sig) {
444         /* parse the signature */
445         sig = new StructSigState;
446         sig->id = id;
447         sig->name = read_string();
448         sig->num_members = read_uint();
449         const char **member_names = new const char *[sig->num_members];
450         for (unsigned i = 0; i < sig->num_members; ++i) {
451             member_names[i] = read_string();
452         }
453         sig->member_names = member_names;
454         sig->offset = file->currentOffset();
455         structs[id] = sig;
456     } else if (file->currentOffset() < sig->offset) {
457         /* skip over the signature */
458         skip_string(); /* name */
459         unsigned num_members = read_uint();
460         for (unsigned i = 0; i < num_members; ++i) {
461             skip_string(); /* member_name */
462         }
463     }
464
465     assert(sig);
466     return sig;
467 }
468
469 Value *Parser::parse_struct() {
470     StructSig *sig = parse_struct_sig();
471     Struct *value = new Struct(sig);
472
473     for (size_t i = 0; i < sig->num_members; ++i) {
474         value->members[i] = parse_value();
475     }
476
477     return value;
478 }
479
480
481 Value *Parser::parse_opaque() {
482     unsigned long long addr;
483     addr = read_uint();
484     return new Pointer(addr);
485 }
486
487
488 const char * Parser::read_string(void) {
489     size_t len = read_uint();
490     char * value = new char[len + 1];
491     if (len) {
492         file->read(value, (unsigned)len);
493     }
494     value[len] = 0;
495 #if TRACE_VERBOSE
496     std::cerr << "\tSTRING \"" << value << "\"\n";
497 #endif
498     return value;
499 }
500
501
502 unsigned long long Parser::read_uint(void) {
503     unsigned long long value = 0;
504     int c;
505     unsigned shift = 0;
506     do {
507         c = file->getc();
508         if (c == -1) {
509             break;
510         }
511         value |= (unsigned long long)(c & 0x7f) << shift;
512         shift += 7;
513     } while(c & 0x80);
514 #if TRACE_VERBOSE
515     std::cerr << "\tUINT " << value << "\n";
516 #endif
517     return value;
518 }
519
520
521 inline int Parser::read_byte(void) {
522     int c = file->getc();
523 #if TRACE_VERBOSE
524     if (c < 0)
525         std::cerr << "\tEOF" << "\n";
526     else
527         std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
528 #endif
529     return c;
530 }
531
532
533 Call * Parser::scan_call()
534 {
535     assert(m_supportsSeeking);
536     do {
537         int c = read_byte();
538         switch(c) {
539         case Trace::EVENT_ENTER:
540             scan_enter();
541             break;
542         case Trace::EVENT_LEAVE:
543             return scan_leave();
544         default:
545             std::cerr << "error: unknown event " << c << "\n";
546             exit(1);
547         case -1:
548             for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
549                 std::cerr << "warning: incomplete call " << (*it)->name() << "\n";
550                 std::cerr << **it << "\n";
551             }
552             return NULL;
553         }
554     } while (true);
555 }
556
557 void Parser::scan_enter(void) {
558     FunctionSig *sig = parse_function_sig();
559
560     Call *call = new Call(sig);
561     call->no = next_call_no++;
562
563     if (scan_call_details(call)) {
564         calls.push_back(call);
565     } else {
566         delete call;
567     }
568 }
569
570 Call *Parser::scan_leave(void) {
571     unsigned call_no = read_uint();
572     Call *call = NULL;
573     for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
574         if ((*it)->no == call_no) {
575             call = *it;
576             calls.erase(it);
577             break;
578         }
579     }
580     if (!call) {
581         return NULL;
582     }
583
584     if (scan_call_details(call)) {
585         return call;
586     } else {
587         delete call;
588         return NULL;
589     }
590 }
591
592 bool Parser::scan_call_details(Call *call) {
593     do {
594         int c = read_byte();
595         switch(c) {
596         case Trace::CALL_END:
597             return true;
598         case Trace::CALL_ARG:
599             scan_arg(call);
600             break;
601         case Trace::CALL_RET:
602             scan_value();
603             break;
604         default:
605             std::cerr << "error: ("<<call->name()<< ") unknown call detail "
606                       << c << "\n";
607             exit(1);
608         case -1:
609             return false;
610         }
611     } while(true);
612 }
613
614 void Parser::scan_arg(Call *call) {
615     skip_uint(); /* index */
616     scan_value(); /* value */
617 }
618
619
620 void Parser::scan_value(void) {
621     int c = read_byte();
622     switch(c) {
623     case Trace::TYPE_NULL:
624     case Trace::TYPE_FALSE:
625     case Trace::TYPE_TRUE:
626         break;
627     case Trace::TYPE_SINT:
628         scan_sint();
629         break;
630     case Trace::TYPE_UINT:
631         scan_uint();
632         break;
633     case Trace::TYPE_FLOAT:
634         scan_float();
635         break;
636     case Trace::TYPE_DOUBLE:
637         scan_double();
638         break;
639     case Trace::TYPE_STRING:
640         scan_string();
641         break;
642     case Trace::TYPE_ENUM:
643         scan_enum();
644         break;
645     case Trace::TYPE_BITMASK:
646         scan_bitmask();
647         break;
648     case Trace::TYPE_ARRAY:
649         scan_array();
650         break;
651     case Trace::TYPE_STRUCT:
652         scan_struct();
653         break;
654     case Trace::TYPE_BLOB:
655         scan_blob();
656         break;
657     case Trace::TYPE_OPAQUE:
658         scan_opaque();
659         break;
660     default:
661         std::cerr << "error: unknown type " << c << "\n";
662         exit(1);
663     case -1:
664         break;
665     }
666 }
667
668
669 void Parser::scan_sint() {
670     skip_uint();
671 }
672
673
674 void Parser::scan_uint() {
675     skip_uint();
676 }
677
678
679 void Parser::scan_float() {
680     file->skip(sizeof(float));
681 }
682
683
684 void Parser::scan_double() {
685     file->skip(sizeof(double));
686 }
687
688
689 void Parser::scan_string() {
690     skip_string();
691 }
692
693
694 void Parser::scan_enum() {
695     parse_enum_sig();
696 }
697
698
699 void Parser::scan_bitmask() {
700     parse_bitmask_sig();
701     skip_uint(); /* value */
702 }
703
704
705 void Parser::scan_array(void) {
706     size_t len = read_uint();
707     for (size_t i = 0; i < len; ++i) {
708         scan_value();
709     }
710 }
711
712
713 void Parser::scan_blob(void) {
714     size_t size = read_uint();
715     if (size) {
716         file->skip(size);
717     }
718 }
719
720
721 void Parser::scan_struct() {
722     StructSig *sig = parse_struct_sig();
723     for (size_t i = 0; i < sig->num_members; ++i) {
724         scan_value();
725     }
726 }
727
728
729 void Parser::scan_opaque() {
730     skip_uint();
731 }
732
733
734 void Parser::skip_string(void) {
735     size_t len = read_uint();
736     file->skip(len);
737 }
738
739
740 void Parser::skip_uint(void) {
741     int c;
742     do {
743         c = file->getc();
744         if (c == -1) {
745             break;
746         }
747     } while(c & 0x80);
748 }
749
750
751 inline void Parser::skip_byte(void) {
752     file->skip(1);
753 }
754
755
756 } /* namespace Trace */