]> git.cworth.org Git - apitrace/blob - common/trace_parser.cpp
Fix typo in wgl function call detection.
[apitrace] / common / 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 #include <string.h>
31
32 #include "trace_file.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     api = API_UNKNOWN;
47
48     glGetErrorSig = NULL;
49 }
50
51
52 Parser::~Parser() {
53     close();
54 }
55
56
57 bool Parser::open(const char *filename) {
58     assert(!file);
59     file = File::createForRead(filename);
60     if (!file) {
61         return false;
62     }
63
64     version = read_uint();
65     if (version > TRACE_VERSION) {
66         std::cerr << "error: unsupported trace format version " << version << "\n";
67         return false;
68     }
69     api = API_UNKNOWN;
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(Container &c)
87 {
88     deleteAll(c.begin(), c.end());
89     c.clear();
90 }
91
92 void Parser::close(void) {
93     if (file) {
94         file->close();
95         delete file;
96         file = NULL;
97     }
98
99     deleteAll(calls);
100
101     // Delete all signature data.  Signatures are mere structures which don't
102     // own their own memory, so we need to destroy all data we created here.
103
104     for (FunctionMap::iterator it = functions.begin(); it != functions.end(); ++it) {
105         FunctionSigState *sig = *it;
106         if (sig) {
107             delete [] sig->name;
108             for (unsigned arg = 0; arg < sig->num_args; ++arg) {
109                 delete [] sig->arg_names[arg];
110             }
111             delete [] sig->arg_names;
112             delete sig;
113         }
114     }
115     functions.clear();
116
117     for (StructMap::iterator it = structs.begin(); it != structs.end(); ++it) {
118         StructSigState *sig = *it;
119         if (sig) {
120             delete [] sig->name;
121             for (unsigned member = 0; member < sig->num_members; ++member) {
122                 delete [] sig->member_names[member];
123             }
124             delete [] sig->member_names;
125             delete sig;
126         }
127     }
128     structs.clear();
129
130     for (EnumMap::iterator it = enums.begin(); it != enums.end(); ++it) {
131         EnumSigState *sig = *it;
132         if (sig) {
133             for (unsigned value = 0; value < sig->num_values; ++value) {
134                 delete [] sig->values[value].name;
135             }
136             delete [] sig->values;
137             delete sig;
138         }
139     }
140     enums.clear();
141     
142     for (BitmaskMap::iterator it = bitmasks.begin(); it != bitmasks.end(); ++it) {
143         BitmaskSigState *sig = *it;
144         if (sig) {
145             for (unsigned flag = 0; flag < sig->num_flags; ++flag) {
146                 delete [] sig->flags[flag].name;
147             }
148             delete [] sig->flags;
149             delete sig;
150         }
151     }
152     bitmasks.clear();
153
154     next_call_no = 0;
155 }
156
157
158 void Parser::getBookmark(ParseBookmark &bookmark) {
159     bookmark.offset = file->currentOffset();
160     bookmark.next_call_no = next_call_no;
161 }
162
163
164 void Parser::setBookmark(const ParseBookmark &bookmark) {
165     file->setCurrentOffset(bookmark.offset);
166     next_call_no = bookmark.next_call_no;
167     
168     // Simply ignore all pending calls
169     deleteAll(calls);
170 }
171
172
173 Call *Parser::parse_call(Mode mode) {
174     do {
175         Call *call;
176         int c = read_byte();
177         switch (c) {
178         case trace::EVENT_ENTER:
179             parse_enter(mode);
180             break;
181         case trace::EVENT_LEAVE:
182             call = parse_leave(mode);
183             adjust_call_flags(call);
184             return call;
185         default:
186             std::cerr << "error: unknown event " << c << "\n";
187             exit(1);
188         case -1:
189             if (!calls.empty()) {
190                 call = calls.front();
191                 call->flags |= CALL_FLAG_INCOMPLETE;
192                 calls.pop_front();
193                 adjust_call_flags(call);
194                 return call;
195             }
196             return NULL;
197         }
198     } while(true);
199 }
200
201
202 /**
203  * Helper function to lookup an ID in a vector, resizing the vector if it doesn't fit.
204  */
205 template<class T>
206 T *lookup(std::vector<T *> &map, size_t index) {
207     if (index >= map.size()) {
208         map.resize(index + 1);
209         return NULL;
210     } else {
211         return map[index];
212     }
213 }
214
215
216 Parser::FunctionSigFlags *
217 Parser::parse_function_sig(void) {
218     size_t id = read_uint();
219
220     FunctionSigState *sig = lookup(functions, id);
221
222     if (!sig) {
223         /* parse the signature */
224         sig = new FunctionSigState;
225         sig->id = id;
226         sig->name = read_string();
227         sig->num_args = read_uint();
228         const char **arg_names = new const char *[sig->num_args];
229         for (unsigned i = 0; i < sig->num_args; ++i) {
230             arg_names[i] = read_string();
231         }
232         sig->arg_names = arg_names;
233         sig->flags = lookupCallFlags(sig->name);
234         sig->offset = file->currentOffset();
235         functions[id] = sig;
236
237         /**
238          * Try to autodetect the API.
239          *
240          * XXX: Ideally we would allow to mix multiple APIs in a single trace,
241          * but as it stands today, retrace is done separately for each API.
242          */
243         if (api == API_UNKNOWN) {
244             const char *n = sig->name;
245             if ((n[0] == 'g' && n[1] == 'l' && n[2] == 'X') || // glX
246                 (n[0] == 'w' && n[1] == 'g' && n[2] == 'l' && n[3] >= 'A' && n[3] <= 'Z') || // wgl[A-Z]
247                 (n[0] == 'C' && n[1] == 'G' && n[2] == 'L')) { // CGL
248                 api = trace::API_GL;
249             } else if (n[0] == 'e' && n[1] == 'g' && n[2] == 'l' && n[3] >= 'A' && n[3] <= 'Z') { // egl
250                 api = trace::API_EGL;
251             } else {
252                 /* TODO */
253             }
254         }
255
256         /**
257          * Note down the signature of special functions for future reference.
258          *
259          * NOTE: If the number of comparisons increases we should move this to a
260          * separate function and use bisection.
261          */
262         if (sig->num_args == 0 &&
263             strcmp(sig->name, "glGetError") == 0) {
264             glGetErrorSig = sig;
265         }
266
267     } else if (file->currentOffset() < sig->offset) {
268         /* skip over the signature */
269         skip_string(); /* name */
270         unsigned num_args = read_uint();
271         for (unsigned i = 0; i < num_args; ++i) {
272              skip_string(); /*arg_name*/
273         }
274     }
275
276     assert(sig);
277     return sig;
278 }
279
280
281 StructSig *Parser::parse_struct_sig() {
282     size_t id = read_uint();
283
284     StructSigState *sig = lookup(structs, id);
285
286     if (!sig) {
287         /* parse the signature */
288         sig = new StructSigState;
289         sig->id = id;
290         sig->name = read_string();
291         sig->num_members = read_uint();
292         const char **member_names = new const char *[sig->num_members];
293         for (unsigned i = 0; i < sig->num_members; ++i) {
294             member_names[i] = read_string();
295         }
296         sig->member_names = member_names;
297         sig->offset = file->currentOffset();
298         structs[id] = sig;
299     } else if (file->currentOffset() < sig->offset) {
300         /* skip over the signature */
301         skip_string(); /* name */
302         unsigned num_members = read_uint();
303         for (unsigned i = 0; i < num_members; ++i) {
304             skip_string(); /* member_name */
305         }
306     }
307
308     assert(sig);
309     return sig;
310 }
311
312
313 /*
314  * Old enum signatures would cover a single name/value only:
315  *
316  *   enum_sig = id name value
317  *            | id
318  */
319 EnumSig *Parser::parse_old_enum_sig() {
320     size_t id = read_uint();
321
322     EnumSigState *sig = lookup(enums, id);
323
324     if (!sig) {
325         /* parse the signature */
326         sig = new EnumSigState;
327         sig->id = id;
328         sig->num_values = 1;
329         EnumValue *values = new EnumValue[sig->num_values];
330         values->name = read_string();
331         values->value = read_sint();
332         sig->values = values;
333         sig->offset = file->currentOffset();
334         enums[id] = sig;
335     } else if (file->currentOffset() < sig->offset) {
336         /* skip over the signature */
337         skip_string(); /*name*/
338         scan_value();
339     }
340
341     assert(sig);
342     return sig;
343 }
344
345
346 EnumSig *Parser::parse_enum_sig() {
347     size_t id = read_uint();
348
349     EnumSigState *sig = lookup(enums, id);
350
351     if (!sig) {
352         /* parse the signature */
353         sig = new EnumSigState;
354         sig->id = id;
355         sig->num_values = read_uint();
356         EnumValue *values = new EnumValue[sig->num_values];
357         for (EnumValue *it = values; it != values + sig->num_values; ++it) {
358             it->name = read_string();
359             it->value = read_sint();
360         }
361         sig->values = values;
362         sig->offset = file->currentOffset();
363         enums[id] = sig;
364     } else if (file->currentOffset() < sig->offset) {
365         /* skip over the signature */
366         int num_values = read_uint();
367         for (int i = 0; i < num_values; ++i) {
368             skip_string(); /*name */
369             skip_sint(); /* value */
370         }
371     }
372
373     assert(sig);
374     return sig;
375 }
376
377
378 BitmaskSig *Parser::parse_bitmask_sig() {
379     size_t id = read_uint();
380
381     BitmaskSigState *sig = lookup(bitmasks, id);
382
383     if (!sig) {
384         /* parse the signature */
385         sig = new BitmaskSigState;
386         sig->id = id;
387         sig->num_flags = read_uint();
388         BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
389         for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
390             it->name = read_string();
391             it->value = read_uint();
392             if (it->value == 0 && it != flags) {
393                 std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
394             }
395         }
396         sig->flags = flags;
397         sig->offset = file->currentOffset();
398         bitmasks[id] = sig;
399     } else if (file->currentOffset() < sig->offset) {
400         /* skip over the signature */
401         int num_flags = read_uint();
402         for (int i = 0; i < num_flags; ++i) {
403             skip_string(); /*name */
404             skip_uint(); /* value */
405         }
406     }
407
408     assert(sig);
409     return sig;
410 }
411
412
413 void Parser::parse_enter(Mode mode) {
414     unsigned thread_id;
415
416     if (version >= 4) {
417         thread_id = read_uint();
418     } else {
419         thread_id = 0;
420     }
421
422     FunctionSigFlags *sig = parse_function_sig();
423
424     Call *call = new Call(sig, sig->flags, thread_id);
425
426     call->no = next_call_no++;
427
428     if (parse_call_details(call, mode)) {
429         calls.push_back(call);
430     } else {
431         delete call;
432     }
433 }
434
435
436 Call *Parser::parse_leave(Mode mode) {
437     unsigned call_no = read_uint();
438     Call *call = NULL;
439     for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
440         if ((*it)->no == call_no) {
441             call = *it;
442             calls.erase(it);
443             break;
444         }
445     }
446     if (!call) {
447         return NULL;
448     }
449
450     if (parse_call_details(call, mode)) {
451         return call;
452     } else {
453         delete call;
454         return NULL;
455     }
456 }
457
458
459 bool Parser::parse_call_details(Call *call, Mode mode) {
460     do {
461         int c = read_byte();
462         switch (c) {
463         case trace::CALL_END:
464             return true;
465         case trace::CALL_ARG:
466             parse_arg(call, mode);
467             break;
468         case trace::CALL_RET:
469             call->ret = parse_value(mode);
470             break;
471         default:
472             std::cerr << "error: ("<<call->name()<< ") unknown call detail "
473                       << c << "\n";
474             exit(1);
475         case -1:
476             return false;
477         }
478     } while(true);
479 }
480
481
482 /**
483  * Make adjustments to this particular call flags.
484  *
485  * NOTE: This is called per-call so no string comparisons should be done here.
486  * All name comparisons should be done when the signature is parsed instead.
487  */
488 void Parser::adjust_call_flags(Call *call) {
489     // Mark glGetError() = GL_NO_ERROR as verbose
490     if (call->sig == glGetErrorSig &&
491         call->ret &&
492         call->ret->toSInt() == 0) {
493         call->flags |= CALL_FLAG_VERBOSE;
494     }
495 }
496
497 void Parser::parse_arg(Call *call, Mode mode) {
498     unsigned index = read_uint();
499     Value *value = parse_value(mode);
500     if (value) {
501         if (index >= call->args.size()) {
502             call->args.resize(index + 1);
503         }
504         call->args[index].value = value;
505     }
506 }
507
508
509 Value *Parser::parse_value(void) {
510     int c;
511     Value *value;
512     c = read_byte();
513     switch (c) {
514     case trace::TYPE_NULL:
515         value = new Null;
516         break;
517     case trace::TYPE_FALSE:
518         value = new Bool(false);
519         break;
520     case trace::TYPE_TRUE:
521         value = new Bool(true);
522         break;
523     case trace::TYPE_SINT:
524         value = parse_sint();
525         break;
526     case trace::TYPE_UINT:
527         value = parse_uint();
528         break;
529     case trace::TYPE_FLOAT:
530         value = parse_float();
531         break;
532     case trace::TYPE_DOUBLE:
533         value = parse_double();
534         break;
535     case trace::TYPE_STRING:
536         value = parse_string();
537         break;
538     case trace::TYPE_ENUM:
539         value = parse_enum();
540         break;
541     case trace::TYPE_BITMASK:
542         value = parse_bitmask();
543         break;
544     case trace::TYPE_ARRAY:
545         value = parse_array();
546         break;
547     case trace::TYPE_STRUCT:
548         value = parse_struct();
549         break;
550     case trace::TYPE_BLOB:
551         value = parse_blob();
552         break;
553     case trace::TYPE_OPAQUE:
554         value = parse_opaque();
555         break;
556     default:
557         std::cerr << "error: unknown type " << c << "\n";
558         exit(1);
559     case -1:
560         value = NULL;
561         break;
562     }
563 #if TRACE_VERBOSE
564     if (value) {
565         std::cerr << "\tVALUE " << value << "\n";
566     }
567 #endif
568     return value;
569 }
570
571
572 void Parser::scan_value(void) {
573     int c = read_byte();
574     switch (c) {
575     case trace::TYPE_NULL:
576     case trace::TYPE_FALSE:
577     case trace::TYPE_TRUE:
578         break;
579     case trace::TYPE_SINT:
580         scan_sint();
581         break;
582     case trace::TYPE_UINT:
583         scan_uint();
584         break;
585     case trace::TYPE_FLOAT:
586         scan_float();
587         break;
588     case trace::TYPE_DOUBLE:
589         scan_double();
590         break;
591     case trace::TYPE_STRING:
592         scan_string();
593         break;
594     case trace::TYPE_ENUM:
595         scan_enum();
596         break;
597     case trace::TYPE_BITMASK:
598         scan_bitmask();
599         break;
600     case trace::TYPE_ARRAY:
601         scan_array();
602         break;
603     case trace::TYPE_STRUCT:
604         scan_struct();
605         break;
606     case trace::TYPE_BLOB:
607         scan_blob();
608         break;
609     case trace::TYPE_OPAQUE:
610         scan_opaque();
611         break;
612     default:
613         std::cerr << "error: unknown type " << c << "\n";
614         exit(1);
615     case -1:
616         break;
617     }
618 }
619
620
621 Value *Parser::parse_sint() {
622     return new SInt(-(signed long long)read_uint());
623 }
624
625
626 void Parser::scan_sint() {
627     skip_uint();
628 }
629
630
631 Value *Parser::parse_uint() {
632     return new UInt(read_uint());
633 }
634
635
636 void Parser::scan_uint() {
637     skip_uint();
638 }
639
640
641 Value *Parser::parse_float() {
642     float value;
643     file->read(&value, sizeof value);
644     return new Float(value);
645 }
646
647
648 void Parser::scan_float() {
649     file->skip(sizeof(float));
650 }
651
652
653 Value *Parser::parse_double() {
654     double value;
655     file->read(&value, sizeof value);
656     return new Double(value);
657 }
658
659
660 void Parser::scan_double() {
661     file->skip(sizeof(double));
662 }
663
664
665 Value *Parser::parse_string() {
666     return new String(read_string());
667 }
668
669
670 void Parser::scan_string() {
671     skip_string();
672 }
673
674
675 Value *Parser::parse_enum() {
676     EnumSig *sig;
677     signed long long value;
678     if (version >= 3) {
679         sig = parse_enum_sig();
680         value = read_sint();
681     } else {
682         sig = parse_old_enum_sig();
683         assert(sig->num_values == 1);
684         value = sig->values->value;
685     }
686     return new Enum(sig, value);
687 }
688
689
690 void Parser::scan_enum() {
691     if (version >= 3) {
692         parse_enum_sig();
693         skip_sint();
694     } else {
695         parse_old_enum_sig();
696     }
697 }
698
699
700 Value *Parser::parse_bitmask() {
701     BitmaskSig *sig = parse_bitmask_sig();
702
703     unsigned long long value = read_uint();
704
705     return new Bitmask(sig, value);
706 }
707
708
709 void Parser::scan_bitmask() {
710     parse_bitmask_sig();
711     skip_uint(); /* value */
712 }
713
714
715 Value *Parser::parse_array(void) {
716     size_t len = read_uint();
717     Array *array = new Array(len);
718     for (size_t i = 0; i < len; ++i) {
719         array->values[i] = parse_value();
720     }
721     return array;
722 }
723
724
725 void Parser::scan_array(void) {
726     size_t len = read_uint();
727     for (size_t i = 0; i < len; ++i) {
728         scan_value();
729     }
730 }
731
732
733 Value *Parser::parse_blob(void) {
734     size_t size = read_uint();
735     Blob *blob = new Blob(size);
736     if (size) {
737         file->read(blob->buf, (unsigned)size);
738     }
739     return blob;
740 }
741
742
743 void Parser::scan_blob(void) {
744     size_t size = read_uint();
745     if (size) {
746         file->skip(size);
747     }
748 }
749
750
751 Value *Parser::parse_struct() {
752     StructSig *sig = parse_struct_sig();
753     Struct *value = new Struct(sig);
754
755     for (size_t i = 0; i < sig->num_members; ++i) {
756         value->members[i] = parse_value();
757     }
758
759     return value;
760 }
761
762
763 void Parser::scan_struct() {
764     StructSig *sig = parse_struct_sig();
765     for (size_t i = 0; i < sig->num_members; ++i) {
766         scan_value();
767     }
768 }
769
770
771 Value *Parser::parse_opaque() {
772     unsigned long long addr;
773     addr = read_uint();
774     return new Pointer(addr);
775 }
776
777
778 void Parser::scan_opaque() {
779     skip_uint();
780 }
781
782
783 const char * Parser::read_string(void) {
784     size_t len = read_uint();
785     char * value = new char[len + 1];
786     if (len) {
787         file->read(value, (unsigned)len);
788     }
789     value[len] = 0;
790 #if TRACE_VERBOSE
791     std::cerr << "\tSTRING \"" << value << "\"\n";
792 #endif
793     return value;
794 }
795
796
797 void Parser::skip_string(void) {
798     size_t len = read_uint();
799     file->skip(len);
800 }
801
802
803 /*
804  * For the time being, a signed int is encoded as any other value, but we here parse
805  * it without the extra baggage of the Value class.
806  */
807 signed long long
808 Parser::read_sint(void) {
809     int c;
810     c = read_byte();
811     switch (c) {
812     case trace::TYPE_SINT:
813         return -read_uint();
814     case trace::TYPE_UINT:
815         return read_uint();
816     default:
817         std::cerr << "error: unexpected type " << c << "\n";
818         exit(1);
819     case -1:
820         return 0;
821     }
822 }
823
824 void
825 Parser::skip_sint(void) {
826     skip_byte();
827     skip_uint();
828 }
829
830 unsigned long long Parser::read_uint(void) {
831     unsigned long long value = 0;
832     int c;
833     unsigned shift = 0;
834     do {
835         c = file->getc();
836         if (c == -1) {
837             break;
838         }
839         value |= (unsigned long long)(c & 0x7f) << shift;
840         shift += 7;
841     } while(c & 0x80);
842 #if TRACE_VERBOSE
843     std::cerr << "\tUINT " << value << "\n";
844 #endif
845     return value;
846 }
847
848
849 void Parser::skip_uint(void) {
850     int c;
851     do {
852         c = file->getc();
853         if (c == -1) {
854             break;
855         }
856     } while(c & 0x80);
857 }
858
859
860 inline int Parser::read_byte(void) {
861     int c = file->getc();
862 #if TRACE_VERBOSE
863     if (c < 0)
864         std::cerr << "\tEOF" << "\n";
865     else
866         std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
867 #endif
868     return c;
869 }
870
871
872 inline void Parser::skip_byte(void) {
873     file->skip(1);
874 }
875
876
877 } /* namespace trace */