blob: b5572b93d93a95874d67506333e8042581dc48d6 [file] [log] [blame] [edit]
//===-- source/Host/aix/Host.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/Host/Host.h"
#include "lldb/Host/posix/Support.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/ProcessInfo.h"
#include "lldb/Utility/Status.h"
#include "llvm/BinaryFormat/XCOFF.h"
#include <dirent.h>
#include <sys/proc.h>
#include <sys/procfs.h>
using namespace lldb;
using namespace lldb_private;
namespace {
enum class ProcessState {
Unknown,
Dead,
DiskSleep,
Idle,
Paging,
Parked,
Running,
Sleeping,
TracedOrStopped,
Zombie,
};
}
static ProcessInstanceInfo::timespec convert(pr_timestruc64_t t) {
ProcessInstanceInfo::timespec ts;
ts.tv_sec = t.tv_sec;
ts.tv_usec = t.tv_nsec / 1000; // nanos to micros
return ts;
}
static bool GetStatusInfo(::pid_t pid, ProcessInstanceInfo &processInfo,
ProcessState &State) {
struct pstatus pstatusData;
auto BufferOrError = getProcFile(pid, "status");
if (!BufferOrError)
return false;
std::unique_ptr<llvm::MemoryBuffer> StatusBuffer = std::move(*BufferOrError);
// Ensure there's enough data for psinfoData
if (StatusBuffer->getBufferSize() < sizeof(pstatusData))
return false;
std::memcpy(&pstatusData, StatusBuffer->getBufferStart(),
sizeof(pstatusData));
switch (pstatusData.pr_stat) {
case SIDL:
State = ProcessState::Idle;
break;
case SACTIVE:
State = ProcessState::Running;
break;
case SSTOP:
State = ProcessState::TracedOrStopped;
break;
case SZOMB:
State = ProcessState::Zombie;
break;
default:
State = ProcessState::Unknown;
break;
}
processInfo.SetIsZombie(State == ProcessState::Zombie);
processInfo.SetUserTime(convert(pstatusData.pr_utime));
processInfo.SetSystemTime(convert(pstatusData.pr_stime));
processInfo.SetCumulativeUserTime(convert(pstatusData.pr_cutime));
processInfo.SetCumulativeSystemTime(convert(pstatusData.pr_cstime));
return true;
}
static bool GetExePathAndIds(::pid_t pid, ProcessInstanceInfo &process_info) {
struct psinfo psinfoData;
auto BufferOrError = getProcFile(pid, "psinfo");
if (!BufferOrError)
return false;
std::unique_ptr<llvm::MemoryBuffer> PsinfoBuffer = std::move(*BufferOrError);
// Ensure there's enough data for psinfoData
if (PsinfoBuffer->getBufferSize() < sizeof(psinfoData))
return false;
std::memcpy(&psinfoData, PsinfoBuffer->getBufferStart(), sizeof(psinfoData));
llvm::StringRef PathRef(
psinfoData.pr_psargs,
strnlen(psinfoData.pr_psargs, sizeof(psinfoData.pr_psargs)));
if (PathRef.empty())
return false;
process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native);
ArchSpec arch_spec = ArchSpec();
arch_spec.SetArchitecture(eArchTypeXCOFF, llvm::XCOFF::TCPU_PPC64,
LLDB_INVALID_CPUTYPE, llvm::Triple::AIX);
process_info.SetArchitecture(arch_spec);
process_info.SetParentProcessID(psinfoData.pr_ppid);
process_info.SetGroupID(psinfoData.pr_gid);
process_info.SetEffectiveGroupID(psinfoData.pr_egid);
process_info.SetUserID(psinfoData.pr_uid);
process_info.SetEffectiveUserID(psinfoData.pr_euid);
process_info.SetProcessGroupID(psinfoData.pr_pgid);
process_info.SetProcessSessionID(psinfoData.pr_sid);
return true;
}
static bool GetProcessAndStatInfo(::pid_t pid,
ProcessInstanceInfo &process_info,
ProcessState &State) {
process_info.Clear();
process_info.SetProcessID(pid);
if (pid == LLDB_INVALID_PROCESS_ID)
return false;
// Get Executable path/Arch and Get User and Group IDs.
if (!GetExePathAndIds(pid, process_info))
return false;
// Get process status and timing info.
if (!GetStatusInfo(pid, process_info, State))
return false;
return true;
}
uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
ProcessInstanceInfoList &process_infos) {
static const char procdir[] = "/proc/";
DIR *dirproc = opendir(procdir);
if (dirproc) {
struct dirent *direntry = nullptr;
const uid_t our_uid = getuid();
const lldb::pid_t our_pid = getpid();
bool all_users = match_info.GetMatchAllUsers();
while ((direntry = readdir(dirproc)) != nullptr) {
lldb::pid_t pid;
// Skip non-numeric name directories
if (!llvm::to_integer(direntry->d_name, pid))
continue;
// Skip this process.
if (pid == our_pid)
continue;
ProcessState State;
ProcessInstanceInfo process_info;
if (!GetProcessAndStatInfo(pid, process_info, State))
continue;
if (State == ProcessState::Zombie ||
State == ProcessState::TracedOrStopped)
continue;
// Check for user match if we're not matching all users and not running
// as root.
if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid))
continue;
if (match_info.Matches(process_info))
process_infos.push_back(process_info);
}
closedir(dirproc);
}
return process_infos.size();
}
bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
ProcessState State;
return GetProcessAndStatInfo(pid, process_info, State);
}
Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
return Status("unimplemented");
}