Commit 3cee7dad authored by hjk's avatar hjk
Browse files

debugger: make parts of python debugger work again with the new states

parent 97775d9c
......@@ -3,239 +3,250 @@ import pdb;
import sys;
import linecache
class qdebug:
def __init__(self,
options = None,
def qdebug(options = None,
expanded = None,
typeformats = None,
individualformats = None,
watchers = None):
self.options = options
self.expandedINames = expanded
self.typeformats = typeformats
self.individualformats = individualformats
self.watchers = watchers
if self.options == "listmodules":
self.handleListModules()
elif self.options == "listsymbols":
self.handleListSymbols(expanded)
else:
self.handleListVars()
def put(self, value):
sys.stdout.write(value)
def putField(self, name, value):
self.put('%s="%s",' % (name, value))
def putItemCount(self, count):
self.put('value="<%s items>",' % count)
def putEllipsis(self):
self.put('{name="<incomplete>",value="",type="",numchild="0"},')
def cleanType(self, type):
t = str(type)
if t.startswith("<type '") and t.endswith("'>"):
t = t[7:-2]
if t.startswith("<class '") and t.endswith("'>"):
t = t[8:-2]
return t
def putType(self, type, priority = 0):
self.putField("type", self.cleanType(type))
def putAddress(self, addr):
self.put('addr="%s",' % cleanAddress(addr))
def putNumChild(self, numchild):
self.put('numchild="%s",' % numchild)
def putValue(self, value, encoding = None, priority = 0):
self.putField("value", value)
def putName(self, name):
self.put('name="%s",' % name)
def isExpanded(self, iname):
#self.warn("IS EXPANDED: %s in %s" % (iname, self.expandedINames))
if iname.startswith("None"):
raise "Illegal iname '%s'" % iname
#self.warn(" --> %s" % (iname in self.expandedINames))
return iname in self.expandedINames
def isExpandedIName(self, iname):
return iname in self.expandedINames
def itemFormat(self, item):
format = self.formats.get(str(cleanAddress(item.value.address)))
if format is None:
format = self.typeformats.get(stripClassTag(str(item.value.type)))
return format
def dumpFrame(self, frame):
for var in frame.f_locals.keys():
if var == "__file__":
continue
#if var == "__name__":
# continue
if var == "__package__":
continue
if var == "qdebug":
continue
if var != '__builtins__':
value = frame.f_locals[var]
self.dumpValue(value, var, "local.%s" % var)
def dumpValue(self, value, name, iname):
t = type(value)
tt = self.cleanType(t)
if tt == "module" or tt == "function":
return
if str(value).startswith("<class '"):
return
# FIXME: Should we?
if str(value).startswith("<enum-item "):
return
self.put("{")
self.putField("iname", iname)
self.putName(name)
self.putType(tt)
if tt == "NoneType":
self.putValue("None")
self.putNumChild(0)
elif tt == "list" or tt == "tuple":
self.putItemCount(len(value))
#self.putValue(value)
self.put("children=[")
for i in xrange(len(value)):
self.dumpValue(value[i], str(i), "%s.%d" % (iname, i))
self.put("]")
elif tt == "str":
v = value
self.putValue(v.encode('hex'))
self.putField("valueencoded", 6)
self.putNumChild(0)
elif tt == "unicode":
v = value
self.putValue(v.encode('hex'))
self.putField("valueencoded", 6)
self.putNumChild(0)
elif tt == "buffer":
v = str(value)
self.putValue(v.encode('hex'))
self.putField("valueencoded", 6)
self.putNumChild(0)
elif tt == "xrange":
b = iter(value).next()
e = b + len(value)
self.putValue("(%d, %d)" % (b, e))
self.putNumChild(0)
elif tt == "dict":
self.putItemCount(len(value))
self.putField("childnumchild", 2)
self.put("children=[")
i = 0
for (k, v) in value.iteritems():
self.put("{")
self.putType(" ")
self.putValue("%s: %s" % (k, v))
class QDebug:
def __init__(self,
options = None,
expanded = None,
typeformats = None,
individualformats = None,
watchers = None):
self.options = options
self.expandedINames = expanded
self.typeformats = typeformats
self.individualformats = individualformats
self.watchers = watchers
self.buffer = ""
if self.options == "listmodules":
self.handleListModules()
elif self.options == "listsymbols":
self.handleListSymbols(expanded)
else:
self.handleListVars()
def put(self, value):
#sys.stdout.write(value)
self.buffer += value
def putField(self, name, value):
self.put('%s="%s",' % (name, value))
def putItemCount(self, count):
self.put('value="<%s items>",' % count)
def putEllipsis(self):
self.put('{name="<incomplete>",value="",type="",numchild="0"},')
def cleanType(self, type):
t = str(type)
if t.startswith("<type '") and t.endswith("'>"):
t = t[7:-2]
if t.startswith("<class '") and t.endswith("'>"):
t = t[8:-2]
return t
def putType(self, type, priority = 0):
self.putField("type", self.cleanType(type))
def putAddress(self, addr):
self.put('addr="%s",' % cleanAddress(addr))
def putNumChild(self, numchild):
self.put('numchild="%s",' % numchild)
def putValue(self, value, encoding = None, priority = 0):
self.putField("value", value)
def putName(self, name):
self.put('name="%s",' % name)
def isExpanded(self, iname):
#self.warn("IS EXPANDED: %s in %s" % (iname, self.expandedINames))
if iname.startswith("None"):
raise "Illegal iname '%s'" % iname
#self.warn(" --> %s" % (iname in self.expandedINames))
return iname in self.expandedINames
def isExpandedIName(self, iname):
return iname in self.expandedINames
def itemFormat(self, item):
format = self.formats.get(str(cleanAddress(item.value.address)))
if format is None:
format = self.typeformats.get(stripClassTag(str(item.value.type)))
return format
def dumpFrame(self, frame):
for var in frame.f_locals.keys():
if var == "__file__":
continue
#if var == "__name__":
# continue
if var == "__package__":
continue
if var == "qdebug":
continue
if var != '__builtins__':
value = frame.f_locals[var]
self.dumpValue(value, var, "local.%s" % var)
def dumpValue(self, value, name, iname):
t = type(value)
tt = self.cleanType(t)
if tt == "module" or tt == "function":
return
if str(value).startswith("<class '"):
return
# FIXME: Should we?
if str(value).startswith("<enum-item "):
return
self.put("{")
self.putField("iname", iname)
self.putName(name)
self.putType(tt)
if tt == "NoneType":
self.putValue("None")
self.putNumChild(0)
elif tt == "list" or tt == "tuple":
self.putItemCount(len(value))
#self.putValue(value)
self.put("children=[")
for i in xrange(len(value)):
self.dumpValue(value[i], str(i), "%s.%d" % (iname, i))
self.put("]")
elif tt == "str":
v = value
self.putValue(v.encode('hex'))
self.putField("valueencoded", 6)
self.putNumChild(0)
elif tt == "unicode":
v = value
self.putValue(v.encode('hex'))
self.putField("valueencoded", 6)
self.putNumChild(0)
elif tt == "buffer":
v = str(value)
self.putValue(v.encode('hex'))
self.putField("valueencoded", 6)
self.putNumChild(0)
elif tt == "xrange":
b = iter(value).next()
e = b + len(value)
self.putValue("(%d, %d)" % (b, e))
self.putNumChild(0)
elif tt == "dict":
self.putItemCount(len(value))
self.putField("childnumchild", 2)
self.put("children=[")
i = 0
for (k, v) in value.iteritems():
self.put("{")
self.putType(" ")
self.putValue("%s: %s" % (k, v))
if self.isExpanded(iname):
self.put("children=[")
self.dumpValue(k, "key", "%s.%d.k" % (iname, i))
self.dumpValue(v, "value", "%s.%d.v" % (iname, i))
self.put("]")
self.put("},")
i += 1
self.put("]")
elif tt == "class":
pass
elif tt == "module":
pass
elif tt == "function":
pass
elif str(value).startswith("<enum-item "):
# FIXME: Having enums always shown like this is not nice.
self.putValue(str(value)[11:-1])
self.putNumChild(0)
else:
v = str(value)
p = v.find(" object at ")
if p > 1:
v = "@" + v[p + 11:-1]
self.putValue(v)
if self.isExpanded(iname):
self.put("children=[")
self.dumpValue(k, "key", "%s.%d.k" % (iname, i))
self.dumpValue(v, "value", "%s.%d.v" % (iname, i))
self.put("]")
for child in dir(value):
if child == "__dict__":
continue
if child == "__doc__":
continue
if child == "__module__":
continue
attr = getattr(value, child)
if callable(attr):
continue
try:
self.dumpValue(attr, child, "%s.%s" % (iname, child))
except:
pass
self.put("],")
self.put("},")
def warn(self, msg):
self.putField("warning", msg)
def handleListVars(self):
# Trigger error to get a backtrace.
frame = None
#self.warn("frame: %s" % frame)
try:
raise ZeroDivisionError
except ZeroDivisionError:
frame = sys.exc_info()[2].tb_frame.f_back
limit = 30
n = 0
isActive = False
while frame is not None and n < limit:
#self.warn("frame: %s" % frame.f_locals.keys())
lineno = frame.f_lineno
code = frame.f_code
filename = code.co_filename
name = code.co_name
if isActive:
linecache.checkcache(filename)
line = linecache.getline(filename, lineno, frame.f_globals)
self.dumpFrame(frame)
if name == "<module>":
isActive = False
if name == "trace_dispatch":
isActive = True
frame = frame.f_back
n = n + 1
#sys.stdout.flush()
def handleListModules(self):
self.put("modules=[");
for name in sys.modules:
self.put("{")
self.putName(name)
self.putValue(sys.modules[name])
self.put("},")
i += 1
self.put("]")
elif tt == "class":
pass
elif tt == "module":
pass
elif tt == "function":
pass
elif str(value).startswith("<enum-item "):
# FIXME: Having enums always shown like this is not nice.
self.putValue(str(value)[11:-1])
self.putNumChild(0)
else:
v = str(value)
p = v.find(" object at ")
if p > 1:
v = "@" + v[p + 11:-1]
self.putValue(v)
if self.isExpanded(iname):
self.put("children=[")
for child in dir(value):
if child == "__dict__":
continue
if child == "__doc__":
continue
if child == "__module__":
continue
attr = getattr(value, child)
if callable(attr):
continue
try:
self.dumpValue(attr, child, "%s.%s" % (iname, child))
except:
pass
self.put("],")
self.put("},")
def warn(self, msg):
self.putField("warning", msg)
def handleListVars(self):
# Trigger error to get a backtrace.
frame = None
#self.warn("frame: %s" % frame)
try:
raise ZeroDivisionError
except ZeroDivisionError:
frame = sys.exc_info()[2].tb_frame.f_back
limit = 30
n = 0
isActive = False
while frame is not None and n < limit:
#self.warn("frame: %s" % frame.f_locals.keys())
lineno = frame.f_lineno
code = frame.f_code
filename = code.co_filename
name = code.co_name
if isActive:
linecache.checkcache(filename)
line = linecache.getline(filename, lineno, frame.f_globals)
self.dumpFrame(frame)
if name == "<module>":
isActive = False
if name == "trace_dispatch":
isActive = True
frame = frame.f_back
n = n + 1
sys.stdout.flush()
def handleListModules(self):
self.put("modules=[");
for name in sys.modules:
self.put("{")
self.putName(name)
self.putValue(sys.modules[name])
self.put("},")
self.put("]")
sys.stdout.flush()
#sys.stdout.flush()
def handleListSymbols(self, module):
#self.put("symbols=%s" % dir(sys.modules[module]))
self.put("symbols=[");
for name in sys.modules:
self.put("{")
self.putName(name)
#self.putValue(sys.modules[name])
self.put("},")
self.put("]")
sys.stdout.flush()
def handleListSymbols(self, module):
#self.put("symbols=%s" % dir(sys.modules[module]))
self.put("symbols=[");
for name in sys.modules:
self.put("{")
self.putName(name)
#self.putValue(sys.modules[name])
self.put("},")
self.put("]")
#sys.stdout.flush()
d = QDebug(options, expanded, typeformats, individualformats, watchers)
#print d.buffer
sys.stdout.write(d.buffer)
sys.stdout.flush()
......@@ -61,8 +61,8 @@
#include <QtCore/QVariant>
#include <QtGui/QApplication>
#include <QtGui/QToolTip>
#include <QtGui/QMessageBox>
#include <QtGui/QToolTip>
#define DEBUG_SCRIPT 1
......@@ -94,12 +94,26 @@ PdbEngine::~PdbEngine()
void PdbEngine::executeDebuggerCommand(const QString &command)
{
XSDEBUG("PdbEngine::executeDebuggerCommand:" << command);
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
//XSDEBUG("PdbEngine::executeDebuggerCommand:" << command);
if (state() == DebuggerNotReady) {
showMessage(_("PDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command);
return;
}
m_pdbProc.write(command.toLatin1() + "\n");
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");
}
void PdbEngine::postCommand(const QByteArray &command,
......@@ -108,12 +122,14 @@ void PdbEngine::postCommand(const QByteArray &command,
const char *callbackName,
const QVariant &cookie)
{
QTC_ASSERT(m_pdbProc.state() == QProcess::Running, notifyEngineIll());
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);
m_pdbProc.write(cmd.command + "\n");
}
......@@ -127,7 +143,6 @@ void PdbEngine::shutdownInferior()
void PdbEngine::shutdownEngine()
{
QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
SDEBUG("PdbEngine::shutdownEngine()");
m_pdbProc.kill();
}
......@@ -135,24 +150,8 @@ void PdbEngine::setupEngine()
{
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
m_scriptFileName = QFileInfo(startParameters().executable).absoluteFilePath();
QFile scriptFile(m_scriptFileName);
if (!scriptFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
//showMessage("STARTING " +m_scriptFileName + "FAILED");
showMessage(QString::fromLatin1("Cannot open %1: %2").
arg(m_scriptFileName, scriptFile.errorString()), LogError);
notifyEngineSetupFailed();
return;
}
m_pdbProc.disconnect(); // From any previous runs
m_pdb = _("/usr/bin/python");
m_pdb = _("python");
showMessage(_("STARTING PDB ") + m_pdb);
QStringList gdbArgs;
gdbArgs += _("-i");
gdbArgs += _("/usr/bin/pdb");
gdbArgs += m_scriptFileName;
//gdbArgs += args;
connect(&m_pdbProc, SIGNAL(error(QProcess::ProcessError)),
SLOT(handlePdbError(QProcess::ProcessError)));
......@@ -163,13 +162,15 @@ void PdbEngine::setupEngine()
connect(&m_pdbProc, SIGNAL(readyReadStandardError()),
SLOT(readPdbStandardError()));
connect(this, SIGNAL(outputReady(QByteArray)),
SLOT(handleOutput2(QByteArray)), Qt::QueuedConnection);
// We will stop immediatly, so setup a proper callback.
PdbCommand cmd;
cmd.callback = &PdbEngine::handleFirstCommand;
m_commands.enqueue(cmd);
m_pdbProc.start(m_pdb, gdbArgs);
//qDebug() << "STARTING:" << m_pdb << gdbArgs;
m_pdbProc.start(m_pdb, QStringList() << _("-i"));
if (!m_pdbProc.waitForStarted()) {
const QString msg = tr("Unable to start pdb '%1': %2")
......@@ -189,21 +190,33 @@ void PdbEngine::setupEngine()
void PdbEngine::setupInferior()
{
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
attemptBreakpointSynchronization();
showMessage(_("PDB STARTED, INITIALIZING IT"));
const QByteArray dumperSourcePath =
Core::ICore::instance()->resourcePath().toLocal8Bit() + "/gdbmacros/";
postCommand("execfile('" + dumperSourcePath + "pdumper.py')",
CB(handleLoadDumper));
QString fileName = QFileInfo(startParameters().executable).absoluteFilePath();
QFile scriptFile(fileName);
if (!scriptFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
showMessageBox