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"
|
|
|
|
|
|
2009-09-23 16:11:25 +02:00
|
|
|
#include "debuggeractions.h"
|
2010-06-16 11:08:54 +02:00
|
|
|
#include "debuggerengine.h"
|
|
|
|
|
#include "debuggerplugin.h"
|
2010-05-07 15:16:31 +02:00
|
|
|
#include "debuggerstringutils.h"
|
2010-06-16 11:08:54 +02:00
|
|
|
#include "threadshandler.h"
|
|
|
|
|
#include "stackhandler.h"
|
2009-08-14 13:04:05 +02:00
|
|
|
#include "stackframe.h"
|
|
|
|
|
|
2010-02-04 13:18:44 +01:00
|
|
|
#include <texteditor/basetextmark.h>
|
2010-03-26 08:52:49 +01:00
|
|
|
#include <utils/qtcassert.h>
|
2008-12-09 16:18:28 +01:00
|
|
|
|
2010-05-20 19:35:34 +02:00
|
|
|
#include <QtCore/QByteArray>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <QtCore/QFileInfo>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace Debugger {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
static DebuggerPlugin *plugin() { return DebuggerPlugin::instance(); }
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// BreakHandler
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2010-09-13 13:30:35 +02:00
|
|
|
BreakHandler::BreakHandler(Debugger::DebuggerEngine *engine)
|
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-06-25 15:02:53 +02:00
|
|
|
m_engine(engine),
|
2010-06-16 11:08:54 +02:00
|
|
|
m_lastFound(0),
|
|
|
|
|
m_lastFoundQueried(false)
|
2010-06-25 15:02:53 +02:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_engine, /**/);
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-04 11:37:43 +01:00
|
|
|
BreakHandler::~BreakHandler()
|
|
|
|
|
{
|
|
|
|
|
clear();
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
return parent.isValid() ? 0 : size();
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
bool BreakHandler::hasPendingBreakpoints() const
|
|
|
|
|
{
|
|
|
|
|
for (int i = size() - 1; i >= 0; i--)
|
|
|
|
|
if (at(i)->pending)
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-26 08:52:49 +01:00
|
|
|
BreakpointData *BreakHandler::at(int index) const
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(index < size(), return 0);
|
|
|
|
|
return m_bp.at(index);
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void BreakHandler::removeAt(int index)
|
|
|
|
|
{
|
|
|
|
|
BreakpointData *data = at(index);
|
|
|
|
|
m_bp.removeAt(index);
|
|
|
|
|
delete data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::clear()
|
|
|
|
|
{
|
2009-06-30 15:50:56 +02:00
|
|
|
qDeleteAll(m_bp);
|
|
|
|
|
m_bp.clear();
|
|
|
|
|
m_enabled.clear();
|
|
|
|
|
m_disabled.clear();
|
|
|
|
|
m_removed.clear();
|
|
|
|
|
m_inserted.clear();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
BreakpointData *BreakHandler::findSimilarBreakpoint(const BreakpointData *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.
|
2008-12-02 12:01:29 +01:00
|
|
|
for (int index = 0; index != size(); ++index) {
|
2010-05-10 12:34:52 +02:00
|
|
|
BreakpointData *data = m_bp[index];
|
2010-06-16 11:08:54 +02:00
|
|
|
if (data->isSimilarTo(needle))
|
2010-05-10 12:34:52 +02:00
|
|
|
return data;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-05-10 12:34:52 +02:00
|
|
|
return 0;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-10 10:33:52 +02:00
|
|
|
BreakpointData *BreakHandler::findBreakpointByNumber(int bpNumber) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-06-10 10:29:31 +02:00
|
|
|
if (!size())
|
2010-03-26 10:29:19 +01:00
|
|
|
return 0;
|
2009-06-10 10:29:31 +02:00
|
|
|
QString numStr = QString::number(bpNumber);
|
2008-12-02 12:01:29 +01:00
|
|
|
for (int index = 0; index != size(); ++index)
|
2009-06-10 10:29:31 +02:00
|
|
|
if (at(index)->bpNumber == numStr)
|
2010-03-26 10:29:19 +01:00
|
|
|
return at(index);
|
|
|
|
|
return 0;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-09-21 14:26:45 +02:00
|
|
|
int BreakHandler::findWatchPointIndexByAddress(quint64 address) const
|
2010-05-19 17:34:47 +02:00
|
|
|
{
|
|
|
|
|
for (int index = size() - 1; index >= 0; --index) {
|
|
|
|
|
BreakpointData *bd = at(index);
|
2010-09-21 14:26:45 +02:00
|
|
|
if (bd->type == BreakpointData::WatchpointType && bd->address == address)
|
2010-05-20 20:25:54 +02:00
|
|
|
return index;
|
2010-05-19 17:34:47 +02:00
|
|
|
}
|
2010-05-20 20:25:54 +02:00
|
|
|
return -1;
|
2010-05-19 17:34:47 +02:00
|
|
|
}
|
|
|
|
|
|
2010-05-20 19:35:34 +02:00
|
|
|
bool BreakHandler::watchPointAt(quint64 address) const
|
|
|
|
|
{
|
2010-09-21 14:26:45 +02:00
|
|
|
return findWatchPointIndexByAddress(address) != -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...";
|
|
|
|
|
QTC_ASSERT(plugin(), return);
|
2008-12-02 12:01:29 +01:00
|
|
|
QList<QVariant> list;
|
|
|
|
|
for (int index = 0; index != size(); ++index) {
|
|
|
|
|
const BreakpointData *data = at(index);
|
|
|
|
|
QMap<QString, QVariant> map;
|
2010-05-07 15:16:31 +02:00
|
|
|
// Do not persist Watchpoints.
|
|
|
|
|
//if (data->type == BreakpointData::WatchpointType)
|
|
|
|
|
// continue;
|
|
|
|
|
if (data->type != BreakpointData::BreakpointType)
|
|
|
|
|
map.insert(_("type"), data->type);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!data->fileName.isEmpty())
|
2010-05-07 15:16:31 +02:00
|
|
|
map.insert(_("filename"), data->fileName);
|
2010-09-21 14:26:45 +02:00
|
|
|
if (data->lineNumber)
|
|
|
|
|
map.insert(_("linenumber"), QVariant(data->lineNumber));
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!data->funcName.isEmpty())
|
2010-05-07 15:16:31 +02:00
|
|
|
map.insert(_("funcname"), data->funcName);
|
2010-09-21 14:26:45 +02:00
|
|
|
if (data->address)
|
2010-05-07 15:16:31 +02:00
|
|
|
map.insert(_("address"), data->address);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!data->condition.isEmpty())
|
2010-05-07 15:16:31 +02:00
|
|
|
map.insert(_("condition"), data->condition);
|
2010-09-21 14:26:45 +02:00
|
|
|
if (data->ignoreCount)
|
|
|
|
|
map.insert(_("ignorecount"), QVariant(data->ignoreCount));
|
2010-04-29 18:36:18 +02:00
|
|
|
if (!data->threadSpec.isEmpty())
|
2010-05-07 15:16:31 +02:00
|
|
|
map.insert(_("threadspec"), data->threadSpec);
|
2009-04-28 15:08:52 +02:00
|
|
|
if (!data->enabled)
|
2010-05-07 15:16:31 +02:00
|
|
|
map.insert(_("disabled"), _("1"));
|
2009-05-11 13:21:59 +02: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-06-16 11:08:54 +02:00
|
|
|
plugin()->setSessionValue("Breakpoints", list);
|
|
|
|
|
//qDebug() << "SAVED BREAKPOINTS" << this << list.size();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::loadBreakpoints()
|
|
|
|
|
{
|
2010-06-16 11:08:54 +02:00
|
|
|
QTC_ASSERT(plugin(), return);
|
|
|
|
|
//qDebug() << "LOADING BREAKPOINTS...";
|
|
|
|
|
QVariant value = plugin()->sessionValue("Breakpoints");
|
2008-12-02 12:01:29 +01:00
|
|
|
QList<QVariant> list = value.toList();
|
|
|
|
|
clear();
|
|
|
|
|
foreach (const QVariant &var, list) {
|
|
|
|
|
const QMap<QString, QVariant> map = var.toMap();
|
2010-05-07 15:16:31 +02:00
|
|
|
BreakpointData *data = new BreakpointData;
|
|
|
|
|
QVariant v = map.value(_("filename"));
|
2009-06-30 15:50:56 +02:00
|
|
|
if (v.isValid())
|
|
|
|
|
data->fileName = 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-09-21 14:26:45 +02:00
|
|
|
data->lineNumber = 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-01-05 16:51:55 +01:00
|
|
|
data->condition = v.toString().toLatin1();
|
2010-05-07 15:16:31 +02:00
|
|
|
v = map.value(_("address"));
|
|
|
|
|
if (v.isValid())
|
2010-09-21 14:26:45 +02:00
|
|
|
data->address = 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-09-21 14:26:45 +02:00
|
|
|
data->ignoreCount = 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())
|
|
|
|
|
data->threadSpec = 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())
|
|
|
|
|
data->funcName = 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())
|
|
|
|
|
data->enabled = !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())
|
|
|
|
|
data->useFullPath = bool(v.toInt());
|
2010-05-07 15:16:31 +02:00
|
|
|
v = map.value(_("type"));
|
|
|
|
|
if (v.isValid())
|
|
|
|
|
data->type = BreakpointData::Type(v.toInt());
|
2010-03-26 10:29:19 +01:00
|
|
|
data->setMarkerFileName(data->fileName);
|
2010-09-21 14:26:45 +02:00
|
|
|
data->setMarkerLineNumber(data->lineNumber);
|
2008-12-02 12:01:29 +01:00
|
|
|
append(data);
|
|
|
|
|
}
|
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()
|
|
|
|
|
{
|
|
|
|
|
for (int index = 0; index != size(); ++index)
|
|
|
|
|
at(index)->updateMarker();
|
|
|
|
|
emit layoutChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant BreakHandler::data(const QModelIndex &mi, int role) const
|
|
|
|
|
{
|
|
|
|
|
static const QString empty = QString(QLatin1Char('-'));
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
switch (role) {
|
|
|
|
|
case CurrentThreadIdRole:
|
|
|
|
|
QTC_ASSERT(m_engine, return QVariant());
|
|
|
|
|
return m_engine->threadsHandler()->currentThreadId();
|
|
|
|
|
|
|
|
|
|
case EngineActionsEnabledRole:
|
|
|
|
|
QTC_ASSERT(m_engine, return QVariant());
|
|
|
|
|
return m_engine->debuggerActionsEnabled();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
case EngineCapabilitiesRole:
|
|
|
|
|
QTC_ASSERT(m_engine, return QVariant());
|
|
|
|
|
return m_engine->debuggerCapabilities();
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QTC_ASSERT(mi.isValid(), return QVariant());
|
2008-12-02 12:01:29 +01:00
|
|
|
if (mi.row() >= size())
|
|
|
|
|
return QVariant();
|
|
|
|
|
|
|
|
|
|
const BreakpointData *data = at(mi.row());
|
2010-06-16 11:08:54 +02:00
|
|
|
|
|
|
|
|
if (role == BreakpointUseFullPathRole)
|
|
|
|
|
return data->useFullPath;
|
|
|
|
|
|
|
|
|
|
if (role == BreakpointFileNameRole)
|
|
|
|
|
return data->fileName;
|
|
|
|
|
|
|
|
|
|
if (role == BreakpointEnabledRole)
|
|
|
|
|
return data->enabled;
|
|
|
|
|
|
|
|
|
|
if (role == BreakpointFunctionNameRole)
|
|
|
|
|
return data->funcName;
|
|
|
|
|
|
2010-09-08 12:18:04 +02:00
|
|
|
if (role == BreakpointConditionRole)
|
|
|
|
|
return data->condition;
|
|
|
|
|
|
|
|
|
|
if (role == BreakpointIgnoreCountRole)
|
2010-09-21 14:26:45 +02:00
|
|
|
return data->ignoreCount ? QVariant(data->ignoreCount) : QVariant(QString());
|
2010-09-08 12:18:04 +02:00
|
|
|
|
|
|
|
|
if (role == BreakpointThreadSpecRole)
|
|
|
|
|
return data->threadSpec;
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
switch (mi.column()) {
|
|
|
|
|
case 0:
|
|
|
|
|
if (role == Qt::DisplayRole) {
|
2010-02-10 10:47:34 +01:00
|
|
|
const QString str = data->bpNumber;
|
2008-12-02 12:01:29 +01:00
|
|
|
return str.isEmpty() ? empty : str;
|
|
|
|
|
}
|
2010-02-10 10:47:34 +01:00
|
|
|
if (role == Qt::DecorationRole) {
|
2010-05-07 15:16:31 +02:00
|
|
|
if (data->type == BreakpointData::WatchpointType)
|
|
|
|
|
return m_watchpointIcon;
|
2010-02-10 10:47:34 +01:00
|
|
|
if (!data->enabled)
|
|
|
|
|
return m_disabledBreakpointIcon;
|
|
|
|
|
return data->pending ? m_pendingBreakPointIcon : m_breakpointIcon;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
if (role == Qt::DisplayRole) {
|
2010-02-10 10:47:34 +01:00
|
|
|
const QString str = data->pending ? data->funcName : data->bpFuncName;
|
2008-12-02 12:01:29 +01:00
|
|
|
return str.isEmpty() ? empty : str;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
if (role == Qt::DisplayRole) {
|
|
|
|
|
QString str = data->pending ? data->fileName : data->bpFileName;
|
|
|
|
|
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;
|
2009-05-11 13:21:59 +02:00
|
|
|
str = str.isEmpty() ? empty : str;
|
|
|
|
|
if (data->useFullPath)
|
2010-01-29 21:33:57 +01:00
|
|
|
str = "/.../" + 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?
|
|
|
|
|
//if (data->bpMultiple && str.isEmpty() && !data->markerFileName.isEmpty())
|
|
|
|
|
// str = data->markerLineNumber;
|
2010-09-21 14:26:45 +02:00
|
|
|
const int nr = data->pending ? data->lineNumber : data->bpLineNumber;
|
|
|
|
|
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)
|
|
|
|
|
return data->lineNumber;
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
if (role == Qt::DisplayRole)
|
|
|
|
|
return data->pending ? data->condition : data->bpCondition;
|
|
|
|
|
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)
|
|
|
|
|
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) {
|
|
|
|
|
const int ignoreCount = data->pending ? data->ignoreCount : data->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.");
|
2010-04-29 18:36:18 +02:00
|
|
|
if (role == Qt::UserRole + 1)
|
|
|
|
|
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) {
|
|
|
|
|
if (data->pending)
|
|
|
|
|
return !data->threadSpec.isEmpty() ? data->threadSpec : tr("(all)");
|
|
|
|
|
else
|
|
|
|
|
return !data->bpThreadSpec.isEmpty() ? data->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;
|
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;
|
|
|
|
|
const quint64 effectiveAddress = data->type == BreakpointData::WatchpointType ?
|
|
|
|
|
data->address : data->bpAddress;
|
|
|
|
|
if (effectiveAddress)
|
|
|
|
|
displayValue += QString::fromAscii("0x%1").arg(effectiveAddress, 0, 16);
|
|
|
|
|
if (!data->bpState.isEmpty()) {
|
|
|
|
|
if (!displayValue.isEmpty())
|
|
|
|
|
displayValue += QLatin1Char(' ');
|
|
|
|
|
displayValue += QString::fromAscii(data->bpState);
|
|
|
|
|
}
|
|
|
|
|
return displayValue;
|
2010-06-16 11:08:54 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (role == Qt::ToolTipRole)
|
2009-10-01 11:22:44 +02:00
|
|
|
return theDebuggerBoolSetting(UseToolTipsInBreakpointsView)
|
2009-09-23 16:11:25 +02:00
|
|
|
? data->toToolTip() : QVariant();
|
2008-12-02 12:01:29 +01:00
|
|
|
return QVariant();
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
Qt::ItemFlags BreakHandler::flags(const QModelIndex &index) const
|
2009-04-28 15:08:52 +02:00
|
|
|
{
|
2010-06-30 14:25:09 +02:00
|
|
|
// switch (index.column()) {
|
|
|
|
|
// //case 0:
|
|
|
|
|
// // return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
|
|
|
|
|
// default:
|
2010-06-16 11:08:54 +02:00
|
|
|
return QAbstractTableModel::flags(index);
|
2010-06-30 14:25:09 +02:00
|
|
|
// }
|
2009-04-28 15:08:52 +02:00
|
|
|
}
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
bool BreakHandler::setData(const QModelIndex &index, const QVariant &value, int role)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-06-16 11:08:54 +02:00
|
|
|
switch (role) {
|
|
|
|
|
case RequestActivateBreakpointRole: {
|
|
|
|
|
const BreakpointData *data = at(value.toInt());
|
|
|
|
|
QTC_ASSERT(data, return false);
|
|
|
|
|
m_engine->gotoLocation(data->markerFileName(),
|
|
|
|
|
data->markerLineNumber(), false);
|
|
|
|
|
return true;
|
2010-04-29 18:36:18 +02:00
|
|
|
}
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
case RequestRemoveBreakpointByIndexRole: {
|
|
|
|
|
BreakpointData *data = at(value.toInt());
|
|
|
|
|
QTC_ASSERT(data, return false);
|
|
|
|
|
removeBreakpoint(data);
|
|
|
|
|
return true;
|
2010-04-29 18:36:18 +02:00
|
|
|
}
|
2010-06-16 11:08:54 +02:00
|
|
|
|
|
|
|
|
case RequestSynchronizeBreakpointsRole:
|
|
|
|
|
QTC_ASSERT(m_engine, return false);
|
|
|
|
|
m_engine->attemptBreakpointSynchronization();
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case RequestBreakByFunctionRole:
|
|
|
|
|
QTC_ASSERT(m_engine, return false);
|
|
|
|
|
m_engine->breakByFunction(value.toString());
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case RequestBreakByFunctionMainRole:
|
|
|
|
|
QTC_ASSERT(m_engine, return false);
|
|
|
|
|
m_engine->breakByFunctionMain();
|
|
|
|
|
return true;
|
2010-04-29 18:36:18 +02:00
|
|
|
}
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
BreakpointData *data = at(index.row());
|
2010-04-29 18:36:18 +02:00
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
switch (role) {
|
|
|
|
|
case BreakpointEnabledRole:
|
2010-09-08 08:15:54 +02:00
|
|
|
if (data->enabled != value.toBool())
|
2010-06-16 11:08:54 +02:00
|
|
|
toggleBreakpointEnabled(data);
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case BreakpointUseFullPathRole:
|
|
|
|
|
if (data->useFullPath != value.toBool()) {
|
|
|
|
|
data->useFullPath = value.toBool();
|
2010-07-07 13:26:32 +02:00
|
|
|
emit layoutChanged();
|
2010-06-16 11:08:54 +02:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case BreakpointConditionRole: {
|
|
|
|
|
QByteArray val = value.toString().toLatin1();
|
|
|
|
|
if (val != data->condition) {
|
|
|
|
|
data->condition = val;
|
2010-07-07 13:26:32 +02:00
|
|
|
emit layoutChanged();
|
2010-06-16 11:08:54 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
return true;
|
2010-06-16 11:08:54 +02:00
|
|
|
|
|
|
|
|
case BreakpointIgnoreCountRole: {
|
2010-09-21 14:26:45 +02:00
|
|
|
const int ignoreCount = value.toInt();
|
|
|
|
|
if (ignoreCount != data->ignoreCount) {
|
|
|
|
|
data->ignoreCount = ignoreCount;
|
2010-07-07 13:26:32 +02:00
|
|
|
emit layoutChanged();
|
2010-06-16 11:08:54 +02:00
|
|
|
}
|
2010-04-29 18:36:18 +02:00
|
|
|
}
|
|
|
|
|
return true;
|
2010-06-16 11:08:54 +02:00
|
|
|
|
|
|
|
|
case BreakpointThreadSpecRole: {
|
|
|
|
|
QByteArray val = value.toString().toLatin1();
|
|
|
|
|
if (val != data->threadSpec) {
|
|
|
|
|
data->threadSpec = val;
|
2010-07-07 13:26:32 +02:00
|
|
|
emit layoutChanged();
|
2010-06-16 11:08:54 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2010-06-16 11:08:54 +02:00
|
|
|
return false;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-05-12 14:28:27 +02:00
|
|
|
void BreakHandler::append(BreakpointData *data)
|
|
|
|
|
{
|
2010-05-07 15:16:31 +02:00
|
|
|
data->m_handler = this;
|
2009-05-12 14:28:27 +02:00
|
|
|
m_bp.append(data);
|
|
|
|
|
m_inserted.append(data);
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
Breakpoints BreakHandler::insertedBreakpoints() const
|
2009-05-12 14:28:27 +02:00
|
|
|
{
|
|
|
|
|
return m_inserted;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::takeInsertedBreakPoint(BreakpointData *d)
|
|
|
|
|
{
|
|
|
|
|
m_inserted.removeAll(d);
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
Breakpoints BreakHandler::takeRemovedBreakpoints()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-06-16 11:08:54 +02:00
|
|
|
Breakpoints result = m_removed;
|
2008-12-02 12:01:29 +01:00
|
|
|
m_removed.clear();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
Breakpoints BreakHandler::takeEnabledBreakpoints()
|
2009-04-28 15:08:52 +02:00
|
|
|
{
|
2010-06-16 11:08:54 +02:00
|
|
|
Breakpoints result = m_enabled;
|
2009-04-28 15:08:52 +02:00
|
|
|
m_enabled.clear();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
Breakpoints BreakHandler::takeDisabledBreakpoints()
|
2009-04-28 15:08:52 +02:00
|
|
|
{
|
2010-06-16 11:08:54 +02:00
|
|
|
Breakpoints result = m_disabled;
|
2009-04-28 15:08:52 +02:00
|
|
|
m_disabled.clear();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void BreakHandler::removeBreakpointHelper(int index)
|
|
|
|
|
{
|
|
|
|
|
BreakpointData *data = m_bp.at(index);
|
|
|
|
|
m_bp.removeAt(index);
|
|
|
|
|
data->removeMarker();
|
|
|
|
|
m_removed.append(data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::removeBreakpoint(int index)
|
|
|
|
|
{
|
|
|
|
|
if (index < 0 || index >= size())
|
|
|
|
|
return;
|
2009-06-11 13:40:44 +02:00
|
|
|
removeBreakpointHelper(index);
|
2008-12-02 12:01:29 +01:00
|
|
|
emit layoutChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-12 16:48:04 +02:00
|
|
|
void BreakHandler::removeBreakpoint(BreakpointData *data)
|
|
|
|
|
{
|
|
|
|
|
removeBreakpointHelper(m_bp.indexOf(data));
|
|
|
|
|
emit layoutChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-28 15:08:52 +02:00
|
|
|
void BreakHandler::toggleBreakpointEnabled(BreakpointData *data)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(data, return);
|
|
|
|
|
data->enabled = !data->enabled;
|
|
|
|
|
if (data->enabled) {
|
|
|
|
|
m_enabled.append(data);
|
|
|
|
|
m_disabled.removeAll(data);
|
|
|
|
|
} else {
|
|
|
|
|
m_enabled.removeAll(data);
|
|
|
|
|
m_disabled.append(data);
|
|
|
|
|
}
|
2010-09-08 08:15:54 +02:00
|
|
|
data->updateMarker();
|
|
|
|
|
emit layoutChanged();
|
|
|
|
|
m_engine->attemptBreakpointSynchronization();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::toggleBreakpointEnabled(const QString &fileName, int lineNumber)
|
|
|
|
|
{
|
|
|
|
|
BreakpointData *data = findBreakpoint(fileName, lineNumber);
|
|
|
|
|
toggleBreakpointEnabled(data);
|
2009-04-28 15:08:52 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-04-09 15:19:10 +02:00
|
|
|
void BreakHandler::appendBreakpoint(BreakpointData *data)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
append(data);
|
|
|
|
|
emit layoutChanged();
|
2010-06-25 16:06:48 +02:00
|
|
|
saveBreakpoints(); // FIXME: remove?
|
2008-12-02 12:01:29 +01:00
|
|
|
updateMarkers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::removeAllBreakpoints()
|
|
|
|
|
{
|
|
|
|
|
for (int index = size(); --index >= 0;)
|
|
|
|
|
removeBreakpointHelper(index);
|
|
|
|
|
emit layoutChanged();
|
|
|
|
|
updateMarkers();
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-21 14:26:45 +02:00
|
|
|
BreakpointData *BreakHandler::findBreakpoint(quint64 address) const
|
|
|
|
|
{
|
|
|
|
|
foreach (BreakpointData *data, m_bp)
|
|
|
|
|
if (data->address == address)
|
|
|
|
|
return data;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-08 09:54:40 +02:00
|
|
|
BreakpointData *BreakHandler::findBreakpoint(const QString &fileName,
|
|
|
|
|
int lineNumber, bool useMarkerPosition)
|
2010-06-25 16:06:48 +02:00
|
|
|
{
|
|
|
|
|
foreach (BreakpointData *data, m_bp)
|
2010-09-08 09:54:40 +02:00
|
|
|
if (data->isLocatedAt(fileName, lineNumber, useMarkerPosition))
|
2010-06-25 16:06:48 +02:00
|
|
|
return data;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
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-09-21 14:26:45 +02:00
|
|
|
BreakpointData *data = 0;
|
|
|
|
|
do {
|
|
|
|
|
if (address) {
|
|
|
|
|
data = findBreakpoint(address);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
data = findBreakpoint(fileName, lineNumber, true);
|
|
|
|
|
if (!data)
|
|
|
|
|
data = findBreakpoint(fileName, lineNumber, false);
|
|
|
|
|
} while (false);
|
|
|
|
|
|
2010-06-25 16:06:48 +02:00
|
|
|
if (data) {
|
|
|
|
|
removeBreakpoint(data);
|
|
|
|
|
} else {
|
|
|
|
|
data = new BreakpointData;
|
2010-09-21 14:26:45 +02:00
|
|
|
if (address) {
|
|
|
|
|
data->address = address;
|
|
|
|
|
} else {
|
|
|
|
|
data->fileName = fileName;
|
|
|
|
|
data->lineNumber = lineNumber;
|
|
|
|
|
}
|
2010-06-25 16:06:48 +02:00
|
|
|
data->pending = true;
|
|
|
|
|
data->setMarkerFileName(fileName);
|
|
|
|
|
data->setMarkerLineNumber(lineNumber);
|
|
|
|
|
appendBreakpoint(data);
|
2010-06-25 15:02:53 +02:00
|
|
|
}
|
2010-08-12 15:39:12 +02:00
|
|
|
m_engine->attemptBreakpointSynchronization();
|
2010-06-25 16:06:48 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void BreakHandler::saveSessionData()
|
|
|
|
|
{
|
2010-06-25 09:53:23 +02:00
|
|
|
QTC_ASSERT(m_engine->isSessionEngine(), return);
|
2008-12-02 12:01:29 +01:00
|
|
|
saveBreakpoints();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BreakHandler::loadSessionData()
|
|
|
|
|
{
|
2010-06-25 09:53:23 +02:00
|
|
|
QTC_ASSERT(m_engine->isSessionEngine(), return);
|
2008-12-02 12:01:29 +01:00
|
|
|
loadBreakpoints();
|
|
|
|
|
updateMarkers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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.
|
2008-12-02 12:01:29 +01:00
|
|
|
for (int index = size(); --index >= 0;) {
|
|
|
|
|
const BreakpointData *data = at(index);
|
2008-12-09 12:08:56 +01:00
|
|
|
QTC_ASSERT(data, break);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (data->funcName == functionName && data->condition.isEmpty()
|
2010-09-21 14:26:45 +02:00
|
|
|
&& data->ignoreCount == 0)
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2010-05-07 15:16:31 +02:00
|
|
|
BreakpointData *data = new BreakpointData;
|
2008-12-02 12:01:29 +01:00
|
|
|
data->funcName = functionName;
|
|
|
|
|
append(data);
|
2010-06-22 15:37:27 +02:00
|
|
|
//saveBreakpoints();
|
2008-12-02 12:01:29 +01:00
|
|
|
updateMarkers();
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-13 17:16:31 +02:00
|
|
|
bool BreakHandler::isActive() const
|
|
|
|
|
{
|
|
|
|
|
return m_engine->isActive();
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
void BreakHandler::initializeFromTemplate(BreakHandler *other)
|
|
|
|
|
{
|
|
|
|
|
//qDebug() << "COPYING BREAKPOINTS INTO NEW SESSION";
|
2010-06-22 14:52:26 +02:00
|
|
|
QTC_ASSERT(m_bp.isEmpty(), /**/);
|
2010-06-22 15:37:27 +02:00
|
|
|
foreach (BreakpointData *data, other->m_bp) {
|
2010-06-22 15:14:44 +02:00
|
|
|
append(data->clone());
|
2010-06-22 15:37:27 +02:00
|
|
|
data->removeMarker();
|
|
|
|
|
}
|
2010-06-16 11:08:54 +02:00
|
|
|
updateMarkers();
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-22 15:37:27 +02:00
|
|
|
void BreakHandler::storeToTemplate(BreakHandler *other)
|
|
|
|
|
{
|
|
|
|
|
other->removeAllBreakpoints();
|
2010-09-21 14:26:45 +02:00
|
|
|
foreach (const BreakpointData *data, m_bp)
|
2010-06-22 15:37:27 +02:00
|
|
|
other->append(data->clone());
|
|
|
|
|
removeAllBreakpoints();
|
|
|
|
|
other->updateMarkers();
|
|
|
|
|
other->saveSessionData();
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|