1 //===-- ProcessInfo.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/Utility/ProcessInfo.h"
10 
11 #include "lldb/Utility/ArchSpec.h"
12 #include "lldb/Utility/Stream.h"
13 #include "lldb/Utility/StreamString.h"
14 #include "lldb/Utility/UserIDResolver.h"
15 #include "llvm/ADT/SmallString.h"
16 
17 #include <climits>
18 #include <optional>
19 
20 using namespace lldb;
21 using namespace lldb_private;
22 
23 ProcessInfo::ProcessInfo()
24     : m_executable(), m_arguments(), m_environment(), m_arch() {}
25 
26 ProcessInfo::ProcessInfo(const char *name, const ArchSpec &arch,
27                          lldb::pid_t pid)
28     : m_executable(name), m_arguments(), m_environment(), m_arch(arch),
29       m_pid(pid) {}
30 
31 void ProcessInfo::Clear() {
32   m_executable.Clear();
33   m_arguments.Clear();
34   m_environment.clear();
35   m_uid = UINT32_MAX;
36   m_gid = UINT32_MAX;
37   m_arch.Clear();
38   m_pid = LLDB_INVALID_PROCESS_ID;
39 }
40 
41 const char *ProcessInfo::GetName() const {
42   return m_executable.GetFilename().GetCString();
43 }
44 
45 llvm::StringRef ProcessInfo::GetNameAsStringRef() const {
46   return m_executable.GetFilename().GetStringRef();
47 }
48 
49 void ProcessInfo::Dump(Stream &s, Platform *platform) const {
50   s << "Executable: " << GetName() << "\n";
51   s << "Triple: ";
52   m_arch.DumpTriple(s.AsRawOstream());
53   s << "\n";
54 
55   s << "Arguments:\n";
56   m_arguments.Dump(s);
57 
58   s.Format("Environment:\n{0}", m_environment);
59 }
60 
61 void ProcessInfo::SetExecutableFile(const FileSpec &exe_file,
62                                     bool add_exe_file_as_first_arg) {
63   if (exe_file) {
64     m_executable = exe_file;
65     if (add_exe_file_as_first_arg) {
66       llvm::SmallString<128> filename;
67       exe_file.GetPath(filename);
68       if (!filename.empty())
69         m_arguments.InsertArgumentAtIndex(0, filename);
70     }
71   } else {
72     m_executable.Clear();
73   }
74 }
75 
76 llvm::StringRef ProcessInfo::GetArg0() const { return m_arg0; }
77 
78 void ProcessInfo::SetArg0(llvm::StringRef arg) { m_arg0 = std::string(arg); }
79 
80 void ProcessInfo::SetArguments(char const **argv,
81                                bool first_arg_is_executable) {
82   m_arguments.SetArguments(argv);
83 
84   // Is the first argument the executable?
85   if (first_arg_is_executable) {
86     const char *first_arg = m_arguments.GetArgumentAtIndex(0);
87     if (first_arg) {
88       // Yes the first argument is an executable, set it as the executable in
89       // the launch options. Don't resolve the file path as the path could be a
90       // remote platform path
91       m_executable.SetFile(first_arg, FileSpec::Style::native);
92     }
93   }
94 }
95 
96 void ProcessInfo::SetArguments(const Args &args, bool first_arg_is_executable) {
97   // Copy all arguments
98   m_arguments = args;
99 
100   // Is the first argument the executable?
101   if (first_arg_is_executable) {
102     const char *first_arg = m_arguments.GetArgumentAtIndex(0);
103     if (first_arg) {
104       // Yes the first argument is an executable, set it as the executable in
105       // the launch options. Don't resolve the file path as the path could be a
106       // remote platform path
107       m_executable.SetFile(first_arg, FileSpec::Style::native);
108     }
109   }
110 }
111 
112 void ProcessInstanceInfo::Dump(Stream &s, UserIDResolver &resolver) const {
113   if (m_pid != LLDB_INVALID_PROCESS_ID)
114     s.Printf("    pid = %" PRIu64 "\n", m_pid);
115 
116   if (m_parent_pid != LLDB_INVALID_PROCESS_ID)
117     s.Printf(" parent = %" PRIu64 "\n", m_parent_pid);
118 
119   if (m_executable) {
120     s.Printf("   name = %s\n", m_executable.GetFilename().GetCString());
121     s.PutCString("   file = ");
122     m_executable.Dump(s.AsRawOstream());
123     s.EOL();
124   }
125   const uint32_t argc = m_arguments.GetArgumentCount();
126   if (argc > 0) {
127     for (uint32_t i = 0; i < argc; i++) {
128       const char *arg = m_arguments.GetArgumentAtIndex(i);
129       if (i < 10)
130         s.Printf(" arg[%u] = %s\n", i, arg);
131       else
132         s.Printf("arg[%u] = %s\n", i, arg);
133     }
134   }
135 
136   s.Format("{0}", m_environment);
137 
138   if (m_arch.IsValid()) {
139     s.Printf("   arch = ");
140     m_arch.DumpTriple(s.AsRawOstream());
141     s.EOL();
142   }
143 
144   if (UserIDIsValid()) {
145     s.Format("    uid = {0,-5} ({1})\n", GetUserID(),
146              resolver.GetUserName(GetUserID()).value_or(""));
147   }
148   if (GroupIDIsValid()) {
149     s.Format("    gid = {0,-5} ({1})\n", GetGroupID(),
150              resolver.GetGroupName(GetGroupID()).value_or(""));
151   }
152   if (EffectiveUserIDIsValid()) {
153     s.Format("   euid = {0,-5} ({1})\n", GetEffectiveUserID(),
154              resolver.GetUserName(GetEffectiveUserID()).value_or(""));
155   }
156   if (EffectiveGroupIDIsValid()) {
157     s.Format("   egid = {0,-5} ({1})\n", GetEffectiveGroupID(),
158              resolver.GetGroupName(GetEffectiveGroupID()).value_or(""));
159   }
160 }
161 
162 void ProcessInstanceInfo::DumpTableHeader(Stream &s, bool show_args,
163                                           bool verbose) {
164   const char *label;
165   if (show_args || verbose)
166     label = "ARGUMENTS";
167   else
168     label = "NAME";
169 
170   if (verbose) {
171     s.Printf("PID    PARENT USER       GROUP      EFF USER   EFF GROUP  TRIPLE "
172              "                        %s\n",
173              label);
174     s.PutCString(
175         "====== ====== ========== ========== ========== ========== "
176         "============================== ============================\n");
177   } else {
178     s.Printf("PID    PARENT USER       TRIPLE                         %s\n",
179              label);
180     s.PutCString("====== ====== ========== ============================== "
181                  "============================\n");
182   }
183 }
184 
185 void ProcessInstanceInfo::DumpAsTableRow(Stream &s, UserIDResolver &resolver,
186                                          bool show_args, bool verbose) const {
187   if (m_pid != LLDB_INVALID_PROCESS_ID) {
188     s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, m_parent_pid);
189 
190     StreamString arch_strm;
191     if (m_arch.IsValid())
192       m_arch.DumpTriple(arch_strm.AsRawOstream());
193 
194     auto print = [&](bool (ProcessInstanceInfo::*isValid)() const,
195                      uint32_t (ProcessInstanceInfo::*getID)() const,
196                      std::optional<llvm::StringRef> (UserIDResolver::*getName)(
197                          UserIDResolver::id_t id)) {
198       const char *format = "{0,-10} ";
199       if (!(this->*isValid)()) {
200         s.Format(format, "");
201         return;
202       }
203       uint32_t id = (this->*getID)();
204       if (auto name = (resolver.*getName)(id))
205         s.Format(format, *name);
206       else
207         s.Format(format, id);
208     };
209     if (verbose) {
210       print(&ProcessInstanceInfo::UserIDIsValid,
211             &ProcessInstanceInfo::GetUserID, &UserIDResolver::GetUserName);
212       print(&ProcessInstanceInfo::GroupIDIsValid,
213             &ProcessInstanceInfo::GetGroupID, &UserIDResolver::GetGroupName);
214       print(&ProcessInstanceInfo::EffectiveUserIDIsValid,
215             &ProcessInstanceInfo::GetEffectiveUserID,
216             &UserIDResolver::GetUserName);
217       print(&ProcessInstanceInfo::EffectiveGroupIDIsValid,
218             &ProcessInstanceInfo::GetEffectiveGroupID,
219             &UserIDResolver::GetGroupName);
220 
221       s.Printf("%-30s ", arch_strm.GetData());
222     } else {
223       print(&ProcessInstanceInfo::EffectiveUserIDIsValid,
224             &ProcessInstanceInfo::GetEffectiveUserID,
225             &UserIDResolver::GetUserName);
226       s.Printf("%-30s ", arch_strm.GetData());
227     }
228 
229     if (verbose || show_args) {
230       s.PutCString(m_arg0);
231       const uint32_t argc = m_arguments.GetArgumentCount();
232       for (uint32_t i = 0; i < argc; i++) {
233         s.PutChar(' ');
234         s.PutCString(m_arguments.GetArgumentAtIndex(i));
235       }
236     } else {
237       s.PutCString(GetName());
238     }
239 
240     s.EOL();
241   }
242 }
243 
244 bool ProcessInstanceInfoMatch::ArchitectureMatches(
245     const ArchSpec &arch_spec) const {
246   return !m_match_info.GetArchitecture().IsValid() ||
247          m_match_info.GetArchitecture().IsCompatibleMatch(arch_spec);
248 }
249 
250 bool ProcessInstanceInfoMatch::NameMatches(const char *process_name) const {
251   if (m_name_match_type == NameMatch::Ignore)
252     return true;
253   const char *match_name = m_match_info.GetName();
254   if (!match_name)
255     return true;
256 
257   return lldb_private::NameMatches(process_name, m_name_match_type, match_name);
258 }
259 
260 bool ProcessInstanceInfoMatch::ProcessIDsMatch(
261     const ProcessInstanceInfo &proc_info) const {
262   if (m_match_info.ProcessIDIsValid() &&
263       m_match_info.GetProcessID() != proc_info.GetProcessID())
264     return false;
265 
266   if (m_match_info.ParentProcessIDIsValid() &&
267       m_match_info.GetParentProcessID() != proc_info.GetParentProcessID())
268     return false;
269   return true;
270 }
271 
272 bool ProcessInstanceInfoMatch::UserIDsMatch(
273     const ProcessInstanceInfo &proc_info) const {
274   if (m_match_info.UserIDIsValid() &&
275       m_match_info.GetUserID() != proc_info.GetUserID())
276     return false;
277 
278   if (m_match_info.GroupIDIsValid() &&
279       m_match_info.GetGroupID() != proc_info.GetGroupID())
280     return false;
281 
282   if (m_match_info.EffectiveUserIDIsValid() &&
283       m_match_info.GetEffectiveUserID() != proc_info.GetEffectiveUserID())
284     return false;
285 
286   if (m_match_info.EffectiveGroupIDIsValid() &&
287       m_match_info.GetEffectiveGroupID() != proc_info.GetEffectiveGroupID())
288     return false;
289   return true;
290 }
291 bool ProcessInstanceInfoMatch::Matches(
292     const ProcessInstanceInfo &proc_info) const {
293   return ArchitectureMatches(proc_info.GetArchitecture()) &&
294          ProcessIDsMatch(proc_info) && UserIDsMatch(proc_info) &&
295          NameMatches(proc_info.GetName());
296 }
297 
298 bool ProcessInstanceInfoMatch::MatchAllProcesses() const {
299   if (m_name_match_type != NameMatch::Ignore)
300     return false;
301 
302   if (m_match_info.ProcessIDIsValid())
303     return false;
304 
305   if (m_match_info.ParentProcessIDIsValid())
306     return false;
307 
308   if (m_match_info.UserIDIsValid())
309     return false;
310 
311   if (m_match_info.GroupIDIsValid())
312     return false;
313 
314   if (m_match_info.EffectiveUserIDIsValid())
315     return false;
316 
317   if (m_match_info.EffectiveGroupIDIsValid())
318     return false;
319 
320   if (m_match_info.GetArchitecture().IsValid())
321     return false;
322 
323   if (m_match_all_users)
324     return false;
325 
326   return true;
327 }
328 
329 void ProcessInstanceInfoMatch::Clear() {
330   m_match_info.Clear();
331   m_name_match_type = NameMatch::Ignore;
332   m_match_all_users = false;
333 }
334