forked from qt-creator/qt-creator
Attach properly, first glimpse of symbols.
This commit is contained in:
committed by
unknown
parent
d9cbcdc94b
commit
c83782043a
@@ -44,6 +44,7 @@
|
|||||||
#include <QtCore/QFileInfo>
|
#include <QtCore/QFileInfo>
|
||||||
#include <QtCore/QDir>
|
#include <QtCore/QDir>
|
||||||
#include <QtCore/QLibrary>
|
#include <QtCore/QLibrary>
|
||||||
|
#include <QtCore/QCoreApplication>
|
||||||
|
|
||||||
#define DBGHELP_TRANSLATE_TCHAR
|
#define DBGHELP_TRANSLATE_TCHAR
|
||||||
#include <inc/Dbghelp.h>
|
#include <inc/Dbghelp.h>
|
||||||
@@ -78,6 +79,16 @@ static QString msgDebugEngineComResult(HRESULT hr)
|
|||||||
return Core::Utils::winErrorMessage(HRESULT_CODE(hr));
|
return Core::Utils::winErrorMessage(HRESULT_CODE(hr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QString msgStackIndexOutOfRange(int idx, int size)
|
||||||
|
{
|
||||||
|
return QString::fromLatin1("Frame index %1 out of range (%2).").arg(idx).arg(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString msgComFailed(const char *func, HRESULT hr)
|
||||||
|
{
|
||||||
|
return QString::fromLatin1("%1 failed: %2").arg(QLatin1String(func), msgDebugEngineComResult(hr));
|
||||||
|
}
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -109,52 +120,84 @@ bool DebuggerEngineLibrary::init(QString *errorMessage)
|
|||||||
|
|
||||||
// --- CdbDebugEnginePrivate
|
// --- CdbDebugEnginePrivate
|
||||||
|
|
||||||
CdbDebugEnginePrivate::CdbDebugEnginePrivate(const DebuggerEngineLibrary &lib, DebuggerManager *parent, CdbDebugEngine* engine) :
|
CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEngine* engine) :
|
||||||
m_hDebuggeeProcess(0),
|
m_hDebuggeeProcess(0),
|
||||||
m_hDebuggeeThread(0),
|
m_hDebuggeeThread(0),
|
||||||
m_bIgnoreNextDebugEvent(false),
|
m_bIgnoreNextDebugEvent(false),
|
||||||
m_watchTimer(-1),
|
m_watchTimer(-1),
|
||||||
m_debugEventCallBack(engine),
|
m_debugEventCallBack(engine),
|
||||||
m_debugOutputCallBack(engine),
|
m_debugOutputCallBack(engine),
|
||||||
|
m_pDebugClient(0),
|
||||||
|
m_pDebugControl(0),
|
||||||
|
m_pDebugSystemObjects(0),
|
||||||
|
m_pDebugSymbols(0),
|
||||||
|
m_pDebugRegisters(0),
|
||||||
m_engine(engine),
|
m_engine(engine),
|
||||||
m_debuggerManager(parent),
|
m_debuggerManager(parent),
|
||||||
m_debuggerManagerAccess(parent->engineInterface())
|
m_debuggerManagerAccess(parent->engineInterface()),
|
||||||
|
m_mode(AttachCore)
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CdbDebugEnginePrivate::init(QString *errorMessage)
|
||||||
|
{
|
||||||
|
// Load the DLL
|
||||||
|
DebuggerEngineLibrary lib;
|
||||||
|
if (!lib.init(errorMessage))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Initialize the COM interfaces
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
hr = lib.debugCreate( __uuidof(IDebugClient5), reinterpret_cast<void**>(&m_pDebugClient));
|
hr = lib.debugCreate( __uuidof(IDebugClient5), reinterpret_cast<void**>(&m_pDebugClient));
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
m_pDebugClient = 0;
|
*errorMessage = QString::fromLatin1("Creation of IDebugClient5 failed: %1").arg(msgDebugEngineComResult(hr));
|
||||||
} else {
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_pDebugClient->SetOutputCallbacks(&m_debugOutputCallBack);
|
m_pDebugClient->SetOutputCallbacks(&m_debugOutputCallBack);
|
||||||
m_pDebugClient->SetEventCallbacks(&m_debugEventCallBack);
|
m_pDebugClient->SetEventCallbacks(&m_debugEventCallBack);
|
||||||
}
|
|
||||||
|
|
||||||
hr = lib.debugCreate( __uuidof(IDebugControl4), reinterpret_cast<void**>(&m_pDebugControl));
|
hr = lib.debugCreate( __uuidof(IDebugControl4), reinterpret_cast<void**>(&m_pDebugControl));
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
m_pDebugControl = 0;
|
*errorMessage = QString::fromLatin1("Creation of IDebugControl4 failed: %1").arg(msgDebugEngineComResult(hr));
|
||||||
} else {
|
return false;
|
||||||
m_pDebugControl->SetCodeLevel(DEBUG_LEVEL_SOURCE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_pDebugControl->SetCodeLevel(DEBUG_LEVEL_SOURCE);
|
||||||
|
|
||||||
hr = lib.debugCreate( __uuidof(IDebugSystemObjects4), reinterpret_cast<void**>(&m_pDebugSystemObjects));
|
hr = lib.debugCreate( __uuidof(IDebugSystemObjects4), reinterpret_cast<void**>(&m_pDebugSystemObjects));
|
||||||
if (FAILED(hr)) m_pDebugSystemObjects = 0;
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage = QString::fromLatin1("Creation of IDebugSystemObjects4 failed: %1").arg(msgDebugEngineComResult(hr));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
hr = lib.debugCreate( __uuidof(IDebugSymbols3), reinterpret_cast<void**>(&m_pDebugSymbols));
|
hr = lib.debugCreate( __uuidof(IDebugSymbols3), reinterpret_cast<void**>(&m_pDebugSymbols));
|
||||||
if (FAILED(hr)) m_pDebugSymbols = 0;
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage = QString::fromLatin1("Creation of IDebugSymbols3 failed: %1").arg(msgDebugEngineComResult(hr));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
hr = lib.debugCreate( __uuidof(IDebugRegisters2), reinterpret_cast<void**>(&m_pDebugRegisters));
|
hr = lib.debugCreate( __uuidof(IDebugRegisters2), reinterpret_cast<void**>(&m_pDebugRegisters));
|
||||||
if (FAILED(hr)) m_pDebugRegisters = 0;
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage = QString::fromLatin1("Creation of IDebugRegisters2 failed: %1").arg(msgDebugEngineComResult(hr));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
IDebuggerEngine *CdbDebugEngine::create(DebuggerManager *parent)
|
IDebuggerEngine *CdbDebugEngine::create(DebuggerManager *parent)
|
||||||
{
|
{
|
||||||
DebuggerEngineLibrary lib;
|
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
if (!lib.init(&errorMessage)) {
|
IDebuggerEngine *rc = 0;
|
||||||
|
CdbDebugEngine *e = new CdbDebugEngine(parent);
|
||||||
|
if (e->m_d->init(&errorMessage)) {
|
||||||
|
rc = e;
|
||||||
|
} else {
|
||||||
|
delete e;
|
||||||
qWarning("%s", qPrintable(errorMessage));
|
qWarning("%s", qPrintable(errorMessage));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return new CdbDebugEngine(lib, parent);
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
|
CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
|
||||||
@@ -171,9 +214,9 @@ CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
|
|||||||
m_pDebugRegisters->Release();
|
m_pDebugRegisters->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
CdbDebugEngine::CdbDebugEngine(const DebuggerEngineLibrary &lib, DebuggerManager *parent) :
|
CdbDebugEngine::CdbDebugEngine(DebuggerManager *parent) :
|
||||||
IDebuggerEngine(parent),
|
IDebuggerEngine(parent),
|
||||||
m_d(new CdbDebugEnginePrivate(lib, parent, this))
|
m_d(new CdbDebugEnginePrivate(parent, this))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,12 +227,18 @@ CdbDebugEngine::~CdbDebugEngine()
|
|||||||
|
|
||||||
void CdbDebugEngine::startWatchTimer()
|
void CdbDebugEngine::startWatchTimer()
|
||||||
{
|
{
|
||||||
|
if (debugCDB)
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
|
||||||
if (m_d->m_watchTimer == -1)
|
if (m_d->m_watchTimer == -1)
|
||||||
m_d->m_watchTimer = startTimer(0);
|
m_d->m_watchTimer = startTimer(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEngine::killWatchTimer()
|
void CdbDebugEngine::killWatchTimer()
|
||||||
{
|
{
|
||||||
|
if (debugCDB)
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
|
||||||
if (m_d->m_watchTimer != -1) {
|
if (m_d->m_watchTimer != -1) {
|
||||||
killTimer(m_d->m_watchTimer);
|
killTimer(m_d->m_watchTimer);
|
||||||
m_d->m_watchTimer = -1;
|
m_d->m_watchTimer = -1;
|
||||||
@@ -211,7 +260,8 @@ bool CdbDebugEngine::startDebugger()
|
|||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
bool rc = false;
|
bool rc = false;
|
||||||
m_d->m_bIgnoreNextDebugEvent = false;
|
m_d->m_bIgnoreNextDebugEvent = false;
|
||||||
switch (m_d->m_debuggerManager->startMode()) {
|
m_d->m_mode = m_d->m_debuggerManager->startMode();
|
||||||
|
switch (m_d->m_mode) {
|
||||||
case AttachExternal:
|
case AttachExternal:
|
||||||
rc = startAttachDebugger(m_d->m_debuggerManager->m_attachedPID, &errorMessage);
|
rc = startAttachDebugger(m_d->m_debuggerManager->m_attachedPID, &errorMessage);
|
||||||
break;
|
break;
|
||||||
@@ -234,8 +284,10 @@ bool CdbDebugEngine::startDebugger()
|
|||||||
|
|
||||||
bool CdbDebugEngine::startAttachDebugger(unsigned long pid, QString *errorMessage)
|
bool CdbDebugEngine::startAttachDebugger(unsigned long pid, QString *errorMessage)
|
||||||
{
|
{
|
||||||
|
// Need to aatrach invasively, otherwise, no notification signals
|
||||||
|
// for for CreateProcess/ExitProcess occur.
|
||||||
const HRESULT hr = m_d->m_pDebugClient->AttachProcess(NULL, pid,
|
const HRESULT hr = m_d->m_pDebugClient->AttachProcess(NULL, pid,
|
||||||
DEBUG_ATTACH_NONINVASIVE |DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND);
|
DEBUG_ATTACH_INVASIVE_RESUME_PROCESS);
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << "Attaching to " << pid << " returns " << hr;
|
qDebug() << "Attaching to " << pid << " returns " << hr;
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
@@ -280,7 +332,7 @@ bool CdbDebugEngine::startDebuggerWithExecutable(QString *errorMessage)
|
|||||||
m_d->m_debuggerManager->m_workingDir.utf16(),
|
m_d->m_debuggerManager->m_workingDir.utf16(),
|
||||||
env);
|
env);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
*errorMessage = tr("CreateProcess2Wide failed for '%1': %2").arg(cmd).arg(msgDebugEngineComResult(hr));
|
*errorMessage = tr("CreateProcess2Wide failed for '%1': %2").arg(cmd, msgDebugEngineComResult(hr));
|
||||||
m_d->m_debuggerManagerAccess->notifyInferiorExited();
|
m_d->m_debuggerManagerAccess->notifyInferiorExited();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -293,13 +345,134 @@ void CdbDebugEngine::exitDebugger()
|
|||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO;
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
|
||||||
m_d->m_pDebugClient->TerminateCurrentProcess();
|
if (m_d->m_hDebuggeeProcess) {
|
||||||
|
// Terminate or detach if we are running
|
||||||
|
HRESULT hr;
|
||||||
|
switch (m_d->m_mode) {
|
||||||
|
case AttachExternal:
|
||||||
|
if (m_d->isDebuggeeRunning()) { // Process must be stopped in order to detach
|
||||||
|
DebugBreakProcess(m_d->m_hDebuggeeProcess);
|
||||||
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||||
|
}
|
||||||
|
hr = m_d->m_pDebugClient->DetachCurrentProcess();
|
||||||
|
if (debugCDB)
|
||||||
|
qDebug() << Q_FUNC_INFO << "detached" << msgDebugEngineComResult(hr);
|
||||||
|
break;
|
||||||
|
case StartExternal:
|
||||||
|
case StartInternal:
|
||||||
|
hr = m_d->m_pDebugClient->TerminateCurrentProcess();
|
||||||
|
if (debugCDB)
|
||||||
|
qDebug() << Q_FUNC_INFO << "terminated" << msgDebugEngineComResult(hr);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case AttachCore:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_d->setDebuggeeHandles(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
killWatchTimer();
|
killWatchTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CdbDebugEnginePrivate::updateLocals(int frameIndex,
|
||||||
|
WatchHandler *wh,
|
||||||
|
QString *errorMessage)
|
||||||
|
{
|
||||||
|
if (debugCDB)
|
||||||
|
qDebug() << Q_FUNC_INFO << frameIndex;
|
||||||
|
|
||||||
|
CdbStackTrace cdbStackTrace;
|
||||||
|
if (!getCdbStrackTrace(&cdbStackTrace, errorMessage))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((unsigned)frameIndex >= cdbStackTrace.frameCount) {
|
||||||
|
*errorMessage = msgStackIndexOutOfRange(frameIndex, cdbStackTrace.frameCount);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDebugSymbolGroup2 *pDbgSymGroup = 0;
|
||||||
|
DEBUG_SYMBOL_PARAMETERS *symParams = 0;
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
do {
|
||||||
|
HRESULT hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, NULL, &pDbgSymGroup);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage = msgComFailed("GetScopeSymbolGroup", hr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = m_pDebugSymbols->SetScope(0, cdbStackTrace.frames + frameIndex, NULL, 0);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage = msgComFailed("SetScope", hr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// refresh with current frame
|
||||||
|
hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, pDbgSymGroup, &pDbgSymGroup);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage = msgComFailed("GetScopeSymbolGroup", hr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG symbolCount;
|
||||||
|
hr = pDbgSymGroup->GetNumberSymbols(&symbolCount);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage = msgComFailed("GetNumberSymbols", hr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
symParams = new DEBUG_SYMBOL_PARAMETERS[symbolCount];
|
||||||
|
hr = pDbgSymGroup->GetSymbolParameters(0, symbolCount, symParams);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage = msgComFailed("GetSymbolParameters", hr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
wh->cleanup();
|
||||||
|
// retrieve symbol names and value strings
|
||||||
|
ULONG nameLength;
|
||||||
|
WCHAR nameBuffer[MAX_PATH + 1];
|
||||||
|
for (ULONG s = 0 ; s < symbolCount ; s++ ) {
|
||||||
|
// Name
|
||||||
|
pDbgSymGroup->GetSymbolNameWide(s, nameBuffer, MAX_PATH, &nameLength);
|
||||||
|
nameBuffer[nameLength] = 0;
|
||||||
|
const QString name = QString::fromUtf16(nameBuffer);
|
||||||
|
// Type name
|
||||||
|
pDbgSymGroup->GetSymbolTypeNameWide(s, nameBuffer, MAX_PATH, &nameLength);
|
||||||
|
nameBuffer[nameLength] = 0;
|
||||||
|
const QString type = QString::fromUtf16(nameBuffer);
|
||||||
|
// Value
|
||||||
|
QString value;
|
||||||
|
hr = pDbgSymGroup->GetSymbolValueTextWide(s, nameBuffer, MAX_PATH, &nameLength);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
nameBuffer[nameLength] = 0;
|
||||||
|
value = QString::fromUtf16(nameBuffer);
|
||||||
|
} else {
|
||||||
|
value = QLatin1String("<unknown>");
|
||||||
|
}
|
||||||
|
WatchData wd;
|
||||||
|
wd.iname = QLatin1String("local");
|
||||||
|
wd.name = name;
|
||||||
|
wd.value = value;
|
||||||
|
wd.type = type;
|
||||||
|
wd.setAllUnneeded();
|
||||||
|
wh->insertData(wd);
|
||||||
|
if (debugCDB)
|
||||||
|
qDebug() << ' ' << s << '/'<< symbolCount << name << type << value;
|
||||||
|
}
|
||||||
|
wh->rebuildModel();
|
||||||
|
success = true;
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
delete [] symParams;
|
||||||
|
if (pDbgSymGroup)
|
||||||
|
pDbgSymGroup->Release();
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CdbDebugEngine::updateWatchModel()
|
void CdbDebugEngine::updateWatchModel()
|
||||||
{
|
{
|
||||||
const QList<WatchData> incomplete = m_d->m_debuggerManagerAccess->watchHandler()->takeCurrentIncompletes();
|
WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler();
|
||||||
|
const QList<WatchData> incomplete = watchHandler->takeCurrentIncompletes();
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO << incomplete.size();
|
qDebug() << Q_FUNC_INFO << incomplete.size();
|
||||||
}
|
}
|
||||||
@@ -464,25 +637,33 @@ void CdbDebugEngine::activateFrame(int frameIndex)
|
|||||||
if (m_d->m_debuggerManager->status() != DebuggerInferiorStopped)
|
if (m_d->m_debuggerManager->status() != DebuggerInferiorStopped)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
QString errorMessage;
|
||||||
|
bool success = false;
|
||||||
|
do {
|
||||||
StackHandler *stackHandler = m_d->m_debuggerManagerAccess->stackHandler();
|
StackHandler *stackHandler = m_d->m_debuggerManagerAccess->stackHandler();
|
||||||
const int oldIndex = stackHandler->currentIndex();
|
const int oldIndex = stackHandler->currentIndex();
|
||||||
//qDebug() << "ACTIVATE FRAME: " << frameIndex << oldIndex
|
if (frameIndex >= stackHandler->stackSize()) {
|
||||||
// << stackHandler->currentIndex();
|
errorMessage = msgStackIndexOutOfRange(frameIndex, stackHandler->stackSize());
|
||||||
|
break;
|
||||||
QTC_ASSERT(frameIndex < stackHandler->stackSize(), return);
|
}
|
||||||
|
|
||||||
if (oldIndex != frameIndex) {
|
if (oldIndex != frameIndex) {
|
||||||
stackHandler->setCurrentIndex(frameIndex);
|
stackHandler->setCurrentIndex(frameIndex);
|
||||||
//updateLocals();
|
if (!m_d->updateLocals(frameIndex, m_d->m_debuggerManagerAccess->watchHandler(), &errorMessage))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StackFrame &frame = stackHandler->currentFrame();
|
const StackFrame &frame = stackHandler->currentFrame();
|
||||||
|
if (frame.file.isEmpty() || !QFileInfo(frame.file).isReadable()) {
|
||||||
const bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
|
errorMessage = QString::fromLatin1("%1: file %2 unusable.").
|
||||||
if (usable)
|
arg(QLatin1String(Q_FUNC_INFO), frame.file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
m_d->m_debuggerManager->gotoLocation(frame.file, frame.line, true);
|
m_d->m_debuggerManager->gotoLocation(frame.file, frame.line, true);
|
||||||
else
|
success =true;
|
||||||
qDebug() << "FULL NAME NOT USABLE: " << frame.file;
|
} while (false);
|
||||||
|
if (!success)
|
||||||
|
qWarning("%s", qPrintable(errorMessage));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEngine::selectThread(int index)
|
void CdbDebugEngine::selectThread(int index)
|
||||||
@@ -603,7 +784,7 @@ void CdbDebugEngine::timerEvent(QTimerEvent* te)
|
|||||||
case E_PENDING:
|
case E_PENDING:
|
||||||
case E_FAIL:
|
case E_FAIL:
|
||||||
break;
|
break;
|
||||||
case E_UNEXPECTED:
|
case E_UNEXPECTED: // Occurs on ExitProcess.
|
||||||
killWatchTimer();
|
killWatchTimer();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -667,74 +848,85 @@ void CdbDebugEnginePrivate::updateThreadList()
|
|||||||
th->setThreads(threads);
|
th->setThreads(threads);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEnginePrivate::updateStackTrace()
|
// Get CDB stack trace
|
||||||
|
bool CdbDebugEnginePrivate::getCdbStrackTrace(CdbStackTrace *st, QString *errorMessage)
|
||||||
{
|
{
|
||||||
if (debugCDB)
|
|
||||||
qDebug() << Q_FUNC_INFO;
|
|
||||||
|
|
||||||
//qDebug() << "updateStackTrace()";
|
|
||||||
HRESULT hr = m_pDebugSystemObjects->SetCurrentThreadId(m_currentThreadId);
|
HRESULT hr = m_pDebugSystemObjects->SetCurrentThreadId(m_currentThreadId);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage = QString::fromLatin1("%1: SetCurrentThreadId %2 failed: %3").
|
||||||
|
arg(QString::fromLatin1(Q_FUNC_INFO)).
|
||||||
|
arg(m_currentThreadId).
|
||||||
|
arg(msgDebugEngineComResult(hr));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
hr = m_pDebugControl->GetStackTrace(0, 0, 0, st->frames, CdbStackTrace::maxFrames, &(st->frameCount));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage = *errorMessage = msgComFailed("GetStackTrace", hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//ULONG64 frameOffset, instructionOffset, stackOffset;
|
bool CdbDebugEnginePrivate::getStackTrace(QList<StackFrame> *stackFrames,
|
||||||
//if (FAILED(m_pDebugRegisters->GetFrameOffset2(DEBUG_REGSRC_DEBUGGEE, &frameOffset)) ||
|
int *current, QString *errorMessage)
|
||||||
// FAILED(m_pDebugRegisters->GetInstructionOffset2(DEBUG_REGSRC_DEBUGGEE, &instructionOffset)) ||
|
{
|
||||||
// FAILED(m_pDebugRegisters->GetStackOffset2(DEBUG_REGSRC_DEBUGGEE, &stackOffset)))
|
stackFrames->clear();
|
||||||
//{
|
*current = -1;
|
||||||
// frameOffset = instructionOffset = stackOffset = 0;
|
// Get the CDB trace and convert into debugger plugin structures
|
||||||
//}
|
CdbStackTrace cdbStackTrace;
|
||||||
//frameOffset = instructionOffset = stackOffset = 0;
|
if (!getCdbStrackTrace(&cdbStackTrace, errorMessage))
|
||||||
|
return false;
|
||||||
const ULONG numFrames = 100;
|
|
||||||
ULONG numFramesFilled = 0;
|
|
||||||
DEBUG_STACK_FRAME frames[numFrames];
|
|
||||||
//hr = m_pDebugControl->GetStackTrace(frameOffset, stackOffset, instructionOffset, frames, numFrames, &numFramesFilled);
|
|
||||||
hr = m_pDebugControl->GetStackTrace(0, 0, 0, frames, numFrames, &numFramesFilled);
|
|
||||||
if (FAILED(hr))
|
|
||||||
qDebug() << "GetStackTrace failed";
|
|
||||||
|
|
||||||
QList<StackFrame> stackFrames;
|
|
||||||
|
|
||||||
WCHAR wszBuf[MAX_PATH];
|
WCHAR wszBuf[MAX_PATH];
|
||||||
for (ULONG i=0; i < numFramesFilled; ++i) {
|
for (ULONG i=0; i < cdbStackTrace.frameCount; ++i) {
|
||||||
StackFrame frame;
|
StackFrame frame;
|
||||||
frame.line = 0;
|
frame.line = 0;
|
||||||
frame.level = i;
|
frame.level = i;
|
||||||
frame.address = QString::fromLatin1("0x%1").arg(frames[i].InstructionOffset, 0, 16);
|
frame.address = QString::fromLatin1("0x%1").arg(cdbStackTrace.frames[i].InstructionOffset, 0, 16);
|
||||||
|
|
||||||
m_pDebugSymbols->GetNameByOffsetWide(frames[i].InstructionOffset, wszBuf, MAX_PATH, 0, 0);
|
m_pDebugSymbols->GetNameByOffsetWide(cdbStackTrace.frames[i].InstructionOffset, wszBuf, MAX_PATH, 0, 0);
|
||||||
frame.function = QString::fromUtf16(wszBuf);
|
frame.function = QString::fromUtf16(wszBuf);
|
||||||
|
|
||||||
ULONG ulLine;
|
ULONG ulLine;
|
||||||
ULONG ulFileNameSize;
|
ULONG ulFileNameSize;
|
||||||
ULONG64 ul64Displacement;
|
ULONG64 ul64Displacement;
|
||||||
hr = m_pDebugSymbols->GetLineByOffsetWide(frames[i].InstructionOffset, &ulLine, wszBuf, MAX_PATH, &ulFileNameSize, &ul64Displacement);
|
const HRESULT hr = m_pDebugSymbols->GetLineByOffsetWide(cdbStackTrace.frames[i].InstructionOffset, &ulLine, wszBuf, MAX_PATH, &ulFileNameSize, &ul64Displacement);
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
frame.line = ulLine;
|
frame.line = ulLine;
|
||||||
frame.file = QString::fromUtf16(wszBuf, ulFileNameSize);
|
frame.file = QString::fromUtf16(wszBuf, ulFileNameSize);
|
||||||
}
|
}
|
||||||
stackFrames.append(frame);
|
stackFrames->append(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_debuggerManagerAccess->stackHandler()->setFrames(stackFrames);
|
|
||||||
|
|
||||||
// find the first usable frame and select it
|
// find the first usable frame and select it
|
||||||
for (int i=0; i < stackFrames.count(); ++i) {
|
const int count = stackFrames->count();
|
||||||
const StackFrame &frame = stackFrames.at(i);
|
for (int i=0; i < count; ++i) {
|
||||||
|
const StackFrame &frame = stackFrames->at(i);
|
||||||
const bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
|
const bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
|
||||||
if (usable) {
|
if (usable) {
|
||||||
m_debuggerManagerAccess->stackHandler()->setCurrentIndex(i);
|
*current = i;
|
||||||
m_debuggerManager->gotoLocation(frame.file, frame.line, true);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//m_pDebugSymbols->GetImagePathWide(wszBuf, buflen, 0);
|
void CdbDebugEnginePrivate::updateStackTrace()
|
||||||
//qDebug() << "ImagePath" << QString::fromUtf16(wszBuf);
|
{
|
||||||
//m_pDebugSymbols->GetSymbolPathWide(wszBuf, buflen, 0);
|
if (debugCDB)
|
||||||
//qDebug() << "SymbolPath" << QString::fromUtf16(wszBuf);
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
QList<StackFrame> stackFrames;
|
||||||
|
int current;
|
||||||
|
QString errorMessage;
|
||||||
|
if (getStackTrace(&stackFrames, ¤t, &errorMessage))
|
||||||
|
qWarning("%s", qPrintable(errorMessage));
|
||||||
|
|
||||||
//m_pDebugControl->OutputStackTrace(DEBUG_OUTCTL_THIS_CLIENT, 0, 2, DEBUG_STACK_FRAME_ADDRESSES | DEBUG_STACK_COLUMN_NAMES | DEBUG_STACK_FRAME_NUMBERS);
|
m_debuggerManagerAccess->stackHandler()->setFrames(stackFrames);
|
||||||
//m_pDebugControl->OutputStackTrace(DEBUG_OUTCTL_THIS_CLIENT, frames, numFramesFilled, DEBUG_STACK_SOURCE_LINE);
|
if (current >= 0) {
|
||||||
|
m_debuggerManagerAccess->stackHandler()->setCurrentIndex(current);
|
||||||
|
m_debuggerManager->gotoLocation(stackFrames.at(current).file,
|
||||||
|
stackFrames.at(current).line, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEnginePrivate::handleDebugOutput(const char* szOutputString)
|
void CdbDebugEnginePrivate::handleDebugOutput(const char* szOutputString)
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ namespace Internal {
|
|||||||
|
|
||||||
class DebuggerManager;
|
class DebuggerManager;
|
||||||
class CdbDebugEventCallback;
|
class CdbDebugEventCallback;
|
||||||
class DebuggerEngineLibrary;
|
|
||||||
class CdbDebugOutput;
|
class CdbDebugOutput;
|
||||||
struct CdbDebugEnginePrivate;
|
struct CdbDebugEnginePrivate;
|
||||||
|
|
||||||
@@ -45,7 +44,7 @@ class CdbDebugEngine : public IDebuggerEngine
|
|||||||
{
|
{
|
||||||
Q_DISABLE_COPY(CdbDebugEngine)
|
Q_DISABLE_COPY(CdbDebugEngine)
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
explicit CdbDebugEngine(const DebuggerEngineLibrary &lib, DebuggerManager *parent);
|
explicit CdbDebugEngine(DebuggerManager *parent);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~CdbDebugEngine();
|
~CdbDebugEngine();
|
||||||
|
|||||||
@@ -32,12 +32,15 @@
|
|||||||
|
|
||||||
#include "cdbdebugeventcallback.h"
|
#include "cdbdebugeventcallback.h"
|
||||||
#include "cdbdebugoutput.h"
|
#include "cdbdebugoutput.h"
|
||||||
|
#include "stackhandler.h"
|
||||||
|
#include "debuggermanager.h"
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class DebuggerManager;
|
class DebuggerManager;
|
||||||
class IDebuggerManagerAccessForEngines;
|
class IDebuggerManagerAccessForEngines;
|
||||||
|
class WatchHandler;
|
||||||
|
|
||||||
// Thin wrapper around the 'DBEng' debugger engine shared library
|
// Thin wrapper around the 'DBEng' debugger engine shared library
|
||||||
// which is loaded at runtime.
|
// which is loaded at runtime.
|
||||||
@@ -57,9 +60,20 @@ private:
|
|||||||
DebugCreateFunction m_debugCreate;
|
DebugCreateFunction m_debugCreate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Helper struct for stack traces
|
||||||
|
struct CdbStackTrace {
|
||||||
|
CdbStackTrace() : frameCount(0) {}
|
||||||
|
enum { maxFrames = 100 };
|
||||||
|
|
||||||
|
ULONG frameCount;
|
||||||
|
DEBUG_STACK_FRAME frames[maxFrames];
|
||||||
|
};
|
||||||
|
|
||||||
struct CdbDebugEnginePrivate
|
struct CdbDebugEnginePrivate
|
||||||
{
|
{
|
||||||
explicit CdbDebugEnginePrivate(const DebuggerEngineLibrary &lib, DebuggerManager *parent, CdbDebugEngine* engine);
|
explicit CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEngine* engine);
|
||||||
|
bool init(QString *errorMessage);
|
||||||
~CdbDebugEnginePrivate();
|
~CdbDebugEnginePrivate();
|
||||||
|
|
||||||
void setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE hDebuggeeThread);
|
void setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE hDebuggeeThread);
|
||||||
@@ -68,6 +82,9 @@ struct CdbDebugEnginePrivate
|
|||||||
void handleDebugEvent();
|
void handleDebugEvent();
|
||||||
void updateThreadList();
|
void updateThreadList();
|
||||||
void updateStackTrace();
|
void updateStackTrace();
|
||||||
|
bool updateLocals(int frameIndex, WatchHandler *wh, QString *errorMessage);
|
||||||
|
bool getCdbStrackTrace(CdbStackTrace *st, QString *errorMessage);
|
||||||
|
bool getStackTrace(QList<StackFrame> *stackFrames, int *current, QString *errorMessage);
|
||||||
void handleDebugOutput(const char* szOutputString);
|
void handleDebugOutput(const char* szOutputString);
|
||||||
void handleBreakpointEvent(PDEBUG_BREAKPOINT pBP);
|
void handleBreakpointEvent(PDEBUG_BREAKPOINT pBP);
|
||||||
|
|
||||||
@@ -88,6 +105,7 @@ struct CdbDebugEnginePrivate
|
|||||||
CdbDebugEngine* m_engine;
|
CdbDebugEngine* m_engine;
|
||||||
DebuggerManager *m_debuggerManager;
|
DebuggerManager *m_debuggerManager;
|
||||||
IDebuggerManagerAccessForEngines *m_debuggerManagerAccess;
|
IDebuggerManagerAccessForEngines *m_debuggerManagerAccess;
|
||||||
|
DebuggerStartMode m_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { debugCDB = 0 };
|
enum { debugCDB = 0 };
|
||||||
|
|||||||
Reference in New Issue
Block a user