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