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;
87 ProcessState &State,
::pid_t &TracerPid,
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);
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;
172 ProcessInfo.SetIsZombie(State == ProcessState::Zombie);
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);
216 }
else if (Line.consume_front(
"CoreDumping:")) {
217 uint32_t coredumping;
219 if (!Line.consumeInteger(2, coredumping))
227 for (; *dname; dname++) {
228 if (!isdigit(*dname))
242 llvm::object::getElfArchType(
243 {
reinterpret_cast<const char *
>(buffer_sp->GetBytes()),
244 size_t(buffer_sp->GetByteSize())})
248 case llvm::ELF::ELFCLASS32:
249 return HostInfo::GetArchitecture(HostInfo::eArchKind32);
250 case llvm::ELF::ELFCLASS64:
251 return HostInfo::GetArchitecture(HostInfo::eArchKind64);
253 LLDB_LOG(log,
"Unknown elf class ({0}) in file {1}", exe_class, exe_path);
262 std::unique_ptr<llvm::MemoryBuffer> Cmdline = std::move(*BufferOrError);
264 llvm::StringRef Arg0, Rest;
265 std::tie(Arg0, Rest) = Cmdline->getBuffer().split(
'\0');
267 while (!Rest.empty()) {
269 std::tie(Arg, Rest) = Rest.split(
'\0');
276 std::string ExePath(
PATH_MAX,
'\0');
279 llvm::SmallString<64> ProcExe;
280 (llvm::Twine(
"/proc/") + llvm::Twine(pid) +
"/exe").toVector(ProcExe);
282 ssize_t len = readlink(ProcExe.c_str(), &ExePath[0],
PATH_MAX);
286 LLDB_LOG(log,
"failed to read link exe link for {0}: {1}", pid,
292 llvm::StringRef PathRef = ExePath;
293 PathRef.consume_back(
" (deleted)");
295 if (!PathRef.empty()) {
307 std::unique_ptr<llvm::MemoryBuffer> Environ = std::move(*BufferOrError);
308 llvm::StringRef Rest = Environ->getBuffer();
309 while (!Rest.empty()) {
311 std::tie(Var, Rest) = Rest.split(
'\0');
318 ProcessState &State,
::pid_t &tracerpid) {
321 process_info.
Clear();
330 if (!
GetStatusInfo(pid, process_info, State, tracerpid, tgid))
338 static const char procdir[] =
"/proc/";
340 DIR *dirproc = opendir(procdir);
342 struct dirent *direntry =
nullptr;
343 const uid_t our_uid = getuid();
347 while ((direntry = readdir(dirproc)) !=
nullptr) {
348 if (direntry->d_type != DT_DIR || !
IsDirNumeric(direntry->d_name))
359 ProcessInstanceInfo process_info;
368 if (
State == ProcessState::Zombie)
373 if (!all_users && (our_uid != 0) && (process_info.
GetUserID() != our_uid))
376 if (match_info.
Matches(process_info)) {
377 process_infos.push_back(process_info);
384 return process_infos.size();
388 bool tids_changed =
false;
389 static const char procdir[] =
"/proc/";
390 static const char taskdir[] =
"/task/";
391 std::string process_task_dir = procdir + llvm::to_string(pid) + taskdir;
392 DIR *dirproc = opendir(process_task_dir.c_str());
395 struct dirent *direntry =
nullptr;
396 while ((direntry = readdir(dirproc)) !=
nullptr) {
397 if (direntry->d_type != DT_DIR || !
IsDirNumeric(direntry->d_name))
401 TidMap::iterator it = tids_to_attach.find(tid);
402 if (it == tids_to_attach.end()) {
403 tids_to_attach.insert(
TidPair(tid,
false));
428 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.
static ProcessInstanceInfo::timespec convert(pr_timestruc64_t t)
static bool GetStatusInfo(::pid_t pid, ProcessInstanceInfo &processInfo, ProcessState &State)
static bool GetProcessAndStatInfo(::pid_t pid, ProcessInstanceInfo &process_info, ProcessState &State)
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 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.