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

source code of lldb/source/Utility/ProcessInfo.cpp