| //===-- source/Host/aix/Host.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/Host/Host.h" |
| #include "lldb/Host/posix/Support.h" |
| #include "lldb/Utility/LLDBLog.h" |
| #include "lldb/Utility/Log.h" |
| #include "lldb/Utility/ProcessInfo.h" |
| #include "lldb/Utility/Status.h" |
| #include "llvm/BinaryFormat/XCOFF.h" |
| #include <dirent.h> |
| #include <sys/proc.h> |
| #include <sys/procfs.h> |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| |
| namespace { |
| enum class ProcessState { |
| Unknown, |
| Dead, |
| DiskSleep, |
| Idle, |
| Paging, |
| Parked, |
| Running, |
| Sleeping, |
| TracedOrStopped, |
| Zombie, |
| }; |
| } |
| |
| static ProcessInstanceInfo::timespec convert(pr_timestruc64_t t) { |
| ProcessInstanceInfo::timespec ts; |
| ts.tv_sec = t.tv_sec; |
| ts.tv_usec = t.tv_nsec / 1000; // nanos to micros |
| return ts; |
| } |
| |
| static bool GetStatusInfo(::pid_t pid, ProcessInstanceInfo &processInfo, |
| ProcessState &State) { |
| struct pstatus pstatusData; |
| auto BufferOrError = getProcFile(pid, "status"); |
| if (!BufferOrError) |
| return false; |
| |
| std::unique_ptr<llvm::MemoryBuffer> StatusBuffer = std::move(*BufferOrError); |
| // Ensure there's enough data for psinfoData |
| if (StatusBuffer->getBufferSize() < sizeof(pstatusData)) |
| return false; |
| |
| std::memcpy(&pstatusData, StatusBuffer->getBufferStart(), |
| sizeof(pstatusData)); |
| switch (pstatusData.pr_stat) { |
| case SIDL: |
| State = ProcessState::Idle; |
| break; |
| case SACTIVE: |
| State = ProcessState::Running; |
| break; |
| case SSTOP: |
| State = ProcessState::TracedOrStopped; |
| break; |
| case SZOMB: |
| State = ProcessState::Zombie; |
| break; |
| default: |
| State = ProcessState::Unknown; |
| break; |
| } |
| processInfo.SetIsZombie(State == ProcessState::Zombie); |
| processInfo.SetUserTime(convert(pstatusData.pr_utime)); |
| processInfo.SetSystemTime(convert(pstatusData.pr_stime)); |
| processInfo.SetCumulativeUserTime(convert(pstatusData.pr_cutime)); |
| processInfo.SetCumulativeSystemTime(convert(pstatusData.pr_cstime)); |
| return true; |
| } |
| |
| static bool GetExePathAndIds(::pid_t pid, ProcessInstanceInfo &process_info) { |
| struct psinfo psinfoData; |
| auto BufferOrError = getProcFile(pid, "psinfo"); |
| if (!BufferOrError) |
| return false; |
| |
| std::unique_ptr<llvm::MemoryBuffer> PsinfoBuffer = std::move(*BufferOrError); |
| // Ensure there's enough data for psinfoData |
| if (PsinfoBuffer->getBufferSize() < sizeof(psinfoData)) |
| return false; |
| |
| std::memcpy(&psinfoData, PsinfoBuffer->getBufferStart(), sizeof(psinfoData)); |
| llvm::StringRef PathRef( |
| psinfoData.pr_psargs, |
| strnlen(psinfoData.pr_psargs, sizeof(psinfoData.pr_psargs))); |
| if (PathRef.empty()) |
| return false; |
| |
| process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native); |
| ArchSpec arch_spec = ArchSpec(); |
| arch_spec.SetArchitecture(eArchTypeXCOFF, llvm::XCOFF::TCPU_PPC64, |
| LLDB_INVALID_CPUTYPE, llvm::Triple::AIX); |
| process_info.SetArchitecture(arch_spec); |
| process_info.SetParentProcessID(psinfoData.pr_ppid); |
| process_info.SetGroupID(psinfoData.pr_gid); |
| process_info.SetEffectiveGroupID(psinfoData.pr_egid); |
| process_info.SetUserID(psinfoData.pr_uid); |
| process_info.SetEffectiveUserID(psinfoData.pr_euid); |
| process_info.SetProcessGroupID(psinfoData.pr_pgid); |
| process_info.SetProcessSessionID(psinfoData.pr_sid); |
| return true; |
| } |
| |
| static bool GetProcessAndStatInfo(::pid_t pid, |
| ProcessInstanceInfo &process_info, |
| ProcessState &State) { |
| process_info.Clear(); |
| process_info.SetProcessID(pid); |
| |
| if (pid == LLDB_INVALID_PROCESS_ID) |
| return false; |
| // Get Executable path/Arch and Get User and Group IDs. |
| if (!GetExePathAndIds(pid, process_info)) |
| return false; |
| // Get process status and timing info. |
| if (!GetStatusInfo(pid, process_info, State)) |
| return false; |
| |
| return true; |
| } |
| |
| uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, |
| ProcessInstanceInfoList &process_infos) { |
| static const char procdir[] = "/proc/"; |
| |
| DIR *dirproc = opendir(procdir); |
| if (dirproc) { |
| struct dirent *direntry = nullptr; |
| const uid_t our_uid = getuid(); |
| const lldb::pid_t our_pid = getpid(); |
| bool all_users = match_info.GetMatchAllUsers(); |
| |
| while ((direntry = readdir(dirproc)) != nullptr) { |
| lldb::pid_t pid; |
| // Skip non-numeric name directories |
| if (!llvm::to_integer(direntry->d_name, pid)) |
| continue; |
| // Skip this process. |
| if (pid == our_pid) |
| continue; |
| |
| ProcessState State; |
| ProcessInstanceInfo process_info; |
| if (!GetProcessAndStatInfo(pid, process_info, State)) |
| continue; |
| |
| if (State == ProcessState::Zombie || |
| State == ProcessState::TracedOrStopped) |
| continue; |
| |
| // Check for user match if we're not matching all users and not running |
| // as root. |
| if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid)) |
| continue; |
| |
| if (match_info.Matches(process_info)) |
| process_infos.push_back(process_info); |
| } |
| closedir(dirproc); |
| } |
| return process_infos.size(); |
| } |
| |
| bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { |
| ProcessState State; |
| return GetProcessAndStatInfo(pid, process_info, State); |
| } |
| |
| Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { |
| return Status("unimplemented"); |
| } |