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