1 //===-- ProcessInfo.cpp ---------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Utility/ProcessInfo.h"
11 #include "lldb/Utility/ArchSpec.h"
12 #include "lldb/Utility/ReproducerProvider.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"
21 using namespace lldb_private
;
22 using namespace lldb_private::repro
;
24 ProcessInfo::ProcessInfo()
25 : m_executable(), m_arguments(), m_environment(), m_arch() {}
27 ProcessInfo::ProcessInfo(const char *name
, const ArchSpec
&arch
,
29 : m_executable(name
), m_arguments(), m_environment(), m_uid(UINT32_MAX
),
30 m_gid(UINT32_MAX
), m_arch(arch
), m_pid(pid
) {}
32 void ProcessInfo::Clear() {
35 m_environment
.clear();
39 m_pid
= LLDB_INVALID_PROCESS_ID
;
42 const char *ProcessInfo::GetName() const {
43 return m_executable
.GetFilename().GetCString();
46 llvm::StringRef
ProcessInfo::GetNameAsStringRef() const {
47 return m_executable
.GetFilename().GetStringRef();
50 void ProcessInfo::Dump(Stream
&s
, Platform
*platform
) const {
51 s
<< "Executable: " << GetName() << "\n";
53 m_arch
.DumpTriple(s
.AsRawOstream());
59 s
.Format("Environment:\n{0}", m_environment
);
62 void ProcessInfo::SetExecutableFile(const FileSpec
&exe_file
,
63 bool add_exe_file_as_first_arg
) {
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
);
77 llvm::StringRef
ProcessInfo::GetArg0() const { return m_arg0
; }
79 void ProcessInfo::SetArg0(llvm::StringRef arg
) { m_arg0
= std::string(arg
); }
81 void ProcessInfo::SetArguments(char const **argv
,
82 bool first_arg_is_executable
) {
83 m_arguments
.SetArguments(argv
);
85 // Is the first argument the executable?
86 if (first_arg_is_executable
) {
87 const char *first_arg
= m_arguments
.GetArgumentAtIndex(0);
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
);
97 void ProcessInfo::SetArguments(const Args
&args
, bool first_arg_is_executable
) {
101 // Is the first argument the executable?
102 if (first_arg_is_executable
) {
103 const char *first_arg
= m_arguments
.GetArgumentAtIndex(0);
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
);
113 void ProcessInstanceInfo::Dump(Stream
&s
, UserIDResolver
&resolver
) const {
114 if (m_pid
!= LLDB_INVALID_PROCESS_ID
)
115 s
.Printf(" pid = %" PRIu64
"\n", m_pid
);
117 if (m_parent_pid
!= LLDB_INVALID_PROCESS_ID
)
118 s
.Printf(" parent = %" PRIu64
"\n", m_parent_pid
);
121 s
.Printf(" name = %s\n", m_executable
.GetFilename().GetCString());
122 s
.PutCString(" file = ");
123 m_executable
.Dump(s
.AsRawOstream());
126 const uint32_t argc
= m_arguments
.GetArgumentCount();
128 for (uint32_t i
= 0; i
< argc
; i
++) {
129 const char *arg
= m_arguments
.GetArgumentAtIndex(i
);
131 s
.Printf(" arg[%u] = %s\n", i
, arg
);
133 s
.Printf("arg[%u] = %s\n", i
, arg
);
137 s
.Format("{0}", m_environment
);
139 if (m_arch
.IsValid()) {
140 s
.Printf(" arch = ");
141 m_arch
.DumpTriple(s
.AsRawOstream());
145 if (UserIDIsValid()) {
146 s
.Format(" uid = {0,-5} ({1})\n", GetUserID(),
147 resolver
.GetUserName(GetUserID()).getValueOr(""));
149 if (GroupIDIsValid()) {
150 s
.Format(" gid = {0,-5} ({1})\n", GetGroupID(),
151 resolver
.GetGroupName(GetGroupID()).getValueOr(""));
153 if (EffectiveUserIDIsValid()) {
154 s
.Format(" euid = {0,-5} ({1})\n", GetEffectiveUserID(),
155 resolver
.GetUserName(GetEffectiveUserID()).getValueOr(""));
157 if (EffectiveGroupIDIsValid()) {
158 s
.Format(" egid = {0,-5} ({1})\n", GetEffectiveGroupID(),
159 resolver
.GetGroupName(GetEffectiveGroupID()).getValueOr(""));
163 void ProcessInstanceInfo::DumpTableHeader(Stream
&s
, bool show_args
,
166 if (show_args
|| verbose
)
172 s
.Printf("PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE "
176 "====== ====== ========== ========== ========== ========== "
177 "============================== ============================\n");
179 s
.Printf("PID PARENT USER TRIPLE %s\n",
181 s
.PutCString("====== ====== ========== ============================== "
182 "============================\n");
186 void 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
);
191 StreamString arch_strm
;
192 if (m_arch
.IsValid())
193 m_arch
.DumpTriple(arch_strm
.AsRawOstream());
195 auto print
= [&](bool (ProcessInstanceInfo::*isValid
)() const,
196 uint32_t (ProcessInstanceInfo::*getID
)() const,
197 llvm::Optional
<llvm::StringRef
> (UserIDResolver::*getName
)(
198 UserIDResolver::id_t id
)) {
199 const char *format
= "{0,-10} ";
200 if (!(this->*isValid
)()) {
201 s
.Format(format
, "");
204 uint32_t id
= (this->*getID
)();
205 if (auto name
= (resolver
.*getName
)(id
))
206 s
.Format(format
, *name
);
208 s
.Format(format
, id
);
211 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
);
222 s
.Printf("%-30s ", arch_strm
.GetData());
224 print(&ProcessInstanceInfo::EffectiveUserIDIsValid
,
225 &ProcessInstanceInfo::GetEffectiveUserID
,
226 &UserIDResolver::GetUserName
);
227 s
.Printf("%-30s ", arch_strm
.GetData());
230 if (verbose
|| show_args
) {
231 s
.PutCString(m_arg0
);
232 const uint32_t argc
= m_arguments
.GetArgumentCount();
233 for (uint32_t i
= 0; i
< argc
; i
++) {
235 s
.PutCString(m_arguments
.GetArgumentAtIndex(i
));
238 s
.PutCString(GetName());
245 bool ProcessInstanceInfoMatch::ArchitectureMatches(
246 const ArchSpec
&arch_spec
) const {
247 return !m_match_info
.GetArchitecture().IsValid() ||
248 m_match_info
.GetArchitecture().IsCompatibleMatch(arch_spec
);
251 bool ProcessInstanceInfoMatch::NameMatches(const char *process_name
) const {
252 if (m_name_match_type
== NameMatch::Ignore
)
254 const char *match_name
= m_match_info
.GetName();
258 return lldb_private::NameMatches(process_name
, m_name_match_type
, match_name
);
261 bool ProcessInstanceInfoMatch::ProcessIDsMatch(
262 const ProcessInstanceInfo
&proc_info
) const {
263 if (m_match_info
.ProcessIDIsValid() &&
264 m_match_info
.GetProcessID() != proc_info
.GetProcessID())
267 if (m_match_info
.ParentProcessIDIsValid() &&
268 m_match_info
.GetParentProcessID() != proc_info
.GetParentProcessID())
273 bool ProcessInstanceInfoMatch::UserIDsMatch(
274 const ProcessInstanceInfo
&proc_info
) const {
275 if (m_match_info
.UserIDIsValid() &&
276 m_match_info
.GetUserID() != proc_info
.GetUserID())
279 if (m_match_info
.GroupIDIsValid() &&
280 m_match_info
.GetGroupID() != proc_info
.GetGroupID())
283 if (m_match_info
.EffectiveUserIDIsValid() &&
284 m_match_info
.GetEffectiveUserID() != proc_info
.GetEffectiveUserID())
287 if (m_match_info
.EffectiveGroupIDIsValid() &&
288 m_match_info
.GetEffectiveGroupID() != proc_info
.GetEffectiveGroupID())
292 bool 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());
299 bool ProcessInstanceInfoMatch::MatchAllProcesses() const {
300 if (m_name_match_type
!= NameMatch::Ignore
)
303 if (m_match_info
.ProcessIDIsValid())
306 if (m_match_info
.ParentProcessIDIsValid())
309 if (m_match_info
.UserIDIsValid())
312 if (m_match_info
.GroupIDIsValid())
315 if (m_match_info
.EffectiveUserIDIsValid())
318 if (m_match_info
.EffectiveGroupIDIsValid())
321 if (m_match_info
.GetArchitecture().IsValid())
324 if (m_match_all_users
)
330 void ProcessInstanceInfoMatch::Clear() {
331 m_match_info
.Clear();
332 m_name_match_type
= NameMatch::Ignore
;
333 m_match_all_users
= false;
336 void llvm::yaml::MappingTraits
<ProcessInstanceInfo
>::mapping(
337 IO
&io
, ProcessInstanceInfo
&Info
) {
338 io
.mapRequired("executable", Info
.m_executable
);
339 io
.mapRequired("arg0", Info
.m_arg0
);
340 io
.mapRequired("args", Info
.m_arguments
);
341 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
);
351 llvm::Optional
<ProcessInstanceInfoList
>
352 repro::GetReplayProcessInstanceInfoList() {
353 static std::unique_ptr
<repro::MultiLoader
<repro::ProcessInfoProvider
>>
354 loader
= repro::MultiLoader
<repro::ProcessInfoProvider
>::Create(
355 repro::Reproducer::Instance().GetLoader());
360 llvm::Optional
<std::string
> nextfile
= loader
->GetNextFile();
364 auto error_or_file
= llvm::MemoryBuffer::getFile(*nextfile
);
365 if (std::error_code err
= error_or_file
.getError())
368 ProcessInstanceInfoList infos
;
369 llvm::yaml::Input
yin((*error_or_file
)->getBuffer());
372 if (auto err
= yin
.error())