Android: Start lldb-server and attach

Change-Id: Id7c45d9161d3389e9de419835c312d87916a34bc
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
hjk
2020-04-15 09:01:38 +02:00
parent 0603eb925f
commit 7d3c6f7c02
4 changed files with 97 additions and 62 deletions

View File

@@ -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)

View File

@@ -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);
} }

View File

@@ -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,32 +500,38 @@ 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 debugServerExecutable = "gdbserver"; QString debugServerFile;
QString debugServerPrefix = "./lib/"; if (m_useLldb) {
auto findGdbServer = [this, &debugServerExecutable, debugServerPrefix](const QString& gdbEx) { debugServerFile = "./lldb-server";
if (!packageFileExists(debugServerPrefix + gdbEx)) uploadDebugServer(debugServerFile);
return false;
debugServerExecutable = gdbEx;
return true;
};
if (!findGdbServer("gdbserver") && !findGdbServer("libgdbserver.so")) {
// Armv8. symlink lib is not available.
// Kill the previous instances of gdbserver. Do this before copying the gdbserver.
runAdb({"shell", "run-as", m_packageName, "killall", debugServerExecutable});
if (!m_debugServerPath.isEmpty() && uploadDebugServer()) {
debugServerPrefix = "./";
} else {
emit remoteProcessFinished(tr("Cannot find or copy C++ debug server."));
return;
}
} else { } else {
qCDebug(androidRunWorkerLog) << "Found GDB server under ./lib"; QString debugServerExecutable = "gdbserver";
runAdb({"shell", "run-as", m_packageName, "killall", debugServerExecutable}); QString debugServerPrefix = "./lib/";
} auto findGdbServer = [this, &debugServerExecutable, debugServerPrefix](const QString& gdbEx) {
if (!packageFileExists(debugServerPrefix + gdbEx))
return false;
debugServerExecutable = gdbEx;
return true;
};
if (!findGdbServer("gdbserver") && !findGdbServer("libgdbserver.so")) {
// Armv8. symlink lib is not available.
// Kill the previous instances of gdbserver. Do this before copying the gdbserver.
runAdb({"shell", "run-as", m_packageName, "killall", debugServerExecutable});
if (!m_debugServerPath.isEmpty() && uploadDebugServer("./gdbserver")) {
debugServerPrefix = "./";
} else {
emit remoteProcessFinished(tr("Cannot find or copy C++ debug server."));
return;
}
} else {
qCDebug(androidRunWorkerLog) << "Found GDB server under ./lib";
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,37 +584,56 @@ 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)
{ {
QString gdbServerSocket = packageDir + "/debug-socket"; if (m_useLldb) {
runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket}); 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));
QString gdbProcessErr; if (!m_debugServerProcess) {
QStringList gdbServerArgs = selector(); qCDebug(androidRunWorkerLog) << "Debugger process failed to start" << lldbServerErr;
gdbServerArgs << "shell" << "run-as" << m_packageName << debugServerPrefix + debugServerExecutable if (errorStr)
<< "--multi" << "+" + gdbServerSocket; *errorStr = tr("Failed to start debugger server.");
m_debugServerProcess.reset(AndroidManager::runAdbCommandDetached(gdbServerArgs, &gdbProcessErr)); return false;
}
qCDebug(androidRunWorkerLog) << "Debugger process started";
m_debugServerProcess->setObjectName("AndroidDebugServerProcess");
if (!m_debugServerProcess) { } else {
qCDebug(androidRunWorkerLog) << "Debugger process failed to start" << gdbProcessErr; QString gdbServerSocket = packageDir + "/debug-socket";
if (errorStr) runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket});
*errorStr = tr("Failed to start debugger server.");
return false; QString gdbProcessErr;
QStringList gdbServerErr = selector();
gdbServerErr << "shell" << "run-as" << m_packageName << debugServerFile
<< "--multi" << "+" + gdbServerSocket;
m_debugServerProcess.reset(AndroidManager::runAdbCommandDetached(gdbServerErr, &gdbProcessErr));
if (!m_debugServerProcess) {
qCDebug(androidRunWorkerLog) << "Debugger process failed to start" << gdbServerErr;
if (errorStr)
*errorStr = tr("Failed to start debugger server.");
return false;
}
qCDebug(androidRunWorkerLog) << "Debugger process started";
m_debugServerProcess->setObjectName("AndroidDebugServerProcess");
QStringList removeForward{"forward", "--remove", "tcp:" + m_localDebugServerPort.toString()};
runAdb(removeForward);
if (!runAdb({"forward", "tcp:" + m_localDebugServerPort.toString(),
"localfilesystem:" + gdbServerSocket})) {
if (errorStr)
*errorStr = tr("Failed to forward C++ debugging ports.");
return false;
}
m_afterFinishAdbCommands.push_back(removeForward.join(' '));
} }
qCDebug(androidRunWorkerLog) << "Debugger process started";
m_debugServerProcess->setObjectName("AndroidDebugServerProcess");
QStringList removeForward{"forward", "--remove", "tcp:" + m_localDebugServerPort.toString()};
runAdb(removeForward);
if (!runAdb({"forward", "tcp:" + m_localDebugServerPort.toString(),
"localfilesystem:" + gdbServerSocket})) {
if (errorStr)
*errorStr = tr("Failed to forward C++ debugging ports.");
return false;
}
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();

View File

@@ -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,