]> git.cworth.org Git - apitrace/blob - trace_parser.cpp
Switch the gui to the on-demand-loader.
[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 void Parser::parse_enter(void) {
148     size_t id = read_uint();
149
150     FunctionSig *sig = lookup(functions, id);
151
152
153     File::Offset offset;
154     bool callWithSig = false;
155     if (m_supportsSeeking) {
156         offset = file->currentOffset();
157         callWithSig = callWithSignature(offset);
158     }
159
160     if (!sig || callWithSig) {
161         if (!sig) {
162             sig = new FunctionSig;
163             sig->id = id;
164             sig->name = read_string();
165             sig->num_args = read_uint();
166             const char **arg_names = new const char *[sig->num_args];
167             for (unsigned i = 0; i < sig->num_args; ++i) {
168                 arg_names[i] = read_string();
169             }
170             sig->arg_names = arg_names;
171             functions[id] = sig;
172             if (m_supportsSeeking) {
173                 m_callSigOffsets.insert(offset);
174             }
175         } else {
176             /* skip over the signature */
177             skip_string(); /* name */
178             int num_args = read_uint();
179             for (unsigned i = 0; i < num_args; ++i) {
180                  skip_string(); /*arg_name*/
181             }
182         }
183     }
184     assert(sig);
185
186     Call *call = new Call(sig);
187
188
189     call->no = next_call_no++;
190
191     if (parse_call_details(call)) {
192         calls.push_back(call);
193     } else {
194         delete call;
195     }
196 }
197
198
199 Call *Parser::parse_leave(void) {
200     unsigned call_no = read_uint();
201     Call *call = NULL;
202     for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
203         if ((*it)->no == call_no) {
204             call = *it;
205             calls.erase(it);
206             break;
207         }
208     }
209     if (!call) {
210         return NULL;
211     }
212
213     if (parse_call_details(call)) {
214         return call;
215     } else {
216         delete call;
217         return NULL;
218     }
219 }
220
221
222 bool Parser::parse_call_details(Call *call) {
223     do {
224         int c = read_byte();
225         switch(c) {
226         case Trace::CALL_END:
227             return true;
228         case Trace::CALL_ARG:
229             parse_arg(call);
230             break;
231         case Trace::CALL_RET:
232             call->ret = parse_value();
233             break;
234         default:
235             std::cerr << "error: ("<<call->name()<< ") unknown call detail "
236                       << c << "\n";
237             exit(1);
238         case -1:
239             return false;
240         }
241     } while(true);
242 }
243
244
245 void Parser::parse_arg(Call *call) {
246     unsigned index = read_uint();
247     Value *value = parse_value();
248     if (index >= call->args.size()) {
249         call->args.resize(index + 1);
250     }
251     call->args[index] = value;
252 }
253
254
255 Value *Parser::parse_value(void) {
256     int c;
257     Value *value;
258     c = read_byte();
259     switch(c) {
260     case Trace::TYPE_NULL:
261         value = new Null;
262         break;
263     case Trace::TYPE_FALSE:
264         value = new Bool(false);
265         break;
266     case Trace::TYPE_TRUE:
267         value = new Bool(true);
268         break;
269     case Trace::TYPE_SINT:
270         value = parse_sint();
271         break;
272     case Trace::TYPE_UINT:
273         value = parse_uint();
274         break;
275     case Trace::TYPE_FLOAT:
276         value = parse_float();
277         break;
278     case Trace::TYPE_DOUBLE:
279         value = parse_double();
280         break;
281     case Trace::TYPE_STRING:
282         value = parse_string();
283         break;
284     case Trace::TYPE_ENUM:
285         value = parse_enum();
286         break;
287     case Trace::TYPE_BITMASK:
288         value = parse_bitmask();
289         break;
290     case Trace::TYPE_ARRAY:
291         value = parse_array();
292         break;
293     case Trace::TYPE_STRUCT:
294         value = parse_struct();
295         break;
296     case Trace::TYPE_BLOB:
297         value = parse_blob();
298         break;
299     case Trace::TYPE_OPAQUE:
300         value = parse_opaque();
301         break;
302     default:
303         std::cerr << "error: unknown type " << c << "\n";
304         exit(1);
305     case -1:
306         value = NULL;
307         break;
308     }
309 #if TRACE_VERBOSE
310     if (value) {
311         std::cerr << "\tVALUE " << value << "\n";
312     }
313 #endif
314     return value;
315 }
316
317
318 Value *Parser::parse_sint() {
319     return new SInt(-(signed long long)read_uint());
320 }
321
322
323 Value *Parser::parse_uint() {
324     return new UInt(read_uint());
325 }
326
327
328 Value *Parser::parse_float() {
329     float value;
330     file->read(&value, sizeof value);
331     return new Float(value);
332 }
333
334
335 Value *Parser::parse_double() {
336     double value;
337     file->read(&value, sizeof value);
338     return new Float(value);
339 }
340
341
342 Value *Parser::parse_string() {
343     return new String(read_string());
344 }
345
346
347 Value *Parser::parse_enum() {
348     size_t id = read_uint();
349     EnumSig *sig = lookup(enums, id);
350     File::Offset offset;
351     bool enumWithSig = false;
352
353     if (m_supportsSeeking) {
354         offset = file->currentOffset();
355         enumWithSig = enumWithSignature(offset);
356     }
357
358     if (!sig || enumWithSig) {
359         if (!sig) {
360             sig = new EnumSig;
361             sig->id = id;
362             sig->name = read_string();
363             Value *value = parse_value();
364             sig->value = value->toSInt();
365             delete value;
366             enums[id] = sig;
367             if (m_supportsSeeking) {
368                 m_enumSigOffsets.insert(offset);
369             }
370         } else {
371             skip_string(); /*name*/
372             scan_value();
373         }
374     }
375     assert(sig);
376     return new Enum(sig);
377 }
378
379
380 Value *Parser::parse_bitmask() {
381     size_t id = read_uint();
382     BitmaskSig *sig = lookup(bitmasks, id);
383     File::Offset offset;
384     bool bitmaskWithSig = false;
385
386     if (m_supportsSeeking) {
387         offset = file->currentOffset();
388         bitmaskWithSig = bitmaskWithSignature(offset);
389     }
390
391     if (!sig || bitmaskWithSig) {
392         if (!sig) {
393             sig = new BitmaskSig;
394             sig->id = id;
395             sig->num_flags = read_uint();
396             BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
397             for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
398                 it->name = read_string();
399                 it->value = read_uint();
400                 if (it->value == 0 && it != flags) {
401                     std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
402                 }
403             }
404             sig->flags = flags;
405             bitmasks[id] = sig;
406             if (m_supportsSeeking) {
407                 m_bitmaskSigOffsets.insert(offset);
408             }
409         } else {
410             int num_flags = read_uint();
411             for (int i = 0; i < num_flags; ++i) {
412                 skip_string(); /*name */
413                 skip_uint(); /* value */
414             }
415         }
416     }
417     assert(sig);
418
419     unsigned long long value = read_uint();
420
421     return new Bitmask(sig, value);
422 }
423
424
425 Value *Parser::parse_array(void) {
426     size_t len = read_uint();
427     Array *array = new Array(len);
428     for (size_t i = 0; i < len; ++i) {
429         array->values[i] = parse_value();
430     }
431     return array;
432 }
433
434
435 Value *Parser::parse_blob(void) {
436     size_t size = read_uint();
437     Blob *blob = new Blob(size);
438     if (size) {
439         file->read(blob->buf, (unsigned)size);
440     }
441     return blob;
442 }
443
444
445 Value *Parser::parse_struct() {
446     size_t id = read_uint();
447
448     StructSig *sig = lookup(structs, id);
449     File::Offset offset;
450     bool structWithSig = false;
451
452     if (m_supportsSeeking) {
453         offset = file->currentOffset();
454         structWithSig = structWithSignature(offset);
455     }
456
457     if (!sig || structWithSig) {
458         if (!sig) {
459             sig = new StructSig;
460             sig->id = id;
461             sig->name = read_string();
462             sig->num_members = read_uint();
463             const char **member_names = new const char *[sig->num_members];
464             for (unsigned i = 0; i < sig->num_members; ++i) {
465                 member_names[i] = read_string();
466             }
467             sig->member_names = member_names;
468             structs[id] = sig;
469             if (m_supportsSeeking) {
470                 m_structSigOffsets.insert(offset);
471             }
472         } else {
473             skip_string(); /* name */
474             unsigned num_members = read_uint();
475             for (unsigned i = 0; i < num_members; ++i) {
476                 skip_string(); /* member_name */
477             }
478         }
479     }
480     assert(sig);
481
482     Struct *value = new Struct(sig);
483
484     for (size_t i = 0; i < sig->num_members; ++i) {
485         value->members[i] = parse_value();
486     }
487
488     return value;
489 }
490
491
492 Value *Parser::parse_opaque() {
493     unsigned long long addr;
494     addr = read_uint();
495     return new Pointer(addr);
496 }
497
498
499 const char * Parser::read_string(void) {
500     size_t len = read_uint();
501     char * value = new char[len + 1];
502     if (len) {
503         file->read(value, (unsigned)len);
504     }
505     value[len] = 0;
506 #if TRACE_VERBOSE
507     std::cerr << "\tSTRING \"" << value << "\"\n";
508 #endif
509     return value;
510 }
511
512
513 unsigned long long Parser::read_uint(void) {
514     unsigned long long value = 0;
515     int c;
516     unsigned shift = 0;
517     do {
518         c = file->getc();
519         if (c == -1) {
520             break;
521         }
522         value |= (unsigned long long)(c & 0x7f) << shift;
523         shift += 7;
524     } while(c & 0x80);
525 #if TRACE_VERBOSE
526     std::cerr << "\tUINT " << value << "\n";
527 #endif
528     return value;
529 }
530
531
532 inline int Parser::read_byte(void) {
533     int c = file->getc();
534 #if TRACE_VERBOSE
535     if (c < 0)
536         std::cerr << "\tEOF" << "\n";
537     else
538         std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
539 #endif
540     return c;
541 }
542
543
544 inline bool Parser::callWithSignature(const File::Offset &offset) const
545 {
546     return m_callSigOffsets.find(offset) != m_callSigOffsets.end();
547 }
548
549 inline bool Parser::structWithSignature(const File::Offset &offset) const
550 {
551     return m_structSigOffsets.find(offset) != m_structSigOffsets.end();
552 }
553
554 inline bool Parser::enumWithSignature(const File::Offset &offset) const
555 {
556     return m_enumSigOffsets.find(offset) != m_enumSigOffsets.end();
557 }
558
559 inline bool Parser::bitmaskWithSignature(const File::Offset &offset) const
560 {
561     return m_bitmaskSigOffsets.find(offset) != m_bitmaskSigOffsets.end();
562 }
563
564 Call * Parser::scan_call()
565 {
566     assert(m_supportsSeeking);
567     do {
568         int c = read_byte();
569         switch(c) {
570         case Trace::EVENT_ENTER:
571             scan_enter();
572             break;
573         case Trace::EVENT_LEAVE:
574             return scan_leave();
575         default:
576             std::cerr << "error: unknown event " << c << "\n";
577             exit(1);
578         case -1:
579             for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
580                 std::cerr << "warning: incomplete call " << (*it)->name() << "\n";
581                 std::cerr << **it << "\n";
582             }
583             return NULL;
584         }
585     } while (true);
586 }
587
588 void Parser::scan_enter(void) {
589     size_t id = read_uint();
590
591     FunctionSig *sig = lookup(functions, id);
592     const File::Offset offset = file->currentOffset();
593     if (!sig) {
594         sig = new FunctionSig;
595         sig->id = id;
596         sig->name = read_string();
597         sig->num_args = read_uint();
598         const char **arg_names = new const char *[sig->num_args];
599         for (unsigned i = 0; i < sig->num_args; ++i) {
600             arg_names[i] = read_string();
601         }
602         sig->arg_names = arg_names;
603         functions[id] = sig;
604         m_callSigOffsets.insert(offset);
605     }
606     assert(sig);
607
608     Call *call = new Call(sig);
609     call->no = next_call_no++;
610
611     if (scan_call_details(call)) {
612         calls.push_back(call);
613     } else {
614         delete call;
615     }
616 }
617
618 Call *Parser::scan_leave(void) {
619     unsigned call_no = read_uint();
620     Call *call = NULL;
621     for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
622         if ((*it)->no == call_no) {
623             call = *it;
624             calls.erase(it);
625             break;
626         }
627     }
628     if (!call) {
629         return NULL;
630     }
631
632     if (scan_call_details(call)) {
633         return call;
634     } else {
635         delete call;
636         return NULL;
637     }
638 }
639
640 bool Parser::scan_call_details(Call *call) {
641     do {
642         int c = read_byte();
643         switch(c) {
644         case Trace::CALL_END:
645             return true;
646         case Trace::CALL_ARG:
647             scan_arg(call);
648             break;
649         case Trace::CALL_RET:
650             scan_value();
651             break;
652         default:
653             std::cerr << "error: ("<<call->name()<< ") unknown call detail "
654                       << c << "\n";
655             exit(1);
656         case -1:
657             return false;
658         }
659     } while(true);
660 }
661
662 void Parser::scan_arg(Call *call) {
663     skip_uint(); /* index */
664     scan_value(); /* value */
665 }
666
667
668 void Parser::scan_value(void) {
669     int c = read_byte();
670     switch(c) {
671     case Trace::TYPE_NULL:
672     case Trace::TYPE_FALSE:
673     case Trace::TYPE_TRUE:
674         break;
675     case Trace::TYPE_SINT:
676         scan_sint();
677         break;
678     case Trace::TYPE_UINT:
679         scan_uint();
680         break;
681     case Trace::TYPE_FLOAT:
682         scan_float();
683         break;
684     case Trace::TYPE_DOUBLE:
685         scan_double();
686         break;
687     case Trace::TYPE_STRING:
688         scan_string();
689         break;
690     case Trace::TYPE_ENUM:
691         scan_enum();
692         break;
693     case Trace::TYPE_BITMASK:
694         scan_bitmask();
695         break;
696     case Trace::TYPE_ARRAY:
697         scan_array();
698         break;
699     case Trace::TYPE_STRUCT:
700         scan_struct();
701         break;
702     case Trace::TYPE_BLOB:
703         scan_blob();
704         break;
705     case Trace::TYPE_OPAQUE:
706         scan_opaque();
707         break;
708     default:
709         std::cerr << "error: unknown type " << c << "\n";
710         exit(1);
711     case -1:
712         break;
713     }
714 }
715
716
717 void Parser::scan_sint() {
718     skip_uint();
719 }
720
721
722 void Parser::scan_uint() {
723     skip_uint();
724 }
725
726
727 void Parser::scan_float() {
728     file->skip(sizeof(float));
729 }
730
731
732 void Parser::scan_double() {
733     file->skip(sizeof(double));
734 }
735
736
737 void Parser::scan_string() {
738     skip_string();
739 }
740
741
742 void Parser::scan_enum() {
743     size_t id = read_uint();
744     EnumSig *sig = lookup(enums, id);
745     const File::Offset offset = file->currentOffset();
746     if (!sig) {
747         sig = new EnumSig;
748         sig->id = id;
749         sig->name = read_string();
750         Value *value = parse_value();
751         sig->value = value->toSInt();
752         delete value;
753         enums[id] = sig;
754         m_enumSigOffsets.insert(offset);
755     }
756     assert(sig);
757 }
758
759
760 void Parser::scan_bitmask() {
761     size_t id = read_uint();
762     BitmaskSig *sig = lookup(bitmasks, id);
763     const File::Offset offset = file->currentOffset();
764     if (!sig) {
765         sig = new BitmaskSig;
766         sig->id = id;
767         sig->num_flags = read_uint();
768         BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
769         for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
770             it->name = read_string();
771             it->value = read_uint();
772             if (it->value == 0 && it != flags) {
773                 std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
774             }
775         }
776         sig->flags = flags;
777         bitmasks[id] = sig;
778         m_bitmaskSigOffsets.insert(offset);
779     }
780     assert(sig);
781
782     skip_uint(); /* value */
783 }
784
785
786 void Parser::scan_array(void) {
787     size_t len = read_uint();
788     for (size_t i = 0; i < len; ++i) {
789         scan_value();
790     }
791 }
792
793
794 void Parser::scan_blob(void) {
795     size_t size = read_uint();
796     if (size) {
797         file->skip((unsigned)size);
798     }
799 }
800
801
802 void Parser::scan_struct() {
803     size_t id = read_uint();
804
805     StructSig *sig = lookup(structs, id);
806     const File::Offset offset = file->currentOffset();
807     if (!sig) {
808         sig = new StructSig;
809         sig->id = id;
810         sig->name = read_string();
811         sig->num_members = read_uint();
812         const char **member_names = new const char *[sig->num_members];
813         for (unsigned i = 0; i < sig->num_members; ++i) {
814             member_names[i] = read_string();
815         }
816         sig->member_names = member_names;
817         structs[id] = sig;
818         m_structSigOffsets.insert(offset);
819     }
820     assert(sig);
821
822     for (size_t i = 0; i < sig->num_members; ++i) {
823         scan_value();
824     }
825 }
826
827
828 void Parser::scan_opaque() {
829     skip_uint();
830 }
831
832
833 void Parser::skip_string(void) {
834     size_t len = read_uint();
835     file->skip((unsigned)len);
836 }
837
838
839 void Parser::skip_uint(void) {
840     int c;
841     do {
842         c = file->getc();
843         if (c == -1) {
844             break;
845         }
846     } while(c & 0x80);
847 }
848
849
850 inline void Parser::skip_byte(void) {
851     file->skip(1);
852 }
853
854
855 } /* namespace Trace */