forked from qt-creator/qt-creator
Fixed breakpoints for CDB.
Set/modify breakpoints using the new takeXX() APIs of the breakhandler. Add API for inserted breakpoints (as a 2-step process for pending breakpoints). Format breakpoint tooltip properly with tr() and more esthetically pleasing. Get rid of the old scheme of retrieving and matching the breakpoints from the debugger engine, use ids.
This commit is contained in:
@@ -34,6 +34,7 @@
|
|||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
|
#include <QtCore/QTextStream>
|
||||||
#include <QtCore/QFileInfo>
|
#include <QtCore/QFileInfo>
|
||||||
|
|
||||||
using namespace Debugger;
|
using namespace Debugger;
|
||||||
@@ -191,23 +192,25 @@ void BreakpointData::updateMarker()
|
|||||||
|
|
||||||
QString BreakpointData::toToolTip() const
|
QString BreakpointData::toToolTip() const
|
||||||
{
|
{
|
||||||
QString str;
|
QString rc;
|
||||||
str += "<table>";
|
QTextStream str(&rc);
|
||||||
str += "<tr><td>Marker File:</td><td>" + markerFileName + "</td></tr>";
|
str << "<html><body><table>";
|
||||||
str += "<tr><td>Marker Line:</td><td>" + QString::number(markerLineNumber) + "</td></tr>";
|
str << "<tr><td>" << BreakHandler::tr("Marker File:") << "</td><td>" << markerFileName << "</td></tr>";
|
||||||
str += "<tr><td>BP Number:</td><td>" + bpNumber + "</td></tr>";
|
str << "<tr><td>" << BreakHandler::tr("Marker Line:") << "</td><td>" << markerLineNumber << "</td></tr>";
|
||||||
str += "<tr><td>BP Address:</td><td>" + bpAddress + "</td></tr>";
|
str << "<tr><td>" << BreakHandler::tr("Breakpoint Number:") << "</td><td>" << bpNumber << "</td></tr>";
|
||||||
str += "<tr><td>----------</td><td></td><td></td></tr>";
|
str << "<tr><td>" << BreakHandler::tr("Breakpoint Address:") << "</td><td>" << bpAddress << "</td></tr>";
|
||||||
str += "<tr><td>Property:</td><td>Wanted:</td><td>Actual:</td></tr>";
|
str << "</table><br><hr><table>";
|
||||||
str += "<tr><td></td><td></td><td></td></tr>";
|
str << "<tr><th>" << BreakHandler::tr("Property")
|
||||||
str += "<tr><td>Internal Number:</td><td>-</td><td>" + bpNumber + "</td></tr>";
|
<< "</th><th>" << BreakHandler::tr("Requested")
|
||||||
str += "<tr><td>File Name:</td><td>" + fileName + "</td><td>" + bpFileName + "</td></tr>";
|
<< "</th><th>" << BreakHandler::tr("Obtained") << "</th></tr>";
|
||||||
str += "<tr><td>Function Name:</td><td>" + funcName + "</td><td>" + bpFuncName + "</td></tr>";
|
str << "<tr><td>" << BreakHandler::tr("Internal Number:") << "</td><td>—</td><td>" << bpNumber << "</td></tr>";
|
||||||
str += "<tr><td>Line Number:</td><td>" + lineNumber + "</td><td>" + bpLineNumber + "</td></tr>";
|
str << "<tr><td>" << BreakHandler::tr("File Name:") << "</td><td>" << fileName << "</td><td>" << bpFileName << "</td></tr>";
|
||||||
str += "<tr><td>Condition:</td><td>" + condition + "</td><td>" + bpCondition + "</td></tr>";
|
str << "<tr><td>" << BreakHandler::tr("Function Name:") << "</td><td>" << funcName << "</td><td>" << bpFuncName << "</td></tr>";
|
||||||
str += "<tr><td>Ignore count:</td><td>" + ignoreCount + "</td><td>" + bpIgnoreCount + "</td></tr>";
|
str << "<tr><td>" << BreakHandler::tr("Line Number:") << "</td><td>" << lineNumber << "</td><td>" << bpLineNumber << "</td></tr>";
|
||||||
str += "</table>";
|
str << "<tr><td>" << BreakHandler::tr("Condition:") << "</td><td>" << condition << "</td><td>" << bpCondition << "</td></tr>";
|
||||||
return str;
|
str << "<tr><td>" << BreakHandler::tr("Ignore Count:") << "</td><td>" << ignoreCount << "</td><td>" << bpIgnoreCount << "</td></tr>";
|
||||||
|
str << "</table></body></html>";
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BreakpointData::isLocatedAt(const QString &fileName_, int lineNumber_) const
|
bool BreakpointData::isLocatedAt(const QString &fileName_, int lineNumber_) const
|
||||||
@@ -524,6 +527,22 @@ bool BreakHandler::setData(const QModelIndex &mi, const QVariant &value, int rol
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BreakHandler::append(BreakpointData *data)
|
||||||
|
{
|
||||||
|
m_bp.append(data);
|
||||||
|
m_inserted.append(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<BreakpointData *> BreakHandler::insertedBreakpoints() const
|
||||||
|
{
|
||||||
|
return m_inserted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BreakHandler::takeInsertedBreakPoint(BreakpointData *d)
|
||||||
|
{
|
||||||
|
m_inserted.removeAll(d);
|
||||||
|
}
|
||||||
|
|
||||||
QList<BreakpointData *> BreakHandler::takeRemovedBreakpoints()
|
QList<BreakpointData *> BreakHandler::takeRemovedBreakpoints()
|
||||||
{
|
{
|
||||||
QList<BreakpointData *> result = m_removed;
|
QList<BreakpointData *> result = m_removed;
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ public:
|
|||||||
BreakpointData *at(int index) const { return index < size() ? m_bp.at(index) : 0; }
|
BreakpointData *at(int index) const { return index < size() ? m_bp.at(index) : 0; }
|
||||||
int size() const { return m_bp.size(); }
|
int size() const { return m_bp.size(); }
|
||||||
bool hasPendingBreakpoints() const;
|
bool hasPendingBreakpoints() const;
|
||||||
void append(BreakpointData *data) { m_bp.append(data); }
|
void append(BreakpointData *data);
|
||||||
void removeAt(int index); // also deletes the marker
|
void removeAt(int index); // also deletes the marker
|
||||||
void clear(); // also deletes all the marker
|
void clear(); // also deletes all the marker
|
||||||
int indexOf(BreakpointData *data) { return m_bp.indexOf(data); }
|
int indexOf(BreakpointData *data) { return m_bp.indexOf(data); }
|
||||||
@@ -132,6 +132,8 @@ public:
|
|||||||
int findBreakpoint(int bpNumber); // returns index
|
int findBreakpoint(int bpNumber); // returns index
|
||||||
void updateMarkers();
|
void updateMarkers();
|
||||||
|
|
||||||
|
QList<BreakpointData *> insertedBreakpoints() const;
|
||||||
|
void takeInsertedBreakPoint(BreakpointData *);
|
||||||
QList<BreakpointData *> takeRemovedBreakpoints(); // owned
|
QList<BreakpointData *> takeRemovedBreakpoints(); // owned
|
||||||
QList<BreakpointData *> takeEnabledBreakpoints(); // not owned
|
QList<BreakpointData *> takeEnabledBreakpoints(); // not owned
|
||||||
QList<BreakpointData *> takeDisabledBreakpoints(); // not owned
|
QList<BreakpointData *> takeDisabledBreakpoints(); // not owned
|
||||||
@@ -171,6 +173,7 @@ private:
|
|||||||
void removeBreakpointHelper(int index);
|
void removeBreakpointHelper(int index);
|
||||||
|
|
||||||
QList<BreakpointData *> m_bp;
|
QList<BreakpointData *> m_bp;
|
||||||
|
QList<BreakpointData *> m_inserted; // lately inserted breakpoints
|
||||||
QList<BreakpointData *> m_removed; // lately removed breakpoints
|
QList<BreakpointData *> m_removed; // lately removed breakpoints
|
||||||
QList<BreakpointData *> m_enabled; // lately enabled breakpoints
|
QList<BreakpointData *> m_enabled; // lately enabled breakpoints
|
||||||
QList<BreakpointData *> m_disabled; // lately disabled breakpoints
|
QList<BreakpointData *> m_disabled; // lately disabled breakpoints
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QtCore/QMap>
|
#include <QtCore/QMap>
|
||||||
|
|
||||||
|
enum { debugBP = 0 };
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -49,17 +51,19 @@ static const char sourceFileQuoteC = '`';
|
|||||||
CDBBreakPoint::CDBBreakPoint() :
|
CDBBreakPoint::CDBBreakPoint() :
|
||||||
ignoreCount(0),
|
ignoreCount(0),
|
||||||
lineNumber(-1),
|
lineNumber(-1),
|
||||||
oneShot(false)
|
oneShot(false),
|
||||||
|
enabled(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CDBBreakPoint::CDBBreakPoint(const BreakpointData &bpd) :
|
CDBBreakPoint::CDBBreakPoint(const BreakpointData &bpd) :
|
||||||
fileName(bpd.fileName),
|
fileName(QDir::toNativeSeparators(bpd.fileName)),
|
||||||
condition(bpd.condition),
|
condition(bpd.condition),
|
||||||
ignoreCount(0),
|
ignoreCount(0),
|
||||||
funcName(bpd.funcName),
|
funcName(bpd.funcName),
|
||||||
lineNumber(-1),
|
lineNumber(-1),
|
||||||
oneShot(false)
|
oneShot(false),
|
||||||
|
enabled(bpd.enabled)
|
||||||
{
|
{
|
||||||
if (!bpd.ignoreCount.isEmpty())
|
if (!bpd.ignoreCount.isEmpty())
|
||||||
ignoreCount = bpd.ignoreCount.toInt();
|
ignoreCount = bpd.ignoreCount.toInt();
|
||||||
@@ -81,6 +85,10 @@ int CDBBreakPoint::compare(const CDBBreakPoint& rhs) const
|
|||||||
return 1;
|
return 1;
|
||||||
if (!oneShot && rhs.oneShot)
|
if (!oneShot && rhs.oneShot)
|
||||||
return -1;
|
return -1;
|
||||||
|
if (enabled && !rhs.enabled)
|
||||||
|
return 1;
|
||||||
|
if (!enabled && rhs.enabled)
|
||||||
|
return -1;
|
||||||
if (const int fileCmp = fileName.compare(rhs.fileName))
|
if (const int fileCmp = fileName.compare(rhs.fileName))
|
||||||
return fileCmp;
|
return fileCmp;
|
||||||
if (const int funcCmp = funcName.compare(rhs.funcName))
|
if (const int funcCmp = funcName.compare(rhs.funcName))
|
||||||
@@ -94,6 +102,7 @@ void CDBBreakPoint::clear()
|
|||||||
{
|
{
|
||||||
ignoreCount = 0;
|
ignoreCount = 0;
|
||||||
oneShot = false;
|
oneShot = false;
|
||||||
|
enabled = true;
|
||||||
clearExpressionData();
|
clearExpressionData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +126,8 @@ QDebug operator<<(QDebug dbg, const CDBBreakPoint &bp)
|
|||||||
nsp << " condition='" << bp.condition << '\'';
|
nsp << " condition='" << bp.condition << '\'';
|
||||||
if (bp.ignoreCount)
|
if (bp.ignoreCount)
|
||||||
nsp << " ignoreCount=" << bp.ignoreCount;
|
nsp << " ignoreCount=" << bp.ignoreCount;
|
||||||
|
if (bp.enabled)
|
||||||
|
nsp << " enabled";
|
||||||
if (bp.oneShot)
|
if (bp.oneShot)
|
||||||
nsp << " oneShot";
|
nsp << " oneShot";
|
||||||
return dbg;
|
return dbg;
|
||||||
@@ -153,27 +164,48 @@ bool CDBBreakPoint::apply(CIDebugBreakpoint *ibp, QString *errorMessage) const
|
|||||||
}
|
}
|
||||||
// Pass Count is ignoreCount + 1
|
// Pass Count is ignoreCount + 1
|
||||||
ibp->SetPassCount(ignoreCount + 1u);
|
ibp->SetPassCount(ignoreCount + 1u);
|
||||||
ULONG flags = DEBUG_BREAKPOINT_ENABLED;
|
ULONG flags = 0;
|
||||||
|
if (enabled)
|
||||||
|
flags |= DEBUG_BREAKPOINT_ENABLED;
|
||||||
if (oneShot)
|
if (oneShot)
|
||||||
flags |= DEBUG_BREAKPOINT_ONE_SHOT;
|
flags |= DEBUG_BREAKPOINT_ONE_SHOT;
|
||||||
ibp->AddFlags(flags);
|
ibp->AddFlags(flags);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CDBBreakPoint::add(CIDebugControl* debugControl, QString *errorMessage) const
|
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
|
||||||
{
|
{
|
||||||
IDebugBreakpoint2* ibp = 0;
|
IDebugBreakpoint2* ibp = 0;
|
||||||
const HRESULT hr = debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &ibp);
|
*address = 0;
|
||||||
|
*id = 0;
|
||||||
|
HRESULT hr = debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &ibp);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
*errorMessage = QString::fromLatin1("Unable to add breakpoint: %1").
|
*errorMessage = msgCannotAddBreakPoint(msgComFailed("AddBreakpoint2", hr));
|
||||||
arg(msgComFailed("AddBreakpoint2", hr));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ibp) {
|
if (!ibp) {
|
||||||
*errorMessage = QString::fromLatin1("Unable to add breakpoint: <Unknown error>");
|
*errorMessage = msgCannotAddBreakPoint(QLatin1String("<Unknown error>"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return apply(ibp, errorMessage);
|
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));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure file can be found in editor manager and text markers
|
// Make sure file can be found in editor manager and text markers
|
||||||
@@ -204,8 +236,8 @@ bool CDBBreakPoint::retrieve(CIDebugBreakpoint *ibp, QString *errorMessage)
|
|||||||
ignoreCount--;
|
ignoreCount--;
|
||||||
ULONG flags = 0;
|
ULONG flags = 0;
|
||||||
ibp->GetFlags(&flags);
|
ibp->GetFlags(&flags);
|
||||||
if (flags & DEBUG_BREAKPOINT_ONE_SHOT)
|
oneShot = (flags & DEBUG_BREAKPOINT_ONE_SHOT);
|
||||||
oneShot = true;
|
enabled = (flags & DEBUG_BREAKPOINT_ENABLED);
|
||||||
const QString expr = QString::fromUtf16(wszBuf);
|
const QString expr = QString::fromUtf16(wszBuf);
|
||||||
if (!parseExpression(expr)) {
|
if (!parseExpression(expr)) {
|
||||||
*errorMessage = QString::fromLatin1("Parsing of '%1' failed.").arg(expr);
|
*errorMessage = QString::fromLatin1("Parsing of '%1' failed.").arg(expr);
|
||||||
@@ -296,31 +328,107 @@ bool CDBBreakPoint::getBreakPoints(CIDebugControl* debugControl, QList<CDBBreakP
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
// Synchronize (halted) engine breakpoints with those of the BreakHandler.
|
// Synchronize (halted) engine breakpoints with those of the BreakHandler.
|
||||||
bool CDBBreakPoint::synchronizeBreakPoints(IDebugControl4* debugControl,
|
bool CDBBreakPoint::synchronizeBreakPoints(CIDebugControl* debugControl,
|
||||||
IDebugSymbols3 *syms,
|
CIDebugSymbols *syms,
|
||||||
BreakHandler *handler,
|
BreakHandler *handler,
|
||||||
QString *errorMessage)
|
QString *errorMessage)
|
||||||
{
|
{
|
||||||
typedef QMap<CDBBreakPoint, int> BreakPointIndexMap;
|
// Do an initial check whether we are in a state that allows
|
||||||
if (debugCDB)
|
// for modifying breakPoints
|
||||||
qDebug() << Q_FUNC_INFO;
|
ULONG engineCount;
|
||||||
|
if (!getBreakPointCount(debugControl, &engineCount, errorMessage)) {
|
||||||
BreakPointIndexMap breakPointIndexMap;
|
*errorMessage = QString::fromLatin1("Cannot modify breakpoints: %1").arg(*errorMessage);
|
||||||
// convert BreakHandler's bps into a map of BreakPoint->BreakHandler->Index
|
return false;
|
||||||
// Ignore invalid functions (that could not be found) as they make
|
}
|
||||||
// the debugger hang.
|
// Insert new ones
|
||||||
const int handlerCount = handler->size();
|
bool updateMarkers = false;
|
||||||
const QChar moduleDelimiter = QLatin1Char('!');
|
foreach (BreakpointData *nbd, handler->insertedBreakpoints()) {
|
||||||
for (int i=0; i < handlerCount; ++i) {
|
|
||||||
BreakpointData *bd = handler->at(i);
|
|
||||||
// Function breakpoints: Are the module names specified?
|
// Function breakpoints: Are the module names specified?
|
||||||
bool breakPointOk = false;
|
bool breakPointOk = false;
|
||||||
if (bd->funcName.isEmpty()) {
|
if (nbd->funcName.isEmpty()) {
|
||||||
breakPointOk = true;
|
breakPointOk = true;
|
||||||
} else {
|
} else {
|
||||||
switch (resolveSymbol(syms, &bd->funcName, errorMessage)) {
|
switch (resolveSymbol(syms, &nbd->funcName, errorMessage)) {
|
||||||
case ResolveSymbolOk:
|
case ResolveSymbolOk:
|
||||||
breakPointOk = true;
|
breakPointOk = true;
|
||||||
break;
|
break;
|
||||||
@@ -334,66 +442,49 @@ bool CDBBreakPoint::synchronizeBreakPoints(IDebugControl4* debugControl,
|
|||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
} // function breakpoint
|
} // function breakpoint
|
||||||
if (breakPointOk)
|
// Now add...
|
||||||
breakPointIndexMap.insert(CDBBreakPoint(*bd), i);
|
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;
|
||||||
}
|
}
|
||||||
errorMessage->clear();
|
} // had symbol
|
||||||
// get number of engine breakpoints
|
if (!breakPointOk)
|
||||||
ULONG engineCount;
|
qWarning("%s\n", qPrintable(*errorMessage));
|
||||||
if (!getBreakPointCount(debugControl, &engineCount, errorMessage))
|
}
|
||||||
return false;
|
// Delete
|
||||||
|
foreach (BreakpointData *rbd, handler->takeRemovedBreakpoints()) {
|
||||||
|
if (!removeBreakPointById(debugControl, rbd->bpNumber.toUInt(), errorMessage))
|
||||||
|
qWarning("%s\n", qPrintable(*errorMessage));
|
||||||
|
delete rbd;
|
||||||
|
}
|
||||||
|
// 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));
|
||||||
|
|
||||||
// Starting from end, check if engine breakpoints are still in handler.
|
if (updateMarkers)
|
||||||
// If not->remove
|
handler->updateMarkers();
|
||||||
if (engineCount) {
|
|
||||||
for (ULONG eb = engineCount - 1u; ; eb--) {
|
if (debugBP > 1) {
|
||||||
// get engine breakpoint.
|
|
||||||
IDebugBreakpoint2 *ibp = 0;
|
|
||||||
HRESULT hr = debugControl->GetBreakpointByIndex2(eb, &ibp);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
*errorMessage = QString::fromLatin1("Cannot retrieve breakpoint %1: %2").
|
|
||||||
arg(eb).arg(msgComFailed("GetBreakpointByIndex2", hr));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Ignore one shot break points set by "Step out"
|
|
||||||
ULONG flags = 0;
|
|
||||||
hr = ibp->GetFlags(&flags);
|
|
||||||
if (!(flags & DEBUG_BREAKPOINT_ONE_SHOT)) {
|
|
||||||
CDBBreakPoint engineBreakPoint;
|
|
||||||
if (!engineBreakPoint.retrieve(ibp, errorMessage))
|
|
||||||
return false;
|
|
||||||
// Still in handler?
|
|
||||||
if (!breakPointIndexMap.contains(engineBreakPoint)) {
|
|
||||||
if (debugCDB)
|
|
||||||
qDebug() << " Removing" << engineBreakPoint;
|
|
||||||
hr = debugControl->RemoveBreakpoint2(ibp);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
*errorMessage = QString::fromLatin1("Cannot remove breakpoint %1: %2").
|
|
||||||
arg(engineBreakPoint.expression(), msgComFailed("RemoveBreakpoint2", hr));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} // not in handler
|
|
||||||
} // one shot
|
|
||||||
if (!eb)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add pending breakpoints
|
|
||||||
const BreakPointIndexMap::const_iterator pcend = breakPointIndexMap.constEnd();
|
|
||||||
for (BreakPointIndexMap::const_iterator it = breakPointIndexMap.constBegin(); it != pcend; ++it) {
|
|
||||||
const int index = it.value();
|
|
||||||
if (handler->at(index)->pending) {
|
|
||||||
if (debugCDB)
|
|
||||||
qDebug() << " Adding " << it.key();
|
|
||||||
if (it.key().add(debugControl, errorMessage)) {
|
|
||||||
handler->at(index)->pending = false;
|
|
||||||
} else {
|
|
||||||
const QString msg = QString::fromLatin1("Failed to add breakpoint '%1': %2").arg(it.key().expression(), *errorMessage);
|
|
||||||
qWarning("%s\n", qPrintable(msg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (debugCDB > 1) {
|
|
||||||
QList<CDBBreakPoint> bps;
|
QList<CDBBreakPoint> bps;
|
||||||
CDBBreakPoint::getBreakPoints(debugControl, &bps, errorMessage);
|
CDBBreakPoint::getBreakPoints(debugControl, &bps, errorMessage);
|
||||||
qDebug().nospace() << "### Breakpoints in engine: " << bps;
|
qDebug().nospace() << "### Breakpoints in engine: " << bps;
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ struct CDBBreakPoint
|
|||||||
// Apply parameters
|
// Apply parameters
|
||||||
bool apply(IDebugBreakpoint2 *ibp, QString *errorMessage) const;
|
bool apply(IDebugBreakpoint2 *ibp, QString *errorMessage) const;
|
||||||
// Convenience to add to a IDebugControl4
|
// Convenience to add to a IDebugControl4
|
||||||
bool add(CIDebugControl* debugControl, QString *errorMessage) const;
|
bool add(CIDebugControl* debugControl, quint64 *address, unsigned long *id, QString *errorMessage) const;
|
||||||
|
|
||||||
// Retrieve/parse breakpoints from the interfaces
|
// Retrieve/parse breakpoints from the interfaces
|
||||||
bool retrieve(IDebugBreakpoint2 *ibp, QString *errorMessage);
|
bool retrieve(IDebugBreakpoint2 *ibp, QString *errorMessage);
|
||||||
@@ -84,6 +84,7 @@ struct CDBBreakPoint
|
|||||||
int lineNumber; // line in source file
|
int lineNumber; // line in source file
|
||||||
QString funcName; // name of containing function
|
QString funcName; // name of containing function
|
||||||
bool oneShot;
|
bool oneShot;
|
||||||
|
bool enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
QDebug operator<<(QDebug, const CDBBreakPoint &bp);
|
QDebug operator<<(QDebug, const CDBBreakPoint &bp);
|
||||||
@@ -92,9 +93,6 @@ inline bool operator==(const CDBBreakPoint& b1, const CDBBreakPoint& b2)
|
|||||||
{ return b1.compare(b2) == 0; }
|
{ return b1.compare(b2) == 0; }
|
||||||
inline bool operator!=(const CDBBreakPoint& b1, const CDBBreakPoint& b2)
|
inline bool operator!=(const CDBBreakPoint& b1, const CDBBreakPoint& b2)
|
||||||
{ return b1.compare(b2) != 0; }
|
{ return b1.compare(b2) != 0; }
|
||||||
inline bool operator<(const CDBBreakPoint& b1, const CDBBreakPoint& b2)
|
|
||||||
{ return b1.compare(b2) < 0; }
|
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
|
|||||||
@@ -135,9 +135,11 @@ bool CdbStackFrameContext::populateModelInitially(WatchHandler *wh, QString *err
|
|||||||
qDebug() << "populateModelInitially";
|
qDebug() << "populateModelInitially";
|
||||||
const bool rc = m_useDumpers ?
|
const bool rc = m_useDumpers ?
|
||||||
CdbSymbolGroupContext::populateModelInitially(m_symbolContext,
|
CdbSymbolGroupContext::populateModelInitially(m_symbolContext,
|
||||||
|
wh->expandedINames(),
|
||||||
WatchHandlerSorterInserter(wh, m_dumper),
|
WatchHandlerSorterInserter(wh, m_dumper),
|
||||||
errorMessage) :
|
errorMessage) :
|
||||||
CdbSymbolGroupContext::populateModelInitially(m_symbolContext,
|
CdbSymbolGroupContext::populateModelInitially(m_symbolContext,
|
||||||
|
wh->expandedINames(),
|
||||||
WatchHandlerModelInserter(wh),
|
WatchHandlerModelInserter(wh),
|
||||||
errorMessage);
|
errorMessage);
|
||||||
return rc;
|
return rc;
|
||||||
|
|||||||
@@ -213,12 +213,24 @@ CdbSymbolGroupContext::SymbolState CdbSymbolGroupContext::symbolState(const QStr
|
|||||||
{
|
{
|
||||||
if (prefix == m_prefix) // root
|
if (prefix == m_prefix) // root
|
||||||
return ExpandedSymbol;
|
return ExpandedSymbol;
|
||||||
const NameIndexMap::const_iterator it = m_inameIndexMap.constFind(prefix);
|
unsigned long index;
|
||||||
if (it != m_inameIndexMap.constEnd())
|
if (!lookupPrefix(prefix, &index)) {
|
||||||
return symbolState(it.value());
|
|
||||||
qWarning("WARNING %s: %s\n", Q_FUNC_INFO, msgSymbolNotFound(prefix));
|
qWarning("WARNING %s: %s\n", Q_FUNC_INFO, msgSymbolNotFound(prefix));
|
||||||
return LeafSymbol;
|
return LeafSymbol;
|
||||||
}
|
}
|
||||||
|
return symbolState(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find index of a prefix
|
||||||
|
bool CdbSymbolGroupContext::lookupPrefix(const QString &prefix, unsigned long *index) const
|
||||||
|
{
|
||||||
|
*index = 0;
|
||||||
|
const NameIndexMap::const_iterator it = m_inameIndexMap.constFind(prefix);
|
||||||
|
if (it == m_inameIndexMap.constEnd())
|
||||||
|
return false;
|
||||||
|
*index = it.value();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Retrieve children and get the position. */
|
/* Retrieve children and get the position. */
|
||||||
bool CdbSymbolGroupContext::getChildSymbolsPosition(const QString &prefix,
|
bool CdbSymbolGroupContext::getChildSymbolsPosition(const QString &prefix,
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include <QtCore/QStringList>
|
#include <QtCore/QStringList>
|
||||||
#include <QtCore/QPair>
|
#include <QtCore/QPair>
|
||||||
#include <QtCore/QMap>
|
#include <QtCore/QMap>
|
||||||
|
#include <QtCore/QSet>
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -74,7 +75,9 @@ public:
|
|||||||
QString *newValue /* = 0 */, QString *errorMessage);
|
QString *newValue /* = 0 */, QString *errorMessage);
|
||||||
|
|
||||||
template <class OutputIterator>
|
template <class OutputIterator>
|
||||||
static bool populateModelInitially(CdbSymbolGroupContext *sg, OutputIterator it, QString *errorMessage);
|
static bool populateModelInitially(CdbSymbolGroupContext *sg,
|
||||||
|
QSet<QString> expandedINames,
|
||||||
|
OutputIterator it, QString *errorMessage);
|
||||||
|
|
||||||
template <class OutputIterator>
|
template <class OutputIterator>
|
||||||
static bool completeModel(CdbSymbolGroupContext *sg,
|
static bool completeModel(CdbSymbolGroupContext *sg,
|
||||||
@@ -116,6 +119,7 @@ private:
|
|||||||
void populateINameIndexMap(const QString &prefix, unsigned long parentId, unsigned long start, unsigned long count);
|
void populateINameIndexMap(const QString &prefix, unsigned long parentId, unsigned long start, unsigned long count);
|
||||||
WatchData symbolAt(unsigned long index) const;
|
WatchData symbolAt(unsigned long index) const;
|
||||||
QString symbolINameAt(unsigned long index) const;
|
QString symbolINameAt(unsigned long index) const;
|
||||||
|
bool lookupPrefix(const QString &prefix, unsigned long *index) const;
|
||||||
int getDisplayableChildCount(unsigned long index) const;
|
int getDisplayableChildCount(unsigned long index) const;
|
||||||
|
|
||||||
inline DEBUG_SYMBOL_PARAMETERS *symbolParameters() { return &(*m_symbolParameters.begin()); }
|
inline DEBUG_SYMBOL_PARAMETERS *symbolParameters() { return &(*m_symbolParameters.begin()); }
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ template <class OutputIterator>
|
|||||||
|
|
||||||
template <class OutputIterator>
|
template <class OutputIterator>
|
||||||
bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg,
|
bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg,
|
||||||
|
QSet<QString> expandedINames,
|
||||||
OutputIterator it,
|
OutputIterator it,
|
||||||
QString *errorMessage)
|
QString *errorMessage)
|
||||||
{
|
{
|
||||||
@@ -164,7 +165,26 @@ bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg,
|
|||||||
QList<WatchData> watchList;
|
QList<WatchData> watchList;
|
||||||
if (!sg->getChildSymbols(sg->prefix(), WatchDataBackInserter(watchList), errorMessage))
|
if (!sg->getChildSymbols(sg->prefix(), WatchDataBackInserter(watchList), errorMessage))
|
||||||
return false;
|
return false;
|
||||||
|
// (Recursively) expand symbols stored as expanded in the history until no more matches
|
||||||
|
// are found.
|
||||||
|
while (!expandedINames.empty()) {
|
||||||
|
unsigned matchCount = 0;
|
||||||
|
for (QSet<QString>::iterator it = expandedINames.begin(); it != expandedINames.end(); ) {
|
||||||
|
// Try to expand. We might hit on a leaf due to name mismatches, ignore errors.
|
||||||
|
unsigned long index;
|
||||||
|
if (sg->lookupPrefix(*it, &index)) {
|
||||||
|
if (!sg->expandSymbol(*it, index, errorMessage))
|
||||||
|
qWarning("%s\n", qPrintable(*errorMessage));
|
||||||
|
matchCount++;
|
||||||
|
it = expandedINames.erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
} // loop set
|
||||||
|
if (matchCount == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Insert data
|
||||||
foreach(const WatchData &wd, watchList)
|
foreach(const WatchData &wd, watchList)
|
||||||
if (!insertSymbolRecursion(wd, sg, it, 0, 0, errorMessage))
|
if (!insertSymbolRecursion(wd, sg, it, 0, 0, errorMessage))
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -181,6 +181,8 @@ public:
|
|||||||
{ return m_displayedINames.contains(iname); }
|
{ return m_displayedINames.contains(iname); }
|
||||||
bool isExpandedIName(const QString &iname) const
|
bool isExpandedIName(const QString &iname) const
|
||||||
{ return m_expandedINames.contains(iname); }
|
{ return m_expandedINames.contains(iname); }
|
||||||
|
QSet<QString> expandedINames() const
|
||||||
|
{ return m_expandedINames; }
|
||||||
|
|
||||||
void insertData(const WatchData &data);
|
void insertData(const WatchData &data);
|
||||||
QList<WatchData> takeCurrentIncompletes();
|
QList<WatchData> takeCurrentIncompletes();
|
||||||
|
|||||||
Reference in New Issue
Block a user