17#include <sys/utsname.h>
20#include "llvm/ADT/StringSwitch.h"
21#include "llvm/Object/ELF.h"
22#include "llvm/Support/ScopedPrinter.h"
40enum class ProcessState {
53constexpr int task_comm_len = 16;
57 char comm[task_comm_len];
66 long unsigned cminflt;
68 long unsigned cmajflt;
90 llvm::StringRef Rest = BufferOrError.get()->getBuffer();
93 StatFields stat_fields;
94 if (sscanf(Rest.data(),
95 "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld",
96 &stat_fields.pid, stat_fields.comm, &stat_fields.state,
97 &stat_fields.ppid, &stat_fields.pgrp, &stat_fields.session,
98 &stat_fields.tty_nr, &stat_fields.tpgid, &stat_fields.flags,
99 &stat_fields.minflt, &stat_fields.cminflt, &stat_fields.majflt,
100 &stat_fields.cmajflt, &stat_fields.utime, &stat_fields.stime,
101 &stat_fields.cutime, &stat_fields.cstime) < 0) {
105 auto convert = [sc_clk_ticks = sysconf(_SC_CLK_TCK)](
auto time_in_ticks) {
107 if (sc_clk_ticks <= 0) {
110 ts.
tv_sec = time_in_ticks / sc_clk_ticks;
112 (
static_cast<double>(time_in_ticks) / sc_clk_ticks) - ts.
tv_sec;
114 std::chrono::microseconds{std::lround(1e+6 * remainder)}.count();
120 ProcessInfo.SetProcessSessionID(stat_fields.session);
121 ProcessInfo.SetUserTime(convert(stat_fields.utime));
122 ProcessInfo.SetSystemTime(convert(stat_fields.stime));
123 ProcessInfo.SetCumulativeUserTime(convert(stat_fields.cutime));
124 ProcessInfo.SetCumulativeSystemTime(convert(stat_fields.cstime));
125 switch (stat_fields.state) {
127 State = ProcessState::Running;
130 State = ProcessState::Sleeping;
133 State = ProcessState::DiskSleep;
136 State = ProcessState::Zombie;
139 State = ProcessState::Dead;
142 State = ProcessState::Parked;
145 State = ProcessState::Paging;
148 State = ProcessState::Idle;
153 State = ProcessState::TracedOrStopped;
156 State = ProcessState::Unknown;
160 if (
State == ProcessState::Unknown) {
161 LLDB_LOG(log,
"Unknown process state {0}", stat_fields.state);
168 Rest = BufferOrError.get()->getBuffer();
172 while (!Rest.empty()) {
173 llvm::StringRef Line;
174 std::tie(Line, Rest) = Rest.split(
'\n');
176 if (Line.consume_front(
"Gid:")) {
180 Line.consumeInteger(10, RGid);
182 Line.consumeInteger(10, EGid);
186 }
else if (Line.consume_front(
"Uid:")) {
190 Line.consumeInteger(10, RUid);
192 Line.consumeInteger(10, EUid);
196 }
else if (Line.consume_front(
"TracerPid:")) {
198 Line.consumeInteger(10, TracerPid);
199 }
else if (Line.consume_front(
"Tgid:")) {
201 Line.consumeInteger(10, Tgid);
208 for (; *dname; dname++) {
209 if (!isdigit(*dname))
223 llvm::object::getElfArchType(
224 {
reinterpret_cast<const char *
>(buffer_sp->GetBytes()),
225 size_t(buffer_sp->GetByteSize())})
229 case llvm::ELF::ELFCLASS32:
230 return HostInfo::GetArchitecture(HostInfo::eArchKind32);
231 case llvm::ELF::ELFCLASS64:
232 return HostInfo::GetArchitecture(HostInfo::eArchKind64);
234 LLDB_LOG(log,
"Unknown elf class ({0}) in file {1}", exe_class, exe_path);
243 std::unique_ptr<llvm::MemoryBuffer> Cmdline = std::move(*BufferOrError);
245 llvm::StringRef Arg0, Rest;
246 std::tie(Arg0, Rest) = Cmdline->getBuffer().split(
'\0');
248 while (!Rest.empty()) {
250 std::tie(Arg, Rest) = Rest.split(
'\0');
257 std::string ExePath(
PATH_MAX,
'\0');
260 llvm::SmallString<64> ProcExe;
261 (llvm::Twine(
"/proc/") + llvm::Twine(pid) +
"/exe").toVector(ProcExe);
263 ssize_t len = readlink(ProcExe.c_str(), &ExePath[0],
PATH_MAX);
267 LLDB_LOG(log,
"failed to read link exe link for {0}: {1}", pid,
273 llvm::StringRef PathRef = ExePath;
274 PathRef.consume_back(
" (deleted)");
276 if (!PathRef.empty()) {
288 std::unique_ptr<llvm::MemoryBuffer> Environ = std::move(*BufferOrError);
289 llvm::StringRef Rest = Environ->getBuffer();
290 while (!Rest.empty()) {
292 std::tie(Var, Rest) = Rest.split(
'\0');
302 process_info.
Clear();
319 static const char procdir[] =
"/proc/";
321 DIR *dirproc = opendir(procdir);
323 struct dirent *direntry =
nullptr;
324 const uid_t our_uid = getuid();
328 while ((direntry = readdir(dirproc)) !=
nullptr) {
329 if (direntry->d_type != DT_DIR || !
IsDirNumeric(direntry->d_name))
349 if (
State == ProcessState::Zombie)
354 if (!all_users && (our_uid != 0) && (process_info.
GetUserID() != our_uid))
357 if (match_info.
Matches(process_info)) {
358 process_infos.push_back(process_info);
365 return process_infos.size();
369 bool tids_changed =
false;
370 static const char procdir[] =
"/proc/";
371 static const char taskdir[] =
"/task/";
372 std::string process_task_dir = procdir + llvm::to_string(pid) + taskdir;
373 DIR *dirproc = opendir(process_task_dir.c_str());
376 struct dirent *direntry =
nullptr;
377 while ((direntry = readdir(dirproc)) !=
nullptr) {
378 if (direntry->d_type != DT_DIR || !
IsDirNumeric(direntry->d_name))
382 TidMap::iterator it = tids_to_attach.find(tid);
383 if (it == tids_to_attach.end()) {
384 tids_to_attach.insert(
TidPair(tid,
false));
403 return Status(
"unimplemented");
411 if (!
GetStatusInfo(tid, process_info, state, tracerpid, tgid) ||
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
An architecture specification class.
void AppendArgument(llvm::StringRef arg_str, char quote_char='\0')
Appends a new argument to the end of the list argument list.
std::pair< iterator, bool > insert(llvm::StringRef KeyEqValue)
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
static FileSystem & Instance()
std::shared_ptr< DataBuffer > CreateDataBuffer(const llvm::Twine &path, uint64_t size=0, uint64_t offset=0)
Create memory buffer from path.
static bool FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach)
static Status ShellExpandArguments(ProcessLaunchInfo &launch_info)
Perform expansion of the command-line for this launch info This can potentially involve wildcard expa...
static Environment GetEnvironment()
static uint32_t FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &proc_infos)
static bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info)
std::pair< lldb::pid_t, bool > TidPair
void SetGroupID(uint32_t gid)
void SetArchitecture(const ArchSpec &arch)
void SetArg0(llvm::StringRef arg)
void SetProcessID(lldb::pid_t pid)
FileSpec & GetExecutableFile()
uint32_t GetUserID() const
Environment & GetEnvironment()
void SetUserID(uint32_t uid)
bool Matches(const ProcessInstanceInfo &proc_info) const
bool GetMatchAllUsers() const
static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info)
static ArchSpec GetELFProcessCPUType(llvm::StringRef exe_path)
static bool GetProcessAndStatInfo(::pid_t pid, ProcessInstanceInfo &process_info, ProcessState &State, ::pid_t &tracerpid)
static void GetProcessArgs(::pid_t pid, ProcessInstanceInfo &process_info)
static bool IsDirNumeric(const char *dname)
static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info)
static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo, ProcessState &State, ::pid_t &TracerPid, ::pid_t &Tgid)
#define LLDB_INVALID_PROCESS_ID
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
std::optional< lldb::pid_t > getPIDForTID(lldb::pid_t tid)
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file)
std::vector< ProcessInstanceInfo > ProcessInstanceInfoList
@ eErrorTypePOSIX
POSIX error codes.