Host.cpp revision 296417
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 48extern "C" { 49 extern char **environ; 50} 51 52using namespace lldb; 53using namespace lldb_private; 54 55size_t 56Host::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 70static bool 71GetNetBSDProcessArgs (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 124static bool 125GetNetBSDProcessCPUType (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 136static bool 137GetNetBSDProcessUserAndGroup(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 174error: 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 183uint32_t 184Host::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 261bool 262Host::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 277lldb::DataBufferSP 278Host::GetAuxvData(lldb_private::Process *process) 279{ 280 return lldb::DataBufferSP(); 281} 282 283Error 284Host::ShellExpandArguments (ProcessLaunchInfo &launch_info) 285{ 286 return Error("unimplemented"); 287} 288