From 581dae100abf61d8c4d2a647cd7f546fda85d93d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Fri, 13 Feb 2009 12:56:39 +0100 Subject: [PATCH 01/62] Fixed dock widget features on startup in locked state In locked state the dock widgets shouldn't have AllDockWidgetFeatures set, but rather NoDockWidgetFeatures. Otherwise a hidden one-pixel wide area exists that allows people to move/float a dockwidget, which can be confusing. Task: 244531 (cherry picked from commit ba9ade6d0cb89baacf1ee6a42d2381d772f8938e) --- src/plugins/debugger/debuggermanager.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 423321fc7ba..95b874a3f8a 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -451,10 +451,7 @@ QDockWidget *DebuggerManager::createDockForWidget(QWidget *widget) { QDockWidget *dockWidget = new QDockWidget(widget->windowTitle(), m_mainWindow); dockWidget->setObjectName(widget->windowTitle()); - //dockWidget->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::RightDockWidgetArea); - dockWidget->setAllowedAreas(Qt::AllDockWidgetAreas); // that space is needed. - //dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures); - dockWidget->setFeatures(QDockWidget::AllDockWidgetFeatures); + dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures); dockWidget->setTitleBarWidget(new QWidget(dockWidget)); dockWidget->setWidget(widget); connect(dockWidget->toggleViewAction(), SIGNAL(toggled(bool)), From ae7864f9c0ba2778756a89c3d0e6c97b76902263 Mon Sep 17 00:00:00 2001 From: lowinu Date: Fri, 13 Feb 2009 13:53:11 +0100 Subject: [PATCH 02/62] Fixes: cpaster plugin options RevBy: andre Details: - the settings have not been taken into respect so far. --- src/plugins/cpaster/cpasterplugin.cpp | 4 +++- src/plugins/cpaster/settingspage.h | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/plugins/cpaster/cpasterplugin.cpp b/src/plugins/cpaster/cpasterplugin.cpp index f0cda5147c2..82a8be37d72 100644 --- a/src/plugins/cpaster/cpasterplugin.cpp +++ b/src/plugins/cpaster/cpasterplugin.cpp @@ -185,7 +185,9 @@ void CodepasterPlugin::post() // Submit to codepaster - m_poster = new CustomPoster(serverUrl()); + m_poster = new CustomPoster(serverUrl(), + m_settingsPage->copyToClipBoard(), + m_settingsPage->displayOutput()); // Copied from cpaster. Otherwise lineendings will screw up if (!data.contains("\r\n")) { diff --git a/src/plugins/cpaster/settingspage.h b/src/plugins/cpaster/settingspage.h index a492030752c..98df299a5f6 100644 --- a/src/plugins/cpaster/settingspage.h +++ b/src/plugins/cpaster/settingspage.h @@ -65,8 +65,8 @@ public: QString username() const; QUrl serverUrl() const; - bool copyToClipBoard() const; - bool displayOutput() const; + inline bool copyToClipBoard() const { return m_copy; } + inline bool displayOutput() const { return m_output; } private: Ui_SettingsPage m_ui; From b6c15d1ba906f9e7ed124b91bd2d7adbd46953ea Mon Sep 17 00:00:00 2001 From: lowinu Date: Fri, 13 Feb 2009 12:52:01 +0100 Subject: [PATCH 03/62] Fixes: add timeout value to git plugin RevBy: tba Details: - as on windows some git commands take much longer it happens fairly often, that git timeouts. - added a timeout value to the option to let the user choose maximum timeout value (minimum is 10 seconds, maximum 5 minutes) --- src/plugins/git/gitclient.cpp | 8 ++++---- src/plugins/git/gitcommand.cpp | 11 ++++++----- src/plugins/git/gitcommand.h | 5 +++-- src/plugins/git/gitsettings.cpp | 10 +++++++--- src/plugins/git/gitsettings.h | 1 + src/plugins/git/settingspage.cpp | 2 ++ src/plugins/git/settingspage.ui | 33 ++++++++++++++++++++++++-------- 7 files changed, 48 insertions(+), 22 deletions(-) diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index fe2394c019d..08bdac4ee60 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -207,20 +207,20 @@ void GitClient::diff(const QString &workingDirectory, QStringList arguments; arguments << QLatin1String("diff") << diffArgs; m_plugin->outputWindow()->append(formatCommand(binary, arguments)); - command->addJob(arguments); + command->addJob(arguments, m_settings.timeout); } else { // Files diff. if (!unstagedFileNames.empty()) { QStringList arguments; arguments << QLatin1String("diff") << diffArgs << QLatin1String("--") << unstagedFileNames; m_plugin->outputWindow()->append(formatCommand(binary, arguments)); - command->addJob(arguments); + command->addJob(arguments, m_settings.timeout); } if (!stagedFileNames.empty()) { QStringList arguments; arguments << QLatin1String("diff") << QLatin1String("--cached") << diffArgs << QLatin1String("--") << stagedFileNames; m_plugin->outputWindow()->append(formatCommand(binary, arguments)); - command->addJob(arguments); + command->addJob(arguments, m_settings.timeout); } } command->execute(); @@ -503,7 +503,7 @@ void GitClient::executeGit(const QString &workingDirectory, { m_plugin->outputWindow()->append(formatCommand(QLatin1String(Constants::GIT_BINARY), arguments)); GitCommand *command = createCommand(workingDirectory, editor, outputToWindow); - command->addJob(arguments); + command->addJob(arguments, m_settings.timeout); command->execute(); } diff --git a/src/plugins/git/gitcommand.cpp b/src/plugins/git/gitcommand.cpp index fa62401b011..8362926cecc 100644 --- a/src/plugins/git/gitcommand.cpp +++ b/src/plugins/git/gitcommand.cpp @@ -55,8 +55,9 @@ static inline QStringList environmentToList(const ProjectExplorer::Environment & return ProjectExplorer::Environment::systemEnvironment().toStringList(); } -GitCommand::Job::Job(const QStringList &a) : - arguments(a) +GitCommand::Job::Job(const QStringList &a, int t) : + arguments(a), + timeout(t) { } @@ -67,9 +68,9 @@ GitCommand::GitCommand(const QString &workingDirectory, { } -void GitCommand::addJob(const QStringList &arguments) +void GitCommand::addJob(const QStringList &arguments, int timeout) { - m_jobs.push_back(Job(arguments)); + m_jobs.push_back(Job(arguments, timeout)); } void GitCommand::execute() @@ -109,7 +110,7 @@ void GitCommand::run() qDebug() << "GitCommand::run" << j << '/' << count << m_jobs.at(j).arguments; process.start(QLatin1String(Constants::GIT_BINARY), m_jobs.at(j).arguments); - if (!process.waitForFinished()) { + if (!process.waitForFinished(m_jobs.at(j).timeout * 1000)) { ok = false; error += QLatin1String("Error: Git timed out"); break; diff --git a/src/plugins/git/gitcommand.h b/src/plugins/git/gitcommand.h index a587b748761..32b76bf3485 100644 --- a/src/plugins/git/gitcommand.h +++ b/src/plugins/git/gitcommand.h @@ -49,7 +49,7 @@ public: ProjectExplorer::Environment &environment); - void addJob(const QStringList &arguments); + void addJob(const QStringList &arguments, int timeout); void execute(); private: @@ -61,9 +61,10 @@ Q_SIGNALS: private: struct Job { - explicit Job(const QStringList &a); + explicit Job(const QStringList &a, int t); QStringList arguments; + int timeout; }; QStringList environment() const; diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp index 2b528a72d2a..02a1acc1d9e 100644 --- a/src/plugins/git/gitsettings.cpp +++ b/src/plugins/git/gitsettings.cpp @@ -40,15 +40,17 @@ static const char *groupC = "Git"; static const char *sysEnvKeyC = "SysEnv"; static const char *pathKeyC = "Path"; static const char *logCountKeyC = "LogCount"; +static const char *timeoutKeyC = "TimeOut"; -enum { defaultLogCount = 10 }; +enum { defaultLogCount = 10 , defaultTimeOut = 30}; namespace Git { namespace Internal { GitSettings::GitSettings() : adoptPath(false), - logCount(defaultLogCount) + logCount(defaultLogCount), + timeout(defaultTimeOut) { } @@ -58,6 +60,7 @@ void GitSettings::fromSettings(QSettings *settings) adoptPath = settings->value(QLatin1String(sysEnvKeyC), false).toBool(); path = settings->value(QLatin1String(pathKeyC), QString()).toString(); logCount = settings->value(QLatin1String(logCountKeyC), defaultLogCount).toInt(); + timeout = settings->value(QLatin1String(timeoutKeyC), defaultTimeOut).toInt(); settings->endGroup(); } @@ -67,12 +70,13 @@ void GitSettings::toSettings(QSettings *settings) const settings->setValue(QLatin1String(sysEnvKeyC), adoptPath); settings->setValue(QLatin1String(pathKeyC), path); settings->setValue(QLatin1String(logCountKeyC), logCount); + settings->setValue(QLatin1String(timeoutKeyC), timeout); settings->endGroup(); } bool GitSettings::equals(const GitSettings &s) const { - return adoptPath == s.adoptPath && path == s.path && logCount == s.logCount; + return adoptPath == s.adoptPath && path == s.path && logCount == s.logCount && timeout == s.timeout; } } diff --git a/src/plugins/git/gitsettings.h b/src/plugins/git/gitsettings.h index 59169922605..c2463eb326d 100644 --- a/src/plugins/git/gitsettings.h +++ b/src/plugins/git/gitsettings.h @@ -56,6 +56,7 @@ struct GitSettings bool adoptPath; QString path; int logCount; + int timeout; }; inline bool operator==(const GitSettings &p1, const GitSettings &p2) diff --git a/src/plugins/git/settingspage.cpp b/src/plugins/git/settingspage.cpp index a3b82194cec..121c7cd889b 100644 --- a/src/plugins/git/settingspage.cpp +++ b/src/plugins/git/settingspage.cpp @@ -52,6 +52,7 @@ GitSettings SettingsPageWidget::settings() const rc.path = m_ui.pathLineEdit->text(); rc.adoptPath = m_ui.environmentGroupBox->isChecked() && !rc.path.isEmpty(); rc.logCount = m_ui.logCountSpinBox->value(); + rc.timeout = m_ui.timeoutSpinBox->value(); return rc; } @@ -60,6 +61,7 @@ void SettingsPageWidget::setSettings(const GitSettings &s) m_ui.environmentGroupBox->setChecked(s.adoptPath); m_ui.pathLineEdit->setText(s.path); m_ui.logCountSpinBox->setValue(s.logCount); + m_ui.timeoutSpinBox->setValue(s.timeout); } void SettingsPageWidget::setSystemPath() diff --git a/src/plugins/git/settingspage.ui b/src/plugins/git/settingspage.ui index 94c04493aab..1a594bf4313 100644 --- a/src/plugins/git/settingspage.ui +++ b/src/plugins/git/settingspage.ui @@ -7,7 +7,7 @@ 0 0 403 - 183 + 251 @@ -69,10 +69,14 @@ - - - QFormLayout::ExpandingFieldsGrow - + + + + + Log commit display count: + + + @@ -83,10 +87,23 @@ - - + + - Log commit display count: + Timeout (seconds): + + + + + + + 10 + + + 300 + + + 30 From cbcc2e518d7365f18211a6baecbaafb0b9bcce27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Fri, 13 Feb 2009 16:29:30 +0100 Subject: [PATCH 04/62] Don't move cursor on collapse/uncollapse When the cursor isn't within the block that's being collapsed, it shouldn't be moved. When it is, it will now move upwards instead of to the start of the line. Reviewed-by: mae --- src/plugins/texteditor/basetexteditor.cpp | 10 +++++----- src/plugins/texteditor/basetexteditor_p.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index 88e145a0e58..d5b088396a5 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -2504,14 +2504,13 @@ void BaseTextEditor::extraAreaMouseEvent(QMouseEvent *e) } } - if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonDblClick) { if (e->button() == Qt::LeftButton) { if (d->m_codeFoldingVisible && TextBlockUserData::canCollapse(cursor.block()) && !TextBlockUserData::hasClosingCollapseInside(cursor.block().next()) && collapseBox(cursor.block()).contains(e->pos())) { - setTextCursor(cursor); toggleBlockVisible(cursor.block()); + d->moveCursorVisible(false); } else if (d->m_marksVisible && e->pos().x() > markWidth) { QTextCursor selection = cursor; selection.setVisualNavigation(true); @@ -3392,15 +3391,16 @@ void BaseTextEditor::setIfdefedOutBlocks(const QList } -void BaseTextEditorPrivate::moveCursorVisible() +void BaseTextEditorPrivate::moveCursorVisible(bool ensureVisible) { QTextCursor cursor = q->textCursor(); if (!cursor.block().isVisible()) { cursor.setVisualNavigation(true); - cursor.movePosition(QTextCursor::PreviousBlock); + cursor.movePosition(QTextCursor::Up); q->setTextCursor(cursor); } - q->ensureCursorVisible(); + if (ensureVisible) + q->ensureCursorVisible(); } void BaseTextEditor::collapse() diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h index 270b7444f42..9da5b27248c 100644 --- a/src/plugins/texteditor/basetexteditor_p.h +++ b/src/plugins/texteditor/basetexteditor_p.h @@ -218,7 +218,7 @@ public: QTextCursor m_findScope; QTextCursor m_selectBlockAnchor; - void moveCursorVisible(); + void moveCursorVisible(bool ensureVisible = true); }; } // namespace Internal From a0f521c7b68f9908abe9ac5d131c4fb5eab40ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Fri, 13 Feb 2009 17:33:59 +0100 Subject: [PATCH 05/62] Allow opening/closing debugger mode dockwidgets in locked mode There is no particular reason to disallow changing the visiblity of the dockwidgets in the debug mode in locked mode. --- src/plugins/debugger/debuggermanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 95b874a3f8a..f017cebccef 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -451,7 +451,7 @@ QDockWidget *DebuggerManager::createDockForWidget(QWidget *widget) { QDockWidget *dockWidget = new QDockWidget(widget->windowTitle(), m_mainWindow); dockWidget->setObjectName(widget->windowTitle()); - dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures); + dockWidget->setFeatures(QDockWidget::DockWidgetClosable); dockWidget->setTitleBarWidget(new QWidget(dockWidget)); dockWidget->setWidget(widget); connect(dockWidget->toggleViewAction(), SIGNAL(toggled(bool)), @@ -488,7 +488,7 @@ void DebuggerManager::setSimpleDockWidgetArrangement() void DebuggerManager::setLocked(bool locked) { const QDockWidget::DockWidgetFeatures features = - (locked) ? QDockWidget::NoDockWidgetFeatures : + (locked) ? QDockWidget::DockWidgetClosable : QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable; foreach (QDockWidget *dockWidget, m_dockWidgets) { From d98c141918c5f6d0618549893fbd15a199aa327d Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Fri, 13 Feb 2009 15:37:42 +0100 Subject: [PATCH 06/62] Improved the type pretty printer. (cherry picked from commit e801434799f8f4b25028f63c2595bd810277edb7) --- src/libs/cplusplus/Overview.cpp | 9 +- src/libs/cplusplus/Overview.h | 5 +- src/libs/cplusplus/TypePrettyPrinter.cpp | 240 +++++++++++++---------- src/libs/cplusplus/TypePrettyPrinter.h | 28 +-- 4 files changed, 156 insertions(+), 126 deletions(-) diff --git a/src/libs/cplusplus/Overview.cpp b/src/libs/cplusplus/Overview.cpp index 2494d11ec5e..0f973753d0b 100644 --- a/src/libs/cplusplus/Overview.cpp +++ b/src/libs/cplusplus/Overview.cpp @@ -68,6 +68,11 @@ bool Overview::showReturnTypes() const return _showReturnTypes; } +unsigned Overview::markArgument() const +{ + return _markArgument; +} + void Overview::setMarkArgument(unsigned position) { _markArgument = position; @@ -98,9 +103,5 @@ QString Overview::prettyType(const FullySpecifiedType &ty, const QString &name) const { TypePrettyPrinter pp(this); - pp.setMarkArgument(_markArgument); - pp.setShowArgumentNames(_showArgumentNames); - pp.setShowReturnTypes(_showReturnTypes); - pp.setShowFunctionSignatures(_showFunctionSignatures); return pp(ty, name); } diff --git a/src/libs/cplusplus/Overview.h b/src/libs/cplusplus/Overview.h index fa1f3cf919f..6918ee45ff8 100644 --- a/src/libs/cplusplus/Overview.h +++ b/src/libs/cplusplus/Overview.h @@ -57,7 +57,10 @@ public: bool showFunctionSignatures() const; void setShowFunctionSignatures(bool showFunctionSignatures); - void setMarkArgument(unsigned position); // 1-based + // 1-based + // ### rename + unsigned markArgument() const; + void setMarkArgument(unsigned position); QString operator()(Name *name) const { return prettyName(name); } diff --git a/src/libs/cplusplus/TypePrettyPrinter.cpp b/src/libs/cplusplus/TypePrettyPrinter.cpp index 6fd6a2cf245..6e46361b7f4 100644 --- a/src/libs/cplusplus/TypePrettyPrinter.cpp +++ b/src/libs/cplusplus/TypePrettyPrinter.cpp @@ -42,37 +42,12 @@ using namespace CPlusPlus; TypePrettyPrinter::TypePrettyPrinter(const Overview *overview) : _overview(overview), - _name(0), - _markArgument(0), - _showArgumentNames(false), - _showReturnTypes(false), - _showFunctionSignatures(true) + _name(0) { } TypePrettyPrinter::~TypePrettyPrinter() { } -bool TypePrettyPrinter::showArgumentNames() const -{ return _showArgumentNames; } - -void TypePrettyPrinter::setShowArgumentNames(bool showArgumentNames) -{ _showArgumentNames = showArgumentNames; } - -bool TypePrettyPrinter::showReturnTypes() const -{ return _showReturnTypes; } - -void TypePrettyPrinter::setShowReturnTypes(bool showReturnTypes) -{ _showReturnTypes = showReturnTypes; } - -bool TypePrettyPrinter::showFunctionSignatures() const -{ return _showFunctionSignatures; } - -void TypePrettyPrinter::setShowFunctionSignatures(bool showFunctionSignatures) -{ _showFunctionSignatures = showFunctionSignatures; } - -void TypePrettyPrinter::setMarkArgument(unsigned position) -{ _markArgument = position; } - const Overview *TypePrettyPrinter::overview() const { return _overview; } @@ -102,15 +77,16 @@ QString TypePrettyPrinter::operator()(const FullySpecifiedType &type, const QStr void TypePrettyPrinter::acceptType(const FullySpecifiedType &ty) { - if (ty.isConst()) - _text += QLatin1String("const "); - if (ty.isVolatile()) - _text += QLatin1String("volatile "); if (ty.isSigned()) - _text += QLatin1String("signed "); - if (ty.isUnsigned()) - _text += QLatin1String("unsigned "); + out(QLatin1String("signed ")); + + else if (ty.isUnsigned()) + out(QLatin1String("unsigned ")); + + const FullySpecifiedType previousFullySpecifiedType = _fullySpecifiedType; + _fullySpecifiedType = ty; accept(ty.type()); + _fullySpecifiedType = previousFullySpecifiedType; } QString TypePrettyPrinter::switchName(const QString &name) @@ -127,9 +103,9 @@ QString TypePrettyPrinter::switchText(const QString &name) return previousName; } -QList TypePrettyPrinter::switchPtrOperators(const QList &ptrOperators) +QList TypePrettyPrinter::switchPtrOperators(const QList &ptrOperators) { - QList previousPtrOperators = _ptrOperators; + QList previousPtrOperators = _ptrOperators; _ptrOperators = ptrOperators; return previousPtrOperators; } @@ -137,31 +113,53 @@ QList TypePrettyPrinter::switchPtrOperators(const QList &ptrOper void TypePrettyPrinter::applyPtrOperators(bool wantSpace) { for (int i = _ptrOperators.size() - 1; i != -1; --i) { - Type *op = _ptrOperators.at(i); + const FullySpecifiedType op = _ptrOperators.at(i); if (i == 0 && wantSpace) - _text += QLatin1Char(' '); + space(); - if (PointerType *ptrTy = op->asPointerType()) { - _text += QLatin1Char('*'); - if (ptrTy->elementType().isConst()) - _text += " const"; - if (ptrTy->elementType().isVolatile()) - _text += " volatile"; + if (op->isPointerType()) { + out(QLatin1Char('*')); + outCV(op); } else if (op->isReferenceType()) { - _text += QLatin1Char('&'); - } else if (PointerToMemberType *memPtrTy = op->asPointerToMemberType()) { - _text += QLatin1Char(' '); - _text += _overview->prettyName(memPtrTy->memberName()); - _text += QLatin1Char('*'); + out(QLatin1Char('&')); + } else if (const PointerToMemberType *memPtrTy = op->asPointerToMemberType()) { + space(); + out(_overview->prettyName(memPtrTy->memberName())); + out(QLatin1Char('*')); + outCV(op); } } } void TypePrettyPrinter::visit(VoidType *) { - _text += QLatin1String("void"); + out(QLatin1String("void")); + applyPtrOperators(); +} +void TypePrettyPrinter::visit(NamedType *type) +{ + out(overview()->prettyName(type->name())); + applyPtrOperators(); +} + +void TypePrettyPrinter::visit(Namespace *type) +{ + _text += overview()->prettyName(type->name()); + applyPtrOperators(); +} + +void TypePrettyPrinter::visit(Class *type) +{ + _text += overview()->prettyName(type->name()); + applyPtrOperators(); +} + + +void TypePrettyPrinter::visit(Enum *type) +{ + _text += overview()->prettyName(type->name()); applyPtrOperators(); } @@ -169,25 +167,25 @@ void TypePrettyPrinter::visit(IntegerType *type) { switch (type->kind()) { case IntegerType::Char: - _text += QLatin1String("char"); + out(QLatin1String("char")); break; case IntegerType::WideChar: - _text += QLatin1String("wchar_t"); + out(QLatin1String("wchar_t")); break; case IntegerType::Bool: - _text += QLatin1String("bool"); + out(QLatin1String("bool")); break; case IntegerType::Short: - _text += QLatin1String("short"); + out(QLatin1String("short")); break; case IntegerType::Int: - _text += QLatin1String("int"); + out(QLatin1String("int")); break; case IntegerType::Long: - _text += QLatin1String("long"); + out(QLatin1String("long")); break; case IntegerType::LongLong: - _text += QLatin1String("long long"); + out(QLatin1String("long long")); break; } @@ -198,13 +196,13 @@ void TypePrettyPrinter::visit(FloatType *type) { switch (type->kind()) { case FloatType::Float: - _text += QLatin1String("float"); + out(QLatin1String("float")); break; case FloatType::Double: - _text += QLatin1String("double"); + out(QLatin1String("double")); break; case FloatType::LongDouble: - _text += QLatin1String("long double"); + out(QLatin1String("long double")); break; } @@ -213,99 +211,135 @@ void TypePrettyPrinter::visit(FloatType *type) void TypePrettyPrinter::visit(PointerToMemberType *type) { - _ptrOperators.append(type); + outCV(type->elementType()); + space(); + + _ptrOperators.append(_fullySpecifiedType); acceptType(type->elementType()); } void TypePrettyPrinter::visit(PointerType *type) { - _ptrOperators.append(type); + outCV(type->elementType()); + space(); + + _ptrOperators.append(_fullySpecifiedType); acceptType(type->elementType()); } void TypePrettyPrinter::visit(ReferenceType *type) { - _ptrOperators.append(type); + outCV(type->elementType()); + space(); + + _ptrOperators.append(_fullySpecifiedType); acceptType(type->elementType()); } void TypePrettyPrinter::visit(ArrayType *type) { - _text += overview()->prettyType(type->elementType()); + out(overview()->prettyType(type->elementType())); if (! _ptrOperators.isEmpty()) { - _text += QLatin1Char('('); + out(QLatin1Char('(')); applyPtrOperators(false); if (! _name.isEmpty()) { - _text += _name; + out(_name); _name.clear(); } - _text += QLatin1Char(')'); + out(QLatin1Char(')')); } - _text += QLatin1String("[]"); -} - -void TypePrettyPrinter::visit(NamedType *type) -{ - _text += overview()->prettyName(type->name()); - applyPtrOperators(); + out(QLatin1String("[]")); } void TypePrettyPrinter::visit(Function *type) { - if (_showReturnTypes) - _text += _overview->prettyType(type->returnType()); + if (_overview->showReturnTypes()) + out(_overview->prettyType(type->returnType())); if (! _ptrOperators.isEmpty()) { - _text += QLatin1Char('('); + out(QLatin1Char('(')); applyPtrOperators(false); if (! _name.isEmpty()) { _text += _name; _name.clear(); } - _text += QLatin1Char(')'); - } else if (! _name.isEmpty() && _showFunctionSignatures) { - _text += QLatin1Char(' '); // ### fixme - _text += _name; + out(QLatin1Char(')')); + } else if (! _name.isEmpty() && _overview->showFunctionSignatures()) { + space(); + out(_name); _name.clear(); } - if (_showFunctionSignatures) { + if (_overview->showFunctionSignatures()) { Overview argumentText; - _text += QLatin1Char('('); + argumentText.setShowReturnTypes(true); + argumentText.setShowArgumentNames(false); + argumentText.setShowFunctionSignatures(true); + + out(QLatin1Char('(')); + for (unsigned index = 0; index < type->argumentCount(); ++index) { if (index != 0) - _text += QLatin1String(", "); + out(QLatin1String(", ")); if (Argument *arg = type->argumentAt(index)->asArgument()) { - if (index + 1 == _markArgument) - _text += QLatin1String(""); + if (index + 1 == _overview->markArgument()) + out(QLatin1String("")); + Name *name = 0; - if (_showArgumentNames) + + if (_overview->showArgumentNames()) name = arg->name(); - _text += argumentText(arg->type(), name); - if (index + 1 == _markArgument) - _text += QLatin1String(""); + + out(argumentText(arg->type(), name)); + + if (index + 1 == _overview->markArgument()) + out(QLatin1String("")); } } if (type->isVariadic()) - _text += QLatin1String("..."); + out(QLatin1String("...")); - _text += QLatin1Char(')'); - - if (type->isConst()) - _text += QLatin1String(" const"); - - if (type->isVolatile()) - _text += QLatin1String(" volatile"); + out(QLatin1Char(')')); + if (type->isConst() && type->isVolatile()) { + space(); + out("const volatile"); + } else if (type->isConst()) { + space(); + out("const"); + } else if (type->isVolatile()) { + space(); + out("volatile"); + } } } -void TypePrettyPrinter::visit(Namespace *type) -{ _text += overview()->prettyName(type->name()); } +void TypePrettyPrinter::space() +{ + if (_text.isEmpty()) + return; -void TypePrettyPrinter::visit(Class *type) -{ _text += overview()->prettyName(type->name()); } + const QChar ch = _text.at(_text.length() - 1); -void TypePrettyPrinter::visit(Enum *type) -{ _text += overview()->prettyName(type->name()); } + if (ch.isLetterOrNumber() || ch == QLatin1Char('_') || ch == QLatin1Char(')')) + _text += QLatin1Char(' '); +} + +void TypePrettyPrinter::out(const QString &text) +{ _text += text; } + +void TypePrettyPrinter::out(const QChar &ch) +{ _text += ch; } + +void TypePrettyPrinter::outCV(const FullySpecifiedType &ty) +{ + if (ty.isConst() && ty.isVolatile()) + out(QLatin1String("const volatile")); + + else if (ty.isConst()) + out(QLatin1String("const")); + + else if (ty.isVolatile()) + out(QLatin1String("volatile")); +} diff --git a/src/libs/cplusplus/TypePrettyPrinter.h b/src/libs/cplusplus/TypePrettyPrinter.h index 790999dc824..6191cf01af0 100644 --- a/src/libs/cplusplus/TypePrettyPrinter.h +++ b/src/libs/cplusplus/TypePrettyPrinter.h @@ -33,7 +33,8 @@ #ifndef TYPEPRETTYPRINTER_H #define TYPEPRETTYPRINTER_H -#include "TypeVisitor.h" +#include +#include #include #include @@ -50,23 +51,12 @@ public: const Overview *overview() const; - bool showArgumentNames() const; - void setShowArgumentNames(bool showArgumentNames); - - bool showReturnTypes() const; - void setShowReturnTypes(bool showReturnTypes); - - bool showFunctionSignatures() const; - void setShowFunctionSignatures(bool showFunctionSignatures); - - void setMarkArgument(unsigned position); // 1-based - QString operator()(const FullySpecifiedType &type); QString operator()(const FullySpecifiedType &type, const QString &name); protected: QString switchText(const QString &text = QString()); - QList switchPtrOperators(const QList &ptrOperators); + QList switchPtrOperators(const QList &ptrOperators); QString switchName(const QString &name); void applyPtrOperators(bool wantSpace = true); @@ -85,15 +75,17 @@ protected: virtual void visit(Class *type); virtual void visit(Enum *type); + void space(); + void out(const QString &text); + void out(const QChar &ch); + void outCV(const FullySpecifiedType &ty); + private: const Overview *_overview; QString _name; QString _text; - QList _ptrOperators; - unsigned _markArgument; - bool _showArgumentNames: 1; - bool _showReturnTypes: 1; - bool _showFunctionSignatures: 1; + FullySpecifiedType _fullySpecifiedType; + QList _ptrOperators; }; } // end of namespace CPlusPlus From 7c71b1bf38add9ae086d4af254ba97e94a3e518e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Mon, 16 Feb 2009 11:20:11 +0100 Subject: [PATCH 07/62] Fixed crash on updating function argument widget Crashed for example in the case of template instantiation. To make sure the Function* stays valid, we need to not only keep around the Snapshot but the whole LookupContext. Done with Roberto Raggi. --- src/plugins/cpptools/cppcodecompletion.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index bca1d576e9f..f06b88ec303 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -78,7 +78,7 @@ class FunctionArgumentWidget : public QLabel { public: FunctionArgumentWidget(); - void showFunctionHint(Function *functionSymbol, const Snapshot &snapshot); + void showFunctionHint(Function *functionSymbol, const LookupContext &context); protected: bool eventFilter(QObject *obj, QEvent *e); @@ -95,7 +95,7 @@ private: QFrame *m_popupFrame; Function *m_item; - Snapshot m_snapshot; + LookupContext m_context; }; class ConvertToCompletionItem: protected NameVisitor @@ -215,10 +215,10 @@ FunctionArgumentWidget::FunctionArgumentWidget() } void FunctionArgumentWidget::showFunctionHint(Function *functionSymbol, - const Snapshot &snapshot) + const LookupContext &context) { m_item = functionSymbol; - m_snapshot = snapshot; + m_context = context; m_startpos = m_editor->position(); // update the text @@ -1041,7 +1041,7 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item) QTC_ASSERT(function, return); m_functionArgumentWidget = new FunctionArgumentWidget(); - m_functionArgumentWidget->showFunctionHint(function, typeOfExpression.snapshot()); + m_functionArgumentWidget->showFunctionHint(function, typeOfExpression.lookupContext()); } } else if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) { QString toInsert = item.m_text; From e539a9375b6279b84390ee3be3a1529b5b779b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Mon, 16 Feb 2009 14:54:41 +0100 Subject: [PATCH 08/62] Avoid inserting characters that are already there When completing, don't insert "();" characters when they're already there. Skip them instead. (cherry picked from commit 86427ecf62def3ae13caaf3f7785cdc0e95943d9) Conflicts: src/plugins/cpptools/cppcodecompletion.cpp --- src/plugins/cpptools/cppcodecompletion.cpp | 25 +++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index f06b88ec303..0ff66aaa6ee 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -1052,11 +1052,14 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item) m_editor->replace(length, toInsert); } else { QString toInsert = item.m_text; + int extraLength = 0; //qDebug() << "current symbol:" << overview.prettyName(symbol->name()) //<< overview.prettyType(symbol->type()); if (m_autoInsertBraces && symbol) { + QString extraChars; + if (Function *function = symbol->type()->asFunction()) { // If the member is a function, automatically place the opening parenthesis, // except when it might take template parameters. @@ -1069,28 +1072,40 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item) } else if (function->templateParameterCount() != 0) { // If there are no arguments, then we need the template specification if (function->argumentCount() == 0) { - toInsert.append(QLatin1Char('<')); + extraChars += QLatin1Char('<'); } } else { - toInsert.append(QLatin1Char('(')); + extraChars += QLatin1Char('('); // If the function takes no arguments, automatically place the closing parenthesis if (function->argumentCount() == 0 || (function->argumentCount() == 1 && function->argumentAt(0)->type()->isVoidType())) { - toInsert.append(QLatin1Char(')')); + extraChars += QLatin1Char(')'); // If the function doesn't return anything, automatically place the semicolon, // unless we're doing a scope completion (then it might be function definition). if (function->returnType()->isVoidType() && m_completionOperator != T_COLON_COLON) { - toInsert.append(QLatin1Char(';')); + extraChars += QLatin1Char(';'); } } } } + + // Avoid inserting characters that are already there + for (int i = 0; i < extraChars.length(); ++i) { + const QChar a = extraChars.at(i); + const QChar b = m_editor->characterAt(m_editor->position() + i); + if (a == b) + ++extraLength; + else + break; + } + + toInsert += extraChars; } // Insert the remainder of the name - int length = m_editor->position() - m_startPosition; + int length = m_editor->position() - m_startPosition + extraLength; m_editor->setCurPos(m_startPosition); m_editor->replace(length, toInsert); } From 9aa86f91356630b3609ffc577c0232992dca3050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Wed, 4 Feb 2009 16:40:42 +0100 Subject: [PATCH 09/62] Completion for constructors used on initialization Deals with cases like "QString s(", but for the moment doesn't handle yet "QString const s(". Done with Roberto Raggi. (cherry picked from commit fca3ec1f3288ac4bcbfaed7f6c613af5cc762dda) --- src/plugins/cpptools/cppcodecompletion.cpp | 85 ++++++++++++++++------ src/plugins/cpptools/cppcodecompletion.h | 4 +- 2 files changed, 65 insertions(+), 24 deletions(-) diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 0ff66aaa6ee..20faa6e7a3c 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -432,7 +432,7 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) return -1; m_editor = editor; - m_startPosition = findStartOfName(editor); + m_startPosition = findStartOfName(); m_completionOperator = T_EOF_SYMBOL; int endOfOperator = m_startPosition; @@ -520,7 +520,7 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) if (m_completionOperator == T_LPAREN && completeFunction(exprTy, resolvedTypes, context)) { return m_startPosition; - } if ((m_completionOperator == T_DOT || m_completionOperator == T_ARROW) && + } else if ((m_completionOperator == T_DOT || m_completionOperator == T_ARROW) && completeMember(resolvedTypes, context)) { return m_startPosition; } else if (m_completionOperator == T_COLON_COLON && completeScope(resolvedTypes, context)) { @@ -531,6 +531,32 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) return m_startPosition; } } + + if (m_completionOperator == T_LPAREN) { + // Find the expression that precedes the current name + int index = endOfExpression; + while (m_editor->characterAt(index - 1).isSpace()) + --index; + index = findStartOfName(index); + + QTextCursor tc(edit->document()); + tc.setPosition(index); + QString baseExpression = expressionUnderCursor(tc); + + // Resolve the type of this expression + QList results = + typeOfExpression(baseExpression, thisDocument, symbol, TypeOfExpression::Preprocess); + + // If it's a class, add completions for the constructors + foreach (const TypeOfExpression::Result &result, results) { + if (result.first->isClass()) { + FullySpecifiedType exprTy = result.first; + if (completeConstructors(exprTy->asClass())) + return m_startPosition; + break; + } + } + } } // nothing to do. @@ -541,26 +567,14 @@ bool CppCodeCompletion::completeFunction(FullySpecifiedType exprTy, const QList &resolvedTypes, const LookupContext &) { - ConvertToCompletionItem toCompletionItem(this); - Overview o; - o.setShowReturnTypes(true); - o.setShowArgumentNames(true); - if (Class *klass = exprTy->asClass()) { - for (unsigned i = 0; i < klass->memberCount(); ++i) { - Symbol *member = klass->memberAt(i); - if (! member->type()->isFunction()) - continue; - else if (! member->identity()) - continue; - else if (! member->identity()->isEqualTo(klass->identity())) - continue; - if (TextEditor::CompletionItem item = toCompletionItem(member)) { - item.m_text = o(member->type(), member->name()); - m_completions.append(item); - } - } + completeConstructors(klass); } else { + ConvertToCompletionItem toCompletionItem(this); + Overview o; + o.setShowReturnTypes(true); + o.setShowArgumentNames(true); + QSet signatures; foreach (TypeOfExpression::Result p, resolvedTypes) { FullySpecifiedType ty = p.first; @@ -873,6 +887,30 @@ void CppCodeCompletion::completeClass(const QList &candidates, } } +bool CppCodeCompletion::completeConstructors(Class *klass) +{ + ConvertToCompletionItem toCompletionItem(this); + Overview o; + o.setShowReturnTypes(true); + o.setShowArgumentNames(true); + + for (unsigned i = 0; i < klass->memberCount(); ++i) { + Symbol *member = klass->memberAt(i); + if (! member->type()->isFunction()) + continue; + else if (! member->identity()) + continue; + else if (! member->identity()->isEqualTo(klass->identity())) + continue; + if (TextEditor::CompletionItem item = toCompletionItem(member)) { + item.m_text = o(member->type(), member->name()); + m_completions.append(item); + } + } + + return ! m_completions.isEmpty(); +} + bool CppCodeCompletion::completeQtMethod(CPlusPlus::FullySpecifiedType, const QList &results, const LookupContext &context, @@ -1150,14 +1188,15 @@ void CppCodeCompletion::cleanup() typeOfExpression.setSnapshot(Snapshot()); } -int CppCodeCompletion::findStartOfName(const TextEditor::ITextEditor *editor) +int CppCodeCompletion::findStartOfName(int pos) const { - int pos = editor->position(); + if (pos == -1) + pos = m_editor->position(); QChar chr; // Skip to the start of a name do { - chr = editor->characterAt(--pos); + chr = m_editor->characterAt(--pos); } while (chr.isLetterOrNumber() || chr == QLatin1Char('_')); return pos + 1; diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h index 08a767ea6ce..02bcdc0f524 100644 --- a/src/plugins/cpptools/cppcodecompletion.h +++ b/src/plugins/cpptools/cppcodecompletion.h @@ -103,6 +103,8 @@ private: const CPlusPlus::LookupContext &context, bool staticLookup = true); + bool completeConstructors(CPlusPlus::Class *klass); + bool completeQtMethod(CPlusPlus::FullySpecifiedType exprTy, const QList &, const CPlusPlus::LookupContext &context, @@ -118,7 +120,7 @@ private: const CPlusPlus::LookupContext &context) { return completeQtMethod(exprTy, results, context, false); } - static int findStartOfName(const TextEditor::ITextEditor *editor); + int findStartOfName(int pos = -1) const; QList m_completions; From 100a6254f69c6326d8bd6bd41b2b90eba6dfa0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Mon, 16 Feb 2009 15:15:43 +0100 Subject: [PATCH 10/62] More intelligent function argument widget Now it shows immediately when there is only a single signature of a given method/constructor. (cherry picked from commit 8b9dd766c822a9f7b929ae14eab3e2e402307c8c) Conflicts: src/plugins/cpptools/cppcodecompletion.cpp --- src/plugins/cpptools/cppcodecompletion.cpp | 63 ++++++++++------------ src/plugins/cpptools/cppcodecompletion.h | 5 +- 2 files changed, 29 insertions(+), 39 deletions(-) diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 20faa6e7a3c..94258decc1a 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -518,7 +518,7 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) if (exprTy->isReferenceType()) exprTy = exprTy->asReferenceType()->elementType(); - if (m_completionOperator == T_LPAREN && completeFunction(exprTy, resolvedTypes, context)) { + if (m_completionOperator == T_LPAREN && completeConstructorOrFunction(exprTy, resolvedTypes)) { return m_startPosition; } else if ((m_completionOperator == T_DOT || m_completionOperator == T_ARROW) && completeMember(resolvedTypes, context)) { @@ -551,7 +551,7 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) foreach (const TypeOfExpression::Result &result, results) { if (result.first->isClass()) { FullySpecifiedType exprTy = result.first; - if (completeConstructors(exprTy->asClass())) + if (completeConstructorOrFunction(exprTy, QList())) return m_startPosition; break; } @@ -563,18 +563,29 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) return -1; } -bool CppCodeCompletion::completeFunction(FullySpecifiedType exprTy, - const QList &resolvedTypes, - const LookupContext &) +bool CppCodeCompletion::completeConstructorOrFunction(FullySpecifiedType exprTy, + const QList &resolvedTypes) { - if (Class *klass = exprTy->asClass()) { - completeConstructors(klass); - } else { - ConvertToCompletionItem toCompletionItem(this); - Overview o; - o.setShowReturnTypes(true); - o.setShowArgumentNames(true); + ConvertToCompletionItem toCompletionItem(this); + Overview o; + o.setShowReturnTypes(true); + o.setShowArgumentNames(true); + if (Class *klass = exprTy->asClass()) { + for (unsigned i = 0; i < klass->memberCount(); ++i) { + Symbol *member = klass->memberAt(i); + if (! member->type()->isFunction()) + continue; + else if (! member->identity()) + continue; + else if (! member->identity()->isEqualTo(klass->identity())) + continue; + if (TextEditor::CompletionItem item = toCompletionItem(member)) { + item.m_text = o(member->type(), member->name()); + m_completions.append(item); + } + } + } else { QSet signatures; foreach (TypeOfExpression::Result p, resolvedTypes) { FullySpecifiedType ty = p.first; @@ -594,6 +605,10 @@ bool CppCodeCompletion::completeFunction(FullySpecifiedType exprTy, } } + // If there is only one item, show the function argument widget immediately + if (m_completions.size() == 1) + complete(m_completions.takeFirst()); + return ! m_completions.isEmpty(); } @@ -887,30 +902,6 @@ void CppCodeCompletion::completeClass(const QList &candidates, } } -bool CppCodeCompletion::completeConstructors(Class *klass) -{ - ConvertToCompletionItem toCompletionItem(this); - Overview o; - o.setShowReturnTypes(true); - o.setShowArgumentNames(true); - - for (unsigned i = 0; i < klass->memberCount(); ++i) { - Symbol *member = klass->memberAt(i); - if (! member->type()->isFunction()) - continue; - else if (! member->identity()) - continue; - else if (! member->identity()->isEqualTo(klass->identity())) - continue; - if (TextEditor::CompletionItem item = toCompletionItem(member)) { - item.m_text = o(member->type(), member->name()); - m_completions.append(item); - } - } - - return ! m_completions.isEmpty(); -} - bool CppCodeCompletion::completeQtMethod(CPlusPlus::FullySpecifiedType, const QList &results, const LookupContext &context, diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h index 02bcdc0f524..79f580236f9 100644 --- a/src/plugins/cpptools/cppcodecompletion.h +++ b/src/plugins/cpptools/cppcodecompletion.h @@ -86,9 +86,8 @@ private: void addMacros(const CPlusPlus::LookupContext &context); void addCompletionItem(CPlusPlus::Symbol *symbol); - bool completeFunction(CPlusPlus::FullySpecifiedType exprTy, - const QList &, - const CPlusPlus::LookupContext &context); + bool completeConstructorOrFunction(CPlusPlus::FullySpecifiedType exprTy, + const QList &); bool completeMember(const QList &, const CPlusPlus::LookupContext &context); From d94dd392cb3cbb0c39ec9eb5cce4deba4afc4c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Mon, 16 Feb 2009 18:34:56 +0100 Subject: [PATCH 11/62] Reuse the function argument widget when possible Now that we're showing this thing instantly, we can no longer rely on the thing hiding cause of a focus change. (cherry picked from commit 5a0a084c3130e0401eed687795371c2a49b4b635) Conflicts: src/plugins/cpptools/cppcodecompletion.cpp --- src/plugins/cpptools/cppcodecompletion.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 94258decc1a..b9dc55f0b99 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -187,10 +187,10 @@ using namespace CppTools::Internal; FunctionArgumentWidget::FunctionArgumentWidget() : m_item(0) { - QObject *editorObject = Core::ICore::instance()->editorManager()->currentEditor(); + QObject *editorObject = Core::EditorManager::instance()->currentEditor(); m_editor = qobject_cast(editorObject); - m_popupFrame = new QFrame(0, Qt::ToolTip|Qt::WindowStaysOnTopHint); + m_popupFrame = new QFrame(0, Qt::ToolTip | Qt::WindowStaysOnTopHint); m_popupFrame->setFocusPolicy(Qt::NoFocus); m_popupFrame->setAttribute(Qt::WA_DeleteOnClose); @@ -1069,7 +1069,10 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item) Function *function = symbol->type()->asFunction(); QTC_ASSERT(function, return); - m_functionArgumentWidget = new FunctionArgumentWidget(); + // Recreate if necessary + if (!m_functionArgumentWidget) + m_functionArgumentWidget = new FunctionArgumentWidget; + m_functionArgumentWidget->showFunctionHint(function, typeOfExpression.lookupContext()); } } else if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) { From a26bef5ff41ba4389fad3aacfa9d74d15e0423e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Tue, 17 Feb 2009 11:09:07 +0100 Subject: [PATCH 12/62] Ignore undefined macros in macro completion Done with Roberto Raggi --- src/plugins/cpptools/cppcodecompletion.cpp | 50 ++++++++++++++-------- src/plugins/cpptools/cppcodecompletion.h | 4 ++ 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index b9dc55f0b99..81cc4741b5e 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -819,33 +819,45 @@ void CppCodeCompletion::addKeywords() void CppCodeCompletion::addMacros(const LookupContext &context) { - // macro completion items. - QSet macroNames; QSet processed; - QList todo; - todo.append(context.thisDocument()->fileName()); - while (! todo.isEmpty()) { - QString fn = todo.last(); - todo.removeLast(); - if (processed.contains(fn)) - continue; - processed.insert(fn); - if (Document::Ptr doc = context.document(fn)) { - foreach (const Macro ¯o, doc->definedMacros()) { - macroNames.insert(macro.name()); - } - todo += doc->includedFiles(); - } - } + QSet definedMacros; - foreach (const QByteArray ¯oName, macroNames) { + addMacros_helper(context, context.thisDocument()->fileName(), + &processed, &definedMacros); + + foreach (const QString ¯oName, definedMacros) { TextEditor::CompletionItem item(this); - item.m_text = QString::fromUtf8(macroName.constData(), macroName.length()); + item.m_text = macroName; item.m_icon = m_icons.macroIcon(); m_completions.append(item); } } +void CppCodeCompletion::addMacros_helper(const LookupContext &context, + const QString &fileName, + QSet *processed, + QSet *definedMacros) +{ + Document::Ptr doc = context.document(fileName); + + if (! doc || processed->contains(doc->fileName())) + return; + + processed->insert(doc->fileName()); + + foreach (const Document::Include &i, doc->includes()) { + addMacros_helper(context, i.fileName(), processed, definedMacros); + } + + foreach (const Macro ¯o, doc->definedMacros()) { + const QString macroName = QString::fromUtf8(macro.name().constData(), macro.name().length()); + if (! macro.isHidden()) + definedMacros->insert(macroName); + else + definedMacros->remove(macroName); + } +} + void CppCodeCompletion::addCompletionItem(Symbol *symbol) { ConvertToCompletionItem toCompletionItem(this); diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h index 79f580236f9..3c1be57bd5d 100644 --- a/src/plugins/cpptools/cppcodecompletion.h +++ b/src/plugins/cpptools/cppcodecompletion.h @@ -84,6 +84,10 @@ public: private: void addKeywords(); void addMacros(const CPlusPlus::LookupContext &context); + void addMacros_helper(const CPlusPlus::LookupContext &context, + const QString &fileName, + QSet *processed, + QSet *definedMacros); void addCompletionItem(CPlusPlus::Symbol *symbol); bool completeConstructorOrFunction(CPlusPlus::FullySpecifiedType exprTy, From 7774977e5d506ea7f414daca362edd9a333f6de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Tue, 17 Feb 2009 11:23:46 +0100 Subject: [PATCH 13/62] Fixed handling of attribute specifiers in front of declaration Done with Roberto Raggi --- src/shared/cplusplus/CheckSpecifier.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shared/cplusplus/CheckSpecifier.cpp b/src/shared/cplusplus/CheckSpecifier.cpp index eeb59eebcc0..a001947ff50 100644 --- a/src/shared/cplusplus/CheckSpecifier.cpp +++ b/src/shared/cplusplus/CheckSpecifier.cpp @@ -384,8 +384,9 @@ bool CheckSpecifier::visit(TypeofSpecifierAST *ast) return false; } -bool CheckSpecifier::visit(AttributeSpecifierAST *) +bool CheckSpecifier::visit(AttributeSpecifierAST *ast) { + accept(ast->next); return false; } From 6edae34a54df4acc38c035aa516798a3e6ed805c Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Tue, 17 Feb 2009 12:24:19 +0100 Subject: [PATCH 14/62] Fixes: Flicker-free update of the editor toolbars (mac -only). --- src/plugins/coreplugin/editormanager/stackededitorgroup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/editormanager/stackededitorgroup.cpp b/src/plugins/coreplugin/editormanager/stackededitorgroup.cpp index cc759c6c7ff..7ad5d056fe5 100644 --- a/src/plugins/coreplugin/editormanager/stackededitorgroup.cpp +++ b/src/plugins/coreplugin/editormanager/stackededitorgroup.cpp @@ -329,8 +329,8 @@ void StackedEditorGroup::updateToolBar(IEditor *editor) toolBar = m_defaultToolBar; if (m_activeToolBar == toolBar) return; - toolBar->setVisible(true); m_activeToolBar->setVisible(false); + toolBar->setVisible(true); m_activeToolBar = toolBar; } From c05e9347bb349b265c61cb38f0c4382363dc91b4 Mon Sep 17 00:00:00 2001 From: con Date: Tue, 17 Feb 2009 12:59:58 +0100 Subject: [PATCH 15/62] Fixes: - Make sure that we find make command for gdbmacros library. Task: - 244273 Details: - We need to search in the path for it. --- src/plugins/qt4projectmanager/gdbmacrosbuildstep.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/plugins/qt4projectmanager/gdbmacrosbuildstep.cpp b/src/plugins/qt4projectmanager/gdbmacrosbuildstep.cpp index 507c059239e..6e2ccbc2506 100644 --- a/src/plugins/qt4projectmanager/gdbmacrosbuildstep.cpp +++ b/src/plugins/qt4projectmanager/gdbmacrosbuildstep.cpp @@ -124,7 +124,15 @@ void GdbMacrosBuildStep::run(QFutureInterface & fi) qmake.start(m_qmake, QStringList()<<"-spec"<qtVersion(m_buildConfiguration)->makeCommand(), makeArguments); + QString makeCmd = qt4Project->qtVersion(m_buildConfiguration)->makeCommand(); + if (!value(m_buildConfiguration, "makeCmd").toString().isEmpty()) + makeCmd = value(m_buildConfiguration, "makeCmd").toString(); + if (!QFileInfo(makeCmd).isAbsolute()) { + // Try to detect command in environment + QString tmp = qt4Project->environment(m_buildConfiguration).searchInPath(makeCmd); + makeCmd = tmp; + } + qmake.start(makeCmd, makeArguments); qmake.waitForFinished(); fi.reportResult(true); From 7b8b947946877eecd6dd306c59abed0c307acdca Mon Sep 17 00:00:00 2001 From: con Date: Tue, 17 Feb 2009 13:01:09 +0100 Subject: [PATCH 16/62] Fixes: - Rename System Qt to perhaps avoid some confusion. Task: - 243948 --- src/plugins/qt4projectmanager/qtversionmanager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/qt4projectmanager/qtversionmanager.cpp b/src/plugins/qt4projectmanager/qtversionmanager.cpp index f79cc4b5964..e39dc8bf57e 100644 --- a/src/plugins/qt4projectmanager/qtversionmanager.cpp +++ b/src/plugins/qt4projectmanager/qtversionmanager.cpp @@ -296,12 +296,13 @@ void QtVersionManager::updateSystemVersion() foreach (QtVersion *version, m_versions) { if (version->isSystemVersion()) { version->setPath(findSystemQt()); + version->setName(tr("Auto-detected Qt")); haveSystemVersion = true; } } if (haveSystemVersion) return; - QtVersion *version = new QtVersion(tr("System Qt"), + QtVersion *version = new QtVersion(tr("Auto-detected Qt"), findSystemQt(), getUniqueId(), true); From b32198d73645be42924cd0468b780b022bcda08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Tue, 17 Feb 2009 15:11:56 +0100 Subject: [PATCH 17/62] Fix size problems on reusing function argument widget We now hide the parent QFrame while updating the label to work around the problem where the it wouldn't shrink the widget. --- src/plugins/cpptools/cppcodecompletion.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 81cc4741b5e..233398026fe 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -217,6 +217,8 @@ FunctionArgumentWidget::FunctionArgumentWidget() void FunctionArgumentWidget::showFunctionHint(Function *functionSymbol, const LookupContext &context) { + m_popupFrame->hide(); + m_item = functionSymbol; m_context = context; m_startpos = m_editor->position(); @@ -230,7 +232,7 @@ void FunctionArgumentWidget::showFunctionHint(Function *functionSymbol, m_popupFrame->move(pos); m_popupFrame->show(); - QCoreApplication::instance()->installEventFilter(this); + qApp->installEventFilter(this); } void FunctionArgumentWidget::update() From 7ec3f73594c21aae67fa695b87c84152222a14bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Tue, 17 Feb 2009 16:14:52 +0100 Subject: [PATCH 18/62] Center the cursor after (un)collapse all Requested on the mailing list. Increases usability. --- src/plugins/texteditor/basetexteditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index d5b088396a5..1d0d910a4c8 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -3463,12 +3463,12 @@ void BaseTextEditor::unCollapseAll() if (TextBlockUserData::canCollapse(block)) TextBlockUserData::doCollapse(block, makeVisible); block = block.next(); - } d->moveCursorVisible(); documentLayout->requestUpdate(); documentLayout->emitDocumentSizeChanged(); + centerCursor(); } void BaseTextEditor::setTextCodec(QTextCodec *codec) From 4f20ef9f4e20d9c2080ec66121c5fd4a6cfc2114 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Feb 2009 17:34:10 +0100 Subject: [PATCH 19/62] Fixes: correct name for gdmacros.cpp hint Conflicts: src/plugins/debugger/gdbengine.cpp --- src/plugins/debugger/gdbengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index f6413db72f9..2a4068b447a 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -3338,7 +3338,7 @@ void GdbEngine::handleQueryDataDumper2(const GdbResultRecord &record) tr("The debugged binary does not contain information needed for " "nice display of Qt data types.\n\n" "You might want to try including the file\n\n" - ".../share/qtcreator/gdbmacros/gdbmacros.cpp\n\n" + ".../share/qtcreator/gdbmacros/gdbmacros.cpp'\n\n" "into your project directly.") ); } else { From 433ded47d82dc3fb26b8f5cbcd53058de6b9d83c Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Feb 2009 17:34:41 +0100 Subject: [PATCH 20/62] Fixes: correct path for gcbmnacros.cpp hint Conflicts: src/plugins/debugger/gdbengine.cpp --- src/plugins/debugger/gdbengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 2a4068b447a..f6413db72f9 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -3338,7 +3338,7 @@ void GdbEngine::handleQueryDataDumper2(const GdbResultRecord &record) tr("The debugged binary does not contain information needed for " "nice display of Qt data types.\n\n" "You might want to try including the file\n\n" - ".../share/qtcreator/gdbmacros/gdbmacros.cpp'\n\n" + ".../share/qtcreator/gdbmacros/gdbmacros.cpp\n\n" "into your project directly.") ); } else { From 153766b956bbf5b61681bbae8d4aac3d9095cca6 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Feb 2009 17:36:54 +0100 Subject: [PATCH 21/62] Fixes: debugger: revert accidental parts of b0650238 Conflicts: src/plugins/debugger/gdbengine.cpp --- src/plugins/debugger/gdbengine.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index f6413db72f9..66c9efb887a 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -3590,7 +3590,6 @@ void GdbEngine::updateLocals() setTokenBarrier(); m_pendingRequests = 0; - PENDING_DEBUG("\nRESET PENDING"); m_toolTipCache.clear(); m_toolTipExpression.clear(); @@ -3602,8 +3601,6 @@ void GdbEngine::updateLocals() sendSynchronizedCommand(cmd, StackListArguments); // stage 1/2 // '2' is 'list with type and value' sendSynchronizedCommand("-stack-list-locals 2", StackListLocals); // stage 2/2 - - tryLoadCustomDumpers(); } void GdbEngine::handleStackListArguments(const GdbResultRecord &record) From 1afd270da250f59a893d36dc53124831bd63864d Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Feb 2009 17:38:24 +0100 Subject: [PATCH 22/62] Fixes: debugger: move custom dumper initialization into the first watch view update Conflicts: src/plugins/debugger/gdbengine.cpp --- src/plugins/debugger/gdbengine.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 66c9efb887a..9e818be0d1a 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -3590,6 +3590,7 @@ void GdbEngine::updateLocals() setTokenBarrier(); m_pendingRequests = 0; + PENDING_DEBUG("\nRESET PENDING"); m_toolTipCache.clear(); m_toolTipExpression.clear(); @@ -3601,6 +3602,8 @@ void GdbEngine::updateLocals() sendSynchronizedCommand(cmd, StackListArguments); // stage 1/2 // '2' is 'list with type and value' sendSynchronizedCommand("-stack-list-locals 2", StackListLocals); // stage 2/2 + + tryLoadCustomDumpers(); } void GdbEngine::handleStackListArguments(const GdbResultRecord &record) @@ -3982,9 +3985,9 @@ void GdbEngine::tryLoadCustomDumpers() //if (qq->useFastStart()) // sendCommand("set stop-on-solib-events 0"); QString flag = QString::number(RTLD_NOW); - sendSynchronizedCommand("call (void)dlopen(\"" + lib + "\", " + flag + ")", + sendSyncronizedCommand("call (void)dlopen(\"" + lib + "\", " + flag + ")", WatchDumpCustomSetup); - sendSynchronizedCommand("sharedlibrary " + dotEscape(lib)); + sendSyncronizedCommand("sharedlibrary " + dotEscape(lib)); //if (qq->useFastStart()) // sendCommand("set stop-on-solib-events 1"); } else { @@ -3999,9 +4002,9 @@ void GdbEngine::tryLoadCustomDumpers() // sendCommand("set stop-on-solib-events 0"); //sendCommand("handle SIGSEGV pass stop print"); //sendCommand("set unwindonsignal off"); - sendSynchronizedCommand("call LoadLibraryA(\"" + lib + "\")", + sendSyncronizedCommand("call LoadLibraryA(\"" + lib + "\")", WatchDumpCustomSetup); - sendSynchronizedCommand("sharedlibrary " + dotEscape(lib)); + sendSyncronizedCommand("sharedlibrary " + dotEscape(lib)); //if (qq->useFastStart()) // sendCommand("set stop-on-solib-events 1"); } else { From 7ebfeb037bf83b25ad00805040cef6f87e5943d3 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 12 Feb 2009 09:55:59 +0100 Subject: [PATCH 23/62] Fixes: debugger: introduce early break after application initialization --- src/plugins/debugger/debuggermanager.cpp | 6 -- src/plugins/debugger/gdbengine.cpp | 106 ++++++++++++++++++++--- src/plugins/debugger/gdbengine.h | 3 + 3 files changed, 97 insertions(+), 18 deletions(-) diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index f017cebccef..4868cf4c517 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -540,12 +540,6 @@ void DebuggerManager::notifyStartupFinished() { setStatus(DebuggerProcessReady); showStatusMessage(tr("Startup finished. Debugger ready."), -1); - if (m_startMode == attachExternal) { - // we continue the execution - engine()->continueInferior(); - } else { - engine()->runInferior(); - } } void DebuggerManager::notifyInferiorStopped() diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 9e818be0d1a..6084831b1b4 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -100,6 +100,9 @@ enum GdbCommandType GdbQuerySources, GdbAsyncOutput2, GdbExecRun, + GdbExecStart1, + GdbExecStart2, + GdbExecStart3, GdbExecRunToFunction, GdbExecStep, GdbExecNext, @@ -635,6 +638,7 @@ void GdbEngine::maybeHandleInferiorPidChanged(const QString &pid0) } if (pid == q->m_attachedPID) return; + //qDebug() << "FOUND PID " << pid; q->m_attachedPID = pid; qq->notifyInferiorPidChanged(pid); } @@ -686,8 +690,8 @@ void GdbEngine::sendCommand(const QString &command, int type, //qDebug() << qPrintable(currentTime()) << "RUNNING" << cmd.command; m_gdbProc.write(cmd.command.toLatin1() + "\r\n"); //emit gdbInputAvailable(QString(), " " + currentTime()); - emit gdbInputAvailable(QString(), "[" + currentTime() + "] " + cmd.command); - //emit gdbInputAvailable(QString(), cmd.command); + //emit gdbInputAvailable(QString(), "[" + currentTime() + "] " + cmd.command); + emit gdbInputAvailable(QString(), cmd.command); } if (temporarilyStopped) @@ -753,9 +757,18 @@ void GdbEngine::handleResult(const GdbResultRecord & record, int type, case GdbExecContinue: case GdbExecFinish: // evil code sharing - case GdbExecRun: handleExecRun(record); break; + + case GdbExecStart1: + handleExecStart1(record); + break; + case GdbExecStart2: + handleExecStart2(record); + break; + case GdbExecStart3: + handleExecStart3(record); + break; case GdbInfoProc: handleInfoProc(record); break; @@ -1134,6 +1147,34 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) const QString reason = data.findChild("reason").data(); QString console = data.findChild("consolestreamoutput").data(); + if (reason.isEmpty()) { + GdbMi frame = data.findChild("frame"); + if (frame.findChild("func").data() == "_start") { + // that's the "early stop" + frame.findChild("func").data() + '%'; + #if defined(Q_OS_WIN) + sendCommand("info proc", GdbInfoProc); + #endif + #if defined(Q_OS_LINUX) + sendCommand("info proc", GdbInfoProc); + #endif + #if defined(Q_OS_MAC) + sendCommand("info pid", GdbInfoProc, QVariant(), true); + #endif + sendCommand("-file-list-exec-source-files", GdbQuerySources); + sendCommand("set auto-solib-add on"); + sendCommand("sharedlibrary libc"); // for malloc + sendCommand("sharedlibrary libdl"); // for dlopen + tryLoadCustomDumpers(); + sendCommand("info shared", ModulesList, QVariant()); + // this will "continue" if done + attemptBreakpointSynchronization(); + return; + } + // fall through + } + +#if 0 if (console.contains("Stopped due to shared library event") || reason.isEmpty()) { ++m_shared; //if (m_shared == 2) @@ -1162,6 +1203,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) } return; } +#endif if (isExitedReason(reason)) { qq->notifyInferiorExited(); @@ -1218,7 +1260,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) if (reason == "breakpoint-hit") { q->showStatusMessage(tr("Stopped at breakpoint")); GdbMi frame = data.findChild("frame"); - //qDebug() << frame.toString(); + qDebug() << "HIT BREAKPOINT: " << frame.toString(); m_currentFrame = frame.findChild("addr").data() + '%' + frame.findChild("func").data() + '%'; @@ -1604,16 +1646,27 @@ bool GdbEngine::startDebugger() } } + if (q->startMode() == q->startInternal) { + sendCommand("-file-exec-and-symbols " + fileName, GdbFileExecAndSymbols); + //sendCommand("file " + fileName, GdbFileExecAndSymbols); + #ifdef Q_OS_MAC + sendCommand("sharedlibrary apply-load-rules all"); + #endif + //sendCommand("-gdb-set stop-on-solib-events 1"); + runInferior(); + } + if (q->startMode() == q->attachExternal) { sendCommand("attach " + QString::number(q->m_attachedPID)); } - if (q->startMode() == q->startInternal || q->startMode() == q->startExternal) { - sendCommand("-file-exec-and-symbols " + fileName, GdbFileExecAndSymbols); + if (q->startMode() == q->startExternal) { + //sendCommand("-file-exec-and-symbols " + fileName, GdbFileExecAndSymbols); + sendCommand("file " + fileName, GdbFileExecAndSymbols); #ifdef Q_OS_MAC sendCommand("sharedlibrary apply-load-rules all"); #endif - sendCommand("-file-list-exec-source-files", GdbQuerySources); + //sendCommand("-file-list-exec-source-files", GdbQuerySources); //sendCommand("-gdb-set stop-on-solib-events 1"); } @@ -1625,7 +1678,7 @@ bool GdbEngine::startDebugger() else qq->breakHandler()->setAllPending(); - QTimer::singleShot(0, this, SLOT(attemptBreakpointSynchronization())); + //QTimer::singleShot(0, this, SLOT(attemptBreakpointSynchronization())); return true; } @@ -1648,7 +1701,33 @@ void GdbEngine::runInferior() sendCommand("-exec-arguments " + q->m_processArgs.join(" ")); qq->notifyInferiorRunningRequested(); emit gdbInputAvailable(QString(), QString()); - sendCommand("-exec-run", GdbExecRun); + + sendCommand("set auto-solib-add off"); + sendCommand("x/2i _start", GdbExecStart1); +} + +void GdbEngine::handleExecStart1(const GdbResultRecord &response) +{ + if (response.resultClass == GdbResultDone) { + // stdout:&"x/2i _start\n" + // stdout:~"0x404540 <_start>:\txor %ebp,%ebp\n" + // stdout:~"0x404542 <_start+2>:\tmov %rdx,%r9\n" + QString msg = response.data.findChild("consolestreamoutput").data(); + QRegExp needle("0x([0-9a-f]+) <_start\\+.*>:"); + if (needle.indexIn(msg) != -1) { + //qDebug() << "STREAM: " << msg << needle.cap(1); + sendCommand("tbreak *0x" + needle.cap(1)); // GdbExecStart3); + sendCommand("-exec-run"); // GdbExecStart3); + } else { + qDebug() << "PARSING START ADDRESS FAILED" << msg; + } + } else if (response.resultClass == GdbResultError) { + qDebug() << "PARSING START ADDRESS FAILED" << response.toString(); + } +} + +void GdbEngine::handleExecStart3(const GdbResultRecord &response) +{ #if defined(Q_OS_WIN) sendCommand("info proc", GdbInfoProc); #endif @@ -1658,6 +1737,7 @@ void GdbEngine::runInferior() #if defined(Q_OS_MAC) sendCommand("info pid", GdbInfoProc, QVariant(), true); #endif + attemptBreakpointSynchronization(); } void GdbEngine::stepExec() @@ -2183,8 +2263,10 @@ void GdbEngine::attemptBreakpointSynchronization() //sendListBreakpoints(); } - if (!updateNeeded && q->status() == DebuggerProcessStartingUp) - qq->notifyStartupFinished(); + if (!updateNeeded && q->status() == DebuggerProcessStartingUp) { + // we continue the execution + continueInferior(); + } } @@ -3603,7 +3685,7 @@ void GdbEngine::updateLocals() // '2' is 'list with type and value' sendSynchronizedCommand("-stack-list-locals 2", StackListLocals); // stage 2/2 - tryLoadCustomDumpers(); + //tryLoadCustomDumpers(); } void GdbEngine::handleStackListArguments(const GdbResultRecord &record) diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index a603aee375d..14cb65d7cdf 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -185,6 +185,9 @@ private: void handleResultRecord(const GdbResultRecord &response); void handleFileExecAndSymbols(const GdbResultRecord &response); void handleExecRun(const GdbResultRecord &response); + void handleExecStart1(const GdbResultRecord &response); + void handleExecStart2(const GdbResultRecord &response); + void handleExecStart3(const GdbResultRecord &response); void handleExecJumpToLine(const GdbResultRecord &response); void handleExecRunToFunction(const GdbResultRecord &response); void handleInfoShared(const GdbResultRecord &response); From ab31640462d4ffffa2d6b2e2236ca7d42e460a34 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 12 Feb 2009 11:18:38 +0100 Subject: [PATCH 24/62] Fixes: debugger: work on more fine-grained breakpoints-in-plugins setting --- src/plugins/debugger/debuggermanager.h | 5 + src/plugins/debugger/debuggerplugin.cpp | 52 ++++++++--- src/plugins/debugger/gdbengine.cpp | 4 +- src/plugins/debugger/gdbengine.h | 1 - src/plugins/debugger/gdboptionpage.ui | 119 +++++++++++++++--------- 5 files changed, 122 insertions(+), 59 deletions(-) diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index 1c12a731643..a43feb7e96c 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -200,6 +200,11 @@ public: bool m_useToolTips; QString m_scriptFile; + + bool m_pluginAllBreakpoints; + bool m_pluginSelectedBreakpoints; + bool m_pluginNoBreakpoints; + QString m_pluginSelectedBreakpointsPattern; }; // diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index b8bffaa14eb..aa3fca911f6 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -274,15 +274,24 @@ QWidget *GdbOptionPage::createPage(QWidget *parent) m_ui.scriptFileChooser->setPromptDialogTitle(tr("Choose Location of Startup Script File")); m_ui.scriptFileChooser->setPath(m_settings.m_scriptFile); m_ui.environmentEdit->setText(m_settings.m_gdbEnv); - m_ui.autoStartBox->setChecked(m_settings.m_autoRun); - m_ui.autoQuitBox->setChecked(m_settings.m_autoQuit); + + m_ui.radioButtonAllPluginBreakpoints-> + setChecked(m_settings.m_pluginAllBreakpoints); + m_ui.radioButtonSelectedPluginBreakpoints-> + setChecked(m_settings.m_pluginSelectedBreakpoints); + m_ui.radioButtonNoPluginBreakpoints-> + setChecked(m_settings.m_pluginNoBreakpoints); + m_ui.lineEditSelectedPluginBreakpointsPattern-> + setEnabled(m_settings.m_pluginSelectedBreakpoints); m_ui.checkBoxSkipKnownFrames->setChecked(m_settings.m_skipKnownFrames); m_ui.checkBoxDebugDumpers->setChecked(m_settings.m_debugDumpers); m_ui.checkBoxUseCustomDumpers->setChecked(m_settings.m_useCustomDumpers); - m_ui.checkBoxFastStart->setChecked(m_settings.m_useFastStart); m_ui.checkBoxUseToolTips->setChecked(m_settings.m_useToolTips); + connect(m_ui.radioButtonSelectedPluginBreakpoints, SIGNAL(toggled(bool)), + m_ui.lineEditSelectedPluginBreakpointsPattern, SLOT(setEnabled(bool))); + #ifndef QT_DEBUG #if 0 cmd = am->registerAction(m_manager->m_dumpLogAction, @@ -294,14 +303,9 @@ QWidget *GdbOptionPage::createPage(QWidget *parent) #endif // FIXME - m_ui.autoStartBox->hide(); - m_ui.autoQuitBox->hide(); m_ui.environmentEdit->hide(); m_ui.labelEnvironment->hide(); - m_ui.checkBoxFastStart->setChecked(false); - m_ui.checkBoxFastStart->hide(); - //m_dumpLogAction = new QAction(this); //m_dumpLogAction->setText(tr("Dump Log File for Debugging Purposes")); // @@ -315,16 +319,23 @@ void GdbOptionPage::apply() { m_settings.m_gdbCmd = m_ui.gdbLocationChooser->path(); m_settings.m_gdbEnv = m_ui.environmentEdit->text(); - m_settings.m_autoRun = m_ui.autoStartBox->isChecked(); - m_settings.m_autoQuit = m_ui.autoQuitBox->isChecked(); m_settings.m_scriptFile = m_ui.scriptFileChooser->path(); m_settings.m_skipKnownFrames = m_ui.checkBoxSkipKnownFrames->isChecked(); m_settings.m_debugDumpers = m_ui.checkBoxDebugDumpers->isChecked(); m_settings.m_useCustomDumpers = m_ui.checkBoxUseCustomDumpers->isChecked(); - m_settings.m_useFastStart = m_ui.checkBoxFastStart->isChecked(); m_settings.m_useToolTips = m_ui.checkBoxUseToolTips->isChecked(); + m_settings.m_pluginAllBreakpoints = + m_ui.radioButtonAllPluginBreakpoints->isChecked(); + m_settings.m_pluginSelectedBreakpoints = + m_ui.radioButtonSelectedPluginBreakpoints->isChecked(); + m_settings.m_pluginNoBreakpoints = + m_ui.radioButtonNoPluginBreakpoints->isChecked(); + m_settings.m_pluginSelectedBreakpointsPattern = + m_ui.lineEditSelectedPluginBreakpointsPattern->text(); + + *m_plugin->m_manager->settings() = m_settings; m_plugin->writeSettings(); } @@ -889,11 +900,16 @@ void DebuggerPlugin::writeSettings() const s->setValue("AutoRun", m->m_autoRun); s->setValue("AutoQuit", m->m_autoQuit); - s->setValue("UseFastStart", m->m_useFastStart); s->setValue("UseToolTips", m->m_useToolTips); s->setValue("UseCustomDumpers", m->m_useCustomDumpers); s->setValue("SkipKnowFrames", m->m_skipKnownFrames); s->setValue("DebugDumpers", m->m_debugDumpers); + + s->setValue("AllPluginBreakpoints", m->m_pluginAllBreakpoints); + s->setValue("SelectedPluginBreakpoints", m->m_pluginSelectedBreakpoints); + s->setValue("NoPluginBreakpoints", m->m_pluginNoBreakpoints); + s->setValue("SelectedPluginBreakpointsPattern", m->m_pluginSelectedBreakpointsPattern); + s->endGroup(); } @@ -911,6 +927,7 @@ void DebuggerPlugin::readSettings() QString defaultScript; s->beginGroup(QLatin1String("DebugMode")); + QByteArray ba = s->value("State", QByteArray()).toByteArray(); m_toggleLockedAction->setChecked(s->value("Locked", true).toBool()); m->m_gdbCmd = s->value("Location", defaultCommand).toString(); @@ -922,8 +939,17 @@ void DebuggerPlugin::readSettings() m->m_skipKnownFrames = s->value("SkipKnownFrames", false).toBool(); m->m_debugDumpers = s->value("DebugDumpers", false).toBool(); m->m_useCustomDumpers = s->value("UseCustomDumpers", true).toBool(); - m->m_useFastStart = s->value("UseFastStart", false).toBool(); m->m_useToolTips = s->value("UseToolTips", false).toBool(); + + m->m_pluginAllBreakpoints = + s->value("AllPluginBreakpoints", false).toBool(); + m->m_pluginSelectedBreakpoints = + s->value("SelectedPluginBreakpoints", false).toBool(); + m->m_pluginNoBreakpoints = + s->value("NoPluginBreakpoints", true).toBool(); + m->m_pluginSelectedBreakpointsPattern = + s->value("SelectedPluginBreakpointsPattern").toString(); + s->endGroup(); m_manager->mainWindow()->restoreState(ba); diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 6084831b1b4..ad97e748b70 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -764,7 +764,7 @@ void GdbEngine::handleResult(const GdbResultRecord & record, int type, handleExecStart1(record); break; case GdbExecStart2: - handleExecStart2(record); + //handleExecStart2(record); break; case GdbExecStart3: handleExecStart3(record); @@ -1726,7 +1726,7 @@ void GdbEngine::handleExecStart1(const GdbResultRecord &response) } } -void GdbEngine::handleExecStart3(const GdbResultRecord &response) +void GdbEngine::handleExecStart3(const GdbResultRecord &) { #if defined(Q_OS_WIN) sendCommand("info proc", GdbInfoProc); diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index 14cb65d7cdf..fbb56a1b4d5 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -186,7 +186,6 @@ private: void handleFileExecAndSymbols(const GdbResultRecord &response); void handleExecRun(const GdbResultRecord &response); void handleExecStart1(const GdbResultRecord &response); - void handleExecStart2(const GdbResultRecord &response); void handleExecStart3(const GdbResultRecord &response); void handleExecJumpToLine(const GdbResultRecord &response); void handleExecRunToFunction(const GdbResultRecord &response); diff --git a/src/plugins/debugger/gdboptionpage.ui b/src/plugins/debugger/gdboptionpage.ui index ef485ccbf83..e6c46c9bc3a 100644 --- a/src/plugins/debugger/gdboptionpage.ui +++ b/src/plugins/debugger/gdboptionpage.ui @@ -6,22 +6,16 @@ 0 0 - 465 - 372 + 398 + 385 Form - - - 6 - - - 9 - - - + + + Locations @@ -74,7 +68,70 @@ - + + + + Behaviour of breakpoint setting in plugins + + + + + + This is the slowest but safest option. + + + Try to set breakpoints in plugins always automatically. + + + + + + + Try to set breakpoints in selected plugins + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 10 + 10 + + + + + + + + Matching regular expression: + + + + + + + + + + + + Never set breakpoints in plugins automatically + + + + + + + Checking this will make the debugger try to use code to format certain data (QObject, QString, std::string etc.) nicely. @@ -84,17 +141,7 @@ - - - - Checking this will make the debugger start fast by loading only very few debug symbols on start up. This might lead to situations where breakpoints can not be set properly. So uncheck this option if you experience breakpoint related problems. - - - Fast debugger start - - - - + When this option is checked, 'Step Into' compresses several steps into one in certain situations, leading to 'less noisy' debugging. So will, e.g., the atomic @@ -105,7 +152,7 @@ - + Checking this will make enable tooltips for variable values during debugging. Since this can slow down debugging and does not provide reliable information as it does not use scope information, it is switched off by default. @@ -115,7 +162,7 @@ - + This is an internal tool to make debugging the Custom Data Dumper code easier. Using this action is in general not needed unless you want do debug Qt Creator itself. @@ -125,29 +172,15 @@ - - - - Auto run executable on debugger startup - - - - - - - Quit debugger when the executable exits - - - - - + + Qt::Vertical - 415 - 41 + 10 + 1 From 04626a3e2a60fd4caedc7e9f2bf2b49a35701cd8 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Feb 2009 17:39:20 +0100 Subject: [PATCH 25/62] Fixes: debugger: work on plugin breakpoints Conflicts: src/plugins/debugger/gdbengine.cpp --- src/plugins/debugger/debuggermanager.cpp | 10 --- src/plugins/debugger/debuggermanager.h | 16 +++- src/plugins/debugger/debuggerplugin.cpp | 2 + src/plugins/debugger/gdbengine.cpp | 102 +++++++++-------------- src/plugins/debugger/gdbengine.h | 1 - 5 files changed, 53 insertions(+), 78 deletions(-) diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 4868cf4c517..95010977da6 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -1079,22 +1079,12 @@ bool DebuggerManager::useCustomDumpers() const return m_settings.m_useCustomDumpers; } -bool DebuggerManager::useFastStart() const -{ - return 0; // && m_settings.m_useFastStart; -} - void DebuggerManager::setUseCustomDumpers(bool on) { m_settings.m_useCustomDumpers = on; engine()->setUseCustomDumpers(on); } -void DebuggerManager::setUseFastStart(bool on) -{ - m_settings.m_useFastStart = on; -} - void DebuggerManager::setDebugDumpers(bool on) { m_settings.m_debugDumpers = on; diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index a43feb7e96c..a3407a0aa59 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -170,7 +170,11 @@ private: virtual bool skipKnownFrames() const = 0; virtual bool debugDumpers() const = 0; virtual bool useCustomDumpers() const = 0; - virtual bool useFastStart() const = 0; + + virtual bool wantsAllPluginBreakpoints() const = 0; + virtual bool wantsSelectedPluginBreakpoints() const = 0; + virtual bool wantsNoPluginBreakpoints() const = 0; + virtual QString selectedPluginBreakpointsPattern() const = 0; virtual void reloadDisassembler() = 0; virtual void reloadModules() = 0; @@ -288,7 +292,6 @@ public slots: void setUseCustomDumpers(bool on); void setDebugDumpers(bool on); void setSkipKnownFrames(bool on); - void setUseFastStart(bool on); private slots: void showDebuggerOutput(const QString &prefix, const QString &msg); @@ -323,7 +326,14 @@ private: bool skipKnownFrames() const; bool debugDumpers() const; bool useCustomDumpers() const; - bool useFastStart() const; + bool wantsAllPluginBreakpoints() const + { return m_settings.m_pluginAllBreakpoints; } + bool wantsSelectedPluginBreakpoints() const + { return m_settings.m_pluginSelectedBreakpoints; } + bool wantsNoPluginBreakpoints() const + { return m_settings.m_pluginNoBreakpoints; } + QString selectedPluginBreakpointsPattern() const + { return m_settings.m_pluginSelectedBreakpointsPattern; } void notifyStartupFinished(); void notifyInferiorStopped(); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index aa3fca911f6..18c7e6d0c56 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -281,6 +281,8 @@ QWidget *GdbOptionPage::createPage(QWidget *parent) setChecked(m_settings.m_pluginSelectedBreakpoints); m_ui.radioButtonNoPluginBreakpoints-> setChecked(m_settings.m_pluginNoBreakpoints); + m_ui.lineEditSelectedPluginBreakpointsPattern-> + setText(m_settings.m_pluginSelectedBreakpointsPattern); m_ui.lineEditSelectedPluginBreakpointsPattern-> setEnabled(m_settings.m_pluginSelectedBreakpoints); diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index ad97e748b70..49b76a5e34d 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -254,7 +254,6 @@ void GdbEngine::init() { m_pendingRequests = 0; m_gdbVersion = 100; - m_shared = 0; m_outputCodec = QTextCodec::codecForLocale(); m_dataDumperState = DataDumperUninitialized; @@ -988,18 +987,6 @@ void GdbEngine::handleInfoShared(const GdbResultRecord &record) if (record.resultClass == GdbResultDone) { // let the modules handler do the parsing handleModulesList(record); - QList modules = qq->modulesHandler()->modules(); - bool reloadNeeded = false; - foreach (const Module &module, modules) { - // FIXME: read this from some list - if (!module.symbolsRead && !module.moduleName.contains("Q")) { - reloadNeeded = true; - sendCommand("sharedlibrary " + dotEscape(module.moduleName)); - } - } - if (reloadNeeded) - reloadModules(); - continueInferior(); } } @@ -1146,7 +1133,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) { const QString reason = data.findChild("reason").data(); - QString console = data.findChild("consolestreamoutput").data(); + QString msg = data.findChild("consolestreamoutput").data(); if (reason.isEmpty()) { GdbMi frame = data.findChild("frame"); if (frame.findChild("func").data() == "_start") { @@ -1162,11 +1149,27 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) sendCommand("info pid", GdbInfoProc, QVariant(), true); #endif sendCommand("-file-list-exec-source-files", GdbQuerySources); - sendCommand("set auto-solib-add on"); + sendCommand("sharedlibrary libc"); // for malloc sendCommand("sharedlibrary libdl"); // for dlopen tryLoadCustomDumpers(); - sendCommand("info shared", ModulesList, QVariant()); + + // intentionally after tryLoadCustomDumpers(), + // otherwise we'd interupt solib loading. + if (qq->wantsAllPluginBreakpoints()) { + sendCommand("set auto-solib-add on"); + sendCommand("set stop-on-solib-events 0"); + sendCommand("sharedlibrary .*"); + } else if (qq->wantsSelectedPluginBreakpoints()) { + sendCommand("set auto-solib-add on"); + sendCommand("set stop-on-solib-events 1"); + sendCommand("sharedlibrary "+qq->selectedPluginBreakpointsPattern()); + } else if (qq->wantsNoPluginBreakpoints()) { + // should be like that already + sendCommand("set auto-solib-add off"); + sendCommand("set stop-on-solib-events 0"); + } + reloadModules(); // this will "continue" if done attemptBreakpointSynchronization(); return; @@ -1174,36 +1177,19 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) // fall through } -#if 0 - if (console.contains("Stopped due to shared library event") || reason.isEmpty()) { - ++m_shared; - //if (m_shared == 2) - // tryLoadCustomDumpers(); - //qDebug() << "SHARED LIBRARY EVENT " << data.toString() << m_shared; - if (qq->useFastStart()) { - if (1 || m_shared <= 16) { // libpthread? - sendCommand("info shared", GdbInfoShared); - //sendCommand("sharedlibrary gdbdebugger "); - //continueInferior(); - } else { - // auto-load from now on - sendCommand("info shared"); - sendCommand("set auto-solib-add on"); - sendCommand("-file-list-exec-source-files", GdbQuerySources); - sendCommand("-break-list", BreakList); - //sendCommand("bt"); - //QVariant var = QVariant::fromValue(data); - //sendCommand("p 1", GdbAsyncOutput2, var); // dummy - continueInferior(); - } - } else { - // slow start requested. - q->showStatusMessage(tr("Loading %1...").arg(QString(data.toString()))); + static bool modulesDirty = false; + if (msg.contains("Stopped due to shared library event") || reason.isEmpty()) { + if (qq->wantsSelectedPluginBreakpoints()) { + qDebug() << "SHARED LIBRARY EVENT " << data.toString(); + qDebug() << "PATTERN" << qq->selectedPluginBreakpointsPattern(); + sendCommand("sharedlibrary " + qq->selectedPluginBreakpointsPattern()); continueInferior(); + q->showStatusMessage(tr("Loading %1...").arg(QString(data.toString()))); + return; } - return; + modulesDirty = true; + // fall through } -#endif if (isExitedReason(reason)) { qq->notifyInferiorExited(); @@ -1256,11 +1242,17 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) } if (isStoppedReason(reason) || reason.isEmpty()) { + if (modulesDirty) { + sendCommand("-file-list-exec-source-files", GdbQuerySources); + sendCommand("-break-list", BreakList); + reloadModules(); + modulesDirty = false; + } // Need another round trip if (reason == "breakpoint-hit") { q->showStatusMessage(tr("Stopped at breakpoint")); GdbMi frame = data.findChild("frame"); - qDebug() << "HIT BREAKPOINT: " << frame.toString(); + //qDebug() << "HIT BREAKPOINT: " << frame.toString(); m_currentFrame = frame.findChild("addr").data() + '%' + frame.findChild("func").data() + '%'; @@ -1504,7 +1496,6 @@ void GdbEngine::exitDebugger() m_fullToShortName.clear(); m_varToType.clear(); m_dataDumperState = DataDumperUninitialized; - m_shared = 0; m_outputCollector.shutdown(); //q->settings()->m_debugDumpers = false; } @@ -1572,12 +1563,7 @@ bool GdbEngine::startDebugger() q->showStatusMessage(tr("Gdb Running")); sendCommand("show version", GdbShowVersion); - if (qq->useFastStart()) { - sendCommand("set auto-solib-add off"); - sendCommand("set stop-on-solib-events 1"); - } //sendCommand("-enable-timings"); - //sendCommand("set stop-on-solib-events 1"); sendCommand("set print static-members off"); // Seemingly doesn't work. //sendCommand("define hook-stop\n-thread-list-ids\n-stack-list-frames\nend"); //sendCommand("define hook-stop\nprint 4\nend"); @@ -4044,8 +4030,6 @@ void GdbEngine::tryLoadCustomDumpers() QString lib = q->m_buildDir + "/qtc-gdbmacros/libgdbmacros.so"; if (QFileInfo(lib).isExecutable()) { //sendCommand("p dlopen"); - //if (qq->useFastStart()) - // sendCommand("set stop-on-solib-events 0"); QString flag = QString::number(RTLD_NOW); sendSynchronizedCommand("call (void)dlopen(\"" + lib + "\", " + flag + ")", WatchDumpCustomSetup); @@ -4053,8 +4037,6 @@ void GdbEngine::tryLoadCustomDumpers() sendSynchronizedCommand("call (void)__dlopen(\"" + lib + "\", " + flag + ")", WatchDumpCustomSetup); sendSynchronizedCommand("sharedlibrary " + dotEscape(lib)); - //if (qq->useFastStart()) - // sendCommand("set stop-on-solib-events 1"); } else { qDebug() << "DEBUG HELPER LIBRARY IS NOT USABLE: " << lib << QFileInfo(lib).isExecutable(); @@ -4064,14 +4046,10 @@ void GdbEngine::tryLoadCustomDumpers() QString lib = q->m_buildDir + "/qtc-gdbmacros/libgdbmacros.dylib"; if (QFileInfo(lib).isExecutable()) { //sendCommand("p dlopen"); // FIXME: remove me - //if (qq->useFastStart()) - // sendCommand("set stop-on-solib-events 0"); QString flag = QString::number(RTLD_NOW); sendSyncronizedCommand("call (void)dlopen(\"" + lib + "\", " + flag + ")", WatchDumpCustomSetup); - sendSyncronizedCommand("sharedlibrary " + dotEscape(lib)); - //if (qq->useFastStart()) - // sendCommand("set stop-on-solib-events 1"); + sendSynchronizedCommand("sharedlibrary " + dotEscape(lib)); } else { qDebug() << "DEBUG HELPER LIBRARY IS NOT USABLE: " << lib << QFileInfo(lib).isExecutable(); @@ -4080,15 +4058,11 @@ void GdbEngine::tryLoadCustomDumpers() #if defined(Q_OS_WIN) QString lib = q->m_buildDir + "/qtc-gdbmacros/debug/gdbmacros.dll"; if (QFileInfo(lib).exists()) { - //if (qq->useFastStart()) - // sendCommand("set stop-on-solib-events 0"); //sendCommand("handle SIGSEGV pass stop print"); //sendCommand("set unwindonsignal off"); sendSyncronizedCommand("call LoadLibraryA(\"" + lib + "\")", WatchDumpCustomSetup); - sendSyncronizedCommand("sharedlibrary " + dotEscape(lib)); - //if (qq->useFastStart()) - // sendCommand("set stop-on-solib-events 1"); + sendSynchronizedCommand("sharedlibrary " + dotEscape(lib)); } else { qDebug() << "DEBUG HELPER LIBRARY IS NOT USABLE: " << lib << QFileInfo(lib).isExecutable(); diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index fbb56a1b4d5..7973ef4c681 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -217,7 +217,6 @@ private: int m_oldestAcceptableToken; int m_gdbVersion; // 6.8.0 is 680 - int m_shared; // awful hack to keep track of used files QHash m_shortToFullName; From 3aa08efb757b0801686f8d6fa47a6e02ea378ec2 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 12 Feb 2009 13:31:19 +0100 Subject: [PATCH 26/62] Fixes: debugger: work on breakpoints in plugins --- src/plugins/debugger/debuggermanager.cpp | 4 +- src/plugins/debugger/debuggerplugin.cpp | 1 - src/plugins/debugger/gdbengine.cpp | 166 +++++------------------ src/plugins/debugger/gdbengine.h | 5 +- src/plugins/debugger/idebuggerengine.h | 1 - 5 files changed, 36 insertions(+), 141 deletions(-) diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 95010977da6..6d2b629e77a 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -558,7 +558,7 @@ void DebuggerManager::notifyInferiorUpdateFinished() void DebuggerManager::notifyInferiorRunningRequested() { setStatus(DebuggerInferiorRunningRequested); - showStatusMessage(tr("Running..."), 5000); + showStatusMessage(tr("Running requested..."), 5000); } void DebuggerManager::notifyInferiorRunning() @@ -576,7 +576,7 @@ void DebuggerManager::notifyInferiorExited() void DebuggerManager::notifyInferiorPidChanged(int pid) { //QMessageBox::warning(0, "PID", "PID: " + QString::number(pid)); - //qDebug() << "PID: " << pid; + qDebug() << "PID: " << pid; emit inferiorPidChanged(pid); } diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 18c7e6d0c56..d3e61c79c29 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -337,7 +337,6 @@ void GdbOptionPage::apply() m_settings.m_pluginSelectedBreakpointsPattern = m_ui.lineEditSelectedPluginBreakpointsPattern->text(); - *m_plugin->m_manager->settings() = m_settings; m_plugin->writeSettings(); } diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 49b76a5e34d..350981b8715 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -99,10 +99,8 @@ enum GdbCommandType GdbQueryPwd, GdbQuerySources, GdbAsyncOutput2, + GdbStart, GdbExecRun, - GdbExecStart1, - GdbExecStart2, - GdbExecStart3, GdbExecRunToFunction, GdbExecStep, GdbExecNext, @@ -460,13 +458,28 @@ void GdbEngine::handleResponse() break; } - case '~': - case '@': + case '~': { + QString data = GdbMi::parseCString(from, to); + m_pendingConsoleStreamOutput += data; + m_inbuffer = QByteArray(from, to - from); + break; + } + + case '@': { + QString data = GdbMi::parseCString(from, to); + m_pendingTargetStreamOutput += data; + m_inbuffer = QByteArray(from, to - from); + break; + } + case '&': { QString data = GdbMi::parseCString(from, to); - handleStreamOutput(data, c); - //dump(oldfrom, from, record.toString()); + m_pendingLogStreamOutput += data; m_inbuffer = QByteArray(from, to - from); + // On Windows, the contents seem to depend on the debugger + // version and/or OS version used. + if (data.startsWith("warning:")) + qq->showApplicationOutput(data); break; } @@ -759,14 +772,8 @@ void GdbEngine::handleResult(const GdbResultRecord & record, int type, handleExecRun(record); break; - case GdbExecStart1: - handleExecStart1(record); - break; - case GdbExecStart2: - //handleExecStart2(record); - break; - case GdbExecStart3: - handleExecStart3(record); + case GdbStart: + handleStart(record); break; case GdbInfoProc: handleInfoProc(record); @@ -1028,84 +1035,6 @@ void GdbEngine::handleExecRunToFunction(const GdbResultRecord &record) q->gotoLocation(file, line, true); } -void GdbEngine::handleStreamOutput(const QString &data, char code) -{ - // Linux - if (data.contains("[New Thread")) { - QRegExp re("\\[New Thread 0x([0-9a-f]*) \\(LWP ([0-9]*)\\)\\]"); - if (re.indexIn(data) != -1) - maybeHandleInferiorPidChanged(re.cap(2)); - } - - // Mac - if (data.contains("[Switching to process ")) { - QRegExp re("\\[Switching to process ([0-9]*) local thread 0x([0-9a-f]*)\\]"); - if (re.indexIn(data) != -1) - maybeHandleInferiorPidChanged(re.cap(1)); - } - - // present it twice: now and together with the next 'real' result - switch (code) { - case '~': - m_pendingConsoleStreamOutput += data; - break; - case '@': - m_pendingTargetStreamOutput += data; - break; - case '&': - m_pendingLogStreamOutput += data; - // On Windows, the contents seem to depend on the debugger - // version and/or OS version used. - if (data.startsWith("warning:")) - qq->showApplicationOutput(data); - break; - } - -#ifdef Q_OS_LINUX - if (data.startsWith("Pending break") && data.contains("\" resolved")) { - qDebug() << "SCHEDULING -break-list"; - //m_breakListOnStopNeeded = true; - } -#endif - -#if 0 - if (m_slurpingPTypeOutput) - qDebug() << "SLURP: " << output.data; - - // "No symbol \"__dlopen\" in current context." - // "No symbol \"dlopen\" in current context." - if (output.data.startsWith("No symbol ") - && output.data.contains("dlopen")) { - m_dlopened = true; - return; - } - - // output of 'ptype ' - if (output.data.startsWith("type = ")) { - if (output.data.endsWith("{") || output.data.endsWith("{\\n")) { - // multi-line output started here... - m_slurpingPTypeOutput = true; - m_slurpedPTypeOutput = output.data; - } else { - // Happens for simple types. Process it immediately - m_watchHandler->handleTypeContents(output.data); - } - return; - } - if (m_slurpingPTypeOutput) { - m_slurpedPTypeOutput += '\n'; - m_slurpedPTypeOutput += output.data; - if (output.data.startsWith("}")) { - // this is the last line... - m_slurpingPTypeOutput = false; - m_watchHandler->handleTypeContents(m_slurpedPTypeOutput); - m_slurpedPTypeOutput.clear(); - } - return; - } -#endif -} - static bool isExitedReason(const QString &reason) { return reason == QLatin1String("exited-normally") // inferior exited normally @@ -1633,13 +1562,17 @@ bool GdbEngine::startDebugger() } if (q->startMode() == q->startInternal) { + emit gdbInputAvailable(QString(), QString()); sendCommand("-file-exec-and-symbols " + fileName, GdbFileExecAndSymbols); //sendCommand("file " + fileName, GdbFileExecAndSymbols); #ifdef Q_OS_MAC sendCommand("sharedlibrary apply-load-rules all"); #endif - //sendCommand("-gdb-set stop-on-solib-events 1"); - runInferior(); + setTokenBarrier(); + if (!q->m_processArgs.isEmpty()) + sendCommand("-exec-arguments " + q->m_processArgs.join(" ")); + sendCommand("set auto-solib-add off"); + sendCommand("x/2i _start", GdbStart); } if (q->startMode() == q->attachExternal) { @@ -1678,21 +1611,7 @@ void GdbEngine::continueInferior() sendCommand("-exec-continue", GdbExecContinue); } -void GdbEngine::runInferior() -{ - q->resetLocation(); - // FIXME: this ignores important startup messages - setTokenBarrier(); - if (!q->m_processArgs.isEmpty()) - sendCommand("-exec-arguments " + q->m_processArgs.join(" ")); - qq->notifyInferiorRunningRequested(); - emit gdbInputAvailable(QString(), QString()); - - sendCommand("set auto-solib-add off"); - sendCommand("x/2i _start", GdbExecStart1); -} - -void GdbEngine::handleExecStart1(const GdbResultRecord &response) +void GdbEngine::handleStart(const GdbResultRecord &response) { if (response.resultClass == GdbResultDone) { // stdout:&"x/2i _start\n" @@ -1702,8 +1621,9 @@ void GdbEngine::handleExecStart1(const GdbResultRecord &response) QRegExp needle("0x([0-9a-f]+) <_start\\+.*>:"); if (needle.indexIn(msg) != -1) { //qDebug() << "STREAM: " << msg << needle.cap(1); - sendCommand("tbreak *0x" + needle.cap(1)); // GdbExecStart3); - sendCommand("-exec-run"); // GdbExecStart3); + sendCommand("tbreak *0x" + needle.cap(1)); + sendCommand("-exec-run"); + qq->notifyInferiorRunningRequested(); } else { qDebug() << "PARSING START ADDRESS FAILED" << msg; } @@ -1712,20 +1632,6 @@ void GdbEngine::handleExecStart1(const GdbResultRecord &response) } } -void GdbEngine::handleExecStart3(const GdbResultRecord &) -{ -#if defined(Q_OS_WIN) - sendCommand("info proc", GdbInfoProc); -#endif -#if defined(Q_OS_LINUX) - sendCommand("info proc", GdbInfoProc); -#endif -#if defined(Q_OS_MAC) - sendCommand("info pid", GdbInfoProc, QVariant(), true); -#endif - attemptBreakpointSynchronization(); -} - void GdbEngine::stepExec() { setTokenBarrier(); @@ -2244,12 +2150,7 @@ void GdbEngine::attemptBreakpointSynchronization() } } - if (updateNeeded) { - //interruptAndContinue(); - //sendListBreakpoints(); - } - - if (!updateNeeded && q->status() == DebuggerProcessStartingUp) { + if (!updateNeeded) { // we continue the execution continueInferior(); } @@ -4017,7 +3918,6 @@ void GdbEngine::assignValueInDebugger(const QString &expression, const QString & sendCommand("-var-assign assign " + value, WatchVarAssign); } - void GdbEngine::tryLoadCustomDumpers() { if (m_dataDumperState != DataDumperUninitialized) diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index 7973ef4c681..0b304e10660 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -113,7 +113,6 @@ private: void exitDebugger(); void continueInferior(); - void runInferior(); void interruptInferior(); void runToLineExec(const QString &fileName, int lineNumber); @@ -179,14 +178,12 @@ private slots: private: int terminationIndex(const QByteArray &buffer, int &length); - void handleStreamOutput(const QString &output, char code); + void handleStart(const GdbResultRecord &response); void handleAsyncOutput2(const GdbMi &data); void handleAsyncOutput(const GdbMi &data); void handleResultRecord(const GdbResultRecord &response); void handleFileExecAndSymbols(const GdbResultRecord &response); void handleExecRun(const GdbResultRecord &response); - void handleExecStart1(const GdbResultRecord &response); - void handleExecStart3(const GdbResultRecord &response); void handleExecJumpToLine(const GdbResultRecord &response); void handleExecRunToFunction(const GdbResultRecord &response); void handleInfoShared(const GdbResultRecord &response); diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index 1558d140ee6..ee1e15793f3 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -62,7 +62,6 @@ public: virtual void nextIExec() = 0; virtual void continueInferior() = 0; - virtual void runInferior() = 0; virtual void interruptInferior() = 0; virtual void runToLineExec(const QString &fileName, int lineNumber) = 0; From 1b5703b72959603a2ff4fc1d24250f6d843da5ad Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 12 Feb 2009 16:06:23 +0100 Subject: [PATCH 27/62] Fixes: uic warning about duplicate name Details: Give the layout a name. --- src/plugins/debugger/gdboptionpage.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/gdboptionpage.ui b/src/plugins/debugger/gdboptionpage.ui index e6c46c9bc3a..884080c1a30 100644 --- a/src/plugins/debugger/gdboptionpage.ui +++ b/src/plugins/debugger/gdboptionpage.ui @@ -19,7 +19,7 @@ Locations - + 9 From 0565b3a7fea5b3450475f1d98dace55670da40da Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Feb 2009 17:40:13 +0100 Subject: [PATCH 28/62] Fixes: debugger: start symbol is WinMainCRTStartup, not _start sometimes... Conflicts: src/plugins/debugger/gdbengine.cpp --- src/plugins/debugger/gdbengine.cpp | 72 +++++++++++++++++++----------- src/plugins/debugger/gdbengine.h | 2 + 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 350981b8715..663bd7c38cf 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -230,6 +230,15 @@ static bool isLeavableFunction(const QString &funcName, const QString &fileName) return false; } +static QString startSymbolName() +{ +#ifdef Q_OS_WIN + return "WinMainCRTStartup"; +#else + return "_start"; +#endif +} + /////////////////////////////////////////////////////////////////////// // @@ -251,6 +260,7 @@ GdbEngine::~GdbEngine() void GdbEngine::init() { m_pendingRequests = 0; + m_waitingForBreakpointSynchronizationToContinue = false; m_gdbVersion = 100; m_outputCodec = QTextCodec::codecForLocale(); m_dataDumperState = DataDumperUninitialized; @@ -650,7 +660,7 @@ void GdbEngine::maybeHandleInferiorPidChanged(const QString &pid0) } if (pid == q->m_attachedPID) return; - //qDebug() << "FOUND PID " << pid; + qDebug() << "FOUND PID " << pid; q->m_attachedPID = pid; qq->notifyInferiorPidChanged(pid); } @@ -750,8 +760,10 @@ void GdbEngine::handleResultRecord(const GdbResultRecord &record) --m_pendingRequests; PENDING_DEBUG(" TYPE " << cmd.type << " DECREMENTS PENDING TO: " << m_pendingRequests << cmd.command); - if (m_pendingRequests <= 0) + if (m_pendingRequests <= 0) { + PENDING_DEBUG(" .... AND TRIGGERS MODEL UPDATE"); updateWatchModel2(); + } } else { PENDING_DEBUG(" UNKNOWN TYPE " << cmd.type << " LEAVES PENDING AT: " << m_pendingRequests << cmd.command); @@ -1065,8 +1077,10 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) QString msg = data.findChild("consolestreamoutput").data(); if (reason.isEmpty()) { GdbMi frame = data.findChild("frame"); - if (frame.findChild("func").data() == "_start") { + if (frame.findChild("func").data() == startSymbolName()) { + // // that's the "early stop" + // frame.findChild("func").data() + '%'; #if defined(Q_OS_WIN) sendCommand("info proc", GdbInfoProc); @@ -1078,9 +1092,6 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) sendCommand("info pid", GdbInfoProc, QVariant(), true); #endif sendCommand("-file-list-exec-source-files", GdbQuerySources); - - sendCommand("sharedlibrary libc"); // for malloc - sendCommand("sharedlibrary libdl"); // for dlopen tryLoadCustomDumpers(); // intentionally after tryLoadCustomDumpers(), @@ -1098,11 +1109,12 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) sendCommand("set auto-solib-add off"); sendCommand("set stop-on-solib-events 0"); } - reloadModules(); // this will "continue" if done - attemptBreakpointSynchronization(); + m_waitingForBreakpointSynchronizationToContinue = true; + QTimer::singleShot(0, this, SLOT(attemptBreakpointSynchronization())); return; } + qDebug() << "EMPTY REASON FOR STOPPED"; // fall through } @@ -1231,7 +1243,7 @@ void GdbEngine::handleAsyncOutput2(const GdbMi &data) // // Breakpoints // - //qDebug() << "BREAK ASYNC: " << output.toString(); + //qDebug() << "BREAK ASYNC: " << data.toString(); //sendListBreakpoints(); //attemptBreakpointSynchronization(); //if (m_breakListOnStopNeeded) @@ -1572,7 +1584,7 @@ bool GdbEngine::startDebugger() if (!q->m_processArgs.isEmpty()) sendCommand("-exec-arguments " + q->m_processArgs.join(" ")); sendCommand("set auto-solib-add off"); - sendCommand("x/2i _start", GdbStart); + sendCommand("x/2i " + startSymbolName(), GdbStart); } if (q->startMode() == q->attachExternal) { @@ -1597,8 +1609,6 @@ bool GdbEngine::startDebugger() else qq->breakHandler()->setAllPending(); - //QTimer::singleShot(0, this, SLOT(attemptBreakpointSynchronization())); - return true; } @@ -1618,7 +1628,7 @@ void GdbEngine::handleStart(const GdbResultRecord &response) // stdout:~"0x404540 <_start>:\txor %ebp,%ebp\n" // stdout:~"0x404542 <_start+2>:\tmov %rdx,%r9\n" QString msg = response.data.findChild("consolestreamoutput").data(); - QRegExp needle("0x([0-9a-f]+) <_start\\+.*>:"); + QRegExp needle("0x([0-9a-f]+) <" + startSymbolName() + "\\+.*>:"); if (needle.indexIn(msg) != -1) { //qDebug() << "STREAM: " << msg << needle.cap(1); sendCommand("tbreak *0x" + needle.cap(1)); @@ -2080,11 +2090,14 @@ void GdbEngine::handleBreakInsert1(const GdbResultRecord &record, int index) void GdbEngine::attemptBreakpointSynchronization() { + // Non-lethal check for nested calls + static bool inBreakpointSychronization = false; + QTC_ASSERT(!inBreakpointSychronization, /**/); + inBreakpointSychronization = true; + BreakHandler *handler = qq->breakHandler(); - //qDebug() << "BREAKPOINT SYNCHRONIZATION "; foreach (BreakpointData *data, handler->takeRemovedBreakpoints()) { - //qDebug() << " SYNCHRONIZATION REMOVING" << data; QString bpNumber = data->bpNumber; if (!bpNumber.trimmed().isEmpty()) sendCommand("-break-delete " + bpNumber, BreakDelete, 0, true); @@ -2150,10 +2163,13 @@ void GdbEngine::attemptBreakpointSynchronization() } } - if (!updateNeeded) { + if (!updateNeeded && m_waitingForBreakpointSynchronizationToContinue) { + m_waitingForBreakpointSynchronizationToContinue = false; // we continue the execution continueInferior(); } + + inBreakpointSychronization = false; } @@ -3931,12 +3947,14 @@ void GdbEngine::tryLoadCustomDumpers() if (QFileInfo(lib).isExecutable()) { //sendCommand("p dlopen"); QString flag = QString::number(RTLD_NOW); - sendSynchronizedCommand("call (void)dlopen(\"" + lib + "\", " + flag + ")", + sendCommand("sharedlibrary libc"); // for malloc + sendCommand("sharedlibrary libdl"); // for dlopen + sendCommand("call (void)dlopen(\"" + lib + "\", " + flag + ")", WatchDumpCustomSetup); // some older systems like CentOS 4.6 prefer this: - sendSynchronizedCommand("call (void)__dlopen(\"" + lib + "\", " + flag + ")", + sendCommand("call (void)__dlopen(\"" + lib + "\", " + flag + ")", WatchDumpCustomSetup); - sendSynchronizedCommand("sharedlibrary " + dotEscape(lib)); + sendCommand("sharedlibrary " + dotEscape(lib)); } else { qDebug() << "DEBUG HELPER LIBRARY IS NOT USABLE: " << lib << QFileInfo(lib).isExecutable(); @@ -3945,11 +3963,12 @@ void GdbEngine::tryLoadCustomDumpers() #if defined(Q_OS_MAC) QString lib = q->m_buildDir + "/qtc-gdbmacros/libgdbmacros.dylib"; if (QFileInfo(lib).isExecutable()) { - //sendCommand("p dlopen"); // FIXME: remove me + sendCommand("sharedlibrary libc"); // for malloc + sendCommand("sharedlibrary libdl"); // for dlopen QString flag = QString::number(RTLD_NOW); - sendSyncronizedCommand("call (void)dlopen(\"" + lib + "\", " + flag + ")", + sendCommand("call (void)dlopen(\"" + lib + "\", " + flag + ")", WatchDumpCustomSetup); - sendSynchronizedCommand("sharedlibrary " + dotEscape(lib)); + sendCommand("sharedlibrary " + dotEscape(lib)); } else { qDebug() << "DEBUG HELPER LIBRARY IS NOT USABLE: " << lib << QFileInfo(lib).isExecutable(); @@ -3958,11 +3977,12 @@ void GdbEngine::tryLoadCustomDumpers() #if defined(Q_OS_WIN) QString lib = q->m_buildDir + "/qtc-gdbmacros/debug/gdbmacros.dll"; if (QFileInfo(lib).exists()) { + sendCommand("sharedlibrary .*"); // for LoadLibraryA //sendCommand("handle SIGSEGV pass stop print"); //sendCommand("set unwindonsignal off"); - sendSyncronizedCommand("call LoadLibraryA(\"" + lib + "\")", + sendCommand("call LoadLibraryA(\"" + lib + "\")", WatchDumpCustomSetup); - sendSynchronizedCommand("sharedlibrary " + dotEscape(lib)); + sendCommand("sharedlibrary " + dotEscape(lib)); } else { qDebug() << "DEBUG HELPER LIBRARY IS NOT USABLE: " << lib << QFileInfo(lib).isExecutable(); @@ -3970,9 +3990,9 @@ void GdbEngine::tryLoadCustomDumpers() #endif // retreive list of dumpable classes - sendSynchronizedCommand("call qDumpObjectData440(1,%1+1,0,0,0,0,0,0)", + sendCommand("call qDumpObjectData440(1,%1+1,0,0,0,0,0,0)", GdbQueryDataDumper1); - sendSynchronizedCommand("p (char*)qDumpOutBuffer", GdbQueryDataDumper2); + sendCommand("p (char*)qDumpOutBuffer", GdbQueryDataDumper2); } diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index 0b304e10660..f41990747d5 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -328,6 +328,8 @@ private: QString m_currentFrame; QMap m_varToType; + bool m_waitingForBreakpointSynchronizationToContinue; + DebuggerManager *q; IDebuggerManagerAccessForEngines *qq; }; From ce652e8ffc6e651d61712f4c736f6bc2b6626219 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 13 Feb 2009 13:50:50 +0100 Subject: [PATCH 29/62] Fixes: debugger: load modules list early Details: feels better --- src/plugins/debugger/debuggerrunner.cpp | 9 +++-- src/plugins/debugger/gdbengine.cpp | 44 ++++++++++++++----------- src/plugins/debugger/gdbengine.h | 4 ++- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp index 7f3e42f47fa..21313428aef 100644 --- a/src/plugins/debugger/debuggerrunner.cpp +++ b/src/plugins/debugger/debuggerrunner.cpp @@ -107,11 +107,14 @@ DebuggerRunControl::DebuggerRunControl(DebuggerManager *manager, : RunControl(runConfiguration), m_manager(manager), m_running(false) { connect(m_manager, SIGNAL(debuggingFinished()), - this, SLOT(debuggingFinished())); + this, SLOT(debuggingFinished()), + Qt::QueuedConnection); connect(m_manager, SIGNAL(applicationOutputAvailable(QString)), - this, SLOT(slotAddToOutputWindowInline(QString))); + this, SLOT(slotAddToOutputWindowInline(QString)), + Qt::QueuedConnection); connect(m_manager, SIGNAL(inferiorPidChanged(qint64)), - this, SLOT(bringApplicationToForeground(qint64))); + this, SLOT(bringApplicationToForeground(qint64)), + Qt::QueuedConnection); } void DebuggerRunControl::start() diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 663bd7c38cf..3238862d355 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -250,23 +250,16 @@ GdbEngine::GdbEngine(DebuggerManager *parent) { q = parent; qq = parent->engineInterface(); - init(); + initializeVariables(); + initializeConnections(); } GdbEngine::~GdbEngine() { } -void GdbEngine::init() +void GdbEngine::initializeConnections() { - m_pendingRequests = 0; - m_waitingForBreakpointSynchronizationToContinue = false; - m_gdbVersion = 100; - m_outputCodec = QTextCodec::codecForLocale(); - m_dataDumperState = DataDumperUninitialized; - - m_oldestAcceptableToken = -1; - // Gdb Process interaction connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)), this, SLOT(gdbProcError(QProcess::ProcessError))); @@ -294,6 +287,22 @@ void GdbEngine::init() Qt::QueuedConnection); } +void GdbEngine::initializeVariables() +{ + m_dataDumperState = DataDumperUninitialized; + m_gdbVersion = 100; + + m_fullToShortName.clear(); + m_shortToFullName.clear(); + m_varToType.clear(); + + m_modulesListOutdated = true; + m_oldestAcceptableToken = -1; + m_outputCodec = QTextCodec::codecForLocale(); + m_pendingRequests = 0; + m_waitingForBreakpointSynchronizationToContinue = false; +} + void GdbEngine::gdbProcError(QProcess::ProcessError error) { QString msg; @@ -1109,6 +1118,8 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) sendCommand("set auto-solib-add off"); sendCommand("set stop-on-solib-events 0"); } + // nicer to see a bit of the world we live in + reloadModules(); // this will "continue" if done m_waitingForBreakpointSynchronizationToContinue = true; QTimer::singleShot(0, this, SLOT(attemptBreakpointSynchronization())); @@ -1118,7 +1129,6 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) // fall through } - static bool modulesDirty = false; if (msg.contains("Stopped due to shared library event") || reason.isEmpty()) { if (qq->wantsSelectedPluginBreakpoints()) { qDebug() << "SHARED LIBRARY EVENT " << data.toString(); @@ -1128,7 +1138,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) q->showStatusMessage(tr("Loading %1...").arg(QString(data.toString()))); return; } - modulesDirty = true; + m_modulesListOutdated = true; // fall through } @@ -1183,11 +1193,11 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) } if (isStoppedReason(reason) || reason.isEmpty()) { - if (modulesDirty) { + if (m_modulesListOutdated) { sendCommand("-file-list-exec-source-files", GdbQuerySources); sendCommand("-break-list", BreakList); reloadModules(); - modulesDirty = false; + m_modulesListOutdated = false; } // Need another round trip if (reason == "breakpoint-hit") { @@ -1345,7 +1355,6 @@ void GdbEngine::handleExecRun(const GdbResultRecord &response) if (response.resultClass == GdbResultRunning) { qq->notifyInferiorRunning(); q->showStatusMessage(tr("Running...")); - //reloadModules(); } else if (response.resultClass == GdbResultError) { QString msg = response.data.findChild("msg").data(); if (msg == "Cannot find bounds of current function") { @@ -1433,11 +1442,8 @@ void GdbEngine::exitDebugger() if (m_gdbProc.state() != QProcess::NotRunning) qDebug() << "PROBLEM STOPPING DEBUGGER"; - m_shortToFullName.clear(); - m_fullToShortName.clear(); - m_varToType.clear(); - m_dataDumperState = DataDumperUninitialized; m_outputCollector.shutdown(); + initializeVariables(); //q->settings()->m_debugDumpers = false; } diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index f41990747d5..58021fb765a 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -144,7 +144,8 @@ private: bool supportsThreads() const; - void init(); // called by destructor + void initializeConnections(); + void initializeVariables(); void queryFullName(const QString &fileName, QString *fullName); QString fullName(const QString &fileName); QString shortName(const QString &fullName); @@ -329,6 +330,7 @@ private: QMap m_varToType; bool m_waitingForBreakpointSynchronizationToContinue; + bool m_modulesListOutdated; DebuggerManager *q; IDebuggerManagerAccessForEngines *qq; From 50d486685c89717842953e4b385d2e735e62962e Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 13 Feb 2009 14:45:46 +0100 Subject: [PATCH 30/62] Fixes: debugger: put error message into log if loading of dumpers failed --- src/plugins/debugger/gdbengine.cpp | 33 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 3238862d355..07e842307a5 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -3946,11 +3946,12 @@ void GdbEngine::tryLoadCustomDumpers() return; PENDING_DEBUG("TRY LOAD CUSTOM DUMPERS"); - m_dataDumperState = DataDumperLoadTried; + m_dataDumperState = DataDumperUnavailable; #if defined(Q_OS_LINUX) QString lib = q->m_buildDir + "/qtc-gdbmacros/libgdbmacros.so"; - if (QFileInfo(lib).isExecutable()) { + if (QFileInfo(lib).exists()) { + m_dataDumperState = DataDumperLoadTried; //sendCommand("p dlopen"); QString flag = QString::number(RTLD_NOW); sendCommand("sharedlibrary libc"); // for malloc @@ -3961,44 +3962,44 @@ void GdbEngine::tryLoadCustomDumpers() sendCommand("call (void)__dlopen(\"" + lib + "\", " + flag + ")", WatchDumpCustomSetup); sendCommand("sharedlibrary " + dotEscape(lib)); - } else { - qDebug() << "DEBUG HELPER LIBRARY IS NOT USABLE: " - << lib << QFileInfo(lib).isExecutable(); } #endif #if defined(Q_OS_MAC) QString lib = q->m_buildDir + "/qtc-gdbmacros/libgdbmacros.dylib"; - if (QFileInfo(lib).isExecutable()) { + if (QFileInfo(lib).exists()) { + m_dataDumperState = DataDumperLoadTried; sendCommand("sharedlibrary libc"); // for malloc sendCommand("sharedlibrary libdl"); // for dlopen QString flag = QString::number(RTLD_NOW); sendCommand("call (void)dlopen(\"" + lib + "\", " + flag + ")", WatchDumpCustomSetup); sendCommand("sharedlibrary " + dotEscape(lib)); - } else { - qDebug() << "DEBUG HELPER LIBRARY IS NOT USABLE: " - << lib << QFileInfo(lib).isExecutable(); } #endif #if defined(Q_OS_WIN) QString lib = q->m_buildDir + "/qtc-gdbmacros/debug/gdbmacros.dll"; if (QFileInfo(lib).exists()) { + m_dataDumperState = DataDumperLoadTried; sendCommand("sharedlibrary .*"); // for LoadLibraryA //sendCommand("handle SIGSEGV pass stop print"); //sendCommand("set unwindonsignal off"); sendCommand("call LoadLibraryA(\"" + lib + "\")", WatchDumpCustomSetup); sendCommand("sharedlibrary " + dotEscape(lib)); - } else { - qDebug() << "DEBUG HELPER LIBRARY IS NOT USABLE: " - << lib << QFileInfo(lib).isExecutable(); } #endif - // retreive list of dumpable classes - sendCommand("call qDumpObjectData440(1,%1+1,0,0,0,0,0,0)", - GdbQueryDataDumper1); - sendCommand("p (char*)qDumpOutBuffer", GdbQueryDataDumper2); + if (m_dataDumperState == DataDumperLoadTried) { + // retreive list of dumpable classes + sendCommand("call qDumpObjectData440(1,%1+1,0,0,0,0,0,0)", + GdbQueryDataDumper1); + sendCommand("p (char*)qDumpOutBuffer", GdbQueryDataDumper2); + } else { + gdbOutputAvailable("", QString("DEBUG HELPER LIBRARY IS NOT USABLE: " + " %1 EXISTS: %2, EXECUTABLE: %3").arg(lib) + .arg(QFileInfo(lib).exists()) + .arg(QFileInfo(lib).isExecutable())); + } } From 8dd03e5f530f74d895f08ad7162294f49c0b25ff Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 13 Feb 2009 14:54:36 +0100 Subject: [PATCH 31/62] Fixes: debugger: don't run -file-list-exec-source-files too often --- src/plugins/debugger/gdbengine.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 07e842307a5..c0ce1fb7f6e 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -1194,8 +1194,6 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) if (isStoppedReason(reason) || reason.isEmpty()) { if (m_modulesListOutdated) { - sendCommand("-file-list-exec-source-files", GdbQuerySources); - sendCommand("-break-list", BreakList); reloadModules(); m_modulesListOutdated = false; } From 7008467506231bd8491af42e7e07c6ba5aee7139 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 13 Feb 2009 14:57:24 +0100 Subject: [PATCH 32/62] Fixes: debugger: remove some dead code --- src/plugins/debugger/gdbengine.cpp | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index c0ce1fb7f6e..aa96254d5a9 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -1195,6 +1195,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) if (isStoppedReason(reason) || reason.isEmpty()) { if (m_modulesListOutdated) { reloadModules(); +QT_END_INCLUDE_NAMESPACE m_modulesListOutdated = false; } // Need another round trip @@ -1248,30 +1249,6 @@ void GdbEngine::handleAsyncOutput2(const GdbMi &data) { qq->notifyInferiorStopped(); - // - // Breakpoints - // - //qDebug() << "BREAK ASYNC: " << data.toString(); - //sendListBreakpoints(); - //attemptBreakpointSynchronization(); - //if (m_breakListOnStopNeeded) - // sendListBreakpoints(); - - // something reasonably 'invariant' - // Linux: - //"79*stopped,reason="end-stepping-range",reason="breakpoint-hit",bkptno="1", - //thread-id="1",frame={addr="0x0000000000405d8f",func="run1", - //args=[{name="argc",value="1"},{name="argv",value="0x7fffb7c23058"}], - //file="test1.cpp",fullname="/home/apoenitz/dev/work/test1/test1.cpp" - //,line="261"}" - // Mac: (but only sometimes) - // "82*stopped,bkpt={number="0",type="step - // resume",disp="keep",enabled="y",addr="0x43127171",at="",thread="1",shlib="/Users/epreuss/dev/ide/main/bin/ - // workbench.app/Contents/PlugIns/Trolltech/libFind.1.0.0.dylib", - // frame="0xbfffd800",thread="1",times="1"}, - // // Stack // @@ -3461,8 +3438,6 @@ void GdbEngine::handleDumpCustomValue1(const GdbResultRecord &record, && msg.startsWith("The program being debugged stopped while") && msg.contains("qDumpObjectData440")) { // Fake full stop - sendCommand("-file-list-exec-source-files", GdbQuerySources); - sendCommand("-break-list", BreakList); sendCommand("p 0", GdbAsyncOutput2); // dummy return; } From 140f34c529119072215828babae4e1a5905dacd0 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 13 Feb 2009 16:55:24 +0100 Subject: [PATCH 33/62] Fixes: debugger: try fixing startup break on make --- src/plugins/debugger/gdbengine.cpp | 93 ++++++++++++++++-------------- src/plugins/debugger/gdbengine.h | 1 + 2 files changed, 51 insertions(+), 43 deletions(-) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index aa96254d5a9..381b28c4ef0 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -301,6 +301,7 @@ void GdbEngine::initializeVariables() m_outputCodec = QTextCodec::codecForLocale(); m_pendingRequests = 0; m_waitingForBreakpointSynchronizationToContinue = false; + m_waitingForFirstBreakpointToBeHit = false; } void GdbEngine::gdbProcError(QProcess::ProcessError error) @@ -1083,52 +1084,47 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) { const QString reason = data.findChild("reason").data(); - QString msg = data.findChild("consolestreamoutput").data(); - if (reason.isEmpty()) { - GdbMi frame = data.findChild("frame"); - if (frame.findChild("func").data() == startSymbolName()) { - // - // that's the "early stop" - // - frame.findChild("func").data() + '%'; - #if defined(Q_OS_WIN) - sendCommand("info proc", GdbInfoProc); - #endif - #if defined(Q_OS_LINUX) - sendCommand("info proc", GdbInfoProc); - #endif - #if defined(Q_OS_MAC) - sendCommand("info pid", GdbInfoProc, QVariant(), true); - #endif - sendCommand("-file-list-exec-source-files", GdbQuerySources); - tryLoadCustomDumpers(); + bool isFirstStop = data.findChild("bkptno").data() == "1"; + if (isFirstStop && m_waitingForFirstBreakpointToBeHit) { + // + // that's the "early stop" + // + #if defined(Q_OS_WIN) + sendCommand("info proc", GdbInfoProc); + #endif + #if defined(Q_OS_LINUX) + sendCommand("info proc", GdbInfoProc); + #endif + #if defined(Q_OS_MAC) + sendCommand("info pid", GdbInfoProc, QVariant(), true); + #endif + sendCommand("-file-list-exec-source-files", GdbQuerySources); + tryLoadCustomDumpers(); - // intentionally after tryLoadCustomDumpers(), - // otherwise we'd interupt solib loading. - if (qq->wantsAllPluginBreakpoints()) { - sendCommand("set auto-solib-add on"); - sendCommand("set stop-on-solib-events 0"); - sendCommand("sharedlibrary .*"); - } else if (qq->wantsSelectedPluginBreakpoints()) { - sendCommand("set auto-solib-add on"); - sendCommand("set stop-on-solib-events 1"); - sendCommand("sharedlibrary "+qq->selectedPluginBreakpointsPattern()); - } else if (qq->wantsNoPluginBreakpoints()) { - // should be like that already - sendCommand("set auto-solib-add off"); - sendCommand("set stop-on-solib-events 0"); - } - // nicer to see a bit of the world we live in - reloadModules(); - // this will "continue" if done - m_waitingForBreakpointSynchronizationToContinue = true; - QTimer::singleShot(0, this, SLOT(attemptBreakpointSynchronization())); - return; + // intentionally after tryLoadCustomDumpers(), + // otherwise we'd interupt solib loading. + if (qq->wantsAllPluginBreakpoints()) { + sendCommand("set auto-solib-add on"); + sendCommand("set stop-on-solib-events 0"); + sendCommand("sharedlibrary .*"); + } else if (qq->wantsSelectedPluginBreakpoints()) { + sendCommand("set auto-solib-add on"); + sendCommand("set stop-on-solib-events 1"); + sendCommand("sharedlibrary "+qq->selectedPluginBreakpointsPattern()); + } else if (qq->wantsNoPluginBreakpoints()) { + // should be like that already + sendCommand("set auto-solib-add off"); + sendCommand("set stop-on-solib-events 0"); } - qDebug() << "EMPTY REASON FOR STOPPED"; - // fall through + // nicer to see a bit of the world we live in + reloadModules(); + // this will "continue" if done + m_waitingForBreakpointSynchronizationToContinue = true; + QTimer::singleShot(0, this, SLOT(attemptBreakpointSynchronization())); + return; } + QString msg = data.findChild("consolestreamoutput").data(); if (msg.contains("Stopped due to shared library event") || reason.isEmpty()) { if (qq->wantsSelectedPluginBreakpoints()) { qDebug() << "SHARED LIBRARY EVENT " << data.toString(); @@ -1142,6 +1138,17 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) // fall through } + // seen on XP after removing a breakpoint while running + // stdout:945*stopped,reason="signal-received",signal-name="SIGTRAP", + // signal-meaning="Trace/breakpoint trap",thread-id="2", + // frame={addr="0x7c91120f",func="ntdll!DbgUiConnectToDbg", + // args=[],from="C:\\WINDOWS\\system32\\ntdll.dll"} + if (reason == "signal-received" + && data.findChild("signal-name").toString() == "SIGTRAP") { + continueInferior(); + return; + } + if (isExitedReason(reason)) { qq->notifyInferiorExited(); QString msg = "Program exited normally"; @@ -1195,7 +1202,6 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) if (isStoppedReason(reason) || reason.isEmpty()) { if (m_modulesListOutdated) { reloadModules(); -QT_END_INCLUDE_NAMESPACE m_modulesListOutdated = false; } // Need another round trip @@ -1613,6 +1619,7 @@ void GdbEngine::handleStart(const GdbResultRecord &response) if (needle.indexIn(msg) != -1) { //qDebug() << "STREAM: " << msg << needle.cap(1); sendCommand("tbreak *0x" + needle.cap(1)); + m_waitingForFirstBreakpointToBeHit = true; sendCommand("-exec-run"); qq->notifyInferiorRunningRequested(); } else { diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index 58021fb765a..bf90ad97c99 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -330,6 +330,7 @@ private: QMap m_varToType; bool m_waitingForBreakpointSynchronizationToContinue; + bool m_waitingForFirstBreakpointToBeHit; bool m_modulesListOutdated; DebuggerManager *q; From 24479744ebc24100c4592f561b708be9725e6dcf Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 13 Feb 2009 17:11:34 +0100 Subject: [PATCH 34/62] Fixes: debugger: try to extact pid from 'info threads' on windows --- src/plugins/debugger/gdbengine.cpp | 25 ++++++++++++++++++++++--- src/plugins/debugger/gdbengine.h | 1 + 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 381b28c4ef0..0641dac2114 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -112,6 +112,7 @@ enum GdbCommandType GdbExecInterrupt, GdbInfoShared, GdbInfoProc, + GdbInfoThreads, GdbQueryDataDumper1, GdbQueryDataDumper2, @@ -800,6 +801,9 @@ void GdbEngine::handleResult(const GdbResultRecord & record, int type, case GdbInfoProc: handleInfoProc(record); break; + case GdbInfoThreads: + handleInfoThreads(record); + break; case GdbShowVersion: handleShowVersion(record); @@ -993,6 +997,19 @@ void GdbEngine::handleQuerySources(const GdbResultRecord &record) } } +void GdbEngine::handleInfoThreads(const GdbResultRecord &record) +{ + if (record.resultClass == GdbResultDone) { + // FIXME: use something more robust + // WIN: * 3 Thread 2312.0x4d0 0x7c91120f in ?? () + // LINUX: * 1 Thread 0x7f466273c6f0 (LWP 21455) 0x0000000000404542 in ... + QRegExp re(QLatin1String("Thread (\\d+)\\.0x.* in")); + QString data = record.data.findChild("consolestreamoutput").data(); + if (re.indexIn(data) != -1) + maybeHandleInferiorPidChanged(re.cap(1)); + } +} + void GdbEngine::handleInfoProc(const GdbResultRecord &record) { if (record.resultClass == GdbResultDone) { @@ -1084,13 +1101,15 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) { const QString reason = data.findChild("reason").data(); - bool isFirstStop = data.findChild("bkptno").data() == "1"; - if (isFirstStop && m_waitingForFirstBreakpointToBeHit) { + //MAC: bool isFirstStop = data.findChild("bkptno").data() == "1"; + //!MAC: startSymbolName == data.findChild("frame").findChild("func") + if (m_waitingForFirstBreakpointToBeHit) { + m_waitingForFirstBreakpointToBeHit = false; // // that's the "early stop" // #if defined(Q_OS_WIN) - sendCommand("info proc", GdbInfoProc); + sendCommand("info thread", GdbInfoThreads); #endif #if defined(Q_OS_LINUX) sendCommand("info proc", GdbInfoProc); diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index bf90ad97c99..0d710e359cf 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -189,6 +189,7 @@ private: void handleExecRunToFunction(const GdbResultRecord &response); void handleInfoShared(const GdbResultRecord &response); void handleInfoProc(const GdbResultRecord &response); + void handleInfoThreads(const GdbResultRecord &response); void handleShowVersion(const GdbResultRecord &response); void handleQueryPwd(const GdbResultRecord &response); void handleQuerySources(const GdbResultRecord &response); From 65212f119c975f53121c2cf60796774680ec1940 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 16 Feb 2009 09:59:12 +0100 Subject: [PATCH 35/62] Fixes: debugger: make shutdown a bit more robust --- src/plugins/debugger/debuggermanager.cpp | 138 ++++++++++++++++------- src/plugins/debugger/debuggermanager.h | 2 + 2 files changed, 98 insertions(+), 42 deletions(-) diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 6d2b629e77a..a41b2be883c 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -33,7 +33,6 @@ #include "debuggermanager.h" -#include "assert.h" #include "debuggerconstants.h" #include "idebuggerengine.h" @@ -58,6 +57,8 @@ #include "startexternaldialog.h" #include "attachexternaldialog.h" +#include + #include #include #include @@ -149,6 +150,7 @@ void DebuggerManager::init() { m_status = -1; m_busy = false; + m_shutdown = false; m_attachedPID = 0; m_startMode = startInternal; @@ -588,7 +590,18 @@ void DebuggerManager::showApplicationOutput(const QString &str) void DebuggerManager::shutdown() { //qDebug() << "DEBUGGER_MANAGER SHUTDOWN START"; - engine()->shutdown(); + m_shutdown = true; + if (m_engine) + m_engine->shutdown(); + m_engine = 0; + + delete scriptEngine; + scriptEngine = 0; + delete gdbEngine; + gdbEngine = 0; + delete winEngine; + winEngine = 0; + // Delete these manually before deleting the manager // (who will delete the models for most views) delete m_breakWindow; @@ -642,41 +655,49 @@ void DebuggerManager::toggleBreakpoint() void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber) { + QTC_ASSERT(m_engine, return); + QTC_ASSERT(m_breakHandler, return); int index = m_breakHandler->indexOf(fileName, lineNumber); if (index == -1) - breakHandler()->setBreakpoint(fileName, lineNumber); + m_breakHandler->setBreakpoint(fileName, lineNumber); else - breakHandler()->removeBreakpoint(index); - engine()->attemptBreakpointSynchronization(); + m_breakHandler->removeBreakpoint(index); + m_engine->attemptBreakpointSynchronization(); } void DebuggerManager::setToolTipExpression(const QPoint &pos, const QString &exp) { - engine()->setToolTipExpression(pos, exp); + QTC_ASSERT(m_engine, return); + m_engine->setToolTipExpression(pos, exp); } void DebuggerManager::updateWatchModel() { - engine()->updateWatchModel(); + QTC_ASSERT(m_engine, return); + m_engine->updateWatchModel(); } void DebuggerManager::expandChildren(const QModelIndex &idx) { - watchHandler()->expandChildren(idx); + QTC_ASSERT(m_watchHandler, return); + m_watchHandler->expandChildren(idx); } void DebuggerManager::collapseChildren(const QModelIndex &idx) { - watchHandler()->collapseChildren(idx); + QTC_ASSERT(m_watchHandler, return); + m_watchHandler->collapseChildren(idx); } void DebuggerManager::removeWatchExpression(const QString &exp) { - watchHandler()->removeWatchExpression(exp); + QTC_ASSERT(m_watchHandler, return); + m_watchHandler->removeWatchExpression(exp); } QVariant DebuggerManager::sessionValue(const QString &name) { + // this is answered by the plugin QVariant value; emit sessionValueRequested(name, &value); return value; @@ -684,16 +705,19 @@ QVariant DebuggerManager::sessionValue(const QString &name) void DebuggerManager::querySessionValue(const QString &name, QVariant *value) { + // this is answered by the plugin emit sessionValueRequested(name, value); } void DebuggerManager::setSessionValue(const QString &name, const QVariant &value) { + // this is answered by the plugin emit setSessionValueRequested(name, value); } QVariant DebuggerManager::configValue(const QString &name) { + // this is answered by the plugin QVariant value; emit configValueRequested(name, &value); return value; @@ -701,11 +725,13 @@ QVariant DebuggerManager::configValue(const QString &name) void DebuggerManager::queryConfigValue(const QString &name, QVariant *value) { + // this is answered by the plugin emit configValueRequested(name, value); } void DebuggerManager::setConfigValue(const QString &name, const QVariant &value) { + // this is answered by the plugin emit setConfigValueRequested(name, value); } @@ -788,7 +814,7 @@ bool DebuggerManager::startNewDebugger(StartMode mode) else setDebuggerType(GdbDebugger); - if (!engine()->startDebugger()) + if (!m_engine->startDebugger()) return false; m_busy = false; @@ -809,7 +835,10 @@ void DebuggerManager::cleanupViews() void DebuggerManager::exitDebugger() { - engine()->exitDebugger(); + if (m_shutdown) + return; + QTC_ASSERT(m_engine, return); + m_engine->exitDebugger(); cleanupViews(); setStatus(DebuggerProcessNotReady); setBusyCursor(false); @@ -818,62 +847,73 @@ void DebuggerManager::exitDebugger() void DebuggerManager::assignValueInDebugger(const QString &expr, const QString &value) { - engine()->assignValueInDebugger(expr, value); + QTC_ASSERT(m_engine, return); + m_engine->assignValueInDebugger(expr, value); } void DebuggerManager::activateFrame(int index) { - engine()->activateFrame(index); + QTC_ASSERT(m_engine, return); + m_engine->activateFrame(index); } void DebuggerManager::selectThread(int index) { - engine()->selectThread(index); + QTC_ASSERT(m_engine, return); + m_engine->selectThread(index); } void DebuggerManager::loadAllSymbols() { - engine()->loadAllSymbols(); + QTC_ASSERT(m_engine, return); + m_engine->loadAllSymbols(); } void DebuggerManager::loadSymbols(const QString &module) { - engine()->loadSymbols(module); + QTC_ASSERT(m_engine, return); + m_engine->loadSymbols(module); } void DebuggerManager::stepExec() { + QTC_ASSERT(m_engine, return); resetLocation(); - engine()->stepExec(); + m_engine->stepExec(); } void DebuggerManager::stepOutExec() { + QTC_ASSERT(m_engine, return); resetLocation(); - engine()->stepOutExec(); + m_engine->stepOutExec(); } void DebuggerManager::nextExec() { + QTC_ASSERT(m_engine, return); resetLocation(); - engine()->nextExec(); + m_engine->nextExec(); } void DebuggerManager::stepIExec() { + QTC_ASSERT(m_engine, return); resetLocation(); - engine()->stepIExec(); + m_engine->stepIExec(); } void DebuggerManager::nextIExec() { + QTC_ASSERT(m_engine, return); resetLocation(); - engine()->nextIExec(); + m_engine->nextIExec(); } void DebuggerManager::executeDebuggerCommand(const QString &command) { - engine()->executeDebuggerCommand(command); + QTC_ASSERT(m_engine, return); + m_engine->executeDebuggerCommand(command); } void DebuggerManager::sessionLoaded() @@ -891,16 +931,18 @@ void DebuggerManager::aboutToSaveSession() void DebuggerManager::loadSessionData() { + QTC_ASSERT(m_engine, return); m_breakHandler->loadSessionData(); m_watchHandler->loadSessionData(); - engine()->loadSessionData(); + m_engine->loadSessionData(); } void DebuggerManager::saveSessionData() { + QTC_ASSERT(m_engine, return); m_breakHandler->saveSessionData(); m_watchHandler->saveSessionData(); - engine()->saveSessionData(); + m_engine->saveSessionData(); } void DebuggerManager::dumpLog() @@ -959,19 +1001,24 @@ void DebuggerManager::addToWatchWindow() void DebuggerManager::watchExpression(const QString &expression) { - watchHandler()->watchExpression(expression); + QTC_ASSERT(m_watchHandler, return); + m_watchHandler->watchExpression(expression); } void DebuggerManager::setBreakpoint(const QString &fileName, int lineNumber) { - breakHandler()->setBreakpoint(fileName, lineNumber); - engine()->attemptBreakpointSynchronization(); + QTC_ASSERT(m_breakHandler, return); + QTC_ASSERT(m_engine, return); + m_breakHandler->setBreakpoint(fileName, lineNumber); + m_engine->attemptBreakpointSynchronization(); } void DebuggerManager::breakByFunction(const QString &functionName) { - breakHandler()->breakByFunction(functionName); - engine()->attemptBreakpointSynchronization(); + QTC_ASSERT(m_breakHandler, return); + QTC_ASSERT(m_engine, return); + m_breakHandler->breakByFunction(functionName); + m_engine->attemptBreakpointSynchronization(); } void DebuggerManager::breakByFunction() @@ -1081,14 +1128,16 @@ bool DebuggerManager::useCustomDumpers() const void DebuggerManager::setUseCustomDumpers(bool on) { + QTC_ASSERT(m_engine, return); m_settings.m_useCustomDumpers = on; - engine()->setUseCustomDumpers(on); + m_engine->setUseCustomDumpers(on); } void DebuggerManager::setDebugDumpers(bool on) { + QTC_ASSERT(m_engine, return); m_settings.m_debugDumpers = on; - engine()->setDebugDumpers(on); + m_engine->setDebugDumpers(on); } void DebuggerManager::setSkipKnownFrames(bool on) @@ -1104,29 +1153,31 @@ void DebuggerManager::queryCurrentTextEditor(QString *fileName, int *lineNumber, void DebuggerManager::continueExec() { - engine()->continueInferior(); + m_engine->continueInferior(); } void DebuggerManager::interruptDebuggingRequest() { + QTC_ASSERT(m_engine, return); //qDebug() << "INTERRUPTING AT" << status(); bool interruptIsExit = (status() != DebuggerInferiorRunning); if (interruptIsExit) exitDebugger(); else { setStatus(DebuggerInferiorStopRequested); - engine()->interruptInferior(); + m_engine->interruptInferior(); } } void DebuggerManager::runToLineExec() { + QTC_ASSERT(m_engine, return); QString fileName; int lineNumber = -1; emit currentTextEditorRequested(&fileName, &lineNumber, 0); if (!fileName.isEmpty()) - engine()->runToLineExec(fileName, lineNumber); + m_engine->runToLineExec(fileName, lineNumber); } void DebuggerManager::runToFunctionExec() @@ -1158,7 +1209,7 @@ void DebuggerManager::runToFunctionExec() } //qDebug() << "RUN TO FUNCTION " << functionName; if (!functionName.isEmpty()) - engine()->runToFunctionExec(functionName); + m_engine->runToFunctionExec(functionName); } void DebuggerManager::jumpToLineExec() @@ -1167,20 +1218,20 @@ void DebuggerManager::jumpToLineExec() int lineNumber = -1; emit currentTextEditorRequested(&fileName, &lineNumber, 0); if (!fileName.isEmpty()) - engine()->jumpToLineExec(fileName, lineNumber); + m_engine->jumpToLineExec(fileName, lineNumber); } void DebuggerManager::resetLocation() { - //m_watchHandler->removeMouseMoveCatcher(editor->widget()); + // connected to the plugin emit resetLocationRequested(); } void DebuggerManager::gotoLocation(const QString &fileName, int line, bool setMarker) { + // connected to the plugin emit gotoLocationRequested(fileName, line, setMarker); - //m_watchHandler->installMouseMoveCatcher(editor->widget()); } @@ -1192,9 +1243,10 @@ void DebuggerManager::gotoLocation(const QString &fileName, int line, void DebuggerManager::reloadDisassembler() { + QTC_ASSERT(m_engine, return); if (!m_disassemblerDock || !m_disassemblerDock->isVisible()) return; - engine()->reloadDisassembler(); + m_engine->reloadDisassembler(); } void DebuggerManager::disassemblerDockToggled(bool on) @@ -1214,7 +1266,7 @@ void DebuggerManager::reloadModules() { if (!m_modulesDock || !m_modulesDock->isVisible()) return; - engine()->reloadModules(); + m_engine->reloadModules(); } void DebuggerManager::modulesDockToggled(bool on) @@ -1232,11 +1284,13 @@ void DebuggerManager::modulesDockToggled(bool on) void DebuggerManager::showDebuggerOutput(const QString &prefix, const QString &msg) { + QTC_ASSERT(m_outputWindow, return); m_outputWindow->showOutput(prefix, msg); } void DebuggerManager::showDebuggerInput(const QString &prefix, const QString &msg) { + QTC_ASSERT(m_outputWindow, return); m_outputWindow->showInput(prefix, msg); } @@ -1257,7 +1311,7 @@ void DebuggerManager::reloadRegisters() { if (!m_registerDock || !m_registerDock->isVisible()) return; - engine()->reloadRegisters(); + m_engine->reloadRegisters(); } diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index a3407a0aa59..bd10b7b0259 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -466,6 +466,8 @@ private: IDebuggerEngine *engine(); IDebuggerEngine *m_engine; DebuggerSettings m_settings; + // set during application shutdown + bool m_shutdown; }; } // namespace Internal From 2cb3536a3c7e959be7b30e9c56a4ddfcf4739c95 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 16 Feb 2009 13:29:57 +0100 Subject: [PATCH 36/62] Fixes: debugger: work on shutdown --- src/plugins/debugger/debuggermanager.cpp | 42 +++---------- src/plugins/debugger/debuggermanager.h | 2 - src/plugins/debugger/debuggerrunner.cpp | 8 ++- src/plugins/debugger/debuggerrunner.h | 3 + src/plugins/debugger/gdbengine.cpp | 79 +++++++++++++----------- src/plugins/debugger/gdbengine.h | 1 + 6 files changed, 62 insertions(+), 73 deletions(-) diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index a41b2be883c..93597c51768 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -150,7 +150,6 @@ void DebuggerManager::init() { m_status = -1; m_busy = false; - m_shutdown = false; m_attachedPID = 0; m_startMode = startInternal; @@ -578,7 +577,7 @@ void DebuggerManager::notifyInferiorExited() void DebuggerManager::notifyInferiorPidChanged(int pid) { //QMessageBox::warning(0, "PID", "PID: " + QString::number(pid)); - qDebug() << "PID: " << pid; + //qDebug() << "PID: " << pid; emit inferiorPidChanged(pid); } @@ -590,9 +589,10 @@ void DebuggerManager::showApplicationOutput(const QString &str) void DebuggerManager::shutdown() { //qDebug() << "DEBUGGER_MANAGER SHUTDOWN START"; - m_shutdown = true; - if (m_engine) + if (m_engine) { + //qDebug() << "SHUTTING DOWN ENGINE" << m_engine; m_engine->shutdown(); + } m_engine = 0; delete scriptEngine; @@ -835,10 +835,9 @@ void DebuggerManager::cleanupViews() void DebuggerManager::exitDebugger() { - if (m_shutdown) - return; - QTC_ASSERT(m_engine, return); - m_engine->exitDebugger(); + //qDebug() << "DebuggerManager::exitDebugger"; + if (m_engine) + m_engine->exitDebugger(); cleanupViews(); setStatus(DebuggerProcessNotReady); setBusyCursor(false); @@ -960,33 +959,6 @@ void DebuggerManager::dumpLog() ts << m_outputWindow->combinedContents(); } -#if 0 -// call after m_gdbProc exited. -void GdbEngine::procFinished() -{ - //qDebug() << "GDB PROCESS FINISHED"; - setStatus(DebuggerProcessNotReady); - showStatusMessage(tr("Done"), 5000); - q->m_breakHandler->procFinished(); - q->m_watchHandler->cleanup(); - m_stackHandler->m_stackFrames.clear(); - m_stackHandler->resetModel(); - m_threadsHandler->resetModel(); - if (q->m_modulesHandler) - q->m_modulesHandler->procFinished(); - q->resetLocation(); - setStatus(DebuggerProcessNotReady); - emit q->previousModeRequested(); - emit q->debuggingFinished(); - //exitDebugger(); - //showStatusMessage("Gdb killed"); - m_shortToFullName.clear(); - m_fullToShortName.clear(); - m_shared = 0; - q->m_busy = false; -} -#endif - void DebuggerManager::addToWatchWindow() { // requires a selection, but that's the only case we want... diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index bd10b7b0259..a3407a0aa59 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -466,8 +466,6 @@ private: IDebuggerEngine *engine(); IDebuggerEngine *m_engine; DebuggerSettings m_settings; - // set during application shutdown - bool m_shutdown; }; } // namespace Internal diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp index 21313428aef..5034a0d9a4a 100644 --- a/src/plugins/debugger/debuggerrunner.cpp +++ b/src/plugins/debugger/debuggerrunner.cpp @@ -115,6 +115,8 @@ DebuggerRunControl::DebuggerRunControl(DebuggerManager *manager, connect(m_manager, SIGNAL(inferiorPidChanged(qint64)), this, SLOT(bringApplicationToForeground(qint64)), Qt::QueuedConnection); + connect(this, SIGNAL(stopRequested()), + m_manager, SLOT(exitDebugger())); } void DebuggerRunControl::start() @@ -148,17 +150,21 @@ void DebuggerRunControl::slotAddToOutputWindowInline(const QString &data) void DebuggerRunControl::stop() { - m_manager->exitDebugger(); + //qDebug() << "DebuggerRunControl::stop"; + m_running = false; + emit stopRequested(); } void DebuggerRunControl::debuggingFinished() { m_running = false; + //qDebug() << "DebuggerRunControl::finished"; //emit addToOutputWindow(this, tr("Debugging %1 finished").arg(m_executable)); emit finished(); } bool DebuggerRunControl::isRunning() const { + //qDebug() << "DebuggerRunControl::isRunning" << m_running; return m_running; } diff --git a/src/plugins/debugger/debuggerrunner.h b/src/plugins/debugger/debuggerrunner.h index 0c6d979c010..7b73178d103 100644 --- a/src/plugins/debugger/debuggerrunner.h +++ b/src/plugins/debugger/debuggerrunner.h @@ -82,6 +82,9 @@ public: virtual void stop(); virtual bool isRunning() const; +signals: + void stopRequested(); + private slots: void debuggingFinished(); void slotAddToOutputWindowInline(const QString &output); diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 0641dac2114..7f99a0a9b3e 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -257,6 +257,8 @@ GdbEngine::GdbEngine(DebuggerManager *parent) GdbEngine::~GdbEngine() { + // prevent sending error messages afterwards + m_gdbProc.disconnect(this); } void GdbEngine::initializeConnections() @@ -386,6 +388,11 @@ void GdbEngine::readDebugeeOutput(const QByteArray &data) data.constData(), data.length(), &m_outputCodecState)); } +void GdbEngine::debugMessage(const QString &msg) +{ + emit gdbOutputAvailable("debug:", msg); +} + // called asyncronously as response to Gdb stdout output in // gdbResponseAvailable() void GdbEngine::handleResponse() @@ -656,7 +663,7 @@ void GdbEngine::interruptInferior() sendCommand("-exec-interrupt", GdbExecInterrupt); qq->notifyInferiorStopped(); #else - qDebug() << "CANNOT STOP INFERIOR" << m_gdbProc.pid(); + debugMessage(QString("CANNOT STOP INFERIOR %1").arg(m_gdbProc.pid())); if (interruptChildProcess(m_gdbProc.pid())) qq->notifyInferiorStopped(); #endif @@ -666,12 +673,12 @@ void GdbEngine::maybeHandleInferiorPidChanged(const QString &pid0) { int pid = pid0.toInt(); if (pid == 0) { - qDebug() << "Cannot parse PID from " << pid0; + debugMessage(QString("Cannot parse PID from %1").arg(pid0)); return; } if (pid == q->m_attachedPID) return; - qDebug() << "FOUND PID " << pid; + debugMessage(QString("FOUND PID %1").arg(pid)); q->m_attachedPID = pid; qq->notifyInferiorPidChanged(pid); } @@ -686,7 +693,7 @@ void GdbEngine::sendCommand(const QString &command, int type, const QVariant &cookie, bool needStop, bool synchronized) { if (m_gdbProc.state() == QProcess::NotRunning) { - //qDebug() << "NO GDB PROCESS RUNNING, CMD IGNORED:" << command; + debugMessage("NO GDB PROCESS RUNNING, CMD IGNORED: " + command); return; } @@ -718,9 +725,7 @@ void GdbEngine::sendCommand(const QString &command, int type, m_cookieForToken[currentToken()] = cmd; - //qDebug() << ""; if (!command.isEmpty()) { - //qDebug() << qPrintable(currentTime()) << "RUNNING" << cmd.command; m_gdbProc.write(cmd.command.toLatin1() + "\r\n"); //emit gdbInputAvailable(QString(), " " + currentTime()); //emit gdbInputAvailable(QString(), "[" + currentTime() + "] " + cmd.command); @@ -920,8 +925,8 @@ void GdbEngine::handleResult(const GdbResultRecord & record, int type, break; default: - qDebug() << "FIXME: GdbEngine::handleResult: " - "should not happen" << type; + debugMessage(QString("FIXME: GdbEngine::handleResult: " + "should not happen %1").arg(type)); break; } } @@ -930,7 +935,7 @@ void GdbEngine::executeDebuggerCommand(const QString &command) { //createGdbProcessIfNeeded(); if (m_gdbProc.state() == QProcess::NotRunning) { - qDebug() << "NO GDB PROCESS RUNNING, PLAIN CMD IGNORED: " << command; + debugMessage("NO GDB PROCESS RUNNING, PLAIN CMD IGNORED: " + command); return; } @@ -938,11 +943,6 @@ void GdbEngine::executeDebuggerCommand(const QString &command) cmd.command = command; cmd.type = -1; - //m_cookieForToken[currentToken()] = cmd; - //++currentToken(); - - //qDebug() << ""; - //qDebug() << currentTime() << "Running command: " << cmd.command; emit gdbInputAvailable(QString(), cmd.command); m_gdbProc.write(cmd.command.toLatin1() + "\r\n"); } @@ -969,7 +969,7 @@ void GdbEngine::handleQueryPwd(const GdbResultRecord &record) m_pwd = record.data.findChild("consolestreamoutput").data(); m_pwd = m_pwd.trimmed(); #endif - //qDebug() << "PWD RESULT:" << m_pwd; + debugMessage("PWD RESULT: " + m_pwd); } } @@ -1146,8 +1146,8 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) QString msg = data.findChild("consolestreamoutput").data(); if (msg.contains("Stopped due to shared library event") || reason.isEmpty()) { if (qq->wantsSelectedPluginBreakpoints()) { - qDebug() << "SHARED LIBRARY EVENT " << data.toString(); - qDebug() << "PATTERN" << qq->selectedPluginBreakpointsPattern(); + debugMessage("SHARED LIBRARY EVENT: " + data.toString()); + debugMessage("PATTERN: " + qq->selectedPluginBreakpointsPattern()); sendCommand("sharedlibrary " + qq->selectedPluginBreakpointsPattern()); continueInferior(); q->showStatusMessage(tr("Loading %1...").arg(QString(data.toString()))); @@ -1182,6 +1182,8 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) + data.findChild("signal-name").toString(); } q->showStatusMessage(msg); + // FIXME: shouldn't this use a statis change? + debugMessage("CALLING PARENT EXITDEBUGGER"); q->exitDebugger(); return; } @@ -1193,21 +1195,21 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) if (qq->skipKnownFrames()) { if (reason == "end-stepping-range" || reason == "function-finished") { GdbMi frame = data.findChild("frame"); - //qDebug() << frame.toString(); + //debugMessage(frame.toString()); m_currentFrame = frame.findChild("addr").data() + '%' + frame.findChild("func").data() + '%'; QString funcName = frame.findChild("func").data(); QString fileName = frame.findChild("file").data(); if (isLeavableFunction(funcName, fileName)) { - //qDebug() << "LEAVING" << funcName; + //debugMessage("LEAVING" + funcName); ++stepCounter; q->stepOutExec(); //stepExec(); return; } if (isSkippableFunction(funcName, fileName)) { - //qDebug() << "SKIPPING" << funcName; + //debugMessage("SKIPPING" + funcName); ++stepCounter; q->stepExec(); return; @@ -1227,7 +1229,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) if (reason == "breakpoint-hit") { q->showStatusMessage(tr("Stopped at breakpoint")); GdbMi frame = data.findChild("frame"); - //qDebug() << "HIT BREAKPOINT: " << frame.toString(); + //debugMessage("HIT BREAKPOINT: " + frame.toString()); m_currentFrame = frame.findChild("addr").data() + '%' + frame.findChild("func").data() + '%'; @@ -1243,7 +1245,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) return; } - qDebug() << "STOPPED FOR UNKNOWN REASON" << data.toString(); + debugMessage("STOPPED FOR UNKNOWN REASON: " + data.toString()); // Ignore it. Will be handled with full response later in the // JumpToLine or RunToFunction handlers #if 1 @@ -1310,7 +1312,7 @@ void GdbEngine::handleShowVersion(const GdbResultRecord &response) QString msg = response.data.findChild("consolestreamoutput").data(); QRegExp supported("GNU gdb(.*) (\\d+)\\.(\\d+)(\\.(\\d+))?"); if (supported.indexIn(msg) == -1) { - qDebug() << "UNSUPPORTED GDB VERSION " << msg; + debugMessage("UNSUPPORTED GDB VERSION " + msg); QStringList list = msg.split("\n"); while (list.size() > 2) list.removeLast(); @@ -1331,7 +1333,7 @@ void GdbEngine::handleShowVersion(const GdbResultRecord &response) m_gdbVersion = 10000 * supported.cap(2).toInt() + 100 * supported.cap(3).toInt() + 1 * supported.cap(5).toInt(); - //qDebug() << "GDB VERSION " << m_gdbVersion; + //debugMessage(QString("GDB VERSION: %1").arg(m_gdbVersion)); } } } @@ -1387,7 +1389,7 @@ QString GdbEngine::fullName(const QString &fileName) if (fileName.isEmpty()) return QString(); QString full = m_shortToFullName.value(fileName, QString()); - //qDebug() << "RESOLVING: " << fileName << full; + //debugMessage("RESOLVING: " + fileName + " " + full); if (!full.isEmpty()) return full; QFileInfo fi(fileName); @@ -1397,7 +1399,7 @@ QString GdbEngine::fullName(const QString &fileName) #ifdef Q_OS_WIN full = QDir::cleanPath(full); #endif - //qDebug() << "STORING: " << fileName << full; + //debugMessage("STORING: " + fileName + " " + full); m_shortToFullName[fileName] = full; m_fullToShortName[full] = fileName; return full; @@ -1425,22 +1427,29 @@ void GdbEngine::shutdown() void GdbEngine::exitDebugger() { - //qDebug() << "EXITING: " << m_gdbProc.state(); - if (m_gdbProc.state() == QProcess::Starting) + debugMessage(QString("GDBENGINE EXITDEBUFFER: %1").arg(m_gdbProc.state())); + if (m_gdbProc.state() == QProcess::Starting) { + debugMessage(QString("WAITING FOR GDB STARTUP TO SHUTDOWN: %1") + .arg(m_gdbProc.state())); m_gdbProc.waitForStarted(); + } if (m_gdbProc.state() == QProcess::Running) { + debugMessage(QString("WAITING FOR RUNNING GDB TO SHUTDOWN: %1") + .arg(m_gdbProc.state())); interruptInferior(); sendCommand("kill"); sendCommand("-gdb-exit"); // 20s can easily happen when loading webkit debug information m_gdbProc.waitForFinished(20000); if (m_gdbProc.state() != QProcess::Running) { + debugMessage(QString("FORCING TERMINATION: %1") + .arg(m_gdbProc.state())); m_gdbProc.terminate(); m_gdbProc.waitForFinished(20000); } } if (m_gdbProc.state() != QProcess::NotRunning) - qDebug() << "PROBLEM STOPPING DEBUGGER"; + debugMessage("PROBLEM STOPPING DEBUGGER"); m_outputCollector.shutdown(); initializeVariables(); @@ -1462,7 +1471,7 @@ bool GdbEngine::startDebugger() QString fileName = '"' + fi.absoluteFilePath() + '"'; if (m_gdbProc.state() != QProcess::NotRunning) { - qDebug() << "GDB IS ALREADY RUNNING!"; + debugMessage("GDB IS ALREADY RUNNING!"); return false; } @@ -1636,16 +1645,16 @@ void GdbEngine::handleStart(const GdbResultRecord &response) QString msg = response.data.findChild("consolestreamoutput").data(); QRegExp needle("0x([0-9a-f]+) <" + startSymbolName() + "\\+.*>:"); if (needle.indexIn(msg) != -1) { - //qDebug() << "STREAM: " << msg << needle.cap(1); + //debugMessage("STREAM: " + msg + " " + needle.cap(1)); sendCommand("tbreak *0x" + needle.cap(1)); m_waitingForFirstBreakpointToBeHit = true; sendCommand("-exec-run"); qq->notifyInferiorRunningRequested(); } else { - qDebug() << "PARSING START ADDRESS FAILED" << msg; + debugMessage("PARSING START ADDRESS FAILED: " + msg); } } else if (response.resultClass == GdbResultError) { - qDebug() << "PARSING START ADDRESS FAILED" << response.toString(); + debugMessage("PARSING START ADDRESS FAILED: " + response.toString()); } } @@ -1740,12 +1749,12 @@ void GdbEngine::setTokenBarrier() void GdbEngine::setDebugDumpers(bool on) { if (on) { - qDebug() << "SWITCHING ON DUMPER DEBUGGING"; + debugMessage("SWITCHING ON DUMPER DEBUGGING"); sendCommand("set unwindonsignal off"); q->breakByFunction("qDumpObjectData440"); //updateLocals(); } else { - qDebug() << "SWITCHING OFF DUMPER DEBUGGING"; + debugMessage("SWITCHING OFF DUMPER DEBUGGING"); sendCommand("set unwindonsignal on"); } } diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index 0d710e359cf..ee5de645c3d 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -193,6 +193,7 @@ private: void handleShowVersion(const GdbResultRecord &response); void handleQueryPwd(const GdbResultRecord &response); void handleQuerySources(const GdbResultRecord &response); + void debugMessage(const QString &msg); OutputCollector m_outputCollector; QTextCodec *m_outputCodec; From 32ff5cf9eeed51d652d7243d3e126a5231940338 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 16 Feb 2009 13:41:57 +0100 Subject: [PATCH 37/62] Fixes: debugging external apps just treat it the same as internal apps as far as gdbengine is concerned. --- src/plugins/debugger/gdbengine.cpp | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 7f99a0a9b3e..6e68184913d 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -1588,7 +1588,9 @@ bool GdbEngine::startDebugger() } } - if (q->startMode() == q->startInternal) { + if (q->startMode() == q->attachExternal) { + sendCommand("attach " + QString::number(q->m_attachedPID)); + } else { emit gdbInputAvailable(QString(), QString()); sendCommand("-file-exec-and-symbols " + fileName, GdbFileExecAndSymbols); //sendCommand("file " + fileName, GdbFileExecAndSymbols); @@ -1602,20 +1604,6 @@ bool GdbEngine::startDebugger() sendCommand("x/2i " + startSymbolName(), GdbStart); } - if (q->startMode() == q->attachExternal) { - sendCommand("attach " + QString::number(q->m_attachedPID)); - } - - if (q->startMode() == q->startExternal) { - //sendCommand("-file-exec-and-symbols " + fileName, GdbFileExecAndSymbols); - sendCommand("file " + fileName, GdbFileExecAndSymbols); - #ifdef Q_OS_MAC - sendCommand("sharedlibrary apply-load-rules all"); - #endif - //sendCommand("-file-list-exec-source-files", GdbQuerySources); - //sendCommand("-gdb-set stop-on-solib-events 1"); - } - sendCommand("-data-list-register-names", RegisterListNames); // set all to "pending" From aef3fa67039739f4a223a446b0138009dcffa957 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 16 Feb 2009 13:58:43 +0100 Subject: [PATCH 38/62] Fixes: debugger: enum naming cosmetics --- src/plugins/debugger/debuggermanager.cpp | 12 ++++++------ src/plugins/debugger/debuggermanager.h | 2 +- src/plugins/debugger/debuggerrunner.cpp | 2 +- src/plugins/debugger/gdbengine.cpp | 5 +++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 93597c51768..660448a6bcc 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -152,7 +152,7 @@ void DebuggerManager::init() m_busy = false; m_attachedPID = 0; - m_startMode = startInternal; + m_startMode = StartInternal; m_disassemblerHandler = 0; m_modulesHandler = 0; @@ -737,13 +737,13 @@ void DebuggerManager::setConfigValue(const QString &name, const QVariant &value) void DebuggerManager::startExternalApplication() { - if (!startNewDebugger(startExternal)) + if (!startNewDebugger(StartExternal)) emit debuggingFinished(); } void DebuggerManager::attachExternalApplication() { - if (!startNewDebugger(attachExternal)) + if (!startNewDebugger(AttachExternal)) emit debuggingFinished(); } @@ -752,7 +752,7 @@ bool DebuggerManager::startNewDebugger(StartMode mode) m_startMode = mode; // FIXME: Clean up - if (startMode() == startExternal) { + if (startMode() == StartExternal) { StartExternalDialog dlg(mainWindow()); dlg.setExecutableFile( configValue(QLatin1String("LastExternalExecutableFile")).toString()); @@ -768,7 +768,7 @@ bool DebuggerManager::startNewDebugger(StartMode mode) m_processArgs = dlg.executableArguments().split(' '); m_workingDir = QString(); m_attachedPID = -1; - } else if (startMode() == attachExternal) { + } else if (startMode() == AttachExternal) { AttachExternalDialog dlg(mainWindow()); if (dlg.exec() != QDialog::Accepted) return false; @@ -781,7 +781,7 @@ bool DebuggerManager::startNewDebugger(StartMode mode) tr("Cannot attach to PID 0")); return false; } - } else if (startMode() == startInternal) { + } else if (startMode() == StartInternal) { if (m_executable.isEmpty()) { QString startDirectory = m_executable; if (m_executable.isEmpty()) { diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index a3407a0aa59..8af4a683378 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -229,7 +229,7 @@ public: QLabel *statusLabel() const { return m_statusLabel; } DebuggerSettings *settings() { return &m_settings; } - enum StartMode { startInternal, startExternal, attachExternal }; + enum StartMode { StartInternal, StartExternal, AttachExternal }; enum DebuggerType { GdbDebugger, ScriptDebugger, WinDebugger }; public slots: diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp index 5034a0d9a4a..149b137727e 100644 --- a/src/plugins/debugger/debuggerrunner.cpp +++ b/src/plugins/debugger/debuggerrunner.cpp @@ -137,7 +137,7 @@ void DebuggerRunControl::start() // andre: + "\qtc-gdbmacros\" //emit addToOutputWindow(this, tr("Debugging %1").arg(m_executable)); - if (m_manager->startNewDebugger(DebuggerManager::startInternal)) + if (m_manager->startNewDebugger(DebuggerManager::StartInternal)) emit started(); else debuggingFinished(); diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 6e68184913d..4e5c8bf82b2 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -1588,9 +1588,10 @@ bool GdbEngine::startDebugger() } } - if (q->startMode() == q->attachExternal) { + if (q->startMode() == DebuggerManager::AttachExternal) { sendCommand("attach " + QString::number(q->m_attachedPID)); } else { + // StartInternal or StartExternal emit gdbInputAvailable(QString(), QString()); sendCommand("-file-exec-and-symbols " + fileName, GdbFileExecAndSymbols); //sendCommand("file " + fileName, GdbFileExecAndSymbols); @@ -1607,7 +1608,7 @@ bool GdbEngine::startDebugger() sendCommand("-data-list-register-names", RegisterListNames); // set all to "pending" - if (q->startMode() == q->attachExternal) + if (q->startMode() == DebuggerManager::AttachExternal) qq->breakHandler()->removeAllBreakpoints(); else qq->breakHandler()->setAllPending(); From 1dd1752c4e7f961c4f1bc27b971f7445eb7144da Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 16 Feb 2009 16:00:46 +0100 Subject: [PATCH 39/62] move -data-list-register-names up to the other initializers. --- src/plugins/debugger/gdbengine.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 4e5c8bf82b2..58cba9c426a 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -1534,6 +1534,7 @@ bool GdbEngine::startDebugger() //sendCommand("set pagination off"); sendCommand("set breakpoint pending on", BreakEnablePending); sendCommand("set print elements 10000"); + sendCommand("-data-list-register-names", RegisterListNames); // one of the following is needed to prevent crashes in gdb on code like: // template T foo() { return T(0); } @@ -1605,8 +1606,6 @@ bool GdbEngine::startDebugger() sendCommand("x/2i " + startSymbolName(), GdbStart); } - sendCommand("-data-list-register-names", RegisterListNames); - // set all to "pending" if (q->startMode() == DebuggerManager::AttachExternal) qq->breakHandler()->removeAllBreakpoints(); From 25c7eb3dff87d1a47378e9980f39a779e7623a6f Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 16 Feb 2009 16:50:20 +0100 Subject: [PATCH 40/62] Fixes: windows build --- src/plugins/debugger/gdbengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 58cba9c426a..ae80da5b716 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -663,7 +663,7 @@ void GdbEngine::interruptInferior() sendCommand("-exec-interrupt", GdbExecInterrupt); qq->notifyInferiorStopped(); #else - debugMessage(QString("CANNOT STOP INFERIOR %1").arg(m_gdbProc.pid())); + debugMessage(QString("CANNOT STOP INFERIOR")); if (interruptChildProcess(m_gdbProc.pid())) qq->notifyInferiorStopped(); #endif From b4a79218326b622a0c2dd8918fb6e2824583070c Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Feb 2009 17:42:08 +0100 Subject: [PATCH 41/62] Fixes: debugger: work on process logic Conflicts: src/plugins/debugger/gdbengine.cpp --- src/plugins/debugger/debuggermanager.cpp | 12 +++ src/plugins/debugger/debuggermanager.h | 2 + src/plugins/debugger/gdbengine.cpp | 105 +++++++++++++++-------- src/plugins/debugger/gdbengine.h | 11 ++- 4 files changed, 89 insertions(+), 41 deletions(-) diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 660448a6bcc..9130d57c54b 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -543,6 +543,12 @@ void DebuggerManager::notifyStartupFinished() showStatusMessage(tr("Startup finished. Debugger ready."), -1); } +void DebuggerManager::notifyInferiorStopRequested() +{ + setStatus(DebuggerInferiorStopRequested); + showStatusMessage(tr("Stop requested..."), 5000); +} + void DebuggerManager::notifyInferiorStopped() { resetLocation(); @@ -657,6 +663,12 @@ void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber) { QTC_ASSERT(m_engine, return); QTC_ASSERT(m_breakHandler, return); + if (status() != DebuggerInferiorRunning && status() != DebuggerInferiorStopped) { + showStatusMessage(tr("Changing breakpoint state requires either a " + "fully running or fully stopped application.")); + return; + } + int index = m_breakHandler->indexOf(fileName, lineNumber); if (index == -1) m_breakHandler->setBreakpoint(fileName, lineNumber); diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index 8af4a683378..636187d68cd 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -151,6 +151,7 @@ private: // called from the engines after successful startup virtual void notifyStartupFinished() = 0; + virtual void notifyInferiorStopRequested() = 0; virtual void notifyInferiorStopped() = 0; virtual void notifyInferiorUpdateFinished() = 0; virtual void notifyInferiorRunningRequested() = 0; @@ -339,6 +340,7 @@ private: void notifyInferiorStopped(); void notifyInferiorUpdateFinished(); void notifyInferiorRunningRequested(); + void notifyInferiorStopRequested(); void notifyInferiorRunning(); void notifyInferiorExited(); void notifyInferiorPidChanged(int); diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index ae80da5b716..6f41c83379d 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -115,6 +115,7 @@ enum GdbCommandType GdbInfoThreads, GdbQueryDataDumper1, GdbQueryDataDumper2, + GdbTemporaryContinue, BreakCondition = 200, BreakEnablePending, @@ -305,6 +306,7 @@ void GdbEngine::initializeVariables() m_pendingRequests = 0; m_waitingForBreakpointSynchronizationToContinue = false; m_waitingForFirstBreakpointToBeHit = false; + m_commandsToRunOnTemporaryBreak.clear(); } void GdbEngine::gdbProcError(QProcess::ProcessError error) @@ -650,22 +652,29 @@ void GdbEngine::readGdbStandardOutput() void GdbEngine::interruptInferior() { - if (m_gdbProc.state() == QProcess::NotRunning) + qq->notifyInferiorStopRequested(); + if (m_gdbProc.state() == QProcess::NotRunning) { + debugMessage("TRYING TO INTERRUPT INFERIOR WITHOUT RUNNING GDB"); + qq->notifyInferiorExited(); return; + } if (q->m_attachedPID > 0) { - if (interruptProcess(q->m_attachedPID)) - qq->notifyInferiorStopped(); + if (!interruptProcess(q->m_attachedPID)) + // qq->notifyInferiorStopped(); + //else + debugMessage(QString("CANNOT INTERRUPT %1").arg(q->m_attachedPID)); return; } #ifdef Q_OS_MAC sendCommand("-exec-interrupt", GdbExecInterrupt); - qq->notifyInferiorStopped(); + //qq->notifyInferiorStopped(); #else - debugMessage(QString("CANNOT STOP INFERIOR")); - if (interruptChildProcess(m_gdbProc.pid())) - qq->notifyInferiorStopped(); + if (!interruptChildProcess(m_gdbProc.pid())) + // qq->notifyInferiorStopped(); + //else + debugMessage(QString("CANNOT STOP INFERIOR")); #endif } @@ -684,27 +693,19 @@ void GdbEngine::maybeHandleInferiorPidChanged(const QString &pid0) } void GdbEngine::sendSynchronizedCommand(const QString & command, - int type, const QVariant &cookie, bool needStop) + int type, const QVariant &cookie, StopNeeded needStop) { - sendCommand(command, type, cookie, needStop, true); + sendCommand(command, type, cookie, needStop, Synchronized); } void GdbEngine::sendCommand(const QString &command, int type, - const QVariant &cookie, bool needStop, bool synchronized) + const QVariant &cookie, StopNeeded needStop, Synchronization synchronized) { if (m_gdbProc.state() == QProcess::NotRunning) { debugMessage("NO GDB PROCESS RUNNING, CMD IGNORED: " + command); return; } - bool temporarilyStopped = false; - if (needStop && q->status() == DebuggerInferiorRunning) { - q->showStatusMessage(tr("Temporarily stopped")); - interruptInferior(); - temporarilyStopped = true; - } - - ++currentToken(); if (synchronized) { ++m_pendingRequests; PENDING_DEBUG(" TYPE " << type << " INCREMENTS PENDING TO: " @@ -717,26 +718,30 @@ void GdbEngine::sendCommand(const QString &command, int type, GdbCookie cmd; cmd.synchronized = synchronized; cmd.command = command; - cmd.command = QString::number(currentToken()) + cmd.command; - if (cmd.command.contains("%1")) - cmd.command = cmd.command.arg(currentToken()); cmd.type = type; cmd.cookie = cookie; - m_cookieForToken[currentToken()] = cmd; + if (needStop && q->status() != DebuggerInferiorStopped + && q->status() != DebuggerProcessStartingUp) { + // queue the commands that we cannot send at once + QTC_ASSERT(q->status() == DebuggerInferiorRunning, + qDebug() << "STATUS: " << q->status()); + q->showStatusMessage(tr("Stopping temporarily.")); + debugMessage("QUEUING COMMAND " + cmd.command); + m_commandsToRunOnTemporaryBreak.append(cmd); + interruptInferior(); + } else if (!command.isEmpty()) { + ++currentToken(); + m_cookieForToken[currentToken()] = cmd; + cmd.command = QString::number(currentToken()) + cmd.command; + if (cmd.command.contains("%1")) + cmd.command = cmd.command.arg(currentToken()); - if (!command.isEmpty()) { m_gdbProc.write(cmd.command.toLatin1() + "\r\n"); //emit gdbInputAvailable(QString(), " " + currentTime()); //emit gdbInputAvailable(QString(), "[" + currentTime() + "] " + cmd.command); emit gdbInputAvailable(QString(), cmd.command); } - - if (temporarilyStopped) - sendCommand("-exec-continue"); - - // slows down - //qApp->processEvents(); } void GdbEngine::handleResultRecord(const GdbResultRecord &record) @@ -822,6 +827,7 @@ void GdbEngine::handleResult(const GdbResultRecord & record, int type, //handleExecRunToFunction(record); break; case GdbExecInterrupt: + qq->notifyInferiorStopped(); break; case GdbExecJumpToLine: handleExecJumpToLine(record); @@ -844,6 +850,10 @@ void GdbEngine::handleResult(const GdbResultRecord & record, int type, case GdbQueryDataDumper2: handleQueryDataDumper2(record); break; + case GdbTemporaryContinue: + continueInferior(); + q->showStatusMessage(tr("Continuing after temporary stop.")); + break; case BreakList: handleBreakList(record); @@ -1104,6 +1114,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) //MAC: bool isFirstStop = data.findChild("bkptno").data() == "1"; //!MAC: startSymbolName == data.findChild("frame").findChild("func") if (m_waitingForFirstBreakpointToBeHit) { + qq->notifyInferiorStopped(); m_waitingForFirstBreakpointToBeHit = false; // // that's the "early stop" @@ -1143,6 +1154,23 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) return; } + if (!m_commandsToRunOnTemporaryBreak.isEmpty()) { + QTC_ASSERT(q->status() == DebuggerInferiorStopRequested, + qDebug() << "STATUS: " << q->status()) + qq->notifyInferiorStopped(); + q->showStatusMessage(tr("Temporarily stopped.")); + // FIXME: racy + foreach (const GdbCookie &cmd, m_commandsToRunOnTemporaryBreak) { + debugMessage(QString("RUNNING QUEUED COMMAND %1 %2") + .arg(cmd.command).arg(cmd.type)); + sendCommand(cmd.command, cmd.type, cmd.cookie); + } + sendCommand("p temporaryStop", GdbTemporaryContinue); + m_commandsToRunOnTemporaryBreak.clear(); + q->showStatusMessage(tr("Handling queued commands.")); + return; + } + QString msg = data.findChild("consolestreamoutput").data(); if (msg.contains("Stopped due to shared library event") || reason.isEmpty()) { if (qq->wantsSelectedPluginBreakpoints()) { @@ -1619,8 +1647,8 @@ void GdbEngine::continueInferior() { q->resetLocation(); setTokenBarrier(); - qq->notifyInferiorRunningRequested(); emit gdbInputAvailable(QString(), QString()); + qq->notifyInferiorRunningRequested(); sendCommand("-exec-continue", GdbExecContinue); } @@ -1636,8 +1664,8 @@ void GdbEngine::handleStart(const GdbResultRecord &response) //debugMessage("STREAM: " + msg + " " + needle.cap(1)); sendCommand("tbreak *0x" + needle.cap(1)); m_waitingForFirstBreakpointToBeHit = true; - sendCommand("-exec-run"); qq->notifyInferiorRunningRequested(); + sendCommand("-exec-run"); } else { debugMessage("PARSING START ADDRESS FAILED: " + msg); } @@ -1649,8 +1677,8 @@ void GdbEngine::handleStart(const GdbResultRecord &response) void GdbEngine::stepExec() { setTokenBarrier(); - qq->notifyInferiorRunningRequested(); emit gdbInputAvailable(QString(), QString()); + qq->notifyInferiorRunningRequested(); sendCommand("-exec-step", GdbExecStep); } @@ -1671,8 +1699,8 @@ void GdbEngine::stepOutExec() void GdbEngine::nextExec() { setTokenBarrier(); - qq->notifyInferiorRunningRequested(); emit gdbInputAvailable(QString(), QString()); + qq->notifyInferiorRunningRequested(); sendCommand("-exec-next", GdbExecNext); } @@ -1865,8 +1893,8 @@ void GdbEngine::sendInsertBreakpoint(int index) // cmd += "-c " + data->condition + " "; cmd += where; #endif - sendCommand(cmd, BreakInsert, index, true); - //processQueueAndContinue(); + debugMessage(QString("Current state: %1").arg(q->status())); + sendCommand(cmd, BreakInsert, index, NeedsStop); } void GdbEngine::handleBreakList(const GdbResultRecord &record) @@ -2103,10 +2131,11 @@ void GdbEngine::attemptBreakpointSynchronization() foreach (BreakpointData *data, handler->takeRemovedBreakpoints()) { QString bpNumber = data->bpNumber; + debugMessage(QString("DELETING BP %1 IN %2").arg(bpNumber) + .arg(data->markerFileName)); if (!bpNumber.trimmed().isEmpty()) - sendCommand("-break-delete " + bpNumber, BreakDelete, 0, true); - //else - // qDebug() << "BP HAS NO NUMBER: " << data->markerFileName; + sendCommand("-break-delete " + bpNumber, BreakDelete, QVariant(), + NeedsStop); delete data; } diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index ee5de645c3d..0b59af8b1c7 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -158,12 +158,15 @@ private: // queue". resultNeeded == true increments m_pendingResults on // send and decrements on receipt, effectively preventing // watch model updates before everything is finished. - void sendCommand(const QString & command, + enum StopNeeded { DoesNotNeedStop, NeedsStop }; + enum Synchronization { NotSynchronized, Synchronized }; + void sendCommand(const QString &command, int type = 0, const QVariant &cookie = QVariant(), - bool needStop = false, bool synchronized = false); + StopNeeded needStop = DoesNotNeedStop, + Synchronization synchronized = NotSynchronized); void sendSynchronizedCommand(const QString & command, int type = 0, const QVariant &cookie = QVariant(), - bool needStop = false); + StopNeeded needStop = DoesNotNeedStop); void setTokenBarrier(); @@ -335,6 +338,8 @@ private: bool m_waitingForFirstBreakpointToBeHit; bool m_modulesListOutdated; + QList m_commandsToRunOnTemporaryBreak; + DebuggerManager *q; IDebuggerManagerAccessForEngines *qq; }; From 7020acb36715a69f790c9ca4efc064a32f0feee1 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 16 Feb 2009 18:38:10 +0100 Subject: [PATCH 42/62] Fixes: debugger: set width and height of "terminal" to 0 to avoid extra prompting --- src/plugins/debugger/gdbengine.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 6f41c83379d..6b472e25577 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -1588,6 +1588,8 @@ bool GdbEngine::startDebugger() sendCommand("set unwindonsignal on"); sendCommand("pwd", GdbQueryPwd); + sendCommand("set width 0"); + sendCommand("set height 0"); #ifdef Q_OS_MAC sendCommand("-gdb-set inferior-auto-start-cfm off"); From 97d77408a05d9394bb43245bdd7c9f0b89e1afa7 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Feb 2009 17:43:49 +0100 Subject: [PATCH 43/62] Fixes: debugger: fix assert includes Conflicts: src/plugins/debugger/cdbdebugengine.cpp --- src/plugins/debugger/disassemblerhandler.cpp | 2 +- src/plugins/debugger/moduleshandler.cpp | 2 +- src/plugins/debugger/registerhandler.cpp | 3 ++- src/plugins/debugger/stackwindow.cpp | 3 ++- src/plugins/debugger/threadswindow.cpp | 3 ++- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/plugins/debugger/disassemblerhandler.cpp b/src/plugins/debugger/disassemblerhandler.cpp index ff935dabfdf..59ca259e80e 100644 --- a/src/plugins/debugger/disassemblerhandler.cpp +++ b/src/plugins/debugger/disassemblerhandler.cpp @@ -33,7 +33,7 @@ #include "disassemblerhandler.h" -#include "assert.h" +#include #include #include diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp index e87c92a73d2..a49e87495ec 100644 --- a/src/plugins/debugger/moduleshandler.cpp +++ b/src/plugins/debugger/moduleshandler.cpp @@ -33,7 +33,7 @@ #include "moduleshandler.h" -#include "assert.h" +#include #include #include diff --git a/src/plugins/debugger/registerhandler.cpp b/src/plugins/debugger/registerhandler.cpp index e594326009a..9300e5a4df7 100644 --- a/src/plugins/debugger/registerhandler.cpp +++ b/src/plugins/debugger/registerhandler.cpp @@ -33,9 +33,10 @@ #include "registerhandler.h" -#include "assert.h" #include "debuggerconstants.h" +#include + #include #include diff --git a/src/plugins/debugger/stackwindow.cpp b/src/plugins/debugger/stackwindow.cpp index d40f8a3c5ff..8b33b08ae7c 100644 --- a/src/plugins/debugger/stackwindow.cpp +++ b/src/plugins/debugger/stackwindow.cpp @@ -33,9 +33,10 @@ #include "stackwindow.h" -#include "assert.h" #include "stackhandler.h" +#include + #include #include #include diff --git a/src/plugins/debugger/threadswindow.cpp b/src/plugins/debugger/threadswindow.cpp index bf418cd0fc5..5d49e5dc798 100644 --- a/src/plugins/debugger/threadswindow.cpp +++ b/src/plugins/debugger/threadswindow.cpp @@ -33,9 +33,10 @@ #include "threadswindow.h" -#include "assert.h" #include "stackhandler.h" +#include + #include #include #include From 84e5a57bab506511753db63152c9b220364562fd Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Feb 2009 14:08:49 +0100 Subject: [PATCH 44/62] Fixes: add a view to see current source file mapping --- src/plugins/debugger/debugger.pro | 2 + src/plugins/debugger/debuggermanager.cpp | 33 ++++ src/plugins/debugger/debuggermanager.h | 9 + src/plugins/debugger/gdbengine.cpp | 24 ++- src/plugins/debugger/gdbengine.h | 8 +- src/plugins/debugger/idebuggerengine.h | 2 + src/plugins/debugger/scriptengine.h | 1 + src/plugins/debugger/sourcefileswindow.cpp | 213 +++++++++++++++++++++ src/plugins/debugger/sourcefileswindow.h | 76 ++++++++ src/plugins/debugger/statuswindow.cpp | 213 +++++++++++++++++++++ 10 files changed, 575 insertions(+), 6 deletions(-) create mode 100644 src/plugins/debugger/sourcefileswindow.cpp create mode 100644 src/plugins/debugger/sourcefileswindow.h create mode 100644 src/plugins/debugger/statuswindow.cpp diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro index 469ea346011..0578a52720b 100644 --- a/src/plugins/debugger/debugger.pro +++ b/src/plugins/debugger/debugger.pro @@ -37,6 +37,7 @@ HEADERS += attachexternaldialog.h \ scriptengine.h \ stackhandler.h \ stackwindow.h \ + sourcefileswindow.h \ startexternaldialog.h \ threadswindow.h \ watchhandler.h \ @@ -64,6 +65,7 @@ SOURCES += attachexternaldialog.cpp \ scriptengine.cpp \ stackhandler.cpp \ stackwindow.cpp \ + sourcefileswindow.cpp \ startexternaldialog.cpp \ threadswindow.cpp \ watchhandler.cpp \ diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 9130d57c54b..769d63c7228 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -42,6 +42,7 @@ #include "moduleswindow.h" #include "registerwindow.h" #include "stackwindow.h" +#include "sourcefileswindow.h" #include "threadswindow.h" #include "watchwindow.h" @@ -165,6 +166,7 @@ void DebuggerManager::init() m_outputWindow = new DebuggerOutputWindow; m_registerWindow = new RegisterWindow; m_stackWindow = new StackWindow; + m_sourceFilesWindow = new SourceFilesWindow; m_threadsWindow = new ThreadsWindow; m_localsWindow = new WatchWindow(WatchWindow::LocalsType); m_watchersWindow = new WatchWindow(WatchWindow::WatchersType); @@ -227,6 +229,13 @@ void DebuggerManager::init() connect(modulesView, SIGNAL(loadAllSymbolsRequested()), this, SLOT(loadAllSymbols())); + // Source Files + //m_sourceFilesHandler = new SourceFilesHandler; + QAbstractItemView *sourceFilesView = + qobject_cast(m_sourceFilesWindow); + //sourceFileView->setModel(m_stackHandler->stackModel()); + connect(sourceFilesView, SIGNAL(reloadSourceFilesRequested()), + this, SLOT(reloadSourceFiles())); // Registers QAbstractItemView *registerView = @@ -403,6 +412,10 @@ void DebuggerManager::init() m_stackDock = createDockForWidget(m_stackWindow); + m_sourceFilesDock = createDockForWidget(m_sourceFilesWindow); + connect(m_sourceFilesDock->toggleViewAction(), SIGNAL(toggled(bool)), + this, SLOT(reloadSourceFiles()), Qt::QueuedConnection); + m_threadsDock = createDockForWidget(m_threadsWindow); setStatus(DebuggerProcessNotReady); @@ -1240,6 +1253,26 @@ void DebuggerManager::disassemblerDockToggled(bool on) } +////////////////////////////////////////////////////////////////////// +// +// Sourec files specific stuff +// +////////////////////////////////////////////////////////////////////// + +void DebuggerManager::reloadSourceFiles() +{ + if (!m_sourceFilesDock || !m_sourceFilesDock->isVisible()) + return; + m_engine->reloadSourceFiles(); +} + +void DebuggerManager::sourceFilesDockToggled(bool on) +{ + if (on) + reloadSourceFiles(); +} + + ////////////////////////////////////////////////////////////////////// // // Modules specific stuff diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index 636187d68cd..fd5c06e4c6e 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -66,6 +66,7 @@ class RegisterHandler; class StackHandler; class ThreadsHandler; class WatchHandler; +class SourceFilesWindow; class WatchData; class BreakpointData; @@ -166,6 +167,7 @@ private: virtual StackHandler *stackHandler() = 0; virtual ThreadsHandler *threadsHandler() = 0; virtual WatchHandler *watchHandler() = 0; + virtual SourceFilesWindow *sourceFileWindow() = 0; virtual void showApplicationOutput(const QString &data) = 0; virtual bool skipKnownFrames() const = 0; @@ -179,6 +181,7 @@ private: virtual void reloadDisassembler() = 0; virtual void reloadModules() = 0; + virtual void reloadSourceFiles() = 0; virtual void reloadRegisters() = 0; }; @@ -302,6 +305,9 @@ private slots: void reloadDisassembler(); void disassemblerDockToggled(bool on); + void reloadSourceFiles(); + void sourceFilesDockToggled(bool on); + void reloadModules(); void modulesDockToggled(bool on); void loadSymbols(const QString &moduleName); @@ -323,6 +329,7 @@ private: StackHandler *stackHandler() { return m_stackHandler; } ThreadsHandler *threadsHandler() { return m_threadsHandler; } WatchHandler *watchHandler() { return m_watchHandler; } + SourceFilesWindow *sourceFileWindow() { return m_sourceFilesWindow; } bool skipKnownFrames() const; bool debugDumpers() const; @@ -416,6 +423,7 @@ private: QDockWidget *m_outputDock; QDockWidget *m_registerDock; QDockWidget *m_stackDock; + QDockWidget *m_sourceFilesDock; QDockWidget *m_threadsDock; QDockWidget *m_watchDock; QList m_dockWidgets; @@ -427,6 +435,7 @@ private: StackHandler *m_stackHandler; ThreadsHandler *m_threadsHandler; WatchHandler *m_watchHandler; + SourceFilesWindow *m_sourceFilesWindow; /// Actions friend class DebuggerPlugin; diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 6b472e25577..33c930fbe30 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -44,6 +44,7 @@ #include "registerhandler.h" #include "stackhandler.h" #include "watchhandler.h" +#include "sourcefileswindow.h" #include "startexternaldialog.h" #include "attachexternaldialog.h" @@ -986,6 +987,7 @@ void GdbEngine::handleQueryPwd(const GdbResultRecord &record) void GdbEngine::handleQuerySources(const GdbResultRecord &record) { if (record.resultClass == GdbResultDone) { + QMap oldShortToFull = m_shortToFullName; m_shortToFullName.clear(); m_fullToShortName.clear(); // "^done,files=[{file="../../../../bin/gdbmacros/gdbmacros.cpp", @@ -1004,6 +1006,8 @@ void GdbEngine::handleQuerySources(const GdbResultRecord &record) m_fullToShortName[full] = fileName; } } + if (m_shortToFullName != oldShortToFull) + qq->sourceFileWindow()->setSourceFiles(m_shortToFullName); } } @@ -1128,7 +1132,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) #if defined(Q_OS_MAC) sendCommand("info pid", GdbInfoProc, QVariant(), true); #endif - sendCommand("-file-list-exec-source-files", GdbQuerySources); + reloadSourceFiles(); tryLoadCustomDumpers(); // intentionally after tryLoadCustomDumpers(), @@ -1262,7 +1266,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) frame.findChild("func").data() + '%'; QApplication::alert(q->mainWindow(), 3000); - sendCommand("-file-list-exec-source-files", GdbQuerySources); + reloadSourceFiles(); sendCommand("-break-list", BreakList); QVariant var = QVariant::fromValue(data); sendCommand("p 0", GdbAsyncOutput2, var); // dummy @@ -2317,6 +2321,18 @@ void GdbEngine::handleModulesList(const GdbResultRecord &record) } +////////////////////////////////////////////////////////////////////// +// +// Source files specific stuff +// +////////////////////////////////////////////////////////////////////// + +void GdbEngine::reloadSourceFiles() +{ + sendCommand("-file-list-exec-source-files", GdbQuerySources); +} + + ////////////////////////////////////////////////////////////////////// // // Stack specific stuff @@ -2546,7 +2562,7 @@ bool GdbEngine::supportsThreads() const static WatchData m_toolTip; static QString m_toolTipExpression; static QPoint m_toolTipPos; -static QHash m_toolTipCache; +static QMap m_toolTipCache; static bool hasLetterOrNumber(const QString &exp) { @@ -3672,7 +3688,7 @@ void GdbEngine::handleStackListLocals(const GdbResultRecord &record) void GdbEngine::setLocals(const QList &locals) { //qDebug() << m_varToType; - QHash seen; + QMap seen; foreach (const GdbMi &item, locals) { // Local variables of inlined code are reported as diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index 0b59af8b1c7..43b87b873c8 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -222,8 +222,8 @@ private: int m_gdbVersion; // 6.8.0 is 680 // awful hack to keep track of used files - QHash m_shortToFullName; - QHash m_fullToShortName; + QMap m_shortToFullName; + QMap m_fullToShortName; // // Breakpoint specific stuff @@ -263,6 +263,10 @@ private: void handleRegisterListNames(const GdbResultRecord &record); void handleRegisterListValues(const GdbResultRecord &record); + // + // Source file specific stuff + // + void reloadSourceFiles(); // // Stack specific stuff diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index ee1e15793f3..6da7ecb15ed 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -87,6 +87,8 @@ public: virtual void reloadRegisters() = 0; virtual void setDebugDumpers(bool on) = 0; virtual void setUseCustomDumpers(bool on) = 0; + + virtual void reloadSourceFiles() = 0; }; } // namespace Internal diff --git a/src/plugins/debugger/scriptengine.h b/src/plugins/debugger/scriptengine.h index b7f37f2cc67..8368d367e82 100644 --- a/src/plugins/debugger/scriptengine.h +++ b/src/plugins/debugger/scriptengine.h @@ -112,6 +112,7 @@ private: void reloadDisassembler(); void reloadModules(); void reloadRegisters() {} + void reloadSourceFiles() {} bool supportsThreads() const { return true; } void maybeBreakNow(bool byFunction); diff --git a/src/plugins/debugger/sourcefileswindow.cpp b/src/plugins/debugger/sourcefileswindow.cpp new file mode 100644 index 00000000000..17b68a1c775 --- /dev/null +++ b/src/plugins/debugger/sourcefileswindow.cpp @@ -0,0 +1,213 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception +** version 1.3, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + +#include "sourcefileswindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using Debugger::Internal::SourceFilesWindow; +using Debugger::Internal::SourceFilesModel; + +////////////////////////////////////////////////////////////////// +// +// SourceFilesModel +// +////////////////////////////////////////////////////////////////// + +class Debugger::Internal::SourceFilesModel : public QAbstractItemModel +{ +public: + SourceFilesModel(QObject *parent = 0) : QAbstractItemModel(parent) {} + + // QAbstractItemModel + int columnCount(const QModelIndex &parent) const + { return parent.isValid() ? 0 : 2; } + int rowCount(const QModelIndex &parent) const + { return parent.isValid() ? 0 : m_shortNames.size(); } + QModelIndex parent(const QModelIndex &) const { return QModelIndex(); } + QModelIndex index(int row, int column, const QModelIndex &) const + { return createIndex(row, column); } + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role); + Qt::ItemFlags flags(const QModelIndex &index) const; + + void clearModel(); + void update() { reset(); } + void setSourceFiles(const QMap &sourceFiles); + +public: + QStringList m_shortNames; + QStringList m_fullNames; +}; + +void SourceFilesModel::clearModel() +{ + if (m_shortNames.isEmpty()) + return; + m_shortNames.clear(); + m_fullNames.clear(); + reset(); +} + +QVariant SourceFilesModel::headerData(int section, + Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + static QString headers[] = { + tr("Internal name") + " ", + tr("Full name") + " ", + }; + return headers[section]; + } + return QVariant(); +} + +Qt::ItemFlags SourceFilesModel::flags(const QModelIndex &index) const +{ + if (index.row() >= m_fullNames.size()) + return 0; + QFileInfo fi(m_fullNames.at(index.row())); + return fi.isReadable() ? QAbstractItemModel::flags(index) : Qt::ItemFlags(0); +} + +QVariant SourceFilesModel::data(const QModelIndex &index, int role) const +{ + //static const QIcon icon(":/gdbdebugger/images/breakpoint.svg"); + //static const QIcon icon2(":/gdbdebugger/images/breakpoint_pending.svg"); + + int row = index.row(); + if (row < 0 || row >= m_shortNames.size()) + return QVariant(); + + switch (index.column()) { + case 0: + if (role == Qt::DisplayRole) + return m_shortNames.at(row); + // FIXME: add icons + //if (role == Qt::DecorationRole) + // return module.symbolsRead ? icon2 : icon; + break; + case 1: + if (role == Qt::DisplayRole) + return m_fullNames.at(row); + //if (role == Qt::DecorationRole) + // return module.symbolsRead ? icon2 : icon; + break; + } + return QVariant(); +} + +bool SourceFilesModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + return QAbstractItemModel::setData(index, value, role); +} + +void SourceFilesModel::setSourceFiles(const QMap &sourceFiles) +{ + m_shortNames.clear(); + m_fullNames.clear(); + QMap::ConstIterator it = sourceFiles.begin(); + QMap::ConstIterator et = sourceFiles.end(); + for (; it != et; ++it) { + m_shortNames.append(it.key()); + m_fullNames.append(it.value()); + } + reset(); +} + +////////////////////////////////////////////////////////////////// +// +// SourceFilesWindow +// +////////////////////////////////////////////////////////////////// + +SourceFilesWindow::SourceFilesWindow(QWidget *parent) + : QTreeView(parent) +{ + m_model = new SourceFilesModel(this); + + QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this); + proxyModel->setSourceModel(m_model); + setModel(proxyModel); + + setWindowTitle(tr("Source Files")); + setSortingEnabled(true); + setAlternatingRowColors(true); + setRootIsDecorated(false); + setIconSize(QSize(10, 10)); + //header()->setDefaultAlignment(Qt::AlignLeft); + + connect(this, SIGNAL(activated(QModelIndex)), + this, SLOT(sourceFileActivated(QModelIndex))); +} + +SourceFilesWindow::~SourceFilesWindow() +{ +} + +void SourceFilesWindow::sourceFileActivated(const QModelIndex &index) +{ + qDebug() << "ACTIVATED: " << index.row() << index.column(); +} + +void SourceFilesWindow::contextMenuEvent(QContextMenuEvent *ev) +{ + QMenu menu; + QAction *act1 = new QAction(tr("Reload data"), &menu); + //act1->setCheckable(true); + + menu.addAction(act1); + + QAction *act = menu.exec(ev->globalPos()); + + if (act == act1) { + emit reloadSourceFilesRequested(); + } +} + +void SourceFilesWindow::setSourceFiles(const QMap &sourceFiles) +{ + m_model->setSourceFiles(sourceFiles); + header()->setResizeMode(0, QHeaderView::ResizeToContents); +} diff --git a/src/plugins/debugger/sourcefileswindow.h b/src/plugins/debugger/sourcefileswindow.h new file mode 100644 index 00000000000..4d17d0cb1e9 --- /dev/null +++ b/src/plugins/debugger/sourcefileswindow.h @@ -0,0 +1,76 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception +** version 1.3, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + +#ifndef DEBUGGER_SOURCEFILEWINDOW_H +#define DEBUGGER_SOURCEFILEWINDOW_H + +#include +#include + +QT_BEGIN_NAMESPACE +class QComboBox; +class QModelIndex; +class QStandardItemModel; +QT_END_NAMESPACE + +namespace Debugger { +namespace Internal { + +class SourceFilesModel; + +class SourceFilesWindow : public QTreeView +{ + Q_OBJECT + +public: + SourceFilesWindow(QWidget *parent = 0); + ~SourceFilesWindow(); + + void setSourceFiles(const QMap &sourceFiles); + +signals: + void reloadSourceFilesRequested(); + +private slots: + void sourceFileActivated(const QModelIndex &index); + +private: + void contextMenuEvent(QContextMenuEvent *ev); + SourceFilesModel *m_model; +}; + +} // namespace Internal +} // namespace Debugger + +#endif // DEBUGGER_SOURCEFILEWINDOW_H + diff --git a/src/plugins/debugger/statuswindow.cpp b/src/plugins/debugger/statuswindow.cpp new file mode 100644 index 00000000000..17b68a1c775 --- /dev/null +++ b/src/plugins/debugger/statuswindow.cpp @@ -0,0 +1,213 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception +** version 1.3, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + +#include "sourcefileswindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using Debugger::Internal::SourceFilesWindow; +using Debugger::Internal::SourceFilesModel; + +////////////////////////////////////////////////////////////////// +// +// SourceFilesModel +// +////////////////////////////////////////////////////////////////// + +class Debugger::Internal::SourceFilesModel : public QAbstractItemModel +{ +public: + SourceFilesModel(QObject *parent = 0) : QAbstractItemModel(parent) {} + + // QAbstractItemModel + int columnCount(const QModelIndex &parent) const + { return parent.isValid() ? 0 : 2; } + int rowCount(const QModelIndex &parent) const + { return parent.isValid() ? 0 : m_shortNames.size(); } + QModelIndex parent(const QModelIndex &) const { return QModelIndex(); } + QModelIndex index(int row, int column, const QModelIndex &) const + { return createIndex(row, column); } + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role); + Qt::ItemFlags flags(const QModelIndex &index) const; + + void clearModel(); + void update() { reset(); } + void setSourceFiles(const QMap &sourceFiles); + +public: + QStringList m_shortNames; + QStringList m_fullNames; +}; + +void SourceFilesModel::clearModel() +{ + if (m_shortNames.isEmpty()) + return; + m_shortNames.clear(); + m_fullNames.clear(); + reset(); +} + +QVariant SourceFilesModel::headerData(int section, + Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + static QString headers[] = { + tr("Internal name") + " ", + tr("Full name") + " ", + }; + return headers[section]; + } + return QVariant(); +} + +Qt::ItemFlags SourceFilesModel::flags(const QModelIndex &index) const +{ + if (index.row() >= m_fullNames.size()) + return 0; + QFileInfo fi(m_fullNames.at(index.row())); + return fi.isReadable() ? QAbstractItemModel::flags(index) : Qt::ItemFlags(0); +} + +QVariant SourceFilesModel::data(const QModelIndex &index, int role) const +{ + //static const QIcon icon(":/gdbdebugger/images/breakpoint.svg"); + //static const QIcon icon2(":/gdbdebugger/images/breakpoint_pending.svg"); + + int row = index.row(); + if (row < 0 || row >= m_shortNames.size()) + return QVariant(); + + switch (index.column()) { + case 0: + if (role == Qt::DisplayRole) + return m_shortNames.at(row); + // FIXME: add icons + //if (role == Qt::DecorationRole) + // return module.symbolsRead ? icon2 : icon; + break; + case 1: + if (role == Qt::DisplayRole) + return m_fullNames.at(row); + //if (role == Qt::DecorationRole) + // return module.symbolsRead ? icon2 : icon; + break; + } + return QVariant(); +} + +bool SourceFilesModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + return QAbstractItemModel::setData(index, value, role); +} + +void SourceFilesModel::setSourceFiles(const QMap &sourceFiles) +{ + m_shortNames.clear(); + m_fullNames.clear(); + QMap::ConstIterator it = sourceFiles.begin(); + QMap::ConstIterator et = sourceFiles.end(); + for (; it != et; ++it) { + m_shortNames.append(it.key()); + m_fullNames.append(it.value()); + } + reset(); +} + +////////////////////////////////////////////////////////////////// +// +// SourceFilesWindow +// +////////////////////////////////////////////////////////////////// + +SourceFilesWindow::SourceFilesWindow(QWidget *parent) + : QTreeView(parent) +{ + m_model = new SourceFilesModel(this); + + QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this); + proxyModel->setSourceModel(m_model); + setModel(proxyModel); + + setWindowTitle(tr("Source Files")); + setSortingEnabled(true); + setAlternatingRowColors(true); + setRootIsDecorated(false); + setIconSize(QSize(10, 10)); + //header()->setDefaultAlignment(Qt::AlignLeft); + + connect(this, SIGNAL(activated(QModelIndex)), + this, SLOT(sourceFileActivated(QModelIndex))); +} + +SourceFilesWindow::~SourceFilesWindow() +{ +} + +void SourceFilesWindow::sourceFileActivated(const QModelIndex &index) +{ + qDebug() << "ACTIVATED: " << index.row() << index.column(); +} + +void SourceFilesWindow::contextMenuEvent(QContextMenuEvent *ev) +{ + QMenu menu; + QAction *act1 = new QAction(tr("Reload data"), &menu); + //act1->setCheckable(true); + + menu.addAction(act1); + + QAction *act = menu.exec(ev->globalPos()); + + if (act == act1) { + emit reloadSourceFilesRequested(); + } +} + +void SourceFilesWindow::setSourceFiles(const QMap &sourceFiles) +{ + m_model->setSourceFiles(sourceFiles); + header()->setResizeMode(0, QHeaderView::ResizeToContents); +} From 72f72d5119d018be3c6b8a60a07c6fce73fd6e4c Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Tue, 17 Feb 2009 11:25:44 +0100 Subject: [PATCH 45/62] Compile. --- src/plugins/debugger/gdbengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 33c930fbe30..01db793c359 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -1130,7 +1130,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) sendCommand("info proc", GdbInfoProc); #endif #if defined(Q_OS_MAC) - sendCommand("info pid", GdbInfoProc, QVariant(), true); + sendCommand("info pid", GdbInfoProc); #endif reloadSourceFiles(); tryLoadCustomDumpers(); From 5ba9809489054eca52f657459ddf9ac4340fc58a Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Feb 2009 14:09:52 +0100 Subject: [PATCH 46/62] Fixes: debugger: remove accidentally commited file --- src/plugins/debugger/statuswindow.cpp | 213 -------------------------- 1 file changed, 213 deletions(-) delete mode 100644 src/plugins/debugger/statuswindow.cpp diff --git a/src/plugins/debugger/statuswindow.cpp b/src/plugins/debugger/statuswindow.cpp deleted file mode 100644 index 17b68a1c775..00000000000 --- a/src/plugins/debugger/statuswindow.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/*************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Qt Software Information (qt-info@nokia.com) -** -** -** Non-Open Source Usage -** -** Licensees may use this file in accordance with the Qt Beta Version -** License Agreement, Agreement version 2.2 provided with the Software or, -** alternatively, in accordance with the terms contained in a written -** agreement between you and Nokia. -** -** GNU General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU General -** Public License versions 2.0 or 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the packaging -** of this file. Please review the following information to ensure GNU -** General Public Licensing requirements will be met: -** -** http://www.fsf.org/licensing/licenses/info/GPLv2.html and -** http://www.gnu.org/copyleft/gpl.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt GPL Exception -** version 1.3, included in the file GPL_EXCEPTION.txt in this package. -** -***************************************************************************/ - -#include "sourcefileswindow.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using Debugger::Internal::SourceFilesWindow; -using Debugger::Internal::SourceFilesModel; - -////////////////////////////////////////////////////////////////// -// -// SourceFilesModel -// -////////////////////////////////////////////////////////////////// - -class Debugger::Internal::SourceFilesModel : public QAbstractItemModel -{ -public: - SourceFilesModel(QObject *parent = 0) : QAbstractItemModel(parent) {} - - // QAbstractItemModel - int columnCount(const QModelIndex &parent) const - { return parent.isValid() ? 0 : 2; } - int rowCount(const QModelIndex &parent) const - { return parent.isValid() ? 0 : m_shortNames.size(); } - QModelIndex parent(const QModelIndex &) const { return QModelIndex(); } - QModelIndex index(int row, int column, const QModelIndex &) const - { return createIndex(row, column); } - QVariant headerData(int section, Qt::Orientation orientation, int role) const; - QVariant data(const QModelIndex &index, int role) const; - bool setData(const QModelIndex &index, const QVariant &value, int role); - Qt::ItemFlags flags(const QModelIndex &index) const; - - void clearModel(); - void update() { reset(); } - void setSourceFiles(const QMap &sourceFiles); - -public: - QStringList m_shortNames; - QStringList m_fullNames; -}; - -void SourceFilesModel::clearModel() -{ - if (m_shortNames.isEmpty()) - return; - m_shortNames.clear(); - m_fullNames.clear(); - reset(); -} - -QVariant SourceFilesModel::headerData(int section, - Qt::Orientation orientation, int role) const -{ - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { - static QString headers[] = { - tr("Internal name") + " ", - tr("Full name") + " ", - }; - return headers[section]; - } - return QVariant(); -} - -Qt::ItemFlags SourceFilesModel::flags(const QModelIndex &index) const -{ - if (index.row() >= m_fullNames.size()) - return 0; - QFileInfo fi(m_fullNames.at(index.row())); - return fi.isReadable() ? QAbstractItemModel::flags(index) : Qt::ItemFlags(0); -} - -QVariant SourceFilesModel::data(const QModelIndex &index, int role) const -{ - //static const QIcon icon(":/gdbdebugger/images/breakpoint.svg"); - //static const QIcon icon2(":/gdbdebugger/images/breakpoint_pending.svg"); - - int row = index.row(); - if (row < 0 || row >= m_shortNames.size()) - return QVariant(); - - switch (index.column()) { - case 0: - if (role == Qt::DisplayRole) - return m_shortNames.at(row); - // FIXME: add icons - //if (role == Qt::DecorationRole) - // return module.symbolsRead ? icon2 : icon; - break; - case 1: - if (role == Qt::DisplayRole) - return m_fullNames.at(row); - //if (role == Qt::DecorationRole) - // return module.symbolsRead ? icon2 : icon; - break; - } - return QVariant(); -} - -bool SourceFilesModel::setData(const QModelIndex &index, const QVariant &value, int role) -{ - return QAbstractItemModel::setData(index, value, role); -} - -void SourceFilesModel::setSourceFiles(const QMap &sourceFiles) -{ - m_shortNames.clear(); - m_fullNames.clear(); - QMap::ConstIterator it = sourceFiles.begin(); - QMap::ConstIterator et = sourceFiles.end(); - for (; it != et; ++it) { - m_shortNames.append(it.key()); - m_fullNames.append(it.value()); - } - reset(); -} - -////////////////////////////////////////////////////////////////// -// -// SourceFilesWindow -// -////////////////////////////////////////////////////////////////// - -SourceFilesWindow::SourceFilesWindow(QWidget *parent) - : QTreeView(parent) -{ - m_model = new SourceFilesModel(this); - - QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this); - proxyModel->setSourceModel(m_model); - setModel(proxyModel); - - setWindowTitle(tr("Source Files")); - setSortingEnabled(true); - setAlternatingRowColors(true); - setRootIsDecorated(false); - setIconSize(QSize(10, 10)); - //header()->setDefaultAlignment(Qt::AlignLeft); - - connect(this, SIGNAL(activated(QModelIndex)), - this, SLOT(sourceFileActivated(QModelIndex))); -} - -SourceFilesWindow::~SourceFilesWindow() -{ -} - -void SourceFilesWindow::sourceFileActivated(const QModelIndex &index) -{ - qDebug() << "ACTIVATED: " << index.row() << index.column(); -} - -void SourceFilesWindow::contextMenuEvent(QContextMenuEvent *ev) -{ - QMenu menu; - QAction *act1 = new QAction(tr("Reload data"), &menu); - //act1->setCheckable(true); - - menu.addAction(act1); - - QAction *act = menu.exec(ev->globalPos()); - - if (act == act1) { - emit reloadSourceFilesRequested(); - } -} - -void SourceFilesWindow::setSourceFiles(const QMap &sourceFiles) -{ - m_model->setSourceFiles(sourceFiles); - header()->setResizeMode(0, QHeaderView::ResizeToContents); -} From f47ef22fabe44f2d950425925f1b41f3360a571d Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Feb 2009 14:35:32 +0100 Subject: [PATCH 47/62] Fixes: debugger: enable debugger view actions even if "locked" --- src/plugins/debugger/debuggermanager.cpp | 3 +++ src/plugins/debugger/debuggerplugin.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 769d63c7228..711a3ae2bc7 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -490,9 +490,11 @@ void DebuggerManager::setSimpleDockWidgetArrangement() m_mainWindow->tabifyDockWidget(m_watchDock, m_outputDock); m_mainWindow->tabifyDockWidget(m_watchDock, m_registerDock); m_mainWindow->tabifyDockWidget(m_watchDock, m_threadsDock); + m_mainWindow->tabifyDockWidget(m_watchDock, m_sourceFilesDock); // They are rarely used even in ordinary debugging. Hiding them also saves // cycles since the corresponding information won't be retrieved. + m_sourceFilesDock->hide(); m_registerDock->hide(); m_disassemblerDock->hide(); m_modulesDock->hide(); @@ -515,6 +517,7 @@ void DebuggerManager::setLocked(bool locked) } dockWidget->setTitleBarWidget(titleBarWidget); dockWidget->setFeatures(features); + dockWidget->toggleViewAction()->setEnabled(true); } } diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index d3e61c79c29..c313b0592e7 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -453,7 +453,7 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *error_mes #endif cmd = am->registerAction(m_manager->m_continueAction, - ProjectExplorer::Constants::DEBUG, QList()<< m_gdbRunningContext); + ProjectExplorer::Constants::DEBUG, QList() << m_gdbRunningContext); cmd = am->registerAction(m_manager->m_stopAction, Constants::INTERRUPT, globalcontext); From fff32b5fd266d9fde7ca762d65019ea897833064 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Feb 2009 17:44:46 +0100 Subject: [PATCH 48/62] Fixes: debugger: simplify state logic Conflicts: src/plugins/debugger/cdbdebugeventcallback.cpp --- src/plugins/debugger/debuggermanager.cpp | 33 +++++++----------------- src/plugins/debugger/debuggermanager.h | 24 +++-------------- src/plugins/debugger/scriptengine.cpp | 1 - 3 files changed, 13 insertions(+), 45 deletions(-) diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 711a3ae2bc7..e92bdfcdec1 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -553,12 +553,6 @@ void DebuggerManager::showStatusMessage(const QString &msg, int timeout) } } -void DebuggerManager::notifyStartupFinished() -{ - setStatus(DebuggerProcessReady); - showStatusMessage(tr("Startup finished. Debugger ready."), -1); -} - void DebuggerManager::notifyInferiorStopRequested() { setStatus(DebuggerInferiorStopRequested); @@ -572,12 +566,6 @@ void DebuggerManager::notifyInferiorStopped() showStatusMessage(tr("Stopped."), 5000); } -void DebuggerManager::notifyInferiorUpdateFinished() -{ - setStatus(DebuggerInferiorReady); - showStatusMessage(tr("Stopped."), 5000); -} - void DebuggerManager::notifyInferiorRunningRequested() { setStatus(DebuggerInferiorRunningRequested); @@ -592,7 +580,7 @@ void DebuggerManager::notifyInferiorRunning() void DebuggerManager::notifyInferiorExited() { - setStatus(DebuggerProcessReady); + setStatus(DebuggerProcessNotReady); showStatusMessage(tr("Stopped."), 5000); } @@ -679,7 +667,9 @@ void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber) { QTC_ASSERT(m_engine, return); QTC_ASSERT(m_breakHandler, return); - if (status() != DebuggerInferiorRunning && status() != DebuggerInferiorStopped) { + if (status() != DebuggerInferiorRunning + && status() != DebuggerInferiorStopped + && status() != DebuggerProcessNotReady) { showStatusMessage(tr("Changing breakpoint state requires either a " "fully running or fully stopped application.")); return; @@ -842,11 +832,13 @@ bool DebuggerManager::startNewDebugger(StartMode mode) else setDebuggerType(GdbDebugger); - if (!m_engine->startDebugger()) + setStatus(DebuggerProcessStartingUp); + if (!m_engine->startDebugger()) { + setStatus(DebuggerProcessNotReady); return false; + } m_busy = false; - setStatus(DebuggerProcessStartingUp); return true; } @@ -1049,16 +1041,11 @@ void DebuggerManager::setStatus(int status) const bool started = status == DebuggerInferiorRunning || status == DebuggerInferiorRunningRequested || status == DebuggerInferiorStopRequested - || status == DebuggerInferiorStopped - || status == DebuggerInferiorUpdating - || status == DebuggerInferiorUpdateFinishing - || status == DebuggerInferiorReady; + || status == DebuggerInferiorStopped; const bool starting = status == DebuggerProcessStartingUp; const bool running = status == DebuggerInferiorRunning; - const bool ready = status == DebuggerInferiorStopped - || status == DebuggerInferiorReady - || status == DebuggerProcessReady; + const bool ready = status == DebuggerInferiorStopped; m_startExternalAction->setEnabled(!started && !starting); m_attachExternalAction->setEnabled(!started && !starting); diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index fd5c06e4c6e..18d5475e728 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -77,23 +77,15 @@ class BreakpointData; // DebuggerProcessNotReady // | // DebuggerProcessStartingUp -// | -// DebuggerReady [R] [N] // | <-------------------------------------. // DebuggerInferiorRunningRequested | -// | | -// DebuggerInferiorRunning | -// | | +// | | +// DebuggerInferiorRunning | +// | | // DebuggerInferiorStopRequested | // | | // DebuggerInferiorStopped | // | | -// DebuggerInferiorUpdating | -// | | -// DebuggerInferiorUpdateFinishing | -// | | -// DebuggerInferiorReady [C] [N] | -// | | // `---------------------------------------' // // Allowed actions: @@ -107,17 +99,11 @@ enum DebuggerStatus { DebuggerProcessNotReady, // Debugger not started DebuggerProcessStartingUp, // Debugger starting up - DebuggerProcessReady, // Debugger started, Inferior not yet - // running or already finished DebuggerInferiorRunningRequested, // Debuggee requested to run DebuggerInferiorRunning, // Debuggee running DebuggerInferiorStopRequested, // Debuggee running, stop requested DebuggerInferiorStopped, // Debuggee stopped - - DebuggerInferiorUpdating, // Debuggee updating data views - DebuggerInferiorUpdateFinishing, // Debuggee updating data views aborting - DebuggerInferiorReady, }; @@ -151,10 +137,8 @@ private: friend class WinEngine; // called from the engines after successful startup - virtual void notifyStartupFinished() = 0; virtual void notifyInferiorStopRequested() = 0; virtual void notifyInferiorStopped() = 0; - virtual void notifyInferiorUpdateFinished() = 0; virtual void notifyInferiorRunningRequested() = 0; virtual void notifyInferiorRunning() = 0; virtual void notifyInferiorExited() = 0; @@ -343,9 +327,7 @@ private: QString selectedPluginBreakpointsPattern() const { return m_settings.m_pluginSelectedBreakpointsPattern; } - void notifyStartupFinished(); void notifyInferiorStopped(); - void notifyInferiorUpdateFinished(); void notifyInferiorRunningRequested(); void notifyInferiorStopRequested(); void notifyInferiorRunning(); diff --git a/src/plugins/debugger/scriptengine.cpp b/src/plugins/debugger/scriptengine.cpp index b868dcd99ad..0af40332273 100644 --- a/src/plugins/debugger/scriptengine.cpp +++ b/src/plugins/debugger/scriptengine.cpp @@ -216,7 +216,6 @@ bool ScriptEngine::startDebugger() m_scriptContents = stream.readAll(); scriptFile.close(); attemptBreakpointSynchronization(); - QTimer::singleShot(0, q, SLOT(notifyStartupFinished())); return true; } From 5a07f48691068aa2aaecce78ab042b8af586c642 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Feb 2009 16:25:48 +0100 Subject: [PATCH 49/62] Fixes: debugger: on async output, first handle all cases where the inferior exited. Details: that catches early exits due to startup problems as well --- src/plugins/debugger/gdbengine.cpp | 45 +++++++++++++++++------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 01db793c359..37f35929edc 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -1115,9 +1115,34 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) { const QString reason = data.findChild("reason").data(); + if (isExitedReason(reason)) { + qq->notifyInferiorExited(); + QString msg = "Program exited normally"; + if (reason == "exited") { + msg = "Program exited with exit code " + + data.findChild("exit-code").toString(); + } else if (reason == "exited-signalled") { + msg = "Program exited after receiving signal " + + data.findChild("signal-name").toString(); + } else if (reason == "signal-received") { + msg = "Program exited after receiving signal " + + data.findChild("signal-name").toString(); + } + q->showStatusMessage(msg); + // FIXME: shouldn't this use a statis change? + debugMessage("CALLING PARENT EXITDEBUGGER"); + q->exitDebugger(); + return; + } + + //MAC: bool isFirstStop = data.findChild("bkptno").data() == "1"; //!MAC: startSymbolName == data.findChild("frame").findChild("func") if (m_waitingForFirstBreakpointToBeHit) { + // If the executable dies already that early we might get something + // like stdout:49*stopped,reason="exited",exit-code="0177" + // This is handled now above. + qq->notifyInferiorStopped(); m_waitingForFirstBreakpointToBeHit = false; // @@ -1200,26 +1225,6 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) return; } - if (isExitedReason(reason)) { - qq->notifyInferiorExited(); - QString msg = "Program exited normally"; - if (reason == "exited") { - msg = "Program exited with exit code " - + data.findChild("exit-code").toString(); - } else if (reason == "exited-signalled") { - msg = "Program exited after receiving signal " - + data.findChild("signal-name").toString(); - } else if (reason == "signal-received") { - msg = "Program exited after receiving signal " - + data.findChild("signal-name").toString(); - } - q->showStatusMessage(msg); - // FIXME: shouldn't this use a statis change? - debugMessage("CALLING PARENT EXITDEBUGGER"); - q->exitDebugger(); - return; - } - //tryLoadCustomDumpers(); // jump over well-known frames From 7587f6e39f084c4fa88d4348d54486ae20a1b793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Tue, 17 Feb 2009 15:27:44 +0100 Subject: [PATCH 50/62] This line shouldn't be necessary Enabled state of the action is managed by QDockWidget. --- src/plugins/debugger/debuggermanager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index e92bdfcdec1..0bc4b47c5c3 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -517,7 +517,6 @@ void DebuggerManager::setLocked(bool locked) } dockWidget->setTitleBarWidget(titleBarWidget); dockWidget->setFeatures(features); - dockWidget->toggleViewAction()->setEnabled(true); } } From 8c14daf980d15bd5614e38fe79e0a04404c2f536 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 18 Feb 2009 10:32:02 +0100 Subject: [PATCH 51/62] do not create bizarre or even invalid fifo names under windows --- src/plugins/debugger/outputcollector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/outputcollector.cpp b/src/plugins/debugger/outputcollector.cpp index f091ca92084..205ee91581b 100644 --- a/src/plugins/debugger/outputcollector.cpp +++ b/src/plugins/debugger/outputcollector.cpp @@ -80,7 +80,7 @@ bool OutputCollector::listen() return m_server->isListening(); m_server = new QLocalServer(this); connect(m_server, SIGNAL(newConnection()), SLOT(newConnectionAvailable())); - return m_server->listen(QLatin1String("creator-") + QCoreApplication::applicationPid()); // XXX how to make that secure? + return m_server->listen(QLatin1String("creator-%1").arg(QCoreApplication::applicationPid())); // XXX how to make that secure? #else if (!m_serverPath.isEmpty()) return true; From f338c4eed709412eadd9c5f66ed0d928474ecd91 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 18 Feb 2009 12:25:22 +0100 Subject: [PATCH 52/62] Fixes: Fixes: backport debugger: remove unneeded #include that confused --- share/qtcreator/gdbmacros/gdbmacros.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index ae006133509..9784c8f657d 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -70,10 +70,6 @@ int qtGhVersion = QT_VERSION; #include #include -#ifdef Q_OS_WIN -# include -#endif - /*! \class QDumper \brief Helper class for producing "nice" output in Qt Creator's debugger. From d3bc2aabe2862947625a8187e39d86e62ddb8a0c Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 18 Feb 2009 14:36:36 +0100 Subject: [PATCH 53/62] Fixes: debugger: make "always all" the default for loading debug information Details: the user should make a conscious decision to switch it off --- src/plugins/debugger/debuggerplugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index c313b0592e7..89e8e59c69b 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -943,11 +943,11 @@ void DebuggerPlugin::readSettings() m->m_useToolTips = s->value("UseToolTips", false).toBool(); m->m_pluginAllBreakpoints = - s->value("AllPluginBreakpoints", false).toBool(); + s->value("AllPluginBreakpoints", true).toBool(); m->m_pluginSelectedBreakpoints = s->value("SelectedPluginBreakpoints", false).toBool(); m->m_pluginNoBreakpoints = - s->value("NoPluginBreakpoints", true).toBool(); + s->value("NoPluginBreakpoints", false).toBool(); m->m_pluginSelectedBreakpointsPattern = s->value("SelectedPluginBreakpointsPattern").toString(); From 58736bb56a80616b5aebcc77dcb86fa1df02f038 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Wed, 18 Feb 2009 15:55:21 +0100 Subject: [PATCH 54/62] Fixes: Possible crash while resolving qualified name ids. There is no need to "expand" again the scope we get from invoking `resolve'. --- src/libs/cplusplus/LookupContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 01d4e13b4eb..491a9914ab9 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -176,7 +176,7 @@ QList LookupContext::resolve(Name *name, const QList &visible scopes.clear(); foreach (Symbol *candidate, candidates) { if (ScopedSymbol *scoped = candidate->asScopedSymbol()) { - expand(scoped->members(), visibleScopes, &scopes); + scopes.append(scoped->members()); } } } From 819d0886b1951dc89524fee391ac6ddfbbf435e5 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Wed, 18 Feb 2009 15:55:21 +0100 Subject: [PATCH 55/62] Fixes: Possible crash while resolving qualified name ids. There is no need to "expand" again the scope we get from invoking `resolve'. (cherry picked from commit c72c84d8375692b1cf1ad5c9ba3594f3727f9c02) --- src/libs/cplusplus/LookupContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 01d4e13b4eb..491a9914ab9 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -176,7 +176,7 @@ QList LookupContext::resolve(Name *name, const QList &visible scopes.clear(); foreach (Symbol *candidate, candidates) { if (ScopedSymbol *scoped = candidate->asScopedSymbol()) { - expand(scoped->members(), visibleScopes, &scopes); + scopes.append(scoped->members()); } } } From 5cacd137445ba75620e4ca2e7a570ac5ab50d866 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 18 Feb 2009 17:05:52 +0100 Subject: [PATCH 56/62] Compile Windows --- src/plugins/debugger/outputcollector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/outputcollector.cpp b/src/plugins/debugger/outputcollector.cpp index 205ee91581b..d97f28ff0d9 100644 --- a/src/plugins/debugger/outputcollector.cpp +++ b/src/plugins/debugger/outputcollector.cpp @@ -80,7 +80,7 @@ bool OutputCollector::listen() return m_server->isListening(); m_server = new QLocalServer(this); connect(m_server, SIGNAL(newConnection()), SLOT(newConnectionAvailable())); - return m_server->listen(QLatin1String("creator-%1").arg(QCoreApplication::applicationPid())); // XXX how to make that secure? + return m_server->listen(QString::fromLatin1("creator-%1").arg(QCoreApplication::applicationPid())); // XXX how to make that secure? #else if (!m_serverPath.isEmpty()) return true; From e863c9bd9eb8907df71e56cf978fff5b6a4fa049 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 19 Feb 2009 10:29:25 +0100 Subject: [PATCH 57/62] Fixes: debugger: watch view: collapsed items did not stay collapsed --- src/plugins/debugger/watchhandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index a00b7fad7ce..0068d364a86 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -790,9 +790,9 @@ void WatchHandler::collapseChildren(const QModelIndex &idx) return; } QTC_ASSERT(checkIndex(idx.internalId()), return); -#if 0 QString iname0 = m_displaySet.at(idx.internalId()).iname; MODEL_DEBUG("COLLAPSE NODE" << iname0); +#if 0 QString iname1 = iname0 + '.'; for (int i = m_completeSet.size(); --i >= 0; ) { QString iname = m_completeSet.at(i).iname; @@ -803,10 +803,10 @@ void WatchHandler::collapseChildren(const QModelIndex &idx) m_expandedINames.remove(iname); } } +#endif m_expandedINames.remove(iname0); //MODEL_DEBUG(toString()); //rebuildModel(); -#endif } void WatchHandler::expandChildren(const QModelIndex &idx) From d1edc2a2fa9fb3d8d230e25c966869e43e5f217d Mon Sep 17 00:00:00 2001 From: con Date: Thu, 19 Feb 2009 12:42:32 +0100 Subject: [PATCH 58/62] Fixes: - Console application doesn't start on Mac Task: - 244263 RevBy: - dt --- src/shared/proparser/profileevaluator.cpp | 10 +++++++--- src/shared/proparser/proparserutils.h | 6 ++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp index c54b75a1e2d..8795b97d5b7 100644 --- a/src/shared/proparser/profileevaluator.cpp +++ b/src/shared/proparser/profileevaluator.cpp @@ -768,11 +768,15 @@ bool ProFileEvaluator::Private::visitProValue(ProValue *value) case ProVariable::RemoveOperator: // -= if (!m_cumulative) { if (!m_skipLevel) { - removeEach(&m_valuemap, varName, v); - removeEach(&m_filevaluemap[currentProFile()], varName, v); + // the insertUnique is a hack for the moment to fix the + // CONFIG -= app_bundle problem on Mac (add it to a variable -CONFIG as was done before) + if (removeEach(&m_valuemap, varName, v) == 0) + insertUnique(&m_valuemap, QString("-%1").arg(varName), v); + if (removeEach(&m_filevaluemap[currentProFile()], varName, v) == 0) + insertUnique(&m_filevaluemap[currentProFile()], QString("-%1").arg(varName), v); } } else if (!m_skipLevel) { - // this is a hack for the moment to fix the + // the insertUnique is a hack for the moment to fix the // CONFIG -= app_bundle problem on Mac (add it to a variable -CONFIG as was done before) insertUnique(&m_valuemap, QString("-%1").arg(varName), v); insertUnique(&m_filevaluemap[currentProFile()], QString("-%1").arg(varName), v); diff --git a/src/shared/proparser/proparserutils.h b/src/shared/proparser/proparserutils.h index 7c751c9c273..41c62c88191 100644 --- a/src/shared/proparser/proparserutils.h +++ b/src/shared/proparser/proparserutils.h @@ -140,12 +140,14 @@ static void insertUnique(QHash *map, sl.append(str); } -static void removeEach(QHash *map, +static int removeEach(QHash *map, const QString &key, const QStringList &value) { + int count = 0; QStringList &sl = (*map)[key]; foreach (const QString &str, value) - sl.removeAll(str); + count += sl.removeAll(str); + return count; } /* From 26eb511df8121473fdd83ef8ecb3dc87fa6d05a6 Mon Sep 17 00:00:00 2001 From: con Date: Thu, 19 Feb 2009 15:31:16 +0100 Subject: [PATCH 59/62] Fixes: - Unused include --- src/libs/extensionsystem/pluginmanager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index 5a1c8a00e6a..2900f0437d3 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -39,7 +39,6 @@ #include "iplugin.h" #include -#include #include #include #include From 9c3ff6d31c2b906bb910fe71f645d6748315ec2c Mon Sep 17 00:00:00 2001 From: con Date: Thu, 19 Feb 2009 15:31:29 +0100 Subject: [PATCH 60/62] Fixes: - Updated mac application icon --- src/app/qtcreator.icns | Bin 35774 -> 42937 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/app/qtcreator.icns b/src/app/qtcreator.icns index 9d309e683e8749ba72226ac4d588693949afc6bd..25241e2264427912fb3acb09ebe955f5f9c47f6c 100644 GIT binary patch literal 42937 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 literal 35774 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 TN|hyg zP+(~62{NVxRDgn#0i+WErt}HJI9>au~fNKm>*1j@M&nTv;uDYTG6gf$8 zks=vZ9<67ibI03_P7)+e06aLR3P9ben)&2huKDmH4rV}(Z|NsAopkqU@pHf0lJEaQp z|NsBr#lXNIC_t%6Wa+O4oit&u>riGCIl4JFLacwwrfF;}MUDv+>5+pS$ud{N*w~ov zHIF^ySib-N|7RE*8*5VJ6*4quf{rQ#hyM>NV`F3V^K{5CkrXX#kc1Dm|Ddt4u`%o% zAyNz>U#%kIh@=1i+vy(sQJ=vchZ5d&4t}9^P>UhdZ8`_P2hveYAQ!AOHa6BGKPpMo z$&ZxqK(_z?pHI)=k9rQV6hVS>ADvoX>U$CP!dQomjg7TQ3`FvjbGE~a9GK<*|NozC zY;25l3>JAt6QPSa87=7`9TxrW)7$oBvLlZ_$ACz4_;k!lJ0{r~^}A5D!R z$1@UXCh^KF3H$y3|No$-59oABtmgjzaOTXJITaxWSY`1FYT--s@W_WWeQm_F*?=uR5l+FcFDM*!AEL1vP!}w7hWW`dJOL4xN_1heHbv;dW!Zy>1-3{{P>F zy~yB1I@cAaUStVx{4FnJrKs#DHt1dl@#mu|BFF=EJn#fR(lMnNM*YN+40AA45fGS# zukb+}>5J8rKWQKzBV%czOC6Yjp~lAI$R?n(Vd}8c=&6v@(Eoqi*civb$WVu1w-+u7 zKMNVGT#ncxAFhA0G5FwRux_jbTqSnKA3tPWE!Y*|5%o1T7DhG!gN;WoSn3=2vIVHN zn_wXlh%3g%`uImY2^#hg(Q?xws2E*ApRutF)a^JZbRC%dEpVO5n3DKKe%Kou5g7Bq zZva@f6y|{0U@i&7TEY!KB24?K0(HPaA{3)2i6q?ZK~ax`1B-$CIOK5&pEowvCe-W1 zr58oq8xjDYPy`8cDv9WJ5H{ui|NplkEg}+2pQjeaI)uEBul_-DS^_u#kOYWfHW?e^ zKGPm-Ac6V^VaW|}qZGj>hV{slnDJ&}O#1)-Klpfm(!#&e*oYhEOWZV(_8$hB06E#5 zNFC=17JVQiiH!gM|3UqCQd)k$LXCCsm;7MsiMGFvfq~%|kzNNW>oF#7t_h@;7<`+7 zfngOf3L$Ea5H|NA@Ug*Vu?`)R+De61sRTBwsa#f#rSWZ4@G z42VlnkR{;k?cv%aFRy@WCddF?;+Bd>)utd-0piL$MCgOA#KB`EiqvNY1_rUeC_)I% zuTB0k#1=Wo))QU-fv!YhU|=|huoA)gd$?L(kaVwu-GMNLAPc0v6P5=HDtJxCWGOhTUmWD1faU#%;`GfE6nObmwH-ic%^ZYIb$G}#-~l+J2n zpRY!<2ExT+|NsC04}dQJ1WA#HZ$Qi@h6GuFP2HI&kPMlagyC$E4cP4e|NoLDNRBKF zU7d#ATvSnz`KTfY-WIMuv@j?sV=k%CDWPzM={)BgYe+aZHA zAXOw_dpsthNr6m76GGu0BWHOV0VJ38&NqRvrt8F^3H(Nl7OLG1aO)MmH?Rt zW)MM;xYb6Qn4x`A?B5PjOacxk!cQRMh)@PmLh5o$A_^gr>_@&-7Nn67<|jP40Wt#O zIU>kQAl0N`U4lz1K&BC4GgJxky}lrw1hF5Xh5*O}sNqCVMIhxQ;Y|1W9@$ zNI7X3yh{to2s9?hFf<`N+_xl_!64I%@R$d=rWmgRR7sK(00RR9-nJ0Pg{W5G#3u0)B!XIQA7%K+W%{+PL Z%pa1=-~YHPfXw8)Fa`z&9;Xis3;@eJBK80P From 91707ee07599002074fcedb3f75da4b8d0896352 Mon Sep 17 00:00:00 2001 From: dt Date: Mon, 16 Feb 2009 15:23:49 +0100 Subject: [PATCH 61/62] Fixes: Move code from ~OutputWindow to an earlier place. Details: We should stop all running runners, while the plugins are still alive. --- src/plugins/projectexplorer/outputwindow.cpp | 9 ++++++++- src/plugins/projectexplorer/outputwindow.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/outputwindow.cpp b/src/plugins/projectexplorer/outputwindow.cpp index 6dc95b2bf05..5ac6f7e2df2 100644 --- a/src/plugins/projectexplorer/outputwindow.cpp +++ b/src/plugins/projectexplorer/outputwindow.cpp @@ -110,9 +110,12 @@ OutputPane::OutputPane() connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int))); m_mainWidget->setLayout(layout); + + connect(Core::ICore::instance(), SIGNAL(coreAboutToClose()), + this, SLOT(coreAboutToClose())); } -OutputPane::~OutputPane() +void OutputPane::coreAboutToClose() { while (m_tabWidget->count()) { RunControl *rc = runControlForTab(0); @@ -120,6 +123,10 @@ OutputPane::~OutputPane() rc->stop(); closeTab(0); } +} + +OutputPane::~OutputPane() +{ delete m_mainWidget; } diff --git a/src/plugins/projectexplorer/outputwindow.h b/src/plugins/projectexplorer/outputwindow.h index edc39ac2fb2..ceafb0a36a0 100644 --- a/src/plugins/projectexplorer/outputwindow.h +++ b/src/plugins/projectexplorer/outputwindow.h @@ -84,6 +84,7 @@ public: public slots: void projectRemoved(); + void coreAboutToClose(); private slots: void insertLine(); From 469639fb3c532c54ef03852b08f162ffd227c994 Mon Sep 17 00:00:00 2001 From: dt Date: Thu, 19 Feb 2009 16:11:29 +0100 Subject: [PATCH 62/62] Fixes: Make QtCreator fly even in face of perforce misconfiguration. Details: If p4 is in path, but the server isn't configured correctly we were pretty slow, this fixes that by running p4 client -o after the settings have changed, if that doesn't return after 2 seconds, then we cache that as a invalid configuration. --- .../cmakeprojectmanager/cmakeprojectmanager.h | 4 +- src/plugins/perforce/perforceplugin.cpp | 65 ++++----- src/plugins/perforce/perforceplugin.h | 5 +- src/plugins/perforce/perforcesettings.cpp | 131 +++++++++++++++--- src/plugins/perforce/perforcesettings.h | 38 +++-- src/plugins/perforce/settingspage.cpp | 42 ++++-- src/plugins/perforce/settingspage.h | 7 +- 7 files changed, 207 insertions(+), 85 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h index d8a61e6e802..3a8dda54aa7 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h @@ -71,14 +71,14 @@ class CMakeRunner { public: CMakeRunner(); - void run(QFutureInterface &fi); void setExecutable(const QString &executable); QString executable() const; QString version() const; bool supportsQtCreator() const; - void waitForUpToDate() const; private: + void run(QFutureInterface &fi); + void waitForUpToDate() const; QString m_executable; QString m_version; bool m_supportsQtCreator; diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index 7d126c4bb94..b4685419c08 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -221,7 +221,6 @@ bool PerforcePlugin::initialize(const QStringList &arguments, QString *errorMess m_coreListener = new CoreListener(this); addObject(m_coreListener); - //register actions Core::ActionManager *am = Core::ICore::instance()->actionManager(); @@ -682,6 +681,8 @@ void PerforcePlugin::updateActions() bool PerforcePlugin::managesDirectory(const QString &directory) const { + if (!checkP4Command()) + return false; const QString p4Path = directory + QLatin1String("/..."); QStringList args; args << QLatin1String("fstat") << QLatin1String("-m1") << p4Path; @@ -758,7 +759,7 @@ PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args, tempfile.setAutoRemove(true); const QChar newLine = QLatin1Char('\n'); const QChar blank = QLatin1Char(' '); - QStringList actualArgs = basicP4Args(); + QStringList actualArgs = m_settings.basicP4Args(); if (!extraArgs.isEmpty()) { if (tempfile.open()) { QTextStream stream(&tempfile); @@ -773,7 +774,7 @@ PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args, actualArgs << args; if (logFlags & CommandToWindow) { - QString command = m_settings.p4Command; + QString command = m_settings.p4Command(); command += blank; command += actualArgs.join(QString(blank)); const QString timeStamp = QTime::currentTime().toString(QLatin1String("HH:mm")); @@ -799,7 +800,7 @@ PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args, connect(&process, SIGNAL(stdOutBuffered(QString,bool)), m_perforceOutputWindow, SLOT(append(QString,bool))); } - const Core::Utils::SynchronousProcessResponse sp_resp = process.run(m_settings.p4Command, actualArgs); + const Core::Utils::SynchronousProcessResponse sp_resp = process.run(m_settings.p4Command(), actualArgs); if (Perforce::Constants::debug) qDebug() << sp_resp; @@ -817,7 +818,7 @@ PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args, response.message = tr("The process terminated abnormally."); break; case Core::Utils::SynchronousProcessResponse::StartFailed: - response.message = tr("Could not start perforce '%1'. Please check your settings in the preferences.").arg(m_settings.p4Command); + response.message = tr("Could not start perforce '%1'. Please check your settings in the preferences.").arg(m_settings.p4Command()); break; case Core::Utils::SynchronousProcessResponse::Hang: response.message = tr("Perforce did not respond within timeout limit (%1 ms).").arg(p4Timeout ); @@ -969,8 +970,8 @@ bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor) proc.setEnvironment(environment()); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - proc.start(m_settings.p4Command, - basicP4Args() << QLatin1String("submit") << QLatin1String("-i")); + proc.start(m_settings.p4Command(), + m_settings.basicP4Args() << QLatin1String("submit") << QLatin1String("-i")); if (!proc.waitForStarted(p4Timeout)) { showOutput(tr("Cannot execute p4 submit."), true); QApplication::restoreOverrideCursor(); @@ -1018,8 +1019,8 @@ QString PerforcePlugin::clientFilePath(const QString &serverFilePath) QApplication::setOverrideCursor(Qt::WaitCursor); QProcess proc; proc.setEnvironment(environment()); - proc.start(m_settings.p4Command, - basicP4Args() << QLatin1String("fstat") << serverFilePath); + proc.start(m_settings.p4Command(), + m_settings.basicP4Args() << QLatin1String("fstat") << serverFilePath); QString path; if (proc.waitForFinished(3000)) { @@ -1047,22 +1048,9 @@ QString PerforcePlugin::currentFileName() return fileName; } -QStringList PerforcePlugin::basicP4Args() const -{ - QStringList lst; - if (!m_settings.defaultEnv) { - lst << QLatin1String("-c") << m_settings.p4Client; - lst << QLatin1String("-p") << m_settings.p4Port; - lst << QLatin1String("-u") << m_settings.p4User; - } - return lst; -} - bool PerforcePlugin::checkP4Command() const { - if (m_settings.p4Command.isEmpty()) - return false; - return true; + return m_settings.isValid(); } QString PerforcePlugin::pendingChangesData() @@ -1074,8 +1062,8 @@ QString PerforcePlugin::pendingChangesData() QString user; QProcess proc; proc.setEnvironment(environment()); - proc.start(m_settings.p4Command, - basicP4Args() << QLatin1String("info")); + proc.start(m_settings.p4Command(), + m_settings.basicP4Args() << QLatin1String("info")); if (proc.waitForFinished(3000)) { QString output = QString::fromUtf8(proc.readAllStandardOutput()); if (!output.isEmpty()) { @@ -1087,8 +1075,8 @@ QString PerforcePlugin::pendingChangesData() } if (user.isEmpty()) return data; - proc.start(m_settings.p4Command, - basicP4Args() << QLatin1String("changes") << QLatin1String("-s") << QLatin1String("pending") << QLatin1String("-u") << user); + proc.start(m_settings.p4Command(), + m_settings.basicP4Args() << QLatin1String("changes") << QLatin1String("-s") << QLatin1String("pending") << QLatin1String("-u") << user); if (proc.waitForFinished(3000)) data = QString::fromUtf8(proc.readAllStandardOutput()); return data; @@ -1139,17 +1127,24 @@ PerforcePlugin::~PerforcePlugin() } } -PerforceSettings PerforcePlugin::settings() const +const PerforceSettings& PerforcePlugin::settings() const { return m_settings; } -void PerforcePlugin::setSettings(const PerforceSettings &s) +void PerforcePlugin::setSettings(const QString &p4Command, const QString &p4Port, const QString &p4Client, const QString p4User, bool defaultEnv) { - if (s != m_settings) { - m_settings = s; - if (QSettings *settings = Core::ICore::instance()->settings()) - m_settings.toSettings(settings); + + if (m_settings.p4Command() == p4Command + && m_settings.p4Port() == p4Port + && m_settings.p4Client() == p4Client + && m_settings.p4User() == p4User + && m_settings.defaultEnv() == defaultEnv) + { + // Nothing to do + } else { + m_settings.setSettings(p4Command, p4Port, p4Client, p4User, defaultEnv); + m_settings.toSettings(Core::ICore::instance()->settings()); } } @@ -1162,9 +1157,9 @@ QString PerforcePlugin::fileNameFromPerforceName(const QString& perforceName, return perforceName; // "where" remaps the file to client file tree QProcess proc; - QStringList args(basicP4Args()); + QStringList args(m_settings.basicP4Args()); args << QLatin1String("where") << perforceName; - proc.start(m_settings.p4Command, args); + proc.start(m_settings.p4Command(), args); if (!proc.waitForFinished()) { *errorMessage = tr("Timeout waiting for \"where\" (%1).").arg(perforceName); return QString(); diff --git a/src/plugins/perforce/perforceplugin.h b/src/plugins/perforce/perforceplugin.h index e5985a28ab5..d856685bba9 100644 --- a/src/plugins/perforce/perforceplugin.h +++ b/src/plugins/perforce/perforceplugin.h @@ -93,7 +93,6 @@ public: PerforcePlugin(); ~PerforcePlugin(); - QStringList basicP4Args() const; SettingsPage *settingsPage() const { return m_settingsPage; } bool initialize(const QStringList &arguments, QString *error_message); @@ -113,8 +112,8 @@ public: static PerforcePlugin *perforcePluginInstance(); - PerforceSettings settings() const; - void setSettings(const PerforceSettings &s); + const PerforceSettings& settings() const; + void setSettings(const QString &p4Command, const QString &p4Port, const QString &p4Client, const QString p4User, bool defaultEnv); // Map a perforce name "//xx" to its real name in the file system QString fileNameFromPerforceName(const QString& perforceName, QString *errorMessage) const; diff --git a/src/plugins/perforce/perforcesettings.cpp b/src/plugins/perforce/perforcesettings.cpp index 7ba51b78e00..b30d12a4145 100644 --- a/src/plugins/perforce/perforcesettings.cpp +++ b/src/plugins/perforce/perforcesettings.cpp @@ -33,7 +33,11 @@ #include "perforcesettings.h" +#include +#include #include +#include +#include static const char *groupC = "Perforce"; static const char *commandKeyC = "Command"; @@ -55,41 +59,134 @@ static QString defaultCommand() namespace Perforce { namespace Internal { -PerforceSettings::PerforceSettings() : - p4Command(defaultCommand()), - defaultEnv(true) +PerforceSettings::PerforceSettings() + : m_valid(false) { + // We do all the initialization in fromSettings +} + +PerforceSettings::~PerforceSettings() +{ + // ensure that we are not still running + m_future.waitForFinished(); +} + +bool PerforceSettings::isValid() const +{ + m_future.waitForFinished(); + m_mutex.lock(); + bool valid = m_valid; + m_mutex.unlock(); + return valid; +} + +void PerforceSettings::run(QFutureInterface &fi) +{ + m_mutex.lock(); + QString executable = m_p4Command; + QStringList arguments = basicP4Args(); + m_mutex.unlock(); + + // TODO actually check + bool valid = true; + + QProcess p4; + p4.start(m_p4Command, QStringList() << "client"<<"-o"); + p4.waitForFinished(2000); + if (p4.state() != QProcess::NotRunning) { + p4.kill(); + p4.waitForFinished(); + valid = false; + } else { + QString response = p4.readAllStandardOutput(); + if (!response.contains("View:")) + valid = false; + } + + m_mutex.lock(); + if (executable == m_p4Command && arguments == basicP4Args()) // Check that those settings weren't changed in between + m_valid = valid; + m_mutex.unlock(); + fi.reportFinished(); } void PerforceSettings::fromSettings(QSettings *settings) { + m_mutex.lock(); settings->beginGroup(QLatin1String(groupC)); - p4Command = settings->value(QLatin1String(commandKeyC), defaultCommand()).toString(); - defaultEnv = settings->value(QLatin1String(defaultKeyC), true).toBool(); - p4Port = settings->value(QLatin1String(portKeyC), QString()).toString(); - p4Client = settings->value(QLatin1String(clientKeyC), QString()).toString(); - p4User = settings->value(QLatin1String(userKeyC), QString()).toString(); + m_p4Command = settings->value(QLatin1String(commandKeyC), defaultCommand()).toString(); + m_defaultEnv = settings->value(QLatin1String(defaultKeyC), true).toBool(); + m_p4Port = settings->value(QLatin1String(portKeyC), QString()).toString(); + m_p4Client = settings->value(QLatin1String(clientKeyC), QString()).toString(); + m_p4User = settings->value(QLatin1String(userKeyC), QString()).toString(); settings->endGroup(); + m_mutex.unlock(); + m_future = QtConcurrent::run(&PerforceSettings::run, this); } void PerforceSettings::toSettings(QSettings *settings) const { + m_mutex.lock(); settings->beginGroup(QLatin1String(groupC)); - settings->setValue(commandKeyC, p4Command); - settings->setValue(defaultKeyC, defaultEnv); - settings->setValue(portKeyC, p4Port); - settings->setValue(clientKeyC, p4Client); - settings->setValue(userKeyC, p4User); + settings->setValue(commandKeyC, m_p4Command); + settings->setValue(defaultKeyC, m_defaultEnv); + settings->setValue(portKeyC, m_p4Port); + settings->setValue(clientKeyC, m_p4Client); + settings->setValue(userKeyC, m_p4User); settings->endGroup(); + m_mutex.unlock(); } -bool PerforceSettings::equals(const PerforceSettings &s) const +void PerforceSettings::setSettings(const QString &p4Command, const QString &p4Port, const QString &p4Client, const QString p4User, bool defaultEnv) { - return p4Command == s.p4Command && p4Port == s.p4Port - && p4Client == s.p4Client && p4User == s.p4User - && defaultEnv == s.defaultEnv; + m_mutex.lock(); + m_p4Command = p4Command; + m_p4Port = p4Port; + m_p4Client = p4Client; + m_p4User = p4User; + m_defaultEnv = defaultEnv; + m_valid = false; + m_mutex.unlock(); + m_future = QtConcurrent::run(&PerforceSettings::run, this); } +QString PerforceSettings::p4Command() const +{ + return m_p4Command; +} + +QString PerforceSettings::p4Port() const +{ + return m_p4Port; +} + +QString PerforceSettings::p4Client() const +{ + return m_p4Client; +} + +QString PerforceSettings::p4User() const +{ + return m_p4User; +} + +bool PerforceSettings::defaultEnv() const +{ + return m_defaultEnv; +} + +QStringList PerforceSettings::basicP4Args() const +{ + QStringList lst; + if (!m_defaultEnv) { + lst << QLatin1String("-c") << m_p4Client; + lst << QLatin1String("-p") << m_p4Port; + lst << QLatin1String("-u") << m_p4User; + } + return lst; +} + + } // Internal } // Perforce diff --git a/src/plugins/perforce/perforcesettings.h b/src/plugins/perforce/perforcesettings.h index 4451d4ad617..0ca1147f4f3 100644 --- a/src/plugins/perforce/perforcesettings.h +++ b/src/plugins/perforce/perforcesettings.h @@ -35,6 +35,7 @@ #define PERFOCESETTINGS_H #include +#include QT_BEGIN_NAMESPACE class QSettings; @@ -43,24 +44,35 @@ QT_END_NAMESPACE namespace Perforce { namespace Internal { -struct PerforceSettings { +class PerforceSettings { +public: PerforceSettings(); - void fromSettings(QSettings *); + ~PerforceSettings(); + void fromSettings(QSettings *settings); void toSettings(QSettings *) const; - bool equals(const PerforceSettings &s) const; + void setSettings(const QString &p4Command, const QString &p4Port, const QString &p4Client, const QString p4User, bool defaultEnv); + bool isValid() const; - QString p4Command; - QString p4Port; - QString p4Client; - QString p4User; - bool defaultEnv; + QString p4Command() const; + QString p4Port() const; + QString p4Client() const; + QString p4User() const; + bool defaultEnv() const; + QStringList basicP4Args() const; +private: + void run(QFutureInterface &fi); + mutable QFuture m_future; + mutable QMutex m_mutex; + + QString m_p4Command; + QString m_p4Port; + QString m_p4Client; + QString m_p4User; + bool m_defaultEnv; + bool m_valid; + Q_DISABLE_COPY(PerforceSettings); }; -inline bool operator==(const PerforceSettings &p1, const PerforceSettings &p2) - { return p1.equals(p2); } -inline bool operator!=(const PerforceSettings &p1, const PerforceSettings &p2) - { return !p1.equals(p2); } - } // Internal } // Perforce diff --git a/src/plugins/perforce/settingspage.cpp b/src/plugins/perforce/settingspage.cpp index 70ef649b0e6..53d32714ff2 100644 --- a/src/plugins/perforce/settingspage.cpp +++ b/src/plugins/perforce/settingspage.cpp @@ -49,24 +49,38 @@ SettingsPageWidget::SettingsPageWidget(QWidget *parent) : m_ui.pathChooser->setExpectedKind(PathChooser::Command); } -PerforceSettings SettingsPageWidget::settings() const +QString SettingsPageWidget::p4Command() const { - PerforceSettings rc; - rc.p4Command = m_ui.pathChooser->path(); - rc.defaultEnv = m_ui.defaultCheckBox->isChecked(); - rc.p4Port = m_ui.portLineEdit->text(); - rc.p4Client = m_ui.clientLineEdit->text(); - rc.p4User = m_ui.userLineEdit->text(); - return rc; + return m_ui.pathChooser->path(); +} + +bool SettingsPageWidget::defaultEnv() const +{ + return m_ui.defaultCheckBox->isChecked(); +} + +QString SettingsPageWidget::p4Port() const +{ + return m_ui.portLineEdit->text(); +} + +QString SettingsPageWidget::p4User() const +{ + return m_ui.userLineEdit->text(); +} + +QString SettingsPageWidget::p4Client() const +{ + return m_ui.clientLineEdit->text(); } void SettingsPageWidget::setSettings(const PerforceSettings &s) { - m_ui.pathChooser->setPath(s.p4Command); - m_ui.defaultCheckBox->setChecked(s.defaultEnv); - m_ui.portLineEdit->setText(s.p4Port); - m_ui.clientLineEdit->setText(s.p4Client); - m_ui.userLineEdit->setText(s.p4User); + m_ui.pathChooser->setPath(s.p4Command()); + m_ui.defaultCheckBox->setChecked(s.defaultEnv()); + m_ui.portLineEdit->setText(s.p4Port()); + m_ui.clientLineEdit->setText(s.p4Client()); + m_ui.userLineEdit->setText(s.p4User()); } SettingsPage::SettingsPage() @@ -101,5 +115,5 @@ void SettingsPage::apply() if (!m_widget) return; - PerforcePlugin::perforcePluginInstance()->setSettings(m_widget->settings()); + PerforcePlugin::perforcePluginInstance()->setSettings(m_widget->p4Command(), m_widget->p4Port(), m_widget->p4Client(), m_widget->p4User(), m_widget->defaultEnv()); } diff --git a/src/plugins/perforce/settingspage.h b/src/plugins/perforce/settingspage.h index f5c43599fad..10a3a0c93b7 100644 --- a/src/plugins/perforce/settingspage.h +++ b/src/plugins/perforce/settingspage.h @@ -51,7 +51,12 @@ class SettingsPageWidget : public QWidget { public: explicit SettingsPageWidget(QWidget *parent); - PerforceSettings settings() const; + QString p4Command() const; + bool defaultEnv() const; + QString p4Port() const; + QString p4User() const; + QString p4Client() const; + void setSettings(const PerforceSettings &); private: