Fix debugging on Android arm64/x86_64

On Android 64, there is no lib/ symlink anymore, so we need to upload
gdbserver from QtCreator.

Change-Id: Ib6f6d9b623dc61b72dd434ce1b3b409e880bdeaa
Reviewed-by: Vikas Pachdha <vikas.pachdha@qt.io>
This commit is contained in:
BogDan Vatra
2018-10-01 14:22:49 +03:00
parent 8f987866b6
commit 25264d9bd9
8 changed files with 71 additions and 25 deletions

View File

@@ -443,7 +443,8 @@ static bool isGuiThread()
}
SynchronousProcessResponse SynchronousProcess::run(const QString &binary,
const QStringList &args)
const QStringList &args,
const QByteArray &writeData)
{
if (debug)
qDebug() << '>' << Q_FUNC_INFO << binary << args;
@@ -454,8 +455,20 @@ SynchronousProcessResponse SynchronousProcess::run(const QString &binary,
// executable cannot be found in the path. Do not start the
// event loop in that case.
d->m_binary = binary;
d->m_process.start(binary, args, QIODevice::ReadOnly);
d->m_process.start(binary, args, writeData.isEmpty() ? QIODevice::ReadOnly : QIODevice::ReadWrite);
connect(&d->m_process, &QProcess::started, this, [this, writeData] {
if (!writeData.isEmpty()) {
int pos = 0;
int sz = writeData.size();
do {
d->m_process.waitForBytesWritten();
auto res = d->m_process.write(writeData.constData() + pos, sz - pos);
if (res > 0) pos += res;
} while (pos < sz);
d->m_process.waitForBytesWritten();
}
d->m_process.closeWriteChannel();
});
if (!d->m_startFailure) {
d->m_timer.start();
if (isGuiThread())

View File

@@ -127,7 +127,7 @@ public:
ExitCodeInterpreter exitCodeInterpreter() const;
// Starts an nested event loop and runs the binary with the arguments
SynchronousProcessResponse run(const QString &binary, const QStringList &args);
SynchronousProcessResponse run(const QString &binary, const QStringList &args, const QByteArray &writeData = {});
// Starts the binary with the arguments blocking the UI fully
SynchronousProcessResponse runBlocking(const QString &binary, const QStringList &args);

View File

@@ -768,6 +768,27 @@ FileName AndroidConfig::ndkLocation() const
return m_ndkLocation;
}
static inline QString gdbServerArch(const Abi &abi)
{
switch (abi.architecture()) {
case Abi::X86Architecture:
return abi.wordWidth() == 64 ? QString{"x86_64"} : QString{"x86"};
case Abi::ArmArchitecture:
return abi.wordWidth() == 64 ? QString{"arm64"} : QString{"arm"};
default: return {};
};
}
FileName AndroidConfig::gdbServer(const ProjectExplorer::Abi &abi) const
{
FileName path = AndroidConfigurations::currentConfig().ndkLocation();
path.appendPath(QString::fromLatin1("prebuilt/android-%1/gdbserver/gdbserver")
.arg(gdbServerArch(abi)));
if (path.exists())
return path;
return {};
}
QVersionNumber AndroidConfig::ndkVersion() const
{
QVersionNumber version;
@@ -1081,7 +1102,7 @@ void AndroidConfigurations::updateAutomaticKitList()
QVariant id = Debugger::DebuggerItemManager::registerDebugger(debugger);
Debugger::DebuggerKitInformation::setDebugger(toSetup, id);
AndroidGdbServerKitInformation::setGdbSever(toSetup, tc->suggestedGdbServer());
AndroidGdbServerKitInformation::setGdbSever(toSetup, currentConfig().gdbServer(tc->targetAbi()));
toSetup->makeSticky();
toSetup->setUnexpandedDisplayName(tr("Android for %1 (GCC %2, %3)")
.arg(static_cast<const AndroidQtVersion *>(qt)->targetArch())

View File

@@ -106,6 +106,7 @@ public:
void setSdkManagerToolArgs(const QStringList &args);
Utils::FileName ndkLocation() const;
Utils::FileName gdbServer(const ProjectExplorer::Abi &abi) const;
QVersionNumber ndkVersion() const;
void setNdkLocation(const Utils::FileName &ndkLocation);

View File

@@ -29,6 +29,7 @@
#include "androidconstants.h"
#include "androidmanager.h"
#include "androidrunconfiguration.h"
#include "androidgdbserverkitinformation.h"
#include <debugger/debuggerrunconfigurationaspect.h>
#include <projectexplorer/environmentaspect.h>
@@ -42,6 +43,7 @@
#include <utils/temporaryfile.h>
#include <utils/qtcprocess.h>
#include <utils/url.h>
#include <utils/fileutils.h>
#include <QLoggingCategory>
#include <QTcpServer>
@@ -222,6 +224,7 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
<< "Extra Start Args:" << m_amStartExtraArgs
<< "Before Start ADB cmds:" << m_beforeStartAdbCommands
<< "After finish ADB cmds:" << m_afterFinishAdbCommands;
m_gdbserverPath = AndroidGdbServerKitInformation::gdbServer(target->kit()).toString();
}
AndroidRunnerWorker::~AndroidRunnerWorker()
@@ -255,13 +258,13 @@ bool AndroidRunnerWorker::adbShellAmNeedsQuotes()
return !oldSdk;
}
bool AndroidRunnerWorker::runAdb(const QStringList &args, int timeoutS)
bool AndroidRunnerWorker::runAdb(const QStringList &args, int timeoutS, const QByteArray &writeData)
{
QStringList adbArgs = selector() + args;
qCDebug(androidRunWorkerLog) << "ADB command: " << m_adb << adbArgs.join(' ');
Utils::SynchronousProcess adb;
adb.setTimeoutS(timeoutS);
Utils::SynchronousProcessResponse response = adb.run(m_adb, adbArgs);
Utils::SynchronousProcessResponse response = adb.run(m_adb, adbArgs, writeData);
m_lastRunAdbError = response.exitMessage(m_adb, timeoutS);
m_lastRunAdbRawOutput = response.allRawOutput();
bool success = response.result == Utils::SynchronousProcessResponse::Finished;
@@ -269,6 +272,18 @@ bool AndroidRunnerWorker::runAdb(const QStringList &args, int timeoutS)
return success;
}
bool AndroidRunnerWorker::uploadFile(const QString &from, const QString &to, const QString &flags)
{
QFile f(from);
if (!f.open(QIODevice::ReadOnly))
return false;
runAdb({"shell", "run-as", m_packageName, "rm", to});
auto res = runAdb({"shell", "run-as", m_packageName, "sh", "-c", QString("'cat > %1'").arg(to)}, 60, f.readAll());
if (!res)
return false;
return runAdb({"shell", "run-as", m_packageName, "chmod", flags, to});
}
void AndroidRunnerWorker::adbKill(qint64 pid)
{
runAdb({"shell", "kill", "-9", QString::number(pid)});
@@ -411,10 +426,16 @@ void AndroidRunnerWorker::asyncStartHelper()
runAdb({"shell", "run-as", m_packageName, "chmod", "a+x", packageDir});
QString gdbServerExecutable;
QString gdbServerPrefix = "./lib/";
if (!runAdb({"shell", "run-as", m_packageName, "ls", "lib/"})) {
if (m_gdbserverPath.isEmpty()) {
emit remoteProcessFinished(tr("Failed to get process path. Reason: %1.").arg(m_lastRunAdbError));
return;
}
uploadFile(m_gdbserverPath, "gdbserver");
runAdb({"shell", "run-as", m_packageName, "ls"});
gdbServerPrefix = "./";
}
for (const auto &line: m_lastRunAdbRawOutput.split('\n')) {
if (line.indexOf("gdbserver") != -1/* || line.indexOf("lldb-server") != -1*/) {
@@ -433,7 +454,7 @@ void AndroidRunnerWorker::asyncStartHelper()
runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket});
std::unique_ptr<QProcess, Deleter> gdbServerProcess(new QProcess, deleter);
gdbServerProcess->start(m_adb, selector() << "shell" << "run-as"
<< m_packageName << "lib/" + gdbServerExecutable
<< m_packageName << gdbServerPrefix + gdbServerExecutable
<< "--multi" << "+" + gdbServerSocket);
if (!gdbServerProcess->waitForStarted()) {
emit remoteProcessFinished(tr("Failed to start C++ debugger."));

View File

@@ -47,7 +47,8 @@ public:
AndroidRunnerWorker(ProjectExplorer::RunWorker *runner, const QString &packageName);
~AndroidRunnerWorker() override;
bool adbShellAmNeedsQuotes();
bool runAdb(const QStringList &args, int timeoutS = 10);
bool runAdb(const QStringList &args, int timeoutS = 10, const QByteArray &writeData = {});
bool uploadFile(const QString &from, const QString &to, const QString &flags = "+x");
void adbKill(qint64 pid);
QStringList selector() const;
void forceStop();
@@ -110,6 +111,7 @@ protected:
int m_apiLevel = -1;
QString m_extraAppParams;
Utils::Environment m_extraEnvVars;
QString m_gdbserverPath;
};
} // namespace Internal

View File

@@ -193,19 +193,7 @@ FileName AndroidToolChain::suggestedDebugger() const
FileName AndroidToolChain::suggestedGdbServer() const
{
FileName path = AndroidConfigurations::currentConfig().ndkLocation();
path.appendPath(QString::fromLatin1("prebuilt/android-%1/gdbserver/gdbserver")
.arg(Abi::toString(targetAbi().architecture())));
if (path.exists())
return path;
path = AndroidConfigurations::currentConfig().ndkLocation();
path.appendPath(QString::fromLatin1("toolchains/%1-%2/prebuilt/gdbserver")
.arg(AndroidConfig::toolchainPrefix(targetAbi()))
.arg(m_ndkToolChainVersion));
if (path.exists())
return path;
return FileName();
return AndroidConfigurations::currentConfig().gdbServer(targetAbi());
}
QVariantMap AndroidToolChain::toMap() const

View File

@@ -2529,7 +2529,7 @@ Context CppDebuggerEngine::languageContext() const
void CppDebuggerEngine::validateExecutable()
{
DebuggerRunParameters &rp = mutableRunParameters();
const bool warnOnRelease = boolSetting(WarnOnReleaseBuilds);
const bool warnOnRelease = boolSetting(WarnOnReleaseBuilds) && rp.toolChainAbi.osFlavor() != Abi::AndroidLinuxFlavor;
bool warnOnInappropriateDebugger = false;
QString detailedWarning;
switch (rp.toolChainAbi.binaryFormat()) {