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