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