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