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