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