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/Object/ELF.h" 24 #include "llvm/Support/ScopedPrinter.h" 25 26 // Project includes 27 #include "lldb/Target/Process.h" 28 #include "lldb/Utility/Log.h" 29 #include "lldb/Utility/Status.h" 30 31 #include "lldb/Host/Host.h" 32 #include "lldb/Host/HostInfo.h" 33 #include "lldb/Host/linux/Support.h" 34 #include "lldb/Utility/DataBufferLLVM.h" 35 #include "lldb/Utility/DataExtractor.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 ArchSpec GetELFProcessCPUType(llvm::StringRef exe_path) { 126 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 127 128 auto buffer_sp = DataBufferLLVM::CreateSliceFromPath(exe_path, 0x20, 0); 129 if (!buffer_sp) 130 return ArchSpec(); 131 132 uint8_t exe_class = 133 llvm::object::getElfArchType( 134 {buffer_sp->GetChars(), size_t(buffer_sp->GetByteSize())}) 135 .first; 136 137 switch (exe_class) { 138 case llvm::ELF::ELFCLASS32: 139 return HostInfo::GetArchitecture(HostInfo::eArchKind32); 140 case llvm::ELF::ELFCLASS64: 141 return HostInfo::GetArchitecture(HostInfo::eArchKind64); 142 default: 143 LLDB_LOG(log, "Unknown elf class ({0}) in file {1}", exe_class, exe_path); 144 return ArchSpec(); 145 } 146 } 147 148 static bool GetProcessAndStatInfo(::pid_t pid, 149 ProcessInstanceInfo &process_info, 150 ProcessState &State, ::pid_t &tracerpid) { 151 tracerpid = 0; 152 process_info.Clear(); 153 154 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); 155 156 // We can't use getProcFile here because proc/[pid]/exe is a symbolic link. 157 llvm::SmallString<64> ProcExe; 158 (llvm::Twine("/proc/") + llvm::Twine(pid) + "/exe").toVector(ProcExe); 159 std::string ExePath(PATH_MAX, '\0'); 160 161 ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX); 162 if (len <= 0) { 163 LLDB_LOG(log, "failed to read link exe link for {0}: {1}", pid, 164 Status(errno, eErrorTypePOSIX)); 165 return false; 166 } 167 ExePath.resize(len); 168 169 // If the binary has been deleted, the link name has " (deleted)" appended. 170 // Remove if there. 171 llvm::StringRef PathRef = ExePath; 172 PathRef.consume_back(" (deleted)"); 173 174 process_info.SetArchitecture(GetELFProcessCPUType(PathRef)); 175 176 // Get the process environment. 177 auto BufferOrError = getProcFile(pid, "environ"); 178 if (!BufferOrError) 179 return false; 180 std::unique_ptr<llvm::MemoryBuffer> Environ = std::move(*BufferOrError); 181 182 // Get the command line used to start the process. 183 BufferOrError = getProcFile(pid, "cmdline"); 184 if (!BufferOrError) 185 return false; 186 std::unique_ptr<llvm::MemoryBuffer> Cmdline = std::move(*BufferOrError); 187 188 // Get User and Group IDs and get tracer pid. 189 if (!GetStatusInfo(pid, process_info, State, tracerpid)) 190 return false; 191 192 process_info.SetProcessID(pid); 193 process_info.GetExecutableFile().SetFile(PathRef, false, 194 FileSpec::Style::native); 195 196 llvm::StringRef Rest = Environ->getBuffer(); 197 while (!Rest.empty()) { 198 llvm::StringRef Var; 199 std::tie(Var, Rest) = Rest.split('\0'); 200 process_info.GetEnvironment().insert(Var); 201 } 202 203 llvm::StringRef Arg0; 204 std::tie(Arg0, Rest) = Cmdline->getBuffer().split('\0'); 205 process_info.SetArg0(Arg0); 206 while (!Rest.empty()) { 207 llvm::StringRef Arg; 208 std::tie(Arg, Rest) = Rest.split('\0'); 209 process_info.GetArguments().AppendArgument(Arg); 210 } 211 212 return true; 213 } 214 215 uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, 216 ProcessInstanceInfoList &process_infos) { 217 static const char procdir[] = "/proc/"; 218 219 DIR *dirproc = opendir(procdir); 220 if (dirproc) { 221 struct dirent *direntry = NULL; 222 const uid_t our_uid = getuid(); 223 const lldb::pid_t our_pid = getpid(); 224 bool all_users = match_info.GetMatchAllUsers(); 225 226 while ((direntry = readdir(dirproc)) != NULL) { 227 if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name)) 228 continue; 229 230 lldb::pid_t pid = atoi(direntry->d_name); 231 232 // Skip this process. 233 if (pid == our_pid) 234 continue; 235 236 ::pid_t tracerpid; 237 ProcessState State; 238 ProcessInstanceInfo process_info; 239 240 if (!GetProcessAndStatInfo(pid, process_info, State, tracerpid)) 241 continue; 242 243 // Skip if process is being debugged. 244 if (tracerpid != 0) 245 continue; 246 247 if (State == ProcessState::Zombie) 248 continue; 249 250 // Check for user match if we're not matching all users and not running 251 // as root. 252 if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid)) 253 continue; 254 255 if (match_info.Matches(process_info)) { 256 process_infos.Append(process_info); 257 } 258 } 259 260 closedir(dirproc); 261 } 262 263 return process_infos.GetSize(); 264 } 265 266 bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) { 267 bool tids_changed = false; 268 static const char procdir[] = "/proc/"; 269 static const char taskdir[] = "/task/"; 270 std::string process_task_dir = procdir + llvm::to_string(pid) + taskdir; 271 DIR *dirproc = opendir(process_task_dir.c_str()); 272 273 if (dirproc) { 274 struct dirent *direntry = NULL; 275 while ((direntry = readdir(dirproc)) != NULL) { 276 if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name)) 277 continue; 278 279 lldb::tid_t tid = atoi(direntry->d_name); 280 TidMap::iterator it = tids_to_attach.find(tid); 281 if (it == tids_to_attach.end()) { 282 tids_to_attach.insert(TidPair(tid, false)); 283 tids_changed = true; 284 } 285 } 286 closedir(dirproc); 287 } 288 289 return tids_changed; 290 } 291 292 bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { 293 ::pid_t tracerpid; 294 ProcessState State; 295 return GetProcessAndStatInfo(pid, process_info, State, tracerpid); 296 } 297 298 Environment Host::GetEnvironment() { return Environment(environ); } 299 300 Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { 301 return Status("unimplemented"); 302 } 303