1 //===-- DNB.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 // Created by Greg Clayton on 3/23/07. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "DNB.h" 15 #include <inttypes.h> 16 #include <signal.h> 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <sys/resource.h> 20 #include <sys/stat.h> 21 #include <sys/types.h> 22 #include <sys/wait.h> 23 #include <unistd.h> 24 #include <sys/sysctl.h> 25 #include <map> 26 #include <vector> 27 #include <libproc.h> 28 29 #define TRY_KQUEUE 1 30 31 #ifdef TRY_KQUEUE 32 #include <sys/event.h> 33 #include <sys/time.h> 34 #ifdef NOTE_EXIT_DETAIL 35 #define USE_KQUEUE 36 #endif 37 #endif 38 39 #include "MacOSX/MachProcess.h" 40 #include "MacOSX/MachTask.h" 41 #include "CFString.h" 42 #include "DNBLog.h" 43 #include "DNBDataRef.h" 44 #include "DNBThreadResumeActions.h" 45 #include "DNBTimer.h" 46 #include "CFBundle.h" 47 48 49 typedef std::shared_ptr<MachProcess> MachProcessSP; 50 typedef std::map<nub_process_t, MachProcessSP> ProcessMap; 51 typedef ProcessMap::iterator ProcessMapIter; 52 typedef ProcessMap::const_iterator ProcessMapConstIter; 53 54 size_t GetAllInfos (std::vector<struct kinfo_proc>& proc_infos); 55 static size_t GetAllInfosMatchingName (const char *process_name, std::vector<struct kinfo_proc>& matching_proc_infos); 56 57 //---------------------------------------------------------------------- 58 // A Thread safe singleton to get a process map pointer. 59 // 60 // Returns a pointer to the existing process map, or a pointer to a 61 // newly created process map if CAN_CREATE is non-zero. 62 //---------------------------------------------------------------------- 63 static ProcessMap* 64 GetProcessMap(bool can_create) 65 { 66 static ProcessMap* g_process_map_ptr = NULL; 67 68 if (can_create && g_process_map_ptr == NULL) 69 { 70 static pthread_mutex_t g_process_map_mutex = PTHREAD_MUTEX_INITIALIZER; 71 PTHREAD_MUTEX_LOCKER (locker, &g_process_map_mutex); 72 if (g_process_map_ptr == NULL) 73 g_process_map_ptr = new ProcessMap; 74 } 75 return g_process_map_ptr; 76 } 77 78 //---------------------------------------------------------------------- 79 // Add PID to the shared process pointer map. 80 // 81 // Return non-zero value if we succeed in adding the process to the map. 82 // The only time this should fail is if we run out of memory and can't 83 // allocate a ProcessMap. 84 //---------------------------------------------------------------------- 85 static nub_bool_t 86 AddProcessToMap (nub_process_t pid, MachProcessSP& procSP) 87 { 88 ProcessMap* process_map = GetProcessMap(true); 89 if (process_map) 90 { 91 process_map->insert(std::make_pair(pid, procSP)); 92 return true; 93 } 94 return false; 95 } 96 97 //---------------------------------------------------------------------- 98 // Remove the shared pointer for PID from the process map. 99 // 100 // Returns the number of items removed from the process map. 101 //---------------------------------------------------------------------- 102 static size_t 103 RemoveProcessFromMap (nub_process_t pid) 104 { 105 ProcessMap* process_map = GetProcessMap(false); 106 if (process_map) 107 { 108 return process_map->erase(pid); 109 } 110 return 0; 111 } 112 113 //---------------------------------------------------------------------- 114 // Get the shared pointer for PID from the existing process map. 115 // 116 // Returns true if we successfully find a shared pointer to a 117 // MachProcess object. 118 //---------------------------------------------------------------------- 119 static nub_bool_t 120 GetProcessSP (nub_process_t pid, MachProcessSP& procSP) 121 { 122 ProcessMap* process_map = GetProcessMap(false); 123 if (process_map != NULL) 124 { 125 ProcessMapIter pos = process_map->find(pid); 126 if (pos != process_map->end()) 127 { 128 procSP = pos->second; 129 return true; 130 } 131 } 132 procSP.reset(); 133 return false; 134 } 135 136 #ifdef USE_KQUEUE 137 void * 138 kqueue_thread (void *arg) 139 { 140 int kq_id = (int) (intptr_t) arg; 141 142 struct kevent death_event; 143 while (1) 144 { 145 int n_events = kevent (kq_id, NULL, 0, &death_event, 1, NULL); 146 if (n_events == -1) 147 { 148 if (errno == EINTR) 149 continue; 150 else 151 { 152 DNBLogError ("kqueue failed with error: (%d): %s", errno, strerror(errno)); 153 return NULL; 154 } 155 } 156 else if (death_event.flags & EV_ERROR) 157 { 158 int error_no = death_event.data; 159 const char *error_str = strerror(death_event.data); 160 if (error_str == NULL) 161 error_str = "Unknown error"; 162 DNBLogError ("Failed to initialize kqueue event: (%d): %s", error_no, error_str ); 163 return NULL; 164 } 165 else 166 { 167 int status; 168 const pid_t pid = (pid_t)death_event.ident; 169 const pid_t child_pid = waitpid (pid, &status, 0); 170 171 172 bool exited = false; 173 int signal = 0; 174 int exit_status = 0; 175 const char *status_cstr = NULL; 176 if (WIFSTOPPED(status)) 177 { 178 signal = WSTOPSIG(status); 179 status_cstr = "STOPPED"; 180 DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> STOPPED (signal = %i)", child_pid, signal); 181 } 182 else if (WIFEXITED(status)) 183 { 184 exit_status = WEXITSTATUS(status); 185 status_cstr = "EXITED"; 186 exited = true; 187 DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> EXITED (status = %i)", child_pid, exit_status); 188 } 189 else if (WIFSIGNALED(status)) 190 { 191 signal = WTERMSIG(status); 192 status_cstr = "SIGNALED"; 193 if (child_pid == abs(pid)) 194 { 195 DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> SIGNALED and EXITED (signal = %i)", child_pid, signal); 196 char exit_info[64]; 197 ::snprintf (exit_info, sizeof(exit_info), "Terminated due to signal %i", signal); 198 DNBProcessSetExitInfo (child_pid, exit_info); 199 exited = true; 200 exit_status = INT8_MAX; 201 } 202 else 203 { 204 DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> SIGNALED (signal = %i)", child_pid, signal); 205 } 206 } 207 208 if (exited) 209 { 210 if (death_event.data & NOTE_EXIT_MEMORY) 211 { 212 if (death_event.data & NOTE_VM_PRESSURE) 213 DNBProcessSetExitInfo (child_pid, "Terminated due to Memory Pressure"); 214 else if (death_event.data & NOTE_VM_ERROR) 215 DNBProcessSetExitInfo (child_pid, "Terminated due to Memory Error"); 216 else 217 DNBProcessSetExitInfo (child_pid, "Terminated due to unknown Memory condition"); 218 } 219 else if (death_event.data & NOTE_EXIT_DECRYPTFAIL) 220 DNBProcessSetExitInfo (child_pid, "Terminated due to decrypt failure"); 221 else if (death_event.data & NOTE_EXIT_CSERROR) 222 DNBProcessSetExitInfo (child_pid, "Terminated due to code signing error"); 223 224 DNBLogThreadedIf(LOG_PROCESS, "waitpid_process_thread (): setting exit status for pid = %i to %i", child_pid, exit_status); 225 DNBProcessSetExitStatus (child_pid, status); 226 return NULL; 227 } 228 } 229 } 230 } 231 232 static bool 233 spawn_kqueue_thread (pid_t pid) 234 { 235 pthread_t thread; 236 int kq_id; 237 238 kq_id = kqueue(); 239 if (kq_id == -1) 240 { 241 DNBLogError ("Could not get kqueue for pid = %i.", pid); 242 return false; 243 } 244 245 struct kevent reg_event; 246 247 EV_SET(®_event, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT|NOTE_EXIT_DETAIL, 0, NULL); 248 // Register the event: 249 int result = kevent (kq_id, ®_event, 1, NULL, 0, NULL); 250 if (result != 0) 251 { 252 DNBLogError ("Failed to register kqueue NOTE_EXIT event for pid %i, error: %d.", pid, result); 253 return false; 254 } 255 256 int ret = ::pthread_create (&thread, NULL, kqueue_thread, (void *)(intptr_t)kq_id); 257 258 // pthread_create returns 0 if successful 259 if (ret == 0) 260 { 261 ::pthread_detach (thread); 262 return true; 263 } 264 return false; 265 } 266 #endif // #if USE_KQUEUE 267 268 static void * 269 waitpid_thread (void *arg) 270 { 271 const pid_t pid = (pid_t)(intptr_t)arg; 272 int status; 273 while (1) 274 { 275 pid_t child_pid = waitpid(pid, &status, 0); 276 DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): waitpid (pid = %i, &status, 0) => %i, status = %i, errno = %i", pid, child_pid, status, errno); 277 278 if (child_pid < 0) 279 { 280 if (errno == EINTR) 281 continue; 282 break; 283 } 284 else 285 { 286 if (WIFSTOPPED(status)) 287 { 288 continue; 289 } 290 else// if (WIFEXITED(status) || WIFSIGNALED(status)) 291 { 292 DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): setting exit status for pid = %i to %i", child_pid, status); 293 DNBProcessSetExitStatus (child_pid, status); 294 return NULL; 295 } 296 } 297 } 298 299 // We should never exit as long as our child process is alive, so if we 300 // do something else went wrong and we should exit... 301 DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): main loop exited, setting exit status to an invalid value (-1) for pid %i", pid); 302 DNBProcessSetExitStatus (pid, -1); 303 return NULL; 304 } 305 static bool 306 spawn_waitpid_thread (pid_t pid) 307 { 308 #ifdef USE_KQUEUE 309 bool success = spawn_kqueue_thread (pid); 310 if (success) 311 return true; 312 #endif 313 314 pthread_t thread; 315 int ret = ::pthread_create (&thread, NULL, waitpid_thread, (void *)(intptr_t)pid); 316 // pthread_create returns 0 if successful 317 if (ret == 0) 318 { 319 ::pthread_detach (thread); 320 return true; 321 } 322 return false; 323 } 324 325 nub_process_t 326 DNBProcessLaunch (const char *path, 327 char const *argv[], 328 const char *envp[], 329 const char *working_directory, // NULL => dont' change, non-NULL => set working directory for inferior to this 330 const char *stdin_path, 331 const char *stdout_path, 332 const char *stderr_path, 333 bool no_stdio, 334 nub_launch_flavor_t launch_flavor, 335 int disable_aslr, 336 const char *event_data, 337 char *err_str, 338 size_t err_len) 339 { 340 DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv = %p, envp = %p, working_dir=%s, stdin=%s, stdout=%s, stderr=%s, no-stdio=%i, launch_flavor = %u, disable_aslr = %d, err = %p, err_len = %llu) called...", 341 __FUNCTION__, 342 path, 343 argv, 344 envp, 345 working_directory, 346 stdin_path, 347 stdout_path, 348 stderr_path, 349 no_stdio, 350 launch_flavor, 351 disable_aslr, 352 err_str, 353 (uint64_t)err_len); 354 355 if (err_str && err_len > 0) 356 err_str[0] = '\0'; 357 struct stat path_stat; 358 if (::stat(path, &path_stat) == -1) 359 { 360 char stat_error[256]; 361 ::strerror_r (errno, stat_error, sizeof(stat_error)); 362 snprintf(err_str, err_len, "%s (%s)", stat_error, path); 363 return INVALID_NUB_PROCESS; 364 } 365 366 MachProcessSP processSP (new MachProcess); 367 if (processSP.get()) 368 { 369 DNBError launch_err; 370 pid_t pid = processSP->LaunchForDebug (path, 371 argv, 372 envp, 373 working_directory, 374 stdin_path, 375 stdout_path, 376 stderr_path, 377 no_stdio, 378 launch_flavor, 379 disable_aslr, 380 event_data, 381 launch_err); 382 if (err_str) 383 { 384 *err_str = '\0'; 385 if (launch_err.Fail()) 386 { 387 const char *launch_err_str = launch_err.AsString(); 388 if (launch_err_str) 389 { 390 strncpy(err_str, launch_err_str, err_len-1); 391 err_str[err_len-1] = '\0'; // Make sure the error string is terminated 392 } 393 } 394 } 395 396 DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) new pid is %d...", pid); 397 398 if (pid != INVALID_NUB_PROCESS) 399 { 400 // Spawn a thread to reap our child inferior process... 401 spawn_waitpid_thread (pid); 402 403 if (processSP->Task().TaskPortForProcessID (launch_err) == TASK_NULL) 404 { 405 // We failed to get the task for our process ID which is bad. 406 // Kill our process otherwise it will be stopped at the entry 407 // point and get reparented to someone else and never go away. 408 DNBLog ("Could not get task port for process, sending SIGKILL and exiting."); 409 kill (SIGKILL, pid); 410 411 if (err_str && err_len > 0) 412 { 413 if (launch_err.AsString()) 414 { 415 ::snprintf (err_str, err_len, "failed to get the task for process %i (%s)", pid, launch_err.AsString()); 416 } 417 else 418 { 419 ::snprintf (err_str, err_len, "failed to get the task for process %i", pid); 420 } 421 } 422 } 423 else 424 { 425 bool res = AddProcessToMap(pid, processSP); 426 assert(res && "Couldn't add process to map!"); 427 return pid; 428 } 429 } 430 } 431 return INVALID_NUB_PROCESS; 432 } 433 434 nub_process_t 435 DNBProcessAttachByName (const char *name, struct timespec *timeout, char *err_str, size_t err_len) 436 { 437 if (err_str && err_len > 0) 438 err_str[0] = '\0'; 439 std::vector<struct kinfo_proc> matching_proc_infos; 440 size_t num_matching_proc_infos = GetAllInfosMatchingName(name, matching_proc_infos); 441 if (num_matching_proc_infos == 0) 442 { 443 DNBLogError ("error: no processes match '%s'\n", name); 444 return INVALID_NUB_PROCESS; 445 } 446 else if (num_matching_proc_infos > 1) 447 { 448 DNBLogError ("error: %llu processes match '%s':\n", (uint64_t)num_matching_proc_infos, name); 449 size_t i; 450 for (i=0; i<num_matching_proc_infos; ++i) 451 DNBLogError ("%6u - %s\n", matching_proc_infos[i].kp_proc.p_pid, matching_proc_infos[i].kp_proc.p_comm); 452 return INVALID_NUB_PROCESS; 453 } 454 455 return DNBProcessAttach (matching_proc_infos[0].kp_proc.p_pid, timeout, err_str, err_len); 456 } 457 458 nub_process_t 459 DNBProcessAttach (nub_process_t attach_pid, struct timespec *timeout, char *err_str, size_t err_len) 460 { 461 if (err_str && err_len > 0) 462 err_str[0] = '\0'; 463 464 pid_t pid = INVALID_NUB_PROCESS; 465 MachProcessSP processSP(new MachProcess); 466 if (processSP.get()) 467 { 468 DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...", attach_pid); 469 pid = processSP->AttachForDebug (attach_pid, err_str, err_len); 470 471 if (pid != INVALID_NUB_PROCESS) 472 { 473 bool res = AddProcessToMap(pid, processSP); 474 assert(res && "Couldn't add process to map!"); 475 spawn_waitpid_thread(pid); 476 } 477 } 478 479 while (pid != INVALID_NUB_PROCESS) 480 { 481 // Wait for process to start up and hit entry point 482 DNBLogThreadedIf (LOG_PROCESS, 483 "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...", 484 __FUNCTION__, 485 pid); 486 nub_event_t set_events = DNBProcessWaitForEvents (pid, 487 eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, 488 true, 489 timeout); 490 491 DNBLogThreadedIf (LOG_PROCESS, 492 "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x", 493 __FUNCTION__, 494 pid, 495 set_events); 496 497 if (set_events == 0) 498 { 499 if (err_str && err_len > 0) 500 snprintf(err_str, err_len, "operation timed out"); 501 pid = INVALID_NUB_PROCESS; 502 } 503 else 504 { 505 if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged)) 506 { 507 nub_state_t pid_state = DNBProcessGetState (pid); 508 DNBLogThreadedIf (LOG_PROCESS, "%s process %4.4x state changed (eEventProcessStateChanged): %s", 509 __FUNCTION__, pid, DNBStateAsString(pid_state)); 510 511 switch (pid_state) 512 { 513 default: 514 case eStateInvalid: 515 case eStateUnloaded: 516 case eStateAttaching: 517 case eStateLaunching: 518 case eStateSuspended: 519 break; // Ignore 520 521 case eStateRunning: 522 case eStateStepping: 523 // Still waiting to stop at entry point... 524 break; 525 526 case eStateStopped: 527 case eStateCrashed: 528 return pid; 529 530 case eStateDetached: 531 case eStateExited: 532 if (err_str && err_len > 0) 533 snprintf(err_str, err_len, "process exited"); 534 return INVALID_NUB_PROCESS; 535 } 536 } 537 538 DNBProcessResetEvents(pid, set_events); 539 } 540 } 541 542 return INVALID_NUB_PROCESS; 543 } 544 545 size_t 546 GetAllInfos (std::vector<struct kinfo_proc>& proc_infos) 547 { 548 size_t size = 0; 549 int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL }; 550 u_int namelen = sizeof(name)/sizeof(int); 551 int err; 552 553 // Try to find out how many processes are around so we can 554 // size the buffer appropriately. sysctl's man page specifically suggests 555 // this approach, and says it returns a bit larger size than needed to 556 // handle any new processes created between then and now. 557 558 err = ::sysctl (name, namelen, NULL, &size, NULL, 0); 559 560 if ((err < 0) && (err != ENOMEM)) 561 { 562 proc_infos.clear(); 563 perror("sysctl (mib, miblen, NULL, &num_processes, NULL, 0)"); 564 return 0; 565 } 566 567 568 // Increase the size of the buffer by a few processes in case more have 569 // been spawned 570 proc_infos.resize (size / sizeof(struct kinfo_proc)); 571 size = proc_infos.size() * sizeof(struct kinfo_proc); // Make sure we don't exceed our resize... 572 err = ::sysctl (name, namelen, &proc_infos[0], &size, NULL, 0); 573 if (err < 0) 574 { 575 proc_infos.clear(); 576 return 0; 577 } 578 579 // Trim down our array to fit what we actually got back 580 proc_infos.resize(size / sizeof(struct kinfo_proc)); 581 return proc_infos.size(); 582 } 583 584 static size_t 585 GetAllInfosMatchingName(const char *full_process_name, std::vector<struct kinfo_proc>& matching_proc_infos) 586 { 587 588 matching_proc_infos.clear(); 589 if (full_process_name && full_process_name[0]) 590 { 591 // We only get the process name, not the full path, from the proc_info. So just take the 592 // base name of the process name... 593 const char *process_name; 594 process_name = strrchr (full_process_name, '/'); 595 if (process_name == NULL) 596 process_name = full_process_name; 597 else 598 process_name++; 599 600 const int process_name_len = strlen(process_name); 601 std::vector<struct kinfo_proc> proc_infos; 602 const size_t num_proc_infos = GetAllInfos(proc_infos); 603 if (num_proc_infos > 0) 604 { 605 uint32_t i; 606 for (i=0; i<num_proc_infos; i++) 607 { 608 // Skip zombie processes and processes with unset status 609 if (proc_infos[i].kp_proc.p_stat == 0 || proc_infos[i].kp_proc.p_stat == SZOMB) 610 continue; 611 612 // Check for process by name. We only check the first MAXCOMLEN 613 // chars as that is all that kp_proc.p_comm holds. 614 615 if (::strncasecmp(process_name, proc_infos[i].kp_proc.p_comm, MAXCOMLEN) == 0) 616 { 617 if (process_name_len > MAXCOMLEN) 618 { 619 // We found a matching process name whose first MAXCOMLEN 620 // characters match, but there is more to the name than 621 // this. We need to get the full process name. Use proc_pidpath, which will get 622 // us the full path to the executed process. 623 624 char proc_path_buf[PATH_MAX]; 625 626 int return_val = proc_pidpath (proc_infos[i].kp_proc.p_pid, proc_path_buf, PATH_MAX); 627 if (return_val > 0) 628 { 629 // Okay, now search backwards from that to see if there is a 630 // slash in the name. Note, even though we got all the args we don't care 631 // because the list data is just a bunch of concatenated null terminated strings 632 // so strrchr will start from the end of argv0. 633 634 const char *argv_basename = strrchr(proc_path_buf, '/'); 635 if (argv_basename) 636 { 637 // Skip the '/' 638 ++argv_basename; 639 } 640 else 641 { 642 // We didn't find a directory delimiter in the process argv[0], just use what was in there 643 argv_basename = proc_path_buf; 644 } 645 646 if (argv_basename) 647 { 648 if (::strncasecmp(process_name, argv_basename, PATH_MAX) == 0) 649 { 650 matching_proc_infos.push_back(proc_infos[i]); 651 } 652 } 653 } 654 } 655 else 656 { 657 // We found a matching process, add it to our list 658 matching_proc_infos.push_back(proc_infos[i]); 659 } 660 } 661 } 662 } 663 } 664 // return the newly added matches. 665 return matching_proc_infos.size(); 666 } 667 668 nub_process_t 669 DNBProcessAttachWait (const char *waitfor_process_name, 670 nub_launch_flavor_t launch_flavor, 671 bool ignore_existing, 672 struct timespec *timeout_abstime, 673 useconds_t waitfor_interval, 674 char *err_str, 675 size_t err_len, 676 DNBShouldCancelCallback should_cancel_callback, 677 void *callback_data) 678 { 679 DNBError prepare_error; 680 std::vector<struct kinfo_proc> exclude_proc_infos; 681 size_t num_exclude_proc_infos; 682 683 // If the PrepareForAttach returns a valid token, use MachProcess to check 684 // for the process, otherwise scan the process table. 685 686 const void *attach_token = MachProcess::PrepareForAttach (waitfor_process_name, launch_flavor, true, prepare_error); 687 688 if (prepare_error.Fail()) 689 { 690 DNBLogError ("Error in PrepareForAttach: %s", prepare_error.AsString()); 691 return INVALID_NUB_PROCESS; 692 } 693 694 if (attach_token == NULL) 695 { 696 if (ignore_existing) 697 num_exclude_proc_infos = GetAllInfosMatchingName (waitfor_process_name, exclude_proc_infos); 698 else 699 num_exclude_proc_infos = 0; 700 } 701 702 DNBLogThreadedIf (LOG_PROCESS, "Waiting for '%s' to appear...\n", waitfor_process_name); 703 704 // Loop and try to find the process by name 705 nub_process_t waitfor_pid = INVALID_NUB_PROCESS; 706 707 while (waitfor_pid == INVALID_NUB_PROCESS) 708 { 709 if (attach_token != NULL) 710 { 711 nub_process_t pid; 712 pid = MachProcess::CheckForProcess(attach_token); 713 if (pid != INVALID_NUB_PROCESS) 714 { 715 waitfor_pid = pid; 716 break; 717 } 718 } 719 else 720 { 721 722 // Get the current process list, and check for matches that 723 // aren't in our original list. If anyone wants to attach 724 // to an existing process by name, they should do it with 725 // --attach=PROCNAME. Else we will wait for the first matching 726 // process that wasn't in our exclusion list. 727 std::vector<struct kinfo_proc> proc_infos; 728 const size_t num_proc_infos = GetAllInfosMatchingName (waitfor_process_name, proc_infos); 729 for (size_t i=0; i<num_proc_infos; i++) 730 { 731 nub_process_t curr_pid = proc_infos[i].kp_proc.p_pid; 732 for (size_t j=0; j<num_exclude_proc_infos; j++) 733 { 734 if (curr_pid == exclude_proc_infos[j].kp_proc.p_pid) 735 { 736 // This process was in our exclusion list, don't use it. 737 curr_pid = INVALID_NUB_PROCESS; 738 break; 739 } 740 } 741 742 // If we didn't find CURR_PID in our exclusion list, then use it. 743 if (curr_pid != INVALID_NUB_PROCESS) 744 { 745 // We found our process! 746 waitfor_pid = curr_pid; 747 break; 748 } 749 } 750 } 751 752 // If we haven't found our process yet, check for a timeout 753 // and then sleep for a bit until we poll again. 754 if (waitfor_pid == INVALID_NUB_PROCESS) 755 { 756 if (timeout_abstime != NULL) 757 { 758 // Check to see if we have a waitfor-duration option that 759 // has timed out? 760 if (DNBTimer::TimeOfDayLaterThan(*timeout_abstime)) 761 { 762 if (err_str && err_len > 0) 763 snprintf(err_str, err_len, "operation timed out"); 764 DNBLogError ("error: waiting for process '%s' timed out.\n", waitfor_process_name); 765 return INVALID_NUB_PROCESS; 766 } 767 } 768 769 // Call the should cancel callback as well... 770 771 if (should_cancel_callback != NULL 772 && should_cancel_callback (callback_data)) 773 { 774 DNBLogThreadedIf (LOG_PROCESS, "DNBProcessAttachWait cancelled by should_cancel callback."); 775 waitfor_pid = INVALID_NUB_PROCESS; 776 break; 777 } 778 779 ::usleep (waitfor_interval); // Sleep for WAITFOR_INTERVAL, then poll again 780 } 781 } 782 783 if (waitfor_pid != INVALID_NUB_PROCESS) 784 { 785 DNBLogThreadedIf (LOG_PROCESS, "Attaching to %s with pid %i...\n", waitfor_process_name, waitfor_pid); 786 waitfor_pid = DNBProcessAttach (waitfor_pid, timeout_abstime, err_str, err_len); 787 } 788 789 bool success = waitfor_pid != INVALID_NUB_PROCESS; 790 MachProcess::CleanupAfterAttach (attach_token, success, prepare_error); 791 792 return waitfor_pid; 793 } 794 795 nub_bool_t 796 DNBProcessDetach (nub_process_t pid) 797 { 798 MachProcessSP procSP; 799 if (GetProcessSP (pid, procSP)) 800 { 801 const bool remove = true; 802 DNBLogThreaded("Disabling breakpoints and watchpoints, and detaching from %d.", pid); 803 procSP->DisableAllBreakpoints(remove); 804 procSP->DisableAllWatchpoints (remove); 805 return procSP->Detach(); 806 } 807 return false; 808 } 809 810 nub_bool_t 811 DNBProcessKill (nub_process_t pid) 812 { 813 MachProcessSP procSP; 814 if (GetProcessSP (pid, procSP)) 815 { 816 return procSP->Kill (); 817 } 818 return false; 819 } 820 821 nub_bool_t 822 DNBProcessSignal (nub_process_t pid, int signal) 823 { 824 MachProcessSP procSP; 825 if (GetProcessSP (pid, procSP)) 826 { 827 return procSP->Signal (signal); 828 } 829 return false; 830 } 831 832 833 nub_bool_t 834 DNBProcessInterrupt(nub_process_t pid) 835 { 836 MachProcessSP procSP; 837 if (GetProcessSP (pid, procSP)) 838 return procSP->Interrupt(); 839 return false; 840 } 841 842 nub_bool_t 843 DNBProcessSendEvent (nub_process_t pid, const char *event) 844 { 845 MachProcessSP procSP; 846 if (GetProcessSP (pid, procSP)) 847 { 848 // FIXME: Do something with the error... 849 DNBError send_error; 850 return procSP->SendEvent (event, send_error); 851 } 852 return false; 853 } 854 855 856 nub_bool_t 857 DNBProcessIsAlive (nub_process_t pid) 858 { 859 MachProcessSP procSP; 860 if (GetProcessSP (pid, procSP)) 861 { 862 return MachTask::IsValid (procSP->Task().TaskPort()); 863 } 864 return eStateInvalid; 865 } 866 867 //---------------------------------------------------------------------- 868 // Process and Thread state information 869 //---------------------------------------------------------------------- 870 nub_state_t 871 DNBProcessGetState (nub_process_t pid) 872 { 873 MachProcessSP procSP; 874 if (GetProcessSP (pid, procSP)) 875 { 876 return procSP->GetState(); 877 } 878 return eStateInvalid; 879 } 880 881 //---------------------------------------------------------------------- 882 // Process and Thread state information 883 //---------------------------------------------------------------------- 884 nub_bool_t 885 DNBProcessGetExitStatus (nub_process_t pid, int* status) 886 { 887 MachProcessSP procSP; 888 if (GetProcessSP (pid, procSP)) 889 { 890 return procSP->GetExitStatus(status); 891 } 892 return false; 893 } 894 895 nub_bool_t 896 DNBProcessSetExitStatus (nub_process_t pid, int status) 897 { 898 MachProcessSP procSP; 899 if (GetProcessSP (pid, procSP)) 900 { 901 procSP->SetExitStatus(status); 902 return true; 903 } 904 return false; 905 } 906 907 const char * 908 DNBProcessGetExitInfo (nub_process_t pid) 909 { 910 MachProcessSP procSP; 911 if (GetProcessSP (pid, procSP)) 912 { 913 return procSP->GetExitInfo(); 914 } 915 return NULL; 916 } 917 918 nub_bool_t 919 DNBProcessSetExitInfo (nub_process_t pid, const char *info) 920 { 921 MachProcessSP procSP; 922 if (GetProcessSP (pid, procSP)) 923 { 924 procSP->SetExitInfo(info); 925 return true; 926 } 927 return false; 928 } 929 930 const char * 931 DNBThreadGetName (nub_process_t pid, nub_thread_t tid) 932 { 933 MachProcessSP procSP; 934 if (GetProcessSP (pid, procSP)) 935 return procSP->ThreadGetName(tid); 936 return NULL; 937 } 938 939 940 nub_bool_t 941 DNBThreadGetIdentifierInfo (nub_process_t pid, nub_thread_t tid, thread_identifier_info_data_t *ident_info) 942 { 943 MachProcessSP procSP; 944 if (GetProcessSP (pid, procSP)) 945 return procSP->GetThreadList().GetIdentifierInfo(tid, ident_info); 946 return false; 947 } 948 949 nub_state_t 950 DNBThreadGetState (nub_process_t pid, nub_thread_t tid) 951 { 952 MachProcessSP procSP; 953 if (GetProcessSP (pid, procSP)) 954 { 955 return procSP->ThreadGetState(tid); 956 } 957 return eStateInvalid; 958 } 959 960 const char * 961 DNBStateAsString(nub_state_t state) 962 { 963 switch (state) 964 { 965 case eStateInvalid: return "Invalid"; 966 case eStateUnloaded: return "Unloaded"; 967 case eStateAttaching: return "Attaching"; 968 case eStateLaunching: return "Launching"; 969 case eStateStopped: return "Stopped"; 970 case eStateRunning: return "Running"; 971 case eStateStepping: return "Stepping"; 972 case eStateCrashed: return "Crashed"; 973 case eStateDetached: return "Detached"; 974 case eStateExited: return "Exited"; 975 case eStateSuspended: return "Suspended"; 976 } 977 return "nub_state_t ???"; 978 } 979 980 const char * 981 DNBProcessGetExecutablePath (nub_process_t pid) 982 { 983 MachProcessSP procSP; 984 if (GetProcessSP (pid, procSP)) 985 { 986 return procSP->Path(); 987 } 988 return NULL; 989 } 990 991 nub_size_t 992 DNBProcessGetArgumentCount (nub_process_t pid) 993 { 994 MachProcessSP procSP; 995 if (GetProcessSP (pid, procSP)) 996 { 997 return procSP->ArgumentCount(); 998 } 999 return 0; 1000 } 1001 1002 const char * 1003 DNBProcessGetArgumentAtIndex (nub_process_t pid, nub_size_t idx) 1004 { 1005 MachProcessSP procSP; 1006 if (GetProcessSP (pid, procSP)) 1007 { 1008 return procSP->ArgumentAtIndex (idx); 1009 } 1010 return NULL; 1011 } 1012 1013 1014 //---------------------------------------------------------------------- 1015 // Execution control 1016 //---------------------------------------------------------------------- 1017 nub_bool_t 1018 DNBProcessResume (nub_process_t pid, const DNBThreadResumeAction *actions, size_t num_actions) 1019 { 1020 DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid); 1021 MachProcessSP procSP; 1022 if (GetProcessSP (pid, procSP)) 1023 { 1024 DNBThreadResumeActions thread_actions (actions, num_actions); 1025 1026 // Below we add a default thread plan just in case one wasn't 1027 // provided so all threads always know what they were supposed to do 1028 if (thread_actions.IsEmpty()) 1029 { 1030 // No thread plans were given, so the default it to run all threads 1031 thread_actions.SetDefaultThreadActionIfNeeded (eStateRunning, 0); 1032 } 1033 else 1034 { 1035 // Some thread plans were given which means anything that wasn't 1036 // specified should remain stopped. 1037 thread_actions.SetDefaultThreadActionIfNeeded (eStateStopped, 0); 1038 } 1039 return procSP->Resume (thread_actions); 1040 } 1041 return false; 1042 } 1043 1044 nub_bool_t 1045 DNBProcessHalt (nub_process_t pid) 1046 { 1047 DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid); 1048 MachProcessSP procSP; 1049 if (GetProcessSP (pid, procSP)) 1050 return procSP->Signal (SIGSTOP); 1051 return false; 1052 } 1053 // 1054 //nub_bool_t 1055 //DNBThreadResume (nub_process_t pid, nub_thread_t tid, nub_bool_t step) 1056 //{ 1057 // DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u)", __FUNCTION__, pid, tid, (uint32_t)step); 1058 // MachProcessSP procSP; 1059 // if (GetProcessSP (pid, procSP)) 1060 // { 1061 // return procSP->Resume(tid, step, 0); 1062 // } 1063 // return false; 1064 //} 1065 // 1066 //nub_bool_t 1067 //DNBThreadResumeWithSignal (nub_process_t pid, nub_thread_t tid, nub_bool_t step, int signal) 1068 //{ 1069 // DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u, signal = %i)", __FUNCTION__, pid, tid, (uint32_t)step, signal); 1070 // MachProcessSP procSP; 1071 // if (GetProcessSP (pid, procSP)) 1072 // { 1073 // return procSP->Resume(tid, step, signal); 1074 // } 1075 // return false; 1076 //} 1077 1078 nub_event_t 1079 DNBProcessWaitForEvents (nub_process_t pid, nub_event_t event_mask, bool wait_for_set, struct timespec* timeout) 1080 { 1081 nub_event_t result = 0; 1082 MachProcessSP procSP; 1083 if (GetProcessSP (pid, procSP)) 1084 { 1085 if (wait_for_set) 1086 result = procSP->Events().WaitForSetEvents(event_mask, timeout); 1087 else 1088 result = procSP->Events().WaitForEventsToReset(event_mask, timeout); 1089 } 1090 return result; 1091 } 1092 1093 void 1094 DNBProcessResetEvents (nub_process_t pid, nub_event_t event_mask) 1095 { 1096 MachProcessSP procSP; 1097 if (GetProcessSP (pid, procSP)) 1098 procSP->Events().ResetEvents(event_mask); 1099 } 1100 1101 // Breakpoints 1102 nub_bool_t 1103 DNBBreakpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, nub_bool_t hardware) 1104 { 1105 MachProcessSP procSP; 1106 if (GetProcessSP (pid, procSP)) 1107 return procSP->CreateBreakpoint(addr, size, hardware) != NULL; 1108 return false; 1109 } 1110 1111 nub_bool_t 1112 DNBBreakpointClear (nub_process_t pid, nub_addr_t addr) 1113 { 1114 MachProcessSP procSP; 1115 if (GetProcessSP (pid, procSP)) 1116 return procSP->DisableBreakpoint(addr, true); 1117 return false; // Failed 1118 } 1119 1120 1121 //---------------------------------------------------------------------- 1122 // Watchpoints 1123 //---------------------------------------------------------------------- 1124 nub_bool_t 1125 DNBWatchpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, uint32_t watch_flags, nub_bool_t hardware) 1126 { 1127 MachProcessSP procSP; 1128 if (GetProcessSP (pid, procSP)) 1129 return procSP->CreateWatchpoint(addr, size, watch_flags, hardware) != NULL; 1130 return false; 1131 } 1132 1133 nub_bool_t 1134 DNBWatchpointClear (nub_process_t pid, nub_addr_t addr) 1135 { 1136 MachProcessSP procSP; 1137 if (GetProcessSP (pid, procSP)) 1138 return procSP->DisableWatchpoint(addr, true); 1139 return false; // Failed 1140 } 1141 1142 //---------------------------------------------------------------------- 1143 // Return the number of supported hardware watchpoints. 1144 //---------------------------------------------------------------------- 1145 uint32_t 1146 DNBWatchpointGetNumSupportedHWP (nub_process_t pid) 1147 { 1148 MachProcessSP procSP; 1149 if (GetProcessSP (pid, procSP)) 1150 return procSP->GetNumSupportedHardwareWatchpoints(); 1151 return 0; 1152 } 1153 1154 //---------------------------------------------------------------------- 1155 // Read memory in the address space of process PID. This call will take 1156 // care of setting and restoring permissions and breaking up the memory 1157 // read into multiple chunks as required. 1158 // 1159 // RETURNS: number of bytes actually read 1160 //---------------------------------------------------------------------- 1161 nub_size_t 1162 DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub_size_t size, void *buf) 1163 { 1164 MachProcessSP procSP; 1165 if (GetProcessSP (pid, procSP)) 1166 return procSP->ReadMemory(addr, size, buf); 1167 return 0; 1168 } 1169 1170 //---------------------------------------------------------------------- 1171 // Write memory to the address space of process PID. This call will take 1172 // care of setting and restoring permissions and breaking up the memory 1173 // write into multiple chunks as required. 1174 // 1175 // RETURNS: number of bytes actually written 1176 //---------------------------------------------------------------------- 1177 nub_size_t 1178 DNBProcessMemoryWrite (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf) 1179 { 1180 MachProcessSP procSP; 1181 if (GetProcessSP (pid, procSP)) 1182 return procSP->WriteMemory(addr, size, buf); 1183 return 0; 1184 } 1185 1186 nub_addr_t 1187 DNBProcessMemoryAllocate (nub_process_t pid, nub_size_t size, uint32_t permissions) 1188 { 1189 MachProcessSP procSP; 1190 if (GetProcessSP (pid, procSP)) 1191 return procSP->Task().AllocateMemory (size, permissions); 1192 return 0; 1193 } 1194 1195 nub_bool_t 1196 DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr) 1197 { 1198 MachProcessSP procSP; 1199 if (GetProcessSP (pid, procSP)) 1200 return procSP->Task().DeallocateMemory (addr); 1201 return 0; 1202 } 1203 1204 //---------------------------------------------------------------------- 1205 // Find attributes of the memory region that contains ADDR for process PID, 1206 // if possible, and return a string describing those attributes. 1207 // 1208 // Returns 1 if we could find attributes for this region and OUTBUF can 1209 // be sent to the remote debugger. 1210 // 1211 // Returns 0 if we couldn't find the attributes for a region of memory at 1212 // that address and OUTBUF should not be sent. 1213 // 1214 // Returns -1 if this platform cannot look up information about memory regions 1215 // or if we do not yet have a valid launched process. 1216 // 1217 //---------------------------------------------------------------------- 1218 int 1219 DNBProcessMemoryRegionInfo (nub_process_t pid, nub_addr_t addr, DNBRegionInfo *region_info) 1220 { 1221 MachProcessSP procSP; 1222 if (GetProcessSP (pid, procSP)) 1223 return procSP->Task().GetMemoryRegionInfo (addr, region_info); 1224 1225 return -1; 1226 } 1227 1228 std::string 1229 DNBProcessGetProfileData (nub_process_t pid, DNBProfileDataScanType scanType) 1230 { 1231 MachProcessSP procSP; 1232 if (GetProcessSP (pid, procSP)) 1233 return procSP->Task().GetProfileData(scanType); 1234 1235 return std::string(""); 1236 } 1237 1238 nub_bool_t 1239 DNBProcessSetEnableAsyncProfiling (nub_process_t pid, nub_bool_t enable, uint64_t interval_usec, DNBProfileDataScanType scan_type) 1240 { 1241 MachProcessSP procSP; 1242 if (GetProcessSP (pid, procSP)) 1243 { 1244 procSP->SetEnableAsyncProfiling(enable, interval_usec, scan_type); 1245 return true; 1246 } 1247 1248 return false; 1249 } 1250 1251 //---------------------------------------------------------------------- 1252 // Formatted output that uses memory and registers from process and 1253 // thread in place of arguments. 1254 //---------------------------------------------------------------------- 1255 nub_size_t 1256 DNBPrintf (nub_process_t pid, nub_thread_t tid, nub_addr_t base_addr, FILE *file, const char *format) 1257 { 1258 if (file == NULL) 1259 return 0; 1260 enum printf_flags 1261 { 1262 alternate_form = (1 << 0), 1263 zero_padding = (1 << 1), 1264 negative_field_width = (1 << 2), 1265 blank_space = (1 << 3), 1266 show_sign = (1 << 4), 1267 show_thousands_separator= (1 << 5), 1268 }; 1269 1270 enum printf_length_modifiers 1271 { 1272 length_mod_h = (1 << 0), 1273 length_mod_hh = (1 << 1), 1274 length_mod_l = (1 << 2), 1275 length_mod_ll = (1 << 3), 1276 length_mod_L = (1 << 4), 1277 length_mod_j = (1 << 5), 1278 length_mod_t = (1 << 6), 1279 length_mod_z = (1 << 7), 1280 length_mod_q = (1 << 8), 1281 }; 1282 1283 nub_addr_t addr = base_addr; 1284 char *end_format = (char*)format + strlen(format); 1285 char *end = NULL; // For strtoXXXX calls; 1286 std::basic_string<uint8_t> buf; 1287 nub_size_t total_bytes_read = 0; 1288 DNBDataRef data; 1289 const char *f; 1290 for (f = format; *f != '\0' && f < end_format; f++) 1291 { 1292 char ch = *f; 1293 switch (ch) 1294 { 1295 case '%': 1296 { 1297 f++; // Skip the '%' character 1298 // int min_field_width = 0; 1299 // int precision = 0; 1300 //uint32_t flags = 0; 1301 uint32_t length_modifiers = 0; 1302 uint32_t byte_size = 0; 1303 uint32_t actual_byte_size = 0; 1304 bool is_string = false; 1305 bool is_register = false; 1306 DNBRegisterValue register_value; 1307 int64_t register_offset = 0; 1308 nub_addr_t register_addr = INVALID_NUB_ADDRESS; 1309 1310 // Create the format string to use for this conversion specification 1311 // so we can remove and mprintf specific flags and formatters. 1312 std::string fprintf_format("%"); 1313 1314 // Decode any flags 1315 switch (*f) 1316 { 1317 case '#': fprintf_format += *f++; break; //flags |= alternate_form; break; 1318 case '0': fprintf_format += *f++; break; //flags |= zero_padding; break; 1319 case '-': fprintf_format += *f++; break; //flags |= negative_field_width; break; 1320 case ' ': fprintf_format += *f++; break; //flags |= blank_space; break; 1321 case '+': fprintf_format += *f++; break; //flags |= show_sign; break; 1322 case ',': fprintf_format += *f++; break; //flags |= show_thousands_separator;break; 1323 case '{': 1324 case '[': 1325 { 1326 // We have a register name specification that can take two forms: 1327 // ${regname} or ${regname+offset} 1328 // The action is to read the register value and add the signed offset 1329 // (if any) and use that as the value to format. 1330 // $[regname] or $[regname+offset] 1331 // The action is to read the register value and add the signed offset 1332 // (if any) and use the result as an address to dereference. The size 1333 // of what is dereferenced is specified by the actual byte size that 1334 // follows the minimum field width and precision (see comments below). 1335 switch (*f) 1336 { 1337 case '{': 1338 case '[': 1339 { 1340 char open_scope_ch = *f; 1341 f++; 1342 const char *reg_name = f; 1343 size_t reg_name_length = strcspn(f, "+-}]"); 1344 if (reg_name_length > 0) 1345 { 1346 std::string register_name(reg_name, reg_name_length); 1347 f += reg_name_length; 1348 register_offset = strtoll(f, &end, 0); 1349 if (f < end) 1350 f = end; 1351 if ((open_scope_ch == '{' && *f != '}') || (open_scope_ch == '[' && *f != ']')) 1352 { 1353 fprintf(file, "error: Invalid register format string. Valid formats are %%{regname} or %%{regname+offset}, %%[regname] or %%[regname+offset]\n"); 1354 return total_bytes_read; 1355 } 1356 else 1357 { 1358 f++; 1359 if (DNBThreadGetRegisterValueByName(pid, tid, REGISTER_SET_ALL, register_name.c_str(), ®ister_value)) 1360 { 1361 // Set the address to dereference using the register value plus the offset 1362 switch (register_value.info.size) 1363 { 1364 default: 1365 case 0: 1366 fprintf (file, "error: unsupported register size of %u.\n", register_value.info.size); 1367 return total_bytes_read; 1368 1369 case 1: register_addr = register_value.value.uint8 + register_offset; break; 1370 case 2: register_addr = register_value.value.uint16 + register_offset; break; 1371 case 4: register_addr = register_value.value.uint32 + register_offset; break; 1372 case 8: register_addr = register_value.value.uint64 + register_offset; break; 1373 case 16: 1374 if (open_scope_ch == '[') 1375 { 1376 fprintf (file, "error: register size (%u) too large for address.\n", register_value.info.size); 1377 return total_bytes_read; 1378 } 1379 break; 1380 } 1381 1382 if (open_scope_ch == '{') 1383 { 1384 byte_size = register_value.info.size; 1385 is_register = true; // value is in a register 1386 1387 } 1388 else 1389 { 1390 addr = register_addr; // Use register value and offset as the address 1391 } 1392 } 1393 else 1394 { 1395 fprintf(file, "error: unable to read register '%s' for process %#.4x and thread %#.8" PRIx64 "\n", register_name.c_str(), pid, tid); 1396 return total_bytes_read; 1397 } 1398 } 1399 } 1400 } 1401 break; 1402 1403 default: 1404 fprintf(file, "error: %%$ must be followed by (regname + n) or [regname + n]\n"); 1405 return total_bytes_read; 1406 } 1407 } 1408 break; 1409 } 1410 1411 // Check for a minimum field width 1412 if (isdigit(*f)) 1413 { 1414 //min_field_width = strtoul(f, &end, 10); 1415 strtoul(f, &end, 10); 1416 if (end > f) 1417 { 1418 fprintf_format.append(f, end - f); 1419 f = end; 1420 } 1421 } 1422 1423 1424 // Check for a precision 1425 if (*f == '.') 1426 { 1427 f++; 1428 if (isdigit(*f)) 1429 { 1430 fprintf_format += '.'; 1431 //precision = strtoul(f, &end, 10); 1432 strtoul(f, &end, 10); 1433 if (end > f) 1434 { 1435 fprintf_format.append(f, end - f); 1436 f = end; 1437 } 1438 } 1439 } 1440 1441 1442 // mprintf specific: read the optional actual byte size (abs) 1443 // after the standard minimum field width (mfw) and precision (prec). 1444 // Standard printf calls you can have "mfw.prec" or ".prec", but 1445 // mprintf can have "mfw.prec.abs", ".prec.abs" or "..abs". This is nice 1446 // for strings that may be in a fixed size buffer, but may not use all bytes 1447 // in that buffer for printable characters. 1448 if (*f == '.') 1449 { 1450 f++; 1451 actual_byte_size = strtoul(f, &end, 10); 1452 if (end > f) 1453 { 1454 byte_size = actual_byte_size; 1455 f = end; 1456 } 1457 } 1458 1459 // Decode the length modifiers 1460 switch (*f) 1461 { 1462 case 'h': // h and hh length modifiers 1463 fprintf_format += *f++; 1464 length_modifiers |= length_mod_h; 1465 if (*f == 'h') 1466 { 1467 fprintf_format += *f++; 1468 length_modifiers |= length_mod_hh; 1469 } 1470 break; 1471 1472 case 'l': // l and ll length modifiers 1473 fprintf_format += *f++; 1474 length_modifiers |= length_mod_l; 1475 if (*f == 'h') 1476 { 1477 fprintf_format += *f++; 1478 length_modifiers |= length_mod_ll; 1479 } 1480 break; 1481 1482 case 'L': fprintf_format += *f++; length_modifiers |= length_mod_L; break; 1483 case 'j': fprintf_format += *f++; length_modifiers |= length_mod_j; break; 1484 case 't': fprintf_format += *f++; length_modifiers |= length_mod_t; break; 1485 case 'z': fprintf_format += *f++; length_modifiers |= length_mod_z; break; 1486 case 'q': fprintf_format += *f++; length_modifiers |= length_mod_q; break; 1487 } 1488 1489 // Decode the conversion specifier 1490 switch (*f) 1491 { 1492 case '_': 1493 // mprintf specific format items 1494 { 1495 ++f; // Skip the '_' character 1496 switch (*f) 1497 { 1498 case 'a': // Print the current address 1499 ++f; 1500 fprintf_format += "ll"; 1501 fprintf_format += *f; // actual format to show address with folows the 'a' ("%_ax") 1502 fprintf (file, fprintf_format.c_str(), addr); 1503 break; 1504 case 'o': // offset from base address 1505 ++f; 1506 fprintf_format += "ll"; 1507 fprintf_format += *f; // actual format to show address with folows the 'a' ("%_ox") 1508 fprintf(file, fprintf_format.c_str(), addr - base_addr); 1509 break; 1510 default: 1511 fprintf (file, "error: unsupported mprintf specific format character '%c'.\n", *f); 1512 break; 1513 } 1514 continue; 1515 } 1516 break; 1517 1518 case 'D': 1519 case 'O': 1520 case 'U': 1521 fprintf_format += *f; 1522 if (byte_size == 0) 1523 byte_size = sizeof(long int); 1524 break; 1525 1526 case 'd': 1527 case 'i': 1528 case 'o': 1529 case 'u': 1530 case 'x': 1531 case 'X': 1532 fprintf_format += *f; 1533 if (byte_size == 0) 1534 { 1535 if (length_modifiers & length_mod_hh) 1536 byte_size = sizeof(char); 1537 else if (length_modifiers & length_mod_h) 1538 byte_size = sizeof(short); 1539 else if (length_modifiers & length_mod_ll) 1540 byte_size = sizeof(long long); 1541 else if (length_modifiers & length_mod_l) 1542 byte_size = sizeof(long); 1543 else 1544 byte_size = sizeof(int); 1545 } 1546 break; 1547 1548 case 'a': 1549 case 'A': 1550 case 'f': 1551 case 'F': 1552 case 'e': 1553 case 'E': 1554 case 'g': 1555 case 'G': 1556 fprintf_format += *f; 1557 if (byte_size == 0) 1558 { 1559 if (length_modifiers & length_mod_L) 1560 byte_size = sizeof(long double); 1561 else 1562 byte_size = sizeof(double); 1563 } 1564 break; 1565 1566 case 'c': 1567 if ((length_modifiers & length_mod_l) == 0) 1568 { 1569 fprintf_format += *f; 1570 if (byte_size == 0) 1571 byte_size = sizeof(char); 1572 break; 1573 } 1574 // Fall through to 'C' modifier below... 1575 1576 case 'C': 1577 fprintf_format += *f; 1578 if (byte_size == 0) 1579 byte_size = sizeof(wchar_t); 1580 break; 1581 1582 case 's': 1583 fprintf_format += *f; 1584 if (is_register || byte_size == 0) 1585 is_string = 1; 1586 break; 1587 1588 case 'p': 1589 fprintf_format += *f; 1590 if (byte_size == 0) 1591 byte_size = sizeof(void*); 1592 break; 1593 } 1594 1595 if (is_string) 1596 { 1597 std::string mem_string; 1598 const size_t string_buf_len = 4; 1599 char string_buf[string_buf_len+1]; 1600 char *string_buf_end = string_buf + string_buf_len; 1601 string_buf[string_buf_len] = '\0'; 1602 nub_size_t bytes_read; 1603 nub_addr_t str_addr = is_register ? register_addr : addr; 1604 while ((bytes_read = DNBProcessMemoryRead(pid, str_addr, string_buf_len, &string_buf[0])) > 0) 1605 { 1606 // Did we get a NULL termination character yet? 1607 if (strchr(string_buf, '\0') == string_buf_end) 1608 { 1609 // no NULL terminator yet, append as a std::string 1610 mem_string.append(string_buf, string_buf_len); 1611 str_addr += string_buf_len; 1612 } 1613 else 1614 { 1615 // yep 1616 break; 1617 } 1618 } 1619 // Append as a C-string so we don't get the extra NULL 1620 // characters in the temp buffer (since it was resized) 1621 mem_string += string_buf; 1622 size_t mem_string_len = mem_string.size() + 1; 1623 fprintf(file, fprintf_format.c_str(), mem_string.c_str()); 1624 if (mem_string_len > 0) 1625 { 1626 if (!is_register) 1627 { 1628 addr += mem_string_len; 1629 total_bytes_read += mem_string_len; 1630 } 1631 } 1632 else 1633 return total_bytes_read; 1634 } 1635 else 1636 if (byte_size > 0) 1637 { 1638 buf.resize(byte_size); 1639 nub_size_t bytes_read = 0; 1640 if (is_register) 1641 bytes_read = register_value.info.size; 1642 else 1643 bytes_read = DNBProcessMemoryRead(pid, addr, buf.size(), &buf[0]); 1644 if (bytes_read > 0) 1645 { 1646 if (!is_register) 1647 total_bytes_read += bytes_read; 1648 1649 if (bytes_read == byte_size) 1650 { 1651 switch (*f) 1652 { 1653 case 'd': 1654 case 'i': 1655 case 'o': 1656 case 'u': 1657 case 'X': 1658 case 'x': 1659 case 'a': 1660 case 'A': 1661 case 'f': 1662 case 'F': 1663 case 'e': 1664 case 'E': 1665 case 'g': 1666 case 'G': 1667 case 'p': 1668 case 'c': 1669 case 'C': 1670 { 1671 if (is_register) 1672 data.SetData(®ister_value.value.v_uint8[0], register_value.info.size); 1673 else 1674 data.SetData(&buf[0], bytes_read); 1675 DNBDataRef::offset_t data_offset = 0; 1676 if (byte_size <= 4) 1677 { 1678 uint32_t u32 = data.GetMax32(&data_offset, byte_size); 1679 // Show the actual byte width when displaying hex 1680 fprintf(file, fprintf_format.c_str(), u32); 1681 } 1682 else if (byte_size <= 8) 1683 { 1684 uint64_t u64 = data.GetMax64(&data_offset, byte_size); 1685 // Show the actual byte width when displaying hex 1686 fprintf(file, fprintf_format.c_str(), u64); 1687 } 1688 else 1689 { 1690 fprintf(file, "error: integer size not supported, must be 8 bytes or less (%u bytes).\n", byte_size); 1691 } 1692 if (!is_register) 1693 addr += byte_size; 1694 } 1695 break; 1696 1697 case 's': 1698 fprintf(file, fprintf_format.c_str(), buf.c_str()); 1699 addr += byte_size; 1700 break; 1701 1702 default: 1703 fprintf(file, "error: unsupported conversion specifier '%c'.\n", *f); 1704 break; 1705 } 1706 } 1707 } 1708 } 1709 else 1710 return total_bytes_read; 1711 } 1712 break; 1713 1714 case '\\': 1715 { 1716 f++; 1717 switch (*f) 1718 { 1719 case 'e': ch = '\e'; break; 1720 case 'a': ch = '\a'; break; 1721 case 'b': ch = '\b'; break; 1722 case 'f': ch = '\f'; break; 1723 case 'n': ch = '\n'; break; 1724 case 'r': ch = '\r'; break; 1725 case 't': ch = '\t'; break; 1726 case 'v': ch = '\v'; break; 1727 case '\'': ch = '\''; break; 1728 case '\\': ch = '\\'; break; 1729 case '0': 1730 case '1': 1731 case '2': 1732 case '3': 1733 case '4': 1734 case '5': 1735 case '6': 1736 case '7': 1737 ch = strtoul(f, &end, 8); 1738 f = end; 1739 break; 1740 default: 1741 ch = *f; 1742 break; 1743 } 1744 fputc(ch, file); 1745 } 1746 break; 1747 1748 default: 1749 fputc(ch, file); 1750 break; 1751 } 1752 } 1753 return total_bytes_read; 1754 } 1755 1756 1757 //---------------------------------------------------------------------- 1758 // Get the number of threads for the specified process. 1759 //---------------------------------------------------------------------- 1760 nub_size_t 1761 DNBProcessGetNumThreads (nub_process_t pid) 1762 { 1763 MachProcessSP procSP; 1764 if (GetProcessSP (pid, procSP)) 1765 return procSP->GetNumThreads(); 1766 return 0; 1767 } 1768 1769 //---------------------------------------------------------------------- 1770 // Get the thread ID of the current thread. 1771 //---------------------------------------------------------------------- 1772 nub_thread_t 1773 DNBProcessGetCurrentThread (nub_process_t pid) 1774 { 1775 MachProcessSP procSP; 1776 if (GetProcessSP (pid, procSP)) 1777 return procSP->GetCurrentThread(); 1778 return 0; 1779 } 1780 1781 //---------------------------------------------------------------------- 1782 // Get the mach port number of the current thread. 1783 //---------------------------------------------------------------------- 1784 nub_thread_t 1785 DNBProcessGetCurrentThreadMachPort (nub_process_t pid) 1786 { 1787 MachProcessSP procSP; 1788 if (GetProcessSP (pid, procSP)) 1789 return procSP->GetCurrentThreadMachPort(); 1790 return 0; 1791 } 1792 1793 //---------------------------------------------------------------------- 1794 // Change the current thread. 1795 //---------------------------------------------------------------------- 1796 nub_thread_t 1797 DNBProcessSetCurrentThread (nub_process_t pid, nub_thread_t tid) 1798 { 1799 MachProcessSP procSP; 1800 if (GetProcessSP (pid, procSP)) 1801 return procSP->SetCurrentThread (tid); 1802 return INVALID_NUB_THREAD; 1803 } 1804 1805 1806 //---------------------------------------------------------------------- 1807 // Dump a string describing a thread's stop reason to the specified file 1808 // handle 1809 //---------------------------------------------------------------------- 1810 nub_bool_t 1811 DNBThreadGetStopReason (nub_process_t pid, nub_thread_t tid, struct DNBThreadStopInfo *stop_info) 1812 { 1813 MachProcessSP procSP; 1814 if (GetProcessSP (pid, procSP)) 1815 return procSP->GetThreadStoppedReason (tid, stop_info); 1816 return false; 1817 } 1818 1819 //---------------------------------------------------------------------- 1820 // Return string description for the specified thread. 1821 // 1822 // RETURNS: NULL if the thread isn't valid, else a NULL terminated C 1823 // string from a static buffer that must be copied prior to subsequent 1824 // calls. 1825 //---------------------------------------------------------------------- 1826 const char * 1827 DNBThreadGetInfo (nub_process_t pid, nub_thread_t tid) 1828 { 1829 MachProcessSP procSP; 1830 if (GetProcessSP (pid, procSP)) 1831 return procSP->GetThreadInfo (tid); 1832 return NULL; 1833 } 1834 1835 //---------------------------------------------------------------------- 1836 // Get the thread ID given a thread index. 1837 //---------------------------------------------------------------------- 1838 nub_thread_t 1839 DNBProcessGetThreadAtIndex (nub_process_t pid, size_t thread_idx) 1840 { 1841 MachProcessSP procSP; 1842 if (GetProcessSP (pid, procSP)) 1843 return procSP->GetThreadAtIndex (thread_idx); 1844 return INVALID_NUB_THREAD; 1845 } 1846 1847 //---------------------------------------------------------------------- 1848 // Do whatever is needed to sync the thread's register state with it's kernel values. 1849 //---------------------------------------------------------------------- 1850 nub_bool_t 1851 DNBProcessSyncThreadState (nub_process_t pid, nub_thread_t tid) 1852 { 1853 MachProcessSP procSP; 1854 if (GetProcessSP (pid, procSP)) 1855 return procSP->SyncThreadState (tid); 1856 return false; 1857 1858 } 1859 1860 nub_addr_t 1861 DNBProcessGetSharedLibraryInfoAddress (nub_process_t pid) 1862 { 1863 MachProcessSP procSP; 1864 DNBError err; 1865 if (GetProcessSP (pid, procSP)) 1866 return procSP->Task().GetDYLDAllImageInfosAddress (err); 1867 return INVALID_NUB_ADDRESS; 1868 } 1869 1870 1871 nub_bool_t 1872 DNBProcessSharedLibrariesUpdated(nub_process_t pid) 1873 { 1874 MachProcessSP procSP; 1875 if (GetProcessSP (pid, procSP)) 1876 { 1877 procSP->SharedLibrariesUpdated (); 1878 return true; 1879 } 1880 return false; 1881 } 1882 1883 //---------------------------------------------------------------------- 1884 // Get the current shared library information for a process. Only return 1885 // the shared libraries that have changed since the last shared library 1886 // state changed event if only_changed is non-zero. 1887 //---------------------------------------------------------------------- 1888 nub_size_t 1889 DNBProcessGetSharedLibraryInfo (nub_process_t pid, nub_bool_t only_changed, struct DNBExecutableImageInfo **image_infos) 1890 { 1891 MachProcessSP procSP; 1892 if (GetProcessSP (pid, procSP)) 1893 return procSP->CopyImageInfos (image_infos, only_changed); 1894 1895 // If we have no process, then return NULL for the shared library info 1896 // and zero for shared library count 1897 *image_infos = NULL; 1898 return 0; 1899 } 1900 1901 //---------------------------------------------------------------------- 1902 // Get the register set information for a specific thread. 1903 //---------------------------------------------------------------------- 1904 const DNBRegisterSetInfo * 1905 DNBGetRegisterSetInfo (nub_size_t *num_reg_sets) 1906 { 1907 return DNBArchProtocol::GetRegisterSetInfo (num_reg_sets); 1908 } 1909 1910 1911 //---------------------------------------------------------------------- 1912 // Read a register value by register set and register index. 1913 //---------------------------------------------------------------------- 1914 nub_bool_t 1915 DNBThreadGetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *value) 1916 { 1917 MachProcessSP procSP; 1918 ::bzero (value, sizeof(DNBRegisterValue)); 1919 if (GetProcessSP (pid, procSP)) 1920 { 1921 if (tid != INVALID_NUB_THREAD) 1922 return procSP->GetRegisterValue (tid, set, reg, value); 1923 } 1924 return false; 1925 } 1926 1927 nub_bool_t 1928 DNBThreadSetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value) 1929 { 1930 if (tid != INVALID_NUB_THREAD) 1931 { 1932 MachProcessSP procSP; 1933 if (GetProcessSP (pid, procSP)) 1934 return procSP->SetRegisterValue (tid, set, reg, value); 1935 } 1936 return false; 1937 } 1938 1939 nub_size_t 1940 DNBThreadGetRegisterContext (nub_process_t pid, nub_thread_t tid, void *buf, size_t buf_len) 1941 { 1942 MachProcessSP procSP; 1943 if (GetProcessSP (pid, procSP)) 1944 { 1945 if (tid != INVALID_NUB_THREAD) 1946 return procSP->GetThreadList().GetRegisterContext (tid, buf, buf_len); 1947 } 1948 ::bzero (buf, buf_len); 1949 return 0; 1950 1951 } 1952 1953 nub_size_t 1954 DNBThreadSetRegisterContext (nub_process_t pid, nub_thread_t tid, const void *buf, size_t buf_len) 1955 { 1956 MachProcessSP procSP; 1957 if (GetProcessSP (pid, procSP)) 1958 { 1959 if (tid != INVALID_NUB_THREAD) 1960 return procSP->GetThreadList().SetRegisterContext (tid, buf, buf_len); 1961 } 1962 return 0; 1963 } 1964 1965 uint32_t 1966 DNBThreadSaveRegisterState (nub_process_t pid, nub_thread_t tid) 1967 { 1968 if (tid != INVALID_NUB_THREAD) 1969 { 1970 MachProcessSP procSP; 1971 if (GetProcessSP (pid, procSP)) 1972 return procSP->GetThreadList().SaveRegisterState (tid); 1973 } 1974 return 0; 1975 } 1976 nub_bool_t 1977 DNBThreadRestoreRegisterState (nub_process_t pid, nub_thread_t tid, uint32_t save_id) 1978 { 1979 if (tid != INVALID_NUB_THREAD) 1980 { 1981 MachProcessSP procSP; 1982 if (GetProcessSP (pid, procSP)) 1983 return procSP->GetThreadList().RestoreRegisterState (tid, save_id); 1984 } 1985 return false; 1986 } 1987 1988 1989 1990 //---------------------------------------------------------------------- 1991 // Read a register value by name. 1992 //---------------------------------------------------------------------- 1993 nub_bool_t 1994 DNBThreadGetRegisterValueByName (nub_process_t pid, nub_thread_t tid, uint32_t reg_set, const char *reg_name, DNBRegisterValue *value) 1995 { 1996 MachProcessSP procSP; 1997 ::bzero (value, sizeof(DNBRegisterValue)); 1998 if (GetProcessSP (pid, procSP)) 1999 { 2000 const struct DNBRegisterSetInfo *set_info; 2001 nub_size_t num_reg_sets = 0; 2002 set_info = DNBGetRegisterSetInfo (&num_reg_sets); 2003 if (set_info) 2004 { 2005 uint32_t set = reg_set; 2006 uint32_t reg; 2007 if (set == REGISTER_SET_ALL) 2008 { 2009 for (set = 1; set < num_reg_sets; ++set) 2010 { 2011 for (reg = 0; reg < set_info[set].num_registers; ++reg) 2012 { 2013 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) 2014 return procSP->GetRegisterValue (tid, set, reg, value); 2015 } 2016 } 2017 } 2018 else 2019 { 2020 for (reg = 0; reg < set_info[set].num_registers; ++reg) 2021 { 2022 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) 2023 return procSP->GetRegisterValue (tid, set, reg, value); 2024 } 2025 } 2026 } 2027 } 2028 return false; 2029 } 2030 2031 2032 //---------------------------------------------------------------------- 2033 // Read a register set and register number from the register name. 2034 //---------------------------------------------------------------------- 2035 nub_bool_t 2036 DNBGetRegisterInfoByName (const char *reg_name, DNBRegisterInfo* info) 2037 { 2038 const struct DNBRegisterSetInfo *set_info; 2039 nub_size_t num_reg_sets = 0; 2040 set_info = DNBGetRegisterSetInfo (&num_reg_sets); 2041 if (set_info) 2042 { 2043 uint32_t set, reg; 2044 for (set = 1; set < num_reg_sets; ++set) 2045 { 2046 for (reg = 0; reg < set_info[set].num_registers; ++reg) 2047 { 2048 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) 2049 { 2050 *info = set_info[set].registers[reg]; 2051 return true; 2052 } 2053 } 2054 } 2055 2056 for (set = 1; set < num_reg_sets; ++set) 2057 { 2058 uint32_t reg; 2059 for (reg = 0; reg < set_info[set].num_registers; ++reg) 2060 { 2061 if (set_info[set].registers[reg].alt == NULL) 2062 continue; 2063 2064 if (strcasecmp(reg_name, set_info[set].registers[reg].alt) == 0) 2065 { 2066 *info = set_info[set].registers[reg]; 2067 return true; 2068 } 2069 } 2070 } 2071 } 2072 2073 ::bzero (info, sizeof(DNBRegisterInfo)); 2074 return false; 2075 } 2076 2077 2078 //---------------------------------------------------------------------- 2079 // Set the name to address callback function that this nub can use 2080 // for any name to address lookups that are needed. 2081 //---------------------------------------------------------------------- 2082 nub_bool_t 2083 DNBProcessSetNameToAddressCallback (nub_process_t pid, DNBCallbackNameToAddress callback, void *baton) 2084 { 2085 MachProcessSP procSP; 2086 if (GetProcessSP (pid, procSP)) 2087 { 2088 procSP->SetNameToAddressCallback (callback, baton); 2089 return true; 2090 } 2091 return false; 2092 } 2093 2094 2095 //---------------------------------------------------------------------- 2096 // Set the name to address callback function that this nub can use 2097 // for any name to address lookups that are needed. 2098 //---------------------------------------------------------------------- 2099 nub_bool_t 2100 DNBProcessSetSharedLibraryInfoCallback (nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, void *baton) 2101 { 2102 MachProcessSP procSP; 2103 if (GetProcessSP (pid, procSP)) 2104 { 2105 procSP->SetSharedLibraryInfoCallback (callback, baton); 2106 return true; 2107 } 2108 return false; 2109 } 2110 2111 nub_addr_t 2112 DNBProcessLookupAddress (nub_process_t pid, const char *name, const char *shlib) 2113 { 2114 MachProcessSP procSP; 2115 if (GetProcessSP (pid, procSP)) 2116 { 2117 return procSP->LookupSymbol (name, shlib); 2118 } 2119 return INVALID_NUB_ADDRESS; 2120 } 2121 2122 2123 nub_size_t 2124 DNBProcessGetAvailableSTDOUT (nub_process_t pid, char *buf, nub_size_t buf_size) 2125 { 2126 MachProcessSP procSP; 2127 if (GetProcessSP (pid, procSP)) 2128 return procSP->GetAvailableSTDOUT (buf, buf_size); 2129 return 0; 2130 } 2131 2132 nub_size_t 2133 DNBProcessGetAvailableSTDERR (nub_process_t pid, char *buf, nub_size_t buf_size) 2134 { 2135 MachProcessSP procSP; 2136 if (GetProcessSP (pid, procSP)) 2137 return procSP->GetAvailableSTDERR (buf, buf_size); 2138 return 0; 2139 } 2140 2141 nub_size_t 2142 DNBProcessGetAvailableProfileData (nub_process_t pid, char *buf, nub_size_t buf_size) 2143 { 2144 MachProcessSP procSP; 2145 if (GetProcessSP (pid, procSP)) 2146 return procSP->GetAsyncProfileData (buf, buf_size); 2147 return 0; 2148 } 2149 2150 nub_size_t 2151 DNBProcessGetStopCount (nub_process_t pid) 2152 { 2153 MachProcessSP procSP; 2154 if (GetProcessSP (pid, procSP)) 2155 return procSP->StopCount(); 2156 return 0; 2157 } 2158 2159 uint32_t 2160 DNBProcessGetCPUType (nub_process_t pid) 2161 { 2162 MachProcessSP procSP; 2163 if (GetProcessSP (pid, procSP)) 2164 return procSP->GetCPUType (); 2165 return 0; 2166 2167 } 2168 2169 nub_bool_t 2170 DNBResolveExecutablePath (const char *path, char *resolved_path, size_t resolved_path_size) 2171 { 2172 if (path == NULL || path[0] == '\0') 2173 return false; 2174 2175 char max_path[PATH_MAX]; 2176 std::string result; 2177 CFString::GlobPath(path, result); 2178 2179 if (result.empty()) 2180 result = path; 2181 2182 struct stat path_stat; 2183 if (::stat(path, &path_stat) == 0) 2184 { 2185 if ((path_stat.st_mode & S_IFMT) == S_IFDIR) 2186 { 2187 CFBundle bundle (path); 2188 CFReleaser<CFURLRef> url(bundle.CopyExecutableURL ()); 2189 if (url.get()) 2190 { 2191 if (::CFURLGetFileSystemRepresentation (url.get(), true, (UInt8*)resolved_path, resolved_path_size)) 2192 return true; 2193 } 2194 } 2195 } 2196 2197 if (realpath(path, max_path)) 2198 { 2199 // Found the path relatively... 2200 ::strncpy(resolved_path, max_path, resolved_path_size); 2201 return strlen(resolved_path) + 1 < resolved_path_size; 2202 } 2203 else 2204 { 2205 // Not a relative path, check the PATH environment variable if the 2206 const char *PATH = getenv("PATH"); 2207 if (PATH) 2208 { 2209 const char *curr_path_start = PATH; 2210 const char *curr_path_end; 2211 while (curr_path_start && *curr_path_start) 2212 { 2213 curr_path_end = strchr(curr_path_start, ':'); 2214 if (curr_path_end == NULL) 2215 { 2216 result.assign(curr_path_start); 2217 curr_path_start = NULL; 2218 } 2219 else if (curr_path_end > curr_path_start) 2220 { 2221 size_t len = curr_path_end - curr_path_start; 2222 result.assign(curr_path_start, len); 2223 curr_path_start += len + 1; 2224 } 2225 else 2226 break; 2227 2228 result += '/'; 2229 result += path; 2230 struct stat s; 2231 if (stat(result.c_str(), &s) == 0) 2232 { 2233 ::strncpy(resolved_path, result.c_str(), resolved_path_size); 2234 return result.size() + 1 < resolved_path_size; 2235 } 2236 } 2237 } 2238 } 2239 return false; 2240 } 2241 2242 2243 void 2244 DNBInitialize() 2245 { 2246 DNBLogThreadedIf (LOG_PROCESS, "DNBInitialize ()"); 2247 #if defined (__i386__) || defined (__x86_64__) 2248 DNBArchImplI386::Initialize(); 2249 DNBArchImplX86_64::Initialize(); 2250 #elif defined (__arm__) || defined (__arm64__) 2251 DNBArchMachARM::Initialize(); 2252 DNBArchMachARM64::Initialize(); 2253 #endif 2254 } 2255 2256 void 2257 DNBTerminate() 2258 { 2259 } 2260 2261 nub_bool_t 2262 DNBSetArchitecture (const char *arch) 2263 { 2264 if (arch && arch[0]) 2265 { 2266 if (strcasecmp (arch, "i386") == 0) 2267 return DNBArchProtocol::SetArchitecture (CPU_TYPE_I386); 2268 else if ((strcasecmp (arch, "x86_64") == 0) || (strcasecmp (arch, "x86_64h") == 0)) 2269 return DNBArchProtocol::SetArchitecture (CPU_TYPE_X86_64); 2270 else if (strstr (arch, "arm64") == arch || strstr (arch, "armv8") == arch) 2271 return DNBArchProtocol::SetArchitecture (CPU_TYPE_ARM64); 2272 else if (strstr (arch, "arm") == arch) 2273 return DNBArchProtocol::SetArchitecture (CPU_TYPE_ARM); 2274 } 2275 return false; 2276 } 2277