debugger: introduce watchpoint-by-expression

This commit is contained in:
hjk
2011-05-09 08:35:58 +02:00
parent 8a9cde986a
commit c620749b95
15 changed files with 155 additions and 69 deletions

View File

@@ -114,8 +114,10 @@ static QString typeToString(BreakpointType type)
return msgBreakpointAtSpecialFunc("syscall"); return msgBreakpointAtSpecialFunc("syscall");
case BreakpointAtMain: case BreakpointAtMain:
return BreakHandler::tr("Breakpoint at Function \"main()\""); return BreakHandler::tr("Breakpoint at Function \"main()\"");
case Watchpoint: case WatchpointAtAddress:
return BreakHandler::tr("Watchpoint"); return BreakHandler::tr("Watchpoint at Address");
case WatchpointAtExpression:
return BreakHandler::tr("Watchpoint at Expression");
case UnknownType: case UnknownType:
break; break;
} }
@@ -517,7 +519,7 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
//|| data.type == BreakpointAtVFork //|| data.type == BreakpointAtVFork
|| data.type == BreakpointAtSysCall) || data.type == BreakpointAtSysCall)
return typeToString(data.type); return typeToString(data.type);
if (data.type == Watchpoint) if (data.type == WatchpointAtAddress)
return tr("Watchpoint at 0x%1").arg(data.address, 0, 16); return tr("Watchpoint at 0x%1").arg(data.address, 0, 16);
return empty; return empty;
} }
@@ -648,6 +650,7 @@ PROPERTY(int, threadSpec, setThreadSpec)
PROPERTY(QByteArray, condition, setCondition) PROPERTY(QByteArray, condition, setCondition)
GETTER(int, lineNumber) GETTER(int, lineNumber)
PROPERTY(quint64, address, setAddress) PROPERTY(quint64, address, setAddress)
PROPERTY(QByteArray, expression, setExpression)
PROPERTY(int, ignoreCount, setIgnoreCount) PROPERTY(int, ignoreCount, setIgnoreCount)
bool BreakHandler::isEnabled(BreakpointId id) const bool BreakHandler::isEnabled(BreakpointId id) const
@@ -673,6 +676,13 @@ void BreakHandler::setEnabled(BreakpointId id, bool on)
} }
} }
bool BreakHandler::isWatchpoint(BreakpointId id) const
{
ConstIterator it = m_storage.find(id);
BREAK_ASSERT(it != m_storage.end(), return false);
return it->data.isWatchpoint();
}
bool BreakHandler::isTracepoint(BreakpointId id) const bool BreakHandler::isTracepoint(BreakpointId id) const
{ {
ConstIterator it = m_storage.find(id); ConstIterator it = m_storage.find(id);
@@ -1195,7 +1205,7 @@ QIcon BreakHandler::BreakpointItem::icon() const
// cursor is near a line with a breakpoint marker (+/- 2 lines or so). // cursor is near a line with a breakpoint marker (+/- 2 lines or so).
if (data.isTracepoint()) if (data.isTracepoint())
return BreakHandler::tracepointIcon(); return BreakHandler::tracepointIcon();
if (data.type == Watchpoint) if (data.type == WatchpointAtAddress)
return BreakHandler::watchpointIcon(); return BreakHandler::watchpointIcon();
if (!data.enabled) if (!data.enabled)
return BreakHandler::disabledBreakpointIcon(); return BreakHandler::disabledBreakpointIcon();

View File

@@ -115,6 +115,8 @@ public:
void setFileName(BreakpointId, const QString &fileName); void setFileName(BreakpointId, const QString &fileName);
QString functionName(BreakpointId id) const; QString functionName(BreakpointId id) const;
void setFunctionName(BreakpointId, const QString &functionName); void setFunctionName(BreakpointId, const QString &functionName);
QByteArray expression(BreakpointId id) const;
void setExpression(BreakpointId, const QByteArray &expression);
BreakpointType type(BreakpointId id) const; BreakpointType type(BreakpointId id) const;
void setType(BreakpointId id, const BreakpointType &type); void setType(BreakpointId id, const BreakpointType &type);
quint64 address(BreakpointId id) const; quint64 address(BreakpointId id) const;
@@ -129,6 +131,7 @@ public:
void updateLineNumberFromMarker(BreakpointId id, int lineNumber); void updateLineNumberFromMarker(BreakpointId id, int lineNumber);
void setMarkerFileAndLine(BreakpointId id, void setMarkerFileAndLine(BreakpointId id,
const QString &fileName, int lineNumber); const QString &fileName, int lineNumber);
bool isWatchpoint(BreakpointId id) const;
bool isTracepoint(BreakpointId id) const; bool isTracepoint(BreakpointId id) const;
void setTracepoint(BreakpointId, bool on); void setTracepoint(BreakpointId, bool on);
DebuggerEngine *engine(BreakpointId id) const; DebuggerEngine *engine(BreakpointId id) const;

View File

@@ -119,9 +119,12 @@ QString BreakpointParameters::toString() const
ts << " FunctionName: " << functionName; ts << " FunctionName: " << functionName;
break; break;
case BreakpointByAddress: case BreakpointByAddress:
case Watchpoint: case WatchpointAtAddress:
ts << " Address: " << address; ts << " Address: " << address;
break; break;
case WatchpointAtExpression:
ts << " Expression: " << expression;
break;
case BreakpointAtThrow: case BreakpointAtThrow:
case BreakpointAtCatch: case BreakpointAtCatch:
case BreakpointAtMain: case BreakpointAtMain:

View File

@@ -62,7 +62,8 @@ enum BreakpointType
BreakpointAtExec, BreakpointAtExec,
//BreakpointAtVFork, //BreakpointAtVFork,
BreakpointAtSysCall, BreakpointAtSysCall,
Watchpoint WatchpointAtAddress,
WatchpointAtExpression
}; };
//! \enum Debugger::Internal::BreakpointState //! \enum Debugger::Internal::BreakpointState
@@ -93,19 +94,21 @@ enum BreakpointParts
FileAndLinePart = 0x1, FileAndLinePart = 0x1,
FunctionPart = 0x2, FunctionPart = 0x2,
AddressPart = 0x4, AddressPart = 0x4,
ConditionPart = 0x8, ExpressionPart = 0x8,
IgnoreCountPart = 0x10, ConditionPart = 0x10,
ThreadSpecPart = 0x20, IgnoreCountPart = 0x20,
ThreadSpecPart = 0x40,
AllConditionParts = ConditionPart|IgnoreCountPart|ThreadSpecPart, AllConditionParts = ConditionPart|IgnoreCountPart|ThreadSpecPart,
ModulePart = 0x40, ModulePart = 0x80,
TracePointPart = 0x80, TracePointPart = 0x100,
EnabledPart = 0x100, EnabledPart = 0x200,
TypePart = 0x200, TypePart = 0x400,
PathUsagePart = 0x400, PathUsagePart = 0x800,
CommandPart = 0x400, CommandPart = 0x1000,
AllParts = FileAndLinePart|FunctionPart|AddressPart|ConditionPart AllParts = FileAndLinePart|FunctionPart
|ExpressionPart|AddressPart|ConditionPart
|IgnoreCountPart|ThreadSpecPart|ModulePart|TracePointPart |IgnoreCountPart|ThreadSpecPart|ModulePart|TracePointPart
|EnabledPart|TypePart|PathUsagePart|CommandPart |EnabledPart|TypePart|PathUsagePart|CommandPart
}; };
@@ -123,9 +126,10 @@ public:
BreakpointParts differencesTo(const BreakpointParameters &rhs) const; BreakpointParts differencesTo(const BreakpointParameters &rhs) const;
bool equals(const BreakpointParameters &rhs) const; bool equals(const BreakpointParameters &rhs) const;
bool conditionsMatch(const QByteArray &other) const; bool conditionsMatch(const QByteArray &other) const;
bool isWatchpoint() const { return type == Watchpoint; } bool isWatchpoint() const
{ return type == WatchpointAtAddress || type == WatchpointAtExpression; }
// Enough for now. // Enough for now.
bool isBreakpoint() const { return type != Watchpoint && !tracepoint; } bool isBreakpoint() const { return !isWatchpoint() && !isTracepoint(); }
bool isTracepoint() const { return tracepoint; } bool isTracepoint() const { return tracepoint; }
QString toString() const; QString toString() const;
@@ -139,7 +143,8 @@ public:
QByteArray condition; //!< Condition associated with breakpoint. QByteArray condition; //!< Condition associated with breakpoint.
int ignoreCount; //!< Ignore count associated with breakpoint. int ignoreCount; //!< Ignore count associated with breakpoint.
int lineNumber; //!< Line in source file. int lineNumber; //!< Line in source file.
quint64 address; //!< Address for watchpoints. quint64 address; //!< Address for address based watchpoints.
QByteArray expression; //!< Address for expression based watchpoints.
uint size; //!< Size of watched area for watchpoints. uint size; //!< Size of watched area for watchpoints.
uint bitpos; //!< Location of watched bitfield within watched area. uint bitpos; //!< Location of watched bitfield within watched area.
uint bitsize; //!< Size of watched bitfield within watched area. uint bitsize; //!< Size of watched bitfield within watched area.

