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