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