2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2010-04-23 12:12:22 +02:00
|
|
|
**
|
2015-01-14 18:07:15 +01:00
|
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
|
|
|
** Contact: http://www.qt.io/licensing
|
2010-04-23 12:12:22 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2010-04-23 12:12:22 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2015-01-14 18:07:15 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms and
|
|
|
|
|
** conditions see http://www.qt.io/terms-conditions. For further information
|
2014-10-01 13:21:18 +02:00
|
|
|
** use the contact form at http://www.qt.io/contact-us.
|
2010-04-23 12:12:22 +02:00
|
|
|
**
|
|
|
|
|
** GNU Lesser General Public License Usage
|
2012-10-02 09:12:39 +02:00
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
2014-10-01 13:21:18 +02:00
|
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
|
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
|
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
|
|
|
** following information to ensure the GNU Lesser General Public License
|
|
|
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
|
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2012-10-02 09:12:39 +02:00
|
|
|
**
|
2015-01-14 18:07:15 +01:00
|
|
|
** In addition, as a special exception, The Qt Company gives you certain additional
|
|
|
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2010-04-23 12:12:22 +02:00
|
|
|
|
|
|
|
|
#include "pdbengine.h"
|
2015-02-26 15:29:28 +01:00
|
|
|
#include "threaddata.h"
|
2010-04-23 12:12:22 +02:00
|
|
|
|
2013-08-29 16:36:42 +02:00
|
|
|
#include <debugger/debuggeractions.h>
|
|
|
|
|
#include <debugger/debuggercore.h>
|
|
|
|
|
#include <debugger/debuggerdialogs.h>
|
|
|
|
|
#include <debugger/debuggerplugin.h>
|
|
|
|
|
#include <debugger/debuggerprotocol.h>
|
|
|
|
|
#include <debugger/debuggerstartparameters.h>
|
|
|
|
|
#include <debugger/debuggerstringutils.h>
|
|
|
|
|
#include <debugger/debuggertooltipmanager.h>
|
2010-06-16 11:08:54 +02:00
|
|
|
|
2013-08-29 16:36:42 +02:00
|
|
|
#include <debugger/breakhandler.h>
|
|
|
|
|
#include <debugger/moduleshandler.h>
|
|
|
|
|
#include <debugger/registerhandler.h>
|
|
|
|
|
#include <debugger/stackhandler.h>
|
|
|
|
|
#include <debugger/sourceutils.h>
|
|
|
|
|
#include <debugger/watchhandler.h>
|
|
|
|
|
#include <debugger/watchutils.h>
|
2010-06-16 11:08:54 +02:00
|
|
|
|
2010-04-23 12:12:22 +02:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
|
2014-09-26 09:14:03 +02:00
|
|
|
#include <texteditor/texteditor.h>
|
2012-02-14 16:43:51 +01:00
|
|
|
#include <coreplugin/idocument.h>
|
2010-04-23 12:12:22 +02:00
|
|
|
#include <coreplugin/icore.h>
|
2014-11-25 13:08:18 +01:00
|
|
|
#include <coreplugin/messagebox.h>
|
2010-04-23 12:12:22 +02:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QDateTime>
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QTimer>
|
|
|
|
|
#include <QVariant>
|
2010-04-23 12:12:22 +02:00
|
|
|
|
2015-02-13 18:37:45 +01:00
|
|
|
using namespace Core;
|
2010-04-23 12:12:22 +02:00
|
|
|
|
|
|
|
|
namespace Debugger {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
PdbEngine::PdbEngine(const DebuggerStartParameters &startParameters)
|
2012-08-14 17:54:01 +02:00
|
|
|
: DebuggerEngine(startParameters)
|
2010-08-24 15:35:46 +02:00
|
|
|
{
|
|
|
|
|
setObjectName(QLatin1String("PdbEngine"));
|
|
|
|
|
}
|
2010-04-23 12:12:22 +02:00
|
|
|
|
2012-04-10 09:36:15 +02:00
|
|
|
void PdbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages languages)
|
2010-04-23 12:12:22 +02:00
|
|
|
{
|
2012-04-10 09:36:15 +02:00
|
|
|
if (!(languages & CppLanguage))
|
|
|
|
|
return;
|
2010-07-23 16:05:56 +02:00
|
|
|
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
|
|
|
|
|
//XSDEBUG("PdbEngine::executeDebuggerCommand:" << command);
|
2010-04-23 12:12:22 +02:00
|
|
|
if (state() == DebuggerNotReady) {
|
2010-06-14 18:19:02 +02:00
|
|
|
showMessage(_("PDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command);
|
2010-04-23 12:12:22 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2010-07-23 16:05:56 +02:00
|
|
|
QTC_ASSERT(m_pdbProc.state() == QProcess::Running, notifyEngineIll());
|
2015-02-13 18:37:45 +01:00
|
|
|
postDirectCommand(command.toLatin1());
|
2010-07-23 16:05:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::postDirectCommand(const QByteArray &command)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_pdbProc.state() == QProcess::Running, notifyEngineIll());
|
|
|
|
|
showMessage(_(command), LogInput);
|
2011-02-23 15:28:39 +01:00
|
|
|
m_pdbProc.write(command + '\n');
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:46:35 +01:00
|
|
|
void PdbEngine::runCommand(const DebuggerCommand &cmd)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_pdbProc.state() == QProcess::Running, notifyEngineIll());
|
2015-02-13 15:45:19 +01:00
|
|
|
QByteArray command = "qdebug('" + cmd.function + "',{" + cmd.args + "})";
|
2015-02-13 14:46:35 +01:00
|
|
|
showMessage(_(command), LogInput);
|
|
|
|
|
m_pdbProc.write(command + '\n');
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-09 17:07:59 +02:00
|
|
|
void PdbEngine::shutdownInferior()
|
2010-04-23 12:12:22 +02:00
|
|
|
{
|
2010-07-09 17:07:59 +02:00
|
|
|
QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
|
|
|
|
|
notifyInferiorShutdownOk();
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-09 17:07:59 +02:00
|
|
|
void PdbEngine::shutdownEngine()
|
2010-04-23 12:12:22 +02:00
|
|
|
{
|
2010-07-09 17:07:59 +02:00
|
|
|
QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
|
2010-04-23 12:12:22 +02:00
|
|
|
m_pdbProc.kill();
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-08 18:10:50 +02:00
|
|
|
void PdbEngine::setupEngine()
|
2010-04-23 12:12:22 +02:00
|
|
|
{
|
2010-07-09 17:07:59 +02:00
|
|
|
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
|
2010-04-23 12:12:22 +02:00
|
|
|
|
2010-07-23 16:05:56 +02:00
|
|
|
m_pdb = _("python");
|
2010-06-14 18:19:02 +02:00
|
|
|
showMessage(_("STARTING PDB ") + m_pdb);
|
2010-04-23 12:12:22 +02:00
|
|
|
|
2015-02-05 12:26:16 +01:00
|
|
|
connect(&m_pdbProc, static_cast<void(QProcess::*)(QProcess::ProcessError)>(&QProcess::error),
|
|
|
|
|
this, &PdbEngine::handlePdbError);
|
|
|
|
|
connect(&m_pdbProc, static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished),
|
|
|
|
|
this, &PdbEngine::handlePdbFinished);
|
|
|
|
|
connect(&m_pdbProc, &QProcess::readyReadStandardOutput,
|
|
|
|
|
this, &PdbEngine::readPdbStandardOutput);
|
|
|
|
|
connect(&m_pdbProc, &QProcess::readyReadStandardError,
|
|
|
|
|
this, &PdbEngine::readPdbStandardError);
|
|
|
|
|
|
2010-07-23 16:05:56 +02:00
|
|
|
m_pdbProc.start(m_pdb, QStringList() << _("-i"));
|
2010-04-23 12:12:22 +02:00
|
|
|
|
|
|
|
|
if (!m_pdbProc.waitForStarted()) {
|
2014-04-17 14:09:47 +02:00
|
|
|
const QString msg = tr("Unable to start pdb \"%1\": %2")
|
2010-04-23 12:12:22 +02:00
|
|
|
.arg(m_pdb, m_pdbProc.errorString());
|
2010-07-12 15:34:05 +02:00
|
|
|
notifyEngineSetupFailed();
|
2010-06-14 18:19:02 +02:00
|
|
|
showMessage(_("ADAPTER START FAILED"));
|
2015-02-13 18:37:45 +01:00
|
|
|
if (!msg.isEmpty())
|
|
|
|
|
ICore::showWarningWithOptions(tr("Adapter start failed"), msg);
|
2010-07-09 08:48:33 +02:00
|
|
|
notifyEngineSetupFailed();
|
2010-04-23 12:12:22 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2010-07-09 08:48:33 +02:00
|
|
|
notifyEngineSetupOk();
|
2010-07-08 18:10:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::setupInferior()
|
|
|
|
|
{
|
2010-07-09 17:07:59 +02:00
|
|
|
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
|
2010-04-23 12:12:22 +02:00
|
|
|
|
2015-02-13 09:18:27 +01:00
|
|
|
QString fileName = mainPythonFile();
|
2010-07-23 16:05:56 +02:00
|
|
|
QFile scriptFile(fileName);
|
|
|
|
|
if (!scriptFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
|
2015-02-13 18:37:45 +01:00
|
|
|
AsynchronousMessageBox::critical(tr("Python Error"),
|
2010-07-23 16:05:56 +02:00
|
|
|
_("Cannot open script file %1:\n%2").
|
|
|
|
|
arg(fileName, scriptFile.errorString()));
|
|
|
|
|
notifyInferiorSetupFailed();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
notifyInferiorSetupOk();
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-13 09:18:27 +01:00
|
|
|
QString PdbEngine::mainPythonFile() const
|
|
|
|
|
{
|
|
|
|
|
return QFileInfo(startParameters().processArgs).absoluteFilePath();
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-08 18:10:50 +02:00
|
|
|
void PdbEngine::runEngine()
|
2010-04-23 12:12:22 +02:00
|
|
|
{
|
2010-07-23 16:05:56 +02:00
|
|
|
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
|
2010-07-08 18:10:50 +02:00
|
|
|
showStatusMessage(tr("Running requested..."), 5000);
|
2015-02-13 18:37:45 +01:00
|
|
|
const QByteArray dumperSourcePath = ICore::resourcePath().toLocal8Bit() + "/debugger/";
|
2010-07-23 16:05:56 +02:00
|
|
|
postDirectCommand("import sys");
|
2015-02-13 09:18:27 +01:00
|
|
|
postDirectCommand("sys.argv.append('" + mainPythonFile().toLocal8Bit() + "')");
|
2010-07-23 16:05:56 +02:00
|
|
|
postDirectCommand("execfile('/usr/bin/pdb')");
|
2015-02-13 09:18:27 +01:00
|
|
|
postDirectCommand("execfile('" + dumperSourcePath + "pdbbridge.py')");
|
2010-07-23 16:05:56 +02:00
|
|
|
attemptBreakpointSynchronization();
|
|
|
|
|
notifyEngineRunAndInferiorStopOk();
|
|
|
|
|
continueInferior();
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::interruptInferior()
|
|
|
|
|
{
|
2010-07-12 15:34:05 +02:00
|
|
|
notifyInferiorStopOk();
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::executeStep()
|
|
|
|
|
{
|
2010-06-16 11:08:54 +02:00
|
|
|
resetLocation();
|
2010-07-12 15:34:05 +02:00
|
|
|
notifyInferiorRunRequested();
|
|
|
|
|
notifyInferiorRunOk();
|
2015-02-13 18:37:45 +01:00
|
|
|
postDirectCommand("step");
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::executeStepI()
|
|
|
|
|
{
|
2010-06-16 11:08:54 +02:00
|
|
|
resetLocation();
|
2010-07-12 15:34:05 +02:00
|
|
|
notifyInferiorRunRequested();
|
|
|
|
|
notifyInferiorRunOk();
|
2015-02-13 18:37:45 +01:00
|
|
|
postDirectCommand("step");
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::executeStepOut()
|
|
|
|
|
{
|
2010-06-16 11:08:54 +02:00
|
|
|
resetLocation();
|
2010-07-12 15:34:05 +02:00
|
|
|
notifyInferiorRunRequested();
|
|
|
|
|
notifyInferiorRunOk();
|
2015-02-13 19:14:00 +01:00
|
|
|
postDirectCommand("return");
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::executeNext()
|
|
|
|
|
{
|
2010-06-16 11:08:54 +02:00
|
|
|
resetLocation();
|
2010-07-12 15:34:05 +02:00
|
|
|
notifyInferiorRunRequested();
|
|
|
|
|
notifyInferiorRunOk();
|
2015-02-13 18:37:45 +01:00
|
|
|
postDirectCommand("next");
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::executeNextI()
|
|
|
|
|
{
|
2010-06-16 11:08:54 +02:00
|
|
|
resetLocation();
|
2010-07-12 15:34:05 +02:00
|
|
|
notifyInferiorRunRequested();
|
|
|
|
|
notifyInferiorRunOk();
|
2015-02-13 18:37:45 +01:00
|
|
|
postDirectCommand("next");
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::continueInferior()
|
|
|
|
|
{
|
2010-06-16 11:08:54 +02:00
|
|
|
resetLocation();
|
2010-07-12 15:34:05 +02:00
|
|
|
notifyInferiorRunRequested();
|
|
|
|
|
notifyInferiorRunOk();
|
2010-04-23 12:12:22 +02:00
|
|
|
// Callback will be triggered e.g. when breakpoint is hit.
|
2015-02-13 18:37:45 +01:00
|
|
|
postDirectCommand("continue");
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
2011-02-23 10:16:11 +01:00
|
|
|
void PdbEngine::executeRunToLine(const ContextData &data)
|
2010-04-23 12:12:22 +02:00
|
|
|
{
|
2011-02-23 10:16:11 +01:00
|
|
|
Q_UNUSED(data)
|
2015-02-13 18:37:45 +01:00
|
|
|
QTC_CHECK("FIXME: PdbEngine::runToLineExec()" && false);
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::executeRunToFunction(const QString &functionName)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(functionName)
|
2015-02-13 18:37:45 +01:00
|
|
|
QTC_CHECK("FIXME: PdbEngine::runToFunctionExec()" && false);
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
2011-02-23 10:16:11 +01:00
|
|
|
void PdbEngine::executeJumpToLine(const ContextData &data)
|
2010-04-23 12:12:22 +02:00
|
|
|
{
|
2011-02-23 10:16:11 +01:00
|
|
|
Q_UNUSED(data)
|
2015-02-13 18:37:45 +01:00
|
|
|
QTC_CHECK("FIXME: PdbEngine::jumpToLineExec()" && false);
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::activateFrame(int frameIndex)
|
|
|
|
|
{
|
2010-06-16 11:08:54 +02:00
|
|
|
resetLocation();
|
2010-07-09 17:07:59 +02:00
|
|
|
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
|
2010-04-23 12:12:22 +02:00
|
|
|
return;
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
StackHandler *handler = stackHandler();
|
|
|
|
|
int oldIndex = handler->currentIndex();
|
2010-04-23 12:12:22 +02:00
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
//if (frameIndex == handler->stackSize()) {
|
2010-04-23 12:12:22 +02:00
|
|
|
// reloadFullStack();
|
|
|
|
|
// return;
|
|
|
|
|
//}
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
QTC_ASSERT(frameIndex < handler->stackSize(), return);
|
2010-04-23 12:12:22 +02:00
|
|
|
|
|
|
|
|
if (oldIndex != frameIndex) {
|
|
|
|
|
// Assuming the command always succeeds this saves a roundtrip.
|
|
|
|
|
// Otherwise the lines below would need to get triggered
|
|
|
|
|
// after a response to this -stack-select-frame here.
|
2010-06-16 11:08:54 +02:00
|
|
|
handler->setCurrentIndex(frameIndex);
|
2015-02-13 18:37:45 +01:00
|
|
|
//postDirectCommand("-stack-select-frame " + QByteArray::number(frameIndex));
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
2010-12-16 19:06:33 +01:00
|
|
|
gotoLocation(handler->currentFrame());
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
2012-10-19 16:37:57 +02:00
|
|
|
void PdbEngine::selectThread(ThreadId threadId)
|
2010-04-23 12:12:22 +02:00
|
|
|
{
|
2012-10-19 16:37:57 +02:00
|
|
|
Q_UNUSED(threadId)
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-10 01:07:01 +01:00
|
|
|
bool PdbEngine::acceptsBreakpoint(Breakpoint bp) const
|
2010-11-25 14:33:13 +01:00
|
|
|
{
|
2015-01-10 01:07:01 +01:00
|
|
|
const QString fileName = bp.fileName();
|
2010-11-25 14:33:13 +01:00
|
|
|
return fileName.endsWith(QLatin1String(".py"));
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-10 01:07:01 +01:00
|
|
|
void PdbEngine::insertBreakpoint(Breakpoint bp)
|
2010-04-23 12:12:22 +02:00
|
|
|
{
|
2015-01-10 01:07:01 +01:00
|
|
|
QTC_CHECK(bp.state() == BreakpointInsertRequested);
|
|
|
|
|
bp.notifyBreakpointInsertProceeding();
|
2010-11-25 14:33:13 +01:00
|
|
|
|
|
|
|
|
QByteArray loc;
|
2015-01-10 01:07:01 +01:00
|
|
|
if (bp.type() == BreakpointByFunction)
|
|
|
|
|
loc = bp.functionName().toLatin1();
|
2010-11-25 14:33:13 +01:00
|
|
|
else
|
2015-01-10 01:07:01 +01:00
|
|
|
loc = bp.fileName().toLocal8Bit() + ':'
|
|
|
|
|
+ QByteArray::number(bp.lineNumber());
|
2010-11-25 14:33:13 +01:00
|
|
|
|
2015-02-13 18:37:45 +01:00
|
|
|
postDirectCommand("break " + loc);
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-10 01:07:01 +01:00
|
|
|
void PdbEngine::removeBreakpoint(Breakpoint bp)
|
2010-11-25 14:33:13 +01:00
|
|
|
{
|
2015-01-10 01:07:01 +01:00
|
|
|
QTC_CHECK(bp.state() == BreakpointRemoveRequested);
|
|
|
|
|
bp.notifyBreakpointRemoveProceeding();
|
|
|
|
|
BreakpointResponse br = bp.response();
|
|
|
|
|
showMessage(_("DELETING BP %1 IN %2").arg(br.id.toString()).arg(bp.fileName()));
|
2015-02-13 18:37:45 +01:00
|
|
|
postDirectCommand("clear " + br.id.toByteArray());
|
2010-11-25 14:33:13 +01:00
|
|
|
// Pretend it succeeds without waiting for response.
|
2015-01-10 01:07:01 +01:00
|
|
|
bp.notifyBreakpointRemoveOk();
|
2010-11-25 14:33:13 +01:00
|
|
|
}
|
|
|
|
|
|
2010-04-23 12:12:22 +02:00
|
|
|
void PdbEngine::loadSymbols(const QString &moduleName)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(moduleName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::loadAllSymbols()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::reloadModules()
|
|
|
|
|
{
|
2015-02-13 16:46:27 +01:00
|
|
|
runCommand("listModules");
|
2010-05-03 19:12:52 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-13 16:46:27 +01:00
|
|
|
void PdbEngine::refreshModules(const GdbMi &modules)
|
2010-05-03 19:12:52 +02:00
|
|
|
{
|
2015-01-13 22:42:30 +01:00
|
|
|
ModulesHandler *handler = modulesHandler();
|
|
|
|
|
handler->beginUpdateAll();
|
2015-02-13 16:46:27 +01:00
|
|
|
foreach (const GdbMi &item, modules.children()) {
|
2010-05-03 19:12:52 +02:00
|
|
|
Module module;
|
2013-05-03 18:26:10 +02:00
|
|
|
module.moduleName = _(item["name"].data());
|
|
|
|
|
QString path = _(item["value"].data());
|
2010-05-03 19:12:52 +02:00
|
|
|
int pos = path.indexOf(_("' from '"));
|
|
|
|
|
if (pos != -1) {
|
|
|
|
|
path = path.mid(pos + 8);
|
|
|
|
|
if (path.size() >= 2)
|
|
|
|
|
path.chop(2);
|
|
|
|
|
} else if (path.startsWith(_("<module '"))
|
|
|
|
|
&& path.endsWith(_("' (built-in)>"))) {
|
|
|
|
|
path = _("(builtin)");
|
|
|
|
|
}
|
|
|
|
|
module.modulePath = path;
|
2015-01-13 22:42:30 +01:00
|
|
|
handler->updateModule(module);
|
2010-05-03 19:12:52 +02:00
|
|
|
}
|
2015-01-13 22:42:30 +01:00
|
|
|
handler->endUpdateAll();
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
2010-05-03 19:12:52 +02:00
|
|
|
void PdbEngine::requestModuleSymbols(const QString &moduleName)
|
2010-04-23 12:12:22 +02:00
|
|
|
{
|
2015-02-13 18:37:45 +01:00
|
|
|
DebuggerCommand cmd("listSymbols");
|
|
|
|
|
cmd.arg("module", moduleName);
|
|
|
|
|
runCommand(cmd);
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-13 16:46:27 +01:00
|
|
|
void PdbEngine::refreshSymbols(const GdbMi &symbols)
|
2010-05-03 19:12:52 +02:00
|
|
|
{
|
2015-02-13 16:46:27 +01:00
|
|
|
QString moduleName = symbols["module"].toUtf8();
|
|
|
|
|
Symbols syms;
|
|
|
|
|
foreach (const GdbMi &item, symbols["symbols"].children()) {
|
2010-05-03 19:12:52 +02:00
|
|
|
Symbol symbol;
|
2015-02-13 16:46:27 +01:00
|
|
|
symbol.name = item["name"].toUtf8();
|
|
|
|
|
syms.append(symbol);
|
2010-05-03 19:12:52 +02:00
|
|
|
}
|
2015-02-13 16:46:27 +01:00
|
|
|
Internal::showModuleSymbols(moduleName, syms);
|
2010-05-03 19:12:52 +02:00
|
|
|
}
|
2010-04-23 12:12:22 +02:00
|
|
|
|
2015-02-13 15:28:56 +01:00
|
|
|
bool PdbEngine::setToolTipExpression(TextEditor::TextEditorWidget *,
|
2014-07-08 18:16:54 +02:00
|
|
|
const DebuggerToolTipContext &ctx)
|
2010-04-23 12:12:22 +02:00
|
|
|
{
|
2015-02-13 15:28:56 +01:00
|
|
|
if (state() != InferiorStopOk)
|
2011-02-17 10:08:57 +01:00
|
|
|
return false;
|
2010-04-23 12:12:22 +02:00
|
|
|
|
2015-02-13 15:28:56 +01:00
|
|
|
DebuggerCommand cmd("evaluateTooltip");
|
|
|
|
|
ctx.appendFormatRequest(&cmd);
|
2015-02-13 16:46:27 +01:00
|
|
|
watchHandler()->appendFormatRequests(&cmd);
|
2015-02-13 15:28:56 +01:00
|
|
|
runCommand(cmd);
|
|
|
|
|
return true;
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-13 17:18:16 +01:00
|
|
|
void PdbEngine::assignValueInDebugger(const WatchData *, const QString &expression, const QVariant &value)
|
|
|
|
|
{
|
|
|
|
|
//DebuggerCommand cmd("assignValue");
|
|
|
|
|
//cmd.arg("expression", expression);
|
|
|
|
|
//cmd.arg("value", value.toString());
|
|
|
|
|
//runCommand(cmd);
|
|
|
|
|
QByteArray exp = expression.toUtf8();
|
|
|
|
|
postDirectCommand("global " + exp + ';' + exp + "=" + value.toString().toUtf8());
|
2010-04-23 12:12:22 +02:00
|
|
|
updateLocals();
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-13 08:32:12 +02:00
|
|
|
void PdbEngine::updateWatchData(const WatchData &data, const WatchUpdateFlags &flags)
|
2010-04-23 12:12:22 +02:00
|
|
|
{
|
|
|
|
|
Q_UNUSED(data);
|
2010-09-13 10:26:56 +02:00
|
|
|
Q_UNUSED(flags);
|
2010-04-23 12:12:22 +02:00
|
|
|
updateAll();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::handlePdbError(QProcess::ProcessError error)
|
|
|
|
|
{
|
2010-07-23 16:05:56 +02:00
|
|
|
qDebug() << "HANDLE PDB ERROR";
|
2010-06-14 18:19:02 +02:00
|
|
|
showMessage(_("HANDLE PDB ERROR"));
|
2010-04-23 12:12:22 +02:00
|
|
|
switch (error) {
|
|
|
|
|
case QProcess::Crashed:
|
|
|
|
|
break; // will get a processExited() as well
|
|
|
|
|
// impossible case QProcess::FailedToStart:
|
|
|
|
|
case QProcess::ReadError:
|
|
|
|
|
case QProcess::WriteError:
|
|
|
|
|
case QProcess::Timedout:
|
|
|
|
|
default:
|
2010-07-12 15:34:05 +02:00
|
|
|
//setState(EngineShutdownRequested, true);
|
2010-04-23 12:12:22 +02:00
|
|
|
m_pdbProc.kill();
|
2015-02-13 18:37:45 +01:00
|
|
|
AsynchronousMessageBox::critical(tr("Pdb I/O Error"), errorMessage(error));
|
2010-04-23 12:12:22 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString PdbEngine::errorMessage(QProcess::ProcessError error) const
|
|
|
|
|
{
|
|
|
|
|
switch (error) {
|
|
|
|
|
case QProcess::FailedToStart:
|
|
|
|
|
return tr("The Pdb process failed to start. Either the "
|
2014-04-17 14:09:47 +02:00
|
|
|
"invoked program \"%1\" is missing, or you may have insufficient "
|
2010-04-23 12:12:22 +02:00
|
|
|
"permissions to invoke the program.")
|
|
|
|
|
.arg(m_pdb);
|
|
|
|
|
case QProcess::Crashed:
|
|
|
|
|
return tr("The Pdb process crashed some time after starting "
|
|
|
|
|
"successfully.");
|
|
|
|
|
case QProcess::Timedout:
|
|
|
|
|
return tr("The last waitFor...() function timed out. "
|
|
|
|
|
"The state of QProcess is unchanged, and you can try calling "
|
|
|
|
|
"waitFor...() again.");
|
|
|
|
|
case QProcess::WriteError:
|
|
|
|
|
return tr("An error occurred when attempting to write "
|
|
|
|
|
"to the Pdb process. For example, the process may not be running, "
|
|
|
|
|
"or it may have closed its input channel.");
|
|
|
|
|
case QProcess::ReadError:
|
|
|
|
|
return tr("An error occurred when attempting to read from "
|
|
|
|
|
"the Pdb process. For example, the process may not be running.");
|
|
|
|
|
default:
|
2013-10-17 14:52:10 +02:00
|
|
|
return tr("An unknown error in the Pdb process occurred.") + QLatin1Char(' ');
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::handlePdbFinished(int code, QProcess::ExitStatus type)
|
|
|
|
|
{
|
2010-07-23 16:05:56 +02:00
|
|
|
qDebug() << "PDB FINISHED";
|
2010-06-14 18:19:02 +02:00
|
|
|
showMessage(_("PDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
|
2010-07-12 15:34:05 +02:00
|
|
|
notifyEngineSpontaneousShutdown();
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::readPdbStandardError()
|
|
|
|
|
{
|
|
|
|
|
QByteArray err = m_pdbProc.readAllStandardError();
|
2010-07-23 16:05:56 +02:00
|
|
|
qDebug() << "\nPDB STDERR" << err;
|
|
|
|
|
//qWarning() << "Unexpected pdb stderr:" << err;
|
|
|
|
|
//showMessage(_("Unexpected pdb stderr: " + err));
|
|
|
|
|
//handleOutput(err);
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::readPdbStandardOutput()
|
|
|
|
|
{
|
2010-07-23 16:05:56 +02:00
|
|
|
QByteArray out = m_pdbProc.readAllStandardOutput();
|
|
|
|
|
qDebug() << "\nPDB STDOUT" << out;
|
|
|
|
|
handleOutput(out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::handleOutput(const QByteArray &data)
|
|
|
|
|
{
|
|
|
|
|
//qDebug() << "READ: " << data;
|
|
|
|
|
m_inbuffer.append(data);
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << "BUFFER FROM: '" << m_inbuffer << '\'';
|
2010-07-23 16:05:56 +02:00
|
|
|
while (true) {
|
|
|
|
|
int pos = m_inbuffer.indexOf("(Pdb)");
|
|
|
|
|
if (pos == -1)
|
|
|
|
|
pos = m_inbuffer.indexOf(">>>");
|
|
|
|
|
if (pos == -1)
|
|
|
|
|
break;
|
|
|
|
|
QByteArray response = m_inbuffer.left(pos).trimmed();
|
2010-04-23 12:12:22 +02:00
|
|
|
m_inbuffer = m_inbuffer.mid(pos + 6);
|
2015-02-13 18:37:45 +01:00
|
|
|
handleOutput2(response);
|
2010-07-23 16:05:56 +02:00
|
|
|
}
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << "BUFFER LEFT: '" << m_inbuffer << '\'';
|
2010-07-23 16:05:56 +02:00
|
|
|
//m_inbuffer.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::handleOutput2(const QByteArray &data)
|
|
|
|
|
{
|
2015-02-13 14:46:35 +01:00
|
|
|
QByteArray lineContext;
|
|
|
|
|
foreach (QByteArray line, data.split('\n')) {
|
|
|
|
|
|
2015-02-13 18:37:45 +01:00
|
|
|
GdbMi item;
|
|
|
|
|
item.fromString(line);
|
2015-02-13 16:46:27 +01:00
|
|
|
|
2015-02-13 14:46:35 +01:00
|
|
|
showMessage(_("LINE: " + line));
|
|
|
|
|
|
|
|
|
|
if (line.startsWith("stack={")) {
|
2015-02-13 18:37:45 +01:00
|
|
|
refreshStack(item);
|
2015-02-13 16:46:27 +01:00
|
|
|
} else if (line.startsWith("data={")) {
|
2015-02-13 18:37:45 +01:00
|
|
|
refreshLocals(item);
|
2015-02-13 16:46:27 +01:00
|
|
|
} else if (line.startsWith("modules=[")) {
|
2015-02-13 18:37:45 +01:00
|
|
|
refreshModules(item);
|
2015-02-13 16:46:27 +01:00
|
|
|
} else if (line.startsWith("symbols={")) {
|
2015-02-13 18:37:45 +01:00
|
|
|
refreshSymbols(item);
|
2015-02-13 16:46:27 +01:00
|
|
|
} else if (line.startsWith("Breakpoint")) {
|
2015-02-13 18:37:45 +01:00
|
|
|
int pos1 = line.indexOf(" at ");
|
|
|
|
|
QTC_ASSERT(pos1 != -1, continue);
|
|
|
|
|
QByteArray bpnr = line.mid(11, pos1 - 11);
|
|
|
|
|
int pos2 = line.lastIndexOf(':');
|
|
|
|
|
QTC_ASSERT(pos2 != -1, continue);
|
|
|
|
|
QByteArray fileName = line.mid(pos1 + 4, pos2 - pos1 - 4);
|
|
|
|
|
QByteArray lineNumber = line.mid(pos2 + 1);
|
|
|
|
|
BreakpointResponse br;
|
|
|
|
|
br.id = BreakpointResponseId(bpnr);
|
|
|
|
|
br.fileName = _(fileName);
|
|
|
|
|
br.lineNumber = lineNumber.toInt();
|
|
|
|
|
Breakpoint bp = breakHandler()->findBreakpointByFileAndLine(br.fileName, br.lineNumber, false);
|
|
|
|
|
if (bp.isValid()) {
|
|
|
|
|
bp.setResponse(br);
|
|
|
|
|
QTC_CHECK(!bp.needsChange());
|
|
|
|
|
bp.notifyBreakpointInsertOk();
|
|
|
|
|
}
|
2015-02-13 16:46:27 +01:00
|
|
|
} else {
|
|
|
|
|
if (line.startsWith("> /")) {
|
|
|
|
|
lineContext = line;
|
|
|
|
|
int pos1 = line.indexOf('(');
|
|
|
|
|
int pos2 = line.indexOf(')', pos1);
|
|
|
|
|
if (pos1 != -1 && pos2 != -1) {
|
|
|
|
|
int lineNumber = line.mid(pos1 + 1, pos2 - pos1 - 1).toInt();
|
|
|
|
|
QByteArray fileName = line.mid(2, pos1 - 2);
|
|
|
|
|
qDebug() << " " << pos1 << pos2 << lineNumber << fileName
|
|
|
|
|
<< line.mid(pos1 + 1, pos2 - pos1 - 1);
|
|
|
|
|
StackFrame frame;
|
|
|
|
|
frame.file = _(fileName);
|
|
|
|
|
frame.line = lineNumber;
|
|
|
|
|
if (state() == InferiorRunOk) {
|
|
|
|
|
showMessage(QString::fromLatin1("STOPPED AT: %1:%2").arg(frame.file).arg(frame.line));
|
|
|
|
|
gotoLocation(frame);
|
|
|
|
|
notifyInferiorSpontaneousStop();
|
|
|
|
|
updateAll();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-02-13 14:46:35 +01:00
|
|
|
}
|
|
|
|
|
}
|
2015-02-13 16:46:27 +01:00
|
|
|
showMessage(_(" #### ... UNHANDLED"));
|
2015-02-13 14:46:35 +01:00
|
|
|
}
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
}
|
2015-02-13 16:46:27 +01:00
|
|
|
|
2010-07-23 16:05:56 +02:00
|
|
|
/*
|
2010-04-23 12:12:22 +02:00
|
|
|
void PdbEngine::handleResponse(const QByteArray &response0)
|
|
|
|
|
{
|
|
|
|
|
QByteArray response = response0;
|
|
|
|
|
qDebug() << "RESPONSE: '" << response << "'";
|
|
|
|
|
if (response.startsWith("--Call--")) {
|
|
|
|
|
qDebug() << "SKIPPING '--Call--' MARKER";
|
|
|
|
|
response = response.mid(9);
|
|
|
|
|
}
|
|
|
|
|
if (response.startsWith("--Return--")) {
|
|
|
|
|
qDebug() << "SKIPPING '--Return--' MARKER";
|
|
|
|
|
response = response.mid(11);
|
|
|
|
|
}
|
2015-02-13 14:46:35 +01:00
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void PdbEngine::refreshLocals(const GdbMi &vars)
|
|
|
|
|
{
|
|
|
|
|
WatchHandler *handler = watchHandler();
|
|
|
|
|
handler->resetValueCache();
|
|
|
|
|
|
|
|
|
|
QSet<QByteArray> toDelete;
|
|
|
|
|
foreach (WatchItem *item, handler->model()->treeLevelItems<WatchItem *>(2))
|
|
|
|
|
toDelete.insert(item->d.iname);
|
|
|
|
|
|
|
|
|
|
foreach (const GdbMi &child, vars.children()) {
|
|
|
|
|
WatchItem *item = new WatchItem(child);
|
|
|
|
|
handler->insertItem(item);
|
|
|
|
|
toDelete.remove(item->d.iname);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handler->purgeOutdatedItems(toDelete);
|
|
|
|
|
|
|
|
|
|
DebuggerToolTipManager::updateEngine(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::refreshStack(const GdbMi &stack)
|
|
|
|
|
{
|
|
|
|
|
StackHandler *handler = stackHandler();
|
|
|
|
|
StackFrames frames;
|
|
|
|
|
foreach (const GdbMi &item, stack["frames"].children()) {
|
|
|
|
|
StackFrame frame;
|
|
|
|
|
frame.level = item["level"].toInt();
|
|
|
|
|
frame.file = item["file"].toUtf8();
|
|
|
|
|
frame.function = item["func"].toUtf8();
|
|
|
|
|
frame.from = item["func"].toUtf8();
|
|
|
|
|
frame.line = item["line"].toInt();
|
|
|
|
|
frame.address = item["addr"].toAddress();
|
|
|
|
|
GdbMi usable = item["usable"];
|
|
|
|
|
if (usable.isValid())
|
|
|
|
|
frame.usable = usable.data().toInt();
|
|
|
|
|
else
|
|
|
|
|
frame.usable = QFileInfo(frame.file).isReadable();
|
|
|
|
|
if (item["language"].data() == "js"
|
|
|
|
|
|| frame.file.endsWith(QLatin1String(".js"))
|
|
|
|
|
|| frame.file.endsWith(QLatin1String(".qml"))) {
|
|
|
|
|
frame.language = QmlLanguage;
|
|
|
|
|
frame.fixQmlFrame(startParameters());
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
2015-02-13 14:46:35 +01:00
|
|
|
frames.append(frame);
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
2015-02-13 14:46:35 +01:00
|
|
|
bool canExpand = stack["hasmore"].toInt();
|
|
|
|
|
//action(ExpandStack)->setEnabled(canExpand);
|
|
|
|
|
handler->setFrames(frames, canExpand);
|
|
|
|
|
|
|
|
|
|
int index = stackHandler()->firstUsableIndex();
|
|
|
|
|
handler->setCurrentIndex(index);
|
|
|
|
|
if (index >= 0 && index < handler->stackSize())
|
|
|
|
|
gotoLocation(handler->frameAt(index));
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::updateAll()
|
2010-07-23 16:05:56 +02:00
|
|
|
{
|
2015-02-13 18:37:45 +01:00
|
|
|
runCommand("stackListFrames");
|
2015-02-13 14:46:35 +01:00
|
|
|
updateLocals();
|
2010-07-23 16:05:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbEngine::updateLocals()
|
2010-04-23 12:12:22 +02:00
|
|
|
{
|
2015-02-13 14:46:35 +01:00
|
|
|
DebuggerCommand cmd("updateData");
|
|
|
|
|
cmd.arg("nativeMixed", isNativeMixedActive());
|
|
|
|
|
watchHandler()->appendFormatRequests(&cmd);
|
2010-04-23 12:12:22 +02:00
|
|
|
|
2015-02-13 14:46:35 +01:00
|
|
|
const static bool alwaysVerbose = !qgetenv("QTC_DEBUGGER_PYTHON_VERBOSE").isEmpty();
|
|
|
|
|
cmd.arg("passexceptions", alwaysVerbose);
|
|
|
|
|
cmd.arg("fancy", boolSetting(UseDebuggingHelpers));
|
|
|
|
|
|
|
|
|
|
cmd.beginList("watchers");
|
|
|
|
|
|
|
|
|
|
// Watchers
|
|
|
|
|
QHashIterator<QByteArray, int> it(WatchHandler::watcherNames());
|
2010-04-23 12:12:22 +02:00
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
2015-02-13 14:46:35 +01:00
|
|
|
cmd.beginGroup();
|
|
|
|
|
cmd.arg("iname", "watch." + QByteArray::number(it.value()));
|
|
|
|
|
cmd.arg("exp", it.key().toHex());
|
|
|
|
|
cmd.endGroup();
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:46:35 +01:00
|
|
|
// Tooltips
|
|
|
|
|
DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(this);
|
|
|
|
|
foreach (const DebuggerToolTipContext &p, toolTips) {
|
|
|
|
|
cmd.beginGroup();
|
|
|
|
|
cmd.arg("iname", p.iname);
|
|
|
|
|
cmd.arg("exp", p.expression.toLatin1().toHex());
|
|
|
|
|
cmd.endGroup();
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
2010-07-23 16:05:56 +02:00
|
|
|
|
2015-02-13 14:46:35 +01:00
|
|
|
cmd.endList();
|
|
|
|
|
|
|
|
|
|
//cmd.arg("resultvarname", m_resultVarName);
|
|
|
|
|
//m_lastDebuggableCommand = cmd;
|
|
|
|
|
//m_lastDebuggableCommand.args.replace("\"passexceptions\":0", "\"passexceptions\":1");
|
|
|
|
|
|
|
|
|
|
runCommand(cmd);
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
2012-01-12 20:28:17 +01:00
|
|
|
bool PdbEngine::hasCapability(unsigned cap) const
|
2010-05-03 19:12:52 +02:00
|
|
|
{
|
2015-02-13 16:46:27 +01:00
|
|
|
return cap & (ReloadModuleCapability
|
|
|
|
|
| BreakConditionCapability
|
|
|
|
|
| ShowModuleSymbolsCapability);
|
2010-05-03 19:12:52 +02:00
|
|
|
}
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
DebuggerEngine *createPdbEngine(const DebuggerStartParameters &startParameters)
|
2010-04-23 12:12:22 +02:00
|
|
|
{
|
2010-06-16 11:08:54 +02:00
|
|
|
return new PdbEngine(startParameters);
|
2010-04-23 12:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|