return msgBreakpointAtSpecialFunc("syscall");
case BreakpointAtMain:
return BreakHandler::tr("Breakpoint at Function \"main()\"");
- case Watchpoint:
- return BreakHandler::tr("Watchpoint");
+ case WatchpointAtAddress:
+ return BreakHandler::tr("Watchpoint at Address");
+ case WatchpointAtExpression:
+ return BreakHandler::tr("Watchpoint at Expression");
case UnknownType:
break;
}
//|| data.type == BreakpointAtVFork
|| data.type == BreakpointAtSysCall)
return typeToString(data.type);
- if (data.type == Watchpoint)
+ if (data.type == WatchpointAtAddress)
return tr("Watchpoint at 0x%1").arg(data.address, 0, 16);
return empty;
}
PROPERTY(QByteArray, condition, setCondition)
GETTER(int, lineNumber)
PROPERTY(quint64, address, setAddress)
+PROPERTY(QByteArray, expression, setExpression)
PROPERTY(int, ignoreCount, setIgnoreCount)
bool BreakHandler::isEnabled(BreakpointId id) const
}
}
+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
{
ConstIterator it = m_storage.find(id);
// cursor is near a line with a breakpoint marker (+/- 2 lines or so).
if (data.isTracepoint())
return BreakHandler::tracepointIcon();
- if (data.type == Watchpoint)
+ if (data.type == WatchpointAtAddress)
return BreakHandler::watchpointIcon();
if (!data.enabled)
return BreakHandler::disabledBreakpointIcon();
void setFileName(BreakpointId, const QString &fileName);
QString functionName(BreakpointId id) const;
void setFunctionName(BreakpointId, const QString &functionName);
+ QByteArray expression(BreakpointId id) const;
+ void setExpression(BreakpointId, const QByteArray &expression);
BreakpointType type(BreakpointId id) const;
void setType(BreakpointId id, const BreakpointType &type);
quint64 address(BreakpointId id) const;
void updateLineNumberFromMarker(BreakpointId id, int lineNumber);
void setMarkerFileAndLine(BreakpointId id,
const QString &fileName, int lineNumber);
+ bool isWatchpoint(BreakpointId id) const;
bool isTracepoint(BreakpointId id) const;
void setTracepoint(BreakpointId, bool on);
DebuggerEngine *engine(BreakpointId id) const;
ts << " FunctionName: " << functionName;
break;
case BreakpointByAddress:
- case Watchpoint:
+ case WatchpointAtAddress:
ts << " Address: " << address;
break;
+ case WatchpointAtExpression:
+ ts << " Expression: " << expression;
+ break;
case BreakpointAtThrow:
case BreakpointAtCatch:
case BreakpointAtMain:
BreakpointAtExec,
//BreakpointAtVFork,
BreakpointAtSysCall,
- Watchpoint
+ WatchpointAtAddress,
+ WatchpointAtExpression
};
//! \enum Debugger::Internal::BreakpointState
FileAndLinePart = 0x1,
FunctionPart = 0x2,
AddressPart = 0x4,
- ConditionPart = 0x8,
- IgnoreCountPart = 0x10,
- ThreadSpecPart = 0x20,
+ ExpressionPart = 0x8,
+ ConditionPart = 0x10,
+ IgnoreCountPart = 0x20,
+ ThreadSpecPart = 0x40,
AllConditionParts = ConditionPart|IgnoreCountPart|ThreadSpecPart,
- ModulePart = 0x40,
- TracePointPart = 0x80,
+ ModulePart = 0x80,
+ TracePointPart = 0x100,
- EnabledPart = 0x100,
- TypePart = 0x200,
- PathUsagePart = 0x400,
- CommandPart = 0x400,
+ EnabledPart = 0x200,
+ TypePart = 0x400,
+ PathUsagePart = 0x800,
+ CommandPart = 0x1000,
- AllParts = FileAndLinePart|FunctionPart|AddressPart|ConditionPart
+ AllParts = FileAndLinePart|FunctionPart
+ |ExpressionPart|AddressPart|ConditionPart
|IgnoreCountPart|ThreadSpecPart|ModulePart|TracePointPart
|EnabledPart|TypePart|PathUsagePart|CommandPart
};
BreakpointParts differencesTo(const BreakpointParameters &rhs) const;
bool equals(const BreakpointParameters &rhs) const;
bool conditionsMatch(const QByteArray &other) const;
- bool isWatchpoint() const { return type == Watchpoint; }
+ bool isWatchpoint() const
+ { return type == WatchpointAtAddress || type == WatchpointAtExpression; }
// Enough for now.
- bool isBreakpoint() const { return type != Watchpoint && !tracepoint; }
+ bool isBreakpoint() const { return !isWatchpoint() && !isTracepoint(); }
bool isTracepoint() const { return tracepoint; }
QString toString() const;
QByteArray condition; //!< Condition associated with breakpoint.
int ignoreCount; //!< Ignore count associated with breakpoint.
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 bitpos; //!< Location of watched bitfield within watched area.
uint bitsize; //!< Size of watched bitfield within watched area.
<widget class="QLineEdit" name="lineEditAddress"/>
</item>
<item row="5" column="0">
+ <widget class="QLabel" name="labelExpression">
+ <property name="text">
+ <string>&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">
<property name="text">
<string>Fun&ction:</string>
</property>
</widget>
</item>
- <item row="5" column="1">
+ <item row="6" column="1">
<widget class="QLineEdit" name="lineEditFunction"/>
</item>
</layout>
void typeChanged(int index);
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 clearOtherParts(unsigned partsMask);
void getParts(unsigned partsMask, BreakpointParameters *data) const;
// Match BreakpointType (omitting unknown type).
m_ui.setupUi(this);
QStringList types;
- types << tr("File and Line Number")
- << tr("Function Name")
+ types << tr("File name and line number")
+ << tr("Function name")
<< tr("Address")
- << tr("Break when C++ Exception is Thrown")
- << tr("Break when C++ Exception is Caught")
- << tr("Break when Function \"main()\" Starts")
- << tr("Break when a new Process is Forked")
- << tr("Break when a new Process is Executed")
- << tr("Break when a System Call is Executed")
- << tr("Break on Data Access (Watchpoint)");
- QTC_ASSERT(types.size() == Watchpoint, return; )
+ << tr("Break when C++ exception is thrown")
+ << tr("Break when C++ exception is caught")
+ << tr("Break when function \"main()\" starts")
+ << tr("Break when a new process is forked")
+ << tr("Break when a new process is executed")
+ << tr("Break when a system call is executed")
+ << tr("Break on data access (Watchpoint at address)")
+ << tr("Break on data access (Watchpoint at expression)");
+ QTC_ASSERT(types.size() == WatchpointAtExpression, return; )
m_ui.comboBoxType->addItems(types);
m_ui.pathChooserFileName->setExpectedKind(Utils::PathChooser::File);
connect(m_ui.comboBoxType, SIGNAL(activated(int)), SLOT(typeChanged(int)));
m_ui.labelAddress->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.lineEditCondition->setEnabled(partsMask & ConditionPart);
if (invertedPartsMask & AddressPart)
m_ui.lineEditAddress->clear();
+ if (invertedPartsMask & ExpressionPart)
+ m_ui.lineEditExpression->clear();
if (invertedPartsMask & ConditionPart)
m_ui.lineEditCondition->clear();
if (partsMask & AddressPart)
data->address = m_ui.lineEditAddress->text().toULongLong(0, 0);
+ if (partsMask & ExpressionPart)
+ data->expression = m_ui.lineEditExpression->text().toUtf8();
if (partsMask & ConditionPart)
data->condition = m_ui.lineEditCondition->text().toUtf8();
}
}
+ if (mask & ExpressionPart) {
+ if (!data.expression.isEmpty()) {
+ m_ui.lineEditExpression->setText(data.expression);
+ } else {
+ m_ui.lineEditExpression->clear();
+ }
+ }
+
if (mask & ConditionPart)
m_ui.lineEditCondition->setText(QString::fromUtf8(data.condition));
if (mask & IgnoreCountPart)
case BreakpointAtSysCall:
break;
case BreakpointByAddress:
- case Watchpoint:
+ case WatchpointAtAddress:
getParts(AddressPart|AllConditionParts|TracePointPart, &m_savedParameters);
break;
+ case WatchpointAtExpression:
+ getParts(ExpressionPart|AllConditionParts|TracePointPart, &m_savedParameters);
+ break;
}
// Enable and set up new state from saved values.
setPartsEnabled(0);
break;
case BreakpointByAddress:
- case Watchpoint:
+ case WatchpointAtAddress:
setParts(AddressPart|AllConditionParts|TracePointPart, m_savedParameters);
setPartsEnabled(AddressPart|AllConditionParts|TracePointPart|TracePointPart);
clearOtherParts(AddressPart|AllConditionParts|TracePointPart);
break;
+ case WatchpointAtExpression:
+ setParts(ExpressionPart|AllConditionParts|TracePointPart, m_savedParameters);
+ setPartsEnabled(ExpressionPart|AllConditionParts|TracePointPart|TracePointPart);
+ clearOtherParts(ExpressionPart|AllConditionParts|TracePointPart);
+ break;
}
}
unsigned CdbEngine::debuggerCapabilities() const
{
return DisassemblerCapability | RegisterCapability | ShowMemoryCapability
- |WatchpointCapability|JumpToLineCapability|AddWatcherCapability
+ |WatchpointByAddressCapability|JumpToLineCapability|AddWatcherCapability
|ReloadModuleCapability
|BreakOnThrowAndCatchCapability // Sort-of: Can break on throw().
|BreakConditionCapability|TracePointCapability
id = 0;
}
}
- if (id && breakHandler()->type(id) == Watchpoint) {
- *message = msgWatchpointTriggered(id, number, breakHandler()->address(id), QString::number(threadId));
+ QString tid = 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 {
- *message = msgBreakpointTriggered(id, number, QString::number(threadId));
+ *message = msgBreakpointTriggered(id, number, tid);
}
rc |= StopReportStatusMessage|StopNotifyStop;
return rc;
//case BreakpointAtVFork:
case BreakpointAtSysCall:
return false;
- case Watchpoint:
+ case WatchpointAtAddress:
case BreakpointByFileAndLine:
case BreakpointByFunction:
case BreakpointByAddress:
case BreakpointAtFork:
//case BreakpointAtVFork:
case BreakpointAtSysCall:
- case Watchpoint:
+ case WatchpointAtAddress:
break;
case BreakpointAtExec: { // Emulate by breaking on CreateProcessW().
BreakpointParameters rc(BreakpointByFunction);
// Currently use 'bu' so that the offset expression (including file name)
// is kept when reporting back breakpoints (which is otherwise discarded
// when resolving).
- str << (bp.type == Watchpoint ? "ba" : "bu");
+ str << (bp.type == WatchpointAtAddress ? "ba" : "bu");
if (id != BreakpointId(-1))
str << id;
str << ' ';
str << bp.module << '!';
str << cdbBreakPointFileName(bp, sourcePathMapping) << ':' << bp.lineNumber << '`';
break;
- case Watchpoint: { // Read/write, no space here
+ case WatchpointAtAddress: { // Read/write, no space here
const unsigned size = bp.size ? bp.size : 1;
str << "r" << size << ' ' << hex << hexPrefixOn << bp.address << hexPrefixOff << dec;
}
ReturnFromFunctionCapability = 0x2000,
CreateFullBacktraceCapability = 0x4000,
AddWatcherCapability = 0x8000,
- WatchpointCapability = 0x10000,
- ShowModuleSymbolsCapability = 0x20000,
- CatchCapability = 0x40000, //!< fork, vfork, syscall
+ WatchpointByAddressCapability = 0x10000,
+ WatchpointByExpressionCapability = 0x20000,
+ ShowModuleSymbolsCapability = 0x40000,
+ CatchCapability = 0x80000, //!< fork, vfork, syscall
AllDebuggerCapabilities = 0xFFFFFFFF
};
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)
{
return id
.arg(number).arg(address, 0, 16);
}
-QString DebuggerEngine::msgWatchpointTriggered(BreakpointId id,
+QString DebuggerEngine::msgWatchpointByAddressTriggered(BreakpointId id,
const int number, quint64 address, const QString &threadId)
{
return id
DebuggerRunControl *runControl() const;
- static QString msgWatchpointTriggered(BreakpointId id,
+ static QString msgWatchpointByAddressTriggered(BreakpointId id,
int number, quint64 address);
- static QString msgWatchpointTriggered(BreakpointId id,
+ static QString msgWatchpointByAddressTriggered(BreakpointId id,
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,
int number, const QString &threadId);
static QString msgStopped(const QString &reason = QString());
const int bpNumber = wpt.findChild("number").data().toInt();
const BreakpointId id = breakHandler()->findBreakpointByNumber(bpNumber);
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 oldValue = value.findChild("old");
GdbMi newValue = value.findChild("new");
| TracePointCapability
| ReturnFromFunctionCapability
| CreateFullBacktraceCapability
- | WatchpointCapability
+ | WatchpointByAddressCapability
+ | WatchpointByExpressionCapability
| AddWatcherCapability
| ShowModuleSymbolsCapability
| CatchCapability;
if (child.data().contains("tracepoint"))
response.tracepoint = true;
else if (!child.data().contains("reakpoint"))
- response.type = Watchpoint;
+ response.type = WatchpointAtAddress;
}
// This field is not present. Contents needs to be parsed from
// the plain "ignore" response.
QTC_ASSERT(handler->state(id) == BreakpointInsertRequested, /**/);
handler->notifyBreakpointInsertProceeding(id);
BreakpointType type = handler->type(id);
- if (type == Watchpoint) {
+ if (type == WatchpointAtAddress) {
postCommand("watch " + addressSpec(handler->address(id)),
NeedsStop | RebuildBreakpointModel,
CB(handleWatchInsert), id);
return;
}
+ if (type == WatchpointAtExpression) {
+ postCommand("watch " + handler->expression(id),
+ NeedsStop | RebuildBreakpointModel,
+ CB(handleWatchInsert), id);
+ return;
+ }
if (type == BreakpointAtFork) {
postCommand("catch fork", NeedsStop | RebuildBreakpointModel,
CB(handleCatchInsert), id);
return QVariant(quint64(0));
case LocalsIsWatchpointAtAddressRole: {
- BreakpointParameters bp(Watchpoint);
+ BreakpointParameters bp(WatchpointAtAddress);
bp.address = data.coreAddress();
return engine()->breakHandler()->findWatchpoint(bp) != 0;
}
case LocalsIsWatchpointAtPointerValueRole:
if (isPointerType(data.type)) {
- BreakpointParameters bp(Watchpoint);
+ BreakpointParameters bp(WatchpointAtAddress);
bp.address = pointerValue(data.value);
return engine()->breakHandler()->findWatchpoint(bp) != 0;
}
QAction *actSetWatchpointAtVariableAddress = 0;
QAction *actSetWatchpointAtPointerValue = 0;
- const bool canSetWatchpoint = engineCapabilities & WatchpointCapability;
+ const bool canSetWatchpoint = engineCapabilities & WatchpointByAddressCapability;
if (canSetWatchpoint && address) {
actSetWatchpointAtVariableAddress =
new QAction(tr("Add Watchpoint at Object's Address (0x%1)")
void WatchWindow::setWatchpoint(quint64 address, unsigned size)
{
- BreakpointParameters data(Watchpoint);
+ BreakpointParameters data(WatchpointAtAddress);
data.address = address;
data.size = size;
BreakpointId id = breakHandler()->findWatchpoint(data);
}
+enum E {
+ ONE = 6
+};
+
int main(int argc, char *argv[])
{
int *x = new int(32);