X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=trace_parser.cpp;h=d7b20d2c450faaab61cc986c6c046b72df5a4caa;hb=1a9f7af32205d900c88fef0b544546eb0d7c84ee;hp=67f31b7c3489c24ee7d5b61210dbbd307241d5a1;hpb=3632cc842b5f7cc8813b0436d78b441d5f226dc5;p=apitrace diff --git a/trace_parser.cpp b/trace_parser.cpp index 67f31b7..d7b20d2 100644 --- a/trace_parser.cpp +++ b/trace_parser.cpp @@ -28,8 +28,8 @@ #include #include -#include - +#include "trace_file.hpp" +#include "trace_snappyfile.hpp" #include "trace_parser.hpp" @@ -52,8 +52,14 @@ Parser::~Parser() { bool Parser::open(const char *filename) { - file = gzopen(filename, "rb"); - if (!file) { + assert(!file); + if (File::isZLibCompressed(filename)) { + file = new ZLibFile; + } else { + file = new SnappyFile; + } + + if (!file->open(filename, File::Read)) { return false; } @@ -78,34 +84,97 @@ deleteAll(Iter begin, Iter end) template inline void -deleteAll(const Container &c) +deleteAll(Container &c) { deleteAll(c.begin(), c.end()); + c.clear(); } void Parser::close(void) { if (file) { - gzclose(file); + file->close(); + delete file; file = NULL; } deleteAll(calls); - deleteAll(functions); - deleteAll(structs); - deleteAll(enums); - deleteAll(bitmasks); + + // Delete all signature data. Signatures are mere structures which don't + // own their own memory, so we need to destroy all data we created here. + + for (FunctionMap::iterator it = functions.begin(); it != functions.end(); ++it) { + FunctionSigState *sig = *it; + if (sig) { + delete [] sig->name; + for (unsigned arg = 0; arg < sig->num_args; ++arg) { + delete [] sig->arg_names[arg]; + } + delete [] sig->arg_names; + delete sig; + } + } + functions.clear(); + + for (StructMap::iterator it = structs.begin(); it != structs.end(); ++it) { + StructSigState *sig = *it; + if (sig) { + delete [] sig->name; + for (unsigned member = 0; member < sig->num_members; ++member) { + delete [] sig->member_names[member]; + } + delete [] sig->member_names; + delete sig; + } + } + structs.clear(); + + for (EnumMap::iterator it = enums.begin(); it != enums.end(); ++it) { + EnumSigState *sig = *it; + if (sig) { + delete [] sig->name; + delete sig; + } + } + enums.clear(); + + for (BitmaskMap::iterator it = bitmasks.begin(); it != bitmasks.end(); ++it) { + BitmaskSigState *sig = *it; + if (sig) { + for (unsigned flag = 0; flag < sig->num_flags; ++flag) { + delete [] sig->flags[flag].name; + } + delete [] sig->flags; + delete sig; + } + } + bitmasks.clear(); } -Call *Parser::parse_call(void) { +void Parser::getBookmark(ParseBookmark &bookmark) { + bookmark.offset = file->currentOffset(); + bookmark.next_call_no = next_call_no; +} + + +void Parser::setBookmark(const ParseBookmark &bookmark) { + file->setCurrentOffset(bookmark.offset); + next_call_no = bookmark.next_call_no; + + // Simply ignore all pending calls + deleteAll(calls); +} + + +Call *Parser::parse_call(Mode mode) { do { int c = read_byte(); switch(c) { case Trace::EVENT_ENTER: - parse_enter(); + parse_enter(mode); break; case Trace::EVENT_LEAVE: - return parse_leave(); + return parse_leave(mode); default: std::cerr << "error: unknown event " << c << "\n"; exit(1); @@ -134,25 +203,139 @@ T *lookup(std::vector &map, size_t index) { } -void Parser::parse_enter(void) { +FunctionSig *Parser::parse_function_sig(void) { size_t id = read_uint(); - Call::Signature *sig = lookup(functions, id); + FunctionSigState *sig = lookup(functions, id); + if (!sig) { - sig = new Call::Signature; + /* parse the signature */ + sig = new FunctionSigState; + sig->id = id; sig->name = read_string(); - unsigned size = read_uint(); - for (unsigned i = 0; i < size; ++i) { - sig->arg_names.push_back(read_string()); + sig->num_args = read_uint(); + const char **arg_names = new const char *[sig->num_args]; + for (unsigned i = 0; i < sig->num_args; ++i) { + arg_names[i] = read_string(); } + sig->arg_names = arg_names; + sig->offset = file->currentOffset(); functions[id] = sig; + } else if (file->currentOffset() < sig->offset) { + /* skip over the signature */ + skip_string(); /* name */ + int num_args = read_uint(); + for (unsigned i = 0; i < num_args; ++i) { + skip_string(); /*arg_name*/ + } + } + + assert(sig); + return sig; +} + + +StructSig *Parser::parse_struct_sig() { + size_t id = read_uint(); + + StructSigState *sig = lookup(structs, id); + + if (!sig) { + /* parse the signature */ + sig = new StructSigState; + sig->id = id; + sig->name = read_string(); + sig->num_members = read_uint(); + const char **member_names = new const char *[sig->num_members]; + for (unsigned i = 0; i < sig->num_members; ++i) { + member_names[i] = read_string(); + } + sig->member_names = member_names; + sig->offset = file->currentOffset(); + structs[id] = sig; + } else if (file->currentOffset() < sig->offset) { + /* skip over the signature */ + skip_string(); /* name */ + unsigned num_members = read_uint(); + for (unsigned i = 0; i < num_members; ++i) { + skip_string(); /* member_name */ + } } + assert(sig); + return sig; +} + + +EnumSig *Parser::parse_enum_sig() { + size_t id = read_uint(); + + EnumSigState *sig = lookup(enums, id); + + if (!sig) { + /* parse the signature */ + sig = new EnumSigState; + sig->id = id; + sig->name = read_string(); + Value *value = parse_value(); + sig->value = value->toSInt(); + delete value; + sig->offset = file->currentOffset(); + enums[id] = sig; + } else if (file->currentOffset() < sig->offset) { + /* skip over the signature */ + skip_string(); /*name*/ + scan_value(); + } + + assert(sig); + return sig; +} + + +BitmaskSig *Parser::parse_bitmask_sig() { + size_t id = read_uint(); + + BitmaskSigState *sig = lookup(bitmasks, id); + + if (!sig) { + /* parse the signature */ + sig = new BitmaskSigState; + sig->id = id; + sig->num_flags = read_uint(); + BitmaskFlag *flags = new BitmaskFlag[sig->num_flags]; + for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) { + it->name = read_string(); + it->value = read_uint(); + if (it->value == 0 && it != flags) { + std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n"; + } + } + sig->flags = flags; + sig->offset = file->currentOffset(); + bitmasks[id] = sig; + } else if (file->currentOffset() < sig->offset) { + /* skip over the signature */ + int num_flags = read_uint(); + for (int i = 0; i < num_flags; ++i) { + skip_string(); /*name */ + skip_uint(); /* value */ + } + } + + assert(sig); + return sig; +} + + +void Parser::parse_enter(Mode mode) { + FunctionSig *sig = parse_function_sig(); Call *call = new Call(sig); + call->no = next_call_no++; - if (parse_call_details(call)) { + if (parse_call_details(call, mode)) { calls.push_back(call); } else { delete call; @@ -160,7 +343,7 @@ void Parser::parse_enter(void) { } -Call *Parser::parse_leave(void) { +Call *Parser::parse_leave(Mode mode) { unsigned call_no = read_uint(); Call *call = NULL; for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) { @@ -174,7 +357,7 @@ Call *Parser::parse_leave(void) { return NULL; } - if (parse_call_details(call)) { + if (parse_call_details(call, mode)) { return call; } else { delete call; @@ -183,20 +366,21 @@ Call *Parser::parse_leave(void) { } -bool Parser::parse_call_details(Call *call) { +bool Parser::parse_call_details(Call *call, Mode mode) { do { int c = read_byte(); switch(c) { case Trace::CALL_END: return true; case Trace::CALL_ARG: - parse_arg(call); + parse_arg(call, mode); break; case Trace::CALL_RET: - call->ret = parse_value(); + call->ret = parse_value(mode); break; default: - std::cerr << "error: unknown call detail " << c << "\n"; + std::cerr << "error: ("<name()<< ") unknown call detail " + << c << "\n"; exit(1); case -1: return false; @@ -205,53 +389,126 @@ bool Parser::parse_call_details(Call *call) { } -void Parser::parse_arg(Call *call) { +void Parser::parse_arg(Call *call, Mode mode) { unsigned index = read_uint(); - Value *value = parse_value(); - if (index >= call->args.size()) { - call->args.resize(index + 1); + Value *value = parse_value(mode); + if (value) { + if (index >= call->args.size()) { + call->args.resize(index + 1); + } + call->args[index] = value; } - call->args[index] = value; } Value *Parser::parse_value(void) { int c; + Value *value; c = read_byte(); switch(c) { case Trace::TYPE_NULL: - return new Null; + value = new Null; + break; case Trace::TYPE_FALSE: - return new Bool(false); + value = new Bool(false); + break; case Trace::TYPE_TRUE: - return new Bool(true); + value = new Bool(true); + break; case Trace::TYPE_SINT: - return parse_sint(); + value = parse_sint(); + break; case Trace::TYPE_UINT: - return parse_uint(); + value = parse_uint(); + break; case Trace::TYPE_FLOAT: - return parse_float(); + value = parse_float(); + break; case Trace::TYPE_DOUBLE: - return parse_double(); + value = parse_double(); + break; case Trace::TYPE_STRING: - return parse_string(); + value = parse_string(); + break; case Trace::TYPE_ENUM: - return parse_enum(); + value = parse_enum(); + break; case Trace::TYPE_BITMASK: - return parse_bitmask(); + value = parse_bitmask(); + break; case Trace::TYPE_ARRAY: - return parse_array(); + value = parse_array(); + break; case Trace::TYPE_STRUCT: - return parse_struct(); + value = parse_struct(); + break; case Trace::TYPE_BLOB: - return parse_blob(); + value = parse_blob(); + break; case Trace::TYPE_OPAQUE: - return parse_opaque(); + value = parse_opaque(); + break; default: std::cerr << "error: unknown type " << c << "\n"; exit(1); case -1: - return NULL; + value = NULL; + break; + } +#if TRACE_VERBOSE + if (value) { + std::cerr << "\tVALUE " << value << "\n"; + } +#endif + return value; +} + + +void Parser::scan_value(void) { + int c = read_byte(); + switch(c) { + case Trace::TYPE_NULL: + case Trace::TYPE_FALSE: + case Trace::TYPE_TRUE: + break; + case Trace::TYPE_SINT: + scan_sint(); + break; + case Trace::TYPE_UINT: + scan_uint(); + break; + case Trace::TYPE_FLOAT: + scan_float(); + break; + case Trace::TYPE_DOUBLE: + scan_double(); + break; + case Trace::TYPE_STRING: + scan_string(); + break; + case Trace::TYPE_ENUM: + scan_enum(); + break; + case Trace::TYPE_BITMASK: + scan_bitmask(); + break; + case Trace::TYPE_ARRAY: + scan_array(); + break; + case Trace::TYPE_STRUCT: + scan_struct(); + break; + case Trace::TYPE_BLOB: + scan_blob(); + break; + case Trace::TYPE_OPAQUE: + scan_opaque(); + break; + default: + std::cerr << "error: unknown type " << c << "\n"; + exit(1); + case -1: + break; } } @@ -261,60 +518,68 @@ Value *Parser::parse_sint() { } +void Parser::scan_sint() { + skip_uint(); +} + + Value *Parser::parse_uint() { return new UInt(read_uint()); } +void Parser::scan_uint() { + skip_uint(); +} + + Value *Parser::parse_float() { float value; - gzread(file, &value, sizeof value); + file->read(&value, sizeof value); return new Float(value); } +void Parser::scan_float() { + file->skip(sizeof(float)); +} + + Value *Parser::parse_double() { double value; - gzread(file, &value, sizeof value); + file->read(&value, sizeof value); return new Float(value); } +void Parser::scan_double() { + file->skip(sizeof(double)); +} + + Value *Parser::parse_string() { return new String(read_string()); } +void Parser::scan_string() { + skip_string(); +} + + Value *Parser::parse_enum() { - size_t id = read_uint(); - Enum::Signature *sig = lookup(enums, id); - if (!sig) { - std::string name = read_string(); - Value *value = parse_value(); - sig = new Enum::Signature(name, value); - enums[id] = sig; - } - assert(sig); + EnumSig *sig = parse_enum_sig(); return new Enum(sig); } +void Parser::scan_enum() { + parse_enum_sig(); +} + + Value *Parser::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(); - if (it->second == 0 && it != sig->begin()) { - std::cerr << "warning: bitmask " << it->first << " is zero but is not first flag\n"; - } - } - bitmasks[id] = sig; - } - assert(sig); + BitmaskSig *sig = parse_bitmask_sig(); unsigned long long value = read_uint(); @@ -322,6 +587,12 @@ Value *Parser::parse_bitmask() { } +void Parser::scan_bitmask() { + parse_bitmask_sig(); + skip_uint(); /* value */ +} + + Value *Parser::parse_array(void) { size_t len = read_uint(); Array *array = new Array(len); @@ -332,34 +603,37 @@ Value *Parser::parse_array(void) { } +void Parser::scan_array(void) { + size_t len = read_uint(); + for (size_t i = 0; i < len; ++i) { + scan_value(); + } +} + + Value *Parser::parse_blob(void) { size_t size = read_uint(); Blob *blob = new Blob(size); if (size) { - gzread(file, blob->buf, (unsigned)size); + file->read(blob->buf, (unsigned)size); } return blob; } -Value *Parser::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; +void Parser::scan_blob(void) { + size_t size = read_uint(); + if (size) { + file->skip(size); } - assert(sig); +} + +Value *Parser::parse_struct() { + StructSig *sig = parse_struct_sig(); Struct *value = new Struct(sig); - for (size_t i = 0; i < sig->member_names.size(); ++i) { + for (size_t i = 0; i < sig->num_members; ++i) { value->members[i] = parse_value(); } @@ -367,6 +641,14 @@ Value *Parser::parse_struct() { } +void Parser::scan_struct() { + StructSig *sig = parse_struct_sig(); + for (size_t i = 0; i < sig->num_members; ++i) { + scan_value(); + } +} + + Value *Parser::parse_opaque() { unsigned long long addr; addr = read_uint(); @@ -374,15 +656,18 @@ Value *Parser::parse_opaque() { } -std::string Parser::read_string(void) { +void Parser::scan_opaque() { + skip_uint(); +} + + +const char * Parser::read_string(void) { size_t len = read_uint(); - if (!len) { - return std::string(); + char * value = new char[len + 1]; + if (len) { + file->read(value, (unsigned)len); } - char * buf = new char[len]; - gzread(file, buf, (unsigned)len); - std::string value(buf, len); - delete [] buf; + value[len] = 0; #if TRACE_VERBOSE std::cerr << "\tSTRING \"" << value << "\"\n"; #endif @@ -390,12 +675,18 @@ std::string Parser::read_string(void) { } +void Parser::skip_string(void) { + size_t len = read_uint(); + file->skip(len); +} + + unsigned long long Parser::read_uint(void) { unsigned long long value = 0; int c; unsigned shift = 0; do { - c = gzgetc(file); + c = file->getc(); if (c == -1) { break; } @@ -409,8 +700,19 @@ unsigned long long Parser::read_uint(void) { } +void Parser::skip_uint(void) { + int c; + do { + c = file->getc(); + if (c == -1) { + break; + } + } while(c & 0x80); +} + + inline int Parser::read_byte(void) { - int c = gzgetc(file); + int c = file->getc(); #if TRACE_VERBOSE if (c < 0) std::cerr << "\tEOF" << "\n"; @@ -421,4 +723,9 @@ inline int Parser::read_byte(void) { } +inline void Parser::skip_byte(void) { + file->skip(1); +} + + } /* namespace Trace */