diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index a88b7e9e4e90d3f48769a3108cf24100d196e604..12de1c163e2d97bbe63791d6a36f0da75f2c8066 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -775,12 +775,59 @@ void CdbEngine::setupInferior() postExtensionCommand("pid", QByteArray(), 0, &CdbEngine::handlePid); } +static QByteArray msvcRunTime(const Abi::OSFlavor flavour) +{ + switch (flavour) { + case Abi::WindowsMsvc2005Flavor: + return "MSVCR80"; + case Abi::WindowsMsvc2008Flavor: + return "MSVCR90"; + case Abi::WindowsMsvc2010Flavor: + return "MSVCR100"; + case Abi::WindowsMsvc2012Flavor: + return "MSVCR110"; // #FIXME: VS2012 beta, will probably be 12 in final? + default: + break; + } + return "MSVCRT"; // MinGW, others. +} + +static QByteArray breakAtFunctionCommand(const QByteArray &function, + const QByteArray &module = QByteArray()) +{ + QByteArray result = "bu "; + if (!module.isEmpty()) { + result += module; + result += '!'; + } + result += function; + return result; +} + void CdbEngine::runEngine() { if (debug) qDebug("runEngine"); foreach (const QString &breakEvent, m_options->breakEvents) postCommand(QByteArray("sxe ") + breakEvent.toAscii(), 0); + // Break functions: each function must be fully qualified, + // else the debugger will slow down considerably. + foreach (const QString &breakFunctionS, m_options->breakFunctions) { + const QByteArray breakFunction = breakFunctionS.toLatin1(); + if (breakFunction == CdbOptions::crtDbgReport) { + // CrtDbgReport(): Add MSVC runtime (debug, release) + // and stop at Wide character version as well + const QByteArray module = msvcRunTime(startParameters().toolChainAbi.osFlavor()); + const QByteArray debugModule = module + 'D'; + const QByteArray wideFunc = breakFunction + 'W'; + postCommand(breakAtFunctionCommand(breakFunction, module), 0); + postCommand(breakAtFunctionCommand(wideFunc, module), 0); + postCommand(breakAtFunctionCommand(breakFunction, debugModule), 0); + postCommand(breakAtFunctionCommand(wideFunc, debugModule), 0); + } else { + postCommand(breakAtFunctionCommand(breakFunction), 0); + } + } if (startParameters().startMode == AttachCore) { QTC_ASSERT(!m_coreStopReason.isNull(), return; ); notifyInferiorUnrunnable(); @@ -2990,6 +3037,8 @@ void CdbEngine::handleBreakPoints(const GdbMi &value) qPrintable(reportedResponse.toString())); if (reportedResponse.id.isValid() && !reportedResponse.pending) { const BreakpointModelId mid = handler->findBreakpointByResponseId(reportedResponse.id); + if (!mid.isValid() && reportedResponse.type == BreakpointByFunction) + continue; // Breakpoints from options, CrtDbgReport() and others. QTC_ASSERT(mid.isValid(), continue); const PendingBreakPointMap::iterator it = m_pendingBreakpointMap.find(mid); if (it != m_pendingBreakpointMap.end()) { diff --git a/src/plugins/debugger/cdb/cdboptions.cpp b/src/plugins/debugger/cdb/cdboptions.cpp index 413b2763c843ebda4187a5b45b5767b04961f1d6..1c629da9411c37322367c3c3b16bb958a49ff3af 100644 --- a/src/plugins/debugger/cdb/cdboptions.cpp +++ b/src/plugins/debugger/cdb/cdboptions.cpp @@ -36,6 +36,7 @@ static const char settingsGroupC[] = "CDB2"; static const char symbolPathsKeyC[] = "SymbolPaths"; static const char sourcePathsKeyC[] = "SourcePaths"; static const char breakEventKeyC[] = "BreakEvent"; +static const char breakFunctionsKeyC[] = "BreakFunctions"; static const char additionalArgumentsKeyC[] = "AdditionalArguments"; static const char cdbConsoleKeyC[] = "CDB_Console"; static const char breakpointCorrectionKeyC[] = "BreakpointCorrection"; @@ -43,6 +44,8 @@ static const char breakpointCorrectionKeyC[] = "BreakpointCorrection"; namespace Debugger { namespace Internal { +const char *CdbOptions::crtDbgReport = "CrtDbgReport"; + CdbOptions::CdbOptions() : cdbConsole(false), breakpointCorrection(true) { } @@ -57,6 +60,8 @@ void CdbOptions::clear() symbolPaths.clear(); sourcePaths.clear(); cdbConsole = false; + breakEvents.clear(); + breakFunctions.clear(); } QStringList CdbOptions::oldEngineSymbolPaths(const QSettings *s) @@ -72,6 +77,7 @@ void CdbOptions::fromSettings(QSettings *s) symbolPaths = s->value(keyRoot + QLatin1String(symbolPathsKeyC), QStringList()).toStringList(); sourcePaths = s->value(keyRoot + QLatin1String(sourcePathsKeyC), QStringList()).toStringList(); breakEvents = s->value(keyRoot + QLatin1String(breakEventKeyC), QStringList()).toStringList(); + breakFunctions = s->value(keyRoot + QLatin1String(breakFunctionsKeyC), QStringList()).toStringList(); cdbConsole = s->value(keyRoot + QLatin1String(cdbConsoleKeyC), QVariant(false)).toBool(); breakpointCorrection = s->value(keyRoot + QLatin1String(breakpointCorrectionKeyC), QVariant(true)).toBool(); } @@ -82,6 +88,7 @@ void CdbOptions::toSettings(QSettings *s) const s->setValue(QLatin1String(symbolPathsKeyC), symbolPaths); s->setValue(QLatin1String(sourcePathsKeyC), sourcePaths); s->setValue(QLatin1String(breakEventKeyC), breakEvents); + s->setValue(QLatin1String(breakFunctionsKeyC), breakFunctions); s->setValue(QLatin1String(additionalArgumentsKeyC), additionalArguments); s->setValue(QLatin1String(cdbConsoleKeyC), QVariant(cdbConsole)); s->setValue(QLatin1String(breakpointCorrectionKeyC), QVariant(breakpointCorrection)); @@ -95,7 +102,8 @@ bool CdbOptions::equals(const CdbOptions &rhs) const && additionalArguments == rhs.additionalArguments && symbolPaths == rhs.symbolPaths && sourcePaths == rhs.sourcePaths - && breakEvents == rhs.breakEvents; + && breakEvents == rhs.breakEvents + && breakFunctions == rhs.breakFunctions; } } // namespace Internal diff --git a/src/plugins/debugger/cdb/cdboptions.h b/src/plugins/debugger/cdb/cdboptions.h index 7e29a3eb05ef4e5112449a1fb424c37f178bb354..f681c5e9f0f155e64f696e48c614caca61b2c411 100644 --- a/src/plugins/debugger/cdb/cdboptions.h +++ b/src/plugins/debugger/cdb/cdboptions.h @@ -62,10 +62,13 @@ public: QStringList sourcePaths; // Events to break on (Command 'sxe' with abbreviation and optional parameter) QStringList breakEvents; + QStringList breakFunctions; // Launch CDB's own console instead of Qt Creator's bool cdbConsole; // Perform code-model based correction of breakpoint location. bool breakpointCorrection; + + static const char *crtDbgReport; }; inline bool operator==(const CdbOptions &s1, const CdbOptions &s2) diff --git a/src/plugins/debugger/cdb/cdboptionspage.cpp b/src/plugins/debugger/cdb/cdboptionspage.cpp index a8b09f35fc8f08fd077c539ad4652584b3fc27e9..2ee23b4c119f8996511d12620549e5f2d30a9ac3 100644 --- a/src/plugins/debugger/cdb/cdboptionspage.cpp +++ b/src/plugins/debugger/cdb/cdboptionspage.cpp @@ -30,6 +30,7 @@ #include "cdboptionspage.h" #include "cdboptions.h" +#include "commonoptionspage.h" #include "debuggerinternalconstants.h" #include "cdbengine.h" @@ -176,6 +177,11 @@ CdbOptionsPageWidget::CdbOptionsPageWidget(QWidget *parent) : eventLayout->setContentsMargins(margins); eventLayout->addWidget(m_breakEventWidget); m_ui.eventGroupBox->setLayout(eventLayout); + m_ui.breakCrtDbgReportCheckBox + ->setText(CommonOptionsPage::msgSetBreakpointAtFunction(CdbOptions::crtDbgReport)); + const QString hint = tr("This is useful to catch runtime error messages, for example caused by assert()."); + m_ui.breakCrtDbgReportCheckBox + ->setToolTip(CommonOptionsPage::msgSetBreakpointAtFunctionToolTip(CdbOptions::crtDbgReport, hint)); } void CdbOptionsPageWidget::setOptions(CdbOptions &o) @@ -186,6 +192,7 @@ void CdbOptionsPageWidget::setOptions(CdbOptions &o) m_breakEventWidget->setBreakEvents(o.breakEvents); m_ui.consoleCheckBox->setChecked(o.cdbConsole); m_ui.breakpointCorrectionCheckBox->setChecked(o.breakpointCorrection); + m_ui.breakCrtDbgReportCheckBox->setChecked(o.breakFunctions.contains(QLatin1String(CdbOptions::crtDbgReport))); } CdbOptions CdbOptionsPageWidget::options() const @@ -197,6 +204,8 @@ CdbOptions CdbOptionsPageWidget::options() const rc.breakEvents = m_breakEventWidget->breakEvents(); rc.cdbConsole = m_ui.consoleCheckBox->isChecked(); rc.breakpointCorrection = m_ui.breakpointCorrectionCheckBox->isChecked(); + if (m_ui.breakCrtDbgReportCheckBox->isChecked()) + rc.breakFunctions.push_back(QLatin1String(CdbOptions::crtDbgReport)); return rc; } diff --git a/src/plugins/debugger/cdb/cdboptionspagewidget.ui b/src/plugins/debugger/cdb/cdboptionspagewidget.ui index 8160cd74db31e63e57e9d3f6bd239b409bf8b0f3..41b3d6a1ffb0eeee6e75410a056819afad65cdbf 100644 --- a/src/plugins/debugger/cdb/cdboptionspagewidget.ui +++ b/src/plugins/debugger/cdb/cdboptionspagewidget.ui @@ -120,6 +120,18 @@ </property> </widget> </item> + <item> + <widget class="QGroupBox" name="breakFunctionGroupBox"> + <property name="title"> + <string>Break on functions:</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QCheckBox" name="breakCrtDbgReportCheckBox"/> + </item> + </layout> + </widget> + </item> <item> <spacer name="verticalSpacer"> <property name="orientation"> diff --git a/src/plugins/debugger/commonoptionspage.cpp b/src/plugins/debugger/commonoptionspage.cpp index 495f28af0fb5a2b97d07b5c1413e5a00288f4175..06a74b5235b57dc277c7117cd7d570c96ea5d1e4 100644 --- a/src/plugins/debugger/commonoptionspage.cpp +++ b/src/plugins/debugger/commonoptionspage.cpp @@ -200,6 +200,24 @@ bool CommonOptionsPage::matches(const QString &s) const return m_searchKeywords.contains(s, Qt::CaseInsensitive); } +QString CommonOptionsPage::msgSetBreakpointAtFunction(const char *function) +{ + return tr("Stop when %1() is called").arg(QLatin1String(function)); +} + +QString CommonOptionsPage::msgSetBreakpointAtFunctionToolTip(const char *function, + const QString &hint) +{ + QString result = QLatin1String("<html><head/><body>"); + result += tr("Always add a breakpoint on the <i>%1()</i> function.").arg(QLatin1String(function)); + if (!hint.isEmpty()) { + result += QLatin1String("<br>"); + result += hint; + } + result += QLatin1String("</body></html>"); + return result; +} + /////////////////////////////////////////////////////////////////////// // // LocalsAndExpressionsOptionsPage diff --git a/src/plugins/debugger/commonoptionspage.h b/src/plugins/debugger/commonoptionspage.h index b5eaf9392a58a61e4323a2e8660deec6303c200d..4f5b76ab2c09f58a8930d4cc60498b5d187939ad 100644 --- a/src/plugins/debugger/commonoptionspage.h +++ b/src/plugins/debugger/commonoptionspage.h @@ -79,6 +79,10 @@ public: void finish(); bool matches(const QString &s) const; + static QString msgSetBreakpointAtFunction(const char *function); + static QString msgSetBreakpointAtFunctionToolTip(const char *function, + const QString &hint = QString()); + private: const QSharedPointer<GlobalDebuggerOptions> m_options; QSharedPointer<Utils::SavedActionSet> m_group; diff --git a/src/plugins/debugger/gdb/gdboptionspage.cpp b/src/plugins/debugger/gdb/gdboptionspage.cpp index 5f3bc80efa45798222bb9352b544c833cb60108a..4d11152141e549f406cc850a9c79ebe8bafa493b 100644 --- a/src/plugins/debugger/gdb/gdboptionspage.cpp +++ b/src/plugins/debugger/gdb/gdboptionspage.cpp @@ -29,6 +29,7 @@ **************************************************************************/ #include "gdboptionspage.h" +#include "commonoptionspage.h" #include "debuggeractions.h" #include "debuggercore.h" #include "debuggerinternalconstants.h" @@ -181,22 +182,16 @@ GdbOptionsPageWidget::GdbOptionsPageWidget(QWidget *parent) "when starting GDB.</body></html>")); checkBoxBreakOnWarning = new QCheckBox(groupBoxGeneral); - checkBoxBreakOnWarning->setText(GdbOptionsPage::tr("Stop when qWarning() is called")); - checkBoxBreakOnWarning->setToolTip(GdbOptionsPage::tr( - "<html><head/><body>Always add a breakpoint on the <i>qWarning()</i> function." - "</body></html>")); + checkBoxBreakOnWarning->setText(CommonOptionsPage::msgSetBreakpointAtFunction("qWarning")); + checkBoxBreakOnWarning->setToolTip(CommonOptionsPage::msgSetBreakpointAtFunctionToolTip("qWarning")); checkBoxBreakOnFatal = new QCheckBox(groupBoxGeneral); - checkBoxBreakOnFatal->setText(GdbOptionsPage::tr("Stop when qFatal() is called")); - checkBoxBreakOnFatal->setToolTip(GdbOptionsPage::tr( - "<html><head/><body>Always add a breakpoint on the <i>qFatal()</i> function." - "</body></html>")); + checkBoxBreakOnFatal->setText(CommonOptionsPage::msgSetBreakpointAtFunction("qFatal")); + checkBoxBreakOnFatal->setToolTip(CommonOptionsPage::msgSetBreakpointAtFunctionToolTip("qFatal")); checkBoxBreakOnAbort = new QCheckBox(groupBoxGeneral); - checkBoxBreakOnAbort->setText(GdbOptionsPage::tr("Stop when abort() is called")); - checkBoxBreakOnAbort->setToolTip(GdbOptionsPage::tr( - "<html><head/><body><p>Always add a breakpoint on the <i>abort()</i> function." - "</p></body></html>")); + checkBoxBreakOnAbort->setText(CommonOptionsPage::msgSetBreakpointAtFunction("abort")); + checkBoxBreakOnAbort->setText(CommonOptionsPage::msgSetBreakpointAtFunctionToolTip("abort")); checkBoxEnableReverseDebugging = new QCheckBox(groupBoxGeneral); checkBoxEnableReverseDebugging->setText(GdbOptionsPage::tr("Enable reverse debugging"));