2009-04-07 17:07:11 +02:00
|
|
|
/**************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
|
**
|
|
|
|
|
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
|
|
|
**
|
|
|
|
|
** Contact: Qt Software Information (qt-info@nokia.com)
|
|
|
|
|
**
|
|
|
|
|
** Commercial Usage
|
|
|
|
|
**
|
|
|
|
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
|
|
|
|
** accordance with the Qt Commercial License Agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and Nokia.
|
|
|
|
|
**
|
|
|
|
|
** GNU Lesser General Public License Usage
|
|
|
|
|
**
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
|
|
|
** General Public License version 2.1 as published by the Free Software
|
|
|
|
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
|
|
|
** packaging of this file. Please review the following information to
|
|
|
|
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
|
|
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
|
|
|
**
|
|
|
|
|
** If you are unsure which license is appropriate for your use, please
|
|
|
|
|
** contact the sales department at qt-sales@nokia.com.
|
|
|
|
|
**
|
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "cdbbreakpoint.h"
|
2009-04-15 10:05:40 +02:00
|
|
|
#include "cdbmodules.h"
|
2009-04-07 17:07:11 +02:00
|
|
|
#include "breakhandler.h"
|
|
|
|
|
#include "cdbdebugengine_p.h"
|
|
|
|
|
|
|
|
|
|
#include <QtCore/QTextStream>
|
|
|
|
|
#include <QtCore/QDir>
|
|
|
|
|
#include <QtCore/QDebug>
|
|
|
|
|
#include <QtCore/QMap>
|
|
|
|
|
|
2009-05-12 14:28:27 +02:00
|
|
|
enum { debugBP = 0 };
|
|
|
|
|
|
2009-04-07 17:07:11 +02:00
|
|
|
namespace Debugger {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
// The CDB breakpoint expression syntax is:
|
|
|
|
|
// `foo.cpp:523`[ "condition"]
|
|
|
|
|
// module!function[ "condition"]
|
|
|
|
|
|
|
|
|
|
static const char sourceFileQuoteC = '`';
|
|
|
|
|
|
|
|
|
|
CDBBreakPoint::CDBBreakPoint() :
|
|
|
|
|
ignoreCount(0),
|
2009-04-22 17:28:26 +02:00
|
|
|
lineNumber(-1),
|
2009-05-12 14:28:27 +02:00
|
|
|
oneShot(false),
|
|
|
|
|
enabled(true)
|
2009-04-07 17:07:11 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CDBBreakPoint::CDBBreakPoint(const BreakpointData &bpd) :
|
2009-05-12 14:28:27 +02:00
|
|
|
fileName(QDir::toNativeSeparators(bpd.fileName)),
|
2009-04-07 17:07:11 +02:00
|
|
|
condition(bpd.condition),
|
|
|
|
|
ignoreCount(0),
|
|
|
|
|
funcName(bpd.funcName),
|
2009-04-22 17:28:26 +02:00
|
|
|
lineNumber(-1),
|
2009-05-12 14:28:27 +02:00
|
|
|
oneShot(false),
|
|
|
|
|
enabled(bpd.enabled)
|
2009-04-07 17:07:11 +02:00
|
|
|
{
|
|
|
|
|
if (!bpd.ignoreCount.isEmpty())
|
|
|
|
|
ignoreCount = bpd.ignoreCount.toInt();
|
|
|
|
|
if (!bpd.lineNumber.isEmpty())
|
|
|
|
|
lineNumber = bpd.lineNumber.toInt();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int CDBBreakPoint::compare(const CDBBreakPoint& rhs) const
|
|
|
|
|
{
|
|
|
|
|
if (ignoreCount > rhs.ignoreCount)
|
|
|
|
|
return 1;
|
|
|
|
|
if (ignoreCount < rhs.ignoreCount)
|
|
|
|
|
return -1;
|
|
|
|
|
if (lineNumber > rhs.lineNumber)
|
|
|
|
|
return 1;
|
|
|
|
|
if (lineNumber < rhs.lineNumber)
|
|
|
|
|
return -1;
|
2009-04-22 17:28:26 +02:00
|
|
|
if (oneShot && !rhs.oneShot)
|
|
|
|
|
return 1;
|
|
|
|
|
if (!oneShot && rhs.oneShot)
|
|
|
|
|
return -1;
|
2009-05-12 14:28:27 +02:00
|
|
|
if (enabled && !rhs.enabled)
|
|
|
|
|
return 1;
|
|
|
|
|
if (!enabled && rhs.enabled)
|
|
|
|
|
return -1;
|
2009-04-07 17:07:11 +02:00
|
|
|
if (const int fileCmp = fileName.compare(rhs.fileName))
|
|
|
|
|
return fileCmp;
|
|
|
|
|
if (const int funcCmp = funcName.compare(rhs.funcName))
|
|
|
|
|
return funcCmp;
|
|
|
|
|
if (const int condCmp = condition.compare(rhs.condition))
|
|
|
|
|
return condCmp;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CDBBreakPoint::clear()
|
|
|
|
|
{
|
|
|
|
|
ignoreCount = 0;
|
2009-04-22 17:28:26 +02:00
|
|
|
oneShot = false;
|
2009-05-12 14:28:27 +02:00
|
|
|
enabled = true;
|
2009-04-22 17:28:26 +02:00
|
|
|
clearExpressionData();
|
2009-04-07 17:07:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CDBBreakPoint::clearExpressionData()
|
|
|
|
|
{
|
|
|
|
|
fileName.clear();
|
|
|
|
|
condition.clear();
|
|
|
|
|
funcName.clear();
|
|
|
|
|
lineNumber = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QDebug operator<<(QDebug dbg, const CDBBreakPoint &bp)
|
|
|
|
|
{
|
2009-04-08 16:37:41 +02:00
|
|
|
QDebug nsp = dbg.nospace();
|
|
|
|
|
if (!bp.fileName.isEmpty()) {
|
|
|
|
|
nsp << "fileName='" << bp.fileName << ':' << bp.lineNumber << '\'';
|
|
|
|
|
} else {
|
|
|
|
|
nsp << "funcName='" << bp.funcName << '\'';
|
|
|
|
|
}
|
|
|
|
|
if (!bp.condition.isEmpty())
|
|
|
|
|
nsp << " condition='" << bp.condition << '\'';
|
|
|
|
|
if (bp.ignoreCount)
|
|
|
|
|
nsp << " ignoreCount=" << bp.ignoreCount;
|
2009-05-12 14:28:27 +02:00
|
|
|
if (bp.enabled)
|
|
|
|
|
nsp << " enabled";
|
2009-04-22 17:28:26 +02:00
|
|
|
if (bp.oneShot)
|
|
|
|
|
nsp << " oneShot";
|
2009-04-07 17:07:11 +02:00
|
|
|
return dbg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString CDBBreakPoint::expression() const
|
|
|
|
|
{
|
|
|
|
|
// format the breakpoint expression (file/function and condition)
|
|
|
|
|
QString rc;
|
|
|
|
|
QTextStream str(&rc);
|
|
|
|
|
if (funcName.isEmpty()) {
|
|
|
|
|
const QChar sourceFileQuote = QLatin1Char(sourceFileQuoteC);
|
|
|
|
|
str << sourceFileQuote << QDir::toNativeSeparators(fileName) << QLatin1Char(':') << lineNumber << sourceFileQuote;
|
|
|
|
|
} else {
|
|
|
|
|
str << funcName;
|
|
|
|
|
}
|
|
|
|
|
if (!condition.isEmpty()) {
|
|
|
|
|
const QChar doubleQuote = QLatin1Char('"');
|
|
|
|
|
str << QLatin1Char(' ') << doubleQuote << condition << doubleQuote;
|
|
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-21 12:30:12 +02:00
|
|
|
bool CDBBreakPoint::apply(CIDebugBreakpoint *ibp, QString *errorMessage) const
|
2009-04-07 17:07:11 +02:00
|
|
|
{
|
|
|
|
|
const QString expr = expression();
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << *this << expr;
|
|
|
|
|
const HRESULT hr = ibp->SetOffsetExpressionWide(expr.utf16());
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = QString::fromLatin1("Unable to set breakpoint '%1' : %2").
|
|
|
|
|
arg(expr, msgComFailed("SetOffsetExpressionWide", hr));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Pass Count is ignoreCount + 1
|
|
|
|
|
ibp->SetPassCount(ignoreCount + 1u);
|
2009-05-12 14:28:27 +02:00
|
|
|
ULONG flags = 0;
|
|
|
|
|
if (enabled)
|
|
|
|
|
flags |= DEBUG_BREAKPOINT_ENABLED;
|
2009-04-22 17:28:26 +02:00
|
|
|
if (oneShot)
|
|
|
|
|
flags |= DEBUG_BREAKPOINT_ONE_SHOT;
|
|
|
|
|
ibp->AddFlags(flags);
|
2009-04-07 17:07:11 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-12 14:28:27 +02:00
|
|
|
static inline QString msgCannotAddBreakPoint(const QString &why)
|
|
|
|
|
{
|
|
|
|
|
return QString::fromLatin1("Unable to add breakpoint: %1").arg(why);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CDBBreakPoint::add(CIDebugControl* debugControl,
|
|
|
|
|
quint64 *address, unsigned long *id,
|
|
|
|
|
QString *errorMessage) const
|
2009-04-07 17:07:11 +02:00
|
|
|
{
|
|
|
|
|
IDebugBreakpoint2* ibp = 0;
|
2009-05-12 14:28:27 +02:00
|
|
|
*address = 0;
|
|
|
|
|
*id = 0;
|
|
|
|
|
HRESULT hr = debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &ibp);
|
2009-04-07 17:07:11 +02:00
|
|
|
if (FAILED(hr)) {
|
2009-05-12 14:28:27 +02:00
|
|
|
*errorMessage = msgCannotAddBreakPoint(msgComFailed("AddBreakpoint2", hr));
|
2009-04-07 17:07:11 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!ibp) {
|
2009-05-12 14:28:27 +02:00
|
|
|
*errorMessage = msgCannotAddBreakPoint(QLatin1String("<Unknown error>"));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!apply(ibp, errorMessage))
|
|
|
|
|
return false;
|
|
|
|
|
// GetOffset can fail when attaching to remote processes.
|
|
|
|
|
hr = ibp->GetOffset(address);
|
|
|
|
|
if (FAILED(hr))
|
|
|
|
|
*address = 0;
|
|
|
|
|
hr = ibp->GetId(id);
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = msgCannotAddBreakPoint(msgComFailed("GetId", hr));
|
2009-04-07 17:07:11 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2009-05-12 14:28:27 +02:00
|
|
|
return true;
|
2009-04-07 17:07:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure file can be found in editor manager and text markers
|
|
|
|
|
// Use '/' and capitalize drive letter
|
|
|
|
|
QString CDBBreakPoint::canonicalSourceFile(const QString &f)
|
|
|
|
|
{
|
|
|
|
|
if (f.isEmpty())
|
|
|
|
|
return f;
|
|
|
|
|
QString rc = QDir::fromNativeSeparators(f);
|
|
|
|
|
if (rc.size() > 2 && rc.at(1) == QLatin1Char(':'))
|
|
|
|
|
rc[0] = rc.at(0).toUpper();
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-21 12:30:12 +02:00
|
|
|
bool CDBBreakPoint::retrieve(CIDebugBreakpoint *ibp, QString *errorMessage)
|
2009-04-07 17:07:11 +02:00
|
|
|
{
|
|
|
|
|
clear();
|
|
|
|
|
WCHAR wszBuf[MAX_PATH];
|
|
|
|
|
const HRESULT hr =ibp->GetOffsetExpressionWide(wszBuf, MAX_PATH, 0);
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = QString::fromLatin1("Cannot retrieve breakpoint: %1").
|
|
|
|
|
arg(msgComFailed("GetOffsetExpressionWide", hr));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Pass Count is ignoreCount + 1
|
|
|
|
|
ibp->GetPassCount(&ignoreCount);
|
|
|
|
|
if (ignoreCount)
|
|
|
|
|
ignoreCount--;
|
2009-04-22 17:28:26 +02:00
|
|
|
ULONG flags = 0;
|
|
|
|
|
ibp->GetFlags(&flags);
|
2009-05-12 14:28:27 +02:00
|
|
|
oneShot = (flags & DEBUG_BREAKPOINT_ONE_SHOT);
|
|
|
|
|
enabled = (flags & DEBUG_BREAKPOINT_ENABLED);
|
2009-04-07 17:07:11 +02:00
|
|
|
const QString expr = QString::fromUtf16(wszBuf);
|
|
|
|
|
if (!parseExpression(expr)) {
|
|
|
|
|
*errorMessage = QString::fromLatin1("Parsing of '%1' failed.").arg(expr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CDBBreakPoint::parseExpression(const QString &expr)
|
|
|
|
|
{
|
|
|
|
|
clearExpressionData();
|
|
|
|
|
const QChar sourceFileQuote = QLatin1Char(sourceFileQuoteC);
|
|
|
|
|
// Check for file or function
|
|
|
|
|
int conditionPos = 0;
|
|
|
|
|
if (expr.startsWith(sourceFileQuote)) { // `c:\foo.cpp:523`[ "condition"]
|
|
|
|
|
// Do not fall for the drive letter colon here
|
|
|
|
|
const int colonPos = expr.indexOf(QLatin1Char(':'), 3);
|
|
|
|
|
if (colonPos == -1)
|
|
|
|
|
return false;
|
|
|
|
|
conditionPos = expr.indexOf(sourceFileQuote, colonPos + 1);
|
|
|
|
|
if (conditionPos == -1)
|
|
|
|
|
return false;
|
|
|
|
|
fileName = canonicalSourceFile(expr.mid(1, colonPos - 1));
|
|
|
|
|
const QString lineNumberS = expr.mid(colonPos + 1, conditionPos - colonPos - 1);
|
|
|
|
|
bool lineNumberOk = false;
|
|
|
|
|
lineNumber = lineNumberS.toInt(&lineNumberOk);
|
|
|
|
|
if (!lineNumberOk)
|
|
|
|
|
return false;
|
|
|
|
|
conditionPos++;
|
|
|
|
|
} else {
|
|
|
|
|
// Check function token
|
|
|
|
|
conditionPos = expr.indexOf(QLatin1Char(' '));
|
|
|
|
|
if (conditionPos != -1) {
|
|
|
|
|
funcName = expr.mid(0, conditionPos);
|
|
|
|
|
conditionPos++;
|
|
|
|
|
} else {
|
|
|
|
|
funcName = expr;
|
|
|
|
|
conditionPos = expr.size();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Condition? ".if bla"
|
|
|
|
|
if (conditionPos >= expr.size())
|
|
|
|
|
return true;
|
|
|
|
|
const QChar doubleQuote = QLatin1Char('"');
|
|
|
|
|
conditionPos = expr.indexOf(doubleQuote, conditionPos);
|
|
|
|
|
if (conditionPos == -1)
|
|
|
|
|
return true;
|
|
|
|
|
conditionPos++;
|
|
|
|
|
const int condEndPos = expr.lastIndexOf(doubleQuote);
|
|
|
|
|
if (condEndPos == -1)
|
|
|
|
|
return false;
|
|
|
|
|
condition = expr.mid(conditionPos, condEndPos - conditionPos);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-21 12:30:12 +02:00
|
|
|
bool CDBBreakPoint::getBreakPointCount(CIDebugControl* debugControl, ULONG *count, QString *errorMessage /* = 0*/)
|
2009-04-08 16:37:41 +02:00
|
|
|
{
|
|
|
|
|
const HRESULT hr = debugControl->GetNumberBreakpoints(count);
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
if (errorMessage)
|
|
|
|
|
*errorMessage = QString::fromLatin1("Cannot determine breakpoint count: %1").
|
|
|
|
|
arg(msgComFailed("GetNumberBreakpoints", hr));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-21 12:30:12 +02:00
|
|
|
bool CDBBreakPoint::getBreakPoints(CIDebugControl* debugControl, QList<CDBBreakPoint> *bps, QString *errorMessage)
|
2009-04-07 17:07:11 +02:00
|
|
|
{
|
|
|
|
|
ULONG count = 0;
|
|
|
|
|
bps->clear();
|
2009-04-08 16:37:41 +02:00
|
|
|
if (!getBreakPointCount(debugControl, &count, errorMessage))
|
2009-04-07 17:07:11 +02:00
|
|
|
return false;
|
|
|
|
|
// retrieve one by one and parse
|
|
|
|
|
for (ULONG b= 0; b < count; b++) {
|
|
|
|
|
IDebugBreakpoint2 *ibp = 0;
|
2009-04-08 16:37:41 +02:00
|
|
|
const HRESULT hr = debugControl->GetBreakpointByIndex2(b, &ibp);
|
2009-04-07 17:07:11 +02:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = QString::fromLatin1("Cannot retrieve breakpoint %1: %2").
|
|
|
|
|
arg(b).arg(msgComFailed("GetBreakpointByIndex2", hr));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
CDBBreakPoint bp;
|
|
|
|
|
if (!bp.retrieve(ibp, errorMessage))
|
|
|
|
|
return false;
|
|
|
|
|
bps->push_back(bp);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-12 14:28:27 +02:00
|
|
|
// Find a breakpoint by id
|
|
|
|
|
static inline QString msgNoBreakPointWithId(unsigned long id, const QString &why)
|
|
|
|
|
{
|
|
|
|
|
return QString::fromLatin1("Unable to find breakpoint with id %1: %2").arg(id).arg(why);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static IDebugBreakpoint2 *breakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage)
|
|
|
|
|
{
|
|
|
|
|
CIDebugBreakpoint *ibp = 0;
|
|
|
|
|
const HRESULT hr = ctl->GetBreakpointById2(id, &ibp);
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = msgNoBreakPointWithId(id, msgComFailed("GetBreakpointById2", hr));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!ibp) {
|
|
|
|
|
*errorMessage = msgNoBreakPointWithId(id, QLatin1String("<not found>"));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return ibp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove breakpoint by id
|
|
|
|
|
static bool removeBreakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage)
|
|
|
|
|
{
|
|
|
|
|
if (debugBP)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << id;
|
|
|
|
|
CIDebugBreakpoint *ibp = breakPointById(ctl, id, errorMessage);
|
|
|
|
|
if (!ibp)
|
|
|
|
|
return false;
|
|
|
|
|
const HRESULT hr = ctl->RemoveBreakpoint2(ibp);
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = QString::fromLatin1("Cannot remove breakpoint %1: %2").arg(id).arg(msgComFailed("RemoveBreakpointById2", hr));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set enabled by id
|
|
|
|
|
|
|
|
|
|
// Change enabled state of a breakpoint by id
|
|
|
|
|
static inline QString msgCannotSetBreakPointEnabled(unsigned long id, bool enabled, const QString &why)
|
|
|
|
|
{
|
|
|
|
|
return QString::fromLatin1("Cannot %1 breakpoint %2: %3").
|
|
|
|
|
arg(QLatin1String(enabled ? "enable" : "disable")).arg(id).arg(why);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool setBreakPointEnabledById(CIDebugControl *ctl, unsigned long id, bool enabled, QString *errorMessage)
|
|
|
|
|
{
|
|
|
|
|
if (debugBP)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << id << enabled;
|
|
|
|
|
CIDebugBreakpoint *ibp = breakPointById(ctl, id, errorMessage);
|
|
|
|
|
if (!ibp) {
|
|
|
|
|
*errorMessage = msgCannotSetBreakPointEnabled(id, enabled, *errorMessage);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Compare flags
|
|
|
|
|
ULONG flags;
|
|
|
|
|
HRESULT hr = ibp->GetFlags(&flags);
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = msgCannotSetBreakPointEnabled(id, enabled, msgComFailed("GetFlags", hr));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
const bool wasEnabled = (flags & DEBUG_BREAKPOINT_ENABLED);
|
|
|
|
|
if (wasEnabled == enabled)
|
|
|
|
|
return true;
|
|
|
|
|
// Set new value
|
|
|
|
|
if (enabled) {
|
|
|
|
|
flags |= DEBUG_BREAKPOINT_ENABLED;
|
|
|
|
|
} else {
|
|
|
|
|
flags &= ~DEBUG_BREAKPOINT_ENABLED;
|
|
|
|
|
}
|
|
|
|
|
hr = ibp->SetFlags(flags);
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = msgCannotSetBreakPointEnabled(id, enabled, msgComFailed("SetFlags", hr));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2009-04-15 10:05:40 +02:00
|
|
|
|
2009-04-07 17:07:11 +02:00
|
|
|
// Synchronize (halted) engine breakpoints with those of the BreakHandler.
|
2009-05-12 14:28:27 +02:00
|
|
|
bool CDBBreakPoint::synchronizeBreakPoints(CIDebugControl* debugControl,
|
|
|
|
|
CIDebugSymbols *syms,
|
2009-04-07 17:07:11 +02:00
|
|
|
BreakHandler *handler,
|
|
|
|
|
QString *errorMessage)
|
|
|
|
|
{
|
2009-05-12 14:28:27 +02:00
|
|
|
// Do an initial check whether we are in a state that allows
|
|
|
|
|
// for modifying breakPoints
|
|
|
|
|
ULONG engineCount;
|
|
|
|
|
if (!getBreakPointCount(debugControl, &engineCount, errorMessage)) {
|
|
|
|
|
*errorMessage = QString::fromLatin1("Cannot modify breakpoints: %1").arg(*errorMessage);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Insert new ones
|
|
|
|
|
bool updateMarkers = false;
|
|
|
|
|
foreach (BreakpointData *nbd, handler->insertedBreakpoints()) {
|
2009-04-15 10:05:40 +02:00
|
|
|
// Function breakpoints: Are the module names specified?
|
|
|
|
|
bool breakPointOk = false;
|
2009-05-12 14:28:27 +02:00
|
|
|
if (nbd->funcName.isEmpty()) {
|
2009-04-15 10:05:40 +02:00
|
|
|
breakPointOk = true;
|
|
|
|
|
} else {
|
2009-05-12 14:28:27 +02:00
|
|
|
switch (resolveSymbol(syms, &nbd->funcName, errorMessage)) {
|
2009-04-15 10:05:40 +02:00
|
|
|
case ResolveSymbolOk:
|
|
|
|
|
breakPointOk = true;
|
|
|
|
|
break;
|
|
|
|
|
case ResolveSymbolAmbiguous:
|
|
|
|
|
qWarning("Warning: %s\n", qPrintable(*errorMessage));
|
|
|
|
|
breakPointOk = true;
|
|
|
|
|
break;
|
|
|
|
|
case ResolveSymbolNotFound:
|
|
|
|
|
case ResolveSymbolError:
|
|
|
|
|
qWarning("Warning: %s\n", qPrintable(*errorMessage));
|
|
|
|
|
break;
|
|
|
|
|
};
|
|
|
|
|
} // function breakpoint
|
2009-05-12 14:28:27 +02:00
|
|
|
// Now add...
|
|
|
|
|
if (breakPointOk) {
|
|
|
|
|
quint64 address;
|
|
|
|
|
unsigned long id;
|
|
|
|
|
CDBBreakPoint ncdbbp(*nbd);
|
|
|
|
|
breakPointOk = ncdbbp.add(debugControl, &address, &id, errorMessage);
|
|
|
|
|
if (breakPointOk) {
|
|
|
|
|
if (debugBP)
|
|
|
|
|
qDebug() << "Added " << id << " at " << address << ncdbbp;
|
|
|
|
|
handler->takeInsertedBreakPoint(nbd);
|
|
|
|
|
updateMarkers = true;
|
|
|
|
|
nbd->pending = false;
|
|
|
|
|
nbd->bpNumber = QString::number(id);
|
|
|
|
|
nbd->bpAddress = QLatin1String("0x") + QString::number(address, 16);
|
|
|
|
|
// Take over rest as is
|
|
|
|
|
nbd->bpCondition = nbd->condition;
|
|
|
|
|
nbd->bpIgnoreCount = nbd->ignoreCount;
|
|
|
|
|
nbd->bpFileName = nbd->fileName;
|
|
|
|
|
nbd->bpLineNumber = nbd->lineNumber;
|
|
|
|
|
nbd->bpFuncName = nbd->funcName;
|
2009-04-07 17:07:11 +02:00
|
|
|
}
|
2009-05-12 14:28:27 +02:00
|
|
|
} // had symbol
|
|
|
|
|
if (!breakPointOk)
|
|
|
|
|
qWarning("%s\n", qPrintable(*errorMessage));
|
2009-04-07 17:07:11 +02:00
|
|
|
}
|
2009-05-12 14:28:27 +02:00
|
|
|
// Delete
|
|
|
|
|
foreach (BreakpointData *rbd, handler->takeRemovedBreakpoints()) {
|
|
|
|
|
if (!removeBreakPointById(debugControl, rbd->bpNumber.toUInt(), errorMessage))
|
|
|
|
|
qWarning("%s\n", qPrintable(*errorMessage));
|
|
|
|
|
delete rbd;
|
2009-04-07 17:07:11 +02:00
|
|
|
}
|
2009-05-12 14:28:27 +02:00
|
|
|
// Enable/Disable
|
|
|
|
|
foreach (BreakpointData *ebd, handler->takeEnabledBreakpoints())
|
|
|
|
|
if (!setBreakPointEnabledById(debugControl, ebd->bpNumber.toUInt(), true, errorMessage))
|
|
|
|
|
qWarning("%s\n", qPrintable(*errorMessage));
|
|
|
|
|
foreach (BreakpointData *dbd, handler->takeDisabledBreakpoints())
|
|
|
|
|
if (!setBreakPointEnabledById(debugControl, dbd->bpNumber.toUInt(), false, errorMessage))
|
|
|
|
|
qWarning("%s\n", qPrintable(*errorMessage));
|
|
|
|
|
|
|
|
|
|
if (updateMarkers)
|
|
|
|
|
handler->updateMarkers();
|
|
|
|
|
|
|
|
|
|
if (debugBP > 1) {
|
2009-04-07 17:07:11 +02:00
|
|
|
QList<CDBBreakPoint> bps;
|
|
|
|
|
CDBBreakPoint::getBreakPoints(debugControl, &bps, errorMessage);
|
|
|
|
|
qDebug().nospace() << "### Breakpoints in engine: " << bps;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-15 14:26:08 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|