/*
* Trace binary format.
*
+ * This file defines the trace binary stream, which is then compressed by
+ * snappy or gzip.
+ */
+
+#ifndef _TRACE_FORMAT_HPP_
+#define _TRACE_FORMAT_HPP_
+
+namespace trace {
+
+/*
+ * Trace file version number.
+ *
+ * We keep backwards compatability reading old traces, i.e., it should always be
+ * possible to parse and retrace old trace files.
+ *
+ * So the trace version number refers not only to changes in the binary format
+ * representation, but also semantic changes in the way certain functions
+ * should be retraced.
+ *
+ * Writing/editing old traces will not be supported however. An older version
+ * of apitrace should be used in such circunstances.
+ *
+ * Changelog:
+ *
+ * - version 0:
+ * - initial implementation
+ *
+ * - version 1:
+ * - support for GL user arrays -- a blob is provided whenever an user memory
+ * is referred (whereas before calls that operate wit user memory instead of
+ * VBOs should be ignore)
+ *
+ * - version 2:
+ * - malloc/free memory calls -- allow to pass user memory as malloc memory
+ * as opposed to blobs
+ * - glFlushMappedBufferRange will emit a memcpy only for the flushed range
+ * (whereas previously it would emit a memcpy for the whole mapped range)
+ *
+ * - version 3:
+ * - enums signatures are recorded for the a whole set of values (not as individual values)
+ */
+#define TRACE_VERSION 3
+
+
+/*
* Grammar:
*
* trace = event* EOF
* call_sig = id name arg_name*
* | id
*
- * enum_sig = id name value
+ * enum_sig = id count (name value)+
* | id
*
* bitmask_sig = id count (name value)+
*
*/
-#ifndef _TRACE_FORMAT_HPP_
-#define _TRACE_FORMAT_HPP_
-
-namespace trace {
-
-/*
- * Trace file version number.
- *
- * We keep backwards compatability reading old traces, i.e., it should always be
- * possible to parse and retrace old trace files.
- *
- * So the trace version number refers not only to changes in the binary format
- * representation, but also semantic changes in the way certain functions
- * should be retraced.
- *
- * Writing/editing old traces will not be supported however. An older version
- * of apitrace should be used in such circunstances.
- *
- * Changelog:
- *
- * - version 0:
- * - initial implementation
- *
- * - version 1:
- * - support for GL user arrays -- a blob is provided whenever an user memory
- * is referred (whereas before calls that operate wit user memory instead of
- * VBOs should be ignore)
- *
- * - version 2:
- * - malloc/free memory calls -- allow to pass user memory as malloc memory
- * as opposed to blobs
- * - glFlushMappedBufferRange will emit a memcpy only for the flushed range
- * (whereas previously it would emit a memcpy for the whole mapped range)
- */
-#define TRACE_VERSION 2
enum Event {
EVENT_ENTER = 0,
bool Float ::toBool(void) const { return value != 0; }
bool Double ::toBool(void) const { return value != 0; }
bool String ::toBool(void) const { return true; }
-bool Enum ::toBool(void) const { return sig->value != 0; }
bool Struct ::toBool(void) const { return true; }
bool Array ::toBool(void) const { return true; }
bool Blob ::toBool(void) const { return true; }
signed long long UInt ::toSInt(void) const { assert(static_cast<signed long long>(value) >= 0); return static_cast<signed long long>(value); }
signed long long Float ::toSInt(void) const { return static_cast<signed long long>(value); }
signed long long Double ::toSInt(void) const { return static_cast<signed long long>(value); }
-signed long long Enum ::toSInt(void) const { return sig->value; }
// unsigned integer cast
unsigned long long UInt ::toUInt(void) const { return value; }
unsigned long long Float ::toUInt(void) const { return static_cast<unsigned long long>(value); }
unsigned long long Double ::toUInt(void) const { return static_cast<unsigned long long>(value); }
-unsigned long long Enum ::toUInt(void) const { assert(sig->value >= 0); return sig->value; }
// floating point cast
float UInt ::toFloat(void) const { return static_cast<float>(value); }
float Float ::toFloat(void) const { return value; }
float Double ::toFloat(void) const { return value; }
-float Enum ::toFloat(void) const { return static_cast<float>(sig->value); }
// floating point cast
double UInt ::toDouble(void) const { return static_cast<double>(value); }
double Float ::toDouble(void) const { return value; }
double Double ::toDouble(void) const { return value; }
-double Enum ::toDouble(void) const { return static_cast<double>(sig->value); }
// pointer cast
}
void visit(Enum *node) {
- os << literal << node->sig->name << normal;
+ const EnumSig *sig = node->sig;
+ for (const EnumValue *it = sig->values; it != sig->values + sig->num_values; ++it) {
+ if (it->value == node->value) {
+ os << literal << it->name << normal;
+ return;
+ }
+ }
+ os << literal << node->value << normal;
}
void visit(Bitmask *bitmask) {
};
-struct EnumSig {
- Id id;
+struct EnumValue {
const char *name;
signed long long value;
};
+struct EnumSig {
+ Id id;
+ unsigned num_values;
+ const EnumValue *values;
+};
+
+
struct BitmaskFlag {
const char *name;
unsigned long long value;
};
-class Enum : public Value
+class Enum : public SInt
{
public:
- Enum(const EnumSig *_sig) : sig(_sig) {}
+ Enum(const EnumSig *_sig, signed long long _value) : SInt(_value), sig(_sig) {}
- bool toBool(void) const;
- signed long long toSInt(void) const;
- unsigned long long toUInt(void) const;
- virtual float toFloat(void) const;
- virtual double toDouble(void) const;
void visit(Visitor &visitor);
const EnumSig *sig;
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;
}
}
}
-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);
/* 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) {
}
+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();
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();
+ }
}
}
+/*
+ * 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 -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;
FunctionSigFlags *parse_function_sig(void);
StructSig *parse_struct_sig();
+ EnumSig *parse_old_enum_sig();
EnumSig *parse_enum_sig();
BitmaskSig *parse_bitmask_sig();
const char * read_string(void);
void skip_string(void);
+ signed long long read_sint(void);
+ void skip_sint(void);
+
unsigned long long read_uint(void);
void skip_uint(void);
}
}
-void Writer::writeEnum(const EnumSig *sig) {
+void Writer::writeEnum(const EnumSig *sig, signed long long value) {
_writeByte(trace::TYPE_ENUM);
_writeUInt(sig->id);
if (!lookup(enums, sig->id)) {
- _writeString(sig->name);
- Writer::writeSInt(sig->value);
+ _writeUInt(sig->num_values);
+ for (unsigned i = 0; i < sig->num_values; ++i) {
+ _writeString(sig->values[i].name);
+ writeSInt(sig->values[i].value);
+ }
enums[sig->id] = true;
}
+ writeSInt(value);
}
void Writer::writeBitmask(const BitmaskSig *sig, unsigned long long value) {
void writeString(const char *str, size_t size);
void writeWString(const wchar_t *str);
void writeBlob(const void *data, size_t size);
- void writeEnum(const EnumSig *sig);
+ void writeEnum(const EnumSig *sig, signed long long value);
void writeBitmask(const BitmaskSig *sig, unsigned long long value);
void writeNull(void);
void writeOpaque(const void *ptr);
}
void visit(Enum *node) {
- writer.writeEnum(node->sig);
+ writer.writeEnum(node->sig, node->value);
}
void visit(Bitmask *node) {
sig = m_loader->enumSignature(e->sig->id);
}
if (!sig) {
- sig = new ApiTraceEnumSignature(
- QString::fromStdString(e->sig->name),
- QVariant(e->sig->value));
+ sig = new ApiTraceEnumSignature(e->sig);
if (m_loader) {
m_loader->addEnumSignature(e->sig->id, sig);
}
}
- m_variant = QVariant::fromValue(ApiEnum(sig));
+ m_variant = QVariant::fromValue(ApiEnum(sig, e->value));
}
void VariantVisitor::visit(trace::Bitmask *bitmask)
m_variant = QVariant::fromValue(ApiPointer(ptr->value));
}
+ApiTraceEnumSignature::ApiTraceEnumSignature(const trace::EnumSig *sig)
+{
+ for (const trace::EnumValue *it = sig->values;
+ it != sig->values + sig->num_values; ++it) {
+ QPair<QString, signed long long> pair;
+
+ pair.first = QString::fromStdString(it->name);
+ pair.second = it->value;
+
+ m_names.append(pair);
+ }
+}
+
+QString ApiTraceEnumSignature::name(signed long long value) const
+{
+ for (ValueList::const_iterator it = m_names.begin();
+ it != m_names.end(); ++it) {
+ if (value == it->second) {
+ return it->first;
+ }
+ }
+ return QString::fromLatin1("%1").arg(value);
+}
-ApiEnum::ApiEnum(ApiTraceEnumSignature *sig)
- : m_sig(sig)
+ApiEnum::ApiEnum(ApiTraceEnumSignature *sig, signed long long value)
+ : m_sig(sig), m_value(value)
{
}
QString ApiEnum::toString() const
{
if (m_sig) {
- return m_sig->name();
+ return m_sig->name(m_value);
}
Q_ASSERT(!"should never happen");
return QString();
QVariant ApiEnum::value() const
{
if (m_sig) {
- return m_sig->value();
+ return QVariant::fromValue(m_value);
}
Q_ASSERT(!"should never happen");
return QVariant();
QString ApiEnum::name() const
{
if (m_sig) {
- return m_sig->name();
+ return m_sig->name(m_value);
}
Q_ASSERT(!"should never happen");
return QString();
class ApiTraceEnumSignature
{
public:
- ApiTraceEnumSignature(const QString &name = QString(),
- const QVariant &val=QVariant())\
- : m_name(name),
- m_value(val)
- {}
+ ApiTraceEnumSignature(const trace::EnumSig *sig);
+
+ QString name(signed long long value) const;
- QVariant value() const { return m_value; }
- QString name() const { return m_name; }
private:
- QString m_name;
- QVariant m_value;
+ typedef QList<QPair<QString, signed long long> > ValueList;
+ ValueList m_names;
};
class ApiEnum
{
public:
- ApiEnum(ApiTraceEnumSignature *sig=0);
+ ApiEnum(ApiTraceEnumSignature *sig=0, signed long long value = 0);
QString toString() const;
QString name() const;
private:
ApiTraceEnumSignature *m_sig;
+ signed long long m_value;
};
Q_DECLARE_METATYPE(ApiEnum);
__enum_id = 0
def visit_enum(self, enum):
- print 'static void _write__%s(const %s value) {' % (enum.tag, enum.expr)
- n = len(enum.values)
- for i in range(n):
- value = enum.values[i]
- print ' static const trace::EnumSig sig%u = {%u, "%s", %s};' % (i, DumpDeclarator.__enum_id, value, value)
- DumpDeclarator.__enum_id += 1
- print ' const trace::EnumSig *sig;'
- print ' switch (value) {'
- for i in range(n):
- value = enum.values[i]
- print ' case %s:' % value
- print ' sig = &sig%u;' % i
- print ' break;'
- print ' default:'
- print ' trace::localWriter.writeSInt(value);'
- print ' return;'
- print ' }'
- print ' trace::localWriter.writeEnum(sig);'
- print '}'
+ print 'static const trace::EnumValue __enum%s_values[] = {' % (enum.tag)
+ for value in enum.values:
+ print ' {"%s", %s},' % (value, value)
+ print '};'
+ print
+ print 'static const trace::EnumSig __enum%s_sig = {' % (enum.tag)
+ print ' %u, %u, __enum%s_values' % (enum.id, len(enum.values), enum.tag)
+ print '};'
print
def visit_bitmask(self, bitmask):
print ' trace::localWriter.writeBlob(%s, %s);' % (instance, blob.size)
def visit_enum(self, enum, instance):
- print ' _write__%s(%s);' % (enum.tag, instance)
+ print ' trace::localWriter.writeEnum(&__enum%s_sig, %s);' % (enum.tag, instance)
def visit_bitmask(self, bitmask, instance):
print ' trace::localWriter.writeBitmask(&__bitmask%s_sig, %s);' % (bitmask.tag, instance)