blob: aae48d6a4872ef9cdae5036833324bad2aa6370a [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"
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
19using namespace lldb;
20using namespace lldb_private;
Jonas Devlieghere2451cbf2020-03-13 08:49:15 -070021using namespace lldb_private::repro;
Zachary Turner805e7102019-03-04 21:51:03 +000022
23ProcessInfo::ProcessInfo()
24 : m_executable(), m_arguments(), m_environment(), m_uid(UINT32_MAX),
25 m_gid(UINT32_MAX), m_arch(), m_pid(LLDB_INVALID_PROCESS_ID) {}
26
27ProcessInfo::ProcessInfo(const char *name, const ArchSpec &arch,
28 lldb::pid_t pid)
29 : m_executable(name), m_arguments(), m_environment(), m_uid(UINT32_MAX),
30 m_gid(UINT32_MAX), m_arch(arch), m_pid(pid) {}
31
32void ProcessInfo::Clear() {
33 m_executable.Clear();
34 m_arguments.Clear();
35 m_environment.clear();
36 m_uid = UINT32_MAX;
37 m_gid = UINT32_MAX;
38 m_arch.Clear();
39 m_pid = LLDB_INVALID_PROCESS_ID;
40}
41
42const char *ProcessInfo::GetName() const {
43 return m_executable.GetFilename().GetCString();
44}
45
Raphael Isemann72ca5f32019-08-26 08:22:52 +000046llvm::StringRef ProcessInfo::GetNameAsStringRef() const {
47 return m_executable.GetFilename().GetStringRef();
Zachary Turner805e7102019-03-04 21:51:03 +000048}
49
50void ProcessInfo::Dump(Stream &s, Platform *platform) const {
51 s << "Executable: " << GetName() << "\n";
52 s << "Triple: ";
Raphael Isemann2f1e7b32019-12-04 08:27:43 +010053 m_arch.DumpTriple(s.AsRawOstream());
Zachary Turner805e7102019-03-04 21:51:03 +000054 s << "\n";
55
56 s << "Arguments:\n";
57 m_arguments.Dump(s);
58
59 s.Format("Environment:\n{0}", m_environment);
60}
61
62void ProcessInfo::SetExecutableFile(const FileSpec &exe_file,
63 bool add_exe_file_as_first_arg) {
64 if (exe_file) {
65 m_executable = exe_file;
66 if (add_exe_file_as_first_arg) {
67 llvm::SmallString<128> filename;
68 exe_file.GetPath(filename);
69 if (!filename.empty())
70 m_arguments.InsertArgumentAtIndex(0, filename);
71 }
72 } else {
73 m_executable.Clear();
74 }
75}
76
77llvm::StringRef ProcessInfo::GetArg0() const { return m_arg0; }
78
Benjamin Krameradcd0262020-01-28 20:23:46 +010079void ProcessInfo::SetArg0(llvm::StringRef arg) { m_arg0 = std::string(arg); }
Zachary Turner805e7102019-03-04 21:51:03 +000080
81void ProcessInfo::SetArguments(char const **argv,
82 bool first_arg_is_executable) {
83 m_arguments.SetArguments(argv);
84
85 // Is the first argument the executable?
86 if (first_arg_is_executable) {
87 const char *first_arg = m_arguments.GetArgumentAtIndex(0);
88 if (first_arg) {
89 // Yes the first argument is an executable, set it as the executable in
90 // the launch options. Don't resolve the file path as the path could be a
91 // remote platform path
92 m_executable.SetFile(first_arg, FileSpec::Style::native);
93 }
94 }
95}
96
97void ProcessInfo::SetArguments(const Args &args, bool first_arg_is_executable) {
98 // Copy all arguments
99 m_arguments = args;
100
101 // Is the first argument the executable?
102 if (first_arg_is_executable) {
103 const char *first_arg = m_arguments.GetArgumentAtIndex(0);
104 if (first_arg) {
105 // Yes the first argument is an executable, set it as the executable in
106 // the launch options. Don't resolve the file path as the path could be a
107 // remote platform path
108 m_executable.SetFile(first_arg, FileSpec::Style::native);
109 }
110 }
111}
112
113void ProcessInstanceInfo::Dump(Stream &s, UserIDResolver &resolver) const {
114 if (m_pid != LLDB_INVALID_PROCESS_ID)
115 s.Printf(" pid = %" PRIu64 "\n", m_pid);
116
117 if (m_parent_pid != LLDB_INVALID_PROCESS_ID)
118 s.Printf(" parent = %" PRIu64 "\n", m_parent_pid);
119
120 if (m_executable) {
121 s.Printf(" name = %s\n", m_executable.GetFilename().GetCString());
122 s.PutCString(" file = ");
Raphael Isemann4dac97e2019-12-06 08:38:23 +0100123 m_executable.Dump(s.AsRawOstream());
Zachary Turner805e7102019-03-04 21:51:03 +0000124 s.EOL();
125 }
126 const uint32_t argc = m_arguments.GetArgumentCount();
127 if (argc > 0) {
128 for (uint32_t i = 0; i < argc; i++) {
129 const char *arg = m_arguments.GetArgumentAtIndex(i);
130 if (i < 10)
131 s.Printf(" arg[%u] = %s\n", i, arg);
132 else
133 s.Printf("arg[%u] = %s\n", i, arg);
134 }
135 }
136
137 s.Format("{0}", m_environment);
138
139 if (m_arch.IsValid()) {
140 s.Printf(" arch = ");
Raphael Isemann2f1e7b32019-12-04 08:27:43 +0100141 m_arch.DumpTriple(s.AsRawOstream());
Zachary Turner805e7102019-03-04 21:51:03 +0000142 s.EOL();
143 }
144
145 if (UserIDIsValid()) {
146 s.Format(" uid = {0,-5} ({1})\n", GetUserID(),
147 resolver.GetUserName(GetUserID()).getValueOr(""));
148 }
149 if (GroupIDIsValid()) {
150 s.Format(" gid = {0,-5} ({1})\n", GetGroupID(),
151 resolver.GetGroupName(GetGroupID()).getValueOr(""));
152 }
153 if (EffectiveUserIDIsValid()) {
154 s.Format(" euid = {0,-5} ({1})\n", GetEffectiveUserID(),
155 resolver.GetUserName(GetEffectiveUserID()).getValueOr(""));
156 }
157 if (EffectiveGroupIDIsValid()) {
158 s.Format(" egid = {0,-5} ({1})\n", GetEffectiveGroupID(),
159 resolver.GetGroupName(GetEffectiveGroupID()).getValueOr(""));
160 }
161}
162
163void ProcessInstanceInfo::DumpTableHeader(Stream &s, bool show_args,
164 bool verbose) {
165 const char *label;
166 if (show_args || verbose)
167 label = "ARGUMENTS";
168 else
169 label = "NAME";
170
171 if (verbose) {
172 s.Printf("PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE "
Walter Erquinigoe0a398b2019-10-03 21:57:01 +0000173 " %s\n",
Zachary Turner805e7102019-03-04 21:51:03 +0000174 label);
Walter Erquinigoe0a398b2019-10-03 21:57:01 +0000175 s.PutCString(
176 "====== ====== ========== ========== ========== ========== "
177 "============================== ============================\n");
Zachary Turner805e7102019-03-04 21:51:03 +0000178 } else {
Walter Erquinigoe0a398b2019-10-03 21:57:01 +0000179 s.Printf("PID PARENT USER TRIPLE %s\n",
180 label);
181 s.PutCString("====== ====== ========== ============================== "
Zachary Turner805e7102019-03-04 21:51:03 +0000182 "============================\n");
183 }
184}
185
186void ProcessInstanceInfo::DumpAsTableRow(Stream &s, UserIDResolver &resolver,
187 bool show_args, bool verbose) const {
188 if (m_pid != LLDB_INVALID_PROCESS_ID) {
189 s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, m_parent_pid);
190
191 StreamString arch_strm;
192 if (m_arch.IsValid())
Raphael Isemann2f1e7b32019-12-04 08:27:43 +0100193 m_arch.DumpTriple(arch_strm.AsRawOstream());
Zachary Turner805e7102019-03-04 21:51:03 +0000194
Pavel Labath602f29f2019-08-26 13:03:21 +0000195 auto print = [&](bool (ProcessInstanceInfo::*isValid)() const,
196 uint32_t (ProcessInstanceInfo::*getID)() const,
197 llvm::Optional<llvm::StringRef> (UserIDResolver::*getName)(
Zachary Turner805e7102019-03-04 21:51:03 +0000198 UserIDResolver::id_t id)) {
Pavel Labath602f29f2019-08-26 13:03:21 +0000199 const char *format = "{0,-10} ";
200 if (!(this->*isValid)()) {
201 s.Format(format, "");
202 return;
203 }
204 uint32_t id = (this->*getID)();
205 if (auto name = (resolver.*getName)(id))
206 s.Format(format, *name);
Zachary Turner805e7102019-03-04 21:51:03 +0000207 else
Pavel Labath602f29f2019-08-26 13:03:21 +0000208 s.Format(format, id);
Zachary Turner805e7102019-03-04 21:51:03 +0000209 };
210 if (verbose) {
Pavel Labath602f29f2019-08-26 13:03:21 +0000211 print(&ProcessInstanceInfo::UserIDIsValid,
212 &ProcessInstanceInfo::GetUserID, &UserIDResolver::GetUserName);
213 print(&ProcessInstanceInfo::GroupIDIsValid,
214 &ProcessInstanceInfo::GetGroupID, &UserIDResolver::GetGroupName);
215 print(&ProcessInstanceInfo::EffectiveUserIDIsValid,
216 &ProcessInstanceInfo::GetEffectiveUserID,
217 &UserIDResolver::GetUserName);
218 print(&ProcessInstanceInfo::EffectiveGroupIDIsValid,
219 &ProcessInstanceInfo::GetEffectiveGroupID,
220 &UserIDResolver::GetGroupName);
Zachary Turner805e7102019-03-04 21:51:03 +0000221
Walter Erquinigoe0a398b2019-10-03 21:57:01 +0000222 s.Printf("%-30s ", arch_strm.GetData());
Zachary Turner805e7102019-03-04 21:51:03 +0000223 } else {
Pavel Labath602f29f2019-08-26 13:03:21 +0000224 print(&ProcessInstanceInfo::EffectiveUserIDIsValid,
225 &ProcessInstanceInfo::GetEffectiveUserID,
226 &UserIDResolver::GetUserName);
Walter Erquinigoe0a398b2019-10-03 21:57:01 +0000227 s.Printf("%-30s ", arch_strm.GetData());
Zachary Turner805e7102019-03-04 21:51:03 +0000228 }
229
230 if (verbose || show_args) {
Walter Erquinigo48a50ee2019-10-16 18:47:05 +0000231 s.PutCString(m_arg0);
Zachary Turner805e7102019-03-04 21:51:03 +0000232 const uint32_t argc = m_arguments.GetArgumentCount();
Walter Erquinigo48a50ee2019-10-16 18:47:05 +0000233 for (uint32_t i = 0; i < argc; i++) {
234 s.PutChar(' ');
235 s.PutCString(m_arguments.GetArgumentAtIndex(i));
Zachary Turner805e7102019-03-04 21:51:03 +0000236 }
237 } else {
238 s.PutCString(GetName());
239 }
240
241 s.EOL();
242 }
243}
244
Pavel Labatha8b18ba2019-10-11 10:56:54 +0000245bool ProcessInstanceInfoMatch::ArchitectureMatches(
246 const ArchSpec &arch_spec) const {
247 return !m_match_info.GetArchitecture().IsValid() ||
248 m_match_info.GetArchitecture().IsCompatibleMatch(arch_spec);
249}
250
Zachary Turner805e7102019-03-04 21:51:03 +0000251bool ProcessInstanceInfoMatch::NameMatches(const char *process_name) const {
Pavel Labatha8b18ba2019-10-11 10:56:54 +0000252 if (m_name_match_type == NameMatch::Ignore)
Zachary Turner805e7102019-03-04 21:51:03 +0000253 return true;
254 const char *match_name = m_match_info.GetName();
255 if (!match_name)
256 return true;
257
258 return lldb_private::NameMatches(process_name, m_name_match_type, match_name);
259}
260
Pavel Labatha8b18ba2019-10-11 10:56:54 +0000261bool ProcessInstanceInfoMatch::ProcessIDsMatch(
Zachary Turner805e7102019-03-04 21:51:03 +0000262 const ProcessInstanceInfo &proc_info) const {
Zachary Turner805e7102019-03-04 21:51:03 +0000263 if (m_match_info.ProcessIDIsValid() &&
264 m_match_info.GetProcessID() != proc_info.GetProcessID())
265 return false;
266
267 if (m_match_info.ParentProcessIDIsValid() &&
268 m_match_info.GetParentProcessID() != proc_info.GetParentProcessID())
269 return false;
Pavel Labatha8b18ba2019-10-11 10:56:54 +0000270 return true;
271}
Zachary Turner805e7102019-03-04 21:51:03 +0000272
Pavel Labatha8b18ba2019-10-11 10:56:54 +0000273bool ProcessInstanceInfoMatch::UserIDsMatch(
274 const ProcessInstanceInfo &proc_info) const {
Zachary Turner805e7102019-03-04 21:51:03 +0000275 if (m_match_info.UserIDIsValid() &&
276 m_match_info.GetUserID() != proc_info.GetUserID())
277 return false;
278
279 if (m_match_info.GroupIDIsValid() &&
280 m_match_info.GetGroupID() != proc_info.GetGroupID())
281 return false;
282
283 if (m_match_info.EffectiveUserIDIsValid() &&
284 m_match_info.GetEffectiveUserID() != proc_info.GetEffectiveUserID())
285 return false;
286
287 if (m_match_info.EffectiveGroupIDIsValid() &&
288 m_match_info.GetEffectiveGroupID() != proc_info.GetEffectiveGroupID())
289 return false;
Zachary Turner805e7102019-03-04 21:51:03 +0000290 return true;
291}
Pavel Labatha8b18ba2019-10-11 10:56:54 +0000292bool ProcessInstanceInfoMatch::Matches(
293 const ProcessInstanceInfo &proc_info) const {
294 return ArchitectureMatches(proc_info.GetArchitecture()) &&
295 ProcessIDsMatch(proc_info) && UserIDsMatch(proc_info) &&
296 NameMatches(proc_info.GetName());
297}
Zachary Turner805e7102019-03-04 21:51:03 +0000298
299bool ProcessInstanceInfoMatch::MatchAllProcesses() const {
300 if (m_name_match_type != NameMatch::Ignore)
301 return false;
302
303 if (m_match_info.ProcessIDIsValid())
304 return false;
305
306 if (m_match_info.ParentProcessIDIsValid())
307 return false;
308
309 if (m_match_info.UserIDIsValid())
310 return false;
311
312 if (m_match_info.GroupIDIsValid())
313 return false;
314
315 if (m_match_info.EffectiveUserIDIsValid())
316 return false;
317
318 if (m_match_info.EffectiveGroupIDIsValid())
319 return false;
320
321 if (m_match_info.GetArchitecture().IsValid())
322 return false;
323
324 if (m_match_all_users)
325 return false;
326
327 return true;
328}
329
330void ProcessInstanceInfoMatch::Clear() {
331 m_match_info.Clear();
332 m_name_match_type = NameMatch::Ignore;
333 m_match_all_users = false;
334}
Jonas Devlieghere0ce3b712020-03-12 14:34:44 -0700335
336void llvm::yaml::MappingTraits<ProcessInstanceInfo>::mapping(
337 IO &io, ProcessInstanceInfo &Info) {
338 io.mapRequired("executable", Info.m_executable);
339 io.mapRequired("arg0", Info.m_arg0);
Jonas Devliegherebad61542020-05-12 10:28:27 -0700340 io.mapRequired("args", Info.m_arguments);
Jonas Devlieghere0ce3b712020-03-12 14:34:44 -0700341 io.mapRequired("arch", Info.m_arch);
342 io.mapRequired("uid", Info.m_uid);
343 io.mapRequired("gid", Info.m_gid);
344 io.mapRequired("pid", Info.m_pid);
345 io.mapRequired("effective-uid", Info.m_euid);
346 io.mapRequired("effective-gid", Info.m_egid);
347 io.mapRequired("parent-pid", Info.m_parent_pid);
348}
Jonas Devlieghere2451cbf2020-03-13 08:49:15 -0700349
350llvm::Expected<std::unique_ptr<ProcessInfoRecorder>>
351ProcessInfoRecorder::Create(const FileSpec &filename) {
352 std::error_code ec;
353 auto recorder =
354 std::make_unique<ProcessInfoRecorder>(std::move(filename), ec);
355 if (ec)
356 return llvm::errorCodeToError(ec);
357 return std::move(recorder);
358}
359
360void ProcessInfoProvider::Keep() {
361 std::vector<std::string> files;
362 for (auto &recorder : m_process_info_recorders) {
363 recorder->Stop();
364 files.push_back(recorder->GetFilename().GetPath());
365 }
366
367 FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file);
368 std::error_code ec;
369 llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text);
370 if (ec)
371 return;
372 llvm::yaml::Output yout(os);
373 yout << files;
374}
375
376void ProcessInfoProvider::Discard() { m_process_info_recorders.clear(); }
377
378ProcessInfoRecorder *ProcessInfoProvider::GetNewProcessInfoRecorder() {
379 std::size_t i = m_process_info_recorders.size() + 1;
380 std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") +
381 llvm::Twine(i) + llvm::Twine(".yaml"))
382 .str();
383 auto recorder_or_error = ProcessInfoRecorder::Create(
384 GetRoot().CopyByAppendingPathComponent(filename));
385 if (!recorder_or_error) {
386 llvm::consumeError(recorder_or_error.takeError());
387 return nullptr;
388 }
389
390 m_process_info_recorders.push_back(std::move(*recorder_or_error));
391 return m_process_info_recorders.back().get();
392}
393
394void ProcessInfoRecorder::Record(const ProcessInstanceInfoList &process_infos) {
395 if (!m_record)
396 return;
397 llvm::yaml::Output yout(m_os);
398 yout << const_cast<ProcessInstanceInfoList &>(process_infos);
399 m_os.flush();
400}
401
402llvm::Optional<ProcessInstanceInfoList>
403repro::GetReplayProcessInstanceInfoList() {
404 static std::unique_ptr<repro::MultiLoader<repro::ProcessInfoProvider>>
405 loader = repro::MultiLoader<repro::ProcessInfoProvider>::Create(
406 repro::Reproducer::Instance().GetLoader());
407
408 if (!loader)
409 return {};
410
411 llvm::Optional<std::string> nextfile = loader->GetNextFile();
412 if (!nextfile)
413 return {};
414
415 auto error_or_file = llvm::MemoryBuffer::getFile(*nextfile);
416 if (std::error_code err = error_or_file.getError())
417 return {};
418
419 ProcessInstanceInfoList infos;
420 llvm::yaml::Input yin((*error_or_file)->getBuffer());
421 yin >> infos;
422
423 if (auto err = yin.error())
424 return {};
425
426 return infos;
427}
428
429char ProcessInfoProvider::ID = 0;
430const char *ProcessInfoProvider::Info::file = "process-info.yaml";
431const char *ProcessInfoProvider::Info::name = "process-info";