1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
10 ** GNU Lesser General Public License Usage
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
31 **************************************************************************/
33 #include "remotegdbserveradapter.h"
35 #include "debuggerstartparameters.h"
36 #include "debuggercore.h"
37 #include "debuggerstringutils.h"
38 #include "gdbengine.h"
41 #include <utils/qtcassert.h>
42 #include <utils/fancymainwindow.h>
43 #include <projectexplorer/abi.h>
45 #include <QtCore/QFileInfo>
46 #include <QtGui/QMessageBox>
51 #define CB(callback) \
52 static_cast<GdbEngine::AdapterCallback>(&RemoteGdbServerAdapter::callback), \
55 ///////////////////////////////////////////////////////////////////////
59 ///////////////////////////////////////////////////////////////////////
61 RemoteGdbServerAdapter::RemoteGdbServerAdapter(GdbEngine *engine,
62 const ProjectExplorer::Abi &abi,
64 AbstractGdbAdapter(engine, parent),
67 connect(&m_uploadProc, SIGNAL(error(QProcess::ProcessError)),
68 SLOT(uploadProcError(QProcess::ProcessError)));
69 connect(&m_uploadProc, SIGNAL(readyReadStandardOutput()),
70 SLOT(readUploadStandardOutput()));
71 connect(&m_uploadProc, SIGNAL(readyReadStandardError()),
72 SLOT(readUploadStandardError()));
73 connect(&m_uploadProc, SIGNAL(finished(int)),
74 SLOT(uploadProcFinished()));
77 AbstractGdbAdapter::DumperHandling RemoteGdbServerAdapter::dumperHandling() const
79 if (m_abi.os() == ProjectExplorer::Abi::SymbianOS
80 || m_abi.os() == ProjectExplorer::Abi::WindowsOS
81 || m_abi.binaryFormat() == ProjectExplorer::Abi::ElfFormat)
82 return DumperLoadedByGdb;
83 return DumperLoadedByGdbPreload;
86 void RemoteGdbServerAdapter::startAdapter()
88 QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
89 showMessage(_("TRYING TO START ADAPTER"));
90 if (!startParameters().useServerStartScript) {
94 if (startParameters().serverStartScript.isEmpty()) {
95 showMessage(_("No server start script given. "), StatusBar);
96 m_engine->requestRemoteSetup();
98 m_uploadProc.start(_("/bin/sh ") + startParameters().serverStartScript);
99 m_uploadProc.waitForStarted();
103 void RemoteGdbServerAdapter::uploadProcError(QProcess::ProcessError error)
107 case QProcess::FailedToStart:
108 msg = tr("The upload process failed to start. Shell missing?");
110 case QProcess::Crashed:
111 msg = tr("The upload process crashed some time after starting "
114 case QProcess::Timedout:
115 msg = tr("The last waitFor...() function timed out. "
116 "The state of QProcess is unchanged, and you can try calling "
117 "waitFor...() again.");
119 case QProcess::WriteError:
120 msg = tr("An error occurred when attempting to write "
121 "to the upload process. For example, the process may not be running, "
122 "or it may have closed its input channel.");
124 case QProcess::ReadError:
125 msg = tr("An error occurred when attempting to read from "
126 "the upload process. For example, the process may not be running.");
129 msg = tr("An unknown error in the upload process occurred. "
130 "This is the default return value of error().");
133 showMessage(msg, StatusBar);
134 showMessageBox(QMessageBox::Critical, tr("Error"), msg);
137 void RemoteGdbServerAdapter::readUploadStandardOutput()
139 const QByteArray ba = m_uploadProc.readAllStandardOutput();
140 const QString msg = QString::fromLocal8Bit(ba, ba.length());
141 showMessage(msg, LogOutput);
142 showMessage(msg, AppOutput);
145 void RemoteGdbServerAdapter::readUploadStandardError()
147 const QByteArray ba = m_uploadProc.readAllStandardError();
148 const QString msg = QString::fromLocal8Bit(ba, ba.length());
149 showMessage(msg, LogOutput);
150 showMessage(msg, AppError);
153 void RemoteGdbServerAdapter::uploadProcFinished()
155 if (m_uploadProc.exitStatus() == QProcess::NormalExit
156 && m_uploadProc.exitCode() == 0)
159 handleRemoteSetupFailed(m_uploadProc.errorString());
162 void RemoteGdbServerAdapter::setupInferior()
164 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
167 if (!startParameters().executable.isEmpty()) {
168 QFileInfo fi(startParameters().executable);
169 fileName = fi.absoluteFilePath();
171 const QByteArray sysRoot = startParameters().sysRoot.toLocal8Bit();
172 const QByteArray remoteArch = startParameters().remoteArchitecture.toLatin1();
173 const QByteArray gnuTarget = startParameters().gnuTarget.toLatin1();
174 const QByteArray solibPath =
175 QFileInfo(startParameters().dumperLibrary).path().toLocal8Bit();
176 const QString args = startParameters().processArgs;
178 if (!remoteArch.isEmpty())
179 m_engine->postCommand("set architecture " + remoteArch);
180 if (!gnuTarget.isEmpty())
181 m_engine->postCommand("set gnutarget " + gnuTarget);
182 if (!sysRoot.isEmpty())
183 m_engine->postCommand("set sysroot " + sysRoot);
184 if (!solibPath.isEmpty())
185 m_engine->postCommand("set solib-search-path " + solibPath);
187 m_engine->postCommand("-exec-arguments " + args.toLocal8Bit());
189 // This has to be issued before 'target remote'. On pre-7.0 the
190 // command is not present and will result in ' No symbol table is
191 // loaded. Use the "file" command.' as gdb tries to set the
192 // value of a variable with name 'target-async'.
194 // Testing with -list-target-features which was introduced at
195 // the same time would not work either, as this need an existing
198 // Using it even without a target and having it fail might still
200 // Some external comment: '[but] "set target-async on" with a native
201 // windows gdb will work, but then fail when you actually do
202 // "run"/"attach", I think..
203 m_engine->postCommand("set target-async on", CB(handleSetTargetAsync));
205 if (fileName.isEmpty()) {
206 showMessage(tr("No symbol file given."), StatusBar);
211 m_engine->postCommand("-file-exec-and-symbols \""
212 + fileName.toLocal8Bit() + '"',
213 CB(handleFileExecAndSymbols));
216 void RemoteGdbServerAdapter::handleSetTargetAsync(const GdbResponse &response)
218 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
219 if (response.resultClass == GdbResultError)
220 qDebug() << "Adapter too old: does not support asynchronous mode.";
223 void RemoteGdbServerAdapter::handleFileExecAndSymbols(const GdbResponse &response)
225 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
226 if (response.resultClass == GdbResultDone) {
229 QString msg = tr("Reading debug information failed:\n");
230 msg += QString::fromLocal8Bit(response.data.findChild("msg").data());
231 m_engine->notifyInferiorSetupFailed(msg);
235 void RemoteGdbServerAdapter::callTargetRemote()
237 //m_breakHandler->clearBreakMarkers();
239 // "target remote" does three things:
240 // (1) connects to the gdb server
241 // (2) starts the remote application
242 // (3) stops the remote application (early, e.g. in the dynamic linker)
243 QString channel = startParameters().remoteChannel;
244 m_engine->postCommand("target remote " + channel.toLatin1(),
245 CB(handleTargetRemote));
248 void RemoteGdbServerAdapter::handleTargetRemote(const GdbResponse &record)
250 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
251 if (record.resultClass == GdbResultDone) {
252 // gdb server will stop the remote application itself.
253 showMessage(_("INFERIOR STARTED"));
254 showMessage(msgAttachedToStoppedInferior(), StatusBar);
255 m_engine->handleInferiorPrepared();
257 // 16^error,msg="hd:5555: Connection timed out."
258 QString msg = msgConnectRemoteServerFailed(
259 QString::fromLocal8Bit(record.data.findChild("msg").data()));
260 m_engine->notifyInferiorSetupFailed(msg);
264 void RemoteGdbServerAdapter::runEngine()
266 QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
267 m_engine->notifyEngineRunAndInferiorStopOk();
268 m_engine->continueInferiorInternal();
271 void RemoteGdbServerAdapter::interruptInferior()
273 QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
274 m_engine->postCommand("-exec-interrupt", GdbEngine::Immediate,
275 CB(handleInterruptInferior));
278 void RemoteGdbServerAdapter::handleInterruptInferior(const GdbResponse &response)
280 if (response.resultClass == GdbResultDone) {
281 // The gdb server will trigger extra output that we will pick up
282 // to do a proper state transition.
284 // FIXME: On some gdb versions like git 170ffa5d7dd this produces
285 // >810^error,msg="mi_cmd_exec_interrupt: Inferior not executing."
286 m_engine->notifyInferiorStopOk();
290 void RemoteGdbServerAdapter::shutdownInferior()
292 m_engine->defaultInferiorShutdown("kill");
295 void RemoteGdbServerAdapter::shutdownAdapter()
297 m_engine->notifyAdapterShutdownOk();
300 void RemoteGdbServerAdapter::handleRemoteSetupDone(int gdbServerPort, int qmlPort)
302 QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
305 startParameters().qmlServerPort = qmlPort;
306 if (gdbServerPort != -1) {
307 QString &rc = startParameters().remoteChannel;
308 const int sepIndex = rc.lastIndexOf(QLatin1Char(':'));
309 if (sepIndex != -1) {
310 rc.replace(sepIndex + 1, rc.count() - sepIndex - 1,
311 QString::number(gdbServerPort));
317 void RemoteGdbServerAdapter::handleSetupDone()
319 if (m_engine->startGdb())
320 m_engine->handleAdapterStarted();
323 void RemoteGdbServerAdapter::handleRemoteSetupFailed(const QString &reason)
325 QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
327 m_engine->handleAdapterStartFailed(reason);
330 } // namespace Internal
331 } // namespace Debugger