OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / debugger / gdb / remotegdbserveradapter.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
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.
18 **
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.
22 **
23 ** Other Usage
24 **
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.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32
33 #include "remotegdbserveradapter.h"
34
35 #include "debuggerstartparameters.h"
36 #include "debuggercore.h"
37 #include "debuggerstringutils.h"
38 #include "gdbengine.h"
39 #include "gdbmi.h"
40
41 #include <utils/qtcassert.h>
42 #include <utils/fancymainwindow.h>
43 #include <projectexplorer/abi.h>
44
45 #include <QtCore/QFileInfo>
46 #include <QtGui/QMessageBox>
47
48 namespace Debugger {
49 namespace Internal {
50
51 #define CB(callback) \
52     static_cast<GdbEngine::AdapterCallback>(&RemoteGdbServerAdapter::callback), \
53     STRINGIFY(callback)
54
55 ///////////////////////////////////////////////////////////////////////
56 //
57 // RemoteGdbAdapter
58 //
59 ///////////////////////////////////////////////////////////////////////
60
61 RemoteGdbServerAdapter::RemoteGdbServerAdapter(GdbEngine *engine,
62                                                const ProjectExplorer::Abi &abi,
63                                                QObject *parent) :
64     AbstractGdbAdapter(engine, parent),
65     m_abi(abi)
66 {
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()));
75 }
76
77 AbstractGdbAdapter::DumperHandling RemoteGdbServerAdapter::dumperHandling() const
78 {
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;
84 }
85
86 void RemoteGdbServerAdapter::startAdapter()
87 {
88     QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
89     showMessage(_("TRYING TO START ADAPTER"));
90     if (!startParameters().useServerStartScript) {
91         handleSetupDone();
92         return;
93     }
94     if (startParameters().serverStartScript.isEmpty()) {
95         showMessage(_("No server start script given. "), StatusBar);
96         m_engine->requestRemoteSetup();
97     } else {
98         m_uploadProc.start(_("/bin/sh ") + startParameters().serverStartScript);
99         m_uploadProc.waitForStarted();
100     }
101 }
102
103 void RemoteGdbServerAdapter::uploadProcError(QProcess::ProcessError error)
104 {
105     QString msg;
106     switch (error) {
107         case QProcess::FailedToStart:
108             msg = tr("The upload process failed to start. Shell missing?");
109             break;
110         case QProcess::Crashed:
111             msg = tr("The upload process crashed some time after starting "
112                 "successfully.");
113             break;
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.");
118             break;
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.");
123             break;
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.");
127             break;
128         default:
129             msg = tr("An unknown error in the upload process occurred. "
130                 "This is the default return value of error().");
131     }
132
133     showMessage(msg, StatusBar);
134     showMessageBox(QMessageBox::Critical, tr("Error"), msg);
135 }
136
137 void RemoteGdbServerAdapter::readUploadStandardOutput()
138 {
139     const QByteArray ba = m_uploadProc.readAllStandardOutput();
140     const QString msg = QString::fromLocal8Bit(ba, ba.length());
141     showMessage(msg, LogOutput);
142     showMessage(msg, AppOutput);
143 }
144
145 void RemoteGdbServerAdapter::readUploadStandardError()
146 {
147     const QByteArray ba = m_uploadProc.readAllStandardError();
148     const QString msg = QString::fromLocal8Bit(ba, ba.length());
149     showMessage(msg, LogOutput);
150     showMessage(msg, AppError);
151 }
152
153 void RemoteGdbServerAdapter::uploadProcFinished()
154 {
155     if (m_uploadProc.exitStatus() == QProcess::NormalExit
156         && m_uploadProc.exitCode() == 0)
157         handleSetupDone();
158     else
159         handleRemoteSetupFailed(m_uploadProc.errorString());
160 }
161
162 void RemoteGdbServerAdapter::setupInferior()
163 {
164     QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
165
166     QString fileName;
167     if (!startParameters().executable.isEmpty()) {
168         QFileInfo fi(startParameters().executable);
169         fileName = fi.absoluteFilePath();
170     }
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;
177
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);
186     if (!args.isEmpty())
187         m_engine->postCommand("-exec-arguments " + args.toLocal8Bit());
188
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'.
193     //
194     // Testing with -list-target-features which was introduced at
195     // the same time would not work either, as this need an existing
196     // target.
197     //
198     // Using it even without a target and having it fail might still
199     // be better as:
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));
204
205     if (fileName.isEmpty()) {
206         showMessage(tr("No symbol file given."), StatusBar);
207         callTargetRemote();
208         return;
209     }
210
211     m_engine->postCommand("-file-exec-and-symbols \""
212         + fileName.toLocal8Bit() + '"',
213         CB(handleFileExecAndSymbols));
214 }
215
216 void RemoteGdbServerAdapter::handleSetTargetAsync(const GdbResponse &response)
217 {
218     QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
219     if (response.resultClass == GdbResultError)
220         qDebug() << "Adapter too old: does not support asynchronous mode.";
221 }
222
223 void RemoteGdbServerAdapter::handleFileExecAndSymbols(const GdbResponse &response)
224 {
225     QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
226     if (response.resultClass == GdbResultDone) {
227         callTargetRemote();
228     } else {
229         QString msg = tr("Reading debug information failed:\n");
230         msg += QString::fromLocal8Bit(response.data.findChild("msg").data());
231         m_engine->notifyInferiorSetupFailed(msg);
232     }
233 }
234
235 void RemoteGdbServerAdapter::callTargetRemote()
236 {
237     //m_breakHandler->clearBreakMarkers();
238
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));
246 }
247
248 void RemoteGdbServerAdapter::handleTargetRemote(const GdbResponse &record)
249 {
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();
256     } else {
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);
261     }
262 }
263
264 void RemoteGdbServerAdapter::runEngine()
265 {
266     QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
267     m_engine->notifyEngineRunAndInferiorStopOk();
268     m_engine->continueInferiorInternal();
269 }
270
271 void RemoteGdbServerAdapter::interruptInferior()
272 {
273     QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
274     m_engine->postCommand("-exec-interrupt", GdbEngine::Immediate,
275         CB(handleInterruptInferior));
276 }
277
278 void RemoteGdbServerAdapter::handleInterruptInferior(const GdbResponse &response)
279 {
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.
283     } else {
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();
287     }
288 }
289
290 void RemoteGdbServerAdapter::shutdownInferior()
291 {
292     m_engine->defaultInferiorShutdown("kill");
293 }
294
295 void RemoteGdbServerAdapter::shutdownAdapter()
296 {
297     m_engine->notifyAdapterShutdownOk();
298 }
299
300 void RemoteGdbServerAdapter::handleRemoteSetupDone(int gdbServerPort, int qmlPort)
301 {
302     QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
303
304     if (qmlPort != -1)
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));
312         }
313     }
314     handleSetupDone();
315 }
316
317 void RemoteGdbServerAdapter::handleSetupDone()
318 {
319     if (m_engine->startGdb())
320         m_engine->handleAdapterStarted();
321 }
322
323 void RemoteGdbServerAdapter::handleRemoteSetupFailed(const QString &reason)
324 {
325     QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
326
327     m_engine->handleAdapterStartFailed(reason);
328 }
329
330 } // namespace Internal
331 } // namespace Debugger