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