//===-- ProcessInfo.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "lldb/Utility/ProcessInfo.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/UserIDResolver.h" #include "llvm/ADT/SmallString.h" #include using namespace lldb; using namespace lldb_private; using namespace lldb_private::repro; ProcessInfo::ProcessInfo() : m_executable(), m_arguments(), m_environment(), m_uid(UINT32_MAX), m_gid(UINT32_MAX), m_arch(), m_pid(LLDB_INVALID_PROCESS_ID) {} ProcessInfo::ProcessInfo(const char *name, const ArchSpec &arch, lldb::pid_t pid) : m_executable(name), m_arguments(), m_environment(), m_uid(UINT32_MAX), m_gid(UINT32_MAX), m_arch(arch), m_pid(pid) {} void ProcessInfo::Clear() { m_executable.Clear(); m_arguments.Clear(); m_environment.clear(); m_uid = UINT32_MAX; m_gid = UINT32_MAX; m_arch.Clear(); m_pid = LLDB_INVALID_PROCESS_ID; } const char *ProcessInfo::GetName() const { return m_executable.GetFilename().GetCString(); } llvm::StringRef ProcessInfo::GetNameAsStringRef() const { return m_executable.GetFilename().GetStringRef(); } void ProcessInfo::Dump(Stream &s, Platform *platform) const { s << "Executable: " << GetName() << "\n"; s << "Triple: "; m_arch.DumpTriple(s.AsRawOstream()); s << "\n"; s << "Arguments:\n"; m_arguments.Dump(s); s.Format("Environment:\n{0}", m_environment); } void ProcessInfo::SetExecutableFile(const FileSpec &exe_file, bool add_exe_file_as_first_arg) { if (exe_file) { m_executable = exe_file; if (add_exe_file_as_first_arg) { llvm::SmallString<128> filename; exe_file.GetPath(filename); if (!filename.empty()) m_arguments.InsertArgumentAtIndex(0, filename); } } else { m_executable.Clear(); } } llvm::StringRef ProcessInfo::GetArg0() const { return m_arg0; } void ProcessInfo::SetArg0(llvm::StringRef arg) { m_arg0 = std::string(arg); } void ProcessInfo::SetArguments(char const **argv, bool first_arg_is_executable) { m_arguments.SetArguments(argv); // Is the first argument the executable? if (first_arg_is_executable) { const char *first_arg = m_arguments.GetArgumentAtIndex(0); if (first_arg) { // Yes the first argument is an executable, set it as the executable in // the launch options. Don't resolve the file path as the path could be a // remote platform path m_executable.SetFile(first_arg, FileSpec::Style::native); } } } void ProcessInfo::SetArguments(const Args &args, bool first_arg_is_executable) { // Copy all arguments m_arguments = args; // Is the first argument the executable? if (first_arg_is_executable) { const char *first_arg = m_arguments.GetArgumentAtIndex(0); if (first_arg) { // Yes the first argument is an executable, set it as the executable in // the launch options. Don't resolve the file path as the path could be a // remote platform path m_executable.SetFile(first_arg, FileSpec::Style::native); } } } void ProcessInstanceInfo::Dump(Stream &s, UserIDResolver &resolver) const { if (m_pid != LLDB_INVALID_PROCESS_ID) s.Printf(" pid = %" PRIu64 "\n", m_pid); if (m_parent_pid != LLDB_INVALID_PROCESS_ID) s.Printf(" parent = %" PRIu64 "\n", m_parent_pid); if (m_executable) { s.Printf(" name = %s\n", m_executable.GetFilename().GetCString()); s.PutCString(" file = "); m_executable.Dump(s.AsRawOstream()); s.EOL(); } const uint32_t argc = m_arguments.GetArgumentCount(); if (argc > 0) { for (uint32_t i = 0; i < argc; i++) { const char *arg = m_arguments.GetArgumentAtIndex(i); if (i < 10) s.Printf(" arg[%u] = %s\n", i, arg); else s.Printf("arg[%u] = %s\n", i, arg); } } s.Format("{0}", m_environment); if (m_arch.IsValid()) { s.Printf(" arch = "); m_arch.DumpTriple(s.AsRawOstream()); s.EOL(); } if (UserIDIsValid()) { s.Format(" uid = {0,-5} ({1})\n", GetUserID(), resolver.GetUserName(GetUserID()).getValueOr("")); } if (GroupIDIsValid()) { s.Format(" gid = {0,-5} ({1})\n", GetGroupID(), resolver.GetGroupName(GetGroupID()).getValueOr("")); } if (EffectiveUserIDIsValid()) { s.Format(" euid = {0,-5} ({1})\n", GetEffectiveUserID(), resolver.GetUserName(GetEffectiveUserID()).getValueOr("")); } if (EffectiveGroupIDIsValid()) { s.Format(" egid = {0,-5} ({1})\n", GetEffectiveGroupID(), resolver.GetGroupName(GetEffectiveGroupID()).getValueOr("")); } } void ProcessInstanceInfo::DumpTableHeader(Stream &s, bool show_args, bool verbose) { const char *label; if (show_args || verbose) label = "ARGUMENTS"; else label = "NAME"; if (verbose) { s.Printf("PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE " " %s\n", label); s.PutCString( "====== ====== ========== ========== ========== ========== " "============================== ============================\n"); } else { s.Printf("PID PARENT USER TRIPLE %s\n", label); s.PutCString("====== ====== ========== ============================== " "============================\n"); } } void ProcessInstanceInfo::DumpAsTableRow(Stream &s, UserIDResolver &resolver, bool show_args, bool verbose) const { if (m_pid != LLDB_INVALID_PROCESS_ID) { s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, m_parent_pid); StreamString arch_strm; if (m_arch.IsValid()) m_arch.DumpTriple(arch_strm.AsRawOstream()); auto print = [&](bool (ProcessInstanceInfo::*isValid)() const, uint32_t (ProcessInstanceInfo::*getID)() const, llvm::Optional (UserIDResolver::*getName)( UserIDResolver::id_t id)) { const char *format = "{0,-10} "; if (!(this->*isValid)()) { s.Format(format, ""); return; } uint32_t id = (this->*getID)(); if (auto name = (resolver.*getName)(id)) s.Format(format, *name); else s.Format(format, id); }; if (verbose) { print(&ProcessInstanceInfo::UserIDIsValid, &ProcessInstanceInfo::GetUserID, &UserIDResolver::GetUserName); print(&ProcessInstanceInfo::GroupIDIsValid, &ProcessInstanceInfo::GetGroupID, &UserIDResolver::GetGroupName); print(&ProcessInstanceInfo::EffectiveUserIDIsValid, &ProcessInstanceInfo::GetEffectiveUserID, &UserIDResolver::GetUserName); print(&ProcessInstanceInfo::EffectiveGroupIDIsValid, &ProcessInstanceInfo::GetEffectiveGroupID, &UserIDResolver::GetGroupName); s.Printf("%-30s ", arch_strm.GetData()); } else { print(&ProcessInstanceInfo::EffectiveUserIDIsValid, &ProcessInstanceInfo::GetEffectiveUserID, &UserIDResolver::GetUserName); s.Printf("%-30s ", arch_strm.GetData()); } if (verbose || show_args) { s.PutCString(m_arg0); const uint32_t argc = m_arguments.GetArgumentCount(); for (uint32_t i = 0; i < argc; i++) { s.PutChar(' '); s.PutCString(m_arguments.GetArgumentAtIndex(i)); } } else { s.PutCString(GetName()); } s.EOL(); } } bool ProcessInstanceInfoMatch::ArchitectureMatches( const ArchSpec &arch_spec) const { return !m_match_info.GetArchitecture().IsValid() || m_match_info.GetArchitecture().IsCompatibleMatch(arch_spec); } bool ProcessInstanceInfoMatch::NameMatches(const char *process_name) const { if (m_name_match_type == NameMatch::Ignore) return true; const char *match_name = m_match_info.GetName(); if (!match_name) return true; return lldb_private::NameMatches(process_name, m_name_match_type, match_name); } bool ProcessInstanceInfoMatch::ProcessIDsMatch( const ProcessInstanceInfo &proc_info) const { if (m_match_info.ProcessIDIsValid() && m_match_info.GetProcessID() != proc_info.GetProcessID()) return false; if (m_match_info.ParentProcessIDIsValid() && m_match_info.GetParentProcessID() != proc_info.GetParentProcessID()) return false; return true; } bool ProcessInstanceInfoMatch::UserIDsMatch( const ProcessInstanceInfo &proc_info) const { if (m_match_info.UserIDIsValid() && m_match_info.GetUserID() != proc_info.GetUserID()) return false; if (m_match_info.GroupIDIsValid() && m_match_info.GetGroupID() != proc_info.GetGroupID()) return false; if (m_match_info.EffectiveUserIDIsValid() && m_match_info.GetEffectiveUserID() != proc_info.GetEffectiveUserID()) return false; if (m_match_info.EffectiveGroupIDIsValid() && m_match_info.GetEffectiveGroupID() != proc_info.GetEffectiveGroupID()) return false; return true; } bool ProcessInstanceInfoMatch::Matches( const ProcessInstanceInfo &proc_info) const { return ArchitectureMatches(proc_info.GetArchitecture()) && ProcessIDsMatch(proc_info) && UserIDsMatch(proc_info) && NameMatches(proc_info.GetName()); } bool ProcessInstanceInfoMatch::MatchAllProcesses() const { if (m_name_match_type != NameMatch::Ignore) return false; if (m_match_info.ProcessIDIsValid()) return false; if (m_match_info.ParentProcessIDIsValid()) return false; if (m_match_info.UserIDIsValid()) return false; if (m_match_info.GroupIDIsValid()) return false; if (m_match_info.EffectiveUserIDIsValid()) return false; if (m_match_info.EffectiveGroupIDIsValid()) return false; if (m_match_info.GetArchitecture().IsValid()) return false; if (m_match_all_users) return false; return true; } void ProcessInstanceInfoMatch::Clear() { m_match_info.Clear(); m_name_match_type = NameMatch::Ignore; m_match_all_users = false; } void llvm::yaml::MappingTraits::mapping( IO &io, ProcessInstanceInfo &Info) { io.mapRequired("executable", Info.m_executable); io.mapRequired("arg0", Info.m_arg0); io.mapRequired("args", Info.m_arguments); io.mapRequired("arch", Info.m_arch); io.mapRequired("uid", Info.m_uid); io.mapRequired("gid", Info.m_gid); io.mapRequired("pid", Info.m_pid); io.mapRequired("effective-uid", Info.m_euid); io.mapRequired("effective-gid", Info.m_egid); io.mapRequired("parent-pid", Info.m_parent_pid); } llvm::Optional repro::GetReplayProcessInstanceInfoList() { static std::unique_ptr> loader = repro::MultiLoader::Create( repro::Reproducer::Instance().GetLoader()); if (!loader) return {}; llvm::Optional nextfile = loader->GetNextFile(); if (!nextfile) return {}; auto error_or_file = llvm::MemoryBuffer::getFile(*nextfile); if (std::error_code err = error_or_file.getError()) return {}; ProcessInstanceInfoList infos; llvm::yaml::Input yin((*error_or_file)->getBuffer()); yin >> infos; if (auto err = yin.error()) return {}; return infos; }