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 21 using namespace lldb; 22 using namespace lldb_private; 23 24 ProcessInfo::ProcessInfo() 25 : m_executable(), m_arguments(), m_environment(), m_arch(), m_listener_sp(), 26 m_hijack_listener_sp(), m_shadow_listener_sp() {} 27 28 ProcessInfo::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 34 void 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 45 const char *ProcessInfo::GetName() const { 46 return m_executable.GetFilename().GetCString(); 47 } 48 49 llvm::StringRef ProcessInfo::GetNameAsStringRef() const { 50 return m_executable.GetFilename().GetStringRef(); 51 } 52 53 void ProcessInfo::Dump(Stream &s, Platform *platform) const { 54 s << "Executable: " << GetName() << "\n"; 55 s << "Triple: "; 56 m_arch.DumpTriple(s.AsRawOstream()); 57 s << "\n"; 58 59 s << "Arguments:\n"; 60 m_arguments.Dump(s); 61 62 s.Format("Environment:\n{0}", m_environment); 63 } 64 65 void 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(filename); 72 if (!filename.empty()) 73 m_arguments.InsertArgumentAtIndex(0, filename); 74 } 75 } else { 76 m_executable.Clear(); 77 } 78 } 79 80 llvm::StringRef ProcessInfo::GetArg0() const { return m_arg0; } 81 82 void ProcessInfo::SetArg0(llvm::StringRef arg) { m_arg0 = std::string(arg); } 83 84 void 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(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(first_arg, FileSpec::Style::native); 96 } 97 } 98 } 99 100 void 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(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(first_arg, FileSpec::Style::native); 112 } 113 } 114 } 115 116 bool ProcessInfo::IsScriptedProcess() const { 117 return m_scripted_metadata_sp && *m_scripted_metadata_sp; 118 } 119 120 void ProcessInstanceInfo::Dump(Stream &s, UserIDResolver &resolver) const { 121 if (m_pid != LLDB_INVALID_PROCESS_ID) 122 s.Printf(" pid = %" PRIu64 "\n", m_pid); 123 124 if (m_parent_pid != LLDB_INVALID_PROCESS_ID) 125 s.Printf(" parent = %" PRIu64 "\n", m_parent_pid); 126 127 if (m_executable) { 128 s.Printf(" name = %s\n", m_executable.GetFilename().GetCString()); 129 s.PutCString(" file = "); 130 m_executable.Dump(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(i); 137 if (i < 10) 138 s.Printf(" arg[%u] = %s\n", i, arg); 139 else 140 s.Printf("arg[%u] = %s\n", i, arg); 141 } 142 } 143 144 s.Format("{0}", m_environment); 145 146 if (m_arch.IsValid()) { 147 s.Printf(" arch = "); 148 m_arch.DumpTriple(s.AsRawOstream()); 149 s.EOL(); 150 } 151 152 if (UserIDIsValid()) { 153 s.Format(" uid = {0,-5} ({1})\n", GetUserID(), 154 resolver.GetUserName(GetUserID()).value_or("")); 155 } 156 if (GroupIDIsValid()) { 157 s.Format(" gid = {0,-5} ({1})\n", GetGroupID(), 158 resolver.GetGroupName(GetGroupID()).value_or("")); 159 } 160 if (EffectiveUserIDIsValid()) { 161 s.Format(" euid = {0,-5} ({1})\n", GetEffectiveUserID(), 162 resolver.GetUserName(GetEffectiveUserID()).value_or("")); 163 } 164 if (EffectiveGroupIDIsValid()) { 165 s.Format(" egid = {0,-5} ({1})\n", GetEffectiveGroupID(), 166 resolver.GetGroupName(GetEffectiveGroupID()).value_or("")); 167 } 168 } 169 170 void 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("PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE " 180 " %s\n", 181 label); 182 s.PutCString( 183 "====== ====== ========== ========== ========== ========== " 184 "============================== ============================\n"); 185 } else { 186 s.Printf("PID PARENT USER TRIPLE %s\n", 187 label); 188 s.PutCString("====== ====== ========== ============================== " 189 "============================\n"); 190 } 191 } 192 193 void ProcessInstanceInfo::DumpAsTableRow(Stream &s, UserIDResolver &resolver, 194 bool show_args, bool verbose) const { 195 if (m_pid != LLDB_INVALID_PROCESS_ID) { 196 s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, m_parent_pid); 197 198 StreamString arch_strm; 199 if (m_arch.IsValid()) 200 m_arch.DumpTriple(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, ""); 209 return; 210 } 211 uint32_t id = (this->*getID)(); 212 if (auto name = (resolver.*getName)(id)) 213 s.Format(format, *name); 214 else 215 s.Format(format, 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("%-30s ", arch_strm.GetData()); 230 } else { 231 print(&ProcessInstanceInfo::EffectiveUserIDIsValid, 232 &ProcessInstanceInfo::GetEffectiveUserID, 233 &UserIDResolver::GetUserName); 234 s.Printf("%-30s ", arch_strm.GetData()); 235 } 236 237 if (verbose || show_args) { 238 s.PutCString(m_arg0); 239 const uint32_t argc = m_arguments.GetArgumentCount(); 240 for (uint32_t i = 0; i < argc; i++) { 241 s.PutChar(' '); 242 s.PutCString(m_arguments.GetArgumentAtIndex(i)); 243 } 244 } else { 245 s.PutCString(GetName()); 246 } 247 248 s.EOL(); 249 } 250 } 251 252 bool ProcessInstanceInfoMatch::ArchitectureMatches( 253 const ArchSpec &arch_spec) const { 254 return !m_match_info.GetArchitecture().IsValid() || 255 m_match_info.GetArchitecture().IsCompatibleMatch(arch_spec); 256 } 257 258 bool 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(process_name, m_name_match_type, match_name); 266 } 267 268 bool 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 280 bool 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 } 299 bool ProcessInstanceInfoMatch::Matches( 300 const ProcessInstanceInfo &proc_info) const { 301 return ArchitectureMatches(proc_info.GetArchitecture()) && 302 ProcessIDsMatch(proc_info) && UserIDsMatch(proc_info) && 303 NameMatches(proc_info.GetName()); 304 } 305 306 bool 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 337 void ProcessInstanceInfoMatch::Clear() { 338 m_match_info.Clear(); 339 m_name_match_type = NameMatch::Ignore; 340 m_match_all_users = false; 341 } 342