LLDB mainline
linux/Host.cpp
Go to the documentation of this file.
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 <optional>
15#include <sys/stat.h>
16#include <sys/types.h>
17#include <sys/utsname.h>
18#include <unistd.h>
19
20#include "llvm/ADT/StringSwitch.h"
21#include "llvm/Object/ELF.h"
22#include "llvm/Support/ScopedPrinter.h"
23
25#include "lldb/Utility/Log.h"
27#include "lldb/Utility/Status.h"
28
30#include "lldb/Host/Host.h"
31#include "lldb/Host/HostInfo.h"
35
36using namespace lldb;
37using namespace lldb_private;
38
39namespace {
40enum class ProcessState {
41 Unknown,
42 Dead,
43 DiskSleep,
44 Idle,
45 Paging,
46 Parked,
47 Running,
48 Sleeping,
49 TracedOrStopped,
50 Zombie,
51};
52
53constexpr int task_comm_len = 16;
54
55struct StatFields {
57 char comm[task_comm_len];
58 char state;
62 int tty_nr;
63 int tpgid;
64 unsigned flags;
65 long unsigned minflt;
66 long unsigned cminflt;
67 long unsigned majflt;
68 long unsigned cmajflt;
69 long unsigned utime;
70 long unsigned stime;
71 long cutime;
72 long cstime;
73 // .... other things. We don't need them below
74};
75}
76
77namespace lldb_private {
79}
80
82 ProcessState &State, ::pid_t &TracerPid,
83 ::pid_t &Tgid) {
84 Log *log = GetLog(LLDBLog::Host);
85
86 auto BufferOrError = getProcFile(Pid, "stat");
87 if (!BufferOrError)
88 return false;
89
90 llvm::StringRef Rest = BufferOrError.get()->getBuffer();
91 if (Rest.empty())
92 return false;
93 StatFields stat_fields;
94 if (sscanf(Rest.data(),
95 "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld",
96 &stat_fields.pid, stat_fields.comm, &stat_fields.state,
97 &stat_fields.ppid, &stat_fields.pgrp, &stat_fields.session,
98 &stat_fields.tty_nr, &stat_fields.tpgid, &stat_fields.flags,
99 &stat_fields.minflt, &stat_fields.cminflt, &stat_fields.majflt,
100 &stat_fields.cmajflt, &stat_fields.utime, &stat_fields.stime,
101 &stat_fields.cutime, &stat_fields.cstime) < 0) {
102 return false;
103 }
104
105 auto convert = [sc_clk_ticks = sysconf(_SC_CLK_TCK)](auto time_in_ticks) {
107 if (sc_clk_ticks <= 0) {
108 return ts;
109 }
110 ts.tv_sec = time_in_ticks / sc_clk_ticks;
111 double remainder =
112 (static_cast<double>(time_in_ticks) / sc_clk_ticks) - ts.tv_sec;
113 ts.tv_usec =
114 std::chrono::microseconds{std::lround(1e+6 * remainder)}.count();
115 return ts;
116 };
117
118 ProcessInfo.SetParentProcessID(stat_fields.ppid);
119 ProcessInfo.SetProcessGroupID(stat_fields.pgrp);
120 ProcessInfo.SetProcessSessionID(stat_fields.session);
121 ProcessInfo.SetUserTime(convert(stat_fields.utime));
122 ProcessInfo.SetSystemTime(convert(stat_fields.stime));
123 ProcessInfo.SetCumulativeUserTime(convert(stat_fields.cutime));
124 ProcessInfo.SetCumulativeSystemTime(convert(stat_fields.cstime));
125 switch (stat_fields.state) {
126 case 'R':
127 State = ProcessState::Running;
128 break;
129 case 'S':
130 State = ProcessState::Sleeping;
131 break;
132 case 'D':
133 State = ProcessState::DiskSleep;
134 break;
135 case 'Z':
136 State = ProcessState::Zombie;
137 break;
138 case 'X':
139 State = ProcessState::Dead;
140 break;
141 case 'P':
142 State = ProcessState::Parked;
143 break;
144 case 'W':
145 State = ProcessState::Paging;
146 break;
147 case 'I':
148 State = ProcessState::Idle;
149 break;
150 case 'T': // Stopped on a signal or (before Linux 2.6.33) trace stopped
151 [[fallthrough]];
152 case 't':
153 State = ProcessState::TracedOrStopped;
154 break;
155 default:
156 State = ProcessState::Unknown;
157 break;
158 }
159
160 if (State == ProcessState::Unknown) {
161 LLDB_LOG(log, "Unknown process state {0}", stat_fields.state);
162 }
163
164 BufferOrError = getProcFile(Pid, "status");
165 if (!BufferOrError)
166 return false;
167
168 Rest = BufferOrError.get()->getBuffer();
169 if (Rest.empty())
170 return false;
171
172 while (!Rest.empty()) {
173 llvm::StringRef Line;
174 std::tie(Line, Rest) = Rest.split('\n');
175
176 if (Line.consume_front("Gid:")) {
177 // Real, effective, saved set, and file system GIDs. Read the first two.
178 Line = Line.ltrim();
179 uint32_t RGid, EGid;
180 Line.consumeInteger(10, RGid);
181 Line = Line.ltrim();
182 Line.consumeInteger(10, EGid);
183
185 ProcessInfo.SetEffectiveGroupID(EGid);
186 } else if (Line.consume_front("Uid:")) {
187 // Real, effective, saved set, and file system UIDs. Read the first two.
188 Line = Line.ltrim();
189 uint32_t RUid, EUid;
190 Line.consumeInteger(10, RUid);
191 Line = Line.ltrim();
192 Line.consumeInteger(10, EUid);
193
195 ProcessInfo.SetEffectiveUserID(EUid);
196 } else if (Line.consume_front("TracerPid:")) {
197 Line = Line.ltrim();
198 Line.consumeInteger(10, TracerPid);
199 } else if (Line.consume_front("Tgid:")) {
200 Line = Line.ltrim();
201 Line.consumeInteger(10, Tgid);
202 }
203 }
204 return true;
205}
206
207static bool IsDirNumeric(const char *dname) {
208 for (; *dname; dname++) {
209 if (!isdigit(*dname))
210 return false;
211 }
212 return true;
213}
214
215static ArchSpec GetELFProcessCPUType(llvm::StringRef exe_path) {
216 Log *log = GetLog(LLDBLog::Host);
217
218 auto buffer_sp = FileSystem::Instance().CreateDataBuffer(exe_path, 0x20, 0);
219 if (!buffer_sp)
220 return ArchSpec();
221
222 uint8_t exe_class =
223 llvm::object::getElfArchType(
224 {reinterpret_cast<const char *>(buffer_sp->GetBytes()),
225 size_t(buffer_sp->GetByteSize())})
226 .first;
227
228 switch (exe_class) {
229 case llvm::ELF::ELFCLASS32:
230 return HostInfo::GetArchitecture(HostInfo::eArchKind32);
231 case llvm::ELF::ELFCLASS64:
232 return HostInfo::GetArchitecture(HostInfo::eArchKind64);
233 default:
234 LLDB_LOG(log, "Unknown elf class ({0}) in file {1}", exe_class, exe_path);
235 return ArchSpec();
236 }
237}
238
239static void GetProcessArgs(::pid_t pid, ProcessInstanceInfo &process_info) {
240 auto BufferOrError = getProcFile(pid, "cmdline");
241 if (!BufferOrError)
242 return;
243 std::unique_ptr<llvm::MemoryBuffer> Cmdline = std::move(*BufferOrError);
244
245 llvm::StringRef Arg0, Rest;
246 std::tie(Arg0, Rest) = Cmdline->getBuffer().split('\0');
247 process_info.SetArg0(Arg0);
248 while (!Rest.empty()) {
249 llvm::StringRef Arg;
250 std::tie(Arg, Rest) = Rest.split('\0');
251 process_info.GetArguments().AppendArgument(Arg);
252 }
253}
254
255static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) {
257 std::string ExePath(PATH_MAX, '\0');
258
259 // We can't use getProcFile here because proc/[pid]/exe is a symbolic link.
260 llvm::SmallString<64> ProcExe;
261 (llvm::Twine("/proc/") + llvm::Twine(pid) + "/exe").toVector(ProcExe);
262
263 ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX);
264 if (len > 0) {
265 ExePath.resize(len);
266 } else {
267 LLDB_LOG(log, "failed to read link exe link for {0}: {1}", pid,
268 Status(errno, eErrorTypePOSIX));
269 ExePath.resize(0);
270 }
271 // If the binary has been deleted, the link name has " (deleted)" appended.
272 // Remove if there.
273 llvm::StringRef PathRef = ExePath;
274 PathRef.consume_back(" (deleted)");
275
276 if (!PathRef.empty()) {
277 process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native);
278 process_info.SetArchitecture(GetELFProcessCPUType(PathRef));
279 }
280}
281
282static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info) {
283 // Get the process environment.
284 auto BufferOrError = getProcFile(pid, "environ");
285 if (!BufferOrError)
286 return;
287
288 std::unique_ptr<llvm::MemoryBuffer> Environ = std::move(*BufferOrError);
289 llvm::StringRef Rest = Environ->getBuffer();
290 while (!Rest.empty()) {
291 llvm::StringRef Var;
292 std::tie(Var, Rest) = Rest.split('\0');
293 process_info.GetEnvironment().insert(Var);
294 }
295}
296
298 ProcessInstanceInfo &process_info,
299 ProcessState &State, ::pid_t &tracerpid) {
300 ::pid_t tgid;
301 tracerpid = 0;
302 process_info.Clear();
303
304 process_info.SetProcessID(pid);
305
306 GetExePathAndArch(pid, process_info);
307 GetProcessArgs(pid, process_info);
308 GetProcessEnviron(pid, process_info);
309
310 // Get User and Group IDs and get tracer pid.
311 if (!GetStatusInfo(pid, process_info, State, tracerpid, tgid))
312 return false;
313
314 return true;
315}
316
317uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
318 ProcessInstanceInfoList &process_infos) {
319 static const char procdir[] = "/proc/";
320
321 DIR *dirproc = opendir(procdir);
322 if (dirproc) {
323 struct dirent *direntry = nullptr;
324 const uid_t our_uid = getuid();
325 const lldb::pid_t our_pid = getpid();
326 bool all_users = match_info.GetMatchAllUsers();
327
328 while ((direntry = readdir(dirproc)) != nullptr) {
329 if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name))
330 continue;
331
332 lldb::pid_t pid = atoi(direntry->d_name);
333
334 // Skip this process.
335 if (pid == our_pid)
336 continue;
337
338 ::pid_t tracerpid;
339 ProcessState State;
340 ProcessInstanceInfo process_info;
341
342 if (!GetProcessAndStatInfo(pid, process_info, State, tracerpid))
343 continue;
344
345 // Skip if process is being debugged.
346 if (tracerpid != 0)
347 continue;
348
349 if (State == ProcessState::Zombie)
350 continue;
351
352 // Check for user match if we're not matching all users and not running
353 // as root.
354 if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid))
355 continue;
356
357 if (match_info.Matches(process_info)) {
358 process_infos.push_back(process_info);
359 }
360 }
361
362 closedir(dirproc);
363 }
364
365 return process_infos.size();
366}
367
368bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) {
369 bool tids_changed = false;
370 static const char procdir[] = "/proc/";
371 static const char taskdir[] = "/task/";
372 std::string process_task_dir = procdir + llvm::to_string(pid) + taskdir;
373 DIR *dirproc = opendir(process_task_dir.c_str());
374
375 if (dirproc) {
376 struct dirent *direntry = nullptr;
377 while ((direntry = readdir(dirproc)) != nullptr) {
378 if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name))
379 continue;
380
381 lldb::tid_t tid = atoi(direntry->d_name);
382 TidMap::iterator it = tids_to_attach.find(tid);
383 if (it == tids_to_attach.end()) {
384 tids_to_attach.insert(TidPair(tid, false));
385 tids_changed = true;
386 }
387 }
388 closedir(dirproc);
389 }
390
391 return tids_changed;
392}
393
395 ::pid_t tracerpid;
396 ProcessState State;
397 return GetProcessAndStatInfo(pid, process_info, State, tracerpid);
398}
399
401
403 return Status("unimplemented");
404}
405
406std::optional<lldb::pid_t> lldb_private::getPIDForTID(lldb::pid_t tid) {
407 ::pid_t tracerpid, tgid = LLDB_INVALID_PROCESS_ID;
408 ProcessInstanceInfo process_info;
409 ProcessState state;
410
411 if (!GetStatusInfo(tid, process_info, state, tracerpid, tgid) ||
413 return std::nullopt;
414 return tgid;
415}
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:342
An architecture specification class.
Definition: ArchSpec.h:31
void AppendArgument(llvm::StringRef arg_str, char quote_char='\0')
Appends a new argument to the end of the list argument list.
Definition: Args.cpp:322
std::pair< iterator, bool > insert(llvm::StringRef KeyEqValue)
Definition: Environment.h:71
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
Definition: FileSpec.cpp:174
static FileSystem & Instance()
std::shared_ptr< DataBuffer > CreateDataBuffer(const llvm::Twine &path, uint64_t size=0, uint64_t offset=0)
Create memory buffer from path.
static bool FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach)
static Status ShellExpandArguments(ProcessLaunchInfo &launch_info)
Perform expansion of the command-line for this launch info This can potentially involve wildcard expa...
static Environment GetEnvironment()
static uint32_t FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &proc_infos)
static bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info)
std::pair< lldb::pid_t, bool > TidPair
Definition: Host.h:161
void SetGroupID(uint32_t gid)
Definition: ProcessInfo.h:59
void SetArchitecture(const ArchSpec &arch)
Definition: ProcessInfo.h:65
void SetArg0(llvm::StringRef arg)
Definition: ProcessInfo.cpp:82
void SetProcessID(lldb::pid_t pid)
Definition: ProcessInfo.h:69
FileSpec & GetExecutableFile()
Definition: ProcessInfo.h:42
uint32_t GetUserID() const
Definition: ProcessInfo.h:49
Environment & GetEnvironment()
Definition: ProcessInfo.h:87
void SetUserID(uint32_t uid)
Definition: ProcessInfo.h:57
bool Matches(const ProcessInstanceInfo &proc_info) const
An error handling class.
Definition: Status.h:44
char ** environ
static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info)
Definition: linux/Host.cpp:255
static ArchSpec GetELFProcessCPUType(llvm::StringRef exe_path)
Definition: linux/Host.cpp:215
static bool GetProcessAndStatInfo(::pid_t pid, ProcessInstanceInfo &process_info, ProcessState &State, ::pid_t &tracerpid)
Definition: linux/Host.cpp:297
static void GetProcessArgs(::pid_t pid, ProcessInstanceInfo &process_info)
Definition: linux/Host.cpp:239
static bool IsDirNumeric(const char *dname)
Definition: linux/Host.cpp:207
static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info)
Definition: linux/Host.cpp:282
static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo, ProcessState &State, ::pid_t &TracerPid, ::pid_t &Tgid)
Definition: linux/Host.cpp:81
#define LLDB_INVALID_PROCESS_ID
Definition: lldb-defines.h:89
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:314
std::optional< lldb::pid_t > getPIDForTID(lldb::pid_t tid)
Definition: linux/Host.cpp:406
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file)
Definition: Support.cpp:15
std::vector< ProcessInstanceInfo > ProcessInstanceInfoList
Definition: Host.h:32
Definition: SBAddress.h:15
@ eErrorTypePOSIX
POSIX error codes.
uint64_t pid_t
Definition: lldb-types.h:81
uint64_t tid_t
Definition: lldb-types.h:82
#define PATH_MAX