xref: /freebsd/contrib/llvm-project/lldb/source/Host/aix/Host.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
convert(pr_timestruc64_t t)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 
GetStatusInfo(::pid_t pid,ProcessInstanceInfo & processInfo,ProcessState & State)45 static 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 psinfoData
54   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 
GetExePathAndIds(::pid_t pid,ProcessInstanceInfo & process_info)84 static 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 psinfoData
92   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 
GetProcessAndStatInfo(::pid_t pid,ProcessInstanceInfo & process_info,ProcessState & State)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, process_info, State))
130     return false;
131 
132   return true;
133 }
134 
FindProcessesImpl(const ProcessInstanceInfoMatch & match_info,ProcessInstanceInfoList & process_infos)135 uint32_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 directories
149       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 running
165       // 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 
GetProcessInfo(lldb::pid_t pid,ProcessInstanceInfo & process_info)177 bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
178   ProcessState State;
179   return GetProcessAndStatInfo(pid, process_info, State);
180 }
181 
ShellExpandArguments(ProcessLaunchInfo & launch_info)182 Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
183   return Status("unimplemented");
184 }
185