forked from qt-creator/qt-creator
Android: Start lldb-server and attach
Change-Id: Id7c45d9161d3389e9de419835c312d87916a34bc Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -891,14 +891,20 @@ class Dumper(DumperBase):
|
|||||||
if (self.startMode_ == DebuggerStartMode.AttachToRemoteServer
|
if (self.startMode_ == DebuggerStartMode.AttachToRemoteServer
|
||||||
or self.startMode_ == DebuggerStartMode.AttachToRemoteProcess):
|
or self.startMode_ == DebuggerStartMode.AttachToRemoteProcess):
|
||||||
|
|
||||||
|
# For some reason, 127.0.0.1 doesn't work with Android.
|
||||||
remote_channel = 'connect://' + self.remoteChannel_
|
remote_channel = ('connect://'
|
||||||
|
+ self.remoteChannel_.replace('127.0.0.1', 'localhost'))
|
||||||
connect_options = lldb.SBPlatformConnectOptions(remote_channel)
|
connect_options = lldb.SBPlatformConnectOptions(remote_channel)
|
||||||
|
|
||||||
res = self.target.GetPlatform().ConnectRemote(connect_options)
|
res = self.target.GetPlatform().ConnectRemote(connect_options)
|
||||||
DumperBase.warn("CONNECT: %s %s %s" % (res,
|
DumperBase.warn("CONNECT: %s %s %s %s" % (res,
|
||||||
|
remote_channel,
|
||||||
self.target.GetPlatform().GetName(),
|
self.target.GetPlatform().GetName(),
|
||||||
self.target.GetPlatform().IsConnected()))
|
self.target.GetPlatform().IsConnected()))
|
||||||
|
if not res.Success():
|
||||||
|
self.report(self.describeError(error))
|
||||||
|
self.reportState('enginerunfailed')
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
broadcaster = self.target.GetBroadcaster()
|
broadcaster = self.target.GetBroadcaster()
|
||||||
@@ -928,7 +934,7 @@ class Dumper(DumperBase):
|
|||||||
def prepare(self, args):
|
def prepare(self, args):
|
||||||
error = lldb.SBError()
|
error = lldb.SBError()
|
||||||
|
|
||||||
if self.attachPid_ > 0:
|
if self.attachPid_ > 0 and self.platform_ != "remote-linux":
|
||||||
attachInfo = lldb.SBAttachInfo(self.attachPid_)
|
attachInfo = lldb.SBAttachInfo(self.attachPid_)
|
||||||
self.process = self.target.Attach(attachInfo, error)
|
self.process = self.target.Attach(attachInfo, error)
|
||||||
if not error.Success():
|
if not error.Success():
|
||||||
@@ -944,6 +950,7 @@ class Dumper(DumperBase):
|
|||||||
self.reportState('enginerunandinferiorstopok')
|
self.reportState('enginerunandinferiorstopok')
|
||||||
else:
|
else:
|
||||||
self.reportState('enginerunandinferiorrunok')
|
self.reportState('enginerunandinferiorrunok')
|
||||||
|
|
||||||
elif (self.startMode_ == DebuggerStartMode.AttachToRemoteServer
|
elif (self.startMode_ == DebuggerStartMode.AttachToRemoteServer
|
||||||
or self.startMode_ == DebuggerStartMode.AttachToRemoteProcess):
|
or self.startMode_ == DebuggerStartMode.AttachToRemoteProcess):
|
||||||
|
|
||||||
@@ -953,6 +960,9 @@ class Dumper(DumperBase):
|
|||||||
launchInfo = lldb.SBLaunchInfo(self.processArgs_)
|
launchInfo = lldb.SBLaunchInfo(self.processArgs_)
|
||||||
#launchInfo.SetWorkingDirectory(self.workingDirectory_)
|
#launchInfo.SetWorkingDirectory(self.workingDirectory_)
|
||||||
launchInfo.SetWorkingDirectory('/tmp')
|
launchInfo.SetWorkingDirectory('/tmp')
|
||||||
|
if self.platform_ == 'remote-android':
|
||||||
|
launchInfo.SetWorkingDirectory('/data/local/tmp')
|
||||||
|
launchInfo.SetEnvironmentEntries(self.environment_, False)
|
||||||
launchInfo.SetExecutableFile(f, True)
|
launchInfo.SetExecutableFile(f, True)
|
||||||
|
|
||||||
DumperBase.warn("TARGET: %s" % self.target)
|
DumperBase.warn("TARGET: %s" % self.target)
|
||||||
|
@@ -105,6 +105,7 @@ AndroidDebugSupport::AndroidDebugSupport(RunControl *runControl, const QString &
|
|||||||
: Debugger::DebuggerRunTool(runControl)
|
: Debugger::DebuggerRunTool(runControl)
|
||||||
{
|
{
|
||||||
setId("AndroidDebugger");
|
setId("AndroidDebugger");
|
||||||
|
setLldbPlatform("remote-android");
|
||||||
m_runner = new AndroidRunner(runControl, intentName);
|
m_runner = new AndroidRunner(runControl, intentName);
|
||||||
addStartDependency(m_runner);
|
addStartDependency(m_runner);
|
||||||
}
|
}
|
||||||
|
@@ -307,7 +307,7 @@ bool AndroidRunnerWorker::runAdb(const QStringList &args, QString *stdOut,
|
|||||||
return result.success();
|
return result.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidRunnerWorker::uploadDebugServer()
|
bool AndroidRunnerWorker::uploadDebugServer(const QString &debugServerFileName)
|
||||||
{
|
{
|
||||||
// Push the gdbserver or lldb-server to temp location and then to package dir.
|
// Push the gdbserver or lldb-server to temp location and then to package dir.
|
||||||
// the files can't be pushed directly to package because of permissions.
|
// the files can't be pushed directly to package because of permissions.
|
||||||
@@ -322,7 +322,7 @@ bool AndroidRunnerWorker::uploadDebugServer()
|
|||||||
std::unique_ptr<QString, decltype (cleanUp)>
|
std::unique_ptr<QString, decltype (cleanUp)>
|
||||||
tempGdbServerPath(new QString("/data/local/tmp/%1"), cleanUp);
|
tempGdbServerPath(new QString("/data/local/tmp/%1"), cleanUp);
|
||||||
|
|
||||||
// Get a unique temp file name for gdbserver copy
|
// Get a unique temp file name for gdb/lldbserver copy
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while (deviceFileExists(tempGdbServerPath->arg(++count))) {
|
while (deviceFileExists(tempGdbServerPath->arg(++count))) {
|
||||||
if (count > GdbTempFileMaxCounter) {
|
if (count > GdbTempFileMaxCounter) {
|
||||||
@@ -340,11 +340,11 @@ bool AndroidRunnerWorker::uploadDebugServer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy gdbserver from temp location to app directory
|
// Copy gdbserver from temp location to app directory
|
||||||
if (!runAdb({"shell", "run-as", m_packageName, "cp" , *tempGdbServerPath, "./gdbserver"})) {
|
if (!runAdb({"shell", "run-as", m_packageName, "cp" , *tempGdbServerPath, debugServerFileName})) {
|
||||||
qCDebug(androidRunWorkerLog) << "Gdbserver copy from temp directory failed";
|
qCDebug(androidRunWorkerLog) << "Gdbserver copy from temp directory failed";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QTC_ASSERT(runAdb({"shell", "run-as", m_packageName, "chmod", "777", "./gdbserver"}),
|
QTC_ASSERT(runAdb({"shell", "run-as", m_packageName, "chmod", "777", debugServerFileName}),
|
||||||
qCDebug(androidRunWorkerLog) << "Gdbserver chmod 777 failed.");
|
qCDebug(androidRunWorkerLog) << "Gdbserver chmod 777 failed.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -500,6 +500,11 @@ void AndroidRunnerWorker::asyncStartHelper()
|
|||||||
// e.g. on Android 8 with NDK 10e
|
// e.g. on Android 8 with NDK 10e
|
||||||
runAdb({"shell", "run-as", m_packageName, "chmod", "a+x", packageDir.trimmed()});
|
runAdb({"shell", "run-as", m_packageName, "chmod", "a+x", packageDir.trimmed()});
|
||||||
|
|
||||||
|
QString debugServerFile;
|
||||||
|
if (m_useLldb) {
|
||||||
|
debugServerFile = "./lldb-server";
|
||||||
|
uploadDebugServer(debugServerFile);
|
||||||
|
} else {
|
||||||
QString debugServerExecutable = "gdbserver";
|
QString debugServerExecutable = "gdbserver";
|
||||||
QString debugServerPrefix = "./lib/";
|
QString debugServerPrefix = "./lib/";
|
||||||
auto findGdbServer = [this, &debugServerExecutable, debugServerPrefix](const QString& gdbEx) {
|
auto findGdbServer = [this, &debugServerExecutable, debugServerPrefix](const QString& gdbEx) {
|
||||||
@@ -513,7 +518,7 @@ void AndroidRunnerWorker::asyncStartHelper()
|
|||||||
// Armv8. symlink lib is not available.
|
// Armv8. symlink lib is not available.
|
||||||
// Kill the previous instances of gdbserver. Do this before copying the gdbserver.
|
// Kill the previous instances of gdbserver. Do this before copying the gdbserver.
|
||||||
runAdb({"shell", "run-as", m_packageName, "killall", debugServerExecutable});
|
runAdb({"shell", "run-as", m_packageName, "killall", debugServerExecutable});
|
||||||
if (!m_debugServerPath.isEmpty() && uploadDebugServer()) {
|
if (!m_debugServerPath.isEmpty() && uploadDebugServer("./gdbserver")) {
|
||||||
debugServerPrefix = "./";
|
debugServerPrefix = "./";
|
||||||
} else {
|
} else {
|
||||||
emit remoteProcessFinished(tr("Cannot find or copy C++ debug server."));
|
emit remoteProcessFinished(tr("Cannot find or copy C++ debug server."));
|
||||||
@@ -523,9 +528,10 @@ void AndroidRunnerWorker::asyncStartHelper()
|
|||||||
qCDebug(androidRunWorkerLog) << "Found GDB server under ./lib";
|
qCDebug(androidRunWorkerLog) << "Found GDB server under ./lib";
|
||||||
runAdb({"shell", "run-as", m_packageName, "killall", debugServerExecutable});
|
runAdb({"shell", "run-as", m_packageName, "killall", debugServerExecutable});
|
||||||
}
|
}
|
||||||
|
debugServerFile = debugServerPrefix + debugServerExecutable;
|
||||||
|
}
|
||||||
QString debuggerServerErr;
|
QString debuggerServerErr;
|
||||||
if (!startDebuggerServer(packageDir, debugServerPrefix, debugServerExecutable, &debuggerServerErr)) {
|
if (!startDebuggerServer(packageDir, debugServerFile, &debuggerServerErr)) {
|
||||||
emit remoteProcessFinished(debuggerServerErr);
|
emit remoteProcessFinished(debuggerServerErr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -578,21 +584,39 @@ void AndroidRunnerWorker::asyncStartHelper()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidRunnerWorker::startDebuggerServer(const QString &packageDir,
|
bool AndroidRunnerWorker::startDebuggerServer(const QString &packageDir,
|
||||||
const QString &debugServerPrefix,
|
const QString &debugServerFile,
|
||||||
const QString &debugServerExecutable,
|
|
||||||
QString *errorStr)
|
QString *errorStr)
|
||||||
{
|
{
|
||||||
|
if (m_useLldb) {
|
||||||
|
QString lldbServerErr;
|
||||||
|
QStringList lldbServerArgs = selector();
|
||||||
|
lldbServerArgs << "shell" << "run-as" << m_packageName << debugServerFile
|
||||||
|
<< "platform"
|
||||||
|
<< "--server"
|
||||||
|
<< "--listen" << QString("*:%1").arg(m_localDebugServerPort.toString());
|
||||||
|
m_debugServerProcess.reset(AndroidManager::runAdbCommandDetached(lldbServerArgs, &lldbServerErr));
|
||||||
|
|
||||||
|
if (!m_debugServerProcess) {
|
||||||
|
qCDebug(androidRunWorkerLog) << "Debugger process failed to start" << lldbServerErr;
|
||||||
|
if (errorStr)
|
||||||
|
*errorStr = tr("Failed to start debugger server.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
qCDebug(androidRunWorkerLog) << "Debugger process started";
|
||||||
|
m_debugServerProcess->setObjectName("AndroidDebugServerProcess");
|
||||||
|
|
||||||
|
} else {
|
||||||
QString gdbServerSocket = packageDir + "/debug-socket";
|
QString gdbServerSocket = packageDir + "/debug-socket";
|
||||||
runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket});
|
runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket});
|
||||||
|
|
||||||
QString gdbProcessErr;
|
QString gdbProcessErr;
|
||||||
QStringList gdbServerArgs = selector();
|
QStringList gdbServerErr = selector();
|
||||||
gdbServerArgs << "shell" << "run-as" << m_packageName << debugServerPrefix + debugServerExecutable
|
gdbServerErr << "shell" << "run-as" << m_packageName << debugServerFile
|
||||||
<< "--multi" << "+" + gdbServerSocket;
|
<< "--multi" << "+" + gdbServerSocket;
|
||||||
m_debugServerProcess.reset(AndroidManager::runAdbCommandDetached(gdbServerArgs, &gdbProcessErr));
|
m_debugServerProcess.reset(AndroidManager::runAdbCommandDetached(gdbServerErr, &gdbProcessErr));
|
||||||
|
|
||||||
if (!m_debugServerProcess) {
|
if (!m_debugServerProcess) {
|
||||||
qCDebug(androidRunWorkerLog) << "Debugger process failed to start" << gdbProcessErr;
|
qCDebug(androidRunWorkerLog) << "Debugger process failed to start" << gdbServerErr;
|
||||||
if (errorStr)
|
if (errorStr)
|
||||||
*errorStr = tr("Failed to start debugger server.");
|
*errorStr = tr("Failed to start debugger server.");
|
||||||
return false;
|
return false;
|
||||||
@@ -609,6 +633,7 @@ bool AndroidRunnerWorker::startDebuggerServer(const QString &packageDir,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_afterFinishAdbCommands.push_back(removeForward.join(' '));
|
m_afterFinishAdbCommands.push_back(removeForward.join(' '));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -665,7 +690,7 @@ void AndroidRunnerWorker::handleJdbWaiting()
|
|||||||
void AndroidRunnerWorker::handleJdbSettled()
|
void AndroidRunnerWorker::handleJdbSettled()
|
||||||
{
|
{
|
||||||
qCDebug(androidRunWorkerLog) << "Handle JDB settled";
|
qCDebug(androidRunWorkerLog) << "Handle JDB settled";
|
||||||
auto waitForCommand = [&]() {
|
auto waitForCommand = [this]() {
|
||||||
for (int i= 0; i < 5 && m_jdbProcess->state() == QProcess::Running; ++i) {
|
for (int i= 0; i < 5 && m_jdbProcess->state() == QProcess::Running; ++i) {
|
||||||
m_jdbProcess->waitForReadyRead(500);
|
m_jdbProcess->waitForReadyRead(500);
|
||||||
QByteArray lines = m_jdbProcess->readAll();
|
QByteArray lines = m_jdbProcess->readAll();
|
||||||
@@ -708,7 +733,7 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
|
|||||||
if (pid == -1) {
|
if (pid == -1) {
|
||||||
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.")
|
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.")
|
||||||
.arg(m_packageName));
|
.arg(m_packageName));
|
||||||
// App died/killed. Reset log, monitor, jdb & gdb processes.
|
// App died/killed. Reset log, monitor, jdb & gdbserver/lldb-server processes.
|
||||||
m_adbLogcatProcess.reset();
|
m_adbLogcatProcess.reset();
|
||||||
m_psIsAlive.reset();
|
m_psIsAlive.reset();
|
||||||
m_jdbProcess.reset();
|
m_jdbProcess.reset();
|
||||||
|
@@ -72,11 +72,10 @@ signals:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void asyncStartHelper();
|
void asyncStartHelper();
|
||||||
bool startDebuggerServer(const QString &packageDir, const QString &gdbServerPrefix,
|
bool startDebuggerServer(const QString &packageDir, const QString &debugServerFile, QString *errorStr = nullptr);
|
||||||
const QString &debugServerExecutable, QString *errorStr = nullptr);
|
|
||||||
bool deviceFileExists(const QString &filePath);
|
bool deviceFileExists(const QString &filePath);
|
||||||
bool packageFileExists(const QString& filePath);
|
bool packageFileExists(const QString& filePath);
|
||||||
bool uploadDebugServer();
|
bool uploadDebugServer(const QString &debugServerFileName);
|
||||||
|
|
||||||
enum class JDBState {
|
enum class JDBState {
|
||||||
Idle,
|
Idle,
|
||||||
|
Reference in New Issue
Block a user