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