View File

@@ -90,6 +90,19 @@
<widget class="QLineEdit" name="lineEditAddress"/> <widget class="QLineEdit" name="lineEditAddress"/>
</item> </item>
<item row="5" column="0"> <item row="5" column="0">
<widget class="QLabel" name="labelExpression">
<property name="text">
<string>&amp;Expression:</string>
</property>
<property name="buddy">
<cstring>lineEditExpression</cstring>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="lineEditExpression"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="labelFunction"> <widget class="QLabel" name="labelFunction">
<property name="text"> <property name="text">
<string>Fun&amp;ction:</string> <string>Fun&amp;ction:</string>
@@ -99,7 +112,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="6" column="1">
<widget class="QLineEdit" name="lineEditFunction"/> <widget class="QLineEdit" name="lineEditFunction"/>
</item> </item>
</layout> </layout>

View File

@@ -80,20 +80,6 @@ public slots:
void typeChanged(int index); void typeChanged(int index);
private: private:
enum DialogPart {
FileAndLinePart = 0x1,
FunctionPart = 0x2,
AddressPart = 0x4,
ConditionPart = 0x8,
IgnoreCountPart = 0x10,
ThreadSpecPart = 0x20,
AllConditionParts = ConditionPart|IgnoreCountPart|ThreadSpecPart,
ModulePart = 0x40,
TracePointPart = 0x80,
AllParts = FileAndLinePart|FunctionPart|AddressPart|ConditionPart
|IgnoreCountPart|ThreadSpecPart|ModulePart|TracePointPart
};
void setPartsEnabled(unsigned partsMask); void setPartsEnabled(unsigned partsMask);
void clearOtherParts(unsigned partsMask); void clearOtherParts(unsigned partsMask);
void getParts(unsigned partsMask, BreakpointParameters *data) const; void getParts(unsigned partsMask, BreakpointParameters *data) const;
@@ -122,17 +108,18 @@ BreakpointDialog::BreakpointDialog(unsigned engineCapabilities, QWidget *parent)
// Match BreakpointType (omitting unknown type). // Match BreakpointType (omitting unknown type).
m_ui.setupUi(this); m_ui.setupUi(this);
QStringList types; QStringList types;
types << tr("File and Line Number") types << tr("File name and line number")
<< tr("Function Name") << tr("Function name")
<< tr("Address") << tr("Address")
<< tr("Break when C++ Exception is Thrown") << tr("Break when C++ exception is thrown")
<< tr("Break when C++ Exception is Caught") << tr("Break when C++ exception is caught")
<< tr("Break when Function \"main()\" Starts") << tr("Break when function \"main()\" starts")
<< tr("Break when a new Process is Forked") << tr("Break when a new process is forked")
<< tr("Break when a new Process is Executed") << tr("Break when a new process is executed")
<< tr("Break when a System Call is Executed") << tr("Break when a system call is executed")
<< tr("Break on Data Access (Watchpoint)"); << tr("Break on data access (Watchpoint at address)")
QTC_ASSERT(types.size() == Watchpoint, return; ) << tr("Break on data access (Watchpoint at expression)");
QTC_ASSERT(types.size() == WatchpointAtExpression, return; )
m_ui.comboBoxType->addItems(types); m_ui.comboBoxType->addItems(types);
m_ui.pathChooserFileName->setExpectedKind(Utils::PathChooser::File); m_ui.pathChooserFileName->setExpectedKind(Utils::PathChooser::File);
connect(m_ui.comboBoxType, SIGNAL(activated(int)), SLOT(typeChanged(int))); connect(m_ui.comboBoxType, SIGNAL(activated(int)), SLOT(typeChanged(int)));
@@ -213,6 +200,8 @@ void BreakpointDialog::setPartsEnabled(unsigned partsMask)
m_ui.labelAddress->setEnabled(partsMask & AddressPart); m_ui.labelAddress->setEnabled(partsMask & AddressPart);
m_ui.lineEditAddress->setEnabled(partsMask & AddressPart); m_ui.lineEditAddress->setEnabled(partsMask & AddressPart);
m_ui.labelExpression->setEnabled(partsMask & ExpressionPart);
m_ui.lineEditExpression->setEnabled(partsMask & ExpressionPart);
m_ui.labelCondition->setEnabled(partsMask & ConditionPart); m_ui.labelCondition->setEnabled(partsMask & ConditionPart);
m_ui.lineEditCondition->setEnabled(partsMask & ConditionPart); m_ui.lineEditCondition->setEnabled(partsMask & ConditionPart);
@@ -242,6 +231,8 @@ void BreakpointDialog::clearOtherParts(unsigned partsMask)
if (invertedPartsMask & AddressPart) if (invertedPartsMask & AddressPart)
m_ui.lineEditAddress->clear(); m_ui.lineEditAddress->clear();
if (invertedPartsMask & ExpressionPart)
m_ui.lineEditExpression->clear();
if (invertedPartsMask & ConditionPart) if (invertedPartsMask & ConditionPart)
m_ui.lineEditCondition->clear(); m_ui.lineEditCondition->clear();
@@ -271,6 +262,8 @@ void BreakpointDialog::getParts(unsigned partsMask, BreakpointParameters *data)
if (partsMask & AddressPart) if (partsMask & AddressPart)
data->address = m_ui.lineEditAddress->text().toULongLong(0, 0); data->address = m_ui.lineEditAddress->text().toULongLong(0, 0);
if (partsMask & ExpressionPart)
data->expression = m_ui.lineEditExpression->text().toUtf8();
if (partsMask & ConditionPart) if (partsMask & ConditionPart)
data->condition = m_ui.lineEditCondition->text().toUtf8(); data->condition = m_ui.lineEditCondition->text().toUtf8();
@@ -309,6 +302,14 @@ void BreakpointDialog::setParts(unsigned mask, const BreakpointParameters &data)
} }
} }
if (mask & ExpressionPart) {
if (!data.expression.isEmpty()) {
m_ui.lineEditExpression->setText(data.expression);
} else {
m_ui.lineEditExpression->clear();
}
}
if (mask & ConditionPart) if (mask & ConditionPart)
m_ui.lineEditCondition->setText(QString::fromUtf8(data.condition)); m_ui.lineEditCondition->setText(QString::fromUtf8(data.condition));
if (mask & IgnoreCountPart) if (mask & IgnoreCountPart)
@@ -347,9 +348,12 @@ void BreakpointDialog::typeChanged(int)
case BreakpointAtSysCall: case BreakpointAtSysCall:
break; break;
case BreakpointByAddress: case BreakpointByAddress:
case Watchpoint: case WatchpointAtAddress:
getParts(AddressPart|AllConditionParts|TracePointPart, &m_savedParameters); getParts(AddressPart|AllConditionParts|TracePointPart, &m_savedParameters);
break; break;
case WatchpointAtExpression:
getParts(ExpressionPart|AllConditionParts|TracePointPart, &m_savedParameters);
break;
} }
// Enable and set up new state from saved values. // Enable and set up new state from saved values.
@@ -381,11 +385,16 @@ void BreakpointDialog::typeChanged(int)
setPartsEnabled(0); setPartsEnabled(0);
break; break;
case BreakpointByAddress: case BreakpointByAddress:
case Watchpoint: case WatchpointAtAddress:
setParts(AddressPart|AllConditionParts|TracePointPart, m_savedParameters); setParts(AddressPart|AllConditionParts|TracePointPart, m_savedParameters);
setPartsEnabled(AddressPart|AllConditionParts|TracePointPart|TracePointPart); setPartsEnabled(AddressPart|AllConditionParts|TracePointPart|TracePointPart);
clearOtherParts(AddressPart|AllConditionParts|TracePointPart); clearOtherParts(AddressPart|AllConditionParts|TracePointPart);
break; break;
case WatchpointAtExpression:
setParts(ExpressionPart|AllConditionParts|TracePointPart, m_savedParameters);
setPartsEnabled(ExpressionPart|AllConditionParts|TracePointPart|TracePointPart);
clearOtherParts(ExpressionPart|AllConditionParts|TracePointPart);
break;
} }
} }

