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