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