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