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 19 #include <sys/ptrace.h> 20 #include <sys/exec.h> 21 #include <machine/elf.h> 22 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/DataExtractor.h" 31 #include "lldb/Core/StreamFile.h" 32 #include "lldb/Core/StreamString.h" 33 #include "lldb/Target/Process.h" 34 35 #include "lldb/Core/DataBufferHeap.h" 36 #include "lldb/Core/DataExtractor.h" 37 #include "llvm/Support/Host.h" 38 39 40 extern "C" { 41 extern char **environ; 42 } 43 44 using namespace lldb; 45 using namespace lldb_private; 46 47 48 class FreeBSDThread 49 { 50 public: 51 FreeBSDThread(const char *thread_name) 52 { 53 Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name); 54 } 55 static void PThreadDestructor (void *v) 56 { 57 delete (FreeBSDThread*)v; 58 } 59 }; 60 61 static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT; 62 static pthread_key_t g_thread_create_key = 0; 63 64 static void 65 InitThreadCreated() 66 { 67 ::pthread_key_create (&g_thread_create_key, FreeBSDThread::PThreadDestructor); 68 } 69 70 void 71 Host::ThreadCreated (const char *thread_name) 72 { 73 ::pthread_once (&g_thread_create_once, InitThreadCreated); 74 if (g_thread_create_key) 75 { 76 ::pthread_setspecific (g_thread_create_key, new FreeBSDThread(thread_name)); 77 } 78 } 79 80 void 81 Host::Backtrace (Stream &strm, uint32_t max_frames) 82 { 83 char backtrace_path[] = "/tmp/lldb-backtrace-tmp-XXXXXX"; 84 int backtrace_fd = ::mkstemp (backtrace_path); 85 if (backtrace_fd != -1) 86 { 87 std::vector<void *> frame_buffer (max_frames, NULL); 88 int count = ::backtrace (&frame_buffer[0], frame_buffer.size()); 89 ::backtrace_symbols_fd (&frame_buffer[0], count, backtrace_fd); 90 91 const off_t buffer_size = ::lseek(backtrace_fd, 0, SEEK_CUR); 92 93 if (::lseek(backtrace_fd, 0, SEEK_SET) == 0) 94 { 95 char *buffer = (char *)::malloc (buffer_size); 96 if (buffer) 97 { 98 ssize_t bytes_read = ::read (backtrace_fd, buffer, buffer_size); 99 if (bytes_read > 0) 100 strm.Write(buffer, bytes_read); 101 ::free (buffer); 102 } 103 } 104 ::close (backtrace_fd); 105 ::unlink (backtrace_path); 106 } 107 } 108 109 size_t 110 Host::GetEnvironment (StringList &env) 111 { 112 char *v; 113 char **var = environ; 114 for (; var != NULL && *var != NULL; ++var) { 115 v = strchr(*var, (int)'-'); 116 if (v == NULL) 117 continue; 118 env.AppendString(v); 119 } 120 return env.GetSize(); 121 } 122 123 bool 124 Host::GetOSVersion(uint32_t &major, 125 uint32_t &minor, 126 uint32_t &update) 127 { 128 struct utsname un; 129 int status; 130 131 if (uname(&un) < 0) 132 return false; 133 134 status = sscanf(un.release, "%u.%u-%u", &major, &minor, &update); 135 return status == 3; 136 } 137 138 Error 139 Host::LaunchProcess (ProcessLaunchInfo &launch_info) 140 { 141 Error error; 142 assert(!"Not implemented yet!!!"); 143 return error; 144 } 145 146 bool 147 Host::GetOSBuildString (std::string &s) 148 { 149 int mib[2] = { CTL_KERN, KERN_OSREV }; 150 char cstr[PATH_MAX]; 151 size_t cstr_len = sizeof(cstr); 152 if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0) 153 { 154 s.assign (cstr, cstr_len); 155 return true; 156 } 157 s.clear(); 158 return false; 159 } 160 161 bool 162 Host::GetOSKernelDescription (std::string &s) 163 { 164 int mib[2] = { CTL_KERN, KERN_VERSION }; 165 char cstr[PATH_MAX]; 166 size_t cstr_len = sizeof(cstr); 167 if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0) 168 { 169 s.assign (cstr, cstr_len); 170 return true; 171 } 172 s.clear(); 173 return false; 174 } 175 176 static bool 177 GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr, 178 ProcessInstanceInfo &process_info) 179 { 180 if (process_info.ProcessIDIsValid()) { 181 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, (int)process_info.GetProcessID() }; 182 183 char arg_data[8192]; 184 size_t arg_data_size = sizeof(arg_data); 185 if (::sysctl (mib, 4, arg_data, &arg_data_size , NULL, 0) == 0) 186 { 187 DataExtractor data (arg_data, arg_data_size, lldb::endian::InlHostByteOrder(), sizeof(void *)); 188 lldb::offset_t offset = 0; 189 const char *cstr; 190 191 cstr = data.GetCStr (&offset); 192 if (cstr) 193 { 194 process_info.GetExecutableFile().SetFile(cstr, false); 195 196 if (!(match_info_ptr == NULL || 197 NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(), 198 match_info_ptr->GetNameMatchType(), 199 match_info_ptr->GetProcessInfo().GetName()))) 200 return false; 201 202 Args &proc_args = process_info.GetArguments(); 203 while (1) 204 { 205 const uint8_t *p = data.PeekData(offset, 1); 206 while ((p != NULL) && (*p == '\0') && offset < arg_data_size) 207 { 208 ++offset; 209 p = data.PeekData(offset, 1); 210 } 211 if (p == NULL || offset >= arg_data_size) 212 return true; 213 214 cstr = data.GetCStr(&offset); 215 if (cstr) 216 proc_args.AppendArgument(cstr); 217 else 218 return true; 219 } 220 } 221 } 222 } 223 return false; 224 } 225 226 static bool 227 GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info) 228 { 229 if (process_info.ProcessIDIsValid()) { 230 process_info.GetArchitecture() = Host::GetArchitecture (Host::eSystemDefaultArchitecture); 231 return true; 232 } 233 process_info.GetArchitecture().Clear(); 234 return false; 235 } 236 237 static bool 238 GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) 239 { 240 struct kinfo_proc proc_kinfo; 241 size_t proc_kinfo_size; 242 243 if (process_info.ProcessIDIsValid()) 244 { 245 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 246 (int)process_info.GetProcessID() }; 247 proc_kinfo_size = sizeof(struct kinfo_proc); 248 249 if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) 250 { 251 if (proc_kinfo_size > 0) 252 { 253 process_info.SetParentProcessID (proc_kinfo.ki_ppid); 254 process_info.SetUserID (proc_kinfo.ki_ruid); 255 process_info.SetGroupID (proc_kinfo.ki_rgid); 256 process_info.SetEffectiveUserID (proc_kinfo.ki_uid); 257 if (proc_kinfo.ki_ngroups > 0) 258 process_info.SetEffectiveGroupID (proc_kinfo.ki_groups[0]); 259 else 260 process_info.SetEffectiveGroupID (UINT32_MAX); 261 return true; 262 } 263 } 264 } 265 process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID); 266 process_info.SetUserID (UINT32_MAX); 267 process_info.SetGroupID (UINT32_MAX); 268 process_info.SetEffectiveUserID (UINT32_MAX); 269 process_info.SetEffectiveGroupID (UINT32_MAX); 270 return false; 271 } 272 273 bool 274 Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) 275 { 276 process_info.SetProcessID(pid); 277 if (GetFreeBSDProcessArgs(NULL, process_info)) { 278 // should use libprocstat instead of going right into sysctl? 279 GetFreeBSDProcessCPUType(process_info); 280 GetFreeBSDProcessUserAndGroup(process_info); 281 return true; 282 } 283 process_info.Clear(); 284 return false; 285 } 286 287 lldb::DataBufferSP 288 Host::GetAuxvData(lldb_private::Process *process) 289 { 290 int mib[2] = { CTL_KERN, KERN_PS_STRINGS }; 291 void *ps_strings_addr, *auxv_addr; 292 size_t ps_strings_size = sizeof(void *); 293 Elf_Auxinfo aux_info[AT_COUNT]; 294 struct ps_strings ps_strings; 295 struct ptrace_io_desc pid; 296 DataBufferSP buf_sp; 297 std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0)); 298 299 if (::sysctl(mib, 2, &ps_strings_addr, &ps_strings_size, NULL, 0) == 0) { 300 pid.piod_op = PIOD_READ_D; 301 pid.piod_addr = &ps_strings; 302 pid.piod_offs = ps_strings_addr; 303 pid.piod_len = sizeof(ps_strings); 304 if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) { 305 perror("failed to fetch ps_strings"); 306 buf_ap.release(); 307 goto done; 308 } 309 310 auxv_addr = ps_strings.ps_envstr + ps_strings.ps_nenvstr + 1; 311 312 pid.piod_addr = aux_info; 313 pid.piod_offs = auxv_addr; 314 pid.piod_len = sizeof(aux_info); 315 if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) { 316 perror("failed to fetch aux_info"); 317 buf_ap.release(); 318 goto done; 319 } 320 memcpy(buf_ap->GetBytes(), aux_info, pid.piod_len); 321 buf_sp.reset(buf_ap.release()); 322 } else { 323 perror("sysctl failed on ps_strings"); 324 } 325 326 done: 327 return buf_sp; 328 } 329