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