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