forked from qt-creator/qt-creator
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:
@@ -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()
|
|
||||||
|
|
||||||
|
@@ -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();
|
||||||
|
@@ -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)();
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user