Debugger[new CDB]: Polish options, add remote debugging.

This commit is contained in:
Friedemann Kleint
2010-11-19 16:13:22 +01:00
parent 8b59a52bc1
commit 1b9b962b2c
13 changed files with 360 additions and 36 deletions

View File

@@ -221,9 +221,11 @@ STDMETHODIMP EventCallback::ExitProcess(
{ {
ExtensionContext::instance().report('E', 0, eventContextC, "Process exited (%lu)", ExtensionContext::instance().report('E', 0, eventContextC, "Process exited (%lu)",
ExitCode); ExitCode);
const HRESULT hr = m_wrapped ? m_wrapped->ExitProcess(ExitCode) : S_OK;
dprintf("%s ExitProcess %u\n", creatorOutputPrefixC, ExitCode); // Remotely debugged process exited, there is no session-inactive notification.
return m_wrapped ? m_wrapped->ExitProcess(ExitCode) : S_OK; // Note: We get deleted here, so, order is important.
ExtensionContext::instance().unhookCallbacks();
return hr;
} }
STDMETHODIMP EventCallback::LoadModule( STDMETHODIMP EventCallback::LoadModule(

View File

@@ -61,6 +61,8 @@ public:
// Call this from the first extension command that gets a client. // Call this from the first extension command that gets a client.
// Does not work when called from initialization. // Does not work when called from initialization.
void hookCallbacks(CIDebugClient *client); void hookCallbacks(CIDebugClient *client);
// Undo hooking.
void unhookCallbacks();
// Report output in standardized format understood by Qt Creator. // Report output in standardized format understood by Qt Creator.
// '<qtcreatorcdbext>|R|<token>|<serviceName>|<one-line-output>'. // '<qtcreatorcdbext>|R|<token>|<serviceName>|<one-line-output>'.
@@ -81,7 +83,6 @@ public:
void setStopReason(const StopReasonMap &, const std::string &reason = std::string()); void setStopReason(const StopReasonMap &, const std::string &reason = std::string());
private: private:
void unhookCallbacks();
bool isInitialized() const; bool isInitialized() const;
void discardSymbolGroup(); void discardSymbolGroup();

View File

@@ -12,4 +12,5 @@ modules
idle idle
help help
memory memory
shutdownex
KnownStructOutput KnownStructOutput

View File

@@ -351,6 +351,15 @@ extern "C" HRESULT CALLBACK memory(CIDebugClient *Client, PCSTR argsIn)
return S_OK; return S_OK;
} }
// Extension command 'shutdownex' (shutdown is reserved):
// Unhook the output callbacks. This is normally done by the session
// inaccessible notification, however, this does not work for remote-controlled sessions.
extern "C" HRESULT CALLBACK shutdownex(CIDebugClient *, PCSTR)
{
ExtensionContext::instance().unhookCallbacks();
return S_OK;
}
// Hook for dumping Known Structs. Not currently used. // Hook for dumping Known Structs. Not currently used.
// Shows up in 'dv' as well as IDebugSymbolGroup::GetValueText. // Shows up in 'dv' as well as IDebugSymbolGroup::GetValueText.

View File

@@ -48,6 +48,7 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <utils/synchronousprocess.h>
#include <utils/winutils.h> #include <utils/winutils.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/savedaction.h> #include <utils/savedaction.h>
@@ -228,7 +229,6 @@ static inline bool validMode(DebuggerStartMode sm)
case NoStartMode: case NoStartMode:
case AttachTcf: case AttachTcf:
case AttachCore: case AttachCore:
case AttachToRemote:
case StartRemoteGdb: case StartRemoteGdb:
return false; return false;
default: default:
@@ -334,7 +334,7 @@ void CdbEngine::setupEngine()
} }
// Determine full path to the CDB extension library. // Determine full path to the CDB extension library.
static inline QString extensionLibraryName(bool is64Bit) QString CdbEngine::extensionLibraryName(bool is64Bit)
{ {
// Determine extension lib name and path to use // Determine extension lib name and path to use
QString rc; QString rc;
@@ -387,18 +387,24 @@ bool CdbEngine::doSetupEngine(QString *errorMessage)
// Determine extension lib name and path to use // Determine extension lib name and path to use
// The extension is passed as relative name with the path variable set // The extension is passed as relative name with the path variable set
//(does not work with absolute path names) //(does not work with absolute path names)
const QFileInfo extensionFi(extensionLibraryName(m_options->is64bit)); const QFileInfo extensionFi(CdbEngine::extensionLibraryName(m_options->is64bit));
if (!extensionFi.isFile()) { if (!extensionFi.isFile()) {
*errorMessage = QString::fromLatin1("Internal error: The extension %1 cannot be found."). *errorMessage = QString::fromLatin1("Internal error: The extension %1 cannot be found.").
arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath())); arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath()));
return false; return false;
} }
const QString extensionFileName = extensionFi.fileName();
// Prepare arguments // Prepare arguments
const DebuggerStartParameters &sp = startParameters(); const DebuggerStartParameters &sp = startParameters();
QStringList arguments; QStringList arguments;
const bool isRemote = sp.startMode == AttachToRemote;
if (isRemote) { // Must be first
arguments << QLatin1String("-remote") << sp.remoteChannel;
} else {
arguments << (QLatin1String("-a") + extensionFileName);
}
// Source line info/No terminal breakpoint / Pull extension // Source line info/No terminal breakpoint / Pull extension
arguments << QLatin1String("-lines") << QLatin1String("-G") arguments << QLatin1String("-lines") << QLatin1String("-G")
<< (QLatin1String("-a") + extensionFi.fileName())
// register idle (debuggee stop) notification // register idle (debuggee stop) notification
<< QLatin1String("-c") << QLatin1String("-c")
<< QString::fromAscii(".idle_cmd " + m_extensionCommandPrefixBA + "idle"); << QString::fromAscii(".idle_cmd " + m_extensionCommandPrefixBA + "idle");
@@ -413,8 +419,10 @@ bool CdbEngine::doSetupEngine(QString *errorMessage)
case StartExternal: case StartExternal:
arguments << QDir::toNativeSeparators(sp.executable); arguments << QDir::toNativeSeparators(sp.executable);
break; break;
case AttachToRemote:
break;
case AttachExternal: case AttachExternal:
case AttachCrashedExternal: // @TODO: event handle for crashed? case AttachCrashedExternal:
arguments << QLatin1String("-p") << QString::number(sp.attachPID); arguments << QLatin1String("-p") << QString::number(sp.attachPID);
if (sp.startMode == AttachCrashedExternal) if (sp.startMode == AttachCrashedExternal)
arguments << QLatin1String("-e") << sp.crashParameter << QLatin1String("-g"); arguments << QLatin1String("-e") << sp.crashParameter << QLatin1String("-g");
@@ -451,17 +459,28 @@ bool CdbEngine::doSetupEngine(QString *errorMessage)
showMessage(QString::fromLatin1("%1 running as %2"). showMessage(QString::fromLatin1("%1 running as %2").
arg(QDir::toNativeSeparators(executable)).arg(pid), LogMisc); arg(QDir::toNativeSeparators(executable)).arg(pid), LogMisc);
m_hasDebuggee = true; m_hasDebuggee = true;
if (isRemote) { // We do not get an 'idle' in a remote session, but are accessible
m_accessible = true;
const QByteArray loadCommand = QByteArray(".load ")
+ extensionFileName.toLocal8Bit();
postCommand(loadCommand, 0);
notifyEngineSetupOk();
}
return true; return true;
} }
void CdbEngine::setupInferior() void CdbEngine::setupInferior()
{ {
if (debug)
qDebug("setupInferior");
attemptBreakpointSynchronization(); attemptBreakpointSynchronization();
postExtensionCommand("pid", QByteArray(), 0, &CdbEngine::handlePid); postExtensionCommand("pid", QByteArray(), 0, &CdbEngine::handlePid);
} }
void CdbEngine::runEngine() void CdbEngine::runEngine()
{ {
if (debug)
qDebug("runEngine");
postCommand("g", 0); postCommand("g", 0);
} }
@@ -477,6 +496,11 @@ void CdbEngine::shutdownInferior()
notifyInferiorShutdownOk(); notifyInferiorShutdownOk();
return; return;
} }
if (!canInterruptInferior()) {
notifyInferiorShutdownFailed();
return;
}
if (m_accessible) { if (m_accessible) {
if (startParameters().startMode == AttachExternal || startParameters().startMode == AttachCrashedExternal) if (startParameters().startMode == AttachExternal || startParameters().startMode == AttachCrashedExternal)
detachDebugger(); detachDebugger();
@@ -513,9 +537,20 @@ void CdbEngine::shutdownEngine()
if (m_accessible) { if (m_accessible) {
if (startParameters().startMode == AttachExternal) if (startParameters().startMode == AttachExternal)
detachDebugger(); detachDebugger();
postCommand("q", 0); // Remote requires a bit more force to quit.
if (startParameters().startMode == AttachToRemote) {
postCommand(m_extensionCommandPrefixBA + "shutdownex", 0);
postCommand("qq", 0);
} else {
postCommand("q", 0);
}
m_notifyEngineShutdownOnTermination = true; m_notifyEngineShutdownOnTermination = true;
return; return;
} else {
// Remote process. No can do, currently
m_notifyEngineShutdownOnTermination = true;
Utils::SynchronousProcess::stopProcess(m_process);
return;
} }
// Lost debuggee, debugger should quit anytime now // Lost debuggee, debugger should quit anytime now
if (!m_hasDebuggee) { if (!m_hasDebuggee) {
@@ -638,9 +673,21 @@ void CdbEngine::doContinueInferior()
postCommand(QByteArray("g"), 0); postCommand(QByteArray("g"), 0);
} }
bool CdbEngine::canInterruptInferior() const
{
return startParameters().startMode != AttachToRemote;
}
void CdbEngine::interruptInferior() void CdbEngine::interruptInferior()
{ {
doInterruptInferior(NoSpecialStop); if (canInterruptInferior()) {
doInterruptInferior(NoSpecialStop);
} else {
showMessage(tr("Interrupting is not possible in remote sessions."), LogError);
notifyInferiorStopOk();
notifyInferiorRunRequested();
notifyInferiorRunOk();
}
} }
void CdbEngine::doInterruptInferior(SpecialStopMode sm) void CdbEngine::doInterruptInferior(SpecialStopMode sm)

View File

@@ -115,7 +115,7 @@ public:
virtual void reloadSourceFiles(); virtual void reloadSourceFiles();
virtual void reloadFullStack(); virtual void reloadFullStack();
//virtual bool isSynchronous() const { return true; } static QString extensionLibraryName(bool is64Bit);
private slots: private slots:
void readyReadStandardOut(); void readyReadStandardOut();
@@ -151,6 +151,7 @@ private:
void doContinueInferior(); void doContinueInferior();
inline void parseOutputLine(QByteArray line); inline void parseOutputLine(QByteArray line);
inline bool isCdbProcessRunning() const { return m_process.state() != QProcess::NotRunning; } inline bool isCdbProcessRunning() const { return m_process.state() != QProcess::NotRunning; }
bool canInterruptInferior() const;
// Builtin commands // Builtin commands
void dummyHandler(const CdbBuiltinCommandPtr &); void dummyHandler(const CdbBuiltinCommandPtr &);

View File

@@ -30,15 +30,23 @@
#include "cdboptionspage2.h" #include "cdboptionspage2.h"
#include "cdboptions2.h" #include "cdboptions2.h"
#include "debuggerconstants.h" #include "debuggerconstants.h"
#include "cdbengine2.h"
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
# include <utils/winutils.h> # include <utils/winutils.h>
#endif #endif
#include <utils/synchronousprocess.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtCore/QUrl> #include <QtCore/QUrl>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QDateTime>
#include <QtCore/QTextStream> #include <QtCore/QTextStream>
#include <QtCore/QTimer>
#include <QtCore/QProcess>
#include <QtGui/QMessageBox> #include <QtGui/QMessageBox>
#include <QtGui/QDesktopServices> #include <QtGui/QDesktopServices>
@@ -66,7 +74,7 @@ static inline QString msgPathConfigNote()
} }
CdbOptionsPageWidget::CdbOptionsPageWidget(QWidget *parent) : CdbOptionsPageWidget::CdbOptionsPageWidget(QWidget *parent) :
QWidget(parent) QWidget(parent), m_reportTimer(0)
{ {
m_ui.setupUi(this); m_ui.setupUi(this);
m_ui.noteLabel->setText(msgPathConfigNote()); m_ui.noteLabel->setText(msgPathConfigNote());
@@ -75,10 +83,9 @@ CdbOptionsPageWidget::CdbOptionsPageWidget(QWidget *parent) :
m_ui.pathChooser->setExpectedKind(Utils::PathChooser::ExistingCommand); m_ui.pathChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
m_ui.pathChooser->addButton(tr("Autodetect"), this, SLOT(autoDetect())); m_ui.pathChooser->addButton(tr("Autodetect"), this, SLOT(autoDetect()));
m_ui.failureLabel->setVisible(false); m_ui.cdbPathGroupBox->installEventFilter(this);
} }
void CdbOptionsPageWidget::setOptions(CdbOptions &o) void CdbOptionsPageWidget::setOptions(CdbOptions &o)
{ {
m_ui.pathChooser->setPath(o.executable); m_ui.pathChooser->setPath(o.executable);
@@ -88,17 +95,33 @@ void CdbOptionsPageWidget::setOptions(CdbOptions &o)
m_ui.sourcePathListEditor->setPathList(o.sourcePaths); m_ui.sourcePathListEditor->setPathList(o.sourcePaths);
} }
bool CdbOptionsPageWidget::is64Bit() const
{
return m_ui.is64BitCheckBox->isChecked();
}
QString CdbOptionsPageWidget::path() const
{
return m_ui.pathChooser->path();
}
CdbOptions CdbOptionsPageWidget::options() const CdbOptions CdbOptionsPageWidget::options() const
{ {
CdbOptions rc; CdbOptions rc;
rc.executable = m_ui.pathChooser->path(); rc.executable = path();
rc.enabled = m_ui.cdbPathGroupBox->isChecked(); rc.enabled = m_ui.cdbPathGroupBox->isChecked();
rc.is64bit = m_ui.is64BitCheckBox->isChecked(); rc.is64bit = is64Bit();
rc.symbolPaths = m_ui.symbolPathListEditor->pathList(); rc.symbolPaths = m_ui.symbolPathListEditor->pathList();
rc.sourcePaths = m_ui.sourcePathListEditor->pathList(); rc.sourcePaths = m_ui.sourcePathListEditor->pathList();
return rc; return rc;
} }
void CdbOptionsPageWidget::hideReportLabel()
{
m_ui.reportLabel->clear();
m_ui.reportLabel->setVisible(false);
}
void CdbOptionsPageWidget::autoDetect() void CdbOptionsPageWidget::autoDetect()
{ {
QString executable; QString executable;
@@ -109,6 +132,10 @@ void CdbOptionsPageWidget::autoDetect()
if (ok) { if (ok) {
m_ui.is64BitCheckBox->setChecked(is64bit); m_ui.is64BitCheckBox->setChecked(is64bit);
m_ui.pathChooser->setPath(executable); m_ui.pathChooser->setPath(executable);
QString report;
// Now check for the extension library as well.
const bool allOk = checkInstallation(executable, is64Bit(), &report);
setReport(report, allOk);
} else { } else {
const QString msg = tr("\"Debugging Tools for Windows\" could not be found."); const QString msg = tr("\"Debugging Tools for Windows\" could not be found.");
const QString details = tr("Checked:\n%1").arg(checkedDirectories.join(QString(QLatin1Char('\n')))); const QString details = tr("Checked:\n%1").arg(checkedDirectories.join(QString(QLatin1Char('\n'))));
@@ -118,10 +145,23 @@ void CdbOptionsPageWidget::autoDetect()
} }
} }
void CdbOptionsPageWidget::setFailureMessage(const QString &msg) void CdbOptionsPageWidget::setReport(const QString &msg, bool success)
{ {
m_ui.failureLabel->setText(msg); // Hide label after some interval
m_ui.failureLabel->setVisible(!msg.isEmpty()); if (!m_reportTimer) {
m_reportTimer = new QTimer(this);
m_reportTimer->setSingleShot(true);
connect(m_reportTimer, SIGNAL(timeout()), this, SLOT(hideReportLabel()));
} else {
if (m_reportTimer->isActive())
m_reportTimer->stop();
}
m_reportTimer->setInterval(success ? 10000 : 20000);
m_reportTimer->start();
m_ui.reportLabel->setText(msg);
m_ui.reportLabel->setStyleSheet(success ? QString() : QString::fromAscii("background-color : 'red'"));
m_ui.reportLabel->setVisible(true);
} }
void CdbOptionsPageWidget::downLoadLinkActivated(const QString &link) void CdbOptionsPageWidget::downLoadLinkActivated(const QString &link)
@@ -138,6 +178,62 @@ QString CdbOptionsPageWidget::searchKeywords() const
return rc; return rc;
} }
static QString cdbVersion(const QString &executable)
{
QProcess cdb;
cdb.start(executable, QStringList(QLatin1String("-version")));
cdb.closeWriteChannel();
if (!cdb.waitForStarted())
return QString();
if (!cdb.waitForFinished()) {
Utils::SynchronousProcess::stopProcess(cdb);
return QString();
}
return QString::fromLocal8Bit(cdb.readAllStandardOutput());
}
bool CdbOptionsPageWidget::checkInstallation(const QString &executable,
bool is64Bit, QString *message)
{
// 1) Check on executable
unsigned checkedItems = 0;
QString rc;
if (executable.isEmpty()) {
message->append(tr("No cdb executable specified.\n"));
} else {
const QString version = cdbVersion(executable);
if (version.isEmpty()) {
message->append(tr("Unable to determine version of %1.\n").
arg(executable));
} else {
message->append(tr("Version: %1").arg(version));
checkedItems++;
}
}
// 2) Check on extension library
const QFileInfo extensionFi(CdbEngine::extensionLibraryName(is64Bit));
if (extensionFi.isFile()) {
message->append(tr("Extension library: %1, built: %3.\n").
arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath())).
arg(extensionFi.lastModified().toString(Qt::SystemLocaleShortDate)));
checkedItems++;
} else {
message->append("Extension library not found.\n");
}
return checkedItems == 2u;
}
bool CdbOptionsPageWidget::eventFilter(QObject *o, QEvent *e)
{
if (o != m_ui.cdbPathGroupBox || e->type() != QEvent::ToolTip)
return QWidget::eventFilter(o, e);
QString message;
checkInstallation(path(), is64Bit(), &message);
m_ui.cdbPathGroupBox->setToolTip(message);
return false;
}
// ---------- CdbOptionsPage // ---------- CdbOptionsPage
CdbOptionsPage *CdbOptionsPage::m_instance = 0; CdbOptionsPage *CdbOptionsPage::m_instance = 0;
@@ -183,7 +279,6 @@ QWidget *CdbOptionsPage::createPage(QWidget *parent)
{ {
m_widget = new CdbOptionsPageWidget(parent); m_widget = new CdbOptionsPageWidget(parent);
m_widget->setOptions(*m_options); m_widget->setOptions(*m_options);
m_widget->setFailureMessage(m_failureMessage);
if (m_searchKeywords.isEmpty()) if (m_searchKeywords.isEmpty())
m_searchKeywords = m_widget->searchKeywords(); m_searchKeywords = m_widget->searchKeywords();
return m_widget; return m_widget;

View File

@@ -39,6 +39,8 @@
#include <QtCore/QPointer> #include <QtCore/QPointer>
#include <QtCore/QSharedPointer> #include <QtCore/QSharedPointer>
QT_FORWARD_DECLARE_CLASS(QTimer)
namespace Debugger { namespace Debugger {
namespace Cdb { namespace Cdb {
@@ -51,16 +53,25 @@ public:
void setOptions(CdbOptions &o); void setOptions(CdbOptions &o);
CdbOptions options() const; CdbOptions options() const;
void setFailureMessage(const QString &);
QString searchKeywords() const; QString searchKeywords() const;
virtual bool eventFilter(QObject *, QEvent *);
private slots: private slots:
void autoDetect(); void autoDetect();
void downLoadLinkActivated(const QString &); void downLoadLinkActivated(const QString &);
void hideReportLabel();
private: private:
void setReport(const QString &, bool success);
inline bool is64Bit() const;
inline QString path() const;
static bool checkInstallation(const QString &executable, bool is64Bit,
QString *message);
Ui::CdbOptionsPageWidget2 m_ui; Ui::CdbOptionsPageWidget2 m_ui;
QTimer *m_reportTimer;
}; };
class CdbOptionsPage : public Core::IOptionsPage class CdbOptionsPage : public Core::IOptionsPage
@@ -87,15 +98,12 @@ public:
static QString settingsId(); static QString settingsId();
// Load failure messages can be displayed here
void setFailureMessage(const QString &msg) { m_failureMessage = msg; }
QSharedPointer<CdbOptions> options() const { return m_options; } QSharedPointer<CdbOptions> options() const { return m_options; }
private: private:
static CdbOptionsPage *m_instance; static CdbOptionsPage *m_instance;
const QSharedPointer<CdbOptions> m_options; const QSharedPointer<CdbOptions> m_options;
QPointer<CdbOptionsPageWidget> m_widget; QPointer<CdbOptionsPageWidget> m_widget;
QString m_failureMessage;
QString m_searchKeywords; QString m_searchKeywords;
}; };

View File

@@ -2,14 +2,19 @@
<ui version="4.0"> <ui version="4.0">
<class>Debugger::Cdb::CdbOptionsPageWidget2</class> <class>Debugger::Cdb::CdbOptionsPageWidget2</class>
<widget class="QWidget" name="Debugger::Cdb::CdbOptionsPageWidget2"> <widget class="QWidget" name="Debugger::Cdb::CdbOptionsPageWidget2">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>135</width>
<height>246</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="QGroupBox" name="cdbPathGroupBox"> <widget class="QGroupBox" name="cdbPathGroupBox">
<property name="toolTip">
<string>These options take effect at the next start of Qt Creator.</string>
</property>
<property name="title"> <property name="title">
<string extracomment="Placeholder">CDB</string> <string extracomment="Placeholder">CDB</string>
</property> </property>
@@ -92,13 +97,16 @@
</spacer> </spacer>
</item> </item>
<item> <item>
<widget class="QLabel" name="failureLabel"> <widget class="QLabel" name="reportLabel">
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">background-color: 'red';</string> <string notr="true"/>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>

View File

@@ -154,10 +154,14 @@ QVariant cdbIntegerValue(const QByteArray &t)
return converted; return converted;
} }
/* Parse: /* Parse: 64bit:
\code \code
Child-SP RetAddr Call Site Child-SP RetAddr Call Site
00000000`0012a290 00000000`70deb844 QtCored4!QString::QString+0x18 [c:\qt\src\corelib\tools\qstring.h @ 729] 00000000`0012a290 00000000`70deb844 QtCored4!QString::QString+0x18 [c:\qt\src\corelib\tools\qstring.h @ 729]
\endcode 32bit:
\code
ChildEBP RetAddr
0012cc68 6714d114 QtCored4!QString::QString+0xf [d:\dev\qt4.7-vs8\qt\src\corelib\tools\qstring.h @ 729]
\endcode */ \endcode */
static inline bool isHexDigit(char c) static inline bool isHexDigit(char c)
@@ -168,7 +172,7 @@ static inline bool isHexDigit(char c)
static inline bool parseStackFrame(QByteArray line, Debugger::Internal::StackFrame *frame) static inline bool parseStackFrame(QByteArray line, Debugger::Internal::StackFrame *frame)
{ {
frame->clear(); frame->clear();
if (line.isEmpty() || line.startsWith("Child-SP") || !isHexDigit(line.at(0))) if (line.isEmpty() || line.startsWith("Child") || !isHexDigit(line.at(0)))
return false; return false;
if (line.endsWith(']')) { if (line.endsWith(']')) {
const int sourceFilePos = line.lastIndexOf('['); const int sourceFilePos = line.lastIndexOf('[');

View File

@@ -29,6 +29,7 @@
#include "debuggerdialogs.h" #include "debuggerdialogs.h"
#include "debuggerconstants.h" #include "debuggerconstants.h"
#include "cdb2/cdbengine2.h"
#include "ui_attachcoredialog.h" #include "ui_attachcoredialog.h"
#include "ui_attachexternaldialog.h" #include "ui_attachexternaldialog.h"
@@ -43,9 +44,11 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <utils/synchronousprocess.h> #include <utils/synchronousprocess.h>
#include <utils/historycompleter.h> #include <utils/historycompleter.h>
#include <utils/qtcassert.h>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QProcess> #include <QtCore/QProcess>
#include <QtCore/QRegExp>
#include <QtCore/QDir> #include <QtCore/QDir>
#include <QtCore/QFile> #include <QtCore/QFile>
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
@@ -56,6 +59,7 @@
#include <QtGui/QProxyModel> #include <QtGui/QProxyModel>
#include <QtGui/QSortFilterProxyModel> #include <QtGui/QSortFilterProxyModel>
#include <QtGui/QMessageBox> #include <QtGui/QMessageBox>
#include <QtGui/QGroupBox>
using namespace Utils; using namespace Utils;
@@ -744,6 +748,97 @@ void StartRemoteDialog::updateState()
m_ui->serverStartScript->setEnabled(enabled); m_ui->serverStartScript->setEnabled(enabled);
} }
// --------- StartRemoteCdbDialog
static inline QString cdbRemoteHelp()
{
const char *cdbConnectionSyntax =
"Server:Port<br>"
"tcp:server=Server,port=Port[,password=Password][,ipversion=6]\n"
"tcp:clicon=Server,port=Port[,password=Password][,ipversion=6]\n"
"npipe:server=Server,pipe=PipeName[,password=Password]\n"
"com:port=COMPort,baud=BaudRate,channel=COMChannel[,password=Password]\n"
"spipe:proto=Protocol,{certuser=Cert|machuser=Cert},server=Server,pipe=PipeName[,password=Password]\n"
"ssl:proto=Protocol,{certuser=Cert|machuser=Cert},server=Server,port=Socket[,password=Password]\n"
"ssl:proto=Protocol,{certuser=Cert|machuser=Cert},clicon=Server,port=Socket[,password=Password]";
const QString ext32 = QDir::toNativeSeparators(Debugger::Cdb::CdbEngine::extensionLibraryName(false));
const QString ext64 = QDir::toNativeSeparators(Debugger::Cdb::CdbEngine::extensionLibraryName(true));
return StartRemoteCdbDialog::tr(
"<html><body><p>The remote CDB needs to load the matching Qt Creator CDB extension "
"(<code>%1</code> or <code>%2</code>, respectively).</p><p>Copy it onto the remote machine and set the "
"environment variable <code>%3</code> to point to its folder.</p><p>"
"Launch the remote CDB as <code>%4 &lt;executable&gt;</code> "
" to use TCP/IP as communication protocol.</p><p>Enter the connection parameters as:</p>"
"<pre>%5</pre></body></html>").
arg(ext32, ext64, QLatin1String("_NT_DEBUGGER_EXTENSION_PATH"),
QLatin1String("cdb.exe -server tcp:port=1234"),
QLatin1String(cdbConnectionSyntax));
}
StartRemoteCdbDialog::StartRemoteCdbDialog(QWidget *parent) :
QDialog(parent), m_okButton(0), m_lineEdit(new QLineEdit)
{
setWindowTitle(tr("Start a CDB Remote Session"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
QGroupBox *groupBox = new QGroupBox;
QFormLayout *formLayout = new QFormLayout;
QLabel *helpLabel = new QLabel(cdbRemoteHelp());
helpLabel->setWordWrap(true);
helpLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
formLayout->addRow(helpLabel);
QLabel *label = new QLabel(tr("&Connection:"));
label->setBuddy(m_lineEdit);
m_lineEdit->setMinimumWidth(400);
connect(m_lineEdit, SIGNAL(textChanged(QString)), this, SLOT(textChanged(QString)));
formLayout->addRow(label, m_lineEdit);
groupBox->setLayout(formLayout);
QVBoxLayout *vLayout = new QVBoxLayout;
vLayout->addWidget(groupBox);
QDialogButtonBox *box = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
vLayout->addWidget(box);
m_okButton = box->button(QDialogButtonBox::Ok);
connect(m_lineEdit, SIGNAL(returnPressed()), m_okButton, SLOT(animateClick()));
m_okButton->setEnabled(false);
connect(box, SIGNAL(accepted()), this, SLOT(accept()));
connect(box, SIGNAL(rejected()), this, SLOT(reject()));
setLayout(vLayout);
}
void StartRemoteCdbDialog::accept()
{
if (!m_lineEdit->text().isEmpty())
QDialog::accept();
}
StartRemoteCdbDialog::~StartRemoteCdbDialog()
{
}
void StartRemoteCdbDialog::textChanged(const QString &t)
{
m_okButton->setEnabled(!t.isEmpty());
}
QString StartRemoteCdbDialog::connection() const
{
const QString rc = m_lineEdit->text();
// Transform an IP:POrt ('localhost:1234') specification into full spec
QRegExp ipRegexp(QLatin1String("([\\w\\.\\-_]+):([0-9]{1,4})"));
QTC_ASSERT(ipRegexp.isValid(), return QString());
if (ipRegexp.exactMatch(rc))
return QString::fromAscii("tcp:server=%1,port=%2").arg(ipRegexp.cap(1), ipRegexp.cap(2));
return rc;
}
void StartRemoteCdbDialog::setConnection(const QString &c)
{
m_lineEdit->setText(c);
m_okButton->setEnabled(!c.isEmpty());
}
AddressDialog::AddressDialog(QWidget *parent) : AddressDialog::AddressDialog(QWidget *parent) :
QDialog(parent), QDialog(parent),
m_lineEdit(new QLineEdit), m_lineEdit(new QLineEdit),

View File

@@ -200,6 +200,27 @@ private:
Ui::StartRemoteDialog *m_ui; Ui::StartRemoteDialog *m_ui;
}; };
class StartRemoteCdbDialog : public QDialog
{
Q_OBJECT
public:
explicit StartRemoteCdbDialog(QWidget *parent);
~StartRemoteCdbDialog();
QString connection() const;
void setConnection(const QString &);
virtual void accept();
private slots:
void textChanged(const QString &);
private:
QPushButton *m_okButton;
QLineEdit *m_lineEdit;
};
class AddressDialog : public QDialog { class AddressDialog : public QDialog {
Q_OBJECT Q_OBJECT
public: public:

View File

@@ -343,6 +343,7 @@ const char * const ATTACHEXTERNAL = "Debugger.AttachExternal";
const char * const ATTACHCORE = "Debugger.AttachCore"; const char * const ATTACHCORE = "Debugger.AttachCore";
const char * const ATTACHTCF = "Debugger.AttachTcf"; const char * const ATTACHTCF = "Debugger.AttachTcf";
const char * const ATTACHREMOTE = "Debugger.AttachRemote"; const char * const ATTACHREMOTE = "Debugger.AttachRemote";
const char * const ATTACHREMOTECDB = "Debugger.AttachRemoteCDB";
const char * const DETACH = "Debugger.Detach"; const char * const DETACH = "Debugger.Detach";
const char * const RUN_TO_LINE1 = "Debugger.RunToLine1"; const char * const RUN_TO_LINE1 = "Debugger.RunToLine1";
@@ -971,6 +972,7 @@ public slots:
void debugProject(); void debugProject();
void startExternalApplication(); void startExternalApplication();
void startRemoteCdbSession();
void startRemoteApplication(); void startRemoteApplication();
void attachExternalApplication(); void attachExternalApplication();
void attachExternalApplication void attachExternalApplication
@@ -1243,6 +1245,7 @@ public:
QAction *m_debugAction; QAction *m_debugAction;
QAction *m_startExternalAction; QAction *m_startExternalAction;
QAction *m_startRemoteAction; QAction *m_startRemoteAction;
QAction *m_startRemoteCdbAction;
QAction *m_attachExternalAction; QAction *m_attachExternalAction;
QAction *m_attachCoreAction; QAction *m_attachCoreAction;
QAction *m_attachTcfAction; QAction *m_attachTcfAction;
@@ -1303,8 +1306,7 @@ public:
bool m_gdbBinariesChanged; bool m_gdbBinariesChanged;
}; };
DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin) : m_startRemoteCdbAction(0)
DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin)
{ {
QTC_ASSERT(!theDebuggerCore, /**/); QTC_ASSERT(!theDebuggerCore, /**/);
theDebuggerCore = this; theDebuggerCore = this;
@@ -1669,11 +1671,15 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
act->setText(tr("Start and Attach to Remote Application...")); act->setText(tr("Start and Attach to Remote Application..."));
connect(act, SIGNAL(triggered()), SLOT(startRemoteApplication())); connect(act, SIGNAL(triggered()), SLOT(startRemoteApplication()));
#ifdef Q_OS_WIN
m_startRemoteCdbAction = new QAction(tr("Attach to Remote CDB Session..."), this);
connect(m_startRemoteCdbAction, SIGNAL(triggered()), SLOT(startRemoteCdbSession()));
#endif
act = m_detachAction = new QAction(this); act = m_detachAction = new QAction(this);
act->setText(tr("Detach Debugger")); act->setText(tr("Detach Debugger"));
connect(act, SIGNAL(triggered()), SLOT(handleExecDetach())); connect(act, SIGNAL(triggered()), SLOT(handleExecDetach()));
Core::Command *cmd = 0; Core::Command *cmd = 0;
Core::ActionContainer *mstart = Core::ActionContainer *mstart =
@@ -1716,6 +1722,13 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
cmd->setAttribute(Command::CA_Hide); cmd->setAttribute(Command::CA_Hide);
mstart->addAction(cmd, CC::G_DEFAULT_ONE); mstart->addAction(cmd, CC::G_DEFAULT_ONE);
if (m_startRemoteCdbAction) {
cmd = am->registerAction(m_startRemoteCdbAction,
Constants::ATTACHREMOTECDB, globalcontext);
cmd->setAttribute(Command::CA_Hide);
mstart->addAction(cmd, CC::G_DEFAULT_ONE);
}
cmd = am->registerAction(m_detachAction, cmd = am->registerAction(m_detachAction,
Constants::DETACH, globalcontext); Constants::DETACH, globalcontext);
cmd->setAttribute(Command::CA_Hide); cmd->setAttribute(Command::CA_Hide);
@@ -2124,6 +2137,25 @@ void DebuggerPluginPrivate::attachRemote(const QString &spec)
startDebugger(rc); startDebugger(rc);
} }
void DebuggerPluginPrivate::startRemoteCdbSession()
{
const QString connectionKey = _("CdbRemoteConnection");
DebuggerStartParameters sp;
sp.toolChainType = ProjectExplorer::ToolChain_MSVC;
sp.startMode = AttachToRemote;
StartRemoteCdbDialog dlg(mainWindow());
QString previousConnection = configValue(connectionKey).toString();
if (previousConnection.isEmpty())
previousConnection = QLatin1String("localhost:1234");
dlg.setConnection(previousConnection);
if (dlg.exec() != QDialog::Accepted)
return;
sp.remoteChannel = dlg.connection();
setConfigValue(connectionKey, sp.remoteChannel);
if (RunControl *rc = createDebugger(sp))
startDebugger(rc);
}
void DebuggerPluginPrivate::startRemoteApplication() void DebuggerPluginPrivate::startRemoteApplication()
{ {
DebuggerStartParameters sp; DebuggerStartParameters sp;