forked from qt-creator/qt-creator
Make break by function work for CDB.
Add function to automagically resolve function symbol names that are missing the module name (module!foo). Kill some trailing whitespace. Add a hack to transform qMain->main for VS.
This commit is contained in:
@@ -28,6 +28,7 @@
|
|||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
#include "cdbbreakpoint.h"
|
#include "cdbbreakpoint.h"
|
||||||
|
#include "cdbmodules.h"
|
||||||
#include "breakhandler.h"
|
#include "breakhandler.h"
|
||||||
#include "cdbdebugengine_p.h"
|
#include "cdbdebugengine_p.h"
|
||||||
|
|
||||||
@@ -279,20 +280,48 @@ bool CDBBreakPoint::getBreakPoints(IDebugControl4* debugControl, QList<CDBBreakP
|
|||||||
return true;
|
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(IDebugControl4* debugControl,
|
||||||
|
IDebugSymbols3 *syms,
|
||||||
BreakHandler *handler,
|
BreakHandler *handler,
|
||||||
QString *errorMessage)
|
QString *errorMessage)
|
||||||
{
|
{
|
||||||
typedef QMap<CDBBreakPoint, int> BreakPointIndexMap;
|
typedef QMap<CDBBreakPoint, int> BreakPointIndexMap;
|
||||||
BreakPointIndexMap breakPointIndexMap;
|
|
||||||
// convert BreakHandler's bps into a map of BreakPoint->BreakHandler->Index
|
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO;
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
|
||||||
|
BreakPointIndexMap breakPointIndexMap;
|
||||||
|
// convert BreakHandler's bps into a map of BreakPoint->BreakHandler->Index
|
||||||
|
// Ignore invalid functions (that could not be found) as they make
|
||||||
|
// the debugger hang.
|
||||||
const int handlerCount = handler->size();
|
const int handlerCount = handler->size();
|
||||||
for (int i=0; i < handlerCount; ++i)
|
const QChar moduleDelimiter = QLatin1Char('!');
|
||||||
breakPointIndexMap.insert(CDBBreakPoint(*handler->at(i)), i);
|
for (int i=0; i < handlerCount; ++i) {
|
||||||
|
BreakpointData *bd = handler->at(i);
|
||||||
|
// Function breakpoints: Are the module names specified?
|
||||||
|
bool breakPointOk = false;
|
||||||
|
if (bd->funcName.isEmpty()) {
|
||||||
|
breakPointOk = true;
|
||||||
|
} else {
|
||||||
|
switch (resolveSymbol(syms, &bd->funcName, errorMessage)) {
|
||||||
|
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
|
||||||
|
if (breakPointOk)
|
||||||
|
breakPointIndexMap.insert(CDBBreakPoint(*bd), i);
|
||||||
|
}
|
||||||
|
errorMessage->clear();
|
||||||
// get number of engine breakpoints
|
// get number of engine breakpoints
|
||||||
ULONG engineCount;
|
ULONG engineCount;
|
||||||
if (!getBreakPointCount(debugControl, &engineCount, errorMessage))
|
if (!getBreakPointCount(debugControl, &engineCount, errorMessage))
|
||||||
|
@@ -72,7 +72,8 @@ struct CDBBreakPoint {
|
|||||||
static bool getBreakPointCount(IDebugControl4* debugControl, ULONG *count, QString *errorMessage = 0);
|
static bool getBreakPointCount(IDebugControl4* debugControl, ULONG *count, QString *errorMessage = 0);
|
||||||
static bool getBreakPoints(IDebugControl4* debugControl, QList<CDBBreakPoint> *bps, QString *errorMessage);
|
static bool getBreakPoints(IDebugControl4* debugControl, QList<CDBBreakPoint> *bps, QString *errorMessage);
|
||||||
// Synchronize (halted) engine with BreakHandler.
|
// Synchronize (halted) engine with BreakHandler.
|
||||||
static bool synchronizeBreakPoints(IDebugControl4* ctl, BreakHandler *bh, QString *errorMessage);
|
static bool synchronizeBreakPoints(IDebugControl4* ctl, IDebugSymbols3 *syms,
|
||||||
|
BreakHandler *bh, QString *errorMessage);
|
||||||
|
|
||||||
// Return a 'canonical' file (using '/' and capitalized drive letter)
|
// Return a 'canonical' file (using '/' and capitalized drive letter)
|
||||||
static QString canonicalSourceFile(const QString &f);
|
static QString canonicalSourceFile(const QString &f);
|
||||||
|
@@ -208,7 +208,7 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEn
|
|||||||
m_currentStackTrace(0),
|
m_currentStackTrace(0),
|
||||||
m_firstActivatedFrame(true),
|
m_firstActivatedFrame(true),
|
||||||
m_mode(AttachCore)
|
m_mode(AttachCore)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CdbDebugEnginePrivate::init(QString *errorMessage)
|
bool CdbDebugEnginePrivate::init(QString *errorMessage)
|
||||||
@@ -252,7 +252,7 @@ bool CdbDebugEnginePrivate::init(QString *errorMessage)
|
|||||||
hr = lib.debugCreate( __uuidof(IDebugRegisters2), reinterpret_cast<void**>(&m_pDebugRegisters));
|
hr = lib.debugCreate( __uuidof(IDebugRegisters2), reinterpret_cast<void**>(&m_pDebugRegisters));
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
*errorMessage = QString::fromLatin1("Creation of IDebugRegisters2 failed: %1").arg(msgDebugEngineComResult(hr));
|
*errorMessage = QString::fromLatin1("Creation of IDebugRegisters2 failed: %1").arg(msgDebugEngineComResult(hr));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << QString::fromLatin1("CDB Initialization succeeded, interrupt time out %1s.").arg(getInterruptTimeOutSecs(m_pDebugControl));
|
qDebug() << QString::fromLatin1("CDB Initialization succeeded, interrupt time out %1s.").arg(getInterruptTimeOutSecs(m_pDebugControl));
|
||||||
@@ -299,7 +299,7 @@ void CdbDebugEnginePrivate::clearForRun()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEnginePrivate::cleanStackTrace()
|
void CdbDebugEnginePrivate::cleanStackTrace()
|
||||||
{
|
{
|
||||||
if (m_currentStackTrace) {
|
if (m_currentStackTrace) {
|
||||||
delete m_currentStackTrace;
|
delete m_currentStackTrace;
|
||||||
m_currentStackTrace = 0;
|
m_currentStackTrace = 0;
|
||||||
@@ -366,7 +366,7 @@ void CdbDebugEnginePrivate::clearDisplay()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CdbDebugEngine::startDebugger()
|
bool CdbDebugEngine::startDebugger()
|
||||||
{
|
{
|
||||||
m_d->clearDisplay();
|
m_d->clearDisplay();
|
||||||
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
|
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
@@ -489,7 +489,7 @@ void CdbDebugEngine::exitDebugger()
|
|||||||
// Terminate or detach if we are running
|
// Terminate or detach if we are running
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
switch (m_d->m_mode) {
|
switch (m_d->m_mode) {
|
||||||
case AttachExternal:
|
case AttachExternal:
|
||||||
wasRunning = m_d->isDebuggeeRunning();
|
wasRunning = m_d->isDebuggeeRunning();
|
||||||
if (wasRunning) { // Process must be stopped in order to detach
|
if (wasRunning) { // Process must be stopped in order to detach
|
||||||
m_d->interruptInterferiorProcess(&errorMessage);
|
m_d->interruptInterferiorProcess(&errorMessage);
|
||||||
@@ -502,7 +502,7 @@ void CdbDebugEngine::exitDebugger()
|
|||||||
qDebug() << Q_FUNC_INFO << "detached" << msgDebugEngineComResult(hr);
|
qDebug() << Q_FUNC_INFO << "detached" << msgDebugEngineComResult(hr);
|
||||||
break;
|
break;
|
||||||
case StartExternal:
|
case StartExternal:
|
||||||
case StartInternal:
|
case StartInternal:
|
||||||
wasRunning = m_d->isDebuggeeRunning();
|
wasRunning = m_d->isDebuggeeRunning();
|
||||||
if (wasRunning) { // Process must be stopped in order to terminate
|
if (wasRunning) { // Process must be stopped in order to terminate
|
||||||
m_d->interruptInterferiorProcess(&errorMessage);
|
m_d->interruptInterferiorProcess(&errorMessage);
|
||||||
@@ -569,7 +569,7 @@ bool CdbDebugEnginePrivate::updateLocals(int frameIndex,
|
|||||||
qDebug() << Q_FUNC_INFO << "\n " << frameIndex << formatWatchList(incompletes);
|
qDebug() << Q_FUNC_INFO << "\n " << frameIndex << formatWatchList(incompletes);
|
||||||
|
|
||||||
m_engine->filterEvaluateWatchers(&incompletes, wh);
|
m_engine->filterEvaluateWatchers(&incompletes, wh);
|
||||||
if (!incompletes.empty()) {
|
if (!incompletes.empty()) {
|
||||||
const QString msg = QLatin1String("Warning: Locals left in incomplete list: ") + formatWatchList(incompletes);
|
const QString msg = QLatin1String("Warning: Locals left in incomplete list: ") + formatWatchList(incompletes);
|
||||||
qWarning("%s\n", qPrintable(msg));
|
qWarning("%s\n", qPrintable(msg));
|
||||||
}
|
}
|
||||||
@@ -613,7 +613,7 @@ void CdbDebugEngine::filterEvaluateWatchers(QList<WatchData> *wd, WatchHandler *
|
|||||||
bool placeHolderSeen = false;
|
bool placeHolderSeen = false;
|
||||||
for (WatchList::iterator it = wd->begin(); it != wd->end(); ) {
|
for (WatchList::iterator it = wd->begin(); it != wd->end(); ) {
|
||||||
if (it->iname.startsWith(watcherPrefix)) {
|
if (it->iname.startsWith(watcherPrefix)) {
|
||||||
const bool isPlaceHolder = it->exp.startsWith(lessThan) && it->exp.endsWith(greaterThan);
|
const bool isPlaceHolder = it->exp.startsWith(lessThan) && it->exp.endsWith(greaterThan);
|
||||||
if (isPlaceHolder) {
|
if (isPlaceHolder) {
|
||||||
if (!placeHolderSeen) { // Max one place holder
|
if (!placeHolderSeen) { // Max one place holder
|
||||||
it->setChildCount(0);
|
it->setChildCount(0);
|
||||||
@@ -624,7 +624,7 @@ void CdbDebugEngine::filterEvaluateWatchers(QList<WatchData> *wd, WatchHandler *
|
|||||||
} else {
|
} else {
|
||||||
evaluateWatcher(&(*it));
|
evaluateWatcher(&(*it));
|
||||||
wh->insertData(*it);
|
wh->insertData(*it);
|
||||||
}
|
}
|
||||||
it = wd->erase(it);
|
it = wd->erase(it);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
@@ -778,7 +778,7 @@ bool CdbDebugEnginePrivate::continueInferiorProcess(QString *errorMessage)
|
|||||||
|
|
||||||
// Continue process with notifications
|
// Continue process with notifications
|
||||||
bool CdbDebugEnginePrivate::continueInferior(QString *errorMessage)
|
bool CdbDebugEnginePrivate::continueInferior(QString *errorMessage)
|
||||||
{
|
{
|
||||||
ULONG executionStatus;
|
ULONG executionStatus;
|
||||||
if (!getExecutionStatus(m_pDebugControl, &executionStatus, errorMessage))
|
if (!getExecutionStatus(m_pDebugControl, &executionStatus, errorMessage))
|
||||||
return false;
|
return false;
|
||||||
@@ -817,7 +817,7 @@ bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage)
|
|||||||
*errorMessage = QString::fromLatin1("DebugBreakProcess failed: %1").arg(Core::Utils::winErrorMessage(GetLastError()));
|
*errorMessage = QString::fromLatin1("DebugBreakProcess failed: %1").arg(Core::Utils::winErrorMessage(GetLastError()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
const HRESULT hr = m_pDebugControl->SetInterrupt(DEBUG_INTERRUPT_ACTIVE|DEBUG_INTERRUPT_EXIT);
|
const HRESULT hr = m_pDebugControl->SetInterrupt(DEBUG_INTERRUPT_ACTIVE|DEBUG_INTERRUPT_EXIT);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
*errorMessage = QString::fromLatin1("Unable to interrupt debuggee after %1s: %2").
|
*errorMessage = QString::fromLatin1("Unable to interrupt debuggee after %1s: %2").
|
||||||
@@ -864,7 +864,7 @@ void CdbDebugEngine::assignValueInDebugger(const QString &expr, const QString &v
|
|||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO << expr << value;
|
qDebug() << Q_FUNC_INFO << expr << value;
|
||||||
const int frameIndex = m_d->m_debuggerManagerAccess->stackHandler()->currentIndex();
|
const int frameIndex = m_d->m_debuggerManagerAccess->stackHandler()->currentIndex();
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
bool success = false;
|
bool success = false;
|
||||||
do {
|
do {
|
||||||
QString newValue;
|
QString newValue;
|
||||||
@@ -872,7 +872,7 @@ void CdbDebugEngine::assignValueInDebugger(const QString &expr, const QString &v
|
|||||||
if (!sg)
|
if (!sg)
|
||||||
break;
|
break;
|
||||||
if (!sg->assignValue(expr, value, &newValue, &errorMessage))
|
if (!sg->assignValue(expr, value, &newValue, &errorMessage))
|
||||||
break;
|
break;
|
||||||
// Update view
|
// Update view
|
||||||
WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler();
|
WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler();
|
||||||
if (WatchData *fwd = watchHandler->findData(expr)) {
|
if (WatchData *fwd = watchHandler->findData(expr)) {
|
||||||
@@ -1032,6 +1032,7 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa
|
|||||||
}
|
}
|
||||||
|
|
||||||
return CDBBreakPoint::synchronizeBreakPoints(m_pDebugControl,
|
return CDBBreakPoint::synchronizeBreakPoints(m_pDebugControl,
|
||||||
|
m_pDebugSymbols,
|
||||||
m_debuggerManagerAccess->breakHandler(),
|
m_debuggerManagerAccess->breakHandler(),
|
||||||
errorMessage);
|
errorMessage);
|
||||||
}
|
}
|
||||||
@@ -1045,7 +1046,7 @@ void CdbDebugEngine::saveSessionData()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEngine::reloadDisassembler()
|
void CdbDebugEngine::reloadDisassembler()
|
||||||
{
|
{
|
||||||
enum { ContextLines = 40 };
|
enum { ContextLines = 40 };
|
||||||
// Do we have a top stack frame?
|
// Do we have a top stack frame?
|
||||||
const ULONG64 offset = m_d->m_currentStackTrace ? m_d->m_currentStackTrace->instructionOffset() : ULONG64(0);
|
const ULONG64 offset = m_d->m_currentStackTrace ? m_d->m_currentStackTrace->instructionOffset() : ULONG64(0);
|
||||||
@@ -1140,7 +1141,7 @@ void CdbDebugEngine::timerEvent(QTimerEvent* te)
|
|||||||
break;
|
break;
|
||||||
case E_UNEXPECTED: // Occurs on ExitProcess.
|
case E_UNEXPECTED: // Occurs on ExitProcess.
|
||||||
killWatchTimer();
|
killWatchTimer();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1260,6 +1261,10 @@ void CdbDebugEnginePrivate::updateStackTrace()
|
|||||||
qWarning("%s: failed to create trace context: %s", Q_FUNC_INFO, qPrintable(errorMessage));
|
qWarning("%s: failed to create trace context: %s", Q_FUNC_INFO, qPrintable(errorMessage));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Disassembling slows things down a bit. Assembler is still available via menu.
|
||||||
|
#if 0
|
||||||
|
m_engine->reloadDisassembler(); // requires stack trace
|
||||||
|
#endif
|
||||||
const QList<StackFrame> stackFrames = m_currentStackTrace->frames();
|
const QList<StackFrame> stackFrames = m_currentStackTrace->frames();
|
||||||
// find the first usable frame and select it
|
// find the first usable frame and select it
|
||||||
int current = -1;
|
int current = -1;
|
||||||
@@ -1275,7 +1280,7 @@ void CdbDebugEnginePrivate::updateStackTrace()
|
|||||||
if (current >= 0) {
|
if (current >= 0) {
|
||||||
m_debuggerManagerAccess->stackHandler()->setCurrentIndex(current);
|
m_debuggerManagerAccess->stackHandler()->setCurrentIndex(current);
|
||||||
m_engine->activateFrame(current);
|
m_engine->activateFrame(current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -77,5 +77,61 @@ bool getModuleList(IDebugSymbols3 *syms, QList<Module> *modules, QString *errorM
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Search symbols matching a pattern
|
||||||
|
bool searchSymbols(IDebugSymbols3 *syms, const QString &pattern,
|
||||||
|
QStringList *matches, QString *errorMessage)
|
||||||
|
{
|
||||||
|
matches->clear();
|
||||||
|
ULONG64 handle;
|
||||||
|
// E_NOINTERFACE means "no match"
|
||||||
|
HRESULT hr = syms->StartSymbolMatchWide(pattern.utf16(), &handle);
|
||||||
|
if (hr == E_NOINTERFACE) {
|
||||||
|
syms->EndSymbolMatch(handle);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage= msgComFailed("StartSymbolMatchWide", hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
WCHAR wszBuf[MAX_PATH];
|
||||||
|
while (true) {
|
||||||
|
hr = syms->GetNextSymbolMatchWide(handle, wszBuf, MAX_PATH - 1, 0, 0);
|
||||||
|
if (hr == E_NOINTERFACE)
|
||||||
|
break;
|
||||||
|
if (hr == S_OK)
|
||||||
|
matches->push_back(QString::fromUtf16(wszBuf));
|
||||||
|
}
|
||||||
|
syms->EndSymbolMatch(handle);
|
||||||
|
if (matches->empty())
|
||||||
|
*errorMessage = QString::fromLatin1("No symbol matches '%1'.").arg(pattern);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add missing the module specifier: "main" -> "project!main"
|
||||||
|
|
||||||
|
ResolveSymbolResult resolveSymbol(IDebugSymbols3 *syms, QString *symbol,
|
||||||
|
QString *errorMessage)
|
||||||
|
{
|
||||||
|
// Is it an incomplete symbol?
|
||||||
|
if (symbol->contains(QLatin1Char('!')))
|
||||||
|
return ResolveSymbolOk;
|
||||||
|
// 'main' is a #define for gdb, but not for VS
|
||||||
|
if (*symbol == QLatin1String("qMain"))
|
||||||
|
*symbol = QLatin1String("main");
|
||||||
|
// resolve
|
||||||
|
QStringList matches;
|
||||||
|
if (!searchSymbols(syms, *symbol, &matches, errorMessage))
|
||||||
|
return ResolveSymbolError;
|
||||||
|
if (matches.empty())
|
||||||
|
return ResolveSymbolNotFound;
|
||||||
|
*symbol = matches.front();
|
||||||
|
if (matches.size() > 1) {
|
||||||
|
*errorMessage = QString::fromLatin1("Ambiguous symbol '%1': %2").
|
||||||
|
arg(*symbol, matches.join(QString(QLatin1Char(' '))));
|
||||||
|
return ResolveSymbolAmbiguous;
|
||||||
|
}
|
||||||
|
return ResolveSymbolOk;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -42,6 +42,17 @@ namespace Internal {
|
|||||||
class Module;
|
class Module;
|
||||||
|
|
||||||
bool getModuleList(IDebugSymbols3 *syms, QList<Module> *modules, QString *errorMessage);
|
bool getModuleList(IDebugSymbols3 *syms, QList<Module> *modules, QString *errorMessage);
|
||||||
|
// Search symbols matching a pattern
|
||||||
|
bool searchSymbols(IDebugSymbols3 *syms, const QString &pattern,
|
||||||
|
QStringList *matches, QString *errorMessage);
|
||||||
|
|
||||||
|
// ResolveSymbol: For symbols that are missing the module specifier,
|
||||||
|
// find the module and expand: "main" -> "project!main".
|
||||||
|
|
||||||
|
enum ResolveSymbolResult { ResolveSymbolOk, ResolveSymbolAmbiguous,
|
||||||
|
ResolveSymbolNotFound, ResolveSymbolError };
|
||||||
|
|
||||||
|
ResolveSymbolResult resolveSymbol(IDebugSymbols3 *syms, QString *symbol, QString *errorMessage);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user