diff options
Diffstat (limited to 'src/tools/tracegen/provider.cpp')
-rw-r--r-- | src/tools/tracegen/provider.cpp | 270 |
1 files changed, 218 insertions, 52 deletions
diff --git a/src/tools/tracegen/provider.cpp b/src/tools/tracegen/provider.cpp index 11322e951c..bdd669c9cd 100644 --- a/src/tools/tracegen/provider.cpp +++ b/src/tools/tracegen/provider.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com> -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "provider.h" #include "panic.h" @@ -9,6 +9,7 @@ #include <qtextstream.h> #include <qregularexpression.h> #include <qstring.h> +#include <qtpreprocessorsupport.h> using namespace Qt::StringLiterals; @@ -95,46 +96,53 @@ static QString removeBraces(QString type) return type.remove(rx); } -static Tracepoint::Field::BackendType backendType(QString rawType) +#define TYPEDATA_ENTRY(type, backendType) \ +{ QT_STRINGIFY(type), backendType } + +static Tracepoint::Field::Type backendType(QString rawType) { - static const struct { + static const struct TypeData { const char *type; - Tracepoint::Field::BackendType backendType; + Tracepoint::Field::Type backendType; } 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 }, - { "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 } + 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), + 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), + TYPEDATA_ENTRY(QString, Tracepoint::Field::QtString), + TYPEDATA_ENTRY(QByteArray, Tracepoint::Field::QtByteArray), + TYPEDATA_ENTRY(QUrl, Tracepoint::Field::QtUrl), + TYPEDATA_ENTRY(QRect, Tracepoint::Field::QtRect), + TYPEDATA_ENTRY(QSize, Tracepoint::Field::QtSize), + TYPEDATA_ENTRY(QRectF, Tracepoint::Field::QtRectF), + TYPEDATA_ENTRY(QSizeF, Tracepoint::Field::QtSizeF) }; auto backendType = [](const QString &rawType) { @@ -142,14 +150,16 @@ 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 }; + return unknown; }; - if (arrayLength(rawType) > 0) - return Tracepoint::Field::Array; + int arrayLen = arrayLength(rawType); + if (arrayLen > 0) + rawType = removeBraces(rawType); if (!sequenceLength(rawType).isNull()) return Tracepoint::Field::Sequence; @@ -169,15 +179,32 @@ static Tracepoint::Field::BackendType backendType(QString rawType) if (rawType.endsWith("_ptr"_L1)) return Tracepoint::Field::Pointer; - return backendType(rawType); + TypeData d = backendType(rawType); + return d.backendType; } -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<TraceEnum> &enums, const QString &name) { + for (const auto &e : enums) { + if (e.name == name) + return e; + } + return TraceEnum(); + }; + auto findFlags = [](const QList<TraceFlags> &flags, const QString &name) { + for (const auto &f : flags) { + if (f.name == name) + return f; + } + return TraceFlags(); + }; + + if (args.isEmpty()) return t; @@ -213,14 +240,23 @@ 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; + field.enumValueSize = e.valueSize; + } else if (!f.name.isEmpty()) { + field.backendType = Tracepoint::Field::FlagType; + } 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; } @@ -228,6 +264,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<char>::min() && max <= std::numeric_limits<char>::max()) + return 8; + if (min >= std::numeric_limits<short>::min() && max <= std::numeric_limits<short>::max()) + return 16; + return 32; + } + if (max <= std::numeric_limits<unsigned char>::max()) + return 8; + if (max <= std::numeric_limits<unsigned short>::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); @@ -238,11 +299,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_]*)( *= *([xabcdef0-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<int>::max(); + int maxEnumValue = std::numeric_limits<int>::min(); for (int lineNumber = 1; !s.atEnd(); ++lineNumber) { QString line = s.readLine().trimmed(); @@ -255,18 +326,113 @@ Provider parseProvider(const QString &filename) } 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<int>::max(); + maxEnumValue = std::numeric_limits<int>::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 + 1; + 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 + 1; + currentEnum.values.push_back(value); + maxEnumValue = qMax(maxEnumValue, value.value); + minEnumValue = qMin(minEnumValue, value.value); + } else { + TraceFlags::FlagValue value; + value.name = m.captured(1); + if (m.captured(3).startsWith(QStringLiteral("0x"))) + value.value = m.captured(3).toInt(nullptr, 16); + else + value.value = m.captured(3).toInt(); + if (!isPow2OrZero(value.value)) { + printf("Warning: '%s' line %d:\n" + " '%s' flag value is not power of two.\n", + qPrintable(filename), lineNumber, + qPrintable(line)); + } else { + 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", |