View File

@@ -1069,7 +1069,7 @@ void CdbEngine::updateLocalVariable(const QByteArray &iname)
unsigned CdbEngine::debuggerCapabilities() const unsigned CdbEngine::debuggerCapabilities() const
{ {
return DisassemblerCapability | RegisterCapability | ShowMemoryCapability return DisassemblerCapability | RegisterCapability | ShowMemoryCapability
|WatchpointCapability|JumpToLineCapability|AddWatcherCapability |WatchpointByAddressCapability|JumpToLineCapability|AddWatcherCapability
|ReloadModuleCapability |ReloadModuleCapability
|BreakOnThrowAndCatchCapability // Sort-of: Can break on throw(). |BreakOnThrowAndCatchCapability // Sort-of: Can break on throw().
|BreakConditionCapability|TracePointCapability |BreakConditionCapability|TracePointCapability
@@ -1849,10 +1849,13 @@ unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
id = 0; id = 0;
} }
} }
if (id && breakHandler()->type(id) == Watchpoint) { QString tid = QString::number(threadId);
*message = msgWatchpointTriggered(id, number, breakHandler()->address(id), QString::number(threadId)); if (id && breakHandler()->type(id) == WatchpointAtAddress) {
*message = msgWatchpointByAddressTriggered(id, number, breakHandler()->address(id), tid);
} else if (id && breakHandler()->type(id) == WatchpointAtExpression) {
*message = msgWatchpointByExpressionTriggered(id, number, breakHandler()->expression(id), tid);
} else { } else {
*message = msgBreakpointTriggered(id, number, QString::number(threadId)); *message = msgBreakpointTriggered(id, number, tid);
} }
rc |= StopReportStatusMessage|StopNotifyStop; rc |= StopReportStatusMessage|StopNotifyStop;
return rc; return rc;
@@ -2347,7 +2350,7 @@ bool CdbEngine::acceptsBreakpoint(BreakpointId id) const
//case BreakpointAtVFork: //case BreakpointAtVFork:
case BreakpointAtSysCall: case BreakpointAtSysCall:
return false; return false;
case Watchpoint: case WatchpointAtAddress:
case BreakpointByFileAndLine: case BreakpointByFileAndLine:
case BreakpointByFunction: case BreakpointByFunction:
case BreakpointByAddress: case BreakpointByAddress:

