#include <utils/qtcassert.h>
+#if USE_BREAK_MODEL_TEST
+#include "modeltest.h"
+#endif
+
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QTimerEvent>
BreakHandler::BreakHandler()
: m_syncTimerId(-1)
-{}
+{
+#if USE_BREAK_MODEL_TEST
+ new ModelTest(this, 0);
+#endif
+}
BreakHandler::~BreakHandler()
{}
return icon;
}
-int BreakHandler::columnCount(const QModelIndex &parent) const
-{
- return parent.isValid() ? 0 : 8;
-}
-
-int BreakHandler::rowCount(const QModelIndex &parent) const
-{
- return parent.isValid() ? 0 : m_storage.size();
-}
-
static inline bool fileNameMatch(const QString &f1, const QString &f2)
{
#ifdef Q_OS_WIN
BreakpointId BreakHandler::findBreakpointByIndex(const QModelIndex &index) const
{
- int r = index.row();
- ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
- for (int i = 0; it != et; ++it, ++i)
- if (i == r)
- return it.key();
- return BreakpointId();
+ //qDebug() << "FIND: " << index <<
+ // BreakpointId::fromInternalId(index.internalId());
+ return BreakpointId::fromInternalId(index.internalId());
}
BreakpointIds BreakHandler::findBreakpointsByIndex(const QList<QModelIndex> &list) const
return ok ? result : -1;
}
-QModelIndex BreakHandler::index(int row, int col, const QModelIndex &parent) const
+QModelIndex BreakHandler::createIndex(int row, int column, quint32 id) const
{
- Q_UNUSED(parent);
- return createIndex(row, col, 0);
+ return QAbstractItemModel::createIndex(row, column, id);
}
-QModelIndex BreakHandler::parent(const QModelIndex &parent) const
+QModelIndex BreakHandler::createIndex(int row, int column, void *ptr) const
{
- Q_UNUSED(parent);
+ QTC_ASSERT(false, /**/); // This function is not used.
+ return QAbstractItemModel::createIndex(row, column, ptr);
+}
+
+int BreakHandler::columnCount(const QModelIndex &idx) const
+{
+ if (idx.column() > 0)
+ return 0;
+ const BreakpointId id = findBreakpointByIndex(idx);
+ return id.isMinor() ? 0 : 8;
+}
+
+int BreakHandler::rowCount(const QModelIndex &idx) const
+{
+ if (idx.column() > 0)
+ return 0;
+ if (!idx.isValid())
+ return m_storage.size();
+ const BreakpointId id = findBreakpointByIndex(idx);
+ if (id.isMajor())
+ return m_storage.value(id).subItems.size();
+ return 0;
+}
+
+QModelIndex BreakHandler::index(int row, int col, const QModelIndex &parent) const
+{
+ if (row < 0 || col < 0)
+ return QModelIndex();
+ if (parent.column() > 0)
+ return QModelIndex();
+ BreakpointId id = findBreakpointByIndex(parent);
+ if (id.isMajor()) {
+ ConstIterator it = m_storage.find(id);
+ if (row >= it->subItems.size())
+ return QModelIndex();
+ BreakpointId sub = id.child(row);
+ return createIndex(row, col, sub.toInternalId());
+ }
+ if (id.isMinor())
+ return QModelIndex();
+ QTC_ASSERT(!id.isValid(), return QModelIndex());
+ if (row >= m_storage.size())
+ return QModelIndex();
+ id = at(row);
+ return createIndex(row, col, id.toInternalId());
+}
+
+QModelIndex BreakHandler::parent(const QModelIndex &idx) const
+{
+ if (!idx.isValid())
+ return QModelIndex();
+ BreakpointId id = findBreakpointByIndex(idx);
+ if (id.isMajor())
+ return QModelIndex();
+ if (id.isMinor()) {
+ BreakpointId pid = id.parent();
+ int row = indexOf(pid);
+ return createIndex(row, 0, pid.toInternalId());
+ }
return QModelIndex();
}
return QVariant();
BreakpointId id = findBreakpointByIndex(mi);
- //qDebug() << "DATA: " << id << role << mi.column();
- ConstIterator it = m_storage.find(id);
- BREAK_ASSERT(it != m_storage.end(), return QVariant());
+
+ BreakpointId pid = id;
+ if (id.isMinor())
+ pid = id.parent();
+
+ ConstIterator it = m_storage.find(pid);
+ QTC_ASSERT(it != m_storage.end(), return QVariant());
const BreakpointParameters &data = it->data;
const BreakpointResponse &response = it->response;
break;
};
+ if (id.isMinor()) {
+ QTC_ASSERT(id.minorPart() <= it->subItems.size(), return QVariant());
+ const BreakpointResponse &res = it->subItems.at(id.minorPart() - 1);
+ switch (mi.column()) {
+ case 0:
+ if (role == Qt::DisplayRole)
+ return id.toString();
+ case 1:
+ if (role == Qt::DisplayRole)
+ return res.functionName;
+ }
+ return QVariant();
+ }
+
switch (mi.column()) {
case 0:
if (role == Qt::DisplayRole) {
- return QString::number(id);
+ return id.toString();
//return QString("%1 - %2").arg(id).arg(response.number);
}
if (role == Qt::DecorationRole)
it->state = BreakpointNew;
it->engine = 0;
it->response = BreakpointResponse();
+ it->subItems.clear();
delete it->marker;
it->marker = 0;
if (it->data.type == WatchpointAtAddress
cleanupBreakpoint(id);
break;
default:
- qWarning("Warning: Cannot remove breakpoint %llu in state '%s'.",
- id, qPrintable(stateToString(it->state)));
+ qWarning("Warning: Cannot remove breakpoint %s in state '%s'.",
+ qPrintable(id.toString()), qPrintable(stateToString(it->state)));
it->state = BreakpointRemoveRequested;
break;
}
m_storage.insert(id, item);
endInsertRows();
+ layoutChanged();
+
updateMarker(id);
scheduleSynchronization();
+}
+BreakpointId BreakHandler::at(int n) const
+{
+ if (n < 0 || n >= m_storage.size())
+ return BreakpointId();
+ ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
+ for ( ; --n >= 0; ++it)
+ ;
+ return it.key();
+}
+
+int BreakHandler::indexOf(BreakpointId id) const
+{
+ int row = 0;
+ ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
+ for ( ; it != et; ++it, ++row)
+ if (it.key() == id)
+ return row;
+ return -1;
+}
+
+void BreakHandler::appendSubBreakpoint(BreakpointId id, const BreakpointResponse &data)
+{
+ Iterator it = m_storage.find(id);
+ QTC_ASSERT(it != m_storage.end(), return);
+ int row = indexOf(id);
+ QTC_ASSERT(row != -1, return);
+ QModelIndex idx = createIndex(row, 0, id.toInternalId());
+ beginInsertRows(idx, it->subItems.size(), it->subItems.size());
+ it->subItems.append(data);
+ endInsertRows();
}
void BreakHandler::saveSessionData()
// The only way to add a new breakpoint.
void appendBreakpoint(const BreakpointParameters &data);
+ void appendSubBreakpoint(BreakpointId id, const BreakpointResponse &data);
BreakpointIds allBreakpointIds() const;
BreakpointIds engineBreakpointIds(DebuggerEngine *engine) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
QModelIndex index(int row, int col, const QModelIndex &parent) const;
QModelIndex parent(const QModelIndex &parent) const;
+ QModelIndex createIndex(int row, int column, quint32 id) const;
+ QModelIndex createIndex(int row, int column, void *ptr) const;
+ int indexOf(BreakpointId id) const;
+ BreakpointId at(int index) const;
bool isEngineRunning(BreakpointId id) const;
void setState(BreakpointId id, BreakpointState state);
void loadBreakpoints();
DebuggerEngine *engine; // Engine currently handling the breakpoint.
BreakpointResponse response;
BreakpointMarker *marker;
+ QList<BreakpointResponse> subItems;
};
typedef QHash<BreakpointId, BreakpointItem> BreakpointStorage;
typedef BreakpointStorage::ConstIterator ConstIterator;
#include "breakpoint.h"
+#include "utils/qtcassert.h"
+
#include <QtCore/QByteArray>
#include <QtCore/QDebug>
//////////////////////////////////////////////////////////////////
//
+// BreakpointId
+//
+//////////////////////////////////////////////////////////////////
+
+QDebug operator<<(QDebug d, const BreakpointId &id)
+{
+ d << qPrintable(id.toString());
+ return d;
+}
+
+QString BreakpointId::toString() const
+{
+ if (!isValid())
+ return "<invalid bkpt>";
+ if (isMinor())
+ return QString("%1.%2").arg(m_majorPart).arg(m_minorPart);
+ return QString::number(m_majorPart);
+}
+
+BreakpointId BreakpointId::parent() const
+{
+ QTC_ASSERT(isMinor(), return BreakpointId());
+ return BreakpointId(m_majorPart, 0);
+}
+
+BreakpointId BreakpointId::child(int row) const
+{
+ QTC_ASSERT(isMajor(), return BreakpointId());
+ return BreakpointId(m_majorPart, row + 1);
+}
+
+//////////////////////////////////////////////////////////////////
+//
// BreakpointParameters
//
//////////////////////////////////////////////////////////////////
*/
BreakpointResponse::BreakpointResponse()
- : number(0), pending(true), multiple(false), correctedLineNumber(0)
-{}
+{
+ number = 0;
+ subNumber = 0;
+ pending = true;
+ multiple = false;
+ correctedLineNumber = 0;
+}
QString BreakpointResponse::toString() const
{
QString result = BreakpointParameters::toString();
QTextStream ts(&result);
ts << " Number: " << number;
+ if (subNumber)
+ ts << "." << subNumber;
if (pending)
ts << " [pending]";
if (!fullName.isEmpty())
ts << " FullName: " << fullName;
+ if (!functionName.isEmpty())
+ ts << " Function: " << functionName;
if (multiple)
ts << " Multiple: " << multiple;
if (!extra.isEmpty())
ts << " Extra: " << extra;
if (correctedLineNumber)
ts << " CorrectedLineNumber: " << correctedLineNumber;
+ ts << ' ';
return result + BreakpointParameters::toString();
}
{
BreakpointParameters::operator=(p);
number = 0;
+ subNumber = 0;
fullName.clear();
multiple = false;
extra.clear();
#ifndef DEBUGGER_BREAKPOINT_H
#define DEBUGGER_BREAKPOINT_H
+#include <QtCore/QDebug>
#include <QtCore/QList>
#include <QtCore/QMetaType>
#include <QtCore/QString>
namespace Debugger {
namespace Internal {
-typedef quint64 BreakpointId;
+class BreakpointId
+{
+public:
+ BreakpointId() { m_majorPart = m_minorPart = 0; }
+ explicit BreakpointId(quint16 ma) { m_majorPart = ma; m_minorPart = 0; }
+ BreakpointId(quint16 ma, quint16 mi) { m_majorPart = ma; m_minorPart = mi; }
+
+ bool isValid() const { return m_majorPart != 0; }
+ bool isMajor() const { return m_majorPart != 0 && m_minorPart == 0; }
+ bool isMinor() const { return m_majorPart != 0 && m_minorPart != 0; }
+ bool operator!() const { return !isValid(); }
+ operator const void*() const { return isValid() ? this : 0; }
+ quint32 toInternalId() const { return m_majorPart | (m_minorPart << 16); }
+ QString toString() const;
+ bool operator==(const BreakpointId &id) const
+ { return m_majorPart == id.m_majorPart && m_minorPart == id.m_minorPart; }
+ quint16 majorPart() const { return m_majorPart; }
+ quint16 minorPart() const { return m_minorPart; }
+ BreakpointId parent() const;
+ BreakpointId child(int row) const;
+
+ static BreakpointId fromInternalId(quint32 id)
+ { return BreakpointId(id & 0xff, id >> 16); }
+
+private:
+ quint16 m_majorPart;
+ quint16 m_minorPart;
+};
+
+QDebug operator<<(QDebug d, const BreakpointId &id);
//////////////////////////////////////////////////////////////////
//
void fromParameters(const BreakpointParameters &p);
int number; //!< Breakpoint number assigned by the debugger engine.
+ int subNumber; //!< Breakpoint sub-number assigned by the engine.
bool pending; //!< Breakpoint not fully resolved.
QString fullName; //!< Full file name acknowledged by the debugger engine.
bool multiple; //!< Happens in constructors/gdb.
typedef QList<BreakpointId> BreakpointIds;
+inline uint qHash(const Debugger::Internal::BreakpointId &id)
+{
+ return id.toInternalId();
+}
+
} // namespace Internal
} // namespace Debugger
+Q_DECLARE_METATYPE(Debugger::Internal::BreakpointId)
+
+
#endif // DEBUGGER_BREAKPOINT_H
resizeColumnToContents(0); // Number
resizeColumnToContents(3); // Line
resizeColumnToContents(6); // Ignore count
+ connect(model, SIGNAL(layoutChanged()), this, SLOT(expandAll()));
}
void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
struct ConditionalBreakPointCookie
{
- ConditionalBreakPointCookie(BreakpointId i = 0) : id(i) {}
+ ConditionalBreakPointCookie(BreakpointId i = BreakpointId()) : id(i) {}
BreakpointId id;
GdbMi stopReason;
};
const QString &threadId)
{
return CdbEngine::tr("Trace point %1 (%2) in thread %3 triggered.")
- .arg(id).arg(number).arg(threadId);
+ .arg(id.toString()).arg(number).arg(threadId);
}
static inline QString msgCheckingConditionalBreakPoint(BreakpointId id, const int number,
const QString &threadId)
{
return CdbEngine::tr("Conditional breakpoint %1 (%2) in thread %3 triggered, examining expression '%4'.")
- .arg(id).arg(number).arg(threadId, QString::fromAscii(condition));
+ .arg(id.toString()).arg(number).arg(threadId, QString::fromAscii(condition));
}
unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
if (reason == "breakpoint") {
// Note: Internal breakpoints (run to line) are reported with id=0.
// Step out creates temporary breakpoints with id 10000.
- BreakpointId id = 0;
+ BreakpointId id;
int number = 0;
const GdbMi breakpointIdG = stopReason.findChild("breakpointId");
if (breakpointIdG.isValid()) {
- id = breakpointIdG.data().toULongLong();
+ id = BreakpointId(breakpointIdG.data().toInt());
if (id && breakHandler()->engineBreakpointIds(this).contains(id)) {
const BreakpointResponse parameters = breakHandler()->response(id);
// Trace point? Just report.
return StopReportLog;
}
} else {
- id = 0;
+ id = BreakpointId();
}
}
QString tid = QString::number(threadId);
postCommand(cdbAddBreakpointCommand(parameters, m_sourcePathMappings, id, false), 0);
}
if (!parameters.enabled)
- postCommand("bd " + QByteArray::number(id), 0);
+ postCommand("bd " + QByteArray::number(id.majorPart()), 0);
handler->notifyBreakpointInsertProceeding(id);
handler->notifyBreakpointInsertOk(id);
m_pendingBreakpointMap.insert(id, response);
// Ensure enabled/disabled is correct in handler and line number is there.
handler->setResponse(id, response);
if (debugBreakpoints)
- qDebug("Adding %llu %s\n", id, qPrintable(response.toString()));
+ qDebug("Adding %d %s\n", id.toInternalId(),
+ qPrintable(response.toString()));
break;
case BreakpointChangeRequested:
handler->notifyBreakpointChangeProceeding(id);
if (debugBreakpoints)
- qDebug("Changing %llu:\n %s\nTo %s\n", id, qPrintable(handler->response(id).toString()),
- qPrintable(parameters.toString()));
+ qDebug("Changing %d:\n %s\nTo %s\n", id.toInternalId(),
+ qPrintable(handler->response(id).toString()),
+ qPrintable(parameters.toString()));
if (parameters.enabled != handler->response(id).enabled) {
// Change enabled/disabled breakpoints without triggering update.
- postCommand((parameters.enabled ? "be " : "bd ") + QByteArray::number(id), 0);
+ postCommand((parameters.enabled ? "be " : "bd ")
+ + QByteArray::number(id.majorPart()), 0);
response.pending = false;
response.enabled = parameters.enabled;
handler->setResponse(id, response);
} else {
// Delete and re-add, triggering update
addedChanged = true;
- postCommand("bc " + QByteArray::number(id), 0);
+ postCommand("bc " + QByteArray::number(id.majorPart()), 0);
postCommand(cdbAddBreakpointCommand(parameters, m_sourcePathMappings, id, false), 0);
m_pendingBreakpointMap.insert(id, response);
}
handler->notifyBreakpointChangeOk(id);
break;
case BreakpointRemoveRequested:
- postCommand("bc " + QByteArray::number(id), 0);
+ postCommand("bc " + QByteArray::number(id.majorPart()), 0);
handler->notifyBreakpointRemoveProceeding(id);
handler->notifyBreakpointRemoveOk(id);
m_pendingBreakpointMap.remove(id);
const ConditionalBreakPointCookie cookie = qvariant_cast<ConditionalBreakPointCookie>(command->cookie);
const QString message = value ?
tr("Value %1 obtained from evaluating the condition of breakpoint %2, stopping.").
- arg(value).arg(cookie.id) :
+ arg(value).arg(cookie.id.toString()) :
tr("Value 0 obtained from evaluating the condition of breakpoint %1, continuing.").
- arg(cookie.id);
+ arg(cookie.id.toString());
showMessage(message, LogMisc);
// Stop if evaluation is true, else continue
if (value) {
BreakpointResponse reportedResponse;
const BreakpointId id = parseBreakPoint(breakPointG, &reportedResponse);
if (debugBreakpoints)
- qDebug(" Parsed %llu: pending=%d %s\n", id, reportedResponse.pending,
- qPrintable(reportedResponse.toString()));
+ qDebug(" Parsed %d: pending=%d %s\n", id.majorPart(),
+ reportedResponse.pending,
+ qPrintable(reportedResponse.toString()));
if (!reportedResponse.pending) {
const PendingBreakPointMap::iterator it = m_pendingBreakpointMap.find(id);
currentResponse.enabled = reportedResponse.enabled;
formatCdbBreakPointResponse(id, currentResponse, str);
if (debugBreakpoints)
- qDebug(" Setting for %llu: %s\n", id, qPrintable(currentResponse.toString()));
+ qDebug(" Setting for %d: %s\n", id.majorPart(),
+ qPrintable(currentResponse.toString()));
handler->setResponse(id, currentResponse);
m_pendingBreakpointMap.erase(it);
}
QByteArray cdbAddBreakpointCommand(const BreakpointParameters &bpIn,
const QList<QPair<QString, QString> > &sourcePathMapping,
- BreakpointId id /* = BreakpointId(-1) */,
+ BreakpointId id /* = BreakpointId() */,
bool oneshot)
{
const BreakpointParameters bp = fixWinMSVCBreakpoint(bpIn);
// is kept when reporting back breakpoints (which is otherwise discarded
// when resolving).
str << (bp.type == WatchpointAtAddress ? "ba" : "bu");
- if (id != BreakpointId(-1))
- str << id;
+ if (id.isValid())
+ str << id.toString();
str << ' ';
if (oneshot)
str << "/1 ";
const GdbMi idG = gdbmi.findChild("id");
if (idG.isValid()) { // Might not be valid if there is not id
bool ok;
- const BreakpointId cid = idG.data().toULongLong(&ok);
+ const BreakpointId cid(idG.data().toInt(&ok));
if (ok)
id = cid;
}
RESOURCES += debugger.qrc
-false {
+true {
SOURCES += $$PWD/modeltest.cpp
HEADERS += $$PWD/modeltest.h
- DEFINES += USE_MODEL_TEST=1
+ #DEFINES += USE_WATCH_MODEL_TEST=1
+ #DEFINES += USE_BREAK_MODEL_TEST=1
}
win32 {
include(../../shared/registryaccess/registryaccess.pri)
{
return id
? tr("Data breakpoint %1 (%2) at %3 triggered.")
- .arg(id).arg(number).arg(expr)
+ .arg(id.toString()).arg(number).arg(expr)
: tr("Internal data breakpoint %1 at %2 triggered.")
.arg(number).arg(expr);
}
{
return id
? tr("Data breakpoint %1 (%2) at %3 in thread %4 triggered.")
- .arg(id).arg(number).arg(expr).arg(threadId)
+ .arg(id.toString()).arg(number).arg(expr).arg(threadId)
: tr("Internal data breakpoint %1 at %2 in thread %4 triggered.")
.arg(number).arg(expr).arg(threadId);
}
{
return id
? tr("Data breakpoint %1 (%2) at 0x%3 triggered.")
- .arg(id).arg(number).arg(address, 0, 16)
+ .arg(id.toString()).arg(number).arg(address, 0, 16)
: tr("Internal data breakpoint %1 at 0x%2 triggered.")
.arg(number).arg(address, 0, 16);
}
{
return id
? tr("Data breakpoint %1 (%2) at 0x%3 in thread %4 triggered.")
- .arg(id).arg(number).arg(address, 0, 16).arg(threadId)
+ .arg(id.toString()).arg(number).arg(address, 0, 16).arg(threadId)
: tr("Internal data breakpoint %1 at 0x%2 in thread %3 triggered.")
- .arg(id).arg(number).arg(address, 0, 16).arg(threadId);
+ .arg(id.toString()).arg(number).arg(address, 0, 16).arg(threadId);
}
QString DebuggerEngine::msgBreakpointTriggered(BreakpointId id,
{
return id
? tr("Stopped at breakpoint %1 (%2) in thread %3.")
- .arg(id).arg(number).arg(threadId)
+ .arg(id.toString()).arg(number).arg(threadId)
: tr("Stopped at internal breakpoint %1 in thread %2.")
.arg(number).arg(threadId);
}
{
const QAction *act = qobject_cast<QAction *>(sender());
QTC_ASSERT(act, return);
- m_breakHandler->removeBreakpoint(act->data().toInt());
+ BreakpointId id = act->data().value<BreakpointId>();
+ m_breakHandler->removeBreakpoint(id);
}
void breakpointEnableMarginActionTriggered()
{
const QAction *act = qobject_cast<QAction *>(sender());
QTC_ASSERT(act, return);
- breakHandler()->setEnabled(act->data().toInt(), true);
+ BreakpointId id = act->data().value<BreakpointId>();
+ breakHandler()->setEnabled(id, true);
}
void breakpointDisableMarginActionTriggered()
{
const QAction *act = qobject_cast<QAction *>(sender());
QTC_ASSERT(act, return);
- breakHandler()->setEnabled(act->data().toInt(), false);
+ BreakpointId id = act->data().value<BreakpointId>();;
+ breakHandler()->setEnabled(id, false);
}
void updateWatchersHeader(int section, int, int newSize)
{
const QAction *act = qobject_cast<QAction *>(sender());
QTC_ASSERT(act, return);
- const BreakpointId id = act->data().toInt();
+ const BreakpointId id = act->data().value<BreakpointId>();
QTC_ASSERT(id > 0, return);
BreakWindow::editBreakpoint(id, mainWindow());
}
if (id) {
// Remove existing breakpoint.
QAction *act = new QAction(menu);
- act->setData(int(id));
- act->setText(tr("Remove Breakpoint %1").arg(id));
+ act->setData(QVariant::fromValue(id));
+ act->setText(tr("Remove Breakpoint %1").arg(id.toString()));
connect(act, SIGNAL(triggered()),
SLOT(breakpointRemoveMarginActionTriggered()));
menu->addAction(act);
// Enable/disable existing breakpoint.
act = new QAction(menu);
- act->setData(int(id));
+ act->setData(QVariant::fromValue(id));
if (breakHandler()->isEnabled(id)) {
- act->setText(tr("Disable Breakpoint %1").arg(id));
+ act->setText(tr("Disable Breakpoint %1").arg(id.toString()));
connect(act, SIGNAL(triggered()),
SLOT(breakpointDisableMarginActionTriggered()));
} else {
- act->setText(tr("Enable Breakpoint %1").arg(id));
+ act->setText(tr("Enable Breakpoint %1").arg(id.toString()));
connect(act, SIGNAL(triggered()),
SLOT(breakpointEnableMarginActionTriggered()));
}
// Edit existing breakpoint.
act = new QAction(menu);
- act->setText(tr("Edit Breakpoint %1...").arg(id));
+ act->setText(tr("Edit Breakpoint %1...").arg(id.toString()));
connect(act, SIGNAL(triggered()), SLOT(slotEditBreakpoint()));
- act->setData(int(id));
+ act->setData(QVariant::fromValue(id));
menu->addAction(act);
} else {
// Handle non-existing breakpoint.
// line="1584",shlib="/../libFoo_debug.dylib",times="0"}
const GdbMi bkpt = result.findChild("bkpt");
const int number = bkpt.findChild("number").data().toInt();
- if (!isQmlStepBreakpoint1(number) && isQmlStepBreakpoint2(number)) {
- BreakpointId id = breakHandler()->findBreakpointByNumber(number);
- updateBreakpointDataFromOutput(id, bkpt);
+ if (!isQmlStepBreakpoint(number)) {
+ BreakHandler *handler = breakHandler();
+ BreakpointId id = handler->findBreakpointByNumber(number);
+ BreakpointResponse br = handler->response(id);
+ updateResponse(br, bkpt);
+ handler->setResponse(id, br);
attemptAdjustBreakpointLocation(id);
}
} else if (asyncClass == "breakpoint-modified") {
// New in FSF gdb since 2011-04-27.
- // "{bkpt={number="2",type="breakpoint",disp="keep",enabled="y",
- // addr="0x014e0e34",func="Myns::qFatal(char const*, ...)",
- // file="global/qglobal.cpp",fullname="/data/dev/...cpp",
- // line="2534",times="0",script={"return"},
- // original-location="'Myns::qFatal'"}}"
- const GdbMi bkpt = result.findChild("bkpt");
- const int number = bkpt.findChild("number").data().toInt();
- if (!isQmlStepBreakpoint1(number) && isQmlStepBreakpoint2(number)) {
- BreakpointId id = breakHandler()->findBreakpointByNumber(number);
- updateBreakpointDataFromOutput(id, bkpt);
+ // "{bkpt={number="3",type="breakpoint",disp="keep",
+ // enabled="y",addr="<MULTIPLE>",times="1",
+ // original-location="\\",simple_gdbtest_app.cpp\\":135"},
+ // {number="3.1",enabled="y",addr="0x0805ff68",
+ // func="Vector<int>::Vector(int)",
+ // file="simple_gdbtest_app.cpp",
+ // fullname="/data/...line="135"},{number="3.2"...}}"
+
+ // Note the leading comma in original-location. Filter it out.
+ // We don't need the field anyway.
+ QByteArray ba = result.toString();
+ ba = '[' + ba.mid(6, ba.size() - 7) + ']';
+ const int pos1 = ba.indexOf(",original-location");
+ const int pos2 = ba.indexOf("\":", pos1 + 2);
+ const int pos3 = ba.indexOf('"', pos2 + 2);
+ ba.replace(pos1, pos3 - pos1 + 1, "");
+ result = GdbMi();
+ result.fromString(ba);
+ BreakHandler *handler = breakHandler();
+ BreakpointId id = BreakpointId(-1);
+ BreakpointResponse br;
+ foreach (const GdbMi &bkpt, result.children()) {
+ const QByteArray nr = bkpt.findChild("number").data();
+ if (nr.contains(".")) {
+ // A sub-breakpoint.
+ int subNumber = nr.mid(nr.indexOf('.') + 1).toInt();
+ BreakpointResponse sub;
+ updateResponse(sub, bkpt);
+ sub.number = br.number;
+ sub.type = br.type;
+ sub.subNumber = subNumber;
+ sub.extra.clear();
+ handler->appendSubBreakpoint(id, sub);
+ } else {
+ // A primary breakpoint.
+ id = handler->findBreakpointByNumber(nr.toInt());
+ br = handler->response(id);
+ updateResponse(br, bkpt);
+ }
+ }
+ if (!isQmlStepBreakpoint(br.number)) {
+ handler->setResponse(id, br);
attemptAdjustBreakpointLocation(id);
}
m_hasBreakpointNotifications = true;
void GdbEngine::interruptInferior()
{
- QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state(); return);
+ QTC_ASSERT(state() == InferiorStopRequested,
+ qDebug() << "INTERRUPT INFERIOR: " << state(); return);
if (debuggerCore()->boolSetting(TargetAsync)) {
postCommand("-exec-interrupt");
fullName = QString::fromUtf8(frame.findChild("file").data());
if (bkptno && frame.isValid()
- && !isQmlStepBreakpoint1(bkptno)
- && !isQmlStepBreakpoint2(bkptno)
+ && !isQmlStepBreakpoint(bkptno)
&& !isQFatalBreakpoint(bkptno)) {
// Use opportunity to update the breakpoint marker position.
BreakHandler *handler = breakHandler();
// Quickly set the location marker.
if (lineNumber && !debuggerCore()->boolSetting(OperateByInstruction)
&& QFileInfo(fullName).exists()
- && !isQmlStepBreakpoint1(bkptno)
- && !isQmlStepBreakpoint2(bkptno)
+ && !isQmlStepBreakpoint(bkptno)
&& !isQFatalBreakpoint(bkptno))
gotoLocation(Location(fullName, lineNumber));
}
}
+void GdbEngine::handleListFeatures(const GdbResponse &response)
+{
+ showMessage(_("FEATURES: " + response.toString()));
+}
+
void GdbEngine::handleHasPython(const GdbResponse &response)
{
if (response.resultClass == GdbResultDone) {
//
//////////////////////////////////////////////////////////////////////
-void GdbEngine::updateBreakpointDataFromOutput(BreakpointId id, const GdbMi &bkpt)
+void GdbEngine::updateResponse(BreakpointResponse &response, const GdbMi &bkpt)
{
QTC_ASSERT(bkpt.isValid(), return);
- BreakpointResponse response = breakHandler()->response(id);
-
response.multiple = false;
response.enabled = true;
response.pending = false;
}
if (!name.isEmpty())
response.fileName = name;
-
- breakHandler()->setResponse(id, response);
}
QString GdbEngine::breakLocation(const QString &file) const
void GdbEngine::handleWatchInsert(const GdbResponse &response)
{
- const int id = response.cookie.toInt();
+ BreakpointId id = response.cookie.value<BreakpointId>();
if (response.resultClass == GdbResultDone) {
BreakHandler *handler = breakHandler();
- BreakpointResponse bresponse = handler->response(id);
+ BreakpointResponse br = handler->response(id);
// "Hardware watchpoint 2: *0xbfffed40\n"
QByteArray ba = response.data.findChild("consolestreamoutput").data();
GdbMi wpt = response.data.findChild("wpt");
if (wpt.isValid()) {
// Mac yields:
//>32^done,wpt={number="4",exp="*4355182176"}
- bresponse.number = wpt.findChild("number").data().toInt();
+ br.number = wpt.findChild("number").data().toInt();
QByteArray exp = wpt.findChild("exp").data();
if (exp.startsWith('*'))
- bresponse.address = exp.mid(1).toULongLong(0, 0);
- handler->setResponse(id, bresponse);
+ br.address = exp.mid(1).toULongLong(0, 0);
+ handler->setResponse(id, br);
QTC_ASSERT(!handler->needsChange(id), /**/);
handler->notifyBreakpointInsertOk(id);
} else if (ba.startsWith("Hardware watchpoint ")
const int end = ba.indexOf(':');
const int begin = ba.lastIndexOf(' ', end) + 1;
const QByteArray address = ba.mid(end + 2).trimmed();
- bresponse.number = ba.mid(begin, end - begin).toInt();
+ br.number = ba.mid(begin, end - begin).toInt();
if (address.startsWith('*'))
- bresponse.address = address.mid(1).toULongLong(0, 0);
- handler->setResponse(id, bresponse);
+ br.address = address.mid(1).toULongLong(0, 0);
+ handler->setResponse(id, br);
QTC_ASSERT(!handler->needsChange(id), /**/);
handler->notifyBreakpointInsertOk(id);
} else {
breakHandler()->setResponse(id, response);
postCommand("info line *0x" + QByteArray::number(response.address, 16),
NeedsStop | RebuildBreakpointModel,
- CB(handleInfoLine), id);
+ CB(handleInfoLine), QVariant::fromValue(id));
}
void GdbEngine::handleCatchInsert(const GdbResponse &response)
{
BreakHandler *handler = breakHandler();
- BreakpointId id(response.cookie.toInt());
+ BreakpointId id = response.cookie.value<BreakpointId>();
if (response.resultClass == GdbResultDone) {
handler->notifyBreakpointInsertOk(id);
attemptAdjustBreakpointLocation(id);
void GdbEngine::handleBreakInsert1(const GdbResponse &response)
{
BreakHandler *handler = breakHandler();
- BreakpointId id(response.cookie.toInt());
+ BreakpointId id = response.cookie.value<BreakpointId>();
if (response.resultClass == GdbResultDone) {
// Interesting only on Mac?
GdbMi bkpt = response.data.findChild("bkpt");
- updateBreakpointDataFromOutput(id, bkpt);
+ BreakpointResponse br = handler->response(id);
+ updateResponse(br, bkpt);
+ handler->setResponse(id, br);
if (handler->needsChange(id)) {
handler->notifyBreakpointChangeAfterInsertNeeded(id);
changeBreakpoint(id);
} else {
handler->notifyBreakpointInsertOk(id);
}
- BreakpointResponse bresponse = handler->response(id);
+ br = handler->response(id);
attemptAdjustBreakpointLocation(id);
- if (bresponse.multiple && bresponse.addresses.isEmpty())
- postCommand("info break " + QByteArray::number(bresponse.number),
+ if (br.multiple && br.addresses.isEmpty())
+ postCommand("info break " + QByteArray::number(br.number),
NeedsStop, CB(handleBreakListMultiple), QVariant(id));
} else if (response.data.findChild("msg").data().contains("Unknown option")) {
// Older version of gdb don't know the -a option to set tracepoints
QByteArray cmd = "trace "
"\"" + GdbMi::escapeCString(fileName).toLocal8Bit() + "\":"
+ QByteArray::number(lineNumber);
+ QVariant vid = QVariant::fromValue(id);
postCommand(cmd, NeedsStop | RebuildBreakpointModel,
- CB(handleTraceInsert2), id);
+ CB(handleTraceInsert2), vid);
} else {
// Some versions of gdb like "GNU gdb (GDB) SUSE (6.8.91.20090930-2.4)"
// know how to do pending breakpoints using CLI but not MI. So try
// again with MI.
QByteArray cmd = "break " + breakpointLocation2(id);
+ QVariant vid = QVariant::fromValue(id);
postCommand(cmd, NeedsStop | RebuildBreakpointModel,
- CB(handleBreakInsert2), id);
+ CB(handleBreakInsert2), vid);
}
}
void GdbEngine::handleBreakInsert2(const GdbResponse &response)
{
if (response.resultClass == GdbResultDone) {
- BreakpointId id(response.cookie.toInt());
+ BreakpointId id = response.cookie.value<BreakpointId>();
attemptAdjustBreakpointLocation(id);
breakHandler()->notifyBreakpointInsertOk(id);
} else {
}
}
+ BreakHandler *handler = breakHandler();
foreach (const GdbMi &bkpt, bkpts) {
BreakpointResponse needle;
needle.number = bkpt.findChild("number").data().toInt();
continue;
if (isQFatalBreakpoint(needle.number))
continue;
- BreakpointId id = breakHandler()->findSimilarBreakpoint(needle);
- if (id != BreakpointId(-1)) {
- updateBreakpointDataFromOutput(id, bkpt);
+ BreakpointId id = handler->findSimilarBreakpoint(needle);
+ if (id.isValid()) {
+ BreakpointResponse response = handler->response(id);
+ updateResponse(response, bkpt);
+ handler->setResponse(id, response);
attemptAdjustBreakpointLocation(id);
- BreakpointResponse response = breakHandler()->response(id);
+ response = handler->response(id);
if (response.multiple && response.addresses.isEmpty())
postCommand("info break " + QByteArray::number(response.number),
- NeedsStop, CB(handleBreakListMultiple), QVariant(id));
+ NeedsStop, CB(handleBreakListMultiple),
+ QVariant::fromValue(id));
} else {
qDebug() << " NOTHING SUITABLE FOUND";
showMessage(_("CANNOT FIND BP: " + bkpt.toString()));
void GdbEngine::handleBreakListMultiple(const GdbResponse &response)
{
QTC_ASSERT(response.resultClass == GdbResultDone, /**/)
- const BreakpointId id = response.cookie.toInt();
+ const BreakpointId id = response.cookie.value<BreakpointId>();
const QString str = QString::fromLocal8Bit(
response.data.findChild("consolestreamoutput").data());
extractDataFromInfoBreak(str, id);
void GdbEngine::handleBreakDisable(const GdbResponse &response)
{
QTC_ASSERT(response.resultClass == GdbResultDone, /**/)
- const BreakpointId id = response.cookie.toInt();
+ const BreakpointId id = response.cookie.value<BreakpointId>();
BreakHandler *handler = breakHandler();
// This should only be the requested state.
QTC_ASSERT(!handler->isEnabled(id), /* Prevent later recursion */);
void GdbEngine::handleBreakEnable(const GdbResponse &response)
{
QTC_ASSERT(response.resultClass == GdbResultDone, /**/)
- const BreakpointId id = response.cookie.toInt();
+ const BreakpointId id = response.cookie.value<BreakpointId>();
BreakHandler *handler = breakHandler();
// This should only be the requested state.
QTC_ASSERT(handler->isEnabled(id), /* Prevent later recursion */);
void GdbEngine::handleBreakThreadSpec(const GdbResponse &response)
{
QTC_ASSERT(response.resultClass == GdbResultDone, /**/)
- const BreakpointId id = response.cookie.toInt();
+ const BreakpointId id = response.cookie.value<BreakpointId>();
BreakHandler *handler = breakHandler();
BreakpointResponse br = handler->response(id);
br.threadSpec = handler->threadSpec(id);
// gdb 6.3 does not produce any console output
QTC_ASSERT(response.resultClass == GdbResultDone, /**/)
QString msg = _(response.data.findChild("consolestreamoutput").data());
- BreakpointId id = response.cookie.toInt();
+ BreakpointId id = response.cookie.value<BreakpointId>();
BreakHandler *handler = breakHandler();
BreakpointResponse br = handler->response(id);
//if (msg.contains(__("Will stop next time breakpoint")))
{
// Can happen at invalid condition strings.
//QTC_ASSERT(response.resultClass == GdbResultDone, /**/)
- const BreakpointId id = response.cookie.toInt();
+ const BreakpointId id = response.cookie.value<BreakpointId>();
BreakHandler *handler = breakHandler();
// We just assume it was successful. Otherwise we had to parse
// the output stream data.
// at address 0x80526aa <_Z10...+131> and ends at 0x80526b5
// <_Z10testQStackv+142>.\n"
QByteArray ba = response.data.findChild("consolestreamoutput").data();
- const BreakpointId id = response.cookie.toInt();
+ const BreakpointId id = response.cookie.value<BreakpointId>();
const int pos = ba.indexOf(' ', 5);
if (ba.startsWith("Line ") && pos != -1) {
const int line = ba.mid(5, pos - 5).toInt();
QTC_ASSERT(handler->state(id) == BreakpointInsertRequested, /**/);
handler->notifyBreakpointInsertProceeding(id);
BreakpointType type = handler->type(id);
+ QVariant vid = QVariant::fromValue(id);
if (type == WatchpointAtAddress) {
postCommand("watch " + addressSpec(handler->address(id)),
NeedsStop | RebuildBreakpointModel,
- CB(handleWatchInsert), id);
+ CB(handleWatchInsert), vid);
return;
}
if (type == WatchpointAtExpression) {
postCommand("watch " + handler->expression(id).toLocal8Bit(),
NeedsStop | RebuildBreakpointModel,
- CB(handleWatchInsert), id);
+ CB(handleWatchInsert), vid);
return;
}
if (type == BreakpointAtFork) {
postCommand("catch fork", NeedsStop | RebuildBreakpointModel,
- CB(handleCatchInsert), id);
+ CB(handleCatchInsert), vid);
postCommand("catch vfork", NeedsStop | RebuildBreakpointModel,
- CB(handleCatchInsert), id);
+ CB(handleCatchInsert), vid);
return;
}
//if (type == BreakpointAtVFork) {
// postCommand("catch vfork", NeedsStop | RebuildBreakpointModel,
- // CB(handleCatchInsert), id);
+ // CB(handleCatchInsert), vid);
// return;
//}
if (type == BreakpointAtExec) {
postCommand("catch exec", NeedsStop | RebuildBreakpointModel,
- CB(handleCatchInsert), id);
+ CB(handleCatchInsert), vid);
return;
}
if (type == BreakpointAtSysCall) {
postCommand("catch syscall", NeedsStop | RebuildBreakpointModel,
- CB(handleCatchInsert), id);
+ CB(handleCatchInsert), vid);
return;
}
// cmd += "-c " + data->condition + ' ';
cmd += breakpointLocation(id);
postCommand(cmd, NeedsStop | RebuildBreakpointModel,
- CB(handleBreakInsert1), id);
+ CB(handleBreakInsert1), vid);
}
void GdbEngine::changeBreakpoint(BreakpointId id)
handler->notifyBreakpointChangeProceeding(id);
const BreakpointState state2 = handler->state(id);
QTC_ASSERT(state2 == BreakpointChangeProceeding, qDebug() << state2);
+ QVariant vid = QVariant::fromValue(id);
if (data.threadSpec != response.threadSpec) {
// The only way to change this seems to be to re-set the bp completely.
postCommand("-break-delete " + bpnr,
NeedsStop | RebuildBreakpointModel,
- CB(handleBreakThreadSpec), id);
+ CB(handleBreakThreadSpec), vid);
return;
}
if (data.command != response.command) {
}
}
postCommand(breakCommand, NeedsStop | RebuildBreakpointModel,
- CB(handleBreakIgnore), id);
+ CB(handleBreakIgnore), vid);
return;
}
if (!data.conditionsMatch(response.condition)) {
postCommand("condition " + bpnr + ' ' + data.condition,
NeedsStop | RebuildBreakpointModel,
- CB(handleBreakCondition), id);
+ CB(handleBreakCondition), vid);
return;
}
if (data.ignoreCount != response.ignoreCount) {
postCommand("ignore " + bpnr + ' ' + QByteArray::number(data.ignoreCount),
NeedsStop | RebuildBreakpointModel,
- CB(handleBreakIgnore), id);
+ CB(handleBreakIgnore), vid);
return;
}
if (!data.enabled && response.enabled) {
postCommand("-break-disable " + bpnr,
NeedsStop | RebuildBreakpointModel,
- CB(handleBreakDisable), id);
+ CB(handleBreakDisable), vid);
return;
}
if (data.enabled && !response.enabled) {
postCommand("-break-enable " + bpnr,
NeedsStop | RebuildBreakpointModel,
- CB(handleBreakEnable), id);
+ CB(handleBreakEnable), vid);
return;
}
handler->notifyBreakpointChangeOk(id);
showMessage(_("GDB STARTED, INITIALIZING IT"));
postCommand("show version", CB(handleShowVersion));
+ postCommand("-list-features", CB(handleListFeatures));
//postCommand("-enable-timings");
//postCommand("set print static-members off"); // Seemingly doesn't work.
masterEngine()->readyToExecuteQmlStep();
}
+bool GdbEngine::isQmlStepBreakpoint(int bpnr) const
+{
+ return isQmlStepBreakpoint1(bpnr) || isQmlStepBreakpoint2(bpnr);
+}
+
bool GdbEngine::isQmlStepBreakpoint1(int bpnr) const
{
//qDebug() << "CHECK 1: " << m_qmlBreakpointNumbers[1] << bpnr;
// Gdb initialization sequence
void handleShowVersion(const GdbResponse &response);
+ void handleListFeatures(const GdbResponse &response);
void handleHasPython(const GdbResponse &response);
int m_gdbVersion; // 6.8.0 is 60800
void handleCatchInsert(const GdbResponse &response);
void handleInfoLine(const GdbResponse &response);
void extractDataFromInfoBreak(const QString &output, BreakpointId);
- void updateBreakpointDataFromOutput(BreakpointId id, const GdbMi &bkpt);
+ void updateResponse(BreakpointResponse &response, const GdbMi &bkpt);
QByteArray breakpointLocation(BreakpointId id); // For gdb/MI.
QByteArray breakpointLocation2(BreakpointId id); // For gdb/CLI fallback.
QString breakLocation(const QString &file) const;
bool m_preparedForQmlBreak;
bool setupQmlStep(bool on);
void handleSetQmlStepBreakpoint(const GdbResponse &response);
+ bool isQmlStepBreakpoint(int bpnr) const;
bool isQmlStepBreakpoint1(int bpnr) const;
bool isQmlStepBreakpoint2(int bpnr) const;
bool isQFatalBreakpoint(int bpnr) const;
attemptBreakpointSynchronization();
QDataStream s(payload);
SET_NATIVE_BYTE_ORDER(s);
- BreakpointId id;
- s >> id;
+ quint64 d;
+ s >> d;
+ BreakpointId id = BreakpointId::fromInternalId(d);
breakHandler()->notifyBreakpointInsertOk(id);
}
break;
{
QDataStream s(payload);
SET_NATIVE_BYTE_ORDER(s);
- BreakpointId id;
- s >> id;
+ quint64 d;
+ s >> d;
+ BreakpointId id = BreakpointId::fromInternalId(d);
breakHandler()->notifyBreakpointInsertFailed(id);
}
break;
{
QDataStream s(payload);
SET_NATIVE_BYTE_ORDER(s);
- BreakpointId id;
- s >> id;
+ quint64 d;
+ s >> d;
+ BreakpointId id = BreakpointId::fromInternalId(d);
breakHandler()->notifyBreakpointRemoveOk(id);
}
break;
{
QDataStream s(payload);
SET_NATIVE_BYTE_ORDER(s);
- BreakpointId id;
- s >> id;
+ quint64 d;
+ s >> d;
+ BreakpointId id = BreakpointId::fromInternalId(d);
breakHandler()->notifyBreakpointRemoveFailed(id);
}
break;
{
QDataStream s(payload);
SET_NATIVE_BYTE_ORDER(s);
- BreakpointId id;
- s >> id;
+ quint64 d;
+ s >> d;
+ BreakpointId id = BreakpointId::fromInternalId(d);
breakHandler()->notifyBreakpointChangeOk(id);
}
break;
{
QDataStream s(payload);
SET_NATIVE_BYTE_ORDER(s);
- BreakpointId id;
- s >> id;
+ quint64 d;
+ s >> d;
+ BreakpointId id = BreakpointId::fromInternalId(d);
breakHandler()->notifyBreakpointChangeFailed(id);
}
break;
{
QDataStream s(payload);
SET_NATIVE_BYTE_ORDER(s);
- BreakpointId id;
+ quint64 dd;
BreakpointParameters d;
- s >> id >> d;
+ s >> dd >> d;
+ BreakpointId id = BreakpointId::fromInternalId(dd);
breakHandler()->notifyBreakpointAdjusted(id, d);
}
break;
#include "debuggerengine.h"
#include "watchutils.h"
-#if USE_MODEL_TEST
+#if USE_WATCH_MODEL_TEST
#include "modeltest.h"
#endif
foreach (WatchItem *child, m_root->children)
removeOutdatedHelper(child);
#if DEBUG_MODEL
-#if USE_MODEL_TEST
- //(void) new ModelTest(this, this);
+#if USE_WATCH_MODEL_TEST
+ (void) new ModelTest(this, this);
#endif
#endif
}