diff options
author | hjk <qtc-committer@nokia.com> | 2010-05-07 15:16:31 +0200 |
---|---|---|
committer | hjk <qtc-committer@nokia.com> | 2010-05-07 15:17:11 +0200 |
commit | 6c0b947ec199d8c2dc701adab272e378c44cac13 (patch) | |
tree | b10acdbdf5a8acf8e3d21b5c20ec4a298f66026e /src | |
parent | 4648a5b3a41ae177fbcc3c2fea2c617dd3357d80 (diff) | |
download | qt-creator-6c0b947ec199d8c2dc701adab272e378c44cac13.tar.gz |
debugger: first shot a implementing data watchpoints
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/debugger/breakhandler.cpp | 93 | ||||
-rw-r--r-- | src/plugins/debugger/breakhandler.h | 80 | ||||
-rw-r--r-- | src/plugins/debugger/breakpoint.h | 123 | ||||
-rw-r--r-- | src/plugins/debugger/breakwindow.cpp | 25 | ||||
-rw-r--r-- | src/plugins/debugger/debugger.pro | 1 | ||||
-rw-r--r-- | src/plugins/debugger/debugger.qrc | 1 | ||||
-rw-r--r-- | src/plugins/debugger/debuggerconstants.h | 3 | ||||
-rw-r--r-- | src/plugins/debugger/debuggermanager.cpp | 13 | ||||
-rw-r--r-- | src/plugins/debugger/debuggermanager.h | 1 | ||||
-rw-r--r-- | src/plugins/debugger/gdb/gdbengine.cpp | 44 | ||||
-rw-r--r-- | src/plugins/debugger/gdb/gdbengine.h | 1 | ||||
-rw-r--r-- | src/plugins/debugger/images/watchpoint.png | bin | 0 -> 593 bytes | |||
-rw-r--r-- | src/plugins/debugger/watchwindow.cpp | 21 |
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 Binary files differnew file mode 100644 index 0000000000..133378a8e7 --- /dev/null +++ b/src/plugins/debugger/images/watchpoint.png 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; |