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