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 <execinfo.h> 13 #include <sys/types.h> 14 #include <sys/user.h> 15 #include <sys/utsname.h> 16 #include <sys/sysctl.h> 17 18 // C++ Includes 19 // Other libraries and framework includes 20 // Project includes 21 #include "lldb/Core/Error.h" 22 #include "lldb/Host/Endian.h" 23 #include "lldb/Host/Host.h" 24 #include "lldb/Core/DataExtractor.h" 25 #include "lldb/Core/StreamFile.h" 26 #include "lldb/Core/StreamString.h" 27 #include "lldb/Target/Process.h" 28 29 #include "llvm/Support/Host.h" 30 31 extern "C" { 32 char **environ; 33 } 34 35 using namespace lldb; 36 using namespace lldb_private; 37 38 class FreeBSDThread 39 { 40 public: 41 FreeBSDThread(const char *thread_name) 42 { 43 Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name); 44 } 45 static void PThreadDestructor (void *v) 46 { 47 delete (FreeBSDThread*)v; 48 } 49 }; 50 51 static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT; 52 static pthread_key_t g_thread_create_key = 0; 53 54 static void 55 InitThreadCreated() 56 { 57 ::pthread_key_create (&g_thread_create_key, FreeBSDThread::PThreadDestructor); 58 } 59 60 void 61 Host::ThreadCreated (const char *thread_name) 62 { 63 ::pthread_once (&g_thread_create_once, InitThreadCreated); 64 if (g_thread_create_key) 65 { 66 ::pthread_setspecific (g_thread_create_key, new FreeBSDThread(thread_name)); 67 } 68 } 69 70 void 71 Host::Backtrace (Stream &strm, uint32_t max_frames) 72 { 73 char backtrace_path[] = "/tmp/lldb-backtrace-tmp-XXXXXX"; 74 int backtrace_fd = ::mkstemp (backtrace_path); 75 if (backtrace_fd != -1) 76 { 77 std::vector<void *> frame_buffer (max_frames, NULL); 78 int count = ::backtrace (&frame_buffer[0], frame_buffer.size()); 79 ::backtrace_symbols_fd (&frame_buffer[0], count, backtrace_fd); 80 81 const off_t buffer_size = ::lseek(backtrace_fd, 0, SEEK_CUR); 82 83 if (::lseek(backtrace_fd, 0, SEEK_SET) == 0) 84 { 85 char *buffer = (char *)::malloc (buffer_size); 86 if (buffer) 87 { 88 ssize_t bytes_read = ::read (backtrace_fd, buffer, buffer_size); 89 if (bytes_read > 0) 90 strm.Write(buffer, bytes_read); 91 ::free (buffer); 92 } 93 } 94 ::close (backtrace_fd); 95 ::unlink (backtrace_path); 96 } 97 } 98 99 size_t 100 Host::GetEnvironment (StringList &env) 101 { 102 char *v; 103 char **var = environ; 104 for (var = environ; var != NULL; ++var) { 105 v = strchr(*var, (int)'-'); 106 if (v == NULL) 107 continue; 108 env.AppendString(v); 109 } 110 return env.GetSize(); 111 } 112 113 bool 114 Host::GetOSVersion(uint32_t &major, 115 uint32_t &minor, 116 uint32_t &update) 117 { 118 struct utsname un; 119 int status; 120 121 if (uname(&un) < 0) 122 return false; 123 124 status = sscanf(un.release, "%u.%u-%u", &major, &minor, &update); 125 return status == 3; 126 } 127 128 Error 129 Host::LaunchProcess (ProcessLaunchInfo &launch_info) 130 { 131 Error error; 132 assert(!"Not implemented yet!!!"); 133 return error; 134 } 135 136 bool 137 Host::GetOSBuildString (std::string &s) 138 { 139 int mib[2] = { CTL_KERN, KERN_OSREV }; 140 char cstr[PATH_MAX]; 141 size_t cstr_len = sizeof(cstr); 142 if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0) 143 { 144 s.assign (cstr, cstr_len); 145 return true; 146 } 147 s.clear(); 148 return false; 149 } 150 151 bool 152 Host::GetOSKernelDescription (std::string &s) 153 { 154 int mib[2] = { CTL_KERN, KERN_VERSION }; 155 char cstr[PATH_MAX]; 156 size_t cstr_len = sizeof(cstr); 157 if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0) 158 { 159 s.assign (cstr, cstr_len); 160 return true; 161 } 162 s.clear(); 163 return false; 164 } 165 166 static bool 167 GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr, 168 ProcessInstanceInfo &process_info) 169 { 170 if (process_info.ProcessIDIsValid()) { 171 int mib[3] = { CTL_KERN, KERN_PROC_ARGS, process_info.GetProcessID() }; 172 173 char arg_data[8192]; 174 size_t arg_data_size = sizeof(arg_data); 175 if (::sysctl (mib, 3, arg_data, &arg_data_size , NULL, 0) == 0) 176 { 177 DataExtractor data (arg_data, arg_data_size, lldb::endian::InlHostByteOrder(), sizeof(void *)); 178 uint32_t offset = 0; 179 uint32_t start_offset; 180 uint32_t argc = data.GetU32 (&offset); 181 const char *cstr; 182 183 cstr = data.GetCStr (&offset); 184 if (cstr) 185 { 186 process_info.GetExecutableFile().SetFile(cstr, false); 187 188 if (match_info_ptr == NULL || 189 NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(), 190 match_info_ptr->GetNameMatchType(), 191 match_info_ptr->GetProcessInfo().GetName())) 192 { 193 // Skip NULLs 194 while (1) 195 { 196 const uint8_t *p = data.PeekData(offset, 1); 197 if ((p == NULL) || (*p != '\0')) 198 break; 199 ++offset; 200 } 201 // Now extract all arguments 202 Args &proc_args = process_info.GetArguments(); 203 for (int i=0; i<argc; ++i) 204 { 205 start_offset = offset; 206 cstr = data.GetCStr(&offset); 207 if (cstr) 208 proc_args.AppendArgument(cstr); 209 } 210 return true; 211 } 212 } 213 } 214 } 215 return false; 216 } 217 218 static bool 219 GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info) 220 { 221 if (process_info.ProcessIDIsValid()) { 222 // TODO: This 223 // return true; 224 } 225 process_info.GetArchitecture().Clear(); 226 return false; 227 } 228 229 static bool 230 GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) 231 { 232 struct kinfo_proc proc_kinfo; 233 size_t proc_kinfo_size; 234 235 if (process_info.ProcessIDIsValid()) 236 { 237 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 238 process_info.GetProcessID() }; 239 proc_kinfo_size = sizeof(struct kinfo_proc); 240 241 if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) 242 { 243 if (proc_kinfo_size > 0) 244 { 245 process_info.SetParentProcessID (proc_kinfo.ki_ppid); 246 process_info.SetUserID (proc_kinfo.ki_ruid); 247 process_info.SetGroupID (proc_kinfo.ki_rgid); 248 process_info.SetEffectiveUserID (proc_kinfo.ki_uid); 249 if (proc_kinfo.ki_ngroups > 0) 250 process_info.SetEffectiveGroupID (proc_kinfo.ki_groups[0]); 251 else 252 process_info.SetEffectiveGroupID (UINT32_MAX); 253 return true; 254 } 255 } 256 } 257 process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID); 258 process_info.SetUserID (UINT32_MAX); 259 process_info.SetGroupID (UINT32_MAX); 260 process_info.SetEffectiveUserID (UINT32_MAX); 261 process_info.SetEffectiveGroupID (UINT32_MAX); 262 return false; 263 } 264 265 bool 266 Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) 267 { 268 process_info.SetProcessID(pid); 269 if (GetFreeBSDProcessArgs(NULL, process_info)) { 270 // should use libprocstat instead of going right into sysctl? 271 GetFreeBSDProcessCPUType(process_info); 272 GetFreeBSDProcessUserAndGroup(process_info); 273 return true; 274 } 275 process_info.Clear(); 276 return false; 277 } 278