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