X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=trace_parser.hpp;h=b4017414da646926737a0489ea9f987bd68d0b60;hb=e0081492ba7be522cd5fda88c79fb951d890b232;hp=b77fc3ec68853709dc42cdcdacacee9919f79205;hpb=d35973cb47a75034dbbb64e9b0a91fcb4cc971d6;p=apitrace diff --git a/trace_parser.hpp b/trace_parser.hpp index b77fc3e..b401741 100644 --- a/trace_parser.hpp +++ b/trace_parser.hpp @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -48,314 +49,354 @@ namespace Trace { class Parser { protected: - gzFile file; + gzFile file; - typedef std::map namemap; - namemap names; + typedef std::list CallList; + CallList calls; - typedef std::map callmap; - callmap calls; + typedef std::vector FunctionMap; + FunctionMap functions; - typedef std::map BitmaskMap; - BitmaskMap bitmasks; + typedef std::vector StructMap; + StructMap structs; - unsigned next_call_no; + typedef std::vector EnumMap; + EnumMap enums; + + typedef std::vector BitmaskMap; + BitmaskMap bitmasks; + + unsigned next_call_no; public: - Parser() { - file = NULL; - next_call_no = 0; - } - - ~Parser() { - close(); - } - - bool open(const char *filename) { - unsigned long long version; - - file = gzopen(filename, "rb"); - if (!file) { - return false; - } - - version = read_uint(); - if (version != TRACE_VERSION) { - std::cerr << "error: unsupported format version" << version << "\n"; - return false; - } - - return true; - } - - void close(void) { - if (file) { - gzclose(file); - file = NULL; - } - } - - Call *parse_call(void) { - do { - 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: + Parser() { + file = NULL; + next_call_no = 0; + } + + ~Parser() { + close(); + } + + bool open(const char *filename) { + unsigned long long version; + + file = gzopen(filename, "rb"); + if (!file) { + return false; + } + + version = read_uint(); + if (version != TRACE_VERSION) { + std::cerr << "error: unsupported format version" << version << "\n"; + return false; + } + + return true; + } + + void close(void) { + if (file) { + gzclose(file); + file = NULL; + } + } + + Call *parse_call(void) { + do { + 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); + } + + /** + * Helper function to lookup an ID in a vector, resizing the vector if it doesn't fit. + */ + template + T *lookup(std::vector &map, size_t index) { + if (index >= map.size()) { + map.resize(index + 1); + return NULL; + } else { + return map[index]; + } + } + + void parse_enter(void) { + size_t id = read_uint(); + + Call::Signature *sig = lookup(functions, id); + if (!sig) { + 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; + } + assert(sig); + + Call *call = new Call(sig); + call->no = next_call_no++; + + parse_call_details(call); + + calls.push_back(call); + } + + Call *parse_leave(void) { + unsigned call_no = read_uint(); + + Call *call = NULL; + for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) { + if ((*it)->no == call_no) { + call = *it; + calls.erase(it); + break; + } + } + assert(call); + if (!call) { return NULL; - } - } while(true); - } - - void parse_enter(void) { - Call *call = new Call; - call->no = next_call_no++; - call->name = read_name(); - 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: - parse_arg(call); - break; - case Trace::CALL_RET: - call->ret = parse_value(); - break; - default: - std::cerr << "error: unknown call detail " << c << "\n"; + } + 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: + parse_arg(call); + break; + case Trace::CALL_RET: + call->ret = parse_value(); + break; + default: + std::cerr << "error: unknown call detail " << c << "\n"; + assert(0); + /* fallthrough */ + case -1: + return; + } + } while(true); + } + + void parse_arg(Call *call) { + unsigned index = read_uint(); + Value *value = parse_value(); + if (index >= call->args.size()) { + call->args.resize(index + 1); + } + call->args[index] = value; + } + + Value *parse_value(void) { + int c; + 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 new Bool(true); + case Trace::TYPE_SINT: + return parse_sint(); + case Trace::TYPE_UINT: + return parse_uint(); + case Trace::TYPE_FLOAT: + return parse_float(); + case Trace::TYPE_DOUBLE: + return parse_double(); + case Trace::TYPE_STRING: + return parse_string(); + 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_OPAQUE: + return parse_opaque(); + default: + std::cerr << "error: unknown type " << c << "\n"; assert(0); - /* fallthrough */ - case -1: - return; - } - } while(true); - } - - void parse_arg(Call *call) { - unsigned index = read_uint(); - std::string name = read_name(); - Value *value = parse_value(); - if (index >= call->args.size()) { - call->args.resize(index + 1); - } - call->args[index] = Arg(name, value); - } - - Value *parse_value(void) { - int c; - 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 new Bool(true); - case Trace::TYPE_SINT: - return parse_sint(); - case Trace::TYPE_UINT: - return parse_uint(); - case Trace::TYPE_FLOAT: - return parse_float(); - case Trace::TYPE_DOUBLE: - return parse_double(); - case Trace::TYPE_STRING: - return parse_string(); - case Trace::TYPE_CONST: - return parse_const(); - 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_OPAQUE: - return parse_opaque(); - default: - std::cerr << "error: unknown type " << c << "\n"; - assert(0); - return NULL; - } - } - - Value *parse_sint() { - return new SInt(-(signed long long)read_uint()); - } - - Value *parse_uint() { - return new UInt(read_uint()); - } - - Value *parse_float() { - float value; - gzread(file, &value, sizeof value); - return new Float(value); - } - - Value *parse_double() { - double value; - gzread(file, &value, sizeof value); - return new Float(value); - } - - Value *parse_string() { - return new String(read_string()); - } - - Value *parse_const() { - std::string name = read_name(); - Value *value = parse_value(); - return new Const(name, value); - } - - Value *parse_bitmask() { - 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) { - size_t len = read_uint(); - Array *array = new Array(len); - for (size_t i = 0; i < len; ++i) { - array->values[i] = parse_value(); - } - return array; - } - - Value *parse_blob(void) { - size_t size = read_uint(); - Blob *blob = new Blob(size); - if (size) { - gzread(file, blob->buf, size); - } - return blob; - } - - 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; - addr = read_uint(); - /* 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; + return NULL; + } + } + + Value *parse_sint() { + return new SInt(-(signed long long)read_uint()); + } + + Value *parse_uint() { + return new UInt(read_uint()); + } + + Value *parse_float() { + float value; + gzread(file, &value, sizeof value); + return new Float(value); + } + + Value *parse_double() { + double value; + gzread(file, &value, sizeof value); + return new Float(value); + } + + Value *parse_string() { + return new String(read_string()); + } + + Value *parse_enum() { + size_t id = read_uint(); + Enum *sig = lookup(enums, id); + if (!sig) { + std::string name = read_string(); + Value *value = parse_value(); + sig = new Enum(name, value); + enums[id] = sig; + } + assert(sig); + return sig; + } + + Value *parse_bitmask() { + size_t id = read_uint(); + Bitmask::Signature *sig = lookup(bitmasks, id); + if (!sig) { + 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; + } + assert(sig); + + unsigned long long value = read_uint(); + + return new Bitmask(sig, value); + } + + Value *parse_array(void) { + size_t len = read_uint(); + Array *array = new Array(len); + for (size_t i = 0; i < len; ++i) { + array->values[i] = parse_value(); + } + return array; + } + + Value *parse_blob(void) { + size_t size = read_uint(); + Blob *blob = new Blob(size); + if (size) { + gzread(file, blob->buf, size); + } + return blob; + } + + Value *parse_struct() { + size_t id = read_uint(); + + Struct::Signature *sig = lookup(structs, id); + if (!sig) { + sig = new Struct::Signature; + sig->name = read_string(); + unsigned size = read_uint(); + for (unsigned i = 0; i < size; ++i) { + sig->member_names.push_back(read_string()); + } + structs[id] = sig; + } + assert(sig); + + Struct *value = new Struct(sig); + + for (size_t i = 0; i < sig->member_names.size(); ++i) { + value->members[i] = parse_value(); + } + + return value; + } + + Value *parse_opaque() { + unsigned long long addr; + addr = read_uint(); + return new Pointer(addr); + } + + 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"; + std::cerr << "\tSTRING \"" << value << "\"\n"; #endif - return value; - } - - unsigned long long read_uint(void) { - unsigned long long value = 0; - int c; - unsigned shift = 0; - do { - c = gzgetc(file); - if (c == -1) { - break; - } - value |= (unsigned long long)(c & 0x7f) << shift; - shift += 7; - } while(c & 0x80); + return value; + } + + unsigned long long read_uint(void) { + unsigned long long value = 0; + int c; + unsigned shift = 0; + do { + c = gzgetc(file); + if (c == -1) { + break; + } + value |= (unsigned long long)(c & 0x7f) << shift; + shift += 7; + } while(c & 0x80); #if TRACE_VERBOSE - std::cerr << "\tUINT " << value << "\n"; + std::cerr << "\tUINT " << value << "\n"; #endif - return value; - } + return value; + } - int read_byte(void) { - int c = gzgetc(file); + 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"; + if (c < 0) + std::cerr << "\tEOF" << "\n"; + else + std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n"; #endif - return c; - } + return c; + } };