1 //===-- source/Host/netbsd/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 <dlfcn.h> 12 #include <execinfo.h> 13 #include <stdio.h> 14 #include <sys/proc.h> 15 #include <sys/sysctl.h> 16 #include <sys/types.h> 17 18 #include <limits.h> 19 20 #include <elf.h> 21 #include <kvm.h> 22 #include <sys/exec.h> 23 #include <sys/ptrace.h> 24 25 // C++ Includes 26 // Other libraries and framework includes 27 // Project includes 28 #include "lldb/Core/Module.h" 29 #include "lldb/Host/Host.h" 30 #include "lldb/Host/HostInfo.h" 31 #include "lldb/Target/Platform.h" 32 #include "lldb/Target/Process.h" 33 #include "lldb/Utility/CleanUp.h" 34 #include "lldb/Utility/DataBufferHeap.h" 35 #include "lldb/Utility/DataExtractor.h" 36 #include "lldb/Utility/Endian.h" 37 #include "lldb/Utility/Log.h" 38 #include "lldb/Utility/NameMatches.h" 39 #include "lldb/Utility/Status.h" 40 #include "lldb/Utility/StreamString.h" 41 42 #include "llvm/Support/Host.h" 43 44 extern "C" { 45 extern char **environ; 46 } 47 48 using namespace lldb; 49 using namespace lldb_private; 50 51 size_t Host::GetEnvironment(StringList &env) { 52 char **host_env = environ; 53 char *env_entry; 54 size_t i; 55 for (i = 0; (env_entry = host_env[i]) != NULL; ++i) 56 env.AppendString(env_entry); 57 return i; 58 } 59 60 static bool GetNetBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr, 61 ProcessInstanceInfo &process_info) { 62 if (!process_info.ProcessIDIsValid()) 63 return false; 64 65 int pid = process_info.GetProcessID(); 66 67 int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV}; 68 69 char arg_data[8192]; 70 size_t arg_data_size = sizeof(arg_data); 71 if (::sysctl(mib, 4, arg_data, &arg_data_size, NULL, 0) != 0) 72 return false; 73 74 DataExtractor data(arg_data, arg_data_size, endian::InlHostByteOrder(), 75 sizeof(void *)); 76 lldb::offset_t offset = 0; 77 const char *cstr; 78 79 cstr = data.GetCStr(&offset); 80 if (!cstr) 81 return false; 82 83 process_info.GetExecutableFile().SetFile(cstr, false); 84 85 if (!(match_info_ptr == NULL || 86 NameMatches(process_info.GetExecutableFile().GetFilename().GetCString(), 87 match_info_ptr->GetNameMatchType(), 88 match_info_ptr->GetProcessInfo().GetName()))) 89 return false; 90 91 Args &proc_args = process_info.GetArguments(); 92 while (1) { 93 const uint8_t *p = data.PeekData(offset, 1); 94 while ((p != NULL) && (*p == '\0') && offset < arg_data_size) { 95 ++offset; 96 p = data.PeekData(offset, 1); 97 } 98 if (p == NULL || offset >= arg_data_size) 99 break; 100 101 cstr = data.GetCStr(&offset); 102 if (!cstr) 103 break; 104 105 proc_args.AppendArgument(llvm::StringRef(cstr)); 106 } 107 108 return true; 109 } 110 111 static bool GetNetBSDProcessCPUType(ProcessInstanceInfo &process_info) { 112 if (process_info.ProcessIDIsValid()) { 113 process_info.GetArchitecture() = 114 HostInfo::GetArchitecture(HostInfo::eArchKindDefault); 115 return true; 116 } 117 process_info.GetArchitecture().Clear(); 118 return false; 119 } 120 121 static bool GetNetBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) { 122 ::kvm_t *kdp; 123 char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */ 124 125 struct ::kinfo_proc2 *proc_kinfo; 126 const int pid = process_info.GetProcessID(); 127 int nproc; 128 129 if (!process_info.ProcessIDIsValid()) 130 goto error; 131 132 if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL) 133 goto error; 134 135 if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_PID, pid, 136 sizeof(struct ::kinfo_proc2), &nproc)) == 137 NULL) { 138 ::kvm_close(kdp); 139 goto error; 140 } 141 142 if (nproc < 1) { 143 ::kvm_close(kdp); /* XXX: we don't check for error here */ 144 goto error; 145 } 146 147 process_info.SetParentProcessID(proc_kinfo->p_ppid); 148 process_info.SetUserID(proc_kinfo->p_ruid); 149 process_info.SetGroupID(proc_kinfo->p_rgid); 150 process_info.SetEffectiveUserID(proc_kinfo->p_uid); 151 process_info.SetEffectiveGroupID(proc_kinfo->p_gid); 152 153 ::kvm_close(kdp); /* XXX: we don't check for error here */ 154 155 return true; 156 157 error: 158 process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID); 159 process_info.SetUserID(UINT32_MAX); 160 process_info.SetGroupID(UINT32_MAX); 161 process_info.SetEffectiveUserID(UINT32_MAX); 162 process_info.SetEffectiveGroupID(UINT32_MAX); 163 return false; 164 } 165 166 uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, 167 ProcessInstanceInfoList &process_infos) { 168 const ::pid_t our_pid = ::getpid(); 169 const ::uid_t our_uid = ::getuid(); 170 171 const bool all_users = 172 match_info.GetMatchAllUsers() || 173 // Special case, if lldb is being run as root we can attach to anything 174 (our_uid == 0); 175 176 kvm_t *kdp; 177 char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */ 178 if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL) 179 return 0; 180 181 struct ::kinfo_proc2 *proc_kinfo; 182 int nproc; 183 if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_ALL, 0, 184 sizeof(struct ::kinfo_proc2), &nproc)) == 185 NULL) { 186 ::kvm_close(kdp); 187 return 0; 188 } 189 190 for (int i = 0; i < nproc; i++) { 191 if (proc_kinfo[i].p_pid < 1) 192 continue; /* not valid */ 193 /* Make sure the user is acceptable */ 194 if (!all_users && proc_kinfo[i].p_ruid != our_uid) 195 continue; 196 197 if (proc_kinfo[i].p_pid == our_pid || // Skip this process 198 proc_kinfo[i].p_pid == 0 || // Skip kernel (kernel pid is 0) 199 proc_kinfo[i].p_stat == LSZOMB || // Zombies are bad 200 proc_kinfo[i].p_flag & P_TRACED || // Being debugged? 201 proc_kinfo[i].p_flag & P_WEXIT) // Working on exiting 202 continue; 203 204 // Every thread is a process in NetBSD, but all the threads of a single 205 // process have the same pid. Do not store the process info in the 206 // result list if a process with given identifier is already registered 207 // there. 208 if (proc_kinfo[i].p_nlwps > 1) { 209 bool already_registered = false; 210 for (size_t pi = 0; pi < process_infos.GetSize(); pi++) { 211 if (process_infos.GetProcessIDAtIndex(pi) == proc_kinfo[i].p_pid) { 212 already_registered = true; 213 break; 214 } 215 } 216 217 if (already_registered) 218 continue; 219 } 220 ProcessInstanceInfo process_info; 221 process_info.SetProcessID(proc_kinfo[i].p_pid); 222 process_info.SetParentProcessID(proc_kinfo[i].p_ppid); 223 process_info.SetUserID(proc_kinfo[i].p_ruid); 224 process_info.SetGroupID(proc_kinfo[i].p_rgid); 225 process_info.SetEffectiveUserID(proc_kinfo[i].p_uid); 226 process_info.SetEffectiveGroupID(proc_kinfo[i].p_gid); 227 // Make sure our info matches before we go fetch the name and cpu type 228 if (match_info.Matches(process_info) && 229 GetNetBSDProcessArgs(&match_info, process_info)) { 230 GetNetBSDProcessCPUType(process_info); 231 if (match_info.Matches(process_info)) 232 process_infos.Append(process_info); 233 } 234 } 235 236 kvm_close(kdp); /* XXX: we don't check for error here */ 237 238 return process_infos.GetSize(); 239 } 240 241 bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { 242 process_info.SetProcessID(pid); 243 244 if (GetNetBSDProcessArgs(NULL, process_info)) { 245 GetNetBSDProcessCPUType(process_info); 246 GetNetBSDProcessUserAndGroup(process_info); 247 return true; 248 } 249 250 process_info.Clear(); 251 return false; 252 } 253 254 Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { 255 return Status("unimplemented"); 256 } 257