]> git.cworth.org Git - apitrace/blob - trace_parser.cpp
Merge branch 'master' into multi-context
[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 <zlib.h>
32
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     file = gzopen(filename, "rb");
56     if (!file) {
57         return false;
58     }
59
60     version = read_uint();
61     if (version > TRACE_VERSION) {
62         std::cerr << "error: unsupported 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(const Container &c)
82 {
83     deleteAll(c.begin(), c.end());
84 }
85
86 void Parser::close(void) {
87     if (file) {
88         gzclose(file);
89         file = NULL;
90     }
91
92     deleteAll(calls);
93     deleteAll(functions);
94     deleteAll(structs);
95     deleteAll(enums);
96     deleteAll(bitmasks);
97 }
98
99
100 Call *Parser::parse_call(void) {
101     do {
102         int c = read_byte();
103         switch(c) {
104         case Trace::EVENT_ENTER:
105             parse_enter();
106             break;
107         case Trace::EVENT_LEAVE:
108             return parse_leave();
109         case Trace::EVENT_MESSAGE:
110             std::cerr << "message: " << read_string() << "\n";
111             break;
112         default:
113             std::cerr << "error: unknown event " << c << "\n";
114             exit(1);
115         case -1:
116             return NULL;
117         }
118     } while(true);
119 }
120
121
122 /**
123  * Helper function to lookup an ID in a vector, resizing the vector if it doesn't fit.
124  */
125 template<class T>
126 T *lookup(std::vector<T *> &map, size_t index) {
127     if (index >= map.size()) {
128         map.resize(index + 1);
129         return NULL;
130     } else {
131         return map[index];
132     }
133 }
134
135
136 void Parser::parse_enter(void) {
137     size_t id = read_uint();
138
139     Call::Signature *sig = lookup(functions, id);
140     if (!sig) {
141         sig = new Call::Signature;
142         sig->name = read_string();
143         unsigned size = read_uint();
144         for (unsigned i = 0; i < size; ++i) {
145             sig->arg_names.push_back(read_string());
146         }
147         functions[id] = sig;
148     }
149     assert(sig);
150
151     Call *call = new Call(sig);
152     call->no = next_call_no++;
153
154     if (parse_call_details(call)) {
155         calls.push_back(call);
156     } else {
157         delete call;
158     }
159 }
160
161
162 Call *Parser::parse_leave(void) {
163     unsigned call_no = read_uint();
164     Call *call = NULL;
165     for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
166         if ((*it)->no == call_no) {
167             call = *it;
168             calls.erase(it);
169             break;
170         }
171     }
172     if (!call) {
173         return NULL;
174     }
175
176     if (parse_call_details(call)) {
177         return call;
178     } else {
179         delete call;
180         return NULL;
181     }
182 }
183
184
185 bool Parser::parse_call_details(Call *call) {
186     do {
187         int c = read_byte();
188         switch(c) {
189         case Trace::CALL_END:
190             return true;
191         case Trace::CALL_ARG:
192             parse_arg(call);
193             break;
194         case Trace::CALL_RET:
195             call->ret = parse_value();
196             break;
197         default:
198             std::cerr << "error: unknown call detail " << c << "\n";
199             exit(1);
200         case -1:
201             return false;
202         }
203     } while(true);
204 }
205
206
207 void Parser::parse_arg(Call *call) {
208     unsigned index = read_uint();
209     Value *value = parse_value();
210     if (index >= call->args.size()) {
211         call->args.resize(index + 1);
212     }
213     call->args[index] = value;
214 }
215
216
217 Value *Parser::parse_value(void) {
218     int c;
219     c = read_byte();
220     switch(c) {
221     case Trace::TYPE_NULL:
222         return new Null;
223     case Trace::TYPE_FALSE:
224         return new Bool(false);
225     case Trace::TYPE_TRUE:
226         return new Bool(true);
227     case Trace::TYPE_SINT:
228         return parse_sint();
229     case Trace::TYPE_UINT:
230         return parse_uint();
231     case Trace::TYPE_FLOAT:
232         return parse_float();
233     case Trace::TYPE_DOUBLE:
234         return parse_double();
235     case Trace::TYPE_STRING:
236         return parse_string();
237     case Trace::TYPE_ENUM:
238         return parse_enum();
239     case Trace::TYPE_BITMASK:
240         return parse_bitmask();
241     case Trace::TYPE_ARRAY:
242         return parse_array();
243     case Trace::TYPE_STRUCT:
244         return parse_struct();
245     case Trace::TYPE_BLOB:
246         return parse_blob();
247     case Trace::TYPE_OPAQUE:
248         return parse_opaque();
249     default:
250         std::cerr << "error: unknown type " << c << "\n";
251         exit(1);
252     case -1:
253         return NULL;
254     }
255 }
256
257
258 Value *Parser::parse_sint() {
259     return new SInt(-(signed long long)read_uint());
260 }
261
262
263 Value *Parser::parse_uint() {
264     return new UInt(read_uint());
265 }
266
267
268 Value *Parser::parse_float() {
269     float value;
270     gzread(file, &value, sizeof value);
271     return new Float(value);
272 }
273
274
275 Value *Parser::parse_double() {
276     double value;
277     gzread(file, &value, sizeof value);
278     return new Float(value);
279 }
280
281
282 Value *Parser::parse_string() {
283     return new String(read_string());
284 }
285
286
287 Value *Parser::parse_enum() {
288     size_t id = read_uint();
289     Enum::Signature *sig = lookup(enums, id);
290     if (!sig) {
291         std::string name = read_string();
292         Value *value = parse_value();
293         sig = new Enum::Signature(name, value);
294         enums[id] = sig;
295     }
296     assert(sig);
297     return new Enum(sig);
298 }
299
300
301 Value *Parser::parse_bitmask() {
302     size_t id = read_uint();
303     Bitmask::Signature *sig = lookup(bitmasks, id);
304     if (!sig) {
305         size_t size = read_uint();
306         sig = new Bitmask::Signature(size);
307         for (Bitmask::Signature::iterator it = sig->begin(); it != sig->end(); ++it) {
308             it->first = read_string();
309             it->second = read_uint();
310             if (it->second == 0 && it != sig->begin()) {
311                 std::cerr << "warning: bitmask " << it->first << " is zero but is not first flag\n";
312             }
313         }
314         bitmasks[id] = sig;
315     }
316     assert(sig);
317
318     unsigned long long value = read_uint();
319
320     return new Bitmask(sig, value);
321 }
322
323
324 Value *Parser::parse_array(void) {
325     size_t len = read_uint();
326     Array *array = new Array(len);
327     for (size_t i = 0; i < len; ++i) {
328         array->values[i] = parse_value();
329     }
330     return array;
331 }
332
333
334 Value *Parser::parse_blob(void) {
335     size_t size = read_uint();
336     Blob *blob = new Blob(size);
337     if (size) {
338         gzread(file, blob->buf, (unsigned)size);
339     }
340     return blob;
341 }
342
343
344 Value *Parser::parse_struct() {
345     size_t id = read_uint();
346
347     Struct::Signature *sig = lookup(structs, id);
348     if (!sig) {
349         sig = new Struct::Signature;
350         sig->name = read_string();
351         unsigned size = read_uint();
352         for (unsigned i = 0; i < size; ++i) {
353             sig->member_names.push_back(read_string());
354         }
355         structs[id] = sig;
356     }
357     assert(sig);
358
359     Struct *value = new Struct(sig);
360
361     for (size_t i = 0; i < sig->member_names.size(); ++i) {
362         value->members[i] = parse_value();
363     }
364
365     return value;
366 }
367
368
369 Value *Parser::parse_opaque() {
370     unsigned long long addr;
371     addr = read_uint();
372     return new Pointer(addr);
373 }
374
375
376 std::string Parser::read_string(void) {
377     size_t len = read_uint();
378     if (!len) {
379         return std::string();
380     }
381     char * buf = new char[len];
382     gzread(file, buf, (unsigned)len);
383     std::string value(buf, len);
384     delete [] buf;
385 #if TRACE_VERBOSE
386     std::cerr << "\tSTRING \"" << value << "\"\n";
387 #endif
388     return value;
389 }
390
391
392 unsigned long long Parser::read_uint(void) {
393     unsigned long long value = 0;
394     int c;
395     unsigned shift = 0;
396     do {
397         c = gzgetc(file);
398         if (c == -1) {
399             break;
400         }
401         value |= (unsigned long long)(c & 0x7f) << shift;
402         shift += 7;
403     } while(c & 0x80);
404 #if TRACE_VERBOSE
405     std::cerr << "\tUINT " << value << "\n";
406 #endif
407     return value;
408 }
409
410
411 inline int Parser::read_byte(void) {
412     int c = gzgetc(file);
413 #if TRACE_VERBOSE
414     if (c < 0)
415         std::cerr << "\tEOF" << "\n";
416     else
417         std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
418 #endif
419     return c;
420 }
421
422
423 } /* namespace Trace */