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 {
65 long unsigned cminflt;
67 long unsigned cmajflt;
76 long realtime_priority;
95 llvm::StringRef Rest = BufferOrError.get()->getBuffer();
98 StatFields stat_fields;
101 "%d %*s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld",
102 &stat_fields.pid, &stat_fields.state,
103 &stat_fields.ppid, &stat_fields.pgrp, &stat_fields.session,
104 &stat_fields.tty_nr, &stat_fields.tpgid, &stat_fields.flags,
105 &stat_fields.minflt, &stat_fields.cminflt, &stat_fields.majflt,
106 &stat_fields.cmajflt, &stat_fields.utime, &stat_fields.stime,
107 &stat_fields.cutime, &stat_fields.cstime,
108 &stat_fields.realtime_priority, &stat_fields.priority) < 0) {
112 auto convert = [sc_clk_ticks = sysconf(_SC_CLK_TCK)](
auto time_in_ticks) {
114 if (sc_clk_ticks <= 0) {
117 ts.
tv_sec = time_in_ticks / sc_clk_ticks;
119 (
static_cast<double>(time_in_ticks) / sc_clk_ticks) - ts.
tv_sec;
121 std::chrono::microseconds{std::lround(1e+6 * remainder)}.count();
127 auto priority_value =
static_cast<int8_t
>(
128 (stat_fields.priority < 0 ? 0x80 : 0x00) | (stat_fields.priority & 0x7f));
132 ProcessInfo.SetProcessSessionID(stat_fields.session);
133 ProcessInfo.SetUserTime(convert(stat_fields.utime));
134 ProcessInfo.SetSystemTime(convert(stat_fields.stime));
135 ProcessInfo.SetCumulativeUserTime(convert(stat_fields.cutime));
136 ProcessInfo.SetCumulativeSystemTime(convert(stat_fields.cstime));
138 switch (stat_fields.state) {
140 State = ProcessState::Running;
143 State = ProcessState::Sleeping;
146 State = ProcessState::DiskSleep;
149 State = ProcessState::Zombie;
152 State = ProcessState::Dead;
155 State = ProcessState::Parked;
158 State = ProcessState::Paging;
161 State = ProcessState::Idle;
166 State = ProcessState::TracedOrStopped;
169 State = ProcessState::Unknown;
174 if (
State == ProcessState::Unknown) {
175 LLDB_LOG(log,
"Unknown process state {0}", stat_fields.state);
182 Rest = BufferOrError.get()->getBuffer();
186 while (!Rest.empty()) {
187 llvm::StringRef Line;
188 std::tie(Line, Rest) = Rest.split(
'\n');
190 if (Line.consume_front(
"Gid:")) {
194 Line.consumeInteger(10, RGid);
196 Line.consumeInteger(10, EGid);
200 }
else if (Line.consume_front(
"Uid:")) {
204 Line.consumeInteger(10, RUid);
206 Line.consumeInteger(10, EUid);
210 }
else if (Line.consume_front(
"TracerPid:")) {
212 Line.consumeInteger(10, TracerPid);
213 }
else if (Line.consume_front(
"Tgid:")) {
215 Line.consumeInteger(10, Tgid);
222 for (; *dname; dname++) {
223 if (!isdigit(*dname))
237 llvm::object::getElfArchType(
238 {
reinterpret_cast<const char *
>(buffer_sp->GetBytes()),
239 size_t(buffer_sp->GetByteSize())})
243 case llvm::ELF::ELFCLASS32:
244 return HostInfo::GetArchitecture(HostInfo::eArchKind32);
245 case llvm::ELF::ELFCLASS64:
246 return HostInfo::GetArchitecture(HostInfo::eArchKind64);
248 LLDB_LOG(log,
"Unknown elf class ({0}) in file {1}", exe_class, exe_path);
257 std::unique_ptr<llvm::MemoryBuffer> Cmdline = std::move(*BufferOrError);
259 llvm::StringRef Arg0, Rest;
260 std::tie(Arg0, Rest) = Cmdline->getBuffer().split(
'\0');
262 while (!Rest.empty()) {
264 std::tie(Arg, Rest) = Rest.split(
'\0');
271 std::string ExePath(
PATH_MAX,
'\0');
274 llvm::SmallString<64> ProcExe;
275 (llvm::Twine(
"/proc/") + llvm::Twine(pid) +
"/exe").toVector(ProcExe);
277 ssize_t len = readlink(ProcExe.c_str(), &ExePath[0],
PATH_MAX);
281 LLDB_LOG(log,
"failed to read link exe link for {0}: {1}", pid,
287 llvm::StringRef PathRef = ExePath;
288 PathRef.consume_back(
" (deleted)");
290 if (!PathRef.empty()) {
302 std::unique_ptr<llvm::MemoryBuffer> Environ = std::move(*BufferOrError);
303 llvm::StringRef Rest = Environ->getBuffer();
304 while (!Rest.empty()) {
306 std::tie(Var, Rest) = Rest.split(
'\0');
316 process_info.
Clear();
333 static const char procdir[] =
"/proc/";
335 DIR *dirproc = opendir(procdir);
337 struct dirent *direntry =
nullptr;
338 const uid_t our_uid = getuid();
342 while ((direntry = readdir(dirproc)) !=
nullptr) {
343 if (direntry->d_type != DT_DIR || !
IsDirNumeric(direntry->d_name))
363 if (
State == ProcessState::Zombie)
368 if (!all_users && (our_uid != 0) && (process_info.
GetUserID() != our_uid))
371 if (match_info.
Matches(process_info)) {
372 process_infos.push_back(process_info);
379 return process_infos.size();
383 bool tids_changed =
false;
384 static const char procdir[] =
"/proc/";
385 static const char taskdir[] =
"/task/";
386 std::string process_task_dir = procdir + llvm::to_string(pid) + taskdir;
387 DIR *dirproc = opendir(process_task_dir.c_str());
390 struct dirent *direntry =
nullptr;
391 while ((direntry = readdir(dirproc)) !=
nullptr) {
392 if (direntry->d_type != DT_DIR || !
IsDirNumeric(direntry->d_name))
396 TidMap::iterator it = tids_to_attach.find(tid);
397 if (it == tids_to_attach.end()) {
398 tids_to_attach.insert(
TidPair(tid,
false));
425 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 Status FromErrorString(const char *str)
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.