X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=trace_parser.cpp;h=abed4f51f37cab0543e0183b3fd97655ec9043a2;hb=e0df952b67f3ae38aeb0fd7e32942f8fa53ac49f;hp=104485a5e31201a060a7a717f9925aa3704654a6;hpb=3e6fa1d5f82d6072d81d6c25d1a868521bc5890c;p=apitrace diff --git a/trace_parser.cpp b/trace_parser.cpp index 104485a..abed4f5 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,14 +52,20 @@ 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; } version = read_uint(); if (version > TRACE_VERSION) { - std::cerr << "error: unsupported format version" << version << "\n"; + std::cerr << "error: unsupported trace format version " << version << "\n"; return false; } @@ -78,14 +84,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; } @@ -106,13 +114,14 @@ Call *Parser::parse_call(void) { break; case Trace::EVENT_LEAVE: return parse_leave(); - case Trace::EVENT_MESSAGE: - std::cerr << "message: " << read_string() << "\n"; - break; 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); @@ -136,20 +145,42 @@ T *lookup(std::vector &map, size_t index) { void Parser::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()); + FunctionSig *sig = lookup(functions, id); + const File::Offset offset = file->currentOffset(); + bool 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; + m_callSigOffsets.insert(offset); + } else { + /* skip over the signature */ + read_string(); /* name */ + int num_args = read_uint(); + for (unsigned i = 0; i < num_args; ++i) { + read_string(); /*arg_name*/ + } } - functions[id] = sig; } assert(sig); Call *call = new Call(sig); - call->no = next_call_no++; + + if (hasCallBeenParsed(offset)) { + call->no = callNumForOffset(offset); + } else { + call->no = next_call_no++; + m_callNumOffsets.insert( + std::pair(offset, call->no)); + } if (parse_call_details(call)) { calls.push_back(call); @@ -195,7 +226,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; @@ -216,42 +248,64 @@ void Parser::parse_arg(Call *call) { 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; } @@ -267,14 +321,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); } @@ -286,12 +340,24 @@ Value *Parser::parse_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; + EnumSig *sig = lookup(enums, id); + const File::Offset offset = file->currentOffset(); + bool 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; + m_enumSigOffsets.insert(offset); + } else { + read_string(); /*name*/ + Value *value = parse_value(); + delete value; + } } assert(sig); return new Enum(sig); @@ -300,18 +366,32 @@ Value *Parser::parse_enum() { 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"; + BitmaskSig *sig = lookup(bitmasks, id); + const File::Offset offset = file->currentOffset(); + bool 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; + m_bitmaskSigOffsets.insert(offset); + } else { + int num_flags = read_uint(); + for (int i = 0; i < num_flags; ++i) { + read_string(); /*name */ + read_uint(); /* value */ } } - bitmasks[id] = sig; } assert(sig); @@ -335,7 +415,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; } @@ -344,21 +424,35 @@ Value *Parser::parse_blob(void) { 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()); + StructSig *sig = lookup(structs, id); + const File::Offset offset = file->currentOffset(); + bool 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; + m_structSigOffsets.insert(offset); + } else { + read_string(); /* name */ + unsigned num_members = read_uint(); + for (unsigned i = 0; i < num_members; ++i) { + read_string(); /* member_name */ + } } - structs[id] = sig; } assert(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(); } @@ -373,15 +467,13 @@ Value *Parser::parse_opaque() { } -std::string Parser::read_string(void) { +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 @@ -394,7 +486,7 @@ unsigned long long Parser::read_uint(void) { int c; unsigned shift = 0; do { - c = gzgetc(file); + c = file->getc(); if (c == -1) { break; } @@ -409,7 +501,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"; @@ -420,4 +512,36 @@ 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(); +} + +bool Parser::hasCallBeenParsed(const File::Offset &offset) const +{ + return m_callNumOffsets.find(offset) != m_callNumOffsets.end(); +} + +unsigned Parser::callNumForOffset(const File::Offset &offset) const +{ + CallNumOffsets::const_iterator itr = m_callNumOffsets.find(offset); + assert(itr != m_callNumOffsets.end()); + return itr->second; +} + } /* namespace Trace */