Debugger: Invert LLDB/Python startup order

Instead of starting LLDB through a Python script this now starts
LLDB directly. This did not work a while ago but seems fine nowaday.

Change-Id: I20e915070cd6addf260817c311f4160d010aa861
Reviewed-by: Eike Ziller <eike.ziller@theqtcompany.com>
Reviewed-by: hjk <hjk@theqtcompany.com>
This commit is contained in:
hjk
2015-01-30 12:36:04 +01:00
parent b23182fca2
commit aa39916c41
4 changed files with 44 additions and 107 deletions

View File

@@ -30,44 +30,19 @@
import atexit import atexit
import inspect import inspect
import json
import os import os
import platform import platform
import re import re
import select
import sys import sys
import subprocess import subprocess
import threading import threading
import lldb
currentDir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) currentDir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
sys.path.insert(1, currentDir) sys.path.insert(1, currentDir)
from dumper import * from dumper import *
lldbCmd = 'lldb'
if len(sys.argv) > 1:
lldbCmd = sys.argv[1]
proc = subprocess.Popen(args=[lldbCmd, '-P'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(path, error) = proc.communicate()
if error.startswith('lldb: invalid option -- P'):
sys.stdout.write('msg=\'Could not run "%s -P". Trying to find lldb.so from Xcode.\'@\n' % lldbCmd)
proc = subprocess.Popen(args=['xcode-select', '--print-path'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(path, error) = proc.communicate()
if len(error):
path = '/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/Resources/Python/'
sys.stdout.write('msg=\'Could not run "xcode-select --print-path"@\n')
sys.stdout.write('msg=\'Using hardcoded fallback at %s\'@\n' % path)
else:
path = path.strip() + '/../SharedFrameworks/LLDB.framework/Versions/A/Resources/Python/'
sys.stdout.write('msg=\'Using fallback at %s\'@\n' % path)
sys.path.insert(1, path.strip())
import lldb
####################################################################### #######################################################################
# #
# Helpers # Helpers
@@ -667,6 +642,9 @@ class Dumper(DumperBase):
else: else:
self.target = self.debugger.CreateTarget(None, None, None, True, error) self.target = self.debugger.CreateTarget(None, None, None, True, error)
if self.target.IsValid():
self.handleBreakpoints(args)
state = "inferiorsetupok" if self.target.IsValid() else "inferiorsetupfailed" state = "inferiorsetupok" if self.target.IsValid() else "inferiorsetupfailed"
self.report('state="%s",msg="%s",exe="%s"' % (state, error, self.executable_)) self.report('state="%s",msg="%s",exe="%s"' % (state, error, self.executable_))
@@ -1193,7 +1171,7 @@ class Dumper(DumperBase):
def report(self, stuff): def report(self, stuff):
with self.outputLock: with self.outputLock:
sys.stdout.write(stuff + "@\n") sys.stdout.write("@\n" + stuff + "@\n")
def reportStatus(self, msg): def reportStatus(self, msg):
self.report('statusmessage="%s"' % msg) self.report('statusmessage="%s"' % msg)
@@ -1573,7 +1551,7 @@ class Dumper(DumperBase):
self.report('success="%d",output="%s",error="%s"' % (success, output, error)) self.report('success="%d",output="%s",error="%s"' % (success, output, error))
def addExtraDumper(self, args): def addExtraDumper(self, args):
addDumperModule(args['path']) self.addDumperModule(args['path'])
self.report('ok') self.report('ok')
def updateData(self, args): def updateData(self, args):
@@ -1662,14 +1640,6 @@ class Dumper(DumperBase):
self.reportError(error) self.reportError(error)
self.reportVariables() self.reportVariables()
def execute(self, args):
getattr(self, args['cmd'])(args)
self.report('token="%s"' % args['token'])
if 'continuation' in args:
cont = args['continuation']
self.report('continuation="%s"' % cont)
def convertHash(args): def convertHash(args):
if sys.version_info[0] == 3: if sys.version_info[0] == 3:
return args return args
@@ -1693,36 +1663,19 @@ def convertHash(args):
return cargs return cargs
def doit():
db = Dumper()
db.report('lldbversion="%s"' % lldb.SBDebugger.GetVersionString())
db.reportState("enginesetupok")
line = sys.stdin.readline()
while line:
try:
db.execute(convertHash(json.loads(line)))
except:
(exType, exValue, exTraceback) = sys.exc_info()
showException("MAIN LOOP", exType, exValue, exTraceback)
line = sys.stdin.readline()
# Used in dumper auto test. # Used in dumper auto test.
# Usage: python lldbbridge.py /path/to/testbinary comma-separated-inames # Usage: python lldbbridge.py /path/to/testbinary comma-separated-inames
class Tester(Dumper): class Tester(Dumper):
def __init__(self): def __init__(self, binary, expandedINames):
Dumper.__init__(self) Dumper.__init__(self)
lldb.theDumper = self lldb.theDumper = self
self.expandedINames = set(sys.argv[3].split(',')) self.expandedINames = set(expandedINames)
self.passExceptions = True self.passExceptions = True
self.loadDumperFiles() self.loadDumperFiles()
error = lldb.SBError() error = lldb.SBError()
self.target = self.debugger.CreateTarget(sys.argv[2], self.target = self.debugger.CreateTarget(binary, None, None, True, error)
None, None, True, error)
if error.GetType(): if error.GetType():
warn("ERROR: %s" % error) warn("ERROR: %s" % error)
@@ -1730,6 +1683,7 @@ class Tester(Dumper):
s = threading.Thread(target=self.testLoop, args=[]) s = threading.Thread(target=self.testLoop, args=[])
s.start() s.start()
s.join(30)
def testLoop(self): def testLoop(self):
# Disable intermediate reporting. # Disable intermediate reporting.
@@ -1801,11 +1755,3 @@ class Tester(Dumper):
#self.report("ENV=%s" % os.environ.items()) #self.report("ENV=%s" % os.environ.items())
#self.report("DUMPER=%s" % self.qqDumpers) #self.report("DUMPER=%s" % self.qqDumpers)
lldb.SBDebugger.Destroy(self.debugger) lldb.SBDebugger.Destroy(self.debugger)
if __name__ == "__main__":
if len(sys.argv) > 2:
Tester()
else:
doit()

View File

@@ -129,10 +129,9 @@ void LldbEngine::runCommand(const Command &command)
QTC_ASSERT(m_lldbProc.state() == QProcess::Running, notifyEngineIll()); QTC_ASSERT(m_lldbProc.state() == QProcess::Running, notifyEngineIll());
++m_lastToken; ++m_lastToken;
QByteArray token = QByteArray::number(m_lastToken); QByteArray token = QByteArray::number(m_lastToken);
QByteArray cmd = "{\"cmd\":\"" + command.function + "\"," QByteArray cmd = command.function + "({" + command.args + "})";
+ command.args + "\"token\":" + token + "}\n"; showMessage(_(token + cmd + '\n'), LogInput);
showMessage(_(token + cmd), LogInput); m_lldbProc.write("sc db." + cmd + "\n");
m_lldbProc.write(cmd);
} }
void LldbEngine::debugLastCommand() void LldbEngine::debugLastCommand()
@@ -246,16 +245,12 @@ void LldbEngine::startLldb()
connect(this, &LldbEngine::outputReady, connect(this, &LldbEngine::outputReady,
this, &LldbEngine::handleResponse, Qt::QueuedConnection); this, &LldbEngine::handleResponse, Qt::QueuedConnection);
QStringList args; showMessage(_("STARTING LLDB: ") + m_lldbCmd);
args.append(_("-i"));
args.append(ICore::resourcePath() + _("/debugger/lldbbridge.py"));
args.append(m_lldbCmd);
showMessage(_("STARTING LLDB: python ") + args.join(QLatin1Char(' ')));
m_lldbProc.setEnvironment(startParameters().environment.toStringList()); m_lldbProc.setEnvironment(startParameters().environment.toStringList());
if (!startParameters().workingDirectory.isEmpty()) if (!startParameters().workingDirectory.isEmpty())
m_lldbProc.setWorkingDirectory(startParameters().workingDirectory); m_lldbProc.setWorkingDirectory(startParameters().workingDirectory);
m_lldbProc.start(_("python"), args); m_lldbProc.start(m_lldbCmd);
if (!m_lldbProc.waitForStarted()) { if (!m_lldbProc.waitForStarted()) {
const QString msg = tr("Unable to start LLDB \"%1\": %2") const QString msg = tr("Unable to start LLDB \"%1\": %2")
@@ -265,6 +260,21 @@ void LldbEngine::startLldb()
if (!msg.isEmpty()) if (!msg.isEmpty())
ICore::showWarningWithOptions(tr("Adapter start failed."), msg); ICore::showWarningWithOptions(tr("Adapter start failed."), msg);
} }
showMessage(_("ADAPTER STARTED"));
showStatusMessage(tr("Setting up inferior..."));
const QByteArray dumperSourcePath =
ICore::resourcePath().toLocal8Bit() + "/debugger/";
m_lldbProc.write("sc sys.path.insert(1, '" + dumperSourcePath + "')\n");
m_lldbProc.write("sc from lldbbridge import *\n");
m_lldbProc.write("sc print(dir())\n");
m_lldbProc.write("sc db = Dumper()\n");
m_lldbProc.write("sc db.report('lldbversion=\"%s\"' % lldb.SBDebugger.GetVersionString())\n");
showMessage(_("ENGINE SUCCESSFULLY STARTED"));
notifyEngineSetupOk();
} }
void LldbEngine::setupInferior() void LldbEngine::setupInferior()
@@ -299,6 +309,8 @@ void LldbEngine::setupInferior()
cmd.arg("useTerminal", sp.useTerminal); cmd.arg("useTerminal", sp.useTerminal);
cmd.arg("startMode", sp.startMode); cmd.arg("startMode", sp.startMode);
attemptBreakpointSynchronizationHelper(&cmd);
cmd.beginList("processArgs"); cmd.beginList("processArgs");
foreach (const QString &arg, args.toUnixArgs()) foreach (const QString &arg, args.toUnixArgs())
cmd.arg(arg.toUtf8().toHex()); cmd.arg(arg.toUtf8().toHex());
@@ -338,19 +350,7 @@ void LldbEngine::setupInferior()
void LldbEngine::runEngine() void LldbEngine::runEngine()
{ {
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); QTC_ASSERT(state() == EngineRunRequested, qDebug() << state(); return);
Command cmd("handleBreakpoints");
if (attemptBreakpointSynchronizationHelper(&cmd)) {
runEngine2();
} else {
cmd.arg("continuation", "runEngine2");
runCommand(cmd);
}
}
void LldbEngine::runEngine2()
{
showStatusMessage(tr("Running requested..."), 5000); showStatusMessage(tr("Running requested..."), 5000);
runCommand("runEngine"); runCommand("runEngine");
} }
@@ -446,8 +446,6 @@ void LldbEngine::handleResponse(const QByteArray &response)
refreshDisassembly(item); refreshDisassembly(item);
else if (name == "memory") else if (name == "memory")
refreshMemory(item); refreshMemory(item);
else if (name == "continuation")
runContinuation(item);
else if (name == "full-backtrace") else if (name == "full-backtrace")
showFullBacktrace(item); showFullBacktrace(item);
else if (name == "statusmessage") { else if (name == "statusmessage") {
@@ -465,12 +463,6 @@ void LldbEngine::showFullBacktrace(const GdbMi &data)
QString::fromUtf8(QByteArray::fromHex(data.data()))); QString::fromUtf8(QByteArray::fromHex(data.data())));
} }
void LldbEngine::runContinuation(const GdbMi &data)
{
const QByteArray target = data.data();
QMetaObject::invokeMethod(this, target, Qt::QueuedConnection);
}
void LldbEngine::executeRunToLine(const ContextData &data) void LldbEngine::executeRunToLine(const ContextData &data)
{ {
resetLocation(); resetLocation();

View File

@@ -161,7 +161,6 @@ private:
Q_SLOT void readLldbStandardOutput(); Q_SLOT void readLldbStandardOutput();
Q_SLOT void readLldbStandardError(); Q_SLOT void readLldbStandardError();
Q_SLOT void handleResponse(const QByteArray &data); Q_SLOT void handleResponse(const QByteArray &data);
Q_SLOT void runEngine2();
Q_SLOT void updateAll(); Q_SLOT void updateAll();
Q_SLOT void updateStack(); Q_SLOT void updateStack();
Q_SLOT void updateLocals(); Q_SLOT void updateLocals();
@@ -184,7 +183,6 @@ private:
void refreshAddedBreakpoint(const GdbMi &bkpts); void refreshAddedBreakpoint(const GdbMi &bkpts);
void refreshChangedBreakpoint(const GdbMi &bkpts); void refreshChangedBreakpoint(const GdbMi &bkpts);
void refreshRemovedBreakpoint(const GdbMi &bkpts); void refreshRemovedBreakpoint(const GdbMi &bkpts);
void runContinuation(const GdbMi &data);
void showFullBacktrace(const GdbMi &data); void showFullBacktrace(const GdbMi &data);
typedef void (LldbEngine::*LldbCommandContinuation)(); typedef void (LldbEngine::*LldbCommandContinuation)();

View File

@@ -1210,13 +1210,11 @@ void tst_Dumpers::dumper()
expanded += iname; expanded += iname;
} }
QByteArray exe; QByteArray exe = m_debuggerBinary;
QStringList args; QStringList args;
QByteArray cmds; QByteArray cmds;
if (m_debuggerEngine == GdbEngine) { if (m_debuggerEngine == GdbEngine) {
exe = m_debuggerBinary;
const QFileInfo gdbBinaryFile(QString::fromLatin1(exe)); const QFileInfo gdbBinaryFile(QString::fromLatin1(exe));
const QByteArray uninstalledData = gdbBinaryFile.absolutePath().toLocal8Bit() + "/data-directory/python"; const QByteArray uninstalledData = gdbBinaryFile.absolutePath().toLocal8Bit() + "/data-directory/python";
@@ -1245,7 +1243,6 @@ void tst_Dumpers::dumper()
cmds += "quit\n"; cmds += "quit\n";
} else if (m_debuggerEngine == CdbEngine) { } else if (m_debuggerEngine == CdbEngine) {
exe = m_debuggerBinary;
args << QLatin1String("-aqtcreatorcdbext.dll") args << QLatin1String("-aqtcreatorcdbext.dll")
<< QLatin1String("-G") << QLatin1String("-G")
<< QLatin1String("-xi") << QLatin1String("-xi")
@@ -1258,15 +1255,19 @@ void tst_Dumpers::dumper()
cmds += "!qtcreatorcdbext.locals -t -D -e " + expanded + " -v -c 0\n" cmds += "!qtcreatorcdbext.locals -t -D -e " + expanded + " -v -c 0\n"
"q\n"; "q\n";
} else if (m_debuggerEngine == LldbEngine) { } else if (m_debuggerEngine == LldbEngine) {
exe = "python";
args << QLatin1String(dumperDir + "/lldbbridge.py")
<< QString::fromUtf8(m_debuggerBinary)
<< t->buildPath + QLatin1String("/doit")
<< QString::fromUtf8(expanded);
QFile fullLldb(t->buildPath + QLatin1String("/lldbcommand.txt")); QFile fullLldb(t->buildPath + QLatin1String("/lldbcommand.txt"));
fullLldb.setPermissions(QFile::ReadOwner|QFile::WriteOwner|QFile::ExeOwner|QFile::ReadGroup|QFile::ReadOther); fullLldb.setPermissions(QFile::ReadOwner|QFile::WriteOwner|QFile::ExeOwner|QFile::ReadGroup|QFile::ReadOther);
fullLldb.open(QIODevice::WriteOnly); fullLldb.open(QIODevice::WriteOnly);
fullLldb.write(exe + ' ' + args.join(QLatin1String(" ")).toUtf8()); fullLldb.write(exe + ' ' + args.join(QLatin1String(" ")).toUtf8() + '\n');
cmds = "sc import sys\n"
"sc sys.path.insert(1, '" + dumperDir + "')\n"
"sc from lldbbridge import *\n"
"sc print(dir())\n"
"sc Tester('" + t->buildPath.toLatin1() + "/doit', '" + expanded + "')\n"
"quit\n";
fullLldb.write(cmds);
fullLldb.close(); fullLldb.close();
} }