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