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/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 using namespace lldb_private::repro; 22 23 ProcessInfo::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 27 ProcessInfo::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 32 void 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 42 const char *ProcessInfo::GetName() const { 43 return m_executable.GetFilename().GetCString(); 44 } 45 46 llvm::StringRef ProcessInfo::GetNameAsStringRef() const { 47 return m_executable.GetFilename().GetStringRef(); 48 } 49 50 void ProcessInfo::Dump(Stream &s, Platform *platform) const { 51 s << "Executable: " << GetName() << "\n"; 52 s << "Triple: "; 53 m_arch.DumpTriple(s.AsRawOstream()); 54 s << "\n"; 55 56 s << "Arguments:\n"; 57 m_arguments.Dump(s); 58 59 s.Format("Environment:\n{0}", m_environment); 60 } 61 62 void 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 77 llvm::StringRef ProcessInfo::GetArg0() const { return m_arg0; } 78 79 void ProcessInfo::SetArg0(llvm::StringRef arg) { m_arg0 = std::string(arg); } 80 81 void 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 97 void 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 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); 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 = "); 123 m_executable.Dump(s.AsRawOstream()); 124 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 = "); 141 m_arch.DumpTriple(s.AsRawOstream()); 142 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 163 void 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 " 173 " %s\n", 174 label); 175 s.PutCString( 176 "====== ====== ========== ========== ========== ========== " 177 "============================== ============================\n"); 178 } else { 179 s.Printf("PID PARENT USER TRIPLE %s\n", 180 label); 181 s.PutCString("====== ====== ========== ============================== " 182 "============================\n"); 183 } 184 } 185 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); 190 191 StreamString arch_strm; 192 if (m_arch.IsValid()) 193 m_arch.DumpTriple(arch_strm.AsRawOstream()); 194 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, ""); 202 return; 203 } 204 uint32_t id = (this->*getID)(); 205 if (auto name = (resolver.*getName)(id)) 206 s.Format(format, *name); 207 else 208 s.Format(format, id); 209 }; 210 if (verbose) { 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); 221 222 s.Printf("%-30s ", arch_strm.GetData()); 223 } else { 224 print(&ProcessInstanceInfo::EffectiveUserIDIsValid, 225 &ProcessInstanceInfo::GetEffectiveUserID, 226 &UserIDResolver::GetUserName); 227 s.Printf("%-30s ", arch_strm.GetData()); 228 } 229 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++) { 234 s.PutChar(' '); 235 s.PutCString(m_arguments.GetArgumentAtIndex(i)); 236 } 237 } else { 238 s.PutCString(GetName()); 239 } 240 241 s.EOL(); 242 } 243 } 244 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); 249 } 250 251 bool ProcessInstanceInfoMatch::NameMatches(const char *process_name) const { 252 if (m_name_match_type == NameMatch::Ignore) 253 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 261 bool ProcessInstanceInfoMatch::ProcessIDsMatch( 262 const ProcessInstanceInfo &proc_info) const { 263 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; 270 return true; 271 } 272 273 bool ProcessInstanceInfoMatch::UserIDsMatch( 274 const ProcessInstanceInfo &proc_info) const { 275 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; 290 return true; 291 } 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()); 297 } 298 299 bool 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 330 void ProcessInstanceInfoMatch::Clear() { 331 m_match_info.Clear(); 332 m_name_match_type = NameMatch::Ignore; 333 m_match_all_users = false; 334 } 335 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); 348 } 349 350 llvm::Expected<std::unique_ptr<ProcessInfoRecorder>> 351 ProcessInfoRecorder::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 360 void 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 376 void ProcessInfoProvider::Discard() { m_process_info_recorders.clear(); } 377 378 ProcessInfoRecorder *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 394 void 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 402 llvm::Optional<ProcessInstanceInfoList> 403 repro::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 429 char ProcessInfoProvider::ID = 0; 430 const char *ProcessInfoProvider::Info::file = "process-info.yaml"; 431 const char *ProcessInfoProvider::Info::name = "process-info"; 432