View File

@@ -106,7 +106,7 @@ static BreakpointParameters fixWinMSVCBreakpoint(const BreakpointParameters &p)
case BreakpointAtFork: case BreakpointAtFork:
//case BreakpointAtVFork: //case BreakpointAtVFork:
case BreakpointAtSysCall: case BreakpointAtSysCall:
case Watchpoint: case WatchpointAtAddress:
break; break;
case BreakpointAtExec: { // Emulate by breaking on CreateProcessW(). case BreakpointAtExec: { // Emulate by breaking on CreateProcessW().
BreakpointParameters rc(BreakpointByFunction); BreakpointParameters rc(BreakpointByFunction);
@@ -148,7 +148,7 @@ QByteArray cdbAddBreakpointCommand(const BreakpointParameters &bpIn,
// Currently use 'bu' so that the offset expression (including file name) // Currently use 'bu' so that the offset expression (including file name)
// is kept when reporting back breakpoints (which is otherwise discarded // is kept when reporting back breakpoints (which is otherwise discarded
// when resolving). // when resolving).
str << (bp.type == Watchpoint ? "ba" : "bu"); str << (bp.type == WatchpointAtAddress ? "ba" : "bu");
if (id != BreakpointId(-1)) if (id != BreakpointId(-1))
str << id; str << id;
str << ' '; str << ' ';
@@ -179,7 +179,7 @@ QByteArray cdbAddBreakpointCommand(const BreakpointParameters &bpIn,
str << bp.module << '!'; str << bp.module << '!';
str << cdbBreakPointFileName(bp, sourcePathMapping) << ':' << bp.lineNumber << '`'; str << cdbBreakPointFileName(bp, sourcePathMapping) << ':' << bp.lineNumber << '`';
break; break;
case Watchpoint: { // Read/write, no space here case WatchpointAtAddress: { // Read/write, no space here
const unsigned size = bp.size ? bp.size : 1; const unsigned size = bp.size ? bp.size : 1;
str << "r" << size << ' ' << hex << hexPrefixOn << bp.address << hexPrefixOff << dec; str << "r" << size << ' ' << hex << hexPrefixOn << bp.address << hexPrefixOff << dec;
} }

View File

@@ -147,9 +147,10 @@ enum DebuggerCapabilities
ReturnFromFunctionCapability = 0x2000, ReturnFromFunctionCapability = 0x2000,
CreateFullBacktraceCapability = 0x4000, CreateFullBacktraceCapability = 0x4000,
AddWatcherCapability = 0x8000, AddWatcherCapability = 0x8000,
WatchpointCapability = 0x10000, WatchpointByAddressCapability = 0x10000,
ShowModuleSymbolsCapability = 0x20000, WatchpointByExpressionCapability = 0x20000,
CatchCapability = 0x40000, //!< fork, vfork, syscall ShowModuleSymbolsCapability = 0x40000,
CatchCapability = 0x80000, //!< fork, vfork, syscall
AllDebuggerCapabilities = 0xFFFFFFFF AllDebuggerCapabilities = 0xFFFFFFFF
}; };

