X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=common%2Ftrace_parser.cpp;h=095af670e2159f79299fdba9bc4e642cbb4ac5e4;hb=677f59a10bf71b0bf1b73bfc9c1accbf719fafad;hp=1a1139d0f05a68a9253cfe900dd2a603caa4f652;hpb=d31700077ae75f450b12ad7d9276c08cbad57d1b;p=apitrace diff --git a/common/trace_parser.cpp b/common/trace_parser.cpp index 1a1139d..095af67 100644 --- a/common/trace_parser.cpp +++ b/common/trace_parser.cpp @@ -30,6 +30,7 @@ #include #include "trace_file.hpp" +#include "trace_dump.hpp" #include "trace_parser.hpp" @@ -43,6 +44,7 @@ Parser::Parser() { file = NULL; next_call_no = 0; version = 0; + api = API_UNKNOWN; glGetErrorSig = NULL; } @@ -65,6 +67,7 @@ bool Parser::open(const char *filename) { std::cerr << "error: unsupported trace format version " << version << "\n"; return false; } + api = API_UNKNOWN; return true; } @@ -128,7 +131,10 @@ void Parser::close(void) { for (EnumMap::iterator it = enums.begin(); it != enums.end(); ++it) { EnumSigState *sig = *it; if (sig) { - delete [] sig->name; + for (unsigned value = 0; value < sig->num_values; ++value) { + delete [] sig->values[value].name; + } + delete [] sig->values; delete sig; } } @@ -171,9 +177,15 @@ Call *Parser::parse_call(Mode mode) { int c = read_byte(); switch (c) { case trace::EVENT_ENTER: +#if TRACE_VERBOSE + std::cerr << "\tENTER\n"; +#endif parse_enter(mode); break; case trace::EVENT_LEAVE: +#if TRACE_VERBOSE + std::cerr << "\tLEAVE\n"; +#endif call = parse_leave(mode); adjust_call_flags(call); return call; @@ -229,6 +241,30 @@ Parser::parse_function_sig(void) { sig->offset = file->currentOffset(); functions[id] = sig; + /** + * Try to autodetect the API. + * + * XXX: Ideally we would allow to mix multiple APIs in a single trace, + * but as it stands today, retrace is done separately for each API. + */ + if (api == API_UNKNOWN) { + const char *n = sig->name; + if ((n[0] == 'g' && n[1] == 'l' && n[2] == 'X') || // glX* + (n[0] == 'w' && n[1] == 'g' && n[2] == 'l' && n[3] >= 'A' && n[3] <= 'Z') || // wgl[A-Z]* + (n[0] == 'C' && n[1] == 'G' && n[2] == 'L')) { // CGL* + api = trace::API_GL; + } else if (n[0] == 'e' && n[1] == 'g' && n[2] == 'l' && n[3] >= 'A' && n[3] <= 'Z') { // egl[A-Z]* + api = trace::API_EGL; + } else if ((n[0] == 'D' && + ((n[1] == 'i' && n[2] == 'r' && n[3] == 'e' && n[4] == 'c' && n[5] == 't') || // Direct* + (n[1] == '3' && n[2] == 'D'))) || // D3D* + (n[0] == 'C' && n[1] == 'r' && n[2] == 'e' && n[3] == 'a' && n[4] == 't' && n[5] == 'e')) { // Create* + api = trace::API_DX; + } else { + /* TODO */ + } + } + /** * Note down the signature of special functions for future reference. * @@ -286,7 +322,13 @@ StructSig *Parser::parse_struct_sig() { } -EnumSig *Parser::parse_enum_sig() { +/* + * Old enum signatures would cover a single name/value only: + * + * enum_sig = id name value + * | id + */ +EnumSig *Parser::parse_old_enum_sig() { size_t id = read_uint(); EnumSigState *sig = lookup(enums, id); @@ -295,10 +337,11 @@ EnumSig *Parser::parse_enum_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->num_values = 1; + EnumValue *values = new EnumValue[sig->num_values]; + values->name = read_string(); + values->value = read_sint(); + sig->values = values; sig->offset = file->currentOffset(); enums[id] = sig; } else if (file->currentOffset() < sig->offset) { @@ -312,6 +355,38 @@ EnumSig *Parser::parse_enum_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->num_values = read_uint(); + EnumValue *values = new EnumValue[sig->num_values]; + for (EnumValue *it = values; it != values + sig->num_values; ++it) { + it->name = read_string(); + it->value = read_sint(); + } + sig->values = values; + sig->offset = file->currentOffset(); + enums[id] = sig; + } else if (file->currentOffset() < sig->offset) { + /* skip over the signature */ + int num_values = read_uint(); + for (int i = 0; i < num_values; ++i) { + skip_string(); /*name */ + skip_sint(); /* value */ + } + } + + assert(sig); + return sig; +} + + BitmaskSig *Parser::parse_bitmask_sig() { size_t id = read_uint(); @@ -348,9 +423,17 @@ BitmaskSig *Parser::parse_bitmask_sig() { void Parser::parse_enter(Mode mode) { + unsigned thread_id; + + if (version >= 4) { + thread_id = read_uint(); + } else { + thread_id = 0; + } + FunctionSigFlags *sig = parse_function_sig(); - Call *call = new Call(sig, sig->flags); + Call *call = new Call(sig, sig->flags, thread_id); call->no = next_call_no++; @@ -390,11 +473,20 @@ bool Parser::parse_call_details(Call *call, Mode mode) { int c = read_byte(); switch (c) { case trace::CALL_END: +#if TRACE_VERBOSE + std::cerr << "\tCALL_END\n"; +#endif return true; case trace::CALL_ARG: +#if TRACE_VERBOSE + std::cerr << "\tCALL_ARG\n"; +#endif parse_arg(call, mode); break; case trace::CALL_RET: +#if TRACE_VERBOSE + std::cerr << "\tCALL_RET\n"; +#endif call->ret = parse_value(mode); break; default: @@ -430,7 +522,7 @@ void Parser::parse_arg(Call *call, Mode mode) { if (index >= call->args.size()) { call->args.resize(index + 1); } - call->args[index] = value; + call->args[index].value = value; } } @@ -482,6 +574,9 @@ Value *Parser::parse_value(void) { case trace::TYPE_OPAQUE: value = parse_opaque(); break; + case trace::TYPE_REPR: + value = parse_repr(); + break; default: std::cerr << "error: unknown type " << c << "\n"; exit(1); @@ -491,7 +586,9 @@ Value *Parser::parse_value(void) { } #if TRACE_VERBOSE if (value) { - std::cerr << "\tVALUE " << value << "\n"; + std::cerr << "\tVALUE "; + trace::dump(value, std::cerr); + std::cerr << "\n"; } #endif return value; @@ -538,6 +635,9 @@ void Parser::scan_value(void) { case trace::TYPE_OPAQUE: scan_opaque(); break; + case trace::TYPE_REPR: + scan_repr(); + break; default: std::cerr << "error: unknown type " << c << "\n"; exit(1); @@ -602,13 +702,27 @@ void Parser::scan_string() { Value *Parser::parse_enum() { - EnumSig *sig = parse_enum_sig(); - return new Enum(sig); + EnumSig *sig; + signed long long value; + if (version >= 3) { + sig = parse_enum_sig(); + value = read_sint(); + } else { + sig = parse_old_enum_sig(); + assert(sig->num_values == 1); + value = sig->values->value; + } + return new Enum(sig, value); } void Parser::scan_enum() { - parse_enum_sig(); + if (version >= 3) { + parse_enum_sig(); + skip_sint(); + } else { + parse_old_enum_sig(); + } } @@ -649,7 +763,7 @@ Value *Parser::parse_blob(void) { size_t size = read_uint(); Blob *blob = new Blob(size); if (size) { - file->read(blob->buf, (unsigned)size); + file->read(blob->buf, size); } return blob; } @@ -695,11 +809,24 @@ void Parser::scan_opaque() { } +Value *Parser::parse_repr() { + Value *humanValue = parse_value(); + Value *machineValue = parse_value(); + return new Repr(humanValue, machineValue); +} + + +void Parser::scan_repr() { + scan_value(); + scan_value(); +} + + const char * Parser::read_string(void) { size_t len = read_uint(); char * value = new char[len + 1]; if (len) { - file->read(value, (unsigned)len); + file->read(value, len); } value[len] = 0; #if TRACE_VERBOSE @@ -715,6 +842,33 @@ void Parser::skip_string(void) { } +/* + * For the time being, a signed int is encoded as any other value, but we here parse + * it without the extra baggage of the Value class. + */ +signed long long +Parser::read_sint(void) { + int c; + c = read_byte(); + switch (c) { + case trace::TYPE_SINT: + return -(signed long long)read_uint(); + case trace::TYPE_UINT: + return read_uint(); + default: + std::cerr << "error: unexpected type " << c << "\n"; + exit(1); + case -1: + return 0; + } +} + +void +Parser::skip_sint(void) { + skip_byte(); + skip_uint(); +} + unsigned long long Parser::read_uint(void) { unsigned long long value = 0; int c;