summaryrefslogtreecommitdiffstats
path: root/src/tools/tracepointgen
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/tracepointgen')
-rw-r--r--src/tools/tracepointgen/CMakeLists.txt17
-rw-r--r--src/tools/tracepointgen/parser.cpp609
-rw-r--r--src/tools/tracepointgen/parser.h77
-rw-r--r--src/tools/tracepointgen/tracepointgen.cpp69
-rw-r--r--src/tools/tracepointgen/tracepointgen.h42
5 files changed, 814 insertions, 0 deletions
diff --git a/src/tools/tracepointgen/CMakeLists.txt b/src/tools/tracepointgen/CMakeLists.txt
new file mode 100644
index 0000000000..2f473d376a
--- /dev/null
+++ b/src/tools/tracepointgen/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tracepointgen Tool:
+#####################################################################
+
+qt_get_tool_target_name(target_name tracepointgen)
+qt_internal_add_tool(${target_name}
+ CORE_LIBRARY Bootstrap
+ INSTALL_DIR "${INSTALL_LIBEXECDIR}"
+ TOOLS_TARGET Core
+ SOURCES
+ tracepointgen.cpp tracepointgen.h
+ parser.cpp parser.h
+)
+qt_internal_return_unless_building_tools()
diff --git a/src/tools/tracepointgen/parser.cpp b/src/tools/tracepointgen/parser.cpp
new file mode 100644
index 0000000000..ad94b9a433
--- /dev/null
+++ b/src/tools/tracepointgen/parser.cpp
@@ -0,0 +1,609 @@
+// 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 "tracepointgen.h"
+#include "parser.h"
+#include <qtextstream.h>
+#include <qregularexpression.h>
+#include <qfileinfo.h>
+
+static void removeOffsetRange(qsizetype begin, qsizetype end, QList<LineNumber> &offsets)
+{
+ qsizetype count = end - begin;
+ qsizetype i = 0;
+ DEBUGPRINTF2(printf("tracepointgen: removeOffsetRange: %llu %llu\n", begin, end));
+ while (i < offsets.size()) {
+ LineNumber &cur = offsets[i];
+ if (begin > cur.end) {
+ i++;
+ } else if (begin >= cur.begin && begin <= cur.end) {
+ cur.end = begin;
+ i++;
+ } else if (begin < cur.begin && end > cur.end) {
+ offsets.remove(i);
+ DEBUGPRINTF2(printf("tracepointgen: removeOffsetRange: %llu, %llu, %d\n", cur.begin, cur.end, cur.line));
+ } else if (end >= cur.begin && end <= cur.end) {
+ cur.begin = begin;
+ cur.end -= count;
+ i++;
+ } else if (end < cur.begin) {
+ cur.begin -= count;
+ cur.end -= count;
+ i++;
+ }
+ }
+}
+
+static bool findSpaceRange(const QString &data, qsizetype &offset, qsizetype &end) {
+ qsizetype cur = data.indexOf(QLatin1Char(' '), offset);
+ if (cur >= 0) {
+ qsizetype i = cur + 1;
+ while (data.constData()[i] == QLatin1Char(' ')) i++;
+ if (i - cur > 1) {
+ offset = cur;
+ end = i - 1;
+ return true;
+ }
+ cur = data.indexOf(QLatin1Char(' '), cur + 1);
+ }
+ return false;
+}
+
+static void simplifyData(QString &data, QList<LineNumber> &offsets)
+{
+ qsizetype offset = data.indexOf(QStringLiteral("//"));
+ while (offset >= 0) {
+ qsizetype endOfLine = data.indexOf(QLatin1Char('\n'), offset);
+ if (endOfLine == -1)
+ endOfLine = data.length();
+ removeOffsetRange(offset, endOfLine, offsets);
+ data.remove(offset, endOfLine - offset);
+ offset = data.indexOf(QStringLiteral("//"), offset);
+ }
+ offset = data.indexOf(QStringLiteral("/*"));
+ while (offset >= 0) {
+ qsizetype endOfComment = data.indexOf(QStringLiteral("*/"), offset);
+ if (endOfComment == -1)
+ break;
+ removeOffsetRange(offset, endOfComment + 2, offsets);
+ data.remove(offset, endOfComment - offset + 2);
+ offset = data.indexOf(QStringLiteral("/*"), offset);
+ }
+ offset = 0;
+ qsizetype end = 0;
+ data.replace(QLatin1Char('\n'), QLatin1Char(' '));
+ while (findSpaceRange(data, offset, end)) {
+ removeOffsetRange(offset, end, offsets);
+ data.remove(offset, end - offset);
+ }
+}
+
+static void simplifyData(QString &data)
+{
+ qsizetype offset = data.indexOf(QStringLiteral("//"));
+ while (offset >= 0) {
+ qsizetype endOfLine = data.indexOf(QLatin1Char('\n'), offset);
+ if (endOfLine == -1)
+ endOfLine = data.length();
+ data.remove(offset, endOfLine - offset);
+ offset = data.indexOf(QStringLiteral("//"), offset);
+ }
+ offset = data.indexOf(QStringLiteral("/*"));
+ while (offset >= 0) {
+ qsizetype endOfComment = data.indexOf(QStringLiteral("*/"), offset);
+ if (endOfComment == -1)
+ break;
+ data.remove(offset, endOfComment - offset + 2);
+ offset = data.indexOf(QStringLiteral("/*"), offset);
+ }
+ offset = 0;
+ qsizetype end = 0;
+ while (findSpaceRange(data, offset, end))
+ data.remove(offset, end - offset);
+}
+
+static QString preprocessMetadata(const QString &in)
+{
+ DEBUGPRINTF(printf("in: %s\n", qPrintable(in)));
+ QList<QString> lines = in.split(QLatin1Char('\\'));
+ QString out;
+ for (int i = 0; i < lines.size(); i++) {
+ QString l = lines.at(i).simplified();
+ DEBUGPRINTF(printf("line: %s\n", qPrintable(l)));
+ if (l.length() < 2)
+ continue;
+ if (l.startsWith(QStringLiteral("\"")))
+ l = l.right(l.length() - 1);
+ if (l.endsWith(QStringLiteral("\"")))
+ l = l.left(l.length() - 1);
+ l = l.simplified();
+
+ if (l.length() > 1) {
+ if (out.size() > 0)
+ out.append(QLatin1Char('\n'));
+ out.append(l);
+ }
+ }
+ DEBUGPRINTF(printf("out: %s\n", qPrintable(out)));
+ return out;
+}
+
+int Parser::lineNumber(qsizetype offset) const
+{
+ DEBUGPRINTF(printf("tracepointgen: lineNumber: offset %llu, line count: %llu\n", offset , m_offsets.size()));
+ for (const auto line : m_offsets) {
+ DEBUGPRINTF(printf("tracepointgen: lineNumber: %llu %llu %d\n", line.begin, line.end, line.line));
+ if (offset >= line.begin && offset <= line.end)
+ return line.line;
+ }
+ return 0;
+}
+
+void Parser::parseParamReplace(const QString &data, qsizetype offset, const QString &name)
+{
+ Replace rep;
+ qsizetype beginBrace = data.indexOf(QLatin1Char('('), offset);
+ qsizetype endBrace = data.indexOf(QLatin1Char(')'), beginBrace);
+ QString params = data.mid(beginBrace + 1, endBrace - beginBrace -1);
+ int punc = params.indexOf(QLatin1Char(','));
+ if (punc < 0)
+ panic("Syntax error in Q_TRACE_PARAM_REPLACE at file %s, line %llu", qPrintable(name), lineNumber(offset));
+ rep.in = params.left(punc).simplified();
+ rep.out = params.right(params.length() - punc - 1).simplified();
+ if (rep.in.endsWith(QLatin1Char('*')) || rep.out.endsWith(QLatin1Char(']')))
+ rep.out.append(QLatin1Char(' '));
+ DEBUGPRINTF(printf("tracepointgen: replace: %s with %s\n", qPrintable(rep.in), qPrintable(rep.out)));
+ m_replaces.push_back(rep);
+}
+
+void Parser::parseInstrument(const QString &data, qsizetype offset)
+{
+ qsizetype beginOfProvider = data.indexOf(QLatin1Char('('), offset);
+ qsizetype endOfProvider = data.indexOf(QLatin1Char(')'), beginOfProvider);
+ Function func;
+ QString provider = data.mid(beginOfProvider + 1, endOfProvider - beginOfProvider - 1).simplified();
+ if (provider != m_provider)
+ return;
+
+ qsizetype classMarker = data.indexOf(QStringLiteral("::"), endOfProvider);
+ qsizetype beginOfFunctionMarker = data.indexOf(QLatin1Char('{'), classMarker);
+ QString begin = data.mid(endOfProvider + 1, classMarker - endOfProvider - 1);
+ QString end = data.mid(classMarker + 2, beginOfFunctionMarker - classMarker - 2);
+ int spaceIndex = begin.lastIndexOf(QLatin1Char(' '));
+ if (spaceIndex == -1)
+ func.className = begin;
+ else
+ func.className = begin.mid(spaceIndex + 1, begin.length() - spaceIndex - 1);
+ qsizetype braceIndex = end.indexOf(QLatin1Char('('));
+ spaceIndex = end.indexOf(QLatin1Char(' '));
+ if (spaceIndex < braceIndex)
+ func.functionName = end.left(spaceIndex).simplified();
+ else
+ func.functionName = end.left(braceIndex).simplified();
+
+ qsizetype lastBraceIndex = end.lastIndexOf(QLatin1Char(')'));
+ func.functionParameters = end.mid(braceIndex + 1, lastBraceIndex - braceIndex - 1).simplified();
+
+ DEBUGPRINTF(printf("tracepointgen: %s(%s)\n", qPrintable(func.functionName), qPrintable(func.functionParameters)));
+
+ m_functions.push_back(func);
+}
+
+void Parser::parsePoint(const QString &data, qsizetype offset)
+{
+ qsizetype beginOfProvider = data.indexOf(QLatin1Char('('), offset);
+ qsizetype endOfProvider = data.indexOf(QLatin1Char(','), beginOfProvider);
+ Point point;
+ QString provider = data.mid(beginOfProvider + 1, endOfProvider - beginOfProvider - 1).simplified();
+ if (provider != m_provider)
+ return;
+
+ qsizetype endOfPoint = data.indexOf(QLatin1Char(','), endOfProvider + 1);
+ qsizetype endOfPoint2 = data.indexOf(QLatin1Char(')'), endOfProvider + 1);
+ bool params = true;
+ if (endOfPoint == -1 || endOfPoint2 < endOfPoint) {
+ endOfPoint = endOfPoint2;
+ params = false;
+ }
+ point.name = data.mid(endOfProvider + 1, endOfPoint - endOfProvider - 1).simplified();
+ if (params) {
+ int endOfParams = data.indexOf(QLatin1Char(')'), endOfPoint);
+ point.parameters = data.mid(endOfPoint + 1, endOfParams - endOfPoint - 1).simplified();
+ }
+
+ DEBUGPRINTF(printf("tracepointgen: %s(%s)\n", qPrintable(point.name), qPrintable(point.parameters)));
+
+ m_points.push_back(point);
+}
+
+void Parser::parsePrefix(const QString &data, qsizetype offset)
+{
+ qsizetype beginOfProvider = data.indexOf(QLatin1Char('('), offset);
+ qsizetype endOfProvider = data.indexOf(QLatin1Char(','), beginOfProvider);
+ QString prefix;
+ QString provider = data.mid(beginOfProvider + 1, endOfProvider - beginOfProvider - 1).simplified();
+ if (provider != m_provider)
+ return;
+
+ qsizetype endOfPoint = data.indexOf(QLatin1Char(')'), endOfProvider + 1);
+ prefix = data.mid(endOfProvider + 1, endOfPoint - endOfProvider - 1).simplified();
+
+ DEBUGPRINTF(printf("tracepointgen: prefix: %s\n", qPrintable(prefix)));
+
+ if (!m_prefixes.contains(prefix))
+ m_prefixes.push_back(preprocessMetadata(prefix));
+}
+
+QStringList Parser::findEnumValues(const QString &name, const QStringList &includes)
+{
+ QStringList split = name.split(QStringLiteral("::"));
+ QString enumName = split.last();
+ DEBUGPRINTF(printf("searching for %s\n", qPrintable(name)));
+ QStringList ret;
+ for (const QString &filename : includes) {
+ QFile input(filename);
+ if (!input.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ DEBUGPRINTF(printf("Cannot open '%s' for reading: %s\n",
+ qPrintable(filename), qPrintable(input.errorString())));
+ return ret;
+ }
+ QString data;
+ QTextStream stream(&input);
+ while (!stream.atEnd()) {
+ QString line = stream.readLine().trimmed();
+ data += line + QLatin1Char('\n');
+ }
+ simplifyData(data);
+
+ int pos = 0;
+ bool valid = true;
+ for (int i = 0; i < split.size() - 1; i++) {
+ QRegularExpression macro(QStringLiteral("(struct|class|namespace) +([A-Za-z0-9_]*)? +([A-Za-z0-9]*;?)"));
+ QRegularExpressionMatchIterator m = macro.globalMatch(data);
+ bool found = false;
+ while (m.hasNext() && !found) {
+ QRegularExpressionMatch match = m.next();
+ QString n = match.captured(2);
+ if (!n.endsWith(QLatin1Char(';')) && n == split[i] && match.capturedStart(2) > pos) {
+ pos = match.capturedStart(2);
+ found = true;
+ break;
+ }
+ if (match.hasCaptured(3)) {
+ n = match.captured(3);
+ if (!n.endsWith(QLatin1Char(';')) && n == split[i] && match.capturedStart(3) > pos) {
+ pos = match.capturedStart(3);
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ valid = false;
+ break;
+ }
+ }
+
+ if (valid) {
+ QRegularExpression macro(QStringLiteral("enum +([A-Za-z0-9_]*)"));
+ QRegularExpressionMatchIterator m = macro.globalMatch(data);
+ while (m.hasNext()) {
+ QRegularExpressionMatch match = m.next();
+
+ if (match.capturedStart() < pos)
+ continue;
+
+ QString n = match.captured(1);
+
+ if (n == enumName) {
+ DEBUGPRINTF(printf("Found enum: %s\n", qPrintable(n)));
+ int begin = data.indexOf(QLatin1Char('{'), match.capturedEnd());
+ int end = data.indexOf(QLatin1Char('}'), begin);
+ QString block = data.mid(begin + 1, end - begin - 1);
+ const QStringList enums = block.split(QLatin1Char('\n'));
+ for (const auto &e : enums) {
+ const auto trimmed = e.trimmed();
+ if (!trimmed.isEmpty() && !trimmed.startsWith(QLatin1Char('#')))
+ ret << trimmed;
+ }
+
+ return ret;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+struct EnumNameValue
+{
+ QString name;
+ QString valueStr;
+ int value;
+};
+
+static QList<EnumNameValue> enumsToValues(const QStringList &values)
+{
+ int cur = 0;
+ QList<EnumNameValue> ret;
+ for (const QString &value : values) {
+ EnumNameValue r;
+ if (value.contains(QLatin1Char('='))) {
+ size_t offset = value.indexOf(QLatin1Char('='));
+ r.name = value.left(offset).trimmed();
+ QString val = value.right(value.length() - offset - 1).trimmed();
+ if (val.endsWith(QLatin1Char(',')))
+ val = val.left(val.length() - 1);
+ bool valid = false;
+ int integer = val.toInt(&valid);
+ if (!valid)
+ integer = val.toInt(&valid, 16);
+ if (valid) {
+ cur = r.value = integer;
+ ret << r;
+ } else {
+ auto iter = std::find_if(ret.begin(), ret.end(), [&val](const EnumNameValue &elem){
+ return elem.name == val;
+ });
+ if (iter != ret.end()) {
+ cur = r.value = iter->value;
+ ret << r;
+ } else {
+ DEBUGPRINTF(printf("Invalid value: %s %s\n", qPrintable(r.name), qPrintable(value)));
+ }
+ }
+ } else {
+ if (value.endsWith(QLatin1Char(',')))
+ r.name = value.left(value.length() - 1);
+ else
+ r.name = value;
+ r.value = ++cur;
+ ret << r;
+ }
+ }
+ return ret;
+}
+
+void Parser::parseMetadata(const QString &data, qsizetype offset, const QStringList &includes)
+{
+ 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)));
+
+ QString preprocessed = preprocessMetadata(metadata);
+
+ DEBUGPRINTF2(printf("preprocessed %s\n", qPrintable(preprocessed)));
+
+ QRegularExpression macro(QStringLiteral("([A-Z]*) ?{ ?([A-Za-z0-9=_,. ]*) ?} ?([A-Za-z0-9_:]*) ?;"));
+ QRegularExpressionMatchIterator i = macro.globalMatch(preprocessed);
+ qsizetype prev = 0;
+ while (i.hasNext()) {
+ QRegularExpressionMatch match = i.next();
+ QString values = match.captured(2).trimmed();
+ int cur = match.capturedStart();
+ if (cur > prev)
+ m_metadata.append(preprocessed.mid(prev, cur - prev));
+
+ prev = match.capturedEnd() + 1;
+ DEBUGPRINTF2(printf("values: %s\n", qPrintable(values)));
+ if (values.isEmpty() || values.startsWith(QStringLiteral("AUTO"))) {
+ values.replace(QLatin1Char('\n'), QLatin1Char(' '));
+ QStringList ranges;
+ if (values.contains(QStringLiteral("RANGE"))) {
+ QRegularExpression rangeMacro(QStringLiteral("RANGE +([A-Za-z0-9_]*) +... +([A-Za-z0-9_]*)"));
+ QRegularExpressionMatchIterator r = rangeMacro.globalMatch(values);
+ while (r.hasNext()) {
+ QRegularExpressionMatch rm = r.next();
+ ranges << rm.captured(1);
+ ranges << rm.captured(2);
+ DEBUGPRINTF2(printf("range: %s ... %s\n", qPrintable(rm.captured(1)), qPrintable(rm.captured(2))));
+ }
+ }
+
+ const auto enumOrFlag = match.captured(1);
+ const auto name = match.captured(3);
+ const bool flags = enumOrFlag == QStringLiteral("FLAGS");
+
+ QStringList values = findEnumValues(name, includes);
+ if (values.isEmpty()) {
+ if (flags && name.endsWith(QLatin1Char('s')))
+ values = findEnumValues(name.left(name.length() - 1), includes);
+ if (values.isEmpty()) {
+ DEBUGPRINTF(printf("Unable to find values for %s\n", qPrintable(name)));
+ }
+ }
+ if (!values.isEmpty()) {
+ auto moreValues = enumsToValues(values);
+ if (ranges.size()) {
+ for (int i = 0; i < ranges.size() / 2; i++) {
+ bool rangeFound = false;
+ for (auto &v : moreValues) {
+ if (v.name == ranges[2 * i]) {
+ rangeFound = true;
+ QString rangeEnd = ranges[2 * i + 1];
+ auto iter = std::find_if(moreValues.begin(), moreValues.end(), [&rangeEnd](const EnumNameValue &elem){
+ return elem.name == rangeEnd;
+ });
+ if (iter != moreValues.end())
+ v.valueStr = QStringLiteral("RANGE(%1, %2 ... %3)").arg(v.name).arg(v.value).arg(iter->value);
+ else
+ panic("Unable to find range end: %s\n", qPrintable(rangeEnd));
+ break;
+ }
+ }
+ if (rangeFound == false)
+ panic("Unable to find range begin: %s\n", qPrintable(ranges[2 * i]));
+ }
+ }
+ std::sort(moreValues.begin(), moreValues.end(), [](const EnumNameValue &a, const EnumNameValue &b) {
+ return a.value < b.value;
+ });
+ values.clear();
+ int prevValue = std::as_const(moreValues).front().value;
+ for (const auto &v : std::as_const(moreValues)) {
+ QString a;
+ if (v.valueStr.isNull()) {
+ if (v.value == prevValue + 1 && !flags)
+ a = v.name;
+ else
+ a = QStringLiteral("%1 = %2").arg(v.name).arg(v.value);
+ prevValue = v.value;
+ } else {
+ a = v.valueStr;
+ }
+ values << a;
+ }
+
+ metadata = QStringLiteral("%1 {\n %2 \n} %3;").arg(enumOrFlag).arg(values.join(QStringLiteral(",\n"))).arg(name);
+ if (!m_metadata.contains(metadata))
+ m_metadata.append(metadata);
+ }
+ } else {
+ if (!m_metadata.contains(match.captured()))
+ m_metadata.append(match.captured());
+ }
+ }
+ if (prev < preprocessed.length())
+ m_metadata.append(preprocessed.mid(prev, preprocessed.length() - prev));
+}
+
+QString Parser::resolveInclude(const QString &filename)
+{
+ QFileInfo info(filename);
+ if (info.exists())
+ return info.absoluteFilePath();
+ for (const QString &sp : std::as_const(m_includeDirs)) {
+ info = QFileInfo(sp + QLatin1Char('/') + filename);
+ if (info.exists())
+ return info.absoluteFilePath();
+ }
+ return {};
+}
+
+void Parser::addIncludesRecursive(const QString &filename, QList<QString> &includes)
+{
+ QFileInfo info(filename);
+ DEBUGPRINTF(printf("check include: %s\n", qPrintable(filename)));
+ QFile input(filename);
+ if (!input.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ DEBUGPRINTF(printf("Cannot open '%s' for reading: %s\n",
+ qPrintable(filename), qPrintable(input.errorString())));
+ return;
+ }
+ QString data;
+ QTextStream stream(&input);
+ while (!stream.atEnd()) {
+ QString line = stream.readLine().trimmed();
+ data += line + QLatin1Char(QLatin1Char('\n'));
+ }
+
+ QRegularExpression includeMacro(QStringLiteral("#include [\"<]([A-Za-z0-9_./]*.h)[\">]"));
+ QRegularExpressionMatchIterator i = includeMacro.globalMatch(data);
+ while (i.hasNext()) {
+ QRegularExpressionMatch match = i.next();
+ QString filename = match.captured(1);
+
+ QString rinc = filename;
+ if (filename.startsWith(QStringLiteral("../"))) {
+ QFileInfo info2(info.absolutePath() + QLatin1Char('/') + filename);
+ if (!info2.exists()) {
+ DEBUGPRINTF(printf("unable to find %s\n", qPrintable(filename)));
+ continue;
+ }
+ rinc = info2.absoluteFilePath();
+ filename = info2.fileName();
+ }
+
+ // only search possible qt headers
+ if (filename.startsWith(QLatin1Char('q'), Qt::CaseInsensitive)) {
+ QString resolved = resolveInclude(rinc);
+ if (!resolved.isEmpty() && !includes.contains(resolved)) {
+ includes.push_back(resolved);
+ addIncludesRecursive(resolved, includes);
+ }
+ }
+ }
+}
+
+void Parser::parse(QIODevice &input, const QString &name)
+{
+ QString data;
+ QTextStream stream(&input);
+ int lineNumber = 1;
+ qsizetype prev = 0;
+ while (!stream.atEnd()) {
+ QString line = stream.readLine().trimmed();
+ m_offsets.push_back({prev, prev + line.length(), lineNumber++});
+ prev += line.length() + 1;
+ data += line + QLatin1Char(QLatin1Char('\n'));
+ }
+
+ simplifyData(data, m_offsets);
+
+ QStringList includes;
+
+ QRegularExpression includeMacro(QStringLiteral("#include [\"<]([A-Za-z0-9_./]*.h)[\">]"));
+ QRegularExpressionMatchIterator i = includeMacro.globalMatch(data);
+ while (i.hasNext()) {
+ QRegularExpressionMatch match = i.next();
+ const QString filename = match.captured(1);
+ // only search possible qt headers
+ if (filename.startsWith(QLatin1Char('q'), Qt::CaseInsensitive)) {
+ const QString resolved = resolveInclude(filename);
+ if (!resolved.isEmpty() && !includes.contains(resolved)) {
+ includes.push_back(resolved);
+ addIncludesRecursive(resolved, includes);
+ }
+ }
+ }
+
+ QRegularExpression traceMacro(QStringLiteral("Q_TRACE_([A-Z_]*)"));
+ i = traceMacro.globalMatch(data);
+ while (i.hasNext()) {
+ QRegularExpressionMatch match = i.next();
+
+ QString macroType = match.captured(1);
+ if (macroType == QStringLiteral("PARAM_REPLACE"))
+ parseParamReplace(data, match.capturedEnd(), name);
+ else if (macroType == QStringLiteral("INSTRUMENT"))
+ parseInstrument(data, match.capturedEnd());
+ else if (macroType == QStringLiteral("POINT"))
+ parsePoint(data, match.capturedEnd());
+ else if (macroType == QStringLiteral("PREFIX"))
+ parsePrefix(data, match.capturedEnd());
+ else if (macroType == QStringLiteral("METADATA"))
+ parseMetadata(data, match.capturedEnd(), includes);
+ }
+
+ for (auto &func : m_functions) {
+ for (auto &rep : m_replaces)
+ func.functionParameters.replace(rep.in, rep.out);
+ }
+}
+
+void Parser::write(QIODevice &input) const
+{
+ QTextStream out(&input);
+ if (m_prefixes.size() > 0) {
+ out << QStringLiteral("{\n");
+ for (const auto &prefix : m_prefixes)
+ out << prefix << "\n";
+ out << QStringLiteral("}\n");
+ }
+ for (const auto &m : m_metadata)
+ out << m << "\n";
+ for (const auto &func : m_functions) {
+ out << func.className << "_" << func.functionName << "_entry(" << func.functionParameters << ")\n";
+ out << func.className << "_" << func.functionName << "_exit()\n";
+ }
+ for (const auto &point : m_points)
+ out << point.name << "(" << point.parameters << ")\n";
+}
diff --git a/src/tools/tracepointgen/parser.h b/src/tools/tracepointgen/parser.h
new file mode 100644
index 0000000000..389734983d
--- /dev/null
+++ b/src/tools/tracepointgen/parser.h
@@ -0,0 +1,77 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef PARSER_H
+#define PARSER_H
+
+#include <qiodevice.h>
+#include <qlist.h>
+#include <qbytearray.h>
+
+struct Function
+{
+ QString className;
+ QString functionName;
+ QString functionParameters;
+};
+
+struct Point
+{
+ QString name;
+ QString parameters;
+};
+
+struct Replace
+{
+ QString in;
+ QString out;
+};
+
+struct LineNumber
+{
+ qsizetype begin;
+ qsizetype end;
+ int line;
+};
+
+struct Parser
+{
+ Parser(const QString &provider)
+ : m_provider(provider)
+ {
+
+ }
+
+ void addIncludeDirs(const QStringList &list)
+ {
+ m_includeDirs.append(list);
+ }
+ QString resolveInclude(const QString &filename);
+ void addIncludesRecursive(const QString &filename, QStringList &includes);
+ QStringList findEnumValues(const QString &name, const QStringList &includes);
+
+ 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, const QStringList &includes);
+ int lineNumber(qsizetype offset) const;
+
+ void parse(QIODevice &input, const QString &name);
+ void write(QIODevice &input) const;
+ bool isEmpty() const
+ {
+ return m_functions.isEmpty() && m_points.isEmpty();
+ }
+
+ QList<Function> m_functions;
+ QList<Point> m_points;
+ QList<Replace> m_replaces;
+ QList<QString> m_prefixes;
+ QList<QString> m_metadata;
+ QList<LineNumber> m_offsets;
+ QList<QString> m_includeDirs;
+ QString m_provider;
+};
+
+#endif // PARSER_H
diff --git a/src/tools/tracepointgen/tracepointgen.cpp b/src/tools/tracepointgen/tracepointgen.cpp
new file mode 100644
index 0000000000..d814c69873
--- /dev/null
+++ b/src/tools/tracepointgen/tracepointgen.cpp
@@ -0,0 +1,69 @@
+// 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 <qstring.h>
+#include <qstringlist.h>
+#include <qfile.h>
+
+#include "tracepointgen.h"
+#include "parser.h"
+
+static void usage(int status)
+{
+ printf("Generates a tracepoint file for tracegen tool from input files.\n\n");
+ printf("Usage: tracepointgen <output file> <input files> \n");
+ exit(status);
+}
+
+static void parseArgs(int argc, char *argv[], QString &provider, QString &outFile, QList<QString> &inputFiles)
+{
+ if (argc == 1)
+ usage(0);
+ if (argc < 4)
+ usage(-1);
+
+ provider = QLatin1StringView(argv[1]);
+ outFile = QLatin1StringView(argv[2]);
+ for (int i = 3; i < argc; i++)
+ inputFiles.append(QLatin1StringView(argv[i]));
+}
+
+int main(int argc, char *argv[])
+{
+ QString provider;
+ QList<QString> inputFiles;
+ QString outFile;
+
+ parseArgs(argc, argv, provider, outFile, inputFiles);
+
+ Parser parser(provider);
+
+ for (const QString &inputFile : inputFiles) {
+ if (inputFile.startsWith(QLatin1Char('I'))) {
+ QStringList includeDirs = inputFile.right(inputFile.length() - 1).split(QLatin1Char(';'));
+ parser.addIncludeDirs(includeDirs);
+ continue;
+ }
+ QFile in(inputFile);
+ if (!in.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ panic("Cannot open '%s' for reading: %s\n",
+ qPrintable(inputFile), qPrintable(in.errorString()));
+ }
+ DEBUGPRINTF(printf("tracepointgen: parse %s\n", qPrintable(inputFile)));
+ parser.parse(in, inputFile);
+ }
+ if (parser.isEmpty())
+ panic("empty provider %s\n", qPrintable(provider));
+
+ QFile out(outFile);
+
+ if (!out.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ panic("Cannot open '%s' for writing: %s\n",
+ qPrintable(outFile), qPrintable(out.errorString()));
+ }
+
+ parser.write(out);
+ out.close();
+
+ return 0;
+}
diff --git a/src/tools/tracepointgen/tracepointgen.h b/src/tools/tracepointgen/tracepointgen.h
new file mode 100644
index 0000000000..6aed3dc574
--- /dev/null
+++ b/src/tools/tracepointgen/tracepointgen.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TRACEPOINTGEN_H
+#define TRACEPOINTGEN_H
+
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+
+#define DEBUG_TRACEPOINTGEN 0
+
+#if DEBUG_TRACEPOINTGEN > 0
+ #define DEBUGPRINTF(x) x
+ #if (DEBUG_TRACEPOINTGEN > 1)
+ #define DEBUGPRINTF2(x) x
+ #else
+ #define DEBUGPRINTF2(x)
+ #endif
+#else
+ #define DEBUGPRINTF(x)
+ #define DEBUGPRINTF2(x)
+#endif
+
+
+
+inline void panic(const char *fmt, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "tracepointgen: fatal: ");
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ fputc('\n', stderr);
+
+ exit(EXIT_FAILURE);
+}
+
+#endif