Chad Smith 55b0d143d6
[lldb] fix Android host build failure: use of undeclared identifier 'HostInfo' (#163075)
This should fix
https://github.com/llvm/llvm-project/issues/163050#issuecomment-3394533840

Thank you for tagging me @trcrsired!

```
[105/1932] Building CXX object tools/lldb/source/Plugins/Platfor...d/CMakeFiles/lldbPluginPlatformAndroid.dir/PlatformAndroid.cpp.
FAILED: [code=1] tools/lldb/source/Plugins/Platform/Android/CMakeFiles/lldbPluginPlatformAndroid.dir/PlatformAndroid.cpp.o 
/home/cqwrteur/toolchains/llvm/x86_64-linux-gnu/llvm/bin/clang++ --target=aarch64-linux-android30 --sysroot=/home/cqwrteur/toolchains/llvm/aarch64-linux-android30/aarch64-linux-android30 -DGTEST_HAS_RTTI=0 -DHAVE_ROUND -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/cqwrteur/toolchains_build/toolchainbuildscripts/llvm/.artifacts/llvm/aarch64-linux-android30/llvm/tools/lldb/source/Plugins/Platform/Android -I/home/cqwrteur/toolchains_build/llvm-project/lldb/source/Plugins/Platform/Android -I/home/cqwrteur/toolchains_build/llvm-project/lldb/include -I/home/cqwrteur/toolchains_build/toolchainbuildscripts/llvm/.artifacts/llvm/aarch64-linux-android30/llvm/tools/lldb/include -I/home/cqwrteur/toolchains_build/toolchainbuildscripts/llvm/.artifacts/llvm/aarch64-linux-android30/llvm/include -I/home/cqwrteur/toolchains_build/llvm-project/llvm/include -I/home/cqwrteur/toolchains_build/llvm-project/llvm/../clang/include -I/home/cqwrteur/toolchains_build/toolchainbuildscripts/llvm/.artifacts/llvm/aarch64-linux-android30/llvm/tools/lldb/../clang/include -I/home/cqwrteur/toolchains_build/llvm-project/lldb/source -I/home/cqwrteur/toolchains_build/toolchainbuildscripts/llvm/.artifacts/llvm/aarch64-linux-android30/llvm/tools/lldb/source -isystem /home/cqwrteur/toolchains/llvm/aarch64-linux-android30/aarch64-linux-android30/usr/include/libxml2 -fuse-ld=lld -fuse-lipo=llvm-lipo -flto=thin -Wno-unused-command-line-argument -rtlib=compiler-rt -stdlib=libc++ --unwindlib=libunwind -lc++abi -stdlib=libc++ -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -flto=thin -Wno-unknown-pragmas -Wno-strict-aliasing -Wno-vla-extension -O3 -DNDEBUG -std=c++17 -fPIC  -fno-exceptions -funwind-tables -fno-rtti -MD -MT tools/lldb/source/Plugins/Platform/Android/CMakeFiles/lldbPluginPlatformAndroid.dir/PlatformAndroid.cpp.o -MF tools/lldb/source/Plugins/Platform/Android/CMakeFiles/lldbPluginPlatformAndroid.dir/PlatformAndroid.cpp.o.d -o tools/lldb/source/Plugins/Platform/Android/CMakeFiles/lldbPluginPlatformAndroid.dir/PlatformAndroid.cpp.o -c /home/cqwrteur/toolchains_build/llvm-project/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
/home/cqwrteur/toolchains_build/llvm-project/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp:66:48: error: use of undeclared identifier 'HostInfo'
   66 |     default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
      |                                                ^
1 error generated.
[118/1932] Linking CXX shared library lib/libLLVMAnalysis.so.22.0git
ninja: build stopped: subcommand failed.
llvm: Ninja build failed for aarch64-linux-android30
```
2025-10-13 09:08:50 -07:00

731 lines
25 KiB
C++

//===-- PlatformAndroid.cpp -----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/UriParser.h"
#include "lldb/ValueObject/ValueObject.h"
#include "AdbClient.h"
#include "PlatformAndroid.h"
#include "PlatformAndroidRemoteGDBServer.h"
#include "lldb/Target/Target.h"
#include <optional>
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::platform_android;
using namespace std::chrono;
LLDB_PLUGIN_DEFINE(PlatformAndroid)
namespace {
#define LLDB_PROPERTIES_android
#include "PlatformAndroidProperties.inc"
enum {
#define LLDB_PROPERTIES_android
#include "PlatformAndroidPropertiesEnum.inc"
};
class PluginProperties : public Properties {
public:
PluginProperties() {
m_collection_sp = std::make_shared<OptionValueProperties>(
PlatformAndroid::GetPluginNameStatic(false));
m_collection_sp->Initialize(g_android_properties);
}
};
static PluginProperties &GetGlobalProperties() {
static PluginProperties g_settings;
return g_settings;
}
uint32_t g_initialize_count = 0;
const unsigned int g_android_default_cache_size =
2048; // Fits inside 4k adb packet.
} // end of anonymous namespace
void PlatformAndroid::Initialize() {
PlatformLinux::Initialize();
if (g_initialize_count++ == 0) {
#if defined(__ANDROID__)
PlatformSP default_platform_sp(new PlatformAndroid(true));
default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
Platform::SetHostPlatform(default_platform_sp);
#endif
PluginManager::RegisterPlugin(
PlatformAndroid::GetPluginNameStatic(false),
PlatformAndroid::GetPluginDescriptionStatic(false),
PlatformAndroid::CreateInstance, PlatformAndroid::DebuggerInitialize);
}
}
void PlatformAndroid::Terminate() {
if (g_initialize_count > 0) {
if (--g_initialize_count == 0) {
PluginManager::UnregisterPlugin(PlatformAndroid::CreateInstance);
}
}
PlatformLinux::Terminate();
}
PlatformSP PlatformAndroid::CreateInstance(bool force, const ArchSpec *arch) {
Log *log = GetLog(LLDBLog::Platform);
if (log) {
const char *arch_name;
if (arch && arch->GetArchitectureName())
arch_name = arch->GetArchitectureName();
else
arch_name = "<null>";
const char *triple_cstr =
arch ? arch->GetTriple().getTriple().c_str() : "<null>";
LLDB_LOGF(log, "PlatformAndroid::%s(force=%s, arch={%s,%s})", __FUNCTION__,
force ? "true" : "false", arch_name, triple_cstr);
}
bool create = force;
if (!create && arch && arch->IsValid()) {
const llvm::Triple &triple = arch->GetTriple();
switch (triple.getVendor()) {
case llvm::Triple::PC:
create = true;
break;
#if defined(__ANDROID__)
// Only accept "unknown" for the vendor if the host is android and if
// "unknown" wasn't specified (it was just returned because it was NOT
// specified).
case llvm::Triple::VendorType::UnknownVendor:
create = !arch->TripleVendorWasSpecified();
break;
#endif
default:
break;
}
if (create) {
switch (triple.getEnvironment()) {
case llvm::Triple::Android:
break;
#if defined(__ANDROID__)
// Only accept "unknown" for the OS if the host is android and it
// "unknown" wasn't specified (it was just returned because it was NOT
// specified)
case llvm::Triple::EnvironmentType::UnknownEnvironment:
create = !arch->TripleEnvironmentWasSpecified();
break;
#endif
default:
create = false;
break;
}
}
}
if (create) {
LLDB_LOGF(log, "PlatformAndroid::%s() creating remote-android platform",
__FUNCTION__);
return PlatformSP(new PlatformAndroid(false));
}
LLDB_LOGF(
log, "PlatformAndroid::%s() aborting creation of remote-android platform",
__FUNCTION__);
return PlatformSP();
}
void PlatformAndroid::DebuggerInitialize(Debugger &debugger) {
if (!PluginManager::GetSettingForPlatformPlugin(debugger,
GetPluginNameStatic(false))) {
PluginManager::CreateSettingForPlatformPlugin(
debugger, GetGlobalProperties().GetValueProperties(),
"Properties for the Android platform plugin.",
/*is_global_property=*/true);
}
}
PlatformAndroid::PlatformAndroid(bool is_host)
: PlatformLinux(is_host), m_sdk_version(0) {}
llvm::StringRef PlatformAndroid::GetPluginDescriptionStatic(bool is_host) {
if (is_host)
return "Local Android user platform plug-in.";
return "Remote Android user platform plug-in.";
}
Status PlatformAndroid::ConnectRemote(Args &args) {
m_device_id.clear();
if (IsHost())
return Status::FromErrorString(
"can't connect to the host platform, always connected");
if (!m_remote_platform_sp)
m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer());
const char *url = args.GetArgumentAtIndex(0);
if (!url)
return Status::FromErrorString("URL is null.");
std::optional<URI> parsed_url = URI::Parse(url);
if (!parsed_url)
return Status::FromErrorStringWithFormat("Invalid URL: %s", url);
if (parsed_url->hostname != "localhost")
m_device_id = parsed_url->hostname.str();
auto error = PlatformLinux::ConnectRemote(args);
if (error.Success()) {
auto resolved_device_id_or_error = AdbClient::ResolveDeviceID(m_device_id);
if (!resolved_device_id_or_error)
return Status::FromError(resolved_device_id_or_error.takeError());
m_device_id = *resolved_device_id_or_error;
}
return error;
}
Status PlatformAndroid::GetFile(const FileSpec &source,
const FileSpec &destination) {
if (IsHost() || !m_remote_platform_sp)
return PlatformLinux::GetFile(source, destination);
FileSpec source_spec(source.GetPath(false), FileSpec::Style::posix);
if (source_spec.IsRelative())
source_spec = GetRemoteWorkingDirectory().CopyByAppendingPathComponent(
source_spec.GetPathAsConstString(false).GetStringRef());
Status error;
auto sync_service = GetSyncService(error);
// If sync service is available, try to use it
if (error.Success() && sync_service) {
uint32_t mode = 0, size = 0, mtime = 0;
error = sync_service->Stat(source_spec, mode, size, mtime);
if (error.Success()) {
if (mode != 0)
return sync_service->PullFile(source_spec, destination);
// mode == 0 can signify that adbd cannot access the file due security
// constraints - fall through to try "cat ..." as a fallback.
Log *log = GetLog(LLDBLog::Platform);
LLDB_LOGF(log, "Got mode == 0 on '%s': try to get file via 'shell cat'",
source_spec.GetPath(false).c_str());
}
}
// Fallback to shell cat command if sync service failed or returned mode == 0
std::string source_file = source_spec.GetPath(false);
Log *log = GetLog(LLDBLog::Platform);
LLDB_LOGF(log, "Using shell cat fallback for '%s'", source_file.c_str());
if (strchr(source_file.c_str(), '\'') != nullptr)
return Status::FromErrorString(
"Doesn't support single-quotes in filenames");
AdbClientUP adb(GetAdbClient(error));
if (error.Fail())
return error;
char cmd[PATH_MAX];
snprintf(cmd, sizeof(cmd), "%scat '%s'", GetRunAs().c_str(),
source_file.c_str());
return adb->ShellToFile(cmd, minutes(1), destination);
}
Status PlatformAndroid::PutFile(const FileSpec &source,
const FileSpec &destination, uint32_t uid,
uint32_t gid) {
if (IsHost() || !m_remote_platform_sp)
return PlatformLinux::PutFile(source, destination, uid, gid);
FileSpec destination_spec(destination.GetPath(false), FileSpec::Style::posix);
if (destination_spec.IsRelative())
destination_spec = GetRemoteWorkingDirectory().CopyByAppendingPathComponent(
destination_spec.GetPath(false));
// TODO: Set correct uid and gid on remote file.
Status error;
auto sync_service = GetSyncService(error);
if (error.Fail())
return error;
return sync_service->PushFile(source, destination_spec);
}
const char *PlatformAndroid::GetCacheHostname() { return m_device_id.c_str(); }
Status PlatformAndroid::DownloadModuleSlice(const FileSpec &src_file_spec,
const uint64_t src_offset,
const uint64_t src_size,
const FileSpec &dst_file_spec) {
std::string source_file = src_file_spec.GetPath(false);
if (source_file.empty())
return Status::FromErrorString("Source file path cannot be empty");
std::string destination_file = dst_file_spec.GetPath(false);
if (destination_file.empty())
return Status::FromErrorString("Destination file path cannot be empty");
// In Android API level 23 and above, dynamic loader is able to load .so
// file directly from APK. In that case, src_offset will be an non-zero.
if (src_offset == 0) // Use GetFile for a normal file.
return GetFile(src_file_spec, dst_file_spec);
if (source_file.find('\'') != std::string::npos)
return Status::FromErrorString(
"Doesn't support single-quotes in filenames");
// For zip .so file, src_file_spec will be "zip_path!/so_path".
// Extract "zip_path" from the source_file.
static constexpr llvm::StringLiteral k_zip_separator("!/");
size_t pos = source_file.find(k_zip_separator);
if (pos != std::string::npos)
source_file.resize(pos);
Status error;
AdbClientUP adb(GetAdbClient(error));
if (error.Fail())
return error;
// Use 'shell dd' to download the file slice with the offset and size.
char cmd[PATH_MAX];
snprintf(cmd, sizeof(cmd),
"%sdd if='%s' iflag=skip_bytes,count_bytes "
"skip=%" PRIu64 " count=%" PRIu64 " status=none",
GetRunAs().c_str(), source_file.c_str(), src_offset, src_size);
return adb->ShellToFile(cmd, minutes(1), dst_file_spec);
}
Status PlatformAndroid::DisconnectRemote() {
Status error = PlatformLinux::DisconnectRemote();
if (error.Success()) {
m_device_id.clear();
m_sdk_version = 0;
}
return error;
}
uint32_t PlatformAndroid::GetDefaultMemoryCacheLineSize() {
return g_android_default_cache_size;
}
uint32_t PlatformAndroid::GetSdkVersion() {
if (!IsConnected())
return 0;
if (m_sdk_version != 0)
return m_sdk_version;
std::string version_string;
Status error;
AdbClientUP adb(GetAdbClient(error));
if (error.Fail())
return 0;
error =
adb->Shell("getprop ro.build.version.sdk", seconds(5), &version_string);
version_string = llvm::StringRef(version_string).trim().str();
if (error.Fail() || version_string.empty()) {
Log *log = GetLog(LLDBLog::Platform);
LLDB_LOGF(log, "Get SDK version failed. (error: %s, output: %s)",
error.AsCString(), version_string.c_str());
return 0;
}
// FIXME: improve error handling
llvm::to_integer(version_string, m_sdk_version);
return m_sdk_version;
}
Status PlatformAndroid::DownloadSymbolFile(const lldb::ModuleSP &module_sp,
const FileSpec &dst_file_spec) {
// For oat file we can try to fetch additional debug info from the device
llvm::StringRef extension = module_sp->GetFileSpec().GetFileNameExtension();
if (extension != ".oat" && extension != ".odex")
return Status::FromErrorString(
"Symbol file downloading only supported for oat and odex files");
// If we have no information about the platform file we can't execute oatdump
if (!module_sp->GetPlatformFileSpec())
return Status::FromErrorString("No platform file specified");
// Symbolizer isn't available before SDK version 23
if (GetSdkVersion() < 23)
return Status::FromErrorString(
"Symbol file generation only supported on SDK 23+");
// If we already have symtab then we don't have to try and generate one
if (module_sp->GetSectionList()->FindSectionByName(ConstString(".symtab")) !=
nullptr)
return Status::FromErrorString("Symtab already available in the module");
Status error;
AdbClientUP adb(GetAdbClient(error));
if (error.Fail())
return error;
std::string tmpdir;
error = adb->Shell("mktemp --directory --tmpdir /data/local/tmp", seconds(5),
&tmpdir);
if (error.Fail() || tmpdir.empty())
return Status::FromErrorStringWithFormat(
"Failed to generate temporary directory on the device (%s)",
error.AsCString());
tmpdir = llvm::StringRef(tmpdir).trim().str();
// Create file remover for the temporary directory created on the device
std::unique_ptr<std::string, std::function<void(std::string *)>>
tmpdir_remover(&tmpdir, [&adb](std::string *s) {
StreamString command;
command.Printf("rm -rf %s", s->c_str());
Status error = adb->Shell(command.GetData(), seconds(5), nullptr);
Log *log = GetLog(LLDBLog::Platform);
if (log && error.Fail())
LLDB_LOGF(log, "Failed to remove temp directory: %s",
error.AsCString());
});
FileSpec symfile_platform_filespec(tmpdir);
symfile_platform_filespec.AppendPathComponent("symbolized.oat");
// Execute oatdump on the remote device to generate a file with symtab
StreamString command;
command.Printf("oatdump --symbolize=%s --output=%s",
module_sp->GetPlatformFileSpec().GetPath(false).c_str(),
symfile_platform_filespec.GetPath(false).c_str());
error = adb->Shell(command.GetData(), minutes(1), nullptr);
if (error.Fail())
return Status::FromErrorStringWithFormat("Oatdump failed: %s",
error.AsCString());
// Download the symbolfile from the remote device
return GetFile(symfile_platform_filespec, dst_file_spec);
}
bool PlatformAndroid::GetRemoteOSVersion() {
m_os_version = llvm::VersionTuple(GetSdkVersion());
return !m_os_version.empty();
}
llvm::StringRef
PlatformAndroid::GetLibdlFunctionDeclarations(lldb_private::Process *process) {
SymbolContextList matching_symbols;
std::vector<const char *> dl_open_names = {"__dl_dlopen", "dlopen"};
const char *dl_open_name = nullptr;
Target &target = process->GetTarget();
for (auto *name : dl_open_names) {
target.GetImages().FindFunctionSymbols(
ConstString(name), eFunctionNameTypeFull, matching_symbols);
if (matching_symbols.GetSize()) {
dl_open_name = name;
break;
}
}
// Older platform versions have the dl function symbols mangled
if (dl_open_name == dl_open_names[0])
return R"(
extern "C" void* dlopen(const char*, int) asm("__dl_dlopen");
extern "C" void* dlsym(void*, const char*) asm("__dl_dlsym");
extern "C" int dlclose(void*) asm("__dl_dlclose");
extern "C" char* dlerror(void) asm("__dl_dlerror");
)";
return PlatformPOSIX::GetLibdlFunctionDeclarations(process);
}
PlatformAndroid::AdbClientUP PlatformAndroid::GetAdbClient(Status &error) {
AdbClientUP adb = std::make_unique<AdbClient>(m_device_id);
error = adb->Connect();
return adb;
}
llvm::StringRef PlatformAndroid::GetPropertyPackageName() {
return GetGlobalProperties().GetPropertyAtIndexAs<llvm::StringRef>(
ePropertyPlatformPackageName, "");
}
std::string PlatformAndroid::GetRunAs() {
llvm::StringRef run_as = GetPropertyPackageName();
if (!run_as.empty()) {
// When LLDB fails to pull file from a package directory due to security
// constraint, user needs to set the package name to
// 'platform.plugin.remote-android.package-name' property in order to run
// shell commands as the package user using 'run-as' (e.g. to get file with
// 'cat' and 'dd').
// https://cs.android.com/android/platform/superproject/+/master:
// system/core/run-as/run-as.cpp;l=39-61;
// drc=4a77a84a55522a3b122f9c63ef0d0b8a6a131627
return std::string("run-as '") + run_as.str() + "' ";
}
return run_as.str();
}
// Helper function to populate process status information from
// /proc/[pid]/status
void PlatformAndroid::PopulateProcessStatusInfo(
lldb::pid_t pid, ProcessInstanceInfo &process_info) {
// Read /proc/[pid]/status to get parent PID, UIDs, and GIDs
Status error;
AdbClientUP status_adb = GetAdbClient(error);
if (error.Fail())
return;
std::string status_output;
StreamString status_cmd;
status_cmd.Printf(
"cat /proc/%llu/status 2>/dev/null | grep -E '^(PPid|Uid|Gid):'",
static_cast<unsigned long long>(pid));
Status status_error =
status_adb->Shell(status_cmd.GetData(), seconds(5), &status_output);
if (status_error.Fail() || status_output.empty())
return;
llvm::SmallVector<llvm::StringRef, 16> lines;
llvm::StringRef(status_output).split(lines, '\n');
for (llvm::StringRef line : lines) {
line = line.trim();
if (line.starts_with("PPid:")) {
llvm::StringRef ppid_str = line.substr(5).trim();
lldb::pid_t ppid;
if (llvm::to_integer(ppid_str, ppid))
process_info.SetParentProcessID(ppid);
} else if (line.starts_with("Uid:")) {
llvm::SmallVector<llvm::StringRef, 4> uid_parts;
line.substr(4).trim().split(uid_parts, '\t', -1, false);
if (uid_parts.size() >= 2) {
uint32_t uid, euid;
if (llvm::to_integer(uid_parts[0].trim(), uid))
process_info.SetUserID(uid);
if (llvm::to_integer(uid_parts[1].trim(), euid))
process_info.SetEffectiveUserID(euid);
}
} else if (line.starts_with("Gid:")) {
llvm::SmallVector<llvm::StringRef, 4> gid_parts;
line.substr(4).trim().split(gid_parts, '\t', -1, false);
if (gid_parts.size() >= 2) {
uint32_t gid, egid;
if (llvm::to_integer(gid_parts[0].trim(), gid))
process_info.SetGroupID(gid);
if (llvm::to_integer(gid_parts[1].trim(), egid))
process_info.SetEffectiveGroupID(egid);
}
}
}
}
// Helper function to populate command line arguments from /proc/[pid]/cmdline
void PlatformAndroid::PopulateProcessCommandLine(
lldb::pid_t pid, ProcessInstanceInfo &process_info) {
// Read /proc/[pid]/cmdline to get command line arguments
Status error;
AdbClientUP cmdline_adb = GetAdbClient(error);
if (error.Fail())
return;
std::string cmdline_output;
StreamString cmdline_cmd;
cmdline_cmd.Printf("cat /proc/%llu/cmdline 2>/dev/null | tr '\\000' ' '",
static_cast<unsigned long long>(pid));
Status cmdline_error =
cmdline_adb->Shell(cmdline_cmd.GetData(), seconds(5), &cmdline_output);
if (cmdline_error.Fail() || cmdline_output.empty())
return;
cmdline_output = llvm::StringRef(cmdline_output).trim().str();
if (cmdline_output.empty())
return;
llvm::SmallVector<llvm::StringRef, 16> args;
llvm::StringRef(cmdline_output).split(args, ' ', -1, false);
if (args.empty())
return;
process_info.SetArg0(args[0]);
Args process_args;
for (size_t i = 1; i < args.size(); i++) {
if (!args[i].empty())
process_args.AppendArgument(args[i]);
}
process_info.SetArguments(process_args, false);
}
// Helper function to populate architecture from /proc/[pid]/exe
void PlatformAndroid::PopulateProcessArchitecture(
lldb::pid_t pid, ProcessInstanceInfo &process_info) {
// Read /proc/[pid]/exe to get executable path for architecture detection
Status error;
AdbClientUP exe_adb = GetAdbClient(error);
if (error.Fail())
return;
std::string exe_output;
StreamString exe_cmd;
exe_cmd.Printf("readlink /proc/%llu/exe 2>/dev/null",
static_cast<unsigned long long>(pid));
Status exe_error = exe_adb->Shell(exe_cmd.GetData(), seconds(5), &exe_output);
if (exe_error.Fail() || exe_output.empty())
return;
exe_output = llvm::StringRef(exe_output).trim().str();
// Determine architecture from exe path
ArchSpec arch;
if (exe_output.find("64") != std::string::npos ||
exe_output.find("arm64") != std::string::npos ||
exe_output.find("aarch64") != std::string::npos) {
arch.SetTriple("aarch64-unknown-linux-android");
} else if (exe_output.find("x86_64") != std::string::npos) {
arch.SetTriple("x86_64-unknown-linux-android");
} else if (exe_output.find("x86") != std::string::npos ||
exe_output.find("i686") != std::string::npos) {
arch.SetTriple("i686-unknown-linux-android");
} else {
// Default to armv7 for 32-bit ARM (most common on Android)
arch.SetTriple("armv7-unknown-linux-android");
}
if (arch.IsValid())
process_info.SetArchitecture(arch);
}
uint32_t
PlatformAndroid::FindProcesses(const ProcessInstanceInfoMatch &match_info,
ProcessInstanceInfoList &proc_infos) {
proc_infos.clear();
// When LLDB is running natively on an Android device (IsHost() == true),
// use the parent class's standard Linux /proc enumeration. IsHost() is only
// true when compiled for Android (#if defined(__ANDROID__)), so calling
// PlatformLinux methods is safe (Android is Linux-based).
if (IsHost())
return PlatformLinux::FindProcesses(match_info, proc_infos);
// Remote Android platform: implement process name lookup using 'pidof' over
// adb.
// LLDB stores the search name in GetExecutableFile() (even though it's
// actually a process name like "com.android.chrome" rather than an
// executable path). If no search name is provided, we can't use
// 'pidof', so return early with no results.
const ProcessInstanceInfo &match_process_info = match_info.GetProcessInfo();
if (!match_process_info.GetExecutableFile() ||
match_info.GetNameMatchType() == NameMatch::Ignore) {
return 0;
}
// Extract the process name to search for (typically an Android package name
// like "com.example.app" or binary name like "app_process64")
std::string process_name = match_process_info.GetExecutableFile().GetPath();
if (process_name.empty())
return 0;
// Use adb to find the process by name
Status error;
AdbClientUP adb(GetAdbClient(error));
if (error.Fail()) {
Log *log = GetLog(LLDBLog::Platform);
LLDB_LOGF(log, "PlatformAndroid::%s failed to get ADB client: %s",
__FUNCTION__, error.AsCString());
return 0;
}
// Use 'pidof' command to get PIDs for the process name.
// Quote the process name to handle special characters (spaces, etc.)
std::string pidof_output;
StreamString command;
command.Printf("pidof '%s'", process_name.c_str());
error = adb->Shell(command.GetData(), seconds(5), &pidof_output);
if (error.Fail()) {
Log *log = GetLog(LLDBLog::Platform);
LLDB_LOG(log, "PlatformAndroid::{} 'pidof {}' failed: {}", __FUNCTION__,
process_name.c_str(), error.AsCString());
return 0;
}
// Parse PIDs from pidof output.
// Note: pidof can return multiple PIDs (space-separated) if multiple
// instances of the same executable are running.
pidof_output = llvm::StringRef(pidof_output).trim().str();
if (pidof_output.empty()) {
Log *log = GetLog(LLDBLog::Platform);
LLDB_LOGF(log, "PlatformAndroid::%s no process found with name '%s'",
__FUNCTION__, process_name.c_str());
return 0;
}
// Split the output by whitespace to handle multiple PIDs
llvm::SmallVector<llvm::StringRef, 8> pid_strings;
llvm::StringRef(pidof_output).split(pid_strings, ' ', -1, false);
Log *log = GetLog(LLDBLog::Platform);
// Process each PID and gather information
uint32_t num_matches = 0;
for (llvm::StringRef pid_str : pid_strings) {
pid_str = pid_str.trim();
if (pid_str.empty())
continue;
lldb::pid_t pid;
if (!llvm::to_integer(pid_str, pid)) {
LLDB_LOGF(log, "PlatformAndroid::%s failed to parse PID from: '%s'",
__FUNCTION__, pid_str.str().c_str());
continue;
}
ProcessInstanceInfo process_info;
process_info.SetProcessID(pid);
process_info.GetExecutableFile().SetFile(process_name,
FileSpec::Style::posix);
// Populate additional process information
PopulateProcessStatusInfo(pid, process_info);
PopulateProcessCommandLine(pid, process_info);
PopulateProcessArchitecture(pid, process_info);
// Check if this process matches the criteria
if (match_info.Matches(process_info)) {
proc_infos.push_back(process_info);
num_matches++;
LLDB_LOGF(log, "PlatformAndroid::%s found process '%s' with PID %llu",
__FUNCTION__, process_name.c_str(),
static_cast<unsigned long long>(pid));
}
}
return num_matches;
}
std::unique_ptr<AdbSyncService> PlatformAndroid::GetSyncService(Status &error) {
auto sync_service = std::make_unique<AdbSyncService>(m_device_id);
error = sync_service->SetupSyncConnection();
if (error.Fail())
return nullptr;
return sync_service;
}