OSDN Git Service

It's 2011 now.
[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 (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
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
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
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.
24 **
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.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "remotegdbserveradapter.h"
35
36 #include "debuggerstartparameters.h"
37 #include "debuggercore.h"
38 #include "debuggerstringutils.h"
39 #include "gdbengine.h"
40 #include "gdbmi.h"
41
42 #include <utils/qtcassert.h>
43 #include <utils/fancymainwindow.h>
44 #include <projectexplorer/toolchaintype.h>
45
46 #include <QtCore/QFileInfo>
47 #include <QtGui/QMessageBox>
48
49 namespace Debugger {
50 namespace Internal {
51
52 #define CB(callback) \
53     static_cast<GdbEngine::AdapterCallback>(&RemoteGdbServerAdapter::callback), \
54     STRINGIFY(callback)
55
56 ///////////////////////////////////////////////////////////////////////
57 //
58 // RemoteGdbAdapter
59 //
60 ///////////////////////////////////////////////////////////////////////
61
62 RemoteGdbServerAdapter::RemoteGdbServerAdapter(GdbEngine *engine, int toolChainType, QObject *parent) :
63     AbstractGdbAdapter(engine, parent),
64     m_toolChainType(toolChainType)
65 {
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()));
74 }
75
76 AbstractGdbAdapter::DumperHandling RemoteGdbServerAdapter::dumperHandling() const
77 {
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;
88     default:
89         break;
90     }
91     return DumperLoadedByGdbPreload;
92 }
93
94 void RemoteGdbServerAdapter::startAdapter()
95 {
96     QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
97     showMessage(_("TRYING TO START ADAPTER"));
98     if (!startParameters().useServerStartScript) {
99         handleSetupDone();
100         return;
101     }
102     if (startParameters().serverStartScript.isEmpty()) {
103         showMessage(_("No server start script given. "), StatusBar);
104         m_engine->requestRemoteSetup();
105     } else {
106         m_uploadProc.start(_("/bin/sh ") + startParameters().serverStartScript);
107         m_uploadProc.waitForStarted();
108     }
109 }
110
111 void RemoteGdbServerAdapter::uploadProcError(QProcess::ProcessError error)
112 {
113     QString msg;
114     switch (error) {
115         case QProcess::FailedToStart:
116             msg = tr("The upload process failed to start. Shell missing?");
117             break;
118         case QProcess::Crashed:
119             msg = tr("The upload process crashed some time after starting "
120                 "successfully.");
121             break;
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.");
126             break;
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.");
131             break;
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.");
135             break;
136         default:
137             msg = tr("An unknown error in the upload process occurred. "
138                 "This is the default return value of error().");
139     }
140
141     showMessage(msg, StatusBar);
142     showMessageBox(QMessageBox::Critical, tr("Error"), msg);
143 }
144
145 void RemoteGdbServerAdapter::readUploadStandardOutput()
146 {
147     const QByteArray ba = m_uploadProc.readAllStandardOutput();
148     const QString msg = QString::fromLocal8Bit(ba, ba.length());
149     showMessage(msg, LogOutput);
150     showMessage(msg, AppOutput);
151 }
152
153 void RemoteGdbServerAdapter::readUploadStandardError()
154 {
155     const QByteArray ba = m_uploadProc.readAllStandardError();
156     const QString msg = QString::fromLocal8Bit(ba, ba.length());
157     showMessage(msg, LogOutput);
158     showMessage(msg, AppError);
159 }
160
161 void RemoteGdbServerAdapter::uploadProcFinished()
162 {
163     if (m_uploadProc.exitStatus() == QProcess::NormalExit
164         && m_uploadProc.exitCode() == 0)
165         handleSetupDone();
166     else
167         handleRemoteSetupFailed(m_uploadProc.errorString());
168 }
169
170 void RemoteGdbServerAdapter::setupInferior()
171 {
172     QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
173
174     QString fileName;
175     if (!startParameters().executable.isEmpty()) {
176         QFileInfo fi(startParameters().executable);
177         fileName = fi.absoluteFilePath();
178     }
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;
185
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);
194     if (!args.isEmpty())
195         m_engine->postCommand("-exec-arguments " + args.toLocal8Bit());
196
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'.
201     //
202     // Testing with -list-target-features which was introduced at
203     // the same time would not work either, as this need an existing
204     // target.
205     //
206     // Using it even without a target and having it fail might still
207     // be better as:
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));
212
213     if (fileName.isEmpty()) {
214         showMessage(tr("No symbol file given."), StatusBar);
215         callTargetRemote();
216         return;
217     }
218
219     m_engine->postCommand("-file-exec-and-symbols \""
220         + fileName.toLocal8Bit() + '"',
221         CB(handleFileExecAndSymbols));
222 }
223
224 void RemoteGdbServerAdapter::handleSetTargetAsync(const GdbResponse &response)
225 {
226     QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
227     if (response.resultClass == GdbResultError)
228         qDebug() << "Adapter too old: does not support asynchronous mode.";
229 }
230
231 void RemoteGdbServerAdapter::handleFileExecAndSymbols(const GdbResponse &response)
232 {
233     QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
234     if (response.resultClass == GdbResultDone) {
235         callTargetRemote();
236     } else {
237         QString msg = tr("Reading debug information failed:\n");
238         msg += QString::fromLocal8Bit(response.data.findChild("msg").data());
239         m_engine->notifyInferiorSetupFailed(msg);
240     }
241 }
242
243 void RemoteGdbServerAdapter::callTargetRemote()
244 {
245     //m_breakHandler->clearBreakMarkers();
246
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));
254 }
255
256 void RemoteGdbServerAdapter::handleTargetRemote(const GdbResponse &record)
257 {
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();
264     } else {
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);
269     }
270 }
271
272 void RemoteGdbServerAdapter::runEngine()
273 {
274     QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
275     m_engine->notifyEngineRunAndInferiorStopOk();
276     m_engine->continueInferiorInternal();
277 }
278
279 void RemoteGdbServerAdapter::interruptInferior()
280 {
281     QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
282     m_engine->postCommand("-exec-interrupt", GdbEngine::Immediate,
283         CB(handleInterruptInferior));
284 }
285
286 void RemoteGdbServerAdapter::handleInterruptInferior(const GdbResponse &response)
287 {
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.
291     } else {
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();
295     }
296 }
297
298 void RemoteGdbServerAdapter::shutdownInferior()
299 {
300     m_engine->defaultInferiorShutdown("kill");
301 }
302
303 void RemoteGdbServerAdapter::shutdownAdapter()
304 {
305     m_engine->notifyAdapterShutdownOk();
306 }
307
308 void RemoteGdbServerAdapter::handleRemoteSetupDone(int gdbServerPort, int qmlPort)
309 {
310     QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
311
312     if (qmlPort != -1)
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));
320         }
321     }
322     handleSetupDone();
323 }
324
325 void RemoteGdbServerAdapter::handleSetupDone()
326 {
327     if (m_engine->startGdb(QStringList(), startParameters().debuggerCommand))
328         m_engine->handleAdapterStarted();
329 }
330
331 void RemoteGdbServerAdapter::handleRemoteSetupFailed(const QString &reason)
332 {
333     QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
334
335     m_engine->handleAdapterStartFailed(reason);
336 }
337
338 } // namespace Internal
339 } // namespace Debugger