#include <cassert>
#include <iostream>
+#include <map>
+#include <string>
#include <zlib.h>
#include "trace_model.hpp"
+#define TRACE_VERBOSE 0
+
+
namespace Trace {
{
protected:
gzFile file;
+
+ typedef std::map<size_t, std::string> namemap;
+ namemap names;
+
+ typedef std::map<unsigned, Call *> callmap;
+ callmap calls;
+
+ typedef std::map<size_t, Call::Signature *> FunctionMap;
+ FunctionMap functions;
+
+ typedef std::map<size_t, Enum *> EnumMap;
+ EnumMap enums;
+
+ typedef std::map<size_t, Bitmask::Signature *> BitmaskMap;
+ BitmaskMap bitmasks;
+
+ unsigned next_call_no;
+
public:
Parser() {
file = NULL;
+ next_call_no = 0;
}
- bool parse(const char *filename) {
+ ~Parser() {
+ close();
+ }
+
+ bool open(const char *filename) {
unsigned long long version;
file = gzopen(filename, "rb");
return false;
}
- while (!gzeof(file)) {
- parse_call();
- }
-
return true;
}
- void parse_call(void) {
- Call call;
- call.name = read_string();
- int c;
+ void close(void) {
+ if (file) {
+ gzclose(file);
+ file = NULL;
+ }
+ }
+
+ Call *parse_call(void) {
do {
- c = gzgetc(file);
- if (c == Trace::CALL_END || c == -1) {
+ int c = read_byte();
+ switch(c) {
+ case Trace::EVENT_ENTER:
+ parse_enter();
break;
+ case Trace::EVENT_LEAVE:
+ return parse_leave();
+ case Trace::EVENT_MESSAGE:
+ std::cerr << "message: " << read_string() << "\n";
+ break;
+ default:
+ std::cerr << "error: unknown call detail " << c << "\n";
+ assert(0);
+ /* fallthrough */
+ case -1:
+ return NULL;
}
+ } while(true);
+ }
+
+ void parse_enter(void) {
+ size_t id = read_uint();
+
+ Call::Signature *sig;
+ FunctionMap::const_iterator it = functions.find(id);
+ if (it == functions.end()) {
+ sig = new Call::Signature;
+ sig->name = read_string();
+ unsigned size = read_uint();
+ for (unsigned i = 0; i < size; ++i) {
+ sig->arg_names.push_back(read_string());
+ }
+ functions[id] = sig;
+ } else {
+ sig = it->second;
+ }
+ assert(sig);
+
+ Call *call = new Call(sig);
+ call->no = next_call_no++;
+
+ parse_call_details(call);
+ calls[call->no] = call;
+ }
+
+ Call *parse_leave(void) {
+ unsigned call_no = read_uint();
+ Call *call = calls[call_no];
+ assert(call);
+ if (!call) {
+ return NULL;
+ }
+ parse_call_details(call);
+ return call;
+ }
+
+ void parse_call_details(Call *call) {
+ do {
+ int c = read_byte();
switch(c) {
case Trace::CALL_END:
return;
case Trace::CALL_ARG:
- call.args.push_back(parse_arg());
+ parse_arg(call);
break;
case Trace::CALL_RET:
- call.ret = parse_value();
+ call->ret = parse_value();
break;
default:
std::cerr << "error: unknown call detail " << c << "\n";
assert(0);
- break;
+ /* fallthrough */
+ case -1:
+ return;
}
} while(true);
- handle_call(call);
}
- virtual void handle_call(Call &call) {
- std::cout << call;
- }
-
- Arg parse_arg(void) {
- std::string name = read_string();
+ void parse_arg(Call *call) {
+ unsigned index = read_uint();
Value *value = parse_value();
- return Arg(name, value);
+ if (index >= call->args.size()) {
+ call->args.resize(index + 1);
+ }
+ call->args[index] = value;
}
Value *parse_value(void) {
int c;
- c = gzgetc(file);
+ c = read_byte();
switch(c) {
+ case Trace::TYPE_NULL:
+ return new Null;
case Trace::TYPE_FALSE:
return new Bool(false);
case Trace::TYPE_TRUE:
return parse_double();
case Trace::TYPE_STRING:
return parse_string();
- case Trace::TYPE_CONST:
- return parse_const();
+ case Trace::TYPE_ENUM:
+ return parse_enum();
case Trace::TYPE_BITMASK:
return parse_bitmask();
case Trace::TYPE_ARRAY:
return parse_array();
+ case Trace::TYPE_STRUCT:
+ return parse_struct();
case Trace::TYPE_BLOB:
return parse_blob();
- case Trace::TYPE_POINTER:
- return parse_pointer();
- case Trace::TYPE_NULL:
- return new Null;
+ case Trace::TYPE_OPAQUE:
+ return parse_opaque();
default:
std::cerr << "error: unknown type " << c << "\n";
assert(0);
}
}
- Value *parse_bool() {
- int c;
- c = gzgetc(file);
- return new Bool(c);
- }
-
Value *parse_sint() {
- return new SInt(-read_uint());
+ return new SInt(-(signed long long)read_uint());
}
Value *parse_uint() {
return new String(read_string());
}
- Value *parse_const() {
- std::string name = read_string();
- Value *value = parse_value();
- return new Const(name, value);
+ Value *parse_enum() {
+ size_t id = read_uint();
+ Enum *sig;
+ EnumMap::const_iterator it = enums.find(id);
+ if (it == enums.end()) {
+ std::string name = read_string();
+ Value *value = parse_value();
+ sig = new Enum(name, value);
+ enums[id] = sig;
+ } else {
+ sig = it->second;
+ }
+ assert(sig);
+ return sig;
}
Value *parse_bitmask() {
- unsigned long long value = 0;
- int c;
- do {
- c = gzgetc(file);
- switch(c) {
- case Trace::TYPE_SINT:
- value |= -read_uint();
- break;
- case Trace::TYPE_UINT:
- value |= read_uint();
- break;
- case Trace::TYPE_CONST:
- read_string();
- break;
- case Trace::TYPE_NULL:
- goto done;
- default:
- std::cerr << "error: uexpected type " << c << "\n";
- assert(0);
- return NULL;
- }
- } while(true);
-done:
- return new UInt(value);
+ size_t id = read_uint();
+ Bitmask::Signature *sig;
+ BitmaskMap::const_iterator it = bitmasks.find(id);
+ if (it == bitmasks.end()) {
+ size_t size = read_uint();
+ sig = new Bitmask::Signature(size);
+ for (Bitmask::Signature::iterator it = sig->begin(); it != sig->end(); ++it) {
+ it->first = read_string();
+ it->second = read_uint();
+ assert(it->second);
+ }
+ bitmasks[id] = sig;
+ } else {
+ sig = it->second;
+ }
+ assert(sig);
+
+ unsigned long long value = read_uint();
+
+ return new Bitmask(sig, value);
}
Value *parse_array(void) {
return blob;
}
- Value *parse_pointer() {
+ Value *parse_struct() {
+ size_t length = read_uint();
+ /* XXX */
+ for (size_t i = 0; i < length; ++i) {
+ std::string name = read_name();
+ Value *value = parse_value();
+ std::cout << " " << name << " = " << value << "\n";
+ }
+ return NULL;
+ }
+
+ Value *parse_opaque() {
unsigned long long addr;
- Value *value;
addr = read_uint();
- value = parse_value();
- if (!value)
- value = new UInt(addr);
- return value;
+ /* XXX */
+ return new UInt(addr);
+ }
+
+ std::string read_name(void) {
+ std::string name;
+ size_t id = read_uint();
+ if (id >= names.size()) {
+ assert(id == names.size());
+ name = read_string();
+ names[id] = name;
+ return name;
+ } else {
+ name = names[id];
+ }
+#if TRACE_VERBOSE
+ std::cerr << "\tNAME " << id << " " << name << "\n";
+#endif
+ return name;
}
std::string read_string(void) {
size_t len = read_uint();
+ if (!len) {
+ return std::string();
+ }
char * buf = new char[len];
gzread(file, buf, len);
std::string value(buf, len);
delete [] buf;
+#if TRACE_VERBOSE
+ std::cerr << "\tSTRING \"" << value << "\"\n";
+#endif
return value;
}
value |= (unsigned long long)(c & 0x7f) << shift;
shift += 7;
} while(c & 0x80);
+#if TRACE_VERBOSE
+ std::cerr << "\tUINT " << value << "\n";
+#endif
return value;
}
+
+ int read_byte(void) {
+ int c = gzgetc(file);
+#if TRACE_VERBOSE
+ if (c < 0)
+ std::cerr << "\tEOF" << "\n";
+ else
+ std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
+#endif
+ return c;
+ }
};