blob: 6b519a07e8155b8e66d75830b2bcf53d9e773986 [file] [log] [blame]
José Fonseca7e329022010-11-19 17:05:18 +00001/**************************************************************************
2 *
3 * Copyright 2010 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 **************************************************************************/
25
26#ifndef _TRACE_PARSER_HPP_
27#define _TRACE_PARSER_HPP_
28
29
30#include <cassert>
31
32#include <iostream>
José Fonsecafa922142010-11-25 09:36:04 +000033#include <map>
José Fonseca89851d02010-11-28 12:16:52 +000034#include <list>
José Fonsecafa922142010-11-25 09:36:04 +000035#include <string>
José Fonseca7e329022010-11-19 17:05:18 +000036
37#include <zlib.h>
38
39#include "trace_format.hpp"
40#include "trace_model.hpp"
41
42
José Fonsecaf4b071e2010-11-25 15:48:46 +000043#define TRACE_VERBOSE 0
44
45
José Fonseca7e329022010-11-19 17:05:18 +000046namespace Trace {
47
48
49class Parser
50{
51protected:
52 gzFile file;
José Fonsecafa922142010-11-25 09:36:04 +000053
José Fonseca89851d02010-11-28 12:16:52 +000054 typedef std::list<Call *> CallList;
55 CallList calls;
José Fonseca34957132010-11-25 16:14:45 +000056
José Fonsecabfd33e92010-11-28 12:32:12 +000057 typedef std::vector<Call::Signature *> FunctionMap;
José Fonseca2250a0e2010-11-26 15:01:29 +000058 FunctionMap functions;
59
José Fonsecabfd33e92010-11-28 12:32:12 +000060 typedef std::vector<Struct::Signature *> StructMap;
José Fonseca7eef8ce2010-11-26 15:46:36 +000061 StructMap structs;
62
José Fonsecabfd33e92010-11-28 12:32:12 +000063 typedef std::vector<Enum *> EnumMap;
José Fonsecaf84c70e2010-11-26 15:26:14 +000064 EnumMap enums;
65
José Fonsecabfd33e92010-11-28 12:32:12 +000066 typedef std::vector<Bitmask::Signature *> BitmaskMap;
José Fonsecad35973c2010-11-26 14:14:45 +000067 BitmaskMap bitmasks;
68
José Fonseca34957132010-11-25 16:14:45 +000069 unsigned next_call_no;
70
José Fonseca7e329022010-11-19 17:05:18 +000071public:
72 Parser() {
73 file = NULL;
José Fonseca34957132010-11-25 16:14:45 +000074 next_call_no = 0;
José Fonseca7e329022010-11-19 17:05:18 +000075 }
76
José Fonseca6f51d3b2010-11-22 19:56:19 +000077 ~Parser() {
78 close();
79 }
80
81 bool open(const char *filename) {
José Fonseca7e329022010-11-19 17:05:18 +000082 unsigned long long version;
83
84 file = gzopen(filename, "rb");
85 if (!file) {
86 return false;
87 }
88
89 version = read_uint();
90 if (version != TRACE_VERSION) {
José Fonseca501f2862010-11-19 20:41:18 +000091 std::cerr << "error: unsupported format version" << version << "\n";
José Fonseca7e329022010-11-19 17:05:18 +000092 return false;
93 }
94
José Fonseca7e329022010-11-19 17:05:18 +000095 return true;
96 }
97
José Fonseca6f51d3b2010-11-22 19:56:19 +000098 void close(void) {
99 if (file) {
100 gzclose(file);
101 file = NULL;
102 }
103 }
104
105 Call *parse_call(void) {
José Fonseca34957132010-11-25 16:14:45 +0000106 do {
107 int c = read_byte();
108 switch(c) {
109 case Trace::EVENT_ENTER:
110 parse_enter();
111 break;
112 case Trace::EVENT_LEAVE:
113 return parse_leave();
114 case Trace::EVENT_MESSAGE:
115 std::cerr << "message: " << read_string() << "\n";
116 break;
117 default:
118 std::cerr << "error: unknown call detail " << c << "\n";
119 assert(0);
120 /* fallthrough */
121 case -1:
122 return NULL;
123 }
124 } while(true);
125 }
José Fonsecabfd33e92010-11-28 12:32:12 +0000126
127 /**
128 * Helper function to lookup an ID in a vector, resizing the vector if it doesn't fit.
129 */
130 template<class T>
131 T *lookup(std::vector<T *> &map, size_t index) {
132 if (index >= map.size()) {
133 map.resize(index + 1);
134 return NULL;
135 } else {
136 return map[index];
137 }
138 }
139
José Fonseca34957132010-11-25 16:14:45 +0000140 void parse_enter(void) {
José Fonseca2250a0e2010-11-26 15:01:29 +0000141 size_t id = read_uint();
142
José Fonsecabfd33e92010-11-28 12:32:12 +0000143 Call::Signature *sig = lookup(functions, id);
144 if (!sig) {
José Fonseca2250a0e2010-11-26 15:01:29 +0000145 sig = new Call::Signature;
146 sig->name = read_string();
147 unsigned size = read_uint();
148 for (unsigned i = 0; i < size; ++i) {
149 sig->arg_names.push_back(read_string());
150 }
151 functions[id] = sig;
José Fonseca2250a0e2010-11-26 15:01:29 +0000152 }
153 assert(sig);
154
155 Call *call = new Call(sig);
José Fonseca34957132010-11-25 16:14:45 +0000156 call->no = next_call_no++;
José Fonseca2250a0e2010-11-26 15:01:29 +0000157
José Fonseca34957132010-11-25 16:14:45 +0000158 parse_call_details(call);
José Fonseca89851d02010-11-28 12:16:52 +0000159
160 calls.push_back(call);
José Fonseca34957132010-11-25 16:14:45 +0000161 }
162
163 Call *parse_leave(void) {
164 unsigned call_no = read_uint();
José Fonseca89851d02010-11-28 12:16:52 +0000165
166 Call *call = NULL;
167 for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
168 if ((*it)->no == call_no) {
169 call = *it;
170 calls.erase(it);
171 break;
172 }
173 }
José Fonseca34957132010-11-25 16:14:45 +0000174 assert(call);
175 if (!call) {
176 return NULL;
177 }
178 parse_call_details(call);
179 return call;
180 }
181
182 void parse_call_details(Call *call) {
José Fonseca7e329022010-11-19 17:05:18 +0000183 do {
José Fonseca6f51d3b2010-11-22 19:56:19 +0000184 int c = read_byte();
José Fonseca7e329022010-11-19 17:05:18 +0000185 switch(c) {
186 case Trace::CALL_END:
José Fonseca34957132010-11-25 16:14:45 +0000187 return;
José Fonseca7e329022010-11-19 17:05:18 +0000188 case Trace::CALL_ARG:
José Fonsecadce84c42010-11-24 16:19:49 +0000189 parse_arg(call);
José Fonseca7e329022010-11-19 17:05:18 +0000190 break;
191 case Trace::CALL_RET:
José Fonseca6f51d3b2010-11-22 19:56:19 +0000192 call->ret = parse_value();
José Fonseca7e329022010-11-19 17:05:18 +0000193 break;
194 default:
José Fonseca501f2862010-11-19 20:41:18 +0000195 std::cerr << "error: unknown call detail " << c << "\n";
José Fonseca885f2652010-11-20 11:22:25 +0000196 assert(0);
José Fonseca6f51d3b2010-11-22 19:56:19 +0000197 /* fallthrough */
198 case -1:
José Fonseca34957132010-11-25 16:14:45 +0000199 return;
José Fonseca7e329022010-11-19 17:05:18 +0000200 }
201 } while(true);
José Fonseca7e329022010-11-19 17:05:18 +0000202 }
203
José Fonsecadce84c42010-11-24 16:19:49 +0000204 void parse_arg(Call *call) {
205 unsigned index = read_uint();
José Fonseca7e329022010-11-19 17:05:18 +0000206 Value *value = parse_value();
José Fonsecadce84c42010-11-24 16:19:49 +0000207 if (index >= call->args.size()) {
208 call->args.resize(index + 1);
209 }
José Fonseca2250a0e2010-11-26 15:01:29 +0000210 call->args[index] = value;
José Fonseca7e329022010-11-19 17:05:18 +0000211 }
212
213 Value *parse_value(void) {
214 int c;
José Fonseca5cb3e172010-11-22 16:59:34 +0000215 c = read_byte();
José Fonseca7e329022010-11-19 17:05:18 +0000216 switch(c) {
José Fonsecaf6592d72010-11-21 12:44:41 +0000217 case Trace::TYPE_NULL:
218 return new Null;
José Fonsecab1887f92010-11-21 02:33:38 +0000219 case Trace::TYPE_FALSE:
220 return new Bool(false);
221 case Trace::TYPE_TRUE:
222 return new Bool(true);
José Fonseca7e329022010-11-19 17:05:18 +0000223 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();
José Fonsecaf84c70e2010-11-26 15:26:14 +0000233 case Trace::TYPE_ENUM:
234 return parse_enum();
José Fonseca7e329022010-11-19 17:05:18 +0000235 case Trace::TYPE_BITMASK:
236 return parse_bitmask();
237 case Trace::TYPE_ARRAY:
238 return parse_array();
José Fonseca5cb3e172010-11-22 16:59:34 +0000239 case Trace::TYPE_STRUCT:
240 return parse_struct();
José Fonseca885f2652010-11-20 11:22:25 +0000241 case Trace::TYPE_BLOB:
242 return parse_blob();
José Fonsecaf6592d72010-11-21 12:44:41 +0000243 case Trace::TYPE_OPAQUE:
244 return parse_opaque();
José Fonseca7e329022010-11-19 17:05:18 +0000245 default:
José Fonseca501f2862010-11-19 20:41:18 +0000246 std::cerr << "error: unknown type " << c << "\n";
José Fonseca7e329022010-11-19 17:05:18 +0000247 assert(0);
248 return NULL;
249 }
250 }
251
José Fonseca7e329022010-11-19 17:05:18 +0000252 Value *parse_sint() {
José Fonseca0633bdf2010-11-25 14:54:14 +0000253 return new SInt(-(signed long long)read_uint());
José Fonseca7e329022010-11-19 17:05:18 +0000254 }
255
256 Value *parse_uint() {
257 return new UInt(read_uint());
258 }
259
260 Value *parse_float() {
261 float value;
262 gzread(file, &value, sizeof value);
263 return new Float(value);
264 }
265
266 Value *parse_double() {
267 double value;
268 gzread(file, &value, sizeof value);
269 return new Float(value);
270 }
271
272 Value *parse_string() {
273 return new String(read_string());
274 }
275
José Fonsecaf84c70e2010-11-26 15:26:14 +0000276 Value *parse_enum() {
277 size_t id = read_uint();
José Fonsecabfd33e92010-11-28 12:32:12 +0000278 Enum *sig = lookup(enums, id);
279 if (!sig) {
José Fonsecaf84c70e2010-11-26 15:26:14 +0000280 std::string name = read_string();
281 Value *value = parse_value();
282 sig = new Enum(name, value);
283 enums[id] = sig;
José Fonsecaf84c70e2010-11-26 15:26:14 +0000284 }
285 assert(sig);
286 return sig;
José Fonseca7e329022010-11-19 17:05:18 +0000287 }
288
289 Value *parse_bitmask() {
José Fonsecad35973c2010-11-26 14:14:45 +0000290 size_t id = read_uint();
José Fonsecabfd33e92010-11-28 12:32:12 +0000291 Bitmask::Signature *sig = lookup(bitmasks, id);
292 if (!sig) {
José Fonsecad35973c2010-11-26 14:14:45 +0000293 size_t size = read_uint();
294 sig = new Bitmask::Signature(size);
295 for (Bitmask::Signature::iterator it = sig->begin(); it != sig->end(); ++it) {
296 it->first = read_string();
297 it->second = read_uint();
298 assert(it->second);
299 }
300 bitmasks[id] = sig;
José Fonsecad35973c2010-11-26 14:14:45 +0000301 }
302 assert(sig);
303
304 unsigned long long value = read_uint();
305
306 return new Bitmask(sig, value);
José Fonseca7e329022010-11-19 17:05:18 +0000307 }
308
José Fonseca885f2652010-11-20 11:22:25 +0000309 Value *parse_array(void) {
José Fonseca7e329022010-11-19 17:05:18 +0000310 size_t len = read_uint();
311 Array *array = new Array(len);
312 for (size_t i = 0; i < len; ++i) {
313 array->values[i] = parse_value();
314 }
315 return array;
316 }
317
José Fonseca885f2652010-11-20 11:22:25 +0000318 Value *parse_blob(void) {
319 size_t size = read_uint();
320 Blob *blob = new Blob(size);
321 if (size) {
322 gzread(file, blob->buf, size);
323 }
324 return blob;
325 }
326
José Fonseca5cb3e172010-11-22 16:59:34 +0000327 Value *parse_struct() {
José Fonseca7eef8ce2010-11-26 15:46:36 +0000328 size_t id = read_uint();
329
José Fonsecabfd33e92010-11-28 12:32:12 +0000330 Struct::Signature *sig = lookup(structs, id);
331 if (!sig) {
José Fonseca7eef8ce2010-11-26 15:46:36 +0000332 sig = new Struct::Signature;
333 sig->name = read_string();
334 unsigned size = read_uint();
335 for (unsigned i = 0; i < size; ++i) {
336 sig->member_names.push_back(read_string());
337 }
338 structs[id] = sig;
José Fonseca5cb3e172010-11-22 16:59:34 +0000339 }
José Fonseca7eef8ce2010-11-26 15:46:36 +0000340 assert(sig);
341
342 Struct *value = new Struct(sig);
343
344 for (size_t i = 0; i < sig->member_names.size(); ++i) {
345 value->members[i] = parse_value();
346 }
347
348 return value;
José Fonseca5cb3e172010-11-22 16:59:34 +0000349 }
350
José Fonsecaf6592d72010-11-21 12:44:41 +0000351 Value *parse_opaque() {
352 unsigned long long addr;
353 addr = read_uint();
354 /* XXX */
355 return new UInt(addr);
356 }
José Fonsecafa922142010-11-25 09:36:04 +0000357
José Fonseca7e329022010-11-19 17:05:18 +0000358 std::string read_string(void) {
359 size_t len = read_uint();
José Fonseca5cb3e172010-11-22 16:59:34 +0000360 if (!len) {
361 return std::string();
362 }
José Fonseca7e329022010-11-19 17:05:18 +0000363 char * buf = new char[len];
364 gzread(file, buf, len);
365 std::string value(buf, len);
366 delete [] buf;
José Fonsecaf4b071e2010-11-25 15:48:46 +0000367#if TRACE_VERBOSE
368 std::cerr << "\tSTRING \"" << value << "\"\n";
José Fonseca5cb3e172010-11-22 16:59:34 +0000369#endif
José Fonseca7e329022010-11-19 17:05:18 +0000370 return value;
371 }
372
373 unsigned long long read_uint(void) {
374 unsigned long long value = 0;
375 int c;
376 unsigned shift = 0;
377 do {
378 c = gzgetc(file);
379 if (c == -1) {
380 break;
381 }
382 value |= (unsigned long long)(c & 0x7f) << shift;
383 shift += 7;
384 } while(c & 0x80);
José Fonsecaf4b071e2010-11-25 15:48:46 +0000385#if TRACE_VERBOSE
386 std::cerr << "\tUINT " << value << "\n";
José Fonseca5cb3e172010-11-22 16:59:34 +0000387#endif
José Fonseca7e329022010-11-19 17:05:18 +0000388 return value;
389 }
José Fonseca5cb3e172010-11-22 16:59:34 +0000390
391 int read_byte(void) {
392 int c = gzgetc(file);
José Fonsecaf4b071e2010-11-25 15:48:46 +0000393#if TRACE_VERBOSE
José Fonseca5cb3e172010-11-22 16:59:34 +0000394 if (c < 0)
José Fonsecaf4b071e2010-11-25 15:48:46 +0000395 std::cerr << "\tEOF" << "\n";
José Fonseca5cb3e172010-11-22 16:59:34 +0000396 else
José Fonsecaf4b071e2010-11-25 15:48:46 +0000397 std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
José Fonseca5cb3e172010-11-22 16:59:34 +0000398#endif
399 return c;
400 }
José Fonseca7e329022010-11-19 17:05:18 +0000401};
402
403
404} /* namespace Trace */
405
406#endif /* _TRACE_PARSER_HPP_ */