diff --git a/src/plugins/debugger/breakpoint.cpp b/src/plugins/debugger/breakpoint.cpp index f7dc8a848e22987198a80cb9acb15cd4affe0a2d..0c9fc2341bd473ef558ff25bb1f73a4a158391b6 100644 --- a/src/plugins/debugger/breakpoint.cpp +++ b/src/plugins/debugger/breakpoint.cpp @@ -159,6 +159,9 @@ private: // ////////////////////////////////////////////////////////////////// +const char *BreakpointData::throwFunction = "throw"; +const char *BreakpointData::catchFunction = "catch"; + BreakpointData::BreakpointData() : m_handler(0), enabled(true), pending(true), type(BreakpointType), diff --git a/src/plugins/debugger/breakpoint.h b/src/plugins/debugger/breakpoint.h index 7e22ffdb918b281027b1d0b6b1e11388894692e2..e96a58bc83fd614c86a5971d87fa40fe57d6eb2f 100644 --- a/src/plugins/debugger/breakpoint.h +++ b/src/plugins/debugger/breakpoint.h @@ -66,6 +66,10 @@ public: // This copies only the static data. BreakpointData *clone() const; + // Generic name for function to break on 'throw' + static const char *throwFunction; + static const char *catchFunction; + private: // Intentionally unimplemented. // Making it copyable is tricky because of the markers. @@ -90,7 +94,9 @@ public: int lineNumber; // Line in source file. quint64 address; // Address for watchpoints. QByteArray threadSpec; // Thread specification. - QString funcName; // Name of containing function. + // Name of containing function, special values: + // BreakpointData::throwFunction, BreakpointData::catchFunction + QString funcName; bool useFullPath; // Should we use the full path when setting the bp? // This is what gdb produced in response. diff --git a/src/plugins/debugger/breakwindow.cpp b/src/plugins/debugger/breakwindow.cpp index aa8c49c341ee255efb4e39fd4410a0d2714056f7..36271a08d74fb12e7701917c419456fbb395a826 100644 --- a/src/plugins/debugger/breakwindow.cpp +++ b/src/plugins/debugger/breakwindow.cpp @@ -334,9 +334,9 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev) else if (act == addBreakpointAction) addBreakpoint(); else if (act == breakAtThrowAction) - setModelData(RequestBreakByFunctionRole, "__cxa_throw"); + setModelData(RequestBreakByFunctionRole, QLatin1String(BreakpointData::throwFunction)); else if (act == breakAtCatchAction) - setModelData(RequestBreakByFunctionRole, "__cxa_begin_catch"); + setModelData(RequestBreakByFunctionRole, QLatin1String(BreakpointData::catchFunction)); } void BreakWindow::setBreakpointsEnabled(const QModelIndexList &list, bool enabled) diff --git a/src/plugins/debugger/cdb/cdbbreakpoint.cpp b/src/plugins/debugger/cdb/cdbbreakpoint.cpp index 5dbe1f6219633683f72ce674a212748c1d9ebffc..6115b60053539c6a479cc12f8a8a0a4915606aba 100644 --- a/src/plugins/debugger/cdb/cdbbreakpoint.cpp +++ b/src/plugins/debugger/cdb/cdbbreakpoint.cpp @@ -53,7 +53,8 @@ CdbCore::BreakPoint breakPointFromBreakPointData(const Debugger::Internal::Break } rc.fileName = QDir::toNativeSeparators(bpd.fileName); rc.condition = bpd.condition; - rc.funcName = bpd.funcName; + // Resolved function goes to bpd.bpFuncName. + rc.funcName = bpd.bpFuncName.isEmpty() ? bpd.funcName : bpd.bpFuncName; rc.ignoreCount = bpd.ignoreCount; rc.lineNumber = bpd.lineNumber; rc.oneShot = false; @@ -92,7 +93,8 @@ bool synchronizeBreakPoints(CIDebugControl* debugControl, if (nbd->funcName.isEmpty()) { breakPointOk = true; } else { - switch (resolveSymbol(syms, &nbd->funcName, &warning)) { + nbd->bpFuncName = nbd->funcName; + switch (resolveSymbol(syms, &nbd->bpFuncName, &warning)) { case ResolveSymbolOk: breakPointOk = true; break; @@ -128,7 +130,6 @@ bool synchronizeBreakPoints(CIDebugControl* debugControl, nbd->bpThreadSpec = nbd->threadSpec; nbd->bpFileName = nbd->fileName; nbd->bpLineNumber = nbd->lineNumber; - nbd->bpFuncName = nbd->funcName; } } // had symbol if (!breakPointOk && !warning.isEmpty()) diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 66bc3067a71f78d0f98eba660511c85762b35a94..363daa66d65d1bdcfe935e148c0c3a827bb5aa22 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -409,7 +409,7 @@ void CdbEngine::setupEngine() m_d->m_inferiorStartupComplete = false; // Options QString errorMessage; - if (!m_d->setBreakOnThrow(theDebuggerBoolSetting(BreakOnThrow), &errorMessage)) + if (!m_d->setBreakOnThrow(m_d->m_options->breakOnException, &errorMessage)) showMessage(errorMessage, LogWarning); m_d->setVerboseSymbolLoading(m_d->m_options->verboseSymbolLoading); // Figure out dumper. @TODO: same in gdb... diff --git a/src/plugins/debugger/cdb/cdbmodules.cpp b/src/plugins/debugger/cdb/cdbmodules.cpp index 8082527e1e9f5466e3d2ae9c540d935e4fc9265f..ed5427375a8d06cb8960faf4b1599acdc46a2168 100644 --- a/src/plugins/debugger/cdb/cdbmodules.cpp +++ b/src/plugins/debugger/cdb/cdbmodules.cpp @@ -30,6 +30,7 @@ #include "cdbmodules.h" #include "moduleshandler.h" #include "cdbengine_p.h" +#include "breakpoint.h" #include <QtCore/QFileInfo> #include <QtCore/QRegExp> @@ -180,14 +181,35 @@ static ResolveSymbolResult resolveSymbol(CIDebugSymbols *syms, QString *symbol, // Is it an incomplete symbol? if (symbol->contains(QLatin1Char('!'))) return ResolveSymbolOk; - // 'main' is a #define for gdb, but not for VS - if (*symbol == QLatin1String("qMain")) + // Throw and catch + bool withinMSVCRunTime = false; + if (*symbol == QLatin1String(BreakpointData::throwFunction)) { + *symbol = QLatin1String("CxxThrowException"); + withinMSVCRunTime = true; + } else if (*symbol == QLatin1String(BreakpointData::catchFunction)) { + *symbol = QLatin1String("__CxxCallCatchBlock"); + withinMSVCRunTime = true; + } else if (*symbol == QLatin1String("qMain")) // 'main' is a #define for gdb, but not for VS *symbol = QLatin1String("main"); // resolve if (!searchSymbols(syms, *symbol, matches, errorMessage)) return ResolveSymbolError; - if (matches->empty()) + // Exception functions sometimes show up ambiguously as'QtGuid4!CxxThrowException', + // 'MSVCR100D!CxxThrowException', QtCored4!CxxThrowException', + // 'MSVCP100D!CxxThrowException' and 'msvcrt!CxxThrowException', + // 'OLEAUT32!CxxThrowException'...restrict to MSVC-RunTime (any MSVC version). + if (withinMSVCRunTime && matches->size() > 1) { + for (QStringList::iterator it = matches->begin(); it != matches->end(); ) + if (it->startsWith(QLatin1String("MSVCR"))) { + ++it; + } else { + it = matches->erase(it); + } + } + if (matches->empty()) { + *errorMessage = QString::fromLatin1("No match for '%1' found").arg(*symbol); return ResolveSymbolNotFound; + } *symbol = matches->front(); if (matches->size() > 1) { *errorMessage = QString::fromLatin1("Ambiguous symbol '%1': %2"). diff --git a/src/plugins/debugger/cdb/cdboptions.cpp b/src/plugins/debugger/cdb/cdboptions.cpp index 9443cc531a63b6fbe5f2147bf87bb2097c07a132..0f7e19945d0140f520b8d7c507f683917f45cc46 100644 --- a/src/plugins/debugger/cdb/cdboptions.cpp +++ b/src/plugins/debugger/cdb/cdboptions.cpp @@ -39,6 +39,7 @@ static const char *enabledKeyC = "Enabled"; static const char *pathKeyC = "Path"; static const char *symbolPathsKeyC = "SymbolPaths"; static const char *sourcePathsKeyC = "SourcePaths"; +static const char *breakOnExceptionKeyC = "BreakOnException"; static const char *verboseSymbolLoadingKeyC = "VerboseSymbolLoading"; static const char *fastLoadDebuggingHelpersKeyC = "FastLoadDebuggingHelpers"; @@ -47,6 +48,7 @@ namespace Internal { CdbOptions::CdbOptions() : enabled(false), + breakOnException(false), verboseSymbolLoading(false), fastLoadDebuggingHelpers(true) { @@ -83,6 +85,7 @@ void CdbOptions::fromSettings(const QSettings *s) sourcePaths = s->value(keyRoot + QLatin1String(sourcePathsKeyC), QStringList()).toStringList(); verboseSymbolLoading = s->value(keyRoot + QLatin1String(verboseSymbolLoadingKeyC), false).toBool(); fastLoadDebuggingHelpers = s->value(keyRoot + QLatin1String(fastLoadDebuggingHelpersKeyC), true).toBool(); + breakOnException = s->value(keyRoot + QLatin1String(breakOnExceptionKeyC), false).toBool(); } void CdbOptions::toSettings(QSettings *s) const @@ -94,6 +97,7 @@ void CdbOptions::toSettings(QSettings *s) const s->setValue(QLatin1String(sourcePathsKeyC), sourcePaths); s->setValue(QLatin1String(verboseSymbolLoadingKeyC), verboseSymbolLoading); s->setValue(QLatin1String(fastLoadDebuggingHelpersKeyC), fastLoadDebuggingHelpers); + s->setValue(QLatin1String(breakOnExceptionKeyC), breakOnException); s->endGroup(); } @@ -108,6 +112,8 @@ unsigned CdbOptions::compare(const CdbOptions &rhs) const rc |= SymbolOptionsChanged; if (fastLoadDebuggingHelpers != rhs.fastLoadDebuggingHelpers) rc |= FastLoadDebuggingHelpersChanged; + if (breakOnException != rhs.breakOnException) + rc |= OtherOptionsChanged; return rc; } diff --git a/src/plugins/debugger/cdb/cdboptions.h b/src/plugins/debugger/cdb/cdboptions.h index 43151aebc7896e9588c5fe0d576505caa0b99554..34db9ee1b8f1dc2f8c4297f8050057380e75ae51 100644 --- a/src/plugins/debugger/cdb/cdboptions.h +++ b/src/plugins/debugger/cdb/cdboptions.h @@ -52,7 +52,9 @@ public: enum ChangeFlags { InitializationOptionsChanged = 0x1, DebuggerPathsChanged = 0x2, SymbolOptionsChanged = 0x4, - FastLoadDebuggingHelpersChanged = 0x8 }; + FastLoadDebuggingHelpersChanged = 0x8, + OtherOptionsChanged = 0x100 + }; unsigned compare(const CdbOptions &s) const; // Format a symbol server specification with a cache directory @@ -67,6 +69,7 @@ public: QString path; QStringList symbolPaths; QStringList sourcePaths; + bool breakOnException; bool verboseSymbolLoading; bool fastLoadDebuggingHelpers; }; diff --git a/src/plugins/debugger/cdb/cdboptionspage.cpp b/src/plugins/debugger/cdb/cdboptionspage.cpp index 84252e52048113859c34ee37b1451a5aba538fb5..a42d10fd6f11177464fad05e3d2f972d38883fdf 100644 --- a/src/plugins/debugger/cdb/cdboptionspage.cpp +++ b/src/plugins/debugger/cdb/cdboptionspage.cpp @@ -86,6 +86,7 @@ void CdbOptionsPageWidget::setOptions(CdbOptions &o) m_ui.sourcePathListEditor->setPathList(o.sourcePaths); m_ui.verboseSymbolLoadingCheckBox->setChecked(o.verboseSymbolLoading); m_ui.fastLoadDebuggingHelpersCheckBox->setChecked(o.fastLoadDebuggingHelpers); + m_ui.breakOnExceptionCheckBox->setChecked(o.breakOnException); } CdbOptions CdbOptionsPageWidget::options() const @@ -97,6 +98,7 @@ CdbOptions CdbOptionsPageWidget::options() const rc.sourcePaths = m_ui.sourcePathListEditor->pathList(); rc.verboseSymbolLoading = m_ui.verboseSymbolLoadingCheckBox->isChecked(); rc.fastLoadDebuggingHelpers = m_ui.fastLoadDebuggingHelpersCheckBox->isChecked(); + rc.breakOnException = m_ui.breakOnExceptionCheckBox->isChecked(); return rc; } @@ -134,7 +136,8 @@ QString CdbOptionsPageWidget::searchKeywords() const QTextStream(&rc) << m_ui.pathLabel->text() << ' ' << m_ui.symbolPathLabel->text() << ' ' << m_ui.sourcePathLabel->text() << ' ' << m_ui.verboseSymbolLoadingCheckBox->text() - << ' ' << m_ui.fastLoadDebuggingHelpersCheckBox->text(); + << ' ' << m_ui.fastLoadDebuggingHelpersCheckBox->text() + << ' ' << m_ui.breakOnExceptionCheckBox->text(); rc.remove(QLatin1Char('&')); return rc; } diff --git a/src/plugins/debugger/cdb/cdboptionspagewidget.ui b/src/plugins/debugger/cdb/cdboptionspagewidget.ui index 26bbd3b900c6108ed2d7ec3f71a407778ff503c9..60b0e9959952f3473d990f98f0f799efbc4758ac 100644 --- a/src/plugins/debugger/cdb/cdboptionspagewidget.ui +++ b/src/plugins/debugger/cdb/cdboptionspagewidget.ui @@ -88,20 +88,27 @@ <property name="fieldGrowthPolicy"> <enum>QFormLayout::AllNonFixedFieldsGrow</enum> </property> - <item row="0" column="0" colspan="2"> + <item row="1" column="0" colspan="2"> <widget class="QCheckBox" name="verboseSymbolLoadingCheckBox"> <property name="text"> <string>Verbose symbol loading</string> </property> </widget> </item> - <item row="1" column="0"> + <item row="2" column="0"> <widget class="QCheckBox" name="fastLoadDebuggingHelpersCheckBox"> <property name="text"> <string>Fast loading of debugging helpers</string> </property> </widget> </item> + <item row="0" column="0" colspan="2"> + <widget class="QCheckBox" name="breakOnExceptionCheckBox"> + <property name="text"> + <string>Break on exception</string> + </property> + </widget> + </item> </layout> </widget> </item> diff --git a/src/plugins/debugger/cdb/corebreakpoint.cpp b/src/plugins/debugger/cdb/corebreakpoint.cpp index 4effa092d48b6955a05ee65044deee421ffa24f3..082ce3822377fb0b2f766a3807e0ea22004e5d42 100644 --- a/src/plugins/debugger/cdb/corebreakpoint.cpp +++ b/src/plugins/debugger/cdb/corebreakpoint.cpp @@ -192,6 +192,9 @@ bool BreakPoint::apply(CIDebugBreakpoint *ibp, QString *errorMessage) const *errorMessage = msgCannotSetBreakpoint(expr, msg); return false; } + hr = ibp->GetFlags(&flags); + if (SUCCEEDED(hr)) + qDebug("BP %s Flags %x", qPrintable(expr), flags); return true; } diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index ec860d875aad5ac0d7d4b3a37fee454bbcba4316..739e37bec3f8897b67072941c6ec826fc5bde985 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -2144,8 +2144,13 @@ static inline QByteArray bpAddressSpec(quint64 address) QByteArray GdbEngine::breakpointLocation(const BreakpointData *data) { - if (!data->funcName.isEmpty()) + if (!data->funcName.isEmpty()) { + if (data->funcName == QLatin1String(BreakpointData::throwFunction)) + return QByteArray("__cxa_throw"); + if (data->funcName == QLatin1String(BreakpointData::catchFunction)) + return QByteArray("__cxa_begin_catch"); return data->funcName.toLatin1(); + } if (data->address) return bpAddressSpec(data->address); // In this case, data->funcName is something like '*0xdeadbeef'