forked from qt-creator/qt-creator
Debugger: List break on catch/throw as such and map names in engine.
Introduce special setting 'Stop on exception' for CDB. Reviewed-by: hjk
This commit is contained in:
@@ -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),
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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...
|
||||
|
||||
@@ -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").
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user