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/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" 17 18 #include <climits> 19 20 using namespace lldb; 21 using namespace lldb_private; 22 using namespace lldb_private::repro; 23 24 ProcessInfo::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 28 ProcessInfo::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 33 void 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 43 const char *ProcessInfo::GetName() const { 44 return m_executable.GetFilename().GetCString(); 45 } 46 47 llvm::StringRef ProcessInfo::GetNameAsStringRef() const { 48 return m_executable.GetFilename().GetStringRef(); 49 } 50 51 void ProcessInfo::Dump(Stream &s, Platform *platform) const { 52 s << "Executable: " << GetName() << "\n"; 53 s << "Triple: "; 54 m_arch.DumpTriple(s.AsRawOstream()); 55 s << "\n"; 56 57 s << "Arguments:\n"; 58 m_arguments.Dump(s); 59 60 s.Format("Environment:\n{0}", m_environment); 61 } 62 63 void 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 78 llvm::StringRef ProcessInfo::GetArg0() const { return m_arg0; } 79 80 void ProcessInfo::SetArg0(llvm::StringRef arg) { m_arg0 = std::string(arg); } 81 82 void 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 98 void 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 114 void 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 = "); 124 m_executable.Dump(s.AsRawOstream()); 125 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 = "); 142 m_arch.DumpTriple(s.AsRawOstream()); 143 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 164 void 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 " 174 " %s\n", 175 label); 176 s.PutCString( 177 "====== ====== ========== ========== ========== ========== " 178 "============================== ============================\n"); 179 } else { 180 s.Printf("PID PARENT USER TRIPLE %s\n", 181 label); 182 s.PutCString("====== ====== ========== ============================== " 183 "============================\n"); 184 } 185 } 186 187 void 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()) 194 m_arch.DumpTriple(arch_strm.AsRawOstream()); 195 196 auto print = [&](bool (ProcessInstanceInfo::*isValid)() const, 197 uint32_t (ProcessInstanceInfo::*getID)() const, 198 llvm::Optional<llvm::StringRef> (UserIDResolver::*getName)( 199 UserIDResolver::id_t id)) { 200 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); 208 else 209 s.Format(format, id); 210 }; 211 if (verbose) { 212 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); 222 223 s.Printf("%-30s ", arch_strm.GetData()); 224 } else { 225 print(&ProcessInstanceInfo::EffectiveUserIDIsValid, 226 &ProcessInstanceInfo::GetEffectiveUserID, 227 &UserIDResolver::GetUserName); 228 s.Printf("%-30s ", arch_strm.GetData()); 229 } 230 231 if (verbose || show_args) { 232 s.PutCString(m_arg0); 233 const uint32_t argc = m_arguments.GetArgumentCount(); 234 for (uint32_t i = 0; i < argc; i++) { 235 s.PutChar(' '); 236 s.PutCString(m_arguments.GetArgumentAtIndex(i)); 237 } 238 } else { 239 s.PutCString(GetName()); 240 } 241 242 s.EOL(); 243 } 244 } 245 246 bool 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 252 bool ProcessInstanceInfoMatch::NameMatches(const char *process_name) const { 253 if (m_name_match_type == NameMatch::Ignore) 254 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 262 bool ProcessInstanceInfoMatch::ProcessIDsMatch( 263 const ProcessInstanceInfo &proc_info) const { 264 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; 271 return true; 272 } 273 274 bool ProcessInstanceInfoMatch::UserIDsMatch( 275 const ProcessInstanceInfo &proc_info) const { 276 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; 291 return true; 292 } 293 bool 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 } 299 300 bool 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 331 void ProcessInstanceInfoMatch::Clear() { 332 m_match_info.Clear(); 333 m_name_match_type = NameMatch::Ignore; 334 m_match_all_users = false; 335 } 336 337 void llvm::yaml::MappingTraits<ProcessInstanceInfo>::mapping( 338 IO &io, ProcessInstanceInfo &Info) { 339 io.mapRequired("executable", Info.m_executable); 340 io.mapRequired("arg0", Info.m_arg0); 341 io.mapRequired("args", Info.m_arguments); 342 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 } 350 351 352 llvm::Optional<ProcessInstanceInfoList> 353 repro::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 } 378