Files
qt-creator/src/plugins/debugger/breakhandler.cpp

838 lines
27 KiB
C++
Raw Normal View History

/**************************************************************************
2008-12-02 12:01:29 +01:00
**
** This file is part of Qt Creator
**
2010-03-05 11:25:49 +01:00
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
2008-12-02 12:01:29 +01:00
**
** Contact: Nokia Corporation (qt-info@nokia.com)
2008-12-02 12:01:29 +01:00
**
** 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
2009-08-14 09:30:56 +02:00
** contact the sales department at http://qt.nokia.com/contact.
2008-12-02 12:01:29 +01:00
**
**************************************************************************/
2008-12-02 15:08:31 +01:00
2008-12-02 12:01:29 +01:00
#include "breakhandler.h"
#include "breakpointmarker.h"
2008-12-02 12:01:29 +01:00
#include "debuggeractions.h"
#include "debuggercore.h"
#include "debuggerstringutils.h"
2010-03-26 08:52:49 +01:00
#include <utils/qtcassert.h>
2008-12-09 16:18:28 +01:00
#include <QtCore/QDir>
2008-12-02 12:01:29 +01:00
#include <QtCore/QFileInfo>
2008-12-02 12:01:29 +01:00
//////////////////////////////////////////////////////////////////
//
// BreakHandler
//
//////////////////////////////////////////////////////////////////
namespace Debugger {
namespace Internal {
BreakHandler::BreakHandler()
: m_breakpointIcon(_(":/debugger/images/breakpoint_16.png")),
m_disabledBreakpointIcon(_(":/debugger/images/breakpoint_disabled_16.png")),
m_pendingBreakPointIcon(_(":/debugger/images/breakpoint_pending_16.png")),
//m_emptyIcon(_(":/debugger/images/watchpoint.png")),
m_emptyIcon(_(":/debugger/images/breakpoint_pending_16.png")),
//m_emptyIcon(_(":/debugger/images/debugger_empty_14.png")),
m_watchpointIcon(_(":/debugger/images/watchpoint.png")),
m_syncTimerId(-1)
{}
2008-12-02 12:01:29 +01:00
BreakHandler::~BreakHandler()
{}
2008-12-02 12:01:29 +01:00
int BreakHandler::columnCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : 8;
2008-12-02 12:01:29 +01:00
}
int BreakHandler::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_storage.size();
2008-12-02 12:01:29 +01:00
}
// FIXME: Only used by cdb. Move there?
bool BreakHandler::hasPendingBreakpoints() const
{
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
for ( ; it != et; ++it)
if (it->data->isPending())
return true;
return false;
}
static inline bool fileNameMatch(const QString &f1, const QString &f2)
2010-03-26 08:52:49 +01:00
{
#ifdef Q_OS_WIN
return f1.compare(f2, Qt::CaseInsensitive) == 0;
#else
return f1 == f2;
#endif
2010-03-26 08:52:49 +01:00
}
static bool isSimilarTo(const BreakpointData *data, const BreakpointResponse &needle)
2008-12-02 12:01:29 +01:00
{
// Clear hit.
// Clear miss.
if (needle.bpType != UnknownType && data->type() != UnknownType
&& data->type() != needle.bpType)
return false;
2008-12-02 12:01:29 +01:00
// Clear hit.
if (data->address() && data->address() == needle.bpAddress)
return true;
// At least at a position we were looking for.
// FIXME: breaks multiple breakpoints at the same location
if (!data->fileName().isEmpty()
&& fileNameMatch(data->fileName(), needle.bpFileName)
&& data->lineNumber() == needle.bpLineNumber)
return true;
// At least at a position we were looking for.
// FIXME: breaks multiple breakpoints at the same location
if (!data->fileName().isEmpty()
&& fileNameMatch(data->fileName(), needle.bpFileName)
&& data->lineNumber() == needle.bpLineNumber)
return true;
return false;
2008-12-02 12:01:29 +01:00
}
BreakpointId BreakHandler::findSimilarBreakpoint(const BreakpointResponse &needle) const
2008-12-02 12:01:29 +01:00
{
// Search a breakpoint we might refer to.
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
for ( ; it != et; ++it) {
const BreakpointId id = it.key();
const BreakpointData *data = it->data;
const BreakpointResponse *response = it->response;
qDebug() << "COMPARING " << data->toString() << " WITH " << needle.toString();
if (response->bpNumber && response->bpNumber == needle.bpNumber)
return id;
if (isSimilarTo(data, needle))
return id;
2008-12-02 12:01:29 +01:00
}
return BreakpointId(-1);
2008-12-02 12:01:29 +01:00
}
BreakpointId BreakHandler::findBreakpointByNumber(int bpNumber) const
2008-12-02 12:01:29 +01:00
{
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
for ( ; it != et; ++it)
if (it->response->bpNumber == bpNumber)
return it.key();
return BreakpointId(-1);
2008-12-02 12:01:29 +01:00
}
BreakpointId BreakHandler::findBreakpointByFunction(const QString &functionName) const
{
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
for ( ; it != et; ++it)
if (it->data->functionName() == functionName)
return it.key();
return BreakpointId(-1);
}
BreakpointId BreakHandler::findBreakpointByAddress(quint64 address) const
{
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
for ( ; it != et; ++it)
if (it->data->address() == address)
return it.key();
return BreakpointId(-1);
}
BreakpointId BreakHandler::findBreakpointByFileAndLine(const QString &fileName,
int lineNumber, bool useMarkerPosition)
{
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
for ( ; it != et; ++it)
if (it->data->isLocatedAt(fileName, lineNumber, useMarkerPosition))
return it.key();
return BreakpointId(-1);
}
BreakpointData *BreakHandler::breakpointById(BreakpointId id) const
{
return m_storage.value(id).data;
}
BreakpointId BreakHandler::findWatchpointByAddress(quint64 address) const
{
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
for ( ; it != et; ++it)
if (it->data->isWatchpoint() && it->data->address() == address)
return it.key();
return BreakpointId(-1);
}
void BreakHandler::setWatchpointByAddress(quint64 address)
{
const int id = findWatchpointByAddress(address);
if (id == -1) {
BreakpointData *data = new BreakpointData;
data->setType(Watchpoint);
data->setAddress(address);
appendBreakpoint(data);
scheduleSynchronization();
} else {
qDebug() << "WATCHPOINT EXISTS";
// removeBreakpoint(index);
}
}
bool BreakHandler::hasWatchpointAt(quint64 address) const
{
return findWatchpointByAddress(address) != BreakpointId(-1);
}
2008-12-02 12:01:29 +01:00
void BreakHandler::saveBreakpoints()
{
//qDebug() << "SAVING BREAKPOINTS...";
QTC_ASSERT(debuggerCore(), return);
2008-12-02 12:01:29 +01:00
QList<QVariant> list;
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
for ( ; it != et; ++it) {
const BreakpointData *data = it->data;
2008-12-02 12:01:29 +01:00
QMap<QString, QVariant> map;
// Do not persist Watchpoints.
//if (data->isWatchpoint())
// continue;
if (data->type() != BreakpointByFileAndLine)
map.insert(_("type"), data->type());
if (!data->fileName().isEmpty())
map.insert(_("filename"), data->fileName());
if (data->lineNumber())
map.insert(_("linenumber"), data->lineNumber());
if (!data->functionName().isEmpty())
map.insert(_("funcname"), data->functionName());
if (data->address())
map.insert(_("address"), data->address());
if (!data->condition().isEmpty())
map.insert(_("condition"), data->condition());
if (data->ignoreCount())
map.insert(_("ignorecount"), data->ignoreCount());
if (!data->threadSpec().isEmpty())
map.insert(_("threadspec"), data->threadSpec());
if (!data->isEnabled())
map.insert(_("disabled"), _("1"));
if (data->useFullPath())
map.insert(_("usefullpath"), _("1"));
2008-12-02 12:01:29 +01:00
list.append(map);
}
debuggerCore()->setSessionValue("Breakpoints", list);
//qDebug() << "SAVED BREAKPOINTS" << this << list.size();
2008-12-02 12:01:29 +01:00
}
void BreakHandler::loadBreakpoints()
{
QTC_ASSERT(debuggerCore(), return);
//qDebug() << "LOADING BREAKPOINTS...";
QVariant value = debuggerCore()->sessionValue("Breakpoints");
2008-12-02 12:01:29 +01:00
QList<QVariant> list = value.toList();
//clear();
2008-12-02 12:01:29 +01:00
foreach (const QVariant &var, list) {
const QMap<QString, QVariant> map = var.toMap();
BreakpointData *data = new BreakpointData;
QVariant v = map.value(_("filename"));
if (v.isValid())
data->setFileName(v.toString());
v = map.value(_("linenumber"));
if (v.isValid())
data->setLineNumber(v.toString().toInt());
v = map.value(_("condition"));
if (v.isValid())
data->setCondition(v.toString().toLatin1());
v = map.value(_("address"));
if (v.isValid())
data->setAddress(v.toString().toULongLong());
v = map.value(_("ignorecount"));
if (v.isValid())
data->setIgnoreCount(v.toString().toInt());
v = map.value(_("threadspec"));
if (v.isValid())
data->setThreadSpec(v.toString().toLatin1());
v = map.value(_("funcname"));
if (v.isValid())
data->setFunctionName(v.toString());
v = map.value(_("disabled"));
if (v.isValid())
data->setEnabled(!v.toInt());
v = map.value(_("usefullpath"));
if (v.isValid())
data->setUseFullPath(bool(v.toInt()));
v = map.value(_("type"));
if (v.isValid())
data->setType(BreakpointType(v.toInt()));
data->setMarkerFileName(data->fileName());
data->setMarkerLineNumber(data->lineNumber());
appendBreakpoint(data);
2008-12-02 12:01:29 +01:00
}
//qDebug() << "LOADED BREAKPOINTS" << this << list.size();
2008-12-02 12:01:29 +01:00
}
void BreakHandler::updateMarkers()
{
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
for ( ; it != et; ++it)
updateMarker(it.key());
2008-12-02 12:01:29 +01:00
}
void BreakHandler::updateMarker(BreakpointId id)
{
Iterator it = m_storage.find(id);
BreakpointData *data = it->data;
QTC_ASSERT(data, return);
BreakpointMarker *marker = it->marker;
if (marker && (data->m_markerFileName != marker->fileName()
|| data->m_markerLineNumber != marker->lineNumber())) {
removeMarker(id);
marker = 0;
}
if (!marker && !data->m_markerFileName.isEmpty() && data->m_markerLineNumber > 0) {
marker = new BreakpointMarker(id, data->m_markerFileName, data->m_markerLineNumber);
it->marker = marker;
}
}
void BreakHandler::removeMarker(BreakpointId id)
{
Iterator it = m_storage.find(id);
BreakpointMarker *marker = it->marker;
it->marker = 0;
delete marker;
}
2008-12-02 12:01:29 +01:00
QVariant BreakHandler::headerData(int section,
Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
static QString headers[] = {
tr("Number"), tr("Function"), tr("File"), tr("Line"),
tr("Condition"), tr("Ignore"), tr("Threads"), tr("Address")
2008-12-02 12:01:29 +01:00
};
return headers[section];
}
return QVariant();
}
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(-1);
}
2008-12-02 12:01:29 +01:00
QVariant BreakHandler::data(const QModelIndex &mi, int role) const
{
static const QString empty = QString(QLatin1Char('-'));
QTC_ASSERT(mi.isValid(), return QVariant());
BreakpointId id = findBreakpointByIndex(mi);
ConstIterator it = m_storage.find(id);
BreakpointData *data = it->data;
QTC_ASSERT(data, return QVariant());
BreakpointResponse *response = it->response;
QTC_ASSERT(response, return QVariant());
2008-12-02 12:01:29 +01:00
switch (mi.column()) {
case 0:
if (role == Qt::DisplayRole) {
return QString("%1 - %2").arg(id).arg(response->bpNumber);
2008-12-02 12:01:29 +01:00
}
if (role == Qt::DecorationRole) {
if (data->isWatchpoint())
return m_watchpointIcon;
if (!data->isEnabled())
return m_disabledBreakpointIcon;
return data->isPending() ? m_pendingBreakPointIcon : m_breakpointIcon;
}
2008-12-02 12:01:29 +01:00
break;
case 1:
if (role == Qt::DisplayRole) {
const QString str = data->isPending()
? data->functionName() : response->bpFuncName;
2008-12-02 12:01:29 +01:00
return str.isEmpty() ? empty : str;
}
break;
case 2:
if (role == Qt::DisplayRole) {
QString str = data->isPending()
? data->fileName() : response->bpFileName;
2008-12-02 12:01:29 +01:00
str = QFileInfo(str).fileName();
2010-02-10 11:45:40 +01:00
// FIXME: better?
//if (data->bpMultiple && str.isEmpty() && !data->markerFileName.isEmpty())
// str = data->markerFileName;
str = str.isEmpty() ? empty : str;
if (data->useFullPath())
str = QDir::toNativeSeparators(QLatin1String("/.../") + str);
return str;
2008-12-02 12:01:29 +01:00
}
break;
case 3:
if (role == Qt::DisplayRole) {
2010-02-10 11:45:40 +01:00
// FIXME: better?
//if (data->bpMultiple && str.isEmpty() && !data->markerFileName.isEmpty())
// str = data->markerLineNumber;
const int nr = data->isPending()
? data->lineNumber() : response->bpLineNumber;
return nr ? QString::number(nr) : empty;
2008-12-02 12:01:29 +01:00
}
if (role == Qt::UserRole + 1)
return data->lineNumber();
2008-12-02 12:01:29 +01:00
break;
case 4:
if (role == Qt::DisplayRole)
return data->isPending() ? data->condition() : response->bpCondition;
2008-12-02 12:01:29 +01:00
if (role == Qt::ToolTipRole)
return tr("Breakpoint will only be hit if this condition is met.");
if (role == Qt::UserRole + 1)
return data->condition();
2008-12-02 12:01:29 +01:00
break;
case 5:
if (role == Qt::DisplayRole) {
const int ignoreCount =
data->isPending() ? data->ignoreCount() : response->bpIgnoreCount;
return ignoreCount ? QVariant(ignoreCount) : QVariant(QString());
}
2008-12-02 12:01:29 +01:00
if (role == Qt::ToolTipRole)
return tr("Breakpoint will only be hit after being ignored so many times.");
if (role == Qt::UserRole + 1)
return data->ignoreCount();
break;
case 6:
if (role == Qt::DisplayRole) {
if (data->isPending())
return !data->threadSpec().isEmpty() ? data->threadSpec() : tr("(all)");
else
return !response->bpThreadSpec.isEmpty() ? response->bpThreadSpec : tr("(all)");
}
if (role == Qt::ToolTipRole)
return tr("Breakpoint will only be hit in the specified thread(s).");
if (role == Qt::UserRole + 1)
return data->threadSpec();
break;
case 7:
if (role == Qt::DisplayRole) {
QString displayValue;
const quint64 address =
data->isWatchpoint() ? data->address() : response->bpAddress;
if (address)
displayValue += QString::fromAscii("0x%1").arg(address, 0, 16);
if (!response->bpState.isEmpty()) {
if (!displayValue.isEmpty())
displayValue += QLatin1Char(' ');
displayValue += QString::fromAscii(response->bpState);
}
return displayValue;
}
2008-12-02 12:01:29 +01:00
break;
}
if (role == Qt::ToolTipRole)
return debuggerCore()->boolSetting(UseToolTipsInBreakpointsView)
? data->toToolTip() : QVariant();
2008-12-02 12:01:29 +01:00
return QVariant();
}
#define GETTER(type, getter) \
type BreakHandler::getter(BreakpointId id) const \
{ \
BreakpointData *data = m_storage.value(id).data; \
QTC_ASSERT(data, return type()); \
return data->getter(); \
}
#define SETTER(type, setter) \
void BreakHandler::setter(BreakpointId id, const type &value) \
{ \
BreakpointData *data = m_storage.value(id).data; \
QTC_ASSERT(data, return); \
if (data->setter(value)) \
scheduleSynchronization(); \
}
#define PROPERTY(type, getter, setter) \
GETTER(type, getter) \
SETTER(type, setter)
2008-12-02 12:01:29 +01:00
PROPERTY(bool, useFullPath, setUseFullPath)
PROPERTY(QString, markerFileName, setMarkerFileName)
PROPERTY(QString, fileName, setFileName)
PROPERTY(QString, functionName, setFunctionName)
PROPERTY(int, markerLineNumber, setMarkerLineNumber)
PROPERTY(bool, isEnabled, setEnabled)
PROPERTY(BreakpointType, type, setType)
PROPERTY(BreakpointState, state, setState)
PROPERTY(QByteArray, threadSpec, setThreadSpec)
PROPERTY(QByteArray, condition, setCondition)
PROPERTY(int, lineNumber, setLineNumber)
PROPERTY(quint64, address, setAddress)
PROPERTY(int, ignoreCount, setIgnoreCount)
DebuggerEngine *BreakHandler::engine(BreakpointId id) const
{
BreakpointData *data = m_storage.value(id).data;
QTC_ASSERT(data, return 0);
return data->engine();
}
void BreakHandler::setEngine(BreakpointId id, DebuggerEngine *value)
{
BreakpointData *data = m_storage.value(id).data;
QTC_ASSERT(data, return);
QTC_ASSERT(data->state() == BreakpointNew, /**/);
QTC_ASSERT(!data->engine(), return);
data->setEngine(value);
data->setState(BreakpointInsertRequested);
updateMarker(id);
scheduleSynchronization();
}
void BreakHandler::ackCondition(BreakpointId id)
2008-12-02 12:01:29 +01:00
{
Iterator it = m_storage.find(id);
QTC_ASSERT(it != m_storage.end(), return);
it->response->bpCondition = it->data->condition();
updateMarker(id);
2008-12-02 12:01:29 +01:00
}
void BreakHandler::ackIgnoreCount(BreakpointId id)
2008-12-02 12:01:29 +01:00
{
Iterator it = m_storage.find(id);
QTC_ASSERT(it != m_storage.end(), return);
it->response->bpIgnoreCount = it->data->ignoreCount();
updateMarker(id);
2008-12-02 12:01:29 +01:00
}
Qt::ItemFlags BreakHandler::flags(const QModelIndex &index) const
{
// switch (index.column()) {
// //case 0:
// // return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
// default:
return QAbstractTableModel::flags(index);
// }
}
void BreakHandler::removeBreakpoint(BreakpointId id)
{
BreakpointData *data = m_storage.value(id).data;
if (data->state() == BreakpointInserted) {
qDebug() << "MARK AS CHANGED: " << id;
data->m_state = BreakpointRemoveRequested;
QTC_ASSERT(data->engine(), return);
debuggerCore()->synchronizeBreakpoints();
} else if (data->state() == BreakpointNew) {
data->m_state = BreakpointDead;
cleanupBreakpoint(id);
} else {
qDebug() << "CANNOT REMOVE IN STATE " << data->state();
}
}
2008-12-02 12:01:29 +01:00
void BreakHandler::appendBreakpoint(BreakpointData *data)
2008-12-02 12:01:29 +01:00
{
// Ok to be not thread-safe. The order does not matter and only the gui
// produces authoritative ids.
static quint64 currentId = 0;
2008-12-02 12:01:29 +01:00
BreakpointId id(++currentId);
BreakpointItem item;
item.data = data;
item.response = new BreakpointResponse;
m_storage.insert(id, item);
scheduleSynchronization();
}
void BreakHandler::toggleBreakpoint(const QString &fileName, int lineNumber,
quint64 address /* = 0 */)
2008-12-02 12:01:29 +01:00
{
BreakpointId id(-1);
if (address) {
id = findBreakpointByAddress(address);
} else {
id = findBreakpointByFileAndLine(fileName, lineNumber, true);
if (id == BreakpointId(-1))
id = findBreakpointByFileAndLine(fileName, lineNumber, false);
}
if (id != BreakpointId(-1)) {
removeBreakpoint(id);
} else {
BreakpointData *data = new BreakpointData;
if (address) {
data->setAddress(address);
} else {
data->setFileName(fileName);
data->setLineNumber(lineNumber);
}
data->setMarkerFileName(fileName);
data->setMarkerLineNumber(lineNumber);
appendBreakpoint(data);
}
debuggerCore()->synchronizeBreakpoints();
}
2008-12-02 12:01:29 +01:00
void BreakHandler::saveSessionData()
{
saveBreakpoints();
}
void BreakHandler::loadSessionData()
{
m_storage.clear();
2008-12-02 12:01:29 +01:00
loadBreakpoints();
}
void BreakHandler::breakByFunction(const QString &functionName)
{
2010-03-26 08:52:49 +01:00
// One breakpoint per function is enough for now. This does not handle
// combinations of multiple conditions and ignore counts, though.
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
for ( ; it != et; ++it) {
const BreakpointData *data = it->data;
2008-12-09 12:08:56 +01:00
QTC_ASSERT(data, break);
if (data->functionName() == functionName
&& data->condition().isEmpty()
&& data->ignoreCount() == 0)
2008-12-02 12:01:29 +01:00
return;
}
BreakpointData *data = new BreakpointData;
data->setType(BreakpointByFunction);
data->setFunctionName(functionName);
appendBreakpoint(data);
}
QIcon BreakHandler::icon(BreakpointId id) const
{
//if (!m_handler->isActive())
// return m_handler->emptyIcon();
const BreakpointData *data = m_storage.value(id).data;
QTC_ASSERT(data, return pendingBreakPointIcon());
//if (!isActive())
// return emptyIcon();
switch (data->state()) {
case BreakpointInserted:
return breakpointIcon();
default:
return pendingBreakPointIcon();
}
}
void BreakHandler::scheduleSynchronization()
{
if (m_syncTimerId == -1)
m_syncTimerId = startTimer(10);
}
void BreakHandler::timerEvent(QTimerEvent *event)
{
QTC_ASSERT(event->timerId() == m_syncTimerId, return);
killTimer(m_syncTimerId);
m_syncTimerId = -1;
//qDebug() << "BREAKPOINT SYNCRONIZATION STARTED";
debuggerCore()->synchronizeBreakpoints();
2008-12-02 12:01:29 +01:00
updateMarkers();
emit layoutChanged();
saveBreakpoints(); // FIXME: remove?
}
void BreakHandler::gotoLocation(BreakpointId id) const
{
ConstIterator it = m_storage.find(id);
QTC_ASSERT(it != m_storage.end(), return);
debuggerCore()->gotoLocation(
it->data->fileName(), it->data->lineNumber(), false);
}
void BreakHandler::updateLineNumberFromMarker(BreakpointId id, int lineNumber)
{
Iterator it = m_storage.find(id);
QTC_ASSERT(it != m_storage.end(), return);
//if (data->markerLineNumber == lineNumber)
// return;
if (it->data->markerLineNumber() != lineNumber) {
it->data->setMarkerLineNumber(lineNumber);
// FIXME: Should we tell gdb about the change?
// Ignore it for now, as we would require re-compilation
// and debugger re-start anyway.
//if (0 && data->bpLineNumber) {
// if (!data->bpNumber.trimmed().isEmpty()) {
// data->pending = true;
// }
//}
}
// Ignore updates to the "real" line number while the debugger is
// running, as this can be triggered by moving the breakpoint to
// the next line that generated code.
// FIXME: Do we need yet another data member?
if (it->response->bpNumber == 0) {
it->data->setLineNumber(lineNumber);
updateMarker(id);
}
}
BreakpointIds BreakHandler::allBreakpointIds() const
{
BreakpointIds ids;
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
for ( ; it != et; ++it)
ids.append(it.key());
return ids;
}
BreakpointIds BreakHandler::unclaimedBreakpointIds() const
{
return engineBreakpointIds(0);
}
BreakpointIds BreakHandler::engineBreakpointIds(DebuggerEngine *engine) const
{
BreakpointIds ids;
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
for ( ; it != et; ++it)
if (it->data->engine() == engine)
ids.append(it.key());
return ids;
}
void BreakHandler::notifyBreakpointInsertOk(BreakpointId id)
{
QTC_ASSERT(breakHandler()->state(id)== BreakpointInsertProceeding, /**/);
breakHandler()->setState(id, BreakpointInserted);
2008-12-02 12:01:29 +01:00
}
void BreakHandler::notifyBreakpointInsertFailed(BreakpointId id)
{
QTC_ASSERT(breakHandler()->state(id)== BreakpointInsertProceeding, /**/);
breakHandler()->setState(id, BreakpointDead);
}
void BreakHandler::notifyBreakpointRemoveOk(BreakpointId id)
{
QTC_ASSERT(state(id) == BreakpointRemoveProceeding, /**/);
setState(id, BreakpointDead);
cleanupBreakpoint(id);
}
void BreakHandler::notifyBreakpointRemoveFailed(BreakpointId id)
{
QTC_ASSERT(state(id) == BreakpointRemoveProceeding, /**/);
setState(id, BreakpointDead);
cleanupBreakpoint(id);
}
void BreakHandler::notifyBreakpointChangeOk(BreakpointId id)
{
QTC_ASSERT(state(id) == BreakpointChangeProceeding, /**/);
setState(id, BreakpointInserted);
}
void BreakHandler::notifyBreakpointChangeFailed(BreakpointId id)
{
QTC_ASSERT(state(id) == BreakpointChangeProceeding, /**/);
setState(id, BreakpointDead);
}
void BreakHandler::notifyBreakpointReleased(BreakpointId id)
{
//QTC_ASSERT(state(id) == BreakpointChangeProceeding, /**/);
Iterator it = m_storage.find(id);
QTC_ASSERT(it != m_storage.end(), return);
it->data->setState(BreakpointNew);
it->data->setEngine(0);
delete it->marker;
it->marker = 0;
delete it->response;
it->response = new BreakpointResponse();
updateMarker(id);
}
void BreakHandler::cleanupBreakpoint(BreakpointId id)
{
QTC_ASSERT(state(id) == BreakpointDead, /**/);
BreakpointItem item = m_storage.take(id);
item.destroy();
}
BreakpointResponse BreakHandler::response(BreakpointId id) const
{
ConstIterator it = m_storage.find(id);
QTC_ASSERT(it != m_storage.end(), return BreakpointResponse());
return *it->response;
}
void BreakHandler::setResponse(BreakpointId id, const BreakpointResponse &data)
{
Iterator it = m_storage.find(id);
QTC_ASSERT(it != m_storage.end(), return);
delete it->response;
it->response = new BreakpointResponse(data);
updateMarker(id);
}
#if 0
void BreakHandler::notifyBreakpointAdjusted(BreakpointId id)
{
QTC_ASSERT(state(id)== BreakpointChangeProceeding, /**/);
bp->bpNumber = rbp.bpNumber;
bp->bpCondition = rbp.bpCondition;
bp->bpIgnoreCount = rbp.bpIgnoreCount;
bp->bpFileName = rbp.bpFileName;
bp->bpFullName = rbp.bpFullName;
bp->bpLineNumber = rbp.bpLineNumber;
bp->bpCorrectedLineNumber = rbp.bpCorrectedLineNumber;
bp->bpThreadSpec = rbp.bpThreadSpec;
bp->bpFuncName = rbp.bpFuncName;
bp->bpAddress = rbp.bpAddress;
bp->bpMultiple = rbp.bpMultiple;
bp->bpEnabled = rbp.bpEnabled;
setState(id, BreakpointOk);
}
#endif
void BreakHandler::BreakpointItem::destroy()
{
delete data;
data = 0;
delete response;
response = 0;
delete marker;
marker = 0;
}
} // namespace Internal
} // namespace Debugger