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