1 //===-- DNB.cpp -------------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Created by Greg Clayton on 3/23/07. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "DNB.h" 14 #include <cinttypes> 15 #include <csignal> 16 #include <cstdio> 17 #include <cstdlib> 18 #include <libproc.h> 19 #include <map> 20 #include <sys/resource.h> 21 #include <sys/stat.h> 22 #include <sys/sysctl.h> 23 #include <sys/types.h> 24 #include <sys/wait.h> 25 #include <unistd.h> 26 #include <vector> 27 28 #if defined(__APPLE__) 29 #include <pthread.h> 30 #include <sched.h> 31 #endif 32 33 #define TRY_KQUEUE 1 34 35 #ifdef TRY_KQUEUE 36 #include <sys/event.h> 37 #include <sys/time.h> 38 #ifdef NOTE_EXIT_DETAIL 39 #define USE_KQUEUE 40 #endif 41 #endif 42 43 #include "CFBundle.h" 44 #include "CFString.h" 45 #include "DNBDataRef.h" 46 #include "DNBLog.h" 47 #include "DNBThreadResumeActions.h" 48 #include "DNBTimer.h" 49 #include "MacOSX/Genealogy.h" 50 #include "MacOSX/MachProcess.h" 51 #include "MacOSX/MachTask.h" 52 #include "MacOSX/ThreadInfo.h" 53 #include "RNBRemote.h" 54 55 typedef std::shared_ptr<MachProcess> MachProcessSP; 56 typedef std::map<nub_process_t, MachProcessSP> ProcessMap; 57 typedef ProcessMap::iterator ProcessMapIter; 58 typedef ProcessMap::const_iterator ProcessMapConstIter; 59 60 static size_t 61 GetAllInfosMatchingName(const char *process_name, 62 std::vector<struct kinfo_proc> &matching_proc_infos); 63 64 // A Thread safe singleton to get a process map pointer. 65 // 66 // Returns a pointer to the existing process map, or a pointer to a 67 // newly created process map if CAN_CREATE is non-zero. 68 static ProcessMap *GetProcessMap(bool can_create) { 69 static ProcessMap *g_process_map_ptr = NULL; 70 71 if (can_create && g_process_map_ptr == NULL) { 72 static pthread_mutex_t g_process_map_mutex = PTHREAD_MUTEX_INITIALIZER; 73 PTHREAD_MUTEX_LOCKER(locker, &g_process_map_mutex); 74 if (g_process_map_ptr == NULL) 75 g_process_map_ptr = new ProcessMap; 76 } 77 return g_process_map_ptr; 78 } 79 80 // Add PID to the shared process pointer map. 81 // 82 // Return non-zero value if we succeed in adding the process to the map. 83 // The only time this should fail is if we run out of memory and can't 84 // allocate a ProcessMap. 85 static nub_bool_t AddProcessToMap(nub_process_t pid, MachProcessSP &procSP) { 86 ProcessMap *process_map = GetProcessMap(true); 87 if (process_map) { 88 process_map->insert(std::make_pair(pid, procSP)); 89 return true; 90 } 91 return false; 92 } 93 94 // Remove the shared pointer for PID from the process map. 95 // 96 // Returns the number of items removed from the process map. 97 // static size_t 98 // RemoveProcessFromMap (nub_process_t pid) 99 //{ 100 // ProcessMap* process_map = GetProcessMap(false); 101 // if (process_map) 102 // { 103 // return process_map->erase(pid); 104 // } 105 // return 0; 106 //} 107 108 // Get the shared pointer for PID from the existing process map. 109 // 110 // Returns true if we successfully find a shared pointer to a 111 // MachProcess object. 112 static nub_bool_t GetProcessSP(nub_process_t pid, MachProcessSP &procSP) { 113 ProcessMap *process_map = GetProcessMap(false); 114 if (process_map != NULL) { 115 ProcessMapIter pos = process_map->find(pid); 116 if (pos != process_map->end()) { 117 procSP = pos->second; 118 return true; 119 } 120 } 121 procSP.reset(); 122 return false; 123 } 124 125 #ifdef USE_KQUEUE 126 void *kqueue_thread(void *arg) { 127 int kq_id = (int)(intptr_t)arg; 128 129 #if defined(__APPLE__) 130 pthread_setname_np("kqueue thread"); 131 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 132 struct sched_param thread_param; 133 int thread_sched_policy; 134 if (pthread_getschedparam(pthread_self(), &thread_sched_policy, 135 &thread_param) == 0) { 136 thread_param.sched_priority = 47; 137 pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); 138 } 139 #endif 140 #endif 141 142 struct kevent death_event; 143 while (true) { 144 int n_events = kevent(kq_id, NULL, 0, &death_event, 1, NULL); 145 if (n_events == -1) { 146 if (errno == EINTR) 147 continue; 148 else { 149 DNBLogError("kqueue failed with error: (%d): %s", errno, 150 strerror(errno)); 151 return NULL; 152 } 153 } else if (death_event.flags & EV_ERROR) { 154 int error_no = static_cast<int>(death_event.data); 155 const char *error_str = strerror(error_no); 156 if (error_str == NULL) 157 error_str = "Unknown error"; 158 DNBLogError("Failed to initialize kqueue event: (%d): %s", error_no, 159 error_str); 160 return NULL; 161 } else { 162 int status; 163 const pid_t pid = (pid_t)death_event.ident; 164 const pid_t child_pid = waitpid(pid, &status, 0); 165 166 bool exited = false; 167 int signal = 0; 168 int exit_status = 0; 169 if (WIFSTOPPED(status)) { 170 signal = WSTOPSIG(status); 171 DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> STOPPED (signal = %i)", 172 child_pid, signal); 173 } else if (WIFEXITED(status)) { 174 exit_status = WEXITSTATUS(status); 175 exited = true; 176 DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> EXITED (status = %i)", 177 child_pid, exit_status); 178 } else if (WIFSIGNALED(status)) { 179 signal = WTERMSIG(status); 180 if (child_pid == abs(pid)) { 181 DNBLogThreadedIf(LOG_PROCESS, 182 "waitpid (%i) -> SIGNALED and EXITED (signal = %i)", 183 child_pid, signal); 184 char exit_info[64]; 185 ::snprintf(exit_info, sizeof(exit_info), 186 "Terminated due to signal %i", signal); 187 DNBProcessSetExitInfo(child_pid, exit_info); 188 exited = true; 189 exit_status = INT8_MAX; 190 } else { 191 DNBLogThreadedIf(LOG_PROCESS, 192 "waitpid (%i) -> SIGNALED (signal = %i)", child_pid, 193 signal); 194 } 195 } 196 197 if (exited) { 198 if (death_event.data & NOTE_EXIT_MEMORY) 199 DNBProcessSetExitInfo(child_pid, "Terminated due to memory issue"); 200 else if (death_event.data & NOTE_EXIT_DECRYPTFAIL) 201 DNBProcessSetExitInfo(child_pid, "Terminated due to decrypt failure"); 202 else if (death_event.data & NOTE_EXIT_CSERROR) 203 DNBProcessSetExitInfo(child_pid, 204 "Terminated due to code signing error"); 205 206 DNBLogThreadedIf( 207 LOG_PROCESS, 208 "waitpid_process_thread (): setting exit status for pid = %i to %i", 209 child_pid, exit_status); 210 DNBProcessSetExitStatus(child_pid, status); 211 return NULL; 212 } 213 } 214 } 215 } 216 217 static bool spawn_kqueue_thread(pid_t pid) { 218 pthread_t thread; 219 int kq_id; 220 221 kq_id = kqueue(); 222 if (kq_id == -1) { 223 DNBLogError("Could not get kqueue for pid = %i.", pid); 224 return false; 225 } 226 227 struct kevent reg_event; 228 229 EV_SET(®_event, pid, EVFILT_PROC, EV_ADD, 230 NOTE_EXIT | NOTE_EXITSTATUS | NOTE_EXIT_DETAIL, 0, NULL); 231 // Register the event: 232 int result = kevent(kq_id, ®_event, 1, NULL, 0, NULL); 233 if (result != 0) { 234 DNBLogError( 235 "Failed to register kqueue NOTE_EXIT event for pid %i, error: %d.", pid, 236 result); 237 return false; 238 } 239 240 int ret = 241 ::pthread_create(&thread, NULL, kqueue_thread, (void *)(intptr_t)kq_id); 242 243 // pthread_create returns 0 if successful 244 if (ret == 0) { 245 ::pthread_detach(thread); 246 return true; 247 } 248 return false; 249 } 250 #endif // #if USE_KQUEUE 251 252 static void *waitpid_thread(void *arg) { 253 const pid_t pid = (pid_t)(intptr_t)arg; 254 int status; 255 256 #if defined(__APPLE__) 257 pthread_setname_np("waitpid thread"); 258 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 259 struct sched_param thread_param; 260 int thread_sched_policy; 261 if (pthread_getschedparam(pthread_self(), &thread_sched_policy, 262 &thread_param) == 0) { 263 thread_param.sched_priority = 47; 264 pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); 265 } 266 #endif 267 #endif 268 269 while (true) { 270 pid_t child_pid = waitpid(pid, &status, 0); 271 DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): waitpid (pid = %i, " 272 "&status, 0) => %i, status = %i, errno = %i", 273 pid, child_pid, status, errno); 274 275 if (child_pid < 0) { 276 if (errno == EINTR) 277 continue; 278 break; 279 } else { 280 if (WIFSTOPPED(status)) { 281 continue; 282 } else // if (WIFEXITED(status) || WIFSIGNALED(status)) 283 { 284 DNBLogThreadedIf( 285 LOG_PROCESS, 286 "waitpid_thread (): setting exit status for pid = %i to %i", 287 child_pid, status); 288 DNBProcessSetExitStatus(child_pid, status); 289 return NULL; 290 } 291 } 292 } 293 294 // We should never exit as long as our child process is alive, so if we 295 // do something else went wrong and we should exit... 296 DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): main loop exited, setting " 297 "exit status to an invalid value (-1) for pid " 298 "%i", 299 pid); 300 DNBProcessSetExitStatus(pid, -1); 301 return NULL; 302 } 303 static bool spawn_waitpid_thread(pid_t pid) { 304 #ifdef USE_KQUEUE 305 bool success = spawn_kqueue_thread(pid); 306 if (success) 307 return true; 308 #endif 309 310 pthread_t thread; 311 int ret = 312 ::pthread_create(&thread, NULL, waitpid_thread, (void *)(intptr_t)pid); 313 // pthread_create returns 0 if successful 314 if (ret == 0) { 315 ::pthread_detach(thread); 316 return true; 317 } 318 return false; 319 } 320 321 nub_process_t DNBProcessLaunch( 322 RNBContext *ctx, const char *path, char const *argv[], const char *envp[], 323 const char *working_directory, // NULL => don't change, non-NULL => set 324 // working directory for inferior to this 325 const char *stdin_path, const char *stdout_path, const char *stderr_path, 326 bool no_stdio, int disable_aslr, const char *event_data, char *err_str, 327 size_t err_len) { 328 DNBLogThreadedIf(LOG_PROCESS, 329 "%s ( path='%s', argv = %p, envp = %p, " 330 "working_dir=%s, stdin=%s, stdout=%s, " 331 "stderr=%s, no-stdio=%i, launch_flavor = %u, " 332 "disable_aslr = %d, err = %p, err_len = " 333 "%llu) called...", 334 __FUNCTION__, path, static_cast<void *>(argv), 335 static_cast<void *>(envp), working_directory, stdin_path, 336 stdout_path, stderr_path, no_stdio, ctx->LaunchFlavor(), 337 disable_aslr, static_cast<void *>(err_str), 338 static_cast<uint64_t>(err_len)); 339 340 if (err_str && err_len > 0) 341 err_str[0] = '\0'; 342 struct stat path_stat; 343 if (::stat(path, &path_stat) == -1) { 344 char stat_error[256]; 345 ::strerror_r(errno, stat_error, sizeof(stat_error)); 346 snprintf(err_str, err_len, "%s (%s)", stat_error, path); 347 return INVALID_NUB_PROCESS; 348 } 349 350 MachProcessSP processSP(new MachProcess); 351 if (processSP.get()) { 352 DNBError launch_err; 353 pid_t pid = processSP->LaunchForDebug( 354 path, argv, envp, working_directory, stdin_path, stdout_path, 355 stderr_path, no_stdio, ctx->LaunchFlavor(), disable_aslr, event_data, 356 ctx->GetIgnoredExceptions(), launch_err); 357 if (err_str) { 358 *err_str = '\0'; 359 if (launch_err.Fail()) { 360 const char *launch_err_str = launch_err.AsString(); 361 if (launch_err_str) { 362 strlcpy(err_str, launch_err_str, err_len - 1); 363 err_str[err_len - 1] = 364 '\0'; // Make sure the error string is terminated 365 } 366 } 367 } 368 369 DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) new pid is %d...", pid); 370 371 if (pid != INVALID_NUB_PROCESS) { 372 // Spawn a thread to reap our child inferior process... 373 spawn_waitpid_thread(pid); 374 375 if (processSP->Task().TaskPortForProcessID(launch_err) == TASK_NULL) { 376 // We failed to get the task for our process ID which is bad. 377 // Kill our process otherwise it will be stopped at the entry 378 // point and get reparented to someone else and never go away. 379 DNBLog("Could not get task port for process, sending SIGKILL and " 380 "exiting."); 381 kill(SIGKILL, pid); 382 383 if (err_str && err_len > 0) { 384 if (launch_err.AsString()) { 385 ::snprintf(err_str, err_len, 386 "failed to get the task for process %i: %s", pid, 387 launch_err.AsString()); 388 } else { 389 390 const char *ent_name = 391 #if TARGET_OS_OSX 392 "com.apple.security.get-task-allow"; 393 #else 394 "get-task-allow"; 395 #endif 396 ::snprintf(err_str, err_len, 397 "failed to get the task for process %i: this likely " 398 "means the process cannot be debugged, either because " 399 "it's a system process or because the process is " 400 "missing the %s entitlement.", 401 pid, ent_name); 402 } 403 } 404 } else { 405 bool res = AddProcessToMap(pid, processSP); 406 UNUSED_IF_ASSERT_DISABLED(res); 407 assert(res && "Couldn't add process to map!"); 408 return pid; 409 } 410 } 411 } 412 return INVALID_NUB_PROCESS; 413 } 414 415 // If there is one process with a given name, return the pid for that process. 416 nub_process_t DNBProcessGetPIDByName(const char *name) { 417 std::vector<struct kinfo_proc> matching_proc_infos; 418 size_t num_matching_proc_infos = 419 GetAllInfosMatchingName(name, matching_proc_infos); 420 if (num_matching_proc_infos == 1) { 421 return matching_proc_infos[0].kp_proc.p_pid; 422 } 423 return INVALID_NUB_PROCESS; 424 } 425 426 nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout, 427 const RNBContext::IgnoredExceptions 428 &ignored_exceptions, char *err_str, 429 size_t err_len) { 430 if (err_str && err_len > 0) 431 err_str[0] = '\0'; 432 std::vector<struct kinfo_proc> matching_proc_infos; 433 size_t num_matching_proc_infos = 434 GetAllInfosMatchingName(name, matching_proc_infos); 435 if (num_matching_proc_infos == 0) { 436 DNBLogError("error: no processes match '%s'\n", name); 437 return INVALID_NUB_PROCESS; 438 } 439 if (num_matching_proc_infos > 1) { 440 DNBLogError("error: %llu processes match '%s':\n", 441 (uint64_t)num_matching_proc_infos, name); 442 size_t i; 443 for (i = 0; i < num_matching_proc_infos; ++i) 444 DNBLogError("%6u - %s\n", matching_proc_infos[i].kp_proc.p_pid, 445 matching_proc_infos[i].kp_proc.p_comm); 446 return INVALID_NUB_PROCESS; 447 } 448 449 return DNBProcessAttach(matching_proc_infos[0].kp_proc.p_pid, timeout, 450 ignored_exceptions, err_str, err_len); 451 } 452 453 nub_process_t DNBProcessAttach(nub_process_t attach_pid, 454 struct timespec *timeout, 455 const RNBContext::IgnoredExceptions 456 &ignored_exceptions, 457 char *err_str, size_t err_len) { 458 if (err_str && err_len > 0) 459 err_str[0] = '\0'; 460 461 if (getenv("LLDB_DEBUGSERVER_PATH") == NULL) { 462 int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, 463 static_cast<int>(attach_pid)}; 464 struct kinfo_proc processInfo; 465 size_t bufsize = sizeof(processInfo); 466 if (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, 467 &bufsize, NULL, 0) == 0 && 468 bufsize > 0) { 469 470 if ((processInfo.kp_proc.p_flag & P_TRANSLATED) == P_TRANSLATED) { 471 const char *translated_debugserver = 472 "/Library/Apple/usr/libexec/oah/debugserver"; 473 char fdstr[16]; 474 char pidstr[16]; 475 extern int communication_fd; 476 477 if (communication_fd == -1) { 478 DNBLogError("Trying to attach to a translated process with the " 479 "native debugserver, exiting...\n"); 480 return INVALID_NUB_PROCESS_ARCH; 481 } 482 483 struct stat st; 484 if (::stat(translated_debugserver, &st) != 0) { 485 DNBLogError("Translated inferior process but Rosetta debugserver not " 486 "found at %s", 487 translated_debugserver); 488 return INVALID_NUB_PROCESS_ARCH; 489 } 490 491 snprintf(fdstr, sizeof(fdstr), "--fd=%d", communication_fd); 492 snprintf(pidstr, sizeof(pidstr), "--attach=%d", attach_pid); 493 execl(translated_debugserver, translated_debugserver, "--native-regs", 494 "--setsid", fdstr, "--handoff-attach-from-native", pidstr, 495 (char *)0); 496 DNBLogThreadedIf(LOG_PROCESS, "Failed to launch debugserver for " 497 "translated process: ", errno, strerror(errno)); 498 __builtin_trap(); 499 } 500 } 501 } 502 503 if (DNBDebugserverIsTranslated()) { 504 return INVALID_NUB_PROCESS_ARCH; 505 } 506 507 pid_t pid = INVALID_NUB_PROCESS; 508 MachProcessSP processSP(new MachProcess); 509 if (processSP.get()) { 510 DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...", 511 attach_pid); 512 pid = 513 processSP->AttachForDebug(attach_pid, ignored_exceptions, err_str, 514 err_len); 515 516 if (pid != INVALID_NUB_PROCESS) { 517 bool res = AddProcessToMap(pid, processSP); 518 UNUSED_IF_ASSERT_DISABLED(res); 519 assert(res && "Couldn't add process to map!"); 520 spawn_waitpid_thread(pid); 521 } 522 } 523 524 while (pid != INVALID_NUB_PROCESS) { 525 // Wait for process to start up and hit entry point 526 DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, " 527 "eEventProcessRunningStateChanged | " 528 "eEventProcessStoppedStateChanged, true, " 529 "INFINITE)...", 530 __FUNCTION__, pid); 531 nub_event_t set_events = 532 DNBProcessWaitForEvents(pid, eEventProcessRunningStateChanged | 533 eEventProcessStoppedStateChanged, 534 true, timeout); 535 536 DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, " 537 "eEventProcessRunningStateChanged | " 538 "eEventProcessStoppedStateChanged, true, " 539 "INFINITE) => 0x%8.8x", 540 __FUNCTION__, pid, set_events); 541 542 if (set_events == 0) { 543 if (err_str && err_len > 0) 544 snprintf(err_str, err_len, 545 "attached to process, but could not pause execution; attach " 546 "failed"); 547 pid = INVALID_NUB_PROCESS; 548 } else { 549 if (set_events & (eEventProcessRunningStateChanged | 550 eEventProcessStoppedStateChanged)) { 551 nub_state_t pid_state = DNBProcessGetState(pid); 552 DNBLogThreadedIf( 553 LOG_PROCESS, 554 "%s process %4.4x state changed (eEventProcessStateChanged): %s", 555 __FUNCTION__, pid, DNBStateAsString(pid_state)); 556 557 switch (pid_state) { 558 case eStateInvalid: 559 case eStateUnloaded: 560 case eStateAttaching: 561 case eStateLaunching: 562 case eStateSuspended: 563 break; // Ignore 564 565 case eStateRunning: 566 case eStateStepping: 567 // Still waiting to stop at entry point... 568 break; 569 570 case eStateStopped: 571 case eStateCrashed: 572 return pid; 573 574 case eStateDetached: 575 case eStateExited: 576 if (err_str && err_len > 0) 577 snprintf(err_str, err_len, "process exited"); 578 return INVALID_NUB_PROCESS; 579 } 580 } 581 582 DNBProcessResetEvents(pid, set_events); 583 } 584 } 585 586 return INVALID_NUB_PROCESS; 587 } 588 589 size_t DNBGetAllInfos(std::vector<struct kinfo_proc> &proc_infos) { 590 size_t size = 0; 591 int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL}; 592 u_int namelen = sizeof(name) / sizeof(int); 593 int err; 594 595 // Try to find out how many processes are around so we can 596 // size the buffer appropriately. sysctl's man page specifically suggests 597 // this approach, and says it returns a bit larger size than needed to 598 // handle any new processes created between then and now. 599 600 err = ::sysctl(name, namelen, NULL, &size, NULL, 0); 601 602 if ((err < 0) && (err != ENOMEM)) { 603 proc_infos.clear(); 604 perror("sysctl (mib, miblen, NULL, &num_processes, NULL, 0)"); 605 return 0; 606 } 607 608 // Increase the size of the buffer by a few processes in case more have 609 // been spawned 610 proc_infos.resize(size / sizeof(struct kinfo_proc)); 611 size = proc_infos.size() * 612 sizeof(struct kinfo_proc); // Make sure we don't exceed our resize... 613 err = ::sysctl(name, namelen, &proc_infos[0], &size, NULL, 0); 614 if (err < 0) { 615 proc_infos.clear(); 616 return 0; 617 } 618 619 // Trim down our array to fit what we actually got back 620 proc_infos.resize(size / sizeof(struct kinfo_proc)); 621 return proc_infos.size(); 622 } 623 624 JSONGenerator::ObjectSP DNBGetDyldProcessState(nub_process_t pid) { 625 MachProcessSP procSP; 626 if (GetProcessSP(pid, procSP)) { 627 return procSP->GetDyldProcessState(); 628 } 629 return {}; 630 } 631 632 static size_t 633 GetAllInfosMatchingName(const char *full_process_name, 634 std::vector<struct kinfo_proc> &matching_proc_infos) { 635 636 matching_proc_infos.clear(); 637 if (full_process_name && full_process_name[0]) { 638 // We only get the process name, not the full path, from the proc_info. So 639 // just take the 640 // base name of the process name... 641 const char *process_name; 642 process_name = strrchr(full_process_name, '/'); 643 if (process_name == NULL) 644 process_name = full_process_name; 645 else 646 process_name++; 647 648 const size_t process_name_len = strlen(process_name); 649 std::vector<struct kinfo_proc> proc_infos; 650 const size_t num_proc_infos = DNBGetAllInfos(proc_infos); 651 if (num_proc_infos > 0) { 652 uint32_t i; 653 for (i = 0; i < num_proc_infos; i++) { 654 // Skip zombie processes and processes with unset status 655 if (proc_infos[i].kp_proc.p_stat == 0 || 656 proc_infos[i].kp_proc.p_stat == SZOMB) 657 continue; 658 659 // Check for process by name. We only check the first MAXCOMLEN 660 // chars as that is all that kp_proc.p_comm holds. 661 662 if (::strncasecmp(process_name, proc_infos[i].kp_proc.p_comm, 663 MAXCOMLEN) == 0) { 664 if (process_name_len > MAXCOMLEN) { 665 // We found a matching process name whose first MAXCOMLEN 666 // characters match, but there is more to the name than 667 // this. We need to get the full process name. Use proc_pidpath, 668 // which will get 669 // us the full path to the executed process. 670 671 char proc_path_buf[PATH_MAX]; 672 673 int return_val = proc_pidpath(proc_infos[i].kp_proc.p_pid, 674 proc_path_buf, PATH_MAX); 675 if (return_val > 0) { 676 // Okay, now search backwards from that to see if there is a 677 // slash in the name. Note, even though we got all the args we 678 // don't care 679 // because the list data is just a bunch of concatenated null 680 // terminated strings 681 // so strrchr will start from the end of argv0. 682 683 const char *argv_basename = strrchr(proc_path_buf, '/'); 684 if (argv_basename) { 685 // Skip the '/' 686 ++argv_basename; 687 } else { 688 // We didn't find a directory delimiter in the process argv[0], 689 // just use what was in there 690 argv_basename = proc_path_buf; 691 } 692 693 if (argv_basename) { 694 if (::strncasecmp(process_name, argv_basename, PATH_MAX) == 0) { 695 matching_proc_infos.push_back(proc_infos[i]); 696 } 697 } 698 } 699 } else { 700 // We found a matching process, add it to our list 701 matching_proc_infos.push_back(proc_infos[i]); 702 } 703 } 704 } 705 } 706 } 707 // return the newly added matches. 708 return matching_proc_infos.size(); 709 } 710 711 nub_process_t 712 DNBProcessAttachWait(RNBContext *ctx, const char *waitfor_process_name, 713 bool ignore_existing, struct timespec *timeout_abstime, 714 useconds_t waitfor_interval, char *err_str, size_t err_len, 715 DNBShouldCancelCallback should_cancel_callback, 716 void *callback_data) { 717 DNBError prepare_error; 718 std::vector<struct kinfo_proc> exclude_proc_infos; 719 size_t num_exclude_proc_infos; 720 721 nub_launch_flavor_t launch_flavor = ctx->LaunchFlavor(); 722 723 // If the PrepareForAttach returns a valid token, use MachProcess to check 724 // for the process, otherwise scan the process table. 725 726 const void *attach_token = MachProcess::PrepareForAttach( 727 waitfor_process_name, launch_flavor, true, prepare_error); 728 729 if (prepare_error.Fail()) { 730 DNBLogError("Error in PrepareForAttach: %s", prepare_error.AsString()); 731 return INVALID_NUB_PROCESS; 732 } 733 734 if (attach_token == NULL) { 735 if (ignore_existing) 736 num_exclude_proc_infos = 737 GetAllInfosMatchingName(waitfor_process_name, exclude_proc_infos); 738 else 739 num_exclude_proc_infos = 0; 740 } 741 742 DNBLogThreadedIf(LOG_PROCESS, "Waiting for '%s' to appear...\n", 743 waitfor_process_name); 744 745 // Loop and try to find the process by name 746 nub_process_t waitfor_pid = INVALID_NUB_PROCESS; 747 748 while (waitfor_pid == INVALID_NUB_PROCESS) { 749 if (attach_token != NULL) { 750 nub_process_t pid; 751 pid = MachProcess::CheckForProcess(attach_token, launch_flavor); 752 if (pid != INVALID_NUB_PROCESS) { 753 waitfor_pid = pid; 754 break; 755 } 756 } else { 757 // Get the current process list, and check for matches that 758 // aren't in our original list. If anyone wants to attach 759 // to an existing process by name, they should do it with 760 // --attach=PROCNAME. Else we will wait for the first matching 761 // process that wasn't in our exclusion list. 762 std::vector<struct kinfo_proc> proc_infos; 763 const size_t num_proc_infos = 764 GetAllInfosMatchingName(waitfor_process_name, proc_infos); 765 for (size_t i = 0; i < num_proc_infos; i++) { 766 nub_process_t curr_pid = proc_infos[i].kp_proc.p_pid; 767 for (size_t j = 0; j < num_exclude_proc_infos; j++) { 768 if (curr_pid == exclude_proc_infos[j].kp_proc.p_pid) { 769 // This process was in our exclusion list, don't use it. 770 curr_pid = INVALID_NUB_PROCESS; 771 break; 772 } 773 } 774 775 // If we didn't find CURR_PID in our exclusion list, then use it. 776 if (curr_pid != INVALID_NUB_PROCESS) { 777 // We found our process! 778 waitfor_pid = curr_pid; 779 break; 780 } 781 } 782 } 783 784 // If we haven't found our process yet, check for a timeout 785 // and then sleep for a bit until we poll again. 786 if (waitfor_pid == INVALID_NUB_PROCESS) { 787 if (timeout_abstime != NULL) { 788 // Check to see if we have a waitfor-duration option that 789 // has timed out? 790 if (DNBTimer::TimeOfDayLaterThan(*timeout_abstime)) { 791 if (err_str && err_len > 0) 792 snprintf(err_str, err_len, "operation timed out"); 793 DNBLogError("error: waiting for process '%s' timed out.\n", 794 waitfor_process_name); 795 return INVALID_NUB_PROCESS; 796 } 797 } 798 799 // Call the should cancel callback as well... 800 801 if (should_cancel_callback != NULL && 802 should_cancel_callback(callback_data)) { 803 DNBLogThreadedIf( 804 LOG_PROCESS, 805 "DNBProcessAttachWait cancelled by should_cancel callback."); 806 waitfor_pid = INVALID_NUB_PROCESS; 807 break; 808 } 809 810 // Now we're going to wait a while before polling again. But we also 811 // need to check whether we've gotten an event from the debugger 812 // telling us to interrupt the wait. So we'll use the wait for a possible 813 // next event to also be our short pause... 814 struct timespec short_timeout; 815 DNBTimer::OffsetTimeOfDay(&short_timeout, 0, waitfor_interval); 816 uint32_t event_mask = RNBContext::event_read_packet_available 817 | RNBContext::event_read_thread_exiting; 818 nub_event_t set_events = ctx->Events().WaitForSetEvents(event_mask, 819 &short_timeout); 820 if (set_events & RNBContext::event_read_packet_available) { 821 // If we get any packet from the debugger while waiting on the async, 822 // it has to be telling us to interrupt. So always exit here. 823 // Over here in DNB land we can see that there was a packet, but all 824 // the methods to actually handle it are protected. It's not worth 825 // rearranging all that just to get which packet we were sent... 826 DNBLogError("Interrupted by packet while waiting for '%s' to appear.\n", 827 waitfor_process_name); 828 break; 829 } 830 if (set_events & RNBContext::event_read_thread_exiting) { 831 // The packet thread is shutting down, get out of here... 832 DNBLogError("Interrupted by packet thread shutdown while waiting for " 833 "%s to appear.\n", waitfor_process_name); 834 break; 835 } 836 837 } 838 } 839 840 if (waitfor_pid != INVALID_NUB_PROCESS) { 841 DNBLogThreadedIf(LOG_PROCESS, "Attaching to %s with pid %i...\n", 842 waitfor_process_name, waitfor_pid); 843 // In some cases, we attempt to attach during the transition from 844 // /usr/lib/dyld to the dyld in the shared cache. If that happens, we may 845 // end up in a state where there is no dyld in the process and from there 846 // the debugging session is doomed. 847 // In an attempt to make this scenario much less likely, we sleep 848 // for an additional `waitfor_interval` number of microseconds before 849 // attaching. 850 ::usleep(waitfor_interval); 851 waitfor_pid = DNBProcessAttach(waitfor_pid, timeout_abstime, 852 ctx->GetIgnoredExceptions(), err_str, 853 err_len); 854 } 855 856 bool success = waitfor_pid != INVALID_NUB_PROCESS; 857 MachProcess::CleanupAfterAttach(attach_token, launch_flavor, success, 858 prepare_error); 859 860 return waitfor_pid; 861 } 862 863 nub_bool_t DNBProcessDetach(nub_process_t pid) { 864 MachProcessSP procSP; 865 if (GetProcessSP(pid, procSP)) { 866 const bool remove = true; 867 DNBLogThreaded( 868 "Disabling breakpoints and watchpoints, and detaching from %d.", pid); 869 procSP->DisableAllBreakpoints(remove); 870 procSP->DisableAllWatchpoints(remove); 871 return procSP->Detach(); 872 } 873 return false; 874 } 875 876 nub_bool_t DNBProcessKill(nub_process_t pid) { 877 MachProcessSP procSP; 878 if (GetProcessSP(pid, procSP)) { 879 return procSP->Kill(); 880 } 881 return false; 882 } 883 884 nub_bool_t DNBProcessSignal(nub_process_t pid, int signal) { 885 MachProcessSP procSP; 886 if (GetProcessSP(pid, procSP)) { 887 return procSP->Signal(signal); 888 } 889 return false; 890 } 891 892 nub_bool_t DNBProcessInterrupt(nub_process_t pid) { 893 MachProcessSP procSP; 894 if (GetProcessSP(pid, procSP)) 895 return procSP->Interrupt(); 896 return false; 897 } 898 899 nub_bool_t DNBProcessSendEvent(nub_process_t pid, const char *event) { 900 MachProcessSP procSP; 901 if (GetProcessSP(pid, procSP)) { 902 // FIXME: Do something with the error... 903 DNBError send_error; 904 return procSP->SendEvent(event, send_error); 905 } 906 return false; 907 } 908 909 nub_bool_t DNBProcessIsAlive(nub_process_t pid) { 910 MachProcessSP procSP; 911 if (GetProcessSP(pid, procSP)) { 912 return MachTask::IsValid(procSP->Task().TaskPort()); 913 } 914 return eStateInvalid; 915 } 916 917 // Process and Thread state information 918 nub_state_t DNBProcessGetState(nub_process_t pid) { 919 MachProcessSP procSP; 920 if (GetProcessSP(pid, procSP)) { 921 return procSP->GetState(); 922 } 923 return eStateInvalid; 924 } 925 926 // Process and Thread state information 927 nub_bool_t DNBProcessGetExitStatus(nub_process_t pid, int *status) { 928 MachProcessSP procSP; 929 if (GetProcessSP(pid, procSP)) { 930 return procSP->GetExitStatus(status); 931 } 932 return false; 933 } 934 935 nub_bool_t DNBProcessSetExitStatus(nub_process_t pid, int status) { 936 MachProcessSP procSP; 937 if (GetProcessSP(pid, procSP)) { 938 procSP->SetExitStatus(status); 939 return true; 940 } 941 return false; 942 } 943 944 const char *DNBProcessGetExitInfo(nub_process_t pid) { 945 MachProcessSP procSP; 946 if (GetProcessSP(pid, procSP)) { 947 return procSP->GetExitInfo(); 948 } 949 return NULL; 950 } 951 952 nub_bool_t DNBProcessSetExitInfo(nub_process_t pid, const char *info) { 953 MachProcessSP procSP; 954 if (GetProcessSP(pid, procSP)) { 955 procSP->SetExitInfo(info); 956 return true; 957 } 958 return false; 959 } 960 961 const char *DNBThreadGetName(nub_process_t pid, nub_thread_t tid) { 962 MachProcessSP procSP; 963 if (GetProcessSP(pid, procSP)) 964 return procSP->ThreadGetName(tid); 965 return NULL; 966 } 967 968 nub_bool_t 969 DNBThreadGetIdentifierInfo(nub_process_t pid, nub_thread_t tid, 970 thread_identifier_info_data_t *ident_info) { 971 MachProcessSP procSP; 972 if (GetProcessSP(pid, procSP)) 973 return procSP->GetThreadList().GetIdentifierInfo(tid, ident_info); 974 return false; 975 } 976 977 nub_state_t DNBThreadGetState(nub_process_t pid, nub_thread_t tid) { 978 MachProcessSP procSP; 979 if (GetProcessSP(pid, procSP)) { 980 return procSP->ThreadGetState(tid); 981 } 982 return eStateInvalid; 983 } 984 985 const char *DNBStateAsString(nub_state_t state) { 986 switch (state) { 987 case eStateInvalid: 988 return "Invalid"; 989 case eStateUnloaded: 990 return "Unloaded"; 991 case eStateAttaching: 992 return "Attaching"; 993 case eStateLaunching: 994 return "Launching"; 995 case eStateStopped: 996 return "Stopped"; 997 case eStateRunning: 998 return "Running"; 999 case eStateStepping: 1000 return "Stepping"; 1001 case eStateCrashed: 1002 return "Crashed"; 1003 case eStateDetached: 1004 return "Detached"; 1005 case eStateExited: 1006 return "Exited"; 1007 case eStateSuspended: 1008 return "Suspended"; 1009 } 1010 return "nub_state_t ???"; 1011 } 1012 1013 Genealogy::ThreadActivitySP DNBGetGenealogyInfoForThread(nub_process_t pid, 1014 nub_thread_t tid, 1015 bool &timed_out) { 1016 Genealogy::ThreadActivitySP thread_activity_sp; 1017 MachProcessSP procSP; 1018 if (GetProcessSP(pid, procSP)) 1019 thread_activity_sp = procSP->GetGenealogyInfoForThread(tid, timed_out); 1020 return thread_activity_sp; 1021 } 1022 1023 Genealogy::ProcessExecutableInfoSP DNBGetGenealogyImageInfo(nub_process_t pid, 1024 size_t idx) { 1025 Genealogy::ProcessExecutableInfoSP image_info_sp; 1026 MachProcessSP procSP; 1027 if (GetProcessSP(pid, procSP)) { 1028 image_info_sp = procSP->GetGenealogyImageInfo(idx); 1029 } 1030 return image_info_sp; 1031 } 1032 1033 ThreadInfo::QoS DNBGetRequestedQoSForThread(nub_process_t pid, nub_thread_t tid, 1034 nub_addr_t tsd, 1035 uint64_t dti_qos_class_index) { 1036 MachProcessSP procSP; 1037 if (GetProcessSP(pid, procSP)) { 1038 return procSP->GetRequestedQoS(tid, tsd, dti_qos_class_index); 1039 } 1040 return ThreadInfo::QoS(); 1041 } 1042 1043 nub_addr_t DNBGetPThreadT(nub_process_t pid, nub_thread_t tid) { 1044 MachProcessSP procSP; 1045 if (GetProcessSP(pid, procSP)) { 1046 return procSP->GetPThreadT(tid); 1047 } 1048 return INVALID_NUB_ADDRESS; 1049 } 1050 1051 nub_addr_t DNBGetDispatchQueueT(nub_process_t pid, nub_thread_t tid) { 1052 MachProcessSP procSP; 1053 if (GetProcessSP(pid, procSP)) { 1054 return procSP->GetDispatchQueueT(tid); 1055 } 1056 return INVALID_NUB_ADDRESS; 1057 } 1058 1059 nub_addr_t 1060 DNBGetTSDAddressForThread(nub_process_t pid, nub_thread_t tid, 1061 uint64_t plo_pthread_tsd_base_address_offset, 1062 uint64_t plo_pthread_tsd_base_offset, 1063 uint64_t plo_pthread_tsd_entry_size) { 1064 MachProcessSP procSP; 1065 if (GetProcessSP(pid, procSP)) { 1066 return procSP->GetTSDAddressForThread( 1067 tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, 1068 plo_pthread_tsd_entry_size); 1069 } 1070 return INVALID_NUB_ADDRESS; 1071 } 1072 1073 std::optional<std::pair<cpu_type_t, cpu_subtype_t>> 1074 DNBGetMainBinaryCPUTypes(nub_process_t pid) { 1075 MachProcessSP procSP; 1076 if (GetProcessSP(pid, procSP)) 1077 return procSP->GetMainBinaryCPUTypes(pid); 1078 return {}; 1079 } 1080 1081 JSONGenerator::ObjectSP 1082 DNBGetAllLoadedLibrariesInfos(nub_process_t pid, bool report_load_commands) { 1083 MachProcessSP procSP; 1084 if (GetProcessSP(pid, procSP)) { 1085 return procSP->GetAllLoadedLibrariesInfos(pid, report_load_commands); 1086 } 1087 return JSONGenerator::ObjectSP(); 1088 } 1089 1090 JSONGenerator::ObjectSP 1091 DNBGetLibrariesInfoForAddresses(nub_process_t pid, 1092 std::vector<uint64_t> &macho_addresses) { 1093 MachProcessSP procSP; 1094 if (GetProcessSP(pid, procSP)) { 1095 return procSP->GetLibrariesInfoForAddresses(pid, macho_addresses); 1096 } 1097 return JSONGenerator::ObjectSP(); 1098 } 1099 1100 JSONGenerator::ObjectSP DNBGetSharedCacheInfo(nub_process_t pid) { 1101 MachProcessSP procSP; 1102 if (GetProcessSP(pid, procSP)) { 1103 return procSP->GetSharedCacheInfo(pid); 1104 } 1105 return JSONGenerator::ObjectSP(); 1106 } 1107 1108 const char *DNBProcessGetExecutablePath(nub_process_t pid) { 1109 MachProcessSP procSP; 1110 if (GetProcessSP(pid, procSP)) { 1111 return procSP->Path(); 1112 } 1113 return NULL; 1114 } 1115 1116 nub_size_t DNBProcessGetArgumentCount(nub_process_t pid) { 1117 MachProcessSP procSP; 1118 if (GetProcessSP(pid, procSP)) { 1119 return procSP->ArgumentCount(); 1120 } 1121 return 0; 1122 } 1123 1124 const char *DNBProcessGetArgumentAtIndex(nub_process_t pid, nub_size_t idx) { 1125 MachProcessSP procSP; 1126 if (GetProcessSP(pid, procSP)) { 1127 return procSP->ArgumentAtIndex(idx); 1128 } 1129 return NULL; 1130 } 1131 1132 // Execution control 1133 nub_bool_t DNBProcessResume(nub_process_t pid, 1134 const DNBThreadResumeAction *actions, 1135 size_t num_actions) { 1136 DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid); 1137 MachProcessSP procSP; 1138 if (GetProcessSP(pid, procSP)) { 1139 DNBThreadResumeActions thread_actions(actions, num_actions); 1140 1141 // Below we add a default thread plan just in case one wasn't 1142 // provided so all threads always know what they were supposed to do 1143 if (thread_actions.IsEmpty()) { 1144 // No thread plans were given, so the default it to run all threads 1145 thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, 0); 1146 } else { 1147 // Some thread plans were given which means anything that wasn't 1148 // specified should remain stopped. 1149 thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); 1150 } 1151 return procSP->Resume(thread_actions); 1152 } 1153 return false; 1154 } 1155 1156 nub_bool_t DNBProcessHalt(nub_process_t pid) { 1157 DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid); 1158 MachProcessSP procSP; 1159 if (GetProcessSP(pid, procSP)) 1160 return procSP->Signal(SIGSTOP); 1161 return false; 1162 } 1163 // 1164 // nub_bool_t 1165 // DNBThreadResume (nub_process_t pid, nub_thread_t tid, nub_bool_t step) 1166 //{ 1167 // DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u)", 1168 // __FUNCTION__, pid, tid, (uint32_t)step); 1169 // MachProcessSP procSP; 1170 // if (GetProcessSP (pid, procSP)) 1171 // { 1172 // return procSP->Resume(tid, step, 0); 1173 // } 1174 // return false; 1175 //} 1176 // 1177 // nub_bool_t 1178 // DNBThreadResumeWithSignal (nub_process_t pid, nub_thread_t tid, nub_bool_t 1179 // step, int signal) 1180 //{ 1181 // DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u, 1182 // signal = %i)", __FUNCTION__, pid, tid, (uint32_t)step, signal); 1183 // MachProcessSP procSP; 1184 // if (GetProcessSP (pid, procSP)) 1185 // { 1186 // return procSP->Resume(tid, step, signal); 1187 // } 1188 // return false; 1189 //} 1190 1191 nub_event_t DNBProcessWaitForEvents(nub_process_t pid, nub_event_t event_mask, 1192 bool wait_for_set, 1193 struct timespec *timeout) { 1194 nub_event_t result = 0; 1195 MachProcessSP procSP; 1196 if (GetProcessSP(pid, procSP)) { 1197 if (wait_for_set) 1198 result = procSP->Events().WaitForSetEvents(event_mask, timeout); 1199 else 1200 result = procSP->Events().WaitForEventsToReset(event_mask, timeout); 1201 } 1202 return result; 1203 } 1204 1205 void DNBProcessResetEvents(nub_process_t pid, nub_event_t event_mask) { 1206 MachProcessSP procSP; 1207 if (GetProcessSP(pid, procSP)) 1208 procSP->Events().ResetEvents(event_mask); 1209 } 1210 1211 // Breakpoints 1212 nub_bool_t DNBBreakpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size, 1213 nub_bool_t hardware) { 1214 MachProcessSP procSP; 1215 if (GetProcessSP(pid, procSP)) 1216 return procSP->CreateBreakpoint(addr, size, hardware) != NULL; 1217 return false; 1218 } 1219 1220 nub_bool_t DNBBreakpointClear(nub_process_t pid, nub_addr_t addr) { 1221 MachProcessSP procSP; 1222 if (GetProcessSP(pid, procSP)) 1223 return procSP->DisableBreakpoint(addr, true); 1224 return false; // Failed 1225 } 1226 1227 // Watchpoints 1228 nub_bool_t DNBWatchpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size, 1229 uint32_t watch_flags, nub_bool_t hardware) { 1230 MachProcessSP procSP; 1231 if (GetProcessSP(pid, procSP)) 1232 return procSP->CreateWatchpoint(addr, size, watch_flags, hardware) != NULL; 1233 return false; 1234 } 1235 1236 nub_bool_t DNBWatchpointClear(nub_process_t pid, nub_addr_t addr) { 1237 MachProcessSP procSP; 1238 if (GetProcessSP(pid, procSP)) 1239 return procSP->DisableWatchpoint(addr, true); 1240 return false; // Failed 1241 } 1242 1243 // Return the number of supported hardware watchpoints. 1244 uint32_t DNBWatchpointGetNumSupportedHWP(nub_process_t pid) { 1245 MachProcessSP procSP; 1246 if (GetProcessSP(pid, procSP)) 1247 return procSP->GetNumSupportedHardwareWatchpoints(); 1248 return 0; 1249 } 1250 1251 // Read memory in the address space of process PID. This call will take 1252 // care of setting and restoring permissions and breaking up the memory 1253 // read into multiple chunks as required. 1254 // 1255 // RETURNS: number of bytes actually read 1256 nub_size_t DNBProcessMemoryRead(nub_process_t pid, nub_addr_t addr, 1257 nub_size_t size, void *buf) { 1258 MachProcessSP procSP; 1259 if (GetProcessSP(pid, procSP)) 1260 return procSP->ReadMemory(addr, size, buf); 1261 return 0; 1262 } 1263 1264 uint64_t DNBProcessMemoryReadInteger(nub_process_t pid, nub_addr_t addr, 1265 nub_size_t integer_size, 1266 uint64_t fail_value) { 1267 union Integers { 1268 uint8_t u8; 1269 uint16_t u16; 1270 uint32_t u32; 1271 uint64_t u64; 1272 }; 1273 1274 if (integer_size <= sizeof(uint64_t)) { 1275 Integers ints; 1276 if (DNBProcessMemoryRead(pid, addr, integer_size, &ints) == integer_size) { 1277 switch (integer_size) { 1278 case 1: 1279 return ints.u8; 1280 case 2: 1281 return ints.u16; 1282 case 3: 1283 return ints.u32 & 0xffffffu; 1284 case 4: 1285 return ints.u32; 1286 case 5: 1287 return ints.u32 & 0x000000ffffffffffull; 1288 case 6: 1289 return ints.u32 & 0x0000ffffffffffffull; 1290 case 7: 1291 return ints.u32 & 0x00ffffffffffffffull; 1292 case 8: 1293 return ints.u64; 1294 } 1295 } 1296 } 1297 return fail_value; 1298 } 1299 1300 nub_addr_t DNBProcessMemoryReadPointer(nub_process_t pid, nub_addr_t addr) { 1301 cpu_type_t cputype = DNBProcessGetCPUType(pid); 1302 if (cputype) { 1303 const nub_size_t pointer_size = (cputype & CPU_ARCH_ABI64) ? 8 : 4; 1304 return DNBProcessMemoryReadInteger(pid, addr, pointer_size, 0); 1305 } 1306 return 0; 1307 } 1308 1309 std::string DNBProcessMemoryReadCString(nub_process_t pid, nub_addr_t addr) { 1310 std::string cstr; 1311 char buffer[256]; 1312 const nub_size_t max_buffer_cstr_length = sizeof(buffer) - 1; 1313 buffer[max_buffer_cstr_length] = '\0'; 1314 nub_size_t length = 0; 1315 nub_addr_t curr_addr = addr; 1316 do { 1317 nub_size_t bytes_read = 1318 DNBProcessMemoryRead(pid, curr_addr, max_buffer_cstr_length, buffer); 1319 if (bytes_read == 0) 1320 break; 1321 length = strlen(buffer); 1322 cstr.append(buffer, length); 1323 curr_addr += length; 1324 } while (length == max_buffer_cstr_length); 1325 return cstr; 1326 } 1327 1328 std::string DNBProcessMemoryReadCStringFixed(nub_process_t pid, nub_addr_t addr, 1329 nub_size_t fixed_length) { 1330 std::string cstr; 1331 char buffer[fixed_length + 1]; 1332 buffer[fixed_length] = '\0'; 1333 nub_size_t bytes_read = DNBProcessMemoryRead(pid, addr, fixed_length, buffer); 1334 if (bytes_read > 0) 1335 cstr.assign(buffer); 1336 return cstr; 1337 } 1338 1339 // Write memory to the address space of process PID. This call will take 1340 // care of setting and restoring permissions and breaking up the memory 1341 // write into multiple chunks as required. 1342 // 1343 // RETURNS: number of bytes actually written 1344 nub_size_t DNBProcessMemoryWrite(nub_process_t pid, nub_addr_t addr, 1345 nub_size_t size, const void *buf) { 1346 MachProcessSP procSP; 1347 if (GetProcessSP(pid, procSP)) 1348 return procSP->WriteMemory(addr, size, buf); 1349 return 0; 1350 } 1351 1352 nub_addr_t DNBProcessMemoryAllocate(nub_process_t pid, nub_size_t size, 1353 uint32_t permissions) { 1354 MachProcessSP procSP; 1355 if (GetProcessSP(pid, procSP)) 1356 return procSP->Task().AllocateMemory(size, permissions); 1357 return 0; 1358 } 1359 1360 nub_bool_t DNBProcessMemoryDeallocate(nub_process_t pid, nub_addr_t addr) { 1361 MachProcessSP procSP; 1362 if (GetProcessSP(pid, procSP)) 1363 return procSP->Task().DeallocateMemory(addr); 1364 return 0; 1365 } 1366 1367 // Find attributes of the memory region that contains ADDR for process PID, 1368 // if possible, and return a string describing those attributes. 1369 // 1370 // Returns 1 if we could find attributes for this region and OUTBUF can 1371 // be sent to the remote debugger. 1372 // 1373 // Returns 0 if we couldn't find the attributes for a region of memory at 1374 // that address and OUTBUF should not be sent. 1375 // 1376 // Returns -1 if this platform cannot look up information about memory regions 1377 // or if we do not yet have a valid launched process. 1378 // 1379 int DNBProcessMemoryRegionInfo(nub_process_t pid, nub_addr_t addr, 1380 DNBRegionInfo *region_info) { 1381 MachProcessSP procSP; 1382 if (GetProcessSP(pid, procSP)) 1383 return procSP->Task().GetMemoryRegionInfo(addr, region_info); 1384 1385 return -1; 1386 } 1387 1388 std::string DNBProcessGetProfileData(nub_process_t pid, 1389 DNBProfileDataScanType scanType) { 1390 MachProcessSP procSP; 1391 if (GetProcessSP(pid, procSP)) 1392 return procSP->Task().GetProfileData(scanType); 1393 1394 return std::string(""); 1395 } 1396 1397 nub_bool_t DNBProcessSetEnableAsyncProfiling(nub_process_t pid, 1398 nub_bool_t enable, 1399 uint64_t interval_usec, 1400 DNBProfileDataScanType scan_type) { 1401 MachProcessSP procSP; 1402 if (GetProcessSP(pid, procSP)) { 1403 procSP->SetEnableAsyncProfiling(enable, interval_usec, scan_type); 1404 return true; 1405 } 1406 1407 return false; 1408 } 1409 1410 // Get the number of threads for the specified process. 1411 nub_size_t DNBProcessGetNumThreads(nub_process_t pid) { 1412 MachProcessSP procSP; 1413 if (GetProcessSP(pid, procSP)) 1414 return procSP->GetNumThreads(); 1415 return 0; 1416 } 1417 1418 // Get the thread ID of the current thread. 1419 nub_thread_t DNBProcessGetCurrentThread(nub_process_t pid) { 1420 MachProcessSP procSP; 1421 if (GetProcessSP(pid, procSP)) 1422 return procSP->GetCurrentThread(); 1423 return 0; 1424 } 1425 1426 // Get the mach port number of the current thread. 1427 nub_thread_t DNBProcessGetCurrentThreadMachPort(nub_process_t pid) { 1428 MachProcessSP procSP; 1429 if (GetProcessSP(pid, procSP)) 1430 return procSP->GetCurrentThreadMachPort(); 1431 return 0; 1432 } 1433 1434 // Change the current thread. 1435 nub_thread_t DNBProcessSetCurrentThread(nub_process_t pid, nub_thread_t tid) { 1436 MachProcessSP procSP; 1437 if (GetProcessSP(pid, procSP)) 1438 return procSP->SetCurrentThread(tid); 1439 return INVALID_NUB_THREAD; 1440 } 1441 1442 // Dump a string describing a thread's stop reason to the specified file 1443 // handle 1444 nub_bool_t DNBThreadGetStopReason(nub_process_t pid, nub_thread_t tid, 1445 struct DNBThreadStopInfo *stop_info) { 1446 MachProcessSP procSP; 1447 if (GetProcessSP(pid, procSP)) 1448 return procSP->GetThreadStoppedReason(tid, stop_info); 1449 return false; 1450 } 1451 1452 // Return string description for the specified thread. 1453 // 1454 // RETURNS: NULL if the thread isn't valid, else a NULL terminated C 1455 // string from a static buffer that must be copied prior to subsequent 1456 // calls. 1457 const char *DNBThreadGetInfo(nub_process_t pid, nub_thread_t tid) { 1458 MachProcessSP procSP; 1459 if (GetProcessSP(pid, procSP)) 1460 return procSP->GetThreadInfo(tid); 1461 return NULL; 1462 } 1463 1464 // Get the thread ID given a thread index. 1465 nub_thread_t DNBProcessGetThreadAtIndex(nub_process_t pid, size_t thread_idx) { 1466 MachProcessSP procSP; 1467 if (GetProcessSP(pid, procSP)) 1468 return procSP->GetThreadAtIndex(thread_idx); 1469 return INVALID_NUB_THREAD; 1470 } 1471 1472 // Do whatever is needed to sync the thread's register state with it's kernel 1473 // values. 1474 nub_bool_t DNBProcessSyncThreadState(nub_process_t pid, nub_thread_t tid) { 1475 MachProcessSP procSP; 1476 if (GetProcessSP(pid, procSP)) 1477 return procSP->SyncThreadState(tid); 1478 return false; 1479 } 1480 1481 nub_addr_t DNBProcessGetSharedLibraryInfoAddress(nub_process_t pid) { 1482 MachProcessSP procSP; 1483 DNBError err; 1484 if (GetProcessSP(pid, procSP)) 1485 return procSP->Task().GetDYLDAllImageInfosAddress(err); 1486 return INVALID_NUB_ADDRESS; 1487 } 1488 1489 nub_bool_t DNBProcessSharedLibrariesUpdated(nub_process_t pid) { 1490 MachProcessSP procSP; 1491 if (GetProcessSP(pid, procSP)) { 1492 procSP->SharedLibrariesUpdated(); 1493 return true; 1494 } 1495 return false; 1496 } 1497 1498 std::optional<std::string> 1499 DNBGetDeploymentInfo(nub_process_t pid, bool is_executable, 1500 const struct load_command &lc, 1501 uint64_t load_command_address, uint32_t &major_version, 1502 uint32_t &minor_version, uint32_t &patch_version) { 1503 MachProcessSP procSP; 1504 if (GetProcessSP(pid, procSP)) { 1505 // FIXME: This doesn't return the correct result when xctest (a 1506 // macOS binary) is loaded with the macCatalyst dyld platform 1507 // override. The image info corrects for this, but qProcessInfo 1508 // will return what is in the binary. 1509 auto info = 1510 procSP->GetDeploymentInfo(lc, load_command_address, is_executable); 1511 major_version = info.major_version; 1512 minor_version = info.minor_version; 1513 patch_version = info.patch_version; 1514 // MachProcess::DeploymentInfo has a bool operator to tell whether we have 1515 // set the platform. If that's not true, don't report out the platform: 1516 if (!info) 1517 return {}; 1518 return procSP->GetPlatformString(info.platform); 1519 } 1520 return {}; 1521 } 1522 1523 // Get the current shared library information for a process. Only return 1524 // the shared libraries that have changed since the last shared library 1525 // state changed event if only_changed is non-zero. 1526 nub_size_t 1527 DNBProcessGetSharedLibraryInfo(nub_process_t pid, nub_bool_t only_changed, 1528 struct DNBExecutableImageInfo **image_infos) { 1529 MachProcessSP procSP; 1530 if (GetProcessSP(pid, procSP)) 1531 return procSP->CopyImageInfos(image_infos, only_changed); 1532 1533 // If we have no process, then return NULL for the shared library info 1534 // and zero for shared library count 1535 *image_infos = NULL; 1536 return 0; 1537 } 1538 1539 uint32_t DNBGetRegisterCPUType() { 1540 return DNBArchProtocol::GetRegisterCPUType(); 1541 } 1542 // Get the register set information for a specific thread. 1543 const DNBRegisterSetInfo *DNBGetRegisterSetInfo(nub_size_t *num_reg_sets) { 1544 return DNBArchProtocol::GetRegisterSetInfo(num_reg_sets); 1545 } 1546 1547 // Read a register value by register set and register index. 1548 nub_bool_t DNBThreadGetRegisterValueByID(nub_process_t pid, nub_thread_t tid, 1549 uint32_t set, uint32_t reg, 1550 DNBRegisterValue *value) { 1551 MachProcessSP procSP; 1552 ::bzero(value, sizeof(DNBRegisterValue)); 1553 if (GetProcessSP(pid, procSP)) { 1554 if (tid != INVALID_NUB_THREAD) 1555 return procSP->GetRegisterValue(tid, set, reg, value); 1556 } 1557 return false; 1558 } 1559 1560 nub_bool_t DNBThreadSetRegisterValueByID(nub_process_t pid, nub_thread_t tid, 1561 uint32_t set, uint32_t reg, 1562 const DNBRegisterValue *value) { 1563 if (tid != INVALID_NUB_THREAD) { 1564 MachProcessSP procSP; 1565 if (GetProcessSP(pid, procSP)) 1566 return procSP->SetRegisterValue(tid, set, reg, value); 1567 } 1568 return false; 1569 } 1570 1571 nub_size_t DNBThreadGetRegisterContext(nub_process_t pid, nub_thread_t tid, 1572 void *buf, size_t buf_len) { 1573 MachProcessSP procSP; 1574 if (GetProcessSP(pid, procSP)) { 1575 if (tid != INVALID_NUB_THREAD) 1576 return procSP->GetThreadList().GetRegisterContext(tid, buf, buf_len); 1577 } 1578 ::bzero(buf, buf_len); 1579 return 0; 1580 } 1581 1582 nub_size_t DNBThreadSetRegisterContext(nub_process_t pid, nub_thread_t tid, 1583 const void *buf, size_t buf_len) { 1584 MachProcessSP procSP; 1585 if (GetProcessSP(pid, procSP)) { 1586 if (tid != INVALID_NUB_THREAD) 1587 return procSP->GetThreadList().SetRegisterContext(tid, buf, buf_len); 1588 } 1589 return 0; 1590 } 1591 1592 uint32_t DNBThreadSaveRegisterState(nub_process_t pid, nub_thread_t tid) { 1593 if (tid != INVALID_NUB_THREAD) { 1594 MachProcessSP procSP; 1595 if (GetProcessSP(pid, procSP)) 1596 return procSP->GetThreadList().SaveRegisterState(tid); 1597 } 1598 return 0; 1599 } 1600 nub_bool_t DNBThreadRestoreRegisterState(nub_process_t pid, nub_thread_t tid, 1601 uint32_t save_id) { 1602 if (tid != INVALID_NUB_THREAD) { 1603 MachProcessSP procSP; 1604 if (GetProcessSP(pid, procSP)) 1605 return procSP->GetThreadList().RestoreRegisterState(tid, save_id); 1606 } 1607 return false; 1608 } 1609 1610 // Read a register value by name. 1611 nub_bool_t DNBThreadGetRegisterValueByName(nub_process_t pid, nub_thread_t tid, 1612 uint32_t reg_set, 1613 const char *reg_name, 1614 DNBRegisterValue *value) { 1615 MachProcessSP procSP; 1616 ::bzero(value, sizeof(DNBRegisterValue)); 1617 if (GetProcessSP(pid, procSP)) { 1618 const struct DNBRegisterSetInfo *set_info; 1619 nub_size_t num_reg_sets = 0; 1620 set_info = DNBGetRegisterSetInfo(&num_reg_sets); 1621 if (set_info) { 1622 uint32_t set = reg_set; 1623 uint32_t reg; 1624 if (set == REGISTER_SET_ALL) { 1625 for (set = 1; set < num_reg_sets; ++set) { 1626 for (reg = 0; reg < set_info[set].num_registers; ++reg) { 1627 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) 1628 return procSP->GetRegisterValue(tid, set, reg, value); 1629 } 1630 } 1631 } else { 1632 for (reg = 0; reg < set_info[set].num_registers; ++reg) { 1633 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) 1634 return procSP->GetRegisterValue(tid, set, reg, value); 1635 } 1636 } 1637 } 1638 } 1639 return false; 1640 } 1641 1642 // Read a register set and register number from the register name. 1643 nub_bool_t DNBGetRegisterInfoByName(const char *reg_name, 1644 DNBRegisterInfo *info) { 1645 const struct DNBRegisterSetInfo *set_info; 1646 nub_size_t num_reg_sets = 0; 1647 set_info = DNBGetRegisterSetInfo(&num_reg_sets); 1648 if (set_info) { 1649 uint32_t set, reg; 1650 for (set = 1; set < num_reg_sets; ++set) { 1651 for (reg = 0; reg < set_info[set].num_registers; ++reg) { 1652 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) { 1653 *info = set_info[set].registers[reg]; 1654 return true; 1655 } 1656 } 1657 } 1658 1659 for (set = 1; set < num_reg_sets; ++set) { 1660 uint32_t reg; 1661 for (reg = 0; reg < set_info[set].num_registers; ++reg) { 1662 if (set_info[set].registers[reg].alt == NULL) 1663 continue; 1664 1665 if (strcasecmp(reg_name, set_info[set].registers[reg].alt) == 0) { 1666 *info = set_info[set].registers[reg]; 1667 return true; 1668 } 1669 } 1670 } 1671 } 1672 1673 ::bzero(info, sizeof(DNBRegisterInfo)); 1674 return false; 1675 } 1676 1677 // Set the name to address callback function that this nub can use 1678 // for any name to address lookups that are needed. 1679 nub_bool_t DNBProcessSetNameToAddressCallback(nub_process_t pid, 1680 DNBCallbackNameToAddress callback, 1681 void *baton) { 1682 MachProcessSP procSP; 1683 if (GetProcessSP(pid, procSP)) { 1684 procSP->SetNameToAddressCallback(callback, baton); 1685 return true; 1686 } 1687 return false; 1688 } 1689 1690 // Set the name to address callback function that this nub can use 1691 // for any name to address lookups that are needed. 1692 nub_bool_t DNBProcessSetSharedLibraryInfoCallback( 1693 nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, 1694 void *baton) { 1695 MachProcessSP procSP; 1696 if (GetProcessSP(pid, procSP)) { 1697 procSP->SetSharedLibraryInfoCallback(callback, baton); 1698 return true; 1699 } 1700 return false; 1701 } 1702 1703 nub_addr_t DNBProcessLookupAddress(nub_process_t pid, const char *name, 1704 const char *shlib) { 1705 MachProcessSP procSP; 1706 if (GetProcessSP(pid, procSP)) { 1707 return procSP->LookupSymbol(name, shlib); 1708 } 1709 return INVALID_NUB_ADDRESS; 1710 } 1711 1712 nub_size_t DNBProcessGetAvailableSTDOUT(nub_process_t pid, char *buf, 1713 nub_size_t buf_size) { 1714 MachProcessSP procSP; 1715 if (GetProcessSP(pid, procSP)) 1716 return procSP->GetAvailableSTDOUT(buf, buf_size); 1717 return 0; 1718 } 1719 1720 nub_size_t DNBProcessGetAvailableSTDERR(nub_process_t pid, char *buf, 1721 nub_size_t buf_size) { 1722 MachProcessSP procSP; 1723 if (GetProcessSP(pid, procSP)) 1724 return procSP->GetAvailableSTDERR(buf, buf_size); 1725 return 0; 1726 } 1727 1728 nub_size_t DNBProcessGetAvailableProfileData(nub_process_t pid, char *buf, 1729 nub_size_t buf_size) { 1730 MachProcessSP procSP; 1731 if (GetProcessSP(pid, procSP)) 1732 return procSP->GetAsyncProfileData(buf, buf_size); 1733 return 0; 1734 } 1735 1736 nub_size_t DNBProcessGetStopCount(nub_process_t pid) { 1737 MachProcessSP procSP; 1738 if (GetProcessSP(pid, procSP)) 1739 return procSP->StopCount(); 1740 return 0; 1741 } 1742 1743 uint32_t DNBProcessGetCPUType(nub_process_t pid) { 1744 MachProcessSP procSP; 1745 if (GetProcessSP(pid, procSP)) 1746 return procSP->GetCPUType(); 1747 return 0; 1748 } 1749 1750 nub_bool_t DNBResolveExecutablePath(const char *path, char *resolved_path, 1751 size_t resolved_path_size) { 1752 if (path == NULL || path[0] == '\0') 1753 return false; 1754 1755 char max_path[PATH_MAX]; 1756 std::string result; 1757 CFString::GlobPath(path, result); 1758 1759 if (result.empty()) 1760 result = path; 1761 1762 struct stat path_stat; 1763 if (::stat(path, &path_stat) == 0) { 1764 if ((path_stat.st_mode & S_IFMT) == S_IFDIR) { 1765 CFBundle bundle(path); 1766 CFReleaser<CFURLRef> url(bundle.CopyExecutableURL()); 1767 if (url.get()) { 1768 if (::CFURLGetFileSystemRepresentation( 1769 url.get(), true, (UInt8 *)resolved_path, resolved_path_size)) 1770 return true; 1771 } 1772 } 1773 } 1774 1775 if (realpath(path, max_path)) { 1776 // Found the path relatively... 1777 ::strlcpy(resolved_path, max_path, resolved_path_size); 1778 return strlen(resolved_path) + 1 < resolved_path_size; 1779 } else { 1780 // Not a relative path, check the PATH environment variable if the 1781 const char *PATH = getenv("PATH"); 1782 if (PATH) { 1783 const char *curr_path_start = PATH; 1784 const char *curr_path_end; 1785 while (curr_path_start && *curr_path_start) { 1786 curr_path_end = strchr(curr_path_start, ':'); 1787 if (curr_path_end == NULL) { 1788 result.assign(curr_path_start); 1789 curr_path_start = NULL; 1790 } else if (curr_path_end > curr_path_start) { 1791 size_t len = curr_path_end - curr_path_start; 1792 result.assign(curr_path_start, len); 1793 curr_path_start += len + 1; 1794 } else 1795 break; 1796 1797 result += '/'; 1798 result += path; 1799 struct stat s; 1800 if (stat(result.c_str(), &s) == 0) { 1801 ::strlcpy(resolved_path, result.c_str(), resolved_path_size); 1802 return result.size() + 1 < resolved_path_size; 1803 } 1804 } 1805 } 1806 } 1807 return false; 1808 } 1809 1810 bool DNBGetOSVersionNumbers(uint64_t *major, uint64_t *minor, uint64_t *patch) { 1811 return MachProcess::GetOSVersionNumbers(major, minor, patch); 1812 } 1813 1814 std::string DNBGetMacCatalystVersionString() { 1815 return MachProcess::GetMacCatalystVersionString(); 1816 } 1817 1818 void DNBInitialize() { 1819 DNBLogThreadedIf(LOG_PROCESS, "DNBInitialize ()"); 1820 #if defined(__i386__) || defined(__x86_64__) 1821 DNBArchImplX86_64::Initialize(); 1822 #elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 1823 DNBArchMachARM64::Initialize(); 1824 #endif 1825 } 1826 1827 void DNBTerminate() {} 1828 1829 nub_bool_t DNBSetArchitecture(const char *arch) { 1830 if (arch && arch[0]) { 1831 if (strcasecmp(arch, "i386") == 0) 1832 return DNBArchProtocol::SetArchitecture(CPU_TYPE_I386); 1833 else if (strcasecmp(arch, "x86_64") == 0) 1834 return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64, 1835 CPU_SUBTYPE_X86_64_ALL); 1836 else if (strcasecmp(arch, "x86_64h") == 0) 1837 return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64, 1838 CPU_SUBTYPE_X86_64_H); 1839 else if (strstr(arch, "arm64_32") == arch || 1840 strstr(arch, "aarch64_32") == arch) 1841 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64_32); 1842 else if (strstr(arch, "arm64e") == arch) 1843 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64, 1844 CPU_SUBTYPE_ARM64E); 1845 else if (strstr(arch, "arm64") == arch || strstr(arch, "aarch64") == arch) 1846 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64, 1847 CPU_SUBTYPE_ARM64_ALL); 1848 else if (strstr(arch, "armv8") == arch) 1849 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64, 1850 CPU_SUBTYPE_ARM64_V8); 1851 else if (strstr(arch, "armv7em") == arch) 1852 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, 1853 CPU_SUBTYPE_ARM_V7EM); 1854 else if (strstr(arch, "armv7m") == arch) 1855 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, 1856 CPU_SUBTYPE_ARM_V7M); 1857 else if (strstr(arch, "armv7k") == arch) 1858 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, 1859 CPU_SUBTYPE_ARM_V7K); 1860 else if (strstr(arch, "armv7s") == arch) 1861 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, 1862 CPU_SUBTYPE_ARM_V7S); 1863 else if (strstr(arch, "armv7") == arch) 1864 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7); 1865 else if (strstr(arch, "armv6m") == arch) 1866 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, 1867 CPU_SUBTYPE_ARM_V6M); 1868 else if (strstr(arch, "armv6") == arch) 1869 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6); 1870 else if (strstr(arch, "armv5") == arch) 1871 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, 1872 CPU_SUBTYPE_ARM_V5TEJ); 1873 else if (strstr(arch, "armv4t") == arch) 1874 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, 1875 CPU_SUBTYPE_ARM_V4T); 1876 else if (strstr(arch, "arm") == arch) 1877 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, 1878 CPU_SUBTYPE_ARM_ALL); 1879 } 1880 return false; 1881 } 1882 1883 bool DNBDebugserverIsTranslated() { 1884 int ret = 0; 1885 size_t size = sizeof(ret); 1886 if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) 1887 return false; 1888 return ret == 1; 1889 } 1890 1891 bool DNBGetAddressingBits(uint32_t &addressing_bits) { 1892 static uint32_t g_addressing_bits = 0; 1893 static std::once_flag g_once_flag; 1894 std::call_once(g_once_flag, [&](){ 1895 size_t len = sizeof(uint32_t); 1896 if (::sysctlbyname("machdep.virtual_address_size", &g_addressing_bits, &len, 1897 NULL, 0) != 0) { 1898 g_addressing_bits = 0; 1899 } 1900 }); 1901 1902 addressing_bits = g_addressing_bits; 1903 1904 return addressing_bits > 0; 1905 } 1906 1907 nub_process_t DNBGetParentProcessID(nub_process_t child_pid) { 1908 return MachProcess::GetParentProcessID(child_pid); 1909 } 1910 1911 bool DNBProcessIsBeingDebugged(nub_process_t pid) { 1912 return MachProcess::ProcessIsBeingDebugged(pid); 1913 } 1914