X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=trace_parser.cpp;h=2ef77b6d79daf856636414358fd2c232afd414c6;hb=f682e19bee94eb69a5cfc8b2db17d7f1ebb10c2b;hp=5e253c96bf18a2b29e66ecc80c2cd8e385d1be48;hpb=fcfbf176900a32e0926450a2f1e5faa7f272823b;p=apitrace diff --git a/trace_parser.cpp b/trace_parser.cpp index 5e253c9..2ef77b6 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" @@ -43,6 +43,7 @@ Parser::Parser() { file = NULL; next_call_no = 0; version = 0; + m_supportsSeeking = false; } @@ -52,10 +53,17 @@ 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; } + m_supportsSeeking = file->supportsOffsets(); version = read_uint(); if (version > TRACE_VERSION) { @@ -78,14 +86,16 @@ 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; } @@ -138,20 +148,44 @@ void Parser::parse_enter(void) { size_t id = read_uint(); FunctionSig *sig = lookup(functions, id); - if (!sig) { - sig = new FunctionSig; - sig->name = 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(); + + + File::Offset offset; + bool callWithSig = false; + if (m_supportsSeeking) { + offset = file->currentOffset(); + callWithSig = callWithSignature(offset); + } + + if (!sig || callWithSig) { + if (!sig) { + sig = new FunctionSig; + sig->id = id; + sig->name = 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; + functions[id] = sig; + if (m_supportsSeeking) { + m_callSigOffsets.insert(offset); + } + } else { + /* skip over the signature */ + skip_string(); /* name */ + int num_args = read_uint(); + for (unsigned i = 0; i < num_args; ++i) { + skip_string(); /*arg_name*/ + } } - sig->arg_names = arg_names; - functions[id] = sig; } assert(sig); Call *call = new Call(sig); + + call->no = next_call_no++; if (parse_call_details(call)) { @@ -198,7 +232,8 @@ bool Parser::parse_call_details(Call *call) { call->ret = parse_value(); 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; @@ -292,14 +327,14 @@ Value *Parser::parse_uint() { Value *Parser::parse_float() { float value; - gzread(file, &value, sizeof value); + file->read(&value, sizeof value); return new Float(value); } Value *Parser::parse_double() { double value; - gzread(file, &value, sizeof value); + file->read(&value, sizeof value); return new Float(value); } @@ -312,14 +347,30 @@ Value *Parser::parse_string() { Value *Parser::parse_enum() { size_t id = read_uint(); EnumSig *sig = lookup(enums, id); - if (!sig) { - sig = new EnumSig; - sig->id = id; - sig->name = read_string(); - Value *value = parse_value(); - sig->value = value->toSInt(); - delete value; - enums[id] = sig; + File::Offset offset; + bool enumWithSig = false; + + if (m_supportsSeeking) { + offset = file->currentOffset(); + enumWithSig = enumWithSignature(offset); + } + + if (!sig || enumWithSig) { + if (!sig) { + sig = new EnumSig; + sig->id = id; + sig->name = read_string(); + Value *value = parse_value(); + sig->value = value->toSInt(); + delete value; + enums[id] = sig; + if (m_supportsSeeking) { + m_enumSigOffsets.insert(offset); + } + } else { + skip_string(); /*name*/ + scan_value(); + } } assert(sig); return new Enum(sig); @@ -329,20 +380,39 @@ Value *Parser::parse_enum() { Value *Parser::parse_bitmask() { size_t id = read_uint(); BitmaskSig *sig = lookup(bitmasks, id); - if (!sig) { - sig = new BitmaskSig; - 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"; + File::Offset offset; + bool bitmaskWithSig = false; + + if (m_supportsSeeking) { + offset = file->currentOffset(); + bitmaskWithSig = bitmaskWithSignature(offset); + } + + if (!sig || bitmaskWithSig) { + if (!sig) { + sig = new BitmaskSig; + 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; + bitmasks[id] = sig; + if (m_supportsSeeking) { + m_bitmaskSigOffsets.insert(offset); + } + } else { + int num_flags = read_uint(); + for (int i = 0; i < num_flags; ++i) { + skip_string(); /*name */ + skip_uint(); /* value */ } } - sig->flags = flags; - bitmasks[id] = sig; } assert(sig); @@ -366,7 +436,7 @@ 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; } @@ -376,17 +446,36 @@ Value *Parser::parse_struct() { size_t id = read_uint(); StructSig *sig = lookup(structs, id); - if (!sig) { - sig = new StructSig; - 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(); + File::Offset offset; + bool structWithSig = false; + + if (m_supportsSeeking) { + offset = file->currentOffset(); + structWithSig = structWithSignature(offset); + } + + if (!sig || structWithSig) { + if (!sig) { + sig = new StructSig; + 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; + structs[id] = sig; + if (m_supportsSeeking) { + m_structSigOffsets.insert(offset); + } + } else { + skip_string(); /* name */ + unsigned num_members = read_uint(); + for (unsigned i = 0; i < num_members; ++i) { + skip_string(); /* member_name */ + } } - sig->member_names = member_names; - structs[id] = sig; } assert(sig); @@ -411,7 +500,7 @@ const char * Parser::read_string(void) { size_t len = read_uint(); char * value = new char[len + 1]; if (len) { - gzread(file, value, (unsigned)len); + file->read(value, (unsigned)len); } value[len] = 0; #if TRACE_VERBOSE @@ -426,7 +515,7 @@ unsigned long long Parser::read_uint(void) { int c; unsigned shift = 0; do { - c = gzgetc(file); + c = file->getc(); if (c == -1) { break; } @@ -441,7 +530,7 @@ unsigned long long Parser::read_uint(void) { inline int Parser::read_byte(void) { - int c = gzgetc(file); + int c = file->getc(); #if TRACE_VERBOSE if (c < 0) std::cerr << "\tEOF" << "\n"; @@ -452,4 +541,315 @@ inline int Parser::read_byte(void) { } +inline bool Parser::callWithSignature(const File::Offset &offset) const +{ + return m_callSigOffsets.find(offset) != m_callSigOffsets.end(); +} + +inline bool Parser::structWithSignature(const File::Offset &offset) const +{ + return m_structSigOffsets.find(offset) != m_structSigOffsets.end(); +} + +inline bool Parser::enumWithSignature(const File::Offset &offset) const +{ + return m_enumSigOffsets.find(offset) != m_enumSigOffsets.end(); +} + +inline bool Parser::bitmaskWithSignature(const File::Offset &offset) const +{ + return m_bitmaskSigOffsets.find(offset) != m_bitmaskSigOffsets.end(); +} + +Call * Parser::scan_call() +{ + assert(m_supportsSeeking); + do { + int c = read_byte(); + switch(c) { + case Trace::EVENT_ENTER: + scan_enter(); + break; + case Trace::EVENT_LEAVE: + return scan_leave(); + default: + std::cerr << "error: unknown event " << c << "\n"; + exit(1); + case -1: + for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) { + std::cerr << "warning: incomplete call " << (*it)->name() << "\n"; + std::cerr << **it << "\n"; + } + return NULL; + } + } while (true); +} + +void Parser::scan_enter(void) { + size_t id = read_uint(); + + FunctionSig *sig = lookup(functions, id); + const File::Offset offset = file->currentOffset(); + if (!sig) { + sig = new FunctionSig; + sig->id = id; + sig->name = 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; + functions[id] = sig; + m_callSigOffsets.insert(offset); + } + assert(sig); + + Call *call = new Call(sig); + call->no = next_call_no++; + + if (scan_call_details(call)) { + calls.push_back(call); + } else { + delete call; + } +} + +Call *Parser::scan_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; + } + } + if (!call) { + return NULL; + } + + if (scan_call_details(call)) { + return call; + } else { + delete call; + return NULL; + } +} + +bool Parser::scan_call_details(Call *call) { + do { + int c = read_byte(); + switch(c) { + case Trace::CALL_END: + return true; + case Trace::CALL_ARG: + scan_arg(call); + break; + case Trace::CALL_RET: + scan_value(); + break; + default: + std::cerr << "error: ("<name()<< ") unknown call detail " + << c << "\n"; + exit(1); + case -1: + return false; + } + } while(true); +} + +void Parser::scan_arg(Call *call) { + skip_uint(); /* index */ + scan_value(); /* 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; + } +} + + +void Parser::scan_sint() { + skip_uint(); +} + + +void Parser::scan_uint() { + skip_uint(); +} + + +void Parser::scan_float() { + file->skip(sizeof(float)); +} + + +void Parser::scan_double() { + file->skip(sizeof(double)); +} + + +void Parser::scan_string() { + skip_string(); +} + + +void Parser::scan_enum() { + size_t id = read_uint(); + EnumSig *sig = lookup(enums, id); + const File::Offset offset = file->currentOffset(); + if (!sig) { + sig = new EnumSig; + sig->id = id; + sig->name = read_string(); + Value *value = parse_value(); + sig->value = value->toSInt(); + delete value; + enums[id] = sig; + m_enumSigOffsets.insert(offset); + } + assert(sig); +} + + +void Parser::scan_bitmask() { + size_t id = read_uint(); + BitmaskSig *sig = lookup(bitmasks, id); + const File::Offset offset = file->currentOffset(); + if (!sig) { + sig = new BitmaskSig; + 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; + bitmasks[id] = sig; + m_bitmaskSigOffsets.insert(offset); + } + assert(sig); + + skip_uint(); /* value */ +} + + +void Parser::scan_array(void) { + size_t len = read_uint(); + for (size_t i = 0; i < len; ++i) { + scan_value(); + } +} + + +void Parser::scan_blob(void) { + size_t size = read_uint(); + if (size) { + file->skip((unsigned)size); + } +} + + +void Parser::scan_struct() { + size_t id = read_uint(); + + StructSig *sig = lookup(structs, id); + const File::Offset offset = file->currentOffset(); + if (!sig) { + sig = new StructSig; + 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; + structs[id] = sig; + m_structSigOffsets.insert(offset); + } + assert(sig); + + for (size_t i = 0; i < sig->num_members; ++i) { + scan_value(); + } +} + + +void Parser::scan_opaque() { + skip_uint(); +} + + +void Parser::skip_string(void) { + size_t len = read_uint(); + file->skip((unsigned)len); +} + + +void Parser::skip_uint(void) { + int c; + do { + c = file->getc(); + if (c == -1) { + break; + } + } while(c & 0x80); +} + + +inline void Parser::skip_byte(void) { + file->skip(1); +} + + } /* namespace Trace */