]> git.cworth.org Git - apitrace/blob - trace_parser.cpp
Reset pending call lists on Parser::setBookmark().
[apitrace] / 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
31 #include "trace_file.hpp"
32 #include "trace_snappyfile.hpp"
33 #include "trace_parser.hpp"
34
35
36 #define TRACE_VERBOSE 0
37
38
39 namespace Trace {
40
41
42 Parser::Parser() {
43     file = NULL;
44     next_call_no = 0;
45     version = 0;
46 }
47
48
49 Parser::~Parser() {
50     close();
51 }
52
53
54 bool Parser::open(const char *filename) {
55     assert(!file);
56     if (File::isZLibCompressed(filename)) {
57         file = new ZLibFile;
58     } else {
59         file = new SnappyFile;
60     }
61
62     if (!file->open(filename, File::Read)) {
63         return false;
64     }
65
66     version = read_uint();
67     if (version > TRACE_VERSION) {
68         std::cerr << "error: unsupported trace format version " << version << "\n";
69         return false;
70     }
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     deleteAll(functions);
102     deleteAll(structs);
103     deleteAll(enums);
104     deleteAll(bitmasks);
105 }
106
107
108 void Parser::getBookmark(ParseBookmark &bookmark) {
109     bookmark.offset = file->currentOffset();
110     bookmark.next_call_no = next_call_no;
111 }
112
113
114 void Parser::setBookmark(const ParseBookmark &bookmark) {
115     file->setCurrentOffset(bookmark.offset);
116     next_call_no = bookmark.next_call_no;
117     
118     // Simply ignore all pending calls
119     deleteAll(calls);
120 }
121
122
123 Call *Parser::parse_call(void) {
124     do {
125         int c = read_byte();
126         switch(c) {
127         case Trace::EVENT_ENTER:
128             parse_enter();
129             break;
130         case Trace::EVENT_LEAVE:
131             return parse_leave();
132         default:
133             std::cerr << "error: unknown event " << c << "\n";
134             exit(1);
135         case -1:
136             for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
137                 std::cerr << "warning: incomplete call " << (*it)->name() << "\n";
138                 std::cerr << **it << "\n";
139             }
140             return NULL;
141         }
142     } while(true);
143 }
144
145
146 Call * Parser::scan_call()
147 {
148     do {
149         int c = read_byte();
150         switch(c) {
151         case Trace::EVENT_ENTER:
152             scan_enter();
153             break;
154         case Trace::EVENT_LEAVE:
155             return scan_leave();
156         default:
157             std::cerr << "error: unknown event " << c << "\n";
158             exit(1);
159         case -1:
160             for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
161                 std::cerr << "warning: incomplete call " << (*it)->name() << "\n";
162                 std::cerr << **it << "\n";
163             }
164             return NULL;
165         }
166     } while (true);
167 }
168
169
170 /**
171  * Helper function to lookup an ID in a vector, resizing the vector if it doesn't fit.
172  */
173 template<class T>
174 T *lookup(std::vector<T *> &map, size_t index) {
175     if (index >= map.size()) {
176         map.resize(index + 1);
177         return NULL;
178     } else {
179         return map[index];
180     }
181 }
182
183
184 FunctionSig *Parser::parse_function_sig(void) {
185     size_t id = read_uint();
186
187     FunctionSigState *sig = lookup(functions, id);
188
189     if (!sig) {
190         /* parse the signature */
191         sig = new FunctionSigState;
192         sig->id = id;
193         sig->name = read_string();
194         sig->num_args = read_uint();
195         const char **arg_names = new const char *[sig->num_args];
196         for (unsigned i = 0; i < sig->num_args; ++i) {
197             arg_names[i] = read_string();
198         }
199         sig->arg_names = arg_names;
200         sig->offset = file->currentOffset();
201         functions[id] = sig;
202     } else if (file->currentOffset() < sig->offset) {
203         /* skip over the signature */
204         skip_string(); /* name */
205         int num_args = read_uint();
206         for (unsigned i = 0; i < num_args; ++i) {
207              skip_string(); /*arg_name*/
208         }
209     }
210
211     assert(sig);
212     return sig;
213 }
214
215
216 StructSig *Parser::parse_struct_sig() {
217     size_t id = read_uint();
218
219     StructSigState *sig = lookup(structs, id);
220
221     if (!sig) {
222         /* parse the signature */
223         sig = new StructSigState;
224         sig->id = id;
225         sig->name = read_string();
226         sig->num_members = read_uint();
227         const char **member_names = new const char *[sig->num_members];
228         for (unsigned i = 0; i < sig->num_members; ++i) {
229             member_names[i] = read_string();
230         }
231         sig->member_names = member_names;
232         sig->offset = file->currentOffset();
233         structs[id] = sig;
234     } else if (file->currentOffset() < sig->offset) {
235         /* skip over the signature */
236         skip_string(); /* name */
237         unsigned num_members = read_uint();
238         for (unsigned i = 0; i < num_members; ++i) {
239             skip_string(); /* member_name */
240         }
241     }
242
243     assert(sig);
244     return sig;
245 }
246
247
248 EnumSig *Parser::parse_enum_sig() {
249     size_t id = read_uint();
250
251     EnumSigState *sig = lookup(enums, id);
252
253     if (!sig) {
254         /* parse the signature */
255         sig = new EnumSigState;
256         sig->id = id;
257         sig->name = read_string();
258         Value *value = parse_value();
259         sig->value = value->toSInt();
260         delete value;
261         sig->offset = file->currentOffset();
262         enums[id] = sig;
263     } else if (file->currentOffset() < sig->offset) {
264         /* skip over the signature */
265         skip_string(); /*name*/
266         scan_value();
267     }
268
269     assert(sig);
270     return sig;
271 }
272
273
274 BitmaskSig *Parser::parse_bitmask_sig() {
275     size_t id = read_uint();
276
277     BitmaskSigState *sig = lookup(bitmasks, id);
278
279     if (!sig) {
280         /* parse the signature */
281         sig = new BitmaskSigState;
282         sig->id = id;
283         sig->num_flags = read_uint();
284         BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
285         for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
286             it->name = read_string();
287             it->value = read_uint();
288             if (it->value == 0 && it != flags) {
289                 std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
290             }
291         }
292         sig->flags = flags;
293         sig->offset = file->currentOffset();
294         bitmasks[id] = sig;
295     } else if (file->currentOffset() < sig->offset) {
296         /* skip over the signature */
297         int num_flags = read_uint();
298         for (int i = 0; i < num_flags; ++i) {
299             skip_string(); /*name */
300             skip_uint(); /* value */
301         }
302     }
303
304     assert(sig);
305     return sig;
306 }
307
308
309 void Parser::parse_enter(void) {
310     FunctionSig *sig = parse_function_sig();
311
312     Call *call = new Call(sig);
313
314     call->no = next_call_no++;
315
316     if (parse_call_details(call)) {
317         calls.push_back(call);
318     } else {
319         delete call;
320     }
321 }
322
323
324 void Parser::scan_enter(void) {
325     FunctionSig *sig = parse_function_sig();
326
327     Call *call = new Call(sig);
328     call->no = next_call_no++;
329
330     if (scan_call_details(call)) {
331         calls.push_back(call);
332     } else {
333         delete call;
334     }
335 }
336
337
338 Call *Parser::parse_leave(void) {
339     unsigned call_no = read_uint();
340     Call *call = NULL;
341     for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
342         if ((*it)->no == call_no) {
343             call = *it;
344             calls.erase(it);
345             break;
346         }
347     }
348     if (!call) {
349         return NULL;
350     }
351
352     if (parse_call_details(call)) {
353         return call;
354     } else {
355         delete call;
356         return NULL;
357     }
358 }
359
360
361 Call *Parser::scan_leave(void) {
362     unsigned call_no = read_uint();
363     Call *call = NULL;
364     for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
365         if ((*it)->no == call_no) {
366             call = *it;
367             calls.erase(it);
368             break;
369         }
370     }
371     if (!call) {
372         return NULL;
373     }
374
375     if (scan_call_details(call)) {
376         return call;
377     } else {
378         delete call;
379         return NULL;
380     }
381 }
382
383
384 bool Parser::parse_call_details(Call *call) {
385     do {
386         int c = read_byte();
387         switch(c) {
388         case Trace::CALL_END:
389             return true;
390         case Trace::CALL_ARG:
391             parse_arg(call);
392             break;
393         case Trace::CALL_RET:
394             call->ret = parse_value();
395             break;
396         default:
397             std::cerr << "error: ("<<call->name()<< ") unknown call detail "
398                       << c << "\n";
399             exit(1);
400         case -1:
401             return false;
402         }
403     } while(true);
404 }
405
406
407 bool Parser::scan_call_details(Call *call) {
408     do {
409         int c = read_byte();
410         switch(c) {
411         case Trace::CALL_END:
412             return true;
413         case Trace::CALL_ARG:
414             scan_arg(call);
415             break;
416         case Trace::CALL_RET:
417             scan_value();
418             break;
419         default:
420             std::cerr << "error: ("<<call->name()<< ") unknown call detail "
421                       << c << "\n";
422             exit(1);
423         case -1:
424             return false;
425         }
426     } while(true);
427 }
428
429
430 void Parser::parse_arg(Call *call) {
431     unsigned index = read_uint();
432     Value *value = parse_value();
433     if (index >= call->args.size()) {
434         call->args.resize(index + 1);
435     }
436     call->args[index] = value;
437 }
438
439
440 void Parser::scan_arg(Call *call) {
441     skip_uint(); /* index */
442     scan_value(); /* value */
443 }
444
445
446 Value *Parser::parse_value(void) {
447     int c;
448     Value *value;
449     c = read_byte();
450     switch(c) {
451     case Trace::TYPE_NULL:
452         value = new Null;
453         break;
454     case Trace::TYPE_FALSE:
455         value = new Bool(false);
456         break;
457     case Trace::TYPE_TRUE:
458         value = new Bool(true);
459         break;
460     case Trace::TYPE_SINT:
461         value = parse_sint();
462         break;
463     case Trace::TYPE_UINT:
464         value = parse_uint();
465         break;
466     case Trace::TYPE_FLOAT:
467         value = parse_float();
468         break;
469     case Trace::TYPE_DOUBLE:
470         value = parse_double();
471         break;
472     case Trace::TYPE_STRING:
473         value = parse_string();
474         break;
475     case Trace::TYPE_ENUM:
476         value = parse_enum();
477         break;
478     case Trace::TYPE_BITMASK:
479         value = parse_bitmask();
480         break;
481     case Trace::TYPE_ARRAY:
482         value = parse_array();
483         break;
484     case Trace::TYPE_STRUCT:
485         value = parse_struct();
486         break;
487     case Trace::TYPE_BLOB:
488         value = parse_blob();
489         break;
490     case Trace::TYPE_OPAQUE:
491         value = parse_opaque();
492         break;
493     default:
494         std::cerr << "error: unknown type " << c << "\n";
495         exit(1);
496     case -1:
497         value = NULL;
498         break;
499     }
500 #if TRACE_VERBOSE
501     if (value) {
502         std::cerr << "\tVALUE " << value << "\n";
503     }
504 #endif
505     return value;
506 }
507
508
509 void Parser::scan_value(void) {
510     int c = read_byte();
511     switch(c) {
512     case Trace::TYPE_NULL:
513     case Trace::TYPE_FALSE:
514     case Trace::TYPE_TRUE:
515         break;
516     case Trace::TYPE_SINT:
517         scan_sint();
518         break;
519     case Trace::TYPE_UINT:
520         scan_uint();
521         break;
522     case Trace::TYPE_FLOAT:
523         scan_float();
524         break;
525     case Trace::TYPE_DOUBLE:
526         scan_double();
527         break;
528     case Trace::TYPE_STRING:
529         scan_string();
530         break;
531     case Trace::TYPE_ENUM:
532         scan_enum();
533         break;
534     case Trace::TYPE_BITMASK:
535         scan_bitmask();
536         break;
537     case Trace::TYPE_ARRAY:
538         scan_array();
539         break;
540     case Trace::TYPE_STRUCT:
541         scan_struct();
542         break;
543     case Trace::TYPE_BLOB:
544         scan_blob();
545         break;
546     case Trace::TYPE_OPAQUE:
547         scan_opaque();
548         break;
549     default:
550         std::cerr << "error: unknown type " << c << "\n";
551         exit(1);
552     case -1:
553         break;
554     }
555 }
556
557
558 Value *Parser::parse_sint() {
559     return new SInt(-(signed long long)read_uint());
560 }
561
562
563 void Parser::scan_sint() {
564     skip_uint();
565 }
566
567
568 Value *Parser::parse_uint() {
569     return new UInt(read_uint());
570 }
571
572
573 void Parser::scan_uint() {
574     skip_uint();
575 }
576
577
578 Value *Parser::parse_float() {
579     float value;
580     file->read(&value, sizeof value);
581     return new Float(value);
582 }
583
584
585 void Parser::scan_float() {
586     file->skip(sizeof(float));
587 }
588
589
590 Value *Parser::parse_double() {
591     double value;
592     file->read(&value, sizeof value);
593     return new Float(value);
594 }
595
596
597 void Parser::scan_double() {
598     file->skip(sizeof(double));
599 }
600
601
602 Value *Parser::parse_string() {
603     return new String(read_string());
604 }
605
606
607 void Parser::scan_string() {
608     skip_string();
609 }
610
611
612 Value *Parser::parse_enum() {
613     EnumSig *sig = parse_enum_sig();
614     return new Enum(sig);
615 }
616
617
618 void Parser::scan_enum() {
619     parse_enum_sig();
620 }
621
622
623 Value *Parser::parse_bitmask() {
624     BitmaskSig *sig = parse_bitmask_sig();
625
626     unsigned long long value = read_uint();
627
628     return new Bitmask(sig, value);
629 }
630
631
632 void Parser::scan_bitmask() {
633     parse_bitmask_sig();
634     skip_uint(); /* value */
635 }
636
637
638 Value *Parser::parse_array(void) {
639     size_t len = read_uint();
640     Array *array = new Array(len);
641     for (size_t i = 0; i < len; ++i) {
642         array->values[i] = parse_value();
643     }
644     return array;
645 }
646
647
648 void Parser::scan_array(void) {
649     size_t len = read_uint();
650     for (size_t i = 0; i < len; ++i) {
651         scan_value();
652     }
653 }
654
655
656 Value *Parser::parse_blob(void) {
657     size_t size = read_uint();
658     Blob *blob = new Blob(size);
659     if (size) {
660         file->read(blob->buf, (unsigned)size);
661     }
662     return blob;
663 }
664
665
666 void Parser::scan_blob(void) {
667     size_t size = read_uint();
668     if (size) {
669         file->skip(size);
670     }
671 }
672
673
674 Value *Parser::parse_struct() {
675     StructSig *sig = parse_struct_sig();
676     Struct *value = new Struct(sig);
677
678     for (size_t i = 0; i < sig->num_members; ++i) {
679         value->members[i] = parse_value();
680     }
681
682     return value;
683 }
684
685
686 void Parser::scan_struct() {
687     StructSig *sig = parse_struct_sig();
688     for (size_t i = 0; i < sig->num_members; ++i) {
689         scan_value();
690     }
691 }
692
693
694 Value *Parser::parse_opaque() {
695     unsigned long long addr;
696     addr = read_uint();
697     return new Pointer(addr);
698 }
699
700
701 void Parser::scan_opaque() {
702     skip_uint();
703 }
704
705
706 const char * Parser::read_string(void) {
707     size_t len = read_uint();
708     char * value = new char[len + 1];
709     if (len) {
710         file->read(value, (unsigned)len);
711     }
712     value[len] = 0;
713 #if TRACE_VERBOSE
714     std::cerr << "\tSTRING \"" << value << "\"\n";
715 #endif
716     return value;
717 }
718
719
720 void Parser::skip_string(void) {
721     size_t len = read_uint();
722     file->skip(len);
723 }
724
725
726 unsigned long long Parser::read_uint(void) {
727     unsigned long long value = 0;
728     int c;
729     unsigned shift = 0;
730     do {
731         c = file->getc();
732         if (c == -1) {
733             break;
734         }
735         value |= (unsigned long long)(c & 0x7f) << shift;
736         shift += 7;
737     } while(c & 0x80);
738 #if TRACE_VERBOSE
739     std::cerr << "\tUINT " << value << "\n";
740 #endif
741     return value;
742 }
743
744
745 void Parser::skip_uint(void) {
746     int c;
747     do {
748         c = file->getc();
749         if (c == -1) {
750             break;
751         }
752     } while(c & 0x80);
753 }
754
755
756 inline int Parser::read_byte(void) {
757     int c = file->getc();
758 #if TRACE_VERBOSE
759     if (c < 0)
760         std::cerr << "\tEOF" << "\n";
761     else
762         std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
763 #endif
764     return c;
765 }
766
767
768 inline void Parser::skip_byte(void) {
769     file->skip(1);
770 }
771
772
773 } /* namespace Trace */