diff options
Diffstat (limited to 'src/tools/tracegen/ctf.cpp')
-rw-r--r-- | src/tools/tracegen/ctf.cpp | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/src/tools/tracegen/ctf.cpp b/src/tools/tracegen/ctf.cpp new file mode 100644 index 0000000000..95ffcf89cc --- /dev/null +++ b/src/tools/tracegen/ctf.cpp @@ -0,0 +1,376 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "ctf.h" +#include "provider.h" +#include "helpers.h" +#include "panic.h" +#include "qtheaders.h" + +#include <qfile.h> +#include <qfileinfo.h> +#include <qtextstream.h> +#include <qdebug.h> + + +static void writePrologue(QTextStream &stream, const QString &fileName, const Provider &provider) +{ + writeCommonPrologue(stream); + const QString guard = includeGuard(fileName); + + // include prefix text or qt headers only once + stream << "#if !defined(" << guard << ")\n"; + stream << qtHeaders(); + stream << "\n"; + if (!provider.prefixText.isEmpty()) + stream << provider.prefixText.join(u'\n') << "\n\n"; + stream << "#endif\n\n"; + + /* the first guard is the usual one, the second is required + * by LTTNG to force the re-evaluation of TRACEPOINT_* macros + */ + stream << "#if !defined(" << guard << ") || defined(TRACEPOINT_HEADER_MULTI_READ)\n"; + + stream << "#define " << guard << "\n\n" + << "#undef TRACEPOINT_INCLUDE\n" + << "#define TRACEPOINT_INCLUDE \"" << fileName << "\"\n\n"; + + stream << "#include <private/qctf_p.h>\n\n"; + + const QString namespaceGuard = guard + QStringLiteral("_USE_NAMESPACE"); + stream << "#if !defined(" << namespaceGuard << ")\n" + << "#define " << namespaceGuard << "\n" + << "QT_USE_NAMESPACE\n" + << "#endif // " << namespaceGuard << "\n\n"; + + stream << "TRACEPOINT_PROVIDER(" << provider.name << ");\n\n"; +} + +static void writeEpilogue(QTextStream &stream, const QString &fileName) +{ + stream << "\n"; + stream << "#endif // " << includeGuard(fileName) << "\n" + << "#include <private/qtrace_p.h>\n"; +} + +static void writeWrapper(QTextStream &stream, + const Tracepoint &tracepoint, const Provider &provider) +{ + const QString argList = formatFunctionSignature(tracepoint.args); + const QString paramList = formatParameterList(provider, tracepoint.args, tracepoint.fields, CTF); + const QString &name = tracepoint.name; + const QString includeGuard = QStringLiteral("TP_%1_%2").arg(provider.name).arg(name).toUpper(); + + /* prevents the redefinion of the inline wrapper functions + */ + stream << "\n" + << "#ifndef " << includeGuard << "\n" + << "#define " << includeGuard << "\n" + << "QT_BEGIN_NAMESPACE\n" + << "namespace QtPrivate {\n"; + + stream << "inline void trace_" << name << "(" << argList << ")\n" + << "{\n" + << " tracepoint(" << provider.name << ", " << name << paramList << ");\n" + << "}\n"; + + stream << "inline void do_trace_" << name << "(" << argList << ")\n" + << "{\n" + << " do_tracepoint(" << provider.name << ", " << name << paramList << ");\n" + << "}\n"; + + stream << "inline bool trace_" << name << "_enabled()\n" + << "{\n" + << " return tracepoint_enabled(" << provider.name << ", " << name << ");\n" + << "}\n"; + + stream << "} // namespace QtPrivate\n" + << "QT_END_NAMESPACE\n" + << "#endif // " << includeGuard << "\n\n"; +} + + +static void writeMetadataGenerators(QTextStream &stream) +{ + stream << R"CPP( +template <typename T> +inline QString integerToMetadata(const QString &name) +{ + QString ret; + if (!std::is_signed<T>().value) + ret += QLatin1Char('u'); + if (sizeof(T) == 8) + ret += QStringLiteral("int64_t "); + else if (sizeof(T) == 4) + ret += QStringLiteral("int32_t "); + else if (sizeof(T) == 2) + ret += QStringLiteral("int16_t "); + else if (sizeof(T) == 1) + ret += QStringLiteral("int8_t "); + ret += name + QLatin1Char(';'); + return ret; +} + +template <typename T> +inline QString integerArrayToMetadata(const QString &size, const QString &name) +{ + QString ret; + if (!std::is_signed<T>().value) + ret += QLatin1Char('u'); + if (sizeof(T) == 8) + ret += QStringLiteral("int64_t "); + else if (sizeof(T) == 4) + ret += QStringLiteral("int32_t "); + else if (sizeof(T) == 2) + ret += QStringLiteral("int16_t "); + else if (sizeof(T) == 1) + ret += QStringLiteral("int8_t "); + ret += name + QLatin1Char('[') + size + QStringLiteral("];"); + return ret; +} + +template <typename T> +inline QString floatToMetadata(const QString &name) +{ + QString ret; + if (sizeof(T) == 8) + ret += QStringLiteral("double "); + else if (sizeof(T) == 4) + ret += QStringLiteral("float "); + ret += name + QLatin1Char(';'); + return ret; +} + +template <typename T> +inline QString floatArrayToMetadata(const QString &size, const QString &name) +{ + QString ret; + if (sizeof(T) == 8) + ret += QStringLiteral("double "); + else if (sizeof(T) == 4) + ret += QStringLiteral("float "); + ret += name + QLatin1Char('[') + size + QLatin1Char(']'); + return ret + QLatin1Char(';'); +} + +inline QString pointerToMetadata(const QString &name) +{ + QString ret; + if (QT_POINTER_SIZE == 8) + ret += QStringLiteral("intptr64_t "); + else if (QT_POINTER_SIZE == 4) + ret += QStringLiteral("intptr32_t "); + ret += name + QLatin1Char(';'); + return ret; +} + +)CPP"; +} + +static void writeTracepoint(QTextStream &stream, + const Tracepoint &tracepoint, const QString &providerName) +{ + stream << "TRACEPOINT_EVENT(\n" + << " " << providerName << ",\n" + << " " << tracepoint.name << ",\n"; + + const auto checkUnknownArgs = [](const Tracepoint &tracepoint) { + for (auto &field : tracepoint.fields) { + if (field.backendType == Tracepoint::Field::Unknown) + return true; + } + return false; + }; + + const auto formatType = [](const QString &type) { + QString ret = type; + if (type.endsWith(QLatin1Char('*')) || type.endsWith(QLatin1Char('&'))) + ret = type.left(type.length() - 1).simplified(); + if (ret.startsWith(QStringLiteral("const"))) + ret = ret.right(ret.length() - 6).simplified(); + return typeToTypeName(ret); + }; + QString eventSize; + bool variableSize = false; + const bool emptyMetadata = checkUnknownArgs(tracepoint) || tracepoint.args.size() == 0; + if (!emptyMetadata) { + for (int i = 0; i < tracepoint.args.size(); i++) { + auto &arg = tracepoint.args[i]; + auto &field = tracepoint.fields[i]; + if (i > 0) { + stream << " + QStringLiteral(\"\\n\\\n \") + "; + eventSize += QStringLiteral(" + "); + } + const bool array = field.arrayLen > 0; + switch (field.backendType) { + case Tracepoint::Field::Boolean: { + stream << "QStringLiteral(\"Boolean " << arg.name << ";\")"; + eventSize += QStringLiteral("sizeof(bool)"); + } break; + case Tracepoint::Field::Integer: { + if (array) { + stream << "integerArrayToMetadata<" << formatType(arg.type) + << ">(QStringLiteral(\"" << field.arrayLen << "\"), QStringLiteral(\"" + << arg.name << "\"))"; + } else { + stream << "integerToMetadata<" << formatType(arg.type) << ">(QStringLiteral(\"" + << arg.name << "\"))"; + } + eventSize += QStringLiteral("sizeof(") + formatType(arg.type) + QStringLiteral(")"); + if (array) + eventSize += QStringLiteral(" * ") + QString::number(field.arrayLen); + } break; + case Tracepoint::Field::Pointer: + case Tracepoint::Field::IntegerHex: { + stream << "pointerToMetadata(QStringLiteral(\"" << formatType(arg.type) << "_" + << arg.name << "\"))"; + eventSize += QStringLiteral("QT_POINTER_SIZE"); + } break; + case Tracepoint::Field::Float: { + if (array) { + stream << "floatArrayToMetadata<" << formatType(arg.type) + << ">(QStringLiteral(\"" << field.arrayLen << "\"), QStringLiteral(\"" + << arg.name << "\"))"; + } else { + stream << "floatToMetadata<" << formatType(arg.type) << ">(QStringLiteral(\"" + << arg.name << "\"))"; + } + eventSize += QStringLiteral("sizeof(") + formatType(arg.type) + QStringLiteral(")"); + if (array) + eventSize += QStringLiteral(" * ") + QString::number(field.arrayLen); + } break; + case Tracepoint::Field::QtUrl: + case Tracepoint::Field::QtString: + case Tracepoint::Field::String: { + stream << "QStringLiteral(\"string " << arg.name << ";\")"; + eventSize += QStringLiteral("1"); + variableSize = true; + } break; + case Tracepoint::Field::QtRect: { + stream << "QStringLiteral(\"int32_t QRect_" << arg.name << "_x;\\n\\\n \")"; + stream << " + QStringLiteral(\"int32_t QRect_" << arg.name << "_y;\\n\\\n \")"; + stream << " + QStringLiteral(\"int32_t QRect_" << arg.name << "_width;\\n\\\n \")"; + stream << " + QStringLiteral(\"int32_t QRect_" << arg.name << "_height;\\n\\\n \")"; + eventSize += QStringLiteral("16"); + } break; + case Tracepoint::Field::QtSize: { + stream << "QStringLiteral(\"int32_t QSize_" << arg.name << "_width;\\n\\\n \")"; + stream << " + QStringLiteral(\"int32_t QSize_" << arg.name << "_height;\\n\\\n \")"; + eventSize += QStringLiteral("8"); + } break; + case Tracepoint::Field::QtRectF: { + stream << "QStringLiteral(\"float QRectF_" << arg.name << "_x;\\n\\\n \")"; + stream << " + QStringLiteral(\"float QRectF_" << arg.name << "_y;\\n\\\n \")"; + stream << " + QStringLiteral(\"float QRectF_" << arg.name << "_width;\\n\\\n \")"; + stream << " + QStringLiteral(\"float QRectF_" << arg.name << "_height;\\n\\\n \")"; + eventSize += QStringLiteral("16"); + } break; + case Tracepoint::Field::QtSizeF: { + stream << "QStringLiteral(\"float QSizeF_" << arg.name << "_width;\\n\\\n \")"; + stream << " + QStringLiteral(\"float QSizeF_" << arg.name << "_height;\\n\\\n \")"; + eventSize += QStringLiteral("8"); + } break; + case Tracepoint::Field::Unknown: + break; + case Tracepoint::Field::EnumeratedType: { + stream << "QStringLiteral(\"" << typeToTypeName(arg.type) << " " << arg.name << ";\")"; + eventSize += QString::number(field.enumValueSize / 8); + variableSize = true; + } break; + case Tracepoint::Field::FlagType: { + stream << "QStringLiteral(\"uint8_t " << arg.name << "_length;\\n\\\n "; + stream << typeToTypeName(arg.type) << " " << arg.name << "[" << arg.name << "_length];\")"; + eventSize += QStringLiteral("2"); + variableSize = true; + } break; + case Tracepoint::Field::QtByteArray: + case Tracepoint::Field::Sequence: + panic("Unhandled type '%s %s", qPrintable(arg.type), qPrintable(arg.name)); + break; + } + } + } + + if (emptyMetadata) + stream << "{},\n"; + else + stream << ",\n"; + if (eventSize.length()) + stream << eventSize << ", \n"; + else + stream << "0, \n"; + stream << (variableSize ? "true" : "false") << "\n"; + stream << ")\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); + } +} + +static void writeEnums(QTextStream &stream, const Provider &provider) +{ + for (const auto &e : provider.enumerations) { + QString name = e.name; + name.replace(QStringLiteral("::"), QStringLiteral("_")); + stream << "TRACEPOINT_METADATA(" << provider.name << ", " << name << ", \n"; + stream << "QStringLiteral(\"typealias enum : integer { size = " << e.valueSize << "; } {\\n\\\n"; + + const auto values = e.values; + QList<int> handledValues; + + for (const auto &v : values) { + if (handledValues.contains(v.value)) + continue; + if (v.range) { + stream << v.name << " = " << v.value << " ... " << v.range << ", \\n\\\n"; + } else { + const QString names = aggregateListValues(v.value, values); + stream << names << " = " << v.value << ", \\n\\\n"; + handledValues.append(v.value); + } + } + stream << "} := " << name << ";\\n\\n\"));\n\n"; + } + stream << "\n"; +} + +static void writeFlags(QTextStream &stream, const Provider &provider) +{ + for (const auto &e : provider.flags) { + QString name = e.name; + name.replace(QStringLiteral("::"), QStringLiteral("_")); + stream << "TRACEPOINT_METADATA(" << provider.name << ", " << name << ", \n"; + stream << "QStringLiteral(\"typealias enum : integer { size = 8; } {\\n\\\n"; + + const auto values = e.values; + QList<int> handledValues; + + for (const auto &v : values) { + if (handledValues.contains(v.value)) + continue; + const QString names = aggregateListValues(v.value, values); + stream << names << " = " << v.value << ", \\n\\\n"; + handledValues.append(v.value); + } + stream << "} := " << name << ";\\n\\n\"));\n\n"; + } + stream << "\n"; +} + +void writeCtf(QFile &file, const Provider &provider) +{ + QTextStream stream(&file); + + const QString fileName = QFileInfo(file.fileName()).fileName(); + + writePrologue(stream, fileName, provider); + writeMetadataGenerators(stream); + writeEnums(stream, provider); + writeFlags(stream, provider); + writeTracepoints(stream, provider); + writeEpilogue(stream, fileName); +} |