X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=common%2Ftrace_parser.cpp;h=a9cdd0fbc0586465be407522a0148146e05f283a;hb=refs%2Fheads%2Fglx-copy-sub-buffer;hp=dc9634f0d36f823b635d26c7efd7bc1a1082625f;hpb=ee659c84695e9f94b1f6a5f8be203dc0012ca685;p=apitrace diff --git a/common/trace_parser.cpp b/common/trace_parser.cpp index dc9634f..a9cdd0f 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; } @@ -63,8 +65,11 @@ bool Parser::open(const char *filename) { version = read_uint(); if (version > TRACE_VERSION) { std::cerr << "error: unsupported trace format version " << version << "\n"; + delete file; + file = NULL; return false; } + api = API_UNKNOWN; return true; } @@ -174,12 +179,21 @@ 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; + if (call) { + adjust_call_flags(call); + return call; + } + break; default: std::cerr << "error: unknown event " << c << "\n"; exit(1); @@ -229,9 +243,33 @@ Parser::parse_function_sig(void) { } sig->arg_names = arg_names; sig->flags = lookupCallFlags(sig->name); - sig->offset = file->currentOffset(); + sig->fileOffset = 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. * @@ -243,7 +281,7 @@ Parser::parse_function_sig(void) { glGetErrorSig = sig; } - } else if (file->currentOffset() < sig->offset) { + } else if (file->currentOffset() < sig->fileOffset) { /* skip over the signature */ skip_string(); /* name */ unsigned num_args = read_uint(); @@ -273,9 +311,9 @@ StructSig *Parser::parse_struct_sig() { member_names[i] = read_string(); } sig->member_names = member_names; - sig->offset = file->currentOffset(); + sig->fileOffset = file->currentOffset(); structs[id] = sig; - } else if (file->currentOffset() < sig->offset) { + } else if (file->currentOffset() < sig->fileOffset) { /* skip over the signature */ skip_string(); /* name */ unsigned num_members = read_uint(); @@ -309,9 +347,9 @@ EnumSig *Parser::parse_old_enum_sig() { values->name = read_string(); values->value = read_sint(); sig->values = values; - sig->offset = file->currentOffset(); + sig->fileOffset = file->currentOffset(); enums[id] = sig; - } else if (file->currentOffset() < sig->offset) { + } else if (file->currentOffset() < sig->fileOffset) { /* skip over the signature */ skip_string(); /*name*/ scan_value(); @@ -338,9 +376,9 @@ EnumSig *Parser::parse_enum_sig() { it->value = read_sint(); } sig->values = values; - sig->offset = file->currentOffset(); + sig->fileOffset = file->currentOffset(); enums[id] = sig; - } else if (file->currentOffset() < sig->offset) { + } else if (file->currentOffset() < sig->fileOffset) { /* skip over the signature */ int num_values = read_uint(); for (int i = 0; i < num_values; ++i) { @@ -373,9 +411,9 @@ BitmaskSig *Parser::parse_bitmask_sig() { } } sig->flags = flags; - sig->offset = file->currentOffset(); + sig->fileOffset = file->currentOffset(); bitmasks[id] = sig; - } else if (file->currentOffset() < sig->offset) { + } else if (file->currentOffset() < sig->fileOffset) { /* skip over the signature */ int num_flags = read_uint(); for (int i = 0; i < num_flags; ++i) { @@ -423,6 +461,14 @@ Call *Parser::parse_leave(Mode mode) { } } if (!call) { + /* This might happen on random access, when an asynchronous call is stranded + * between two frames. We won't return this call, but we still need to skip + * over its data. + */ + const FunctionSig sig = {0, NULL, 0, NULL}; + call = new Call(&sig, 0, 0); + parse_call_details(call, SCAN); + delete call; return NULL; } @@ -440,13 +486,28 @@ 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; + case trace::CALL_BACKTRACE: +#if TRACE_VERBOSE + std::cerr << "\tCALL_BACKTRACE\n"; +#endif + parse_call_backtrace(call, mode); + break; default: std::cerr << "error: ("<name()<< ") unknown call detail " << c << "\n"; @@ -457,6 +518,83 @@ bool Parser::parse_call_details(Call *call, Mode mode) { } while(true); } +bool Parser::parse_call_backtrace(Call *call, Mode mode) { + unsigned num_frames = read_uint(); + Backtrace* backtrace = new Backtrace(num_frames); + for (unsigned i = 0; i < num_frames; ++i) { + (*backtrace)[i] = parse_backtrace_frame(mode); + } + call->backtrace = backtrace; + return true; +} + +StackFrame * Parser::parse_backtrace_frame(Mode mode) { + size_t id = read_uint(); + + StackFrameState *frame = lookup(frames, id); + + if (!frame) { + frame = new StackFrameState; + int c = read_byte(); + while (c != trace::BACKTRACE_END && + c != -1) { + switch (c) { + case trace::BACKTRACE_MODULE: + frame->module = read_string(); + break; + case trace::BACKTRACE_FUNCTION: + frame->function = read_string(); + break; + case trace::BACKTRACE_FILENAME: + frame->filename = read_string(); + break; + case trace::BACKTRACE_LINENUMBER: + frame->linenumber = read_uint(); + break; + case trace::BACKTRACE_OFFSET: + frame->offset = read_uint(); + break; + default: + std::cerr << "error: unknown backtrace detail " + << c << "\n"; + exit(1); + } + c = read_byte(); + } + + frame->fileOffset = file->currentOffset(); + frames[id] = frame; + } else if (file->currentOffset() < frame->fileOffset) { + int c = read_byte(); + while (c != trace::BACKTRACE_END && + c != -1) { + switch (c) { + case trace::BACKTRACE_MODULE: + scan_string(); + break; + case trace::BACKTRACE_FUNCTION: + scan_string(); + break; + case trace::BACKTRACE_FILENAME: + scan_string(); + break; + case trace::BACKTRACE_LINENUMBER: + scan_uint(); + break; + case trace::BACKTRACE_OFFSET: + scan_uint(); + break; + default: + std::cerr << "error: unknown backtrace detail " + << c << "\n"; + exit(1); + } + c = read_byte(); + } + } + + return frame; +} /** * Make adjustments to this particular call flags. @@ -532,6 +670,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); @@ -541,7 +682,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; @@ -588,6 +731,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); @@ -713,7 +859,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; } @@ -759,11 +905,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 @@ -789,7 +948,7 @@ Parser::read_sint(void) { c = read_byte(); switch (c) { case trace::TYPE_SINT: - return -read_uint(); + return -(signed long long)read_uint(); case trace::TYPE_UINT: return read_uint(); default: