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