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