xref: /openbsd-src/gnu/llvm/lldb/source/Host/linux/Host.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- source/Host/linux/Host.cpp ----------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9be691f3bSpatrick #include <cerrno>
10be691f3bSpatrick #include <cstdio>
11be691f3bSpatrick #include <cstring>
12061da546Spatrick #include <dirent.h>
13061da546Spatrick #include <fcntl.h>
14*f6aab3d8Srobert #include <optional>
15061da546Spatrick #include <sys/stat.h>
16061da546Spatrick #include <sys/types.h>
17061da546Spatrick #include <sys/utsname.h>
18061da546Spatrick #include <unistd.h>
19061da546Spatrick 
20be691f3bSpatrick #include "llvm/ADT/StringSwitch.h"
21061da546Spatrick #include "llvm/Object/ELF.h"
22061da546Spatrick #include "llvm/Support/ScopedPrinter.h"
23061da546Spatrick 
24*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
25061da546Spatrick #include "lldb/Utility/Log.h"
26061da546Spatrick #include "lldb/Utility/ProcessInfo.h"
27061da546Spatrick #include "lldb/Utility/Status.h"
28061da546Spatrick 
29061da546Spatrick #include "lldb/Host/FileSystem.h"
30061da546Spatrick #include "lldb/Host/Host.h"
31061da546Spatrick #include "lldb/Host/HostInfo.h"
32be691f3bSpatrick #include "lldb/Host/linux/Host.h"
33061da546Spatrick #include "lldb/Host/linux/Support.h"
34061da546Spatrick #include "lldb/Utility/DataExtractor.h"
35061da546Spatrick 
36061da546Spatrick using namespace lldb;
37061da546Spatrick using namespace lldb_private;
38061da546Spatrick 
39061da546Spatrick namespace {
40061da546Spatrick enum class ProcessState {
41061da546Spatrick   Unknown,
42be691f3bSpatrick   Dead,
43061da546Spatrick   DiskSleep,
44be691f3bSpatrick   Idle,
45061da546Spatrick   Paging,
46be691f3bSpatrick   Parked,
47061da546Spatrick   Running,
48061da546Spatrick   Sleeping,
49061da546Spatrick   TracedOrStopped,
50061da546Spatrick   Zombie,
51061da546Spatrick };
52061da546Spatrick }
53061da546Spatrick 
54061da546Spatrick namespace lldb_private {
55061da546Spatrick class ProcessLaunchInfo;
56061da546Spatrick }
57061da546Spatrick 
GetStatusInfo(::pid_t Pid,ProcessInstanceInfo & ProcessInfo,ProcessState & State,::pid_t & TracerPid,::pid_t & Tgid)58061da546Spatrick static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
59be691f3bSpatrick                           ProcessState &State, ::pid_t &TracerPid,
60be691f3bSpatrick                           ::pid_t &Tgid) {
61*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Host);
62be691f3bSpatrick 
63061da546Spatrick   auto BufferOrError = getProcFile(Pid, "status");
64061da546Spatrick   if (!BufferOrError)
65061da546Spatrick     return false;
66061da546Spatrick 
67061da546Spatrick   llvm::StringRef Rest = BufferOrError.get()->getBuffer();
68061da546Spatrick   while (!Rest.empty()) {
69061da546Spatrick     llvm::StringRef Line;
70061da546Spatrick     std::tie(Line, Rest) = Rest.split('\n');
71061da546Spatrick 
72061da546Spatrick     if (Line.consume_front("Gid:")) {
73061da546Spatrick       // Real, effective, saved set, and file system GIDs. Read the first two.
74061da546Spatrick       Line = Line.ltrim();
75061da546Spatrick       uint32_t RGid, EGid;
76061da546Spatrick       Line.consumeInteger(10, RGid);
77061da546Spatrick       Line = Line.ltrim();
78061da546Spatrick       Line.consumeInteger(10, EGid);
79061da546Spatrick 
80061da546Spatrick       ProcessInfo.SetGroupID(RGid);
81061da546Spatrick       ProcessInfo.SetEffectiveGroupID(EGid);
82061da546Spatrick     } else if (Line.consume_front("Uid:")) {
83061da546Spatrick       // Real, effective, saved set, and file system UIDs. Read the first two.
84061da546Spatrick       Line = Line.ltrim();
85061da546Spatrick       uint32_t RUid, EUid;
86061da546Spatrick       Line.consumeInteger(10, RUid);
87061da546Spatrick       Line = Line.ltrim();
88061da546Spatrick       Line.consumeInteger(10, EUid);
89061da546Spatrick 
90061da546Spatrick       ProcessInfo.SetUserID(RUid);
91061da546Spatrick       ProcessInfo.SetEffectiveUserID(EUid);
92061da546Spatrick     } else if (Line.consume_front("PPid:")) {
93061da546Spatrick       ::pid_t PPid;
94061da546Spatrick       Line.ltrim().consumeInteger(10, PPid);
95061da546Spatrick       ProcessInfo.SetParentProcessID(PPid);
96061da546Spatrick     } else if (Line.consume_front("State:")) {
97be691f3bSpatrick       State = llvm::StringSwitch<ProcessState>(Line.ltrim().take_front(1))
98be691f3bSpatrick                   .Case("D", ProcessState::DiskSleep)
99be691f3bSpatrick                   .Case("I", ProcessState::Idle)
100be691f3bSpatrick                   .Case("R", ProcessState::Running)
101be691f3bSpatrick                   .Case("S", ProcessState::Sleeping)
102be691f3bSpatrick                   .CaseLower("T", ProcessState::TracedOrStopped)
103be691f3bSpatrick                   .Case("W", ProcessState::Paging)
104be691f3bSpatrick                   .Case("P", ProcessState::Parked)
105be691f3bSpatrick                   .Case("X", ProcessState::Dead)
106be691f3bSpatrick                   .Case("Z", ProcessState::Zombie)
107be691f3bSpatrick                   .Default(ProcessState::Unknown);
108be691f3bSpatrick       if (State == ProcessState::Unknown) {
109be691f3bSpatrick         LLDB_LOG(log, "Unknown process state {0}", Line);
110061da546Spatrick       }
111061da546Spatrick     } else if (Line.consume_front("TracerPid:")) {
112061da546Spatrick       Line = Line.ltrim();
113061da546Spatrick       Line.consumeInteger(10, TracerPid);
114be691f3bSpatrick     } else if (Line.consume_front("Tgid:")) {
115be691f3bSpatrick       Line = Line.ltrim();
116be691f3bSpatrick       Line.consumeInteger(10, Tgid);
117061da546Spatrick     }
118061da546Spatrick   }
119061da546Spatrick   return true;
120061da546Spatrick }
121061da546Spatrick 
IsDirNumeric(const char * dname)122061da546Spatrick static bool IsDirNumeric(const char *dname) {
123061da546Spatrick   for (; *dname; dname++) {
124061da546Spatrick     if (!isdigit(*dname))
125061da546Spatrick       return false;
126061da546Spatrick   }
127061da546Spatrick   return true;
128061da546Spatrick }
129061da546Spatrick 
GetELFProcessCPUType(llvm::StringRef exe_path)130061da546Spatrick static ArchSpec GetELFProcessCPUType(llvm::StringRef exe_path) {
131*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Host);
132061da546Spatrick 
133061da546Spatrick   auto buffer_sp = FileSystem::Instance().CreateDataBuffer(exe_path, 0x20, 0);
134061da546Spatrick   if (!buffer_sp)
135061da546Spatrick     return ArchSpec();
136061da546Spatrick 
137061da546Spatrick   uint8_t exe_class =
138061da546Spatrick       llvm::object::getElfArchType(
139*f6aab3d8Srobert           {reinterpret_cast<const char *>(buffer_sp->GetBytes()),
140*f6aab3d8Srobert            size_t(buffer_sp->GetByteSize())})
141061da546Spatrick           .first;
142061da546Spatrick 
143061da546Spatrick   switch (exe_class) {
144061da546Spatrick   case llvm::ELF::ELFCLASS32:
145061da546Spatrick     return HostInfo::GetArchitecture(HostInfo::eArchKind32);
146061da546Spatrick   case llvm::ELF::ELFCLASS64:
147061da546Spatrick     return HostInfo::GetArchitecture(HostInfo::eArchKind64);
148061da546Spatrick   default:
149061da546Spatrick     LLDB_LOG(log, "Unknown elf class ({0}) in file {1}", exe_class, exe_path);
150061da546Spatrick     return ArchSpec();
151061da546Spatrick   }
152061da546Spatrick }
153061da546Spatrick 
GetProcessArgs(::pid_t pid,ProcessInstanceInfo & process_info)154061da546Spatrick static void GetProcessArgs(::pid_t pid, ProcessInstanceInfo &process_info) {
155061da546Spatrick   auto BufferOrError = getProcFile(pid, "cmdline");
156061da546Spatrick   if (!BufferOrError)
157061da546Spatrick     return;
158061da546Spatrick   std::unique_ptr<llvm::MemoryBuffer> Cmdline = std::move(*BufferOrError);
159061da546Spatrick 
160061da546Spatrick   llvm::StringRef Arg0, Rest;
161061da546Spatrick   std::tie(Arg0, Rest) = Cmdline->getBuffer().split('\0');
162061da546Spatrick   process_info.SetArg0(Arg0);
163061da546Spatrick   while (!Rest.empty()) {
164061da546Spatrick     llvm::StringRef Arg;
165061da546Spatrick     std::tie(Arg, Rest) = Rest.split('\0');
166061da546Spatrick     process_info.GetArguments().AppendArgument(Arg);
167061da546Spatrick   }
168061da546Spatrick }
169061da546Spatrick 
GetExePathAndArch(::pid_t pid,ProcessInstanceInfo & process_info)170061da546Spatrick static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) {
171*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Process);
172061da546Spatrick   std::string ExePath(PATH_MAX, '\0');
173061da546Spatrick 
174061da546Spatrick   // We can't use getProcFile here because proc/[pid]/exe is a symbolic link.
175061da546Spatrick   llvm::SmallString<64> ProcExe;
176061da546Spatrick   (llvm::Twine("/proc/") + llvm::Twine(pid) + "/exe").toVector(ProcExe);
177061da546Spatrick 
178061da546Spatrick   ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX);
179061da546Spatrick   if (len > 0) {
180061da546Spatrick     ExePath.resize(len);
181061da546Spatrick   } else {
182061da546Spatrick     LLDB_LOG(log, "failed to read link exe link for {0}: {1}", pid,
183061da546Spatrick              Status(errno, eErrorTypePOSIX));
184061da546Spatrick     ExePath.resize(0);
185061da546Spatrick   }
186061da546Spatrick   // If the binary has been deleted, the link name has " (deleted)" appended.
187061da546Spatrick   // Remove if there.
188061da546Spatrick   llvm::StringRef PathRef = ExePath;
189061da546Spatrick   PathRef.consume_back(" (deleted)");
190061da546Spatrick 
191061da546Spatrick   if (!PathRef.empty()) {
192061da546Spatrick     process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native);
193061da546Spatrick     process_info.SetArchitecture(GetELFProcessCPUType(PathRef));
194061da546Spatrick   }
195061da546Spatrick }
196061da546Spatrick 
GetProcessEnviron(::pid_t pid,ProcessInstanceInfo & process_info)197061da546Spatrick static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info) {
198061da546Spatrick   // Get the process environment.
199061da546Spatrick   auto BufferOrError = getProcFile(pid, "environ");
200061da546Spatrick   if (!BufferOrError)
201061da546Spatrick     return;
202061da546Spatrick 
203061da546Spatrick   std::unique_ptr<llvm::MemoryBuffer> Environ = std::move(*BufferOrError);
204061da546Spatrick   llvm::StringRef Rest = Environ->getBuffer();
205061da546Spatrick   while (!Rest.empty()) {
206061da546Spatrick     llvm::StringRef Var;
207061da546Spatrick     std::tie(Var, Rest) = Rest.split('\0');
208061da546Spatrick     process_info.GetEnvironment().insert(Var);
209061da546Spatrick   }
210061da546Spatrick }
211061da546Spatrick 
GetProcessAndStatInfo(::pid_t pid,ProcessInstanceInfo & process_info,ProcessState & State,::pid_t & tracerpid)212061da546Spatrick static bool GetProcessAndStatInfo(::pid_t pid,
213061da546Spatrick                                   ProcessInstanceInfo &process_info,
214061da546Spatrick                                   ProcessState &State, ::pid_t &tracerpid) {
215be691f3bSpatrick   ::pid_t tgid;
216061da546Spatrick   tracerpid = 0;
217061da546Spatrick   process_info.Clear();
218061da546Spatrick 
219061da546Spatrick   process_info.SetProcessID(pid);
220061da546Spatrick 
221061da546Spatrick   GetExePathAndArch(pid, process_info);
222061da546Spatrick   GetProcessArgs(pid, process_info);
223061da546Spatrick   GetProcessEnviron(pid, process_info);
224061da546Spatrick 
225061da546Spatrick   // Get User and Group IDs and get tracer pid.
226be691f3bSpatrick   if (!GetStatusInfo(pid, process_info, State, tracerpid, tgid))
227061da546Spatrick     return false;
228061da546Spatrick 
229061da546Spatrick   return true;
230061da546Spatrick }
231061da546Spatrick 
FindProcessesImpl(const ProcessInstanceInfoMatch & match_info,ProcessInstanceInfoList & process_infos)232dda28197Spatrick uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
233061da546Spatrick                                  ProcessInstanceInfoList &process_infos) {
234061da546Spatrick   static const char procdir[] = "/proc/";
235061da546Spatrick 
236061da546Spatrick   DIR *dirproc = opendir(procdir);
237061da546Spatrick   if (dirproc) {
238061da546Spatrick     struct dirent *direntry = nullptr;
239061da546Spatrick     const uid_t our_uid = getuid();
240061da546Spatrick     const lldb::pid_t our_pid = getpid();
241061da546Spatrick     bool all_users = match_info.GetMatchAllUsers();
242061da546Spatrick 
243061da546Spatrick     while ((direntry = readdir(dirproc)) != nullptr) {
244061da546Spatrick       if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name))
245061da546Spatrick         continue;
246061da546Spatrick 
247061da546Spatrick       lldb::pid_t pid = atoi(direntry->d_name);
248061da546Spatrick 
249061da546Spatrick       // Skip this process.
250061da546Spatrick       if (pid == our_pid)
251061da546Spatrick         continue;
252061da546Spatrick 
253061da546Spatrick       ::pid_t tracerpid;
254061da546Spatrick       ProcessState State;
255061da546Spatrick       ProcessInstanceInfo process_info;
256061da546Spatrick 
257061da546Spatrick       if (!GetProcessAndStatInfo(pid, process_info, State, tracerpid))
258061da546Spatrick         continue;
259061da546Spatrick 
260061da546Spatrick       // Skip if process is being debugged.
261061da546Spatrick       if (tracerpid != 0)
262061da546Spatrick         continue;
263061da546Spatrick 
264061da546Spatrick       if (State == ProcessState::Zombie)
265061da546Spatrick         continue;
266061da546Spatrick 
267061da546Spatrick       // Check for user match if we're not matching all users and not running
268061da546Spatrick       // as root.
269061da546Spatrick       if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid))
270061da546Spatrick         continue;
271061da546Spatrick 
272061da546Spatrick       if (match_info.Matches(process_info)) {
273dda28197Spatrick         process_infos.push_back(process_info);
274061da546Spatrick       }
275061da546Spatrick     }
276061da546Spatrick 
277061da546Spatrick     closedir(dirproc);
278061da546Spatrick   }
279061da546Spatrick 
280dda28197Spatrick   return process_infos.size();
281061da546Spatrick }
282061da546Spatrick 
FindProcessThreads(const lldb::pid_t pid,TidMap & tids_to_attach)283061da546Spatrick bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) {
284061da546Spatrick   bool tids_changed = false;
285061da546Spatrick   static const char procdir[] = "/proc/";
286061da546Spatrick   static const char taskdir[] = "/task/";
287061da546Spatrick   std::string process_task_dir = procdir + llvm::to_string(pid) + taskdir;
288061da546Spatrick   DIR *dirproc = opendir(process_task_dir.c_str());
289061da546Spatrick 
290061da546Spatrick   if (dirproc) {
291061da546Spatrick     struct dirent *direntry = nullptr;
292061da546Spatrick     while ((direntry = readdir(dirproc)) != nullptr) {
293061da546Spatrick       if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name))
294061da546Spatrick         continue;
295061da546Spatrick 
296061da546Spatrick       lldb::tid_t tid = atoi(direntry->d_name);
297061da546Spatrick       TidMap::iterator it = tids_to_attach.find(tid);
298061da546Spatrick       if (it == tids_to_attach.end()) {
299061da546Spatrick         tids_to_attach.insert(TidPair(tid, false));
300061da546Spatrick         tids_changed = true;
301061da546Spatrick       }
302061da546Spatrick     }
303061da546Spatrick     closedir(dirproc);
304061da546Spatrick   }
305061da546Spatrick 
306061da546Spatrick   return tids_changed;
307061da546Spatrick }
308061da546Spatrick 
GetProcessInfo(lldb::pid_t pid,ProcessInstanceInfo & process_info)309061da546Spatrick bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
310061da546Spatrick   ::pid_t tracerpid;
311061da546Spatrick   ProcessState State;
312061da546Spatrick   return GetProcessAndStatInfo(pid, process_info, State, tracerpid);
313061da546Spatrick }
314061da546Spatrick 
GetEnvironment()315061da546Spatrick Environment Host::GetEnvironment() { return Environment(environ); }
316061da546Spatrick 
ShellExpandArguments(ProcessLaunchInfo & launch_info)317061da546Spatrick Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
318061da546Spatrick   return Status("unimplemented");
319061da546Spatrick }
320be691f3bSpatrick 
getPIDForTID(lldb::pid_t tid)321*f6aab3d8Srobert std::optional<lldb::pid_t> lldb_private::getPIDForTID(lldb::pid_t tid) {
322be691f3bSpatrick   ::pid_t tracerpid, tgid = LLDB_INVALID_PROCESS_ID;
323be691f3bSpatrick   ProcessInstanceInfo process_info;
324be691f3bSpatrick   ProcessState state;
325be691f3bSpatrick 
326be691f3bSpatrick   if (!GetStatusInfo(tid, process_info, state, tracerpid, tgid) ||
327be691f3bSpatrick       tgid == LLDB_INVALID_PROCESS_ID)
328*f6aab3d8Srobert     return std::nullopt;
329be691f3bSpatrick   return tgid;
330be691f3bSpatrick }
331