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