blob: dfaf42e4e29d31b9881b6e0283ff5b8e86ef0dc1 [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:
José Fonseca19828972010-11-29 20:34:32 +000052 gzFile file;
José Fonsecafa922142010-11-25 09:36:04 +000053
José Fonseca19828972010-11-29 20:34:32 +000054 typedef std::list<Call *> CallList;
55 CallList calls;
José Fonseca34957132010-11-25 16:14:45 +000056
José Fonseca19828972010-11-29 20:34:32 +000057 typedef std::vector<Call::Signature *> FunctionMap;
58 FunctionMap functions;
José Fonseca2250a0e2010-11-26 15:01:29 +000059
José Fonseca19828972010-11-29 20:34:32 +000060 typedef std::vector<Struct::Signature *> StructMap;
61 StructMap structs;
José Fonseca7eef8ce2010-11-26 15:46:36 +000062
José Fonsecaae9668b2011-02-09 15:15:08 +000063 typedef std::vector<Enum::Signature *> EnumMap;
José Fonseca19828972010-11-29 20:34:32 +000064 EnumMap enums;
José Fonsecaf84c70e2010-11-26 15:26:14 +000065
José Fonseca19828972010-11-29 20:34:32 +000066 typedef std::vector<Bitmask::Signature *> BitmaskMap;
67 BitmaskMap bitmasks;
José Fonsecad35973c2010-11-26 14:14:45 +000068
José Fonseca19828972010-11-29 20:34:32 +000069 unsigned next_call_no;
José Fonseca34957132010-11-25 16:14:45 +000070
José Fonseca7e329022010-11-19 17:05:18 +000071public:
José Fonseca99221832011-03-22 22:15:46 +000072 static unsigned long long version;
73
José Fonseca19828972010-11-29 20:34:32 +000074 Parser() {
75 file = NULL;
76 next_call_no = 0;
77 }
José Fonseca7e329022010-11-19 17:05:18 +000078
José Fonseca19828972010-11-29 20:34:32 +000079 ~Parser() {
80 close();
81 }
José Fonseca6f51d3b2010-11-22 19:56:19 +000082
José Fonseca19828972010-11-29 20:34:32 +000083 bool open(const char *filename) {
José Fonseca19828972010-11-29 20:34:32 +000084 file = gzopen(filename, "rb");
85 if (!file) {
86 return false;
87 }
José Fonseca7e329022010-11-19 17:05:18 +000088
José Fonseca19828972010-11-29 20:34:32 +000089 version = read_uint();
José Fonseca99221832011-03-22 22:15:46 +000090 if (version > TRACE_VERSION) {
José Fonseca19828972010-11-29 20:34:32 +000091 std::cerr << "error: unsupported format version" << version << "\n";
92 return false;
93 }
José Fonseca7e329022010-11-19 17:05:18 +000094
José Fonseca19828972010-11-29 20:34:32 +000095 return true;
96 }
José Fonseca7e329022010-11-19 17:05:18 +000097
José Fonseca19828972010-11-29 20:34:32 +000098 void close(void) {
99 if (file) {
100 gzclose(file);
101 file = NULL;
102 }
103 }
José Fonseca6f51d3b2010-11-22 19:56:19 +0000104
José Fonseca19828972010-11-29 20:34:32 +0000105 Call *parse_call(void) {
106 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 }
126
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);
José Fonseca34957132010-11-25 16:14:45 +0000134 return NULL;
José Fonseca19828972010-11-29 20:34:32 +0000135 } else {
136 return map[index];
137 }
138 }
José Fonsecabfd33e92010-11-28 12:32:12 +0000139
José Fonseca19828972010-11-29 20:34:32 +0000140 void parse_enter(void) {
141 size_t id = read_uint();
José Fonseca2250a0e2010-11-26 15:01:29 +0000142
José Fonseca19828972010-11-29 20:34:32 +0000143 Call::Signature *sig = lookup(functions, id);
144 if (!sig) {
145 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;
152 }
153 assert(sig);
José Fonseca2250a0e2010-11-26 15:01:29 +0000154
José Fonseca19828972010-11-29 20:34:32 +0000155 Call *call = new Call(sig);
156 call->no = next_call_no++;
José Fonseca2250a0e2010-11-26 15:01:29 +0000157
José Fonseca19828972010-11-29 20:34:32 +0000158 parse_call_details(call);
José Fonseca89851d02010-11-28 12:16:52 +0000159
José Fonseca19828972010-11-29 20:34:32 +0000160 calls.push_back(call);
161 }
José Fonseca89851d02010-11-28 12:16:52 +0000162
José Fonseca19828972010-11-29 20:34:32 +0000163 Call *parse_leave(void) {
164 unsigned call_no = read_uint();
165
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 }
174 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) {
183 do {
184 int c = read_byte();
185 switch(c) {
186 case Trace::CALL_END:
187 return;
188 case Trace::CALL_ARG:
189 parse_arg(call);
190 break;
191 case Trace::CALL_RET:
192 call->ret = parse_value();
193 break;
194 default:
195 std::cerr << "error: unknown call detail " << c << "\n";
196 assert(0);
197 /* fallthrough */
198 case -1:
199 return;
200 }
201 } while(true);
202 }
203
204 void parse_arg(Call *call) {
205 unsigned index = read_uint();
206 Value *value = parse_value();
207 if (index >= call->args.size()) {
208 call->args.resize(index + 1);
209 }
210 call->args[index] = value;
211 }
212
213 Value *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";
José Fonseca885f2652010-11-20 11:22:25 +0000247 assert(0);
José Fonseca19828972010-11-29 20:34:32 +0000248 return NULL;
249 }
250 }
José Fonseca7e329022010-11-19 17:05:18 +0000251
José Fonseca19828972010-11-29 20:34:32 +0000252 Value *parse_sint() {
253 return new SInt(-(signed long long)read_uint());
254 }
José Fonsecad35973c2010-11-26 14:14:45 +0000255
José Fonseca19828972010-11-29 20:34:32 +0000256 Value *parse_uint() {
257 return new UInt(read_uint());
258 }
José Fonsecad35973c2010-11-26 14:14:45 +0000259
José Fonseca19828972010-11-29 20:34:32 +0000260 Value *parse_float() {
261 float value;
262 gzread(file, &value, sizeof value);
263 return new Float(value);
264 }
José Fonseca7e329022010-11-19 17:05:18 +0000265
José Fonseca19828972010-11-29 20:34:32 +0000266 Value *parse_double() {
267 double value;
268 gzread(file, &value, sizeof value);
269 return new Float(value);
270 }
José Fonseca7eef8ce2010-11-26 15:46:36 +0000271
José Fonseca19828972010-11-29 20:34:32 +0000272 Value *parse_string() {
273 return new String(read_string());
274 }
José Fonseca7eef8ce2010-11-26 15:46:36 +0000275
José Fonseca19828972010-11-29 20:34:32 +0000276 Value *parse_enum() {
277 size_t id = read_uint();
José Fonsecaae9668b2011-02-09 15:15:08 +0000278 Enum::Signature *sig = lookup(enums, id);
José Fonseca19828972010-11-29 20:34:32 +0000279 if (!sig) {
280 std::string name = read_string();
281 Value *value = parse_value();
José Fonsecaae9668b2011-02-09 15:15:08 +0000282 sig = new Enum::Signature(name, value);
José Fonseca19828972010-11-29 20:34:32 +0000283 enums[id] = sig;
284 }
285 assert(sig);
José Fonsecaae9668b2011-02-09 15:15:08 +0000286 return new Enum(sig);
José Fonseca19828972010-11-29 20:34:32 +0000287 }
José Fonseca7eef8ce2010-11-26 15:46:36 +0000288
José Fonseca19828972010-11-29 20:34:32 +0000289 Value *parse_bitmask() {
290 size_t id = read_uint();
291 Bitmask::Signature *sig = lookup(bitmasks, id);
292 if (!sig) {
293 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;
301 }
302 assert(sig);
José Fonseca7eef8ce2010-11-26 15:46:36 +0000303
José Fonseca19828972010-11-29 20:34:32 +0000304 unsigned long long value = read_uint();
José Fonsecafa922142010-11-25 09:36:04 +0000305
José Fonseca19828972010-11-29 20:34:32 +0000306 return new Bitmask(sig, value);
307 }
308
309 Value *parse_array(void) {
310 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
318 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
327 Value *parse_struct() {
328 size_t id = read_uint();
329
330 Struct::Signature *sig = lookup(structs, id);
331 if (!sig) {
332 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;
339 }
340 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;
349 }
350
351 Value *parse_opaque() {
352 unsigned long long addr;
353 addr = read_uint();
José Fonsecac929e992010-12-04 10:47:15 +0000354 return new Pointer(addr);
José Fonseca19828972010-11-29 20:34:32 +0000355 }
356
357 std::string read_string(void) {
358 size_t len = read_uint();
359 if (!len) {
360 return std::string();
361 }
362 char * buf = new char[len];
363 gzread(file, buf, len);
364 std::string value(buf, len);
365 delete [] buf;
José Fonsecaf4b071e2010-11-25 15:48:46 +0000366#if TRACE_VERBOSE
José Fonseca19828972010-11-29 20:34:32 +0000367 std::cerr << "\tSTRING \"" << value << "\"\n";
José Fonseca5cb3e172010-11-22 16:59:34 +0000368#endif
José Fonseca19828972010-11-29 20:34:32 +0000369 return value;
370 }
José Fonseca7e329022010-11-19 17:05:18 +0000371
José Fonseca19828972010-11-29 20:34:32 +0000372 unsigned long long read_uint(void) {
373 unsigned long long value = 0;
374 int c;
375 unsigned shift = 0;
376 do {
377 c = gzgetc(file);
378 if (c == -1) {
379 break;
380 }
381 value |= (unsigned long long)(c & 0x7f) << shift;
382 shift += 7;
383 } while(c & 0x80);
José Fonsecaf4b071e2010-11-25 15:48:46 +0000384#if TRACE_VERBOSE
José Fonseca19828972010-11-29 20:34:32 +0000385 std::cerr << "\tUINT " << value << "\n";
José Fonseca5cb3e172010-11-22 16:59:34 +0000386#endif
José Fonseca19828972010-11-29 20:34:32 +0000387 return value;
388 }
José Fonseca5cb3e172010-11-22 16:59:34 +0000389
José Fonseca19828972010-11-29 20:34:32 +0000390 int read_byte(void) {
391 int c = gzgetc(file);
José Fonsecaf4b071e2010-11-25 15:48:46 +0000392#if TRACE_VERBOSE
José Fonseca19828972010-11-29 20:34:32 +0000393 if (c < 0)
394 std::cerr << "\tEOF" << "\n";
395 else
396 std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
José Fonseca5cb3e172010-11-22 16:59:34 +0000397#endif
José Fonseca19828972010-11-29 20:34:32 +0000398 return c;
399 }
José Fonseca7e329022010-11-19 17:05:18 +0000400};
401
402
José Fonseca99221832011-03-22 22:15:46 +0000403unsigned long long Trace::Parser::version = 0;
404
405
José Fonseca7e329022010-11-19 17:05:18 +0000406} /* namespace Trace */
407
408#endif /* _TRACE_PARSER_HPP_ */