1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** 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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "remotegdbserveradapter.h"
36 #include "debuggerstartparameters.h"
37 #include "debuggercore.h"
38 #include "debuggerstringutils.h"
39 #include "gdbengine.h"
42 #include <utils/qtcassert.h>
43 #include <utils/fancymainwindow.h>
44 #include <projectexplorer/toolchaintype.h>
46 #include <QtCore/QFileInfo>
47 #include <QtGui/QMessageBox>
52 #define CB(callback) \
53 static_cast<GdbEngine::AdapterCallback>(&RemoteGdbServerAdapter::callback), \
56 ///////////////////////////////////////////////////////////////////////
60 ///////////////////////////////////////////////////////////////////////
62 RemoteGdbServerAdapter::RemoteGdbServerAdapter(GdbEngine *engine, int toolChainType, QObject *parent) :
63 AbstractGdbAdapter(engine, parent),
64 m_toolChainType(toolChainType)
66 connect(&m_uploadProc, SIGNAL(error(QProcess::ProcessError)),
67 SLOT(uploadProcError(QProcess::ProcessError)));
68 connect(&m_uploadProc, SIGNAL(readyReadStandardOutput()),
69 SLOT(readUploadStandardOutput()));
70 connect(&m_uploadProc, SIGNAL(readyReadStandardError()),
71 SLOT(readUploadStandardError()));
72 connect(&m_uploadProc, SIGNAL(finished(int)),
73 SLOT(uploadProcFinished()));
76 AbstractGdbAdapter::DumperHandling RemoteGdbServerAdapter::dumperHandling() const
78 switch (m_toolChainType) {
79 case ProjectExplorer::ToolChain_MinGW:
80 case ProjectExplorer::ToolChain_MSVC:
81 case ProjectExplorer::ToolChain_WINCE:
82 case ProjectExplorer::ToolChain_WINSCW:
83 case ProjectExplorer::ToolChain_GCCE:
84 case ProjectExplorer::ToolChain_RVCT2_ARMV5:
85 case ProjectExplorer::ToolChain_RVCT2_ARMV6:
86 case ProjectExplorer::ToolChain_GCC_MAEMO:
87 return DumperLoadedByGdb;
91 return DumperLoadedByGdbPreload;
94 void RemoteGdbServerAdapter::startAdapter()
96 QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
97 showMessage(_("TRYING TO START ADAPTER"));
98 if (!startParameters().useServerStartScript) {
102 if (startParameters().serverStartScript.isEmpty()) {
103 showMessage(_("No server start script given. "), StatusBar);
104 m_engine->requestRemoteSetup();
106 m_uploadProc.start(_("/bin/sh ") + startParameters().serverStartScript);
107 m_uploadProc.waitForStarted();
111 void RemoteGdbServerAdapter::uploadProcError(QProcess::ProcessError error)
115 case QProcess::FailedToStart:
116 msg = tr("The upload process failed to start. Shell missing?");
118 case QProcess::Crashed:
119 msg = tr("The upload process crashed some time after starting "
122 case QProcess::Timedout:
123 msg = tr("The last waitFor...() function timed out. "
124 "The state of QProcess is unchanged, and you can try calling "
125 "waitFor...() again.");
127 case QProcess::WriteError:
128 msg = tr("An error occurred when attempting to write "
129 "to the upload process. For example, the process may not be running, "
130 "or it may have closed its input channel.");
132 case QProcess::ReadError:
133 msg = tr("An error occurred when attempting to read from "
134 "the upload process. For example, the process may not be running.");
137 msg = tr("An unknown error in the upload process occurred. "
138 "This is the default return value of error().");
141 showMessage(msg, StatusBar);
142 showMessageBox(QMessageBox::Critical, tr("Error"), msg);
145 void RemoteGdbServerAdapter::readUploadStandardOutput()
147 const QByteArray ba = m_uploadProc.readAllStandardOutput();
148 const QString msg = QString::fromLocal8Bit(ba, ba.length());
149 showMessage(msg, LogOutput);
150 showMessage(msg, AppOutput);
153 void RemoteGdbServerAdapter::readUploadStandardError()
155 const QByteArray ba = m_uploadProc.readAllStandardError();
156 const QString msg = QString::fromLocal8Bit(ba, ba.length());
157 showMessage(msg, LogOutput);
158 showMessage(msg, AppError);
161 void RemoteGdbServerAdapter::uploadProcFinished()
163 if (m_uploadProc.exitStatus() == QProcess::NormalExit
164 && m_uploadProc.exitCode() == 0)
167 handleRemoteSetupFailed(m_uploadProc.errorString());
170 void RemoteGdbServerAdapter::setupInferior()
172 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
175 if (!startParameters().executable.isEmpty()) {
176 QFileInfo fi(startParameters().executable);
177 fileName = fi.absoluteFilePath();
179 const QByteArray sysRoot = startParameters().sysRoot.toLocal8Bit();
180 const QByteArray remoteArch = startParameters().remoteArchitecture.toLatin1();
181 const QByteArray gnuTarget = startParameters().gnuTarget.toLatin1();
182 const QByteArray solibPath =
183 QFileInfo(startParameters().dumperLibrary).path().toLocal8Bit();
184 const QString args = startParameters().processArgs;
186 if (!remoteArch.isEmpty())
187 m_engine->postCommand("set architecture " + remoteArch);
188 if (!gnuTarget.isEmpty())
189 m_engine->postCommand("set gnutarget " + gnuTarget);
190 if (!sysRoot.isEmpty())
191 m_engine->postCommand("set sysroot " + sysRoot);
192 if (!solibPath.isEmpty())
193 m_engine->postCommand("set solib-search-path " + solibPath);
195 m_engine->postCommand("-exec-arguments " + args.toLocal8Bit());
197 // This has to be issued before 'target remote'. On pre-7.0 the
198 // command is not present and will result in ' No symbol table is
199 // loaded. Use the "file" command.' as gdb tries to set the
200 // value of a variable with name 'target-async'.
202 // Testing with -list-target-features which was introduced at
203 // the same time would not work either, as this need an existing
206 // Using it even without a target and having it fail might still
208 // Some external comment: '[but] "set target-async on" with a native
209 // windows gdb will work, but then fail when you actually do
210 // "run"/"attach", I think..
211 m_engine->postCommand("set target-async on", CB(handleSetTargetAsync));
213 if (fileName.isEmpty()) {
214 showMessage(tr("No symbol file given."), StatusBar);
219 m_engine->postCommand("-file-exec-and-symbols \""
220 + fileName.toLocal8Bit() + '"',
221 CB(handleFileExecAndSymbols));
224 void RemoteGdbServerAdapter::handleSetTargetAsync(const GdbResponse &response)
226 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
227 if (response.resultClass == GdbResultError)
228 qDebug() << "Adapter too old: does not support asynchronous mode.";
231 void RemoteGdbServerAdapter::handleFileExecAndSymbols(const GdbResponse &response)
233 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
234 if (response.resultClass == GdbResultDone) {
237 QString msg = tr("Reading debug information failed:\n");
238 msg += QString::fromLocal8Bit(response.data.findChild("msg").data());
239 m_engine->notifyInferiorSetupFailed(msg);
243 void RemoteGdbServerAdapter::callTargetRemote()
245 //m_breakHandler->clearBreakMarkers();
247 // "target remote" does three things:
248 // (1) connects to the gdb server
249 // (2) starts the remote application
250 // (3) stops the remote application (early, e.g. in the dynamic linker)
251 QString channel = startParameters().remoteChannel;
252 m_engine->postCommand("target remote " + channel.toLatin1(),
253 CB(handleTargetRemote));
256 void RemoteGdbServerAdapter::handleTargetRemote(const GdbResponse &record)
258 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
259 if (record.resultClass == GdbResultDone) {
260 // gdb server will stop the remote application itself.
261 showMessage(_("INFERIOR STARTED"));
262 showMessage(msgAttachedToStoppedInferior(), StatusBar);
263 m_engine->handleInferiorPrepared();
265 // 16^error,msg="hd:5555: Connection timed out."
266 QString msg = msgConnectRemoteServerFailed(
267 QString::fromLocal8Bit(record.data.findChild("msg").data()));
268 m_engine->notifyInferiorSetupFailed(msg);
272 void RemoteGdbServerAdapter::runEngine()
274 QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
275 m_engine->notifyEngineRunAndInferiorStopOk();
276 m_engine->continueInferiorInternal();
279 void RemoteGdbServerAdapter::interruptInferior()
281 QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
282 m_engine->postCommand("-exec-interrupt", GdbEngine::Immediate,
283 CB(handleInterruptInferior));
286 void RemoteGdbServerAdapter::handleInterruptInferior(const GdbResponse &response)
288 if (response.resultClass == GdbResultDone) {
289 // The gdb server will trigger extra output that we will pick up
290 // to do a proper state transition.
292 // FIXME: On some gdb versions like git 170ffa5d7dd this produces
293 // >810^error,msg="mi_cmd_exec_interrupt: Inferior not executing."
294 m_engine->notifyInferiorStopOk();
298 void RemoteGdbServerAdapter::shutdownInferior()
300 m_engine->defaultInferiorShutdown("kill");
303 void RemoteGdbServerAdapter::shutdownAdapter()
305 m_engine->notifyAdapterShutdownOk();
308 void RemoteGdbServerAdapter::handleRemoteSetupDone(int gdbServerPort, int qmlPort)
310 QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
313 startParameters().qmlServerPort = qmlPort;
314 if (gdbServerPort != -1) {
315 QString &rc = startParameters().remoteChannel;
316 const int sepIndex = rc.lastIndexOf(QLatin1Char(':'));
317 if (sepIndex != -1) {
318 rc.replace(sepIndex + 1, rc.count() - sepIndex - 1,
319 QString::number(gdbServerPort));
325 void RemoteGdbServerAdapter::handleSetupDone()
327 if (m_engine->startGdb(QStringList(), startParameters().debuggerCommand))
328 m_engine->handleAdapterStarted();
331 void RemoteGdbServerAdapter::handleRemoteSetupFailed(const QString &reason)
333 QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
335 m_engine->handleAdapterStartFailed(reason);
338 } // namespace Internal
339 } // namespace Debugger