OSDN Git Service

It's 2011 now.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / debugger / gdb / coregdbadapter.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 "coregdbadapter.h"
35
36 #include "debuggerstartparameters.h"
37 #include "debuggercore.h"
38 #include "debuggeractions.h"
39 #include "debuggerstringutils.h"
40 #include "gdbmi.h"
41 #include "gdbengine.h"
42
43 #include <utils/qtcassert.h>
44
45 #include <QtCore/QDir>
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>(&CoreGdbAdapter::callback), \
54     STRINGIFY(callback)
55
56 ///////////////////////////////////////////////////////////////////////
57 //
58 // CoreGdbAdapter
59 //
60 ///////////////////////////////////////////////////////////////////////
61
62 static QByteArray coreName(const DebuggerStartParameters &sp)
63 {
64     QFileInfo fi(sp.coreFile);
65     return fi.absoluteFilePath().toLocal8Bit();
66 }
67
68 CoreGdbAdapter::CoreGdbAdapter(GdbEngine *engine, QObject *parent)
69   : AbstractGdbAdapter(engine, parent),
70     m_executable(startParameters().executable),
71     m_coreName(coreName(startParameters()))
72 {}
73
74 void CoreGdbAdapter::startAdapter()
75 {
76     QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
77     showMessage(_("TRYING TO START ADAPTER"));
78
79     QStringList args;
80     args.append(_("-ex"));
81     args.append(_("set auto-solib-add off"));
82     if (!m_engine->startGdb(args))
83         return;
84
85     //if (m_executable.isEmpty()) {
86     //    showMessageBox(QMessageBox::Warning,
87     //        tr("Error Loading Symbols"),
88     //        tr("No executable to load symbols from specified."));
89     //}
90
91 #ifdef Q_OS_LINUX
92     const bool canUseExeFromCore = true;
93 #else
94     const bool canUseExeFromCore = false;
95 #endif
96
97     if (!m_executable.isEmpty()) {
98         m_engine->notifyEngineSetupOk();
99     } else if (canUseExeFromCore) {
100         // Extra round trip to get executable name from core file.
101         // This is sometimes not the full name, so it can't be used
102         // as the generic solution.
103
104         // Quoting core name below fails in gdb 6.8-debian.
105         m_engine->postCommand("target core " + m_coreName,
106             CB(handleTemporaryTargetCore));
107     } else {
108         QString msg = tr("The name of the binary file cannot be extracted "
109             "from this core file.");
110         msg += _(" ");
111         msg += tr("Try to specify the binary using the "
112             "<i>Debug->Start Debugging->Attach to Core</i> dialog.");
113         showMessageBox(QMessageBox::Warning,
114             tr("Loading core file failed"), msg);
115         m_engine->notifyEngineSetupFailed();
116     }
117 }
118
119 void CoreGdbAdapter::handleTemporaryTargetCore(const GdbResponse &response)
120 {
121     QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
122     if (response.resultClass != GdbResultDone) {
123         showMessage(tr("Attach to core failed."), StatusBar);
124         m_engine->notifyEngineSetupFailed();
125         return;
126     }
127
128     GdbMi console = response.data.findChild("consolestreamoutput");
129     int pos1 = console.data().indexOf('`');
130     int pos2 = console.data().indexOf('\'');
131     if (pos1 == -1 || pos2 == -1) {
132         showMessage(tr("Attach to core failed."), StatusBar);
133         m_engine->notifyEngineSetupFailed();
134         return;
135     }
136
137     m_executable = console.data().mid(pos1 + 1, pos2 - pos1 - 1);
138     // Strip off command line arguments. FIXME: make robust.
139     int idx = m_executable.indexOf(_c(' '));
140     if (idx >= 0)
141         m_executable.truncate(idx);
142     if (m_executable.isEmpty()) {
143         m_engine->postCommand("detach");
144         m_engine->notifyEngineSetupFailed();
145         return;
146     }
147     m_executable = QFileInfo(startParameters().coreFile).absoluteDir()
148                    .absoluteFilePath(m_executable);
149     showMessage(tr("Attached to core temporarily."), StatusBar);
150     m_engine->postCommand("detach", CB(handleTemporaryDetach));
151 }
152
153 void CoreGdbAdapter::handleTemporaryDetach(const GdbResponse &response)
154 {
155     QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
156     if (response.resultClass == GdbResultDone) {
157         m_engine->notifyEngineSetupOk();
158     } else {
159         m_engine->notifyEngineSetupFailed();
160     }
161 }
162
163 void CoreGdbAdapter::setupInferior()
164 {
165     QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
166     // Do that first, otherwise no symbols are loaded.
167     QFileInfo fi(m_executable);
168     QByteArray path = fi.absoluteFilePath().toLocal8Bit();
169     m_engine->postCommand("-file-exec-and-symbols \"" + path + '"',
170          CB(handleFileExecAndSymbols));
171 }
172
173 void CoreGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
174 {
175     QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
176     if (response.resultClass == GdbResultDone) {
177         showMessage(tr("Symbols found."), StatusBar);
178         m_engine->postCommand("target core " + m_coreName,
179             CB(handleTargetCore));
180         return;
181     }
182     QString msg = tr("No symbols found in core file <i>%1</i>.")
183         .arg(startParameters().coreFile);
184     msg += _(" ");
185     msg += tr("This can be caused by a path length limitation in the "
186         "core file.");
187     msg += _(" ");
188     msg += tr("Try to specify the binary using the "
189         "<i>Debug->Start Debugging->Attach to Core</i> dialog.");
190     m_engine->notifyInferiorSetupFailed(msg);
191 }
192
193 void CoreGdbAdapter::handleTargetCore(const GdbResponse &response)
194 {
195     QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
196     if (response.resultClass == GdbResultDone) {
197         // HACK: The namespace is not accessible in the initial run.
198         m_engine->loadPythonDumpers();
199         showMessage(tr("Attached to core."), StatusBar);
200         m_engine->handleInferiorPrepared();
201         // Due to the auto-solib-add off setting, we don't have any
202         // symbols yet. Load them in order of importance.
203         m_engine->reloadStack(true);
204         m_engine->postCommand("info shared", CB(handleModulesList));
205         return;
206     }
207     QString msg = tr("Attach to core \"%1\" failed:\n")
208         .arg(startParameters().coreFile)
209         + QString::fromLocal8Bit(response.data.findChild("msg").data());
210     m_engine->notifyInferiorSetupFailed(msg);
211 }
212
213 void CoreGdbAdapter::handleModulesList(const GdbResponse &response)
214 {
215     m_engine->handleModulesList(response);
216     loadSymbolsForStack();
217 }
218
219 void CoreGdbAdapter::loadSymbolsForStack()
220 {
221     m_engine->loadSymbolsForStack();
222     QTimer::singleShot(1000, this, SLOT(loadAllSymbols()));
223 }
224
225 void CoreGdbAdapter::loadAllSymbols()
226 {
227     m_engine->loadAllSymbols();
228 }
229
230 void CoreGdbAdapter::runEngine()
231 {
232     QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
233     m_engine->notifyInferiorUnrunnable();
234     m_engine->updateAll();
235 }
236
237 void CoreGdbAdapter::interruptInferior()
238 {
239     // A core never runs, so this cannot be called.
240     QTC_ASSERT(false, /**/);
241 }
242
243 void CoreGdbAdapter::shutdownInferior()
244 {
245     m_engine->notifyInferiorShutdownOk();
246 }
247
248 void CoreGdbAdapter::shutdownAdapter()
249 {
250     m_engine->notifyAdapterShutdownOk();
251 }
252
253 } // namespace Internal
254 } // namespace Debugger