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