diff --git a/src/corelib/global/qtrace_p.h b/src/corelib/global/qtrace_p.h index 49810737499..f548afd91c1 100644 --- a/src/corelib/global/qtrace_p.h +++ b/src/corelib/global/qtrace_p.h @@ -88,6 +88,37 @@ * class QEvent; * QT_END_NAMESPACE * } + * + * Metadata + * + * Metadata is used to add textual information for different types such + * as enums and flags. How this data is handled depends on the used backend. + * For ETW, the values are converted to text, for CTF and LTTNG they are used to add + * CTF enumerations, which are converted to text after tracing. + * + * Enumererations are specified using ENUM: + * + * ENUM { + * Enum0 = 0, + * Enum1 = 1, + * Enum2, + * RANGE(RangeEnum, 3 ... 10), + * } Name; + * + * Name must match to one of the enumerations used in the tracepoints. Range of values + * can be provided using RANGE(name, first ... last). All values must be unique. + * + * Flags are specified using FLAGS: + * + * FLAGS { + * Default = 0, + * Flag0 = 1, + * Flag1 = 2, + * Flag2 = 4, + * } Name; + * + * Name must match to one of the flags used in the tracepoints. Each value must be + * power of two and unique. */ #include @@ -174,11 +205,25 @@ QT_BEGIN_NAMESPACE * "QT_BEGIN_NAMESPACE" \ * "class QEvent;" \ * "QT_END_NAMESPACE") + * + * - Q_TRACE_METADATA(provider, metadata) + * Provides metadata for the tracepoint provider. + * + * Q_TRACE_METADATA(qtgui, + * "ENUM {" \ + * "Format_Invalid," \ + * "Format_Mono," \ + * "Format_MonoLSB," \ + * "Format_Indexed8," \ + * ... + * "} QImage::Format;" \ + * ); */ #define Q_TRACE_INSTRUMENT(provider) #define Q_TRACE_PARAM_REPLACE(in, out) #define Q_TRACE_POINT(provider, tracepoint, ...) #define Q_TRACE_PREFIX(provider, prefix) +#define Q_TRACE_METADATA(provider, metadata) QT_END_NAMESPACE diff --git a/src/tools/tracegen/etw.cpp b/src/tools/tracegen/etw.cpp index 755470af153..c0e13ffb757 100644 --- a/src/tools/tracegen/etw.cpp +++ b/src/tools/tracegen/etw.cpp @@ -31,7 +31,7 @@ static void writeEtwMacro(QTextStream &stream, const Tracepoint::Field &field) return; } - switch (field.backendType) { + switch (field.backendType.backendType) { case Tracepoint::Field::QtString: stream << "TraceLoggingCountedWideString(reinterpret_cast(" << name << ".utf16()), static_cast(" << name << ".size()), \"" @@ -64,6 +64,10 @@ static void writeEtwMacro(QTextStream &stream, const Tracepoint::Field &field) stream << "TraceLoggingCountedWideString(reinterpret_cast(" << name << "Str.utf16()), static_cast(" << name << "Str.size()), \"" << name << "\")"; return; + case Tracepoint::Field::EnumeratedType: + case Tracepoint::Field::FlagType: + stream << "TraceLoggingString(trace_convert_" << typeToName(field.paramType) << "(" << name << ").toUtf8().constData(), \"" << name << "\")"; + return; default: break; } @@ -160,10 +164,10 @@ static void writeWrapper(QTextStream &stream, const Tracepoint &tracepoint, const QString &providerName) { const QString argList = formatFunctionSignature(tracepoint.args); - const QString paramList = formatParameterList(tracepoint.args, ETW); + const QString paramList = formatParameterList(tracepoint.args, tracepoint.fields, ETW); const QString &name = tracepoint.name; const QString includeGuard = QStringLiteral("TP_%1_%2").arg(providerName).arg(name).toUpper(); - const QString provider = providerVar(providerName); + const QString provar = providerVar(providerName); stream << "\n"; @@ -173,12 +177,12 @@ static void writeWrapper(QTextStream &stream, const Tracepoint &tracepoint, // Convert all unknown types to QString's using QDebug. // Note the naming convention: it's field.name##Str for (const Tracepoint::Field &field : tracepoint.fields) { - if (field.backendType == Tracepoint::Field::Unknown) { + if (field.backendType.backendType == Tracepoint::Field::Unknown) { stream << " const QString " << field.name << "Str = QDebug::toString(" << field.name << ");\n"; } } - stream << " TraceLoggingWrite(" << provider << ", \"" << name << "\""; + stream << " TraceLoggingWrite(" << provar << ", \"" << name << "\""; for (const Tracepoint::Field &field : tracepoint.fields) { stream << ",\n"; @@ -196,10 +200,46 @@ static void writeWrapper(QTextStream &stream, const Tracepoint &tracepoint, stream << "inline bool trace_" << name << "_enabled()\n" << "{\n" - << " return TraceLoggingProviderEnabled(" << provider << ", 0, 0);\n" + << " return TraceLoggingProviderEnabled(" << provar << ", 0, 0);\n" << "}\n"; } +static void writeEnumConverter(QTextStream &stream, const TraceEnum &enumeration) +{ + stream << "inline QString trace_convert_" << typeToName(enumeration.name) << "(" << enumeration.name << " val)\n"; + stream << "{\n"; + for (const auto &v : enumeration.values) { + if (v.range != 0) { + stream << " if (val >= " << v.value << " && val <= " << v.range << ")\n" + << " return QStringLiteral(\"" << v.name << " + \") + QString::number((int)val - " << v.value << ");\n"; + } + } + stream << "\n QString ret;\n switch (val) {\n"; + for (const auto &v : enumeration.values) { + if (v.range == 0) + stream << " case " << v.value << ": ret = QStringLiteral(\"" << v.name << "\"); break;\n"; + } + + stream << " }\n return ret;\n}\n"; +} + +static void writeFlagConverter(QTextStream &stream, const TraceFlags &flag) +{ + stream << "inline QString trace_convert_" << typeToName(flag.name) << "(" << flag.name << " val)\n"; + stream << "{\n QString ret;\n"; + for (const auto &v : flag.values) { + if (v.value == 0) { + stream << " if (val == 0)\n return QStringLiteral(\"" << v.name << "\");\n"; + break; + } + } + for (const auto &v : flag.values) { + if (v.value != 0) + stream << " if (val & " << (1 << (v.value - 1)) << ") { if (ret.length()) ret += QLatin1Char(\'|\'); ret += QStringLiteral(\"" << v.name << "\"); }\n"; + } + stream << " return ret;\n}\n"; +} + static void writeTracepoints(QTextStream &stream, const Provider &provider) { if (provider.tracepoints.isEmpty()) @@ -212,6 +252,12 @@ static void writeTracepoints(QTextStream &stream, const Provider &provider) << "QT_BEGIN_NAMESPACE\n" << "namespace QtPrivate {\n"; + for (const auto &enumeration : provider.enumerations) + writeEnumConverter(stream, enumeration); + + for (const auto &flag : provider.flags) + writeFlagConverter(stream, flag); + for (const Tracepoint &t : provider.tracepoints) writeWrapper(stream, t, provider.name); diff --git a/src/tools/tracegen/helpers.cpp b/src/tools/tracegen/helpers.cpp index de523e74a67..6f0c7cb0f2f 100644 --- a/src/tools/tracegen/helpers.cpp +++ b/src/tools/tracegen/helpers.cpp @@ -6,6 +6,12 @@ using namespace Qt::StringLiterals; +QString typeToName(const QString &name) +{ + QString ret = name; + return ret.replace(QStringLiteral("::"), QStringLiteral("_")); +} + QString includeGuard(const QString &filename) { QString guard = filename.toUpper(); @@ -43,8 +49,22 @@ QString formatFunctionSignature(const QList &args) }); } -QString formatParameterList(const QList &args, ParamType type) +QString formatParameterList(const QList &args, const QList &fields, ParamType type) { + if (type == LTTNG) { + QString ret; + + for (int i = 0; i < args.size(); i++) { + const Tracepoint::Argument &arg = args[i]; + const Tracepoint::Field &field = fields[i]; + if (field.backendType.backendType == Tracepoint::Field::FlagType) + ret += ", trace_convert_"_L1 + typeToName(arg.type) + "("_L1 + arg.name + ")"_L1; + else + ret += ", "_L1 + arg.name; + } + return ret; + } + if (type == LTTNG) { QString ret; diff --git a/src/tools/tracegen/helpers.h b/src/tools/tracegen/helpers.h index 4c30eaff0d6..45a0383ff96 100644 --- a/src/tools/tracegen/helpers.h +++ b/src/tools/tracegen/helpers.h @@ -14,8 +14,9 @@ enum ParamType { ETW }; +QString typeToName(const QString &name); QString includeGuard(const QString &filename); QString formatFunctionSignature(const QList &args); -QString formatParameterList(const QList &args, ParamType type); +QString formatParameterList(const QList &args, const QList &fields, ParamType type); #endif // HELPERS_H diff --git a/src/tools/tracegen/lttng.cpp b/src/tools/tracegen/lttng.cpp index d230e024c7f..f9e8ce5c2f7 100644 --- a/src/tools/tracegen/lttng.cpp +++ b/src/tools/tracegen/lttng.cpp @@ -12,7 +12,7 @@ #include #include -static void writeCtfMacro(QTextStream &stream, const Tracepoint::Field &field) +static void writeCtfMacro(QTextStream &stream, const Provider &provider, const Tracepoint::Field &field) { const QString ¶mType = field.paramType; const QString &name = field.name; @@ -25,12 +25,13 @@ static void writeCtfMacro(QTextStream &stream, const Tracepoint::Field &field) return; } - switch (field.backendType) { + switch (field.backendType.backendType) { case Tracepoint::Field::Sequence: stream << "ctf_sequence(" << paramType << ", " << name << ", " << name << ", unsigned int, " << seqLen << ")"; return; + case Tracepoint::Field::Boolean: case Tracepoint::Field::Integer: stream << "ctf_integer(" << paramType << ", " << name << ", " << name << ")"; return; @@ -45,17 +46,14 @@ static void writeCtfMacro(QTextStream &stream, const Tracepoint::Field &field) stream << "ctf_string(" << name << ", " << name << ")"; return; case Tracepoint::Field::QtString: - stream << "ctf_sequence(const ushort, " << name << ", " - << name << ".utf16(), unsigned int, " << name << ".size())"; + stream << "ctf_string(" << name << ", " << name << ".toUtf8().constData())"; return; case Tracepoint::Field::QtByteArray: stream << "ctf_sequence(const char, " << name << ", " << name << ".constData(), unsigned int, " << name << ".size())"; return; case Tracepoint::Field::QtUrl: - stream << "ctf_sequence(const char, " << name << ", " - << name << ".toEncoded().constData(), unsigned int, " - << name << ".toEncoded().size())"; + stream << "ctf_string(" << name << ", " << name << ".toString().toUtf8().constData())"; return; case Tracepoint::Field::QtRect: stream << "ctf_integer(int, x, " << name << ".x()) " @@ -67,6 +65,13 @@ static void writeCtfMacro(QTextStream &stream, const Tracepoint::Field &field) stream << "ctf_integer(int, width, " << name << ".width()) " << "ctf_integer(int, height, " << name << ".height()) "; return; + case Tracepoint::Field::EnumeratedType: + stream << "ctf_enum(" << provider.name << ", " << typeToName(paramType) << ", int, " << name << ", " << name << ") "; + return; + case Tracepoint::Field::FlagType: + stream << "ctf_sequence(const char , " << name << ", " + << name << ".constData(), unsigned int, " << name << ".size())"; + return; case Tracepoint::Field::Unknown: panic("Cannot deduce CTF type for '%s %s", qPrintable(paramType), qPrintable(name)); break; @@ -116,12 +121,12 @@ static void writeEpilogue(QTextStream &stream, const QString &fileName) } static void writeWrapper(QTextStream &stream, - const Tracepoint &tracepoint, const QString &providerName) + const Tracepoint &tracepoint, const Provider &provider) { const QString argList = formatFunctionSignature(tracepoint.args); - const QString paramList = formatParameterList(tracepoint.args, LTTNG); + const QString paramList = formatParameterList(tracepoint.args, tracepoint.fields, LTTNG); const QString &name = tracepoint.name; - const QString includeGuard = QStringLiteral("TP_%1_%2").arg(providerName).arg(name).toUpper(); + const QString includeGuard = QStringLiteral("TP_%1_%2").arg(provider.name).arg(name).toUpper(); /* prevents the redefinion of the inline wrapper functions * once LTTNG recursively includes this header file @@ -134,17 +139,17 @@ static void writeWrapper(QTextStream &stream, stream << "inline void trace_" << name << "(" << argList << ")\n" << "{\n" - << " tracepoint(" << providerName << ", " << name << paramList << ");\n" + << " tracepoint(" << provider.name << ", " << name << paramList << ");\n" << "}\n"; stream << "inline void do_trace_" << name << "(" << argList << ")\n" << "{\n" - << " do_tracepoint(" << providerName << ", " << name << paramList << ");\n" + << " do_tracepoint(" << provider.name << ", " << name << paramList << ");\n" << "}\n"; stream << "inline bool trace_" << name << "_enabled()\n" << "{\n" - << " return tracepoint_enabled(" << providerName << ", " << name << ");\n" + << " return tracepoint_enabled(" << provider.name << ", " << name << ");\n" << "}\n"; stream << "} // namespace QtPrivate\n" @@ -152,7 +157,7 @@ static void writeWrapper(QTextStream &stream, << "#endif // " << includeGuard << "\n\n"; } -static void writeTracepoint(QTextStream &stream, +static void writeTracepoint(QTextStream &stream, const Provider &provider, const Tracepoint &tracepoint, const QString &providerName) { stream << "TRACEPOINT_EVENT(\n" @@ -162,8 +167,13 @@ static void writeTracepoint(QTextStream &stream, const char *comma = nullptr; - for (const Tracepoint::Argument &arg : tracepoint.args) { - stream << comma << arg.type << ", " << arg.name; + for (int i = 0; i < tracepoint.args.size(); i++) { + const auto &arg = tracepoint.args[i]; + const auto &field = tracepoint.fields[i]; + if (field.backendType.backendType == Tracepoint::Field::FlagType) + stream << comma << "QByteArray, " << arg.name; + else + stream << comma << arg.type << ", " << arg.name; comma = ", "; } @@ -174,18 +184,74 @@ static void writeTracepoint(QTextStream &stream, for (const Tracepoint::Field &f : tracepoint.fields) { stream << newline; - writeCtfMacro(stream, f); + writeCtfMacro(stream, provider, f); newline = "\n "; } stream << ")\n)\n\n"; } +static void writeEnums(QTextStream &stream, const Provider &provider) +{ + for (const auto &e : provider.enumerations) { + stream << "TRACEPOINT_ENUM(\n" + << " " << provider.name << ",\n" + << " " << typeToName(e.name) << ",\n" + << " TP_ENUM_VALUES(\n"; + for (const auto &v : e.values) { + if (v.range > 0) + stream << " ctf_enum_range(\"" << v.name << "\", " << v.value << ", " << v.range << ")\n"; + else + stream << " ctf_enum_value(\"" << v.name << "\", " << v.value << ")\n"; + } + stream << " )\n)\n\n"; + } +} + +static void writeFlags(QTextStream &stream, const Provider &provider) +{ + for (const auto &f : provider.flags) { + stream << "TRACEPOINT_ENUM(\n" + << " " << provider.name << ",\n" + << " " << typeToName(f.name) << ",\n" + << " TP_ENUM_VALUES(\n"; + for (const auto &v : f.values) + stream << " ctf_enum_value(\"" << v.name << "\", " << v.value << ")\n"; + stream << " )\n)\n\n"; + } + + // converters + const QString includeGuard = QStringLiteral("TP_%1_CONVERTERS").arg(provider.name).toUpper(); + stream << "\n" + << "#ifndef " << includeGuard << "\n" + << "#define " << includeGuard << "\n"; + stream << "QT_BEGIN_NAMESPACE\n"; + stream << "namespace QtPrivate {\n"; + for (const auto &f : provider.flags) { + stream << "inline QByteArray trace_convert_" << typeToName(f.name) << "(" << f.name << " val)\n"; + stream << "{\n"; + stream << " QByteArray ret;\n"; + stream << " if (val == 0) { ret.append((char)0); return ret; }\n"; + + for (const auto &v : f.values) { + if (!v.value) + continue; + stream << " if (val & " << (1 << (v.value - 1)) << ") { ret.append((char)" << v.value << "); };\n"; + } + stream << " return ret;\n"; + stream << "}\n"; + + } + stream << "} // namespace QtPrivate\n" + << "QT_END_NAMESPACE\n\n" + << "#endif // " << includeGuard << "\n\n"; +} + static void writeTracepoints(QTextStream &stream, const Provider &provider) { for (const Tracepoint &t : provider.tracepoints) { - writeTracepoint(stream, t, provider.name); - writeWrapper(stream, t, provider.name); + writeTracepoint(stream, provider, t, provider.name); + writeWrapper(stream, t, provider); } } @@ -196,6 +262,9 @@ void writeLttng(QFile &file, const Provider &provider) const QString fileName = QFileInfo(file.fileName()).fileName(); writePrologue(stream, fileName, provider); + writeEnums(stream, provider); + writeFlags(stream, provider); writeTracepoints(stream, provider); writeEpilogue(stream, fileName); } + diff --git a/src/tools/tracegen/provider.cpp b/src/tools/tracegen/provider.cpp index 51d0326ecff..10a864f6021 100644 --- a/src/tools/tracegen/provider.cpp +++ b/src/tools/tracegen/provider.cpp @@ -9,6 +9,7 @@ #include #include #include +#include using namespace Qt::StringLiterals; @@ -95,48 +96,55 @@ static QString removeBraces(QString type) return type.remove(rx); } +#define TYPEDATA_ENTRY(type, backendType) \ +{ QT_STRINGIFY(type), backendType, sizeof(type) * 8, std::is_signed::value } + static Tracepoint::Field::BackendType backendType(QString rawType) { - static const struct { + static const struct TypeData { const char *type; - Tracepoint::Field::BackendType backendType; + Tracepoint::Field::Type backendType; + int bits; + bool isSigned; } typeTable[] = { - { "bool", Tracepoint::Field::Integer }, - { "short_int", Tracepoint::Field::Integer }, - { "signed_short", Tracepoint::Field::Integer }, - { "signed_short_int", Tracepoint::Field::Integer }, - { "unsigned_short", Tracepoint::Field::Integer }, - { "unsigned_short_int", Tracepoint::Field::Integer }, - { "int", Tracepoint::Field::Integer }, - { "signed", Tracepoint::Field::Integer }, - { "signed_int", Tracepoint::Field::Integer }, - { "unsigned", Tracepoint::Field::Integer }, - { "unsigned_int", Tracepoint::Field::Integer }, - { "long", Tracepoint::Field::Integer }, - { "long_int", Tracepoint::Field::Integer }, - { "signed_long", Tracepoint::Field::Integer }, - { "signed_long_int", Tracepoint::Field::Integer }, - { "unsigned_long", Tracepoint::Field::Integer }, - { "unsigned_long_int", Tracepoint::Field::Integer }, - { "long_long", Tracepoint::Field::Integer }, - { "long_long_int", Tracepoint::Field::Integer }, - { "signed_long_long", Tracepoint::Field::Integer }, - { "signed_long_long_int", Tracepoint::Field::Integer }, - { "unsigned_long_long", Tracepoint::Field::Integer }, - { "qint64", Tracepoint::Field::Integer }, - { "char", Tracepoint::Field::Integer }, - { "intptr_t", Tracepoint::Field::IntegerHex }, - { "uintptr_t", Tracepoint::Field::IntegerHex }, - { "std::intptr_t", Tracepoint::Field::IntegerHex }, - { "std::uintptr_t", Tracepoint::Field::IntegerHex }, - { "float", Tracepoint::Field::Float }, - { "double", Tracepoint::Field::Float }, - { "long_double", Tracepoint::Field::Float }, - { "QString", Tracepoint::Field::QtString }, - { "QByteArray", Tracepoint::Field::QtByteArray }, - { "QUrl", Tracepoint::Field::QtUrl }, - { "QRect", Tracepoint::Field::QtRect }, - { "QSize", Tracepoint::Field::QtSize } +#ifdef UNDERSCORE_TYPES_DEFINED + TYPEDATA_ENTRY(short_int, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(signed_short, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(signed_short_int, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(unsigned_short, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(unsigned_short_int, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(unsigned_int, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(signed_int, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(long_int, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(signed_long, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(signed_long_int, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(unsigned_long, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(unsigned_long_int, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(long_long, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(long_long_int, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(signed_long_long, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(signed_long_long_int, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(unsigned_long_long, Tracepoint::Field::Integer), +#endif + TYPEDATA_ENTRY(bool, Tracepoint::Field::Boolean), + TYPEDATA_ENTRY(int, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(signed, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(unsigned, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(long, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(qint64, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(char, Tracepoint::Field::Integer), + TYPEDATA_ENTRY(intptr_t, Tracepoint::Field::IntegerHex), + TYPEDATA_ENTRY(uintptr_t, Tracepoint::Field::IntegerHex), + TYPEDATA_ENTRY(std::intptr_t, Tracepoint::Field::IntegerHex), + TYPEDATA_ENTRY(std::uintptr_t, Tracepoint::Field::IntegerHex), + TYPEDATA_ENTRY(float, Tracepoint::Field::Float), + TYPEDATA_ENTRY(double, Tracepoint::Field::Float), + TYPEDATA_ENTRY(long double, Tracepoint::Field::Float), + { "QString", Tracepoint::Field::QtString , 0, false}, + { "QByteArray", Tracepoint::Field::QtByteArray , 0, false}, + { "QUrl", Tracepoint::Field::QtUrl , 0, false}, + { "QRect", Tracepoint::Field::QtRect , 0, false}, + { "QSize", Tracepoint::Field::QtSize , 0, false} }; auto backendType = [](const QString &rawType) { @@ -144,10 +152,11 @@ static Tracepoint::Field::BackendType backendType(QString rawType) for (size_t i = 0; i < tableSize; ++i) { if (rawType == QLatin1StringView(typeTable[i].type)) - return typeTable[i].backendType; + return typeTable[i]; } - return Tracepoint::Field::Unknown; + TypeData unknown = { nullptr, Tracepoint::Field::Unknown, 0, false }; + return unknown; }; int arrayLen = arrayLength(rawType); @@ -155,7 +164,7 @@ static Tracepoint::Field::BackendType backendType(QString rawType) rawType = removeBraces(rawType); if (!sequenceLength(rawType).isNull()) - return Tracepoint::Field::Sequence; + return { Tracepoint::Field::Sequence, 0, false }; static const QRegularExpression constMatch(QStringLiteral("\\bconst\\b")); rawType.remove(constMatch); @@ -167,20 +176,37 @@ static Tracepoint::Field::BackendType backendType(QString rawType) rawType.replace(QStringLiteral(" "), QStringLiteral("_")); if (rawType == "char_ptr"_L1) - return Tracepoint::Field::String; + return { Tracepoint::Field::String, 0, false }; if (rawType.endsWith("_ptr"_L1)) - return Tracepoint::Field::Pointer; + return {Tracepoint::Field::Pointer, QT_POINTER_SIZE, false }; - return backendType(rawType); + TypeData d = backendType(rawType); + return { d.backendType, d.bits, d.isSigned }; } -static Tracepoint parseTracepoint(const QString &name, const QStringList &args, +static Tracepoint parseTracepoint(const Provider &provider, const QString &name, const QStringList &args, const QString &fileName, const int lineNumber) { Tracepoint t; t.name = name; + auto findEnumeration = [](const QList &enums, const QString &name) { + for (const auto &e : enums) { + if (e.name == name) + return e; + } + return TraceEnum(); + }; + auto findFlags = [](const QList &flags, const QString &name) { + for (const auto &f : flags) { + if (f.name == name) + return f; + } + return TraceFlags(); + }; + + if (args.isEmpty()) return t; @@ -216,14 +242,22 @@ static Tracepoint parseTracepoint(const QString &name, const QStringList &args, t.args << std::move(a); - Tracepoint::Field f; - f.backendType = backendType(type); - f.paramType = removeBraces(type); - f.name = name; - f.arrayLen = arrayLen; - f.seqLen = sequenceLength(type); + Tracepoint::Field field; + const TraceEnum &e = findEnumeration(provider.enumerations, type); + const TraceFlags &f = findFlags(provider.flags, type); + if (!e.name.isEmpty()) { + field.backendType = { Tracepoint::Field::EnumeratedType, e.valueSize, false }; + } else if (!f.name.isEmpty()) { + field.backendType = { Tracepoint::Field::FlagType, 0, false }; + } else { + field.backendType = backendType(type); + } + field.paramType = removeBraces(type); + field.name = name; + field.arrayLen = arrayLen; + field.seqLen = sequenceLength(type); - t.fields << std::move(f); + t.fields << std::move(field); ++i; } @@ -231,6 +265,31 @@ static Tracepoint parseTracepoint(const QString &name, const QStringList &args, return t; } +static int minumumValueSize(int min, int max) +{ + if (min < 0) { + if (min >= std::numeric_limits::min() && max <= std::numeric_limits::max()) + return 8; + if (min >= std::numeric_limits::min() && max <= std::numeric_limits::max()) + return 16; + return 32; + } + if (max <= std::numeric_limits::max()) + return 8; + if (max <= std::numeric_limits::max()) + return 16; + return 32; +} + +static bool isPow2OrZero(quint32 value) +{ + return (value & (value - 1)) == 0; +} + +static quint32 pow2Log2(quint32 v) { + return 32 - qCountLeadingZeroBits(v); +} + Provider parseProvider(const QString &filename) { QFile f(filename); @@ -241,11 +300,21 @@ Provider parseProvider(const QString &filename) QTextStream s(&f); static const QRegularExpression tracedef(QStringLiteral("^([A-Za-z][A-Za-z0-9_]*)\\((.*)\\)$")); + static const QRegularExpression enumenddef(QStringLiteral("^} ?([A-Za-z][A-Za-z0-9_:]*);")); + static const QRegularExpression enumdef(QStringLiteral("^([A-Za-z][A-Za-z0-9_]*)( ?= ?([0-9]*))?")); + static const QRegularExpression rangedef(QStringLiteral("^RANGE\\(([A-Za-z][A-Za-z0-9_]*) ?, ?([0-9]*) ?... ?([0-9]*) ?\\)")); Provider provider; provider.name = QFileInfo(filename).baseName(); bool parsingPrefixText = false; + bool parsingEnum = false; + bool parsingFlags = false; + TraceEnum currentEnum; + TraceFlags currentFlags; + int currentEnumValue = 0; + int minEnumValue = std::numeric_limits::max(); + int maxEnumValue = std::numeric_limits::min(); for (int lineNumber = 1; !s.atEnd(); ++lineNumber) { QString line = s.readLine().trimmed(); @@ -257,19 +326,110 @@ Provider parseProvider(const QString &filename) continue; } else if (parsingPrefixText) { provider.prefixText.append(line); + continue; + } else if (line == "ENUM {"_L1) { + parsingEnum = true; + continue; + } else if (line == "FLAGS {"_L1) { + parsingFlags = true; + continue; + } else if (line.startsWith("}"_L1) && (parsingEnum || parsingFlags)) { + auto match = enumenddef.match(line); + if (match.hasMatch()) { + if (parsingEnum) { + currentEnum.name = match.captured(1); + currentEnum.valueSize = minumumValueSize(minEnumValue, maxEnumValue); + provider.enumerations.push_back(currentEnum); + currentEnum = TraceEnum(); + parsingEnum = false; + } else { + currentFlags.name = match.captured(1); + provider.flags.push_back(currentFlags); + currentFlags = TraceFlags(); + parsingFlags = false; + } + + minEnumValue = std::numeric_limits::max(); + maxEnumValue = std::numeric_limits::min(); + } else { + panic("Syntax error while processing '%s' line %d:\n" + " '%s' end of enum/flags does not match", + qPrintable(filename), lineNumber, + qPrintable(line)); + } + continue; } if (line.isEmpty() || line.startsWith(u'#')) continue; + if (parsingEnum || parsingFlags) { + auto m = enumdef.match(line); + if (parsingEnum && line.startsWith(QStringLiteral("RANGE"))) { + auto m = rangedef.match(line); + if (m.hasMatch()) { + TraceEnum::EnumValue value; + value.name = m.captured(1); + value.value = m.captured(2).toInt(); + value.range = m.captured(3).toInt(); + currentEnumValue = value.range; + currentEnum.values.push_back(value); + maxEnumValue = qMax(maxEnumValue, value.range); + minEnumValue = qMin(minEnumValue, value.value); + } + } else if (m.hasMatch()) { + if (m.hasCaptured(3)) { + if (parsingEnum) { + TraceEnum::EnumValue value; + value.name = m.captured(1); + value.value = m.captured(3).toInt(); + value.range = 0; + currentEnumValue = value.value; + currentEnum.values.push_back(value); + maxEnumValue = qMax(maxEnumValue, value.value); + minEnumValue = qMin(minEnumValue, value.value); + } else { + TraceFlags::FlagValue value; + value.name = m.captured(1); + value.value = m.captured(3).toInt(); + if (!isPow2OrZero(value.value)) { + panic("Syntax error while processing '%s' line %d:\n" + " '%s' flag value is now power of two", + qPrintable(filename), lineNumber, + qPrintable(line)); + } + value.value = pow2Log2(value.value); + currentFlags.values.push_back(value); + } + } else { + maxEnumValue = qMax(maxEnumValue, currentEnumValue); + minEnumValue = qMin(minEnumValue, currentEnumValue); + if (parsingEnum) { + currentEnum.values.push_back({m.captured(0), currentEnumValue++, 0}); + } else { + panic("Syntax error while processing '%s' line %d:\n" + " '%s' flags value not set", + qPrintable(filename), lineNumber, + qPrintable(line)); + } + } + } else { + panic("Syntax error while processing '%s' line %d:\n" + " '%s' enum/flags does not match", + qPrintable(filename), lineNumber, + qPrintable(line)); + } + continue; + } + auto match = tracedef.match(line); if (match.hasMatch()) { const QString name = match.captured(1); const QString argsString = match.captured(2); const QStringList args = argsString.split(u',', Qt::SkipEmptyParts); - provider.tracepoints << parseTracepoint(name, args, filename, lineNumber); + provider.tracepoints << parseTracepoint(provider, name, args, filename, lineNumber); } else { panic("Syntax error while processing '%s' line %d:\n" " '%s' does not look like a tracepoint definition", diff --git a/src/tools/tracegen/provider.h b/src/tools/tracegen/provider.h index 18392baaef2..72096590334 100644 --- a/src/tools/tracegen/provider.h +++ b/src/tools/tracegen/provider.h @@ -20,8 +20,9 @@ struct Tracepoint struct Field { - enum BackendType { + enum Type { Sequence, + Boolean, Integer, IntegerHex, Float, @@ -32,9 +33,15 @@ struct Tracepoint QtUrl, QtRect, QtSize, + EnumeratedType, + FlagType, Unknown }; - + struct BackendType { + Type backendType; + int bits; + bool isSigned; + }; BackendType backendType; QString paramType; QString name; @@ -47,17 +54,42 @@ struct Tracepoint QList fields; }; +struct TraceEnum { + QString name; + struct EnumValue { + QString name; + int value; + int range; + }; + QList values; + int valueSize; +}; + +struct TraceFlags { + QString name; + struct FlagValue { + QString name; + int value; + }; + QList values; +}; + +Q_DECLARE_TYPEINFO(TraceEnum, Q_RELOCATABLE_TYPE); +Q_DECLARE_TYPEINFO(TraceFlags, Q_RELOCATABLE_TYPE); +Q_DECLARE_TYPEINFO(Tracepoint::Argument, Q_RELOCATABLE_TYPE); +Q_DECLARE_TYPEINFO(Tracepoint::Field::BackendType, Q_RELOCATABLE_TYPE); +Q_DECLARE_TYPEINFO(Tracepoint::Field, Q_RELOCATABLE_TYPE); +Q_DECLARE_TYPEINFO(Tracepoint, Q_RELOCATABLE_TYPE); + struct Provider { QString name; QList tracepoints; QStringList prefixText; + QList enumerations; + QList flags; }; Provider parseProvider(const QString &filename); -Q_DECLARE_TYPEINFO(Tracepoint::Argument, Q_RELOCATABLE_TYPE); -Q_DECLARE_TYPEINFO(Tracepoint::Field, Q_RELOCATABLE_TYPE); -Q_DECLARE_TYPEINFO(Tracepoint, Q_RELOCATABLE_TYPE); - #endif // PROVIDER_H diff --git a/src/tools/tracepointgen/parser.cpp b/src/tools/tracepointgen/parser.cpp index 6199098371e..940e609b44a 100644 --- a/src/tools/tracepointgen/parser.cpp +++ b/src/tools/tracepointgen/parser.cpp @@ -78,14 +78,14 @@ static void simplifyData(QString &data, QList &offsets) } } -static QString preprocessPrefix(const QString &in) +static QString preprocessMetadata(const QString &in) { - DEBUGPRINTF(printf("prefix: %s\n", qPrintable(in))); + DEBUGPRINTF(printf("in: %s\n", qPrintable(in))); QList lines = in.split(QLatin1Char('\\')); QString out; for (int i = 0; i < lines.size(); i++) { QString l = lines.at(i).simplified(); - DEBUGPRINTF(printf("prefix line: %s\n", qPrintable(l))); + DEBUGPRINTF(printf("line: %s\n", qPrintable(l))); if (l.length() < 2) continue; if (l.startsWith(QStringLiteral("\""))) @@ -100,7 +100,7 @@ static QString preprocessPrefix(const QString &in) out.append(l); } } - DEBUGPRINTF(printf("prefix out: %s\n", qPrintable(out))); + DEBUGPRINTF(printf("out: %s\n", qPrintable(out))); return out; } @@ -207,7 +207,25 @@ void Parser::parsePrefix(const QString &data, qsizetype offset) DEBUGPRINTF(printf("tracepointgen: prefix: %s\n", qPrintable(prefix))); if (!m_prefixes.contains(prefix)) - m_prefixes.push_back(preprocessPrefix(prefix)); + m_prefixes.push_back(preprocessMetadata(prefix)); +} + +void Parser::parseMetadata(const QString &data, qsizetype offset) +{ + qsizetype beginOfProvider = data.indexOf(QLatin1Char('('), offset); + qsizetype endOfProvider = data.indexOf(QLatin1Char(','), beginOfProvider); + QString metadata; + QString provider = data.mid(beginOfProvider + 1, endOfProvider - beginOfProvider - 1).simplified(); + if (provider != m_provider) + return; + + qsizetype endOfPoint = data.indexOf(QLatin1Char(')'), endOfProvider + 1); + metadata = data.mid(endOfProvider + 1, endOfPoint - endOfProvider - 1).simplified(); + + DEBUGPRINTF(printf("tracepointgen: metadata: %s", qPrintable(metadata))); + + if (!m_metadata.contains(metadata)) + m_metadata.push_back(preprocessMetadata(metadata)); } void Parser::parse(QIODevice &input, const QString &name) @@ -239,6 +257,8 @@ void Parser::parse(QIODevice &input, const QString &name) parsePoint(data, match.capturedEnd()); else if (macroType == QStringLiteral("PREFIX")) parsePrefix(data, match.capturedEnd()); + else if (macroType == QStringLiteral("METADATA")) + parseMetadata(data, match.capturedEnd()); } for (auto &func : m_functions) { @@ -256,6 +276,8 @@ void Parser::write(QIODevice &input) const out << prefix << "\n"; out << QStringLiteral("}\n"); } + for (auto m : m_metadata) + out << m << "\n"; for (auto func : m_functions) { out << func.className << "_" << func.functionName << "_entry(" << func.functionParameters << ")\n"; out << func.className << "_" << func.functionName << "_exit()\n"; diff --git a/src/tools/tracepointgen/parser.h b/src/tools/tracepointgen/parser.h index 1d1fda20682..bc46a4d933b 100644 --- a/src/tools/tracepointgen/parser.h +++ b/src/tools/tracepointgen/parser.h @@ -41,10 +41,12 @@ struct Parser { } + void parseParamReplace(const QString &data, qsizetype offset, const QString &name); void parseInstrument(const QString &data, qsizetype offset); void parsePoint(const QString &data, qsizetype offset); void parsePrefix(const QString &data, qsizetype offset); + void parseMetadata(const QString &data, qsizetype offset); int lineNumber(qsizetype offset) const; void parse(QIODevice &input, const QString &name); @@ -58,8 +60,9 @@ struct Parser QList m_points; QList m_replaces; QList m_prefixes; - QString m_provider; + QList m_metadata; QList m_offsets; + QString m_provider; }; #endif // PARSER_H