xref: /openbsd-src/gnu/llvm/lldb/tools/debugserver/source/DNB.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1061da546Spatrick //===-- DNB.cpp -------------------------------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick //
9061da546Spatrick //  Created by Greg Clayton on 3/23/07.
10061da546Spatrick //
11061da546Spatrick //===----------------------------------------------------------------------===//
12061da546Spatrick 
13061da546Spatrick #include "DNB.h"
14be691f3bSpatrick #include <cinttypes>
15be691f3bSpatrick #include <csignal>
16be691f3bSpatrick #include <cstdio>
17be691f3bSpatrick #include <cstdlib>
18061da546Spatrick #include <libproc.h>
19061da546Spatrick #include <map>
20061da546Spatrick #include <sys/resource.h>
21061da546Spatrick #include <sys/stat.h>
22061da546Spatrick #include <sys/sysctl.h>
23061da546Spatrick #include <sys/types.h>
24061da546Spatrick #include <sys/wait.h>
25061da546Spatrick #include <unistd.h>
26061da546Spatrick #include <vector>
27061da546Spatrick 
28061da546Spatrick #if defined(__APPLE__)
29061da546Spatrick #include <pthread.h>
30061da546Spatrick #include <sched.h>
31061da546Spatrick #endif
32061da546Spatrick 
33061da546Spatrick #define TRY_KQUEUE 1
34061da546Spatrick 
35061da546Spatrick #ifdef TRY_KQUEUE
36061da546Spatrick #include <sys/event.h>
37061da546Spatrick #include <sys/time.h>
38061da546Spatrick #ifdef NOTE_EXIT_DETAIL
39061da546Spatrick #define USE_KQUEUE
40061da546Spatrick #endif
41061da546Spatrick #endif
42061da546Spatrick 
43061da546Spatrick #include "CFBundle.h"
44061da546Spatrick #include "CFString.h"
45061da546Spatrick #include "DNBDataRef.h"
46061da546Spatrick #include "DNBLog.h"
47061da546Spatrick #include "DNBThreadResumeActions.h"
48061da546Spatrick #include "DNBTimer.h"
49061da546Spatrick #include "MacOSX/Genealogy.h"
50061da546Spatrick #include "MacOSX/MachProcess.h"
51061da546Spatrick #include "MacOSX/MachTask.h"
52061da546Spatrick #include "MacOSX/ThreadInfo.h"
53061da546Spatrick 
54061da546Spatrick typedef std::shared_ptr<MachProcess> MachProcessSP;
55061da546Spatrick typedef std::map<nub_process_t, MachProcessSP> ProcessMap;
56061da546Spatrick typedef ProcessMap::iterator ProcessMapIter;
57061da546Spatrick typedef ProcessMap::const_iterator ProcessMapConstIter;
58061da546Spatrick 
59061da546Spatrick static size_t
60061da546Spatrick GetAllInfosMatchingName(const char *process_name,
61061da546Spatrick                         std::vector<struct kinfo_proc> &matching_proc_infos);
62061da546Spatrick 
63061da546Spatrick // A Thread safe singleton to get a process map pointer.
64061da546Spatrick //
65061da546Spatrick // Returns a pointer to the existing process map, or a pointer to a
66061da546Spatrick // newly created process map if CAN_CREATE is non-zero.
GetProcessMap(bool can_create)67061da546Spatrick static ProcessMap *GetProcessMap(bool can_create) {
68061da546Spatrick   static ProcessMap *g_process_map_ptr = NULL;
69061da546Spatrick 
70061da546Spatrick   if (can_create && g_process_map_ptr == NULL) {
71061da546Spatrick     static pthread_mutex_t g_process_map_mutex = PTHREAD_MUTEX_INITIALIZER;
72061da546Spatrick     PTHREAD_MUTEX_LOCKER(locker, &g_process_map_mutex);
73061da546Spatrick     if (g_process_map_ptr == NULL)
74061da546Spatrick       g_process_map_ptr = new ProcessMap;
75061da546Spatrick   }
76061da546Spatrick   return g_process_map_ptr;
77061da546Spatrick }
78061da546Spatrick 
79061da546Spatrick // Add PID to the shared process pointer map.
80061da546Spatrick //
81061da546Spatrick // Return non-zero value if we succeed in adding the process to the map.
82061da546Spatrick // The only time this should fail is if we run out of memory and can't
83061da546Spatrick // allocate a ProcessMap.
AddProcessToMap(nub_process_t pid,MachProcessSP & procSP)84061da546Spatrick static nub_bool_t AddProcessToMap(nub_process_t pid, MachProcessSP &procSP) {
85061da546Spatrick   ProcessMap *process_map = GetProcessMap(true);
86061da546Spatrick   if (process_map) {
87061da546Spatrick     process_map->insert(std::make_pair(pid, procSP));
88061da546Spatrick     return true;
89061da546Spatrick   }
90061da546Spatrick   return false;
91061da546Spatrick }
92061da546Spatrick 
93061da546Spatrick // Remove the shared pointer for PID from the process map.
94061da546Spatrick //
95061da546Spatrick // Returns the number of items removed from the process map.
96061da546Spatrick // static size_t
97061da546Spatrick // RemoveProcessFromMap (nub_process_t pid)
98061da546Spatrick //{
99061da546Spatrick //    ProcessMap* process_map = GetProcessMap(false);
100061da546Spatrick //    if (process_map)
101061da546Spatrick //    {
102061da546Spatrick //        return process_map->erase(pid);
103061da546Spatrick //    }
104061da546Spatrick //    return 0;
105061da546Spatrick //}
106061da546Spatrick 
107061da546Spatrick // Get the shared pointer for PID from the existing process map.
108061da546Spatrick //
109061da546Spatrick // Returns true if we successfully find a shared pointer to a
110061da546Spatrick // MachProcess object.
GetProcessSP(nub_process_t pid,MachProcessSP & procSP)111061da546Spatrick static nub_bool_t GetProcessSP(nub_process_t pid, MachProcessSP &procSP) {
112061da546Spatrick   ProcessMap *process_map = GetProcessMap(false);
113061da546Spatrick   if (process_map != NULL) {
114061da546Spatrick     ProcessMapIter pos = process_map->find(pid);
115061da546Spatrick     if (pos != process_map->end()) {
116061da546Spatrick       procSP = pos->second;
117061da546Spatrick       return true;
118061da546Spatrick     }
119061da546Spatrick   }
120061da546Spatrick   procSP.reset();
121061da546Spatrick   return false;
122061da546Spatrick }
123061da546Spatrick 
124061da546Spatrick #ifdef USE_KQUEUE
kqueue_thread(void * arg)125061da546Spatrick void *kqueue_thread(void *arg) {
126061da546Spatrick   int kq_id = (int)(intptr_t)arg;
127061da546Spatrick 
128061da546Spatrick #if defined(__APPLE__)
129061da546Spatrick   pthread_setname_np("kqueue thread");
130061da546Spatrick #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
131061da546Spatrick   struct sched_param thread_param;
132061da546Spatrick   int thread_sched_policy;
133061da546Spatrick   if (pthread_getschedparam(pthread_self(), &thread_sched_policy,
134061da546Spatrick                             &thread_param) == 0) {
135061da546Spatrick     thread_param.sched_priority = 47;
136061da546Spatrick     pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
137061da546Spatrick   }
138061da546Spatrick #endif
139061da546Spatrick #endif
140061da546Spatrick 
141061da546Spatrick   struct kevent death_event;
142061da546Spatrick   while (true) {
143061da546Spatrick     int n_events = kevent(kq_id, NULL, 0, &death_event, 1, NULL);
144061da546Spatrick     if (n_events == -1) {
145061da546Spatrick       if (errno == EINTR)
146061da546Spatrick         continue;
147061da546Spatrick       else {
148061da546Spatrick         DNBLogError("kqueue failed with error: (%d): %s", errno,
149061da546Spatrick                     strerror(errno));
150061da546Spatrick         return NULL;
151061da546Spatrick       }
152061da546Spatrick     } else if (death_event.flags & EV_ERROR) {
153061da546Spatrick       int error_no = static_cast<int>(death_event.data);
154061da546Spatrick       const char *error_str = strerror(error_no);
155061da546Spatrick       if (error_str == NULL)
156061da546Spatrick         error_str = "Unknown error";
157061da546Spatrick       DNBLogError("Failed to initialize kqueue event: (%d): %s", error_no,
158061da546Spatrick                   error_str);
159061da546Spatrick       return NULL;
160061da546Spatrick     } else {
161061da546Spatrick       int status;
162061da546Spatrick       const pid_t pid = (pid_t)death_event.ident;
163061da546Spatrick       const pid_t child_pid = waitpid(pid, &status, 0);
164061da546Spatrick 
165061da546Spatrick       bool exited = false;
166061da546Spatrick       int signal = 0;
167061da546Spatrick       int exit_status = 0;
168061da546Spatrick       if (WIFSTOPPED(status)) {
169061da546Spatrick         signal = WSTOPSIG(status);
170061da546Spatrick         DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> STOPPED (signal = %i)",
171061da546Spatrick                          child_pid, signal);
172061da546Spatrick       } else if (WIFEXITED(status)) {
173061da546Spatrick         exit_status = WEXITSTATUS(status);
174061da546Spatrick         exited = true;
175061da546Spatrick         DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> EXITED (status = %i)",
176061da546Spatrick                          child_pid, exit_status);
177061da546Spatrick       } else if (WIFSIGNALED(status)) {
178061da546Spatrick         signal = WTERMSIG(status);
179061da546Spatrick         if (child_pid == abs(pid)) {
180061da546Spatrick           DNBLogThreadedIf(LOG_PROCESS,
181061da546Spatrick                            "waitpid (%i) -> SIGNALED and EXITED (signal = %i)",
182061da546Spatrick                            child_pid, signal);
183061da546Spatrick           char exit_info[64];
184061da546Spatrick           ::snprintf(exit_info, sizeof(exit_info),
185061da546Spatrick                      "Terminated due to signal %i", signal);
186061da546Spatrick           DNBProcessSetExitInfo(child_pid, exit_info);
187061da546Spatrick           exited = true;
188061da546Spatrick           exit_status = INT8_MAX;
189061da546Spatrick         } else {
190061da546Spatrick           DNBLogThreadedIf(LOG_PROCESS,
191061da546Spatrick                            "waitpid (%i) -> SIGNALED (signal = %i)", child_pid,
192061da546Spatrick                            signal);
193061da546Spatrick         }
194061da546Spatrick       }
195061da546Spatrick 
196061da546Spatrick       if (exited) {
197061da546Spatrick         if (death_event.data & NOTE_EXIT_MEMORY)
198061da546Spatrick           DNBProcessSetExitInfo(child_pid, "Terminated due to memory issue");
199061da546Spatrick         else if (death_event.data & NOTE_EXIT_DECRYPTFAIL)
200061da546Spatrick           DNBProcessSetExitInfo(child_pid, "Terminated due to decrypt failure");
201061da546Spatrick         else if (death_event.data & NOTE_EXIT_CSERROR)
202061da546Spatrick           DNBProcessSetExitInfo(child_pid,
203061da546Spatrick                                 "Terminated due to code signing error");
204061da546Spatrick 
205061da546Spatrick         DNBLogThreadedIf(
206061da546Spatrick             LOG_PROCESS,
207061da546Spatrick             "waitpid_process_thread (): setting exit status for pid = %i to %i",
208061da546Spatrick             child_pid, exit_status);
209061da546Spatrick         DNBProcessSetExitStatus(child_pid, status);
210061da546Spatrick         return NULL;
211061da546Spatrick       }
212061da546Spatrick     }
213061da546Spatrick   }
214061da546Spatrick }
215061da546Spatrick 
spawn_kqueue_thread(pid_t pid)216061da546Spatrick static bool spawn_kqueue_thread(pid_t pid) {
217061da546Spatrick   pthread_t thread;
218061da546Spatrick   int kq_id;
219061da546Spatrick 
220061da546Spatrick   kq_id = kqueue();
221061da546Spatrick   if (kq_id == -1) {
222061da546Spatrick     DNBLogError("Could not get kqueue for pid = %i.", pid);
223061da546Spatrick     return false;
224061da546Spatrick   }
225061da546Spatrick 
226061da546Spatrick   struct kevent reg_event;
227061da546Spatrick 
228061da546Spatrick   EV_SET(&reg_event, pid, EVFILT_PROC, EV_ADD,
229061da546Spatrick          NOTE_EXIT | NOTE_EXITSTATUS | NOTE_EXIT_DETAIL, 0, NULL);
230061da546Spatrick   // Register the event:
231061da546Spatrick   int result = kevent(kq_id, &reg_event, 1, NULL, 0, NULL);
232061da546Spatrick   if (result != 0) {
233061da546Spatrick     DNBLogError(
234061da546Spatrick         "Failed to register kqueue NOTE_EXIT event for pid %i, error: %d.", pid,
235061da546Spatrick         result);
236061da546Spatrick     return false;
237061da546Spatrick   }
238061da546Spatrick 
239061da546Spatrick   int ret =
240061da546Spatrick       ::pthread_create(&thread, NULL, kqueue_thread, (void *)(intptr_t)kq_id);
241061da546Spatrick 
242061da546Spatrick   // pthread_create returns 0 if successful
243061da546Spatrick   if (ret == 0) {
244061da546Spatrick     ::pthread_detach(thread);
245061da546Spatrick     return true;
246061da546Spatrick   }
247061da546Spatrick   return false;
248061da546Spatrick }
249061da546Spatrick #endif // #if USE_KQUEUE
250061da546Spatrick 
waitpid_thread(void * arg)251061da546Spatrick static void *waitpid_thread(void *arg) {
252061da546Spatrick   const pid_t pid = (pid_t)(intptr_t)arg;
253061da546Spatrick   int status;
254061da546Spatrick 
255061da546Spatrick #if defined(__APPLE__)
256061da546Spatrick   pthread_setname_np("waitpid thread");
257061da546Spatrick #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
258061da546Spatrick   struct sched_param thread_param;
259061da546Spatrick   int thread_sched_policy;
260061da546Spatrick   if (pthread_getschedparam(pthread_self(), &thread_sched_policy,
261061da546Spatrick                             &thread_param) == 0) {
262061da546Spatrick     thread_param.sched_priority = 47;
263061da546Spatrick     pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
264061da546Spatrick   }
265061da546Spatrick #endif
266061da546Spatrick #endif
267061da546Spatrick 
268061da546Spatrick   while (true) {
269061da546Spatrick     pid_t child_pid = waitpid(pid, &status, 0);
270061da546Spatrick     DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): waitpid (pid = %i, "
271061da546Spatrick                                   "&status, 0) => %i, status = %i, errno = %i",
272061da546Spatrick                      pid, child_pid, status, errno);
273061da546Spatrick 
274061da546Spatrick     if (child_pid < 0) {
275061da546Spatrick       if (errno == EINTR)
276061da546Spatrick         continue;
277061da546Spatrick       break;
278061da546Spatrick     } else {
279061da546Spatrick       if (WIFSTOPPED(status)) {
280061da546Spatrick         continue;
281061da546Spatrick       } else // if (WIFEXITED(status) || WIFSIGNALED(status))
282061da546Spatrick       {
283061da546Spatrick         DNBLogThreadedIf(
284061da546Spatrick             LOG_PROCESS,
285061da546Spatrick             "waitpid_thread (): setting exit status for pid = %i to %i",
286061da546Spatrick             child_pid, status);
287061da546Spatrick         DNBProcessSetExitStatus(child_pid, status);
288061da546Spatrick         return NULL;
289061da546Spatrick       }
290061da546Spatrick     }
291061da546Spatrick   }
292061da546Spatrick 
293061da546Spatrick   // We should never exit as long as our child process is alive, so if we
294061da546Spatrick   // do something else went wrong and we should exit...
295061da546Spatrick   DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): main loop exited, setting "
296061da546Spatrick                                 "exit status to an invalid value (-1) for pid "
297061da546Spatrick                                 "%i",
298061da546Spatrick                    pid);
299061da546Spatrick   DNBProcessSetExitStatus(pid, -1);
300061da546Spatrick   return NULL;
301061da546Spatrick }
spawn_waitpid_thread(pid_t pid)302061da546Spatrick static bool spawn_waitpid_thread(pid_t pid) {
303061da546Spatrick #ifdef USE_KQUEUE
304061da546Spatrick   bool success = spawn_kqueue_thread(pid);
305061da546Spatrick   if (success)
306061da546Spatrick     return true;
307061da546Spatrick #endif
308061da546Spatrick 
309061da546Spatrick   pthread_t thread;
310061da546Spatrick   int ret =
311061da546Spatrick       ::pthread_create(&thread, NULL, waitpid_thread, (void *)(intptr_t)pid);
312061da546Spatrick   // pthread_create returns 0 if successful
313061da546Spatrick   if (ret == 0) {
314061da546Spatrick     ::pthread_detach(thread);
315061da546Spatrick     return true;
316061da546Spatrick   }
317061da546Spatrick   return false;
318061da546Spatrick }
319061da546Spatrick 
DNBProcessLaunch(RNBContext * ctx,const char * path,char const * argv[],const char * envp[],const char * working_directory,const char * stdin_path,const char * stdout_path,const char * stderr_path,bool no_stdio,int disable_aslr,const char * event_data,char * err_str,size_t err_len)320061da546Spatrick nub_process_t DNBProcessLaunch(
321be691f3bSpatrick     RNBContext *ctx, const char *path, char const *argv[], const char *envp[],
322061da546Spatrick     const char *working_directory, // NULL => don't change, non-NULL => set
323061da546Spatrick                                    // working directory for inferior to this
324061da546Spatrick     const char *stdin_path, const char *stdout_path, const char *stderr_path,
325be691f3bSpatrick     bool no_stdio, int disable_aslr, const char *event_data, char *err_str,
326be691f3bSpatrick     size_t err_len) {
327be691f3bSpatrick   DNBLogThreadedIf(LOG_PROCESS,
328be691f3bSpatrick                    "%s ( path='%s', argv = %p, envp = %p, "
329061da546Spatrick                    "working_dir=%s, stdin=%s, stdout=%s, "
330061da546Spatrick                    "stderr=%s, no-stdio=%i, launch_flavor = %u, "
331061da546Spatrick                    "disable_aslr = %d, err = %p, err_len = "
332061da546Spatrick                    "%llu) called...",
333061da546Spatrick                    __FUNCTION__, path, static_cast<void *>(argv),
334061da546Spatrick                    static_cast<void *>(envp), working_directory, stdin_path,
335be691f3bSpatrick                    stdout_path, stderr_path, no_stdio, ctx->LaunchFlavor(),
336061da546Spatrick                    disable_aslr, static_cast<void *>(err_str),
337061da546Spatrick                    static_cast<uint64_t>(err_len));
338061da546Spatrick 
339061da546Spatrick   if (err_str && err_len > 0)
340061da546Spatrick     err_str[0] = '\0';
341061da546Spatrick   struct stat path_stat;
342061da546Spatrick   if (::stat(path, &path_stat) == -1) {
343061da546Spatrick     char stat_error[256];
344061da546Spatrick     ::strerror_r(errno, stat_error, sizeof(stat_error));
345061da546Spatrick     snprintf(err_str, err_len, "%s (%s)", stat_error, path);
346061da546Spatrick     return INVALID_NUB_PROCESS;
347061da546Spatrick   }
348061da546Spatrick 
349061da546Spatrick   MachProcessSP processSP(new MachProcess);
350061da546Spatrick   if (processSP.get()) {
351061da546Spatrick     DNBError launch_err;
352be691f3bSpatrick     pid_t pid = processSP->LaunchForDebug(
353be691f3bSpatrick         path, argv, envp, working_directory, stdin_path, stdout_path,
354be691f3bSpatrick         stderr_path, no_stdio, ctx->LaunchFlavor(), disable_aslr, event_data,
355*f6aab3d8Srobert         ctx->GetIgnoredExceptions(), launch_err);
356061da546Spatrick     if (err_str) {
357061da546Spatrick       *err_str = '\0';
358061da546Spatrick       if (launch_err.Fail()) {
359061da546Spatrick         const char *launch_err_str = launch_err.AsString();
360061da546Spatrick         if (launch_err_str) {
361061da546Spatrick           strlcpy(err_str, launch_err_str, err_len - 1);
362061da546Spatrick           err_str[err_len - 1] =
363061da546Spatrick               '\0'; // Make sure the error string is terminated
364061da546Spatrick         }
365061da546Spatrick       }
366061da546Spatrick     }
367061da546Spatrick 
368061da546Spatrick     DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) new pid is %d...", pid);
369061da546Spatrick 
370061da546Spatrick     if (pid != INVALID_NUB_PROCESS) {
371061da546Spatrick       // Spawn a thread to reap our child inferior process...
372061da546Spatrick       spawn_waitpid_thread(pid);
373061da546Spatrick 
374061da546Spatrick       if (processSP->Task().TaskPortForProcessID(launch_err) == TASK_NULL) {
375061da546Spatrick         // We failed to get the task for our process ID which is bad.
376061da546Spatrick         // Kill our process otherwise it will be stopped at the entry
377061da546Spatrick         // point and get reparented to someone else and never go away.
378061da546Spatrick         DNBLog("Could not get task port for process, sending SIGKILL and "
379061da546Spatrick                "exiting.");
380061da546Spatrick         kill(SIGKILL, pid);
381061da546Spatrick 
382061da546Spatrick         if (err_str && err_len > 0) {
383061da546Spatrick           if (launch_err.AsString()) {
384061da546Spatrick             ::snprintf(err_str, err_len,
385061da546Spatrick                        "failed to get the task for process %i (%s)", pid,
386061da546Spatrick                        launch_err.AsString());
387061da546Spatrick           } else {
388061da546Spatrick             ::snprintf(err_str, err_len,
389061da546Spatrick                        "failed to get the task for process %i", pid);
390061da546Spatrick           }
391061da546Spatrick         }
392061da546Spatrick       } else {
393061da546Spatrick         bool res = AddProcessToMap(pid, processSP);
394061da546Spatrick         UNUSED_IF_ASSERT_DISABLED(res);
395061da546Spatrick         assert(res && "Couldn't add process to map!");
396061da546Spatrick         return pid;
397061da546Spatrick       }
398061da546Spatrick     }
399061da546Spatrick   }
400061da546Spatrick   return INVALID_NUB_PROCESS;
401061da546Spatrick }
402061da546Spatrick 
403061da546Spatrick // If there is one process with a given name, return the pid for that process.
DNBProcessGetPIDByName(const char * name)404061da546Spatrick nub_process_t DNBProcessGetPIDByName(const char *name) {
405061da546Spatrick   std::vector<struct kinfo_proc> matching_proc_infos;
406061da546Spatrick   size_t num_matching_proc_infos =
407061da546Spatrick       GetAllInfosMatchingName(name, matching_proc_infos);
408061da546Spatrick   if (num_matching_proc_infos == 1) {
409061da546Spatrick     return matching_proc_infos[0].kp_proc.p_pid;
410061da546Spatrick   }
411061da546Spatrick   return INVALID_NUB_PROCESS;
412061da546Spatrick }
413061da546Spatrick 
DNBProcessAttachByName(const char * name,struct timespec * timeout,const RNBContext::IgnoredExceptions & ignored_exceptions,char * err_str,size_t err_len)414061da546Spatrick nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout,
415*f6aab3d8Srobert                                      const RNBContext::IgnoredExceptions
416*f6aab3d8Srobert                                              &ignored_exceptions, char *err_str,
417be691f3bSpatrick                                      size_t err_len) {
418061da546Spatrick   if (err_str && err_len > 0)
419061da546Spatrick     err_str[0] = '\0';
420061da546Spatrick   std::vector<struct kinfo_proc> matching_proc_infos;
421061da546Spatrick   size_t num_matching_proc_infos =
422061da546Spatrick       GetAllInfosMatchingName(name, matching_proc_infos);
423061da546Spatrick   if (num_matching_proc_infos == 0) {
424061da546Spatrick     DNBLogError("error: no processes match '%s'\n", name);
425061da546Spatrick     return INVALID_NUB_PROCESS;
426dda28197Spatrick   }
427dda28197Spatrick   if (num_matching_proc_infos > 1) {
428061da546Spatrick     DNBLogError("error: %llu processes match '%s':\n",
429061da546Spatrick                 (uint64_t)num_matching_proc_infos, name);
430061da546Spatrick     size_t i;
431061da546Spatrick     for (i = 0; i < num_matching_proc_infos; ++i)
432061da546Spatrick       DNBLogError("%6u - %s\n", matching_proc_infos[i].kp_proc.p_pid,
433061da546Spatrick                   matching_proc_infos[i].kp_proc.p_comm);
434061da546Spatrick     return INVALID_NUB_PROCESS;
435061da546Spatrick   }
436061da546Spatrick 
437061da546Spatrick   return DNBProcessAttach(matching_proc_infos[0].kp_proc.p_pid, timeout,
438*f6aab3d8Srobert                           ignored_exceptions, err_str, err_len);
439061da546Spatrick }
440061da546Spatrick 
DNBProcessAttach(nub_process_t attach_pid,struct timespec * timeout,const RNBContext::IgnoredExceptions & ignored_exceptions,char * err_str,size_t err_len)441061da546Spatrick nub_process_t DNBProcessAttach(nub_process_t attach_pid,
442*f6aab3d8Srobert                                struct timespec *timeout,
443*f6aab3d8Srobert                                const RNBContext::IgnoredExceptions
444*f6aab3d8Srobert                                        &ignored_exceptions,
445be691f3bSpatrick                                char *err_str, size_t err_len) {
446061da546Spatrick   if (err_str && err_len > 0)
447061da546Spatrick     err_str[0] = '\0';
448061da546Spatrick 
449be691f3bSpatrick   if (getenv("LLDB_DEBUGSERVER_PATH") == NULL) {
450be691f3bSpatrick     int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID,
451be691f3bSpatrick                  static_cast<int>(attach_pid)};
452be691f3bSpatrick     struct kinfo_proc processInfo;
453be691f3bSpatrick     size_t bufsize = sizeof(processInfo);
454be691f3bSpatrick     if (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo,
455be691f3bSpatrick                &bufsize, NULL, 0) == 0 &&
456be691f3bSpatrick         bufsize > 0) {
457be691f3bSpatrick 
458be691f3bSpatrick       if ((processInfo.kp_proc.p_flag & P_TRANSLATED) == P_TRANSLATED) {
459be691f3bSpatrick         const char *translated_debugserver =
460be691f3bSpatrick             "/Library/Apple/usr/libexec/oah/debugserver";
461be691f3bSpatrick         char fdstr[16];
462be691f3bSpatrick         char pidstr[16];
463be691f3bSpatrick         extern int communication_fd;
464be691f3bSpatrick 
465be691f3bSpatrick         if (communication_fd == -1) {
466be691f3bSpatrick           fprintf(stderr, "Trying to attach to a translated process with the "
467be691f3bSpatrick                           "native debugserver, exiting...\n");
468be691f3bSpatrick           exit(1);
469be691f3bSpatrick         }
470be691f3bSpatrick 
471be691f3bSpatrick         snprintf(fdstr, sizeof(fdstr), "--fd=%d", communication_fd);
472be691f3bSpatrick         snprintf(pidstr, sizeof(pidstr), "--attach=%d", attach_pid);
473be691f3bSpatrick         execl(translated_debugserver, translated_debugserver, "--native-regs",
474be691f3bSpatrick               "--setsid", fdstr, "--handoff-attach-from-native", pidstr,
475be691f3bSpatrick               (char *)0);
476be691f3bSpatrick         DNBLogThreadedIf(LOG_PROCESS, "Failed to launch debugserver for "
477be691f3bSpatrick                          "translated process: ", errno, strerror(errno));
478be691f3bSpatrick         __builtin_trap();
479be691f3bSpatrick       }
480be691f3bSpatrick     }
481be691f3bSpatrick   }
482be691f3bSpatrick 
483*f6aab3d8Srobert   if (DNBDebugserverIsTranslated()) {
484*f6aab3d8Srobert     return INVALID_NUB_PROCESS_ARCH;
485*f6aab3d8Srobert   }
486*f6aab3d8Srobert 
487061da546Spatrick   pid_t pid = INVALID_NUB_PROCESS;
488061da546Spatrick   MachProcessSP processSP(new MachProcess);
489061da546Spatrick   if (processSP.get()) {
490061da546Spatrick     DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...",
491061da546Spatrick                      attach_pid);
492be691f3bSpatrick     pid =
493*f6aab3d8Srobert         processSP->AttachForDebug(attach_pid, ignored_exceptions, err_str,
494*f6aab3d8Srobert                                   err_len);
495061da546Spatrick 
496061da546Spatrick     if (pid != INVALID_NUB_PROCESS) {
497061da546Spatrick       bool res = AddProcessToMap(pid, processSP);
498061da546Spatrick       UNUSED_IF_ASSERT_DISABLED(res);
499061da546Spatrick       assert(res && "Couldn't add process to map!");
500061da546Spatrick       spawn_waitpid_thread(pid);
501061da546Spatrick     }
502061da546Spatrick   }
503061da546Spatrick 
504061da546Spatrick   while (pid != INVALID_NUB_PROCESS) {
505061da546Spatrick     // Wait for process to start up and hit entry point
506061da546Spatrick     DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, "
507061da546Spatrick                                   "eEventProcessRunningStateChanged | "
508061da546Spatrick                                   "eEventProcessStoppedStateChanged, true, "
509061da546Spatrick                                   "INFINITE)...",
510061da546Spatrick                      __FUNCTION__, pid);
511061da546Spatrick     nub_event_t set_events =
512061da546Spatrick         DNBProcessWaitForEvents(pid, eEventProcessRunningStateChanged |
513061da546Spatrick                                          eEventProcessStoppedStateChanged,
514061da546Spatrick                                 true, timeout);
515061da546Spatrick 
516061da546Spatrick     DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, "
517061da546Spatrick                                   "eEventProcessRunningStateChanged | "
518061da546Spatrick                                   "eEventProcessStoppedStateChanged, true, "
519061da546Spatrick                                   "INFINITE) => 0x%8.8x",
520061da546Spatrick                      __FUNCTION__, pid, set_events);
521061da546Spatrick 
522061da546Spatrick     if (set_events == 0) {
523061da546Spatrick       if (err_str && err_len > 0)
524061da546Spatrick         snprintf(err_str, err_len, "operation timed out");
525061da546Spatrick       pid = INVALID_NUB_PROCESS;
526061da546Spatrick     } else {
527061da546Spatrick       if (set_events & (eEventProcessRunningStateChanged |
528061da546Spatrick                         eEventProcessStoppedStateChanged)) {
529061da546Spatrick         nub_state_t pid_state = DNBProcessGetState(pid);
530061da546Spatrick         DNBLogThreadedIf(
531061da546Spatrick             LOG_PROCESS,
532061da546Spatrick             "%s process %4.4x state changed (eEventProcessStateChanged): %s",
533061da546Spatrick             __FUNCTION__, pid, DNBStateAsString(pid_state));
534061da546Spatrick 
535061da546Spatrick         switch (pid_state) {
536061da546Spatrick         case eStateInvalid:
537061da546Spatrick         case eStateUnloaded:
538061da546Spatrick         case eStateAttaching:
539061da546Spatrick         case eStateLaunching:
540061da546Spatrick         case eStateSuspended:
541061da546Spatrick           break; // Ignore
542061da546Spatrick 
543061da546Spatrick         case eStateRunning:
544061da546Spatrick         case eStateStepping:
545061da546Spatrick           // Still waiting to stop at entry point...
546061da546Spatrick           break;
547061da546Spatrick 
548061da546Spatrick         case eStateStopped:
549061da546Spatrick         case eStateCrashed:
550061da546Spatrick           return pid;
551061da546Spatrick 
552061da546Spatrick         case eStateDetached:
553061da546Spatrick         case eStateExited:
554061da546Spatrick           if (err_str && err_len > 0)
555061da546Spatrick             snprintf(err_str, err_len, "process exited");
556061da546Spatrick           return INVALID_NUB_PROCESS;
557061da546Spatrick         }
558061da546Spatrick       }
559061da546Spatrick 
560061da546Spatrick       DNBProcessResetEvents(pid, set_events);
561061da546Spatrick     }
562061da546Spatrick   }
563061da546Spatrick 
564061da546Spatrick   return INVALID_NUB_PROCESS;
565061da546Spatrick }
566061da546Spatrick 
DNBGetAllInfos(std::vector<struct kinfo_proc> & proc_infos)567dda28197Spatrick size_t DNBGetAllInfos(std::vector<struct kinfo_proc> &proc_infos) {
568061da546Spatrick   size_t size = 0;
569061da546Spatrick   int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
570061da546Spatrick   u_int namelen = sizeof(name) / sizeof(int);
571061da546Spatrick   int err;
572061da546Spatrick 
573061da546Spatrick   // Try to find out how many processes are around so we can
574061da546Spatrick   // size the buffer appropriately.  sysctl's man page specifically suggests
575061da546Spatrick   // this approach, and says it returns a bit larger size than needed to
576061da546Spatrick   // handle any new processes created between then and now.
577061da546Spatrick 
578061da546Spatrick   err = ::sysctl(name, namelen, NULL, &size, NULL, 0);
579061da546Spatrick 
580061da546Spatrick   if ((err < 0) && (err != ENOMEM)) {
581061da546Spatrick     proc_infos.clear();
582061da546Spatrick     perror("sysctl (mib, miblen, NULL, &num_processes, NULL, 0)");
583061da546Spatrick     return 0;
584061da546Spatrick   }
585061da546Spatrick 
586061da546Spatrick   // Increase the size of the buffer by a few processes in case more have
587061da546Spatrick   // been spawned
588061da546Spatrick   proc_infos.resize(size / sizeof(struct kinfo_proc));
589061da546Spatrick   size = proc_infos.size() *
590061da546Spatrick          sizeof(struct kinfo_proc); // Make sure we don't exceed our resize...
591061da546Spatrick   err = ::sysctl(name, namelen, &proc_infos[0], &size, NULL, 0);
592061da546Spatrick   if (err < 0) {
593061da546Spatrick     proc_infos.clear();
594061da546Spatrick     return 0;
595061da546Spatrick   }
596061da546Spatrick 
597061da546Spatrick   // Trim down our array to fit what we actually got back
598061da546Spatrick   proc_infos.resize(size / sizeof(struct kinfo_proc));
599061da546Spatrick   return proc_infos.size();
600061da546Spatrick }
601061da546Spatrick 
DNBGetDyldProcessState(nub_process_t pid)602*f6aab3d8Srobert JSONGenerator::ObjectSP DNBGetDyldProcessState(nub_process_t pid) {
603*f6aab3d8Srobert   MachProcessSP procSP;
604*f6aab3d8Srobert   if (GetProcessSP(pid, procSP)) {
605*f6aab3d8Srobert     return procSP->GetDyldProcessState();
606*f6aab3d8Srobert   }
607*f6aab3d8Srobert   return {};
608*f6aab3d8Srobert }
609*f6aab3d8Srobert 
610061da546Spatrick static size_t
GetAllInfosMatchingName(const char * full_process_name,std::vector<struct kinfo_proc> & matching_proc_infos)611061da546Spatrick GetAllInfosMatchingName(const char *full_process_name,
612061da546Spatrick                         std::vector<struct kinfo_proc> &matching_proc_infos) {
613061da546Spatrick 
614061da546Spatrick   matching_proc_infos.clear();
615061da546Spatrick   if (full_process_name && full_process_name[0]) {
616061da546Spatrick     // We only get the process name, not the full path, from the proc_info.  So
617061da546Spatrick     // just take the
618061da546Spatrick     // base name of the process name...
619061da546Spatrick     const char *process_name;
620061da546Spatrick     process_name = strrchr(full_process_name, '/');
621061da546Spatrick     if (process_name == NULL)
622061da546Spatrick       process_name = full_process_name;
623061da546Spatrick     else
624061da546Spatrick       process_name++;
625061da546Spatrick 
626061da546Spatrick     const size_t process_name_len = strlen(process_name);
627061da546Spatrick     std::vector<struct kinfo_proc> proc_infos;
628dda28197Spatrick     const size_t num_proc_infos = DNBGetAllInfos(proc_infos);
629061da546Spatrick     if (num_proc_infos > 0) {
630061da546Spatrick       uint32_t i;
631061da546Spatrick       for (i = 0; i < num_proc_infos; i++) {
632061da546Spatrick         // Skip zombie processes and processes with unset status
633061da546Spatrick         if (proc_infos[i].kp_proc.p_stat == 0 ||
634061da546Spatrick             proc_infos[i].kp_proc.p_stat == SZOMB)
635061da546Spatrick           continue;
636061da546Spatrick 
637061da546Spatrick         // Check for process by name. We only check the first MAXCOMLEN
638061da546Spatrick         // chars as that is all that kp_proc.p_comm holds.
639061da546Spatrick 
640061da546Spatrick         if (::strncasecmp(process_name, proc_infos[i].kp_proc.p_comm,
641061da546Spatrick                           MAXCOMLEN) == 0) {
642061da546Spatrick           if (process_name_len > MAXCOMLEN) {
643061da546Spatrick             // We found a matching process name whose first MAXCOMLEN
644061da546Spatrick             // characters match, but there is more to the name than
645061da546Spatrick             // this. We need to get the full process name.  Use proc_pidpath,
646061da546Spatrick             // which will get
647061da546Spatrick             // us the full path to the executed process.
648061da546Spatrick 
649061da546Spatrick             char proc_path_buf[PATH_MAX];
650061da546Spatrick 
651061da546Spatrick             int return_val = proc_pidpath(proc_infos[i].kp_proc.p_pid,
652061da546Spatrick                                           proc_path_buf, PATH_MAX);
653061da546Spatrick             if (return_val > 0) {
654061da546Spatrick               // Okay, now search backwards from that to see if there is a
655061da546Spatrick               // slash in the name.  Note, even though we got all the args we
656061da546Spatrick               // don't care
657061da546Spatrick               // because the list data is just a bunch of concatenated null
658061da546Spatrick               // terminated strings
659061da546Spatrick               // so strrchr will start from the end of argv0.
660061da546Spatrick 
661061da546Spatrick               const char *argv_basename = strrchr(proc_path_buf, '/');
662061da546Spatrick               if (argv_basename) {
663061da546Spatrick                 // Skip the '/'
664061da546Spatrick                 ++argv_basename;
665061da546Spatrick               } else {
666061da546Spatrick                 // We didn't find a directory delimiter in the process argv[0],
667061da546Spatrick                 // just use what was in there
668061da546Spatrick                 argv_basename = proc_path_buf;
669061da546Spatrick               }
670061da546Spatrick 
671061da546Spatrick               if (argv_basename) {
672061da546Spatrick                 if (::strncasecmp(process_name, argv_basename, PATH_MAX) == 0) {
673061da546Spatrick                   matching_proc_infos.push_back(proc_infos[i]);
674061da546Spatrick                 }
675061da546Spatrick               }
676061da546Spatrick             }
677061da546Spatrick           } else {
678061da546Spatrick             // We found a matching process, add it to our list
679061da546Spatrick             matching_proc_infos.push_back(proc_infos[i]);
680061da546Spatrick           }
681061da546Spatrick         }
682061da546Spatrick       }
683061da546Spatrick     }
684061da546Spatrick   }
685061da546Spatrick   // return the newly added matches.
686061da546Spatrick   return matching_proc_infos.size();
687061da546Spatrick }
688061da546Spatrick 
689be691f3bSpatrick nub_process_t
DNBProcessAttachWait(RNBContext * ctx,const char * waitfor_process_name,bool ignore_existing,struct timespec * timeout_abstime,useconds_t waitfor_interval,char * err_str,size_t err_len,DNBShouldCancelCallback should_cancel_callback,void * callback_data)690be691f3bSpatrick DNBProcessAttachWait(RNBContext *ctx, const char *waitfor_process_name,
691061da546Spatrick                      bool ignore_existing, struct timespec *timeout_abstime,
692061da546Spatrick                      useconds_t waitfor_interval, char *err_str, size_t err_len,
693be691f3bSpatrick                      DNBShouldCancelCallback should_cancel_callback,
694be691f3bSpatrick                      void *callback_data) {
695061da546Spatrick   DNBError prepare_error;
696061da546Spatrick   std::vector<struct kinfo_proc> exclude_proc_infos;
697061da546Spatrick   size_t num_exclude_proc_infos;
698061da546Spatrick 
699be691f3bSpatrick   nub_launch_flavor_t launch_flavor = ctx->LaunchFlavor();
700be691f3bSpatrick 
701061da546Spatrick   // If the PrepareForAttach returns a valid token, use  MachProcess to check
702061da546Spatrick   // for the process, otherwise scan the process table.
703061da546Spatrick 
704061da546Spatrick   const void *attach_token = MachProcess::PrepareForAttach(
705061da546Spatrick       waitfor_process_name, launch_flavor, true, prepare_error);
706061da546Spatrick 
707061da546Spatrick   if (prepare_error.Fail()) {
708061da546Spatrick     DNBLogError("Error in PrepareForAttach: %s", prepare_error.AsString());
709061da546Spatrick     return INVALID_NUB_PROCESS;
710061da546Spatrick   }
711061da546Spatrick 
712061da546Spatrick   if (attach_token == NULL) {
713061da546Spatrick     if (ignore_existing)
714061da546Spatrick       num_exclude_proc_infos =
715061da546Spatrick           GetAllInfosMatchingName(waitfor_process_name, exclude_proc_infos);
716061da546Spatrick     else
717061da546Spatrick       num_exclude_proc_infos = 0;
718061da546Spatrick   }
719061da546Spatrick 
720061da546Spatrick   DNBLogThreadedIf(LOG_PROCESS, "Waiting for '%s' to appear...\n",
721061da546Spatrick                    waitfor_process_name);
722061da546Spatrick 
723061da546Spatrick   // Loop and try to find the process by name
724061da546Spatrick   nub_process_t waitfor_pid = INVALID_NUB_PROCESS;
725061da546Spatrick 
726061da546Spatrick   while (waitfor_pid == INVALID_NUB_PROCESS) {
727061da546Spatrick     if (attach_token != NULL) {
728061da546Spatrick       nub_process_t pid;
729061da546Spatrick       pid = MachProcess::CheckForProcess(attach_token, launch_flavor);
730061da546Spatrick       if (pid != INVALID_NUB_PROCESS) {
731061da546Spatrick         waitfor_pid = pid;
732061da546Spatrick         break;
733061da546Spatrick       }
734061da546Spatrick     } else {
735061da546Spatrick 
736061da546Spatrick       // Get the current process list, and check for matches that
737061da546Spatrick       // aren't in our original list. If anyone wants to attach
738061da546Spatrick       // to an existing process by name, they should do it with
739061da546Spatrick       // --attach=PROCNAME. Else we will wait for the first matching
740061da546Spatrick       // process that wasn't in our exclusion list.
741061da546Spatrick       std::vector<struct kinfo_proc> proc_infos;
742061da546Spatrick       const size_t num_proc_infos =
743061da546Spatrick           GetAllInfosMatchingName(waitfor_process_name, proc_infos);
744061da546Spatrick       for (size_t i = 0; i < num_proc_infos; i++) {
745061da546Spatrick         nub_process_t curr_pid = proc_infos[i].kp_proc.p_pid;
746061da546Spatrick         for (size_t j = 0; j < num_exclude_proc_infos; j++) {
747061da546Spatrick           if (curr_pid == exclude_proc_infos[j].kp_proc.p_pid) {
748061da546Spatrick             // This process was in our exclusion list, don't use it.
749061da546Spatrick             curr_pid = INVALID_NUB_PROCESS;
750061da546Spatrick             break;
751061da546Spatrick           }
752061da546Spatrick         }
753061da546Spatrick 
754061da546Spatrick         // If we didn't find CURR_PID in our exclusion list, then use it.
755061da546Spatrick         if (curr_pid != INVALID_NUB_PROCESS) {
756061da546Spatrick           // We found our process!
757061da546Spatrick           waitfor_pid = curr_pid;
758061da546Spatrick           break;
759061da546Spatrick         }
760061da546Spatrick       }
761061da546Spatrick     }
762061da546Spatrick 
763061da546Spatrick     // If we haven't found our process yet, check for a timeout
764061da546Spatrick     // and then sleep for a bit until we poll again.
765061da546Spatrick     if (waitfor_pid == INVALID_NUB_PROCESS) {
766061da546Spatrick       if (timeout_abstime != NULL) {
767061da546Spatrick         // Check to see if we have a waitfor-duration option that
768061da546Spatrick         // has timed out?
769061da546Spatrick         if (DNBTimer::TimeOfDayLaterThan(*timeout_abstime)) {
770061da546Spatrick           if (err_str && err_len > 0)
771061da546Spatrick             snprintf(err_str, err_len, "operation timed out");
772061da546Spatrick           DNBLogError("error: waiting for process '%s' timed out.\n",
773061da546Spatrick                       waitfor_process_name);
774061da546Spatrick           return INVALID_NUB_PROCESS;
775061da546Spatrick         }
776061da546Spatrick       }
777061da546Spatrick 
778061da546Spatrick       // Call the should cancel callback as well...
779061da546Spatrick 
780061da546Spatrick       if (should_cancel_callback != NULL &&
781061da546Spatrick           should_cancel_callback(callback_data)) {
782061da546Spatrick         DNBLogThreadedIf(
783061da546Spatrick             LOG_PROCESS,
784061da546Spatrick             "DNBProcessAttachWait cancelled by should_cancel callback.");
785061da546Spatrick         waitfor_pid = INVALID_NUB_PROCESS;
786061da546Spatrick         break;
787061da546Spatrick       }
788061da546Spatrick 
789061da546Spatrick       ::usleep(waitfor_interval); // Sleep for WAITFOR_INTERVAL, then poll again
790061da546Spatrick     }
791061da546Spatrick   }
792061da546Spatrick 
793061da546Spatrick   if (waitfor_pid != INVALID_NUB_PROCESS) {
794061da546Spatrick     DNBLogThreadedIf(LOG_PROCESS, "Attaching to %s with pid %i...\n",
795061da546Spatrick                      waitfor_process_name, waitfor_pid);
796be691f3bSpatrick     waitfor_pid = DNBProcessAttach(waitfor_pid, timeout_abstime,
797*f6aab3d8Srobert                                    ctx->GetIgnoredExceptions(), err_str,
798*f6aab3d8Srobert                                    err_len);
799061da546Spatrick   }
800061da546Spatrick 
801061da546Spatrick   bool success = waitfor_pid != INVALID_NUB_PROCESS;
802061da546Spatrick   MachProcess::CleanupAfterAttach(attach_token, launch_flavor, success,
803061da546Spatrick                                   prepare_error);
804061da546Spatrick 
805061da546Spatrick   return waitfor_pid;
806061da546Spatrick }
807061da546Spatrick 
DNBProcessDetach(nub_process_t pid)808061da546Spatrick nub_bool_t DNBProcessDetach(nub_process_t pid) {
809061da546Spatrick   MachProcessSP procSP;
810061da546Spatrick   if (GetProcessSP(pid, procSP)) {
811061da546Spatrick     const bool remove = true;
812061da546Spatrick     DNBLogThreaded(
813061da546Spatrick         "Disabling breakpoints and watchpoints, and detaching from %d.", pid);
814061da546Spatrick     procSP->DisableAllBreakpoints(remove);
815061da546Spatrick     procSP->DisableAllWatchpoints(remove);
816061da546Spatrick     return procSP->Detach();
817061da546Spatrick   }
818061da546Spatrick   return false;
819061da546Spatrick }
820061da546Spatrick 
DNBProcessKill(nub_process_t pid)821061da546Spatrick nub_bool_t DNBProcessKill(nub_process_t pid) {
822061da546Spatrick   MachProcessSP procSP;
823061da546Spatrick   if (GetProcessSP(pid, procSP)) {
824061da546Spatrick     return procSP->Kill();
825061da546Spatrick   }
826061da546Spatrick   return false;
827061da546Spatrick }
828061da546Spatrick 
DNBProcessSignal(nub_process_t pid,int signal)829061da546Spatrick nub_bool_t DNBProcessSignal(nub_process_t pid, int signal) {
830061da546Spatrick   MachProcessSP procSP;
831061da546Spatrick   if (GetProcessSP(pid, procSP)) {
832061da546Spatrick     return procSP->Signal(signal);
833061da546Spatrick   }
834061da546Spatrick   return false;
835061da546Spatrick }
836061da546Spatrick 
DNBProcessInterrupt(nub_process_t pid)837061da546Spatrick nub_bool_t DNBProcessInterrupt(nub_process_t pid) {
838061da546Spatrick   MachProcessSP procSP;
839061da546Spatrick   if (GetProcessSP(pid, procSP))
840061da546Spatrick     return procSP->Interrupt();
841061da546Spatrick   return false;
842061da546Spatrick }
843061da546Spatrick 
DNBProcessSendEvent(nub_process_t pid,const char * event)844061da546Spatrick nub_bool_t DNBProcessSendEvent(nub_process_t pid, const char *event) {
845061da546Spatrick   MachProcessSP procSP;
846061da546Spatrick   if (GetProcessSP(pid, procSP)) {
847061da546Spatrick     // FIXME: Do something with the error...
848061da546Spatrick     DNBError send_error;
849061da546Spatrick     return procSP->SendEvent(event, send_error);
850061da546Spatrick   }
851061da546Spatrick   return false;
852061da546Spatrick }
853061da546Spatrick 
DNBProcessIsAlive(nub_process_t pid)854061da546Spatrick nub_bool_t DNBProcessIsAlive(nub_process_t pid) {
855061da546Spatrick   MachProcessSP procSP;
856061da546Spatrick   if (GetProcessSP(pid, procSP)) {
857061da546Spatrick     return MachTask::IsValid(procSP->Task().TaskPort());
858061da546Spatrick   }
859061da546Spatrick   return eStateInvalid;
860061da546Spatrick }
861061da546Spatrick 
862061da546Spatrick // Process and Thread state information
DNBProcessGetState(nub_process_t pid)863061da546Spatrick nub_state_t DNBProcessGetState(nub_process_t pid) {
864061da546Spatrick   MachProcessSP procSP;
865061da546Spatrick   if (GetProcessSP(pid, procSP)) {
866061da546Spatrick     return procSP->GetState();
867061da546Spatrick   }
868061da546Spatrick   return eStateInvalid;
869061da546Spatrick }
870061da546Spatrick 
871061da546Spatrick // Process and Thread state information
DNBProcessGetExitStatus(nub_process_t pid,int * status)872061da546Spatrick nub_bool_t DNBProcessGetExitStatus(nub_process_t pid, int *status) {
873061da546Spatrick   MachProcessSP procSP;
874061da546Spatrick   if (GetProcessSP(pid, procSP)) {
875061da546Spatrick     return procSP->GetExitStatus(status);
876061da546Spatrick   }
877061da546Spatrick   return false;
878061da546Spatrick }
879061da546Spatrick 
DNBProcessSetExitStatus(nub_process_t pid,int status)880061da546Spatrick nub_bool_t DNBProcessSetExitStatus(nub_process_t pid, int status) {
881061da546Spatrick   MachProcessSP procSP;
882061da546Spatrick   if (GetProcessSP(pid, procSP)) {
883061da546Spatrick     procSP->SetExitStatus(status);
884061da546Spatrick     return true;
885061da546Spatrick   }
886061da546Spatrick   return false;
887061da546Spatrick }
888061da546Spatrick 
DNBProcessGetExitInfo(nub_process_t pid)889061da546Spatrick const char *DNBProcessGetExitInfo(nub_process_t pid) {
890061da546Spatrick   MachProcessSP procSP;
891061da546Spatrick   if (GetProcessSP(pid, procSP)) {
892061da546Spatrick     return procSP->GetExitInfo();
893061da546Spatrick   }
894061da546Spatrick   return NULL;
895061da546Spatrick }
896061da546Spatrick 
DNBProcessSetExitInfo(nub_process_t pid,const char * info)897061da546Spatrick nub_bool_t DNBProcessSetExitInfo(nub_process_t pid, const char *info) {
898061da546Spatrick   MachProcessSP procSP;
899061da546Spatrick   if (GetProcessSP(pid, procSP)) {
900061da546Spatrick     procSP->SetExitInfo(info);
901061da546Spatrick     return true;
902061da546Spatrick   }
903061da546Spatrick   return false;
904061da546Spatrick }
905061da546Spatrick 
DNBThreadGetName(nub_process_t pid,nub_thread_t tid)906061da546Spatrick const char *DNBThreadGetName(nub_process_t pid, nub_thread_t tid) {
907061da546Spatrick   MachProcessSP procSP;
908061da546Spatrick   if (GetProcessSP(pid, procSP))
909061da546Spatrick     return procSP->ThreadGetName(tid);
910061da546Spatrick   return NULL;
911061da546Spatrick }
912061da546Spatrick 
913061da546Spatrick nub_bool_t
DNBThreadGetIdentifierInfo(nub_process_t pid,nub_thread_t tid,thread_identifier_info_data_t * ident_info)914061da546Spatrick DNBThreadGetIdentifierInfo(nub_process_t pid, nub_thread_t tid,
915061da546Spatrick                            thread_identifier_info_data_t *ident_info) {
916061da546Spatrick   MachProcessSP procSP;
917061da546Spatrick   if (GetProcessSP(pid, procSP))
918061da546Spatrick     return procSP->GetThreadList().GetIdentifierInfo(tid, ident_info);
919061da546Spatrick   return false;
920061da546Spatrick }
921061da546Spatrick 
DNBThreadGetState(nub_process_t pid,nub_thread_t tid)922061da546Spatrick nub_state_t DNBThreadGetState(nub_process_t pid, nub_thread_t tid) {
923061da546Spatrick   MachProcessSP procSP;
924061da546Spatrick   if (GetProcessSP(pid, procSP)) {
925061da546Spatrick     return procSP->ThreadGetState(tid);
926061da546Spatrick   }
927061da546Spatrick   return eStateInvalid;
928061da546Spatrick }
929061da546Spatrick 
DNBStateAsString(nub_state_t state)930061da546Spatrick const char *DNBStateAsString(nub_state_t state) {
931061da546Spatrick   switch (state) {
932061da546Spatrick   case eStateInvalid:
933061da546Spatrick     return "Invalid";
934061da546Spatrick   case eStateUnloaded:
935061da546Spatrick     return "Unloaded";
936061da546Spatrick   case eStateAttaching:
937061da546Spatrick     return "Attaching";
938061da546Spatrick   case eStateLaunching:
939061da546Spatrick     return "Launching";
940061da546Spatrick   case eStateStopped:
941061da546Spatrick     return "Stopped";
942061da546Spatrick   case eStateRunning:
943061da546Spatrick     return "Running";
944061da546Spatrick   case eStateStepping:
945061da546Spatrick     return "Stepping";
946061da546Spatrick   case eStateCrashed:
947061da546Spatrick     return "Crashed";
948061da546Spatrick   case eStateDetached:
949061da546Spatrick     return "Detached";
950061da546Spatrick   case eStateExited:
951061da546Spatrick     return "Exited";
952061da546Spatrick   case eStateSuspended:
953061da546Spatrick     return "Suspended";
954061da546Spatrick   }
955061da546Spatrick   return "nub_state_t ???";
956061da546Spatrick }
957061da546Spatrick 
DNBGetGenealogyInfoForThread(nub_process_t pid,nub_thread_t tid,bool & timed_out)958061da546Spatrick Genealogy::ThreadActivitySP DNBGetGenealogyInfoForThread(nub_process_t pid,
959061da546Spatrick                                                          nub_thread_t tid,
960061da546Spatrick                                                          bool &timed_out) {
961061da546Spatrick   Genealogy::ThreadActivitySP thread_activity_sp;
962061da546Spatrick   MachProcessSP procSP;
963061da546Spatrick   if (GetProcessSP(pid, procSP))
964061da546Spatrick     thread_activity_sp = procSP->GetGenealogyInfoForThread(tid, timed_out);
965061da546Spatrick   return thread_activity_sp;
966061da546Spatrick }
967061da546Spatrick 
DNBGetGenealogyImageInfo(nub_process_t pid,size_t idx)968061da546Spatrick Genealogy::ProcessExecutableInfoSP DNBGetGenealogyImageInfo(nub_process_t pid,
969061da546Spatrick                                                             size_t idx) {
970061da546Spatrick   Genealogy::ProcessExecutableInfoSP image_info_sp;
971061da546Spatrick   MachProcessSP procSP;
972061da546Spatrick   if (GetProcessSP(pid, procSP)) {
973061da546Spatrick     image_info_sp = procSP->GetGenealogyImageInfo(idx);
974061da546Spatrick   }
975061da546Spatrick   return image_info_sp;
976061da546Spatrick }
977061da546Spatrick 
DNBGetRequestedQoSForThread(nub_process_t pid,nub_thread_t tid,nub_addr_t tsd,uint64_t dti_qos_class_index)978061da546Spatrick ThreadInfo::QoS DNBGetRequestedQoSForThread(nub_process_t pid, nub_thread_t tid,
979061da546Spatrick                                             nub_addr_t tsd,
980061da546Spatrick                                             uint64_t dti_qos_class_index) {
981061da546Spatrick   MachProcessSP procSP;
982061da546Spatrick   if (GetProcessSP(pid, procSP)) {
983061da546Spatrick     return procSP->GetRequestedQoS(tid, tsd, dti_qos_class_index);
984061da546Spatrick   }
985061da546Spatrick   return ThreadInfo::QoS();
986061da546Spatrick }
987061da546Spatrick 
DNBGetPThreadT(nub_process_t pid,nub_thread_t tid)988061da546Spatrick nub_addr_t DNBGetPThreadT(nub_process_t pid, nub_thread_t tid) {
989061da546Spatrick   MachProcessSP procSP;
990061da546Spatrick   if (GetProcessSP(pid, procSP)) {
991061da546Spatrick     return procSP->GetPThreadT(tid);
992061da546Spatrick   }
993061da546Spatrick   return INVALID_NUB_ADDRESS;
994061da546Spatrick }
995061da546Spatrick 
DNBGetDispatchQueueT(nub_process_t pid,nub_thread_t tid)996061da546Spatrick nub_addr_t DNBGetDispatchQueueT(nub_process_t pid, nub_thread_t tid) {
997061da546Spatrick   MachProcessSP procSP;
998061da546Spatrick   if (GetProcessSP(pid, procSP)) {
999061da546Spatrick     return procSP->GetDispatchQueueT(tid);
1000061da546Spatrick   }
1001061da546Spatrick   return INVALID_NUB_ADDRESS;
1002061da546Spatrick }
1003061da546Spatrick 
1004061da546Spatrick nub_addr_t
DNBGetTSDAddressForThread(nub_process_t pid,nub_thread_t tid,uint64_t plo_pthread_tsd_base_address_offset,uint64_t plo_pthread_tsd_base_offset,uint64_t plo_pthread_tsd_entry_size)1005061da546Spatrick DNBGetTSDAddressForThread(nub_process_t pid, nub_thread_t tid,
1006061da546Spatrick                           uint64_t plo_pthread_tsd_base_address_offset,
1007061da546Spatrick                           uint64_t plo_pthread_tsd_base_offset,
1008061da546Spatrick                           uint64_t plo_pthread_tsd_entry_size) {
1009061da546Spatrick   MachProcessSP procSP;
1010061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1011061da546Spatrick     return procSP->GetTSDAddressForThread(
1012061da546Spatrick         tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset,
1013061da546Spatrick         plo_pthread_tsd_entry_size);
1014061da546Spatrick   }
1015061da546Spatrick   return INVALID_NUB_ADDRESS;
1016061da546Spatrick }
1017061da546Spatrick 
DNBGetLoadedDynamicLibrariesInfos(nub_process_t pid,nub_addr_t image_list_address,nub_addr_t image_count)1018061da546Spatrick JSONGenerator::ObjectSP DNBGetLoadedDynamicLibrariesInfos(
1019061da546Spatrick     nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count) {
1020061da546Spatrick   MachProcessSP procSP;
1021061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1022061da546Spatrick     return procSP->GetLoadedDynamicLibrariesInfos(pid, image_list_address,
1023061da546Spatrick                                                   image_count);
1024061da546Spatrick   }
1025061da546Spatrick   return JSONGenerator::ObjectSP();
1026061da546Spatrick }
1027061da546Spatrick 
DNBGetAllLoadedLibrariesInfos(nub_process_t pid)1028061da546Spatrick JSONGenerator::ObjectSP DNBGetAllLoadedLibrariesInfos(nub_process_t pid) {
1029061da546Spatrick   MachProcessSP procSP;
1030061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1031061da546Spatrick     return procSP->GetAllLoadedLibrariesInfos(pid);
1032061da546Spatrick   }
1033061da546Spatrick   return JSONGenerator::ObjectSP();
1034061da546Spatrick }
1035061da546Spatrick 
1036061da546Spatrick JSONGenerator::ObjectSP
DNBGetLibrariesInfoForAddresses(nub_process_t pid,std::vector<uint64_t> & macho_addresses)1037061da546Spatrick DNBGetLibrariesInfoForAddresses(nub_process_t pid,
1038061da546Spatrick                                 std::vector<uint64_t> &macho_addresses) {
1039061da546Spatrick   MachProcessSP procSP;
1040061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1041061da546Spatrick     return procSP->GetLibrariesInfoForAddresses(pid, macho_addresses);
1042061da546Spatrick   }
1043061da546Spatrick   return JSONGenerator::ObjectSP();
1044061da546Spatrick }
1045061da546Spatrick 
DNBGetSharedCacheInfo(nub_process_t pid)1046061da546Spatrick JSONGenerator::ObjectSP DNBGetSharedCacheInfo(nub_process_t pid) {
1047061da546Spatrick   MachProcessSP procSP;
1048061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1049061da546Spatrick     return procSP->GetSharedCacheInfo(pid);
1050061da546Spatrick   }
1051061da546Spatrick   return JSONGenerator::ObjectSP();
1052061da546Spatrick }
1053061da546Spatrick 
DNBProcessGetExecutablePath(nub_process_t pid)1054061da546Spatrick const char *DNBProcessGetExecutablePath(nub_process_t pid) {
1055061da546Spatrick   MachProcessSP procSP;
1056061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1057061da546Spatrick     return procSP->Path();
1058061da546Spatrick   }
1059061da546Spatrick   return NULL;
1060061da546Spatrick }
1061061da546Spatrick 
DNBProcessGetArgumentCount(nub_process_t pid)1062061da546Spatrick nub_size_t DNBProcessGetArgumentCount(nub_process_t pid) {
1063061da546Spatrick   MachProcessSP procSP;
1064061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1065061da546Spatrick     return procSP->ArgumentCount();
1066061da546Spatrick   }
1067061da546Spatrick   return 0;
1068061da546Spatrick }
1069061da546Spatrick 
DNBProcessGetArgumentAtIndex(nub_process_t pid,nub_size_t idx)1070061da546Spatrick const char *DNBProcessGetArgumentAtIndex(nub_process_t pid, nub_size_t idx) {
1071061da546Spatrick   MachProcessSP procSP;
1072061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1073061da546Spatrick     return procSP->ArgumentAtIndex(idx);
1074061da546Spatrick   }
1075061da546Spatrick   return NULL;
1076061da546Spatrick }
1077061da546Spatrick 
1078061da546Spatrick // Execution control
DNBProcessResume(nub_process_t pid,const DNBThreadResumeAction * actions,size_t num_actions)1079061da546Spatrick nub_bool_t DNBProcessResume(nub_process_t pid,
1080061da546Spatrick                             const DNBThreadResumeAction *actions,
1081061da546Spatrick                             size_t num_actions) {
1082061da546Spatrick   DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
1083061da546Spatrick   MachProcessSP procSP;
1084061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1085061da546Spatrick     DNBThreadResumeActions thread_actions(actions, num_actions);
1086061da546Spatrick 
1087061da546Spatrick     // Below we add a default thread plan just in case one wasn't
1088061da546Spatrick     // provided so all threads always know what they were supposed to do
1089061da546Spatrick     if (thread_actions.IsEmpty()) {
1090061da546Spatrick       // No thread plans were given, so the default it to run all threads
1091061da546Spatrick       thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, 0);
1092061da546Spatrick     } else {
1093061da546Spatrick       // Some thread plans were given which means anything that wasn't
1094061da546Spatrick       // specified should remain stopped.
1095061da546Spatrick       thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);
1096061da546Spatrick     }
1097061da546Spatrick     return procSP->Resume(thread_actions);
1098061da546Spatrick   }
1099061da546Spatrick   return false;
1100061da546Spatrick }
1101061da546Spatrick 
DNBProcessHalt(nub_process_t pid)1102061da546Spatrick nub_bool_t DNBProcessHalt(nub_process_t pid) {
1103061da546Spatrick   DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
1104061da546Spatrick   MachProcessSP procSP;
1105061da546Spatrick   if (GetProcessSP(pid, procSP))
1106061da546Spatrick     return procSP->Signal(SIGSTOP);
1107061da546Spatrick   return false;
1108061da546Spatrick }
1109061da546Spatrick //
1110061da546Spatrick // nub_bool_t
1111061da546Spatrick // DNBThreadResume (nub_process_t pid, nub_thread_t tid, nub_bool_t step)
1112061da546Spatrick //{
1113061da546Spatrick //    DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u)",
1114061da546Spatrick //    __FUNCTION__, pid, tid, (uint32_t)step);
1115061da546Spatrick //    MachProcessSP procSP;
1116061da546Spatrick //    if (GetProcessSP (pid, procSP))
1117061da546Spatrick //    {
1118061da546Spatrick //        return procSP->Resume(tid, step, 0);
1119061da546Spatrick //    }
1120061da546Spatrick //    return false;
1121061da546Spatrick //}
1122061da546Spatrick //
1123061da546Spatrick // nub_bool_t
1124061da546Spatrick // DNBThreadResumeWithSignal (nub_process_t pid, nub_thread_t tid, nub_bool_t
1125061da546Spatrick // step, int signal)
1126061da546Spatrick //{
1127061da546Spatrick //    DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u,
1128061da546Spatrick //    signal = %i)", __FUNCTION__, pid, tid, (uint32_t)step, signal);
1129061da546Spatrick //    MachProcessSP procSP;
1130061da546Spatrick //    if (GetProcessSP (pid, procSP))
1131061da546Spatrick //    {
1132061da546Spatrick //        return procSP->Resume(tid, step, signal);
1133061da546Spatrick //    }
1134061da546Spatrick //    return false;
1135061da546Spatrick //}
1136061da546Spatrick 
DNBProcessWaitForEvents(nub_process_t pid,nub_event_t event_mask,bool wait_for_set,struct timespec * timeout)1137061da546Spatrick nub_event_t DNBProcessWaitForEvents(nub_process_t pid, nub_event_t event_mask,
1138061da546Spatrick                                     bool wait_for_set,
1139061da546Spatrick                                     struct timespec *timeout) {
1140061da546Spatrick   nub_event_t result = 0;
1141061da546Spatrick   MachProcessSP procSP;
1142061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1143061da546Spatrick     if (wait_for_set)
1144061da546Spatrick       result = procSP->Events().WaitForSetEvents(event_mask, timeout);
1145061da546Spatrick     else
1146061da546Spatrick       result = procSP->Events().WaitForEventsToReset(event_mask, timeout);
1147061da546Spatrick   }
1148061da546Spatrick   return result;
1149061da546Spatrick }
1150061da546Spatrick 
DNBProcessResetEvents(nub_process_t pid,nub_event_t event_mask)1151061da546Spatrick void DNBProcessResetEvents(nub_process_t pid, nub_event_t event_mask) {
1152061da546Spatrick   MachProcessSP procSP;
1153061da546Spatrick   if (GetProcessSP(pid, procSP))
1154061da546Spatrick     procSP->Events().ResetEvents(event_mask);
1155061da546Spatrick }
1156061da546Spatrick 
1157061da546Spatrick // Breakpoints
DNBBreakpointSet(nub_process_t pid,nub_addr_t addr,nub_size_t size,nub_bool_t hardware)1158061da546Spatrick nub_bool_t DNBBreakpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size,
1159061da546Spatrick                             nub_bool_t hardware) {
1160061da546Spatrick   MachProcessSP procSP;
1161061da546Spatrick   if (GetProcessSP(pid, procSP))
1162061da546Spatrick     return procSP->CreateBreakpoint(addr, size, hardware) != NULL;
1163061da546Spatrick   return false;
1164061da546Spatrick }
1165061da546Spatrick 
DNBBreakpointClear(nub_process_t pid,nub_addr_t addr)1166061da546Spatrick nub_bool_t DNBBreakpointClear(nub_process_t pid, nub_addr_t addr) {
1167061da546Spatrick   MachProcessSP procSP;
1168061da546Spatrick   if (GetProcessSP(pid, procSP))
1169061da546Spatrick     return procSP->DisableBreakpoint(addr, true);
1170061da546Spatrick   return false; // Failed
1171061da546Spatrick }
1172061da546Spatrick 
1173061da546Spatrick // Watchpoints
DNBWatchpointSet(nub_process_t pid,nub_addr_t addr,nub_size_t size,uint32_t watch_flags,nub_bool_t hardware)1174061da546Spatrick nub_bool_t DNBWatchpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size,
1175061da546Spatrick                             uint32_t watch_flags, nub_bool_t hardware) {
1176061da546Spatrick   MachProcessSP procSP;
1177061da546Spatrick   if (GetProcessSP(pid, procSP))
1178061da546Spatrick     return procSP->CreateWatchpoint(addr, size, watch_flags, hardware) != NULL;
1179061da546Spatrick   return false;
1180061da546Spatrick }
1181061da546Spatrick 
DNBWatchpointClear(nub_process_t pid,nub_addr_t addr)1182061da546Spatrick nub_bool_t DNBWatchpointClear(nub_process_t pid, nub_addr_t addr) {
1183061da546Spatrick   MachProcessSP procSP;
1184061da546Spatrick   if (GetProcessSP(pid, procSP))
1185061da546Spatrick     return procSP->DisableWatchpoint(addr, true);
1186061da546Spatrick   return false; // Failed
1187061da546Spatrick }
1188061da546Spatrick 
1189061da546Spatrick // Return the number of supported hardware watchpoints.
DNBWatchpointGetNumSupportedHWP(nub_process_t pid)1190061da546Spatrick uint32_t DNBWatchpointGetNumSupportedHWP(nub_process_t pid) {
1191061da546Spatrick   MachProcessSP procSP;
1192061da546Spatrick   if (GetProcessSP(pid, procSP))
1193061da546Spatrick     return procSP->GetNumSupportedHardwareWatchpoints();
1194061da546Spatrick   return 0;
1195061da546Spatrick }
1196061da546Spatrick 
1197061da546Spatrick // Read memory in the address space of process PID. This call will take
1198061da546Spatrick // care of setting and restoring permissions and breaking up the memory
1199061da546Spatrick // read into multiple chunks as required.
1200061da546Spatrick //
1201061da546Spatrick // RETURNS: number of bytes actually read
DNBProcessMemoryRead(nub_process_t pid,nub_addr_t addr,nub_size_t size,void * buf)1202061da546Spatrick nub_size_t DNBProcessMemoryRead(nub_process_t pid, nub_addr_t addr,
1203061da546Spatrick                                 nub_size_t size, void *buf) {
1204061da546Spatrick   MachProcessSP procSP;
1205061da546Spatrick   if (GetProcessSP(pid, procSP))
1206061da546Spatrick     return procSP->ReadMemory(addr, size, buf);
1207061da546Spatrick   return 0;
1208061da546Spatrick }
1209061da546Spatrick 
DNBProcessMemoryReadInteger(nub_process_t pid,nub_addr_t addr,nub_size_t integer_size,uint64_t fail_value)1210061da546Spatrick uint64_t DNBProcessMemoryReadInteger(nub_process_t pid, nub_addr_t addr,
1211061da546Spatrick                                      nub_size_t integer_size,
1212061da546Spatrick                                      uint64_t fail_value) {
1213061da546Spatrick   union Integers {
1214061da546Spatrick     uint8_t u8;
1215061da546Spatrick     uint16_t u16;
1216061da546Spatrick     uint32_t u32;
1217061da546Spatrick     uint64_t u64;
1218061da546Spatrick   };
1219061da546Spatrick 
1220061da546Spatrick   if (integer_size <= sizeof(uint64_t)) {
1221061da546Spatrick     Integers ints;
1222061da546Spatrick     if (DNBProcessMemoryRead(pid, addr, integer_size, &ints) == integer_size) {
1223061da546Spatrick       switch (integer_size) {
1224061da546Spatrick       case 1:
1225061da546Spatrick         return ints.u8;
1226061da546Spatrick       case 2:
1227061da546Spatrick         return ints.u16;
1228061da546Spatrick       case 3:
1229061da546Spatrick         return ints.u32 & 0xffffffu;
1230061da546Spatrick       case 4:
1231061da546Spatrick         return ints.u32;
1232061da546Spatrick       case 5:
1233061da546Spatrick         return ints.u32 & 0x000000ffffffffffull;
1234061da546Spatrick       case 6:
1235061da546Spatrick         return ints.u32 & 0x0000ffffffffffffull;
1236061da546Spatrick       case 7:
1237061da546Spatrick         return ints.u32 & 0x00ffffffffffffffull;
1238061da546Spatrick       case 8:
1239061da546Spatrick         return ints.u64;
1240061da546Spatrick       }
1241061da546Spatrick     }
1242061da546Spatrick   }
1243061da546Spatrick   return fail_value;
1244061da546Spatrick }
1245061da546Spatrick 
DNBProcessMemoryReadPointer(nub_process_t pid,nub_addr_t addr)1246061da546Spatrick nub_addr_t DNBProcessMemoryReadPointer(nub_process_t pid, nub_addr_t addr) {
1247061da546Spatrick   cpu_type_t cputype = DNBProcessGetCPUType(pid);
1248061da546Spatrick   if (cputype) {
1249061da546Spatrick     const nub_size_t pointer_size = (cputype & CPU_ARCH_ABI64) ? 8 : 4;
1250061da546Spatrick     return DNBProcessMemoryReadInteger(pid, addr, pointer_size, 0);
1251061da546Spatrick   }
1252061da546Spatrick   return 0;
1253061da546Spatrick }
1254061da546Spatrick 
DNBProcessMemoryReadCString(nub_process_t pid,nub_addr_t addr)1255061da546Spatrick std::string DNBProcessMemoryReadCString(nub_process_t pid, nub_addr_t addr) {
1256061da546Spatrick   std::string cstr;
1257061da546Spatrick   char buffer[256];
1258061da546Spatrick   const nub_size_t max_buffer_cstr_length = sizeof(buffer) - 1;
1259061da546Spatrick   buffer[max_buffer_cstr_length] = '\0';
1260061da546Spatrick   nub_size_t length = 0;
1261061da546Spatrick   nub_addr_t curr_addr = addr;
1262061da546Spatrick   do {
1263061da546Spatrick     nub_size_t bytes_read =
1264061da546Spatrick         DNBProcessMemoryRead(pid, curr_addr, max_buffer_cstr_length, buffer);
1265061da546Spatrick     if (bytes_read == 0)
1266061da546Spatrick       break;
1267061da546Spatrick     length = strlen(buffer);
1268061da546Spatrick     cstr.append(buffer, length);
1269061da546Spatrick     curr_addr += length;
1270061da546Spatrick   } while (length == max_buffer_cstr_length);
1271061da546Spatrick   return cstr;
1272061da546Spatrick }
1273061da546Spatrick 
DNBProcessMemoryReadCStringFixed(nub_process_t pid,nub_addr_t addr,nub_size_t fixed_length)1274061da546Spatrick std::string DNBProcessMemoryReadCStringFixed(nub_process_t pid, nub_addr_t addr,
1275061da546Spatrick                                              nub_size_t fixed_length) {
1276061da546Spatrick   std::string cstr;
1277061da546Spatrick   char buffer[fixed_length + 1];
1278061da546Spatrick   buffer[fixed_length] = '\0';
1279061da546Spatrick   nub_size_t bytes_read = DNBProcessMemoryRead(pid, addr, fixed_length, buffer);
1280061da546Spatrick   if (bytes_read > 0)
1281061da546Spatrick     cstr.assign(buffer);
1282061da546Spatrick   return cstr;
1283061da546Spatrick }
1284061da546Spatrick 
1285061da546Spatrick // Write memory to the address space of process PID. This call will take
1286061da546Spatrick // care of setting and restoring permissions and breaking up the memory
1287061da546Spatrick // write into multiple chunks as required.
1288061da546Spatrick //
1289061da546Spatrick // RETURNS: number of bytes actually written
DNBProcessMemoryWrite(nub_process_t pid,nub_addr_t addr,nub_size_t size,const void * buf)1290061da546Spatrick nub_size_t DNBProcessMemoryWrite(nub_process_t pid, nub_addr_t addr,
1291061da546Spatrick                                  nub_size_t size, const void *buf) {
1292061da546Spatrick   MachProcessSP procSP;
1293061da546Spatrick   if (GetProcessSP(pid, procSP))
1294061da546Spatrick     return procSP->WriteMemory(addr, size, buf);
1295061da546Spatrick   return 0;
1296061da546Spatrick }
1297061da546Spatrick 
DNBProcessMemoryAllocate(nub_process_t pid,nub_size_t size,uint32_t permissions)1298061da546Spatrick nub_addr_t DNBProcessMemoryAllocate(nub_process_t pid, nub_size_t size,
1299061da546Spatrick                                     uint32_t permissions) {
1300061da546Spatrick   MachProcessSP procSP;
1301061da546Spatrick   if (GetProcessSP(pid, procSP))
1302061da546Spatrick     return procSP->Task().AllocateMemory(size, permissions);
1303061da546Spatrick   return 0;
1304061da546Spatrick }
1305061da546Spatrick 
DNBProcessMemoryDeallocate(nub_process_t pid,nub_addr_t addr)1306061da546Spatrick nub_bool_t DNBProcessMemoryDeallocate(nub_process_t pid, nub_addr_t addr) {
1307061da546Spatrick   MachProcessSP procSP;
1308061da546Spatrick   if (GetProcessSP(pid, procSP))
1309061da546Spatrick     return procSP->Task().DeallocateMemory(addr);
1310061da546Spatrick   return 0;
1311061da546Spatrick }
1312061da546Spatrick 
1313061da546Spatrick // Find attributes of the memory region that contains ADDR for process PID,
1314061da546Spatrick // if possible, and return a string describing those attributes.
1315061da546Spatrick //
1316061da546Spatrick // Returns 1 if we could find attributes for this region and OUTBUF can
1317061da546Spatrick // be sent to the remote debugger.
1318061da546Spatrick //
1319061da546Spatrick // Returns 0 if we couldn't find the attributes for a region of memory at
1320061da546Spatrick // that address and OUTBUF should not be sent.
1321061da546Spatrick //
1322061da546Spatrick // Returns -1 if this platform cannot look up information about memory regions
1323061da546Spatrick // or if we do not yet have a valid launched process.
1324061da546Spatrick //
DNBProcessMemoryRegionInfo(nub_process_t pid,nub_addr_t addr,DNBRegionInfo * region_info)1325061da546Spatrick int DNBProcessMemoryRegionInfo(nub_process_t pid, nub_addr_t addr,
1326061da546Spatrick                                DNBRegionInfo *region_info) {
1327061da546Spatrick   MachProcessSP procSP;
1328061da546Spatrick   if (GetProcessSP(pid, procSP))
1329061da546Spatrick     return procSP->Task().GetMemoryRegionInfo(addr, region_info);
1330061da546Spatrick 
1331061da546Spatrick   return -1;
1332061da546Spatrick }
1333061da546Spatrick 
DNBProcessGetProfileData(nub_process_t pid,DNBProfileDataScanType scanType)1334061da546Spatrick std::string DNBProcessGetProfileData(nub_process_t pid,
1335061da546Spatrick                                      DNBProfileDataScanType scanType) {
1336061da546Spatrick   MachProcessSP procSP;
1337061da546Spatrick   if (GetProcessSP(pid, procSP))
1338061da546Spatrick     return procSP->Task().GetProfileData(scanType);
1339061da546Spatrick 
1340061da546Spatrick   return std::string("");
1341061da546Spatrick }
1342061da546Spatrick 
DNBProcessSetEnableAsyncProfiling(nub_process_t pid,nub_bool_t enable,uint64_t interval_usec,DNBProfileDataScanType scan_type)1343061da546Spatrick nub_bool_t DNBProcessSetEnableAsyncProfiling(nub_process_t pid,
1344061da546Spatrick                                              nub_bool_t enable,
1345061da546Spatrick                                              uint64_t interval_usec,
1346061da546Spatrick                                              DNBProfileDataScanType scan_type) {
1347061da546Spatrick   MachProcessSP procSP;
1348061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1349061da546Spatrick     procSP->SetEnableAsyncProfiling(enable, interval_usec, scan_type);
1350061da546Spatrick     return true;
1351061da546Spatrick   }
1352061da546Spatrick 
1353061da546Spatrick   return false;
1354061da546Spatrick }
1355061da546Spatrick 
1356061da546Spatrick // Get the number of threads for the specified process.
DNBProcessGetNumThreads(nub_process_t pid)1357061da546Spatrick nub_size_t DNBProcessGetNumThreads(nub_process_t pid) {
1358061da546Spatrick   MachProcessSP procSP;
1359061da546Spatrick   if (GetProcessSP(pid, procSP))
1360061da546Spatrick     return procSP->GetNumThreads();
1361061da546Spatrick   return 0;
1362061da546Spatrick }
1363061da546Spatrick 
1364061da546Spatrick // Get the thread ID of the current thread.
DNBProcessGetCurrentThread(nub_process_t pid)1365061da546Spatrick nub_thread_t DNBProcessGetCurrentThread(nub_process_t pid) {
1366061da546Spatrick   MachProcessSP procSP;
1367061da546Spatrick   if (GetProcessSP(pid, procSP))
1368061da546Spatrick     return procSP->GetCurrentThread();
1369061da546Spatrick   return 0;
1370061da546Spatrick }
1371061da546Spatrick 
1372061da546Spatrick // Get the mach port number of the current thread.
DNBProcessGetCurrentThreadMachPort(nub_process_t pid)1373061da546Spatrick nub_thread_t DNBProcessGetCurrentThreadMachPort(nub_process_t pid) {
1374061da546Spatrick   MachProcessSP procSP;
1375061da546Spatrick   if (GetProcessSP(pid, procSP))
1376061da546Spatrick     return procSP->GetCurrentThreadMachPort();
1377061da546Spatrick   return 0;
1378061da546Spatrick }
1379061da546Spatrick 
1380061da546Spatrick // Change the current thread.
DNBProcessSetCurrentThread(nub_process_t pid,nub_thread_t tid)1381061da546Spatrick nub_thread_t DNBProcessSetCurrentThread(nub_process_t pid, nub_thread_t tid) {
1382061da546Spatrick   MachProcessSP procSP;
1383061da546Spatrick   if (GetProcessSP(pid, procSP))
1384061da546Spatrick     return procSP->SetCurrentThread(tid);
1385061da546Spatrick   return INVALID_NUB_THREAD;
1386061da546Spatrick }
1387061da546Spatrick 
1388061da546Spatrick // Dump a string describing a thread's stop reason to the specified file
1389061da546Spatrick // handle
DNBThreadGetStopReason(nub_process_t pid,nub_thread_t tid,struct DNBThreadStopInfo * stop_info)1390061da546Spatrick nub_bool_t DNBThreadGetStopReason(nub_process_t pid, nub_thread_t tid,
1391061da546Spatrick                                   struct DNBThreadStopInfo *stop_info) {
1392061da546Spatrick   MachProcessSP procSP;
1393061da546Spatrick   if (GetProcessSP(pid, procSP))
1394061da546Spatrick     return procSP->GetThreadStoppedReason(tid, stop_info);
1395061da546Spatrick   return false;
1396061da546Spatrick }
1397061da546Spatrick 
1398061da546Spatrick // Return string description for the specified thread.
1399061da546Spatrick //
1400061da546Spatrick // RETURNS: NULL if the thread isn't valid, else a NULL terminated C
1401061da546Spatrick // string from a static buffer that must be copied prior to subsequent
1402061da546Spatrick // calls.
DNBThreadGetInfo(nub_process_t pid,nub_thread_t tid)1403061da546Spatrick const char *DNBThreadGetInfo(nub_process_t pid, nub_thread_t tid) {
1404061da546Spatrick   MachProcessSP procSP;
1405061da546Spatrick   if (GetProcessSP(pid, procSP))
1406061da546Spatrick     return procSP->GetThreadInfo(tid);
1407061da546Spatrick   return NULL;
1408061da546Spatrick }
1409061da546Spatrick 
1410061da546Spatrick // Get the thread ID given a thread index.
DNBProcessGetThreadAtIndex(nub_process_t pid,size_t thread_idx)1411061da546Spatrick nub_thread_t DNBProcessGetThreadAtIndex(nub_process_t pid, size_t thread_idx) {
1412061da546Spatrick   MachProcessSP procSP;
1413061da546Spatrick   if (GetProcessSP(pid, procSP))
1414061da546Spatrick     return procSP->GetThreadAtIndex(thread_idx);
1415061da546Spatrick   return INVALID_NUB_THREAD;
1416061da546Spatrick }
1417061da546Spatrick 
1418061da546Spatrick // Do whatever is needed to sync the thread's register state with it's kernel
1419061da546Spatrick // values.
DNBProcessSyncThreadState(nub_process_t pid,nub_thread_t tid)1420061da546Spatrick nub_bool_t DNBProcessSyncThreadState(nub_process_t pid, nub_thread_t tid) {
1421061da546Spatrick   MachProcessSP procSP;
1422061da546Spatrick   if (GetProcessSP(pid, procSP))
1423061da546Spatrick     return procSP->SyncThreadState(tid);
1424061da546Spatrick   return false;
1425061da546Spatrick }
1426061da546Spatrick 
DNBProcessGetSharedLibraryInfoAddress(nub_process_t pid)1427061da546Spatrick nub_addr_t DNBProcessGetSharedLibraryInfoAddress(nub_process_t pid) {
1428061da546Spatrick   MachProcessSP procSP;
1429061da546Spatrick   DNBError err;
1430061da546Spatrick   if (GetProcessSP(pid, procSP))
1431061da546Spatrick     return procSP->Task().GetDYLDAllImageInfosAddress(err);
1432061da546Spatrick   return INVALID_NUB_ADDRESS;
1433061da546Spatrick }
1434061da546Spatrick 
DNBProcessSharedLibrariesUpdated(nub_process_t pid)1435061da546Spatrick nub_bool_t DNBProcessSharedLibrariesUpdated(nub_process_t pid) {
1436061da546Spatrick   MachProcessSP procSP;
1437061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1438061da546Spatrick     procSP->SharedLibrariesUpdated();
1439061da546Spatrick     return true;
1440061da546Spatrick   }
1441061da546Spatrick   return false;
1442061da546Spatrick }
1443061da546Spatrick 
1444*f6aab3d8Srobert std::optional<std::string>
DNBGetDeploymentInfo(nub_process_t pid,bool is_executable,const struct load_command & lc,uint64_t load_command_address,uint32_t & major_version,uint32_t & minor_version,uint32_t & patch_version)1445*f6aab3d8Srobert DNBGetDeploymentInfo(nub_process_t pid, bool is_executable,
1446061da546Spatrick                      const struct load_command &lc,
1447*f6aab3d8Srobert                      uint64_t load_command_address, uint32_t &major_version,
1448*f6aab3d8Srobert                      uint32_t &minor_version, uint32_t &patch_version) {
1449061da546Spatrick   MachProcessSP procSP;
1450dda28197Spatrick   if (GetProcessSP(pid, procSP)) {
1451be691f3bSpatrick     // FIXME: This doesn't return the correct result when xctest (a
1452be691f3bSpatrick     // macOS binary) is loaded with the macCatalyst dyld platform
1453be691f3bSpatrick     // override. The image info corrects for this, but qProcessInfo
1454be691f3bSpatrick     // will return what is in the binary.
1455be691f3bSpatrick     auto info =
1456be691f3bSpatrick         procSP->GetDeploymentInfo(lc, load_command_address, is_executable);
1457dda28197Spatrick     major_version = info.major_version;
1458dda28197Spatrick     minor_version = info.minor_version;
1459dda28197Spatrick     patch_version = info.patch_version;
1460dda28197Spatrick     return procSP->GetPlatformString(info.platform);
1461dda28197Spatrick   }
1462061da546Spatrick   return nullptr;
1463061da546Spatrick }
1464061da546Spatrick 
1465061da546Spatrick // Get the current shared library information for a process. Only return
1466061da546Spatrick // the shared libraries that have changed since the last shared library
1467061da546Spatrick // state changed event if only_changed is non-zero.
1468061da546Spatrick nub_size_t
DNBProcessGetSharedLibraryInfo(nub_process_t pid,nub_bool_t only_changed,struct DNBExecutableImageInfo ** image_infos)1469061da546Spatrick DNBProcessGetSharedLibraryInfo(nub_process_t pid, nub_bool_t only_changed,
1470061da546Spatrick                                struct DNBExecutableImageInfo **image_infos) {
1471061da546Spatrick   MachProcessSP procSP;
1472061da546Spatrick   if (GetProcessSP(pid, procSP))
1473061da546Spatrick     return procSP->CopyImageInfos(image_infos, only_changed);
1474061da546Spatrick 
1475061da546Spatrick   // If we have no process, then return NULL for the shared library info
1476061da546Spatrick   // and zero for shared library count
1477061da546Spatrick   *image_infos = NULL;
1478061da546Spatrick   return 0;
1479061da546Spatrick }
1480061da546Spatrick 
DNBGetRegisterCPUType()1481061da546Spatrick uint32_t DNBGetRegisterCPUType() {
1482061da546Spatrick   return DNBArchProtocol::GetRegisterCPUType();
1483061da546Spatrick }
1484061da546Spatrick // Get the register set information for a specific thread.
DNBGetRegisterSetInfo(nub_size_t * num_reg_sets)1485061da546Spatrick const DNBRegisterSetInfo *DNBGetRegisterSetInfo(nub_size_t *num_reg_sets) {
1486061da546Spatrick   return DNBArchProtocol::GetRegisterSetInfo(num_reg_sets);
1487061da546Spatrick }
1488061da546Spatrick 
1489061da546Spatrick // Read a register value by register set and register index.
DNBThreadGetRegisterValueByID(nub_process_t pid,nub_thread_t tid,uint32_t set,uint32_t reg,DNBRegisterValue * value)1490061da546Spatrick nub_bool_t DNBThreadGetRegisterValueByID(nub_process_t pid, nub_thread_t tid,
1491061da546Spatrick                                          uint32_t set, uint32_t reg,
1492061da546Spatrick                                          DNBRegisterValue *value) {
1493061da546Spatrick   MachProcessSP procSP;
1494061da546Spatrick   ::bzero(value, sizeof(DNBRegisterValue));
1495061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1496061da546Spatrick     if (tid != INVALID_NUB_THREAD)
1497061da546Spatrick       return procSP->GetRegisterValue(tid, set, reg, value);
1498061da546Spatrick   }
1499061da546Spatrick   return false;
1500061da546Spatrick }
1501061da546Spatrick 
DNBThreadSetRegisterValueByID(nub_process_t pid,nub_thread_t tid,uint32_t set,uint32_t reg,const DNBRegisterValue * value)1502061da546Spatrick nub_bool_t DNBThreadSetRegisterValueByID(nub_process_t pid, nub_thread_t tid,
1503061da546Spatrick                                          uint32_t set, uint32_t reg,
1504061da546Spatrick                                          const DNBRegisterValue *value) {
1505061da546Spatrick   if (tid != INVALID_NUB_THREAD) {
1506061da546Spatrick     MachProcessSP procSP;
1507061da546Spatrick     if (GetProcessSP(pid, procSP))
1508061da546Spatrick       return procSP->SetRegisterValue(tid, set, reg, value);
1509061da546Spatrick   }
1510061da546Spatrick   return false;
1511061da546Spatrick }
1512061da546Spatrick 
DNBThreadGetRegisterContext(nub_process_t pid,nub_thread_t tid,void * buf,size_t buf_len)1513061da546Spatrick nub_size_t DNBThreadGetRegisterContext(nub_process_t pid, nub_thread_t tid,
1514061da546Spatrick                                        void *buf, size_t buf_len) {
1515061da546Spatrick   MachProcessSP procSP;
1516061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1517061da546Spatrick     if (tid != INVALID_NUB_THREAD)
1518061da546Spatrick       return procSP->GetThreadList().GetRegisterContext(tid, buf, buf_len);
1519061da546Spatrick   }
1520061da546Spatrick   ::bzero(buf, buf_len);
1521061da546Spatrick   return 0;
1522061da546Spatrick }
1523061da546Spatrick 
DNBThreadSetRegisterContext(nub_process_t pid,nub_thread_t tid,const void * buf,size_t buf_len)1524061da546Spatrick nub_size_t DNBThreadSetRegisterContext(nub_process_t pid, nub_thread_t tid,
1525061da546Spatrick                                        const void *buf, size_t buf_len) {
1526061da546Spatrick   MachProcessSP procSP;
1527061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1528061da546Spatrick     if (tid != INVALID_NUB_THREAD)
1529061da546Spatrick       return procSP->GetThreadList().SetRegisterContext(tid, buf, buf_len);
1530061da546Spatrick   }
1531061da546Spatrick   return 0;
1532061da546Spatrick }
1533061da546Spatrick 
DNBThreadSaveRegisterState(nub_process_t pid,nub_thread_t tid)1534061da546Spatrick uint32_t DNBThreadSaveRegisterState(nub_process_t pid, nub_thread_t tid) {
1535061da546Spatrick   if (tid != INVALID_NUB_THREAD) {
1536061da546Spatrick     MachProcessSP procSP;
1537061da546Spatrick     if (GetProcessSP(pid, procSP))
1538061da546Spatrick       return procSP->GetThreadList().SaveRegisterState(tid);
1539061da546Spatrick   }
1540061da546Spatrick   return 0;
1541061da546Spatrick }
DNBThreadRestoreRegisterState(nub_process_t pid,nub_thread_t tid,uint32_t save_id)1542061da546Spatrick nub_bool_t DNBThreadRestoreRegisterState(nub_process_t pid, nub_thread_t tid,
1543061da546Spatrick                                          uint32_t save_id) {
1544061da546Spatrick   if (tid != INVALID_NUB_THREAD) {
1545061da546Spatrick     MachProcessSP procSP;
1546061da546Spatrick     if (GetProcessSP(pid, procSP))
1547061da546Spatrick       return procSP->GetThreadList().RestoreRegisterState(tid, save_id);
1548061da546Spatrick   }
1549061da546Spatrick   return false;
1550061da546Spatrick }
1551061da546Spatrick 
1552061da546Spatrick // Read a register value by name.
DNBThreadGetRegisterValueByName(nub_process_t pid,nub_thread_t tid,uint32_t reg_set,const char * reg_name,DNBRegisterValue * value)1553061da546Spatrick nub_bool_t DNBThreadGetRegisterValueByName(nub_process_t pid, nub_thread_t tid,
1554061da546Spatrick                                            uint32_t reg_set,
1555061da546Spatrick                                            const char *reg_name,
1556061da546Spatrick                                            DNBRegisterValue *value) {
1557061da546Spatrick   MachProcessSP procSP;
1558061da546Spatrick   ::bzero(value, sizeof(DNBRegisterValue));
1559061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1560061da546Spatrick     const struct DNBRegisterSetInfo *set_info;
1561061da546Spatrick     nub_size_t num_reg_sets = 0;
1562061da546Spatrick     set_info = DNBGetRegisterSetInfo(&num_reg_sets);
1563061da546Spatrick     if (set_info) {
1564061da546Spatrick       uint32_t set = reg_set;
1565061da546Spatrick       uint32_t reg;
1566061da546Spatrick       if (set == REGISTER_SET_ALL) {
1567061da546Spatrick         for (set = 1; set < num_reg_sets; ++set) {
1568061da546Spatrick           for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1569061da546Spatrick             if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
1570061da546Spatrick               return procSP->GetRegisterValue(tid, set, reg, value);
1571061da546Spatrick           }
1572061da546Spatrick         }
1573061da546Spatrick       } else {
1574061da546Spatrick         for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1575061da546Spatrick           if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
1576061da546Spatrick             return procSP->GetRegisterValue(tid, set, reg, value);
1577061da546Spatrick         }
1578061da546Spatrick       }
1579061da546Spatrick     }
1580061da546Spatrick   }
1581061da546Spatrick   return false;
1582061da546Spatrick }
1583061da546Spatrick 
1584061da546Spatrick // Read a register set and register number from the register name.
DNBGetRegisterInfoByName(const char * reg_name,DNBRegisterInfo * info)1585061da546Spatrick nub_bool_t DNBGetRegisterInfoByName(const char *reg_name,
1586061da546Spatrick                                     DNBRegisterInfo *info) {
1587061da546Spatrick   const struct DNBRegisterSetInfo *set_info;
1588061da546Spatrick   nub_size_t num_reg_sets = 0;
1589061da546Spatrick   set_info = DNBGetRegisterSetInfo(&num_reg_sets);
1590061da546Spatrick   if (set_info) {
1591061da546Spatrick     uint32_t set, reg;
1592061da546Spatrick     for (set = 1; set < num_reg_sets; ++set) {
1593061da546Spatrick       for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1594061da546Spatrick         if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) {
1595061da546Spatrick           *info = set_info[set].registers[reg];
1596061da546Spatrick           return true;
1597061da546Spatrick         }
1598061da546Spatrick       }
1599061da546Spatrick     }
1600061da546Spatrick 
1601061da546Spatrick     for (set = 1; set < num_reg_sets; ++set) {
1602061da546Spatrick       uint32_t reg;
1603061da546Spatrick       for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1604061da546Spatrick         if (set_info[set].registers[reg].alt == NULL)
1605061da546Spatrick           continue;
1606061da546Spatrick 
1607061da546Spatrick         if (strcasecmp(reg_name, set_info[set].registers[reg].alt) == 0) {
1608061da546Spatrick           *info = set_info[set].registers[reg];
1609061da546Spatrick           return true;
1610061da546Spatrick         }
1611061da546Spatrick       }
1612061da546Spatrick     }
1613061da546Spatrick   }
1614061da546Spatrick 
1615061da546Spatrick   ::bzero(info, sizeof(DNBRegisterInfo));
1616061da546Spatrick   return false;
1617061da546Spatrick }
1618061da546Spatrick 
1619061da546Spatrick // Set the name to address callback function that this nub can use
1620061da546Spatrick // for any name to address lookups that are needed.
DNBProcessSetNameToAddressCallback(nub_process_t pid,DNBCallbackNameToAddress callback,void * baton)1621061da546Spatrick nub_bool_t DNBProcessSetNameToAddressCallback(nub_process_t pid,
1622061da546Spatrick                                               DNBCallbackNameToAddress callback,
1623061da546Spatrick                                               void *baton) {
1624061da546Spatrick   MachProcessSP procSP;
1625061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1626061da546Spatrick     procSP->SetNameToAddressCallback(callback, baton);
1627061da546Spatrick     return true;
1628061da546Spatrick   }
1629061da546Spatrick   return false;
1630061da546Spatrick }
1631061da546Spatrick 
1632061da546Spatrick // Set the name to address callback function that this nub can use
1633061da546Spatrick // for any name to address lookups that are needed.
DNBProcessSetSharedLibraryInfoCallback(nub_process_t pid,DNBCallbackCopyExecutableImageInfos callback,void * baton)1634061da546Spatrick nub_bool_t DNBProcessSetSharedLibraryInfoCallback(
1635061da546Spatrick     nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback,
1636061da546Spatrick     void *baton) {
1637061da546Spatrick   MachProcessSP procSP;
1638061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1639061da546Spatrick     procSP->SetSharedLibraryInfoCallback(callback, baton);
1640061da546Spatrick     return true;
1641061da546Spatrick   }
1642061da546Spatrick   return false;
1643061da546Spatrick }
1644061da546Spatrick 
DNBProcessLookupAddress(nub_process_t pid,const char * name,const char * shlib)1645061da546Spatrick nub_addr_t DNBProcessLookupAddress(nub_process_t pid, const char *name,
1646061da546Spatrick                                    const char *shlib) {
1647061da546Spatrick   MachProcessSP procSP;
1648061da546Spatrick   if (GetProcessSP(pid, procSP)) {
1649061da546Spatrick     return procSP->LookupSymbol(name, shlib);
1650061da546Spatrick   }
1651061da546Spatrick   return INVALID_NUB_ADDRESS;
1652061da546Spatrick }
1653061da546Spatrick 
DNBProcessGetAvailableSTDOUT(nub_process_t pid,char * buf,nub_size_t buf_size)1654061da546Spatrick nub_size_t DNBProcessGetAvailableSTDOUT(nub_process_t pid, char *buf,
1655061da546Spatrick                                         nub_size_t buf_size) {
1656061da546Spatrick   MachProcessSP procSP;
1657061da546Spatrick   if (GetProcessSP(pid, procSP))
1658061da546Spatrick     return procSP->GetAvailableSTDOUT(buf, buf_size);
1659061da546Spatrick   return 0;
1660061da546Spatrick }
1661061da546Spatrick 
DNBProcessGetAvailableSTDERR(nub_process_t pid,char * buf,nub_size_t buf_size)1662061da546Spatrick nub_size_t DNBProcessGetAvailableSTDERR(nub_process_t pid, char *buf,
1663061da546Spatrick                                         nub_size_t buf_size) {
1664061da546Spatrick   MachProcessSP procSP;
1665061da546Spatrick   if (GetProcessSP(pid, procSP))
1666061da546Spatrick     return procSP->GetAvailableSTDERR(buf, buf_size);
1667061da546Spatrick   return 0;
1668061da546Spatrick }
1669061da546Spatrick 
DNBProcessGetAvailableProfileData(nub_process_t pid,char * buf,nub_size_t buf_size)1670061da546Spatrick nub_size_t DNBProcessGetAvailableProfileData(nub_process_t pid, char *buf,
1671061da546Spatrick                                              nub_size_t buf_size) {
1672061da546Spatrick   MachProcessSP procSP;
1673061da546Spatrick   if (GetProcessSP(pid, procSP))
1674061da546Spatrick     return procSP->GetAsyncProfileData(buf, buf_size);
1675061da546Spatrick   return 0;
1676061da546Spatrick }
1677061da546Spatrick 
DNBProcessGetStopCount(nub_process_t pid)1678061da546Spatrick nub_size_t DNBProcessGetStopCount(nub_process_t pid) {
1679061da546Spatrick   MachProcessSP procSP;
1680061da546Spatrick   if (GetProcessSP(pid, procSP))
1681061da546Spatrick     return procSP->StopCount();
1682061da546Spatrick   return 0;
1683061da546Spatrick }
1684061da546Spatrick 
DNBProcessGetCPUType(nub_process_t pid)1685061da546Spatrick uint32_t DNBProcessGetCPUType(nub_process_t pid) {
1686061da546Spatrick   MachProcessSP procSP;
1687061da546Spatrick   if (GetProcessSP(pid, procSP))
1688061da546Spatrick     return procSP->GetCPUType();
1689061da546Spatrick   return 0;
1690061da546Spatrick }
1691061da546Spatrick 
DNBResolveExecutablePath(const char * path,char * resolved_path,size_t resolved_path_size)1692061da546Spatrick nub_bool_t DNBResolveExecutablePath(const char *path, char *resolved_path,
1693061da546Spatrick                                     size_t resolved_path_size) {
1694061da546Spatrick   if (path == NULL || path[0] == '\0')
1695061da546Spatrick     return false;
1696061da546Spatrick 
1697061da546Spatrick   char max_path[PATH_MAX];
1698061da546Spatrick   std::string result;
1699061da546Spatrick   CFString::GlobPath(path, result);
1700061da546Spatrick 
1701061da546Spatrick   if (result.empty())
1702061da546Spatrick     result = path;
1703061da546Spatrick 
1704061da546Spatrick   struct stat path_stat;
1705061da546Spatrick   if (::stat(path, &path_stat) == 0) {
1706061da546Spatrick     if ((path_stat.st_mode & S_IFMT) == S_IFDIR) {
1707061da546Spatrick       CFBundle bundle(path);
1708061da546Spatrick       CFReleaser<CFURLRef> url(bundle.CopyExecutableURL());
1709061da546Spatrick       if (url.get()) {
1710061da546Spatrick         if (::CFURLGetFileSystemRepresentation(
1711061da546Spatrick                 url.get(), true, (UInt8 *)resolved_path, resolved_path_size))
1712061da546Spatrick           return true;
1713061da546Spatrick       }
1714061da546Spatrick     }
1715061da546Spatrick   }
1716061da546Spatrick 
1717061da546Spatrick   if (realpath(path, max_path)) {
1718061da546Spatrick     // Found the path relatively...
1719061da546Spatrick     ::strlcpy(resolved_path, max_path, resolved_path_size);
1720061da546Spatrick     return strlen(resolved_path) + 1 < resolved_path_size;
1721061da546Spatrick   } else {
1722061da546Spatrick     // Not a relative path, check the PATH environment variable if the
1723061da546Spatrick     const char *PATH = getenv("PATH");
1724061da546Spatrick     if (PATH) {
1725061da546Spatrick       const char *curr_path_start = PATH;
1726061da546Spatrick       const char *curr_path_end;
1727061da546Spatrick       while (curr_path_start && *curr_path_start) {
1728061da546Spatrick         curr_path_end = strchr(curr_path_start, ':');
1729061da546Spatrick         if (curr_path_end == NULL) {
1730061da546Spatrick           result.assign(curr_path_start);
1731061da546Spatrick           curr_path_start = NULL;
1732061da546Spatrick         } else if (curr_path_end > curr_path_start) {
1733061da546Spatrick           size_t len = curr_path_end - curr_path_start;
1734061da546Spatrick           result.assign(curr_path_start, len);
1735061da546Spatrick           curr_path_start += len + 1;
1736061da546Spatrick         } else
1737061da546Spatrick           break;
1738061da546Spatrick 
1739061da546Spatrick         result += '/';
1740061da546Spatrick         result += path;
1741061da546Spatrick         struct stat s;
1742061da546Spatrick         if (stat(result.c_str(), &s) == 0) {
1743061da546Spatrick           ::strlcpy(resolved_path, result.c_str(), resolved_path_size);
1744061da546Spatrick           return result.size() + 1 < resolved_path_size;
1745061da546Spatrick         }
1746061da546Spatrick       }
1747061da546Spatrick     }
1748061da546Spatrick   }
1749061da546Spatrick   return false;
1750061da546Spatrick }
1751061da546Spatrick 
DNBGetOSVersionNumbers(uint64_t * major,uint64_t * minor,uint64_t * patch)1752061da546Spatrick bool DNBGetOSVersionNumbers(uint64_t *major, uint64_t *minor, uint64_t *patch) {
1753061da546Spatrick   return MachProcess::GetOSVersionNumbers(major, minor, patch);
1754061da546Spatrick }
1755061da546Spatrick 
DNBGetMacCatalystVersionString()1756061da546Spatrick std::string DNBGetMacCatalystVersionString() {
1757061da546Spatrick   return MachProcess::GetMacCatalystVersionString();
1758061da546Spatrick }
1759061da546Spatrick 
DNBInitialize()1760061da546Spatrick void DNBInitialize() {
1761061da546Spatrick   DNBLogThreadedIf(LOG_PROCESS, "DNBInitialize ()");
1762061da546Spatrick #if defined(__i386__) || defined(__x86_64__)
1763061da546Spatrick   DNBArchImplI386::Initialize();
1764061da546Spatrick   DNBArchImplX86_64::Initialize();
1765061da546Spatrick #elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
1766061da546Spatrick   DNBArchMachARM::Initialize();
1767061da546Spatrick   DNBArchMachARM64::Initialize();
1768061da546Spatrick #endif
1769061da546Spatrick }
1770061da546Spatrick 
DNBTerminate()1771061da546Spatrick void DNBTerminate() {}
1772061da546Spatrick 
DNBSetArchitecture(const char * arch)1773061da546Spatrick nub_bool_t DNBSetArchitecture(const char *arch) {
1774061da546Spatrick   if (arch && arch[0]) {
1775061da546Spatrick     if (strcasecmp(arch, "i386") == 0)
1776061da546Spatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_I386);
1777be691f3bSpatrick     else if (strcasecmp(arch, "x86_64") == 0)
1778be691f3bSpatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64,
1779be691f3bSpatrick                                               CPU_SUBTYPE_X86_64_ALL);
1780be691f3bSpatrick     else if (strcasecmp(arch, "x86_64h") == 0)
1781be691f3bSpatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64,
1782be691f3bSpatrick                                               CPU_SUBTYPE_X86_64_H);
1783061da546Spatrick     else if (strstr(arch, "arm64_32") == arch ||
1784061da546Spatrick              strstr(arch, "aarch64_32") == arch)
1785061da546Spatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64_32);
1786061da546Spatrick     else if (strstr(arch, "arm64e") == arch)
1787be691f3bSpatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64,
1788be691f3bSpatrick                                               CPU_SUBTYPE_ARM64E);
1789be691f3bSpatrick     else if (strstr(arch, "arm64") == arch || strstr(arch, "aarch64") == arch)
1790be691f3bSpatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64,
1791be691f3bSpatrick                                               CPU_SUBTYPE_ARM64_ALL);
1792be691f3bSpatrick     else if (strstr(arch, "armv8") == arch)
1793be691f3bSpatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64,
1794be691f3bSpatrick                                               CPU_SUBTYPE_ARM64_V8);
1795be691f3bSpatrick     else if (strstr(arch, "armv7em") == arch)
1796be691f3bSpatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1797be691f3bSpatrick                                               CPU_SUBTYPE_ARM_V7EM);
1798be691f3bSpatrick     else if (strstr(arch, "armv7m") == arch)
1799be691f3bSpatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1800be691f3bSpatrick                                               CPU_SUBTYPE_ARM_V7M);
1801be691f3bSpatrick     else if (strstr(arch, "armv7k") == arch)
1802be691f3bSpatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1803be691f3bSpatrick                                               CPU_SUBTYPE_ARM_V7K);
1804be691f3bSpatrick     else if (strstr(arch, "armv7s") == arch)
1805be691f3bSpatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1806be691f3bSpatrick                                               CPU_SUBTYPE_ARM_V7S);
1807be691f3bSpatrick     else if (strstr(arch, "armv7") == arch)
1808be691f3bSpatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7);
1809be691f3bSpatrick     else if (strstr(arch, "armv6m") == arch)
1810be691f3bSpatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1811be691f3bSpatrick                                               CPU_SUBTYPE_ARM_V6M);
1812be691f3bSpatrick     else if (strstr(arch, "armv6") == arch)
1813be691f3bSpatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6);
1814be691f3bSpatrick     else if (strstr(arch, "armv5") == arch)
1815be691f3bSpatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1816be691f3bSpatrick                                               CPU_SUBTYPE_ARM_V5TEJ);
1817be691f3bSpatrick     else if (strstr(arch, "armv4t") == arch)
1818be691f3bSpatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1819be691f3bSpatrick                                               CPU_SUBTYPE_ARM_V4T);
1820061da546Spatrick     else if (strstr(arch, "arm") == arch)
1821be691f3bSpatrick       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1822be691f3bSpatrick                                               CPU_SUBTYPE_ARM_ALL);
1823061da546Spatrick   }
1824061da546Spatrick   return false;
1825061da546Spatrick }
1826be691f3bSpatrick 
DNBDebugserverIsTranslated()1827be691f3bSpatrick bool DNBDebugserverIsTranslated() {
1828be691f3bSpatrick   int ret = 0;
1829be691f3bSpatrick   size_t size = sizeof(ret);
1830be691f3bSpatrick   if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1)
1831be691f3bSpatrick     return false;
1832be691f3bSpatrick   return ret == 1;
1833be691f3bSpatrick }
1834*f6aab3d8Srobert 
DNBGetAddressingBits(uint32_t & addressing_bits)1835*f6aab3d8Srobert bool DNBGetAddressingBits(uint32_t &addressing_bits) {
1836*f6aab3d8Srobert   static uint32_t g_addressing_bits = 0;
1837*f6aab3d8Srobert   static std::once_flag g_once_flag;
1838*f6aab3d8Srobert   std::call_once(g_once_flag, [&](){
1839*f6aab3d8Srobert     size_t len = sizeof(uint32_t);
1840*f6aab3d8Srobert     if (::sysctlbyname("machdep.virtual_address_size", &g_addressing_bits, &len,
1841*f6aab3d8Srobert                        NULL, 0) != 0) {
1842*f6aab3d8Srobert       g_addressing_bits = 0;
1843*f6aab3d8Srobert     }
1844*f6aab3d8Srobert   });
1845*f6aab3d8Srobert 
1846*f6aab3d8Srobert   addressing_bits = g_addressing_bits;
1847*f6aab3d8Srobert 
1848*f6aab3d8Srobert   return addressing_bits > 0;
1849*f6aab3d8Srobert }
1850