xref: /llvm-project/lldb/source/Host/linux/Host.cpp (revision cb04bc05ebab5f44b13639c0e3613506180bdbac)
1 //===-- source/Host/linux/Host.cpp ----------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include <cerrno>
10 #include <cstdio>
11 #include <cstring>
12 #include <dirent.h>
13 #include <fcntl.h>
14 #include <optional>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <sys/utsname.h>
18 #include <unistd.h>
19 
20 #include "llvm/ADT/StringSwitch.h"
21 #include "llvm/Object/ELF.h"
22 #include "llvm/Support/ScopedPrinter.h"
23 
24 #include "lldb/Utility/LLDBLog.h"
25 #include "lldb/Utility/Log.h"
26 #include "lldb/Utility/ProcessInfo.h"
27 #include "lldb/Utility/Status.h"
28 
29 #include "lldb/Host/FileSystem.h"
30 #include "lldb/Host/Host.h"
31 #include "lldb/Host/HostInfo.h"
32 #include "lldb/Host/linux/Host.h"
33 #include "lldb/Host/linux/Support.h"
34 #include "lldb/Utility/DataExtractor.h"
35 
36 using namespace lldb;
37 using namespace lldb_private;
38 
39 namespace {
40 
41 enum class ProcessState {
42   Unknown,
43   Dead,
44   DiskSleep,
45   Idle,
46   Paging,
47   Parked,
48   Running,
49   Sleeping,
50   TracedOrStopped,
51   Zombie,
52 };
53 
54 struct StatFields {
55   ::pid_t pid = LLDB_INVALID_PROCESS_ID;
56   // comm
57   char state;
58   ::pid_t ppid = LLDB_INVALID_PROCESS_ID;
59   ::pid_t pgrp = LLDB_INVALID_PROCESS_ID;
60   ::pid_t session = LLDB_INVALID_PROCESS_ID;
61   int tty_nr;
62   int tpgid;
63   unsigned flags;
64   long unsigned minflt;
65   long unsigned cminflt;
66   long unsigned majflt;
67   long unsigned cmajflt;
68   long unsigned utime;
69   long unsigned stime;
70   long cutime;
71   long cstime;
72   // In proc_pid_stat(5) this field is specified as priority
73   // but documented as realtime priority. To keep with the adopted
74   // nomenclature in ProcessInstanceInfo, we adopt the documented
75   // naming here.
76   long realtime_priority;
77   long priority;
78   // .... other things. We don't need them below
79 };
80 }
81 
82 namespace lldb_private {
83 class ProcessLaunchInfo;
84 }
85 
86 static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
87                           ProcessState &State, ::pid_t &TracerPid,
88                           ::pid_t &Tgid) {
89   Log *log = GetLog(LLDBLog::Host);
90 
91   auto BufferOrError = getProcFile(Pid, "stat");
92   if (!BufferOrError)
93     return false;
94 
95   llvm::StringRef Rest = BufferOrError.get()->getBuffer();
96   if (Rest.empty())
97     return false;
98   StatFields stat_fields;
99   if (sscanf(
100           Rest.data(),
101           "%d %*s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld",
102           &stat_fields.pid, /* comm, */ &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) {
109     return false;
110   }
111 
112   auto convert = [sc_clk_ticks = sysconf(_SC_CLK_TCK)](auto time_in_ticks) {
113     ProcessInstanceInfo::timespec ts;
114     if (sc_clk_ticks <= 0) {
115       return ts;
116     }
117     ts.tv_sec = time_in_ticks / sc_clk_ticks;
118     double remainder =
119         (static_cast<double>(time_in_ticks) / sc_clk_ticks) - ts.tv_sec;
120     ts.tv_usec =
121         std::chrono::microseconds{std::lround(1e+6 * remainder)}.count();
122     return ts;
123   };
124 
125   // Priority (nice) values run from 19 to -20 inclusive (in linux). In the
126   // prpsinfo struct pr_nice is a char.
127   auto priority_value = static_cast<int8_t>(
128       (stat_fields.priority < 0 ? 0x80 : 0x00) | (stat_fields.priority & 0x7f));
129 
130   ProcessInfo.SetParentProcessID(stat_fields.ppid);
131   ProcessInfo.SetProcessGroupID(stat_fields.pgrp);
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));
137   ProcessInfo.SetPriorityValue(priority_value);
138   switch (stat_fields.state) {
139   case 'R':
140     State = ProcessState::Running;
141     break;
142   case 'S':
143     State = ProcessState::Sleeping;
144     break;
145   case 'D':
146     State = ProcessState::DiskSleep;
147     break;
148   case 'Z':
149     State = ProcessState::Zombie;
150     break;
151   case 'X':
152     State = ProcessState::Dead;
153     break;
154   case 'P':
155     State = ProcessState::Parked;
156     break;
157   case 'W':
158     State = ProcessState::Paging;
159     break;
160   case 'I':
161     State = ProcessState::Idle;
162     break;
163   case 'T': // Stopped on a signal or (before Linux 2.6.33) trace stopped
164     [[fallthrough]];
165   case 't':
166     State = ProcessState::TracedOrStopped;
167     break;
168   default:
169     State = ProcessState::Unknown;
170     break;
171   }
172   ProcessInfo.SetIsZombie(State == ProcessState::Zombie);
173 
174   if (State == ProcessState::Unknown) {
175     LLDB_LOG(log, "Unknown process state {0}", stat_fields.state);
176   }
177 
178   BufferOrError = getProcFile(Pid, "status");
179   if (!BufferOrError)
180     return false;
181 
182   Rest = BufferOrError.get()->getBuffer();
183   if (Rest.empty())
184     return false;
185 
186   while (!Rest.empty()) {
187     llvm::StringRef Line;
188     std::tie(Line, Rest) = Rest.split('\n');
189 
190     if (Line.consume_front("Gid:")) {
191       // Real, effective, saved set, and file system GIDs. Read the first two.
192       Line = Line.ltrim();
193       uint32_t RGid, EGid;
194       Line.consumeInteger(10, RGid);
195       Line = Line.ltrim();
196       Line.consumeInteger(10, EGid);
197 
198       ProcessInfo.SetGroupID(RGid);
199       ProcessInfo.SetEffectiveGroupID(EGid);
200     } else if (Line.consume_front("Uid:")) {
201       // Real, effective, saved set, and file system UIDs. Read the first two.
202       Line = Line.ltrim();
203       uint32_t RUid, EUid;
204       Line.consumeInteger(10, RUid);
205       Line = Line.ltrim();
206       Line.consumeInteger(10, EUid);
207 
208       ProcessInfo.SetUserID(RUid);
209       ProcessInfo.SetEffectiveUserID(EUid);
210     } else if (Line.consume_front("TracerPid:")) {
211       Line = Line.ltrim();
212       Line.consumeInteger(10, TracerPid);
213     } else if (Line.consume_front("Tgid:")) {
214       Line = Line.ltrim();
215       Line.consumeInteger(10, Tgid);
216     }
217   }
218   return true;
219 }
220 
221 static bool IsDirNumeric(const char *dname) {
222   for (; *dname; dname++) {
223     if (!isdigit(*dname))
224       return false;
225   }
226   return true;
227 }
228 
229 static ArchSpec GetELFProcessCPUType(llvm::StringRef exe_path) {
230   Log *log = GetLog(LLDBLog::Host);
231 
232   auto buffer_sp = FileSystem::Instance().CreateDataBuffer(exe_path, 0x20, 0);
233   if (!buffer_sp)
234     return ArchSpec();
235 
236   uint8_t exe_class =
237       llvm::object::getElfArchType(
238           {reinterpret_cast<const char *>(buffer_sp->GetBytes()),
239            size_t(buffer_sp->GetByteSize())})
240           .first;
241 
242   switch (exe_class) {
243   case llvm::ELF::ELFCLASS32:
244     return HostInfo::GetArchitecture(HostInfo::eArchKind32);
245   case llvm::ELF::ELFCLASS64:
246     return HostInfo::GetArchitecture(HostInfo::eArchKind64);
247   default:
248     LLDB_LOG(log, "Unknown elf class ({0}) in file {1}", exe_class, exe_path);
249     return ArchSpec();
250   }
251 }
252 
253 static void GetProcessArgs(::pid_t pid, ProcessInstanceInfo &process_info) {
254   auto BufferOrError = getProcFile(pid, "cmdline");
255   if (!BufferOrError)
256     return;
257   std::unique_ptr<llvm::MemoryBuffer> Cmdline = std::move(*BufferOrError);
258 
259   llvm::StringRef Arg0, Rest;
260   std::tie(Arg0, Rest) = Cmdline->getBuffer().split('\0');
261   process_info.SetArg0(Arg0);
262   while (!Rest.empty()) {
263     llvm::StringRef Arg;
264     std::tie(Arg, Rest) = Rest.split('\0');
265     process_info.GetArguments().AppendArgument(Arg);
266   }
267 }
268 
269 static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) {
270   Log *log = GetLog(LLDBLog::Process);
271   std::string ExePath(PATH_MAX, '\0');
272 
273   // We can't use getProcFile here because proc/[pid]/exe is a symbolic link.
274   llvm::SmallString<64> ProcExe;
275   (llvm::Twine("/proc/") + llvm::Twine(pid) + "/exe").toVector(ProcExe);
276 
277   ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX);
278   if (len > 0) {
279     ExePath.resize(len);
280   } else {
281     LLDB_LOG(log, "failed to read link exe link for {0}: {1}", pid,
282              Status(errno, eErrorTypePOSIX));
283     ExePath.resize(0);
284   }
285   // If the binary has been deleted, the link name has " (deleted)" appended.
286   // Remove if there.
287   llvm::StringRef PathRef = ExePath;
288   PathRef.consume_back(" (deleted)");
289 
290   if (!PathRef.empty()) {
291     process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native);
292     process_info.SetArchitecture(GetELFProcessCPUType(PathRef));
293   }
294 }
295 
296 static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info) {
297   // Get the process environment.
298   auto BufferOrError = getProcFile(pid, "environ");
299   if (!BufferOrError)
300     return;
301 
302   std::unique_ptr<llvm::MemoryBuffer> Environ = std::move(*BufferOrError);
303   llvm::StringRef Rest = Environ->getBuffer();
304   while (!Rest.empty()) {
305     llvm::StringRef Var;
306     std::tie(Var, Rest) = Rest.split('\0');
307     process_info.GetEnvironment().insert(Var);
308   }
309 }
310 
311 static bool GetProcessAndStatInfo(::pid_t pid,
312                                   ProcessInstanceInfo &process_info,
313                                   ProcessState &State, ::pid_t &tracerpid) {
314   ::pid_t tgid;
315   tracerpid = 0;
316   process_info.Clear();
317 
318   process_info.SetProcessID(pid);
319 
320   GetExePathAndArch(pid, process_info);
321   GetProcessArgs(pid, process_info);
322   GetProcessEnviron(pid, process_info);
323 
324   // Get User and Group IDs and get tracer pid.
325   if (!GetStatusInfo(pid, process_info, State, tracerpid, tgid))
326     return false;
327 
328   return true;
329 }
330 
331 uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
332                                  ProcessInstanceInfoList &process_infos) {
333   static const char procdir[] = "/proc/";
334 
335   DIR *dirproc = opendir(procdir);
336   if (dirproc) {
337     struct dirent *direntry = nullptr;
338     const uid_t our_uid = getuid();
339     const lldb::pid_t our_pid = getpid();
340     bool all_users = match_info.GetMatchAllUsers();
341 
342     while ((direntry = readdir(dirproc)) != nullptr) {
343       if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name))
344         continue;
345 
346       lldb::pid_t pid = atoi(direntry->d_name);
347 
348       // Skip this process.
349       if (pid == our_pid)
350         continue;
351 
352       ::pid_t tracerpid;
353       ProcessState State;
354       ProcessInstanceInfo process_info;
355 
356       if (!GetProcessAndStatInfo(pid, process_info, State, tracerpid))
357         continue;
358 
359       // Skip if process is being debugged.
360       if (tracerpid != 0)
361         continue;
362 
363       if (State == ProcessState::Zombie)
364         continue;
365 
366       // Check for user match if we're not matching all users and not running
367       // as root.
368       if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid))
369         continue;
370 
371       if (match_info.Matches(process_info)) {
372         process_infos.push_back(process_info);
373       }
374     }
375 
376     closedir(dirproc);
377   }
378 
379   return process_infos.size();
380 }
381 
382 bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) {
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());
388 
389   if (dirproc) {
390     struct dirent *direntry = nullptr;
391     while ((direntry = readdir(dirproc)) != nullptr) {
392       if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name))
393         continue;
394 
395       lldb::tid_t tid = atoi(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));
399         tids_changed = true;
400       }
401     }
402     closedir(dirproc);
403   }
404 
405   return tids_changed;
406 }
407 
408 bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
409   ::pid_t tracerpid;
410   ProcessState State;
411   return GetProcessAndStatInfo(pid, process_info, State, tracerpid);
412 }
413 
414 Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
415   return Status::FromErrorString("unimplemented");
416 }
417 
418 std::optional<lldb::pid_t> lldb_private::getPIDForTID(lldb::pid_t tid) {
419   ::pid_t tracerpid, tgid = LLDB_INVALID_PROCESS_ID;
420   ProcessInstanceInfo process_info;
421   ProcessState state;
422 
423   if (!GetStatusInfo(tid, process_info, state, tracerpid, tgid) ||
424       tgid == LLDB_INVALID_PROCESS_ID)
425     return std::nullopt;
426   return tgid;
427 }
428