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 | |
20 | using namespace lldb; |
21 | using namespace lldb_private; |
22 | |
23 | namespace { |
24 | enum 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 | |
38 | static 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 | |
45 | static 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 | |
84 | static 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 | |
117 | static 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 | |
135 | uint32_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 | |
177 | bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { |
178 | ProcessState State; |
179 | return GetProcessAndStatInfo(pid, process_info, State); |
180 | } |
181 | |
182 | Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { |
183 | return Status("unimplemented" ); |
184 | } |
185 | |