1 //===-- source/Host/linux/Host.cpp ------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // C Includes
11 #include <dirent.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <sys/utsname.h>
19 #include <unistd.h>
20 
21 // C++ Includes
22 // Other libraries and framework includes
23 #include "llvm/Support/ScopedPrinter.h"
24 // Project includes
25 #include "lldb/Target/Process.h"
26 #include "lldb/Utility/Log.h"
27 #include "lldb/Utility/Status.h"
28 
29 #include "lldb/Host/Host.h"
30 #include "lldb/Host/HostInfo.h"
31 #include "lldb/Host/linux/Support.h"
32 #include "lldb/Utility/DataBufferHeap.h"
33 #include "lldb/Utility/DataExtractor.h"
34 
35 #include "lldb/Core/ModuleSpec.h"
36 #include "lldb/Symbol/ObjectFile.h"
37 
38 using namespace lldb;
39 using namespace lldb_private;
40 
41 namespace {
42 enum class ProcessState {
43   Unknown,
44   DiskSleep,
45   Paging,
46   Running,
47   Sleeping,
48   TracedOrStopped,
49   Zombie,
50 };
51 }
52 
53 static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
54                           ProcessState &State, ::pid_t &TracerPid) {
55   auto BufferOrError = getProcFile(Pid, "status");
56   if (!BufferOrError)
57     return false;
58 
59   llvm::StringRef Rest = BufferOrError.get()->getBuffer();
60   while(!Rest.empty()) {
61     llvm::StringRef Line;
62     std::tie(Line, Rest) = Rest.split('\n');
63 
64     if (Line.consume_front("Gid:")) {
65       // Real, effective, saved set, and file system GIDs. Read the first two.
66       Line = Line.ltrim();
67       uint32_t RGid, EGid;
68       Line.consumeInteger(10, RGid);
69       Line = Line.ltrim();
70       Line.consumeInteger(10, EGid);
71 
72       ProcessInfo.SetGroupID(RGid);
73       ProcessInfo.SetEffectiveGroupID(EGid);
74     } else if (Line.consume_front("Uid:")) {
75       // Real, effective, saved set, and file system UIDs. Read the first two.
76       Line = Line.ltrim();
77       uint32_t RUid, EUid;
78       Line.consumeInteger(10, RUid);
79       Line = Line.ltrim();
80       Line.consumeInteger(10, EUid);
81 
82       ProcessInfo.SetUserID(RUid);
83       ProcessInfo.SetEffectiveUserID(EUid);
84     } else if (Line.consume_front("PPid:")) {
85       ::pid_t PPid;
86       Line.ltrim().consumeInteger(10, PPid);
87       ProcessInfo.SetParentProcessID(PPid);
88     } else if (Line.consume_front("State:")) {
89       char S = Line.ltrim().front();
90       switch (S) {
91       case 'R':
92         State = ProcessState::Running;
93         break;
94       case 'S':
95         State = ProcessState::Sleeping;
96         break;
97       case 'D':
98         State = ProcessState::DiskSleep;
99         break;
100       case 'Z':
101         State = ProcessState::Zombie;
102         break;
103       case 'T':
104         State = ProcessState::TracedOrStopped;
105         break;
106       case 'W':
107         State = ProcessState::Paging;
108         break;
109       }
110     } else if (Line.consume_front("TracerPid:")) {
111       Line = Line.ltrim();
112       Line.consumeInteger(10, TracerPid);
113     }
114   }
115   return true;
116 }
117 
118 static bool IsDirNumeric(const char *dname) {
119   for (; *dname; dname++) {
120     if (!isdigit(*dname))
121       return false;
122   }
123   return true;
124 }
125 
126 static bool GetELFProcessCPUType(llvm::StringRef exe_path,
127                                  ProcessInstanceInfo &process_info) {
128   // Clear the architecture.
129   process_info.GetArchitecture().Clear();
130 
131   ModuleSpecList specs;
132   FileSpec filespec(exe_path, false);
133   const size_t num_specs =
134       ObjectFile::GetModuleSpecifications(filespec, 0, 0, specs);
135   // GetModuleSpecifications() could fail if the executable has been deleted or
136   // is locked.
137   // But it shouldn't return more than 1 architecture.
138   assert(num_specs <= 1 && "Linux plugin supports only a single architecture");
139   if (num_specs == 1) {
140     ModuleSpec module_spec;
141     if (specs.GetModuleSpecAtIndex(0, module_spec) &&
142         module_spec.GetArchitecture().IsValid()) {
143       process_info.GetArchitecture() = module_spec.GetArchitecture();
144       return true;
145     }
146   }
147   return false;
148 }
149 
150 static bool GetProcessAndStatInfo(::pid_t pid,
151                                   ProcessInstanceInfo &process_info,
152                                   ProcessState &State, ::pid_t &tracerpid) {
153   tracerpid = 0;
154   process_info.Clear();
155 
156   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
157 
158   // We can't use getProcFile here because proc/[pid]/exe is a symbolic link.
159   llvm::SmallString<64> ProcExe;
160   (llvm::Twine("/proc/") + llvm::Twine(pid) + "/exe").toVector(ProcExe);
161   std::string ExePath(PATH_MAX, '\0');
162 
163   ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX);
164   if (len <= 0) {
165     LLDB_LOG(log, "failed to read link exe link for {0}: {1}", pid,
166              Status(errno, eErrorTypePOSIX));
167     return false;
168   }
169   ExePath.resize(len);
170 
171   // If the binary has been deleted, the link name has " (deleted)" appended.
172   // Remove if there.
173   llvm::StringRef PathRef = ExePath;
174   PathRef.consume_back(" (deleted)");
175 
176   GetELFProcessCPUType(PathRef, process_info);
177 
178   // Get the process environment.
179   auto BufferOrError = getProcFile(pid, "environ");
180   if (!BufferOrError)
181     return false;
182   std::unique_ptr<llvm::MemoryBuffer> Environ = std::move(*BufferOrError);
183 
184   // Get the command line used to start the process.
185   BufferOrError = getProcFile(pid, "cmdline");
186   if (!BufferOrError)
187     return false;
188   std::unique_ptr<llvm::MemoryBuffer> Cmdline = std::move(*BufferOrError);
189 
190   // Get User and Group IDs and get tracer pid.
191   if (!GetStatusInfo(pid, process_info, State, tracerpid))
192     return false;
193 
194   process_info.SetProcessID(pid);
195   process_info.GetExecutableFile().SetFile(PathRef, false);
196   process_info.GetArchitecture().MergeFrom(HostInfo::GetArchitecture());
197 
198   llvm::StringRef Rest = Environ->getBuffer();
199   while (!Rest.empty()) {
200     llvm::StringRef Var;
201     std::tie(Var, Rest) = Rest.split('\0');
202     process_info.GetEnvironment().insert(Var);
203   }
204 
205   llvm::StringRef Arg0;
206   std::tie(Arg0, Rest) = Cmdline->getBuffer().split('\0');
207   process_info.SetArg0(Arg0);
208   while (!Rest.empty()) {
209     llvm::StringRef Arg;
210     std::tie(Arg, Rest) = Rest.split('\0');
211     process_info.GetArguments().AppendArgument(Arg);
212   }
213 
214   return true;
215 }
216 
217 uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
218                              ProcessInstanceInfoList &process_infos) {
219   static const char procdir[] = "/proc/";
220 
221   DIR *dirproc = opendir(procdir);
222   if (dirproc) {
223     struct dirent *direntry = NULL;
224     const uid_t our_uid = getuid();
225     const lldb::pid_t our_pid = getpid();
226     bool all_users = match_info.GetMatchAllUsers();
227 
228     while ((direntry = readdir(dirproc)) != NULL) {
229       if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name))
230         continue;
231 
232       lldb::pid_t pid = atoi(direntry->d_name);
233 
234       // Skip this process.
235       if (pid == our_pid)
236         continue;
237 
238       ::pid_t tracerpid;
239       ProcessState State;
240       ProcessInstanceInfo process_info;
241 
242       if (!GetProcessAndStatInfo(pid, process_info, State, tracerpid))
243         continue;
244 
245       // Skip if process is being debugged.
246       if (tracerpid != 0)
247         continue;
248 
249       if (State == ProcessState::Zombie)
250         continue;
251 
252       // Check for user match if we're not matching all users and not running as
253       // root.
254       if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid))
255         continue;
256 
257       if (match_info.Matches(process_info)) {
258         process_infos.Append(process_info);
259       }
260     }
261 
262     closedir(dirproc);
263   }
264 
265   return process_infos.GetSize();
266 }
267 
268 bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) {
269   bool tids_changed = false;
270   static const char procdir[] = "/proc/";
271   static const char taskdir[] = "/task/";
272   std::string process_task_dir = procdir + llvm::to_string(pid) + taskdir;
273   DIR *dirproc = opendir(process_task_dir.c_str());
274 
275   if (dirproc) {
276     struct dirent *direntry = NULL;
277     while ((direntry = readdir(dirproc)) != NULL) {
278       if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name))
279         continue;
280 
281       lldb::tid_t tid = atoi(direntry->d_name);
282       TidMap::iterator it = tids_to_attach.find(tid);
283       if (it == tids_to_attach.end()) {
284         tids_to_attach.insert(TidPair(tid, false));
285         tids_changed = true;
286       }
287     }
288     closedir(dirproc);
289   }
290 
291   return tids_changed;
292 }
293 
294 bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
295   ::pid_t tracerpid;
296   ProcessState State;
297   return GetProcessAndStatInfo(pid, process_info, State, tracerpid);
298 }
299 
300 Environment Host::GetEnvironment() { return Environment(environ); }
301 
302 Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
303   return Status("unimplemented");
304 }
305