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