Files
qt-creator/src/plugins/debugger/pdb/pdbengine.cpp

850 lines
26 KiB
C++
Raw Normal View History

2010-04-23 12:12:22 +02:00
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** 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.
**
** GNU Lesser General Public License Usage
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#define QT_NO_CAST_FROM_ASCII
#include "pdbengine.h"
#include "debuggeractions.h"
#include "debuggerconstants.h"
2010-04-23 12:12:22 +02:00
#include "debuggerdialogs.h"
#include "debuggerplugin.h"
#include "debuggerstringutils.h"
2010-04-23 12:12:22 +02:00
#include "breakhandler.h"
#include "moduleshandler.h"
#include "registerhandler.h"
#include "stackhandler.h"
#include "watchhandler.h"
#include "watchutils.h"
2010-04-23 12:12:22 +02:00
#include "../gdb/gdbmi.h"
#include <utils/qtcassert.h>
#include <texteditor/itexteditor.h>
#include <coreplugin/ifile.h>
//#include <coreplugin/scriptmanager/scriptmanager.h>
#include <coreplugin/icore.h>
#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QTimer>
#include <QtCore/QVariant>
#include <QtGui/QApplication>
#include <QtGui/QMessageBox>
#include <QtGui/QToolTip>
2010-04-23 12:12:22 +02:00
#define DEBUG_SCRIPT 1
#if DEBUG_SCRIPT
# define SDEBUG(s) qDebug() << s
#else
# define SDEBUG(s)
#endif
# define XSDEBUG(s) qDebug() << s
#define CB(callback) &PdbEngine::callback, STRINGIFY(callback)
namespace Debugger {
namespace Internal {
///////////////////////////////////////////////////////////////////////
//
// PdbEngine
//
///////////////////////////////////////////////////////////////////////
PdbEngine::PdbEngine(const DebuggerStartParameters &startParameters)
: DebuggerEngine(startParameters)
2010-04-23 12:12:22 +02:00
{}
PdbEngine::~PdbEngine()
{}
void PdbEngine::executeDebuggerCommand(const QString &command)
{
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
//XSDEBUG("PdbEngine::executeDebuggerCommand:" << command);
2010-04-23 12:12:22 +02:00
if (state() == DebuggerNotReady) {
showMessage(_("PDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command);
2010-04-23 12:12:22 +02:00
return;
}
QTC_ASSERT(m_pdbProc.state() == QProcess::Running, notifyEngineIll());
postCommand(command.toLatin1(), CB(handleExecuteDebuggerCommand));
}
void PdbEngine::handleExecuteDebuggerCommand(const PdbResponse &response)
{
Q_UNUSED(response);
}
void PdbEngine::postDirectCommand(const QByteArray &command)
{
QTC_ASSERT(m_pdbProc.state() == QProcess::Running, notifyEngineIll());
showMessage(_(command), LogInput);
m_pdbProc.write(command + "\n");
2010-04-23 12:12:22 +02:00
}
void PdbEngine::postCommand(const QByteArray &command,
// PdbCommandFlags flags,
PdbCommandCallback callback,
const char *callbackName,
const QVariant &cookie)
{
QTC_ASSERT(m_pdbProc.state() == QProcess::Running, notifyEngineIll());
2010-04-23 12:12:22 +02:00
PdbCommand cmd;
cmd.command = command;
cmd.callback = callback;
cmd.callbackName = callbackName;
cmd.cookie = cookie;
m_commands.enqueue(cmd);
qDebug() << "ENQUEUE: " << command << cmd.callbackName;
showMessage(_(cmd.command), LogInput);
2010-04-23 12:12:22 +02:00
m_pdbProc.write(cmd.command + "\n");
}
void PdbEngine::shutdownInferior()
2010-04-23 12:12:22 +02:00
{
QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
notifyInferiorShutdownOk();
2010-04-23 12:12:22 +02:00
}
void PdbEngine::shutdownEngine()
2010-04-23 12:12:22 +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
{
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
2010-04-23 12:12:22 +02:00
m_pdb = _("python");
showMessage(_("STARTING PDB ") + m_pdb);
2010-04-23 12:12:22 +02:00
connect(&m_pdbProc, SIGNAL(error(QProcess::ProcessError)),
SLOT(handlePdbError(QProcess::ProcessError)));
connect(&m_pdbProc, SIGNAL(finished(int, QProcess::ExitStatus)),
SLOT(handlePdbFinished(int, QProcess::ExitStatus)));
connect(&m_pdbProc, SIGNAL(readyReadStandardOutput()),
SLOT(readPdbStandardOutput()));
connect(&m_pdbProc, SIGNAL(readyReadStandardError()),
SLOT(readPdbStandardError()));
connect(this, SIGNAL(outputReady(QByteArray)),
SLOT(handleOutput2(QByteArray)), Qt::QueuedConnection);
2010-04-23 12:12:22 +02:00
// We will stop immediatly, so setup a proper callback.
PdbCommand cmd;
2010-07-08 18:10:50 +02:00
cmd.callback = &PdbEngine::handleFirstCommand;
2010-04-23 12:12:22 +02:00
m_commands.enqueue(cmd);
m_pdbProc.start(m_pdb, QStringList() << _("-i"));
2010-04-23 12:12:22 +02:00
if (!m_pdbProc.waitForStarted()) {
const QString msg = tr("Unable to start pdb '%1': %2")
.arg(m_pdb, m_pdbProc.errorString());
notifyEngineSetupFailed();
showMessage(_("ADAPTER START FAILED"));
2010-04-23 12:12:22 +02:00
if (!msg.isEmpty()) {
const QString title = tr("Adapter start failed");
Core::ICore::instance()->showWarningWithOptions(title, msg);
}
notifyEngineSetupFailed();
2010-04-23 12:12:22 +02:00
return;
}
notifyEngineSetupOk();
2010-07-08 18:10:50 +02:00
}
void PdbEngine::setupInferior()
{
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
2010-04-23 12:12:22 +02:00
QString fileName = QFileInfo(startParameters().executable).absoluteFilePath();
QFile scriptFile(fileName);
if (!scriptFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
showMessageBox(QMessageBox::Critical, tr("Python Error"),
_("Cannot open script file %1:\n%2").
arg(fileName, scriptFile.errorString()));
notifyInferiorSetupFailed();
return;
}
notifyInferiorSetupOk();
2010-04-23 12:12:22 +02:00
}
2010-07-08 18:10:50 +02:00
void PdbEngine::runEngine()
2010-04-23 12:12:22 +02:00
{
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
2010-07-08 18:10:50 +02:00
showStatusMessage(tr("Running requested..."), 5000);
const QByteArray dumperSourcePath =
Core::ICore::instance()->resourcePath().toLocal8Bit() + "/gdbmacros/";
QString fileName = QFileInfo(startParameters().executable).absoluteFilePath();
postDirectCommand("import sys");
postDirectCommand("sys.argv.append('" + fileName.toLocal8Bit() + "')");
postDirectCommand("execfile('/usr/bin/pdb')");
postDirectCommand("execfile('" + dumperSourcePath + "pdumper.py')");
attemptBreakpointSynchronization();
notifyEngineRunAndInferiorStopOk();
continueInferior();
2010-04-23 12:12:22 +02:00
}
void PdbEngine::interruptInferior()
{
notifyInferiorStopOk();
2010-04-23 12:12:22 +02:00
}
void PdbEngine::executeStep()
{
resetLocation();
notifyInferiorRunRequested();
notifyInferiorRunOk();
2010-04-23 12:12:22 +02:00
postCommand("step", CB(handleUpdateAll));
}
void PdbEngine::executeStepI()
{
resetLocation();
notifyInferiorRunRequested();
notifyInferiorRunOk();
2010-04-23 12:12:22 +02:00
postCommand("step", CB(handleUpdateAll));
}
void PdbEngine::executeStepOut()
{
resetLocation();
notifyInferiorRunRequested();
notifyInferiorRunOk();
2010-04-23 12:12:22 +02:00
postCommand("finish", CB(handleUpdateAll));
}
void PdbEngine::executeNext()
{
resetLocation();
notifyInferiorRunRequested();
notifyInferiorRunOk();
2010-04-23 12:12:22 +02:00
postCommand("next", CB(handleUpdateAll));
}
void PdbEngine::executeNextI()
{
resetLocation();
notifyInferiorRunRequested();
notifyInferiorRunOk();
2010-04-23 12:12:22 +02:00
postCommand("next", CB(handleUpdateAll));
}
void PdbEngine::continueInferior()
{
resetLocation();
notifyInferiorRunRequested();
notifyInferiorRunOk();
2010-04-23 12:12:22 +02:00
// Callback will be triggered e.g. when breakpoint is hit.
postCommand("continue", CB(handleUpdateAll));
}
void PdbEngine::executeRunToLine(const QString &fileName, int lineNumber)
{
Q_UNUSED(fileName)
Q_UNUSED(lineNumber)
SDEBUG("FIXME: PdbEngine::runToLineExec()");
}
void PdbEngine::executeRunToFunction(const QString &functionName)
{
Q_UNUSED(functionName)
XSDEBUG("FIXME: PdbEngine::runToFunctionExec()");
}
void PdbEngine::executeJumpToLine(const QString &fileName, int lineNumber)
{
Q_UNUSED(fileName)
Q_UNUSED(lineNumber)
XSDEBUG("FIXME: PdbEngine::jumpToLineExec()");
}
void PdbEngine::activateFrame(int frameIndex)
{
resetLocation();
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
2010-04-23 12:12:22 +02:00
return;
StackHandler *handler = stackHandler();
int oldIndex = handler->currentIndex();
2010-04-23 12:12:22 +02:00
//if (frameIndex == handler->stackSize()) {
2010-04-23 12:12:22 +02:00
// reloadFullStack();
// return;
//}
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.
handler->setCurrentIndex(frameIndex);
2010-04-23 12:12:22 +02:00
//postCommand("-stack-select-frame " + QByteArray::number(frameIndex),
// CB(handleStackSelectFrame));
}
gotoLocation(handler->currentFrame(), true);
2010-04-23 12:12:22 +02:00
}
void PdbEngine::selectThread(int index)
{
Q_UNUSED(index)
}
static QByteArray breakpointLocation(const BreakpointData *data)
{
if (!data->funcName.isEmpty())
return data->funcName.toLatin1();
// In this case, data->funcName is something like '*0xdeadbeef'
if (data->lineNumber.toInt() == 0)
return data->funcName.toLatin1();
//QString loc = data->useFullPath ? data->fileName : breakLocation(data->fileName);
// The argument is simply a C-quoted version of the argument to the
// non-MI "break" command, including the "original" quoting it wants.
//return "\"\\\"" + GdbMi::escapeCString(data->fileName).toLocal8Bit() + "\\\":"
// + data->lineNumber + '"';
return data->fileName.toLocal8Bit() + ":" + data->lineNumber;
}
void PdbEngine::attemptBreakpointSynchronization()
{
BreakHandler *handler = breakHandler();
2010-04-23 12:12:22 +02:00
//qDebug() << "ATTEMPT BP SYNC";
bool updateNeeded = false;
for (int index = 0; index != handler->size(); ++index) {
BreakpointData *data = handler->at(index);
if (data->pending) {
data->pending = false; // FIXME
updateNeeded = true;
QByteArray loc = breakpointLocation(data);
postCommand("break " + loc, CB(handleBreakInsert), QVariant(index));
}
/*
if (data->bpNumber.isEmpty()) {
data->bpNumber = QByteArray::number(index + 1);
updateNeeded = true;
}
if (!data->fileName.isEmpty() && data->markerFileName().isEmpty()) {
data->setMarkerFileName(data->fileName);
data->setMarkerLineNumber(data->lineNumber.toInt());
updateNeeded = true;
}
*/
}
//if (updateNeeded)
// handler->updateMarkers();
}
void PdbEngine::handleBreakInsert(const PdbResponse &response)
{
//qDebug() << "BP RESPONSE: " << response.data;
// "Breakpoint 1 at /pdb/math.py:10"
int index = response.cookie.toInt();
BreakHandler *handler = breakHandler();
2010-04-23 12:12:22 +02:00
BreakpointData *data = handler->at(index);
QTC_ASSERT(data, return);
QTC_ASSERT(response.data.startsWith("Breakpoint "), return);
int pos1 = response.data.indexOf(" at ");
QTC_ASSERT(pos1 != -1, return);
QByteArray bpnr = response.data.mid(11, pos1 - 11);
int pos2 = response.data.lastIndexOf(":");
QByteArray file = response.data.mid(pos1 + 4, pos2 - pos1 - 4);
QByteArray line = response.data.mid(pos2 + 1);
data->bpNumber = bpnr;
data->bpFileName = _(file);
data->bpLineNumber = line;
handler->updateMarkers();
}
void PdbEngine::loadSymbols(const QString &moduleName)
{
Q_UNUSED(moduleName)
}
void PdbEngine::loadAllSymbols()
{
}
void PdbEngine::reloadModules()
{
//postCommand("qdebug('listmodules')", CB(handleListModules));
2010-05-03 19:12:52 +02:00
}
void PdbEngine::handleListModules(const PdbResponse &response)
{
GdbMi out;
out.fromString(response.data.trimmed());
Modules modules;
2010-05-03 19:12:52 +02:00
foreach (const GdbMi &item, out.children()) {
Module module;
module.moduleName = _(item.findChild("name").data());
QString path = _(item.findChild("value").data());
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;
modules.append(module);
}
modulesHandler()->setModules(modules);
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
{
2010-05-03 19:12:52 +02:00
postCommand("qdebug('listsymbols','" + moduleName.toLatin1() + "')",
CB(handleListSymbols), moduleName);
2010-04-23 12:12:22 +02:00
}
2010-05-03 19:12:52 +02:00
void PdbEngine::handleListSymbols(const PdbResponse &response)
{
GdbMi out;
out.fromString(response.data.trimmed());
Symbols symbols;
2010-05-03 19:12:52 +02:00
QString moduleName = response.cookie.toString();
foreach (const GdbMi &item, out.children()) {
Symbol symbol;
symbol.name = _(item.findChild("name").data());
symbols.append(symbol);
}
showModuleSymbols(moduleName, symbols);
2010-05-03 19:12:52 +02:00
}
2010-04-23 12:12:22 +02:00
//////////////////////////////////////////////////////////////////////
//
// Tooltip specific stuff
//
//////////////////////////////////////////////////////////////////////
static WatchData m_toolTip;
static QPoint m_toolTipPos;
static QHash<QString, WatchData> m_toolTipCache;
void PdbEngine::setToolTipExpression(const QPoint &mousePos,
TextEditor::ITextEditor *editor, int cursorPos)
{
Q_UNUSED(mousePos)
Q_UNUSED(editor)
Q_UNUSED(cursorPos)
if (state() != InferiorStopOk) {
2010-04-23 12:12:22 +02:00
//SDEBUG("SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED");
return;
}
// Check mime type and get expression (borrowing some C++ - functions)
const QString javaPythonMimeType =
QLatin1String("application/javascript");
if (!editor->file() || editor->file()->mimeType() != javaPythonMimeType)
return;
int line;
int column;
QString exp = cppExpressionAt(editor, cursorPos, &line, &column);
/*
if (m_toolTipCache.contains(exp)) {
const WatchData & data = m_toolTipCache[exp];
q->watchHandler()->removeChildren(data.iname);
insertData(data);
return;
}
*/
QToolTip::hideText();
if (exp.isEmpty() || exp.startsWith(QLatin1Char('#'))) {
QToolTip::hideText();
return;
}
if (!hasLetterOrNumber(exp)) {
QToolTip::showText(m_toolTipPos, tr("'%1' contains no identifier").arg(exp));
return;
}
if (exp.startsWith(QLatin1Char('"')) && exp.endsWith(QLatin1Char('"'))) {
QToolTip::showText(m_toolTipPos, tr("String literal %1").arg(exp));
return;
}
if (exp.startsWith(QLatin1String("++")) || exp.startsWith(QLatin1String("--")))
exp.remove(0, 2);
if (exp.endsWith(QLatin1String("++")) || exp.endsWith(QLatin1String("--")))
exp.remove(0, 2);
if (exp.startsWith(QLatin1Char('<')) || exp.startsWith(QLatin1Char('[')))
return;
if (hasSideEffects(exp)) {
QToolTip::showText(m_toolTipPos,
tr("Cowardly refusing to evaluate expression '%1' "
"with potential side effects").arg(exp));
return;
}
#if 0
//if (status() != InferiorStopOk)
2010-04-23 12:12:22 +02:00
// return;
// FIXME: 'exp' can contain illegal characters
m_toolTip = WatchData();
m_toolTip.exp = exp;
m_toolTip.name = exp;
m_toolTip.iname = tooltipIName;
insertData(m_toolTip);
#endif
}
//////////////////////////////////////////////////////////////////////
//
// Watch specific stuff
//
//////////////////////////////////////////////////////////////////////
void PdbEngine::assignValueInDebugger(const QString &expression,
const QString &value)
{
Q_UNUSED(expression);
Q_UNUSED(value);
SDEBUG("ASSIGNING: " << (expression + QLatin1Char('=') + value));
#if 0
m_scriptEngine->evaluate(expression + QLatin1Char('=') + value);
updateLocals();
#endif
}
void PdbEngine::updateWatchData(const WatchData &data)
{
Q_UNUSED(data);
updateAll();
}
void PdbEngine::handlePdbError(QProcess::ProcessError error)
{
qDebug() << "HANDLE PDB ERROR";
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:
//setState(EngineShutdownRequested, true);
2010-04-23 12:12:22 +02:00
m_pdbProc.kill();
showMessageBox(QMessageBox::Critical, tr("Pdb I/O Error"),
2010-04-23 12:12:22 +02:00
errorMessage(error));
break;
}
}
QString PdbEngine::errorMessage(QProcess::ProcessError error) const
{
switch (error) {
case QProcess::FailedToStart:
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(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:
return tr("An unknown error in the Pdb process occurred. ");
}
}
void PdbEngine::handlePdbFinished(int code, QProcess::ExitStatus type)
{
qDebug() << "PDB FINISHED";
showMessage(_("PDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
notifyEngineSpontaneousShutdown();
2010-04-23 12:12:22 +02:00
}
void PdbEngine::readPdbStandardError()
{
QByteArray err = m_pdbProc.readAllStandardError();
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()
{
QByteArray out = m_pdbProc.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)
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);
emit outputReady(response);
}
qDebug() << "BUFFER LEFT: '" << m_inbuffer << "'";
//m_inbuffer.clear();
}
void PdbEngine::handleOutput2(const QByteArray &data)
{
PdbResponse response;
response.data = data;
showMessage(_(data));
QTC_ASSERT(!m_commands.isEmpty(), qDebug() << "RESPONSE: " << data; return)
PdbCommand cmd = m_commands.dequeue();
response.cookie = cmd.cookie;
qDebug() << "DEQUE: " << cmd.command << cmd.callbackName;
if (cmd.callback) {
//qDebug() << "EXECUTING CALLBACK " << cmd.callbackName
// << " RESPONSE: " << response.data;
(this->*cmd.callback)(response);
} else {
qDebug() << "NO CALLBACK FOR RESPONSE: " << response.data;
2010-04-23 12:12:22 +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);
}
if (response.startsWith("> ")) {
int pos1 = response.indexOf('(');
int pos2 = response.indexOf(')', pos1);
if (pos1 != -1 && pos2 != -1) {
int lineNumber = response.mid(pos1 + 1, pos2 - pos1 - 1).toInt();
QByteArray fileName = response.mid(2, pos1 - 2);
qDebug() << " " << pos1 << pos2 << lineNumber << fileName
2010-04-23 12:12:22 +02:00
<< response.mid(pos1 + 1, pos2 - pos1 - 1);
StackFrame frame;
frame.file = _(fileName);
frame.line = lineNumber;
if (frame.line > 0 && QFileInfo(frame.file).exists()) {
gotoLocation(frame, true);
notifyInferiorSpontaneousStop();
2010-04-23 12:12:22 +02:00
return;
}
}
}
qDebug() << "COULD NOT PARSE RESPONSE: '" << response << "'";
}
*/
2010-04-23 12:12:22 +02:00
2010-07-08 18:10:50 +02:00
void PdbEngine::handleFirstCommand(const PdbResponse &response)
{
Q_UNUSED(response);
}
2010-04-23 12:12:22 +02:00
void PdbEngine::handleUpdateAll(const PdbResponse &response)
{
Q_UNUSED(response);
notifyInferiorSpontaneousStop();
2010-04-23 12:12:22 +02:00
updateAll();
}
void PdbEngine::updateAll()
{
postCommand("bt", CB(handleBacktrace));
//updateLocals();
}
void PdbEngine::updateLocals()
2010-04-23 12:12:22 +02:00
{
WatchHandler *handler = watchHandler();
2010-04-23 12:12:22 +02:00
QByteArray watchers;
//if (!m_toolTipExpression.isEmpty())
// watchers += m_toolTipExpression.toLatin1()
// + '#' + tooltipINameForExpression(m_toolTipExpression.toLatin1());
QHash<QByteArray, int> watcherNames = handler->watcherNames();
QHashIterator<QByteArray, int> it(watcherNames);
while (it.hasNext()) {
it.next();
if (!watchers.isEmpty())
watchers += "##";
watchers += it.key() + "#watch." + QByteArray::number(it.value());
2010-04-23 12:12:22 +02:00
}
QByteArray options;
if (theDebuggerBoolSetting(UseDebuggingHelpers))
options += "fancy,";
if (theDebuggerBoolSetting(AutoDerefPointers))
options += "autoderef,";
if (options.isEmpty())
options += "defaults,";
options.chop(1);
postCommand("qdebug('" + options + "','"
+ handler->expansionRequests() + "','"
+ handler->typeFormatRequests() + "','"
+ handler->individualFormatRequests() + "','"
+ watchers.toHex() + "')", CB(handleListLocals));
}
void PdbEngine::handleBacktrace(const PdbResponse &response)
{
//qDebug() << " BACKTRACE: '" << response.data << "'";
// " /usr/lib/python2.6/bdb.py(368)run()"
// "-> exec cmd in globals, locals"
// " <string>(1)<module>()"
// " /python/math.py(19)<module>()"
// "-> main()"
// " /python/math.py(14)main()"
// "-> print cube(3)"
// " /python/math.py(7)cube()"
// "-> x = square(a)"
// "> /python/math.py(2)square()"
// "-> def square(a):"
// Populate stack view.
StackFrames stackFrames;
2010-04-23 12:12:22 +02:00
int level = 0;
int currentIndex = -1;
foreach (const QByteArray &line, response.data.split('\n')) {
//qDebug() << " LINE: '" << line << "'";
if (line.startsWith("> ") || line.startsWith(" ")) {
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
2010-04-23 12:12:22 +02:00
// << line.mid(pos1 + 1, pos2 - pos1 - 1);
StackFrame frame;
frame.file = _(fileName);
frame.line = lineNumber;
frame.function = _(line.mid(pos2 + 1));
if (frame.line > 0 && QFileInfo(frame.file).exists()) {
if (line.startsWith("> "))
currentIndex = level;
frame.level = level;
stackFrames.prepend(frame);
++level;
}
}
}
}
const int frameCount = stackFrames.size();
for (int i = 0; i != frameCount; ++i)
stackFrames[i].level = frameCount - stackFrames[i].level - 1;
stackHandler()->setFrames(stackFrames);
2010-04-23 12:12:22 +02:00
// Select current frame.
if (currentIndex != -1) {
currentIndex = frameCount - currentIndex - 1;
stackHandler()->setCurrentIndex(currentIndex);
gotoLocation(stackFrames.at(currentIndex), true);
2010-04-23 12:12:22 +02:00
}
updateLocals();
2010-04-23 12:12:22 +02:00
}
void PdbEngine::handleListLocals(const PdbResponse &response)
{
//qDebug() << " LOCALS: '" << response.data << "'";
QByteArray out = response.data.trimmed();
GdbMi all;
all.fromStringMultiple(out);
//qDebug() << "ALL: " << all.toString();
//GdbMi data = all.findChild("data");
QList<WatchData> list;
WatchHandler *handler = watchHandler();
2010-04-23 12:12:22 +02:00
foreach (const GdbMi &child, all.children()) {
WatchData dummy;
dummy.iname = child.findChild("iname").data();
dummy.name = _(child.findChild("name").data());
//qDebug() << "CHILD: " << child.toString();
parseWatchData(handler->expandedINames(), dummy, child, &list);
2010-04-23 12:12:22 +02:00
}
handler->insertBulkData(list);
2010-04-23 12:12:22 +02:00
}
2010-05-03 19:12:52 +02:00
unsigned PdbEngine::debuggerCapabilities() const
{
return ReloadModuleCapability;
}
DebuggerEngine *createPdbEngine(const DebuggerStartParameters &startParameters)
2010-04-23 12:12:22 +02:00
{
return new PdbEngine(startParameters);
2010-04-23 12:12:22 +02:00
}
} // namespace Internal
} // namespace Debugger