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