]> git.cworth.org Git - apitrace/blob - common/trace_parser.cpp
Remove FunctionSig::backtrace member.
[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     Backtrace* backtrace = new Backtrace();
521     StackFrame* frame = NULL;
522     do {
523         int c = read_byte();
524         switch (c) {
525         case trace::CALL_BACKTRACE_FRAME:
526             if (frame != NULL) {
527                 backtrace->addFrame(frame);
528             }
529             frame = new StackFrame();
530             break;
531         case trace::CALL_BACKTRACE_END:
532             if (frame != NULL) {
533                 backtrace->addFrame(frame);
534             }
535             call->backtrace = backtrace;
536             return true;
537         case trace::CALL_BACKTRACE_MODULE:
538             frame->module = static_cast<String*>(parse_value(mode));
539             break;
540         case trace::CALL_BACKTRACE_FUNCTION:
541             frame->function = static_cast<String*>(parse_value(mode));
542             break;
543         case trace::CALL_BACKTRACE_FILENAME:
544             frame->filename = static_cast<String*>(parse_value(mode));
545             break;
546         case trace::CALL_BACKTRACE_LINENUMBER:
547             frame->linenumber = static_cast<String*>(parse_value(mode));
548             break;
549         case trace::CALL_BACKTRACE_OFFSET:
550             frame->offset = static_cast<String*>(parse_value(mode));
551             break;
552         default:
553             std::cerr << "error: ("<< call->name() << ") unknown call backtrace detail "
554                       << c << "\n";
555             exit(1);
556         case -1:
557             return false;
558         }
559     } while(true);
560 }
561
562 /**
563  * Make adjustments to this particular call flags.
564  *
565  * NOTE: This is called per-call so no string comparisons should be done here.
566  * All name comparisons should be done when the signature is parsed instead.
567  */
568 void Parser::adjust_call_flags(Call *call) {
569     // Mark glGetError() = GL_NO_ERROR as verbose
570     if (call->sig == glGetErrorSig &&
571         call->ret &&
572         call->ret->toSInt() == 0) {
573         call->flags |= CALL_FLAG_VERBOSE;
574     }
575 }
576
577 void Parser::parse_arg(Call *call, Mode mode) {
578     unsigned index = read_uint();
579     Value *value = parse_value(mode);
580     if (value) {
581         if (index >= call->args.size()) {
582             call->args.resize(index + 1);
583         }
584         call->args[index].value = value;
585     }
586 }
587
588
589 Value *Parser::parse_value(void) {
590     int c;
591     Value *value;
592     c = read_byte();
593     switch (c) {
594     case trace::TYPE_NULL:
595         value = new Null;
596         break;
597     case trace::TYPE_FALSE:
598         value = new Bool(false);
599         break;
600     case trace::TYPE_TRUE:
601         value = new Bool(true);
602         break;
603     case trace::TYPE_SINT:
604         value = parse_sint();
605         break;
606     case trace::TYPE_UINT:
607         value = parse_uint();
608         break;
609     case trace::TYPE_FLOAT:
610         value = parse_float();
611         break;
612     case trace::TYPE_DOUBLE:
613         value = parse_double();
614         break;
615     case trace::TYPE_STRING:
616         value = parse_string();
617         break;
618     case trace::TYPE_ENUM:
619         value = parse_enum();
620         break;
621     case trace::TYPE_BITMASK:
622         value = parse_bitmask();
623         break;
624     case trace::TYPE_ARRAY:
625         value = parse_array();
626         break;
627     case trace::TYPE_STRUCT:
628         value = parse_struct();
629         break;
630     case trace::TYPE_BLOB:
631         value = parse_blob();
632         break;
633     case trace::TYPE_OPAQUE:
634         value = parse_opaque();
635         break;
636     case trace::TYPE_REPR:
637         value = parse_repr();
638         break;
639     default:
640         std::cerr << "error: unknown type " << c << "\n";
641         exit(1);
642     case -1:
643         value = NULL;
644         break;
645     }
646 #if TRACE_VERBOSE
647     if (value) {
648         std::cerr << "\tVALUE ";
649         trace::dump(value, std::cerr);
650         std::cerr << "\n";
651     }
652 #endif
653     return value;
654 }
655
656
657 void Parser::scan_value(void) {
658     int c = read_byte();
659     switch (c) {
660     case trace::TYPE_NULL:
661     case trace::TYPE_FALSE:
662     case trace::TYPE_TRUE:
663         break;
664     case trace::TYPE_SINT:
665         scan_sint();
666         break;
667     case trace::TYPE_UINT:
668         scan_uint();
669         break;
670     case trace::TYPE_FLOAT:
671         scan_float();
672         break;
673     case trace::TYPE_DOUBLE:
674         scan_double();
675         break;
676     case trace::TYPE_STRING:
677         scan_string();
678         break;
679     case trace::TYPE_ENUM:
680         scan_enum();
681         break;
682     case trace::TYPE_BITMASK:
683         scan_bitmask();
684         break;
685     case trace::TYPE_ARRAY:
686         scan_array();
687         break;
688     case trace::TYPE_STRUCT:
689         scan_struct();
690         break;
691     case trace::TYPE_BLOB:
692         scan_blob();
693         break;
694     case trace::TYPE_OPAQUE:
695         scan_opaque();
696         break;
697     case trace::TYPE_REPR:
698         scan_repr();
699         break;
700     default:
701         std::cerr << "error: unknown type " << c << "\n";
702         exit(1);
703     case -1:
704         break;
705     }
706 }
707
708
709 Value *Parser::parse_sint() {
710     return new SInt(-(signed long long)read_uint());
711 }
712
713
714 void Parser::scan_sint() {
715     skip_uint();
716 }
717
718
719 Value *Parser::parse_uint() {
720     return new UInt(read_uint());
721 }
722
723
724 void Parser::scan_uint() {
725     skip_uint();
726 }
727
728
729 Value *Parser::parse_float() {
730     float value;
731     file->read(&value, sizeof value);
732     return new Float(value);
733 }
734
735
736 void Parser::scan_float() {
737     file->skip(sizeof(float));
738 }
739
740
741 Value *Parser::parse_double() {
742     double value;
743     file->read(&value, sizeof value);
744     return new Double(value);
745 }
746
747
748 void Parser::scan_double() {
749     file->skip(sizeof(double));
750 }
751
752
753 Value *Parser::parse_string() {
754     return new String(read_string());
755 }
756
757
758 void Parser::scan_string() {
759     skip_string();
760 }
761
762
763 Value *Parser::parse_enum() {
764     EnumSig *sig;
765     signed long long value;
766     if (version >= 3) {
767         sig = parse_enum_sig();
768         value = read_sint();
769     } else {
770         sig = parse_old_enum_sig();
771         assert(sig->num_values == 1);
772         value = sig->values->value;
773     }
774     return new Enum(sig, value);
775 }
776
777
778 void Parser::scan_enum() {
779     if (version >= 3) {
780         parse_enum_sig();
781         skip_sint();
782     } else {
783         parse_old_enum_sig();
784     }
785 }
786
787
788 Value *Parser::parse_bitmask() {
789     BitmaskSig *sig = parse_bitmask_sig();
790
791     unsigned long long value = read_uint();
792
793     return new Bitmask(sig, value);
794 }
795
796
797 void Parser::scan_bitmask() {
798     parse_bitmask_sig();
799     skip_uint(); /* value */
800 }
801
802
803 Value *Parser::parse_array(void) {
804     size_t len = read_uint();
805     Array *array = new Array(len);
806     for (size_t i = 0; i < len; ++i) {
807         array->values[i] = parse_value();
808     }
809     return array;
810 }
811
812
813 void Parser::scan_array(void) {
814     size_t len = read_uint();
815     for (size_t i = 0; i < len; ++i) {
816         scan_value();
817     }
818 }
819
820
821 Value *Parser::parse_blob(void) {
822     size_t size = read_uint();
823     Blob *blob = new Blob(size);
824     if (size) {
825         file->read(blob->buf, size);
826     }
827     return blob;
828 }
829
830
831 void Parser::scan_blob(void) {
832     size_t size = read_uint();
833     if (size) {
834         file->skip(size);
835     }
836 }
837
838
839 Value *Parser::parse_struct() {
840     StructSig *sig = parse_struct_sig();
841     Struct *value = new Struct(sig);
842
843     for (size_t i = 0; i < sig->num_members; ++i) {
844         value->members[i] = parse_value();
845     }
846
847     return value;
848 }
849
850
851 void Parser::scan_struct() {
852     StructSig *sig = parse_struct_sig();
853     for (size_t i = 0; i < sig->num_members; ++i) {
854         scan_value();
855     }
856 }
857
858
859 Value *Parser::parse_opaque() {
860     unsigned long long addr;
861     addr = read_uint();
862     return new Pointer(addr);
863 }
864
865
866 void Parser::scan_opaque() {
867     skip_uint();
868 }
869
870
871 Value *Parser::parse_repr() {
872     Value *humanValue = parse_value();
873     Value *machineValue = parse_value();
874     return new Repr(humanValue, machineValue);
875 }
876
877
878 void Parser::scan_repr() {
879     scan_value();
880     scan_value();
881 }
882
883
884 const char * Parser::read_string(void) {
885     size_t len = read_uint();
886     char * value = new char[len + 1];
887     if (len) {
888         file->read(value, len);
889     }
890     value[len] = 0;
891 #if TRACE_VERBOSE
892     std::cerr << "\tSTRING \"" << value << "\"\n";
893 #endif
894     return value;
895 }
896
897
898 void Parser::skip_string(void) {
899     size_t len = read_uint();
900     file->skip(len);
901 }
902
903
904 /*
905  * For the time being, a signed int is encoded as any other value, but we here parse
906  * it without the extra baggage of the Value class.
907  */
908 signed long long
909 Parser::read_sint(void) {
910     int c;
911     c = read_byte();
912     switch (c) {
913     case trace::TYPE_SINT:
914         return -(signed long long)read_uint();
915     case trace::TYPE_UINT:
916         return read_uint();
917     default:
918         std::cerr << "error: unexpected type " << c << "\n";
919         exit(1);
920     case -1:
921         return 0;
922     }
923 }
924
925 void
926 Parser::skip_sint(void) {
927     skip_byte();
928     skip_uint();
929 }
930
931 unsigned long long Parser::read_uint(void) {
932     unsigned long long value = 0;
933     int c;
934     unsigned shift = 0;
935     do {
936         c = file->getc();
937         if (c == -1) {
938             break;
939         }
940         value |= (unsigned long long)(c & 0x7f) << shift;
941         shift += 7;
942     } while(c & 0x80);
943 #if TRACE_VERBOSE
944     std::cerr << "\tUINT " << value << "\n";
945 #endif
946     return value;
947 }
948
949
950 void Parser::skip_uint(void) {
951     int c;
952     do {
953         c = file->getc();
954         if (c == -1) {
955             break;
956         }
957     } while(c & 0x80);
958 }
959
960
961 inline int Parser::read_byte(void) {
962     int c = file->getc();
963 #if TRACE_VERBOSE
964     if (c < 0)
965         std::cerr << "\tEOF" << "\n";
966     else
967         std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
968 #endif
969     return c;
970 }
971
972
973 inline void Parser::skip_byte(void) {
974     file->skip(1);
975 }
976
977
978 } /* namespace trace */