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
ProcessInfo()23 ProcessInfo::ProcessInfo()
24 : m_executable(), m_arguments(), m_environment(), m_arch() {}
25
ProcessInfo(const char * name,const ArchSpec & arch,lldb::pid_t pid)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
Clear()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
GetName() const41 const char *ProcessInfo::GetName() const {
42 return m_executable.GetFilename().GetCString();
43 }
44
GetNameAsStringRef() const45 llvm::StringRef ProcessInfo::GetNameAsStringRef() const {
46 return m_executable.GetFilename().GetStringRef();
47 }
48
Dump(Stream & s,Platform * platform) const49 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
SetExecutableFile(const FileSpec & exe_file,bool add_exe_file_as_first_arg)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
GetArg0() const76 llvm::StringRef ProcessInfo::GetArg0() const { return m_arg0; }
77
SetArg0(llvm::StringRef arg)78 void ProcessInfo::SetArg0(llvm::StringRef arg) { m_arg0 = std::string(arg); }
79
SetArguments(char const ** argv,bool first_arg_is_executable)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
SetArguments(const Args & args,bool first_arg_is_executable)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
Dump(Stream & s,UserIDResolver & resolver) const112 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
DumpTableHeader(Stream & s,bool show_args,bool verbose)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
DumpAsTableRow(Stream & s,UserIDResolver & resolver,bool show_args,bool verbose) const185 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
ArchitectureMatches(const ArchSpec & arch_spec) const244 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
NameMatches(const char * process_name) const250 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
ProcessIDsMatch(const ProcessInstanceInfo & proc_info) const260 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
UserIDsMatch(const ProcessInstanceInfo & proc_info) const272 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 }
Matches(const ProcessInstanceInfo & proc_info) const291 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
MatchAllProcesses() const298 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
Clear()329 void ProcessInstanceInfoMatch::Clear() {
330 m_match_info.Clear();
331 m_name_match_type = NameMatch::Ignore;
332 m_match_all_users = false;
333 }
334