Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmldebug.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:enables-debug-framework
4
5#include "qqmldebug.h"
8
9#include <private/qqmlengine_p.h>
10#include <private/qv4compileddata_p.h>
11
12#include <QByteArray>
13
14#include <atomic>
15#include <cstdio>
16
17#ifdef Q_OS_WIN
18#include <qt_windows.h>
19#endif
20
22
23QT_BEGIN_NAMESPACE
24
25#if __cplusplus >= 202002L
26# define Q_ATOMIC_FLAG_INIT {}
27#else
28# define Q_ATOMIC_FLAG_INIT ATOMIC_FLAG_INIT // deprecated in C++20
29#endif
30
31/*!
32 \class QQmlDebuggingEnabler
33 \inmodule QtQml
34 \brief The QQmlDebuggingEnabler class provides methods to enable debugging or profiling.
35
36 Usually QML debugging and profiling is enabled by passing
37 \c{QT_ENABLE_QML_DEBUG} via CMake or \c{CONFIG+=qml_debug} via qmake when
38 building your application. At run time, the application generally parses
39 any \c{-qmljsdebugger} command line arguments to actually start debugging
40 or profiling.
41
42 You can instead handle these tasks manually by using the methods in this
43 class.
44 */
45
46Q_CONSTINIT static std::atomic_flag s_printedWarning = Q_ATOMIC_FLAG_INIT;
47
48/*!
49 Enable debugging or profiling. If \a printWarning is \c{true}, print the
50 following warning to stderr:
51
52 \badcode
53 QML debugging is enabled. Only use this in a safe environment.
54 \endcode
55
56 This method is automatically called at startup if \c{QT_ENABLE_QML_DEBUG}
57 or \c{CONFIG+=qml_debug} is passed at build time.
58
59 This method needs to be called one way or another before starting a debug
60 connector of any kind. Otherwise the connector will refuse to start.
61
62 \sa startTcpDebugServer(), connectToLocalDebugger(), startDebugConnector()
63 */
64void QQmlDebuggingEnabler::enableDebugging(bool printWarning)
65{
66 if (printWarning && !s_printedWarning.test_and_set(std::memory_order_relaxed)) {
67 QByteArray warning("QML debugging is enabled. Only use this in a safe environment.");
68 if (qEnvironmentVariableIsSet("CLICOLOR_FORCE") || qEnvironmentVariableIsSet("QTC_RUN")
69 || qEnvironmentVariableIsSet("VSCODE_CLI")) {
70 warning = QByteArray("\033[38;2;255;0;0m") + warning + "\033[0m";
71 }
72 warning += '\n';
73#ifdef Q_OS_WIN
74 // Debuggers on Windows (except vscode) do not display the stderr output
75 if (!qEnvironmentVariableIsSet("VSCODE_CLI"))
76 OutputDebugStringA(warning);
77#endif
78
79 fprintf(stderr, "%s", warning.constData());
80 fflush(stderr); // We really want to print this warning, even if stderr is buffered
81 }
82 QQmlEnginePrivate::qml_debugging_enabled.store(true, std::memory_order_relaxed);
83}
84
85#if QT_DEPRECATED_SINCE(6, 4)
86/*!
87 \internal
88 */
89QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
90{
91 enableDebugging(printWarning);
92};
93#endif // QT_DEPRECATED_SINCE(6, 4)
94
95/*!
96 * Retrieves the plugin keys of the debugger services provided by default. The debugger services
97 * enable a debug client to use a Qml/JavaScript debugger, in order to set breakpoints, pause
98 * execution, evaluate expressions and similar debugging tasks.
99 * \return List of plugin keys of default debugger services.
100 */
101QStringList QQmlDebuggingEnabler::debuggerServices()
102{
103 return {QV4DebugService::s_key, QQmlEngineDebugService::s_key, QDebugMessageService::s_key};
104}
105
106/*!
107 * Retrieves the plugin keys of the inspector services provided by default. The inspector services
108 * enable a debug client to use a visual inspector tool for Qt Quick.
109 * \return List of plugin keys of default inspector services.
110 */
111QStringList QQmlDebuggingEnabler::inspectorServices()
112{
113 return {QQmlInspectorService::s_key};
114}
115
116/*!
117 * Retrieves the names of the profiler services provided by default. The profiler services enable a
118 * debug client to use a profiler and track the time taken by various QML and JavaScript constructs,
119 * as well as the QtQuick SceneGraph.
120 * \return List of plugin keys of default profiler services.
121 */
122QStringList QQmlDebuggingEnabler::profilerServices()
123{
124 return {QQmlProfilerService::s_key, QQmlEngineControlService::s_key, QDebugMessageService::s_key};
125}
126
127/*!
128 * Retrieves the plugin keys of the debug services designed to be used with a native debugger. The
129 * native debugger will communicate with these services by directly reading and writing the
130 * application's memory.
131 * \return List of plugin keys of debug services designed to be used with a native debugger.
132 */
133QStringList QQmlDebuggingEnabler::nativeDebuggerServices()
134{
135 return {QQmlNativeDebugService::s_key};
136}
137
138/*!
139 * Restricts the services available from the debug connector. The connector will scan plugins in the
140 * "qmltooling" subdirectory of the default plugin path. If this function is not called before the
141 * debug connector is enabled, all services found that way will be available to any client. If this
142 * function is called, only the services with plugin keys given in \a services will be available.
143 *
144 * Use this method to disable debugger and inspector services when profiling to get better
145 * performance and more realistic profiles. The debugger service will put any JavaScript engine it
146 * connects to into interpreted mode, disabling the JIT compiler.
147 *
148 * \sa debuggerServices(), profilerServices(), inspectorServices()
149 */
150void QQmlDebuggingEnabler::setServices(const QStringList &services)
151{
152 QQmlDebugConnector::setServices(services);
153}
154
155/*!
156 * \enum QQmlDebuggingEnabler::StartMode
157 *
158 * Defines the debug connector's start behavior. You can interrupt QML engines starting while a
159 * debug client is connecting, in order to set breakpoints in or profile startup code.
160 *
161 * \value DoNotWaitForClient Run any QML engines as usual while the debug services are connecting.
162 * \value WaitForClient If a QML engine starts while the debug services are connecting,
163 * interrupt it until they are done.
164 */
165
166/*!
167 * Enables debugging for QML engines created after calling this function. The debug connector will
168 * listen on \a port at \a hostName and block the QML engine until it receives a connection if
169 * \a mode is \c WaitForClient. If \a mode is not specified it won't block and if \a hostName is not
170 * specified it will listen on all available interfaces. You can only start one debug connector at a
171 * time. A debug connector may have already been started if the -qmljsdebugger= command line
172 * argument was given. This method returns \c true if a new debug connector was successfully
173 * started, or \c false otherwise.
174 */
175bool QQmlDebuggingEnabler::startTcpDebugServer(int port, StartMode mode, const QString &hostName)
176{
177 QVariantHash configuration;
178 configuration[QLatin1String("portFrom")] = configuration[QLatin1String("portTo")] = port;
179 configuration[QLatin1String("block")] = (mode == WaitForClient);
180 configuration[QLatin1String("hostAddress")] = hostName;
181 return startDebugConnector(QLatin1String("QQmlDebugServer"), configuration);
182}
183
184/*!
185 * \since 5.6
186 *
187 * Enables debugging for QML engines created after calling this function. The debug connector will
188 * connect to a debugger waiting on a local socket at the given \a socketFileName and block the QML
189 * engine until the connection is established if \a mode is \c WaitForClient. If \a mode is not
190 * specified it will not block. You can only start one debug connector at a time. A debug connector
191 * may have already been started if the -qmljsdebugger= command line argument was given. This method
192 * returns \c true if a new debug connector was successfully started, or \c false otherwise.
193 */
194bool QQmlDebuggingEnabler::connectToLocalDebugger(const QString &socketFileName, StartMode mode)
195{
196 QVariantHash configuration;
197 configuration[QLatin1String("fileName")] = socketFileName;
198 configuration[QLatin1String("block")] = (mode == WaitForClient);
199 return startDebugConnector(QLatin1String("QQmlDebugServer"), configuration);
200}
201
202/*!
203 * \since 5.7
204 *
205 * Enables debugging for QML engines created after calling this function. A debug connector plugin
206 * specified by \a pluginName will be loaded and started using the given \a configuration. Supported
207 * configuration entries and their semantics depend on the plugin being loaded. You can only start
208 * one debug connector at a time. A debug connector may have already been started if the
209 * -qmljsdebugger= command line argument was given. This method returns \c true if a new debug
210 * connector was successfully started, or \c false otherwise.
211 */
212bool QQmlDebuggingEnabler::startDebugConnector(const QString &pluginName,
213 const QVariantHash &configuration)
214{
215 QQmlDebugConnector::setPluginKey(pluginName);
216 QQmlDebugConnector *connector = QQmlDebugConnector::instance();
217 return connector ? connector->open(configuration) : false;
218}
219
220enum { HookCount = 4 };
221
222// Only add to the end, and bump version if you do.
223quintptr Q_QML_EXPORT qtDeclarativeHookData[] = {
224 // Version of this Array. Bump if you add to end.
225 2,
226
227 // Number of entries in this array.
228 HookCount,
229
230 // TypeInformationVersion, an integral value, bumped whenever private
231 // object sizes or member offsets that are used in Qt Creator's
232 // data structure "pretty printing" change.
233 4,
234
235 // Version of the cache data.
236 QV4_DATA_STRUCTURE_VERSION
237};
238
239Q_STATIC_ASSERT(HookCount == sizeof(qtDeclarativeHookData) / sizeof(qtDeclarativeHookData[0]));
240
241QT_END_NAMESPACE
@ HookCount
#define Q_ATOMIC_FLAG_INIT
Definition qqmldebug.cpp:28
static Q_CONSTINIT std::atomic_flag s_printedWarning
Definition qqmldebug.cpp:46
QT_REQUIRE_CONFIG(qml_debug)
QDebug Q_QML_EXPORT operator<<(QDebug debug, const QQmlError &error)
Q_STATIC_ASSERT(sizeof(SharedImageHeader) % 4==0)