From 713b1f203471cb1b5aa708d1bf8e5561473a5707 Mon Sep 17 00:00:00 2001 From: hjk <qtc-committer@nokia.com> Date: Wed, 23 Sep 2009 13:37:39 +0200 Subject: [PATCH] debugger: re-activate core file debugging --- src/plugins/debugger/gdb/coregdbadapter.cpp | 195 ++++++++++++++++++ src/plugins/debugger/gdb/coregdbadapter.h | 83 ++++++++ src/plugins/debugger/gdb/gdb.pri | 2 + src/plugins/debugger/gdb/gdbengine.cpp | 23 +-- src/plugins/debugger/gdb/gdbengine.h | 16 +- src/plugins/debugger/gdb/remotegdbadapter.cpp | 27 ++- src/plugins/debugger/gdb/remotegdbadapter.h | 11 +- 7 files changed, 318 insertions(+), 39 deletions(-) create mode 100644 src/plugins/debugger/gdb/coregdbadapter.cpp create mode 100644 src/plugins/debugger/gdb/coregdbadapter.h diff --git a/src/plugins/debugger/gdb/coregdbadapter.cpp b/src/plugins/debugger/gdb/coregdbadapter.cpp new file mode 100644 index 00000000000..820d158d105 --- /dev/null +++ b/src/plugins/debugger/gdb/coregdbadapter.cpp @@ -0,0 +1,195 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "coregdbadapter.h" + +#include "debuggeractions.h" +#include "gdbengine.h" +#include "procinterrupt.h" + +#include <utils/qtcassert.h> +#include <coreplugin/icore.h> + +#include <QtCore/QFileInfo> +#include <QtGui/QMessageBox> + +namespace Debugger { +namespace Internal { + +#define STRINGIFY_INTERNAL(x) #x +#define STRINGIFY(x) STRINGIFY_INTERNAL(x) +#define CB(callback) \ + static_cast<GdbEngine::AdapterCallback>(&CoreGdbAdapter::callback), \ + STRINGIFY(callback) + +/////////////////////////////////////////////////////////////////////// +// +// CoreGdbAdapter +// +/////////////////////////////////////////////////////////////////////// + +CoreGdbAdapter::CoreGdbAdapter(GdbEngine *engine, QObject *parent) + : AbstractGdbAdapter(engine, parent) +{ + QTC_ASSERT(state() == AdapterNotRunning, qDebug() << state()); + connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)), + this, SIGNAL(error(QProcess::ProcessError))); + connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()), + this, SIGNAL(readyReadStandardOutput())); + connect(&m_gdbProc, SIGNAL(readyReadStandardError()), + this, SIGNAL(readyReadStandardError())); + connect(&m_gdbProc, SIGNAL(started()), + this, SLOT(handleGdbStarted())); + connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)), + this, SLOT(handleGdbFinished(int, QProcess::ExitStatus))); +} + +void CoreGdbAdapter::startAdapter() +{ + QTC_ASSERT(state() == AdapterNotRunning, qDebug() << state()); + setState(AdapterStarting); + debugMessage(_("TRYING TO START ADAPTER")); + + QStringList gdbArgs; + gdbArgs.prepend(_("mi")); + gdbArgs.prepend(_("-i")); + + if (!m_engine->m_outputCollector.listen()) { + emit adapterStartFailed(tr("Cannot set up communication with child process: %1") + .arg(m_engine->m_outputCollector.errorString())); + return; + } + gdbArgs.prepend(_("--tty=") + m_engine->m_outputCollector.serverName()); + + if (!startParameters().workingDir.isEmpty()) + setWorkingDirectory(startParameters().workingDir); + if (!startParameters().environment.isEmpty()) + setEnvironment(startParameters().environment); + + QString location = theDebuggerStringSetting(GdbLocation); + m_gdbProc.start(location, gdbArgs); +} + +void CoreGdbAdapter::handleGdbStarted() +{ + QTC_ASSERT(state() == AdapterStarting, qDebug() << state()); + setState(AdapterStarted); + emit adapterStarted(); +} + +void CoreGdbAdapter::prepareInferior() +{ + QTC_ASSERT(state() == AdapterStarted, qDebug() << state()); + setState(InferiorPreparing); + if (!startParameters().processArgs.isEmpty()) + m_engine->postCommand(_("-exec-arguments ") + + startParameters().processArgs.join(_(" "))); + QFileInfo fi(m_engine->startParameters().executable); + m_engine->postCommand(_("-file-exec-and-symbols \"%1\"").arg(fi.absoluteFilePath()), + CB(handleFileExecAndSymbols)); +} + +void CoreGdbAdapter::handleFileExecAndSymbols(const GdbResultRecord &response, const QVariant &) +{ + QTC_ASSERT(state() == InferiorPreparing, qDebug() << state()); + if (response.resultClass == GdbResultDone) { + //m_breakHandler->clearBreakMarkers(); + setState(InferiorPrepared); + emit inferiorPrepared(); + } else if (response.resultClass == GdbResultError) { + QString msg = tr("Starting executable failed:\n") + + __(response.data.findChild("msg").data()); + setState(InferiorPreparationFailed); + emit inferiorPreparationFailed(msg); + } +} + +void CoreGdbAdapter::startInferior() +{ + QTC_ASSERT(state() == InferiorPrepared, qDebug() << state()); + setState(InferiorStarting); + QFileInfo fi(startParameters().executable); + QString fileName = _c('"') + fi.absoluteFilePath() + _c('"'); + QFileInfo fi2(startParameters().coreFile); + // quoting core name below fails in gdb 6.8-debian + QString coreName = fi2.absoluteFilePath(); + m_engine->postCommand(_("target core ") + coreName, CB(handleTargetCore)); +} + +void CoreGdbAdapter::handleTargetCore(const GdbResultRecord &response, const QVariant &) +{ + QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); + if (response.resultClass == GdbResultDone) { + setState(InferiorStarted); + emit inferiorStarted(); + m_engine->handleTargetCore(); + } else { + QTC_ASSERT(response.resultClass == GdbResultError, /**/); + const QByteArray &msg = response.data.findChild("msg").data(); + setState(InferiorStartFailed); + emit inferiorStartFailed(msg); + } +} + +void CoreGdbAdapter::interruptInferior() +{ + // A core should never 'run' + QTC_ASSERT(false, /**/); +} + +void CoreGdbAdapter::shutdown() +{ + if (state() == InferiorStarted || state() == InferiorShutDown) { + setState(AdapterShuttingDown); + m_engine->postCommand(_("-gdb-exit"), CB(handleExit)); + return; + } + QTC_ASSERT(state() == AdapterNotRunning, qDebug() << state()); +} + +void CoreGdbAdapter::handleExit(const GdbResultRecord &response, const QVariant &) +{ + if (response.resultClass == GdbResultDone) { + // don't set state here, this will be handled in handleGdbFinished() + } else if (response.resultClass == GdbResultError) { + QString msg = tr("Gdb process could not be stopped:\n") + + __(response.data.findChild("msg").data()); + emit adapterShutdownFailed(msg); + } +} + +void CoreGdbAdapter::handleGdbFinished(int, QProcess::ExitStatus) +{ + debugMessage(_("GDB PROESS FINISHED")); + setState(AdapterNotRunning); + emit adapterShutDown(); +} + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/gdb/coregdbadapter.h b/src/plugins/debugger/gdb/coregdbadapter.h new file mode 100644 index 00000000000..152c9bebf57 --- /dev/null +++ b/src/plugins/debugger/gdb/coregdbadapter.h @@ -0,0 +1,83 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef DEBUGGER_COREGDBADAPTER_H +#define DEBUGGER_COREGDBADAPTER_H + +#include "abstractgdbadapter.h" +#include "gdbengine.h" + +#include <QtCore/QDebug> +#include <QtCore/QProcess> + +namespace Debugger { +namespace Internal { + +/////////////////////////////////////////////////////////////////////// +// +// CoreGdbAdapter +// +/////////////////////////////////////////////////////////////////////// + +class CoreGdbAdapter : public AbstractGdbAdapter +{ + Q_OBJECT + +public: + CoreGdbAdapter(GdbEngine *engine, QObject *parent = 0); + +private: + QByteArray readAllStandardError() { return m_gdbProc.readAllStandardError(); } + QByteArray readAllStandardOutput() { return m_gdbProc.readAllStandardOutput(); } + qint64 write(const char *data) { return m_gdbProc.write(data); } + void setWorkingDirectory(const QString &dir) { m_gdbProc.setWorkingDirectory(dir); } + void setEnvironment(const QStringList &env) { m_gdbProc.setEnvironment(env); } + bool isTrkAdapter() const { return false; } + + void startAdapter(); + void prepareInferior(); + void startInferior(); + void interruptInferior(); + void shutdown(); + + void handleFileExecAndSymbols(const GdbResultRecord &, const QVariant &); + void handleTargetCore(const GdbResultRecord &response, const QVariant &); + void handleExit(const GdbResultRecord &, const QVariant &); + + void debugMessage(const QString &msg) { m_engine->debugMessage(msg); } + Q_SLOT void handleGdbFinished(int, QProcess::ExitStatus); + Q_SLOT void handleGdbStarted(); + + QProcess m_gdbProc; +}; + +} // namespace Internal +} // namespace Debugger + +#endif // DEBUGGER_COREDBADAPTER_H diff --git a/src/plugins/debugger/gdb/gdb.pri b/src/plugins/debugger/gdb/gdb.pri index 77a3a42d885..08a45315a94 100644 --- a/src/plugins/debugger/gdb/gdb.pri +++ b/src/plugins/debugger/gdb/gdb.pri @@ -7,6 +7,7 @@ HEADERS += \ $$PWD/gdbengine.h \ $$PWD/gdboptionspage.h \ $$PWD/remotegdbadapter.h \ + $$PWD/coregdbadapter.h \ $$PWD/trkgdbadapter.h \ $$PWD/trkoptions.h \ $$PWD/trkoptionswidget.h \ @@ -18,6 +19,7 @@ SOURCES += \ $$PWD/gdboptionspage.cpp \ $$PWD/plaingdbadapter.cpp \ $$PWD/remotegdbadapter.cpp \ + $$PWD/coregdbadapter.cpp \ $$PWD/trkoptions.cpp \ $$PWD/trkoptionswidget.cpp \ $$PWD/trkoptionspage.cpp \ diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 2a835302fd7..de6556e693a 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -33,9 +33,11 @@ #include "gdboptionspage.h" #include "trkoptions.h" #include "trkoptionspage.h" + #include "plaingdbadapter.h" #include "trkgdbadapter.h" #include "remotegdbadapter.h" +#include "coregdbadapter.h" #include "watchutils.h" #include "debuggeractions.h" @@ -178,7 +180,8 @@ GdbEngine::GdbEngine(DebuggerManager *parent) : options->fromSettings(Core::ICore::instance()->settings()); m_plainAdapter = new PlainGdbAdapter(this); m_trkAdapter = new TrkGdbAdapter(this, options); - m_remoteAdapter = 0; // FIXME + m_remoteAdapter = new RemoteGdbAdapter(this); + m_coreAdapter = new CoreGdbAdapter(this); // Output connect(&m_outputCollector, SIGNAL(byteDelivery(QByteArray)), @@ -228,6 +231,7 @@ GdbEngine::~GdbEngine() delete m_plainAdapter; delete m_trkAdapter; delete m_remoteAdapter; + delete m_coreAdapter; } void GdbEngine::connectAdapter() @@ -900,7 +904,7 @@ void GdbEngine::executeDebuggerCommand(const QString &command) m_gdbAdapter->write(command.toLatin1() + "\r\n"); } -void GdbEngine::handleTargetCore(const GdbResultRecord &, const QVariant &) +void GdbEngine::handleTargetCore() { qq->notifyInferiorStopped(); showStatusMessage(tr("Core file loaded.")); @@ -1229,7 +1233,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) #if 1 // FIXME: remove this special case as soon as there's a real // reason given when the temporary breakpoint is hit. - // reight now we get: + // right now we get: // 14*stopped,thread-id="1",frame={addr="0x0000000000403ce4", // func="foo",args=[{name="str",value="@0x7fff0f450460"}], // file="main.cpp",fullname="/tmp/g/main.cpp",line="37"} @@ -1559,6 +1563,10 @@ void GdbEngine::startDebugger(const DebuggerStartParametersPtr &sp) if (sp->executable.endsWith(_(".sym"))) m_gdbAdapter = m_trkAdapter; + else if (sp->startMode == AttachCore) + m_gdbAdapter = m_coreAdapter; + else if (sp->startMode == StartRemote) + m_gdbAdapter = m_remoteAdapter; else m_gdbAdapter = m_plainAdapter; @@ -4215,15 +4223,6 @@ void GdbEngine::handleInferiorPrepared() postCommand(_("attach %1").arg(m_startParameters->attachPID), CB(handleAttach)); // Task 254674 does not want to remove them //qq->breakHandler()->removeAllBreakpoints(); - } else if (startMode() == AttachCore) { - QFileInfo fi(m_startParameters->executable); - QString fileName = _c('"') + fi.absoluteFilePath() + _c('"'); - QFileInfo fi2(m_startParameters->coreFile); - // quoting core name below fails in gdb 6.8-debian - QString coreName = fi2.absoluteFilePath(); - postCommand(_("-file-exec-and-symbols ") + fileName, CB(handleFileExecAndSymbols)); - postCommand(_("target core ") + coreName, CB(handleTargetCore)); - qq->breakHandler()->removeAllBreakpoints(); } else if (startMode() == StartRemote) { postCommand(_("set architecture %1").arg(m_startParameters->remoteArchitecture)); qq->breakHandler()->setAllPending(); diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index a71cede808c..eb97e06c6a5 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -68,6 +68,7 @@ class BreakpointData; class PlainGdbAdapter; class TrkGdbAdapter; class RemoteGdbAdapter; +class CoreGdbAdapter; enum DebuggingHelperState { @@ -94,6 +95,7 @@ private: friend class PlainGdbAdapter; friend class TrkGdbAdapter; friend class RemoteGdbAdapter; + friend class CoreGdbAdapter; // // IDebuggerEngine implementation @@ -267,12 +269,12 @@ private: void handleShowVersion(const GdbResultRecord &response, const QVariant &); void handleQueryPwd(const GdbResultRecord &response, const QVariant &); void handleQuerySources(const GdbResultRecord &response, const QVariant &); - void handleTargetCore(const GdbResultRecord &, const QVariant &); void handleExit(const GdbResultRecord &, const QVariant &); void handleDetach(const GdbResultRecord &, const QVariant &); //void handleSetTargetAsync(const GdbResultRecord &, const QVariant &); //void handleTargetRemote(const GdbResultRecord &, const QVariant &); void handleWatchPoint(const GdbResultRecord &, const QVariant &); + void handleTargetCore(); bool showToolTip(); // Convenience @@ -293,8 +295,6 @@ private: QByteArray m_inbuffer; - AbstractGdbAdapter *m_gdbAdapter; - QHash<int, GdbCommand> m_cookieForToken; QHash<int, QByteArray> m_customOutputForToken; @@ -442,10 +442,12 @@ private: DebuggerStartParametersPtr m_startParameters; // make sure to re-initialize new members in initializeVariables(); - // only one of those is active at a given time - PlainGdbAdapter *m_plainAdapter; - TrkGdbAdapter *m_trkAdapter; - RemoteGdbAdapter *m_remoteAdapter; + // only one of those is active at a given time, available in m_gdbAdapter + AbstractGdbAdapter *m_gdbAdapter; // pointer to one listed below + PlainGdbAdapter *m_plainAdapter; // owned + TrkGdbAdapter *m_trkAdapter; // owned + RemoteGdbAdapter *m_remoteAdapter; // owned + CoreGdbAdapter *m_coreAdapter; // owned public: void showMessageBox(int icon, const QString &title, const QString &text); diff --git a/src/plugins/debugger/gdb/remotegdbadapter.cpp b/src/plugins/debugger/gdb/remotegdbadapter.cpp index 85aaaa31822..0a4a9f92b61 100644 --- a/src/plugins/debugger/gdb/remotegdbadapter.cpp +++ b/src/plugins/debugger/gdb/remotegdbadapter.cpp @@ -77,12 +77,11 @@ RemoteGdbAdapter::RemoteGdbAdapter(GdbEngine *engine, QObject *parent) this, SLOT(readUploadStandardError())); } -void RemoteGdbAdapter::startAdapter(const DebuggerStartParametersPtr &sp) +void RemoteGdbAdapter::startAdapter() { QTC_ASSERT(state() == AdapterNotRunning, qDebug() << state()); setState(AdapterStarting); debugMessage(_("TRYING TO START ADAPTER")); - m_startParameters = sp; QStringList gdbArgs; gdbArgs.prepend(_("mi")); @@ -95,25 +94,25 @@ void RemoteGdbAdapter::startAdapter(const DebuggerStartParametersPtr &sp) } gdbArgs.prepend(_("--tty=") + m_engine->m_outputCollector.serverName()); - if (!m_startParameters->workingDir.isEmpty()) - setWorkingDirectory(m_startParameters->workingDir); - if (!m_startParameters->environment.isEmpty()) - setEnvironment(m_startParameters->environment); + if (!startParameters().workingDir.isEmpty()) + setWorkingDirectory(startParameters().workingDir); + if (!startParameters().environment.isEmpty()) + setEnvironment(startParameters().environment); QString location = theDebuggerStringSetting(GdbLocation); /* // FIXME: make asynchroneouis // Start the remote server - if (m_startParameters->serverStartScript.isEmpty()) { + if (startParameters().serverStartScript.isEmpty()) { showStatusMessage(_("No server start script given. " "Assuming server runs already.")); } else { - if (!m_startParameters->workingDir.isEmpty()) - m_uploadProc.setWorkingDirectory(m_startParameters->workingDir); - if (!m_startParameters->environment.isEmpty()) - m_uploadProc.setEnvironment(m_startParameters->environment); - m_uploadProc.start(_("/bin/sh ") + m_startParameters->serverStartScript); + if (!startParameters().workingDir.isEmpty()) + m_uploadProc.setWorkingDirectory(startParameters().workingDir); + if (!startParameters().environment.isEmpty()) + m_uploadProc.setEnvironment(startParameters().environment); + m_uploadProc.start(_("/bin/sh ") + startParameters().serverStartScript); m_uploadProc.waitForStarted(); } */ @@ -182,9 +181,9 @@ void RemoteGdbAdapter::prepareInferior() { QTC_ASSERT(state() == AdapterStarted, qDebug() << state()); setState(InferiorPreparing); - if (!m_startParameters->processArgs.isEmpty()) + if (!startParameters().processArgs.isEmpty()) m_engine->postCommand(_("-exec-arguments ") - + m_startParameters->processArgs.join(_(" "))); + + startParameters().processArgs.join(_(" "))); QFileInfo fi(m_engine->startParameters().executable); m_engine->postCommand(_("-file-exec-and-symbols \"%1\"").arg(fi.absoluteFilePath()), CB(handleFileExecAndSymbols)); diff --git a/src/plugins/debugger/gdb/remotegdbadapter.h b/src/plugins/debugger/gdb/remotegdbadapter.h index 054d782fef8..cd15b87e599 100644 --- a/src/plugins/debugger/gdb/remotegdbadapter.h +++ b/src/plugins/debugger/gdb/remotegdbadapter.h @@ -52,6 +52,7 @@ class RemoteGdbAdapter : public AbstractGdbAdapter public: RemoteGdbAdapter(GdbEngine *engine, QObject *parent = 0); +private: QByteArray readAllStandardError() { return m_gdbProc.readAllStandardError(); } QByteArray readAllStandardOutput() { return m_gdbProc.readAllStandardOutput(); } qint64 write(const char *data) { return m_gdbProc.write(data); } @@ -59,17 +60,16 @@ public: void setEnvironment(const QStringList &env) { m_gdbProc.setEnvironment(env); } bool isTrkAdapter() const { return false; } - void startAdapter(const DebuggerStartParametersPtr &sp); + void startAdapter(); void prepareInferior(); void startInferior(); void interruptInferior(); void shutdown(); - void readUploadStandardOutput(); - void readUploadStandardError(); - void uploadProcError(QProcess::ProcessError error); + Q_SLOT void readUploadStandardOutput(); + Q_SLOT void readUploadStandardError(); + Q_SLOT void uploadProcError(QProcess::ProcessError error); -private: void handleFileExecAndSymbols(const GdbResultRecord &, const QVariant &); void handleKill(const GdbResultRecord &, const QVariant &); void handleExit(const GdbResultRecord &, const QVariant &); @@ -80,7 +80,6 @@ private: Q_SLOT void handleGdbStarted(); QProcess m_gdbProc; - DebuggerStartParametersPtr m_startParameters; QProcess m_uploadProc; }; -- GitLab