2009-02-25 09:15:00 +01:00
|
|
|
/**************************************************************************
|
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
|
|
|
**
|
2009-06-17 00:01:27 +10:00
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Commercial Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** 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.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** 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.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** 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
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
**************************************************************************/
|
2008-12-02 15:08:31 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "breakhandler.h"
|
2010-10-25 14:00:19 +02:00
|
|
|
#include "breakpointmarker.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-09-23 16:11:25 +02:00
|
|
|
#include "debuggeractions.h"
|
2010-11-10 11:39:01 +01:00
|
|
|
#include "debuggercore.h"
|
2010-11-15 14:27:06 +01:00
|
|
|
#include "debuggerengine.h"
|
2010-05-07 15:16:31 +02:00
|
|
|
#include "debuggerstringutils.h"
|
2009-08-14 13:04:05 +02:00
|
|
|
|
2010-03-26 08:52:49 +01:00
|
|
|
#include <utils/qtcassert.h>
|
2008-12-09 16:18:28 +01:00
|
|
|
|
2010-10-18 14:54:42 +02:00
|
|
|
#include <QtCore/QDir>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <QtCore/QFileInfo>
|
|
|
|
|
|
2010-11-05 13:35:31 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// BreakHandler
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2010-11-10 11:39:01 +01:00
|
|
|
namespace Debugger {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2010-11-04 09:54:23 +01:00
|
|
|
BreakHandler::BreakHandler()
|
2010-06-16 11:08:54 +02:00
|
|
|
: m_breakpointIcon(_(":/debugger/images/breakpoint_16.png")),
|
2010-05-07 15:16:31 +02:00
|
|
|
m_disabledBreakpointIcon(_(":/debugger/images/breakpoint_disabled_16.png")),
|
|
|
|
|
m_pendingBreakPointIcon(_(":/debugger/images/breakpoint_pending_16.png")),
|
2010-09-01 14:39:19 +02:00
|
|
|
//m_emptyIcon(_(":/debugger/images/watchpoint.png")),
|
|
|
|
|
m_emptyIcon(_(":/debugger/images/breakpoint_pending_16.png")),
|
2010-07-13 17:16:31 +02:00
|
|
|
//m_emptyIcon(_(":/debugger/images/debugger_empty_14.png")),
|
2010-05-07 15:16:31 +02:00
|
|
|
m_watchpointIcon(_(":/debugger/images/watchpoint.png")),
|
2010-11-10 16:33:11 +01:00
|
|
|
m_syncTimerId(-1)
|
2010-11-04 09:54:23 +01:00
|
|
|
{}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-04 11:37:43 +01:00
|
|
|
BreakHandler::~BreakHandler()
|
2010-11-10 16:33:11 +01:00
|
|
|
{}
|
2008-12-04 11:37:43 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
int BreakHandler::columnCount(const QModelIndex &parent) const
|
|
|
|
|
{
|
2010-04-29 18:36:18 +02:00
|
|
|
return parent.isValid() ? 0 : 8;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int BreakHandler::rowCount(const QModelIndex &parent) const
|
|
|
|
|
{
|
2010-11-15 13:12:13 +01:00
|
|
|
return parent.isValid() ? 0 : m_storage.size();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
// FIXME: Only used by cdb. Move there?
|
2009-04-08 16:37:41 +02:00
|
|
|
bool BreakHandler::hasPendingBreakpoints() const
|
|
|
|
|
{
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
|
2010-11-10 16:33:11 +01:00
|
|
|
for ( ; it != et; ++it)
|
2010-11-15 14:12:05 +01:00
|
|
|
if (it->isPending())
|
2009-04-08 16:37:41 +02:00
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
static inline bool fileNameMatch(const QString &f1, const QString &f2)
|
2010-03-26 08:52:49 +01:00
|
|
|
{
|
2010-11-10 16:33:11 +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
|
|
|
}
|
|
|
|
|
|
2010-11-15 14:12:05 +01:00
|
|
|
static bool isSimilarTo(const BreakpointData &data, const BreakpointResponse &needle)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-11-10 16:33:11 +01:00
|
|
|
// Clear hit.
|
|
|
|
|
// Clear miss.
|
2010-11-15 14:12:05 +01:00
|
|
|
if (needle.bpType != UnknownType && data.type() != UnknownType
|
|
|
|
|
&& data.type() != needle.bpType)
|
2010-11-10 16:33:11 +01:00
|
|
|
return false;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
// Clear hit.
|
2010-11-15 14:12:05 +01:00
|
|
|
if (data.address() && data.address() == needle.bpAddress)
|
2010-11-10 16:33:11 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// At least at a position we were looking for.
|
|
|
|
|
// FIXME: breaks multiple breakpoints at the same location
|
2010-11-15 14:12:05 +01:00
|
|
|
if (!data.fileName().isEmpty()
|
|
|
|
|
&& fileNameMatch(data.fileName(), needle.bpFileName)
|
|
|
|
|
&& data.lineNumber() == needle.bpLineNumber)
|
2010-11-10 16:33:11 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// At least at a position we were looking for.
|
|
|
|
|
// FIXME: breaks multiple breakpoints at the same location
|
2010-11-15 14:12:05 +01:00
|
|
|
if (!data.fileName().isEmpty()
|
|
|
|
|
&& fileNameMatch(data.fileName(), needle.bpFileName)
|
|
|
|
|
&& data.lineNumber() == needle.bpLineNumber)
|
2010-11-10 16:33:11 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
BreakpointId BreakHandler::findSimilarBreakpoint(const BreakpointResponse &needle) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-02-11 17:29:10 +01:00
|
|
|
// Search a breakpoint we might refer to.
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
|
2010-11-10 16:33:11 +01:00
|
|
|
for ( ; it != et; ++it) {
|
|
|
|
|
const BreakpointId id = it.key();
|
2010-11-15 14:12:05 +01:00
|
|
|
const BreakpointData &data = it->data;
|
|
|
|
|
const BreakpointResponse &response = it->response;
|
|
|
|
|
qDebug() << "COMPARING " << data.toString() << " WITH " << needle.toString();
|
|
|
|
|
if (response.bpNumber && response.bpNumber == needle.bpNumber)
|
2010-11-10 16:33:11 +01:00
|
|
|
return id;
|
|
|
|
|
|
|
|
|
|
if (isSimilarTo(data, needle))
|
|
|
|
|
return id;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-11-10 16:33:11 +01:00
|
|
|
return BreakpointId(-1);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
BreakpointId BreakHandler::findBreakpointByNumber(int bpNumber) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
|
2010-11-10 16:33:11 +01:00
|
|
|
for ( ; it != et; ++it)
|
2010-11-15 14:12:05 +01:00
|
|
|
if (it->response.bpNumber == bpNumber)
|
2010-11-10 16:33:11 +01:00
|
|
|
return it.key();
|
|
|
|
|
return BreakpointId(-1);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
BreakpointId BreakHandler::findBreakpointByFunction(const QString &functionName) const
|
2010-05-19 17:34:47 +02:00
|
|
|
{
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
|
2010-11-10 16:33:11 +01:00
|
|
|
for ( ; it != et; ++it)
|
2010-11-15 14:12:05 +01:00
|
|
|
if (it->data.functionName() == functionName)
|
2010-11-10 16:33:11 +01:00
|
|
|
return it.key();
|
|
|
|
|
return BreakpointId(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BreakpointId BreakHandler::findBreakpointByAddress(quint64 address) const
|
|
|
|
|
{
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
|
2010-11-10 16:33:11 +01:00
|
|
|
for ( ; it != et; ++it)
|
2010-11-15 14:12:05 +01:00
|
|
|
if (it->data.address() == address)
|
2010-11-10 16:33:11 +01:00
|
|
|
return it.key();
|
|
|
|
|
return BreakpointId(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BreakpointId BreakHandler::findBreakpointByFileAndLine(const QString &fileName,
|
|
|
|
|
int lineNumber, bool useMarkerPosition)
|
|
|
|
|
{
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
|
2010-11-10 16:33:11 +01:00
|
|
|
for ( ; it != et; ++it)
|
2010-11-15 14:12:05 +01:00
|
|
|
if (it->data.isLocatedAt(fileName, lineNumber, useMarkerPosition))
|
2010-11-10 16:33:11 +01:00
|
|
|
return it.key();
|
|
|
|
|
return BreakpointId(-1);
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-15 15:24:27 +01:00
|
|
|
const BreakpointData *BreakHandler::breakpointById(BreakpointId id) const
|
|
|
|
|
{
|
|
|
|
|
ConstIterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return 0);
|
|
|
|
|
return &it->data;
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-15 14:12:05 +01:00
|
|
|
BreakpointData *BreakHandler::breakpointById(BreakpointId id)
|
2010-11-10 16:33:11 +01:00
|
|
|
{
|
2010-11-15 14:12:05 +01:00
|
|
|
Iterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return 0);
|
|
|
|
|
return &it->data;
|
2010-11-10 16:33:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BreakpointId BreakHandler::findWatchpointByAddress(quint64 address) const
|
|
|
|
|
{
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
|
2010-11-10 16:33:11 +01:00
|
|
|
for ( ; it != et; ++it)
|
2010-11-15 14:12:05 +01:00
|
|
|
if (it->data.isWatchpoint() && it->data.address() == address)
|
2010-11-10 16:33:11 +01:00
|
|
|
return it.key();
|
|
|
|
|
return BreakpointId(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::setWatchpointByAddress(quint64 address)
|
|
|
|
|
{
|
|
|
|
|
const int id = findWatchpointByAddress(address);
|
|
|
|
|
if (id == -1) {
|
2010-11-15 14:12:05 +01:00
|
|
|
BreakpointData data;
|
|
|
|
|
data.setType(Watchpoint);
|
|
|
|
|
data.setAddress(address);
|
2010-11-10 16:33:11 +01:00
|
|
|
appendBreakpoint(data);
|
|
|
|
|
scheduleSynchronization();
|
|
|
|
|
} else {
|
|
|
|
|
qDebug() << "WATCHPOINT EXISTS";
|
|
|
|
|
// removeBreakpoint(index);
|
2010-05-19 17:34:47 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
bool BreakHandler::hasWatchpointAt(quint64 address) const
|
2010-05-20 19:35:34 +02:00
|
|
|
{
|
2010-11-10 16:33:11 +01:00
|
|
|
return findWatchpointByAddress(address) != BreakpointId(-1);
|
2010-05-20 19:35:34 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void BreakHandler::saveBreakpoints()
|
|
|
|
|
{
|
2010-06-16 11:08:54 +02:00
|
|
|
//qDebug() << "SAVING BREAKPOINTS...";
|
2010-11-10 11:39:01 +01:00
|
|
|
QTC_ASSERT(debuggerCore(), return);
|
2008-12-02 12:01:29 +01:00
|
|
|
QList<QVariant> list;
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
|
2010-11-10 16:33:11 +01:00
|
|
|
for ( ; it != et; ++it) {
|
2010-11-15 14:12:05 +01:00
|
|
|
const BreakpointData &data = it->data;
|
2008-12-02 12:01:29 +01:00
|
|
|
QMap<QString, QVariant> map;
|
2010-05-07 15:16:31 +02:00
|
|
|
// Do not persist Watchpoints.
|
2010-11-15 14:12:05 +01:00
|
|
|
//if (data.isWatchpoint())
|
2010-05-07 15:16:31 +02:00
|
|
|
// continue;
|
2010-11-15 14:12:05 +01:00
|
|
|
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())
|
2010-05-07 15:16:31 +02:00
|
|
|
map.insert(_("disabled"), _("1"));
|
2010-11-15 14:12:05 +01:00
|
|
|
if (data.useFullPath())
|
2010-05-07 15:16:31 +02:00
|
|
|
map.insert(_("usefullpath"), _("1"));
|
2008-12-02 12:01:29 +01:00
|
|
|
list.append(map);
|
|
|
|
|
}
|
2010-11-10 11:39:01 +01:00
|
|
|
debuggerCore()->setSessionValue("Breakpoints", list);
|
2010-06-16 11:08:54 +02:00
|
|
|
//qDebug() << "SAVED BREAKPOINTS" << this << list.size();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::loadBreakpoints()
|
|
|
|
|
{
|
2010-11-10 11:39:01 +01:00
|
|
|
QTC_ASSERT(debuggerCore(), return);
|
2010-06-16 11:08:54 +02:00
|
|
|
//qDebug() << "LOADING BREAKPOINTS...";
|
2010-11-10 11:39:01 +01:00
|
|
|
QVariant value = debuggerCore()->sessionValue("Breakpoints");
|
2008-12-02 12:01:29 +01:00
|
|
|
QList<QVariant> list = value.toList();
|
2010-11-10 16:33:11 +01:00
|
|
|
//clear();
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (const QVariant &var, list) {
|
|
|
|
|
const QMap<QString, QVariant> map = var.toMap();
|
2010-11-15 14:12:05 +01:00
|
|
|
BreakpointData data;
|
2010-05-07 15:16:31 +02:00
|
|
|
QVariant v = map.value(_("filename"));
|
2009-06-30 15:50:56 +02:00
|
|
|
if (v.isValid())
|
2010-11-15 14:12:05 +01:00
|
|
|
data.setFileName(v.toString());
|
2010-05-07 15:16:31 +02:00
|
|
|
v = map.value(_("linenumber"));
|
2009-06-30 15:50:56 +02:00
|
|
|
if (v.isValid())
|
2010-11-15 14:12:05 +01:00
|
|
|
data.setLineNumber(v.toString().toInt());
|
2010-05-07 15:16:31 +02:00
|
|
|
v = map.value(_("condition"));
|
2009-06-30 15:50:56 +02:00
|
|
|
if (v.isValid())
|
2010-11-15 14:12:05 +01:00
|
|
|
data.setCondition(v.toString().toLatin1());
|
2010-05-07 15:16:31 +02:00
|
|
|
v = map.value(_("address"));
|
|
|
|
|
if (v.isValid())
|
2010-11-15 14:12:05 +01:00
|
|
|
data.setAddress(v.toString().toULongLong());
|
2010-05-07 15:16:31 +02:00
|
|
|
v = map.value(_("ignorecount"));
|
2009-06-30 15:50:56 +02:00
|
|
|
if (v.isValid())
|
2010-11-15 14:12:05 +01:00
|
|
|
data.setIgnoreCount(v.toString().toInt());
|
2010-05-07 15:16:31 +02:00
|
|
|
v = map.value(_("threadspec"));
|
2010-04-29 18:36:18 +02:00
|
|
|
if (v.isValid())
|
2010-11-15 14:12:05 +01:00
|
|
|
data.setThreadSpec(v.toString().toLatin1());
|
2010-05-07 15:16:31 +02:00
|
|
|
v = map.value(_("funcname"));
|
2009-06-30 15:50:56 +02:00
|
|
|
if (v.isValid())
|
2010-11-15 14:12:05 +01:00
|
|
|
data.setFunctionName(v.toString());
|
2010-05-07 15:16:31 +02:00
|
|
|
v = map.value(_("disabled"));
|
2009-06-30 15:50:56 +02:00
|
|
|
if (v.isValid())
|
2010-11-15 14:12:05 +01:00
|
|
|
data.setEnabled(!v.toInt());
|
2010-05-07 15:16:31 +02:00
|
|
|
v = map.value(_("usefullpath"));
|
2009-06-30 15:50:56 +02:00
|
|
|
if (v.isValid())
|
2010-11-15 14:12:05 +01:00
|
|
|
data.setUseFullPath(bool(v.toInt()));
|
2010-05-07 15:16:31 +02:00
|
|
|
v = map.value(_("type"));
|
|
|
|
|
if (v.isValid())
|
2010-11-15 14:12:05 +01:00
|
|
|
data.setType(BreakpointType(v.toInt()));
|
|
|
|
|
data.setMarkerFileName(data.fileName());
|
|
|
|
|
data.setMarkerLineNumber(data.lineNumber());
|
2010-11-10 16:33:11 +01:00
|
|
|
appendBreakpoint(data);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-06-16 11:08:54 +02:00
|
|
|
//qDebug() << "LOADED BREAKPOINTS" << this << list.size();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::updateMarkers()
|
|
|
|
|
{
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
|
2010-11-10 16:33:11 +01:00
|
|
|
for ( ; it != et; ++it)
|
|
|
|
|
updateMarker(it.key());
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
void BreakHandler::updateMarker(BreakpointId id)
|
2010-10-25 14:00:19 +02:00
|
|
|
{
|
2010-11-15 13:12:13 +01:00
|
|
|
Iterator it = m_storage.find(id);
|
2010-11-15 14:12:05 +01:00
|
|
|
QTC_ASSERT(it != m_storage.end(), return);
|
|
|
|
|
const BreakpointData &data = it->data;
|
2010-11-15 13:12:13 +01:00
|
|
|
BreakpointMarker *marker = it->marker;
|
2010-11-10 16:33:11 +01:00
|
|
|
|
2010-11-15 14:12:05 +01:00
|
|
|
if (marker && (data.m_markerFileName != marker->fileName()
|
2010-11-15 14:27:06 +01:00
|
|
|
|| data.m_markerLineNumber != marker->lineNumber()))
|
|
|
|
|
it->destroyMarker();
|
2010-10-25 14:00:19 +02:00
|
|
|
|
2010-11-15 14:12:05 +01:00
|
|
|
if (!marker && !data.m_markerFileName.isEmpty() && data.m_markerLineNumber > 0) {
|
|
|
|
|
marker = new BreakpointMarker(id, data.m_markerFileName, data.m_markerLineNumber);
|
2010-11-15 13:12:13 +01:00
|
|
|
it->marker = marker;
|
2010-10-25 14:00:19 +02:00
|
|
|
}
|
|
|
|
|
}
|
2010-11-10 16:33:11 +01:00
|
|
|
|
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"),
|
2010-04-29 18:36:18 +02:00
|
|
|
tr("Condition"), tr("Ignore"), tr("Threads"), tr("Address")
|
2008-12-02 12:01:29 +01:00
|
|
|
};
|
|
|
|
|
return headers[section];
|
|
|
|
|
}
|
|
|
|
|
return QVariant();
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
BreakpointId BreakHandler::findBreakpointByIndex(const QModelIndex &index) const
|
|
|
|
|
{
|
|
|
|
|
int r = index.row();
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
|
2010-11-10 16:33:11 +01:00
|
|
|
for (int i = 0; it != et; ++it, ++i)
|
|
|
|
|
if (i == r)
|
|
|
|
|
return it.key();
|
|
|
|
|
return BreakpointId(-1);
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-15 15:30:39 +01:00
|
|
|
BreakpointIds BreakHandler::findBreakpointsByIndex(const QList<QModelIndex> &list) const
|
|
|
|
|
{
|
|
|
|
|
BreakpointIds ids;
|
|
|
|
|
foreach (const QModelIndex &index, list)
|
|
|
|
|
ids.append(findBreakpointByIndex(index));
|
|
|
|
|
return ids;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QVariant BreakHandler::data(const QModelIndex &mi, int role) const
|
|
|
|
|
{
|
|
|
|
|
static const QString empty = QString(QLatin1Char('-'));
|
|
|
|
|
|
2010-11-15 14:12:05 +01:00
|
|
|
if (!mi.isValid())
|
|
|
|
|
return QVariant();
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
BreakpointId id = findBreakpointByIndex(mi);
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.find(id);
|
2010-11-15 14:12:05 +01:00
|
|
|
QTC_ASSERT(it != m_storage.end(), return QVariant());
|
|
|
|
|
const BreakpointData &data = it->data;
|
|
|
|
|
const BreakpointResponse &response = it->response;
|
2010-06-16 11:08:54 +02:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
switch (mi.column()) {
|
|
|
|
|
case 0:
|
|
|
|
|
if (role == Qt::DisplayRole) {
|
2010-11-15 14:12:05 +01:00
|
|
|
return QString("%1 - %2").arg(id).arg(response.bpNumber);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-02-10 10:47:34 +01:00
|
|
|
if (role == Qt::DecorationRole) {
|
2010-11-15 14:12:05 +01:00
|
|
|
if (data.isWatchpoint())
|
2010-05-07 15:16:31 +02:00
|
|
|
return m_watchpointIcon;
|
2010-11-15 14:12:05 +01:00
|
|
|
if (!data.isEnabled())
|
2010-02-10 10:47:34 +01:00
|
|
|
return m_disabledBreakpointIcon;
|
2010-11-15 14:12:05 +01:00
|
|
|
return it->isPending() ? m_pendingBreakPointIcon : m_breakpointIcon;
|
2010-02-10 10:47:34 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
if (role == Qt::DisplayRole) {
|
2010-11-15 14:12:05 +01:00
|
|
|
const QString str = it->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) {
|
2010-11-15 14:12:05 +01:00
|
|
|
QString str = it->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?
|
2010-11-15 14:12:05 +01:00
|
|
|
//if (data.bpMultiple && str.isEmpty() && !data.markerFileName.isEmpty())
|
|
|
|
|
// str = data.markerFileName;
|
2009-05-11 13:21:59 +02:00
|
|
|
str = str.isEmpty() ? empty : str;
|
2010-11-15 14:12:05 +01:00
|
|
|
if (data.useFullPath())
|
2010-10-18 14:54:42 +02:00
|
|
|
str = QDir::toNativeSeparators(QLatin1String("/.../") + str);
|
2009-05-11 13:21:59 +02:00
|
|
|
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?
|
2010-11-15 14:12:05 +01:00
|
|
|
//if (data.bpMultiple && str.isEmpty() && !data.markerFileName.isEmpty())
|
|
|
|
|
// str = data.markerLineNumber;
|
|
|
|
|
const int nr = it->isPending()
|
|
|
|
|
? data.lineNumber() : response.bpLineNumber;
|
2010-09-21 14:26:45 +02:00
|
|
|
return nr ? QString::number(nr) : empty;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-04-29 18:36:18 +02:00
|
|
|
if (role == Qt::UserRole + 1)
|
2010-11-15 14:12:05 +01:00
|
|
|
return data.lineNumber();
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
if (role == Qt::DisplayRole)
|
2010-11-15 14:12:05 +01:00
|
|
|
return it->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.");
|
2010-04-29 18:36:18 +02:00
|
|
|
if (role == Qt::UserRole + 1)
|
2010-11-15 14:12:05 +01:00
|
|
|
return data.condition();
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
case 5:
|
2010-09-21 14:26:45 +02:00
|
|
|
if (role == Qt::DisplayRole) {
|
2010-11-10 16:33:11 +01:00
|
|
|
const int ignoreCount =
|
2010-11-15 14:12:05 +01:00
|
|
|
it->isPending() ? data.ignoreCount() : response.bpIgnoreCount;
|
2010-09-21 14:26:45 +02:00
|
|
|
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.");
|
2010-04-29 18:36:18 +02:00
|
|
|
if (role == Qt::UserRole + 1)
|
2010-11-15 14:12:05 +01:00
|
|
|
return data.ignoreCount();
|
2010-06-11 13:39:47 +10:00
|
|
|
break;
|
2009-10-01 11:22:44 +02:00
|
|
|
case 6:
|
2010-04-29 18:36:18 +02:00
|
|
|
if (role == Qt::DisplayRole) {
|
2010-11-15 14:12:05 +01:00
|
|
|
if (it->isPending())
|
|
|
|
|
return !data.threadSpec().isEmpty() ? data.threadSpec() : tr("(all)");
|
2010-04-29 18:36:18 +02:00
|
|
|
else
|
2010-11-15 14:12:05 +01:00
|
|
|
return !response.bpThreadSpec.isEmpty() ? response.bpThreadSpec : tr("(all)");
|
2010-04-29 18:36:18 +02:00
|
|
|
}
|
|
|
|
|
if (role == Qt::ToolTipRole)
|
|
|
|
|
return tr("Breakpoint will only be hit in the specified thread(s).");
|
|
|
|
|
if (role == Qt::UserRole + 1)
|
2010-11-15 14:12:05 +01:00
|
|
|
return data.threadSpec();
|
2010-06-11 13:39:47 +10:00
|
|
|
break;
|
2010-04-29 18:36:18 +02:00
|
|
|
case 7:
|
2010-05-07 15:16:31 +02:00
|
|
|
if (role == Qt::DisplayRole) {
|
2010-09-21 14:26:45 +02:00
|
|
|
QString displayValue;
|
2010-11-10 16:33:11 +01:00
|
|
|
const quint64 address =
|
2010-11-15 14:12:05 +01:00
|
|
|
data.isWatchpoint() ? data.address() : response.bpAddress;
|
2010-11-10 16:33:11 +01:00
|
|
|
if (address)
|
|
|
|
|
displayValue += QString::fromAscii("0x%1").arg(address, 0, 16);
|
2010-11-15 14:12:05 +01:00
|
|
|
if (!response.bpState.isEmpty()) {
|
2010-09-21 14:26:45 +02:00
|
|
|
if (!displayValue.isEmpty())
|
|
|
|
|
displayValue += QLatin1Char(' ');
|
2010-11-15 14:12:05 +01:00
|
|
|
displayValue += QString::fromAscii(response.bpState);
|
2010-09-21 14:26:45 +02:00
|
|
|
}
|
|
|
|
|
return displayValue;
|
2010-06-16 11:08:54 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (role == Qt::ToolTipRole)
|
2010-11-10 16:33:11 +01:00
|
|
|
return debuggerCore()->boolSetting(UseToolTipsInBreakpointsView)
|
2010-11-15 14:27:06 +01:00
|
|
|
? QVariant(it->toToolTip()) : QVariant();
|
2010-11-10 16:33:11 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
return QVariant();
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
#define GETTER(type, getter) \
|
|
|
|
|
type BreakHandler::getter(BreakpointId id) const \
|
|
|
|
|
{ \
|
2010-11-15 14:12:05 +01:00
|
|
|
ConstIterator it = m_storage.find(id); \
|
2010-11-15 15:05:39 +01:00
|
|
|
QTC_ASSERT(it != m_storage.end(), \
|
|
|
|
|
qDebug() << "ID" << id << "NOT KNOWN"; \
|
|
|
|
|
return type()); \
|
2010-11-15 14:12:05 +01:00
|
|
|
return it->data.getter(); \
|
2009-04-28 15:08:52 +02:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
#define SETTER(type, setter) \
|
|
|
|
|
void BreakHandler::setter(BreakpointId id, const type &value) \
|
|
|
|
|
{ \
|
2010-11-15 14:12:05 +01:00
|
|
|
Iterator it = m_storage.find(id); \
|
2010-11-15 15:05:39 +01:00
|
|
|
QTC_ASSERT(it != m_storage.end(), \
|
|
|
|
|
qDebug() << "ID" << id << "NOT KNOWN"; return); \
|
2010-11-15 16:22:51 +01:00
|
|
|
if (!it->data.setter(value)) \
|
|
|
|
|
return; \
|
|
|
|
|
it->state = BreakpointChangeRequested; \
|
|
|
|
|
scheduleSynchronization(); \
|
2010-09-28 13:14:14 +02:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
#define PROPERTY(type, getter, setter) \
|
|
|
|
|
GETTER(type, getter) \
|
|
|
|
|
SETTER(type, setter)
|
2009-05-12 14:28:27 +02:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
PROPERTY(bool, useFullPath, setUseFullPath)
|
|
|
|
|
PROPERTY(QString, markerFileName, setMarkerFileName)
|
|
|
|
|
PROPERTY(QString, fileName, setFileName)
|
|
|
|
|
PROPERTY(QString, functionName, setFunctionName)
|
|
|
|
|
PROPERTY(int, markerLineNumber, setMarkerLineNumber)
|
|
|
|
|
PROPERTY(BreakpointType, type, setType)
|
|
|
|
|
PROPERTY(QByteArray, threadSpec, setThreadSpec)
|
|
|
|
|
PROPERTY(QByteArray, condition, setCondition)
|
|
|
|
|
PROPERTY(int, lineNumber, setLineNumber)
|
|
|
|
|
PROPERTY(quint64, address, setAddress)
|
2010-11-15 12:32:51 +01:00
|
|
|
PROPERTY(int, ignoreCount, setIgnoreCount)
|
2010-11-10 16:33:11 +01:00
|
|
|
|
2010-11-15 15:05:39 +01:00
|
|
|
bool BreakHandler::isEnabled(BreakpointId id) const
|
|
|
|
|
{
|
|
|
|
|
ConstIterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return BreakpointDead);
|
|
|
|
|
return it->data.isEnabled();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::setEnabled(BreakpointId id, bool on)
|
|
|
|
|
{
|
|
|
|
|
Iterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return);
|
|
|
|
|
//qDebug() << "SET ENABLED: " << id << it->data.isEnabled() << on;
|
|
|
|
|
if (it->data.setEnabled(on)) {
|
|
|
|
|
it->destroyMarker();
|
2010-11-15 16:22:51 +01:00
|
|
|
it->state = BreakpointChangeRequested;
|
2010-11-15 15:05:39 +01:00
|
|
|
updateMarker(id);
|
|
|
|
|
scheduleSynchronization();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-15 14:12:05 +01:00
|
|
|
BreakpointState BreakHandler::state(BreakpointId id) const
|
|
|
|
|
{
|
|
|
|
|
ConstIterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return BreakpointDead);
|
|
|
|
|
return it->state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::setState(BreakpointId id, BreakpointState state)
|
|
|
|
|
{
|
|
|
|
|
Iterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return);
|
|
|
|
|
it->state = state;
|
|
|
|
|
updateMarker(id);
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
DebuggerEngine *BreakHandler::engine(BreakpointId id) const
|
2009-04-28 15:08:52 +02:00
|
|
|
{
|
2010-11-15 14:12:05 +01:00
|
|
|
ConstIterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return 0);
|
|
|
|
|
return it->engine;
|
2009-04-28 15:08:52 +02:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
void BreakHandler::setEngine(BreakpointId id, DebuggerEngine *value)
|
2009-04-28 15:08:52 +02:00
|
|
|
{
|
2010-11-15 14:12:05 +01:00
|
|
|
Iterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return);
|
|
|
|
|
QTC_ASSERT(it->state == BreakpointNew, /**/);
|
|
|
|
|
QTC_ASSERT(!it->engine, return);
|
|
|
|
|
it->engine = value;
|
|
|
|
|
it->state = BreakpointInsertRequested;
|
2010-11-10 16:33:11 +01:00
|
|
|
updateMarker(id);
|
|
|
|
|
scheduleSynchronization();
|
2009-04-28 15:08:52 +02:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
void BreakHandler::ackCondition(BreakpointId id)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-11-15 13:12:13 +01:00
|
|
|
Iterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return);
|
2010-11-15 14:12:05 +01:00
|
|
|
it->response.bpCondition = it->data.condition();
|
2010-11-10 16:33:11 +01:00
|
|
|
updateMarker(id);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
void BreakHandler::ackIgnoreCount(BreakpointId id)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-11-15 13:12:13 +01:00
|
|
|
Iterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return);
|
2010-11-15 14:12:05 +01:00
|
|
|
it->response.bpIgnoreCount = it->data.ignoreCount();
|
2010-11-10 16:33:11 +01:00
|
|
|
updateMarker(id);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-11-15 16:22:51 +01:00
|
|
|
void BreakHandler::ackEnabled(BreakpointId id)
|
|
|
|
|
{
|
|
|
|
|
Iterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return);
|
|
|
|
|
it->response.bpEnabled = it->data.isEnabled();
|
|
|
|
|
updateMarker(id);
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
Qt::ItemFlags BreakHandler::flags(const QModelIndex &index) const
|
2010-05-12 16:48:04 +02:00
|
|
|
{
|
2010-11-10 16:33:11 +01:00
|
|
|
// switch (index.column()) {
|
|
|
|
|
// //case 0:
|
|
|
|
|
// // return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
|
|
|
|
|
// default:
|
|
|
|
|
return QAbstractTableModel::flags(index);
|
|
|
|
|
// }
|
2010-05-12 16:48:04 +02:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
void BreakHandler::removeBreakpoint(BreakpointId id)
|
2009-04-28 15:08:52 +02:00
|
|
|
{
|
2010-11-15 14:12:05 +01:00
|
|
|
Iterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return);
|
|
|
|
|
if (it->state == BreakpointInserted) {
|
2010-11-10 16:33:11 +01:00
|
|
|
qDebug() << "MARK AS CHANGED: " << id;
|
2010-11-15 14:12:05 +01:00
|
|
|
it->state = BreakpointRemoveRequested;
|
|
|
|
|
QTC_ASSERT(it->engine, return);
|
2010-11-10 16:33:11 +01:00
|
|
|
debuggerCore()->synchronizeBreakpoints();
|
2010-11-15 14:12:05 +01:00
|
|
|
} else if (it->state == BreakpointNew) {
|
|
|
|
|
it->state = BreakpointDead;
|
2010-11-10 16:33:11 +01:00
|
|
|
cleanupBreakpoint(id);
|
2009-04-28 15:08:52 +02:00
|
|
|
} else {
|
2010-11-15 14:12:05 +01:00
|
|
|
qDebug() << "CANNOT REMOVE IN STATE " << it->state;
|
2009-04-28 15:08:52 +02:00
|
|
|
}
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-11-15 14:12:05 +01:00
|
|
|
void BreakHandler::appendBreakpoint(const BreakpointData &data)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-11-10 16:33:11 +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
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
BreakpointId id(++currentId);
|
2010-11-15 13:12:13 +01:00
|
|
|
BreakpointItem item;
|
|
|
|
|
item.data = data;
|
|
|
|
|
m_storage.insert(id, item);
|
2010-11-10 16:33:11 +01:00
|
|
|
scheduleSynchronization();
|
2010-06-25 16:06:48 +02:00
|
|
|
}
|
|
|
|
|
|
2010-09-21 14:26:45 +02:00
|
|
|
void BreakHandler::toggleBreakpoint(const QString &fileName, int lineNumber,
|
|
|
|
|
quint64 address /* = 0 */)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-11-10 16:33:11 +01:00
|
|
|
BreakpointId id(-1);
|
2010-10-05 11:01:14 +02:00
|
|
|
|
|
|
|
|
if (address) {
|
2010-11-10 16:33:11 +01:00
|
|
|
id = findBreakpointByAddress(address);
|
2010-10-05 11:01:14 +02:00
|
|
|
} else {
|
2010-11-10 16:33:11 +01:00
|
|
|
id = findBreakpointByFileAndLine(fileName, lineNumber, true);
|
|
|
|
|
if (id == BreakpointId(-1))
|
|
|
|
|
id = findBreakpointByFileAndLine(fileName, lineNumber, false);
|
2010-10-05 11:01:14 +02:00
|
|
|
}
|
2010-09-21 14:26:45 +02:00
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
if (id != BreakpointId(-1)) {
|
|
|
|
|
removeBreakpoint(id);
|
2010-06-25 16:06:48 +02:00
|
|
|
} else {
|
2010-11-15 14:12:05 +01:00
|
|
|
BreakpointData data;
|
2010-09-21 14:26:45 +02:00
|
|
|
if (address) {
|
2010-11-15 14:12:05 +01:00
|
|
|
data.setAddress(address);
|
2010-09-21 14:26:45 +02:00
|
|
|
} else {
|
2010-11-15 14:12:05 +01:00
|
|
|
data.setFileName(fileName);
|
|
|
|
|
data.setLineNumber(lineNumber);
|
2010-09-21 14:26:45 +02:00
|
|
|
}
|
2010-11-15 14:12:05 +01:00
|
|
|
data.setMarkerFileName(fileName);
|
|
|
|
|
data.setMarkerLineNumber(lineNumber);
|
2010-06-25 16:06:48 +02:00
|
|
|
appendBreakpoint(data);
|
2010-06-25 15:02:53 +02:00
|
|
|
}
|
2010-11-10 16:33:11 +01:00
|
|
|
debuggerCore()->synchronizeBreakpoints();
|
2010-06-25 16:06:48 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void BreakHandler::saveSessionData()
|
|
|
|
|
{
|
|
|
|
|
saveBreakpoints();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::loadSessionData()
|
|
|
|
|
{
|
2010-11-15 13:12:13 +01:00
|
|
|
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.
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
|
2010-11-10 16:33:11 +01:00
|
|
|
for ( ; it != et; ++it) {
|
2010-11-15 14:12:05 +01:00
|
|
|
const BreakpointData &data = it->data;
|
|
|
|
|
if (data.functionName() == functionName
|
|
|
|
|
&& data.condition().isEmpty()
|
|
|
|
|
&& data.ignoreCount() == 0)
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2010-11-15 14:12:05 +01:00
|
|
|
BreakpointData data;
|
|
|
|
|
data.setType(BreakpointByFunction);
|
|
|
|
|
data.setFunctionName(functionName);
|
2010-11-10 16:33:11 +01:00
|
|
|
appendBreakpoint(data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QIcon BreakHandler::icon(BreakpointId id) const
|
|
|
|
|
{
|
2010-11-15 14:12:05 +01:00
|
|
|
ConstIterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return pendingBreakPointIcon());
|
2010-11-15 15:05:39 +01:00
|
|
|
if (!it->data.isEnabled())
|
|
|
|
|
return m_disabledBreakpointIcon;
|
|
|
|
|
if (it->state == BreakpointInserted)
|
2010-11-10 16:33:11 +01:00
|
|
|
return breakpointIcon();
|
2010-11-15 15:05:39 +01:00
|
|
|
return pendingBreakPointIcon();
|
2010-11-10 16:33:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
2010-11-10 16:33:11 +01:00
|
|
|
emit layoutChanged();
|
|
|
|
|
saveBreakpoints(); // FIXME: remove?
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::gotoLocation(BreakpointId id) const
|
|
|
|
|
{
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return);
|
2010-11-10 16:33:11 +01:00
|
|
|
debuggerCore()->gotoLocation(
|
2010-11-15 14:12:05 +01:00
|
|
|
it->data.fileName(), it->data.lineNumber(), false);
|
2010-11-10 16:33:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::updateLineNumberFromMarker(BreakpointId id, int lineNumber)
|
|
|
|
|
{
|
2010-11-15 13:12:13 +01:00
|
|
|
Iterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return);
|
2010-11-15 14:12:05 +01:00
|
|
|
//if (data.markerLineNumber == lineNumber)
|
2010-11-10 16:33:11 +01:00
|
|
|
// return;
|
2010-11-15 14:12:05 +01:00
|
|
|
if (it->data.markerLineNumber() != lineNumber) {
|
|
|
|
|
it->data.setMarkerLineNumber(lineNumber);
|
2010-11-10 16:33:11 +01:00
|
|
|
// FIXME: Should we tell gdb about the change?
|
|
|
|
|
// Ignore it for now, as we would require re-compilation
|
|
|
|
|
// and debugger re-start anyway.
|
2010-11-15 14:12:05 +01:00
|
|
|
//if (0 && data.bpLineNumber) {
|
|
|
|
|
// if (!data.bpNumber.trimmed().isEmpty()) {
|
|
|
|
|
// data.pending = true;
|
2010-11-10 16:33:11 +01:00
|
|
|
// }
|
|
|
|
|
//}
|
|
|
|
|
}
|
|
|
|
|
// 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?
|
2010-11-15 14:12:05 +01:00
|
|
|
if (it->response.bpNumber == 0) {
|
|
|
|
|
it->data.setLineNumber(lineNumber);
|
2010-11-10 16:33:11 +01:00
|
|
|
updateMarker(id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BreakpointIds BreakHandler::allBreakpointIds() const
|
|
|
|
|
{
|
|
|
|
|
BreakpointIds ids;
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
|
2010-11-10 16:33:11 +01:00
|
|
|
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;
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
|
2010-11-10 16:33:11 +01:00
|
|
|
for ( ; it != et; ++it)
|
2010-11-15 14:12:05 +01:00
|
|
|
if (it->engine == engine)
|
2010-11-10 16:33:11 +01:00
|
|
|
ids.append(it.key());
|
|
|
|
|
return ids;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::notifyBreakpointInsertOk(BreakpointId id)
|
|
|
|
|
{
|
2010-11-15 14:12:05 +01:00
|
|
|
QTC_ASSERT(state(id)== BreakpointInsertProceeding, /**/);
|
|
|
|
|
setState(id, BreakpointInserted);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
void BreakHandler::notifyBreakpointInsertFailed(BreakpointId id)
|
2010-07-13 17:16:31 +02:00
|
|
|
{
|
2010-11-15 14:12:05 +01:00
|
|
|
QTC_ASSERT(state(id)== BreakpointInsertProceeding, /**/);
|
|
|
|
|
setState(id, BreakpointDead);
|
2010-07-13 17:16:31 +02:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
void BreakHandler::notifyBreakpointRemoveOk(BreakpointId id)
|
2010-10-13 17:43:53 +02:00
|
|
|
{
|
2010-11-10 16:33:11 +01:00
|
|
|
QTC_ASSERT(state(id) == BreakpointRemoveProceeding, /**/);
|
|
|
|
|
setState(id, BreakpointDead);
|
|
|
|
|
cleanupBreakpoint(id);
|
2010-10-13 17:43:53 +02:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
void BreakHandler::notifyBreakpointRemoveFailed(BreakpointId id)
|
2010-10-13 17:43:53 +02:00
|
|
|
{
|
2010-11-10 16:33:11 +01:00
|
|
|
QTC_ASSERT(state(id) == BreakpointRemoveProceeding, /**/);
|
|
|
|
|
setState(id, BreakpointDead);
|
|
|
|
|
cleanupBreakpoint(id);
|
2010-10-13 17:43:53 +02:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 16:33:11 +01:00
|
|
|
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, /**/);
|
2010-11-15 13:12:13 +01:00
|
|
|
Iterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return);
|
2010-11-15 14:12:05 +01:00
|
|
|
it->state = BreakpointNew;
|
|
|
|
|
it->engine = 0;
|
|
|
|
|
it->response = BreakpointResponse();
|
2010-11-15 13:12:13 +01:00
|
|
|
delete it->marker;
|
|
|
|
|
it->marker = 0;
|
2010-11-10 16:33:11 +01:00
|
|
|
updateMarker(id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::cleanupBreakpoint(BreakpointId id)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(state(id) == BreakpointDead, /**/);
|
2010-11-15 13:12:13 +01:00
|
|
|
BreakpointItem item = m_storage.take(id);
|
2010-11-15 14:27:06 +01:00
|
|
|
item.destroyMarker();
|
2010-11-15 15:15:09 +01:00
|
|
|
layoutChanged();
|
2010-11-10 16:33:11 +01:00
|
|
|
}
|
|
|
|
|
|
2010-11-15 16:22:51 +01:00
|
|
|
const BreakpointResponse &BreakHandler::response(BreakpointId id) const
|
2010-11-10 16:33:11 +01:00
|
|
|
{
|
2010-11-15 16:22:51 +01:00
|
|
|
static BreakpointResponse dummy;
|
2010-11-15 13:12:13 +01:00
|
|
|
ConstIterator it = m_storage.find(id);
|
2010-11-15 16:22:51 +01:00
|
|
|
QTC_ASSERT(it != m_storage.end(), return dummy);
|
2010-11-15 14:12:05 +01:00
|
|
|
return it->response;
|
2010-11-10 16:33:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::setResponse(BreakpointId id, const BreakpointResponse &data)
|
|
|
|
|
{
|
2010-11-15 13:12:13 +01:00
|
|
|
Iterator it = m_storage.find(id);
|
|
|
|
|
QTC_ASSERT(it != m_storage.end(), return);
|
2010-11-15 14:12:05 +01:00
|
|
|
it->response = BreakpointResponse(data);
|
2010-11-10 16:33:11 +01:00
|
|
|
updateMarker(id);
|
|
|
|
|
}
|
2010-11-04 09:54:23 +01:00
|
|
|
|
2010-11-15 14:27:06 +01:00
|
|
|
void BreakHandler::BreakpointItem::destroyMarker()
|
2010-11-15 13:12:13 +01:00
|
|
|
{
|
2010-11-15 14:27:06 +01:00
|
|
|
BreakpointMarker *m = marker;
|
2010-11-15 13:12:13 +01:00
|
|
|
marker = 0;
|
2010-11-15 14:27:06 +01:00
|
|
|
delete m;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void formatAddress(QTextStream &str, quint64 address)
|
|
|
|
|
{
|
|
|
|
|
if (address) {
|
|
|
|
|
str << "0x";
|
|
|
|
|
str.setIntegerBase(16);
|
|
|
|
|
str << address;
|
|
|
|
|
str.setIntegerBase(10);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-15 14:35:19 +01:00
|
|
|
static QString stateToString(BreakpointState state)
|
|
|
|
|
{
|
|
|
|
|
switch (state) {
|
|
|
|
|
case BreakpointNew: return "new";
|
|
|
|
|
case BreakpointInsertRequested: return "insertion requested";
|
|
|
|
|
case BreakpointInsertProceeding: return "insertion proceeding";
|
|
|
|
|
case BreakpointChangeRequested: return "change requested";
|
|
|
|
|
case BreakpointChangeProceeding: return "change proceeding";
|
|
|
|
|
case BreakpointPending: return "breakpoint pending";
|
|
|
|
|
case BreakpointInserted: return "breakpoint inserted";
|
|
|
|
|
case BreakpointRemoveRequested: return "removal requested";
|
|
|
|
|
case BreakpointRemoveProceeding: return "removal is proceeding";
|
|
|
|
|
case BreakpointDead: return "dead";
|
|
|
|
|
default: return "<invalid state>";
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2010-11-15 14:27:06 +01:00
|
|
|
QString BreakHandler::BreakpointItem::toToolTip() const
|
|
|
|
|
{
|
|
|
|
|
QString t;
|
|
|
|
|
|
|
|
|
|
switch (data.type()) {
|
|
|
|
|
case BreakpointByFileAndLine:
|
|
|
|
|
t = tr("Breakpoint by File and Line");
|
|
|
|
|
break;
|
|
|
|
|
case BreakpointByFunction:
|
|
|
|
|
t = tr("Breakpoint by Function");
|
|
|
|
|
break;
|
|
|
|
|
case BreakpointByAddress:
|
|
|
|
|
t = tr("Breakpoint by Address");
|
|
|
|
|
break;
|
|
|
|
|
case Watchpoint:
|
|
|
|
|
t = tr("Watchpoint");
|
|
|
|
|
break;
|
|
|
|
|
case UnknownType:
|
|
|
|
|
t = tr("Unknown Breakpoint Type");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString rc;
|
|
|
|
|
QTextStream str(&rc);
|
|
|
|
|
str << "<html><body><table>"
|
|
|
|
|
//<< "<tr><td>" << tr("Id:") << "</td><td>" << m_id << "</td></tr>"
|
|
|
|
|
<< "<tr><td>" << tr("State:")
|
2010-11-15 15:05:39 +01:00
|
|
|
<< "</td><td>" << state << " (" << stateToString(state) << ")</td></tr>"
|
2010-11-15 14:27:06 +01:00
|
|
|
<< "<tr><td>" << tr("Engine:")
|
|
|
|
|
<< "</td><td>" << (engine ? engine->objectName() : "0") << "</td></tr>"
|
|
|
|
|
<< "<tr><td>" << tr("Marker File:")
|
|
|
|
|
<< "</td><td>" << QDir::toNativeSeparators(data.m_markerFileName) << "</td></tr>"
|
|
|
|
|
<< "<tr><td>" << tr("Marker Line:")
|
|
|
|
|
<< "</td><td>" << data.m_markerLineNumber << "</td></tr>"
|
|
|
|
|
<< "<tr><td>" << tr("Breakpoint Number:")
|
|
|
|
|
<< "</td><td>" << response.bpNumber << "</td></tr>"
|
|
|
|
|
<< "<tr><td>" << tr("Breakpoint Type:")
|
|
|
|
|
<< "</td><td>" << t << "</td></tr>"
|
|
|
|
|
<< "<tr><td>" << tr("State:")
|
|
|
|
|
<< "</td><td>" << response.bpState << "</td></tr>"
|
|
|
|
|
<< "</table><br><hr><table>"
|
|
|
|
|
<< "<tr><th>" << tr("Property")
|
|
|
|
|
<< "</th><th>" << tr("Requested")
|
|
|
|
|
<< "</th><th>" << tr("Obtained") << "</th></tr>"
|
|
|
|
|
<< "<tr><td>" << tr("Internal Number:")
|
|
|
|
|
<< "</td><td>—</td><td>" << response.bpNumber << "</td></tr>"
|
|
|
|
|
<< "<tr><td>" << tr("File Name:")
|
|
|
|
|
<< "</td><td>" << QDir::toNativeSeparators(data.m_fileName)
|
|
|
|
|
<< "</td><td>" << QDir::toNativeSeparators(response.bpFileName)
|
|
|
|
|
<< "</td></tr>"
|
|
|
|
|
<< "<tr><td>" << tr("Function Name:")
|
|
|
|
|
<< "</td><td>" << data.m_functionName
|
|
|
|
|
<< "</td><td>" << response.bpFuncName << "</td></tr>"
|
|
|
|
|
<< "<tr><td>" << tr("Line Number:") << "</td><td>";
|
|
|
|
|
if (data.m_lineNumber)
|
|
|
|
|
str << data.m_lineNumber;
|
|
|
|
|
str << "</td><td>";
|
|
|
|
|
if (response.bpLineNumber)
|
|
|
|
|
str << response.bpLineNumber;
|
|
|
|
|
str << "</td></tr>"
|
|
|
|
|
<< "<tr><td>" << tr("Breakpoint Address:")
|
|
|
|
|
<< "</td><td>";
|
|
|
|
|
formatAddress(str, data.m_address);
|
|
|
|
|
str << "</td><td>";
|
|
|
|
|
formatAddress(str, response.bpAddress);
|
|
|
|
|
//str << "</td></tr>"
|
|
|
|
|
// << "<tr><td>" << tr("Corrected Line Number:")
|
|
|
|
|
// << "</td><td>-</td><td>";
|
|
|
|
|
//if (response.bpCorrectedLineNumber > 0)
|
|
|
|
|
// str << response.bpCorrectedLineNumber;
|
|
|
|
|
//else
|
|
|
|
|
// str << '-';
|
|
|
|
|
str << "</td></tr>"
|
|
|
|
|
<< "<tr><td>" << tr("Condition:")
|
|
|
|
|
<< "</td><td>" << data.m_condition
|
|
|
|
|
<< "</td><td>" << response.bpCondition << "</td></tr>"
|
|
|
|
|
<< "<tr><td>" << tr("Ignore Count:") << "</td><td>";
|
|
|
|
|
if (data.m_ignoreCount)
|
|
|
|
|
str << data.m_ignoreCount;
|
|
|
|
|
str << "</td><td>";
|
|
|
|
|
if (response.bpIgnoreCount)
|
|
|
|
|
str << response.bpIgnoreCount;
|
|
|
|
|
str << "</td></tr>"
|
|
|
|
|
<< "<tr><td>" << tr("Thread Specification:")
|
|
|
|
|
<< "</td><td>" << data.m_threadSpec
|
|
|
|
|
<< "</td><td>" << response.bpThreadSpec << "</td></tr>"
|
|
|
|
|
<< "</table></body></html>";
|
|
|
|
|
return rc;
|
2010-11-15 13:12:13 +01:00
|
|
|
}
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|