2009-02-25 09:15:00 +01:00
|
|
|
/**************************************************************************
|
2009-02-20 17:07:00 +01:00
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
2009-02-20 17:07:00 +01:00
|
|
|
**
|
|
|
|
|
** Contact: Qt Software Information (qt-info@nokia.com)
|
|
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Commercial Usage
|
2009-02-20 17:07:00 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
|
|
|
|
** accordance with the Qt Commercial License Agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and Nokia.
|
2009-02-20 17:07:00 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2009-02-20 17:07:00 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
|
|
|
** General Public License version 2.1 as published by the Free Software
|
|
|
|
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
|
|
|
** packaging of this file. Please review the following information to
|
|
|
|
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
|
|
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2009-02-20 17:07:00 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** If you are unsure which license is appropriate for your use, please
|
|
|
|
|
** contact the sales department at qt-sales@nokia.com.
|
2009-02-20 17:07:00 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
**************************************************************************/
|
2009-02-20 17:07:00 +01:00
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
#include "cdbdebugengine.h"
|
2009-02-20 17:07:00 +01:00
|
|
|
#include "cdbdebugengine_p.h"
|
2009-03-26 16:49:28 +01:00
|
|
|
#include "cdbsymbolgroupcontext.h"
|
|
|
|
|
#include "cdbstacktracecontext.h"
|
2009-02-09 11:35:43 +01:00
|
|
|
|
|
|
|
|
#include "debuggermanager.h"
|
|
|
|
|
#include "breakhandler.h"
|
|
|
|
|
#include "stackhandler.h"
|
2009-03-05 17:30:29 +01:00
|
|
|
#include "watchhandler.h"
|
2009-03-25 17:33:49 +01:00
|
|
|
#include "watchutils.h"
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-02-17 11:16:23 +01:00
|
|
|
#include <utils/qtcassert.h>
|
2009-03-04 16:00:43 +01:00
|
|
|
#include <utils/winutils.h>
|
2009-03-03 17:11:27 +01:00
|
|
|
#include <utils/consoleprocess.h>
|
2009-02-17 11:16:23 +01:00
|
|
|
|
2009-02-23 14:46:46 +01:00
|
|
|
#include <QtCore/QDebug>
|
|
|
|
|
#include <QtCore/QTimerEvent>
|
|
|
|
|
#include <QtCore/QFileInfo>
|
|
|
|
|
#include <QtCore/QDir>
|
2009-02-23 16:13:35 +01:00
|
|
|
#include <QtCore/QLibrary>
|
2009-03-06 17:10:23 +01:00
|
|
|
#include <QtCore/QCoreApplication>
|
2009-03-17 16:54:35 +01:00
|
|
|
#include <QtGui/QMessageBox>
|
|
|
|
|
#include <QtGui/QMainWindow>
|
2009-02-09 11:35:43 +01:00
|
|
|
|
|
|
|
|
#define DBGHELP_TRANSLATE_TCHAR
|
2009-02-20 14:56:36 +01:00
|
|
|
#include <inc/Dbghelp.h>
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-02-23 16:13:35 +01:00
|
|
|
static const char *dbgEngineDllC = "dbgeng";
|
|
|
|
|
static const char *debugCreateFuncC = "DebugCreate";
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-03-26 16:49:28 +01:00
|
|
|
static const char *localSymbolRootC = "local";
|
|
|
|
|
|
|
|
|
|
namespace Debugger {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
QString msgDebugEngineComResult(HRESULT hr)
|
2009-03-04 16:00:43 +01:00
|
|
|
{
|
|
|
|
|
switch (hr) {
|
2009-03-05 17:30:29 +01:00
|
|
|
case S_OK:
|
|
|
|
|
return QLatin1String("S_OK");
|
|
|
|
|
case S_FALSE:
|
|
|
|
|
return QLatin1String("S_FALSE");
|
2009-03-04 16:00:43 +01:00
|
|
|
case E_FAIL:
|
|
|
|
|
break;
|
|
|
|
|
case E_INVALIDARG:
|
|
|
|
|
return QLatin1String("E_INVALIDARG");
|
|
|
|
|
case E_NOINTERFACE:
|
|
|
|
|
return QLatin1String("E_NOINTERFACE");
|
|
|
|
|
case E_OUTOFMEMORY:
|
|
|
|
|
return QLatin1String("E_OUTOFMEMORY");
|
|
|
|
|
case E_UNEXPECTED:
|
|
|
|
|
return QLatin1String("E_UNEXPECTED");
|
|
|
|
|
case E_NOTIMPL:
|
|
|
|
|
return QLatin1String("E_NOTIMPL");
|
|
|
|
|
}
|
|
|
|
|
if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED))
|
|
|
|
|
return QLatin1String("ERROR_ACCESS_DENIED");;
|
|
|
|
|
if (hr == HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT))
|
|
|
|
|
return QLatin1String("STATUS_CONTROL_C_EXIT");
|
|
|
|
|
return Core::Utils::winErrorMessage(HRESULT_CODE(hr));
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-06 17:10:23 +01:00
|
|
|
static QString msgStackIndexOutOfRange(int idx, int size)
|
|
|
|
|
{
|
|
|
|
|
return QString::fromLatin1("Frame index %1 out of range (%2).").arg(idx).arg(size);
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-26 16:49:28 +01:00
|
|
|
QString msgComFailed(const char *func, HRESULT hr)
|
2009-03-06 17:10:23 +01:00
|
|
|
{
|
|
|
|
|
return QString::fromLatin1("%1 failed: %2").arg(QLatin1String(func), msgDebugEngineComResult(hr));
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-26 16:49:28 +01:00
|
|
|
static const char *msgNoStackTraceC = "Internal error: no stack trace present.";
|
2009-02-23 16:13:35 +01:00
|
|
|
|
|
|
|
|
DebuggerEngineLibrary::DebuggerEngineLibrary() :
|
|
|
|
|
m_debugCreate(0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DebuggerEngineLibrary::init(QString *errorMessage)
|
|
|
|
|
{
|
|
|
|
|
// Load
|
|
|
|
|
QLibrary lib(QLatin1String(dbgEngineDllC), 0);
|
|
|
|
|
|
|
|
|
|
if (!lib.isLoaded() && !lib.load()) {
|
|
|
|
|
*errorMessage = CdbDebugEngine::tr("Unable to load the debugger engine library '%1': %2").
|
|
|
|
|
arg(QLatin1String(dbgEngineDllC), lib.errorString());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Locate symbols
|
|
|
|
|
void *createFunc = lib.resolve(debugCreateFuncC);
|
|
|
|
|
if (!createFunc) {
|
|
|
|
|
*errorMessage = CdbDebugEngine::tr("Unable to resolve '%1' in the debugger engine library '%2'").
|
|
|
|
|
arg(QLatin1String(debugCreateFuncC), QLatin1String(dbgEngineDllC));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
m_debugCreate = static_cast<DebugCreateFunction>(createFunc);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- CdbDebugEnginePrivate
|
|
|
|
|
|
2009-03-06 17:10:23 +01:00
|
|
|
CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEngine* engine) :
|
2009-02-09 11:35:43 +01:00
|
|
|
m_hDebuggeeProcess(0),
|
|
|
|
|
m_hDebuggeeThread(0),
|
|
|
|
|
m_bIgnoreNextDebugEvent(false),
|
|
|
|
|
m_watchTimer(-1),
|
2009-02-20 17:07:00 +01:00
|
|
|
m_debugEventCallBack(engine),
|
2009-03-06 17:10:23 +01:00
|
|
|
m_debugOutputCallBack(engine),
|
|
|
|
|
m_pDebugClient(0),
|
|
|
|
|
m_pDebugControl(0),
|
|
|
|
|
m_pDebugSystemObjects(0),
|
|
|
|
|
m_pDebugSymbols(0),
|
|
|
|
|
m_pDebugRegisters(0),
|
2009-02-23 14:46:46 +01:00
|
|
|
m_engine(engine),
|
|
|
|
|
m_debuggerManager(parent),
|
2009-03-06 17:10:23 +01:00
|
|
|
m_debuggerManagerAccess(parent->engineInterface()),
|
2009-03-26 16:49:28 +01:00
|
|
|
m_currentStackTrace(0),
|
2009-03-27 17:19:39 +01:00
|
|
|
m_firstActivatedFrame(true),
|
2009-03-06 17:10:23 +01:00
|
|
|
m_mode(AttachCore)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CdbDebugEnginePrivate::init(QString *errorMessage)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-03-06 17:10:23 +01:00
|
|
|
// Load the DLL
|
|
|
|
|
DebuggerEngineLibrary lib;
|
|
|
|
|
if (!lib.init(errorMessage))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Initialize the COM interfaces
|
2009-02-09 11:35:43 +01:00
|
|
|
HRESULT hr;
|
2009-02-23 16:13:35 +01:00
|
|
|
hr = lib.debugCreate( __uuidof(IDebugClient5), reinterpret_cast<void**>(&m_pDebugClient));
|
|
|
|
|
if (FAILED(hr)) {
|
2009-03-06 17:10:23 +01:00
|
|
|
*errorMessage = QString::fromLatin1("Creation of IDebugClient5 failed: %1").arg(msgDebugEngineComResult(hr));
|
|
|
|
|
return false;
|
2009-02-23 16:13:35 +01:00
|
|
|
}
|
|
|
|
|
|
2009-03-06 17:10:23 +01:00
|
|
|
m_pDebugClient->SetOutputCallbacks(&m_debugOutputCallBack);
|
|
|
|
|
m_pDebugClient->SetEventCallbacks(&m_debugEventCallBack);
|
|
|
|
|
|
2009-02-23 16:13:35 +01:00
|
|
|
hr = lib.debugCreate( __uuidof(IDebugControl4), reinterpret_cast<void**>(&m_pDebugControl));
|
|
|
|
|
if (FAILED(hr)) {
|
2009-03-06 17:10:23 +01:00
|
|
|
*errorMessage = QString::fromLatin1("Creation of IDebugControl4 failed: %1").arg(msgDebugEngineComResult(hr));
|
|
|
|
|
return false;
|
2009-02-23 16:13:35 +01:00
|
|
|
}
|
|
|
|
|
|
2009-03-06 17:10:23 +01:00
|
|
|
m_pDebugControl->SetCodeLevel(DEBUG_LEVEL_SOURCE);
|
|
|
|
|
|
2009-02-23 16:13:35 +01:00
|
|
|
hr = lib.debugCreate( __uuidof(IDebugSystemObjects4), reinterpret_cast<void**>(&m_pDebugSystemObjects));
|
2009-03-06 17:10:23 +01:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = QString::fromLatin1("Creation of IDebugSystemObjects4 failed: %1").arg(msgDebugEngineComResult(hr));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2009-02-23 16:13:35 +01:00
|
|
|
|
|
|
|
|
hr = lib.debugCreate( __uuidof(IDebugSymbols3), reinterpret_cast<void**>(&m_pDebugSymbols));
|
2009-03-06 17:10:23 +01:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = QString::fromLatin1("Creation of IDebugSymbols3 failed: %1").arg(msgDebugEngineComResult(hr));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2009-02-23 16:13:35 +01:00
|
|
|
|
|
|
|
|
hr = lib.debugCreate( __uuidof(IDebugRegisters2), reinterpret_cast<void**>(&m_pDebugRegisters));
|
2009-03-06 17:10:23 +01:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = QString::fromLatin1("Creation of IDebugRegisters2 failed: %1").arg(msgDebugEngineComResult(hr));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2009-02-23 16:13:35 +01:00
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-02-23 16:13:35 +01:00
|
|
|
IDebuggerEngine *CdbDebugEngine::create(DebuggerManager *parent)
|
|
|
|
|
{
|
|
|
|
|
QString errorMessage;
|
2009-03-06 17:10:23 +01:00
|
|
|
IDebuggerEngine *rc = 0;
|
|
|
|
|
CdbDebugEngine *e = new CdbDebugEngine(parent);
|
|
|
|
|
if (e->m_d->init(&errorMessage)) {
|
|
|
|
|
rc = e;
|
|
|
|
|
} else {
|
|
|
|
|
delete e;
|
2009-02-23 16:13:35 +01:00
|
|
|
qWarning("%s", qPrintable(errorMessage));
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
2009-03-06 17:10:23 +01:00
|
|
|
return rc;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-20 17:07:00 +01:00
|
|
|
CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-03-26 16:49:28 +01:00
|
|
|
cleanStackTrace();
|
2009-02-09 11:35:43 +01:00
|
|
|
if (m_pDebugClient)
|
|
|
|
|
m_pDebugClient->Release();
|
|
|
|
|
if (m_pDebugControl)
|
|
|
|
|
m_pDebugControl->Release();
|
|
|
|
|
if (m_pDebugSystemObjects)
|
|
|
|
|
m_pDebugSystemObjects->Release();
|
|
|
|
|
if (m_pDebugSymbols)
|
|
|
|
|
m_pDebugSymbols->Release();
|
|
|
|
|
if (m_pDebugRegisters)
|
|
|
|
|
m_pDebugRegisters->Release();
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-26 16:49:28 +01:00
|
|
|
void CdbDebugEnginePrivate::cleanStackTrace()
|
|
|
|
|
{
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
|
|
|
|
|
|
|
|
|
if (m_currentStackTrace) {
|
|
|
|
|
delete m_currentStackTrace;
|
|
|
|
|
m_currentStackTrace = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-06 17:10:23 +01:00
|
|
|
CdbDebugEngine::CdbDebugEngine(DebuggerManager *parent) :
|
2009-02-23 16:13:35 +01:00
|
|
|
IDebuggerEngine(parent),
|
2009-03-06 17:10:23 +01:00
|
|
|
m_d(new CdbDebugEnginePrivate(parent, this))
|
2009-02-20 17:07:00 +01:00
|
|
|
{
|
2009-03-17 16:54:35 +01:00
|
|
|
// m_d->m_consoleStubProc.setDebug(true);
|
|
|
|
|
connect(&m_d->m_consoleStubProc, SIGNAL(processError(QString)), this, SLOT(slotConsoleStubError(QString)));
|
|
|
|
|
connect(&m_d->m_consoleStubProc, SIGNAL(processStarted()), this, SLOT(slotConsoleStubStarted()));
|
|
|
|
|
connect(&m_d->m_consoleStubProc, SIGNAL(wrapperStopped()), this, SLOT(slotConsoleStubTerminated()));
|
2009-02-20 17:07:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CdbDebugEngine::~CdbDebugEngine()
|
|
|
|
|
{
|
|
|
|
|
delete m_d;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::startWatchTimer()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-03-06 17:10:23 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
|
|
|
|
|
2009-02-20 17:07:00 +01:00
|
|
|
if (m_d->m_watchTimer == -1)
|
|
|
|
|
m_d->m_watchTimer = startTimer(0);
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::killWatchTimer()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-03-06 17:10:23 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
|
|
|
|
|
2009-02-20 17:07:00 +01:00
|
|
|
if (m_d->m_watchTimer != -1) {
|
|
|
|
|
killTimer(m_d->m_watchTimer);
|
|
|
|
|
m_d->m_watchTimer = -1;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::shutdown()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
|
|
|
|
exitDebugger();
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-20 14:56:36 +01:00
|
|
|
void CdbDebugEngine::setToolTipExpression(const QPoint & /*pos*/, const QString & /*exp*/)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
bool CdbDebugEngine::startDebugger()
|
2009-03-04 16:00:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
|
2009-03-04 16:00:43 +01:00
|
|
|
QString errorMessage;
|
|
|
|
|
bool rc = false;
|
2009-03-05 17:30:29 +01:00
|
|
|
m_d->m_bIgnoreNextDebugEvent = false;
|
2009-03-17 16:54:35 +01:00
|
|
|
const DebuggerStartMode mode = m_d->m_debuggerManager->startMode();
|
|
|
|
|
switch (mode) {
|
2009-03-04 16:00:43 +01:00
|
|
|
case AttachExternal:
|
|
|
|
|
rc = startAttachDebugger(m_d->m_debuggerManager->m_attachedPID, &errorMessage);
|
|
|
|
|
break;
|
|
|
|
|
case StartInternal:
|
|
|
|
|
case StartExternal:
|
2009-03-17 16:54:35 +01:00
|
|
|
if (m_d->m_debuggerManager->m_useTerminal) {
|
|
|
|
|
// Launch console stub and wait for its startup
|
|
|
|
|
m_d->m_consoleStubProc.stop(); // We leave the console open, so recycle it now.
|
|
|
|
|
m_d->m_consoleStubProc.setWorkingDirectory(m_d->m_debuggerManager->m_workingDir);
|
|
|
|
|
m_d->m_consoleStubProc.setEnvironment(m_d->m_debuggerManager->m_environment);
|
|
|
|
|
rc = m_d->m_consoleStubProc.start(m_d->m_debuggerManager->m_executable, m_d->m_debuggerManager->m_processArgs);
|
|
|
|
|
if (!rc)
|
|
|
|
|
errorMessage = tr("The console stub process was unable to start '%1'.").arg(m_d->m_debuggerManager->m_executable);
|
|
|
|
|
} else {
|
|
|
|
|
rc = startDebuggerWithExecutable(mode, &errorMessage);
|
|
|
|
|
}
|
2009-03-04 16:00:43 +01:00
|
|
|
break;
|
|
|
|
|
case AttachCore:
|
|
|
|
|
errorMessage = tr("CdbDebugEngine: Attach to core not supported!");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (rc) {
|
|
|
|
|
m_d->m_debuggerManager->showStatusMessage(tr("Debugger Running"), -1);
|
|
|
|
|
startWatchTimer();
|
|
|
|
|
} else {
|
|
|
|
|
qWarning("%s\n", qPrintable(errorMessage));
|
|
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-03-17 16:54:35 +01:00
|
|
|
bool CdbDebugEngine::startAttachDebugger(qint64 pid, QString *errorMessage)
|
2009-03-04 16:00:43 +01:00
|
|
|
{
|
2009-03-06 17:10:23 +01:00
|
|
|
// Need to aatrach invasively, otherwise, no notification signals
|
|
|
|
|
// for for CreateProcess/ExitProcess occur.
|
2009-03-04 16:00:43 +01:00
|
|
|
const HRESULT hr = m_d->m_pDebugClient->AttachProcess(NULL, pid,
|
2009-03-06 17:10:23 +01:00
|
|
|
DEBUG_ATTACH_INVASIVE_RESUME_PROCESS);
|
2009-03-04 16:00:43 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << "Attaching to " << pid << " returns " << hr;
|
|
|
|
|
if (FAILED(hr)) {
|
2009-03-05 17:30:29 +01:00
|
|
|
*errorMessage = tr("AttachProcess failed for pid %1: %2").arg(pid).arg(msgDebugEngineComResult(hr));
|
2009-03-04 16:00:43 +01:00
|
|
|
return false;
|
2009-03-17 16:54:35 +01:00
|
|
|
} else {
|
|
|
|
|
m_d->m_mode = AttachExternal;
|
2009-03-04 16:00:43 +01:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-17 16:54:35 +01:00
|
|
|
bool CdbDebugEngine::startDebuggerWithExecutable(DebuggerStartMode sm, QString *errorMessage)
|
2009-03-04 16:00:43 +01:00
|
|
|
{
|
|
|
|
|
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
|
2009-02-09 11:35:43 +01:00
|
|
|
|
|
|
|
|
DEBUG_CREATE_PROCESS_OPTIONS dbgopts;
|
|
|
|
|
memset(&dbgopts, 0, sizeof(dbgopts));
|
|
|
|
|
dbgopts.CreateFlags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
|
|
|
|
|
|
2009-02-23 14:46:46 +01:00
|
|
|
const QString filename(m_d->m_debuggerManager->m_executable);
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO <<filename;
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-02-23 14:46:46 +01:00
|
|
|
const QFileInfo fi(filename);
|
|
|
|
|
m_d->m_pDebugSymbols->AppendImagePathWide(QDir::toNativeSeparators(fi.absolutePath()).utf16());
|
2009-02-09 11:35:43 +01:00
|
|
|
//m_pDebugSymbols->SetSymbolOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_DEBUG | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS);
|
2009-02-20 17:07:00 +01:00
|
|
|
m_d->m_pDebugSymbols->SetSymbolOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS);
|
2009-02-09 11:35:43 +01:00
|
|
|
//m_pDebugSymbols->AddSymbolOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS | SYMOPT_NO_IMAGE_SEARCH);
|
|
|
|
|
|
2009-03-04 16:00:43 +01:00
|
|
|
// TODO console
|
|
|
|
|
const QString cmd = Core::Utils::AbstractProcess::createWinCommandline(filename, m_d->m_debuggerManager->m_processArgs);
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << "Starting " << cmd;
|
|
|
|
|
PCWSTR env = 0;
|
|
|
|
|
QByteArray envData;
|
|
|
|
|
if (!m_d->m_debuggerManager->m_environment.empty()) {
|
|
|
|
|
envData = Core::Utils::AbstractProcess::createWinEnvironment(Core::Utils::AbstractProcess::fixWinEnvironment(m_d->m_debuggerManager->m_environment));
|
|
|
|
|
env = reinterpret_cast<PCWSTR>(envData.data());
|
|
|
|
|
}
|
|
|
|
|
const HRESULT hr = m_d->m_pDebugClient->CreateProcess2Wide(NULL,
|
|
|
|
|
const_cast<PWSTR>(cmd.utf16()),
|
|
|
|
|
&dbgopts,
|
|
|
|
|
sizeof(dbgopts),
|
|
|
|
|
m_d->m_debuggerManager->m_workingDir.utf16(),
|
|
|
|
|
env);
|
|
|
|
|
if (FAILED(hr)) {
|
2009-03-06 17:10:23 +01:00
|
|
|
*errorMessage = tr("CreateProcess2Wide failed for '%1': %2").arg(cmd, msgDebugEngineComResult(hr));
|
2009-03-04 16:00:43 +01:00
|
|
|
m_d->m_debuggerManagerAccess->notifyInferiorExited();
|
2009-02-23 14:46:46 +01:00
|
|
|
return false;
|
2009-03-17 16:54:35 +01:00
|
|
|
} else {
|
|
|
|
|
m_d->m_mode = sm;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
2009-03-04 16:00:43 +01:00
|
|
|
m_d->m_debuggerManagerAccess->notifyInferiorRunning();
|
2009-02-09 11:35:43 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-25 13:42:47 +01:00
|
|
|
void CdbDebugEngine::processTerminated(unsigned long exitCode)
|
|
|
|
|
{
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << exitCode;
|
|
|
|
|
|
2009-03-26 16:49:28 +01:00
|
|
|
m_d->cleanStackTrace();
|
2009-03-25 13:42:47 +01:00
|
|
|
m_d->setDebuggeeHandles(0, 0);
|
|
|
|
|
m_d->m_debuggerManagerAccess->notifyInferiorExited();
|
|
|
|
|
m_d->m_debuggerManager->exitDebugger();
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::exitDebugger()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
|
|
|
|
|
2009-03-06 17:10:23 +01:00
|
|
|
if (m_d->m_hDebuggeeProcess) {
|
2009-03-26 16:49:28 +01:00
|
|
|
m_d->cleanStackTrace();
|
2009-03-06 17:10:23 +01:00
|
|
|
// 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:
|
2009-03-25 13:42:47 +01:00
|
|
|
// Terminate and waitr for stop events.
|
2009-03-06 17:10:23 +01:00
|
|
|
hr = m_d->m_pDebugClient->TerminateCurrentProcess();
|
2009-03-25 13:42:47 +01:00
|
|
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
2009-03-06 17:10:23 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << "terminated" << msgDebugEngineComResult(hr);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case AttachCore:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
m_d->setDebuggeeHandles(0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 11:35:43 +01:00
|
|
|
killWatchTimer();
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-27 17:19:39 +01:00
|
|
|
CdbSymbolGroupContext *CdbDebugEnginePrivate::getStackFrameSymbolGroupContext(int frameIndex, QString *errorMessage) const
|
2009-03-26 16:49:28 +01:00
|
|
|
{
|
2009-03-27 17:19:39 +01:00
|
|
|
if (!m_currentStackTrace) {
|
|
|
|
|
*errorMessage = QLatin1String(msgNoStackTraceC);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (CdbSymbolGroupContext *sg = m_currentStackTrace->symbolGroupContextAt(frameIndex, errorMessage))
|
|
|
|
|
return sg;
|
|
|
|
|
return 0;
|
2009-03-25 17:33:49 +01:00
|
|
|
}
|
|
|
|
|
|
2009-03-06 17:10:23 +01:00
|
|
|
bool CdbDebugEnginePrivate::updateLocals(int frameIndex,
|
|
|
|
|
WatchHandler *wh,
|
|
|
|
|
QString *errorMessage)
|
|
|
|
|
{
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << frameIndex;
|
2009-03-26 16:49:28 +01:00
|
|
|
wh->cleanup();
|
2009-03-06 17:10:23 +01:00
|
|
|
|
2009-03-27 17:19:39 +01:00
|
|
|
bool success = false;
|
|
|
|
|
if (CdbSymbolGroupContext *sgc = getStackFrameSymbolGroupContext(frameIndex, errorMessage))
|
|
|
|
|
success = CdbSymbolGroupContext::populateModelInitially(sgc, wh, errorMessage);
|
2009-03-06 17:10:23 +01:00
|
|
|
|
2009-03-27 17:19:39 +01:00
|
|
|
wh->rebuildModel();
|
2009-03-06 17:10:23 +01:00
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::updateWatchModel()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-03-27 17:19:39 +01:00
|
|
|
const int frameIndex = m_d->m_debuggerManagerAccess->stackHandler()->currentIndex();
|
2009-03-05 17:30:29 +01:00
|
|
|
if (debugCDB)
|
2009-03-27 17:19:39 +01:00
|
|
|
qDebug() << Q_FUNC_INFO << "fi=" << frameIndex;
|
|
|
|
|
|
|
|
|
|
bool success = false;
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
if (CdbSymbolGroupContext *sg = m_d->m_currentStackTrace->symbolGroupContextAt(frameIndex, &errorMessage))
|
|
|
|
|
success = CdbSymbolGroupContext::completeModel(sg, m_d->m_debuggerManagerAccess->watchHandler(), &errorMessage);
|
|
|
|
|
|
|
|
|
|
if (!success)
|
|
|
|
|
qWarning("%s : %s", Q_FUNC_INFO, qPrintable(errorMessage));
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::stepExec()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
|
|
|
|
|
2009-02-09 11:35:43 +01:00
|
|
|
//m_pDebugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, "p", 0);
|
2009-03-26 16:49:28 +01:00
|
|
|
m_d->cleanStackTrace();
|
|
|
|
|
const HRESULT hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_INTO);
|
|
|
|
|
Q_UNUSED(hr)
|
2009-02-20 17:07:00 +01:00
|
|
|
m_d->m_bIgnoreNextDebugEvent = true;
|
2009-02-09 11:35:43 +01:00
|
|
|
startWatchTimer();
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::stepOutExec()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
|
|
|
|
|
|
|
|
|
StackHandler* sh = m_d->m_debuggerManagerAccess->stackHandler();
|
2009-02-09 11:35:43 +01:00
|
|
|
const int idx = sh->currentIndex() + 1;
|
|
|
|
|
QList<StackFrame> stackframes = sh->frames();
|
|
|
|
|
if (idx < 0 || idx >= stackframes.size()) {
|
|
|
|
|
qWarning("cannot step out");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const StackFrame& frame = stackframes.at(idx);
|
|
|
|
|
bool ok;
|
|
|
|
|
ULONG64 address = frame.address.toULongLong(&ok, 16);
|
|
|
|
|
if (!ok) {
|
|
|
|
|
qWarning("stepOutExec: cannot obtain address from stack frame");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IDebugBreakpoint2* pBP;
|
2009-02-20 17:07:00 +01:00
|
|
|
HRESULT hr = m_d->m_pDebugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &pBP);
|
2009-02-09 11:35:43 +01:00
|
|
|
if (FAILED(hr) || !pBP) {
|
|
|
|
|
qWarning("stepOutExec: cannot create temporary breakpoint");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pBP->SetOffset(address);
|
|
|
|
|
|
|
|
|
|
//QString str = '`' + frame.file + ':' + frame.line + '`';
|
|
|
|
|
//hr = pBP->SetOffsetExpressionWide(str.utf16());
|
|
|
|
|
//if (FAILED(hr)) {
|
|
|
|
|
// qWarning("SetOffsetExpressionWide failed");
|
|
|
|
|
// return;
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
pBP->AddFlags(DEBUG_BREAKPOINT_ENABLED);
|
|
|
|
|
pBP->AddFlags(DEBUG_BREAKPOINT_ONE_SHOT);
|
|
|
|
|
//hr = m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_GO);
|
|
|
|
|
continueInferior();
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::nextExec()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
|
|
|
|
|
2009-03-26 16:49:28 +01:00
|
|
|
m_d->cleanStackTrace();
|
2009-03-05 17:30:29 +01:00
|
|
|
const HRESULT hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_OVER);
|
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
|
startWatchTimer();
|
|
|
|
|
} else {
|
|
|
|
|
qWarning("%s failed: %s", Q_FUNC_INFO, qPrintable(msgDebugEngineComResult(hr)));
|
|
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::stepIExec()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-09 13:07:38 +01:00
|
|
|
qWarning("CdbDebugEngine::stepIExec() not implemented");
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::nextIExec()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
|
|
|
|
|
2009-03-26 16:49:28 +01:00
|
|
|
m_d->cleanStackTrace();
|
2009-03-05 17:30:29 +01:00
|
|
|
const HRESULT hr = m_d->m_pDebugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, "p", 0);
|
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
|
startWatchTimer();
|
|
|
|
|
} else {
|
|
|
|
|
qWarning("%s failed: %s", Q_FUNC_INFO, qPrintable(msgDebugEngineComResult(hr)));
|
|
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::continueInferior()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
|
|
|
|
|
2009-03-26 16:49:28 +01:00
|
|
|
m_d->cleanStackTrace();
|
2009-02-09 11:35:43 +01:00
|
|
|
killWatchTimer();
|
2009-02-23 14:46:46 +01:00
|
|
|
m_d->m_debuggerManager->resetLocation();
|
2009-02-09 11:35:43 +01:00
|
|
|
|
|
|
|
|
ULONG executionStatus;
|
2009-03-25 13:42:47 +01:00
|
|
|
m_d->m_debuggerManagerAccess->notifyInferiorRunningRequested();
|
2009-02-20 17:07:00 +01:00
|
|
|
HRESULT hr = m_d->m_pDebugControl->GetExecutionStatus(&executionStatus);
|
2009-03-05 17:30:29 +01:00
|
|
|
if (SUCCEEDED(hr) && executionStatus != DEBUG_STATUS_GO) {
|
|
|
|
|
hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_GO);
|
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
|
startWatchTimer();
|
|
|
|
|
m_d->m_debuggerManagerAccess->notifyInferiorRunning();
|
|
|
|
|
} else {
|
|
|
|
|
qWarning("%s failed: %s", Q_FUNC_INFO, qPrintable(msgDebugEngineComResult(hr)));
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::interruptInferior()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
2009-03-05 17:30:29 +01:00
|
|
|
qDebug() << Q_FUNC_INFO << m_d->m_hDebuggeeProcess;
|
2009-02-23 14:46:46 +01:00
|
|
|
|
2009-02-09 11:35:43 +01:00
|
|
|
//TODO: better use IDebugControl::SetInterrupt?
|
2009-02-20 17:07:00 +01:00
|
|
|
if (!m_d->m_hDebuggeeProcess)
|
2009-02-09 11:35:43 +01:00
|
|
|
return;
|
2009-03-05 17:30:29 +01:00
|
|
|
if (DebugBreakProcess(m_d->m_hDebuggeeProcess)) {
|
|
|
|
|
m_d->m_debuggerManagerAccess->notifyInferiorStopped();
|
|
|
|
|
} else {
|
|
|
|
|
qWarning("DebugBreakProcess failed: %s", Core::Utils::winErrorMessage(GetLastError()));
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::runToLineExec(const QString &fileName, int lineNumber)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << fileName << lineNumber;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::runToFunctionExec(const QString &functionName)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << functionName;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::jumpToLineExec(const QString &fileName, int lineNumber)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << fileName << lineNumber;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::assignValueInDebugger(const QString &expr, const QString &value)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << expr << value;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-23 14:46:46 +01:00
|
|
|
void CdbDebugEngine::executeDebuggerCommand(const QString &command)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << command;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::activateFrame(int frameIndex)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << frameIndex;
|
|
|
|
|
|
2009-03-25 13:42:47 +01:00
|
|
|
if (m_d->m_debuggerManager->status() != DebuggerInferiorStopped) {
|
|
|
|
|
qWarning("WARNING %s: invoked while debuggee is running\n", Q_FUNC_INFO);
|
2009-02-09 11:35:43 +01:00
|
|
|
return;
|
2009-03-25 13:42:47 +01:00
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-03-06 17:10:23 +01:00
|
|
|
QString errorMessage;
|
|
|
|
|
bool success = false;
|
|
|
|
|
do {
|
|
|
|
|
StackHandler *stackHandler = m_d->m_debuggerManagerAccess->stackHandler();
|
2009-03-27 17:19:39 +01:00
|
|
|
WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler();
|
2009-03-06 17:10:23 +01:00
|
|
|
const int oldIndex = stackHandler->currentIndex();
|
|
|
|
|
if (frameIndex >= stackHandler->stackSize()) {
|
|
|
|
|
errorMessage = msgStackIndexOutOfRange(frameIndex, stackHandler->stackSize());
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-03-27 17:19:39 +01:00
|
|
|
if (oldIndex != frameIndex)
|
2009-03-06 17:10:23 +01:00
|
|
|
stackHandler->setCurrentIndex(frameIndex);
|
2009-03-27 17:19:39 +01:00
|
|
|
if (oldIndex != frameIndex || m_d->m_firstActivatedFrame)
|
|
|
|
|
if (!m_d->updateLocals(frameIndex, watchHandler, &errorMessage))
|
2009-03-06 17:10:23 +01:00
|
|
|
break;
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-03-06 17:10:23 +01:00
|
|
|
const StackFrame &frame = stackHandler->currentFrame();
|
2009-03-26 16:49:28 +01:00
|
|
|
if (!frame.isUsable()) {
|
2009-03-06 17:10:23 +01:00
|
|
|
errorMessage = QString::fromLatin1("%1: file %2 unusable.").
|
|
|
|
|
arg(QLatin1String(Q_FUNC_INFO), frame.file);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-02-23 14:46:46 +01:00
|
|
|
m_d->m_debuggerManager->gotoLocation(frame.file, frame.line, true);
|
2009-03-06 17:10:23 +01:00
|
|
|
success =true;
|
|
|
|
|
} while (false);
|
|
|
|
|
if (!success)
|
|
|
|
|
qWarning("%s", qPrintable(errorMessage));
|
2009-03-27 17:19:39 +01:00
|
|
|
m_d->m_firstActivatedFrame = false;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::selectThread(int index)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << index;
|
|
|
|
|
|
2009-02-09 11:35:43 +01:00
|
|
|
//reset location arrow
|
2009-02-23 14:46:46 +01:00
|
|
|
m_d->m_debuggerManager->resetLocation();
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-02-23 14:46:46 +01:00
|
|
|
ThreadsHandler *threadsHandler = m_d->m_debuggerManagerAccess->threadsHandler();
|
2009-02-09 11:35:43 +01:00
|
|
|
threadsHandler->setCurrentThread(index);
|
2009-02-20 17:07:00 +01:00
|
|
|
m_d->m_currentThreadId = index;
|
|
|
|
|
m_d->updateStackTrace();
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-23 14:46:46 +01:00
|
|
|
static inline QString breakPointExpression(const QString &fileName, const QString &lineNumber)
|
|
|
|
|
{
|
|
|
|
|
QString str;
|
|
|
|
|
str += QLatin1Char('`');
|
|
|
|
|
str += QDir::toNativeSeparators(fileName);
|
|
|
|
|
str += QLatin1Char(':');
|
|
|
|
|
str += lineNumber;
|
|
|
|
|
str += QLatin1Char('`');
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::attemptBreakpointSynchronization()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
|
|
|
|
|
|
|
|
|
if (!m_d->m_hDebuggeeProcess) {
|
|
|
|
|
qWarning("attemptBreakpointSynchronization() called while debugger is not running");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BreakHandler *handler = m_d->m_debuggerManagerAccess->breakHandler();
|
2009-02-09 11:35:43 +01:00
|
|
|
for (int i=0; i < handler->size(); ++i) {
|
|
|
|
|
BreakpointData* breakpoint = handler->at(i);
|
|
|
|
|
if (breakpoint->pending) {
|
2009-02-23 14:46:46 +01:00
|
|
|
const QString expr = breakPointExpression(breakpoint->fileName, breakpoint->lineNumber);
|
2009-02-09 11:35:43 +01:00
|
|
|
IDebugBreakpoint2* pBP = 0;
|
2009-02-20 17:07:00 +01:00
|
|
|
HRESULT hr = m_d->m_pDebugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &pBP);
|
2009-02-09 11:35:43 +01:00
|
|
|
if (FAILED(hr) || !pBP) {
|
2009-02-23 14:46:46 +01:00
|
|
|
qWarning("m_pDebugControl->AddBreakpoint2 %s failed.", qPrintable(expr));
|
2009-02-09 11:35:43 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 14:46:46 +01:00
|
|
|
hr = pBP->SetOffsetExpressionWide(expr.utf16());
|
2009-02-09 11:35:43 +01:00
|
|
|
if (FAILED(hr)) {
|
2009-02-23 14:46:46 +01:00
|
|
|
qWarning("SetOffsetExpressionWide %s failed", qPrintable(expr));
|
2009-02-09 11:35:43 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ok;
|
|
|
|
|
ULONG ul;
|
|
|
|
|
ul = breakpoint->ignoreCount.toULong(&ok);
|
|
|
|
|
if (ok) pBP->SetPassCount(ul);
|
|
|
|
|
|
|
|
|
|
//TODO: handle breakpoint->condition
|
|
|
|
|
|
|
|
|
|
pBP->AddFlags(DEBUG_BREAKPOINT_ENABLED);
|
|
|
|
|
//pBP->AddFlags(DEBUG_BREAKPOINT_GO_ONLY);
|
|
|
|
|
breakpoint->pending = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::loadSessionData()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::saveSessionData()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::reloadDisassembler()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::reloadModules()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::loadSymbols(const QString &moduleName)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << moduleName;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::loadAllSymbols()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::reloadRegisters()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::timerEvent(QTimerEvent* te)
|
2009-03-03 17:11:27 +01:00
|
|
|
{
|
2009-02-20 17:07:00 +01:00
|
|
|
if (te->timerId() != m_d->m_watchTimer)
|
2009-02-09 11:35:43 +01:00
|
|
|
return;
|
|
|
|
|
|
2009-03-05 17:30:29 +01:00
|
|
|
const HRESULT hr = m_d->m_pDebugControl->WaitForEvent(0, 1);
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
if (debugCDB > 1 || hr != S_FALSE)
|
2009-03-25 13:42:47 +01:00
|
|
|
qDebug() << Q_FUNC_INFO << "WaitForEvent" << m_d->m_debuggerManager->status() << msgDebugEngineComResult(hr);
|
2009-02-23 14:46:46 +01:00
|
|
|
|
2009-02-09 11:35:43 +01:00
|
|
|
switch (hr) {
|
|
|
|
|
case S_OK:
|
|
|
|
|
killWatchTimer();
|
2009-02-20 17:07:00 +01:00
|
|
|
m_d->handleDebugEvent();
|
2009-02-09 11:35:43 +01:00
|
|
|
break;
|
|
|
|
|
case S_FALSE:
|
|
|
|
|
case E_PENDING:
|
2009-03-05 17:30:29 +01:00
|
|
|
case E_FAIL:
|
2009-02-09 11:35:43 +01:00
|
|
|
break;
|
2009-03-06 17:10:23 +01:00
|
|
|
case E_UNEXPECTED: // Occurs on ExitProcess.
|
2009-02-09 11:35:43 +01:00
|
|
|
killWatchTimer();
|
2009-03-05 17:30:29 +01:00
|
|
|
break;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-17 16:54:35 +01:00
|
|
|
void CdbDebugEngine::slotConsoleStubStarted()
|
|
|
|
|
{
|
|
|
|
|
const qint64 appPid = m_d->m_consoleStubProc.applicationPID();
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << appPid;
|
|
|
|
|
// Attach to console process
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
if (startAttachDebugger(appPid, &errorMessage)) {
|
|
|
|
|
m_d->m_debuggerManager->m_attachedPID = appPid;
|
|
|
|
|
m_d->m_debuggerManagerAccess->notifyInferiorPidChanged(appPid);
|
|
|
|
|
} else {
|
|
|
|
|
QMessageBox::critical(m_d->m_debuggerManager->mainWindow(), tr("Debugger Error"), errorMessage);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CdbDebugEngine::slotConsoleStubError(const QString &msg)
|
|
|
|
|
{
|
|
|
|
|
QMessageBox::critical(m_d->m_debuggerManager->mainWindow(), tr("Debugger Error"), msg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CdbDebugEngine::slotConsoleStubTerminated()
|
|
|
|
|
{
|
|
|
|
|
exitDebugger();
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-20 17:07:00 +01:00
|
|
|
void CdbDebugEnginePrivate::handleDebugEvent()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
2009-03-05 17:30:29 +01:00
|
|
|
qDebug() << Q_FUNC_INFO << m_hDebuggeeProcess;
|
2009-02-23 14:46:46 +01:00
|
|
|
|
2009-02-09 11:35:43 +01:00
|
|
|
if (m_bIgnoreNextDebugEvent) {
|
2009-02-20 17:07:00 +01:00
|
|
|
m_engine->startWatchTimer();
|
2009-02-09 11:35:43 +01:00
|
|
|
m_bIgnoreNextDebugEvent = false;
|
|
|
|
|
} else {
|
2009-02-23 14:46:46 +01:00
|
|
|
m_debuggerManagerAccess->notifyInferiorStopped();
|
2009-02-09 11:35:43 +01:00
|
|
|
updateThreadList();
|
|
|
|
|
updateStackTrace();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//ULONG executionStatus;
|
|
|
|
|
//HRESULT hr = m_pDebugControl->GetExecutionStatus(&executionStatus);
|
|
|
|
|
//if (SUCCEEDED(hr) && executionStatus == DEBUG_STATUS_STEP_INTO) {
|
|
|
|
|
// // check if stack trace is valid
|
|
|
|
|
// StackHandler* sh = qq->stackHandler();
|
|
|
|
|
// QList<StackFrame> frames = sh->frames();
|
|
|
|
|
// if (frames.size() > 0 && frames.first().file.isEmpty()) {
|
|
|
|
|
// stepExec();
|
|
|
|
|
// }
|
|
|
|
|
//}
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-05 17:30:29 +01:00
|
|
|
void CdbDebugEnginePrivate::setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE hDebuggeeThread)
|
|
|
|
|
{
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << hDebuggeeProcess << hDebuggeeThread;
|
|
|
|
|
m_hDebuggeeProcess = hDebuggeeProcess;
|
|
|
|
|
m_hDebuggeeThread = hDebuggeeThread;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-20 17:07:00 +01:00
|
|
|
void CdbDebugEnginePrivate::updateThreadList()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
2009-03-05 17:30:29 +01:00
|
|
|
qDebug() << Q_FUNC_INFO << m_hDebuggeeProcess;
|
2009-02-23 14:46:46 +01:00
|
|
|
|
|
|
|
|
ThreadsHandler* th = m_debuggerManagerAccess->threadsHandler();
|
2009-02-09 11:35:43 +01:00
|
|
|
QList<ThreadData> threads;
|
|
|
|
|
|
|
|
|
|
HRESULT hr;
|
|
|
|
|
ULONG numberOfThreads;
|
|
|
|
|
hr = m_pDebugSystemObjects->GetNumberThreads(&numberOfThreads);
|
|
|
|
|
const ULONG maxThreadIds = 256;
|
|
|
|
|
ULONG threadIds[maxThreadIds];
|
|
|
|
|
ULONG biggestThreadId = qMin(maxThreadIds, numberOfThreads - 1);
|
|
|
|
|
hr = m_pDebugSystemObjects->GetThreadIdsByIndex(0, biggestThreadId, threadIds, 0);
|
|
|
|
|
for (ULONG threadId = 0; threadId <= biggestThreadId; ++threadId) {
|
|
|
|
|
ThreadData thread;
|
|
|
|
|
thread.id = threadId;
|
|
|
|
|
threads.append(thread);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
th->setThreads(threads);
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-06 17:10:23 +01:00
|
|
|
void CdbDebugEnginePrivate::updateStackTrace()
|
|
|
|
|
{
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
2009-03-26 16:49:28 +01:00
|
|
|
// Create a new context
|
|
|
|
|
cleanStackTrace();
|
2009-03-06 17:10:23 +01:00
|
|
|
QString errorMessage;
|
2009-03-26 16:49:28 +01:00
|
|
|
m_currentStackTrace =
|
|
|
|
|
CdbStackTraceContext::create(m_pDebugControl, m_pDebugSystemObjects,
|
|
|
|
|
m_pDebugSymbols, m_currentThreadId, &errorMessage);
|
|
|
|
|
if (!m_currentStackTrace) {
|
|
|
|
|
qWarning("%s: failed to create trace context: %s", Q_FUNC_INFO, qPrintable(errorMessage));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const QList<StackFrame> stackFrames = m_currentStackTrace->frames();
|
|
|
|
|
// find the first usable frame and select it
|
|
|
|
|
int current = -1;
|
|
|
|
|
const int count = stackFrames.count();
|
|
|
|
|
for (int i=0; i < count; ++i)
|
|
|
|
|
if (stackFrames.at(i).isUsable()) {
|
|
|
|
|
current = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-03-06 17:10:23 +01:00
|
|
|
m_debuggerManagerAccess->stackHandler()->setFrames(stackFrames);
|
|
|
|
|
if (current >= 0) {
|
|
|
|
|
m_debuggerManagerAccess->stackHandler()->setCurrentIndex(current);
|
|
|
|
|
m_debuggerManager->gotoLocation(stackFrames.at(current).file,
|
|
|
|
|
stackFrames.at(current).line, true);
|
|
|
|
|
}
|
2009-03-27 17:19:39 +01:00
|
|
|
m_firstActivatedFrame = true;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-03-25 13:42:47 +01:00
|
|
|
void CdbDebugEnginePrivate::handleDebugOutput(const char *szOutputString)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-03-25 13:42:47 +01:00
|
|
|
if (debugCDB && strstr(szOutputString, "ModLoad:") == 0)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << szOutputString;
|
2009-02-23 14:46:46 +01:00
|
|
|
m_debuggerManagerAccess->showApplicationOutput(QString::fromLocal8Bit(szOutputString));
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-20 17:07:00 +01:00
|
|
|
void CdbDebugEnginePrivate::handleBreakpointEvent(PDEBUG_BREAKPOINT pBP)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-20 14:56:36 +01:00
|
|
|
Q_UNUSED(pBP)
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-20 14:56:36 +01:00
|
|
|
void CdbDebugEngine::reloadSourceFiles()
|
|
|
|
|
{
|
|
|
|
|
}
|
2009-02-23 16:13:35 +01:00
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|
|
|
|
|
|
|
|
|
|
// Accessed by DebuggerManager
|
|
|
|
|
Debugger::Internal::IDebuggerEngine *createWinEngine(Debugger::Internal::DebuggerManager *parent)
|
|
|
|
|
{
|
|
|
|
|
return Debugger::Internal::CdbDebugEngine::create(parent);
|
|
|
|
|
}
|
|
|
|
|
|