#include <assert.h>
#include <stdlib.h>
+#include <string.h>
#include "trace_file.hpp"
-#include "trace_snappyfile.hpp"
#include "trace_parser.hpp"
#define TRACE_VERBOSE 0
-namespace Trace {
+namespace trace {
Parser::Parser() {
file = NULL;
next_call_no = 0;
version = 0;
+
+ glGetErrorSig = NULL;
}
bool Parser::open(const char *filename) {
assert(!file);
- if (File::isZLibCompressed(filename)) {
- file = new ZLibFile;
- } else {
- file = new SnappyFile;
- }
-
- if (!file->open(filename, File::Read)) {
+ file = File::createForRead(filename);
+ if (!file) {
return false;
}
Call *Parser::parse_call(Mode mode) {
do {
+ Call *call;
int c = read_byte();
- switch(c) {
- case Trace::EVENT_ENTER:
+ switch (c) {
+ case trace::EVENT_ENTER:
parse_enter(mode);
break;
- case Trace::EVENT_LEAVE:
- return parse_leave(mode);
+ case trace::EVENT_LEAVE:
+ call = parse_leave(mode);
+ adjust_call_flags(call);
+ return call;
default:
std::cerr << "error: unknown event " << c << "\n";
exit(1);
case -1:
if (!calls.empty()) {
- Call *call = calls.front();
- std::cerr << call->no << ": warning: incomplete call " << call->name() << "\n";
+ call = calls.front();
+ call->flags |= CALL_FLAG_INCOMPLETE;
calls.pop_front();
+ adjust_call_flags(call);
return call;
}
return NULL;
}
-FunctionSig *Parser::parse_function_sig(void) {
+Parser::FunctionSigFlags *
+Parser::parse_function_sig(void) {
size_t id = read_uint();
FunctionSigState *sig = lookup(functions, id);
arg_names[i] = read_string();
}
sig->arg_names = arg_names;
+ sig->flags = lookupCallFlags(sig->name);
sig->offset = file->currentOffset();
functions[id] = sig;
+
+ /**
+ * Note down the signature of special functions for future reference.
+ *
+ * NOTE: If the number of comparisons increases we should move this to a
+ * separate function and use bisection.
+ */
+ if (sig->num_args == 0 &&
+ strcmp(sig->name, "glGetError") == 0) {
+ glGetErrorSig = sig;
+ }
+
} else if (file->currentOffset() < sig->offset) {
/* skip over the signature */
skip_string(); /* name */
- int num_args = read_uint();
+ unsigned num_args = read_uint();
for (unsigned i = 0; i < num_args; ++i) {
skip_string(); /*arg_name*/
}
void Parser::parse_enter(Mode mode) {
- FunctionSig *sig = parse_function_sig();
+ FunctionSigFlags *sig = parse_function_sig();
- Call *call = new Call(sig);
+ Call *call = new Call(sig, sig->flags);
call->no = next_call_no++;
bool Parser::parse_call_details(Call *call, Mode mode) {
do {
int c = read_byte();
- switch(c) {
- case Trace::CALL_END:
+ switch (c) {
+ case trace::CALL_END:
return true;
- case Trace::CALL_ARG:
+ case trace::CALL_ARG:
parse_arg(call, mode);
break;
- case Trace::CALL_RET:
+ case trace::CALL_RET:
call->ret = parse_value(mode);
break;
default:
}
+/**
+ * Make adjustments to this particular call flags.
+ *
+ * NOTE: This is called per-call so no string comparisons should be done here.
+ * All name comparisons should be done when the signature is parsed instead.
+ */
+void Parser::adjust_call_flags(Call *call) {
+ // Mark glGetError() = GL_NO_ERROR as verbose
+ if (call->sig == glGetErrorSig &&
+ call->ret &&
+ call->ret->toSInt() == 0) {
+ call->flags |= CALL_FLAG_VERBOSE;
+ }
+}
+
void Parser::parse_arg(Call *call, Mode mode) {
unsigned index = read_uint();
Value *value = parse_value(mode);
int c;
Value *value;
c = read_byte();
- switch(c) {
- case Trace::TYPE_NULL:
+ switch (c) {
+ case trace::TYPE_NULL:
value = new Null;
break;
- case Trace::TYPE_FALSE:
+ case trace::TYPE_FALSE:
value = new Bool(false);
break;
- case Trace::TYPE_TRUE:
+ case trace::TYPE_TRUE:
value = new Bool(true);
break;
- case Trace::TYPE_SINT:
+ case trace::TYPE_SINT:
value = parse_sint();
break;
- case Trace::TYPE_UINT:
+ case trace::TYPE_UINT:
value = parse_uint();
break;
- case Trace::TYPE_FLOAT:
+ case trace::TYPE_FLOAT:
value = parse_float();
break;
- case Trace::TYPE_DOUBLE:
+ case trace::TYPE_DOUBLE:
value = parse_double();
break;
- case Trace::TYPE_STRING:
+ case trace::TYPE_STRING:
value = parse_string();
break;
- case Trace::TYPE_ENUM:
+ case trace::TYPE_ENUM:
value = parse_enum();
break;
- case Trace::TYPE_BITMASK:
+ case trace::TYPE_BITMASK:
value = parse_bitmask();
break;
- case Trace::TYPE_ARRAY:
+ case trace::TYPE_ARRAY:
value = parse_array();
break;
- case Trace::TYPE_STRUCT:
+ case trace::TYPE_STRUCT:
value = parse_struct();
break;
- case Trace::TYPE_BLOB:
+ case trace::TYPE_BLOB:
value = parse_blob();
break;
- case Trace::TYPE_OPAQUE:
+ case trace::TYPE_OPAQUE:
value = parse_opaque();
break;
default:
void Parser::scan_value(void) {
int c = read_byte();
- switch(c) {
- case Trace::TYPE_NULL:
- case Trace::TYPE_FALSE:
- case Trace::TYPE_TRUE:
+ switch (c) {
+ case trace::TYPE_NULL:
+ case trace::TYPE_FALSE:
+ case trace::TYPE_TRUE:
break;
- case Trace::TYPE_SINT:
+ case trace::TYPE_SINT:
scan_sint();
break;
- case Trace::TYPE_UINT:
+ case trace::TYPE_UINT:
scan_uint();
break;
- case Trace::TYPE_FLOAT:
+ case trace::TYPE_FLOAT:
scan_float();
break;
- case Trace::TYPE_DOUBLE:
+ case trace::TYPE_DOUBLE:
scan_double();
break;
- case Trace::TYPE_STRING:
+ case trace::TYPE_STRING:
scan_string();
break;
- case Trace::TYPE_ENUM:
+ case trace::TYPE_ENUM:
scan_enum();
break;
- case Trace::TYPE_BITMASK:
+ case trace::TYPE_BITMASK:
scan_bitmask();
break;
- case Trace::TYPE_ARRAY:
+ case trace::TYPE_ARRAY:
scan_array();
break;
- case Trace::TYPE_STRUCT:
+ case trace::TYPE_STRUCT:
scan_struct();
break;
- case Trace::TYPE_BLOB:
+ case trace::TYPE_BLOB:
scan_blob();
break;
- case Trace::TYPE_OPAQUE:
+ case trace::TYPE_OPAQUE:
scan_opaque();
break;
default:
Value *Parser::parse_double() {
double value;
file->read(&value, sizeof value);
- return new Float(value);
+ return new Double(value);
}
}
-} /* namespace Trace */
+} /* namespace trace */