blob: f8eb9b5a753a6126c10e651f968c9fb24b0b3d48 [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é Fonseca2250a0e2010-11-26 15:01:29 +000057 typedef std::map<size_t, Call::Signature *> FunctionMap;
58 FunctionMap functions;
59
José Fonseca7eef8ce2010-11-26 15:46:36 +000060 typedef std::map<size_t, Struct::Signature *> StructMap;
61 StructMap structs;
62
José Fonsecaf84c70e2010-11-26 15:26:14 +000063 typedef std::map<size_t, Enum *> EnumMap;
64 EnumMap enums;
65
José Fonsecad35973c2010-11-26 14:14:45 +000066 typedef std::map<size_t, Bitmask::Signature *> BitmaskMap;
67 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 }
126
127 void parse_enter(void) {
José Fonseca2250a0e2010-11-26 15:01:29 +0000128 size_t id = read_uint();
129
130 Call::Signature *sig;
131 FunctionMap::const_iterator it = functions.find(id);
132 if (it == functions.end()) {
133 sig = new Call::Signature;
134 sig->name = read_string();
135 unsigned size = read_uint();
136 for (unsigned i = 0; i < size; ++i) {
137 sig->arg_names.push_back(read_string());
138 }
139 functions[id] = sig;
140 } else {
141 sig = it->second;
142 }
143 assert(sig);
144
145 Call *call = new Call(sig);
José Fonseca34957132010-11-25 16:14:45 +0000146 call->no = next_call_no++;
José Fonseca2250a0e2010-11-26 15:01:29 +0000147
José Fonseca34957132010-11-25 16:14:45 +0000148 parse_call_details(call);
José Fonseca89851d02010-11-28 12:16:52 +0000149
150 calls.push_back(call);
José Fonseca34957132010-11-25 16:14:45 +0000151 }
152
153 Call *parse_leave(void) {
154 unsigned call_no = read_uint();
José Fonseca89851d02010-11-28 12:16:52 +0000155
156 Call *call = NULL;
157 for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
158 if ((*it)->no == call_no) {
159 call = *it;
160 calls.erase(it);
161 break;
162 }
163 }
José Fonseca34957132010-11-25 16:14:45 +0000164 assert(call);
165 if (!call) {
166 return NULL;
167 }
168 parse_call_details(call);
169 return call;
170 }
171
172 void parse_call_details(Call *call) {
José Fonseca7e329022010-11-19 17:05:18 +0000173 do {
José Fonseca6f51d3b2010-11-22 19:56:19 +0000174 int c = read_byte();
José Fonseca7e329022010-11-19 17:05:18 +0000175 switch(c) {
176 case Trace::CALL_END:
José Fonseca34957132010-11-25 16:14:45 +0000177 return;
José Fonseca7e329022010-11-19 17:05:18 +0000178 case Trace::CALL_ARG:
José Fonsecadce84c42010-11-24 16:19:49 +0000179 parse_arg(call);
José Fonseca7e329022010-11-19 17:05:18 +0000180 break;
181 case Trace::CALL_RET:
José Fonseca6f51d3b2010-11-22 19:56:19 +0000182 call->ret = parse_value();
José Fonseca7e329022010-11-19 17:05:18 +0000183 break;
184 default:
José Fonseca501f2862010-11-19 20:41:18 +0000185 std::cerr << "error: unknown call detail " << c << "\n";
José Fonseca885f2652010-11-20 11:22:25 +0000186 assert(0);
José Fonseca6f51d3b2010-11-22 19:56:19 +0000187 /* fallthrough */
188 case -1:
José Fonseca34957132010-11-25 16:14:45 +0000189 return;
José Fonseca7e329022010-11-19 17:05:18 +0000190 }
191 } while(true);
José Fonseca7e329022010-11-19 17:05:18 +0000192 }
193
José Fonsecadce84c42010-11-24 16:19:49 +0000194 void parse_arg(Call *call) {
195 unsigned index = read_uint();
José Fonseca7e329022010-11-19 17:05:18 +0000196 Value *value = parse_value();
José Fonsecadce84c42010-11-24 16:19:49 +0000197 if (index >= call->args.size()) {
198 call->args.resize(index + 1);
199 }
José Fonseca2250a0e2010-11-26 15:01:29 +0000200 call->args[index] = value;
José Fonseca7e329022010-11-19 17:05:18 +0000201 }
202
203 Value *parse_value(void) {
204 int c;
José Fonseca5cb3e172010-11-22 16:59:34 +0000205 c = read_byte();
José Fonseca7e329022010-11-19 17:05:18 +0000206 switch(c) {
José Fonsecaf6592d72010-11-21 12:44:41 +0000207 case Trace::TYPE_NULL:
208 return new Null;
José Fonsecab1887f92010-11-21 02:33:38 +0000209 case Trace::TYPE_FALSE:
210 return new Bool(false);
211 case Trace::TYPE_TRUE:
212 return new Bool(true);
José Fonseca7e329022010-11-19 17:05:18 +0000213 case Trace::TYPE_SINT:
214 return parse_sint();
215 case Trace::TYPE_UINT:
216 return parse_uint();
217 case Trace::TYPE_FLOAT:
218 return parse_float();
219 case Trace::TYPE_DOUBLE:
220 return parse_double();
221 case Trace::TYPE_STRING:
222 return parse_string();
José Fonsecaf84c70e2010-11-26 15:26:14 +0000223 case Trace::TYPE_ENUM:
224 return parse_enum();
José Fonseca7e329022010-11-19 17:05:18 +0000225 case Trace::TYPE_BITMASK:
226 return parse_bitmask();
227 case Trace::TYPE_ARRAY:
228 return parse_array();
José Fonseca5cb3e172010-11-22 16:59:34 +0000229 case Trace::TYPE_STRUCT:
230 return parse_struct();
José Fonseca885f2652010-11-20 11:22:25 +0000231 case Trace::TYPE_BLOB:
232 return parse_blob();
José Fonsecaf6592d72010-11-21 12:44:41 +0000233 case Trace::TYPE_OPAQUE:
234 return parse_opaque();
José Fonseca7e329022010-11-19 17:05:18 +0000235 default:
José Fonseca501f2862010-11-19 20:41:18 +0000236 std::cerr << "error: unknown type " << c << "\n";
José Fonseca7e329022010-11-19 17:05:18 +0000237 assert(0);
238 return NULL;
239 }
240 }
241
José Fonseca7e329022010-11-19 17:05:18 +0000242 Value *parse_sint() {
José Fonseca0633bdf2010-11-25 14:54:14 +0000243 return new SInt(-(signed long long)read_uint());
José Fonseca7e329022010-11-19 17:05:18 +0000244 }
245
246 Value *parse_uint() {
247 return new UInt(read_uint());
248 }
249
250 Value *parse_float() {
251 float value;
252 gzread(file, &value, sizeof value);
253 return new Float(value);
254 }
255
256 Value *parse_double() {
257 double value;
258 gzread(file, &value, sizeof value);
259 return new Float(value);
260 }
261
262 Value *parse_string() {
263 return new String(read_string());
264 }
265
José Fonsecaf84c70e2010-11-26 15:26:14 +0000266 Value *parse_enum() {
267 size_t id = read_uint();
268 Enum *sig;
269 EnumMap::const_iterator it = enums.find(id);
270 if (it == enums.end()) {
271 std::string name = read_string();
272 Value *value = parse_value();
273 sig = new Enum(name, value);
274 enums[id] = sig;
275 } else {
276 sig = it->second;
277 }
278 assert(sig);
279 return sig;
José Fonseca7e329022010-11-19 17:05:18 +0000280 }
281
282 Value *parse_bitmask() {
José Fonsecad35973c2010-11-26 14:14:45 +0000283 size_t id = read_uint();
284 Bitmask::Signature *sig;
285 BitmaskMap::const_iterator it = bitmasks.find(id);
286 if (it == bitmasks.end()) {
287 size_t size = read_uint();
288 sig = new Bitmask::Signature(size);
289 for (Bitmask::Signature::iterator it = sig->begin(); it != sig->end(); ++it) {
290 it->first = read_string();
291 it->second = read_uint();
292 assert(it->second);
293 }
294 bitmasks[id] = sig;
295 } else {
296 sig = it->second;
297 }
298 assert(sig);
299
300 unsigned long long value = read_uint();
301
302 return new Bitmask(sig, value);
José Fonseca7e329022010-11-19 17:05:18 +0000303 }
304
José Fonseca885f2652010-11-20 11:22:25 +0000305 Value *parse_array(void) {
José Fonseca7e329022010-11-19 17:05:18 +0000306 size_t len = read_uint();
307 Array *array = new Array(len);
308 for (size_t i = 0; i < len; ++i) {
309 array->values[i] = parse_value();
310 }
311 return array;
312 }
313
José Fonseca885f2652010-11-20 11:22:25 +0000314 Value *parse_blob(void) {
315 size_t size = read_uint();
316 Blob *blob = new Blob(size);
317 if (size) {
318 gzread(file, blob->buf, size);
319 }
320 return blob;
321 }
322
José Fonseca5cb3e172010-11-22 16:59:34 +0000323 Value *parse_struct() {
José Fonseca7eef8ce2010-11-26 15:46:36 +0000324 size_t id = read_uint();
325
326 Struct::Signature *sig;
327 StructMap::const_iterator it = structs.find(id);
328 if (it == structs.end()) {
329 sig = new Struct::Signature;
330 sig->name = read_string();
331 unsigned size = read_uint();
332 for (unsigned i = 0; i < size; ++i) {
333 sig->member_names.push_back(read_string());
334 }
335 structs[id] = sig;
336 } else {
337 sig = it->second;
José Fonseca5cb3e172010-11-22 16:59:34 +0000338 }
José Fonseca7eef8ce2010-11-26 15:46:36 +0000339 assert(sig);
340
341 Struct *value = new Struct(sig);
342
343 for (size_t i = 0; i < sig->member_names.size(); ++i) {
344 value->members[i] = parse_value();
345 }
346
347 return value;
José Fonseca5cb3e172010-11-22 16:59:34 +0000348 }
349
José Fonsecaf6592d72010-11-21 12:44:41 +0000350 Value *parse_opaque() {
351 unsigned long long addr;
352 addr = read_uint();
353 /* XXX */
354 return new UInt(addr);
355 }
José Fonsecafa922142010-11-25 09:36:04 +0000356
José Fonseca7e329022010-11-19 17:05:18 +0000357 std::string read_string(void) {
358 size_t len = read_uint();
José Fonseca5cb3e172010-11-22 16:59:34 +0000359 if (!len) {
360 return std::string();
361 }
José Fonseca7e329022010-11-19 17:05:18 +0000362 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
367 std::cerr << "\tSTRING \"" << value << "\"\n";
José Fonseca5cb3e172010-11-22 16:59:34 +0000368#endif
José Fonseca7e329022010-11-19 17:05:18 +0000369 return value;
370 }
371
372 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
385 std::cerr << "\tUINT " << value << "\n";
José Fonseca5cb3e172010-11-22 16:59:34 +0000386#endif
José Fonseca7e329022010-11-19 17:05:18 +0000387 return value;
388 }
José Fonseca5cb3e172010-11-22 16:59:34 +0000389
390 int read_byte(void) {
391 int c = gzgetc(file);
José Fonsecaf4b071e2010-11-25 15:48:46 +0000392#if TRACE_VERBOSE
José Fonseca5cb3e172010-11-22 16:59:34 +0000393 if (c < 0)
José Fonsecaf4b071e2010-11-25 15:48:46 +0000394 std::cerr << "\tEOF" << "\n";
José Fonseca5cb3e172010-11-22 16:59:34 +0000395 else
José Fonsecaf4b071e2010-11-25 15:48:46 +0000396 std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
José Fonseca5cb3e172010-11-22 16:59:34 +0000397#endif
398 return c;
399 }
José Fonseca7e329022010-11-19 17:05:18 +0000400};
401
402
403} /* namespace Trace */
404
405#endif /* _TRACE_PARSER_HPP_ */