185 lines · cpp
1//===-- source/Host/aix/Host.cpp ----------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Host/Host.h"10#include "lldb/Host/posix/Support.h"11#include "lldb/Utility/LLDBLog.h"12#include "lldb/Utility/Log.h"13#include "lldb/Utility/ProcessInfo.h"14#include "lldb/Utility/Status.h"15#include "llvm/BinaryFormat/XCOFF.h"16#include <dirent.h>17#include <sys/proc.h>18#include <sys/procfs.h>19 20using namespace lldb;21using namespace lldb_private;22 23namespace {24enum class ProcessState {25 Unknown,26 Dead,27 DiskSleep,28 Idle,29 Paging,30 Parked,31 Running,32 Sleeping,33 TracedOrStopped,34 Zombie,35};36}37 38static ProcessInstanceInfo::timespec convert(pr_timestruc64_t t) {39 ProcessInstanceInfo::timespec ts;40 ts.tv_sec = t.tv_sec;41 ts.tv_usec = t.tv_nsec / 1000; // nanos to micros42 return ts;43}44 45static bool GetStatusInfo(::pid_t pid, ProcessInstanceInfo &processInfo,46 ProcessState &State) {47 struct pstatus pstatusData;48 auto BufferOrError = getProcFile(pid, "status");49 if (!BufferOrError)50 return false;51 52 std::unique_ptr<llvm::MemoryBuffer> StatusBuffer = std::move(*BufferOrError);53 // Ensure there's enough data for psinfoData54 if (StatusBuffer->getBufferSize() < sizeof(pstatusData))55 return false;56 57 std::memcpy(&pstatusData, StatusBuffer->getBufferStart(),58 sizeof(pstatusData));59 switch (pstatusData.pr_stat) {60 case SIDL:61 State = ProcessState::Idle;62 break;63 case SACTIVE:64 State = ProcessState::Running;65 break;66 case SSTOP:67 State = ProcessState::TracedOrStopped;68 break;69 case SZOMB:70 State = ProcessState::Zombie;71 break;72 default:73 State = ProcessState::Unknown;74 break;75 }76 processInfo.SetIsZombie(State == ProcessState::Zombie);77 processInfo.SetUserTime(convert(pstatusData.pr_utime));78 processInfo.SetSystemTime(convert(pstatusData.pr_stime));79 processInfo.SetCumulativeUserTime(convert(pstatusData.pr_cutime));80 processInfo.SetCumulativeSystemTime(convert(pstatusData.pr_cstime));81 return true;82}83 84static bool GetExePathAndIds(::pid_t pid, ProcessInstanceInfo &process_info) {85 struct psinfo psinfoData;86 auto BufferOrError = getProcFile(pid, "psinfo");87 if (!BufferOrError)88 return false;89 90 std::unique_ptr<llvm::MemoryBuffer> PsinfoBuffer = std::move(*BufferOrError);91 // Ensure there's enough data for psinfoData92 if (PsinfoBuffer->getBufferSize() < sizeof(psinfoData))93 return false;94 95 std::memcpy(&psinfoData, PsinfoBuffer->getBufferStart(), sizeof(psinfoData));96 llvm::StringRef PathRef(97 psinfoData.pr_psargs,98 strnlen(psinfoData.pr_psargs, sizeof(psinfoData.pr_psargs)));99 if (PathRef.empty())100 return false;101 102 process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native);103 ArchSpec arch_spec = ArchSpec();104 arch_spec.SetArchitecture(eArchTypeXCOFF, llvm::XCOFF::TCPU_PPC64,105 LLDB_INVALID_CPUTYPE, llvm::Triple::AIX);106 process_info.SetArchitecture(arch_spec);107 process_info.SetParentProcessID(psinfoData.pr_ppid);108 process_info.SetGroupID(psinfoData.pr_gid);109 process_info.SetEffectiveGroupID(psinfoData.pr_egid);110 process_info.SetUserID(psinfoData.pr_uid);111 process_info.SetEffectiveUserID(psinfoData.pr_euid);112 process_info.SetProcessGroupID(psinfoData.pr_pgid);113 process_info.SetProcessSessionID(psinfoData.pr_sid);114 return true;115}116 117static bool GetProcessAndStatInfo(::pid_t pid,118 ProcessInstanceInfo &process_info,119 ProcessState &State) {120 process_info.Clear();121 process_info.SetProcessID(pid);122 123 if (pid == LLDB_INVALID_PROCESS_ID)124 return false;125 // Get Executable path/Arch and Get User and Group IDs.126 if (!GetExePathAndIds(pid, process_info))127 return false;128 // Get process status and timing info.129 if (!GetStatusInfo(pid, process_info, State))130 return false;131 132 return true;133}134 135uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,136 ProcessInstanceInfoList &process_infos) {137 static const char procdir[] = "/proc/";138 139 DIR *dirproc = opendir(procdir);140 if (dirproc) {141 struct dirent *direntry = nullptr;142 const uid_t our_uid = getuid();143 const lldb::pid_t our_pid = getpid();144 bool all_users = match_info.GetMatchAllUsers();145 146 while ((direntry = readdir(dirproc)) != nullptr) {147 lldb::pid_t pid;148 // Skip non-numeric name directories149 if (!llvm::to_integer(direntry->d_name, pid))150 continue;151 // Skip this process.152 if (pid == our_pid)153 continue;154 155 ProcessState State;156 ProcessInstanceInfo process_info;157 if (!GetProcessAndStatInfo(pid, process_info, State))158 continue;159 160 if (State == ProcessState::Zombie ||161 State == ProcessState::TracedOrStopped)162 continue;163 164 // Check for user match if we're not matching all users and not running165 // as root.166 if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid))167 continue;168 169 if (match_info.Matches(process_info))170 process_infos.push_back(process_info);171 }172 closedir(dirproc);173 }174 return process_infos.size();175}176 177bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {178 ProcessState State;179 return GetProcessAndStatInfo(pid, process_info, State);180}181 182Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {183 return Status("unimplemented");184}185