17#include <sys/utsname.h>
20#include "llvm/ADT/StringSwitch.h"
21#include "llvm/Object/ELF.h"
22#include "llvm/Support/ScopedPrinter.h"
41enum class ProcessState {
54constexpr int task_comm_len = 16;
58 char comm[task_comm_len];
67 long unsigned cminflt;
69 long unsigned cmajflt;
78 long realtime_priority;
97 llvm::StringRef Rest = BufferOrError.get()->getBuffer();
100 StatFields stat_fields;
103 "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld",
104 &stat_fields.pid, stat_fields.comm, &stat_fields.state,
105 &stat_fields.ppid, &stat_fields.pgrp, &stat_fields.session,
106 &stat_fields.tty_nr, &stat_fields.tpgid, &stat_fields.flags,
107 &stat_fields.minflt, &stat_fields.cminflt, &stat_fields.majflt,
108 &stat_fields.cmajflt, &stat_fields.utime, &stat_fields.stime,
109 &stat_fields.cutime, &stat_fields.cstime,
110 &stat_fields.realtime_priority, &stat_fields.priority) < 0) {
114 auto convert = [sc_clk_ticks = sysconf(_SC_CLK_TCK)](
auto time_in_ticks) {
116 if (sc_clk_ticks <= 0) {
119 ts.
tv_sec = time_in_ticks / sc_clk_ticks;
121 (
static_cast<double>(time_in_ticks) / sc_clk_ticks) - ts.
tv_sec;
123 std::chrono::microseconds{std::lround(1e+6 * remainder)}.count();
129 auto priority_value =
static_cast<int8_t
>(
130 (stat_fields.priority < 0 ? 0x80 : 0x00) | (stat_fields.priority & 0x7f));
134 ProcessInfo.SetProcessSessionID(stat_fields.session);
135 ProcessInfo.SetUserTime(convert(stat_fields.utime));
136 ProcessInfo.SetSystemTime(convert(stat_fields.stime));
137 ProcessInfo.SetCumulativeUserTime(convert(stat_fields.cutime));
138 ProcessInfo.SetCumulativeSystemTime(convert(stat_fields.cstime));
140 switch (stat_fields.state) {
142 State = ProcessState::Running;
145 State = ProcessState::Sleeping;
148 State = ProcessState::DiskSleep;
151 State = ProcessState::Zombie;
154 State = ProcessState::Dead;
157 State = ProcessState::Parked;
160 State = ProcessState::Paging;
163 State = ProcessState::Idle;
168 State = ProcessState::TracedOrStopped;
171 State = ProcessState::Unknown;
176 if (
State == ProcessState::Unknown) {
177 LLDB_LOG(log,
"Unknown process state {0}", stat_fields.state);
184 Rest = BufferOrError.get()->getBuffer();
188 while (!Rest.empty()) {
189 llvm::StringRef Line;
190 std::tie(Line, Rest) = Rest.split(
'\n');
192 if (Line.consume_front(
"Gid:")) {
196 Line.consumeInteger(10, RGid);
198 Line.consumeInteger(10, EGid);
202 }
else if (Line.consume_front(
"Uid:")) {
206 Line.consumeInteger(10, RUid);
208 Line.consumeInteger(10, EUid);
212 }
else if (Line.consume_front(
"TracerPid:")) {
214 Line.consumeInteger(10, TracerPid);
215 }
else if (Line.consume_front(
"Tgid:")) {
217 Line.consumeInteger(10, Tgid);
224 for (; *dname; dname++) {
225 if (!isdigit(*dname))
239 llvm::object::getElfArchType(
240 {
reinterpret_cast<const char *
>(buffer_sp->GetBytes()),
241 size_t(buffer_sp->GetByteSize())})
245 case llvm::ELF::ELFCLASS32:
246 return HostInfo::GetArchitecture(HostInfo::eArchKind32);
247 case llvm::ELF::ELFCLASS64:
248 return HostInfo::GetArchitecture(HostInfo::eArchKind64);
250 LLDB_LOG(log,
"Unknown elf class ({0}) in file {1}", exe_class, exe_path);
259 std::unique_ptr<llvm::MemoryBuffer> Cmdline = std::move(*BufferOrError);
261 llvm::StringRef Arg0, Rest;
262 std::tie(Arg0, Rest) = Cmdline->getBuffer().split(
'\0');
264 while (!Rest.empty()) {
266 std::tie(Arg, Rest) = Rest.split(
'\0');
273 std::string ExePath(
PATH_MAX,
'\0');
276 llvm::SmallString<64> ProcExe;
277 (llvm::Twine(
"/proc/") + llvm::Twine(pid) +
"/exe").toVector(ProcExe);
279 ssize_t len = readlink(ProcExe.c_str(), &ExePath[0],
PATH_MAX);
283 LLDB_LOG(log,
"failed to read link exe link for {0}: {1}", pid,
289 llvm::StringRef PathRef = ExePath;
290 PathRef.consume_back(
" (deleted)");
292 if (!PathRef.empty()) {
304 std::unique_ptr<llvm::MemoryBuffer> Environ = std::move(*BufferOrError);
305 llvm::StringRef Rest = Environ->getBuffer();
306 while (!Rest.empty()) {
308 std::tie(Var, Rest) = Rest.split(
'\0');
318 process_info.
Clear();
335 static const char procdir[] =
"/proc/";
337 DIR *dirproc = opendir(procdir);
339 struct dirent *direntry =
nullptr;
340 const uid_t our_uid = getuid();
344 while ((direntry = readdir(dirproc)) !=
nullptr) {
345 if (direntry->d_type != DT_DIR || !
IsDirNumeric(direntry->d_name))
365 if (
State == ProcessState::Zombie)
370 if (!all_users && (our_uid != 0) && (process_info.
GetUserID() != our_uid))
373 if (match_info.
Matches(process_info)) {
374 process_infos.push_back(process_info);
381 return process_infos.size();
385 bool tids_changed =
false;
386 static const char procdir[] =
"/proc/";
387 static const char taskdir[] =
"/task/";
388 std::string process_task_dir = procdir + llvm::to_string(pid) + taskdir;
389 DIR *dirproc = opendir(process_task_dir.c_str());
392 struct dirent *direntry =
nullptr;
393 while ((direntry = readdir(dirproc)) !=
nullptr) {
394 if (direntry->d_type != DT_DIR || !
IsDirNumeric(direntry->d_name))
398 TidMap::iterator it = tids_to_attach.find(tid);
399 if (it == tids_to_attach.end()) {
400 tids_to_attach.insert(
TidPair(tid,
false));
419 return Status(
"unimplemented");
427 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.