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