Debugger: Make CDB compile again.

This commit is contained in:
Friedemann Kleint
2010-11-15 15:24:27 +01:00
parent 4d1cd647b4
commit 30d6ae0e3d
9 changed files with 203 additions and 114 deletions

View File

@@ -177,6 +177,13 @@ BreakpointId BreakHandler::findBreakpointByFileAndLine(const QString &fileName,
return BreakpointId(-1); return BreakpointId(-1);
} }
const BreakpointData *BreakHandler::breakpointById(BreakpointId id) const
{
ConstIterator it = m_storage.find(id);
QTC_ASSERT(it != m_storage.end(), return 0);
return &it->data;
}
BreakpointData *BreakHandler::breakpointById(BreakpointId id) BreakpointData *BreakHandler::breakpointById(BreakpointId id)
{ {
Iterator it = m_storage.find(id); Iterator it = m_storage.find(id);

View File

@@ -89,6 +89,8 @@ public:
BreakpointId findBreakpointByFileAndLine(const QString &fileName, BreakpointId findBreakpointByFileAndLine(const QString &fileName,
int lineNumber, bool useMarkerPosition = true); int lineNumber, bool useMarkerPosition = true);
BreakpointId findBreakpointByAddress(quint64 address) const; BreakpointId findBreakpointByAddress(quint64 address) const;
const BreakpointData *breakpointById(BreakpointId id) const;
BreakpointData *breakpointById(BreakpointId id); // FIXME: For breakwindow.
void breakByFunction(const QString &functionName); void breakByFunction(const QString &functionName);
void removeBreakpoint(BreakpointId id); void removeBreakpoint(BreakpointId id);
@@ -145,9 +147,6 @@ public:
private: private:
friend class BreakpointMarker; friend class BreakpointMarker;
friend class BreakWindow; // FIXME: remove.
BreakpointData *breakpointById(BreakpointId id);
// QAbstractItemModel // QAbstractItemModel
int columnCount(const QModelIndex &parent) const; int columnCount(const QModelIndex &parent) const;
int rowCount(const QModelIndex &parent) const; int rowCount(const QModelIndex &parent) const;

View File

@@ -364,11 +364,13 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
addBreakpoint(); addBreakpoint();
else if (act == breakAtThrowAction) { else if (act == breakAtThrowAction) {
BreakpointData data; BreakpointData data;
data.setType(BreakpointByFunction);
data.setFunctionName(BreakpointData::throwFunction); data.setFunctionName(BreakpointData::throwFunction);
handler->appendBreakpoint(data); handler->appendBreakpoint(data);
} else if (act == breakAtCatchAction) { } else if (act == breakAtCatchAction) {
// FIXME: Use the proper breakpoint type instead. // FIXME: Use the proper breakpoint type instead.
BreakpointData data; BreakpointData data;
data.setType(BreakpointByFunction);
data.setFunctionName(BreakpointData::catchFunction); data.setFunctionName(BreakpointData::catchFunction);
handler->appendBreakpoint(data); handler->appendBreakpoint(data);
} }

View File

@@ -28,38 +28,39 @@
**************************************************************************/ **************************************************************************/
#include "cdbbreakpoint.h" #include "cdbbreakpoint.h"
#include "cdbengine_p.h"
#include "corebreakpoint.h"
#include "cdbmodules.h" #include "cdbmodules.h"
#include "breakhandler.h"
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QDir>
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
enum { debugBP = 0 };
// Convert breakpoint structs // Convert breakpoint structs
CdbCore::BreakPoint breakPointFromBreakPointData(const BreakpointData &bpd) static CdbCore::BreakPoint breakPointFromBreakPointData(const BreakpointData &bpd, const QString &functionName)
{ {
CdbCore::BreakPoint rc; CdbCore::BreakPoint rc;
rc.type = bpd.type == Watchpoint ? rc.type = bpd.type() == Watchpoint ?
CdbCore::BreakPoint::Data : CdbCore::BreakPoint::Data :
CdbCore::BreakPoint::Code ; CdbCore::BreakPoint::Code ;
rc.address = bpd.address; rc.address = bpd.address();
if (!bpd.threadSpec.isEmpty()) { if (!bpd.threadSpec().isEmpty()) {
bool ok; bool ok;
rc.threadId = bpd.threadSpec.toInt(&ok); rc.threadId = bpd.threadSpec().toInt(&ok);
if (!ok) if (!ok)
qWarning("Cdb: Cannot convert breakpoint thread specification '%s'", bpd.threadSpec.constData()); qWarning("Cdb: Cannot convert breakpoint thread specification '%s'", bpd.threadSpec().constData());
} }
rc.fileName = QDir::toNativeSeparators(bpd.fileName); rc.fileName = QDir::toNativeSeparators(bpd.fileName());
rc.condition = bpd.condition; rc.condition = bpd.condition();
// Resolved function goes to bpd.bpFuncName. rc.funcName = functionName.isEmpty() ? bpd.functionName() : functionName;
rc.funcName = bpd.bpFuncName.isEmpty() ? bpd.funcName : bpd.bpFuncName; rc.ignoreCount = bpd.ignoreCount();
rc.ignoreCount = bpd.ignoreCount; rc.lineNumber = bpd.lineNumber();
rc.lineNumber = bpd.lineNumber;
rc.oneShot = false; rc.oneShot = false;
rc.enabled = bpd.enabled; rc.enabled = bpd.isEnabled();
return rc; return rc;
} }
@@ -68,56 +69,63 @@ static inline QString msgCannotSetBreakAtFunction(const QString &func, const QSt
return QString::fromLatin1("Cannot set a breakpoint at '%1': %2").arg(func, why); return QString::fromLatin1("Cannot set a breakpoint at '%1': %2").arg(func, why);
} }
static bool addBreakpoint(CIDebugControl* debugControl, void setBreakpointResponse(const BreakpointData *nbd, int number, BreakpointResponse *response)
CIDebugSymbols *syms,
BreakpointData *nbd,
QString *warning)
{ {
warning->clear(); response->bpAddress = nbd->address();
response->bpNumber = number;
response->bpFuncName = nbd->functionName();
response->bpType = nbd->type();
response->bpCondition = nbd->condition();
response->bpIgnoreCount = nbd->ignoreCount();
response->bpFullName = response->bpFileName = nbd->fileName();
response->bpLineNumber = nbd->lineNumber();
response->bpThreadSpec = nbd->threadSpec();
response->bpEnabled = nbd->isEnabled();
}
bool addCdbBreakpoint(CIDebugControl* debugControl,
CIDebugSymbols *syms,
const BreakpointData *nbd,
BreakpointResponse *response,
QString *errorMessage)
{
errorMessage->clear();
// Function breakpoints: Are the module names specified? // Function breakpoints: Are the module names specified?
if (!nbd->funcName.isEmpty()) { QString resolvedFunction;
nbd->bpFuncName = nbd->funcName; if (nbd->type() == BreakpointByFunction) {
switch (resolveSymbol(syms, &nbd->bpFuncName, warning)) { resolvedFunction = nbd->functionName();
switch (resolveSymbol(syms, &resolvedFunction, errorMessage)) {
case ResolveSymbolOk: case ResolveSymbolOk:
break; break;
case ResolveSymbolAmbiguous: case ResolveSymbolAmbiguous:
*warning = msgCannotSetBreakAtFunction(nbd->funcName, *warning);
break; break;
case ResolveSymbolNotFound: case ResolveSymbolNotFound:
case ResolveSymbolError: case ResolveSymbolError:
*warning = msgCannotSetBreakAtFunction(nbd->funcName, *warning); *errorMessage = msgCannotSetBreakAtFunction(nbd->functionName(), *errorMessage);
return false; return false;
}; }
if (debugBreakpoints)
qDebug() << nbd->functionName() << " resolved to " << resolvedFunction;
} // function breakpoint } // function breakpoint
// Now add... // Now add...
quint64 address; quint64 address;
unsigned long id; unsigned long id;
const CdbCore::BreakPoint ncdbbp = breakPointFromBreakPointData(*nbd); const CdbCore::BreakPoint ncdbbp = breakPointFromBreakPointData(*nbd, resolvedFunction);
if (!ncdbbp.add(debugControl, warning, &id, &address)) if (!ncdbbp.add(debugControl, errorMessage, &id, &address))
return false; return false;
if (debugBP) if (debugBreakpoints)
qDebug("Added %lu at 0x%lx %s", id, address, qPrintable(ncdbbp.toString())); qDebug("Added %lu at 0x%lx %s", id, address, qPrintable(ncdbbp.toString()));
nbd->pending = false; setBreakpointResponse(nbd, id, response);
nbd->bpNumber = QByteArray::number(uint(id)); response->bpAddress = address;
nbd->bpAddress = address; response->bpFuncName = resolvedFunction;
// Take over rest as is
nbd->bpCondition = nbd->condition;
nbd->bpIgnoreCount = nbd->ignoreCount;
nbd->bpThreadSpec = nbd->threadSpec;
nbd->bpFileName = nbd->fileName;
nbd->bpLineNumber = nbd->lineNumber;
return true; return true;
} }
// Synchronize (halted) engine breakpoints with those of the BreakHandler. // Delete all breakpoints
bool synchronizeBreakPoints(CIDebugControl* debugControl, bool deleteCdbBreakpoints(CIDebugControl* debugControl,
CIDebugSymbols *syms, QString *errorMessage)
BreakHandler *handler,
QString *errorMessage,
QStringList *warnings)
{ {
errorMessage->clear(); errorMessage->clear();
warnings->clear();
// Do an initial check whether we are in a state that allows // Do an initial check whether we are in a state that allows
// for modifying breakPoints // for modifying breakPoints
ULONG engineCount; ULONG engineCount;
@@ -125,50 +133,28 @@ bool synchronizeBreakPoints(CIDebugControl* debugControl,
*errorMessage = QString::fromLatin1("Cannot modify breakpoints: %1").arg(*errorMessage); *errorMessage = QString::fromLatin1("Cannot modify breakpoints: %1").arg(*errorMessage);
return false; return false;
} }
// Delete all breakpoints and re-insert all enabled breakpoints. This is the simplest if (debugBreakpoints)
// way to apply changes since CDB ids shift when removing breakpoints and there is no qDebug("Deleting breakpoints 0..%lu", engineCount);
// easy way to re-match them.
if (engineCount) { if (engineCount) {
for (int b = engineCount - 1; b >= 0 ; b--) for (int b = engineCount - 1; b >= 0 ; b--)
if (!CdbCore::BreakPoint::removeBreakPointById(debugControl, b, errorMessage)) if (!CdbCore::BreakPoint::removeBreakPointById(debugControl, b, errorMessage))
return false; return false;
} }
qDeleteAll(handler->takeRemovedBreakpoints()); return true;
// Mark disabled ones
foreach(BreakpointData *dbd, handler->takeDisabledBreakpoints())
dbd->bpEnabled = false;
// Insert all enabled ones as new
QString warning;
bool updateMarkers = false;
const int size = handler->size();
for (int i = 0; i < size; i++) {
BreakpointData *breakpoint = handler->at(i);
if (breakpoint->enabled)
if (addBreakpoint(debugControl, syms, breakpoint, &warning)) {
updateMarkers = true;
} else {
warnings->push_back(warning);
} }
}
// Mark enabled ones
foreach(BreakpointData *ebd, handler->takeEnabledBreakpoints())
ebd->bpEnabled = true;
if (updateMarkers) void debugCdbBreakpoints(CIDebugControl* debugControl)
handler->updateMarkers(); {
QString errorMessage;
if (debugBP > 1) {
QList<CdbCore::BreakPoint> bps; QList<CdbCore::BreakPoint> bps;
CdbCore::BreakPoint::getBreakPoints(debugControl, &bps, errorMessage); CdbCore::BreakPoint::getBreakPoints(debugControl, &bps, &errorMessage);
QDebug nsp = qDebug().nospace(); QDebug nsp = qDebug().nospace();
const int count = bps.size(); const int count = bps.size();
nsp <<"### Breakpoints in engine: " << count << '\n'; nsp <<"### Breakpoints in engine: " << count << '\n';
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
nsp << " #" << i << ' ' << bps.at(i) << '\n'; nsp << " #" << i << ' ' << bps.at(i) << '\n';
} }
return true;
}
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -31,12 +31,8 @@
#define CDBBREAKPOINTS_H #define CDBBREAKPOINTS_H
#include "cdbcom.h" #include "cdbcom.h"
#include "corebreakpoint.h"
#include "breakhandler.h"
#include <QtCore/QString> #include <QtCore/QString>
#include <QtCore/QList>
#include <QtCore/QDir>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QDebug; class QDebug;
@@ -44,14 +40,22 @@ QT_END_NAMESPACE
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class BreakpointData;
class BreakpointResponse;
// Convert breakpoint structs // Convert breakpoint structs
CdbCore::BreakPoint breakPointFromBreakPointData(const Debugger::Internal::BreakpointData &bpd); bool addCdbBreakpoint(CIDebugControl* debugControl,
CIDebugSymbols *syms,
const BreakpointData *nbd,
BreakpointResponse *response,
QString *errorMessage);
// Synchronize (halted) engine with BreakHandler. bool deleteCdbBreakpoints(CIDebugControl* debugControl, QString *errorMessage);
bool synchronizeBreakPoints(CIDebugControl* ctl, CIDebugSymbols *syms,
BreakHandler *bh, void debugCdbBreakpoints(CIDebugControl* debugControl);
QString *errorMessage, QStringList *warnings);
// Set response from data.
void setBreakpointResponse(const BreakpointData *nbd, int number, BreakpointResponse *response);
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -52,6 +52,7 @@
#include "registerhandler.h" #include "registerhandler.h"
#include "moduleshandler.h" #include "moduleshandler.h"
#include "watchutils.h" #include "watchutils.h"
#include "corebreakpoint.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -1223,21 +1224,61 @@ void CdbEngine::attemptBreakpointSynchronization()
if (!m_d->m_hDebuggeeProcess) // Sometimes called from the breakpoint Window if (!m_d->m_hDebuggeeProcess) // Sometimes called from the breakpoint Window
return; return;
QString errorMessage; QString errorMessage;
if (!m_d->attemptBreakpointSynchronization(&errorMessage)) if (!attemptBreakpointSynchronizationI(&errorMessage))
warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage)); warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
} }
bool CdbEnginePrivate::attemptBreakpointSynchronization(QString *errorMessage) // Figure out what kind of changes are required to synchronize
enum BreakPointSyncType {
BreakpointsUnchanged, BreakpointsAdded, BreakpointsRemovedChanged
};
static inline BreakPointSyncType breakPointSyncType(const BreakHandler *handler, const BreakpointIds ids)
{ {
if (!m_hDebuggeeProcess) { bool added = false;
foreach (BreakpointId id, ids) {
switch (handler->state(id)) {
case BreakpointInsertRequested:
added = true;
break;
case BreakpointChangeRequested:
case BreakpointRemoveRequested:
return BreakpointsRemovedChanged;
default:
break;
}
}
return added ? BreakpointsAdded : BreakpointsUnchanged;
}
bool CdbEngine::attemptBreakpointSynchronizationI(QString *errorMessage)
{
if (!m_d->m_hDebuggeeProcess) {
*errorMessage = QLatin1String("attemptBreakpointSynchronization() called while debugger is not running"); *errorMessage = QLatin1String("attemptBreakpointSynchronization() called while debugger is not running");
return false; return false;
} }
// Might be called nested while attempting to stop. // Might be called nested while attempting to stop.
if (m_breakEventMode == BreakEventSyncBreakPoints) { if (m_d->m_breakEventMode == CdbEnginePrivate::BreakEventSyncBreakPoints) {
*errorMessage = QLatin1String("Nested invocation of attemptBreakpointSynchronization."); *errorMessage = QLatin1String("Nested invocation of attemptBreakpointSynchronization.");
return false; return false;
} }
// Check if there is anything to be done at all.
BreakHandler *handler = breakHandler();
// Take ownership of the breakpoint. Requests insertion. TODO: Cpp only?
foreach (BreakpointId id, handler->unclaimedBreakpointIds())
if (acceptsBreakpoint(id))
handler->setEngine(id, this);
// Find out if there is a need to synchronize again
const BreakpointIds ids = handler->engineBreakpointIds(this);
const BreakPointSyncType syncType = breakPointSyncType(handler, ids);
if (debugBreakpoints)
qDebug("attemptBreakpointSynchronizationI %d breakpoints, syncType=%d", ids.size(), syncType);
if (syncType == BreakpointsUnchanged)
return true;
// This is called from // This is called from
// 1) CreateProcessEvent with the halted engine // 1) CreateProcessEvent with the halted engine
// 2) from the break handler, potentially while the debuggee is running // 2) from the break handler, potentially while the debuggee is running
@@ -1245,30 +1286,78 @@ bool CdbEnginePrivate::attemptBreakpointSynchronization(QString *errorMessage)
// no reliable indicator), we temporarily halt and have ourselves // no reliable indicator), we temporarily halt and have ourselves
// called again from the debug event handler. // called again from the debug event handler.
CIDebugControl *control = m_d->interfaces().debugControl;
CIDebugSymbols *symbols = m_d->interfaces().debugSymbols;
ULONG dummy; ULONG dummy;
const bool wasRunning = !CdbCore::BreakPoint::getBreakPointCount(interfaces().debugControl, &dummy); const bool wasRunning = !CdbCore::BreakPoint::getBreakPointCount(control, &dummy);
if (debugCDB) if (debugCDB)
qDebug() << Q_FUNC_INFO << "\n Running=" << wasRunning; qDebug() << Q_FUNC_INFO << "\n Running=" << wasRunning;
if (wasRunning) { if (wasRunning) {
const HandleBreakEventMode oldMode = m_breakEventMode; const CdbEnginePrivate::HandleBreakEventMode oldMode = m_d->m_breakEventMode;
m_breakEventMode = BreakEventSyncBreakPoints; m_d->m_breakEventMode = CdbEnginePrivate::BreakEventSyncBreakPoints;
if (!interruptInterferiorProcess(errorMessage)) { if (!m_d->interruptInterferiorProcess(errorMessage)) {
m_breakEventMode = oldMode; m_d->m_breakEventMode = oldMode;
return false; return false;
} }
return true; return true;
} }
QStringList warnings; // If there are changes/removals, delete all breakpoints and re-insert
const bool ok = synchronizeBreakPoints(interfaces().debugControl, // all enabled breakpoints. This is the simplest
interfaces().debugSymbols, // way to apply changes since CDB ids shift when removing breakpoints and there is no
m_engine->breakHandler(), // easy way to re-match them.
errorMessage, &warnings); if (syncType == BreakpointsRemovedChanged && !deleteCdbBreakpoints(control, errorMessage))
if (const int warningsCount = warnings.size()) return false;
for (int w = 0; w < warningsCount; w++)
m_engine->warning(warnings.at(w)); foreach (BreakpointId id, ids) {
return ok; BreakpointResponse response;
const BreakpointData *data = handler->breakpointById(id);
errorMessage->clear();
switch (handler->state(id)) {
case BreakpointInsertRequested:
handler->setState(id, BreakpointInsertProceeding);
if (addCdbBreakpoint(control, symbols, data, &response, errorMessage)) {
notifyBreakpointInsertOk(id);
handler->setResponse(id, response);
} else {
notifyBreakpointInsertOk(id);
showMessage(*errorMessage, LogError);
}
break;
case BreakpointChangeRequested:
// Skip disabled breakpoints, else add
handler->setState(id, BreakpointChangeProceeding);
if (data->isEnabled()) {
if (addCdbBreakpoint(control, symbols, data, &response, errorMessage)) {
notifyBreakpointChangeOk(id);
handler->setResponse(id, response);
} else {
notifyBreakpointChangeFailed(id);
showMessage(*errorMessage, LogError);
}
} else {
notifyBreakpointChangeOk(id);
}
break;
case BreakpointRemoveRequested:
notifyBreakpointRemoveOk(id);
break;
case BreakpointInserted:
case BreakpointPending:
// Existing breakpoints were deleted due to change/removal, re-set
if (syncType == BreakpointsRemovedChanged
&& !addCdbBreakpoint(control, symbols, handler->breakpointById(id), &response, errorMessage))
showMessage(*errorMessage, LogError);
break;
default:
break;
}
}
if (debugBreakpoints)
debugCdbBreakpoints(control);
return true;
} }
void CdbEngine::fetchDisassembler(DisassemblerViewAgent *agent) void CdbEngine::fetchDisassembler(DisassemblerViewAgent *agent)
@@ -1493,7 +1582,7 @@ void CdbEnginePrivate::handleDebugEvent()
// Temp stop to sync breakpoints (without invoking states). // Temp stop to sync breakpoints (without invoking states).
// Triggered when the users changes breakpoints while running. // Triggered when the users changes breakpoints while running.
QString errorMessage; QString errorMessage;
attemptBreakpointSynchronization(&errorMessage); m_engine->attemptBreakpointSynchronizationI(&errorMessage);
startWatchTimer(); startWatchTimer();
if (!continueInferiorProcess(&errorMessage)) { if (!continueInferiorProcess(&errorMessage)) {
STATE_DEBUG(Q_FUNC_INFO, __LINE__, "BreakEventSyncBreakPoints / notifyInferiorSpontaneousStop"); STATE_DEBUG(Q_FUNC_INFO, __LINE__, "BreakEventSyncBreakPoints / notifyInferiorSpontaneousStop");

View File

@@ -115,6 +115,7 @@ private:
void evaluateWatcher(WatchData *wd); void evaluateWatcher(WatchData *wd);
QString editorToolTip(const QString &exp, const QString &function); QString editorToolTip(const QString &exp, const QString &function);
bool step(unsigned long executionStatus); bool step(unsigned long executionStatus);
bool attemptBreakpointSynchronizationI(QString *errorMessage);
CdbEnginePrivate *m_d; CdbEnginePrivate *m_d;

View File

@@ -95,7 +95,6 @@ public:
bool continueInferior(QString *errorMessage); bool continueInferior(QString *errorMessage);
bool executeContinueCommand(const QString &command); bool executeContinueCommand(const QString &command);
bool attemptBreakpointSynchronization(QString *errorMessage);
void notifyException(long code, bool fatal, const QString &message); void notifyException(long code, bool fatal, const QString &message);
@@ -144,6 +143,7 @@ enum { debugCDB = 0 };
enum { debugCDBExecution = 0 }; enum { debugCDBExecution = 0 };
enum { debugCDBWatchHandling = 0 }; enum { debugCDBWatchHandling = 0 };
enum { debugToolTips = 0 }; enum { debugToolTips = 0 };
enum { debugBreakpoints = 0 };
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -34,6 +34,7 @@
#include "watchutils.h" #include "watchutils.h"
#include "debuggeractions.h" #include "debuggeractions.h"
#include "coreengine.h" #include "coreengine.h"
#include "debuggercore.h"
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QTextStream> #include <QtCore/QTextStream>