summaryrefslogtreecommitdiffstats
path: root/src/tools/tracegen/provider.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/tracegen/provider.cpp')
-rw-r--r--src/tools/tracegen/provider.cpp304
1 files changed, 304 insertions, 0 deletions
diff --git a/src/tools/tracegen/provider.cpp b/src/tools/tracegen/provider.cpp
new file mode 100644
index 0000000000..00e105377e
--- /dev/null
+++ b/src/tools/tracegen/provider.cpp
@@ -0,0 +1,304 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "provider.h"
+#include "panic.h"
+
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+#include <qstring.h>
+
+#ifdef TRACEGEN_DEBUG
+#include <qdebug.h>
+
+static void dumpTracepoint(const Tracepoint &t)
+{
+ qDebug() << "=== BEGIN TRACEPOINT ===";
+ qDebug() << "name:" << t.name;
+ qDebug() << "ARGS\n";
+
+ int j = 0;
+
+ for (auto i = t.args.constBegin(); i != t.args.constEnd(); ++i) {
+ qDebug() << "ARG[" << j << "] type:" << i->type;
+ qDebug() << "ARG[" << j << "] name:" << i->name;
+ qDebug() << "ARG[" << j << "] arrayLen:" << i->arrayLen;
+ ++j;
+ }
+
+ qDebug() << "\nFIELDS\n";
+
+ j = 0;
+
+ for (auto i = t.fields.constBegin(); i != t.fields.constEnd(); ++i) {
+ qDebug() << "FIELD[" << j << "] backend_type" << static_cast<int>(i->backendType);
+ qDebug() << "FIELD[" << j << "] param_type" << i->paramType;
+ qDebug() << "FIELD[" << j << "] name" << i->name;
+ qDebug() << "FIELD[" << j << "] arrayLen" << i->arrayLen;
+ qDebug() << "FIELD[" << j << "] seqLen" << i->seqLen;
+ ++j;
+ }
+
+ qDebug() << "=== END TRACEPOINT ===\n";
+
+}
+#endif
+
+static inline int arrayLength(const QString &rawType)
+{
+ /* matches the length of an ordinary array type
+ * Ex: foo[10] yields '10'
+ */
+ static const QRegExp rx(QStringLiteral(".*\\[([0-9]+)\\].*"));
+
+ if (!rx.exactMatch(rawType.trimmed()))
+ return 0;
+
+ return rx.cap(1).toInt();
+}
+
+static inline QString sequenceLength(const QString &rawType)
+{
+ /* matches the identifier pointing to length of a CTF sequence type, which is
+ * a dynamic sized array.
+ * Ex: in qcoreapplication_foo(const char[len], some_string, unsigned int, * len)
+ * it will match the 'len' part of 'const char[len]')
+ */
+ static const QRegExp rx(QStringLiteral(".*\\[([A-Za-z_][A-Za-z_0-9]*)\\].*"));
+
+ if (!rx.exactMatch(rawType.trimmed()))
+ return QString();
+
+ return rx.cap(1);
+}
+
+static QString decayArrayToPointer(QString type)
+{
+ /* decays an array to a pointer, i.e., if 'type' holds int[10],
+ * this function returns 'int *'
+ */
+ static QRegExp rx(QStringLiteral("\\[(.+)\\]"));
+
+ rx.setMinimal(true);
+ return type.replace(rx, QStringLiteral("*"));
+}
+
+static QString removeBraces(QString type)
+{
+ static const QRegExp rx(QStringLiteral("\\[.*\\]"));
+
+ return type.remove(rx);
+}
+
+static Tracepoint::Field::BackendType backendType(QString rawType)
+{
+ static const struct {
+ const char *type;
+ Tracepoint::Field::BackendType 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 },
+ { "float", Tracepoint::Field::Float },
+ { "double", Tracepoint::Field::Float },
+ { "long_double", Tracepoint::Field::Float },
+ { "char_ptr", Tracepoint::Field::String },
+ { "QString", Tracepoint::Field::QtString },
+ { "QByteArray", Tracepoint::Field::QtByteArray },
+ { "QUrl", Tracepoint::Field::QtUrl },
+ { "QRect", Tracepoint::Field::QtRect }
+ };
+
+ auto backendType = [](const QString &rawType) {
+
+ static const size_t tableSize = sizeof (typeTable) / sizeof (typeTable[0]);
+
+ for (size_t i = 0; i < tableSize; ++i) {
+ if (rawType == QLatin1String(typeTable[i].type))
+ return typeTable[i].backendType;
+ }
+
+ return Tracepoint::Field::Unknown;
+ };
+
+ if (arrayLength(rawType) > 0)
+ return Tracepoint::Field::Array;
+
+ if (!sequenceLength(rawType).isNull())
+ return Tracepoint::Field::Sequence;
+
+ static const QRegExp constMatch(QStringLiteral("\\bconst\\b"));
+ rawType.remove(constMatch);
+ rawType.remove(QLatin1Char('&'));
+
+ static const QRegExp ptrMatch(QStringLiteral("\\s*\\*\\s*"));
+ rawType.replace(ptrMatch, QStringLiteral("_ptr"));
+ rawType = rawType.trimmed();
+ rawType.replace(QStringLiteral(" "), QStringLiteral("_"));
+
+ return backendType(rawType.trimmed());
+}
+
+static Tracepoint parseTracepoint(const QString &name, const QStringList &args,
+ const QString &fileName, const int lineNumber)
+{
+ Tracepoint t;
+ t.name = name;
+
+ if (args.isEmpty())
+ return t;
+
+ auto i = args.constBegin();
+ auto end = args.constEnd();
+ int argc = 0;
+
+ static const QRegExp rx(QStringLiteral("(.*)\\b([A-Za-z_][A-Za-z0-9_]*)$"));
+
+ while (i != end) {
+ rx.exactMatch(*i);
+
+ const QString type = rx.cap(1).trimmed();
+
+ if (type.isNull()) {
+ panic("Missing parameter type for argument %d of %s (%s:%d)",
+ argc, qPrintable(name), qPrintable(fileName), lineNumber);
+ }
+
+ const QString name = rx.cap(2).trimmed();
+
+ if (name.isNull()) {
+ panic("Missing parameter name for argument %d of %s (%s:%d)",
+ argc, qPrintable(name), qPrintable(fileName), lineNumber);
+ }
+
+ int arrayLen = arrayLength(type);
+
+ Tracepoint::Argument a;
+ a.arrayLen = arrayLen;
+ a.name = name;
+ a.type = decayArrayToPointer(type);
+
+ 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);
+
+ t.fields << std::move(f);
+
+ ++i;
+ }
+
+ return t;
+}
+
+Provider parseProvider(const QString &filename)
+{
+ QFile f(filename);
+
+ if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
+ panic("Cannot open %s: %s", qPrintable(filename), qPrintable(f.errorString()));
+
+ QTextStream s(&f);
+
+ static const QRegExp tracedef(QStringLiteral("([A-Za-z][A-Za-z0-9_]*)\\((.*)\\)"));
+
+ int lineNumber = 0;
+
+ Provider provider;
+ provider.name = QFileInfo(filename).baseName();
+
+ for (;;) {
+ QString line = s.readLine().trimmed();
+
+ if (line.isNull())
+ break;
+
+ if (line.isEmpty() || line.startsWith(QStringLiteral("#"))) {
+ ++lineNumber;
+ continue;
+ }
+
+ if (tracedef.exactMatch(line)) {
+ const QString name = tracedef.cap(1);
+ QStringList args = tracedef.cap(2).split(QStringLiteral(","), QString::SkipEmptyParts);
+
+ if (args.at(0).isNull())
+ args.clear();
+
+ provider.tracepoints << parseTracepoint(name, args, filename, lineNumber);
+ } else {
+ panic("Syntax error whilre processing %s on line %d", qPrintable(filename), lineNumber);
+ }
+
+ ++lineNumber;
+ }
+
+#ifdef TRACEGEN_DEBUG
+ for (auto i = provider.tracepoints.constBegin(); i != provider.tracepoints.constEnd(); ++i)
+ dumpTracepoint(*i);
+#endif
+
+ return provider;
+}