| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 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> |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 12 | #include <dlfcn.h> |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 13 | #include <execinfo.h> |
| 14 | #include <sys/types.h> |
| 15 | #include <sys/user.h> |
| 16 | #include <sys/utsname.h> |
| 17 | #include <sys/sysctl.h> |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 18 | #include <sys/proc.h> |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 19 | |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 20 | #include <sys/ptrace.h> |
| 21 | #include <sys/exec.h> |
| 22 | #include <machine/elf.h> |
| 23 | |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 24 | #include <spawn.h> |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 25 | |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 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" |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 32 | #include "lldb/Core/Module.h" |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 33 | #include "lldb/Core/DataExtractor.h" |
| 34 | #include "lldb/Core/StreamFile.h" |
| 35 | #include "lldb/Core/StreamString.h" |
| 36 | #include "lldb/Target/Process.h" |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 37 | #include "lldb/Target/Platform.h" |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 38 | |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 39 | #include "lldb/Core/DataBufferHeap.h" |
| 40 | #include "lldb/Core/DataExtractor.h" |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 41 | #include "lldb/Utility/CleanUp.h" |
| 42 | |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 43 | #include "llvm/Support/Host.h" |
| 44 | |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 45 | |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 46 | extern "C" { |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 47 | extern char **environ; |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 48 | } |
| 49 | |
| 50 | using namespace lldb; |
| 51 | using namespace lldb_private; |
| 52 | |
| 53 | class FreeBSDThread |
| 54 | { |
| 55 | public: |
| 56 | FreeBSDThread(const char *thread_name) |
| 57 | { |
| 58 | Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name); |
| 59 | } |
| 60 | static void PThreadDestructor (void *v) |
| 61 | { |
| 62 | delete (FreeBSDThread*)v; |
| 63 | } |
| 64 | }; |
| 65 | |
| 66 | static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT; |
| 67 | static pthread_key_t g_thread_create_key = 0; |
| 68 | |
| 69 | static void |
| 70 | InitThreadCreated() |
| 71 | { |
| 72 | ::pthread_key_create (&g_thread_create_key, FreeBSDThread::PThreadDestructor); |
| 73 | } |
| 74 | |
| 75 | void |
| 76 | Host::ThreadCreated (const char *thread_name) |
| 77 | { |
| 78 | ::pthread_once (&g_thread_create_once, InitThreadCreated); |
| 79 | if (g_thread_create_key) |
| 80 | { |
| 81 | ::pthread_setspecific (g_thread_create_key, new FreeBSDThread(thread_name)); |
| 82 | } |
| Ed Maste | 02983be | 2013-07-25 19:10:32 +0000 | [diff] [blame] | 83 | |
| 84 | Host::SetShortThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name, 16); |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 85 | } |
| 86 | |
| Ed Maste | 889865f | 2013-07-11 14:12:16 +0000 | [diff] [blame] | 87 | std::string |
| 88 | Host::GetThreadName (lldb::pid_t pid, lldb::tid_t tid) |
| 89 | { |
| 90 | std::string thread_name; |
| 91 | return thread_name; |
| 92 | } |
| 93 | |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 94 | void |
| 95 | Host::Backtrace (Stream &strm, uint32_t max_frames) |
| 96 | { |
| 97 | char backtrace_path[] = "/tmp/lldb-backtrace-tmp-XXXXXX"; |
| 98 | int backtrace_fd = ::mkstemp (backtrace_path); |
| 99 | if (backtrace_fd != -1) |
| 100 | { |
| 101 | std::vector<void *> frame_buffer (max_frames, NULL); |
| 102 | int count = ::backtrace (&frame_buffer[0], frame_buffer.size()); |
| 103 | ::backtrace_symbols_fd (&frame_buffer[0], count, backtrace_fd); |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 104 | |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 105 | const off_t buffer_size = ::lseek(backtrace_fd, 0, SEEK_CUR); |
| 106 | |
| 107 | if (::lseek(backtrace_fd, 0, SEEK_SET) == 0) |
| 108 | { |
| 109 | char *buffer = (char *)::malloc (buffer_size); |
| 110 | if (buffer) |
| 111 | { |
| 112 | ssize_t bytes_read = ::read (backtrace_fd, buffer, buffer_size); |
| 113 | if (bytes_read > 0) |
| 114 | strm.Write(buffer, bytes_read); |
| 115 | ::free (buffer); |
| 116 | } |
| 117 | } |
| 118 | ::close (backtrace_fd); |
| 119 | ::unlink (backtrace_path); |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | size_t |
| 124 | Host::GetEnvironment (StringList &env) |
| 125 | { |
| 126 | char *v; |
| 127 | char **var = environ; |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 128 | for (; var != NULL && *var != NULL; ++var) |
| 129 | { |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 130 | v = strchr(*var, (int)'-'); |
| 131 | if (v == NULL) |
| 132 | continue; |
| 133 | env.AppendString(v); |
| 134 | } |
| 135 | return env.GetSize(); |
| 136 | } |
| 137 | |
| 138 | bool |
| Ed Maste | 5d34af3 | 2013-06-24 15:09:18 +0000 | [diff] [blame] | 139 | Host::GetOSVersion(uint32_t &major, |
| 140 | uint32_t &minor, |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 141 | uint32_t &update) |
| 142 | { |
| 143 | struct utsname un; |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 144 | |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 145 | ::memset(&un, 0, sizeof(utsname)); |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 146 | if (uname(&un) < 0) |
| 147 | return false; |
| 148 | |
| Ed Maste | 2f0d590 | 2013-06-25 20:50:07 +0000 | [diff] [blame] | 149 | status = sscanf(un.release, "%u.%u", &major, &minor); |
| Ed Maste | 2f0d590 | 2013-06-25 20:50:07 +0000 | [diff] [blame] | 150 | return status == 2; |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 151 | } |
| 152 | |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 153 | // The posix_spawn() and posix_spawnp() functions first appeared in FreeBSD 8.0. |
| 154 | static Error |
| 155 | LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, ::pid_t &pid) |
| 156 | { |
| 157 | Error error; |
| 158 | LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS)); |
| 159 | |
| 160 | assert(exe_path); |
| 161 | assert(!launch_info.GetFlags().Test (eLaunchFlagDebug)); |
| 162 | |
| 163 | posix_spawnattr_t attr; |
| 164 | |
| 165 | error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX); |
| 166 | error.LogIfError(log.get(), "::posix_spawnattr_init ( &attr )"); |
| 167 | if (error.Fail()) |
| 168 | return error; |
| 169 | |
| 170 | // Make a quick class that will cleanup the posix spawn attributes in case |
| 171 | // we return in the middle of this function. |
| 172 | lldb_utility::CleanUp <posix_spawnattr_t *, int> posix_spawnattr_cleanup(&attr, posix_spawnattr_destroy); |
| 173 | |
| 174 | sigset_t no_signals; |
| 175 | sigset_t all_signals; |
| 176 | sigemptyset (&no_signals); |
| 177 | sigfillset (&all_signals); |
| 178 | ::posix_spawnattr_setsigmask(&attr, &all_signals); |
| 179 | ::posix_spawnattr_setsigdefault(&attr, &no_signals); |
| 180 | |
| 181 | short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; |
| 182 | |
| 183 | error.SetError( ::posix_spawnattr_setflags (&attr, flags), eErrorTypePOSIX); |
| 184 | error.LogIfError(log.get(), "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", flags); |
| 185 | if (error.Fail()) |
| 186 | return error; |
| 187 | |
| 188 | const size_t num_file_actions = launch_info.GetNumFileActions (); |
| 189 | posix_spawn_file_actions_t file_actions, *file_action_ptr = NULL; |
| 190 | // Make a quick class that will cleanup the posix spawn attributes in case |
| 191 | // we return in the middle of this function. |
| 192 | lldb_utility::CleanUp <posix_spawn_file_actions_t *, int> |
| 193 | posix_spawn_file_actions_cleanup (file_action_ptr, NULL, posix_spawn_file_actions_destroy); |
| 194 | |
| 195 | if (num_file_actions > 0) |
| 196 | { |
| 197 | error.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX); |
| 198 | error.LogIfError(log.get(), "::posix_spawn_file_actions_init ( &file_actions )"); |
| 199 | if (error.Fail()) |
| 200 | return error; |
| 201 | |
| 202 | file_action_ptr = &file_actions; |
| 203 | posix_spawn_file_actions_cleanup.set(file_action_ptr); |
| 204 | |
| 205 | for (size_t i = 0; i < num_file_actions; ++i) |
| 206 | { |
| 207 | const ProcessLaunchInfo::FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i); |
| 208 | if (launch_file_action && |
| 209 | !ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (&file_actions, |
| 210 | launch_file_action, |
| 211 | log.get(), |
| 212 | error)) |
| 213 | return error; |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | // Change working directory if neccessary. |
| 218 | char current_dir[PATH_MAX]; |
| 219 | current_dir[0] = '\0'; |
| 220 | |
| 221 | const char *working_dir = launch_info.GetWorkingDirectory(); |
| 222 | if (working_dir != NULL) |
| 223 | { |
| 224 | if (::getcwd(current_dir, sizeof(current_dir)) == NULL) |
| 225 | { |
| 226 | error.SetError(errno, eErrorTypePOSIX); |
| 227 | error.LogIfError(log.get(), "unable to save the current directory"); |
| 228 | return error; |
| 229 | } |
| 230 | |
| 231 | if (::chdir(working_dir) == -1) |
| 232 | { |
| 233 | error.SetError(errno, eErrorTypePOSIX); |
| 234 | error.LogIfError(log.get(), "unable to change working directory to %s", working_dir); |
| 235 | return error; |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | const char *tmp_argv[2]; |
| 240 | char * const *argv = (char * const*)launch_info.GetArguments().GetConstArgumentVector(); |
| 241 | char * const *envp = (char * const*)launch_info.GetEnvironmentEntries().GetConstArgumentVector(); |
| 242 | |
| 243 | // Prepare minimal argument list if we didn't get it from the launch_info structure. |
| 244 | // We must pass argv into posix_spawnp and it must contain at least two items - |
| 245 | // pointer to an executable and NULL. |
| 246 | if (argv == NULL) |
| 247 | { |
| 248 | tmp_argv[0] = exe_path; |
| 249 | tmp_argv[1] = NULL; |
| 250 | argv = (char * const*)tmp_argv; |
| 251 | } |
| 252 | |
| 253 | error.SetError (::posix_spawnp (&pid, |
| 254 | exe_path, |
| 255 | (num_file_actions > 0) ? &file_actions : NULL, |
| 256 | &attr, |
| 257 | argv, |
| 258 | envp), |
| 259 | eErrorTypePOSIX); |
| 260 | |
| 261 | error.LogIfError(log.get(), "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", |
| 262 | pid, exe_path, file_action_ptr, &attr, argv, envp); |
| 263 | |
| 264 | // Change back the current directory. |
| 265 | // NOTE: do not override previously established error from posix_spawnp. |
| 266 | if (working_dir != NULL && ::chdir(current_dir) == -1 && error.Success()) |
| 267 | { |
| 268 | error.SetError(errno, eErrorTypePOSIX); |
| 269 | error.LogIfError(log.get(), "unable to change current directory back to %s", |
| 270 | current_dir); |
| 271 | } |
| 272 | |
| 273 | return error; |
| 274 | } |
| 275 | |
| 276 | |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 277 | Error |
| 278 | Host::LaunchProcess (ProcessLaunchInfo &launch_info) |
| 279 | { |
| 280 | Error error; |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 281 | char exe_path[PATH_MAX]; |
| 282 | |
| 283 | PlatformSP host_platform_sp (Platform::GetDefaultPlatform ()); |
| 284 | |
| 285 | const ArchSpec &arch_spec = launch_info.GetArchitecture(); |
| 286 | |
| 287 | FileSpec exe_spec(launch_info.GetExecutableFile()); |
| 288 | |
| 289 | FileSpec::FileType file_type = exe_spec.GetFileType(); |
| 290 | if (file_type != FileSpec::eFileTypeRegular) |
| 291 | { |
| 292 | lldb::ModuleSP exe_module_sp; |
| 293 | error = host_platform_sp->ResolveExecutable (exe_spec, |
| 294 | arch_spec, |
| 295 | exe_module_sp, |
| 296 | NULL); |
| 297 | |
| 298 | if (error.Fail()) |
| 299 | return error; |
| 300 | |
| 301 | if (exe_module_sp) |
| 302 | exe_spec = exe_module_sp->GetFileSpec(); |
| 303 | } |
| 304 | |
| 305 | if (exe_spec.Exists()) |
| 306 | { |
| 307 | exe_spec.GetPath (exe_path, sizeof(exe_path)); |
| 308 | } |
| 309 | else |
| 310 | { |
| 311 | launch_info.GetExecutableFile().GetPath (exe_path, sizeof(exe_path)); |
| 312 | error.SetErrorStringWithFormat ("executable doesn't exist: '%s'", exe_path); |
| 313 | return error; |
| 314 | } |
| 315 | |
| 316 | assert(!launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY)); |
| 317 | |
| 318 | ::pid_t pid = LLDB_INVALID_PROCESS_ID; |
| 319 | |
| 320 | error = LaunchProcessPosixSpawn(exe_path, launch_info, pid); |
| 321 | |
| 322 | if (pid != LLDB_INVALID_PROCESS_ID) |
| 323 | { |
| 324 | // If all went well, then set the process ID into the launch info |
| 325 | launch_info.SetProcessID(pid); |
| 326 | |
| 327 | // Make sure we reap any processes we spawn or we will have zombies. |
| 328 | if (!launch_info.MonitorProcess()) |
| 329 | { |
| 330 | const bool monitor_signals = false; |
| 331 | StartMonitoringChildProcess (Process::SetProcessExitStatus, |
| 332 | NULL, |
| 333 | pid, |
| 334 | monitor_signals); |
| 335 | } |
| 336 | } |
| 337 | else |
| 338 | { |
| 339 | // Invalid process ID, something didn't go well |
| 340 | if (error.Success()) |
| 341 | error.SetErrorString ("process launch failed for unknown reasons"); |
| 342 | } |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 343 | return error; |
| 344 | } |
| 345 | |
| 346 | bool |
| 347 | Host::GetOSBuildString (std::string &s) |
| 348 | { |
| 349 | int mib[2] = { CTL_KERN, KERN_OSREV }; |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 350 | char osrev_str[12]; |
| 351 | uint32_t osrev = 0; |
| 352 | size_t osrev_len = sizeof(osrev); |
| 353 | |
| 354 | if (::sysctl (mib, 2, &osrev, &osrev_len, NULL, 0) == 0) |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 355 | { |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 356 | ::snprintf(osrev_str, sizeof(osrev_str), "%-8.8u", osrev); |
| 357 | s.assign (osrev_str); |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 358 | return true; |
| 359 | } |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 360 | |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 361 | s.clear(); |
| 362 | return false; |
| 363 | } |
| 364 | |
| 365 | bool |
| 366 | Host::GetOSKernelDescription (std::string &s) |
| 367 | { |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 368 | struct utsname un; |
| 369 | |
| 370 | ::memset(&un, 0, sizeof(utsname)); |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 371 | s.clear(); |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 372 | |
| 373 | if (uname(&un) < 0) |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 374 | return false; |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 375 | |
| 376 | s.assign (un.version); |
| 377 | |
| 378 | return true; |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 379 | } |
| 380 | |
| 381 | static bool |
| 382 | GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr, |
| 383 | ProcessInstanceInfo &process_info) |
| 384 | { |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 385 | if (process_info.ProcessIDIsValid()) |
| 386 | { |
| Filipe Cabecinhas | d0b87d8 | 2012-09-11 18:11:16 +0000 | [diff] [blame] | 387 | int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, (int)process_info.GetProcessID() }; |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 388 | |
| 389 | char arg_data[8192]; |
| 390 | size_t arg_data_size = sizeof(arg_data); |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 391 | if (::sysctl (mib, 4, arg_data, &arg_data_size , NULL, 0) == 0) |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 392 | { |
| 393 | DataExtractor data (arg_data, arg_data_size, lldb::endian::InlHostByteOrder(), sizeof(void *)); |
| Ashok Thirumurthi | 0f3b9b8 | 2013-05-01 20:38:19 +0000 | [diff] [blame] | 394 | lldb::offset_t offset = 0; |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 395 | const char *cstr; |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 396 | |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 397 | cstr = data.GetCStr (&offset); |
| 398 | if (cstr) |
| 399 | { |
| 400 | process_info.GetExecutableFile().SetFile(cstr, false); |
| 401 | |
| Ed Maste | 5d34af3 | 2013-06-24 15:09:18 +0000 | [diff] [blame] | 402 | if (!(match_info_ptr == NULL || |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 403 | NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(), |
| 404 | match_info_ptr->GetNameMatchType(), |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 405 | match_info_ptr->GetProcessInfo().GetName()))) |
| 406 | return false; |
| 407 | |
| 408 | Args &proc_args = process_info.GetArguments(); |
| 409 | while (1) |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 410 | { |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 411 | const uint8_t *p = data.PeekData(offset, 1); |
| 412 | while ((p != NULL) && (*p == '\0') && offset < arg_data_size) |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 413 | { |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 414 | ++offset; |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 415 | p = data.PeekData(offset, 1); |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 416 | } |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 417 | if (p == NULL || offset >= arg_data_size) |
| 418 | return true; |
| 419 | |
| 420 | cstr = data.GetCStr(&offset); |
| 421 | if (cstr) |
| 422 | proc_args.AppendArgument(cstr); |
| 423 | else |
| 424 | return true; |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 425 | } |
| 426 | } |
| Ed Maste | 5d34af3 | 2013-06-24 15:09:18 +0000 | [diff] [blame] | 427 | } |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 428 | } |
| 429 | return false; |
| 430 | } |
| 431 | |
| 432 | static bool |
| 433 | GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info) |
| 434 | { |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 435 | if (process_info.ProcessIDIsValid()) |
| 436 | { |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 437 | process_info.GetArchitecture() = Host::GetArchitecture (Host::eSystemDefaultArchitecture); |
| 438 | return true; |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 439 | } |
| 440 | process_info.GetArchitecture().Clear(); |
| 441 | return false; |
| 442 | } |
| 443 | |
| 444 | static bool |
| 445 | GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) |
| 446 | { |
| 447 | struct kinfo_proc proc_kinfo; |
| 448 | size_t proc_kinfo_size; |
| 449 | |
| Ed Maste | 5d34af3 | 2013-06-24 15:09:18 +0000 | [diff] [blame] | 450 | if (process_info.ProcessIDIsValid()) |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 451 | { |
| 452 | int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, |
| Filipe Cabecinhas | d0b87d8 | 2012-09-11 18:11:16 +0000 | [diff] [blame] | 453 | (int)process_info.GetProcessID() }; |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 454 | proc_kinfo_size = sizeof(struct kinfo_proc); |
| 455 | |
| 456 | if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) |
| 457 | { |
| 458 | if (proc_kinfo_size > 0) |
| 459 | { |
| 460 | process_info.SetParentProcessID (proc_kinfo.ki_ppid); |
| 461 | process_info.SetUserID (proc_kinfo.ki_ruid); |
| 462 | process_info.SetGroupID (proc_kinfo.ki_rgid); |
| 463 | process_info.SetEffectiveUserID (proc_kinfo.ki_uid); |
| 464 | if (proc_kinfo.ki_ngroups > 0) |
| 465 | process_info.SetEffectiveGroupID (proc_kinfo.ki_groups[0]); |
| 466 | else |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 467 | process_info.SetEffectiveGroupID (UINT32_MAX); |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 468 | return true; |
| 469 | } |
| 470 | } |
| 471 | } |
| 472 | process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID); |
| 473 | process_info.SetUserID (UINT32_MAX); |
| 474 | process_info.SetGroupID (UINT32_MAX); |
| 475 | process_info.SetEffectiveUserID (UINT32_MAX); |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 476 | process_info.SetEffectiveGroupID (UINT32_MAX); |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 477 | return false; |
| 478 | } |
| 479 | |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 480 | uint32_t |
| 481 | Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) |
| 482 | { |
| 483 | std::vector<struct kinfo_proc> kinfos; |
| 484 | |
| 485 | int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL }; |
| 486 | |
| 487 | size_t pid_data_size = 0; |
| 488 | if (::sysctl (mib, 3, NULL, &pid_data_size, NULL, 0) != 0) |
| 489 | return 0; |
| 490 | |
| 491 | // Add a few extra in case a few more show up |
| 492 | const size_t estimated_pid_count = (pid_data_size / sizeof(struct kinfo_proc)) + 10; |
| 493 | |
| 494 | kinfos.resize (estimated_pid_count); |
| 495 | pid_data_size = kinfos.size() * sizeof(struct kinfo_proc); |
| 496 | |
| 497 | if (::sysctl (mib, 3, &kinfos[0], &pid_data_size, NULL, 0) != 0) |
| 498 | return 0; |
| 499 | |
| 500 | const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc)); |
| 501 | |
| 502 | bool all_users = match_info.GetMatchAllUsers(); |
| 503 | const lldb::pid_t our_pid = getpid(); |
| 504 | const uid_t our_uid = getuid(); |
| 505 | for (int i = 0; i < actual_pid_count; i++) |
| 506 | { |
| 507 | const struct kinfo_proc &kinfo = kinfos[i]; |
| 508 | const bool kinfo_user_matches = (all_users || |
| 509 | (kinfo.ki_ruid == our_uid) || |
| 510 | // Special case, if lldb is being run as root we can attach to anything. |
| 511 | (our_uid == 0) |
| 512 | ); |
| 513 | |
| 514 | if (kinfo_user_matches == false || // Make sure the user is acceptable |
| 515 | kinfo.ki_pid == our_pid || // Skip this process |
| 516 | kinfo.ki_pid == 0 || // Skip kernel (kernel pid is zero) |
| 517 | kinfo.ki_stat == SZOMB || // Zombies are bad, they like brains... |
| 518 | kinfo.ki_flag & P_TRACED || // Being debugged? |
| 519 | kinfo.ki_flag & P_WEXIT) // Working on exiting |
| 520 | continue; |
| 521 | |
| 522 | // Every thread is a process in FreeBSD, but all the threads of a single process |
| 523 | // have the same pid. Do not store the process info in the result list if a process |
| 524 | // with given identifier is already registered there. |
| 525 | bool already_registered = false; |
| 526 | for (uint32_t pi = 0; |
| 527 | !already_registered && |
| 528 | (const int)kinfo.ki_numthreads > 1 && |
| 529 | pi < (const uint32_t)process_infos.GetSize(); pi++) |
| 530 | already_registered = (process_infos.GetProcessIDAtIndex(pi) == (uint32_t)kinfo.ki_pid); |
| 531 | |
| 532 | if (already_registered) |
| 533 | continue; |
| 534 | |
| 535 | ProcessInstanceInfo process_info; |
| 536 | process_info.SetProcessID (kinfo.ki_pid); |
| 537 | process_info.SetParentProcessID (kinfo.ki_ppid); |
| 538 | process_info.SetUserID (kinfo.ki_ruid); |
| 539 | process_info.SetGroupID (kinfo.ki_rgid); |
| 540 | process_info.SetEffectiveUserID (kinfo.ki_svuid); |
| 541 | process_info.SetEffectiveGroupID (kinfo.ki_svgid); |
| 542 | |
| 543 | // Make sure our info matches before we go fetch the name and cpu type |
| 544 | if (match_info.Matches (process_info) && |
| 545 | GetFreeBSDProcessArgs (&match_info, process_info)) |
| 546 | { |
| 547 | GetFreeBSDProcessCPUType (process_info); |
| 548 | if (match_info.Matches (process_info)) |
| 549 | process_infos.Append (process_info); |
| 550 | } |
| 551 | } |
| 552 | |
| 553 | return process_infos.GetSize(); |
| 554 | } |
| 555 | |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 556 | bool |
| 557 | Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) |
| 558 | { |
| 559 | process_info.SetProcessID(pid); |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 560 | |
| 561 | if (GetFreeBSDProcessArgs(NULL, process_info)) |
| 562 | { |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 563 | // should use libprocstat instead of going right into sysctl? |
| 564 | GetFreeBSDProcessCPUType(process_info); |
| 565 | GetFreeBSDProcessUserAndGroup(process_info); |
| 566 | return true; |
| 567 | } |
| Daniel Malea | e0f8f57 | 2013-08-26 23:57:52 +0000 | [diff] [blame^] | 568 | |
| Johnny Chen | 8f3d838 | 2011-08-02 20:52:42 +0000 | [diff] [blame] | 569 | process_info.Clear(); |
| 570 | return false; |
| 571 | } |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 572 | |
| 573 | lldb::DataBufferSP |
| 574 | Host::GetAuxvData(lldb_private::Process *process) |
| 575 | { |
| 576 | int mib[2] = { CTL_KERN, KERN_PS_STRINGS }; |
| 577 | void *ps_strings_addr, *auxv_addr; |
| 578 | size_t ps_strings_size = sizeof(void *); |
| 579 | Elf_Auxinfo aux_info[AT_COUNT]; |
| 580 | struct ps_strings ps_strings; |
| 581 | struct ptrace_io_desc pid; |
| 582 | DataBufferSP buf_sp; |
| Greg Clayton | 7b0992d | 2013-04-18 22:45:39 +0000 | [diff] [blame] | 583 | std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0)); |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 584 | |
| 585 | if (::sysctl(mib, 2, &ps_strings_addr, &ps_strings_size, NULL, 0) == 0) { |
| 586 | pid.piod_op = PIOD_READ_D; |
| 587 | pid.piod_addr = &ps_strings; |
| 588 | pid.piod_offs = ps_strings_addr; |
| 589 | pid.piod_len = sizeof(ps_strings); |
| Filipe Cabecinhas | d0b87d8 | 2012-09-11 18:11:16 +0000 | [diff] [blame] | 590 | if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) { |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 591 | perror("failed to fetch ps_strings"); |
| 592 | buf_ap.release(); |
| 593 | goto done; |
| 594 | } |
| 595 | |
| 596 | auxv_addr = ps_strings.ps_envstr + ps_strings.ps_nenvstr + 1; |
| 597 | |
| 598 | pid.piod_addr = aux_info; |
| 599 | pid.piod_offs = auxv_addr; |
| 600 | pid.piod_len = sizeof(aux_info); |
| Filipe Cabecinhas | d0b87d8 | 2012-09-11 18:11:16 +0000 | [diff] [blame] | 601 | if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) { |
| Johnny Chen | 30213ff | 2012-01-05 19:17:38 +0000 | [diff] [blame] | 602 | perror("failed to fetch aux_info"); |
| 603 | buf_ap.release(); |
| 604 | goto done; |
| 605 | } |
| 606 | memcpy(buf_ap->GetBytes(), aux_info, pid.piod_len); |
| 607 | buf_sp.reset(buf_ap.release()); |
| 608 | } else { |
| 609 | perror("sysctl failed on ps_strings"); |
| 610 | } |
| 611 | |
| 612 | done: |
| 613 | return buf_sp; |
| 614 | } |