blob: 310d2b22b1744f0539380bfb90e2c18faa2877da [file] [log] [blame]
Raphael Isemann80814282020-01-24 08:23:27 +01001//===-- ProcessInfo.cpp ---------------------------------------------------===//
Zachary Turner805e7102019-03-04 21:51:03 +00002//
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"
Jonas Devliegherebb894b92020-08-22 00:36:32 -070012#include "lldb/Utility/ReproducerProvider.h"
Zachary Turner805e7102019-03-04 21:51:03 +000013#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
20using namespace lldb;
21using namespace lldb_private;
Jonas Devlieghere2451cbf2020-03-13 08:49:15 -070022using namespace lldb_private::repro;
Zachary Turner805e7102019-03-04 21:51:03 +000023
24ProcessInfo::ProcessInfo()
25 : m_executable(), m_arguments(), m_environment(), m_uid(UINT32_MAX),
26 m_gid(UINT32_MAX), m_arch(), m_pid(LLDB_INVALID_PROCESS_ID) {}
27
28ProcessInfo::ProcessInfo(const char *name, const ArchSpec &arch,
29 lldb::pid_t pid)
30 : m_executable(name), m_arguments(), m_environment(), m_uid(UINT32_MAX),
31 m_gid(UINT32_MAX), m_arch(arch), m_pid(pid) {}
32
33void ProcessInfo::Clear() {
34 m_executable.Clear();
35 m_arguments.Clear();
36 m_environment.clear();
37 m_uid = UINT32_MAX;
38 m_gid = UINT32_MAX;
39 m_arch.Clear();
40 m_pid = LLDB_INVALID_PROCESS_ID;
41}
42
43const char *ProcessInfo::GetName() const {
44 return m_executable.GetFilename().GetCString();
45}
46
Raphael Isemann72ca5f32019-08-26 08:22:52 +000047llvm::StringRef ProcessInfo::GetNameAsStringRef() const {
48 return m_executable.GetFilename().GetStringRef();
Zachary Turner805e7102019-03-04 21:51:03 +000049}
50
51void ProcessInfo::Dump(Stream &s, Platform *platform) const {
52 s << "Executable: " << GetName() << "\n";
53 s << "Triple: ";
Raphael Isemann2f1e7b32019-12-04 08:27:43 +010054 m_arch.DumpTriple(s.AsRawOstream());
Zachary Turner805e7102019-03-04 21:51:03 +000055 s << "\n";
56
57 s << "Arguments:\n";
58 m_arguments.Dump(s);
59
60 s.Format("Environment:\n{0}", m_environment);
61}
62
63void ProcessInfo::SetExecutableFile(const FileSpec &exe_file,
64 bool add_exe_file_as_first_arg) {
65 if (exe_file) {
66 m_executable = exe_file;
67 if (add_exe_file_as_first_arg) {
68 llvm::SmallString<128> filename;
69 exe_file.GetPath(filename);
70 if (!filename.empty())
71 m_arguments.InsertArgumentAtIndex(0, filename);
72 }
73 } else {
74 m_executable.Clear();
75 }
76}
77
78llvm::StringRef ProcessInfo::GetArg0() const { return m_arg0; }
79
Benjamin Krameradcd0262020-01-28 20:23:46 +010080void ProcessInfo::SetArg0(llvm::StringRef arg) { m_arg0 = std::string(arg); }
Zachary Turner805e7102019-03-04 21:51:03 +000081
82void ProcessInfo::SetArguments(char const **argv,
83 bool first_arg_is_executable) {
84 m_arguments.SetArguments(argv);
85
86 // Is the first argument the executable?
87 if (first_arg_is_executable) {
88 const char *first_arg = m_arguments.GetArgumentAtIndex(0);
89 if (first_arg) {
90 // Yes the first argument is an executable, set it as the executable in
91 // the launch options. Don't resolve the file path as the path could be a
92 // remote platform path
93 m_executable.SetFile(first_arg, FileSpec::Style::native);
94 }
95 }
96}
97
98void ProcessInfo::SetArguments(const Args &args, bool first_arg_is_executable) {
99 // Copy all arguments
100 m_arguments = args;
101
102 // Is the first argument the executable?
103 if (first_arg_is_executable) {
104 const char *first_arg = m_arguments.GetArgumentAtIndex(0);
105 if (first_arg) {
106 // Yes the first argument is an executable, set it as the executable in
107 // the launch options. Don't resolve the file path as the path could be a
108 // remote platform path
109 m_executable.SetFile(first_arg, FileSpec::Style::native);
110 }
111 }
112}
113
114void ProcessInstanceInfo::Dump(Stream &s, UserIDResolver &resolver) const {
115 if (m_pid != LLDB_INVALID_PROCESS_ID)
116 s.Printf(" pid = %" PRIu64 "\n", m_pid);
117
118 if (m_parent_pid != LLDB_INVALID_PROCESS_ID)
119 s.Printf(" parent = %" PRIu64 "\n", m_parent_pid);
120
121 if (m_executable) {
122 s.Printf(" name = %s\n", m_executable.GetFilename().GetCString());
123 s.PutCString(" file = ");
Raphael Isemann4dac97e2019-12-06 08:38:23 +0100124 m_executable.Dump(s.AsRawOstream());
Zachary Turner805e7102019-03-04 21:51:03 +0000125 s.EOL();
126 }
127 const uint32_t argc = m_arguments.GetArgumentCount();
128 if (argc > 0) {
129 for (uint32_t i = 0; i < argc; i++) {
130 const char *arg = m_arguments.GetArgumentAtIndex(i);
131 if (i < 10)
132 s.Printf(" arg[%u] = %s\n", i, arg);
133 else
134 s.Printf("arg[%u] = %s\n", i, arg);
135 }
136 }
137
138 s.Format("{0}", m_environment);
139
140 if (m_arch.IsValid()) {
141 s.Printf(" arch = ");
Raphael Isemann2f1e7b32019-12-04 08:27:43 +0100142 m_arch.DumpTriple(s.AsRawOstream());
Zachary Turner805e7102019-03-04 21:51:03 +0000143 s.EOL();
144 }
145
146 if (UserIDIsValid()) {
147 s.Format(" uid = {0,-5} ({1})\n", GetUserID(),
148 resolver.GetUserName(GetUserID()).getValueOr(""));
149 }
150 if (GroupIDIsValid()) {
151 s.Format(" gid = {0,-5} ({1})\n", GetGroupID(),
152 resolver.GetGroupName(GetGroupID()).getValueOr(""));
153 }
154 if (EffectiveUserIDIsValid()) {
155 s.Format(" euid = {0,-5} ({1})\n", GetEffectiveUserID(),
156 resolver.GetUserName(GetEffectiveUserID()).getValueOr(""));
157 }
158 if (EffectiveGroupIDIsValid()) {
159 s.Format(" egid = {0,-5} ({1})\n", GetEffectiveGroupID(),
160 resolver.GetGroupName(GetEffectiveGroupID()).getValueOr(""));
161 }
162}
163
164void ProcessInstanceInfo::DumpTableHeader(Stream &s, bool show_args,
165 bool verbose) {
166 const char *label;
167 if (show_args || verbose)
168 label = "ARGUMENTS";
169 else
170 label = "NAME";
171
172 if (verbose) {
173 s.Printf("PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE "
Walter Erquinigoe0a398b2019-10-03 21:57:01 +0000174 " %s\n",
Zachary Turner805e7102019-03-04 21:51:03 +0000175 label);
Walter Erquinigoe0a398b2019-10-03 21:57:01 +0000176 s.PutCString(
177 "====== ====== ========== ========== ========== ========== "
178 "============================== ============================\n");
Zachary Turner805e7102019-03-04 21:51:03 +0000179 } else {
Walter Erquinigoe0a398b2019-10-03 21:57:01 +0000180 s.Printf("PID PARENT USER TRIPLE %s\n",
181 label);
182 s.PutCString("====== ====== ========== ============================== "
Zachary Turner805e7102019-03-04 21:51:03 +0000183 "============================\n");
184 }
185}
186
187void ProcessInstanceInfo::DumpAsTableRow(Stream &s, UserIDResolver &resolver,
188 bool show_args, bool verbose) const {
189 if (m_pid != LLDB_INVALID_PROCESS_ID) {
190 s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, m_parent_pid);
191
192 StreamString arch_strm;
193 if (m_arch.IsValid())
Raphael Isemann2f1e7b32019-12-04 08:27:43 +0100194 m_arch.DumpTriple(arch_strm.AsRawOstream());
Zachary Turner805e7102019-03-04 21:51:03 +0000195
Pavel Labath602f29f2019-08-26 13:03:21 +0000196 auto print = [&](bool (ProcessInstanceInfo::*isValid)() const,
197 uint32_t (ProcessInstanceInfo::*getID)() const,
198 llvm::Optional<llvm::StringRef> (UserIDResolver::*getName)(
Zachary Turner805e7102019-03-04 21:51:03 +0000199 UserIDResolver::id_t id)) {
Pavel Labath602f29f2019-08-26 13:03:21 +0000200 const char *format = "{0,-10} ";
201 if (!(this->*isValid)()) {
202 s.Format(format, "");
203 return;
204 }
205 uint32_t id = (this->*getID)();
206 if (auto name = (resolver.*getName)(id))
207 s.Format(format, *name);
Zachary Turner805e7102019-03-04 21:51:03 +0000208 else
Pavel Labath602f29f2019-08-26 13:03:21 +0000209 s.Format(format, id);
Zachary Turner805e7102019-03-04 21:51:03 +0000210 };
211 if (verbose) {
Pavel Labath602f29f2019-08-26 13:03:21 +0000212 print(&ProcessInstanceInfo::UserIDIsValid,
213 &ProcessInstanceInfo::GetUserID, &UserIDResolver::GetUserName);
214 print(&ProcessInstanceInfo::GroupIDIsValid,
215 &ProcessInstanceInfo::GetGroupID, &UserIDResolver::GetGroupName);
216 print(&ProcessInstanceInfo::EffectiveUserIDIsValid,
217 &ProcessInstanceInfo::GetEffectiveUserID,
218 &UserIDResolver::GetUserName);
219 print(&ProcessInstanceInfo::EffectiveGroupIDIsValid,
220 &ProcessInstanceInfo::GetEffectiveGroupID,
221 &UserIDResolver::GetGroupName);
Zachary Turner805e7102019-03-04 21:51:03 +0000222
Walter Erquinigoe0a398b2019-10-03 21:57:01 +0000223 s.Printf("%-30s ", arch_strm.GetData());
Zachary Turner805e7102019-03-04 21:51:03 +0000224 } else {
Pavel Labath602f29f2019-08-26 13:03:21 +0000225 print(&ProcessInstanceInfo::EffectiveUserIDIsValid,
226 &ProcessInstanceInfo::GetEffectiveUserID,
227 &UserIDResolver::GetUserName);
Walter Erquinigoe0a398b2019-10-03 21:57:01 +0000228 s.Printf("%-30s ", arch_strm.GetData());
Zachary Turner805e7102019-03-04 21:51:03 +0000229 }
230
231 if (verbose || show_args) {
Walter Erquinigo48a50ee2019-10-16 18:47:05 +0000232 s.PutCString(m_arg0);
Zachary Turner805e7102019-03-04 21:51:03 +0000233 const uint32_t argc = m_arguments.GetArgumentCount();
Walter Erquinigo48a50ee2019-10-16 18:47:05 +0000234 for (uint32_t i = 0; i < argc; i++) {
235 s.PutChar(' ');
236 s.PutCString(m_arguments.GetArgumentAtIndex(i));
Zachary Turner805e7102019-03-04 21:51:03 +0000237 }
238 } else {
239 s.PutCString(GetName());
240 }
241
242 s.EOL();
243 }
244}
245
Pavel Labatha8b18ba2019-10-11 10:56:54 +0000246bool ProcessInstanceInfoMatch::ArchitectureMatches(
247 const ArchSpec &arch_spec) const {
248 return !m_match_info.GetArchitecture().IsValid() ||
249 m_match_info.GetArchitecture().IsCompatibleMatch(arch_spec);
250}
251
Zachary Turner805e7102019-03-04 21:51:03 +0000252bool ProcessInstanceInfoMatch::NameMatches(const char *process_name) const {
Pavel Labatha8b18ba2019-10-11 10:56:54 +0000253 if (m_name_match_type == NameMatch::Ignore)
Zachary Turner805e7102019-03-04 21:51:03 +0000254 return true;
255 const char *match_name = m_match_info.GetName();
256 if (!match_name)
257 return true;
258
259 return lldb_private::NameMatches(process_name, m_name_match_type, match_name);
260}
261
Pavel Labatha8b18ba2019-10-11 10:56:54 +0000262bool ProcessInstanceInfoMatch::ProcessIDsMatch(
Zachary Turner805e7102019-03-04 21:51:03 +0000263 const ProcessInstanceInfo &proc_info) const {
Zachary Turner805e7102019-03-04 21:51:03 +0000264 if (m_match_info.ProcessIDIsValid() &&
265 m_match_info.GetProcessID() != proc_info.GetProcessID())
266 return false;
267
268 if (m_match_info.ParentProcessIDIsValid() &&
269 m_match_info.GetParentProcessID() != proc_info.GetParentProcessID())
270 return false;
Pavel Labatha8b18ba2019-10-11 10:56:54 +0000271 return true;
272}
Zachary Turner805e7102019-03-04 21:51:03 +0000273
Pavel Labatha8b18ba2019-10-11 10:56:54 +0000274bool ProcessInstanceInfoMatch::UserIDsMatch(
275 const ProcessInstanceInfo &proc_info) const {
Zachary Turner805e7102019-03-04 21:51:03 +0000276 if (m_match_info.UserIDIsValid() &&
277 m_match_info.GetUserID() != proc_info.GetUserID())
278 return false;
279
280 if (m_match_info.GroupIDIsValid() &&
281 m_match_info.GetGroupID() != proc_info.GetGroupID())
282 return false;
283
284 if (m_match_info.EffectiveUserIDIsValid() &&
285 m_match_info.GetEffectiveUserID() != proc_info.GetEffectiveUserID())
286 return false;
287
288 if (m_match_info.EffectiveGroupIDIsValid() &&
289 m_match_info.GetEffectiveGroupID() != proc_info.GetEffectiveGroupID())
290 return false;
Zachary Turner805e7102019-03-04 21:51:03 +0000291 return true;
292}
Pavel Labatha8b18ba2019-10-11 10:56:54 +0000293bool ProcessInstanceInfoMatch::Matches(
294 const ProcessInstanceInfo &proc_info) const {
295 return ArchitectureMatches(proc_info.GetArchitecture()) &&
296 ProcessIDsMatch(proc_info) && UserIDsMatch(proc_info) &&
297 NameMatches(proc_info.GetName());
298}
Zachary Turner805e7102019-03-04 21:51:03 +0000299
300bool ProcessInstanceInfoMatch::MatchAllProcesses() const {
301 if (m_name_match_type != NameMatch::Ignore)
302 return false;
303
304 if (m_match_info.ProcessIDIsValid())
305 return false;
306
307 if (m_match_info.ParentProcessIDIsValid())
308 return false;
309
310 if (m_match_info.UserIDIsValid())
311 return false;
312
313 if (m_match_info.GroupIDIsValid())
314 return false;
315
316 if (m_match_info.EffectiveUserIDIsValid())
317 return false;
318
319 if (m_match_info.EffectiveGroupIDIsValid())
320 return false;
321
322 if (m_match_info.GetArchitecture().IsValid())
323 return false;
324
325 if (m_match_all_users)
326 return false;
327
328 return true;
329}
330
331void ProcessInstanceInfoMatch::Clear() {
332 m_match_info.Clear();
333 m_name_match_type = NameMatch::Ignore;
334 m_match_all_users = false;
335}
Jonas Devlieghere0ce3b712020-03-12 14:34:44 -0700336
337void llvm::yaml::MappingTraits<ProcessInstanceInfo>::mapping(
338 IO &io, ProcessInstanceInfo &Info) {
339 io.mapRequired("executable", Info.m_executable);
340 io.mapRequired("arg0", Info.m_arg0);
Jonas Devliegherebad61542020-05-12 10:28:27 -0700341 io.mapRequired("args", Info.m_arguments);
Jonas Devlieghere0ce3b712020-03-12 14:34:44 -0700342 io.mapRequired("arch", Info.m_arch);
343 io.mapRequired("uid", Info.m_uid);
344 io.mapRequired("gid", Info.m_gid);
345 io.mapRequired("pid", Info.m_pid);
346 io.mapRequired("effective-uid", Info.m_euid);
347 io.mapRequired("effective-gid", Info.m_egid);
348 io.mapRequired("parent-pid", Info.m_parent_pid);
349}
Jonas Devlieghere2451cbf2020-03-13 08:49:15 -0700350
Jonas Devlieghere2451cbf2020-03-13 08:49:15 -0700351
352llvm::Optional<ProcessInstanceInfoList>
353repro::GetReplayProcessInstanceInfoList() {
354 static std::unique_ptr<repro::MultiLoader<repro::ProcessInfoProvider>>
355 loader = repro::MultiLoader<repro::ProcessInfoProvider>::Create(
356 repro::Reproducer::Instance().GetLoader());
357
358 if (!loader)
359 return {};
360
361 llvm::Optional<std::string> nextfile = loader->GetNextFile();
362 if (!nextfile)
363 return {};
364
365 auto error_or_file = llvm::MemoryBuffer::getFile(*nextfile);
366 if (std::error_code err = error_or_file.getError())
367 return {};
368
369 ProcessInstanceInfoList infos;
370 llvm::yaml::Input yin((*error_or_file)->getBuffer());
371 yin >> infos;
372
373 if (auto err = yin.error())
374 return {};
375
376 return infos;
377}