View File

@@ -1488,7 +1488,27 @@ bool DebuggerEngine::isDying() const
return targetState() == DebuggerFinished; return targetState() == DebuggerFinished;
} }
QString DebuggerEngine::msgWatchpointTriggered(BreakpointId id, QString DebuggerEngine::msgWatchpointByExpressionTriggered(BreakpointId id,
const int number, const QByteArray &expr)
{
return id
? tr("Watchpoint %1 (%2) at %3 %4 triggered.")
.arg(id).arg(number).arg(_(expr))
: tr("Internal watchpoint %1 at %2 %4 triggered.")
.arg(number).arg(_(expr));
}
QString DebuggerEngine::msgWatchpointByExpressionTriggered(BreakpointId id,
const int number, const QByteArray &expr, const QString &threadId)
{
return id
? tr("Watchpoint %1 (%2) at %3 in thread %4 triggered.")
.arg(id).arg(number).arg(_(expr)).arg(threadId)
: tr("Internal watchpoint %1 at %2 in thread %4 triggered.")
.arg(number).arg(_(expr)).arg(threadId);
}
QString DebuggerEngine::msgWatchpointByAddressTriggered(BreakpointId id,
const int number, quint64 address) const int number, quint64 address)
{ {
return id return id
@@ -1498,7 +1518,7 @@ QString DebuggerEngine::msgWatchpointTriggered(BreakpointId id,
.arg(number).arg(address, 0, 16); .arg(number).arg(address, 0, 16);
} }
QString DebuggerEngine::msgWatchpointTriggered(BreakpointId id, QString DebuggerEngine::msgWatchpointByAddressTriggered(BreakpointId id,
const int number, quint64 address, const QString &threadId) const int number, quint64 address, const QString &threadId)
{ {
return id return id

View File

@@ -359,10 +359,14 @@ protected:
DebuggerRunControl *runControl() const; DebuggerRunControl *runControl() const;
static QString msgWatchpointTriggered(BreakpointId id, static QString msgWatchpointByAddressTriggered(BreakpointId id,
int number, quint64 address); int number, quint64 address);
static QString msgWatchpointTriggered(BreakpointId id, static QString msgWatchpointByAddressTriggered(BreakpointId id,
int number, quint64 address, const QString &threadId); int number, quint64 address, const QString &threadId);
static QString msgWatchpointByExpressionTriggered(BreakpointId id,
int number, const QByteArray &expr);
static QString msgWatchpointByExpressionTriggered(BreakpointId id,
int number, const QByteArray &expr, const QString &threadId);
static QString msgBreakpointTriggered(BreakpointId id, static QString msgBreakpointTriggered(BreakpointId id,
int number, const QString &threadId); int number, const QString &threadId);
static QString msgStopped(const QString &reason = QString()); static QString msgStopped(const QString &reason = QString());

View File

@@ -1499,7 +1499,11 @@ void GdbEngine::handleStop1(const GdbMi &data)
const int bpNumber = wpt.findChild("number").data().toInt(); const int bpNumber = wpt.findChild("number").data().toInt();
const BreakpointId id = breakHandler()->findBreakpointByNumber(bpNumber); const BreakpointId id = breakHandler()->findBreakpointByNumber(bpNumber);
const quint64 bpAddress = wpt.findChild("exp").data().mid(1).toULongLong(0, 0); const quint64 bpAddress = wpt.findChild("exp").data().mid(1).toULongLong(0, 0);
QString msg = msgWatchpointTriggered(id, bpNumber, bpAddress); QString msg;
if (id && breakHandler()->type(id) == WatchpointAtExpression)
msg = msgWatchpointByExpressionTriggered(id, bpNumber, breakHandler()->expression(id));
if (id && breakHandler()->type(id) == WatchpointAtAddress)
msg = msgWatchpointByAddressTriggered(id, bpNumber, bpAddress);
GdbMi value = data.findChild("value"); GdbMi value = data.findChild("value");
GdbMi oldValue = value.findChild("old"); GdbMi oldValue = value.findChild("old");
GdbMi newValue = value.findChild("new"); GdbMi newValue = value.findChild("new");
@@ -1882,7 +1886,8 @@ unsigned GdbEngine::debuggerCapabilities() const
| TracePointCapability | TracePointCapability
| ReturnFromFunctionCapability | ReturnFromFunctionCapability
| CreateFullBacktraceCapability | CreateFullBacktraceCapability
| WatchpointCapability | WatchpointByAddressCapability
| WatchpointByExpressionCapability
| AddWatcherCapability | AddWatcherCapability
| ShowModuleSymbolsCapability | ShowModuleSymbolsCapability
| CatchCapability; | CatchCapability;
@@ -2229,7 +2234,7 @@ void GdbEngine::updateBreakpointDataFromOutput(BreakpointId id, const GdbMi &bkp
if (child.data().contains("tracepoint")) if (child.data().contains("tracepoint"))
response.tracepoint = true; response.tracepoint = true;
else if (!child.data().contains("reakpoint")) else if (!child.data().contains("reakpoint"))
response.type = Watchpoint; response.type = WatchpointAtAddress;
} }
// This field is not present. Contents needs to be parsed from // This field is not present. Contents needs to be parsed from
// the plain "ignore" response. // the plain "ignore" response.
@@ -2692,12 +2697,18 @@ void GdbEngine::insertBreakpoint(BreakpointId id)
QTC_ASSERT(handler->state(id) == BreakpointInsertRequested, /**/); QTC_ASSERT(handler->state(id) == BreakpointInsertRequested, /**/);
handler->notifyBreakpointInsertProceeding(id); handler->notifyBreakpointInsertProceeding(id);
BreakpointType type = handler->type(id); BreakpointType type = handler->type(id);
if (type == Watchpoint) { if (type == WatchpointAtAddress) {
postCommand("watch " + addressSpec(handler->address(id)), postCommand("watch " + addressSpec(handler->address(id)),
NeedsStop | RebuildBreakpointModel, NeedsStop | RebuildBreakpointModel,
CB(handleWatchInsert), id); CB(handleWatchInsert), id);
return; return;
} }
if (type == WatchpointAtExpression) {
postCommand("watch " + handler->expression(id),
NeedsStop | RebuildBreakpointModel,
CB(handleWatchInsert), id);
return;
}
if (type == BreakpointAtFork) { if (type == BreakpointAtFork) {
postCommand("catch fork", NeedsStop | RebuildBreakpointModel, postCommand("catch fork", NeedsStop | RebuildBreakpointModel,
CB(handleCatchInsert), id); CB(handleCatchInsert), id);

View File

@@ -742,7 +742,7 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
return QVariant(quint64(0)); return QVariant(quint64(0));
case LocalsIsWatchpointAtAddressRole: { case LocalsIsWatchpointAtAddressRole: {
BreakpointParameters bp(Watchpoint); BreakpointParameters bp(WatchpointAtAddress);
bp.address = data.coreAddress(); bp.address = data.coreAddress();
return engine()->breakHandler()->findWatchpoint(bp) != 0; return engine()->breakHandler()->findWatchpoint(bp) != 0;
} }
@@ -756,7 +756,7 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
case LocalsIsWatchpointAtPointerValueRole: case LocalsIsWatchpointAtPointerValueRole:
if (isPointerType(data.type)) { if (isPointerType(data.type)) {
BreakpointParameters bp(Watchpoint); BreakpointParameters bp(WatchpointAtAddress);
bp.address = pointerValue(data.value); bp.address = pointerValue(data.value);
return engine()->breakHandler()->findWatchpoint(bp) != 0; return engine()->breakHandler()->findWatchpoint(bp) != 0;
} }

View File

@@ -701,7 +701,7 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
QAction *actSetWatchpointAtVariableAddress = 0; QAction *actSetWatchpointAtVariableAddress = 0;
QAction *actSetWatchpointAtPointerValue = 0; QAction *actSetWatchpointAtPointerValue = 0;
const bool canSetWatchpoint = engineCapabilities & WatchpointCapability; const bool canSetWatchpoint = engineCapabilities & WatchpointByAddressCapability;
if (canSetWatchpoint && address) { if (canSetWatchpoint && address) {
actSetWatchpointAtVariableAddress = actSetWatchpointAtVariableAddress =
new QAction(tr("Add Watchpoint at Object's Address (0x%1)") new QAction(tr("Add Watchpoint at Object's Address (0x%1)")
@@ -1015,7 +1015,7 @@ void WatchWindow::setModelData
void WatchWindow::setWatchpoint(quint64 address, unsigned size) void WatchWindow::setWatchpoint(quint64 address, unsigned size)
{ {
BreakpointParameters data(Watchpoint); BreakpointParameters data(WatchpointAtAddress);
data.address = address; data.address = address;
data.size = size; data.size = size;
BreakpointId id = breakHandler()->findWatchpoint(data); BreakpointId id = breakHandler()->findWatchpoint(data);

View File

@@ -2556,6 +2556,10 @@ void testMPI()
} }
enum E {
ONE = 6
};
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int *x = new int(32); int *x = new int(32);