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