https://github.com/cs01 updated https://github.com/llvm/llvm-project/pull/160931
>From 617de12c6d9ccfdd89d394c99132c596c9fd07ed Mon Sep 17 00:00:00 2001 From: Chad Smith <[email protected]> Date: Fri, 26 Sep 2025 11:01:19 -0700 Subject: [PATCH 1/2] support attaching by name for platform android --- .../Platform/Android/PlatformAndroid.cpp | 79 +++++++++++++++++++ .../Platform/Android/PlatformAndroid.h | 3 + 2 files changed, 82 insertions(+) diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp b/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp index 600cc0a04cd22..bdef98c2d760f 100644 --- a/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp +++ b/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp @@ -477,6 +477,85 @@ std::string PlatformAndroid::GetRunAs() { } return run_as.str(); } +uint32_t +PlatformAndroid::FindProcesses(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &proc_infos) { + // Use the parent implementation for host platform + if (IsHost()) + return PlatformLinux::FindProcesses(match_info, proc_infos); + + // For remote Android platform, implement process name lookup using adb + proc_infos.clear(); + + // Check if we're looking for a process by name + const ProcessInstanceInfo &match_process_info = match_info.GetProcessInfo(); + if (!match_process_info.GetExecutableFile() || + match_info.GetNameMatchType() == NameMatch::Ignore) { + // Fall back to the parent implementation if not searching by name + return PlatformLinux::FindProcesses(match_info, proc_infos); + } + + 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 the PID for the process name + std::string pidof_output; + std::string command = "pidof " + process_name; + error = adb->Shell(command.c_str(), seconds(5), &pidof_output); + + if (error.Fail()) { + Log *log = GetLog(LLDBLog::Platform); + LLDB_LOGF(log, "PlatformAndroid::%s 'pidof %s' failed: %s", __FUNCTION__, + process_name.c_str(), error.AsCString()); + return 0; + } + + // Parse the PID from pidof output + pidof_output = llvm::StringRef(pidof_output).trim().str(); + if (pidof_output.empty()) { + // No process found with that name + return 0; + } + + // Parse the output as a single PID + lldb::pid_t pid; + if (!llvm::to_integer(pidof_output, pid)) { + Log *log = GetLog(LLDBLog::Platform); + LLDB_LOGF(log, "PlatformAndroid::%s failed to parse PID from output: '%s'", + __FUNCTION__, pidof_output.c_str()); + return 0; + } + + // Create ProcessInstanceInfo for the found process + ProcessInstanceInfo process_info; + process_info.SetProcessID(pid); + process_info.GetExecutableFile().SetFile(process_name, + FileSpec::Style::posix); + + // Check if this process matches the criteria + if (match_info.Matches(process_info)) { + proc_infos.push_back(process_info); + + Log *log = GetLog(LLDBLog::Platform); + LLDB_LOGF(log, "PlatformAndroid::%s found process '%s' with PID %llu", + __FUNCTION__, process_name.c_str(), (unsigned long long)pid); + return 1; + } + + return 0; +} + std::unique_ptr<AdbSyncService> PlatformAndroid::GetSyncService(Status &error) { auto sync_service = std::make_unique<AdbSyncService>(m_device_id); error = sync_service->SetupSyncConnection(); diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroid.h b/lldb/source/Plugins/Platform/Android/PlatformAndroid.h index 3384525362ecf..701d12922a383 100644 --- a/lldb/source/Plugins/Platform/Android/PlatformAndroid.h +++ b/lldb/source/Plugins/Platform/Android/PlatformAndroid.h @@ -59,6 +59,9 @@ class PlatformAndroid : public platform_linux::PlatformLinux { uint32_t GetDefaultMemoryCacheLineSize() override; + uint32_t FindProcesses(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &proc_infos) override; + protected: const char *GetCacheHostname() override; >From e292993f31e0ae5f05466672eb64fb0367d13dd0 Mon Sep 17 00:00:00 2001 From: Chad Smith <[email protected]> Date: Wed, 8 Oct 2025 15:45:42 -0700 Subject: [PATCH 2/2] handle edge cases better --- .../Platform/Android/PlatformAndroid.cpp | 232 +++++++++++++++--- .../Platform/Android/PlatformAndroid.h | 8 + 2 files changed, 206 insertions(+), 34 deletions(-) diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp b/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp index bdef98c2d760f..f538fc60ef1e4 100644 --- a/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp +++ b/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp @@ -477,24 +477,166 @@ std::string PlatformAndroid::GetRunAs() { } 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) { - // Use the parent implementation for host platform + 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); - // For remote Android platform, implement process name lookup using adb - proc_infos.clear(); + // Remote Android platform: implement process name lookup using 'pidof' over + // adb. - // Check if we're looking for a process by name + // 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) { - // Fall back to the parent implementation if not searching by name - return PlatformLinux::FindProcesses(match_info, proc_infos); + 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; @@ -509,51 +651,73 @@ PlatformAndroid::FindProcesses(const ProcessInstanceInfoMatch &match_info, return 0; } - // Use 'pidof' command to get the PID for the process name + // Use 'pidof' command to get PIDs for the process name. + // Quote the process name to handle special characters (spaces, etc.) std::string pidof_output; - std::string command = "pidof " + process_name; - error = adb->Shell(command.c_str(), seconds(5), &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_LOGF(log, "PlatformAndroid::%s 'pidof %s' failed: %s", __FUNCTION__, - process_name.c_str(), error.AsCString()); + LLDB_LOG(log, "PlatformAndroid::{} 'pidof {}' failed: {}", __FUNCTION__, + process_name.c_str(), error.AsCString()); return 0; } - // Parse the PID from pidof output + // 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()) { - // No process found with that name - return 0; - } - - // Parse the output as a single PID - lldb::pid_t pid; - if (!llvm::to_integer(pidof_output, pid)) { Log *log = GetLog(LLDBLog::Platform); - LLDB_LOGF(log, "PlatformAndroid::%s failed to parse PID from output: '%s'", - __FUNCTION__, pidof_output.c_str()); + LLDB_LOGF(log, "PlatformAndroid::%s no process found with name '%s'", + __FUNCTION__, process_name.c_str()); return 0; } - // Create ProcessInstanceInfo for the found process - ProcessInstanceInfo process_info; - process_info.SetProcessID(pid); - process_info.GetExecutableFile().SetFile(process_name, - FileSpec::Style::posix); + // 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); - // Check if this process matches the criteria - if (match_info.Matches(process_info)) { - proc_infos.push_back(process_info); + Log *log = GetLog(LLDBLog::Platform); - Log *log = GetLog(LLDBLog::Platform); - LLDB_LOGF(log, "PlatformAndroid::%s found process '%s' with PID %llu", - __FUNCTION__, process_name.c_str(), (unsigned long long)pid); - return 1; + // 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 0; + return num_matches; } std::unique_ptr<AdbSyncService> PlatformAndroid::GetSyncService(Status &error) { diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroid.h b/lldb/source/Plugins/Platform/Android/PlatformAndroid.h index 701d12922a383..e771c6ae97d4d 100644 --- a/lldb/source/Plugins/Platform/Android/PlatformAndroid.h +++ b/lldb/source/Plugins/Platform/Android/PlatformAndroid.h @@ -89,6 +89,14 @@ class PlatformAndroid : public platform_linux::PlatformLinux { private: std::string m_device_id; uint32_t m_sdk_version; + + // Helper functions for process information gathering + void PopulateProcessStatusInfo(lldb::pid_t pid, + ProcessInstanceInfo &process_info); + void PopulateProcessCommandLine(lldb::pid_t pid, + ProcessInstanceInfo &process_info); + void PopulateProcessArchitecture(lldb::pid_t pid, + ProcessInstanceInfo &process_info); }; } // namespace platform_android _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
