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