1dda28197Spatrick //===-- ProcessInfo.cpp ---------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "lldb/Utility/ProcessInfo.h"
10061da546Spatrick 
11061da546Spatrick #include "lldb/Utility/ArchSpec.h"
12061da546Spatrick #include "lldb/Utility/Stream.h"
13061da546Spatrick #include "lldb/Utility/StreamString.h"
14061da546Spatrick #include "lldb/Utility/UserIDResolver.h"
15061da546Spatrick #include "llvm/ADT/SmallString.h"
16061da546Spatrick 
17061da546Spatrick #include <climits>
18*f6aab3d8Srobert #include <optional>
19061da546Spatrick 
20061da546Spatrick using namespace lldb;
21061da546Spatrick using namespace lldb_private;
22061da546Spatrick 
ProcessInfo()23061da546Spatrick ProcessInfo::ProcessInfo()
24be691f3bSpatrick     : m_executable(), m_arguments(), m_environment(), m_arch() {}
25061da546Spatrick 
ProcessInfo(const char * name,const ArchSpec & arch,lldb::pid_t pid)26061da546Spatrick ProcessInfo::ProcessInfo(const char *name, const ArchSpec &arch,
27061da546Spatrick                          lldb::pid_t pid)
28*f6aab3d8Srobert     : m_executable(name), m_arguments(), m_environment(), m_arch(arch),
29*f6aab3d8Srobert       m_pid(pid) {}
30061da546Spatrick 
Clear()31061da546Spatrick void ProcessInfo::Clear() {
32061da546Spatrick   m_executable.Clear();
33061da546Spatrick   m_arguments.Clear();
34061da546Spatrick   m_environment.clear();
35061da546Spatrick   m_uid = UINT32_MAX;
36061da546Spatrick   m_gid = UINT32_MAX;
37061da546Spatrick   m_arch.Clear();
38061da546Spatrick   m_pid = LLDB_INVALID_PROCESS_ID;
39061da546Spatrick }
40061da546Spatrick 
GetName() const41061da546Spatrick const char *ProcessInfo::GetName() const {
42061da546Spatrick   return m_executable.GetFilename().GetCString();
43061da546Spatrick }
44061da546Spatrick 
GetNameAsStringRef() const45061da546Spatrick llvm::StringRef ProcessInfo::GetNameAsStringRef() const {
46061da546Spatrick   return m_executable.GetFilename().GetStringRef();
47061da546Spatrick }
48061da546Spatrick 
Dump(Stream & s,Platform * platform) const49061da546Spatrick void ProcessInfo::Dump(Stream &s, Platform *platform) const {
50061da546Spatrick   s << "Executable: " << GetName() << "\n";
51061da546Spatrick   s << "Triple: ";
52061da546Spatrick   m_arch.DumpTriple(s.AsRawOstream());
53061da546Spatrick   s << "\n";
54061da546Spatrick 
55061da546Spatrick   s << "Arguments:\n";
56061da546Spatrick   m_arguments.Dump(s);
57061da546Spatrick 
58061da546Spatrick   s.Format("Environment:\n{0}", m_environment);
59061da546Spatrick }
60061da546Spatrick 
SetExecutableFile(const FileSpec & exe_file,bool add_exe_file_as_first_arg)61061da546Spatrick void ProcessInfo::SetExecutableFile(const FileSpec &exe_file,
62061da546Spatrick                                     bool add_exe_file_as_first_arg) {
63061da546Spatrick   if (exe_file) {
64061da546Spatrick     m_executable = exe_file;
65061da546Spatrick     if (add_exe_file_as_first_arg) {
66061da546Spatrick       llvm::SmallString<128> filename;
67061da546Spatrick       exe_file.GetPath(filename);
68061da546Spatrick       if (!filename.empty())
69061da546Spatrick         m_arguments.InsertArgumentAtIndex(0, filename);
70061da546Spatrick     }
71061da546Spatrick   } else {
72061da546Spatrick     m_executable.Clear();
73061da546Spatrick   }
74061da546Spatrick }
75061da546Spatrick 
GetArg0() const76061da546Spatrick llvm::StringRef ProcessInfo::GetArg0() const { return m_arg0; }
77061da546Spatrick 
SetArg0(llvm::StringRef arg)78dda28197Spatrick void ProcessInfo::SetArg0(llvm::StringRef arg) { m_arg0 = std::string(arg); }
79061da546Spatrick 
SetArguments(char const ** argv,bool first_arg_is_executable)80061da546Spatrick void ProcessInfo::SetArguments(char const **argv,
81061da546Spatrick                                bool first_arg_is_executable) {
82061da546Spatrick   m_arguments.SetArguments(argv);
83061da546Spatrick 
84061da546Spatrick   // Is the first argument the executable?
85061da546Spatrick   if (first_arg_is_executable) {
86061da546Spatrick     const char *first_arg = m_arguments.GetArgumentAtIndex(0);
87061da546Spatrick     if (first_arg) {
88061da546Spatrick       // Yes the first argument is an executable, set it as the executable in
89061da546Spatrick       // the launch options. Don't resolve the file path as the path could be a
90061da546Spatrick       // remote platform path
91061da546Spatrick       m_executable.SetFile(first_arg, FileSpec::Style::native);
92061da546Spatrick     }
93061da546Spatrick   }
94061da546Spatrick }
95061da546Spatrick 
SetArguments(const Args & args,bool first_arg_is_executable)96061da546Spatrick void ProcessInfo::SetArguments(const Args &args, bool first_arg_is_executable) {
97061da546Spatrick   // Copy all arguments
98061da546Spatrick   m_arguments = args;
99061da546Spatrick 
100061da546Spatrick   // Is the first argument the executable?
101061da546Spatrick   if (first_arg_is_executable) {
102061da546Spatrick     const char *first_arg = m_arguments.GetArgumentAtIndex(0);
103061da546Spatrick     if (first_arg) {
104061da546Spatrick       // Yes the first argument is an executable, set it as the executable in
105061da546Spatrick       // the launch options. Don't resolve the file path as the path could be a
106061da546Spatrick       // remote platform path
107061da546Spatrick       m_executable.SetFile(first_arg, FileSpec::Style::native);
108061da546Spatrick     }
109061da546Spatrick   }
110061da546Spatrick }
111061da546Spatrick 
Dump(Stream & s,UserIDResolver & resolver) const112061da546Spatrick void ProcessInstanceInfo::Dump(Stream &s, UserIDResolver &resolver) const {
113061da546Spatrick   if (m_pid != LLDB_INVALID_PROCESS_ID)
114061da546Spatrick     s.Printf("    pid = %" PRIu64 "\n", m_pid);
115061da546Spatrick 
116061da546Spatrick   if (m_parent_pid != LLDB_INVALID_PROCESS_ID)
117061da546Spatrick     s.Printf(" parent = %" PRIu64 "\n", m_parent_pid);
118061da546Spatrick 
119061da546Spatrick   if (m_executable) {
120061da546Spatrick     s.Printf("   name = %s\n", m_executable.GetFilename().GetCString());
121061da546Spatrick     s.PutCString("   file = ");
122061da546Spatrick     m_executable.Dump(s.AsRawOstream());
123061da546Spatrick     s.EOL();
124061da546Spatrick   }
125061da546Spatrick   const uint32_t argc = m_arguments.GetArgumentCount();
126061da546Spatrick   if (argc > 0) {
127061da546Spatrick     for (uint32_t i = 0; i < argc; i++) {
128061da546Spatrick       const char *arg = m_arguments.GetArgumentAtIndex(i);
129061da546Spatrick       if (i < 10)
130061da546Spatrick         s.Printf(" arg[%u] = %s\n", i, arg);
131061da546Spatrick       else
132061da546Spatrick         s.Printf("arg[%u] = %s\n", i, arg);
133061da546Spatrick     }
134061da546Spatrick   }
135061da546Spatrick 
136061da546Spatrick   s.Format("{0}", m_environment);
137061da546Spatrick 
138061da546Spatrick   if (m_arch.IsValid()) {
139061da546Spatrick     s.Printf("   arch = ");
140061da546Spatrick     m_arch.DumpTriple(s.AsRawOstream());
141061da546Spatrick     s.EOL();
142061da546Spatrick   }
143061da546Spatrick 
144061da546Spatrick   if (UserIDIsValid()) {
145061da546Spatrick     s.Format("    uid = {0,-5} ({1})\n", GetUserID(),
146*f6aab3d8Srobert              resolver.GetUserName(GetUserID()).value_or(""));
147061da546Spatrick   }
148061da546Spatrick   if (GroupIDIsValid()) {
149061da546Spatrick     s.Format("    gid = {0,-5} ({1})\n", GetGroupID(),
150*f6aab3d8Srobert              resolver.GetGroupName(GetGroupID()).value_or(""));
151061da546Spatrick   }
152061da546Spatrick   if (EffectiveUserIDIsValid()) {
153061da546Spatrick     s.Format("   euid = {0,-5} ({1})\n", GetEffectiveUserID(),
154*f6aab3d8Srobert              resolver.GetUserName(GetEffectiveUserID()).value_or(""));
155061da546Spatrick   }
156061da546Spatrick   if (EffectiveGroupIDIsValid()) {
157061da546Spatrick     s.Format("   egid = {0,-5} ({1})\n", GetEffectiveGroupID(),
158*f6aab3d8Srobert              resolver.GetGroupName(GetEffectiveGroupID()).value_or(""));
159061da546Spatrick   }
160061da546Spatrick }
161061da546Spatrick 
DumpTableHeader(Stream & s,bool show_args,bool verbose)162061da546Spatrick void ProcessInstanceInfo::DumpTableHeader(Stream &s, bool show_args,
163061da546Spatrick                                           bool verbose) {
164061da546Spatrick   const char *label;
165061da546Spatrick   if (show_args || verbose)
166061da546Spatrick     label = "ARGUMENTS";
167061da546Spatrick   else
168061da546Spatrick     label = "NAME";
169061da546Spatrick 
170061da546Spatrick   if (verbose) {
171061da546Spatrick     s.Printf("PID    PARENT USER       GROUP      EFF USER   EFF GROUP  TRIPLE "
172061da546Spatrick              "                        %s\n",
173061da546Spatrick              label);
174061da546Spatrick     s.PutCString(
175061da546Spatrick         "====== ====== ========== ========== ========== ========== "
176061da546Spatrick         "============================== ============================\n");
177061da546Spatrick   } else {
178061da546Spatrick     s.Printf("PID    PARENT USER       TRIPLE                         %s\n",
179061da546Spatrick              label);
180061da546Spatrick     s.PutCString("====== ====== ========== ============================== "
181061da546Spatrick                  "============================\n");
182061da546Spatrick   }
183061da546Spatrick }
184061da546Spatrick 
DumpAsTableRow(Stream & s,UserIDResolver & resolver,bool show_args,bool verbose) const185061da546Spatrick void ProcessInstanceInfo::DumpAsTableRow(Stream &s, UserIDResolver &resolver,
186061da546Spatrick                                          bool show_args, bool verbose) const {
187061da546Spatrick   if (m_pid != LLDB_INVALID_PROCESS_ID) {
188061da546Spatrick     s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, m_parent_pid);
189061da546Spatrick 
190061da546Spatrick     StreamString arch_strm;
191061da546Spatrick     if (m_arch.IsValid())
192061da546Spatrick       m_arch.DumpTriple(arch_strm.AsRawOstream());
193061da546Spatrick 
194061da546Spatrick     auto print = [&](bool (ProcessInstanceInfo::*isValid)() const,
195061da546Spatrick                      uint32_t (ProcessInstanceInfo::*getID)() const,
196*f6aab3d8Srobert                      std::optional<llvm::StringRef> (UserIDResolver::*getName)(
197061da546Spatrick                          UserIDResolver::id_t id)) {
198061da546Spatrick       const char *format = "{0,-10} ";
199061da546Spatrick       if (!(this->*isValid)()) {
200061da546Spatrick         s.Format(format, "");
201061da546Spatrick         return;
202061da546Spatrick       }
203061da546Spatrick       uint32_t id = (this->*getID)();
204061da546Spatrick       if (auto name = (resolver.*getName)(id))
205061da546Spatrick         s.Format(format, *name);
206061da546Spatrick       else
207061da546Spatrick         s.Format(format, id);
208061da546Spatrick     };
209061da546Spatrick     if (verbose) {
210061da546Spatrick       print(&ProcessInstanceInfo::UserIDIsValid,
211061da546Spatrick             &ProcessInstanceInfo::GetUserID, &UserIDResolver::GetUserName);
212061da546Spatrick       print(&ProcessInstanceInfo::GroupIDIsValid,
213061da546Spatrick             &ProcessInstanceInfo::GetGroupID, &UserIDResolver::GetGroupName);
214061da546Spatrick       print(&ProcessInstanceInfo::EffectiveUserIDIsValid,
215061da546Spatrick             &ProcessInstanceInfo::GetEffectiveUserID,
216061da546Spatrick             &UserIDResolver::GetUserName);
217061da546Spatrick       print(&ProcessInstanceInfo::EffectiveGroupIDIsValid,
218061da546Spatrick             &ProcessInstanceInfo::GetEffectiveGroupID,
219061da546Spatrick             &UserIDResolver::GetGroupName);
220061da546Spatrick 
221061da546Spatrick       s.Printf("%-30s ", arch_strm.GetData());
222061da546Spatrick     } else {
223061da546Spatrick       print(&ProcessInstanceInfo::EffectiveUserIDIsValid,
224061da546Spatrick             &ProcessInstanceInfo::GetEffectiveUserID,
225061da546Spatrick             &UserIDResolver::GetUserName);
226061da546Spatrick       s.Printf("%-30s ", arch_strm.GetData());
227061da546Spatrick     }
228061da546Spatrick 
229061da546Spatrick     if (verbose || show_args) {
230061da546Spatrick       s.PutCString(m_arg0);
231061da546Spatrick       const uint32_t argc = m_arguments.GetArgumentCount();
232061da546Spatrick       for (uint32_t i = 0; i < argc; i++) {
233061da546Spatrick         s.PutChar(' ');
234061da546Spatrick         s.PutCString(m_arguments.GetArgumentAtIndex(i));
235061da546Spatrick       }
236061da546Spatrick     } else {
237061da546Spatrick       s.PutCString(GetName());
238061da546Spatrick     }
239061da546Spatrick 
240061da546Spatrick     s.EOL();
241061da546Spatrick   }
242061da546Spatrick }
243061da546Spatrick 
ArchitectureMatches(const ArchSpec & arch_spec) const244061da546Spatrick bool ProcessInstanceInfoMatch::ArchitectureMatches(
245061da546Spatrick     const ArchSpec &arch_spec) const {
246061da546Spatrick   return !m_match_info.GetArchitecture().IsValid() ||
247061da546Spatrick          m_match_info.GetArchitecture().IsCompatibleMatch(arch_spec);
248061da546Spatrick }
249061da546Spatrick 
NameMatches(const char * process_name) const250061da546Spatrick bool ProcessInstanceInfoMatch::NameMatches(const char *process_name) const {
251061da546Spatrick   if (m_name_match_type == NameMatch::Ignore)
252061da546Spatrick     return true;
253061da546Spatrick   const char *match_name = m_match_info.GetName();
254061da546Spatrick   if (!match_name)
255061da546Spatrick     return true;
256061da546Spatrick 
257061da546Spatrick   return lldb_private::NameMatches(process_name, m_name_match_type, match_name);
258061da546Spatrick }
259061da546Spatrick 
ProcessIDsMatch(const ProcessInstanceInfo & proc_info) const260061da546Spatrick bool ProcessInstanceInfoMatch::ProcessIDsMatch(
261061da546Spatrick     const ProcessInstanceInfo &proc_info) const {
262061da546Spatrick   if (m_match_info.ProcessIDIsValid() &&
263061da546Spatrick       m_match_info.GetProcessID() != proc_info.GetProcessID())
264061da546Spatrick     return false;
265061da546Spatrick 
266061da546Spatrick   if (m_match_info.ParentProcessIDIsValid() &&
267061da546Spatrick       m_match_info.GetParentProcessID() != proc_info.GetParentProcessID())
268061da546Spatrick     return false;
269061da546Spatrick   return true;
270061da546Spatrick }
271061da546Spatrick 
UserIDsMatch(const ProcessInstanceInfo & proc_info) const272061da546Spatrick bool ProcessInstanceInfoMatch::UserIDsMatch(
273061da546Spatrick     const ProcessInstanceInfo &proc_info) const {
274061da546Spatrick   if (m_match_info.UserIDIsValid() &&
275061da546Spatrick       m_match_info.GetUserID() != proc_info.GetUserID())
276061da546Spatrick     return false;
277061da546Spatrick 
278061da546Spatrick   if (m_match_info.GroupIDIsValid() &&
279061da546Spatrick       m_match_info.GetGroupID() != proc_info.GetGroupID())
280061da546Spatrick     return false;
281061da546Spatrick 
282061da546Spatrick   if (m_match_info.EffectiveUserIDIsValid() &&
283061da546Spatrick       m_match_info.GetEffectiveUserID() != proc_info.GetEffectiveUserID())
284061da546Spatrick     return false;
285061da546Spatrick 
286061da546Spatrick   if (m_match_info.EffectiveGroupIDIsValid() &&
287061da546Spatrick       m_match_info.GetEffectiveGroupID() != proc_info.GetEffectiveGroupID())
288061da546Spatrick     return false;
289061da546Spatrick   return true;
290061da546Spatrick }
Matches(const ProcessInstanceInfo & proc_info) const291061da546Spatrick bool ProcessInstanceInfoMatch::Matches(
292061da546Spatrick     const ProcessInstanceInfo &proc_info) const {
293061da546Spatrick   return ArchitectureMatches(proc_info.GetArchitecture()) &&
294061da546Spatrick          ProcessIDsMatch(proc_info) && UserIDsMatch(proc_info) &&
295061da546Spatrick          NameMatches(proc_info.GetName());
296061da546Spatrick }
297061da546Spatrick 
MatchAllProcesses() const298061da546Spatrick bool ProcessInstanceInfoMatch::MatchAllProcesses() const {
299061da546Spatrick   if (m_name_match_type != NameMatch::Ignore)
300061da546Spatrick     return false;
301061da546Spatrick 
302061da546Spatrick   if (m_match_info.ProcessIDIsValid())
303061da546Spatrick     return false;
304061da546Spatrick 
305061da546Spatrick   if (m_match_info.ParentProcessIDIsValid())
306061da546Spatrick     return false;
307061da546Spatrick 
308061da546Spatrick   if (m_match_info.UserIDIsValid())
309061da546Spatrick     return false;
310061da546Spatrick 
311061da546Spatrick   if (m_match_info.GroupIDIsValid())
312061da546Spatrick     return false;
313061da546Spatrick 
314061da546Spatrick   if (m_match_info.EffectiveUserIDIsValid())
315061da546Spatrick     return false;
316061da546Spatrick 
317061da546Spatrick   if (m_match_info.EffectiveGroupIDIsValid())
318061da546Spatrick     return false;
319061da546Spatrick 
320061da546Spatrick   if (m_match_info.GetArchitecture().IsValid())
321061da546Spatrick     return false;
322061da546Spatrick 
323061da546Spatrick   if (m_match_all_users)
324061da546Spatrick     return false;
325061da546Spatrick 
326061da546Spatrick   return true;
327061da546Spatrick }
328061da546Spatrick 
Clear()329061da546Spatrick void ProcessInstanceInfoMatch::Clear() {
330061da546Spatrick   m_match_info.Clear();
331061da546Spatrick   m_name_match_type = NameMatch::Ignore;
332061da546Spatrick   m_match_all_users = false;
333061da546Spatrick }
334