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