Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
provider.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "provider.h"
5#include "panic.h"
6
7#include <qfile.h>
8#include <qfileinfo.h>
9#include <qtextstream.h>
10#include <qregularexpression.h>
11#include <qstring.h>
13
14using namespace Qt::StringLiterals;
15
16#ifdef TRACEGEN_DEBUG
17#include <qdebug.h>
18
19static void dumpTracepoint(const Tracepoint &t)
20{
21 qDebug() << "=== BEGIN TRACEPOINT ===";
22 qDebug() << "name:" << t.name;
23 qDebug() << "ARGS\n";
24
25 int j = 0;
26
27 for (auto i = t.args.constBegin(); i != t.args.constEnd(); ++i) {
28 qDebug() << "ARG[" << j << "] type:" << i->type;
29 qDebug() << "ARG[" << j << "] name:" << i->name;
30 qDebug() << "ARG[" << j << "] arrayLen:" << i->arrayLen;
31 ++j;
32 }
33
34 qDebug() << "\nFIELDS\n";
35
36 j = 0;
37
38 for (auto i = t.fields.constBegin(); i != t.fields.constEnd(); ++i) {
39 qDebug() << "FIELD[" << j << "] backend_type" << static_cast<int>(i->backendType);
40 qDebug() << "FIELD[" << j << "] param_type" << i->paramType;
41 qDebug() << "FIELD[" << j << "] name" << i->name;
42 qDebug() << "FIELD[" << j << "] arrayLen" << i->arrayLen;
43 qDebug() << "FIELD[" << j << "] seqLen" << i->seqLen;
44 ++j;
45 }
46
47 qDebug() << "=== END TRACEPOINT ===\n";
48
49}
50#endif
51
52static inline int arrayLength(const QString &rawType)
53{
54 /* matches the length of an ordinary array type
55 * Ex: foo[10] yields '10'
56 */
57 static const QRegularExpression rx(QStringLiteral("\\[([0-9]+)\\]"));
58
59 auto match = rx.match(rawType);
60 if (!match.hasMatch())
61 return 0;
62
63 return match.captured(1).toInt();
64}
65
66static inline QString sequenceLength(const QString &rawType)
67{
68 /* matches the identifier pointing to length of a CTF sequence type, which is
69 * a dynamic sized array.
70 * Ex: in qcoreapplication_foo(const char[len], some_string, unsigned int, * len)
71 * it will match the 'len' part of 'const char[len]')
72 */
73 static const QRegularExpression rx(QStringLiteral("\\[([A-Za-z_][A-Za-z_0-9]*)\\]"));
74
75 auto match = rx.match(rawType);
76 if (!match.hasMatch())
77 return QString();
78
79 return match.captured(1);
80}
81
83{
84 /* decays an array to a pointer, i.e., if 'type' holds int[10],
85 * this function returns 'int *'
86 */
87 static QRegularExpression rx(QStringLiteral("\\[([^\\]]+)\\]"));
88
89 return type.replace(rx, QStringLiteral("*"));
90}
91
93{
94 static const QRegularExpression rx(QStringLiteral("\\[.*\\]"));
95
96 return type.remove(rx);
97}
98
99#define TYPEDATA_ENTRY(type, backendType) \
100{ QT_STRINGIFY(type), backendType }
101
103{
104 static const struct TypeData {
105 const char *type;
107 } typeTable[] = {
112 TYPEDATA_ENTRY(unsigned_short_int, Tracepoint::Field::Integer),
119 TYPEDATA_ENTRY(unsigned_long_int, Tracepoint::Field::Integer),
123 TYPEDATA_ENTRY(signed_long_long_int, Tracepoint::Field::Integer),
124 TYPEDATA_ENTRY(unsigned_long_long, Tracepoint::Field::Integer),
146 };
147
148 auto backendType = [](const QString &rawType) {
149 static const size_t tableSize = sizeof (typeTable) / sizeof (typeTable[0]);
150
151 for (size_t i = 0; i < tableSize; ++i) {
152 if (rawType == QLatin1StringView(typeTable[i].type))
153 return typeTable[i];
154 }
155
156 TypeData unknown = { nullptr, Tracepoint::Field::Unknown };
157 return unknown;
158 };
159
160 int arrayLen = arrayLength(rawType);
161 if (arrayLen > 0)
162 rawType = removeBraces(rawType);
163
164 if (!sequenceLength(rawType).isNull())
166
167 static const QRegularExpression constMatch(QStringLiteral("\\bconst\\b"));
168 rawType.remove(constMatch);
169 rawType.remove(u'&');
170
171 static const QRegularExpression ptrMatch(QStringLiteral("\\s*\\*\\s*"));
172 rawType.replace(ptrMatch, QStringLiteral("_ptr"));
173 rawType = rawType.trimmed();
174 rawType.replace(QStringLiteral(" "), QStringLiteral("_"));
175
176 if (rawType == "char_ptr"_L1)
178
179 if (rawType.endsWith("_ptr"_L1))
181
182 TypeData d = backendType(rawType);
183 return d.backendType;
184}
185
186static Tracepoint parseTracepoint(const Provider &provider, const QString &name, const QStringList &args,
187 const QString &fileName, const int lineNumber)
188{
190 t.name = name;
191
192 auto findEnumeration = [](const QList<TraceEnum> &enums, const QString &name) {
193 for (const auto &e : enums) {
194 if (e.name == name)
195 return e;
196 }
197 return TraceEnum();
198 };
199 auto findFlags = [](const QList<TraceFlags> &flags, const QString &name) {
200 for (const auto &f : flags) {
201 if (f.name == name)
202 return f;
203 }
204 return TraceFlags();
205 };
206
207
208 if (args.isEmpty())
209 return t;
210
211 auto i = args.constBegin();
212 auto end = args.constEnd();
213 int argc = 0;
214
215 static const QRegularExpression rx(QStringLiteral("^(.*)\\b([A-Za-z_][A-Za-z0-9_]*)$"));
216
217 while (i != end) {
218 auto match = rx.match(*i);
219
220 const QString type = match.captured(1).trimmed();
221
222 if (type.isNull()) {
223 panic("Missing parameter type for argument %d of %s (%s:%d)",
224 argc, qPrintable(name), qPrintable(fileName), lineNumber);
225 }
226
227 const QString name = match.captured(2).trimmed();
228
229 if (name.isNull()) {
230 panic("Missing parameter name for argument %d of %s (%s:%d)",
231 argc, qPrintable(name), qPrintable(fileName), lineNumber);
232 }
233
234 int arrayLen = arrayLength(type);
235
237 a.arrayLen = arrayLen;
238 a.name = name;
239 a.type = decayArrayToPointer(type);
240
241 t.args << std::move(a);
242
243 Tracepoint::Field field;
244 const TraceEnum &e = findEnumeration(provider.enumerations, type);
245 const TraceFlags &f = findFlags(provider.flags, type);
246 if (!e.name.isEmpty()) {
248 field.enumValueSize = e.valueSize;
249 } else if (!f.name.isEmpty()) {
251 } else {
253 }
254 field.paramType = removeBraces(type);
255 field.name = name;
256 field.arrayLen = arrayLen;
257 field.seqLen = sequenceLength(type);
258
259 t.fields << std::move(field);
260
261 ++i;
262 }
263
264 return t;
265}
266
267static int minumumValueSize(int min, int max)
268{
269 if (min < 0) {
270 if (min >= std::numeric_limits<char>::min() && max <= std::numeric_limits<char>::max())
271 return 8;
272 if (min >= std::numeric_limits<short>::min() && max <= std::numeric_limits<short>::max())
273 return 16;
274 return 32;
275 }
276 if (max <= std::numeric_limits<unsigned char>::max())
277 return 8;
278 if (max <= std::numeric_limits<unsigned short>::max())
279 return 16;
280 return 32;
281}
282
284{
285 return (value & (value - 1)) == 0;
286}
287
289 return 32 - qCountLeadingZeroBits(v);
290}
291
293{
294 QFile f(filename);
295
297 panic("Cannot open %s: %s", qPrintable(filename), qPrintable(f.errorString()));
298
299 QTextStream s(&f);
300
301 static const QRegularExpression tracedef(QStringLiteral("^([A-Za-z][A-Za-z0-9_]*)\\((.*)\\)$"));
302 static const QRegularExpression enumenddef(QStringLiteral("^} ?([A-Za-z][A-Za-z0-9_:]*);"));
303 static const QRegularExpression enumdef(QStringLiteral("^([A-Za-z][A-Za-z0-9_]*)( *= *([xabcdef0-9]*))?"));
304 static const QRegularExpression rangedef(QStringLiteral("^RANGE\\(([A-Za-z][A-Za-z0-9_]*) ?, ?([0-9]*) ?... ?([0-9]*) ?\\)"));
305
306 Provider provider;
307 provider.name = QFileInfo(filename).baseName();
308
309 bool parsingPrefixText = false;
310 bool parsingEnum = false;
311 bool parsingFlags = false;
312 TraceEnum currentEnum;
313 TraceFlags currentFlags;
314 int currentEnumValue = 0;
315 int minEnumValue = std::numeric_limits<int>::max();
316 int maxEnumValue = std::numeric_limits<int>::min();
317 for (int lineNumber = 1; !s.atEnd(); ++lineNumber) {
318 QString line = s.readLine().trimmed();
319
320 if (line == "{"_L1) {
321 parsingPrefixText = true;
322 continue;
323 } else if (parsingPrefixText && line == "}"_L1) {
324 parsingPrefixText = false;
325 continue;
326 } else if (parsingPrefixText) {
327 provider.prefixText.append(line);
328 continue;
329 } else if (line == "ENUM {"_L1) {
330 parsingEnum = true;
331 continue;
332 } else if (line == "FLAGS {"_L1) {
333 parsingFlags = true;
334 continue;
335 } else if (line.startsWith("}"_L1) && (parsingEnum || parsingFlags)) {
336 auto match = enumenddef.match(line);
337 if (match.hasMatch()) {
338 if (parsingEnum) {
339 currentEnum.name = match.captured(1);
340 currentEnum.valueSize = minumumValueSize(minEnumValue, maxEnumValue);
341 provider.enumerations.push_back(currentEnum);
342 currentEnum = TraceEnum();
343 parsingEnum = false;
344 } else {
345 currentFlags.name = match.captured(1);
346 provider.flags.push_back(currentFlags);
347 currentFlags = TraceFlags();
348 parsingFlags = false;
349 }
350
351 minEnumValue = std::numeric_limits<int>::max();
352 maxEnumValue = std::numeric_limits<int>::min();
353 } else {
354 panic("Syntax error while processing '%s' line %d:\n"
355 " '%s' end of enum/flags does not match",
356 qPrintable(filename), lineNumber,
358 }
359
360 continue;
361 }
362
363 if (line.isEmpty() || line.startsWith(u'#'))
364 continue;
365
366 if (parsingEnum || parsingFlags) {
367 auto m = enumdef.match(line);
368 if (parsingEnum && line.startsWith(QStringLiteral("RANGE"))) {
369 auto m = rangedef.match(line);
370 if (m.hasMatch()) {
372 value.name = m.captured(1);
373 value.value = m.captured(2).toInt();
374 value.range = m.captured(3).toInt();
375 currentEnumValue = value.range + 1;
376 currentEnum.values.push_back(value);
377 maxEnumValue = qMax(maxEnumValue, value.range);
378 minEnumValue = qMin(minEnumValue, value.value);
379 }
380 } else if (m.hasMatch()) {
381 if (m.hasCaptured(3)) {
382 if (parsingEnum) {
384 value.name = m.captured(1);
385 value.value = m.captured(3).toInt();
386 value.range = 0;
387 currentEnumValue = value.value + 1;
388 currentEnum.values.push_back(value);
389 maxEnumValue = qMax(maxEnumValue, value.value);
390 minEnumValue = qMin(minEnumValue, value.value);
391 } else {
393 value.name = m.captured(1);
394 if (m.captured(3).startsWith(QStringLiteral("0x")))
395 value.value = m.captured(3).toInt(nullptr, 16);
396 else
397 value.value = m.captured(3).toInt();
398 if (!isPow2OrZero(value.value)) {
399 printf("Warning: '%s' line %d:\n"
400 " '%s' flag value is not power of two.\n",
401 qPrintable(filename), lineNumber,
403 } else {
404 value.value = pow2Log2(value.value);
405 currentFlags.values.push_back(value);
406 }
407 }
408 } else {
409 maxEnumValue = qMax(maxEnumValue, currentEnumValue);
410 minEnumValue = qMin(minEnumValue, currentEnumValue);
411 if (parsingEnum) {
412 currentEnum.values.push_back({m.captured(0), currentEnumValue++, 0});
413 } else {
414 panic("Syntax error while processing '%s' line %d:\n"
415 " '%s' flags value not set",
416 qPrintable(filename), lineNumber,
418 }
419 }
420 } else {
421 panic("Syntax error while processing '%s' line %d:\n"
422 " '%s' enum/flags does not match",
423 qPrintable(filename), lineNumber,
425 }
426 continue;
427 }
428
429 auto match = tracedef.match(line);
430 if (match.hasMatch()) {
431 const QString name = match.captured(1);
432 const QString argsString = match.captured(2);
433 const QStringList args = argsString.split(u',', Qt::SkipEmptyParts);
434
435 provider.tracepoints << parseTracepoint(provider, name, args, filename, lineNumber);
436 } else {
437 panic("Syntax error while processing '%s' line %d:\n"
438 " '%s' does not look like a tracepoint definition",
439 qPrintable(filename), lineNumber,
441 }
442 }
443
444 if (parsingPrefixText) {
445 panic("Syntax error while processing '%s': "
446 "no closing brace found for prefix text block",
447 qPrintable(filename));
448 }
449
450#ifdef TRACEGEN_DEBUG
451 qDebug() << provider.prefixText;
452 for (auto i = provider.tracepoints.constBegin(); i != provider.tracepoints.constEnd(); ++i)
453 dumpTracepoint(*i);
454#endif
455
456 return provider;
457}
\inmodule QtCore
Definition qbytearray.h:57
QString baseName() const
Returns the base name of the file without the path.
\inmodule QtCore
Definition qfile.h:93
bool isEmpty() const noexcept
Definition qlist.h:401
void push_back(parameter_type t)
Definition qlist.h:675
const_iterator constBegin() const noexcept
Definition qlist.h:632
const_iterator constEnd() const noexcept
Definition qlist.h:633
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore\reentrant
Definition qrect.h:30
\inmodule QtCore \reentrant
\inmodule QtCore
Definition qsize.h:208
\inmodule QtCore
Definition qsize.h:25
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5455
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
QString trimmed() const &
Definition qstring.h:447
\inmodule QtCore
\inmodule QtCore
Definition qurl.h:94
@ SkipEmptyParts
Definition qnamespace.h:128
void panic(const char *fmt,...)
Definition panic.cpp:10
static bool isPow2OrZero(quint32 value)
Definition provider.cpp:283
static int arrayLength(const QString &rawType)
Definition provider.cpp:52
static Tracepoint::Field::Type backendType(QString rawType)
Definition provider.cpp:102
#define TYPEDATA_ENTRY(type, backendType)
Definition provider.cpp:99
static QString decayArrayToPointer(QString type)
Definition provider.cpp:82
static quint32 pow2Log2(quint32 v)
Definition provider.cpp:288
static int minumumValueSize(int min, int max)
Definition provider.cpp:267
Provider parseProvider(const QString &filename)
Definition provider.cpp:292
static QString removeBraces(QString type)
Definition provider.cpp:92
static QString sequenceLength(const QString &rawType)
Definition provider.cpp:66
static Tracepoint parseTracepoint(const Provider &provider, const QString &name, const QStringList &args, const QString &fileName, const int lineNumber)
Definition provider.cpp:186
QT_POPCOUNT_RELAXED_CONSTEXPR uint qCountLeadingZeroBits(quint32 v) noexcept
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
INT_PTR intptr_t
#define qDebug
[1]
Definition qlogging.h:164
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint GLuint end
GLfloat GLfloat f
GLenum type
GLbitfield flags
GLuint name
GLdouble s
[6]
Definition qopenglext.h:235
GLdouble GLdouble t
Definition qopenglext.h:243
static const struct ImageFormatTab unknown[]
#define qPrintable(string)
Definition qstring.h:1531
#define QStringLiteral(str)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
unsigned int quint32
Definition qtypes.h:50
long long qint64
Definition qtypes.h:60
p rx()++
QJSValueList args
QStringList prefixText
Definition provider.h:85
QList< TraceEnum > enumerations
Definition provider.h:86
QList< TraceFlags > flags
Definition provider.h:87
QString name
Definition provider.h:83
QList< Tracepoint > tracepoints
Definition provider.h:84
int valueSize
Definition provider.h:63
QString name
Definition provider.h:56
QString name
Definition provider.h:67
QList< FlagValue > values
Definition provider.h:72
QString paramType
Definition provider.h:43
QString name
Definition provider.h:50