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:
QString projectSourceDirectory;
QStringList projectSourceFiles;
// Used by Script debugging
QString interpreter;
QString mainScript;
// Used by AttachCrashedExternal.
QString crashParameter;
......
......@@ -147,7 +147,8 @@ void DebuggerRunControl::start()
QTC_ASSERT(m_engine, return);
// User canceled input dialog asking for executable when working on library project.
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);
emit started();
emit finished();
......@@ -438,6 +439,22 @@ void DebuggerRunControlCreator::enrich(const RunConfiguration *runConfig, const
if (m_runConfig)
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) {
m_rp.multiProcess = m_debuggerAspect->useMultiProcess();
......@@ -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)) {
const QString sysroot = m_rp.sysRoot;
if (m_rp.debugInfoLocation.isEmpty())
......@@ -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
{
public:
......@@ -592,7 +604,8 @@ public:
bool canRun(RunConfiguration *runConfig, Core::Id mode) const override
{
return (mode == DebugRunMode || mode == DebugRunModeWithBreakOnMain)
&& qobject_cast<LocalApplicationRunConfiguration *>(runConfig);
&& (qobject_cast<LocalApplicationRunConfiguration *>(runConfig)
|| isDebuggableScript(runConfig));
}
IRunConfigurationAspect *createRunConfigurationAspect(RunConfiguration *rc) override
......
......@@ -49,6 +49,7 @@
#include <debugger/watchutils.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <coreplugin/idocument.h>
#include <coreplugin/icore.h>
......@@ -77,7 +78,6 @@ void PdbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages
if (!(languages & CppLanguage))
return;
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
//XSDEBUG("PdbEngine::executeDebuggerCommand:" << command);
if (state() == DebuggerNotReady) {
showMessage(_("PDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command);
return;
......@@ -117,8 +117,8 @@ void PdbEngine::setupEngine()
{
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
QString python = pythonInterpreter();
showMessage(_("STARTING PDB ") + python);
m_interpreter = runParameters().interpreter;
QString bridge = ICore::resourcePath() + QLatin1String("/debugger/pdbbridge.py");
connect(&m_proc, static_cast<void(QProcess::*)(QProcess::ProcessError)>(&QProcess::error),
this, &PdbEngine::handlePdbError);
......@@ -129,11 +129,22 @@ void PdbEngine::setupEngine()
connect(&m_proc, &QProcess::readyReadStandardError,
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()) {
const QString msg = tr("Unable to start pdb \"%1\": %2")
.arg(pythonInterpreter(), m_proc.errorString());
.arg(m_interpreter, m_proc.errorString());
notifyEngineSetupFailed();
showMessage(_("ADAPTER START FAILED"));
if (!msg.isEmpty())
......@@ -148,43 +159,19 @@ void PdbEngine::setupInferior()
{
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();
}
QString PdbEngine::mainPythonFile() const
{
return QFileInfo(runParameters().processArgs).absoluteFilePath();
}
QString PdbEngine::pythonInterpreter() const
{
return runParameters().executable;
}
void PdbEngine::runEngine()
{
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
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();
notifyEngineRunAndInferiorStopOk();
continueInferior();
if (runParameters().breakOnMain)
updateAll();
else
continueInferior();
}
void PdbEngine::interruptInferior()
......@@ -198,6 +185,7 @@ void PdbEngine::executeStep()
notifyInferiorRunRequested();
notifyInferiorRunOk();
postDirectCommand("step");
updateAll();
}
void PdbEngine::executeStepI()
......@@ -206,6 +194,7 @@ void PdbEngine::executeStepI()
notifyInferiorRunRequested();
notifyInferiorRunOk();
postDirectCommand("step");
updateAll();
}
void PdbEngine::executeStepOut()
......@@ -214,6 +203,7 @@ void PdbEngine::executeStepOut()
notifyInferiorRunRequested();
notifyInferiorRunOk();
postDirectCommand("return");
updateAll();
}
void PdbEngine::executeNext()
......@@ -222,6 +212,7 @@ void PdbEngine::executeNext()
notifyInferiorRunRequested();
notifyInferiorRunOk();
postDirectCommand("next");
updateAll();
}
void PdbEngine::executeNextI()
......@@ -230,6 +221,7 @@ void PdbEngine::executeNextI()
notifyInferiorRunRequested();
notifyInferiorRunOk();
postDirectCommand("next");
updateAll();
}
void PdbEngine::continueInferior()
......@@ -239,6 +231,7 @@ void PdbEngine::continueInferior()
notifyInferiorRunOk();
// Callback will be triggered e.g. when breakpoint is hit.
postDirectCommand("continue");
updateAll();
}
void PdbEngine::executeRunToLine(const ContextData &data)
......@@ -261,28 +254,14 @@ void PdbEngine::executeJumpToLine(const ContextData &data)
void PdbEngine::activateFrame(int frameIndex)
{
resetLocation();
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
return;
StackHandler *handler = stackHandler();
int oldIndex = handler->currentIndex();
//if (frameIndex == handler->stackSize()) {
// reloadFullStack();
// return;
//}
QTC_ASSERT(frameIndex < handler->stackSize(), return);
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));
}
handler->setCurrentIndex(frameIndex);
gotoLocation(handler->currentFrame());
updateLocals();
}
void PdbEngine::selectThread(ThreadId threadId)
......@@ -402,7 +381,6 @@ void PdbEngine::updateItem(const QByteArray &iname)
void PdbEngine::handlePdbError(QProcess::ProcessError error)
{
qDebug() << "HANDLE PDB ERROR";
showMessage(_("HANDLE PDB ERROR"));
switch (error) {
case QProcess::Crashed:
......@@ -426,7 +404,7 @@ QString PdbEngine::errorMessage(QProcess::ProcessError error) const
return tr("The Pdb process failed to start. Either the "
"invoked program \"%1\" is missing, or you may have insufficient "
"permissions to invoke the program.")
.arg(pythonInterpreter());
.arg(m_interpreter);
case QProcess::Crashed:
return tr("The Pdb process crashed some time after starting "
"successfully.");
......@@ -448,7 +426,6 @@ QString PdbEngine::errorMessage(QProcess::ProcessError error) const
void PdbEngine::handlePdbFinished(int code, QProcess::ExitStatus type)
{
qDebug() << "PDB FINISHED";
showMessage(_("PDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
notifyEngineSpontaneousShutdown();
}
......@@ -456,24 +433,20 @@ void PdbEngine::handlePdbFinished(int code, QProcess::ExitStatus type)
void PdbEngine::readPdbStandardError()
{
QByteArray err = m_proc.readAllStandardError();
qDebug() << "\nPDB STDERR" << err;
//qWarning() << "Unexpected pdb stderr:" << err;
//showMessage(_("Unexpected pdb stderr: " + err));
showMessage(_("Unexpected pdb stderr: " + err));
//handleOutput(err);
}
void PdbEngine::readPdbStandardOutput()
{
QByteArray out = m_proc.readAllStandardOutput();
qDebug() << "\nPDB STDOUT" << out;
handleOutput(out);
}
void PdbEngine::handleOutput(const QByteArray &data)
{
//qDebug() << "READ: " << data;
m_inbuffer.append(data);
qDebug() << "BUFFER FROM: '" << m_inbuffer << '\'';
while (true) {
int pos = m_inbuffer.indexOf("(Pdb)");
if (pos == -1)
......@@ -484,8 +457,6 @@ void PdbEngine::handleOutput(const QByteArray &data)
m_inbuffer = m_inbuffer.mid(pos + 6);
handleOutput2(response);
}
qDebug() << "BUFFER LEFT: '" << m_inbuffer << '\'';
//m_inbuffer.clear();
}
void PdbEngine::handleOutput2(const QByteArray &data)
......@@ -532,8 +503,6 @@ void PdbEngine::handleOutput2(const QByteArray &data)
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;
......@@ -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)
{
WatchHandler *handler = watchHandler();
......@@ -657,6 +609,7 @@ void PdbEngine::updateLocals()
//cmd.arg("resultvarname", m_resultVarName);
//m_lastDebuggableCommand = cmd;
//m_lastDebuggableCommand.args.replace("\"passexceptions\":0", "\"passexceptions\":1");
cmd.arg("frame", stackHandler()->currentIndex());
watchHandler()->notifyUpdateStarted();
runCommand(cmd);
......
......@@ -98,9 +98,6 @@ private:
bool isSynchronous() const { return true; }
void updateItem(const QByteArray &iname);
QString mainPythonFile() const;
QString pythonInterpreter() const;
void runCommand(const DebuggerCommand &cmd);
void postDirectCommand(const QByteArray &command);
......@@ -124,6 +121,7 @@ private:
QByteArray m_inbuffer;
QProcess m_proc;
QString m_interpreter;
};
} // namespace Internal
......
......@@ -32,6 +32,9 @@
#define PYTHONEDITOR_PLUGIN_H
#include <extensionsystem/iplugin.h>
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/target.h>
#include <QSet>
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