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                                            FileSpec::Style::native);
195 
196   llvm::StringRef Rest = Environ->getBuffer();
197   while (!Rest.empty()) {
198     llvm::StringRef Var;
199     std::tie(Var, Rest) = Rest.split('\0');
200     process_info.GetEnvironment().insert(Var);
201   }
202 
203   llvm::StringRef Arg0;
204   std::tie(Arg0, Rest) = Cmdline->getBuffer().split('\0');
205   process_info.SetArg0(Arg0);
206   while (!Rest.empty()) {
207     llvm::StringRef Arg;
208     std::tie(Arg, Rest) = Rest.split('\0');
209     process_info.GetArguments().AppendArgument(Arg);
210   }
211 
212   return true;
213 }
214 
215 uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
216                              ProcessInstanceInfoList &process_infos) {
217   static const char procdir[] = "/proc/";
218 
219   DIR *dirproc = opendir(procdir);
220   if (dirproc) {
221     struct dirent *direntry = NULL;
222     const uid_t our_uid = getuid();
223     const lldb::pid_t our_pid = getpid();
224     bool all_users = match_info.GetMatchAllUsers();
225 
226     while ((direntry = readdir(dirproc)) != NULL) {
227       if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name))
228         continue;
229 
230       lldb::pid_t pid = atoi(direntry->d_name);
231 
232       // Skip this process.
233       if (pid == our_pid)
234         continue;
235 
236       ::pid_t tracerpid;
237       ProcessState State;
238       ProcessInstanceInfo process_info;
239 
240       if (!GetProcessAndStatInfo(pid, process_info, State, tracerpid))
241         continue;
242 
243       // Skip if process is being debugged.
244       if (tracerpid != 0)
245         continue;
246 
247       if (State == ProcessState::Zombie)
248         continue;
249 
250       // Check for user match if we're not matching all users and not running
251       // as root.
252       if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid))
253         continue;
254 
255       if (match_info.Matches(process_info)) {
256         process_infos.Append(process_info);
257       }
258     }
259 
260     closedir(dirproc);
261   }
262 
263   return process_infos.GetSize();
264 }
265 
266 bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) {
267   bool tids_changed = false;
268   static const char procdir[] = "/proc/";
269   static const char taskdir[] = "/task/";
270   std::string process_task_dir = procdir + llvm::to_string(pid) + taskdir;
271   DIR *dirproc = opendir(process_task_dir.c_str());
272 
273   if (dirproc) {
274     struct dirent *direntry = NULL;
275     while ((direntry = readdir(dirproc)) != NULL) {
276       if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name))
277         continue;
278 
279       lldb::tid_t tid = atoi(direntry->d_name);
280       TidMap::iterator it = tids_to_attach.find(tid);
281       if (it == tids_to_attach.end()) {
282         tids_to_attach.insert(TidPair(tid, false));
283         tids_changed = true;
284       }
285     }
286     closedir(dirproc);
287   }
288 
289   return tids_changed;
290 }
291 
292 bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
293   ::pid_t tracerpid;
294   ProcessState State;
295   return GetProcessAndStatInfo(pid, process_info, State, tracerpid);
296 }
297 
298 Environment Host::GetEnvironment() { return Environment(environ); }
299 
300 Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
301   return Status("unimplemented");
302 }
303