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