1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qv4debuggeragent.h"
41#include "qv4debugservice.h"
42#include "qv4datacollector.h"
43
44#include <QtCore/qjsonobject.h>
45#include <QtCore/qjsonarray.h>
46
47QT_BEGIN_NAMESPACE
48
49QV4DebuggerAgent::QV4DebuggerAgent(QV4DebugServiceImpl *debugService)
50 : m_breakOnThrow(false), m_debugService(debugService)
51{}
52
53QV4Debugger *QV4DebuggerAgent::pausedDebugger() const
54{
55 for (QV4Debugger *debugger : m_debuggers) {
56 if (debugger->state() == QV4Debugger::Paused)
57 return debugger;
58 }
59 return nullptr;
60}
61
62bool QV4DebuggerAgent::isRunning() const
63{
64 // "running" means none of the engines are paused.
65 return pausedDebugger() == nullptr;
66}
67
68void QV4DebuggerAgent::debuggerPaused(QV4Debugger *debugger, QV4Debugger::PauseReason reason)
69{
70 Q_UNUSED(reason);
71
72 debugger->collector()->clear();
73
74 QJsonObject event, body, script;
75 event.insert(QStringLiteral("type"), QStringLiteral("event"));
76
77 switch (reason) {
78 case QV4Debugger::Step:
79 case QV4Debugger::PauseRequest:
80 case QV4Debugger::BreakPointHit: {
81 event.insert(QStringLiteral("event"), QStringLiteral("break"));
82 QV4::CppStackFrame *frame = debugger->engine()->currentStackFrame;
83 if (!frame)
84 break;
85
86 body.insert(QStringLiteral("invocationText"), value: frame->function());
87 body.insert(QStringLiteral("sourceLine"), value: qAbs(t: frame->lineNumber()) - 1);
88// if (frame->column > 0)
89// body.insert(QStringLiteral("sourceColumn"), frame->column);
90 QJsonArray breakPoints;
91 foreach (int breakPointId, breakPointIds(frame->source(), frame->lineNumber()))
92 breakPoints.push_back(t: breakPointId);
93 body.insert(QStringLiteral("breakpoints"), value: breakPoints);
94 script.insert(QStringLiteral("name"), value: frame->source());
95 } break;
96 case QV4Debugger::Throwing:
97 // TODO: complete this!
98 event.insert(QStringLiteral("event"), QStringLiteral("exception"));
99 break;
100 }
101
102 if (!script.isEmpty())
103 body.insert(QStringLiteral("script"), value: script);
104 if (!body.isEmpty())
105 event.insert(QStringLiteral("body"), value: body);
106 m_debugService->send(v4Payload: event);
107}
108
109void QV4DebuggerAgent::addDebugger(QV4Debugger *debugger)
110{
111 Q_ASSERT(!m_debuggers.contains(debugger));
112 m_debuggers << debugger;
113
114 debugger->setBreakOnThrow(m_breakOnThrow);
115
116 for (const BreakPoint &breakPoint : qAsConst(t&: m_breakPoints))
117 if (breakPoint.enabled)
118 debugger->addBreakPoint(fileName: breakPoint.fileName, lineNumber: breakPoint.lineNr, condition: breakPoint.condition);
119
120 connect(sender: debugger, signal: &QObject::destroyed, receiver: this, slot: &QV4DebuggerAgent::handleDebuggerDeleted);
121 connect(sender: debugger, signal: &QV4Debugger::debuggerPaused, receiver: this, slot: &QV4DebuggerAgent::debuggerPaused,
122 type: Qt::QueuedConnection);
123}
124
125void QV4DebuggerAgent::removeDebugger(QV4Debugger *debugger)
126{
127 m_debuggers.removeAll(t: debugger);
128 disconnect(sender: debugger, signal: &QObject::destroyed, receiver: this, slot: &QV4DebuggerAgent::handleDebuggerDeleted);
129 disconnect(sender: debugger, signal: &QV4Debugger::debuggerPaused, receiver: this, slot: &QV4DebuggerAgent::debuggerPaused);
130}
131
132const QList<QV4Debugger *> &QV4DebuggerAgent::debuggers()
133{
134 return m_debuggers;
135}
136
137void QV4DebuggerAgent::handleDebuggerDeleted(QObject *debugger)
138{
139 m_debuggers.removeAll(t: static_cast<QV4Debugger *>(debugger));
140}
141
142void QV4DebuggerAgent::pause(QV4Debugger *debugger) const
143{
144 debugger->pause();
145}
146
147void QV4DebuggerAgent::pauseAll() const
148{
149 for (QV4Debugger *debugger : m_debuggers)
150 pause(debugger);
151}
152
153void QV4DebuggerAgent::resumeAll() const
154{
155 for (QV4Debugger *debugger : m_debuggers)
156 if (debugger->state() == QV4Debugger::Paused)
157 debugger->resume(speed: QV4Debugger::FullThrottle);
158}
159
160int QV4DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber, bool enabled, const QString &condition)
161{
162 if (enabled)
163 for (QV4Debugger *debugger : qAsConst(t&: m_debuggers))
164 debugger->addBreakPoint(fileName, lineNumber, condition);
165
166 const int id = ++m_lastBreakPointId;
167 m_breakPoints.insert(key: id, value: BreakPoint(fileName, lineNumber, enabled, condition));
168 return id;
169}
170
171void QV4DebuggerAgent::removeBreakPoint(int id)
172{
173 BreakPoint breakPoint = m_breakPoints.value(key: id);
174 if (!breakPoint.isValid())
175 return;
176
177 m_breakPoints.remove(key: id);
178
179 if (breakPoint.enabled)
180 for (QV4Debugger *debugger : qAsConst(t&: m_debuggers))
181 debugger->removeBreakPoint(fileName: breakPoint.fileName, lineNumber: breakPoint.lineNr);
182}
183
184void QV4DebuggerAgent::removeAllBreakPoints()
185{
186 for (auto it = m_breakPoints.keyBegin(), end = m_breakPoints.keyEnd(); it != end; ++it)
187 removeBreakPoint(id: *it);
188}
189
190void QV4DebuggerAgent::enableBreakPoint(int id, bool onoff)
191{
192 BreakPoint &breakPoint = m_breakPoints[id];
193 if (!breakPoint.isValid() || breakPoint.enabled == onoff)
194 return;
195 breakPoint.enabled = onoff;
196
197 for (QV4Debugger *debugger : qAsConst(t&: m_debuggers)) {
198 if (onoff)
199 debugger->addBreakPoint(fileName: breakPoint.fileName, lineNumber: breakPoint.lineNr, condition: breakPoint.condition);
200 else
201 debugger->removeBreakPoint(fileName: breakPoint.fileName, lineNumber: breakPoint.lineNr);
202 }
203}
204
205QList<int> QV4DebuggerAgent::breakPointIds(const QString &fileName, int lineNumber) const
206{
207 QList<int> ids;
208
209 for (QHash<int, BreakPoint>::const_iterator i = m_breakPoints.begin(), ei = m_breakPoints.end(); i != ei; ++i)
210 if (i->lineNr == lineNumber && fileName.endsWith(s: i->fileName))
211 ids.push_back(t: i.key());
212
213 return ids;
214}
215
216void QV4DebuggerAgent::setBreakOnThrow(bool onoff)
217{
218 if (onoff != m_breakOnThrow) {
219 m_breakOnThrow = onoff;
220 for (QV4Debugger *debugger : qAsConst(t&: m_debuggers))
221 debugger->setBreakOnThrow(onoff);
222 }
223}
224
225void QV4DebuggerAgent::clearAllPauseRequests()
226{
227 for (QV4Debugger *debugger : qAsConst(t&: m_debuggers))
228 debugger->clearPauseRequest();
229}
230
231QT_END_NAMESPACE
232
233#include "moc_qv4debuggeragent.cpp"
234

source code of qtdeclarative/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp