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 24 #include "lldb/Utility/LLDBLog.h" 25 #include "lldb/Utility/Log.h" 26 #include "lldb/Utility/ProcessInfo.h" 27 #include "lldb/Utility/Status.h" 28 29 #include "lldb/Host/FileSystem.h" 30 #include "lldb/Host/Host.h" 31 #include "lldb/Host/HostInfo.h" 32 #include "lldb/Host/linux/Host.h" 33 #include "lldb/Host/linux/Support.h" 34 #include "lldb/Utility/DataExtractor.h" 35 36 using namespace lldb; 37 using namespace lldb_private; 38 39 namespace { 40 enum 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 54 namespace lldb_private { 55 class ProcessLaunchInfo; 56 } 57 58 static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo, 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 80 ProcessInfo.SetGroupID(RGid); 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 90 ProcessInfo.SetUserID(RUid); 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 122 static bool IsDirNumeric(const char *dname) { 123 for (; *dname; dname++) { 124 if (!isdigit(*dname)) 125 return false; 126 } 127 return true; 128 } 129 130 static 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 154 static 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 170 static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) { 171 Log *log = GetLog(LLDBLog::Process); 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 197 static 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 212 static bool GetProcessAndStatInfo(::pid_t pid, 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 232 uint32_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 283 bool 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 309 bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { 310 ::pid_t tracerpid; 311 ProcessState State; 312 return GetProcessAndStatInfo(pid, process_info, State, tracerpid); 313 } 314 315 Environment Host::GetEnvironment() { return Environment(environ); } 316 317 Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { 318 return Status("unimplemented"); 319 } 320 321 std::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) || 327 tgid == LLDB_INVALID_PROCESS_ID) 328 return std::nullopt; 329 return tgid; 330 } 331