forked from qt-creator/qt-creator
Debugger: Progress on LLDB integration
Some breakpoints trigger real state changes now, some locals display name and type (no values yet) Change-Id: I1736d4b499f22b92d4680519853a09558e9dbbf4 Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
@@ -5,6 +5,12 @@ cdbLoaded = False
|
|||||||
lldbLoaded = False
|
lldbLoaded = False
|
||||||
gdbLoaded = False
|
gdbLoaded = False
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# Helpers
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
def warn(message):
|
def warn(message):
|
||||||
print "XXX: %s\n" % message.encode("latin1")
|
print "XXX: %s\n" % message.encode("latin1")
|
||||||
|
|
||||||
@@ -18,37 +24,34 @@ def showException(msg, exType, exValue, exTraceback):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# CDB
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
try:
|
try:
|
||||||
#import cdb_bridge
|
import cdb_bridge
|
||||||
cdbLoaded = True
|
cdbLoaded = True
|
||||||
|
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
|
||||||
#import lldb_bridge
|
|
||||||
lldbLoaded = True
|
|
||||||
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# GDB
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if cdbLoaded:
|
||||||
|
raise "Not needed"
|
||||||
|
|
||||||
import gdb
|
import gdb
|
||||||
gdbLoaded = True
|
gdbLoaded = True
|
||||||
|
|
||||||
#######################################################################
|
|
||||||
#
|
|
||||||
# Sanitize environment
|
|
||||||
#
|
|
||||||
#######################################################################
|
|
||||||
|
|
||||||
#try:
|
|
||||||
# gdb.execute("set auto-load-scripts no")
|
|
||||||
#except:
|
|
||||||
# pass
|
|
||||||
|
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
#
|
#
|
||||||
# Infrastructure
|
# Infrastructure
|
||||||
@@ -434,3 +437,89 @@ try:
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# LLDB
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
try:
|
||||||
|
if gdbLoaded or cdbLoaded:
|
||||||
|
raise "Not needed"
|
||||||
|
|
||||||
|
lldbLoaded = True
|
||||||
|
|
||||||
|
PointerCode, \
|
||||||
|
ArrayCode, \
|
||||||
|
StructCode, \
|
||||||
|
UnionCode, \
|
||||||
|
EnumCode, \
|
||||||
|
FlagsCode, \
|
||||||
|
FunctionCode, \
|
||||||
|
IntCode, \
|
||||||
|
FloatCode, \
|
||||||
|
VoidCode, \
|
||||||
|
SetCode, \
|
||||||
|
RangeCode, \
|
||||||
|
StringCode, \
|
||||||
|
BitStringCode, \
|
||||||
|
ErrorTypeCode, \
|
||||||
|
MethodCode, \
|
||||||
|
MethodPointerCode, \
|
||||||
|
MemberPointerCode, \
|
||||||
|
ReferenceCode, \
|
||||||
|
CharCode, \
|
||||||
|
BoolCode, \
|
||||||
|
ComplexCode, \
|
||||||
|
TypedefCode, \
|
||||||
|
NamespaceCode \
|
||||||
|
= range(24)
|
||||||
|
|
||||||
|
def registerCommand(name, func):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Type:
|
||||||
|
def __init__(self, type):
|
||||||
|
self.raw = type
|
||||||
|
self.code = IntCode
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.raw.name
|
||||||
|
|
||||||
|
|
||||||
|
def unqualified(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
class Value:
|
||||||
|
def __init__(self, var):
|
||||||
|
self.raw = var
|
||||||
|
self.is_optimized_out = False
|
||||||
|
self.type = Type(var.type)
|
||||||
|
self.type.value_type = var.value_type
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
currentThread = None
|
||||||
|
currentFrame = None
|
||||||
|
|
||||||
|
def listOfLocals(varList):
|
||||||
|
global currentThread
|
||||||
|
global currentFrame
|
||||||
|
|
||||||
|
items = []
|
||||||
|
currentThread = lldb.process.GetThreadAtIndex(0)
|
||||||
|
currentFrame = currentThread.GetFrameAtIndex(0)
|
||||||
|
for var in currentFrame.variables:
|
||||||
|
item = LocalItem()
|
||||||
|
item.iname = "local." + var.name
|
||||||
|
item.name = var.name
|
||||||
|
item.value = Value(var)
|
||||||
|
items.append(item)
|
||||||
|
return items
|
||||||
|
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@@ -63,6 +63,8 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QToolTip>
|
#include <QToolTip>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
#define DEBUG_SCRIPT 1
|
#define DEBUG_SCRIPT 1
|
||||||
#if DEBUG_SCRIPT
|
#if DEBUG_SCRIPT
|
||||||
@@ -87,7 +89,7 @@ static QByteArray quoteUnprintable(const QByteArray &ba)
|
|||||||
if (isprint(c)) {
|
if (isprint(c)) {
|
||||||
res += c;
|
res += c;
|
||||||
} else {
|
} else {
|
||||||
qsnprintf(buf, sizeof(buf) - 1, "\\%02x", int(c));
|
qsnprintf(buf, sizeof(buf) - 1, "\\x%02x", int(c));
|
||||||
res += buf;
|
res += buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,6 +107,7 @@ LldbEngine::LldbEngine(const DebuggerStartParameters &startParameters)
|
|||||||
: DebuggerEngine(startParameters)
|
: DebuggerEngine(startParameters)
|
||||||
{
|
{
|
||||||
setObjectName(QLatin1String("LldbEngine"));
|
setObjectName(QLatin1String("LldbEngine"));
|
||||||
|
m_pythonAttemptedToLoad = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LldbEngine::~LldbEngine()
|
LldbEngine::~LldbEngine()
|
||||||
@@ -205,6 +208,43 @@ void LldbEngine::setupEngine()
|
|||||||
notifyEngineSetupFailed();
|
notifyEngineSetupFailed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadPythonDumpers();
|
||||||
|
postCommand("setting set auto-confirm on");
|
||||||
|
postCommand("setting set interpreter.prompt-on-quit off");
|
||||||
|
|
||||||
|
// Default:
|
||||||
|
// frame-format (string) = "frame #${frame.index}: ${frame.pc}
|
||||||
|
// { ${module.file.basename}{`${function.name-with-args}${function.pc-offset}}}
|
||||||
|
// { at ${line.file.basename}:${line.number}}\n"
|
||||||
|
postCommand("settings set frame-format frame=\\{"
|
||||||
|
"index='${frame.index}',"
|
||||||
|
"pc='${frame.pc}',"
|
||||||
|
"module='${module.file.basename}',"
|
||||||
|
//"function='${function.name-with-args}',"
|
||||||
|
"function='${function.name}',"
|
||||||
|
"pcoffset='${function.pc-offset}',"
|
||||||
|
"file='${line.file.basename}',"
|
||||||
|
"line='${line.number}'"
|
||||||
|
"\\},");
|
||||||
|
|
||||||
|
|
||||||
|
// Default:
|
||||||
|
// "thread #${thread.index}: tid = ${thread.id}{, ${frame.pc}}
|
||||||
|
// { ${module.file.basename}{`${function.name-with-args}${function.pc-offset}}}
|
||||||
|
// { at ${line.file.basename}:${line.number}}
|
||||||
|
// {, stop reason = ${thread.stop-reason}}{\nReturn value: ${thread.return-value}}\n"
|
||||||
|
postCommand("settings set thread-format thread=\\{"
|
||||||
|
"index='${thread.index}',"
|
||||||
|
"tid='${thread.id}',"
|
||||||
|
"framepc='${frame.pc}',"
|
||||||
|
"module='${module.file.basename}',"
|
||||||
|
"function='${function.name}',"
|
||||||
|
"pcoffset='${function.pc-offset}',"
|
||||||
|
"stopreason='${thread.stop-reason}'"
|
||||||
|
//"returnvalue='${thread.return-value}'"
|
||||||
|
"\\},");
|
||||||
|
|
||||||
notifyEngineSetupOk();
|
notifyEngineSetupOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -644,11 +684,11 @@ void LldbEngine::readLldbStandardOutput()
|
|||||||
}
|
}
|
||||||
if (j != n)
|
if (j != n)
|
||||||
out.resize(j);
|
out.resize(j);
|
||||||
|
|
||||||
//qDebug("\n\nLLDB STDOUT: '%s'", quoteUnprintable(out).constData());
|
//qDebug("\n\nLLDB STDOUT: '%s'", quoteUnprintable(out).constData());
|
||||||
if (out.isEmpty())
|
if (out.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//qDebug() << "READ: " << data;
|
|
||||||
if (out.startsWith(8)) {
|
if (out.startsWith(8)) {
|
||||||
if (!m_inbuffer.isEmpty())
|
if (!m_inbuffer.isEmpty())
|
||||||
m_inbuffer.chop(1);
|
m_inbuffer.chop(1);
|
||||||
@@ -665,12 +705,29 @@ void LldbEngine::readLldbStandardOutput()
|
|||||||
if (pos == -1)
|
if (pos == -1)
|
||||||
break;
|
break;
|
||||||
QByteArray response = m_inbuffer.left(pos).trimmed();
|
QByteArray response = m_inbuffer.left(pos).trimmed();
|
||||||
m_inbuffer = m_inbuffer.mid(pos + 6);
|
m_inbuffer = m_inbuffer.mid(pos + 7);
|
||||||
qDebug("\nBUFFER RECOGNIZED: '%s'", quoteUnprintable(response).constData());
|
qDebug("\nBUFFER RECOGNIZED: '%s'", quoteUnprintable(response).constData());
|
||||||
emit outputReady(response);
|
emit outputReady(response);
|
||||||
}
|
}
|
||||||
qDebug("\nBUFFER LEFT: '%s'", quoteUnprintable(m_inbuffer).constData());
|
qDebug("\nBUFFER LEFT: '%s'", quoteUnprintable(m_inbuffer).constData());
|
||||||
//m_inbuffer.clear();
|
|
||||||
|
if (m_inbuffer.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Could be a 'stopped' message left.
|
||||||
|
// "<Esc>[KProcess 5564 stopped"
|
||||||
|
// "* thread #1: tid = 0x15bc, 0x0804a17d untitled11`main(argc=1,
|
||||||
|
// argv=0xbfffeff4) + 61 at main.cpp:52, stop reason = breakpoint 1.1 ..."
|
||||||
|
const int pos = m_inbuffer.indexOf("\x1b[KProcess");
|
||||||
|
if (pos != -1) {
|
||||||
|
int pid = 0;
|
||||||
|
const char *format = "\x1b[KProcess %d stopped";
|
||||||
|
if (::sscanf(m_inbuffer.constData() + pos, format, &pid) == 1) {
|
||||||
|
notifyInferiorSpontaneousStop();
|
||||||
|
m_inbuffer.clear();
|
||||||
|
updateAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::handleOutput2(const QByteArray &data)
|
void LldbEngine::handleOutput2(const QByteArray &data)
|
||||||
@@ -680,6 +737,10 @@ void LldbEngine::handleOutput2(const QByteArray &data)
|
|||||||
showMessage(_(data));
|
showMessage(_(data));
|
||||||
QTC_ASSERT(!m_commands.isEmpty(), qDebug() << "RESPONSE: " << data; return);
|
QTC_ASSERT(!m_commands.isEmpty(), qDebug() << "RESPONSE: " << data; return);
|
||||||
LldbCommand cmd = m_commands.dequeue();
|
LldbCommand cmd = m_commands.dequeue();
|
||||||
|
// FIXME: Find a way to tell LLDB to no echo input.
|
||||||
|
if (response.data.startsWith(cmd.command))
|
||||||
|
response.data = response.data.mid(cmd.command.size());
|
||||||
|
|
||||||
response.cookie = cmd.cookie;
|
response.cookie = cmd.cookie;
|
||||||
qDebug("\nDEQUE: '%s' -> '%s'", cmd.command.constData(), cmd.callbackName);
|
qDebug("\nDEQUE: '%s' -> '%s'", cmd.command.constData(), cmd.callbackName);
|
||||||
if (cmd.callback) {
|
if (cmd.callback) {
|
||||||
@@ -704,8 +765,8 @@ void LldbEngine::handleUpdateAll(const LldbResponse &response)
|
|||||||
|
|
||||||
void LldbEngine::updateAll()
|
void LldbEngine::updateAll()
|
||||||
{
|
{
|
||||||
postCommand("bt", CB(handleBacktrace));
|
//postCommand("bt", CB(handleBacktrace));
|
||||||
//updateLocals();
|
updateLocals();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::updateLocals()
|
void LldbEngine::updateLocals()
|
||||||
@@ -734,28 +795,17 @@ void LldbEngine::updateLocals()
|
|||||||
options += "defaults,";
|
options += "defaults,";
|
||||||
options.chop(1);
|
options.chop(1);
|
||||||
|
|
||||||
postCommand("qdebug('" + options + "','"
|
postCommand("script bb('options:" + options + " "
|
||||||
+ handler->expansionRequests() + "','"
|
+ "vars: "
|
||||||
+ handler->typeFormatRequests() + "','"
|
+ "expanded:" + handler->expansionRequests() + " "
|
||||||
+ handler->individualFormatRequests() + "','"
|
+ "typeformats:" + handler->typeFormatRequests() + " "
|
||||||
+ watchers.toHex() + "')", CB(handleListLocals));
|
+ "formats:" + handler->individualFormatRequests() + " "
|
||||||
|
+ "watcher:" + watchers.toHex() + "')",
|
||||||
|
CB(handleListLocals));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::handleBacktrace(const LldbResponse &response)
|
void LldbEngine::handleBacktrace(const LldbResponse &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.
|
// Populate stack view.
|
||||||
StackFrames stackFrames;
|
StackFrames stackFrames;
|
||||||
int level = 0;
|
int level = 0;
|
||||||
@@ -805,21 +855,92 @@ void LldbEngine::handleListLocals(const LldbResponse &response)
|
|||||||
//qDebug() << " LOCALS: '" << response.data << "'";
|
//qDebug() << " LOCALS: '" << response.data << "'";
|
||||||
QByteArray out = response.data.trimmed();
|
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();
|
||||||
|
// 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);
|
||||||
|
// }
|
||||||
|
// handler->insertData(list);
|
||||||
|
|
||||||
|
const bool partial = response.cookie.toBool();
|
||||||
|
int pos = out.indexOf("data=");
|
||||||
|
if (pos != 0) {
|
||||||
|
showMessage(_("DISCARDING JUNK AT BEGIN OF RESPONSE: "
|
||||||
|
+ out.left(pos)));
|
||||||
|
out = out.mid(pos);
|
||||||
|
}
|
||||||
GdbMi all;
|
GdbMi all;
|
||||||
all.fromStringMultiple(out);
|
all.fromStringMultiple(out);
|
||||||
//qDebug() << "ALL: " << all.toString();
|
GdbMi data = all.findChild("data");
|
||||||
|
|
||||||
//GdbMi data = all.findChild("data");
|
|
||||||
QList<WatchData> list;
|
|
||||||
WatchHandler *handler = watchHandler();
|
WatchHandler *handler = watchHandler();
|
||||||
foreach (const GdbMi &child, all.children()) {
|
QList<WatchData> list;
|
||||||
|
|
||||||
|
if (!partial) {
|
||||||
|
list.append(*handler->findData("local"));
|
||||||
|
list.append(*handler->findData("watch"));
|
||||||
|
list.append(*handler->findData("return"));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (const GdbMi &child, data.children()) {
|
||||||
WatchData dummy;
|
WatchData dummy;
|
||||||
dummy.iname = child.findChild("iname").data();
|
dummy.iname = child.findChild("iname").data();
|
||||||
|
GdbMi wname = child.findChild("wname");
|
||||||
|
if (wname.isValid()) {
|
||||||
|
// Happens (only) for watched expressions. They are encoded as
|
||||||
|
// base64 encoded 8 bit data, without quotes
|
||||||
|
dummy.name = decodeData(wname.data(), Base64Encoded8Bit);
|
||||||
|
dummy.exp = dummy.name.toUtf8();
|
||||||
|
} else {
|
||||||
dummy.name = _(child.findChild("name").data());
|
dummy.name = _(child.findChild("name").data());
|
||||||
//qDebug() << "CHILD: " << child.toString();
|
}
|
||||||
parseWatchData(handler->expandedINames(), dummy, child, &list);
|
parseWatchData(handler->expandedINames(), dummy, child, &list);
|
||||||
}
|
}
|
||||||
|
// const GdbMi typeInfo = all.findChild("typeinfo");
|
||||||
|
// if (typeInfo.type() == GdbMi::List) {
|
||||||
|
// foreach (const GdbMi &s, typeInfo.children()) {
|
||||||
|
// const GdbMi name = s.findChild("name");
|
||||||
|
// const GdbMi size = s.findChild("size");
|
||||||
|
// if (name.isValid() && size.isValid())
|
||||||
|
// m_typeInfoCache.insert(QByteArray::fromBase64(name.data()),
|
||||||
|
// TypeInfo(size.data().toUInt()));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// for (int i = 0; i != list.size(); ++i) {
|
||||||
|
// const TypeInfo ti = m_typeInfoCache.value(list.at(i).type);
|
||||||
|
// if (ti.size)
|
||||||
|
// list[i].size = ti.size;
|
||||||
|
// }
|
||||||
|
|
||||||
handler->insertData(list);
|
handler->insertData(list);
|
||||||
|
|
||||||
|
//rebuildWatchModel();
|
||||||
|
if (!partial)
|
||||||
|
emit stackFrameCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LldbEngine::loadPythonDumpers()
|
||||||
|
{
|
||||||
|
if (m_pythonAttemptedToLoad)
|
||||||
|
return;
|
||||||
|
m_pythonAttemptedToLoad = true;
|
||||||
|
|
||||||
|
const QByteArray dumperSourcePath =
|
||||||
|
Core::ICore::resourcePath().toLocal8Bit() + "/dumper/";
|
||||||
|
|
||||||
|
postCommand("script execfile('" + dumperSourcePath + "bridge.py')");
|
||||||
|
postCommand("script execfile('" + dumperSourcePath + "dumper.py')");
|
||||||
|
postCommand("script execfile('" + dumperSourcePath + "qttypes.py')");
|
||||||
|
postCommand("script bbsetup('')");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LldbEngine::hasCapability(unsigned cap) const
|
bool LldbEngine::hasCapability(unsigned cap) const
|
||||||
|
@@ -60,7 +60,6 @@ class LldbEngine : public DebuggerEngine
|
|||||||
public:
|
public:
|
||||||
explicit LldbEngine(const DebuggerStartParameters &startParameters);
|
explicit LldbEngine(const DebuggerStartParameters &startParameters);
|
||||||
~LldbEngine();
|
~LldbEngine();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// DebuggerEngine implementation
|
// DebuggerEngine implementation
|
||||||
void executeStep();
|
void executeStep();
|
||||||
@@ -121,6 +120,8 @@ private:
|
|||||||
Q_SLOT void readLldbStandardError();
|
Q_SLOT void readLldbStandardError();
|
||||||
Q_SLOT void handleOutput2(const QByteArray &data);
|
Q_SLOT void handleOutput2(const QByteArray &data);
|
||||||
void handleResponse(const QByteArray &ba);
|
void handleResponse(const QByteArray &ba);
|
||||||
|
|
||||||
|
void loadPythonDumpers();
|
||||||
void updateAll();
|
void updateAll();
|
||||||
void updateLocals();
|
void updateLocals();
|
||||||
void handleUpdateAll(const LldbResponse &response);
|
void handleUpdateAll(const LldbResponse &response);
|
||||||
@@ -166,6 +167,7 @@ private:
|
|||||||
QString m_scriptFileName;
|
QString m_scriptFileName;
|
||||||
QProcess m_lldbProc;
|
QProcess m_lldbProc;
|
||||||
QString m_lldb;
|
QString m_lldb;
|
||||||
|
bool m_pythonAttemptedToLoad;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
Reference in New Issue
Block a user