1 //===-- ProcessInfo.cpp -----------------------------------------*- C++ -*-===// 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 19 using namespace lldb; 20 using namespace lldb_private; 21 22 ProcessInfo::ProcessInfo() 23 : m_executable(), m_arguments(), m_environment(), m_uid(UINT32_MAX), 24 m_gid(UINT32_MAX), m_arch(), m_pid(LLDB_INVALID_PROCESS_ID) {} 25 26 ProcessInfo::ProcessInfo(const char *name, const ArchSpec &arch, 27 lldb::pid_t pid) 28 : m_executable(name), m_arguments(), m_environment(), m_uid(UINT32_MAX), 29 m_gid(UINT32_MAX), m_arch(arch), m_pid(pid) {} 30 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 41 const char *ProcessInfo::GetName() const { 42 return m_executable.GetFilename().GetCString(); 43 } 44 45 llvm::StringRef ProcessInfo::GetNameAsStringRef() const { 46 return m_executable.GetFilename().GetStringRef(); 47 } 48 49 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 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 76 llvm::StringRef ProcessInfo::GetArg0() const { return m_arg0; } 77 78 void ProcessInfo::SetArg0(llvm::StringRef arg) { m_arg0 = arg; } 79 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 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 112 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()).getValueOr("")); 147 } 148 if (GroupIDIsValid()) { 149 s.Format(" gid = {0,-5} ({1})\n", GetGroupID(), 150 resolver.GetGroupName(GetGroupID()).getValueOr("")); 151 } 152 if (EffectiveUserIDIsValid()) { 153 s.Format(" euid = {0,-5} ({1})\n", GetEffectiveUserID(), 154 resolver.GetUserName(GetEffectiveUserID()).getValueOr("")); 155 } 156 if (EffectiveGroupIDIsValid()) { 157 s.Format(" egid = {0,-5} ({1})\n", GetEffectiveGroupID(), 158 resolver.GetGroupName(GetEffectiveGroupID()).getValueOr("")); 159 } 160 } 161 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 185 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 llvm::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 244 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 250 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 260 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 272 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 } 291 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 298 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 329 void ProcessInstanceInfoMatch::Clear() { 330 m_match_info.Clear(); 331 m_name_match_type = NameMatch::Ignore; 332 m_match_all_users = false; 333 } 334