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 <sys/stat.h>
15 #include <sys/types.h>
16 #include <sys/utsname.h>
17 #include <unistd.h>
18 
19 #include "llvm/ADT/StringSwitch.h"
20 #include "llvm/Object/ELF.h"
21 #include "llvm/Support/ScopedPrinter.h"
22 
23 #include "lldb/Utility/LLDBLog.h"
24 #include "lldb/Utility/Log.h"
25 #include "lldb/Utility/ProcessInfo.h"
26 #include "lldb/Utility/Status.h"
27 
28 #include "lldb/Host/FileSystem.h"
29 #include "lldb/Host/Host.h"
30 #include "lldb/Host/HostInfo.h"
31 #include "lldb/Host/linux/Host.h"
32 #include "lldb/Host/linux/Support.h"
33 #include "lldb/Utility/DataExtractor.h"
34 
35 using namespace lldb;
36 using namespace lldb_private;
37 
38 namespace {
39 enum class ProcessState {
40   Unknown,
41   Dead,
42   DiskSleep,
43   Idle,
44   Paging,
45   Parked,
46   Running,
47   Sleeping,
48   TracedOrStopped,
49   Zombie,
50 };
51 }
52 
53 namespace lldb_private {
54 class ProcessLaunchInfo;
55 }
56 
GetStatusInfo(::pid_t Pid,ProcessInstanceInfo & ProcessInfo,ProcessState & State,::pid_t & TracerPid,::pid_t & Tgid)57 static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
58                           ProcessState &State, ::pid_t &TracerPid,
59                           ::pid_t &Tgid) {
60   Log *log = GetLog(LLDBLog::Host);
61 
62   auto BufferOrError = getProcFile(Pid, "status");
63   if (!BufferOrError)
64     return false;
65 
66   llvm::StringRef Rest = BufferOrError.get()->getBuffer();
67   while (!Rest.empty()) {
68     llvm::StringRef Line;
69     std::tie(Line, Rest) = Rest.split('\n');
70 
71     if (Line.consume_front("Gid:")) {
72       // Real, effective, saved set, and file system GIDs. Read the first two.
73       Line = Line.ltrim();
74       uint32_t RGid, EGid;
75       Line.consumeInteger(10, RGid);
76       Line = Line.ltrim();
77       Line.consumeInteger(10, EGid);
78 
79       ProcessInfo.SetGroupID(RGid);
80       ProcessInfo.SetEffectiveGroupID(EGid);
81     } else if (Line.consume_front("Uid:")) {
82       // Real, effective, saved set, and file system UIDs. Read the first two.
83       Line = Line.ltrim();
84       uint32_t RUid, EUid;
85       Line.consumeInteger(10, RUid);
86       Line = Line.ltrim();
87       Line.consumeInteger(10, EUid);
88 
89       ProcessInfo.SetUserID(RUid);
90       ProcessInfo.SetEffectiveUserID(EUid);
91     } else if (Line.consume_front("PPid:")) {
92       ::pid_t PPid;
93       Line.ltrim().consumeInteger(10, PPid);
94       ProcessInfo.SetParentProcessID(PPid);
95     } else if (Line.consume_front("State:")) {
96       State = llvm::StringSwitch<ProcessState>(Line.ltrim().take_front(1))
97                   .Case("D", ProcessState::DiskSleep)
98                   .Case("I", ProcessState::Idle)
99                   .Case("R", ProcessState::Running)
100                   .Case("S", ProcessState::Sleeping)
101                   .CaseLower("T", ProcessState::TracedOrStopped)
102                   .Case("W", ProcessState::Paging)
103                   .Case("P", ProcessState::Parked)
104                   .Case("X", ProcessState::Dead)
105                   .Case("Z", ProcessState::Zombie)
106                   .Default(ProcessState::Unknown);
107       if (State == ProcessState::Unknown) {
108         LLDB_LOG(log, "Unknown process state {0}", Line);
109       }
110     } else if (Line.consume_front("TracerPid:")) {
111       Line = Line.ltrim();
112       Line.consumeInteger(10, TracerPid);
113     } else if (Line.consume_front("Tgid:")) {
114       Line = Line.ltrim();
115       Line.consumeInteger(10, Tgid);
116     }
117   }
118   return true;
119 }
120 
IsDirNumeric(const char * dname)121 static bool IsDirNumeric(const char *dname) {
122   for (; *dname; dname++) {
123     if (!isdigit(*dname))
124       return false;
125   }
126   return true;
127 }
128 
GetELFProcessCPUType(llvm::StringRef exe_path)129 static ArchSpec GetELFProcessCPUType(llvm::StringRef exe_path) {
130   Log *log = GetLog(LLDBLog::Host);
131 
132   auto buffer_sp = FileSystem::Instance().CreateDataBuffer(exe_path, 0x20, 0);
133   if (!buffer_sp)
134     return ArchSpec();
135 
136   uint8_t exe_class =
137       llvm::object::getElfArchType(
138           {reinterpret_cast<const char *>(buffer_sp->GetBytes()),
139            size_t(buffer_sp->GetByteSize())})
140           .first;
141 
142   switch (exe_class) {
143   case llvm::ELF::ELFCLASS32:
144     return HostInfo::GetArchitecture(HostInfo::eArchKind32);
145   case llvm::ELF::ELFCLASS64:
146     return HostInfo::GetArchitecture(HostInfo::eArchKind64);
147   default:
148     LLDB_LOG(log, "Unknown elf class ({0}) in file {1}", exe_class, exe_path);
149     return ArchSpec();
150   }
151 }
152 
GetProcessArgs(::pid_t pid,ProcessInstanceInfo & process_info)153 static void GetProcessArgs(::pid_t pid, ProcessInstanceInfo &process_info) {
154   auto BufferOrError = getProcFile(pid, "cmdline");
155   if (!BufferOrError)
156     return;
157   std::unique_ptr<llvm::MemoryBuffer> Cmdline = std::move(*BufferOrError);
158 
159   llvm::StringRef Arg0, Rest;
160   std::tie(Arg0, Rest) = Cmdline->getBuffer().split('\0');
161   process_info.SetArg0(Arg0);
162   while (!Rest.empty()) {
163     llvm::StringRef Arg;
164     std::tie(Arg, Rest) = Rest.split('\0');
165     process_info.GetArguments().AppendArgument(Arg);
166   }
167 }
168 
GetExePathAndArch(::pid_t pid,ProcessInstanceInfo & process_info)169 static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) {
170   Log *log = GetLog(LLDBLog::Process);
171   std::string ExePath(PATH_MAX, '\0');
172 
173   // We can't use getProcFile here because proc/[pid]/exe is a symbolic link.
174   llvm::SmallString<64> ProcExe;
175   (llvm::Twine("/proc/") + llvm::Twine(pid) + "/exe").toVector(ProcExe);
176 
177   ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX);
178   if (len > 0) {
179     ExePath.resize(len);
180   } else {
181     LLDB_LOG(log, "failed to read link exe link for {0}: {1}", pid,
182              Status(errno, eErrorTypePOSIX));
183     ExePath.resize(0);
184   }
185   // If the binary has been deleted, the link name has " (deleted)" appended.
186   // Remove if there.
187   llvm::StringRef PathRef = ExePath;
188   PathRef.consume_back(" (deleted)");
189 
190   if (!PathRef.empty()) {
191     process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native);
192     process_info.SetArchitecture(GetELFProcessCPUType(PathRef));
193   }
194 }
195 
GetProcessEnviron(::pid_t pid,ProcessInstanceInfo & process_info)196 static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info) {
197   // Get the process environment.
198   auto BufferOrError = getProcFile(pid, "environ");
199   if (!BufferOrError)
200     return;
201 
202   std::unique_ptr<llvm::MemoryBuffer> Environ = std::move(*BufferOrError);
203   llvm::StringRef Rest = Environ->getBuffer();
204   while (!Rest.empty()) {
205     llvm::StringRef Var;
206     std::tie(Var, Rest) = Rest.split('\0');
207     process_info.GetEnvironment().insert(Var);
208   }
209 }
210 
GetProcessAndStatInfo(::pid_t pid,ProcessInstanceInfo & process_info,ProcessState & State,::pid_t & tracerpid)211 static bool GetProcessAndStatInfo(::pid_t pid,
212                                   ProcessInstanceInfo &process_info,
213                                   ProcessState &State, ::pid_t &tracerpid) {
214   ::pid_t tgid;
215   tracerpid = 0;
216   process_info.Clear();
217 
218   process_info.SetProcessID(pid);
219 
220   GetExePathAndArch(pid, process_info);
221   GetProcessArgs(pid, process_info);
222   GetProcessEnviron(pid, process_info);
223 
224   // Get User and Group IDs and get tracer pid.
225   if (!GetStatusInfo(pid, process_info, State, tracerpid, tgid))
226     return false;
227 
228   return true;
229 }
230 
FindProcessesImpl(const ProcessInstanceInfoMatch & match_info,ProcessInstanceInfoList & process_infos)231 uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
232                                  ProcessInstanceInfoList &process_infos) {
233   static const char procdir[] = "/proc/";
234 
235   DIR *dirproc = opendir(procdir);
236   if (dirproc) {
237     struct dirent *direntry = nullptr;
238     const uid_t our_uid = getuid();
239     const lldb::pid_t our_pid = getpid();
240     bool all_users = match_info.GetMatchAllUsers();
241 
242     while ((direntry = readdir(dirproc)) != nullptr) {
243       if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name))
244         continue;
245 
246       lldb::pid_t pid = atoi(direntry->d_name);
247 
248       // Skip this process.
249       if (pid == our_pid)
250         continue;
251 
252       ::pid_t tracerpid;
253       ProcessState State;
254       ProcessInstanceInfo process_info;
255 
256       if (!GetProcessAndStatInfo(pid, process_info, State, tracerpid))
257         continue;
258 
259       // Skip if process is being debugged.
260       if (tracerpid != 0)
261         continue;
262 
263       if (State == ProcessState::Zombie)
264         continue;
265 
266       // Check for user match if we're not matching all users and not running
267       // as root.
268       if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid))
269         continue;
270 
271       if (match_info.Matches(process_info)) {
272         process_infos.push_back(process_info);
273       }
274     }
275 
276     closedir(dirproc);
277   }
278 
279   return process_infos.size();
280 }
281 
FindProcessThreads(const lldb::pid_t pid,TidMap & tids_to_attach)282 bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) {
283   bool tids_changed = false;
284   static const char procdir[] = "/proc/";
285   static const char taskdir[] = "/task/";
286   std::string process_task_dir = procdir + llvm::to_string(pid) + taskdir;
287   DIR *dirproc = opendir(process_task_dir.c_str());
288 
289   if (dirproc) {
290     struct dirent *direntry = nullptr;
291     while ((direntry = readdir(dirproc)) != nullptr) {
292       if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name))
293         continue;
294 
295       lldb::tid_t tid = atoi(direntry->d_name);
296       TidMap::iterator it = tids_to_attach.find(tid);
297       if (it == tids_to_attach.end()) {
298         tids_to_attach.insert(TidPair(tid, false));
299         tids_changed = true;
300       }
301     }
302     closedir(dirproc);
303   }
304 
305   return tids_changed;
306 }
307 
GetProcessInfo(lldb::pid_t pid,ProcessInstanceInfo & process_info)308 bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
309   ::pid_t tracerpid;
310   ProcessState State;
311   return GetProcessAndStatInfo(pid, process_info, State, tracerpid);
312 }
313 
GetEnvironment()314 Environment Host::GetEnvironment() { return Environment(environ); }
315 
ShellExpandArguments(ProcessLaunchInfo & launch_info)316 Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
317   return Status("unimplemented");
318 }
319 
getPIDForTID(lldb::pid_t tid)320 llvm::Optional<lldb::pid_t> lldb_private::getPIDForTID(lldb::pid_t tid) {
321   ::pid_t tracerpid, tgid = LLDB_INVALID_PROCESS_ID;
322   ProcessInstanceInfo process_info;
323   ProcessState state;
324 
325   if (!GetStatusInfo(tid, process_info, state, tracerpid, tgid) ||
326       tgid == LLDB_INVALID_PROCESS_ID)
327     return llvm::None;
328   return tgid;
329 }
330