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}
53
54namespace lldb_private {
56}
57
59 ProcessState &State, ::pid_t &TracerPid,
60 ::pid_t &Tgid) {
61 Log *log = GetLog(LLDBLog::Host);
62
63 auto BufferOrError = getProcFile(Pid, "status");
64 if (!BufferOrError)
65 return false;
66
67 llvm::StringRef Rest = BufferOrError.get()->getBuffer();
68 while (!Rest.empty()) {
69 llvm::StringRef Line;
70 std::tie(Line, Rest) = Rest.split('\n');
71
72 if (Line.consume_front("Gid:")) {
73 // Real, effective, saved set, and file system GIDs. Read the first two.
74 Line = Line.ltrim();
75 uint32_t RGid, EGid;
76 Line.consumeInteger(10, RGid);
77 Line = Line.ltrim();
78 Line.consumeInteger(10, EGid);
79
81 ProcessInfo.SetEffectiveGroupID(EGid);
82 } else if (Line.consume_front("Uid:")) {
83 // Real, effective, saved set, and file system UIDs. Read the first two.
84 Line = Line.ltrim();
85 uint32_t RUid, EUid;
86 Line.consumeInteger(10, RUid);
87 Line = Line.ltrim();
88 Line.consumeInteger(10, EUid);
89
91 ProcessInfo.SetEffectiveUserID(EUid);
92 } else if (Line.consume_front("PPid:")) {
93 ::pid_t PPid;
94 Line.ltrim().consumeInteger(10, PPid);
95 ProcessInfo.SetParentProcessID(PPid);
96 } else if (Line.consume_front("State:")) {
97 State = llvm::StringSwitch<ProcessState>(Line.ltrim().take_front(1))
98 .Case("D", ProcessState::DiskSleep)
99 .Case("I", ProcessState::Idle)
100 .Case("R", ProcessState::Running)
101 .Case("S", ProcessState::Sleeping)
102 .CaseLower("T", ProcessState::TracedOrStopped)
103 .Case("W", ProcessState::Paging)
104 .Case("P", ProcessState::Parked)
105 .Case("X", ProcessState::Dead)
106 .Case("Z", ProcessState::Zombie)
107 .Default(ProcessState::Unknown);
108 if (State == ProcessState::Unknown) {
109 LLDB_LOG(log, "Unknown process state {0}", Line);
110 }
111 } else if (Line.consume_front("TracerPid:")) {
112 Line = Line.ltrim();
113 Line.consumeInteger(10, TracerPid);
114 } else if (Line.consume_front("Tgid:")) {
115 Line = Line.ltrim();
116 Line.consumeInteger(10, Tgid);
117 }
118 }
119 return true;
120}
121
122static bool IsDirNumeric(const char *dname) {
123 for (; *dname; dname++) {
124 if (!isdigit(*dname))
125 return false;
126 }
127 return true;
128}
129
130static ArchSpec GetELFProcessCPUType(llvm::StringRef exe_path) {
131 Log *log = GetLog(LLDBLog::Host);
132
133 auto buffer_sp = FileSystem::Instance().CreateDataBuffer(exe_path, 0x20, 0);
134 if (!buffer_sp)
135 return ArchSpec();
136
137 uint8_t exe_class =
138 llvm::object::getElfArchType(
139 {reinterpret_cast<const char *>(buffer_sp->GetBytes()),
140 size_t(buffer_sp->GetByteSize())})
141 .first;
142
143 switch (exe_class) {
144 case llvm::ELF::ELFCLASS32:
145 return HostInfo::GetArchitecture(HostInfo::eArchKind32);
146 case llvm::ELF::ELFCLASS64:
147 return HostInfo::GetArchitecture(HostInfo::eArchKind64);
148 default:
149 LLDB_LOG(log, "Unknown elf class ({0}) in file {1}", exe_class, exe_path);
150 return ArchSpec();
151 }
152}
153
154static void GetProcessArgs(::pid_t pid, ProcessInstanceInfo &process_info) {
155 auto BufferOrError = getProcFile(pid, "cmdline");
156 if (!BufferOrError)
157 return;
158 std::unique_ptr<llvm::MemoryBuffer> Cmdline = std::move(*BufferOrError);
159
160 llvm::StringRef Arg0, Rest;
161 std::tie(Arg0, Rest) = Cmdline->getBuffer().split('\0');
162 process_info.SetArg0(Arg0);
163 while (!Rest.empty()) {
164 llvm::StringRef Arg;
165 std::tie(Arg, Rest) = Rest.split('\0');
166 process_info.GetArguments().AppendArgument(Arg);
167 }
168}
169
170static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) {
172 std::string ExePath(PATH_MAX, '\0');
173
174 // We can't use getProcFile here because proc/[pid]/exe is a symbolic link.
175 llvm::SmallString<64> ProcExe;
176 (llvm::Twine("/proc/") + llvm::Twine(pid) + "/exe").toVector(ProcExe);
177
178 ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX);
179 if (len > 0) {
180 ExePath.resize(len);
181 } else {
182 LLDB_LOG(log, "failed to read link exe link for {0}: {1}", pid,
183 Status(errno, eErrorTypePOSIX));
184 ExePath.resize(0);
185 }
186 // If the binary has been deleted, the link name has " (deleted)" appended.
187 // Remove if there.
188 llvm::StringRef PathRef = ExePath;
189 PathRef.consume_back(" (deleted)");
190
191 if (!PathRef.empty()) {
192 process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native);
193 process_info.SetArchitecture(GetELFProcessCPUType(PathRef));
194 }
195}
196
197static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info) {
198 // Get the process environment.
199 auto BufferOrError = getProcFile(pid, "environ");
200 if (!BufferOrError)
201 return;
202
203 std::unique_ptr<llvm::MemoryBuffer> Environ = std::move(*BufferOrError);
204 llvm::StringRef Rest = Environ->getBuffer();
205 while (!Rest.empty()) {
206 llvm::StringRef Var;
207 std::tie(Var, Rest) = Rest.split('\0');
208 process_info.GetEnvironment().insert(Var);
209 }
210}
211
213 ProcessInstanceInfo &process_info,
214 ProcessState &State, ::pid_t &tracerpid) {
215 ::pid_t tgid;
216 tracerpid = 0;
217 process_info.Clear();
218
219 process_info.SetProcessID(pid);
220
221 GetExePathAndArch(pid, process_info);
222 GetProcessArgs(pid, process_info);
223 GetProcessEnviron(pid, process_info);
224
225 // Get User and Group IDs and get tracer pid.
226 if (!GetStatusInfo(pid, process_info, State, tracerpid, tgid))
227 return false;
228
229 return true;
230}
231
232uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
233 ProcessInstanceInfoList &process_infos) {
234 static const char procdir[] = "/proc/";
235
236 DIR *dirproc = opendir(procdir);
237 if (dirproc) {
238 struct dirent *direntry = nullptr;
239 const uid_t our_uid = getuid();
240 const lldb::pid_t our_pid = getpid();
241 bool all_users = match_info.GetMatchAllUsers();
242
243 while ((direntry = readdir(dirproc)) != nullptr) {
244 if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name))
245 continue;
246
247 lldb::pid_t pid = atoi(direntry->d_name);
248
249 // Skip this process.
250 if (pid == our_pid)
251 continue;
252
253 ::pid_t tracerpid;
254 ProcessState State;
255 ProcessInstanceInfo process_info;
256
257 if (!GetProcessAndStatInfo(pid, process_info, State, tracerpid))
258 continue;
259
260 // Skip if process is being debugged.
261 if (tracerpid != 0)
262 continue;
263
264 if (State == ProcessState::Zombie)
265 continue;
266
267 // Check for user match if we're not matching all users and not running
268 // as root.
269 if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid))
270 continue;
271
272 if (match_info.Matches(process_info)) {
273 process_infos.push_back(process_info);
274 }
275 }
276
277 closedir(dirproc);
278 }
279
280 return process_infos.size();
281}
282
283bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) {
284 bool tids_changed = false;
285 static const char procdir[] = "/proc/";
286 static const char taskdir[] = "/task/";
287 std::string process_task_dir = procdir + llvm::to_string(pid) + taskdir;
288 DIR *dirproc = opendir(process_task_dir.c_str());
289
290 if (dirproc) {
291 struct dirent *direntry = nullptr;
292 while ((direntry = readdir(dirproc)) != nullptr) {
293 if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name))
294 continue;
295
296 lldb::tid_t tid = atoi(direntry->d_name);
297 TidMap::iterator it = tids_to_attach.find(tid);
298 if (it == tids_to_attach.end()) {
299 tids_to_attach.insert(TidPair(tid, false));
300 tids_changed = true;
301 }
302 }
303 closedir(dirproc);
304 }
305
306 return tids_changed;
307}
308
310 ::pid_t tracerpid;
311 ProcessState State;
312 return GetProcessAndStatInfo(pid, process_info, State, tracerpid);
313}
314
316
318 return Status("unimplemented");
319}
320
321std::optional<lldb::pid_t> lldb_private::getPIDForTID(lldb::pid_t tid) {
322 ::pid_t tracerpid, tgid = LLDB_INVALID_PROCESS_ID;
323 ProcessInstanceInfo process_info;
324 ProcessState state;
325
326 if (!GetStatusInfo(tid, process_info, state, tracerpid, tgid) ||
328 return std::nullopt;
329 return tgid;
330}
#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:170
static ArchSpec GetELFProcessCPUType(llvm::StringRef exe_path)
Definition: linux/Host.cpp:130
static bool GetProcessAndStatInfo(::pid_t pid, ProcessInstanceInfo &process_info, ProcessState &State, ::pid_t &tracerpid)
Definition: linux/Host.cpp:212
static void GetProcessArgs(::pid_t pid, ProcessInstanceInfo &process_info)
Definition: linux/Host.cpp:154
static bool IsDirNumeric(const char *dname)
Definition: linux/Host.cpp:122
static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info)
Definition: linux/Host.cpp:197
static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo, ProcessState &State, ::pid_t &TracerPid, ::pid_t &Tgid)
Definition: linux/Host.cpp:58
#define LLDB_INVALID_PROCESS_ID
Definition: lldb-defines.h:83
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:321
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