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