1//===-- source/Host/freebsd/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/utsname.h> 17#include <sys/sysctl.h> 18#include <sys/proc.h> 19 20#include <sys/ptrace.h> 21#include <sys/exec.h> 22#include <machine/elf.h> 23 24// C++ Includes 25// Other libraries and framework includes 26// Project includes 27#include "lldb/Core/Error.h" 28#include "lldb/Host/Endian.h" 29#include "lldb/Host/Host.h" 30#include "lldb/Core/Module.h" 31#include "lldb/Core/DataExtractor.h" 32#include "lldb/Core/StreamFile.h" 33#include "lldb/Core/StreamString.h" 34#include "lldb/Core/Log.h" 35#include "lldb/Target/Process.h" 36#include "lldb/Target/Platform.h" 37 38#include "lldb/Core/DataBufferHeap.h" 39#include "lldb/Core/DataExtractor.h" 40#include "lldb/Utility/CleanUp.h" 41 42#include "llvm/Support/Host.h" 43 44 45extern "C" { 46 extern char **environ; 47} 48 49using namespace lldb; 50using namespace lldb_private; 51 52class FreeBSDThread 53{ 54public: 55 FreeBSDThread(const char *thread_name) 56 { 57 Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name); 58 } 59 static void PThreadDestructor (void *v) 60 { 61 delete (FreeBSDThread*)v; 62 } 63}; 64 65static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT; 66static pthread_key_t g_thread_create_key = 0; 67 68static void 69InitThreadCreated() 70{ 71 ::pthread_key_create (&g_thread_create_key, FreeBSDThread::PThreadDestructor); 72} 73 74void 75Host::ThreadCreated (const char *thread_name) 76{ 77 ::pthread_once (&g_thread_create_once, InitThreadCreated); 78 if (g_thread_create_key) 79 { 80 ::pthread_setspecific (g_thread_create_key, new FreeBSDThread(thread_name)); 81 } 82 83 Host::SetShortThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name, 16); 84} 85 86std::string 87Host::GetThreadName (lldb::pid_t pid, lldb::tid_t tid) 88{ 89 std::string thread_name; 90 return thread_name; 91} 92 93void 94Host::Backtrace (Stream &strm, uint32_t max_frames) 95{ 96 char backtrace_path[] = "/tmp/lldb-backtrace-tmp-XXXXXX"; 97 int backtrace_fd = ::mkstemp (backtrace_path); 98 if (backtrace_fd != -1) 99 { 100 std::vector<void *> frame_buffer (max_frames, NULL); 101 int count = ::backtrace (&frame_buffer[0], frame_buffer.size()); 102 ::backtrace_symbols_fd (&frame_buffer[0], count, backtrace_fd); 103 104 const off_t buffer_size = ::lseek(backtrace_fd, 0, SEEK_CUR); 105 106 if (::lseek(backtrace_fd, 0, SEEK_SET) == 0) 107 { 108 char *buffer = (char *)::malloc (buffer_size); 109 if (buffer) 110 { 111 ssize_t bytes_read = ::read (backtrace_fd, buffer, buffer_size); 112 if (bytes_read > 0) 113 strm.Write(buffer, bytes_read); 114 ::free (buffer); 115 } 116 } 117 ::close (backtrace_fd); 118 ::unlink (backtrace_path); 119 } 120} 121 122size_t 123Host::GetEnvironment (StringList &env) 124{ 125 char *v; 126 char **var = environ; 127 for (; var != NULL && *var != NULL; ++var) 128 { 129 v = strchr(*var, (int)'-'); 130 if (v == NULL) 131 continue; 132 env.AppendString(v); 133 } 134 return env.GetSize(); 135} 136 137bool 138Host::GetOSVersion(uint32_t &major, 139 uint32_t &minor, 140 uint32_t &update) 141{ 142 struct utsname un; 143 144 ::memset(&un, 0, sizeof(utsname)); 145 if (uname(&un) < 0) 146 return false; 147 148 int status = sscanf(un.release, "%u.%u", &major, &minor); 149 return status == 2; 150} 151 152bool 153Host::GetOSBuildString (std::string &s) 154{ 155 int mib[2] = { CTL_KERN, KERN_OSREV }; 156 char osrev_str[12]; 157 uint32_t osrev = 0; 158 size_t osrev_len = sizeof(osrev); 159 160 if (::sysctl (mib, 2, &osrev, &osrev_len, NULL, 0) == 0) 161 { 162 ::snprintf(osrev_str, sizeof(osrev_str), "%-8.8u", osrev); 163 s.assign (osrev_str); 164 return true; 165 } 166 167 s.clear(); 168 return false; 169} 170 171bool 172Host::GetOSKernelDescription (std::string &s) 173{ 174 struct utsname un; 175 176 ::memset(&un, 0, sizeof(utsname)); 177 s.clear(); 178 179 if (uname(&un) < 0) 180 return false; 181 182 s.assign (un.version); 183 184 return true; 185} 186 187static bool 188GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr, 189 ProcessInstanceInfo &process_info) 190{ 191 if (process_info.ProcessIDIsValid()) 192 { 193 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, (int)process_info.GetProcessID() }; 194 195 char arg_data[8192]; 196 size_t arg_data_size = sizeof(arg_data); 197 if (::sysctl (mib, 4, arg_data, &arg_data_size , NULL, 0) == 0) 198 { 199 DataExtractor data (arg_data, arg_data_size, lldb::endian::InlHostByteOrder(), sizeof(void *)); 200 lldb::offset_t offset = 0; 201 const char *cstr; 202 203 cstr = data.GetCStr (&offset); 204 if (cstr) 205 { 206 process_info.GetExecutableFile().SetFile(cstr, false); 207 208 if (!(match_info_ptr == NULL || 209 NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(), 210 match_info_ptr->GetNameMatchType(), 211 match_info_ptr->GetProcessInfo().GetName()))) 212 return false; 213 214 Args &proc_args = process_info.GetArguments(); 215 while (1) 216 { 217 const uint8_t *p = data.PeekData(offset, 1); 218 while ((p != NULL) && (*p == '\0') && offset < arg_data_size) 219 { 220 ++offset; 221 p = data.PeekData(offset, 1); 222 } 223 if (p == NULL || offset >= arg_data_size) 224 return true; 225 226 cstr = data.GetCStr(&offset); 227 if (cstr) 228 proc_args.AppendArgument(cstr); 229 else 230 return true; 231 } 232 } 233 } 234 } 235 return false; 236} 237 238static bool 239GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info) 240{ 241 if (process_info.ProcessIDIsValid()) 242 { 243 process_info.GetArchitecture() = Host::GetArchitecture (Host::eSystemDefaultArchitecture); 244 return true; 245 } 246 process_info.GetArchitecture().Clear(); 247 return false; 248} 249 250static bool 251GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) 252{ 253 struct kinfo_proc proc_kinfo; 254 size_t proc_kinfo_size; 255 256 if (process_info.ProcessIDIsValid()) 257 { 258 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 259 (int)process_info.GetProcessID() }; 260 proc_kinfo_size = sizeof(struct kinfo_proc); 261 262 if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) 263 { 264 if (proc_kinfo_size > 0) 265 { 266 process_info.SetParentProcessID (proc_kinfo.ki_ppid); 267 process_info.SetUserID (proc_kinfo.ki_ruid); 268 process_info.SetGroupID (proc_kinfo.ki_rgid); 269 process_info.SetEffectiveUserID (proc_kinfo.ki_uid); 270 if (proc_kinfo.ki_ngroups > 0) 271 process_info.SetEffectiveGroupID (proc_kinfo.ki_groups[0]); 272 else 273 process_info.SetEffectiveGroupID (UINT32_MAX); 274 return true; 275 } 276 } 277 } 278 process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID); 279 process_info.SetUserID (UINT32_MAX); 280 process_info.SetGroupID (UINT32_MAX); 281 process_info.SetEffectiveUserID (UINT32_MAX); 282 process_info.SetEffectiveGroupID (UINT32_MAX); 283 return false; 284} 285 286uint32_t 287Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) 288{ 289 std::vector<struct kinfo_proc> kinfos; 290 291 int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL }; 292 293 size_t pid_data_size = 0; 294 if (::sysctl (mib, 3, NULL, &pid_data_size, NULL, 0) != 0) 295 return 0; 296 297 // Add a few extra in case a few more show up 298 const size_t estimated_pid_count = (pid_data_size / sizeof(struct kinfo_proc)) + 10; 299 300 kinfos.resize (estimated_pid_count); 301 pid_data_size = kinfos.size() * sizeof(struct kinfo_proc); 302 303 if (::sysctl (mib, 3, &kinfos[0], &pid_data_size, NULL, 0) != 0) 304 return 0; 305 306 const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc)); 307 308 bool all_users = match_info.GetMatchAllUsers(); 309 const lldb::pid_t our_pid = getpid(); 310 const uid_t our_uid = getuid(); 311 for (int i = 0; i < actual_pid_count; i++) 312 { 313 const struct kinfo_proc &kinfo = kinfos[i]; 314 const bool kinfo_user_matches = (all_users || 315 (kinfo.ki_ruid == our_uid) || 316 // Special case, if lldb is being run as root we can attach to anything. 317 (our_uid == 0) 318 ); 319 320 if (kinfo_user_matches == false || // Make sure the user is acceptable 321 kinfo.ki_pid == our_pid || // Skip this process 322 kinfo.ki_pid == 0 || // Skip kernel (kernel pid is zero) 323 kinfo.ki_stat == SZOMB || // Zombies are bad, they like brains... 324 kinfo.ki_flag & P_TRACED || // Being debugged? 325 kinfo.ki_flag & P_WEXIT) // Working on exiting 326 continue; 327 328 // Every thread is a process in FreeBSD, but all the threads of a single process 329 // have the same pid. Do not store the process info in the result list if a process 330 // with given identifier is already registered there. 331 bool already_registered = false; 332 for (uint32_t pi = 0; 333 !already_registered && 334 (const int)kinfo.ki_numthreads > 1 && 335 pi < (const uint32_t)process_infos.GetSize(); pi++) 336 already_registered = (process_infos.GetProcessIDAtIndex(pi) == (uint32_t)kinfo.ki_pid); 337 338 if (already_registered) 339 continue; 340 341 ProcessInstanceInfo process_info; 342 process_info.SetProcessID (kinfo.ki_pid); 343 process_info.SetParentProcessID (kinfo.ki_ppid); 344 process_info.SetUserID (kinfo.ki_ruid); 345 process_info.SetGroupID (kinfo.ki_rgid); 346 process_info.SetEffectiveUserID (kinfo.ki_svuid); 347 process_info.SetEffectiveGroupID (kinfo.ki_svgid); 348 349 // Make sure our info matches before we go fetch the name and cpu type 350 if (match_info.Matches (process_info) && 351 GetFreeBSDProcessArgs (&match_info, process_info)) 352 { 353 GetFreeBSDProcessCPUType (process_info); 354 if (match_info.Matches (process_info)) 355 process_infos.Append (process_info); 356 } 357 } 358 359 return process_infos.GetSize(); 360} 361 362bool 363Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) 364{ 365 process_info.SetProcessID(pid); 366 367 if (GetFreeBSDProcessArgs(NULL, process_info)) 368 { 369 // should use libprocstat instead of going right into sysctl? 370 GetFreeBSDProcessCPUType(process_info); 371 GetFreeBSDProcessUserAndGroup(process_info); 372 return true; 373 } 374 375 process_info.Clear(); 376 return false; 377} 378 379lldb::DataBufferSP 380Host::GetAuxvData(lldb_private::Process *process) 381{ 382 int mib[2] = { CTL_KERN, KERN_PS_STRINGS }; 383 void *ps_strings_addr, *auxv_addr; 384 size_t ps_strings_size = sizeof(void *); 385 Elf_Auxinfo aux_info[AT_COUNT]; 386 struct ps_strings ps_strings; 387 struct ptrace_io_desc pid; 388 DataBufferSP buf_sp; 389 std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0)); 390 391 if (::sysctl(mib, 2, &ps_strings_addr, &ps_strings_size, NULL, 0) == 0) { 392 pid.piod_op = PIOD_READ_D; 393 pid.piod_addr = &ps_strings; 394 pid.piod_offs = ps_strings_addr; 395 pid.piod_len = sizeof(ps_strings); 396 if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) { 397 perror("failed to fetch ps_strings"); 398 buf_ap.release(); 399 goto done; 400 } 401 402 auxv_addr = ps_strings.ps_envstr + ps_strings.ps_nenvstr + 1; 403 404 pid.piod_addr = aux_info; 405 pid.piod_offs = auxv_addr; 406 pid.piod_len = sizeof(aux_info); 407 if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) { 408 perror("failed to fetch aux_info"); 409 buf_ap.release(); 410 goto done; 411 } 412 memcpy(buf_ap->GetBytes(), aux_info, pid.piod_len); 413 buf_sp.reset(buf_ap.release()); 414 } else { 415 perror("sysctl failed on ps_strings"); 416 } 417 418 done: 419 return buf_sp; 420} 421