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