]> git.cworth.org Git - apitrace/blob - trace_parser.cpp
3d53b8fc1864371de4cb6f407df17fbb269cf879
[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             assert(it->second);
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 */