This PR is in reference to porting LLDB on AIX. Link to discussions on llvm discourse and github: 1. https://discourse.llvm.org/t/port-lldb-to-ibm-aix/80640 2. https://github.com/llvm/llvm-project/issues/101657 The complete changes for porting are present in this draft PR: https://github.com/llvm/llvm-project/pull/102601 - Added testcase for `GetProgramFileSpec()` & `FindProcesses()` - Added changes to get the host information for AIX (info like FindProcessesImpl() GetProgramFileSpec()), continue from the PR https://github.com/llvm/llvm-project/pull/134354
185 lines
5.6 KiB
C++
185 lines
5.6 KiB
C++
//===-- 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");
|
|
}
|