Commit aa4485af authored by hjk's avatar hjk

Debugger: Rework Python Debugger

The (re-)enables basic stepping, data display, frame selection etc
for Python 2 and 3. Arguments passing, jump to line etc.
don't work yet.

Change-Id: I8af03e5905092360eb268ba3081a1236b1f8577f
Reviewed-by: default avatarChristian Stenger <christian.stenger@theqtcompany.com>
parent 9c27b9fd
This diff is collapsed.
...@@ -110,6 +110,10 @@ public: ...@@ -110,6 +110,10 @@ public:
QString projectSourceDirectory; QString projectSourceDirectory;
QStringList projectSourceFiles; QStringList projectSourceFiles;
// Used by Script debugging
QString interpreter;
QString mainScript;
// Used by AttachCrashedExternal. // Used by AttachCrashedExternal.
QString crashParameter; QString crashParameter;
......
...@@ -147,7 +147,8 @@ void DebuggerRunControl::start() ...@@ -147,7 +147,8 @@ void DebuggerRunControl::start()
QTC_ASSERT(m_engine, return); QTC_ASSERT(m_engine, return);
// User canceled input dialog asking for executable when working on library project. // User canceled input dialog asking for executable when working on library project.
if (m_engine->runParameters().startMode == StartInternal if (m_engine->runParameters().startMode == StartInternal
&& m_engine->runParameters().executable.isEmpty()) { && m_engine->runParameters().executable.isEmpty()
&& m_engine->runParameters().interpreter.isEmpty()) {
appendMessage(tr("No executable specified.") + QLatin1Char('\n'), ErrorMessageFormat); appendMessage(tr("No executable specified.") + QLatin1Char('\n'), ErrorMessageFormat);
emit started(); emit started();
emit finished(); emit finished();
...@@ -438,6 +439,22 @@ void DebuggerRunControlCreator::enrich(const RunConfiguration *runConfig, const ...@@ -438,6 +439,22 @@ void DebuggerRunControlCreator::enrich(const RunConfiguration *runConfig, const
if (m_runConfig) if (m_runConfig)
m_debuggerAspect = m_runConfig->extraAspect<DebuggerRunConfigurationAspect>(); m_debuggerAspect = m_runConfig->extraAspect<DebuggerRunConfigurationAspect>();
if (m_rp.displayName.isEmpty() && m_runConfig)
m_rp.displayName = m_runConfig->displayName();
if (runConfig->property("supportsDebugger").toBool()) {
QString mainScript = runConfig->property("mainScript").toString();
QString interpreter = runConfig->property("interpreter").toString();
if (!interpreter.isEmpty() && mainScript.endsWith(_(".py"))) {
m_rp.mainScript = mainScript;
m_rp.interpreter = interpreter;
QString args = runConfig->property("arguments").toString();
if (!args.isEmpty())
QtcProcess::addArg(&m_rp.processArgs, args);
m_rp.masterEngineType = PdbEngineType;
}
}
if (m_debuggerAspect) { if (m_debuggerAspect) {
m_rp.multiProcess = m_debuggerAspect->useMultiProcess(); m_rp.multiProcess = m_debuggerAspect->useMultiProcess();
...@@ -469,17 +486,6 @@ void DebuggerRunControlCreator::enrich(const RunConfiguration *runConfig, const ...@@ -469,17 +486,6 @@ void DebuggerRunControlCreator::enrich(const RunConfiguration *runConfig, const
} }
} }
if (m_rp.displayName.isEmpty() && m_runConfig)
m_rp.displayName = m_runConfig->displayName();
if (m_rp.masterEngineType == NoEngineType) {
if (m_rp.executable.endsWith(_(".py"))
|| m_rp.executable == _("/usr/bin/python")
|| m_rp.executable == _("/usr/bin/python3")) {
m_rp.masterEngineType = PdbEngineType;
}
}
if (!boolSetting(AutoEnrichParameters)) { if (!boolSetting(AutoEnrichParameters)) {
const QString sysroot = m_rp.sysRoot; const QString sysroot = m_rp.sysRoot;
if (m_rp.debugInfoLocation.isEmpty()) if (m_rp.debugInfoLocation.isEmpty())
...@@ -566,6 +572,12 @@ void DebuggerRunControlCreator::createRunControl(Core::Id runMode) ...@@ -566,6 +572,12 @@ void DebuggerRunControlCreator::createRunControl(Core::Id runMode)
// //
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
static bool isDebuggableScript(RunConfiguration *runConfig)
{
QString mainScript = runConfig->property("mainScript").toString();
return mainScript.endsWith(_(".py")); // Only Python for now.
}
class DebuggerRunControlFactory : public IRunControlFactory class DebuggerRunControlFactory : public IRunControlFactory
{ {
public: public:
...@@ -592,7 +604,8 @@ public: ...@@ -592,7 +604,8 @@ public:
bool canRun(RunConfiguration *runConfig, Core::Id mode) const override bool canRun(RunConfiguration *runConfig, Core::Id mode) const override
{ {
return (mode == DebugRunMode || mode == DebugRunModeWithBreakOnMain) return (mode == DebugRunMode || mode == DebugRunModeWithBreakOnMain)
&& qobject_cast<LocalApplicationRunConfiguration *>(runConfig); && (qobject_cast<LocalApplicationRunConfiguration *>(runConfig)
|| isDebuggableScript(runConfig));
} }
IRunConfigurationAspect *createRunConfigurationAspect(RunConfiguration *rc) override IRunConfigurationAspect *createRunConfigurationAspect(RunConfiguration *rc) override
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include <debugger/watchutils.h> #include <debugger/watchutils.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <coreplugin/idocument.h> #include <coreplugin/idocument.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
...@@ -77,7 +78,6 @@ void PdbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages ...@@ -77,7 +78,6 @@ void PdbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages
if (!(languages & CppLanguage)) if (!(languages & CppLanguage))
return; return;
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state()); QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
//XSDEBUG("PdbEngine::executeDebuggerCommand:" << command);
if (state() == DebuggerNotReady) { if (state() == DebuggerNotReady) {
showMessage(_("PDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command); showMessage(_("PDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command);
return; return;
...@@ -117,8 +117,8 @@ void PdbEngine::setupEngine() ...@@ -117,8 +117,8 @@ void PdbEngine::setupEngine()
{ {
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
QString python = pythonInterpreter(); m_interpreter = runParameters().interpreter;
showMessage(_("STARTING PDB ") + python); QString bridge = ICore::resourcePath() + QLatin1String("/debugger/pdbbridge.py");
connect(&m_proc, static_cast<void(QProcess::*)(QProcess::ProcessError)>(&QProcess::error), connect(&m_proc, static_cast<void(QProcess::*)(QProcess::ProcessError)>(&QProcess::error),
this, &PdbEngine::handlePdbError); this, &PdbEngine::handlePdbError);
...@@ -129,11 +129,22 @@ void PdbEngine::setupEngine() ...@@ -129,11 +129,22 @@ void PdbEngine::setupEngine()
connect(&m_proc, &QProcess::readyReadStandardError, connect(&m_proc, &QProcess::readyReadStandardError,
this, &PdbEngine::readPdbStandardError); this, &PdbEngine::readPdbStandardError);
m_proc.start(python, QStringList() << _("-i")); QFile scriptFile(runParameters().mainScript);
if (!scriptFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
AsynchronousMessageBox::critical(tr("Python Error"),
_("Cannot open script file %1:\n%2").
arg(scriptFile.fileName(), scriptFile.errorString()));
notifyEngineSetupFailed();
}
QStringList args = { bridge, scriptFile.fileName() };
args.append(Utils::QtcProcess::splitArgs(runParameters().processArgs));
showMessage(_("STARTING ") + m_interpreter + QLatin1Char(' ') + args.join(QLatin1Char(' ')));
m_proc.start(m_interpreter, args);
if (!m_proc.waitForStarted()) { if (!m_proc.waitForStarted()) {
const QString msg = tr("Unable to start pdb \"%1\": %2") const QString msg = tr("Unable to start pdb \"%1\": %2")
.arg(pythonInterpreter(), m_proc.errorString()); .arg(m_interpreter, m_proc.errorString());
notifyEngineSetupFailed(); notifyEngineSetupFailed();
showMessage(_("ADAPTER START FAILED")); showMessage(_("ADAPTER START FAILED"));
if (!msg.isEmpty()) if (!msg.isEmpty())
...@@ -148,43 +159,19 @@ void PdbEngine::setupInferior() ...@@ -148,43 +159,19 @@ void PdbEngine::setupInferior()
{ {
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
QString fileName = mainPythonFile();
QFile scriptFile(fileName);
if (!scriptFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
AsynchronousMessageBox::critical(tr("Python Error"),
_("Cannot open script file %1:\n%2").
arg(fileName, scriptFile.errorString()));
notifyInferiorSetupFailed();
return;
}
notifyInferiorSetupOk(); notifyInferiorSetupOk();
} }
QString PdbEngine::mainPythonFile() const
{
return QFileInfo(runParameters().processArgs).absoluteFilePath();
}
QString PdbEngine::pythonInterpreter() const
{
return runParameters().executable;
}
void PdbEngine::runEngine() void PdbEngine::runEngine()
{ {
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
showStatusMessage(tr("Running requested..."), 5000); showStatusMessage(tr("Running requested..."), 5000);
QByteArray bridge = ICore::resourcePath().toUtf8() + "/debugger/pdbbridge.py";
QByteArray pdb = "/usr/bin/pdb";
if (pythonInterpreter().endsWith(QLatin1Char('3')))
pdb += '3';
postDirectCommand("import sys");
postDirectCommand("sys.argv.append('" + mainPythonFile().toLocal8Bit() + "')");
postDirectCommand("exec(open('" + pdb + "').read())");
postDirectCommand("exec(open('" + bridge + "').read())");
attemptBreakpointSynchronization(); attemptBreakpointSynchronization();
notifyEngineRunAndInferiorStopOk(); notifyEngineRunAndInferiorStopOk();
continueInferior(); if (runParameters().breakOnMain)
updateAll();
else
continueInferior();
} }
void PdbEngine::interruptInferior() void PdbEngine::interruptInferior()
...@@ -198,6 +185,7 @@ void PdbEngine::executeStep() ...@@ -198,6 +185,7 @@ void PdbEngine::executeStep()
notifyInferiorRunRequested(); notifyInferiorRunRequested();
notifyInferiorRunOk(); notifyInferiorRunOk();
postDirectCommand("step"); postDirectCommand("step");
updateAll();
} }
void PdbEngine::executeStepI() void PdbEngine::executeStepI()
...@@ -206,6 +194,7 @@ void PdbEngine::executeStepI() ...@@ -206,6 +194,7 @@ void PdbEngine::executeStepI()
notifyInferiorRunRequested(); notifyInferiorRunRequested();
notifyInferiorRunOk(); notifyInferiorRunOk();
postDirectCommand("step"); postDirectCommand("step");
updateAll();
} }
void PdbEngine::executeStepOut() void PdbEngine::executeStepOut()
...@@ -214,6 +203,7 @@ void PdbEngine::executeStepOut() ...@@ -214,6 +203,7 @@ void PdbEngine::executeStepOut()
notifyInferiorRunRequested(); notifyInferiorRunRequested();
notifyInferiorRunOk(); notifyInferiorRunOk();
postDirectCommand("return"); postDirectCommand("return");
updateAll();
} }
void PdbEngine::executeNext() void PdbEngine::executeNext()
...@@ -222,6 +212,7 @@ void PdbEngine::executeNext() ...@@ -222,6 +212,7 @@ void PdbEngine::executeNext()
notifyInferiorRunRequested(); notifyInferiorRunRequested();
notifyInferiorRunOk(); notifyInferiorRunOk();
postDirectCommand("next"); postDirectCommand("next");
updateAll();
} }
void PdbEngine::executeNextI() void PdbEngine::executeNextI()
...@@ -230,6 +221,7 @@ void PdbEngine::executeNextI() ...@@ -230,6 +221,7 @@ void PdbEngine::executeNextI()
notifyInferiorRunRequested(); notifyInferiorRunRequested();
notifyInferiorRunOk(); notifyInferiorRunOk();
postDirectCommand("next"); postDirectCommand("next");
updateAll();
} }
void PdbEngine::continueInferior() void PdbEngine::continueInferior()
...@@ -239,6 +231,7 @@ void PdbEngine::continueInferior() ...@@ -239,6 +231,7 @@ void PdbEngine::continueInferior()
notifyInferiorRunOk(); notifyInferiorRunOk();
// Callback will be triggered e.g. when breakpoint is hit. // Callback will be triggered e.g. when breakpoint is hit.
postDirectCommand("continue"); postDirectCommand("continue");
updateAll();
} }
void PdbEngine::executeRunToLine(const ContextData &data) void PdbEngine::executeRunToLine(const ContextData &data)
...@@ -261,28 +254,14 @@ void PdbEngine::executeJumpToLine(const ContextData &data) ...@@ -261,28 +254,14 @@ void PdbEngine::executeJumpToLine(const ContextData &data)
void PdbEngine::activateFrame(int frameIndex) void PdbEngine::activateFrame(int frameIndex)
{ {
resetLocation();
if (state() != InferiorStopOk && state() != InferiorUnrunnable) if (state() != InferiorStopOk && state() != InferiorUnrunnable)
return; return;
StackHandler *handler = stackHandler(); StackHandler *handler = stackHandler();
int oldIndex = handler->currentIndex();
//if (frameIndex == handler->stackSize()) {
// reloadFullStack();
// return;
//}
QTC_ASSERT(frameIndex < handler->stackSize(), return); QTC_ASSERT(frameIndex < handler->stackSize(), return);
handler->setCurrentIndex(frameIndex);
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.
handler->setCurrentIndex(frameIndex);
//postDirectCommand("-stack-select-frame " + QByteArray::number(frameIndex));
}
gotoLocation(handler->currentFrame()); gotoLocation(handler->currentFrame());
updateLocals();
} }
void PdbEngine::selectThread(ThreadId threadId) void PdbEngine::selectThread(ThreadId threadId)
...@@ -402,7 +381,6 @@ void PdbEngine::updateItem(const QByteArray &iname) ...@@ -402,7 +381,6 @@ void PdbEngine::updateItem(const QByteArray &iname)
void PdbEngine::handlePdbError(QProcess::ProcessError error) void PdbEngine::handlePdbError(QProcess::ProcessError error)
{ {
qDebug() << "HANDLE PDB ERROR";
showMessage(_("HANDLE PDB ERROR")); showMessage(_("HANDLE PDB ERROR"));
switch (error) { switch (error) {
case QProcess::Crashed: case QProcess::Crashed:
...@@ -426,7 +404,7 @@ QString PdbEngine::errorMessage(QProcess::ProcessError error) const ...@@ -426,7 +404,7 @@ QString PdbEngine::errorMessage(QProcess::ProcessError error) const
return tr("The Pdb process failed to start. Either the " return tr("The Pdb process failed to start. Either the "
"invoked program \"%1\" is missing, or you may have insufficient " "invoked program \"%1\" is missing, or you may have insufficient "
"permissions to invoke the program.") "permissions to invoke the program.")
.arg(pythonInterpreter()); .arg(m_interpreter);
case QProcess::Crashed: case QProcess::Crashed:
return tr("The Pdb process crashed some time after starting " return tr("The Pdb process crashed some time after starting "
"successfully."); "successfully.");
...@@ -448,7 +426,6 @@ QString PdbEngine::errorMessage(QProcess::ProcessError error) const ...@@ -448,7 +426,6 @@ QString PdbEngine::errorMessage(QProcess::ProcessError error) const
void PdbEngine::handlePdbFinished(int code, QProcess::ExitStatus type) void PdbEngine::handlePdbFinished(int code, QProcess::ExitStatus type)
{ {
qDebug() << "PDB FINISHED";
showMessage(_("PDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code)); showMessage(_("PDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
notifyEngineSpontaneousShutdown(); notifyEngineSpontaneousShutdown();
} }
...@@ -456,24 +433,20 @@ void PdbEngine::handlePdbFinished(int code, QProcess::ExitStatus type) ...@@ -456,24 +433,20 @@ void PdbEngine::handlePdbFinished(int code, QProcess::ExitStatus type)
void PdbEngine::readPdbStandardError() void PdbEngine::readPdbStandardError()
{ {
QByteArray err = m_proc.readAllStandardError(); QByteArray err = m_proc.readAllStandardError();
qDebug() << "\nPDB STDERR" << err;
//qWarning() << "Unexpected pdb stderr:" << err; //qWarning() << "Unexpected pdb stderr:" << err;
//showMessage(_("Unexpected pdb stderr: " + err)); showMessage(_("Unexpected pdb stderr: " + err));
//handleOutput(err); //handleOutput(err);
} }
void PdbEngine::readPdbStandardOutput() void PdbEngine::readPdbStandardOutput()
{ {
QByteArray out = m_proc.readAllStandardOutput(); QByteArray out = m_proc.readAllStandardOutput();
qDebug() << "\nPDB STDOUT" << out;
handleOutput(out); handleOutput(out);
} }
void PdbEngine::handleOutput(const QByteArray &data) void PdbEngine::handleOutput(const QByteArray &data)
{ {
//qDebug() << "READ: " << data;
m_inbuffer.append(data); m_inbuffer.append(data);
qDebug() << "BUFFER FROM: '" << m_inbuffer << '\'';
while (true) { while (true) {
int pos = m_inbuffer.indexOf("(Pdb)"); int pos = m_inbuffer.indexOf("(Pdb)");
if (pos == -1) if (pos == -1)
...@@ -484,8 +457,6 @@ void PdbEngine::handleOutput(const QByteArray &data) ...@@ -484,8 +457,6 @@ void PdbEngine::handleOutput(const QByteArray &data)
m_inbuffer = m_inbuffer.mid(pos + 6); m_inbuffer = m_inbuffer.mid(pos + 6);
handleOutput2(response); handleOutput2(response);
} }
qDebug() << "BUFFER LEFT: '" << m_inbuffer << '\'';
//m_inbuffer.clear();
} }
void PdbEngine::handleOutput2(const QByteArray &data) void PdbEngine::handleOutput2(const QByteArray &data)
...@@ -532,8 +503,6 @@ void PdbEngine::handleOutput2(const QByteArray &data) ...@@ -532,8 +503,6 @@ void PdbEngine::handleOutput2(const QByteArray &data)
if (pos1 != -1 && pos2 != -1) { if (pos1 != -1 && pos2 != -1) {
int lineNumber = line.mid(pos1 + 1, pos2 - pos1 - 1).toInt(); int lineNumber = line.mid(pos1 + 1, pos2 - pos1 - 1).toInt();
QByteArray fileName = line.mid(2, pos1 - 2); QByteArray fileName = line.mid(2, pos1 - 2);
qDebug() << " " << pos1 << pos2 << lineNumber << fileName
<< line.mid(pos1 + 1, pos2 - pos1 - 1);
StackFrame frame; StackFrame frame;
frame.file = _(fileName); frame.file = _(fileName);
frame.line = lineNumber; frame.line = lineNumber;
...@@ -546,27 +515,10 @@ void PdbEngine::handleOutput2(const QByteArray &data) ...@@ -546,27 +515,10 @@ void PdbEngine::handleOutput2(const QByteArray &data)
} }
} }
} }
showMessage(_(" #### ... UNHANDLED"));
} }
} }
} }
/*
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);
}
}
*/
void PdbEngine::refreshLocals(const GdbMi &vars) void PdbEngine::refreshLocals(const GdbMi &vars)
{ {
WatchHandler *handler = watchHandler(); WatchHandler *handler = watchHandler();
...@@ -657,6 +609,7 @@ void PdbEngine::updateLocals() ...@@ -657,6 +609,7 @@ void PdbEngine::updateLocals()
//cmd.arg("resultvarname", m_resultVarName); //cmd.arg("resultvarname", m_resultVarName);
//m_lastDebuggableCommand = cmd; //m_lastDebuggableCommand = cmd;
//m_lastDebuggableCommand.args.replace("\"passexceptions\":0", "\"passexceptions\":1"); //m_lastDebuggableCommand.args.replace("\"passexceptions\":0", "\"passexceptions\":1");
cmd.arg("frame", stackHandler()->currentIndex());
watchHandler()->notifyUpdateStarted(); watchHandler()->notifyUpdateStarted();
runCommand(cmd); runCommand(cmd);
......
...@@ -98,9 +98,6 @@ private: ...@@ -98,9 +98,6 @@ private:
bool isSynchronous() const { return true; } bool isSynchronous() const { return true; }
void updateItem(const QByteArray &iname); void updateItem(const QByteArray &iname);
QString mainPythonFile() const;
QString pythonInterpreter() const;
void runCommand(const DebuggerCommand &cmd); void runCommand(const DebuggerCommand &cmd);
void postDirectCommand(const QByteArray &command); void postDirectCommand(const QByteArray &command);
...@@ -124,6 +121,7 @@ private: ...@@ -124,6 +121,7 @@ private:
QByteArray m_inbuffer; QByteArray m_inbuffer;
QProcess m_proc; QProcess m_proc;
QString m_interpreter;
}; };
} // namespace Internal } // namespace Internal
......
...@@ -32,6 +32,9 @@ ...@@ -32,6 +32,9 @@
#define PYTHONEDITOR_PLUGIN_H #define PYTHONEDITOR_PLUGIN_H
#include <extensionsystem/iplugin.h> #include <extensionsystem/iplugin.h>
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/target.h>
#include <QSet> #include <QSet>
namespace PythonEditor { namespace PythonEditor {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment