Debugger: Start moving PdbEngine to event based parsing

Change-Id: I63e06045b54226636280678ae7db8326a3e5f02e
Reviewed-by: hjk <hjk@theqtcompany.com>
This commit is contained in:
hjk
2015-02-13 14:46:35 +01:00
parent e5bbd86ab9
commit d479701591
3 changed files with 442 additions and 359 deletions

View File

@@ -1,37 +1,58 @@
import pdb; import pdb
import sys; import sys
import linecache import linecache
import inspect
import os
def qdebug(options = None, class Dumper:
expanded = None, def __init__(self):
typeformats = None, pass
individualformats = None,
watchers = None):
class QDebug: def updateData(self, args):
def __init__(self, self.expandedINames = set(args.get("expanded", []))
options = None, self.typeformats = args.get("typeformats", {})
expanded = None, self.formats = args.get("formats", {})
typeformats = None, self.watchers = args.get("watchers", {})
individualformats = None, self.output = "data={"
watchers = None): # self.handleListModules()
self.options = options # self.handleListSymbols(expanded)
self.expandedINames = expanded
self.typeformats = typeformats # Trigger error to get a backtrace.
self.individualformats = individualformats frame = None
self.watchers = watchers #self.warn("frame: %s" % frame)
self.buffer = "" try:
if self.options == "listmodules": raise ZeroDivisionError
self.handleListModules() except ZeroDivisionError:
elif self.options == "listsymbols": frame = sys.exc_info()[2].tb_frame.f_back
self.handleListSymbols(expanded)
else: limit = 30
self.handleListVars() 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()
self.output += '}'
sys.stdout.write(self.output)
def put(self, value): def put(self, value):
#sys.stdout.write(value) #sys.stdout.write(value)
self.buffer += value self.output += value
def putField(self, name, value): def putField(self, name, value):
self.put('%s="%s",' % (name, value)) self.put('%s="%s",' % (name, value))
@@ -195,36 +216,6 @@ def qdebug(options = None,
def warn(self, msg): def warn(self, msg):
self.putField("warning", 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): def handleListModules(self):
self.put("modules=["); self.put("modules=[");
for name in sys.modules: for name in sys.modules:
@@ -246,7 +237,48 @@ def qdebug(options = None,
self.put("]") self.put("]")
#sys.stdout.flush() #sys.stdout.flush()
d = QDebug(options, expanded, typeformats, individualformats, watchers) def stackListFrames(self, args):
#print d.buffer #isNativeMixed = int(args.get('nativeMixed', 0))
sys.stdout.write(d.buffer) #result = 'stack={current-thread="%s"' % thread.GetThreadID()
result = 'stack={current-thread="%s"' % 1
result += ',frames=['
level = 0
for frame in inspect.stack():
l = [i for i in frame]
fileName = l[1]
(head, tail) = os.path.split(fileName)
if tail in ("pdbbridge.py", "bdb.py", "pdb.py", "cmd.py", "<stdin>"):
continue
level += 1
result += '{'
result += 'a0="%s",' % l[0]
result += 'file="%s",' % fileName
result += 'line="%s",' % l[2]
result += 'a3="%s",' % l[3]
result += 'a4="%s",' % l[4]
result += 'a5="%s",' % l[5]
result += 'level="%s",' % level
result += '}'
result += ']'
#result += ',hasmore="%d"' % isLimited
#result += ',limit="%d"' % limit
result += '}'
self.report(result)
def report(self, stuff):
sys.stdout.write("@\n" + stuff + "@\n")
sys.stdout.flush() sys.stdout.flush()
def qdebug(options = None,
expanded = None,
typeformats = None,
individualformats = None,
watchers = None):
sys.stdout.write("\n(Pdb)\n")
sys.stdout.flush()
theDumper = Dumper()

View File

@@ -132,6 +132,14 @@ void PdbEngine::postCommand(const QByteArray &command, DebuggerCommand::Callback
m_pdbProc.write(cmd.function + '\n'); m_pdbProc.write(cmd.function + '\n');
} }
void PdbEngine::runCommand(const DebuggerCommand &cmd)
{
QTC_ASSERT(m_pdbProc.state() == QProcess::Running, notifyEngineIll());
QByteArray command = "theDumper." + cmd.function + "({" + cmd.args + "})";
showMessage(_(command), LogInput);
m_pdbProc.write(command + '\n');
}
void PdbEngine::shutdownInferior() void PdbEngine::shutdownInferior()
{ {
QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state()); QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
@@ -361,6 +369,8 @@ void PdbEngine::handleBreakInsert(const DebuggerResponse &response, Breakpoint b
br.id = BreakpointResponseId(bpnr); br.id = BreakpointResponseId(bpnr);
br.fileName = _(file); br.fileName = _(file);
br.lineNumber = line.toInt(); br.lineNumber = line.toInt();
if (!bp.isValid())
bp = breakHandler()->findBreakpointByFileAndLine(br.fileName, br.lineNumber, false);
bp.setResponse(br); bp.setResponse(br);
QTC_CHECK(!bp.needsChange()); QTC_CHECK(!bp.needsChange());
bp.notifyBreakpointInsertOk(); bp.notifyBreakpointInsertOk();
@@ -444,7 +454,6 @@ void PdbEngine::handleListSymbols(const DebuggerResponse &response, const QStrin
static WatchData m_toolTip; static WatchData m_toolTip;
static QPoint m_toolTipPos; static QPoint m_toolTipPos;
static QHash<QString, WatchData> m_toolTipCache;
bool PdbEngine::setToolTipExpression(TextEditor::TextEditorWidget *editorWidget, bool PdbEngine::setToolTipExpression(TextEditor::TextEditorWidget *editorWidget,
const DebuggerToolTipContext &ctx) const DebuggerToolTipContext &ctx)
@@ -626,19 +635,71 @@ void PdbEngine::handleOutput(const QByteArray &data)
void PdbEngine::handleOutput2(const QByteArray &data) void PdbEngine::handleOutput2(const QByteArray &data)
{ {
QByteArray lineContext;
foreach (QByteArray line, data.split('\n')) {
// line = line.trimmed();
DebuggerResponse response; DebuggerResponse response;
response.logStreamOutput = data; response.logStreamOutput = line;
showMessage(_(data)); response.data.fromString(line);
QTC_ASSERT(!m_commands.isEmpty(), qDebug() << "RESPONSE: " << data; return); showMessage(_("LINE: " + line));
DebuggerCommand cmd = m_commands.dequeue();
qDebug() << "DEQUE: " << cmd.function; if (line.startsWith("stack={")) {
if (cmd.callback) { refreshStack(response.data);
//qDebug() << "EXECUTING CALLBACK " << cmd.callbackName continue;
// << " RESPONSE: " << response.data;
cmd.callback(response);
} else {
qDebug() << "NO CALLBACK FOR RESPONSE: " << response.logStreamOutput;
} }
if (line.startsWith("data={")) {
refreshLocals(response.data);
continue;
}
if (line.startsWith("Breakpoint")) {
handleBreakInsert(response, Breakpoint());
continue;
}
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;
}
}
}
if (line.startsWith("-> ")) {
// Current line
}
showMessage(_(" #### ... UNHANDLED"));
}
// DebuggerResponse response;
// response.logStreamOutput = data;
// showMessage(_(data));
// QTC_ASSERT(!m_commands.isEmpty(), qDebug() << "RESPONSE: " << data; return);
// DebuggerCommand cmd = m_commands.dequeue();
// qDebug() << "DEQUE: " << cmd.function;
// if (cmd.callback) {
// //qDebug() << "EXECUTING CALLBACK " << cmd.callbackName
// // << " RESPONSE: " << response.data;
// cmd.callback(response);
// } else {
// qDebug() << "NO CALLBACK FOR RESPONSE: " << response.logStreamOutput;
// }
} }
/* /*
void PdbEngine::handleResponse(const QByteArray &response0) void PdbEngine::handleResponse(const QByteArray &response0)
@@ -653,28 +714,65 @@ void PdbEngine::handleResponse(const QByteArray &response0)
qDebug() << "SKIPPING '--Return--' MARKER"; qDebug() << "SKIPPING '--Return--' MARKER";
response = response.mid(11); 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
<< 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);
notifyInferiorSpontaneousStop();
return;
}
}
}
qDebug() << "COULD NOT PARSE RESPONSE: '" << response << "'";
} }
*/ */
void PdbEngine::refreshLocals(const GdbMi &vars)
{
//const bool partial = response.cookie.toBool();
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());
}
frames.append(frame);
}
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));
}
void PdbEngine::handleFirstCommand(const DebuggerResponse &response) void PdbEngine::handleFirstCommand(const DebuggerResponse &response)
{ {
Q_UNUSED(response); Q_UNUSED(response);
@@ -689,100 +787,50 @@ void PdbEngine::handleUpdateAll(const DebuggerResponse &response)
void PdbEngine::updateAll() void PdbEngine::updateAll()
{ {
postCommand("bt", CB(handleBacktrace)); postCommand("dir()");
//updateLocals(); postCommand("theDumper.stackListFrames({})");
updateLocals();
} }
void PdbEngine::updateLocals() void PdbEngine::updateLocals()
{ {
QByteArray watchers; DebuggerCommand cmd("updateData");
//if (!m_toolTipExpression.isEmpty()) cmd.arg("nativeMixed", isNativeMixedActive());
// watchers += m_toolTipExpression.toLatin1() watchHandler()->appendFormatRequests(&cmd);
// + '#' + tooltipINameForExpression(m_toolTipExpression.toLatin1());
WatchHandler *handler = watchHandler(); const static bool alwaysVerbose = !qgetenv("QTC_DEBUGGER_PYTHON_VERBOSE").isEmpty();
QHash<QByteArray, int> watcherNames = handler->watcherNames(); cmd.arg("passexceptions", alwaysVerbose);
QHashIterator<QByteArray, int> it(watcherNames); cmd.arg("fancy", boolSetting(UseDebuggingHelpers));
// cmd.arg("partial", params.tryPartial);
cmd.beginList("watchers");
// Watchers
QHashIterator<QByteArray, int> it(WatchHandler::watcherNames());
while (it.hasNext()) { while (it.hasNext()) {
it.next(); it.next();
if (!watchers.isEmpty()) cmd.beginGroup();
watchers += "##"; cmd.arg("iname", "watch." + QByteArray::number(it.value()));
watchers += it.key() + "#watch." + QByteArray::number(it.value()); cmd.arg("exp", it.key().toHex());
cmd.endGroup();
} }
QByteArray options; // Tooltips
if (boolSetting(UseDebuggingHelpers)) DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(this);
options += "fancy,"; foreach (const DebuggerToolTipContext &p, toolTips) {
if (boolSetting(AutoDerefPointers)) cmd.beginGroup();
options += "autoderef,"; cmd.arg("iname", p.iname);
if (options.isEmpty()) cmd.arg("exp", p.expression.toLatin1().toHex());
options += "defaults,"; cmd.endGroup();
options.chop(1);
postCommand("qdebug('" + options + "','"
// + handler->expansionRequests() + "','"
+ handler->typeFormatRequests() + "','"
+ handler->individualFormatRequests() + "','"
+ watchers.toHex() + "')", CB(handleListLocals));
} }
void PdbEngine::handleBacktrace(const DebuggerResponse &response) cmd.endList();
{
//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. //cmd.arg("resultvarname", m_resultVarName);
StackFrames stackFrames; //m_lastDebuggableCommand = cmd;
int level = 0; //m_lastDebuggableCommand.args.replace("\"passexceptions\":0", "\"passexceptions\":1");
int currentIndex = -1;
foreach (const QByteArray &line, response.logStreamOutput.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
// << line.mid(pos1 + 1, pos2 - pos1 - 1);
StackFrame frame;
frame.file = _(fileName);
frame.line = lineNumber;
frame.function = _(line.mid(pos2 + 1));
frame.usable = QFileInfo(frame.file).isReadable();
if (frame.line > 0 && QFileInfo::exists(frame.file)) {
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);
// Select current frame. runCommand(cmd);
if (currentIndex != -1) {
currentIndex = frameCount - currentIndex - 1;
stackHandler()->setCurrentIndex(currentIndex);
gotoLocation(stackFrames.at(currentIndex));
}
updateLocals();
} }
void PdbEngine::handleListLocals(const DebuggerResponse &response) void PdbEngine::handleListLocals(const DebuggerResponse &response)

View File

@@ -54,6 +54,10 @@ public:
explicit PdbEngine(const DebuggerStartParameters &startParameters); explicit PdbEngine(const DebuggerStartParameters &startParameters);
~PdbEngine(); ~PdbEngine();
void refreshStack(const GdbMi &stack);
void runCommand(const DebuggerCommand &cmd);
void refreshLocals(const GdbMi &vars);
private: private:
// DebuggerEngine implementation // DebuggerEngine implementation
void executeStep(); void executeStep();
@@ -122,7 +126,6 @@ private:
void handleFirstCommand(const DebuggerResponse &response); void handleFirstCommand(const DebuggerResponse &response);
void handleExecuteDebuggerCommand(const DebuggerResponse &response); void handleExecuteDebuggerCommand(const DebuggerResponse &response);
void handleStop(const DebuggerResponse &response); void handleStop(const DebuggerResponse &response);
void handleBacktrace(const DebuggerResponse &response);
void handleListLocals(const DebuggerResponse &response); void handleListLocals(const DebuggerResponse &response);
void handleListModules(const DebuggerResponse &response); void handleListModules(const DebuggerResponse &response);
void handleListSymbols(const DebuggerResponse &response, const QString &moduleName); void handleListSymbols(const DebuggerResponse &response, const QString &moduleName);