summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhjk <qtc-committer@nokia.com>2010-05-07 15:16:31 +0200
committerhjk <qtc-committer@nokia.com>2010-05-07 15:17:11 +0200
commit6c0b947ec199d8c2dc701adab272e378c44cac13 (patch)
treeb10acdbdf5a8acf8e3d21b5c20ec4a298f66026e /src
parent4648a5b3a41ae177fbcc3c2fea2c617dd3357d80 (diff)
downloadqt-creator-6c0b947ec199d8c2dc701adab272e378c44cac13.tar.gz
debugger: first shot a implementing data watchpoints
Diffstat (limited to 'src')
-rw-r--r--src/plugins/debugger/breakhandler.cpp93
-rw-r--r--src/plugins/debugger/breakhandler.h80
-rw-r--r--src/plugins/debugger/breakpoint.h123
-rw-r--r--src/plugins/debugger/breakwindow.cpp25
-rw-r--r--src/plugins/debugger/debugger.pro1
-rw-r--r--src/plugins/debugger/debugger.qrc1
-rw-r--r--src/plugins/debugger/debuggerconstants.h3
-rw-r--r--src/plugins/debugger/debuggermanager.cpp13
-rw-r--r--src/plugins/debugger/debuggermanager.h1
-rw-r--r--src/plugins/debugger/gdb/gdbengine.cpp44
-rw-r--r--src/plugins/debugger/gdb/gdbengine.h1
-rw-r--r--src/plugins/debugger/images/watchpoint.pngbin0 -> 593 bytes
-rw-r--r--src/plugins/debugger/watchwindow.cpp21
13 files changed, 269 insertions, 137 deletions
diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp
index c41eb00c86..8db1e38dc1 100644
--- a/src/plugins/debugger/breakhandler.cpp
+++ b/src/plugins/debugger/breakhandler.cpp
@@ -31,6 +31,7 @@
#include "debuggeractions.h"
#include "debuggermanager.h"
+#include "debuggerstringutils.h"
#include "stackframe.h"
#include <texteditor/basetextmark.h>
@@ -53,13 +54,11 @@ using namespace Debugger::Internal;
// Compare file names case insensitively on Windows.
static inline bool fileNameMatch(const QString &f1, const QString &f2)
{
- return f1.compare(f2,
#ifdef Q_OS_WIN
- Qt::CaseInsensitive
+ return f1.compare(f2, Qt::CaseInsensitive) == 0;
#else
- Qt::CaseSensitive
+ return f1 == f2;
#endif
- ) == 0;
}
namespace Debugger {
@@ -87,7 +86,7 @@ public:
QIcon icon() const
{
- const BreakHandler *handler = DebuggerManager::instance()->breakHandler();
+ const BreakHandler *handler = m_data->handler();
if (!m_enabled)
return handler->disabledBreakpointIcon();
return m_pending ? handler->pendingBreakPointIcon() : handler->breakpointIcon();
@@ -162,28 +161,21 @@ private:
//
//////////////////////////////////////////////////////////////////
-BreakpointData::BreakpointData(BreakHandler *handler)
+BreakpointData::BreakpointData()
{
- //qDebug() << "CREATE BREAKPOINTDATA" << this;
- m_handler = handler;
+ m_handler = 0;
enabled = true;
pending = true;
+ type = BreakpointType;
marker = 0;
m_markerLineNumber = 0;
bpMultiple = false;
-//#if defined(Q_OS_MAC)
-// // full names do not work on Mac/MI
useFullPath = false;
-//#else
-// //where = m_manager->shortName(data->fileName);
-// useFullPath = true;
-//#endif
}
BreakpointData::~BreakpointData()
{
removeMarker();
- //qDebug() << "DESTROY BREAKPOINTDATA" << this;
}
void BreakpointData::removeMarker()
@@ -227,8 +219,6 @@ QString BreakpointData::toToolTip() const
<< "</td><td>" << m_markerLineNumber << "</td></tr>"
<< "<tr><td>" << BreakHandler::tr("Breakpoint Number:")
<< "</td><td>" << bpNumber << "</td></tr>"
- << "<tr><td>" << BreakHandler::tr("Breakpoint Address:")
- << "</td><td>" << bpAddress << "</td></tr>"
<< "</table><br><hr><table>"
<< "<tr><th>" << BreakHandler::tr("Property")
<< "</th><th>" << BreakHandler::tr("Requested")
@@ -241,6 +231,8 @@ QString BreakpointData::toToolTip() const
<< "</td><td>" << funcName << "</td><td>" << bpFuncName << "</td></tr>"
<< "<tr><td>" << BreakHandler::tr("Line Number:")
<< "</td><td>" << lineNumber << "</td><td>" << bpLineNumber << "</td></tr>"
+ << "<tr><td>" << BreakHandler::tr("Breakpoint Address:")
+ << "</td><td>" << address << "</td><td>" << bpAddress << "</td></tr>"
<< "<tr><td>" << BreakHandler::tr("Corrected Line Number:")
<< "</td><td>-</td><td>" << bpCorrectedLineNumber << "</td></tr>"
<< "<tr><td>" << BreakHandler::tr("Condition:")
@@ -260,13 +252,14 @@ QString BreakpointData::toString() const
str << BreakHandler::tr("Marker File:") << m_markerFileName << ' '
<< BreakHandler::tr("Marker Line:") << m_markerLineNumber << ' '
<< BreakHandler::tr("Breakpoint Number:") << bpNumber << ' '
- << BreakHandler::tr("Breakpoint Address:") << bpAddress << '\n'
<< BreakHandler::tr("File Name:")
<< fileName << " -- " << bpFileName << '\n'
<< BreakHandler::tr("Function Name:")
<< funcName << " -- " << bpFuncName << '\n'
<< BreakHandler::tr("Line Number:")
<< lineNumber << " -- " << bpLineNumber << '\n'
+ << BreakHandler::tr("Breakpoint Address:")
+ << address << " -- " << bpAddress << '\n'
<< BreakHandler::tr("Condition:")
<< condition << " -- " << bpCondition << '\n'
<< BreakHandler::tr("Ignore Count:")
@@ -310,9 +303,10 @@ bool BreakpointData::conditionsMatch() const
BreakHandler::BreakHandler(DebuggerManager *manager, QObject *parent) :
QAbstractTableModel(parent),
- m_breakpointIcon(QLatin1String(":/debugger/images/breakpoint_16.png")),
- m_disabledBreakpointIcon(QLatin1String(":/debugger/images/breakpoint_disabled_16.png")),
- m_pendingBreakPointIcon(QLatin1String(":/debugger/images/breakpoint_pending_16.png")),
+ m_breakpointIcon(_(":/debugger/images/breakpoint_16.png")),
+ m_disabledBreakpointIcon(_(":/debugger/images/breakpoint_disabled_16.png")),
+ m_pendingBreakPointIcon(_(":/debugger/images/breakpoint_pending_16.png")),
+ m_watchpointIcon(_(":/debugger/images/watchpoint.png")),
m_manager(manager)
{
}
@@ -412,22 +406,29 @@ void BreakHandler::saveBreakpoints()
for (int index = 0; index != size(); ++index) {
const BreakpointData *data = at(index);
QMap<QString, QVariant> map;
+ // Do not persist Watchpoints.
+ //if (data->type == BreakpointData::WatchpointType)
+ // continue;
+ if (data->type != BreakpointData::BreakpointType)
+ map.insert(_("type"), data->type);
if (!data->fileName.isEmpty())
- map.insert(QLatin1String("filename"), data->fileName);
+ map.insert(_("filename"), data->fileName);
if (!data->lineNumber.isEmpty())
- map.insert(QLatin1String("linenumber"), data->lineNumber);
+ map.insert(_("linenumber"), data->lineNumber);
if (!data->funcName.isEmpty())
- map.insert(QLatin1String("funcname"), data->funcName);
+ map.insert(_("funcname"), data->funcName);
+ if (!data->address.isEmpty())
+ map.insert(_("address"), data->address);
if (!data->condition.isEmpty())
- map.insert(QLatin1String("condition"), data->condition);
+ map.insert(_("condition"), data->condition);
if (!data->ignoreCount.isEmpty())
- map.insert(QLatin1String("ignorecount"), data->ignoreCount);
+ map.insert(_("ignorecount"), data->ignoreCount);
if (!data->threadSpec.isEmpty())
- map.insert(QLatin1String("threadspec"), data->threadSpec);
+ map.insert(_("threadspec"), data->threadSpec);
if (!data->enabled)
- map.insert(QLatin1String("disabled"), QLatin1String("1"));
+ map.insert(_("disabled"), _("1"));
if (data->useFullPath)
- map.insert(QLatin1String("usefullpath"), QLatin1String("1"));
+ map.insert(_("usefullpath"), _("1"));
list.append(map);
}
m_manager->setSessionValue("Breakpoints", list);
@@ -440,31 +441,37 @@ void BreakHandler::loadBreakpoints()
clear();
foreach (const QVariant &var, list) {
const QMap<QString, QVariant> map = var.toMap();
- BreakpointData *data = new BreakpointData(this);
- QVariant v = map.value(QLatin1String("filename"));
+ BreakpointData *data = new BreakpointData;
+ QVariant v = map.value(_("filename"));
if (v.isValid())
data->fileName = v.toString();
- v = map.value(QLatin1String("linenumber"));
+ v = map.value(_("linenumber"));
if (v.isValid())
data->lineNumber = v.toString().toLatin1();
- v = map.value(QLatin1String("condition"));
+ v = map.value(_("condition"));
if (v.isValid())
data->condition = v.toString().toLatin1();
- v = map.value(QLatin1String("ignorecount"));
+ v = map.value(_("address"));
+ if (v.isValid())
+ data->address = v.toString().toLatin1();
+ v = map.value(_("ignorecount"));
if (v.isValid())
data->ignoreCount = v.toString().toLatin1();
- v = map.value(QLatin1String("threadspec"));
+ v = map.value(_("threadspec"));
if (v.isValid())
data->threadSpec = v.toString().toLatin1();
- v = map.value(QLatin1String("funcname"));
+ v = map.value(_("funcname"));
if (v.isValid())
data->funcName = v.toString();
- v = map.value(QLatin1String("disabled"));
+ v = map.value(_("disabled"));
if (v.isValid())
data->enabled = !v.toInt();
- v = map.value(QLatin1String("usefullpath"));
+ v = map.value(_("usefullpath"));
if (v.isValid())
data->useFullPath = bool(v.toInt());
+ v = map.value(_("type"));
+ if (v.isValid())
+ data->type = BreakpointData::Type(v.toInt());
data->setMarkerFileName(data->fileName);
data->setMarkerLineNumber(data->lineNumber.toInt());
append(data);
@@ -538,6 +545,8 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
if (role == Qt::UserRole)
return data->enabled;
if (role == Qt::DecorationRole) {
+ if (data->type == BreakpointData::WatchpointType)
+ return m_watchpointIcon;
if (!data->enabled)
return m_disabledBreakpointIcon;
return data->pending ? m_pendingBreakPointIcon : m_breakpointIcon;
@@ -606,8 +615,11 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
if (role == Qt::UserRole + 1)
return data->threadSpec;
case 7:
- if (role == Qt::DisplayRole)
+ if (role == Qt::DisplayRole) {
+ if (data->type == BreakpointData::WatchpointType)
+ return data->address;
return data->bpAddress;
+ }
break;
}
if (role == Qt::ToolTipRole)
@@ -706,6 +718,7 @@ bool BreakHandler::setData(const QModelIndex &mi, const QVariant &value, int rol
void BreakHandler::append(BreakpointData *data)
{
+ data->m_handler = this;
m_bp.append(data);
m_inserted.append(data);
}
@@ -823,7 +836,7 @@ void BreakHandler::breakByFunction(const QString &functionName)
&& data->ignoreCount.isEmpty())
return;
}
- BreakpointData *data = new BreakpointData(this);
+ BreakpointData *data = new BreakpointData;
data->funcName = functionName;
append(data);
saveBreakpoints();
diff --git a/src/plugins/debugger/breakhandler.h b/src/plugins/debugger/breakhandler.h
index ad2c640a30..c773fdd200 100644
--- a/src/plugins/debugger/breakhandler.h
+++ b/src/plugins/debugger/breakhandler.h
@@ -30,90 +30,15 @@
#ifndef DEBUGGER_BREAKHANDLER_H
#define DEBUGGER_BREAKHANDLER_H
+#include "breakpoint.h"
+
#include <QtCore/QObject>
#include <QtCore/QAbstractTableModel>
#include <QtGui/QIcon>
namespace Debugger {
-class DebuggerManager;
namespace Internal {
-class BreakpointMarker;
-class BreakHandler;
-
-//////////////////////////////////////////////////////////////////
-//
-// BreakpointData
-//
-//////////////////////////////////////////////////////////////////
-
-class BreakpointData
-{
-public:
- explicit BreakpointData(BreakHandler *handler);
- ~BreakpointData();
-
- void removeMarker();
- void updateMarker();
- QString toToolTip() const;
- QString toString() const;
- BreakHandler *handler() { return m_handler; }
-
- bool isLocatedAt(const QString &fileName, int lineNumber) const;
- bool conditionsMatch() const;
-
-private:
- // Intentionally unimplemented.
- // Making it copyable is tricky because of the markers.
- void operator=(const BreakpointData &);
- BreakpointData(const BreakpointData &);
-
- // Our owner
- BreakHandler *m_handler; // Not owned.
-
-public:
- bool enabled; // Should we talk to the debugger engine?
- bool pending; // Does the debugger engine know about us already?
-
- // This "user requested information" will get stored in the session.
- QString fileName; // Short name of source file.
- QByteArray condition; // Condition associated with breakpoint.
- QByteArray ignoreCount; // Ignore count associated with breakpoint.
- QByteArray lineNumber; // Line in source file.
- QByteArray threadSpec; // Thread specification.
- QString funcName; // Name of containing function.
- bool useFullPath; // Should we use the full path when setting the bp?
-
- // This is what gdb produced in response.
- QByteArray bpNumber; // Breakpoint number assigned by the debugger engine.
- QByteArray bpCondition; // Condition acknowledged by the debugger engine.
- QByteArray bpIgnoreCount;// Ignore count acknowledged by the debugger engine.
- QString bpFileName; // File name acknowledged by the debugger engine.
- QString bpFullName; // Full file name acknowledged by the debugger engine.
- QByteArray bpLineNumber; // Line number acknowledged by the debugger engine.
- QByteArray bpCorrectedLineNumber; // Acknowledged by the debugger engine.
- QByteArray bpThreadSpec; // Thread spec acknowledged by the debugger engine.
- QString bpFuncName; // Function name acknowledged by the debugger engine.
- QByteArray bpAddress; // Address acknowledged by the debugger engine.
- bool bpMultiple; // Happens in constructors/gdb.
- bool bpEnabled; // Enable/disable command sent.
-
- void setMarkerFileName(const QString &fileName);
- QString markerFileName() const { return m_markerFileName; }
-
- void setMarkerLineNumber(int lineNumber);
- int markerLineNumber() const { return m_markerLineNumber; }
-
-private:
- // Taken from either user input or gdb responses.
- QString m_markerFileName; // Used to locate the marker.
- int m_markerLineNumber;
-
- // Our red blob in the editor.
- BreakpointMarker *marker;
-};
-
-
//////////////////////////////////////////////////////////////////
//
// BreakHandler
@@ -184,6 +109,7 @@ private:
const QIcon m_breakpointIcon;
const QIcon m_disabledBreakpointIcon;
const QIcon m_pendingBreakPointIcon;
+ const QIcon m_watchpointIcon;
DebuggerManager *m_manager; // Not owned.
QList<BreakpointData *> m_bp;
diff --git a/src/plugins/debugger/breakpoint.h b/src/plugins/debugger/breakpoint.h
new file mode 100644
index 0000000000..5a9eef7a92
--- /dev/null
+++ b/src/plugins/debugger/breakpoint.h
@@ -0,0 +1,123 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DEBUGGER_BREAKPOINT_H
+#define DEBUGGER_BREAKPOINT_H
+
+#include <QtCore/QString>
+
+namespace Debugger {
+class DebuggerManager;
+namespace Internal {
+
+class BreakpointMarker;
+class BreakHandler;
+
+//////////////////////////////////////////////////////////////////
+//
+// BreakpointData
+//
+//////////////////////////////////////////////////////////////////
+
+class BreakpointData
+{
+public:
+ BreakpointData();
+ ~BreakpointData();
+
+ void removeMarker();
+ void updateMarker();
+ QString toToolTip() const;
+ QString toString() const;
+ BreakHandler *handler() { return m_handler; }
+
+ bool isLocatedAt(const QString &fileName, int lineNumber) const;
+ bool conditionsMatch() const;
+
+private:
+ // Intentionally unimplemented.
+ // Making it copyable is tricky because of the markers.
+ void operator=(const BreakpointData &);
+ BreakpointData(const BreakpointData &);
+
+ // Our owner
+ BreakHandler *m_handler; // Not owned.
+ friend class BreakHandler;
+
+public:
+ enum Type { BreakpointType, WatchpointType };
+
+ bool enabled; // Should we talk to the debugger engine?
+ bool pending; // Does the debugger engine know about us already?
+ Type type; // Type of breakpoint.
+
+ // This "user requested information" will get stored in the session.
+ QString fileName; // Short name of source file.
+ QByteArray condition; // Condition associated with breakpoint.
+ QByteArray ignoreCount; // Ignore count associated with breakpoint.
+ QByteArray lineNumber; // Line in source file.
+ QByteArray address; // Address for watchpoints.
+ QByteArray threadSpec; // Thread specification.
+ QString funcName; // Name of containing function.
+ bool useFullPath; // Should we use the full path when setting the bp?
+
+ // This is what gdb produced in response.
+ QByteArray bpNumber; // Breakpoint number assigned by the debugger engine.
+ QByteArray bpCondition; // Condition acknowledged by the debugger engine.
+ QByteArray bpIgnoreCount;// Ignore count acknowledged by the debugger engine.
+ QString bpFileName; // File name acknowledged by the debugger engine.
+ QString bpFullName; // Full file name acknowledged by the debugger engine.
+ QByteArray bpLineNumber; // Line number acknowledged by the debugger engine.
+ QByteArray bpCorrectedLineNumber; // Acknowledged by the debugger engine.
+ QByteArray bpThreadSpec; // Thread spec acknowledged by the debugger engine.
+ QString bpFuncName; // Function name acknowledged by the debugger engine.
+ QByteArray bpAddress; // Address acknowledged by the debugger engine.
+ bool bpMultiple; // Happens in constructors/gdb.
+ bool bpEnabled; // Enable/disable command sent.
+
+ void setMarkerFileName(const QString &fileName);
+ QString markerFileName() const { return m_markerFileName; }
+
+ void setMarkerLineNumber(int lineNumber);
+ int markerLineNumber() const { return m_markerLineNumber; }
+
+private:
+ // Taken from either user input or gdb responses.
+ QString m_markerFileName; // Used to locate the marker.
+ int m_markerLineNumber;
+
+ // Our red blob in the editor.
+ BreakpointMarker *marker;
+};
+
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_BREAKPOINT_H
diff --git a/src/plugins/debugger/breakwindow.cpp b/src/plugins/debugger/breakwindow.cpp
index f26b23ac8b..c92f33ac00 100644
--- a/src/plugins/debugger/breakwindow.cpp
+++ b/src/plugins/debugger/breakwindow.cpp
@@ -355,29 +355,30 @@ void BreakWindow::editBreakpoint(const QModelIndexList &list)
ui.labelFileName->hide();
ui.lineEditLineNumber->hide();
ui.labelLineNumber->hide();
+ QAbstractItemModel *m = model();
//ui.lineEditFunction->setText(
- // model()->data(idx.sibling(row, 1), role).toString());
+ // m->data(idx.sibling(row, 1), role).toString());
//ui.lineEditFileName->setText(
- // model()->data(idx.sibling(row, 2), role).toString());
+ // m->data(idx.sibling(row, 2), role).toString());
//ui.lineEditLineNumber->setText(
- // model()->data(idx.sibling(row, 3), role).toString());
+ // m->data(idx.sibling(row, 3), role).toString());
ui.lineEditCondition->setText(
- model()->data(idx.sibling(row, 4), role).toString());
+ m->data(idx.sibling(row, 4), role).toString());
ui.lineEditIgnoreCount->setText(
- model()->data(idx.sibling(row, 5), role).toString());
+ m->data(idx.sibling(row, 5), role).toString());
ui.lineEditThreadSpec->setText(
- model()->data(idx.sibling(row, 6), role).toString());
+ m->data(idx.sibling(row, 6), role).toString());
if (dlg.exec() == QDialog::Rejected)
return;
foreach (const QModelIndex &idx, list) {
- //model()->setData(idx.sibling(idx.row(), 1), ui.lineEditFunction->text());
- //model()->setData(idx.sibling(idx.row(), 2), ui.lineEditFileName->text());
- //model()->setData(idx.sibling(idx.row(), 3), ui.lineEditLineNumber->text());
- model()->setData(idx.sibling(idx.row(), 4), ui.lineEditCondition->text());
- model()->setData(idx.sibling(idx.row(), 5), ui.lineEditIgnoreCount->text());
- model()->setData(idx.sibling(idx.row(), 6), ui.lineEditThreadSpec->text());
+ //m->setData(idx.sibling(idx.row(), 1), ui.lineEditFunction->text());
+ //m->setData(idx.sibling(idx.row(), 2), ui.lineEditFileName->text());
+ //m->setData(idx.sibling(idx.row(), 3), ui.lineEditLineNumber->text());
+ m->setData(idx.sibling(idx.row(), 4), ui.lineEditCondition->text());
+ m->setData(idx.sibling(idx.row(), 5), ui.lineEditIgnoreCount->text());
+ m->setData(idx.sibling(idx.row(), 6), ui.lineEditThreadSpec->text());
}
emit breakpointSynchronizationRequested();
}
diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro
index 666019ae24..93eec280b6 100644
--- a/src/plugins/debugger/debugger.pro
+++ b/src/plugins/debugger/debugger.pro
@@ -16,6 +16,7 @@ QT += gui \
script
HEADERS += breakhandler.h \
breakwindow.h \
+ breakpoint.h \
debuggeragents.h \
debuggeractions.h \
debuggerconstants.h \
diff --git a/src/plugins/debugger/debugger.qrc b/src/plugins/debugger/debugger.qrc
index a542bdfce2..7688ef39a4 100644
--- a/src/plugins/debugger/debugger.qrc
+++ b/src/plugins/debugger/debugger.qrc
@@ -18,6 +18,7 @@
<file>images/debugger_stepoverproc_small.png</file>
<file>images/debugger_stop.png</file>
<file>images/debugger_stop_small.png</file>
+ <file>images/watchpoint.png</file>
<file>images/breakpoint_16.png</file>
<file>images/breakpoint_24.png</file>
<file>images/breakpoint_disabled_16.png</file>
diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h
index 1aada273ac..020f94f9d0 100644
--- a/src/plugins/debugger/debuggerconstants.h
+++ b/src/plugins/debugger/debuggerconstants.h
@@ -132,7 +132,8 @@ enum DebuggerCapabilities
BreakOnThrowAndCatchCapability = 0x200,
ReturnFromFunctionCapability = 0x400,
CreateFullBacktraceCapability = 0x800,
- AddWatcherCapability = 0x1000
+ AddWatcherCapability = 0x1000,
+ WatchpointCapability = 0x2000
};
enum LogChannel
diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
index 100423734c..a2c6b4e7f1 100644
--- a/src/plugins/debugger/debuggermanager.cpp
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -897,9 +897,9 @@ BreakpointData *DebuggerManager::findBreakpoint(const QString &fileName, int lin
// FIXME: move further up the plugin where there's more specific context
// information available.
static BreakpointData *createBreakpointByFileAndLine
- (const QString &fileName, int lineNumber, BreakHandler *handler)
+ (const QString &fileName, int lineNumber)
{
- BreakpointData *data = new BreakpointData(handler);
+ BreakpointData *data = new BreakpointData;
if (lineNumber > 0) {
data->fileName = fileName;
data->lineNumber = QByteArray::number(lineNumber);
@@ -934,7 +934,7 @@ void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber)
int index = d->m_breakHandler->findBreakpoint(fileName, lineNumber);
if (index == -1)
d->m_breakHandler->appendBreakpoint(
- createBreakpointByFileAndLine(fileName, lineNumber, d->m_breakHandler));
+ createBreakpointByFileAndLine(fileName, lineNumber));
else
d->m_breakHandler->removeBreakpoint(index);
@@ -1410,6 +1410,13 @@ void DebuggerManager::breakByFunction(const QString &functionName)
attemptBreakpointSynchronization();
}
+void DebuggerManager::appendBreakpoint(BreakpointData *data)
+{
+ QTC_ASSERT(d->m_breakHandler, return);
+ d->m_breakHandler->appendBreakpoint(data);
+ attemptBreakpointSynchronization();
+}
+
void DebuggerManager::setBusyCursor(bool busy)
{
//STATE_DEBUG("BUSY FROM: " << d->m_busy << " TO: " << d->m_busy);
diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h
index 19991c84ed..8b15b6487f 100644
--- a/src/plugins/debugger/debuggermanager.h
+++ b/src/plugins/debugger/debuggermanager.h
@@ -289,6 +289,7 @@ public slots: // FIXME
void reloadRegisters();
void registerDockToggled(bool on);
void clearStatusMessage();
+ void appendBreakpoint(Internal::BreakpointData *data);
void attemptBreakpointSynchronization();
void reloadFullStack();
void operateByInstructionTriggered();
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index d42f5e93a4..1f08b61605 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -1394,7 +1394,19 @@ void GdbEngine::handleStop1(const GdbMi &data)
reloadBreakListInternal();
}
- if (reason == "breakpoint-hit") {
+ if (reason == "watchpoint-trigger") {
+ // *stopped,reason="watchpoint-trigger",wpt={number="2",exp="*0xbfffed40"},
+ // value={old="1",new="0"},frame={addr="0x00451e1b",
+ // func="QScopedPointer",args=[{name="this",value="0xbfffed40"},
+ // {name="p",value="0x0"}],file="x.h",fullname="/home/.../x.h",line="95"},
+ // thread-id="1",stopped-threads="all",core="2"
+ GdbMi wpt = data.findChild("wpt");
+ QByteArray bpNumber = wpt.findChild("number").data();
+ QByteArray bpAddress = wpt.findChild("exp").data();
+ //QByteArray threadId = data.findChild("thread-id").data();
+ showStatusMessage(tr("Watchpoint %1 at %2 triggered:")
+ .arg(_(bpNumber), _(bpAddress)));
+ } else if (reason == "breakpoint-hit") {
QByteArray bpNumber = data.findChild("bkptno").data();
QByteArray threadId = data.findChild("thread-id").data();
showStatusMessage(tr("Stopped at breakpoint %1 in thread %2")
@@ -1825,6 +1837,7 @@ unsigned GdbEngine::debuggerCapabilities() const
| ReloadModuleSymbolsCapability | BreakOnThrowAndCatchCapability
| ReturnFromFunctionCapability
| CreateFullBacktraceCapability
+ | WatchpointCapability
| AddWatcherCapability;
}
@@ -2174,6 +2187,13 @@ void GdbEngine::sendInsertBreakpoint(int index)
const BreakpointData *data = manager()->breakHandler()->at(index);
// Set up fallback in case of pending breakpoints which aren't handled
// by the MI interface.
+ if (data->type == BreakpointData::WatchpointType) {
+ postCommand("watch *" + data->address,
+ NeedsStop | RebuildBreakpointModel,
+ CB(handleWatchInsert), index);
+ return;
+ }
+
QByteArray cmd;
if (m_isMacGdb) {
cmd = "-break-insert -l -1 -f ";
@@ -2197,6 +2217,23 @@ void GdbEngine::sendInsertBreakpoint(int index)
CB(handleBreakInsert1), index);
}
+void GdbEngine::handleWatchInsert(const GdbResponse &response)
+{
+ int index = response.cookie.toInt();
+ if (response.resultClass == GdbResultDone) {
+ // "Hardware watchpoint 2: *0xbfffed40\n"
+ QByteArray ba = response.data.findChild("consolestreamoutput").data();
+ if (ba.startsWith("Hardware watchpoint ")) {
+ const int pos = ba.indexOf(':', 20);
+ BreakpointData *data = manager()->breakHandler()->at(index);
+ data->bpNumber = ba.mid(20, pos - 20);
+ manager()->breakHandler()->updateMarkers();
+ } else {
+ debugMessage(_("CANNOT PARSE WATCHPOINT FROM" + ba));
+ }
+ }
+}
+
void GdbEngine::handleBreakInsert1(const GdbResponse &response)
{
int index = response.cookie.toInt();
@@ -2275,7 +2312,7 @@ void GdbEngine::handleBreakList(const GdbMi &table)
BreakHandler *handler = manager()->breakHandler();
for (int index = 0; index != bkpts.size(); ++index) {
- BreakpointData temp(handler);
+ BreakpointData temp;
breakpointDataFromOutput(&temp, bkpts.at(index));
int found = handler->findBreakpoint(temp);
if (found != -1)
@@ -2444,7 +2481,7 @@ void GdbEngine::attemptBreakpointSynchronization()
{
QTC_ASSERT(!m_sourcesListUpdating,
qDebug() << "SOURCES LIST CURRENTLY UPDATING"; return);
- debugMessage(tr("ATTEMPT BREAKPOINT SYNC"));
+ debugMessage(_("ATTEMPT BREAKPOINT SYNC"));
switch (state()) {
case InferiorStarting:
@@ -2455,6 +2492,7 @@ void GdbEngine::attemptBreakpointSynchronization()
break;
default:
//qDebug() << "attempted breakpoint sync in state" << state();
+ debugMessage(_("... NOT POSSIBLE IN CURRENT STATE"));
return;
}
diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h
index 45b48fce6a..553d2833c5 100644
--- a/src/plugins/debugger/gdb/gdbengine.h
+++ b/src/plugins/debugger/gdb/gdbengine.h
@@ -344,6 +344,7 @@ private: ////////// View & Data Stuff //////////
void handleBreakInsert2(const GdbResponse &response);
void handleBreakCondition(const GdbResponse &response);
void handleBreakInfo(const GdbResponse &response);
+ void handleWatchInsert(const GdbResponse &response);
void handleInfoLine(const GdbResponse &response);
void extractDataFromInfoBreak(const QString &output, BreakpointData *data);
void breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt);
diff --git a/src/plugins/debugger/images/watchpoint.png b/src/plugins/debugger/images/watchpoint.png
new file mode 100644
index 0000000000..133378a8e7
--- /dev/null
+++ b/src/plugins/debugger/images/watchpoint.png
Binary files differ
diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp
index af071542d1..e2e4e21e3a 100644
--- a/src/plugins/debugger/watchwindow.cpp
+++ b/src/plugins/debugger/watchwindow.cpp
@@ -30,6 +30,7 @@
#include "watchwindow.h"
#include "watchhandler.h"
+#include "breakpoint.h"
#include "debuggeractions.h"
#include "debuggeragents.h"
#include "debuggerdialogs.h"
@@ -284,7 +285,8 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
const QString address = model()->data(mi0, AddressRole).toString();
QAction *actWatchKnownMemory = 0;
- QAction *actWatchUnknownMemory = new QAction(tr("Open Memory Editor..."), &menu);
+ QAction *actWatchUnknownMemory =
+ new QAction(tr("Open Memory Editor..."), &menu);
const bool canShowMemory = engineCapabilities & ShowMemoryCapability;
actWatchUnknownMemory->setEnabled(actionsEnabled && canShowMemory);
@@ -293,6 +295,17 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
new QAction(tr("Open Memory Editor at %1").arg(address), &menu);
menu.addSeparator();
+ QAction *actSetWatchpoint = 0;
+ const bool canSetWatchpoint = engineCapabilities & WatchpointCapability;
+ if (canSetWatchpoint && !address.isEmpty()) {
+ actSetWatchpoint =
+ new QAction(tr("Break on changing %1").arg(address), &menu);
+ } else {
+ actSetWatchpoint =
+ new QAction(tr("Break on changing contents"), &menu);
+ actSetWatchpoint->setEnabled(false);
+ }
+
QAction *actWatchOrRemove;
if (m_type == LocalsType) {
actWatchOrRemove = theDebuggerAction(WatchExpression)->updatedAction(exp);
@@ -311,6 +324,7 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
if (actWatchKnownMemory)
menu.addAction(actWatchKnownMemory);
menu.addAction(actWatchUnknownMemory);
+ menu.addAction(actSetWatchpoint);
menu.addSeparator();
menu.addAction(theDebuggerAction(RecheckDebuggingHelpers));
@@ -353,6 +367,11 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
if (dialog.exec() == QDialog::Accepted) {
(void) new MemoryViewAgent(m_manager, dialog.address());
}
+ } else if (act == actSetWatchpoint) {
+ BreakpointData *data = new BreakpointData;
+ data->type = BreakpointData::WatchpointType;
+ data->address = address.toLatin1();
+ m_manager->appendBreakpoint(data);
} else if (act == actSelectWidgetToWatch) {
grabMouse(Qt::CrossCursor);
m_grabbing = true;