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