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
|
|
|
**
|
2009-06-17 00:01:27 +10:00
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
2009-02-20 17:07:00 +01:00
|
|
|
**
|
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
|
2009-06-17 00:01:27 +10:00
|
|
|
** contact the sales department at http://www.qtsoftware.com/contact.
|
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 "cdbstacktracecontext.h"
|
2009-07-13 09:11:07 +02:00
|
|
|
#include "cdbstackframecontext.h"
|
2009-04-29 14:15:09 +02:00
|
|
|
#include "cdbsymbolgroupcontext.h"
|
2009-04-07 17:07:11 +02:00
|
|
|
#include "cdbbreakpoint.h"
|
2009-04-09 16:51:13 +02:00
|
|
|
#include "cdbmodules.h"
|
|
|
|
|
#include "cdbassembler.h"
|
2009-04-17 09:03:32 +02:00
|
|
|
#include "cdboptionspage.h"
|
|
|
|
|
#include "cdboptions.h"
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-04-09 16:51:13 +02:00
|
|
|
#include "debuggeractions.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-04-09 16:51:13 +02:00
|
|
|
#include "registerhandler.h"
|
|
|
|
|
#include "moduleshandler.h"
|
2009-04-14 15:04:19 +02:00
|
|
|
#include "disassemblerhandler.h"
|
2009-03-25 17:33:49 +01:00
|
|
|
#include "watchutils.h"
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-04-17 09:03:32 +02:00
|
|
|
#include <coreplugin/icore.h>
|
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-05-14 14:29:37 +02:00
|
|
|
#include <texteditor/itexteditor.h>
|
2009-02-17 11:16:23 +01:00
|
|
|
|
2009-02-23 14:46:46 +01:00
|
|
|
#include <QtCore/QDebug>
|
2009-04-22 17:28:26 +02:00
|
|
|
#include <QtCore/QTimer>
|
2009-02-23 14:46:46 +01:00
|
|
|
#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-04-14 15:04:19 +02:00
|
|
|
#include <QtGui/QApplication>
|
2009-05-14 14:29:37 +02:00
|
|
|
#include <QtGui/QToolTip>
|
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-04-17 10:13:41 +02:00
|
|
|
static const char *dbgHelpDllC = "dbghelp";
|
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 {
|
|
|
|
|
|
2009-04-07 17:07:11 +02:00
|
|
|
typedef QList<WatchData> WatchList;
|
|
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
// ----- Message helpers
|
|
|
|
|
|
2009-03-26 16:49:28 +01:00
|
|
|
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:
|
2009-05-25 16:22:11 +02:00
|
|
|
return QLatin1String("E_NOTIMPL");
|
2009-03-04 16:00:43 +01:00
|
|
|
}
|
|
|
|
|
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");
|
2009-04-22 17:28:26 +02:00
|
|
|
return QLatin1String("E_FAIL ") + Core::Utils::winErrorMessage(HRESULT_CODE(hr));
|
2009-03-04 16:00:43 +01:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
2009-04-17 10:13:41 +02:00
|
|
|
static inline QString msgLibLoadFailed(const QString &lib, const QString &why)
|
|
|
|
|
{
|
|
|
|
|
return CdbDebugEngine::tr("Unable to load the debugger engine library '%1': %2").
|
|
|
|
|
arg(lib, why);
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-25 16:22:11 +02:00
|
|
|
// Format function failure message. Pass in Q_FUNC_INFO
|
|
|
|
|
static QString msgFunctionFailed(const char *func, const QString &why)
|
|
|
|
|
{
|
|
|
|
|
// Strip a "cdecl_ int namespace1::class::foo(int bar)" as
|
|
|
|
|
// returned by Q_FUNC_INFO down to "foo"
|
|
|
|
|
QString function = QLatin1String(func);
|
|
|
|
|
const int firstParentPos = function.indexOf(QLatin1Char('('));
|
|
|
|
|
if (firstParentPos != -1)
|
|
|
|
|
function.truncate(firstParentPos);
|
|
|
|
|
const int classSepPos = function.lastIndexOf(QLatin1String("::"));
|
|
|
|
|
if (classSepPos != -1)
|
|
|
|
|
function.remove(0, classSepPos + 2);
|
|
|
|
|
//: Function call failed
|
|
|
|
|
return CdbDebugEngine::tr("The function \"%1()\" failed: %2").arg(function, why);
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
// ----- Engine helpers
|
|
|
|
|
|
2009-04-21 12:30:12 +02:00
|
|
|
static inline ULONG getInterruptTimeOutSecs(CIDebugControl *ctl)
|
2009-04-08 16:37:41 +02:00
|
|
|
{
|
|
|
|
|
ULONG rc = 0;
|
|
|
|
|
ctl->GetInterruptTimeout(&rc);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-21 12:30:12 +02:00
|
|
|
bool getExecutionStatus(CIDebugControl *ctl,
|
|
|
|
|
ULONG *executionStatus,
|
|
|
|
|
QString *errorMessage /* = 0 */)
|
2009-04-08 16:37:41 +02:00
|
|
|
{
|
|
|
|
|
const HRESULT hr = ctl->GetExecutionStatus(executionStatus);
|
|
|
|
|
if (FAILED(hr)) {
|
2009-04-21 12:30:12 +02:00
|
|
|
if (errorMessage)
|
|
|
|
|
*errorMessage = msgComFailed("GetExecutionStatus", hr);
|
2009-04-08 16:37:41 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-21 12:30:12 +02:00
|
|
|
const char *executionStatusString(ULONG executionStatus)
|
|
|
|
|
{
|
|
|
|
|
switch (executionStatus) {
|
|
|
|
|
case DEBUG_STATUS_NO_CHANGE:
|
|
|
|
|
return "DEBUG_STATUS_NO_CHANGE";
|
|
|
|
|
case DEBUG_STATUS_GO:
|
|
|
|
|
return "DEBUG_STATUS_GO";
|
|
|
|
|
case DEBUG_STATUS_GO_HANDLED:
|
|
|
|
|
return "DEBUG_STATUS_GO_HANDLED";
|
|
|
|
|
case DEBUG_STATUS_GO_NOT_HANDLED:
|
|
|
|
|
return "DEBUG_STATUS_GO_NOT_HANDLED";
|
|
|
|
|
case DEBUG_STATUS_STEP_OVER:
|
|
|
|
|
return "DEBUG_STATUS_STEP_OVER";
|
|
|
|
|
case DEBUG_STATUS_STEP_INTO:
|
|
|
|
|
return "DEBUG_STATUS_STEP_INTO";
|
|
|
|
|
case DEBUG_STATUS_BREAK:
|
|
|
|
|
return "DEBUG_STATUS_BREAK";
|
|
|
|
|
case DEBUG_STATUS_NO_DEBUGGEE:
|
|
|
|
|
return "DEBUG_STATUS_NO_DEBUGGEE";
|
|
|
|
|
case DEBUG_STATUS_STEP_BRANCH:
|
|
|
|
|
return "DEBUG_STATUS_STEP_BRANCH";
|
|
|
|
|
case DEBUG_STATUS_IGNORE_EVENT:
|
|
|
|
|
return "DEBUG_STATUS_IGNORE_EVENT";
|
|
|
|
|
case DEBUG_STATUS_RESTART_REQUESTED:
|
|
|
|
|
return "DEBUG_STATUS_RESTART_REQUESTED";
|
|
|
|
|
case DEBUG_STATUS_REVERSE_GO:
|
|
|
|
|
return "DEBUG_STATUS_REVERSE_GO";
|
|
|
|
|
case DEBUG_STATUS_REVERSE_STEP_BRANCH:
|
|
|
|
|
return "DEBUG_STATUS_REVERSE_STEP_BRANCH";
|
|
|
|
|
case DEBUG_STATUS_REVERSE_STEP_OVER:
|
|
|
|
|
return "DEBUG_STATUS_REVERSE_STEP_OVER";
|
|
|
|
|
case DEBUG_STATUS_REVERSE_STEP_INTO:
|
|
|
|
|
return "DEBUG_STATUS_REVERSE_STEP_INTO";
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return "<Unknown execution status>";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Debug convenience
|
|
|
|
|
const char *executionStatusString(CIDebugControl *ctl)
|
|
|
|
|
{
|
|
|
|
|
ULONG executionStatus;
|
|
|
|
|
if (getExecutionStatus(ctl, &executionStatus))
|
|
|
|
|
return executionStatusString(executionStatus);
|
|
|
|
|
return "<failed>";
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
// --------- DebuggerEngineLibrary
|
2009-02-23 16:13:35 +01:00
|
|
|
DebuggerEngineLibrary::DebuggerEngineLibrary() :
|
|
|
|
|
m_debugCreate(0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-17 10:13:41 +02:00
|
|
|
// Build a lib name as "Path\x.dll"
|
|
|
|
|
static inline QString libPath(const QString &libName, const QString &path = QString())
|
2009-02-23 16:13:35 +01:00
|
|
|
{
|
2009-04-17 10:13:41 +02:00
|
|
|
QString rc = path;
|
|
|
|
|
if (!rc.isEmpty())
|
|
|
|
|
rc += QDir::separator();
|
|
|
|
|
rc += libName;
|
|
|
|
|
rc += QLatin1String(".dll");
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2009-02-23 16:13:35 +01:00
|
|
|
|
2009-04-17 10:13:41 +02:00
|
|
|
bool DebuggerEngineLibrary::init(const QString &path, QString *errorMessage)
|
|
|
|
|
{
|
|
|
|
|
// Load the dependent help lib first
|
|
|
|
|
const QString helpLibPath = libPath(QLatin1String(dbgHelpDllC), path);
|
|
|
|
|
QLibrary helpLib(helpLibPath, 0);
|
|
|
|
|
if (!helpLib.isLoaded() && !helpLib.load()) {
|
|
|
|
|
*errorMessage = msgLibLoadFailed(helpLibPath, helpLib.errorString());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Load dbgeng lib
|
|
|
|
|
const QString engineLibPath = libPath(QLatin1String(dbgEngineDllC), path);
|
|
|
|
|
QLibrary lib(engineLibPath, 0);
|
2009-02-23 16:13:35 +01:00
|
|
|
if (!lib.isLoaded() && !lib.load()) {
|
2009-04-17 10:13:41 +02:00
|
|
|
*errorMessage = msgLibLoadFailed(engineLibPath, lib.errorString());
|
2009-02-23 16:13:35 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-20 16:40:50 +02:00
|
|
|
// ----- SyntaxSetter
|
2009-04-21 12:30:12 +02:00
|
|
|
SyntaxSetter::SyntaxSetter(CIDebugControl *ctl, ULONG desiredSyntax) :
|
2009-04-07 17:07:11 +02:00
|
|
|
m_desiredSyntax(desiredSyntax),
|
|
|
|
|
m_ctl(ctl)
|
|
|
|
|
{
|
|
|
|
|
m_ctl->GetExpressionSyntax(&m_oldSyntax);
|
|
|
|
|
if (m_oldSyntax != m_desiredSyntax)
|
|
|
|
|
m_ctl->SetExpressionSyntax(m_desiredSyntax);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SyntaxSetter::~SyntaxSetter()
|
|
|
|
|
{
|
|
|
|
|
if (m_oldSyntax != m_desiredSyntax)
|
|
|
|
|
m_ctl->SetExpressionSyntax(m_oldSyntax);
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-20 16:40:50 +02:00
|
|
|
// CdbComInterfaces
|
|
|
|
|
CdbComInterfaces::CdbComInterfaces() :
|
|
|
|
|
debugClient(0),
|
|
|
|
|
debugControl(0),
|
|
|
|
|
debugSystemObjects(0),
|
|
|
|
|
debugSymbols(0),
|
|
|
|
|
debugRegisters(0),
|
|
|
|
|
debugDataSpaces(0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 16:13:35 +01:00
|
|
|
// --- CdbDebugEnginePrivate
|
|
|
|
|
|
2009-04-17 09:03:32 +02:00
|
|
|
CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent,
|
|
|
|
|
const QSharedPointer<CdbOptions> &options,
|
|
|
|
|
CdbDebugEngine* engine) :
|
|
|
|
|
m_options(options),
|
2009-02-09 11:35:43 +01:00
|
|
|
m_hDebuggeeProcess(0),
|
|
|
|
|
m_hDebuggeeThread(0),
|
2009-04-08 16:37:41 +02:00
|
|
|
m_breakEventMode(BreakEventHandle),
|
2009-04-29 14:15:09 +02:00
|
|
|
m_dumper(new CdbDumperHelper(parent, &m_cif)),
|
2009-02-09 11:35:43 +01:00
|
|
|
m_watchTimer(-1),
|
2009-02-20 17:07:00 +01:00
|
|
|
m_debugEventCallBack(engine),
|
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-07-13 09:11:07 +02:00
|
|
|
m_mode(AttachCore)
|
2009-04-15 10:05:40 +02:00
|
|
|
{
|
2009-03-06 17:10:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CdbDebugEnginePrivate::init(QString *errorMessage)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-07-27 15:32:46 +02:00
|
|
|
enum { bufLen = 10240 };
|
2009-03-06 17:10:23 +01:00
|
|
|
// Load the DLL
|
|
|
|
|
DebuggerEngineLibrary lib;
|
2009-04-17 09:03:32 +02:00
|
|
|
if (!lib.init(m_options->path, errorMessage))
|
2009-03-06 17:10:23 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Initialize the COM interfaces
|
2009-02-09 11:35:43 +01:00
|
|
|
HRESULT hr;
|
2009-04-20 16:40:50 +02:00
|
|
|
hr = lib.debugCreate( __uuidof(IDebugClient5), reinterpret_cast<void**>(&m_cif.debugClient));
|
2009-02-23 16:13:35 +01:00
|
|
|
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-04-20 16:40:50 +02:00
|
|
|
m_cif.debugClient->SetOutputCallbacksWide(&m_debugOutputCallBack);
|
|
|
|
|
m_cif.debugClient->SetEventCallbacksWide(&m_debugEventCallBack);
|
2009-03-06 17:10:23 +01:00
|
|
|
|
2009-04-20 16:40:50 +02:00
|
|
|
hr = lib.debugCreate( __uuidof(IDebugControl4), reinterpret_cast<void**>(&m_cif.debugControl));
|
2009-02-23 16:13:35 +01:00
|
|
|
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-04-20 16:40:50 +02:00
|
|
|
m_cif.debugControl->SetCodeLevel(DEBUG_LEVEL_SOURCE);
|
2009-03-06 17:10:23 +01:00
|
|
|
|
2009-04-20 16:40:50 +02:00
|
|
|
hr = lib.debugCreate( __uuidof(IDebugSystemObjects4), reinterpret_cast<void**>(&m_cif.debugSystemObjects));
|
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
|
|
|
|
2009-04-20 16:40:50 +02:00
|
|
|
hr = lib.debugCreate( __uuidof(IDebugSymbols3), reinterpret_cast<void**>(&m_cif.debugSymbols));
|
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
|
|
|
|
2009-07-27 15:32:46 +02:00
|
|
|
WCHAR buf[bufLen];
|
|
|
|
|
hr = m_cif.debugSymbols->GetImagePathWide(buf, bufLen, 0);
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = msgComFailed("GetImagePathWide", hr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
m_baseImagePath = QString::fromUtf16(buf);
|
|
|
|
|
|
2009-04-20 16:40:50 +02:00
|
|
|
hr = lib.debugCreate( __uuidof(IDebugRegisters2), reinterpret_cast<void**>(&m_cif.debugRegisters));
|
2009-03-06 17:10:23 +01:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = QString::fromLatin1("Creation of IDebugRegisters2 failed: %1").arg(msgDebugEngineComResult(hr));
|
2009-04-15 10:05:40 +02:00
|
|
|
return false;
|
2009-03-06 17:10:23 +01:00
|
|
|
}
|
2009-04-20 16:40:50 +02:00
|
|
|
|
|
|
|
|
hr = lib.debugCreate( __uuidof(IDebugDataSpaces4), reinterpret_cast<void**>(&m_cif.debugDataSpaces));
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = QString::fromLatin1("Creation of IDebugDataSpaces4 failed: %1").arg(msgDebugEngineComResult(hr));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
if (debugCDB)
|
2009-04-20 16:40:50 +02:00
|
|
|
qDebug() << QString::fromLatin1("CDB Initialization succeeded, interrupt time out %1s.").arg(getInterruptTimeOutSecs(m_cif.debugControl));
|
2009-03-06 17:10:23 +01:00
|
|
|
return true;
|
2009-02-23 16:13:35 +01:00
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-04-17 09:03:32 +02:00
|
|
|
IDebuggerEngine *CdbDebugEngine::create(DebuggerManager *parent,
|
|
|
|
|
const QSharedPointer<CdbOptions> &options,
|
|
|
|
|
QString *errorMessage)
|
2009-02-23 16:13:35 +01:00
|
|
|
{
|
2009-04-17 09:03:32 +02:00
|
|
|
CdbDebugEngine *rc = new CdbDebugEngine(parent, options);
|
2009-05-08 16:56:48 +02:00
|
|
|
if (rc->m_d->init(errorMessage)) {
|
|
|
|
|
rc->syncDebuggerPaths();
|
2009-04-17 09:03:32 +02:00
|
|
|
return rc;
|
2009-05-08 16:56:48 +02:00
|
|
|
}
|
2009-04-17 09:03:32 +02:00
|
|
|
delete rc;
|
|
|
|
|
return 0;
|
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-04-20 16:40:50 +02:00
|
|
|
if (m_cif.debugClient)
|
|
|
|
|
m_cif.debugClient->Release();
|
|
|
|
|
if (m_cif.debugControl)
|
|
|
|
|
m_cif.debugControl->Release();
|
|
|
|
|
if (m_cif.debugSystemObjects)
|
|
|
|
|
m_cif.debugSystemObjects->Release();
|
|
|
|
|
if (m_cif.debugSymbols)
|
|
|
|
|
m_cif.debugSymbols->Release();
|
|
|
|
|
if (m_cif.debugRegisters)
|
|
|
|
|
m_cif.debugRegisters->Release();
|
|
|
|
|
if (m_cif.debugDataSpaces)
|
|
|
|
|
m_cif.debugDataSpaces->Release();
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
void CdbDebugEnginePrivate::clearForRun()
|
2009-03-26 16:49:28 +01:00
|
|
|
{
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
|
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
m_breakEventMode = BreakEventHandle;
|
|
|
|
|
m_firstActivatedFrame = false;
|
|
|
|
|
cleanStackTrace();
|
2009-05-14 14:29:37 +02:00
|
|
|
m_editorToolTipCache.clear();
|
2009-04-08 16:37:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CdbDebugEnginePrivate::cleanStackTrace()
|
2009-04-15 10:05:40 +02:00
|
|
|
{
|
2009-03-26 16:49:28 +01:00
|
|
|
if (m_currentStackTrace) {
|
|
|
|
|
delete m_currentStackTrace;
|
|
|
|
|
m_currentStackTrace = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-17 09:03:32 +02:00
|
|
|
CdbDebugEngine::CdbDebugEngine(DebuggerManager *parent, const QSharedPointer<CdbOptions> &options) :
|
2009-02-23 16:13:35 +01:00
|
|
|
IDebuggerEngine(parent),
|
2009-04-17 09:03:32 +02:00
|
|
|
m_d(new CdbDebugEnginePrivate(parent, options, this))
|
2009-02-20 17:07:00 +01:00
|
|
|
{
|
2009-05-06 14:26:20 +02:00
|
|
|
m_d->m_consoleStubProc.setMode(Core::Utils::ConsoleProcess::Suspend);
|
2009-03-17 16:54:35 +01:00
|
|
|
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-06-19 12:47:23 +02:00
|
|
|
connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggerOutput(int,QString)),
|
|
|
|
|
m_d->m_debuggerManager, SLOT(showDebuggerOutput(int,QString)));
|
|
|
|
|
connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggerInputPrompt(int,QString)),
|
|
|
|
|
m_d->m_debuggerManager, SLOT(showDebuggerInput(int,QString)));
|
2009-04-14 15:04:19 +02:00
|
|
|
connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggeeOutput(QString)),
|
|
|
|
|
m_d->m_debuggerManager, SLOT(showApplicationOutput(QString)));
|
|
|
|
|
connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggeeInputPrompt(QString)),
|
|
|
|
|
m_d->m_debuggerManager, SLOT(showApplicationOutput(QString)));
|
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-05-14 14:29:37 +02:00
|
|
|
QString CdbDebugEngine::editorToolTip(const QString &exp, const QString &function)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-05-14 14:29:37 +02:00
|
|
|
// Figure the editor tooltip. Ask the frame context of the
|
|
|
|
|
// function if it is a local variable it knows. If that is not
|
|
|
|
|
// the case, try to evaluate via debugger
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
QString rc;
|
|
|
|
|
// Find the frame of the function if there is any
|
2009-07-13 09:11:07 +02:00
|
|
|
CdbStackFrameContext *frame = 0;
|
2009-05-14 14:29:37 +02:00
|
|
|
if (m_d->m_currentStackTrace && !function.isEmpty()) {
|
|
|
|
|
const int frameIndex = m_d->m_currentStackTrace->indexOf(function);
|
2009-07-13 09:11:07 +02:00
|
|
|
if (frameIndex != -1)
|
|
|
|
|
frame = m_d->m_currentStackTrace->frameContextAt(frameIndex, &errorMessage);
|
2009-05-14 14:29:37 +02:00
|
|
|
}
|
2009-07-13 09:11:07 +02:00
|
|
|
if (frame && frame->editorToolTip(QLatin1String("local.") + exp, &rc, &errorMessage))
|
|
|
|
|
return rc;
|
2009-05-14 14:29:37 +02:00
|
|
|
// No function/symbol context found, try to evaluate in current context.
|
|
|
|
|
// Do not append type as this will mostly be 'long long' for integers, etc.
|
|
|
|
|
QString type;
|
|
|
|
|
if (!evaluateExpression(exp, &rc, &type, &errorMessage))
|
|
|
|
|
return QString();
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CdbDebugEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
|
|
|
|
|
{
|
|
|
|
|
typedef CdbDebugEnginePrivate::EditorToolTipCache EditorToolTipCache;
|
2009-04-21 12:30:12 +02:00
|
|
|
if (debugCDB)
|
2009-05-14 14:29:37 +02:00
|
|
|
qDebug() << Q_FUNC_INFO << '\n' << cursorPos;
|
|
|
|
|
// Need a stopped debuggee and a cpp file
|
|
|
|
|
if (!m_d->m_hDebuggeeProcess || m_d->isDebuggeeRunning())
|
|
|
|
|
return;
|
|
|
|
|
if (!isCppEditor(editor))
|
|
|
|
|
return;
|
|
|
|
|
// Determine expression and function
|
|
|
|
|
QString toolTip;
|
|
|
|
|
do {
|
|
|
|
|
int line;
|
|
|
|
|
int column;
|
|
|
|
|
QString function;
|
|
|
|
|
const QString exp = cppExpressionAt(editor, cursorPos, &line, &column, &function);
|
|
|
|
|
if (function.isEmpty() || exp.isEmpty())
|
|
|
|
|
break;
|
|
|
|
|
// Check cache (key containing function) or try to figure out expression
|
|
|
|
|
QString cacheKey = function;
|
|
|
|
|
cacheKey += QLatin1Char('@');
|
|
|
|
|
cacheKey += exp;
|
|
|
|
|
const EditorToolTipCache::const_iterator cit = m_d->m_editorToolTipCache.constFind(cacheKey);
|
|
|
|
|
if (cit != m_d->m_editorToolTipCache.constEnd()) {
|
|
|
|
|
toolTip = cit.value();
|
|
|
|
|
} else {
|
|
|
|
|
toolTip = editorToolTip(exp, function);
|
|
|
|
|
if (!toolTip.isEmpty())
|
|
|
|
|
m_d->m_editorToolTipCache.insert(cacheKey, toolTip);
|
|
|
|
|
}
|
|
|
|
|
} while (false);
|
|
|
|
|
// Display
|
|
|
|
|
QToolTip::hideText();
|
|
|
|
|
if (!toolTip.isEmpty())
|
|
|
|
|
QToolTip::showText(mousePos, toolTip);
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-04-09 16:51:13 +02:00
|
|
|
void CdbDebugEnginePrivate::clearDisplay()
|
|
|
|
|
{
|
|
|
|
|
m_debuggerManagerAccess->threadsHandler()->removeAll();
|
|
|
|
|
m_debuggerManagerAccess->modulesHandler()->removeAll();
|
|
|
|
|
m_debuggerManagerAccess->registerHandler()->removeAll();
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-26 16:27:24 +02:00
|
|
|
bool CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp)
|
2009-04-15 10:05:40 +02:00
|
|
|
{
|
2009-06-19 11:07:38 +02:00
|
|
|
if (m_d->m_hDebuggeeProcess) {
|
|
|
|
|
warning(QLatin1String("Internal error: Attempt to start debugger while another process is being debugged."));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2009-04-09 16:51:13 +02:00
|
|
|
m_d->clearDisplay();
|
2009-05-08 16:56:48 +02:00
|
|
|
|
2009-04-22 17:28:26 +02:00
|
|
|
const DebuggerStartMode mode = m_d->m_debuggerManager->startMode();
|
2009-04-20 16:40:50 +02:00
|
|
|
// Figure out dumper. @TODO: same in gdb...
|
2009-04-22 17:28:26 +02:00
|
|
|
const QString dumperLibName = QDir::toNativeSeparators(m_d->m_debuggerManagerAccess->qtDumperLibraryName());
|
2009-05-26 16:27:24 +02:00
|
|
|
bool dumperEnabled = mode != AttachCore
|
|
|
|
|
&& mode != AttachCrashedExternal
|
2009-04-22 17:28:26 +02:00
|
|
|
&& m_d->m_debuggerManagerAccess->qtDumperLibraryEnabled();
|
2009-04-20 16:40:50 +02:00
|
|
|
if (dumperEnabled) {
|
|
|
|
|
const QFileInfo fi(dumperLibName);
|
|
|
|
|
if (!fi.isFile()) {
|
2009-07-15 17:41:45 +02:00
|
|
|
const QStringList &locations = m_d->m_debuggerManagerAccess->qtDumperLibraryLocations();
|
|
|
|
|
const QString loc = locations.join(QLatin1String(", "));
|
|
|
|
|
const QString msg = tr("The dumper library was not found at %1.").arg(loc);
|
2009-04-22 17:28:26 +02:00
|
|
|
m_d->m_debuggerManagerAccess->showQtDumperLibraryWarning(msg);
|
2009-04-20 16:40:50 +02:00
|
|
|
dumperEnabled = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-04-29 14:15:09 +02:00
|
|
|
m_d->m_dumper->reset(dumperLibName, dumperEnabled);
|
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-05-06 14:26:20 +02:00
|
|
|
bool needWatchTimer = false;
|
2009-04-08 16:37:41 +02:00
|
|
|
m_d->clearForRun();
|
2009-03-17 16:54:35 +01:00
|
|
|
switch (mode) {
|
2009-03-04 16:00:43 +01:00
|
|
|
case AttachExternal:
|
2009-05-26 16:27:24 +02:00
|
|
|
case AttachCrashedExternal:
|
|
|
|
|
rc = startAttachDebugger(sp->attachPID, mode, &errorMessage);
|
|
|
|
|
needWatchTimer = true; // Fetch away module load, etc. even if crashed
|
2009-03-04 16:00:43 +01:00
|
|
|
break;
|
|
|
|
|
case StartInternal:
|
|
|
|
|
case StartExternal:
|
2009-05-25 16:22:11 +02:00
|
|
|
if (sp->useTerminal) {
|
2009-03-17 16:54:35 +01:00
|
|
|
// Launch console stub and wait for its startup
|
|
|
|
|
m_d->m_consoleStubProc.stop(); // We leave the console open, so recycle it now.
|
2009-05-25 16:22:11 +02:00
|
|
|
m_d->m_consoleStubProc.setWorkingDirectory(sp->workingDir);
|
|
|
|
|
m_d->m_consoleStubProc.setEnvironment(sp->environment);
|
|
|
|
|
rc = m_d->m_consoleStubProc.start(sp->executable, sp->processArgs);
|
2009-03-17 16:54:35 +01:00
|
|
|
if (!rc)
|
2009-05-25 16:22:11 +02:00
|
|
|
errorMessage = tr("The console stub process was unable to start '%1'.").arg(sp->executable);
|
2009-05-06 14:26:20 +02:00
|
|
|
// continues in slotConsoleStubStarted()...
|
2009-03-17 16:54:35 +01:00
|
|
|
} else {
|
2009-05-06 14:26:20 +02:00
|
|
|
needWatchTimer = true;
|
2009-03-17 16:54:35 +01:00
|
|
|
rc = startDebuggerWithExecutable(mode, &errorMessage);
|
|
|
|
|
}
|
2009-03-04 16:00:43 +01:00
|
|
|
break;
|
|
|
|
|
case AttachCore:
|
2009-05-07 15:34:52 +02:00
|
|
|
errorMessage = tr("Attaching to core files is not supported!");
|
2009-03-04 16:00:43 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (rc) {
|
2009-05-07 15:34:52 +02:00
|
|
|
m_d->m_debuggerManager->showStatusMessage(tr("Debugger running"), -1);
|
2009-05-06 14:26:20 +02:00
|
|
|
if (needWatchTimer)
|
|
|
|
|
startWatchTimer();
|
2009-03-04 16:00:43 +01:00
|
|
|
} else {
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(errorMessage);
|
2009-03-04 16:00:43 +01:00
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-05-26 16:27:24 +02:00
|
|
|
bool CdbDebugEngine::startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage)
|
2009-03-04 16:00:43 +01:00
|
|
|
{
|
2009-05-06 14:26:20 +02:00
|
|
|
// Need to attrach invasively, otherwise, no notification signals
|
2009-03-06 17:10:23 +01:00
|
|
|
// for for CreateProcess/ExitProcess occur.
|
2009-05-06 14:26:20 +02:00
|
|
|
const ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS;
|
|
|
|
|
const HRESULT hr = m_d->m_cif.debugClient->AttachProcess(NULL, pid, flags);
|
2009-03-04 16:00:43 +01:00
|
|
|
if (debugCDB)
|
2009-05-06 14:26:20 +02:00
|
|
|
qDebug() << "Attaching to " << pid << " returns " << hr << executionStatusString(m_d->m_cif.debugControl);
|
2009-03-04 16:00:43 +01:00
|
|
|
if (FAILED(hr)) {
|
2009-05-07 15:34:52 +02:00
|
|
|
*errorMessage = tr("Attaching to a process failed for process id %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 {
|
2009-05-26 16:27:24 +02:00
|
|
|
m_d->m_mode = sm;
|
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-05-25 16:22:11 +02:00
|
|
|
const QSharedPointer<DebuggerStartParameters> sp = m_d->m_debuggerManager->startParameters();
|
|
|
|
|
const QString filename(sp->executable);
|
2009-07-27 15:32:46 +02:00
|
|
|
// Set image path
|
|
|
|
|
const QFileInfo fi(filename);
|
|
|
|
|
QString imagePath = QDir::toNativeSeparators(fi.absolutePath());
|
|
|
|
|
if (!m_d->m_baseImagePath.isEmpty()) {
|
|
|
|
|
imagePath += QLatin1Char(';');
|
|
|
|
|
imagePath += m_d->m_baseImagePath;
|
|
|
|
|
}
|
2009-07-28 09:10:12 +02:00
|
|
|
HRESULT hr = m_d->m_cif.debugSymbols->SetImagePathWide(reinterpret_cast<PCWSTR>(imagePath.utf16()));
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = tr("Unable to set the image path to %1: %2").arg(imagePath, msgComFailed("SetImagePathWide", hr));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
2009-07-27 15:32:46 +02:00
|
|
|
qDebug() << Q_FUNC_INFO <<'\n' << filename << imagePath;
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-07-27 15:32:46 +02:00
|
|
|
ULONG symbolOptions = SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS;
|
|
|
|
|
if (m_d->m_options->verboseSymbolLoading)
|
|
|
|
|
symbolOptions |= SYMOPT_DEBUG;
|
|
|
|
|
m_d->m_cif.debugSymbols->SetSymbolOptions(symbolOptions);
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-05-25 16:22:11 +02:00
|
|
|
const QString cmd = Core::Utils::AbstractProcess::createWinCommandline(filename, sp->processArgs);
|
2009-03-04 16:00:43 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << "Starting " << cmd;
|
|
|
|
|
PCWSTR env = 0;
|
|
|
|
|
QByteArray envData;
|
2009-05-25 16:22:11 +02:00
|
|
|
if (!sp->environment.empty()) {
|
|
|
|
|
envData = Core::Utils::AbstractProcess::createWinEnvironment(Core::Utils::AbstractProcess::fixWinEnvironment(sp->environment));
|
2009-03-04 16:00:43 +01:00
|
|
|
env = reinterpret_cast<PCWSTR>(envData.data());
|
|
|
|
|
}
|
2009-07-28 09:10:12 +02:00
|
|
|
// The working directory cannot be empty.
|
|
|
|
|
PCWSTR workingDirC = 0;
|
|
|
|
|
const QString workingDir = sp->workingDir.isEmpty() ? QString() : QDir::toNativeSeparators(sp->workingDir);
|
|
|
|
|
if (!workingDir.isEmpty())
|
|
|
|
|
workingDirC = workingDir.utf16();
|
|
|
|
|
hr = m_d->m_cif.debugClient->CreateProcess2Wide(NULL,
|
|
|
|
|
reinterpret_cast<PWSTR>(const_cast<ushort *>(cmd.utf16())),
|
|
|
|
|
&dbgopts, sizeof(dbgopts),
|
|
|
|
|
workingDirC, env);
|
2009-03-04 16:00:43 +01:00
|
|
|
if (FAILED(hr)) {
|
2009-05-07 15:34:52 +02:00
|
|
|
*errorMessage = tr("Unable to create a process '%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-04-22 17:28:26 +02:00
|
|
|
void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle)
|
|
|
|
|
{
|
|
|
|
|
setDebuggeeHandles(reinterpret_cast<HANDLE>(processHandle), reinterpret_cast<HANDLE>(initialThreadHandle));
|
|
|
|
|
m_debuggerManagerAccess->notifyInferiorRunning();
|
|
|
|
|
ULONG currentThreadId;
|
|
|
|
|
if (SUCCEEDED(m_cif.debugSystemObjects->GetThreadIdByHandle(initialThreadHandle, ¤tThreadId))) {
|
|
|
|
|
m_currentThreadId = currentThreadId;
|
|
|
|
|
} else {
|
|
|
|
|
m_currentThreadId = 0;
|
|
|
|
|
}
|
2009-04-29 14:15:09 +02:00
|
|
|
// Clear any saved breakpoints and set initial breakpoints
|
|
|
|
|
m_engine->executeDebuggerCommand(QLatin1String("bc"));
|
2009-04-22 17:28:26 +02:00
|
|
|
if (m_debuggerManagerAccess->breakHandler()->hasPendingBreakpoints())
|
2009-05-25 16:22:11 +02:00
|
|
|
m_engine->attemptBreakpointSynchronization();
|
2009-05-26 16:27:24 +02:00
|
|
|
// Attaching to crashed: This handshake (signalling an event) is required for
|
|
|
|
|
// the exception to be delivered to the debugger
|
|
|
|
|
if (m_mode == AttachCrashedExternal) {
|
|
|
|
|
const QString crashParameter = m_debuggerManager->startParameters()->crashParameter;
|
|
|
|
|
if (!crashParameter.isEmpty()) {
|
|
|
|
|
ULONG64 evtNr = crashParameter.toULongLong();
|
|
|
|
|
const HRESULT hr = m_cif.debugControl->SetNotifyEventHandle(evtNr);
|
|
|
|
|
if (FAILED(hr))
|
|
|
|
|
m_engine->warning(QString::fromLatin1("Handshake failed on event #%1: %2").arg(evtNr).arg(msgComFailed("SetNotifyEventHandle", hr)));
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-05-25 16:22:11 +02:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << '\n' << executionStatusString(m_cif.debugControl);
|
2009-04-22 17:28:26 +02:00
|
|
|
}
|
|
|
|
|
|
2009-03-25 13:42:47 +01:00
|
|
|
void CdbDebugEngine::processTerminated(unsigned long exitCode)
|
|
|
|
|
{
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << exitCode;
|
|
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
m_d->clearForRun();
|
2009-03-25 13:42:47 +01:00
|
|
|
m_d->setDebuggeeHandles(0, 0);
|
|
|
|
|
m_d->m_debuggerManagerAccess->notifyInferiorExited();
|
|
|
|
|
m_d->m_debuggerManager->exitDebugger();
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-11 16:54:35 +02:00
|
|
|
// End debugging using
|
|
|
|
|
void CdbDebugEnginePrivate::endDebugging(EndDebuggingMode em)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-05-11 16:54:35 +02:00
|
|
|
enum Action { Detach, Terminate };
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
2009-05-11 16:54:35 +02:00
|
|
|
qDebug() << Q_FUNC_INFO << em;
|
|
|
|
|
|
|
|
|
|
if (m_mode == AttachCore || !m_hDebuggeeProcess)
|
|
|
|
|
return;
|
|
|
|
|
// Figure out action
|
|
|
|
|
Action action;
|
|
|
|
|
switch (em) {
|
|
|
|
|
case EndDebuggingAuto:
|
2009-05-26 16:27:24 +02:00
|
|
|
action = (m_mode == AttachExternal || m_mode == AttachCrashedExternal) ?
|
|
|
|
|
Detach : Terminate;
|
2009-05-11 16:54:35 +02:00
|
|
|
break;
|
|
|
|
|
case EndDebuggingDetach:
|
|
|
|
|
action = Detach;
|
|
|
|
|
break;
|
|
|
|
|
case EndDebuggingTerminate:
|
|
|
|
|
action = Terminate;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << action;
|
|
|
|
|
// Need a stopped debuggee to act
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
const bool wasRunning = isDebuggeeRunning();
|
|
|
|
|
if (wasRunning) { // Process must be stopped in order to terminate
|
|
|
|
|
interruptInterferiorProcess(&errorMessage);
|
|
|
|
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
2009-05-25 16:22:11 +02:00
|
|
|
}
|
2009-05-11 16:54:35 +02:00
|
|
|
HRESULT hr;
|
|
|
|
|
switch (action) {
|
|
|
|
|
case Detach:
|
|
|
|
|
hr = m_cif.debugClient->DetachCurrentProcess();
|
|
|
|
|
if (FAILED(hr))
|
|
|
|
|
errorMessage += msgComFailed("DetachCurrentProcess", hr);
|
|
|
|
|
break;
|
|
|
|
|
case Terminate:
|
|
|
|
|
hr = m_cif.debugClient->TerminateCurrentProcess();
|
|
|
|
|
if (FAILED(hr))
|
|
|
|
|
errorMessage += msgComFailed("TerminateCurrentProcess", hr);
|
|
|
|
|
if (!wasRunning) {
|
|
|
|
|
hr = m_cif.debugClient->TerminateProcesses();
|
2009-04-08 16:37:41 +02:00
|
|
|
if (FAILED(hr))
|
2009-05-11 16:54:35 +02:00
|
|
|
errorMessage += msgComFailed("TerminateProcesses", hr);
|
2009-03-06 17:10:23 +01:00
|
|
|
}
|
2009-05-11 16:54:35 +02:00
|
|
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
setDebuggeeHandles(0, 0);
|
|
|
|
|
m_engine->killWatchTimer();
|
2009-06-15 16:30:52 +02:00
|
|
|
|
|
|
|
|
// Clean up resources (open files, etc.)
|
|
|
|
|
hr = m_cif.debugClient->EndSession(DEBUG_END_PASSIVE);
|
|
|
|
|
if (FAILED(hr))
|
|
|
|
|
errorMessage += msgComFailed("EndSession", hr);
|
|
|
|
|
|
2009-05-11 16:54:35 +02:00
|
|
|
if (!errorMessage.isEmpty()) {
|
|
|
|
|
errorMessage = QString::fromLatin1("There were errors trying to end debugging: %1").arg(errorMessage);
|
2009-06-19 12:47:23 +02:00
|
|
|
m_debuggerManagerAccess->showDebuggerOutput(LogError, errorMessage);
|
2009-05-25 16:22:11 +02:00
|
|
|
m_engine->warning(errorMessage);
|
2009-03-06 17:10:23 +01:00
|
|
|
}
|
2009-05-11 16:54:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CdbDebugEngine::exitDebugger()
|
|
|
|
|
{
|
|
|
|
|
m_d->endDebugging();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CdbDebugEngine::detachDebugger()
|
|
|
|
|
{
|
|
|
|
|
m_d->endDebugging(CdbDebugEnginePrivate::EndDebuggingDetach);
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-07-13 09:11:07 +02:00
|
|
|
CdbStackFrameContext *CdbDebugEnginePrivate::getStackFrameContext(int frameIndex, QString *errorMessage) const
|
|
|
|
|
{
|
|
|
|
|
if (!m_currentStackTrace) {
|
|
|
|
|
*errorMessage = QLatin1String(msgNoStackTraceC);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (CdbStackFrameContext *sg = m_currentStackTrace->frameContextAt(frameIndex, errorMessage))
|
|
|
|
|
return sg;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CdbDebugEngine::evaluateWatcher(WatchData *wd)
|
|
|
|
|
{
|
|
|
|
|
if (debugCDBWatchHandling)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << wd->exp;
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
QString value;
|
|
|
|
|
QString type;
|
|
|
|
|
if (evaluateExpression(wd->exp, &value, &type, &errorMessage)) {
|
|
|
|
|
wd->setValue(value);
|
|
|
|
|
wd->setType(type);
|
|
|
|
|
} else {
|
|
|
|
|
wd->setValue(errorMessage);
|
|
|
|
|
wd->setTypeUnneeded();
|
|
|
|
|
}
|
|
|
|
|
wd->setHasChildren(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CdbDebugEngine::updateWatchData(const WatchData &incomplete)
|
|
|
|
|
{
|
|
|
|
|
// Watch item was edited while running
|
|
|
|
|
if (m_d->isDebuggeeRunning())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (debugCDBWatchHandling)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << "\n " << incomplete.toString();
|
|
|
|
|
|
|
|
|
|
WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler();
|
|
|
|
|
if (incomplete.iname.startsWith(QLatin1String("watch."))) {
|
|
|
|
|
WatchData watchData = incomplete;
|
|
|
|
|
evaluateWatcher(&watchData);
|
|
|
|
|
watchHandler->insertData(watchData);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int frameIndex = m_d->m_debuggerManagerAccess->stackHandler()->currentIndex();
|
|
|
|
|
|
|
|
|
|
bool success = false;
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
do {
|
|
|
|
|
CdbStackFrameContext *sg = m_d->m_currentStackTrace->frameContextAt(frameIndex, &errorMessage);
|
|
|
|
|
if (!sg)
|
|
|
|
|
break;
|
|
|
|
|
if (!sg->completeData(incomplete, watchHandler, &errorMessage))
|
|
|
|
|
break;
|
|
|
|
|
success = true;
|
|
|
|
|
} while (false);
|
|
|
|
|
if (!success)
|
|
|
|
|
warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
|
|
|
|
|
}
|
|
|
|
|
|
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-04-08 16:37:41 +02:00
|
|
|
m_d->clearForRun();
|
2009-04-20 16:40:50 +02:00
|
|
|
const HRESULT hr = m_d->m_cif.debugControl->SetExecutionStatus(DEBUG_STATUS_STEP_INTO);
|
2009-05-20 14:20:38 +02:00
|
|
|
if (FAILED(hr))
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(msgFunctionFailed(Q_FUNC_INFO, msgComFailed("SetExecutionStatus", hr)));
|
2009-04-08 16:37:41 +02:00
|
|
|
|
|
|
|
|
m_d->m_breakEventMode = CdbDebugEnginePrivate::BreakEventIgnoreOnce;
|
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()) {
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(QString::fromLatin1("cannot step out"));
|
2009-02-09 11:35:43 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
// Set a temporary breakpoint and continue
|
2009-02-09 11:35:43 +01:00
|
|
|
const StackFrame& frame = stackframes.at(idx);
|
2009-04-08 16:37:41 +02:00
|
|
|
bool success = false;
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
do {
|
|
|
|
|
const ULONG64 address = frame.address.toULongLong(&success, 16);
|
|
|
|
|
if (!success) {
|
|
|
|
|
errorMessage = QLatin1String("Cannot obtain address from stack frame");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
IDebugBreakpoint2* pBP;
|
2009-04-20 16:40:50 +02:00
|
|
|
HRESULT hr = m_d->m_cif.debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &pBP);
|
2009-04-08 16:37:41 +02:00
|
|
|
if (FAILED(hr) || !pBP) {
|
|
|
|
|
errorMessage = QString::fromLatin1("Cannot create temporary breakpoint: %1").arg(msgDebugEngineComResult(hr));
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
pBP->SetOffset(address);
|
|
|
|
|
pBP->AddFlags(DEBUG_BREAKPOINT_ENABLED);
|
|
|
|
|
pBP->AddFlags(DEBUG_BREAKPOINT_ONE_SHOT);
|
|
|
|
|
if (!m_d->continueInferior(&errorMessage))
|
|
|
|
|
break;
|
|
|
|
|
success = true;
|
|
|
|
|
} while (false);
|
|
|
|
|
if (!success)
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
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-04-08 16:37:41 +02:00
|
|
|
m_d->clearForRun();
|
2009-04-20 16:40:50 +02:00
|
|
|
const HRESULT hr = m_d->m_cif.debugControl->SetExecutionStatus(DEBUG_STATUS_STEP_OVER);
|
2009-03-05 17:30:29 +01:00
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
|
startWatchTimer();
|
|
|
|
|
} else {
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(msgFunctionFailed(Q_FUNC_INFO, msgComFailed("SetExecutionStatus", hr)));
|
2009-03-05 17:30:29 +01:00
|
|
|
}
|
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-05-25 16:22:11 +02:00
|
|
|
warning(QString::fromLatin1("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-04-08 16:37:41 +02:00
|
|
|
m_d->clearForRun();
|
2009-04-20 16:40:50 +02:00
|
|
|
const HRESULT hr = m_d->m_cif.debugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, "p", 0);
|
2009-03-05 17:30:29 +01:00
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
|
startWatchTimer();
|
|
|
|
|
} else {
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(msgFunctionFailed(Q_FUNC_INFO, msgDebugEngineComResult(hr)));
|
2009-03-05 17:30:29 +01:00
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::continueInferior()
|
2009-04-08 16:37:41 +02:00
|
|
|
{
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
if (!m_d->continueInferior(&errorMessage))
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
|
2009-04-08 16:37:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Continue process without notifications
|
2009-04-22 17:28:26 +02:00
|
|
|
bool CdbDebugEnginePrivate::continueInferiorProcess(QString *errorMessagePtr /* = 0 */)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-02-23 14:46:46 +01:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
2009-04-20 16:40:50 +02:00
|
|
|
const HRESULT hr = m_cif.debugControl->SetExecutionStatus(DEBUG_STATUS_GO);
|
2009-04-08 16:37:41 +02:00
|
|
|
if (FAILED(hr)) {
|
2009-04-22 17:28:26 +02:00
|
|
|
const QString errorMessage = msgComFailed("SetExecutionStatus", hr);
|
|
|
|
|
if (errorMessagePtr) {
|
|
|
|
|
*errorMessagePtr = errorMessage;
|
|
|
|
|
} else {
|
2009-05-25 16:22:11 +02:00
|
|
|
m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
|
2009-04-22 17:28:26 +02:00
|
|
|
}
|
2009-04-08 16:37:41 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2009-02-23 14:46:46 +01:00
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
// Continue process with notifications
|
|
|
|
|
bool CdbDebugEnginePrivate::continueInferior(QString *errorMessage)
|
2009-04-15 10:05:40 +02:00
|
|
|
{
|
2009-02-09 11:35:43 +01:00
|
|
|
ULONG executionStatus;
|
2009-04-20 16:40:50 +02:00
|
|
|
if (!getExecutionStatus(m_cif.debugControl, &executionStatus, errorMessage))
|
2009-04-08 16:37:41 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << "\n ex=" << executionStatus;
|
|
|
|
|
|
|
|
|
|
if (executionStatus == DEBUG_STATUS_GO) {
|
2009-05-25 16:22:11 +02:00
|
|
|
m_engine->warning(QLatin1String("continueInferior() called while debuggee is running."));
|
2009-04-08 16:37:41 +02:00
|
|
|
return true;
|
2009-03-05 17:30:29 +01:00
|
|
|
}
|
2009-04-08 16:37:41 +02:00
|
|
|
|
|
|
|
|
clearForRun();
|
|
|
|
|
m_engine->killWatchTimer();
|
|
|
|
|
m_debuggerManager->resetLocation();
|
|
|
|
|
m_debuggerManagerAccess->notifyInferiorRunningRequested();
|
|
|
|
|
|
|
|
|
|
if (!continueInferiorProcess(errorMessage))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
m_engine->startWatchTimer();
|
|
|
|
|
m_debuggerManagerAccess->notifyInferiorRunning();
|
|
|
|
|
return true;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-04-08 16:37:41 +02:00
|
|
|
// Interrupt the interferior process without notifications
|
|
|
|
|
if (debugCDB) {
|
|
|
|
|
ULONG executionStatus;
|
2009-04-20 16:40:50 +02:00
|
|
|
getExecutionStatus(m_cif.debugControl, &executionStatus, errorMessage);
|
2009-04-08 16:37:41 +02:00
|
|
|
qDebug() << Q_FUNC_INFO << "\n ex=" << executionStatus;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!DebugBreakProcess(m_hDebuggeeProcess)) {
|
|
|
|
|
*errorMessage = QString::fromLatin1("DebugBreakProcess failed: %1").arg(Core::Utils::winErrorMessage(GetLastError()));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2009-04-15 10:05:40 +02:00
|
|
|
#if 0
|
2009-04-20 16:40:50 +02:00
|
|
|
const HRESULT hr = m_cif.debugControl->SetInterrupt(DEBUG_INTERRUPT_ACTIVE|DEBUG_INTERRUPT_EXIT);
|
2009-04-08 16:37:41 +02:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = QString::fromLatin1("Unable to interrupt debuggee after %1s: %2").
|
2009-04-20 16:40:50 +02:00
|
|
|
arg(getInterruptTimeOutSecs(m_cif.debugControl)).arg(msgComFailed("SetInterrupt", hr));
|
2009-04-08 16:37:41 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2009-02-23 14:46:46 +01:00
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
void CdbDebugEngine::interruptInferior()
|
|
|
|
|
{
|
|
|
|
|
if (!m_d->m_hDebuggeeProcess || !m_d->isDebuggeeRunning())
|
2009-02-09 11:35:43 +01:00
|
|
|
return;
|
2009-04-08 16:37:41 +02:00
|
|
|
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
if (m_d->interruptInterferiorProcess(&errorMessage)) {
|
2009-03-05 17:30:29 +01:00
|
|
|
m_d->m_debuggerManagerAccess->notifyInferiorStopped();
|
|
|
|
|
} else {
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
|
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-04-03 16:42:02 +02:00
|
|
|
const int frameIndex = m_d->m_debuggerManagerAccess->stackHandler()->currentIndex();
|
2009-04-15 10:05:40 +02:00
|
|
|
QString errorMessage;
|
2009-04-03 16:42:02 +02:00
|
|
|
bool success = false;
|
|
|
|
|
do {
|
|
|
|
|
QString newValue;
|
2009-07-13 09:11:07 +02:00
|
|
|
CdbStackFrameContext *sg = m_d->getStackFrameContext(frameIndex, &errorMessage);
|
|
|
|
|
if (!sg)
|
2009-04-03 16:42:02 +02:00
|
|
|
break;
|
2009-07-13 09:11:07 +02:00
|
|
|
if (!sg->assignValue(expr, value, &newValue, &errorMessage))
|
2009-07-10 14:36:28 +02:00
|
|
|
break;
|
2009-07-13 09:11:07 +02:00
|
|
|
// Update view
|
|
|
|
|
WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler();
|
|
|
|
|
if (WatchData *fwd = watchHandler->findItem(expr)) {
|
|
|
|
|
fwd->setValue(newValue);
|
|
|
|
|
watchHandler->insertData(*fwd);
|
|
|
|
|
watchHandler->updateWatchers();
|
|
|
|
|
}
|
2009-04-03 16:42:02 +02:00
|
|
|
success = true;
|
|
|
|
|
} while (false);
|
|
|
|
|
if (!success) {
|
|
|
|
|
const QString msg = tr("Unable to assign the value '%1' to '%2': %3").arg(value, expr, errorMessage);
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(msg);
|
2009-04-03 16:42:02 +02:00
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-23 14:46:46 +01:00
|
|
|
void CdbDebugEngine::executeDebuggerCommand(const QString &command)
|
2009-04-07 17:07:11 +02:00
|
|
|
{
|
|
|
|
|
QString errorMessage;
|
2009-04-20 16:40:50 +02:00
|
|
|
if (!CdbDebugEnginePrivate::executeDebuggerCommand(m_d->m_cif.debugControl, command, &errorMessage))
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(errorMessage);
|
2009-04-07 17:07:11 +02:00
|
|
|
}
|
|
|
|
|
|
2009-04-21 12:30:12 +02:00
|
|
|
bool CdbDebugEnginePrivate::executeDebuggerCommand(CIDebugControl *ctrl, const QString &command, QString *errorMessage)
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-04-20 16:40:50 +02:00
|
|
|
// output to all clients, else we do not see anything
|
2009-05-30 23:03:43 +09:00
|
|
|
const HRESULT hr = ctrl->ExecuteWide(DEBUG_OUTCTL_ALL_CLIENTS, reinterpret_cast<PCWSTR>(command.utf16()), 0);
|
2009-04-22 17:28:26 +02:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << "executeDebuggerCommand" << command << SUCCEEDED(hr);
|
2009-04-07 17:07:11 +02:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
*errorMessage = QString::fromLatin1("Unable to execute '%1': %2").
|
|
|
|
|
arg(command, msgDebugEngineComResult(hr));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CdbDebugEngine::evaluateExpression(const QString &expression,
|
|
|
|
|
QString *value,
|
|
|
|
|
QString *type,
|
|
|
|
|
QString *errorMessage)
|
2009-04-29 14:15:09 +02:00
|
|
|
{
|
|
|
|
|
DEBUG_VALUE debugValue;
|
|
|
|
|
if (!m_d->evaluateExpression(m_d->m_cif.debugControl, expression, &debugValue, errorMessage))
|
|
|
|
|
return false;
|
|
|
|
|
*value = CdbSymbolGroupContext::debugValueToString(debugValue, m_d->m_cif.debugControl, type);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CdbDebugEnginePrivate::evaluateExpression(CIDebugControl *ctrl,
|
|
|
|
|
const QString &expression,
|
|
|
|
|
DEBUG_VALUE *debugValue,
|
|
|
|
|
QString *errorMessage)
|
2009-04-07 17:07:11 +02:00
|
|
|
{
|
|
|
|
|
if (debugCDB > 1)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << expression;
|
2009-04-29 14:15:09 +02:00
|
|
|
|
|
|
|
|
memset(debugValue, 0, sizeof(DEBUG_VALUE));
|
2009-04-07 17:07:11 +02:00
|
|
|
// Original syntax must be restored, else setting breakpoints will fail.
|
2009-04-29 14:15:09 +02:00
|
|
|
SyntaxSetter syntaxSetter(ctrl, DEBUG_EXPR_CPLUSPLUS);
|
2009-04-07 17:07:11 +02:00
|
|
|
ULONG errorPosition = 0;
|
2009-05-30 23:03:43 +09:00
|
|
|
const HRESULT hr = ctrl->EvaluateWide(reinterpret_cast<PCWSTR>(expression.utf16()),
|
2009-04-29 14:15:09 +02:00
|
|
|
DEBUG_VALUE_INVALID, debugValue,
|
|
|
|
|
&errorPosition);
|
|
|
|
|
if (FAILED(hr)) {
|
2009-04-07 17:07:11 +02:00
|
|
|
if (HRESULT_CODE(hr) == 517) {
|
|
|
|
|
*errorMessage = QString::fromLatin1("Unable to evaluate '%1': Expression out of scope.").
|
|
|
|
|
arg(expression);
|
|
|
|
|
} else {
|
|
|
|
|
*errorMessage = QString::fromLatin1("Unable to evaluate '%1': Error at %2: %3").
|
|
|
|
|
arg(expression).arg(errorPosition).arg(msgDebugEngineComResult(hr));
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
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-07-13 09:11:07 +02: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-07-13 09:11:07 +02:00
|
|
|
if (oldIndex != frameIndex)
|
2009-03-06 17:10:23 +01:00
|
|
|
stackHandler->setCurrentIndex(frameIndex);
|
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-04-08 16:37:41 +02:00
|
|
|
// Clean out model
|
2009-07-13 09:11:07 +02:00
|
|
|
watchHandler->beginCycle();
|
|
|
|
|
watchHandler->endCycle();
|
2009-03-06 17:10:23 +01:00
|
|
|
errorMessage = QString::fromLatin1("%1: file %2 unusable.").
|
|
|
|
|
arg(QLatin1String(Q_FUNC_INFO), frame.file);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-04-08 16:37:41 +02:00
|
|
|
|
2009-02-23 14:46:46 +01:00
|
|
|
m_d->m_debuggerManager->gotoLocation(frame.file, frame.line, true);
|
2009-06-18 10:34:53 +02:00
|
|
|
|
|
|
|
|
if (oldIndex != frameIndex || m_d->m_firstActivatedFrame) {
|
2009-07-13 09:11:07 +02:00
|
|
|
watchHandler->beginCycle();
|
|
|
|
|
if (CdbStackFrameContext *sgc = m_d->getStackFrameContext(frameIndex, &errorMessage))
|
|
|
|
|
success = sgc->populateModelInitially(watchHandler, &errorMessage);
|
|
|
|
|
watchHandler->endCycle();
|
2009-06-18 10:34:53 +02:00
|
|
|
}
|
2009-03-06 17:10:23 +01:00
|
|
|
} while (false);
|
|
|
|
|
if (!success)
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(msgFunctionFailed(Q_FUNC_INFO, 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-07-24 16:05:46 +02:00
|
|
|
const int newThreadId = threadsHandler->threads().at(index).id;
|
|
|
|
|
if (newThreadId != m_d->m_currentThreadId) {
|
|
|
|
|
m_d->m_currentThreadId = threadsHandler->threads().at(index).id;
|
|
|
|
|
m_d->updateStackTrace();
|
|
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::attemptBreakpointSynchronization()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-06-30 15:50:56 +02:00
|
|
|
if (!m_d->m_hDebuggeeProcess) // Sometimes called from the breakpoint Window
|
|
|
|
|
return;
|
2009-04-08 16:37:41 +02:00
|
|
|
QString errorMessage;
|
|
|
|
|
if (!m_d->attemptBreakpointSynchronization(&errorMessage))
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
|
2009-04-08 16:37:41 +02:00
|
|
|
}
|
2009-02-23 14:46:46 +01:00
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessage)
|
|
|
|
|
{
|
|
|
|
|
if (!m_hDebuggeeProcess) {
|
|
|
|
|
*errorMessage = QLatin1String("attemptBreakpointSynchronization() called while debugger is not running");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// This is called from
|
|
|
|
|
// 1) CreateProcessEvent with the halted engine
|
|
|
|
|
// 2) from the break handler, potentially while the debuggee is running
|
|
|
|
|
// If the debuggee is running (for which the execution status is
|
|
|
|
|
// no reliable indicator), we temporarily halt and have ourselves
|
|
|
|
|
// called again from the debug event handler.
|
|
|
|
|
|
|
|
|
|
ULONG dummy;
|
2009-04-20 16:40:50 +02:00
|
|
|
const bool wasRunning = !CDBBreakPoint::getBreakPointCount(m_cif.debugControl, &dummy);
|
2009-04-08 16:37:41 +02:00
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << "\n Running=" << wasRunning;
|
|
|
|
|
|
|
|
|
|
if (wasRunning) {
|
|
|
|
|
const HandleBreakEventMode oldMode = m_breakEventMode;
|
|
|
|
|
m_breakEventMode = BreakEventSyncBreakPoints;
|
|
|
|
|
if (!interruptInterferiorProcess(errorMessage)) {
|
|
|
|
|
m_breakEventMode = oldMode;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2009-02-23 14:46:46 +01:00
|
|
|
}
|
|
|
|
|
|
2009-06-30 15:50:56 +02:00
|
|
|
QStringList warnings;
|
|
|
|
|
const bool ok = CDBBreakPoint::synchronizeBreakPoints(m_cif.debugControl,
|
2009-04-20 16:40:50 +02:00
|
|
|
m_cif.debugSymbols,
|
2009-04-08 16:37:41 +02:00
|
|
|
m_debuggerManagerAccess->breakHandler(),
|
2009-06-30 15:50:56 +02:00
|
|
|
errorMessage, &warnings);
|
2009-07-24 16:05:46 +02:00
|
|
|
if (const int warningsCount = warnings.size())
|
2009-06-30 15:50:56 +02:00
|
|
|
for (int w = 0; w < warningsCount; w++)
|
|
|
|
|
m_engine->warning(warnings.at(w));
|
|
|
|
|
return ok;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::reloadDisassembler()
|
2009-04-15 10:05:40 +02:00
|
|
|
{
|
2009-04-14 15:04:19 +02:00
|
|
|
enum { ContextLines = 40 };
|
|
|
|
|
// Do we have a top stack frame?
|
|
|
|
|
const ULONG64 offset = m_d->m_currentStackTrace ? m_d->m_currentStackTrace->instructionOffset() : ULONG64(0);
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << offset;
|
|
|
|
|
|
|
|
|
|
DisassemblerHandler *dh = m_d->m_debuggerManagerAccess->disassemblerHandler();
|
|
|
|
|
if (offset) {
|
|
|
|
|
QList<DisassemblerLine> lines;
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
2009-04-20 16:40:50 +02:00
|
|
|
const bool drc = dissassemble(m_d->m_cif.debugClient, m_d->m_cif.debugControl, offset,
|
2009-04-14 15:04:19 +02:00
|
|
|
ContextLines, ContextLines, &lines, &errorMessage);
|
|
|
|
|
QApplication::restoreOverrideCursor();
|
|
|
|
|
if (drc) {
|
|
|
|
|
dh->setLines(lines);
|
|
|
|
|
if (lines.size() > ContextLines)
|
|
|
|
|
dh->setCurrentLine(ContextLines);
|
|
|
|
|
} else {
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
|
2009-04-14 15:04:19 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
dh->setLines(QList<DisassemblerLine>());
|
|
|
|
|
}
|
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-04-15 12:04:27 +02:00
|
|
|
QList<Symbol> CdbDebugEngine::moduleSymbols(const QString &moduleName)
|
|
|
|
|
{
|
|
|
|
|
QList<Symbol> rc;
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
bool success = false;
|
|
|
|
|
do {
|
|
|
|
|
if (m_d->isDebuggeeRunning()) {
|
|
|
|
|
errorMessage = tr("Cannot retrieve symbols while the debuggee is running.");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-04-20 16:40:50 +02:00
|
|
|
if (!getModuleSymbols(m_d->m_cif.debugSymbols, moduleName, &rc, &errorMessage))
|
2009-04-15 12:04:27 +02:00
|
|
|
break;
|
|
|
|
|
success = true;
|
|
|
|
|
} while (false);
|
|
|
|
|
if (!success)
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(errorMessage);
|
2009-04-15 12:04:27 +02:00
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-09 16:51:13 +02:00
|
|
|
static inline int registerFormatBase()
|
|
|
|
|
{
|
|
|
|
|
switch(checkedRegisterFormatAction()) {
|
|
|
|
|
case FormatHexadecimal:
|
|
|
|
|
return 16;
|
|
|
|
|
case FormatDecimal:
|
|
|
|
|
return 10;
|
|
|
|
|
case FormatOctal:
|
|
|
|
|
return 8;
|
|
|
|
|
case FormatBinary:
|
|
|
|
|
return 2;
|
|
|
|
|
break;
|
|
|
|
|
case FormatRaw:
|
|
|
|
|
case FormatNatural:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return 10;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 13:07:38 +01:00
|
|
|
void CdbDebugEngine::reloadRegisters()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-04-09 16:51:13 +02:00
|
|
|
const int intBase = registerFormatBase();
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << intBase;
|
|
|
|
|
QList<Register> registers;
|
|
|
|
|
QString errorMessage;
|
2009-04-20 16:40:50 +02:00
|
|
|
if (!getRegisters(m_d->m_cif.debugControl, m_d->m_cif.debugRegisters, ®isters, &errorMessage, intBase))
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(msgFunctionFailed("reloadRegisters" , errorMessage));
|
2009-04-09 16:51:13 +02:00
|
|
|
m_d->m_debuggerManagerAccess->registerHandler()->setRegisters(registers);
|
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-04-21 12:30:12 +02:00
|
|
|
// Fetch away the debug events and notify if debuggee
|
|
|
|
|
// stops. Note that IDebugEventCallback does not
|
|
|
|
|
// cover all cases of a debuggee stopping execution
|
|
|
|
|
// (such as step over,etc).
|
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-04-20 16:40:50 +02:00
|
|
|
const HRESULT hr = m_d->m_cif.debugControl->WaitForEvent(0, 1);
|
2009-03-05 17:30:29 +01:00
|
|
|
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-04-15 10:05:40 +02: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;
|
2009-05-26 16:27:24 +02:00
|
|
|
if (startAttachDebugger(appPid, AttachExternal, &errorMessage)) {
|
2009-05-06 14:26:20 +02:00
|
|
|
startWatchTimer();
|
2009-03-17 16:54:35 +01:00
|
|
|
m_d->m_debuggerManagerAccess->notifyInferiorPidChanged(appPid);
|
2009-05-06 14:26:20 +02:00
|
|
|
m_d->m_debuggerManagerAccess->notifyInferiorRunning();
|
2009-03-17 16:54:35 +01:00
|
|
|
} 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-05-25 16:22:11 +02:00
|
|
|
void CdbDebugEngine::warning(const QString &w)
|
|
|
|
|
{
|
2009-06-19 12:47:23 +02:00
|
|
|
m_d->m_debuggerManagerAccess->showDebuggerOutput(LogWarning, w);
|
2009-05-25 16:22:11 +02:00
|
|
|
qWarning("%s\n", qPrintable(w));
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-05 09:52:24 +02:00
|
|
|
void CdbDebugEnginePrivate::notifyCrashed()
|
|
|
|
|
{
|
|
|
|
|
// Cannot go over crash point to execute calls.
|
|
|
|
|
m_dumper->disable();
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-24 16:05:46 +02:00
|
|
|
static int threadIndexById(const ThreadsHandler *threadsHandler, int id)
|
|
|
|
|
{
|
|
|
|
|
const QList<ThreadData> threads = threadsHandler->threads();
|
|
|
|
|
const int count = threads.count();
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
if (threads.at(i).id == id)
|
|
|
|
|
return i;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
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-05-06 14:26:20 +02:00
|
|
|
qDebug() << Q_FUNC_INFO << '\n' << m_hDebuggeeProcess << m_breakEventMode
|
|
|
|
|
<< executionStatusString(m_cif.debugControl);
|
2009-02-23 14:46:46 +01:00
|
|
|
|
2009-04-08 16:37:41 +02:00
|
|
|
// restore mode and do special handling
|
|
|
|
|
const HandleBreakEventMode mode = m_breakEventMode;
|
|
|
|
|
m_breakEventMode = BreakEventHandle;
|
|
|
|
|
|
|
|
|
|
switch (mode) {
|
2009-07-24 16:05:46 +02:00
|
|
|
case BreakEventHandle: {
|
2009-02-23 14:46:46 +01:00
|
|
|
m_debuggerManagerAccess->notifyInferiorStopped();
|
2009-07-24 16:05:46 +02:00
|
|
|
m_currentThreadId = updateThreadList();
|
|
|
|
|
ThreadsHandler *threadsHandler = m_debuggerManagerAccess->threadsHandler();
|
|
|
|
|
const int threadIndex = threadIndexById(threadsHandler, m_currentThreadId);
|
|
|
|
|
if (threadIndex != -1)
|
|
|
|
|
threadsHandler->setCurrentThread(threadIndex);
|
2009-05-25 16:22:11 +02:00
|
|
|
updateStackTrace();
|
2009-07-24 16:05:46 +02:00
|
|
|
}
|
2009-04-22 17:28:26 +02:00
|
|
|
break;
|
2009-04-08 16:37:41 +02:00
|
|
|
case BreakEventIgnoreOnce:
|
|
|
|
|
m_engine->startWatchTimer();
|
|
|
|
|
break;
|
|
|
|
|
case BreakEventSyncBreakPoints: {
|
|
|
|
|
// Temp stop to sync breakpoints
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
attemptBreakpointSynchronization(&errorMessage);
|
|
|
|
|
m_engine->startWatchTimer();
|
|
|
|
|
continueInferiorProcess(&errorMessage);
|
|
|
|
|
if (!errorMessage.isEmpty())
|
2009-05-25 16:22:11 +02:00
|
|
|
m_engine->warning(QString::fromLatin1("In handleDebugEvent: %1").arg(errorMessage));
|
2009-04-08 16:37:41 +02:00
|
|
|
}
|
|
|
|
|
break;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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-07-24 16:05:46 +02:00
|
|
|
ULONG 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;
|
2009-04-09 16:51:13 +02:00
|
|
|
bool success = false;
|
|
|
|
|
QString errorMessage;
|
2009-07-24 16:05:46 +02:00
|
|
|
ULONG currentThreadId = 0;
|
2009-04-09 16:51:13 +02:00
|
|
|
do {
|
2009-07-24 16:05:46 +02:00
|
|
|
ULONG threadCount;
|
|
|
|
|
HRESULT hr= m_cif.debugSystemObjects->GetNumberThreads(&threadCount);
|
2009-04-09 16:51:13 +02:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
errorMessage= msgComFailed("GetNumberThreads", hr);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-07-24 16:05:46 +02:00
|
|
|
// Get ids and index of current
|
|
|
|
|
if (threadCount) {
|
|
|
|
|
m_cif.debugSystemObjects->GetCurrentThreadId(¤tThreadId);
|
|
|
|
|
QVector<ULONG> threadIds(threadCount);
|
|
|
|
|
hr = m_cif.debugSystemObjects->GetThreadIdsByIndex(0, threadCount, &(*threadIds.begin()), 0);
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
errorMessage= msgComFailed("GetThreadIdsByIndex", hr);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
for (ULONG i = 0; i < threadCount; i++)
|
|
|
|
|
threads.push_back(ThreadData(threadIds.at(i)));
|
2009-04-09 16:51:13 +02:00
|
|
|
}
|
2009-02-09 11:35:43 +01:00
|
|
|
|
2009-04-09 16:51:13 +02:00
|
|
|
th->setThreads(threads);
|
|
|
|
|
success = true;
|
|
|
|
|
} while (false);
|
|
|
|
|
if (!success)
|
2009-05-25 16:22:11 +02:00
|
|
|
m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
|
2009-07-24 16:05:46 +02:00
|
|
|
return currentThreadId;
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
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
|
2009-04-08 16:37:41 +02:00
|
|
|
clearForRun();
|
2009-03-06 17:10:23 +01:00
|
|
|
QString errorMessage;
|
2009-04-09 16:51:13 +02:00
|
|
|
m_engine->reloadRegisters();
|
2009-03-26 16:49:28 +01:00
|
|
|
m_currentStackTrace =
|
2009-04-29 14:15:09 +02:00
|
|
|
CdbStackTraceContext::create(m_dumper, m_currentThreadId, &errorMessage);
|
2009-03-26 16:49:28 +01:00
|
|
|
if (!m_currentStackTrace) {
|
2009-05-25 16:22:11 +02:00
|
|
|
m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
|
2009-03-26 16:49:28 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2009-04-15 10:05:40 +02:00
|
|
|
// Disassembling slows things down a bit. Assembler is still available via menu.
|
|
|
|
|
#if 0
|
|
|
|
|
m_engine->reloadDisassembler(); // requires stack trace
|
|
|
|
|
#endif
|
2009-03-26 16:49:28 +01:00
|
|
|
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);
|
2009-04-03 16:42:02 +02:00
|
|
|
m_firstActivatedFrame = true;
|
2009-03-06 17:10:23 +01:00
|
|
|
if (current >= 0) {
|
|
|
|
|
m_debuggerManagerAccess->stackHandler()->setCurrentIndex(current);
|
2009-04-03 16:42:02 +02:00
|
|
|
m_engine->activateFrame(current);
|
2009-04-15 10:05:40 +02:00
|
|
|
}
|
2009-07-13 09:11:07 +02:00
|
|
|
m_debuggerManagerAccess->watchHandler()->updateWatchers();
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-04-09 16:51:13 +02:00
|
|
|
void CdbDebugEnginePrivate::updateModules()
|
2009-02-09 11:35:43 +01:00
|
|
|
{
|
2009-04-09 16:51:13 +02:00
|
|
|
QList<Module> modules;
|
|
|
|
|
QString errorMessage;
|
2009-04-20 16:40:50 +02:00
|
|
|
if (!getModuleList(m_cif.debugSymbols, &modules, &errorMessage))
|
2009-05-25 16:22:11 +02:00
|
|
|
m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
|
2009-04-09 16:51:13 +02:00
|
|
|
m_debuggerManagerAccess->modulesHandler()->setModules(modules);
|
2009-02-09 11:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2009-07-13 09:11:07 +02:00
|
|
|
static const char *dumperPrefixC = "dumper";
|
|
|
|
|
|
2009-04-20 16:40:50 +02:00
|
|
|
void CdbDebugEnginePrivate::handleModuleLoad(const QString &name)
|
|
|
|
|
{
|
|
|
|
|
if (debugCDB>2)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << "\n " << name;
|
2009-05-05 09:52:24 +02:00
|
|
|
m_dumper->moduleLoadHook(name, m_hDebuggeeProcess);
|
2009-04-20 16:40:50 +02:00
|
|
|
updateModules();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CdbDebugEnginePrivate::handleBreakpointEvent(PDEBUG_BREAKPOINT2 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
|
|
|
|
2009-05-08 16:56:48 +02:00
|
|
|
QStringList CdbDebugEnginePrivate::sourcePaths() const
|
|
|
|
|
{
|
|
|
|
|
WCHAR wszBuf[MAX_PATH];
|
|
|
|
|
if (SUCCEEDED(m_cif.debugSymbols->GetSourcePathWide(wszBuf, MAX_PATH, 0)))
|
2009-05-30 23:03:43 +09:00
|
|
|
return QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)).split(QLatin1Char(';'));
|
2009-05-08 16:56:48 +02:00
|
|
|
return QStringList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CdbDebugEngine::syncDebuggerPaths()
|
|
|
|
|
{
|
|
|
|
|
if (debugCDB)
|
|
|
|
|
qDebug() << Q_FUNC_INFO << m_d->m_options->symbolPaths << m_d->m_options->sourcePaths;
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
if (!m_d->setSourcePaths(m_d->m_options->sourcePaths, &errorMessage)
|
|
|
|
|
|| !m_d->setSymbolPaths(m_d->m_options->symbolPaths, &errorMessage)) {
|
|
|
|
|
errorMessage = QString::fromLatin1("Unable to set the debugger paths: %1").arg(errorMessage);
|
2009-05-25 16:22:11 +02:00
|
|
|
warning(errorMessage);
|
2009-05-08 16:56:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline QString pathString(const QStringList &s)
|
|
|
|
|
{ return s.join(QString(QLatin1Char(';'))); }
|
|
|
|
|
|
|
|
|
|
bool CdbDebugEnginePrivate::setSourcePaths(const QStringList &s, QString *errorMessage)
|
|
|
|
|
{
|
2009-05-30 23:03:43 +09:00
|
|
|
const HRESULT hr = m_cif.debugSymbols->SetSourcePathWide(reinterpret_cast<PCWSTR>(pathString(s).utf16()));
|
2009-05-08 16:56:48 +02:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
if (errorMessage)
|
|
|
|
|
*errorMessage = msgComFailed("SetSourcePathWide", hr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList CdbDebugEnginePrivate::symbolPaths() const
|
|
|
|
|
{
|
|
|
|
|
WCHAR wszBuf[MAX_PATH];
|
|
|
|
|
if (SUCCEEDED(m_cif.debugSymbols->GetSymbolPathWide(wszBuf, MAX_PATH, 0)))
|
2009-05-30 23:03:43 +09:00
|
|
|
return QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)).split(QLatin1Char(';'));
|
2009-05-08 16:56:48 +02:00
|
|
|
return QStringList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CdbDebugEnginePrivate::setSymbolPaths(const QStringList &s, QString *errorMessage)
|
|
|
|
|
{
|
2009-05-30 23:03:43 +09:00
|
|
|
const HRESULT hr = m_cif.debugSymbols->SetSymbolPathWide(reinterpret_cast<PCWSTR>(pathString(s).utf16()));
|
2009-05-08 16:56:48 +02:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
if (errorMessage)
|
|
|
|
|
*errorMessage = msgComFailed("SetSymbolPathWide", hr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 16:13:35 +01:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|
|
|
|
|
|
|
|
|
|
// Accessed by DebuggerManager
|
2009-04-17 09:03:32 +02:00
|
|
|
Debugger::Internal::IDebuggerEngine *createWinEngine(Debugger::Internal::DebuggerManager *parent,
|
2009-05-25 16:22:11 +02:00
|
|
|
bool cmdLineEnabled,
|
2009-04-17 09:03:32 +02:00
|
|
|
QList<Core::IOptionsPage*> *opts)
|
|
|
|
|
{
|
|
|
|
|
// Create options page
|
|
|
|
|
QSharedPointer<Debugger::Internal::CdbOptions> options(new Debugger::Internal::CdbOptions);
|
|
|
|
|
options->fromSettings(Core::ICore::instance()->settings());
|
|
|
|
|
Debugger::Internal::CdbOptionsPage *optionsPage = new Debugger::Internal::CdbOptionsPage(options);
|
|
|
|
|
opts->push_back(optionsPage);
|
2009-05-25 16:22:11 +02:00
|
|
|
if (!cmdLineEnabled || !options->enabled)
|
2009-04-17 09:03:32 +02:00
|
|
|
return 0;
|
|
|
|
|
// Create engine
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
Debugger::Internal::IDebuggerEngine *engine =
|
|
|
|
|
Debugger::Internal::CdbDebugEngine::create(parent, options, &errorMessage);
|
|
|
|
|
if (!engine) {
|
|
|
|
|
optionsPage->setFailureMessage(errorMessage);
|
2009-05-25 16:22:11 +02:00
|
|
|
qWarning("%s\n" ,qPrintable(errorMessage));
|
2009-04-17 09:03:32 +02:00
|
|
|
}
|
2009-05-08 16:56:48 +02:00
|
|
|
QObject::connect(optionsPage, SIGNAL(debuggerPathsChanged()), engine, SLOT(syncDebuggerPaths()));
|
2009-04-17 09:03:32 +02:00
|
|
|
return engine;
|
2009-02-23 16:13:35 +01:00
|
|
|
}
|