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-exception
6//
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 micros
42 return ts;
43}
44
45static bool GetStatusInfo(::pid_t pid, ProcessInstanceInfo &processInfo,
46 ProcessState &State) {
47 struct pstatus pstatusData;
48 auto BufferOrError = getProcFile(pid, file: "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 psinfoData
54 if (StatusBuffer->getBufferSize() < sizeof(pstatusData))
55 return false;
56
57 std::memcpy(dest: &pstatusData, src: StatusBuffer->getBufferStart(),
58 n: 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, file: "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 psinfoData
92 if (PsinfoBuffer->getBufferSize() < sizeof(psinfoData))
93 return false;
94
95 std::memcpy(dest: &psinfoData, src: PsinfoBuffer->getBufferStart(), n: 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(path: PathRef, style: FileSpec::Style::native);
103 ArchSpec arch_spec = ArchSpec();
104 arch_spec.SetArchitecture(arch_type: eArchTypeXCOFF, cpu: llvm::XCOFF::TCPU_PPC64,
105 LLDB_INVALID_CPUTYPE, os: 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, processInfo&: 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(name: 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(dirp: dirproc)) != nullptr) {
147 lldb::pid_t pid;
148 // Skip non-numeric name directories
149 if (!llvm::to_integer(S: direntry->d_name, Num&: 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 running
165 // as root.
166 if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid))
167 continue;
168
169 if (match_info.Matches(proc_info: process_info))
170 process_infos.push_back(x: process_info);
171 }
172 closedir(dirp: 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

source code of lldb/source/Host/aix/Host.cpp