130fdc8d8SChris Lattner //===-- DNB.cpp -------------------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner //
930fdc8d8SChris Lattner //  Created by Greg Clayton on 3/23/07.
1030fdc8d8SChris Lattner //
1130fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
1230fdc8d8SChris Lattner 
1330fdc8d8SChris Lattner #include "DNB.h"
1476e47d48SRaphael Isemann #include <cinttypes>
1576e47d48SRaphael Isemann #include <csignal>
1676e47d48SRaphael Isemann #include <cstdio>
1776e47d48SRaphael Isemann #include <cstdlib>
18b9c1b51eSKate Stone #include <libproc.h>
19b9c1b51eSKate Stone #include <map>
2030fdc8d8SChris Lattner #include <sys/resource.h>
2130fdc8d8SChris Lattner #include <sys/stat.h>
22b9c1b51eSKate Stone #include <sys/sysctl.h>
2330fdc8d8SChris Lattner #include <sys/types.h>
2430fdc8d8SChris Lattner #include <sys/wait.h>
2530fdc8d8SChris Lattner #include <unistd.h>
2630fdc8d8SChris Lattner #include <vector>
2730fdc8d8SChris Lattner 
2836a216eeSJason Molenda #if defined(__APPLE__)
2936a216eeSJason Molenda #include <pthread.h>
3036a216eeSJason Molenda #include <sched.h>
3136a216eeSJason Molenda #endif
3236a216eeSJason Molenda 
33a332978bSJason Molenda #define TRY_KQUEUE 1
34a332978bSJason Molenda 
35a332978bSJason Molenda #ifdef TRY_KQUEUE
36a332978bSJason Molenda #include <sys/event.h>
37a332978bSJason Molenda #include <sys/time.h>
38a332978bSJason Molenda #ifdef NOTE_EXIT_DETAIL
39a332978bSJason Molenda #define USE_KQUEUE
40a332978bSJason Molenda #endif
41a332978bSJason Molenda #endif
42a332978bSJason Molenda 
43b9c1b51eSKate Stone #include "CFBundle.h"
4430fdc8d8SChris Lattner #include "CFString.h"
4530fdc8d8SChris Lattner #include "DNBDataRef.h"
46b9c1b51eSKate Stone #include "DNBLog.h"
4730fdc8d8SChris Lattner #include "DNBThreadResumeActions.h"
4830fdc8d8SChris Lattner #include "DNBTimer.h"
49b9c1b51eSKate Stone #include "MacOSX/Genealogy.h"
50b9c1b51eSKate Stone #include "MacOSX/MachProcess.h"
51b9c1b51eSKate Stone #include "MacOSX/MachTask.h"
52b9c1b51eSKate Stone #include "MacOSX/ThreadInfo.h"
5330fdc8d8SChris Lattner 
547b0992d9SGreg Clayton typedef std::shared_ptr<MachProcess> MachProcessSP;
5530fdc8d8SChris Lattner typedef std::map<nub_process_t, MachProcessSP> ProcessMap;
5630fdc8d8SChris Lattner typedef ProcessMap::iterator ProcessMapIter;
5730fdc8d8SChris Lattner typedef ProcessMap::const_iterator ProcessMapConstIter;
5830fdc8d8SChris Lattner 
59b9c1b51eSKate Stone static size_t
60b9c1b51eSKate Stone GetAllInfosMatchingName(const char *process_name,
61b9c1b51eSKate Stone                         std::vector<struct kinfo_proc> &matching_proc_infos);
6230fdc8d8SChris Lattner 
6330fdc8d8SChris Lattner // A Thread safe singleton to get a process map pointer.
6430fdc8d8SChris Lattner //
6530fdc8d8SChris Lattner // Returns a pointer to the existing process map, or a pointer to a
6630fdc8d8SChris Lattner // newly created process map if CAN_CREATE is non-zero.
GetProcessMap(bool can_create)67b9c1b51eSKate Stone static ProcessMap *GetProcessMap(bool can_create) {
6830fdc8d8SChris Lattner   static ProcessMap *g_process_map_ptr = NULL;
6930fdc8d8SChris Lattner 
70b9c1b51eSKate Stone   if (can_create && g_process_map_ptr == NULL) {
7130fdc8d8SChris Lattner     static pthread_mutex_t g_process_map_mutex = PTHREAD_MUTEX_INITIALIZER;
7230fdc8d8SChris Lattner     PTHREAD_MUTEX_LOCKER(locker, &g_process_map_mutex);
7330fdc8d8SChris Lattner     if (g_process_map_ptr == NULL)
7430fdc8d8SChris Lattner       g_process_map_ptr = new ProcessMap;
7530fdc8d8SChris Lattner   }
7630fdc8d8SChris Lattner   return g_process_map_ptr;
7730fdc8d8SChris Lattner }
7830fdc8d8SChris Lattner 
7930fdc8d8SChris Lattner // Add PID to the shared process pointer map.
8030fdc8d8SChris Lattner //
8130fdc8d8SChris Lattner // Return non-zero value if we succeed in adding the process to the map.
8230fdc8d8SChris Lattner // The only time this should fail is if we run out of memory and can't
8330fdc8d8SChris Lattner // allocate a ProcessMap.
AddProcessToMap(nub_process_t pid,MachProcessSP & procSP)84b9c1b51eSKate Stone static nub_bool_t AddProcessToMap(nub_process_t pid, MachProcessSP &procSP) {
8530fdc8d8SChris Lattner   ProcessMap *process_map = GetProcessMap(true);
86b9c1b51eSKate Stone   if (process_map) {
8730fdc8d8SChris Lattner     process_map->insert(std::make_pair(pid, procSP));
8830fdc8d8SChris Lattner     return true;
8930fdc8d8SChris Lattner   }
9030fdc8d8SChris Lattner   return false;
9130fdc8d8SChris Lattner }
9230fdc8d8SChris Lattner 
9330fdc8d8SChris Lattner // Remove the shared pointer for PID from the process map.
9430fdc8d8SChris Lattner //
9530fdc8d8SChris Lattner // Returns the number of items removed from the process map.
96ee2ed525SGreg Clayton // static size_t
97ee2ed525SGreg Clayton // RemoveProcessFromMap (nub_process_t pid)
98ee2ed525SGreg Clayton //{
99ee2ed525SGreg Clayton //    ProcessMap* process_map = GetProcessMap(false);
100ee2ed525SGreg Clayton //    if (process_map)
101ee2ed525SGreg Clayton //    {
102ee2ed525SGreg Clayton //        return process_map->erase(pid);
103ee2ed525SGreg Clayton //    }
104ee2ed525SGreg Clayton //    return 0;
105ee2ed525SGreg Clayton //}
10630fdc8d8SChris Lattner 
10730fdc8d8SChris Lattner // Get the shared pointer for PID from the existing process map.
10830fdc8d8SChris Lattner //
10930fdc8d8SChris Lattner // Returns true if we successfully find a shared pointer to a
11030fdc8d8SChris Lattner // MachProcess object.
GetProcessSP(nub_process_t pid,MachProcessSP & procSP)111b9c1b51eSKate Stone static nub_bool_t GetProcessSP(nub_process_t pid, MachProcessSP &procSP) {
11230fdc8d8SChris Lattner   ProcessMap *process_map = GetProcessMap(false);
113b9c1b51eSKate Stone   if (process_map != NULL) {
11430fdc8d8SChris Lattner     ProcessMapIter pos = process_map->find(pid);
115b9c1b51eSKate Stone     if (pos != process_map->end()) {
11630fdc8d8SChris Lattner       procSP = pos->second;
11730fdc8d8SChris Lattner       return true;
11830fdc8d8SChris Lattner     }
11930fdc8d8SChris Lattner   }
12030fdc8d8SChris Lattner   procSP.reset();
12130fdc8d8SChris Lattner   return false;
12230fdc8d8SChris Lattner }
12330fdc8d8SChris Lattner 
124a332978bSJason Molenda #ifdef USE_KQUEUE
kqueue_thread(void * arg)125b9c1b51eSKate Stone void *kqueue_thread(void *arg) {
126a332978bSJason Molenda   int kq_id = (int)(intptr_t)arg;
127a332978bSJason Molenda 
12836a216eeSJason Molenda #if defined(__APPLE__)
12936a216eeSJason Molenda   pthread_setname_np("kqueue thread");
13036a216eeSJason Molenda #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
13136a216eeSJason Molenda   struct sched_param thread_param;
13236a216eeSJason Molenda   int thread_sched_policy;
133b9c1b51eSKate Stone   if (pthread_getschedparam(pthread_self(), &thread_sched_policy,
134b9c1b51eSKate Stone                             &thread_param) == 0) {
13536a216eeSJason Molenda     thread_param.sched_priority = 47;
13636a216eeSJason Molenda     pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
13736a216eeSJason Molenda   }
13836a216eeSJason Molenda #endif
13936a216eeSJason Molenda #endif
14036a216eeSJason Molenda 
141a332978bSJason Molenda   struct kevent death_event;
14209ad8c8fSJonas Devlieghere   while (true) {
143a332978bSJason Molenda     int n_events = kevent(kq_id, NULL, 0, &death_event, 1, NULL);
144b9c1b51eSKate Stone     if (n_events == -1) {
145a332978bSJason Molenda       if (errno == EINTR)
146a332978bSJason Molenda         continue;
147b9c1b51eSKate Stone       else {
148b9c1b51eSKate Stone         DNBLogError("kqueue failed with error: (%d): %s", errno,
149b9c1b51eSKate Stone                     strerror(errno));
150a332978bSJason Molenda         return NULL;
151a332978bSJason Molenda       }
152b9c1b51eSKate Stone     } else if (death_event.flags & EV_ERROR) {
153ee2ed525SGreg Clayton       int error_no = static_cast<int>(death_event.data);
154ee2ed525SGreg Clayton       const char *error_str = strerror(error_no);
155a332978bSJason Molenda       if (error_str == NULL)
156a332978bSJason Molenda         error_str = "Unknown error";
157b9c1b51eSKate Stone       DNBLogError("Failed to initialize kqueue event: (%d): %s", error_no,
158b9c1b51eSKate Stone                   error_str);
159a332978bSJason Molenda       return NULL;
160b9c1b51eSKate Stone     } else {
161a332978bSJason Molenda       int status;
162040c560fSGreg Clayton       const pid_t pid = (pid_t)death_event.ident;
163040c560fSGreg Clayton       const pid_t child_pid = waitpid(pid, &status, 0);
164040c560fSGreg Clayton 
165040c560fSGreg Clayton       bool exited = false;
166040c560fSGreg Clayton       int signal = 0;
167040c560fSGreg Clayton       int exit_status = 0;
168b9c1b51eSKate Stone       if (WIFSTOPPED(status)) {
169040c560fSGreg Clayton         signal = WSTOPSIG(status);
170b9c1b51eSKate Stone         DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> STOPPED (signal = %i)",
171b9c1b51eSKate Stone                          child_pid, signal);
172b9c1b51eSKate Stone       } else if (WIFEXITED(status)) {
173040c560fSGreg Clayton         exit_status = WEXITSTATUS(status);
174040c560fSGreg Clayton         exited = true;
175b9c1b51eSKate Stone         DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> EXITED (status = %i)",
176b9c1b51eSKate Stone                          child_pid, exit_status);
177b9c1b51eSKate Stone       } else if (WIFSIGNALED(status)) {
178040c560fSGreg Clayton         signal = WTERMSIG(status);
179b9c1b51eSKate Stone         if (child_pid == abs(pid)) {
180b9c1b51eSKate Stone           DNBLogThreadedIf(LOG_PROCESS,
181b9c1b51eSKate Stone                            "waitpid (%i) -> SIGNALED and EXITED (signal = %i)",
182b9c1b51eSKate Stone                            child_pid, signal);
183040c560fSGreg Clayton           char exit_info[64];
184b9c1b51eSKate Stone           ::snprintf(exit_info, sizeof(exit_info),
185b9c1b51eSKate Stone                      "Terminated due to signal %i", signal);
186040c560fSGreg Clayton           DNBProcessSetExitInfo(child_pid, exit_info);
187040c560fSGreg Clayton           exited = true;
188040c560fSGreg Clayton           exit_status = INT8_MAX;
189b9c1b51eSKate Stone         } else {
190b9c1b51eSKate Stone           DNBLogThreadedIf(LOG_PROCESS,
191b9c1b51eSKate Stone                            "waitpid (%i) -> SIGNALED (signal = %i)", child_pid,
192b9c1b51eSKate Stone                            signal);
193040c560fSGreg Clayton         }
194040c560fSGreg Clayton       }
195040c560fSGreg Clayton 
196b9c1b51eSKate Stone       if (exited) {
197a332978bSJason Molenda         if (death_event.data & NOTE_EXIT_MEMORY)
1980c7ebe96SJim Ingham           DNBProcessSetExitInfo(child_pid, "Terminated due to memory issue");
199a332978bSJason Molenda         else if (death_event.data & NOTE_EXIT_DECRYPTFAIL)
200a332978bSJason Molenda           DNBProcessSetExitInfo(child_pid, "Terminated due to decrypt failure");
201a332978bSJason Molenda         else if (death_event.data & NOTE_EXIT_CSERROR)
202b9c1b51eSKate Stone           DNBProcessSetExitInfo(child_pid,
203b9c1b51eSKate Stone                                 "Terminated due to code signing error");
204a332978bSJason Molenda 
205b9c1b51eSKate Stone         DNBLogThreadedIf(
206b9c1b51eSKate Stone             LOG_PROCESS,
207b9c1b51eSKate Stone             "waitpid_process_thread (): setting exit status for pid = %i to %i",
208b9c1b51eSKate Stone             child_pid, exit_status);
209a332978bSJason Molenda         DNBProcessSetExitStatus(child_pid, status);
210a332978bSJason Molenda         return NULL;
211a332978bSJason Molenda       }
212a332978bSJason Molenda     }
213a332978bSJason Molenda   }
214040c560fSGreg Clayton }
215a332978bSJason Molenda 
spawn_kqueue_thread(pid_t pid)216b9c1b51eSKate Stone static bool spawn_kqueue_thread(pid_t pid) {
217a332978bSJason Molenda   pthread_t thread;
218a332978bSJason Molenda   int kq_id;
219a332978bSJason Molenda 
220a332978bSJason Molenda   kq_id = kqueue();
221b9c1b51eSKate Stone   if (kq_id == -1) {
222a332978bSJason Molenda     DNBLogError("Could not get kqueue for pid = %i.", pid);
223a332978bSJason Molenda     return false;
224a332978bSJason Molenda   }
225a332978bSJason Molenda 
226a332978bSJason Molenda   struct kevent reg_event;
227a332978bSJason Molenda 
228b9c1b51eSKate Stone   EV_SET(&reg_event, pid, EVFILT_PROC, EV_ADD,
229b9c1b51eSKate Stone          NOTE_EXIT | NOTE_EXITSTATUS | NOTE_EXIT_DETAIL, 0, NULL);
230a332978bSJason Molenda   // Register the event:
231a332978bSJason Molenda   int result = kevent(kq_id, &reg_event, 1, NULL, 0, NULL);
232b9c1b51eSKate Stone   if (result != 0) {
233b9c1b51eSKate Stone     DNBLogError(
234b9c1b51eSKate Stone         "Failed to register kqueue NOTE_EXIT event for pid %i, error: %d.", pid,
235b9c1b51eSKate Stone         result);
236a332978bSJason Molenda     return false;
237a332978bSJason Molenda   }
238a332978bSJason Molenda 
239b9c1b51eSKate Stone   int ret =
240b9c1b51eSKate Stone       ::pthread_create(&thread, NULL, kqueue_thread, (void *)(intptr_t)kq_id);
241a332978bSJason Molenda 
242a332978bSJason Molenda   // pthread_create returns 0 if successful
243b9c1b51eSKate Stone   if (ret == 0) {
244a332978bSJason Molenda     ::pthread_detach(thread);
245a332978bSJason Molenda     return true;
246a332978bSJason Molenda   }
247a332978bSJason Molenda   return false;
248a332978bSJason Molenda }
249a332978bSJason Molenda #endif // #if USE_KQUEUE
25030fdc8d8SChris Lattner 
waitpid_thread(void * arg)251b9c1b51eSKate Stone static void *waitpid_thread(void *arg) {
25230fdc8d8SChris Lattner   const pid_t pid = (pid_t)(intptr_t)arg;
25330fdc8d8SChris Lattner   int status;
25436a216eeSJason Molenda 
25536a216eeSJason Molenda #if defined(__APPLE__)
25636a216eeSJason Molenda   pthread_setname_np("waitpid thread");
25736a216eeSJason Molenda #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
25836a216eeSJason Molenda   struct sched_param thread_param;
25936a216eeSJason Molenda   int thread_sched_policy;
260b9c1b51eSKate Stone   if (pthread_getschedparam(pthread_self(), &thread_sched_policy,
261b9c1b51eSKate Stone                             &thread_param) == 0) {
26236a216eeSJason Molenda     thread_param.sched_priority = 47;
26336a216eeSJason Molenda     pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
26436a216eeSJason Molenda   }
26536a216eeSJason Molenda #endif
26636a216eeSJason Molenda #endif
26736a216eeSJason Molenda 
26809ad8c8fSJonas Devlieghere   while (true) {
26930fdc8d8SChris Lattner     pid_t child_pid = waitpid(pid, &status, 0);
270b9c1b51eSKate Stone     DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): waitpid (pid = %i, "
271b9c1b51eSKate Stone                                   "&status, 0) => %i, status = %i, errno = %i",
272b9c1b51eSKate Stone                      pid, child_pid, status, errno);
27330fdc8d8SChris Lattner 
274b9c1b51eSKate Stone     if (child_pid < 0) {
27530fdc8d8SChris Lattner       if (errno == EINTR)
27630fdc8d8SChris Lattner         continue;
27730fdc8d8SChris Lattner       break;
278b9c1b51eSKate Stone     } else {
279b9c1b51eSKate Stone       if (WIFSTOPPED(status)) {
28030fdc8d8SChris Lattner         continue;
281b9c1b51eSKate Stone       } else // if (WIFEXITED(status) || WIFSIGNALED(status))
28230fdc8d8SChris Lattner       {
283b9c1b51eSKate Stone         DNBLogThreadedIf(
284b9c1b51eSKate Stone             LOG_PROCESS,
285b9c1b51eSKate Stone             "waitpid_thread (): setting exit status for pid = %i to %i",
286b9c1b51eSKate Stone             child_pid, status);
28730fdc8d8SChris Lattner         DNBProcessSetExitStatus(child_pid, status);
28830fdc8d8SChris Lattner         return NULL;
28930fdc8d8SChris Lattner       }
29030fdc8d8SChris Lattner     }
29130fdc8d8SChris Lattner   }
29230fdc8d8SChris Lattner 
29330fdc8d8SChris Lattner   // We should never exit as long as our child process is alive, so if we
29430fdc8d8SChris Lattner   // do something else went wrong and we should exit...
295b9c1b51eSKate Stone   DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): main loop exited, setting "
296b9c1b51eSKate Stone                                 "exit status to an invalid value (-1) for pid "
297b9c1b51eSKate Stone                                 "%i",
298b9c1b51eSKate Stone                    pid);
29930fdc8d8SChris Lattner   DNBProcessSetExitStatus(pid, -1);
30030fdc8d8SChris Lattner   return NULL;
30130fdc8d8SChris Lattner }
spawn_waitpid_thread(pid_t pid)302b9c1b51eSKate Stone static bool spawn_waitpid_thread(pid_t pid) {
303a332978bSJason Molenda #ifdef USE_KQUEUE
304a332978bSJason Molenda   bool success = spawn_kqueue_thread(pid);
305a332978bSJason Molenda   if (success)
306a332978bSJason Molenda     return true;
307a332978bSJason Molenda #endif
308a332978bSJason Molenda 
30927148b3dSJason Molenda   pthread_t thread;
310b9c1b51eSKate Stone   int ret =
311b9c1b51eSKate Stone       ::pthread_create(&thread, NULL, waitpid_thread, (void *)(intptr_t)pid);
31227148b3dSJason Molenda   // pthread_create returns 0 if successful
313b9c1b51eSKate Stone   if (ret == 0) {
31430fdc8d8SChris Lattner     ::pthread_detach(thread);
31530fdc8d8SChris Lattner     return true;
31630fdc8d8SChris Lattner   }
31730fdc8d8SChris Lattner   return false;
31830fdc8d8SChris Lattner }
31930fdc8d8SChris Lattner 
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)320b9c1b51eSKate Stone nub_process_t DNBProcessLaunch(
32127012c0fSAlessandro Arzilli     RNBContext *ctx, const char *path, char const *argv[], const char *envp[],
322b9c1b51eSKate Stone     const char *working_directory, // NULL => don't change, non-NULL => set
323b9c1b51eSKate Stone                                    // working directory for inferior to this
324b9c1b51eSKate Stone     const char *stdin_path, const char *stdout_path, const char *stderr_path,
32527012c0fSAlessandro Arzilli     bool no_stdio, int disable_aslr, const char *event_data, char *err_str,
32627012c0fSAlessandro Arzilli     size_t err_len) {
32727012c0fSAlessandro Arzilli   DNBLogThreadedIf(LOG_PROCESS,
32827012c0fSAlessandro Arzilli                    "%s ( path='%s', argv = %p, envp = %p, "
329b9c1b51eSKate Stone                    "working_dir=%s, stdin=%s, stdout=%s, "
330b9c1b51eSKate Stone                    "stderr=%s, no-stdio=%i, launch_flavor = %u, "
331b9c1b51eSKate Stone                    "disable_aslr = %d, err = %p, err_len = "
332bd7ecf4bSSaleem Abdulrasool                    "%llu) called...",
333b9c1b51eSKate Stone                    __FUNCTION__, path, static_cast<void *>(argv),
334b9c1b51eSKate Stone                    static_cast<void *>(envp), working_directory, stdin_path,
33527012c0fSAlessandro Arzilli                    stdout_path, stderr_path, no_stdio, ctx->LaunchFlavor(),
336b9c1b51eSKate Stone                    disable_aslr, static_cast<void *>(err_str),
337b9c1b51eSKate Stone                    static_cast<uint64_t>(err_len));
33830fdc8d8SChris Lattner 
33930fdc8d8SChris Lattner   if (err_str && err_len > 0)
34030fdc8d8SChris Lattner     err_str[0] = '\0';
34130fdc8d8SChris Lattner   struct stat path_stat;
342b9c1b51eSKate Stone   if (::stat(path, &path_stat) == -1) {
34330fdc8d8SChris Lattner     char stat_error[256];
34430fdc8d8SChris Lattner     ::strerror_r(errno, stat_error, sizeof(stat_error));
34530fdc8d8SChris Lattner     snprintf(err_str, err_len, "%s (%s)", stat_error, path);
34630fdc8d8SChris Lattner     return INVALID_NUB_PROCESS;
34730fdc8d8SChris Lattner   }
34830fdc8d8SChris Lattner 
34930fdc8d8SChris Lattner   MachProcessSP processSP(new MachProcess);
350b9c1b51eSKate Stone   if (processSP.get()) {
35130fdc8d8SChris Lattner     DNBError launch_err;
35227012c0fSAlessandro Arzilli     pid_t pid = processSP->LaunchForDebug(
35327012c0fSAlessandro Arzilli         path, argv, envp, working_directory, stdin_path, stdout_path,
35427012c0fSAlessandro Arzilli         stderr_path, no_stdio, ctx->LaunchFlavor(), disable_aslr, event_data,
355*bff4673bSJim Ingham         ctx->GetIgnoredExceptions(), launch_err);
356b9c1b51eSKate Stone     if (err_str) {
35730fdc8d8SChris Lattner       *err_str = '\0';
358b9c1b51eSKate Stone       if (launch_err.Fail()) {
35930fdc8d8SChris Lattner         const char *launch_err_str = launch_err.AsString();
360b9c1b51eSKate Stone         if (launch_err_str) {
361aae5b690SJason Molenda           strlcpy(err_str, launch_err_str, err_len - 1);
362b9c1b51eSKate Stone           err_str[err_len - 1] =
363b9c1b51eSKate Stone               '\0'; // Make sure the error string is terminated
36430fdc8d8SChris Lattner         }
36530fdc8d8SChris Lattner       }
36630fdc8d8SChris Lattner     }
36730fdc8d8SChris Lattner 
36830fdc8d8SChris Lattner     DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) new pid is %d...", pid);
36930fdc8d8SChris Lattner 
370b9c1b51eSKate Stone     if (pid != INVALID_NUB_PROCESS) {
37130fdc8d8SChris Lattner       // Spawn a thread to reap our child inferior process...
37230fdc8d8SChris Lattner       spawn_waitpid_thread(pid);
37330fdc8d8SChris Lattner 
374b9c1b51eSKate Stone       if (processSP->Task().TaskPortForProcessID(launch_err) == TASK_NULL) {
37530fdc8d8SChris Lattner         // We failed to get the task for our process ID which is bad.
376fb640c2dSGreg Clayton         // Kill our process otherwise it will be stopped at the entry
377fb640c2dSGreg Clayton         // point and get reparented to someone else and never go away.
378b9c1b51eSKate Stone         DNBLog("Could not get task port for process, sending SIGKILL and "
379b9c1b51eSKate Stone                "exiting.");
380fb640c2dSGreg Clayton         kill(SIGKILL, pid);
381fb640c2dSGreg Clayton 
382b9c1b51eSKate Stone         if (err_str && err_len > 0) {
383b9c1b51eSKate Stone           if (launch_err.AsString()) {
384b9c1b51eSKate Stone             ::snprintf(err_str, err_len,
385b9c1b51eSKate Stone                        "failed to get the task for process %i (%s)", pid,
386b9c1b51eSKate Stone                        launch_err.AsString());
387b9c1b51eSKate Stone           } else {
388b9c1b51eSKate Stone             ::snprintf(err_str, err_len,
389b9c1b51eSKate Stone                        "failed to get the task for process %i", pid);
39030fdc8d8SChris Lattner           }
39130fdc8d8SChris Lattner         }
392b9c1b51eSKate Stone       } else {
393b786e7d0SCharles Davis         bool res = AddProcessToMap(pid, processSP);
3948a67bf72SBruce Mitchener         UNUSED_IF_ASSERT_DISABLED(res);
395b786e7d0SCharles Davis         assert(res && "Couldn't add process to map!");
39630fdc8d8SChris Lattner         return pid;
39730fdc8d8SChris Lattner       }
39830fdc8d8SChris Lattner     }
39930fdc8d8SChris Lattner   }
40030fdc8d8SChris Lattner   return INVALID_NUB_PROCESS;
40130fdc8d8SChris Lattner }
40230fdc8d8SChris Lattner 
403752e1e83SJason Molenda // If there is one process with a given name, return the pid for that process.
DNBProcessGetPIDByName(const char * name)404b9c1b51eSKate Stone nub_process_t DNBProcessGetPIDByName(const char *name) {
405752e1e83SJason Molenda   std::vector<struct kinfo_proc> matching_proc_infos;
406b9c1b51eSKate Stone   size_t num_matching_proc_infos =
407b9c1b51eSKate Stone       GetAllInfosMatchingName(name, matching_proc_infos);
408b9c1b51eSKate Stone   if (num_matching_proc_infos == 1) {
409752e1e83SJason Molenda     return matching_proc_infos[0].kp_proc.p_pid;
410752e1e83SJason Molenda   }
411752e1e83SJason Molenda   return INVALID_NUB_PROCESS;
412752e1e83SJason Molenda }
413752e1e83SJason Molenda 
DNBProcessAttachByName(const char * name,struct timespec * timeout,const RNBContext::IgnoredExceptions & ignored_exceptions,char * err_str,size_t err_len)414b9c1b51eSKate Stone nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout,
415*bff4673bSJim Ingham                                      const RNBContext::IgnoredExceptions
416*bff4673bSJim Ingham                                              &ignored_exceptions, char *err_str,
41727012c0fSAlessandro Arzilli                                      size_t err_len) {
41830fdc8d8SChris Lattner   if (err_str && err_len > 0)
41930fdc8d8SChris Lattner     err_str[0] = '\0';
42030fdc8d8SChris Lattner   std::vector<struct kinfo_proc> matching_proc_infos;
421b9c1b51eSKate Stone   size_t num_matching_proc_infos =
422b9c1b51eSKate Stone       GetAllInfosMatchingName(name, matching_proc_infos);
423b9c1b51eSKate Stone   if (num_matching_proc_infos == 0) {
42430fdc8d8SChris Lattner     DNBLogError("error: no processes match '%s'\n", name);
42530fdc8d8SChris Lattner     return INVALID_NUB_PROCESS;
4266f9ea260SDavide Italiano   }
4276f9ea260SDavide Italiano   if (num_matching_proc_infos > 1) {
428b9c1b51eSKate Stone     DNBLogError("error: %llu processes match '%s':\n",
429b9c1b51eSKate Stone                 (uint64_t)num_matching_proc_infos, name);
43030fdc8d8SChris Lattner     size_t i;
43130fdc8d8SChris Lattner     for (i = 0; i < num_matching_proc_infos; ++i)
432b9c1b51eSKate Stone       DNBLogError("%6u - %s\n", matching_proc_infos[i].kp_proc.p_pid,
433b9c1b51eSKate Stone                   matching_proc_infos[i].kp_proc.p_comm);
43430fdc8d8SChris Lattner     return INVALID_NUB_PROCESS;
43530fdc8d8SChris Lattner   }
4363af9ea56SGreg Clayton 
437b9c1b51eSKate Stone   return DNBProcessAttach(matching_proc_infos[0].kp_proc.p_pid, timeout,
438*bff4673bSJim Ingham                           ignored_exceptions, err_str, err_len);
43930fdc8d8SChris Lattner }
44030fdc8d8SChris Lattner 
DNBProcessAttach(nub_process_t attach_pid,struct timespec * timeout,const RNBContext::IgnoredExceptions & ignored_exceptions,char * err_str,size_t err_len)441b9c1b51eSKate Stone nub_process_t DNBProcessAttach(nub_process_t attach_pid,
442*bff4673bSJim Ingham                                struct timespec *timeout,
443*bff4673bSJim Ingham                                const RNBContext::IgnoredExceptions
444*bff4673bSJim Ingham                                        &ignored_exceptions,
44527012c0fSAlessandro Arzilli                                char *err_str, size_t err_len) {
44630fdc8d8SChris Lattner   if (err_str && err_len > 0)
44730fdc8d8SChris Lattner     err_str[0] = '\0';
44830fdc8d8SChris Lattner 
44957605758SDavide Italiano   if (getenv("LLDB_DEBUGSERVER_PATH") == NULL) {
45057605758SDavide Italiano     int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID,
45157605758SDavide Italiano                  static_cast<int>(attach_pid)};
45257605758SDavide Italiano     struct kinfo_proc processInfo;
45357605758SDavide Italiano     size_t bufsize = sizeof(processInfo);
45457605758SDavide Italiano     if (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo,
45557605758SDavide Italiano                &bufsize, NULL, 0) == 0 &&
45657605758SDavide Italiano         bufsize > 0) {
45757605758SDavide Italiano 
45857605758SDavide Italiano       if ((processInfo.kp_proc.p_flag & P_TRANSLATED) == P_TRANSLATED) {
45957605758SDavide Italiano         const char *translated_debugserver =
46057605758SDavide Italiano             "/Library/Apple/usr/libexec/oah/debugserver";
46157605758SDavide Italiano         char fdstr[16];
46257605758SDavide Italiano         char pidstr[16];
46357605758SDavide Italiano         extern int communication_fd;
46457605758SDavide Italiano 
46557605758SDavide Italiano         if (communication_fd == -1) {
46657605758SDavide Italiano           fprintf(stderr, "Trying to attach to a translated process with the "
46757605758SDavide Italiano                           "native debugserver, exiting...\n");
46857605758SDavide Italiano           exit(1);
46957605758SDavide Italiano         }
47057605758SDavide Italiano 
47157605758SDavide Italiano         snprintf(fdstr, sizeof(fdstr), "--fd=%d", communication_fd);
47257605758SDavide Italiano         snprintf(pidstr, sizeof(pidstr), "--attach=%d", attach_pid);
47371811048SJonas Devlieghere         execl(translated_debugserver, translated_debugserver, "--native-regs",
47471811048SJonas Devlieghere               "--setsid", fdstr, "--handoff-attach-from-native", pidstr,
47571811048SJonas Devlieghere               (char *)0);
47657605758SDavide Italiano         DNBLogThreadedIf(LOG_PROCESS, "Failed to launch debugserver for "
47757605758SDavide Italiano                          "translated process: ", errno, strerror(errno));
47857605758SDavide Italiano         __builtin_trap();
47957605758SDavide Italiano       }
48057605758SDavide Italiano     }
48157605758SDavide Italiano   }
48257605758SDavide Italiano 
483eb3136f0SAlexandre Perez   if (DNBDebugserverIsTranslated()) {
484eb3136f0SAlexandre Perez     return INVALID_NUB_PROCESS_ARCH;
485eb3136f0SAlexandre Perez   }
486eb3136f0SAlexandre Perez 
48764503c81SJohnny Chen   pid_t pid = INVALID_NUB_PROCESS;
48830fdc8d8SChris Lattner   MachProcessSP processSP(new MachProcess);
489b9c1b51eSKate Stone   if (processSP.get()) {
490b9c1b51eSKate Stone     DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...",
491b9c1b51eSKate Stone                      attach_pid);
49227012c0fSAlessandro Arzilli     pid =
493*bff4673bSJim Ingham         processSP->AttachForDebug(attach_pid, ignored_exceptions, err_str,
494*bff4673bSJim Ingham                                   err_len);
49530fdc8d8SChris Lattner 
496b9c1b51eSKate Stone     if (pid != INVALID_NUB_PROCESS) {
497b786e7d0SCharles Davis       bool res = AddProcessToMap(pid, processSP);
4988a67bf72SBruce Mitchener       UNUSED_IF_ASSERT_DISABLED(res);
499b786e7d0SCharles Davis       assert(res && "Couldn't add process to map!");
50030fdc8d8SChris Lattner       spawn_waitpid_thread(pid);
50130fdc8d8SChris Lattner     }
50230fdc8d8SChris Lattner   }
50330fdc8d8SChris Lattner 
504b9c1b51eSKate Stone   while (pid != INVALID_NUB_PROCESS) {
50530fdc8d8SChris Lattner     // Wait for process to start up and hit entry point
506b9c1b51eSKate Stone     DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, "
507b9c1b51eSKate Stone                                   "eEventProcessRunningStateChanged | "
508b9c1b51eSKate Stone                                   "eEventProcessStoppedStateChanged, true, "
509b9c1b51eSKate Stone                                   "INFINITE)...",
510b9c1b51eSKate Stone                      __FUNCTION__, pid);
511b9c1b51eSKate Stone     nub_event_t set_events =
512b9c1b51eSKate Stone         DNBProcessWaitForEvents(pid, eEventProcessRunningStateChanged |
513b9c1b51eSKate Stone                                          eEventProcessStoppedStateChanged,
514b9c1b51eSKate Stone                                 true, timeout);
5153af9ea56SGreg Clayton 
516b9c1b51eSKate Stone     DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, "
517b9c1b51eSKate Stone                                   "eEventProcessRunningStateChanged | "
518b9c1b51eSKate Stone                                   "eEventProcessStoppedStateChanged, true, "
519b9c1b51eSKate Stone                                   "INFINITE) => 0x%8.8x",
520b9c1b51eSKate Stone                      __FUNCTION__, pid, set_events);
52130fdc8d8SChris Lattner 
522b9c1b51eSKate Stone     if (set_events == 0) {
52330fdc8d8SChris Lattner       if (err_str && err_len > 0)
52430fdc8d8SChris Lattner         snprintf(err_str, err_len, "operation timed out");
52530fdc8d8SChris Lattner       pid = INVALID_NUB_PROCESS;
526b9c1b51eSKate Stone     } else {
527b9c1b51eSKate Stone       if (set_events & (eEventProcessRunningStateChanged |
528b9c1b51eSKate Stone                         eEventProcessStoppedStateChanged)) {
52930fdc8d8SChris Lattner         nub_state_t pid_state = DNBProcessGetState(pid);
530b9c1b51eSKate Stone         DNBLogThreadedIf(
531b9c1b51eSKate Stone             LOG_PROCESS,
532b9c1b51eSKate Stone             "%s process %4.4x state changed (eEventProcessStateChanged): %s",
53330fdc8d8SChris Lattner             __FUNCTION__, pid, DNBStateAsString(pid_state));
53430fdc8d8SChris Lattner 
535b9c1b51eSKate Stone         switch (pid_state) {
53630fdc8d8SChris Lattner         case eStateInvalid:
53730fdc8d8SChris Lattner         case eStateUnloaded:
53830fdc8d8SChris Lattner         case eStateAttaching:
53930fdc8d8SChris Lattner         case eStateLaunching:
54030fdc8d8SChris Lattner         case eStateSuspended:
54130fdc8d8SChris Lattner           break; // Ignore
54230fdc8d8SChris Lattner 
54330fdc8d8SChris Lattner         case eStateRunning:
54430fdc8d8SChris Lattner         case eStateStepping:
54530fdc8d8SChris Lattner           // Still waiting to stop at entry point...
54630fdc8d8SChris Lattner           break;
54730fdc8d8SChris Lattner 
54830fdc8d8SChris Lattner         case eStateStopped:
54930fdc8d8SChris Lattner         case eStateCrashed:
55030fdc8d8SChris Lattner           return pid;
5513af9ea56SGreg Clayton 
55230fdc8d8SChris Lattner         case eStateDetached:
55330fdc8d8SChris Lattner         case eStateExited:
55430fdc8d8SChris Lattner           if (err_str && err_len > 0)
55530fdc8d8SChris Lattner             snprintf(err_str, err_len, "process exited");
55630fdc8d8SChris Lattner           return INVALID_NUB_PROCESS;
55730fdc8d8SChris Lattner         }
55830fdc8d8SChris Lattner       }
55930fdc8d8SChris Lattner 
56030fdc8d8SChris Lattner       DNBProcessResetEvents(pid, set_events);
56130fdc8d8SChris Lattner     }
56230fdc8d8SChris Lattner   }
56330fdc8d8SChris Lattner 
56430fdc8d8SChris Lattner   return INVALID_NUB_PROCESS;
56530fdc8d8SChris Lattner }
56630fdc8d8SChris Lattner 
DNBGetAllInfos(std::vector<struct kinfo_proc> & proc_infos)567843a0f97SJason Molenda size_t DNBGetAllInfos(std::vector<struct kinfo_proc> &proc_infos) {
5689eb4e038SGreg Clayton   size_t size = 0;
56930fdc8d8SChris Lattner   int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
570c1fdb889SJim Ingham   u_int namelen = sizeof(name) / sizeof(int);
57130fdc8d8SChris Lattner   int err;
57230fdc8d8SChris Lattner 
57330fdc8d8SChris Lattner   // Try to find out how many processes are around so we can
57430fdc8d8SChris Lattner   // size the buffer appropriately.  sysctl's man page specifically suggests
57530fdc8d8SChris Lattner   // this approach, and says it returns a bit larger size than needed to
57630fdc8d8SChris Lattner   // handle any new processes created between then and now.
57730fdc8d8SChris Lattner 
57830fdc8d8SChris Lattner   err = ::sysctl(name, namelen, NULL, &size, NULL, 0);
57930fdc8d8SChris Lattner 
580b9c1b51eSKate Stone   if ((err < 0) && (err != ENOMEM)) {
58130fdc8d8SChris Lattner     proc_infos.clear();
58230fdc8d8SChris Lattner     perror("sysctl (mib, miblen, NULL, &num_processes, NULL, 0)");
58330fdc8d8SChris Lattner     return 0;
58430fdc8d8SChris Lattner   }
58530fdc8d8SChris Lattner 
58630fdc8d8SChris Lattner   // Increase the size of the buffer by a few processes in case more have
58730fdc8d8SChris Lattner   // been spawned
58830fdc8d8SChris Lattner   proc_infos.resize(size / sizeof(struct kinfo_proc));
589b9c1b51eSKate Stone   size = proc_infos.size() *
590b9c1b51eSKate Stone          sizeof(struct kinfo_proc); // Make sure we don't exceed our resize...
59130fdc8d8SChris Lattner   err = ::sysctl(name, namelen, &proc_infos[0], &size, NULL, 0);
592b9c1b51eSKate Stone   if (err < 0) {
59330fdc8d8SChris Lattner     proc_infos.clear();
59430fdc8d8SChris Lattner     return 0;
59530fdc8d8SChris Lattner   }
59630fdc8d8SChris Lattner 
59730fdc8d8SChris Lattner   // Trim down our array to fit what we actually got back
59830fdc8d8SChris Lattner   proc_infos.resize(size / sizeof(struct kinfo_proc));
59930fdc8d8SChris Lattner   return proc_infos.size();
60030fdc8d8SChris Lattner }
60130fdc8d8SChris Lattner 
60230fdc8d8SChris Lattner static size_t
GetAllInfosMatchingName(const char * full_process_name,std::vector<struct kinfo_proc> & matching_proc_infos)603b9c1b51eSKate Stone GetAllInfosMatchingName(const char *full_process_name,
604b9c1b51eSKate Stone                         std::vector<struct kinfo_proc> &matching_proc_infos) {
60530fdc8d8SChris Lattner 
60630fdc8d8SChris Lattner   matching_proc_infos.clear();
607b9c1b51eSKate Stone   if (full_process_name && full_process_name[0]) {
608b9c1b51eSKate Stone     // We only get the process name, not the full path, from the proc_info.  So
609b9c1b51eSKate Stone     // just take the
61030fdc8d8SChris Lattner     // base name of the process name...
61130fdc8d8SChris Lattner     const char *process_name;
61230fdc8d8SChris Lattner     process_name = strrchr(full_process_name, '/');
61330fdc8d8SChris Lattner     if (process_name == NULL)
61430fdc8d8SChris Lattner       process_name = full_process_name;
61530fdc8d8SChris Lattner     else
61630fdc8d8SChris Lattner       process_name++;
61730fdc8d8SChris Lattner 
618ee2ed525SGreg Clayton     const size_t process_name_len = strlen(process_name);
61930fdc8d8SChris Lattner     std::vector<struct kinfo_proc> proc_infos;
620843a0f97SJason Molenda     const size_t num_proc_infos = DNBGetAllInfos(proc_infos);
621b9c1b51eSKate Stone     if (num_proc_infos > 0) {
62230fdc8d8SChris Lattner       uint32_t i;
623b9c1b51eSKate Stone       for (i = 0; i < num_proc_infos; i++) {
62430fdc8d8SChris Lattner         // Skip zombie processes and processes with unset status
625b9c1b51eSKate Stone         if (proc_infos[i].kp_proc.p_stat == 0 ||
626b9c1b51eSKate Stone             proc_infos[i].kp_proc.p_stat == SZOMB)
62730fdc8d8SChris Lattner           continue;
62830fdc8d8SChris Lattner 
62930fdc8d8SChris Lattner         // Check for process by name. We only check the first MAXCOMLEN
63030fdc8d8SChris Lattner         // chars as that is all that kp_proc.p_comm holds.
631490bccd6SJim Ingham 
632b9c1b51eSKate Stone         if (::strncasecmp(process_name, proc_infos[i].kp_proc.p_comm,
633b9c1b51eSKate Stone                           MAXCOMLEN) == 0) {
634b9c1b51eSKate Stone           if (process_name_len > MAXCOMLEN) {
6357dab2be2SGreg Clayton             // We found a matching process name whose first MAXCOMLEN
6367dab2be2SGreg Clayton             // characters match, but there is more to the name than
637b9c1b51eSKate Stone             // this. We need to get the full process name.  Use proc_pidpath,
638b9c1b51eSKate Stone             // which will get
639490bccd6SJim Ingham             // us the full path to the executed process.
6407dab2be2SGreg Clayton 
641490bccd6SJim Ingham             char proc_path_buf[PATH_MAX];
6427dab2be2SGreg Clayton 
643b9c1b51eSKate Stone             int return_val = proc_pidpath(proc_infos[i].kp_proc.p_pid,
644b9c1b51eSKate Stone                                           proc_path_buf, PATH_MAX);
645b9c1b51eSKate Stone             if (return_val > 0) {
646490bccd6SJim Ingham               // Okay, now search backwards from that to see if there is a
647b9c1b51eSKate Stone               // slash in the name.  Note, even though we got all the args we
648b9c1b51eSKate Stone               // don't care
649b9c1b51eSKate Stone               // because the list data is just a bunch of concatenated null
650b9c1b51eSKate Stone               // terminated strings
651490bccd6SJim Ingham               // so strrchr will start from the end of argv0.
652490bccd6SJim Ingham 
653490bccd6SJim Ingham               const char *argv_basename = strrchr(proc_path_buf, '/');
654b9c1b51eSKate Stone               if (argv_basename) {
6557dab2be2SGreg Clayton                 // Skip the '/'
6567dab2be2SGreg Clayton                 ++argv_basename;
657b9c1b51eSKate Stone               } else {
658b9c1b51eSKate Stone                 // We didn't find a directory delimiter in the process argv[0],
659b9c1b51eSKate Stone                 // just use what was in there
660490bccd6SJim Ingham                 argv_basename = proc_path_buf;
6617dab2be2SGreg Clayton               }
6627dab2be2SGreg Clayton 
663b9c1b51eSKate Stone               if (argv_basename) {
664b9c1b51eSKate Stone                 if (::strncasecmp(process_name, argv_basename, PATH_MAX) == 0) {
6657dab2be2SGreg Clayton                   matching_proc_infos.push_back(proc_infos[i]);
6667dab2be2SGreg Clayton                 }
6677dab2be2SGreg Clayton               }
6687dab2be2SGreg Clayton             }
669b9c1b51eSKate Stone           } else {
67030fdc8d8SChris Lattner             // We found a matching process, add it to our list
67130fdc8d8SChris Lattner             matching_proc_infos.push_back(proc_infos[i]);
67230fdc8d8SChris Lattner           }
67330fdc8d8SChris Lattner         }
67430fdc8d8SChris Lattner       }
67530fdc8d8SChris Lattner     }
6767dab2be2SGreg Clayton   }
67730fdc8d8SChris Lattner   // return the newly added matches.
67830fdc8d8SChris Lattner   return matching_proc_infos.size();
67930fdc8d8SChris Lattner }
68030fdc8d8SChris Lattner 
68127012c0fSAlessandro Arzilli 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)68227012c0fSAlessandro Arzilli DNBProcessAttachWait(RNBContext *ctx, const char *waitfor_process_name,
683b9c1b51eSKate Stone                      bool ignore_existing, struct timespec *timeout_abstime,
684b9c1b51eSKate Stone                      useconds_t waitfor_interval, char *err_str, size_t err_len,
68527012c0fSAlessandro Arzilli                      DNBShouldCancelCallback should_cancel_callback,
68627012c0fSAlessandro Arzilli                      void *callback_data) {
68730fdc8d8SChris Lattner   DNBError prepare_error;
68830fdc8d8SChris Lattner   std::vector<struct kinfo_proc> exclude_proc_infos;
68930fdc8d8SChris Lattner   size_t num_exclude_proc_infos;
69030fdc8d8SChris Lattner 
69127012c0fSAlessandro Arzilli   nub_launch_flavor_t launch_flavor = ctx->LaunchFlavor();
69227012c0fSAlessandro Arzilli 
69330fdc8d8SChris Lattner   // If the PrepareForAttach returns a valid token, use  MachProcess to check
69430fdc8d8SChris Lattner   // for the process, otherwise scan the process table.
69530fdc8d8SChris Lattner 
696b9c1b51eSKate Stone   const void *attach_token = MachProcess::PrepareForAttach(
697b9c1b51eSKate Stone       waitfor_process_name, launch_flavor, true, prepare_error);
69830fdc8d8SChris Lattner 
699b9c1b51eSKate Stone   if (prepare_error.Fail()) {
70030fdc8d8SChris Lattner     DNBLogError("Error in PrepareForAttach: %s", prepare_error.AsString());
70130fdc8d8SChris Lattner     return INVALID_NUB_PROCESS;
70230fdc8d8SChris Lattner   }
70330fdc8d8SChris Lattner 
704b9c1b51eSKate Stone   if (attach_token == NULL) {
705cd16df91SJim Ingham     if (ignore_existing)
706b9c1b51eSKate Stone       num_exclude_proc_infos =
707b9c1b51eSKate Stone           GetAllInfosMatchingName(waitfor_process_name, exclude_proc_infos);
708cd16df91SJim Ingham     else
709cd16df91SJim Ingham       num_exclude_proc_infos = 0;
710cd16df91SJim Ingham   }
71130fdc8d8SChris Lattner 
712b9c1b51eSKate Stone   DNBLogThreadedIf(LOG_PROCESS, "Waiting for '%s' to appear...\n",
713b9c1b51eSKate Stone                    waitfor_process_name);
71430fdc8d8SChris Lattner 
71530fdc8d8SChris Lattner   // Loop and try to find the process by name
71630fdc8d8SChris Lattner   nub_process_t waitfor_pid = INVALID_NUB_PROCESS;
71730fdc8d8SChris Lattner 
718b9c1b51eSKate Stone   while (waitfor_pid == INVALID_NUB_PROCESS) {
719b9c1b51eSKate Stone     if (attach_token != NULL) {
72030fdc8d8SChris Lattner       nub_process_t pid;
721c611a740SJason Molenda       pid = MachProcess::CheckForProcess(attach_token, launch_flavor);
722b9c1b51eSKate Stone       if (pid != INVALID_NUB_PROCESS) {
72330fdc8d8SChris Lattner         waitfor_pid = pid;
72430fdc8d8SChris Lattner         break;
72530fdc8d8SChris Lattner       }
726b9c1b51eSKate Stone     } else {
72730fdc8d8SChris Lattner 
72830fdc8d8SChris Lattner       // Get the current process list, and check for matches that
72930fdc8d8SChris Lattner       // aren't in our original list. If anyone wants to attach
73030fdc8d8SChris Lattner       // to an existing process by name, they should do it with
73130fdc8d8SChris Lattner       // --attach=PROCNAME. Else we will wait for the first matching
73230fdc8d8SChris Lattner       // process that wasn't in our exclusion list.
73330fdc8d8SChris Lattner       std::vector<struct kinfo_proc> proc_infos;
734b9c1b51eSKate Stone       const size_t num_proc_infos =
735b9c1b51eSKate Stone           GetAllInfosMatchingName(waitfor_process_name, proc_infos);
736b9c1b51eSKate Stone       for (size_t i = 0; i < num_proc_infos; i++) {
73730fdc8d8SChris Lattner         nub_process_t curr_pid = proc_infos[i].kp_proc.p_pid;
738b9c1b51eSKate Stone         for (size_t j = 0; j < num_exclude_proc_infos; j++) {
739b9c1b51eSKate Stone           if (curr_pid == exclude_proc_infos[j].kp_proc.p_pid) {
74030fdc8d8SChris Lattner             // This process was in our exclusion list, don't use it.
74130fdc8d8SChris Lattner             curr_pid = INVALID_NUB_PROCESS;
74230fdc8d8SChris Lattner             break;
74330fdc8d8SChris Lattner           }
74430fdc8d8SChris Lattner         }
74530fdc8d8SChris Lattner 
74630fdc8d8SChris Lattner         // If we didn't find CURR_PID in our exclusion list, then use it.
747b9c1b51eSKate Stone         if (curr_pid != INVALID_NUB_PROCESS) {
74830fdc8d8SChris Lattner           // We found our process!
74930fdc8d8SChris Lattner           waitfor_pid = curr_pid;
75030fdc8d8SChris Lattner           break;
75130fdc8d8SChris Lattner         }
75230fdc8d8SChris Lattner       }
75330fdc8d8SChris Lattner     }
75430fdc8d8SChris Lattner 
75530fdc8d8SChris Lattner     // If we haven't found our process yet, check for a timeout
75630fdc8d8SChris Lattner     // and then sleep for a bit until we poll again.
757b9c1b51eSKate Stone     if (waitfor_pid == INVALID_NUB_PROCESS) {
758b9c1b51eSKate Stone       if (timeout_abstime != NULL) {
75930fdc8d8SChris Lattner         // Check to see if we have a waitfor-duration option that
76030fdc8d8SChris Lattner         // has timed out?
761b9c1b51eSKate Stone         if (DNBTimer::TimeOfDayLaterThan(*timeout_abstime)) {
76230fdc8d8SChris Lattner           if (err_str && err_len > 0)
76330fdc8d8SChris Lattner             snprintf(err_str, err_len, "operation timed out");
764b9c1b51eSKate Stone           DNBLogError("error: waiting for process '%s' timed out.\n",
765b9c1b51eSKate Stone                       waitfor_process_name);
76630fdc8d8SChris Lattner           return INVALID_NUB_PROCESS;
76730fdc8d8SChris Lattner         }
76830fdc8d8SChris Lattner       }
76930fdc8d8SChris Lattner 
77030fdc8d8SChris Lattner       // Call the should cancel callback as well...
77130fdc8d8SChris Lattner 
772b9c1b51eSKate Stone       if (should_cancel_callback != NULL &&
773b9c1b51eSKate Stone           should_cancel_callback(callback_data)) {
774b9c1b51eSKate Stone         DNBLogThreadedIf(
775b9c1b51eSKate Stone             LOG_PROCESS,
776b9c1b51eSKate Stone             "DNBProcessAttachWait cancelled by should_cancel callback.");
77730fdc8d8SChris Lattner         waitfor_pid = INVALID_NUB_PROCESS;
77830fdc8d8SChris Lattner         break;
77930fdc8d8SChris Lattner       }
78030fdc8d8SChris Lattner 
78130fdc8d8SChris Lattner       ::usleep(waitfor_interval); // Sleep for WAITFOR_INTERVAL, then poll again
78230fdc8d8SChris Lattner     }
78330fdc8d8SChris Lattner   }
78430fdc8d8SChris Lattner 
785b9c1b51eSKate Stone   if (waitfor_pid != INVALID_NUB_PROCESS) {
786b9c1b51eSKate Stone     DNBLogThreadedIf(LOG_PROCESS, "Attaching to %s with pid %i...\n",
787b9c1b51eSKate Stone                      waitfor_process_name, waitfor_pid);
78827012c0fSAlessandro Arzilli     waitfor_pid = DNBProcessAttach(waitfor_pid, timeout_abstime,
789*bff4673bSJim Ingham                                    ctx->GetIgnoredExceptions(), err_str,
790*bff4673bSJim Ingham                                    err_len);
79130fdc8d8SChris Lattner   }
79230fdc8d8SChris Lattner 
79330fdc8d8SChris Lattner   bool success = waitfor_pid != INVALID_NUB_PROCESS;
794b9c1b51eSKate Stone   MachProcess::CleanupAfterAttach(attach_token, launch_flavor, success,
795b9c1b51eSKate Stone                                   prepare_error);
79630fdc8d8SChris Lattner 
79730fdc8d8SChris Lattner   return waitfor_pid;
79830fdc8d8SChris Lattner }
79930fdc8d8SChris Lattner 
DNBProcessDetach(nub_process_t pid)800b9c1b51eSKate Stone nub_bool_t DNBProcessDetach(nub_process_t pid) {
80130fdc8d8SChris Lattner   MachProcessSP procSP;
802b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
8035881318cSJim Ingham     const bool remove = true;
804b9c1b51eSKate Stone     DNBLogThreaded(
805b9c1b51eSKate Stone         "Disabling breakpoints and watchpoints, and detaching from %d.", pid);
8065881318cSJim Ingham     procSP->DisableAllBreakpoints(remove);
8075881318cSJim Ingham     procSP->DisableAllWatchpoints(remove);
80830fdc8d8SChris Lattner     return procSP->Detach();
80930fdc8d8SChris Lattner   }
81030fdc8d8SChris Lattner   return false;
81130fdc8d8SChris Lattner }
81230fdc8d8SChris Lattner 
DNBProcessKill(nub_process_t pid)813b9c1b51eSKate Stone nub_bool_t DNBProcessKill(nub_process_t pid) {
81430fdc8d8SChris Lattner   MachProcessSP procSP;
815b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
81630fdc8d8SChris Lattner     return procSP->Kill();
81730fdc8d8SChris Lattner   }
81830fdc8d8SChris Lattner   return false;
81930fdc8d8SChris Lattner }
82030fdc8d8SChris Lattner 
DNBProcessSignal(nub_process_t pid,int signal)821b9c1b51eSKate Stone nub_bool_t DNBProcessSignal(nub_process_t pid, int signal) {
82230fdc8d8SChris Lattner   MachProcessSP procSP;
823b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
82430fdc8d8SChris Lattner     return procSP->Signal(signal);
82530fdc8d8SChris Lattner   }
82630fdc8d8SChris Lattner   return false;
82730fdc8d8SChris Lattner }
82830fdc8d8SChris Lattner 
DNBProcessInterrupt(nub_process_t pid)829b9c1b51eSKate Stone nub_bool_t DNBProcessInterrupt(nub_process_t pid) {
8304296c221SGreg Clayton   MachProcessSP procSP;
8314296c221SGreg Clayton   if (GetProcessSP(pid, procSP))
8324296c221SGreg Clayton     return procSP->Interrupt();
8334296c221SGreg Clayton   return false;
8344296c221SGreg Clayton }
8354296c221SGreg Clayton 
DNBProcessSendEvent(nub_process_t pid,const char * event)836b9c1b51eSKate Stone nub_bool_t DNBProcessSendEvent(nub_process_t pid, const char *event) {
837a332978bSJason Molenda   MachProcessSP procSP;
838b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
839a332978bSJason Molenda     // FIXME: Do something with the error...
840a332978bSJason Molenda     DNBError send_error;
841a332978bSJason Molenda     return procSP->SendEvent(event, send_error);
842a332978bSJason Molenda   }
843a332978bSJason Molenda   return false;
844a332978bSJason Molenda }
845a332978bSJason Molenda 
DNBProcessIsAlive(nub_process_t pid)846b9c1b51eSKate Stone nub_bool_t DNBProcessIsAlive(nub_process_t pid) {
84730fdc8d8SChris Lattner   MachProcessSP procSP;
848b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
84930fdc8d8SChris Lattner     return MachTask::IsValid(procSP->Task().TaskPort());
85030fdc8d8SChris Lattner   }
85130fdc8d8SChris Lattner   return eStateInvalid;
85230fdc8d8SChris Lattner }
85330fdc8d8SChris Lattner 
85430fdc8d8SChris Lattner // Process and Thread state information
DNBProcessGetState(nub_process_t pid)855b9c1b51eSKate Stone nub_state_t DNBProcessGetState(nub_process_t pid) {
85630fdc8d8SChris Lattner   MachProcessSP procSP;
857b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
85830fdc8d8SChris Lattner     return procSP->GetState();
85930fdc8d8SChris Lattner   }
86030fdc8d8SChris Lattner   return eStateInvalid;
86130fdc8d8SChris Lattner }
86230fdc8d8SChris Lattner 
86330fdc8d8SChris Lattner // Process and Thread state information
DNBProcessGetExitStatus(nub_process_t pid,int * status)864b9c1b51eSKate Stone nub_bool_t DNBProcessGetExitStatus(nub_process_t pid, int *status) {
86530fdc8d8SChris Lattner   MachProcessSP procSP;
866b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
86730fdc8d8SChris Lattner     return procSP->GetExitStatus(status);
86830fdc8d8SChris Lattner   }
86930fdc8d8SChris Lattner   return false;
87030fdc8d8SChris Lattner }
87130fdc8d8SChris Lattner 
DNBProcessSetExitStatus(nub_process_t pid,int status)872b9c1b51eSKate Stone nub_bool_t DNBProcessSetExitStatus(nub_process_t pid, int status) {
87330fdc8d8SChris Lattner   MachProcessSP procSP;
874b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
87530fdc8d8SChris Lattner     procSP->SetExitStatus(status);
87630fdc8d8SChris Lattner     return true;
87730fdc8d8SChris Lattner   }
87830fdc8d8SChris Lattner   return false;
87930fdc8d8SChris Lattner }
88030fdc8d8SChris Lattner 
DNBProcessGetExitInfo(nub_process_t pid)881b9c1b51eSKate Stone const char *DNBProcessGetExitInfo(nub_process_t pid) {
882a332978bSJason Molenda   MachProcessSP procSP;
883b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
884a332978bSJason Molenda     return procSP->GetExitInfo();
885a332978bSJason Molenda   }
886a332978bSJason Molenda   return NULL;
887a332978bSJason Molenda }
888a332978bSJason Molenda 
DNBProcessSetExitInfo(nub_process_t pid,const char * info)889b9c1b51eSKate Stone nub_bool_t DNBProcessSetExitInfo(nub_process_t pid, const char *info) {
890a332978bSJason Molenda   MachProcessSP procSP;
891b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
892a332978bSJason Molenda     procSP->SetExitInfo(info);
893a332978bSJason Molenda     return true;
894a332978bSJason Molenda   }
895a332978bSJason Molenda   return false;
896a332978bSJason Molenda }
89730fdc8d8SChris Lattner 
DNBThreadGetName(nub_process_t pid,nub_thread_t tid)898b9c1b51eSKate Stone const char *DNBThreadGetName(nub_process_t pid, nub_thread_t tid) {
89930fdc8d8SChris Lattner   MachProcessSP procSP;
90030fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
90130fdc8d8SChris Lattner     return procSP->ThreadGetName(tid);
90230fdc8d8SChris Lattner   return NULL;
90330fdc8d8SChris Lattner }
90430fdc8d8SChris Lattner 
90530fdc8d8SChris Lattner nub_bool_t
DNBThreadGetIdentifierInfo(nub_process_t pid,nub_thread_t tid,thread_identifier_info_data_t * ident_info)906b9c1b51eSKate Stone DNBThreadGetIdentifierInfo(nub_process_t pid, nub_thread_t tid,
907b9c1b51eSKate Stone                            thread_identifier_info_data_t *ident_info) {
90830fdc8d8SChris Lattner   MachProcessSP procSP;
90930fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
91030fdc8d8SChris Lattner     return procSP->GetThreadList().GetIdentifierInfo(tid, ident_info);
91130fdc8d8SChris Lattner   return false;
91230fdc8d8SChris Lattner }
91330fdc8d8SChris Lattner 
DNBThreadGetState(nub_process_t pid,nub_thread_t tid)914b9c1b51eSKate Stone nub_state_t DNBThreadGetState(nub_process_t pid, nub_thread_t tid) {
91530fdc8d8SChris Lattner   MachProcessSP procSP;
916b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
91730fdc8d8SChris Lattner     return procSP->ThreadGetState(tid);
91830fdc8d8SChris Lattner   }
91930fdc8d8SChris Lattner   return eStateInvalid;
92030fdc8d8SChris Lattner }
92130fdc8d8SChris Lattner 
DNBStateAsString(nub_state_t state)922b9c1b51eSKate Stone const char *DNBStateAsString(nub_state_t state) {
923b9c1b51eSKate Stone   switch (state) {
924b9c1b51eSKate Stone   case eStateInvalid:
925b9c1b51eSKate Stone     return "Invalid";
926b9c1b51eSKate Stone   case eStateUnloaded:
927b9c1b51eSKate Stone     return "Unloaded";
928b9c1b51eSKate Stone   case eStateAttaching:
929b9c1b51eSKate Stone     return "Attaching";
930b9c1b51eSKate Stone   case eStateLaunching:
931b9c1b51eSKate Stone     return "Launching";
932b9c1b51eSKate Stone   case eStateStopped:
933b9c1b51eSKate Stone     return "Stopped";
934b9c1b51eSKate Stone   case eStateRunning:
935b9c1b51eSKate Stone     return "Running";
936b9c1b51eSKate Stone   case eStateStepping:
937b9c1b51eSKate Stone     return "Stepping";
938b9c1b51eSKate Stone   case eStateCrashed:
939b9c1b51eSKate Stone     return "Crashed";
940b9c1b51eSKate Stone   case eStateDetached:
941b9c1b51eSKate Stone     return "Detached";
942b9c1b51eSKate Stone   case eStateExited:
943b9c1b51eSKate Stone     return "Exited";
944b9c1b51eSKate Stone   case eStateSuspended:
945b9c1b51eSKate Stone     return "Suspended";
94630fdc8d8SChris Lattner   }
94730fdc8d8SChris Lattner   return "nub_state_t ???";
94830fdc8d8SChris Lattner }
94930fdc8d8SChris Lattner 
DNBGetGenealogyInfoForThread(nub_process_t pid,nub_thread_t tid,bool & timed_out)950b9c1b51eSKate Stone Genealogy::ThreadActivitySP DNBGetGenealogyInfoForThread(nub_process_t pid,
951b9c1b51eSKate Stone                                                          nub_thread_t tid,
952b9c1b51eSKate Stone                                                          bool &timed_out) {
953705b1809SJason Molenda   Genealogy::ThreadActivitySP thread_activity_sp;
954705b1809SJason Molenda   MachProcessSP procSP;
955705b1809SJason Molenda   if (GetProcessSP(pid, procSP))
956705b1809SJason Molenda     thread_activity_sp = procSP->GetGenealogyInfoForThread(tid, timed_out);
957705b1809SJason Molenda   return thread_activity_sp;
958705b1809SJason Molenda }
959705b1809SJason Molenda 
DNBGetGenealogyImageInfo(nub_process_t pid,size_t idx)960b9c1b51eSKate Stone Genealogy::ProcessExecutableInfoSP DNBGetGenealogyImageInfo(nub_process_t pid,
961b9c1b51eSKate Stone                                                             size_t idx) {
962705b1809SJason Molenda   Genealogy::ProcessExecutableInfoSP image_info_sp;
963705b1809SJason Molenda   MachProcessSP procSP;
964b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
965705b1809SJason Molenda     image_info_sp = procSP->GetGenealogyImageInfo(idx);
966705b1809SJason Molenda   }
967705b1809SJason Molenda   return image_info_sp;
968705b1809SJason Molenda }
969705b1809SJason Molenda 
DNBGetRequestedQoSForThread(nub_process_t pid,nub_thread_t tid,nub_addr_t tsd,uint64_t dti_qos_class_index)970b9c1b51eSKate Stone ThreadInfo::QoS DNBGetRequestedQoSForThread(nub_process_t pid, nub_thread_t tid,
971b9c1b51eSKate Stone                                             nub_addr_t tsd,
972b9c1b51eSKate Stone                                             uint64_t dti_qos_class_index) {
973705b1809SJason Molenda   MachProcessSP procSP;
974b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
975705b1809SJason Molenda     return procSP->GetRequestedQoS(tid, tsd, dti_qos_class_index);
976705b1809SJason Molenda   }
977705b1809SJason Molenda   return ThreadInfo::QoS();
978705b1809SJason Molenda }
979705b1809SJason Molenda 
DNBGetPThreadT(nub_process_t pid,nub_thread_t tid)980b9c1b51eSKate Stone nub_addr_t DNBGetPThreadT(nub_process_t pid, nub_thread_t tid) {
981705b1809SJason Molenda   MachProcessSP procSP;
982b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
983705b1809SJason Molenda     return procSP->GetPThreadT(tid);
984705b1809SJason Molenda   }
985705b1809SJason Molenda   return INVALID_NUB_ADDRESS;
986705b1809SJason Molenda }
987705b1809SJason Molenda 
DNBGetDispatchQueueT(nub_process_t pid,nub_thread_t tid)988b9c1b51eSKate Stone nub_addr_t DNBGetDispatchQueueT(nub_process_t pid, nub_thread_t tid) {
989705b1809SJason Molenda   MachProcessSP procSP;
990b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
991705b1809SJason Molenda     return procSP->GetDispatchQueueT(tid);
992705b1809SJason Molenda   }
993705b1809SJason Molenda   return INVALID_NUB_ADDRESS;
994705b1809SJason Molenda }
995705b1809SJason Molenda 
996705b1809SJason Molenda 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)997b9c1b51eSKate Stone DNBGetTSDAddressForThread(nub_process_t pid, nub_thread_t tid,
998b9c1b51eSKate Stone                           uint64_t plo_pthread_tsd_base_address_offset,
999b9c1b51eSKate Stone                           uint64_t plo_pthread_tsd_base_offset,
1000b9c1b51eSKate Stone                           uint64_t plo_pthread_tsd_entry_size) {
1001705b1809SJason Molenda   MachProcessSP procSP;
1002b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
1003b9c1b51eSKate Stone     return procSP->GetTSDAddressForThread(
1004b9c1b51eSKate Stone         tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset,
1005b9c1b51eSKate Stone         plo_pthread_tsd_entry_size);
1006705b1809SJason Molenda   }
1007705b1809SJason Molenda   return INVALID_NUB_ADDRESS;
1008705b1809SJason Molenda }
1009705b1809SJason Molenda 
DNBGetLoadedDynamicLibrariesInfos(nub_process_t pid,nub_addr_t image_list_address,nub_addr_t image_count)1010b9c1b51eSKate Stone JSONGenerator::ObjectSP DNBGetLoadedDynamicLibrariesInfos(
1011b9c1b51eSKate Stone     nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count) {
101220ee21bdSJason Molenda   MachProcessSP procSP;
1013b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
1014b9c1b51eSKate Stone     return procSP->GetLoadedDynamicLibrariesInfos(pid, image_list_address,
1015b9c1b51eSKate Stone                                                   image_count);
101620ee21bdSJason Molenda   }
101720ee21bdSJason Molenda   return JSONGenerator::ObjectSP();
101820ee21bdSJason Molenda }
101920ee21bdSJason Molenda 
DNBGetAllLoadedLibrariesInfos(nub_process_t pid)1020b9c1b51eSKate Stone JSONGenerator::ObjectSP DNBGetAllLoadedLibrariesInfos(nub_process_t pid) {
1021a2992311SJason Molenda   MachProcessSP procSP;
1022b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
1023a2992311SJason Molenda     return procSP->GetAllLoadedLibrariesInfos(pid);
1024a2992311SJason Molenda   }
1025a2992311SJason Molenda   return JSONGenerator::ObjectSP();
1026a2992311SJason Molenda }
1027a2992311SJason Molenda 
1028a2992311SJason Molenda JSONGenerator::ObjectSP
DNBGetLibrariesInfoForAddresses(nub_process_t pid,std::vector<uint64_t> & macho_addresses)1029b9c1b51eSKate Stone DNBGetLibrariesInfoForAddresses(nub_process_t pid,
1030b9c1b51eSKate Stone                                 std::vector<uint64_t> &macho_addresses) {
1031a2992311SJason Molenda   MachProcessSP procSP;
1032b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
1033a2992311SJason Molenda     return procSP->GetLibrariesInfoForAddresses(pid, macho_addresses);
1034a2992311SJason Molenda   }
1035a2992311SJason Molenda   return JSONGenerator::ObjectSP();
1036a2992311SJason Molenda }
1037a2992311SJason Molenda 
DNBGetSharedCacheInfo(nub_process_t pid)1038b9c1b51eSKate Stone JSONGenerator::ObjectSP DNBGetSharedCacheInfo(nub_process_t pid) {
1039a2992311SJason Molenda   MachProcessSP procSP;
1040b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
1041a2992311SJason Molenda     return procSP->GetSharedCacheInfo(pid);
1042a2992311SJason Molenda   }
1043a2992311SJason Molenda   return JSONGenerator::ObjectSP();
1044a2992311SJason Molenda }
1045a2992311SJason Molenda 
DNBProcessGetExecutablePath(nub_process_t pid)1046b9c1b51eSKate Stone const char *DNBProcessGetExecutablePath(nub_process_t pid) {
104730fdc8d8SChris Lattner   MachProcessSP procSP;
1048b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
104930fdc8d8SChris Lattner     return procSP->Path();
105030fdc8d8SChris Lattner   }
105130fdc8d8SChris Lattner   return NULL;
105230fdc8d8SChris Lattner }
105330fdc8d8SChris Lattner 
DNBProcessGetArgumentCount(nub_process_t pid)1054b9c1b51eSKate Stone nub_size_t DNBProcessGetArgumentCount(nub_process_t pid) {
105530fdc8d8SChris Lattner   MachProcessSP procSP;
1056b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
105730fdc8d8SChris Lattner     return procSP->ArgumentCount();
105830fdc8d8SChris Lattner   }
105930fdc8d8SChris Lattner   return 0;
106030fdc8d8SChris Lattner }
106130fdc8d8SChris Lattner 
DNBProcessGetArgumentAtIndex(nub_process_t pid,nub_size_t idx)1062b9c1b51eSKate Stone const char *DNBProcessGetArgumentAtIndex(nub_process_t pid, nub_size_t idx) {
106330fdc8d8SChris Lattner   MachProcessSP procSP;
1064b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
106530fdc8d8SChris Lattner     return procSP->ArgumentAtIndex(idx);
106630fdc8d8SChris Lattner   }
106730fdc8d8SChris Lattner   return NULL;
106830fdc8d8SChris Lattner }
106930fdc8d8SChris Lattner 
107030fdc8d8SChris Lattner // Execution control
DNBProcessResume(nub_process_t pid,const DNBThreadResumeAction * actions,size_t num_actions)1071b9c1b51eSKate Stone nub_bool_t DNBProcessResume(nub_process_t pid,
1072b9c1b51eSKate Stone                             const DNBThreadResumeAction *actions,
1073b9c1b51eSKate Stone                             size_t num_actions) {
107430fdc8d8SChris Lattner   DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
107530fdc8d8SChris Lattner   MachProcessSP procSP;
1076b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
107730fdc8d8SChris Lattner     DNBThreadResumeActions thread_actions(actions, num_actions);
107830fdc8d8SChris Lattner 
107930fdc8d8SChris Lattner     // Below we add a default thread plan just in case one wasn't
108030fdc8d8SChris Lattner     // provided so all threads always know what they were supposed to do
1081b9c1b51eSKate Stone     if (thread_actions.IsEmpty()) {
108230fdc8d8SChris Lattner       // No thread plans were given, so the default it to run all threads
108330fdc8d8SChris Lattner       thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, 0);
1084b9c1b51eSKate Stone     } else {
108530fdc8d8SChris Lattner       // Some thread plans were given which means anything that wasn't
108630fdc8d8SChris Lattner       // specified should remain stopped.
108730fdc8d8SChris Lattner       thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);
108830fdc8d8SChris Lattner     }
108930fdc8d8SChris Lattner     return procSP->Resume(thread_actions);
109030fdc8d8SChris Lattner   }
109130fdc8d8SChris Lattner   return false;
109230fdc8d8SChris Lattner }
109330fdc8d8SChris Lattner 
DNBProcessHalt(nub_process_t pid)1094b9c1b51eSKate Stone nub_bool_t DNBProcessHalt(nub_process_t pid) {
109530fdc8d8SChris Lattner   DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
109630fdc8d8SChris Lattner   MachProcessSP procSP;
109730fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
109830fdc8d8SChris Lattner     return procSP->Signal(SIGSTOP);
109930fdc8d8SChris Lattner   return false;
110030fdc8d8SChris Lattner }
110130fdc8d8SChris Lattner //
110230fdc8d8SChris Lattner // nub_bool_t
110330fdc8d8SChris Lattner // DNBThreadResume (nub_process_t pid, nub_thread_t tid, nub_bool_t step)
110430fdc8d8SChris Lattner //{
1105b9c1b51eSKate Stone //    DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u)",
1106b9c1b51eSKate Stone //    __FUNCTION__, pid, tid, (uint32_t)step);
110730fdc8d8SChris Lattner //    MachProcessSP procSP;
110830fdc8d8SChris Lattner //    if (GetProcessSP (pid, procSP))
110930fdc8d8SChris Lattner //    {
111030fdc8d8SChris Lattner //        return procSP->Resume(tid, step, 0);
111130fdc8d8SChris Lattner //    }
111230fdc8d8SChris Lattner //    return false;
111330fdc8d8SChris Lattner //}
111430fdc8d8SChris Lattner //
111530fdc8d8SChris Lattner // nub_bool_t
1116b9c1b51eSKate Stone // DNBThreadResumeWithSignal (nub_process_t pid, nub_thread_t tid, nub_bool_t
1117b9c1b51eSKate Stone // step, int signal)
111830fdc8d8SChris Lattner //{
1119b9c1b51eSKate Stone //    DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u,
1120b9c1b51eSKate Stone //    signal = %i)", __FUNCTION__, pid, tid, (uint32_t)step, signal);
112130fdc8d8SChris Lattner //    MachProcessSP procSP;
112230fdc8d8SChris Lattner //    if (GetProcessSP (pid, procSP))
112330fdc8d8SChris Lattner //    {
112430fdc8d8SChris Lattner //        return procSP->Resume(tid, step, signal);
112530fdc8d8SChris Lattner //    }
112630fdc8d8SChris Lattner //    return false;
112730fdc8d8SChris Lattner //}
112830fdc8d8SChris Lattner 
DNBProcessWaitForEvents(nub_process_t pid,nub_event_t event_mask,bool wait_for_set,struct timespec * timeout)1129b9c1b51eSKate Stone nub_event_t DNBProcessWaitForEvents(nub_process_t pid, nub_event_t event_mask,
1130b9c1b51eSKate Stone                                     bool wait_for_set,
1131b9c1b51eSKate Stone                                     struct timespec *timeout) {
113230fdc8d8SChris Lattner   nub_event_t result = 0;
113330fdc8d8SChris Lattner   MachProcessSP procSP;
1134b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
113530fdc8d8SChris Lattner     if (wait_for_set)
113630fdc8d8SChris Lattner       result = procSP->Events().WaitForSetEvents(event_mask, timeout);
113730fdc8d8SChris Lattner     else
113830fdc8d8SChris Lattner       result = procSP->Events().WaitForEventsToReset(event_mask, timeout);
113930fdc8d8SChris Lattner   }
114030fdc8d8SChris Lattner   return result;
114130fdc8d8SChris Lattner }
114230fdc8d8SChris Lattner 
DNBProcessResetEvents(nub_process_t pid,nub_event_t event_mask)1143b9c1b51eSKate Stone void DNBProcessResetEvents(nub_process_t pid, nub_event_t event_mask) {
114430fdc8d8SChris Lattner   MachProcessSP procSP;
114530fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
114630fdc8d8SChris Lattner     procSP->Events().ResetEvents(event_mask);
114730fdc8d8SChris Lattner }
114830fdc8d8SChris Lattner 
114930fdc8d8SChris Lattner // Breakpoints
DNBBreakpointSet(nub_process_t pid,nub_addr_t addr,nub_size_t size,nub_bool_t hardware)1150b9c1b51eSKate Stone nub_bool_t DNBBreakpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size,
1151b9c1b51eSKate Stone                             nub_bool_t hardware) {
115230fdc8d8SChris Lattner   MachProcessSP procSP;
115330fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
1154d8cf1a11SGreg Clayton     return procSP->CreateBreakpoint(addr, size, hardware) != NULL;
1155d8cf1a11SGreg Clayton   return false;
115630fdc8d8SChris Lattner }
115730fdc8d8SChris Lattner 
DNBBreakpointClear(nub_process_t pid,nub_addr_t addr)1158b9c1b51eSKate Stone nub_bool_t DNBBreakpointClear(nub_process_t pid, nub_addr_t addr) {
115930fdc8d8SChris Lattner   MachProcessSP procSP;
116030fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
1161d8cf1a11SGreg Clayton     return procSP->DisableBreakpoint(addr, true);
116230fdc8d8SChris Lattner   return false; // Failed
116330fdc8d8SChris Lattner }
116430fdc8d8SChris Lattner 
116530fdc8d8SChris Lattner // Watchpoints
DNBWatchpointSet(nub_process_t pid,nub_addr_t addr,nub_size_t size,uint32_t watch_flags,nub_bool_t hardware)1166b9c1b51eSKate Stone nub_bool_t DNBWatchpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size,
1167b9c1b51eSKate Stone                             uint32_t watch_flags, nub_bool_t hardware) {
116830fdc8d8SChris Lattner   MachProcessSP procSP;
116930fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
1170d8cf1a11SGreg Clayton     return procSP->CreateWatchpoint(addr, size, watch_flags, hardware) != NULL;
1171d8cf1a11SGreg Clayton   return false;
117230fdc8d8SChris Lattner }
117330fdc8d8SChris Lattner 
DNBWatchpointClear(nub_process_t pid,nub_addr_t addr)1174b9c1b51eSKate Stone nub_bool_t DNBWatchpointClear(nub_process_t pid, nub_addr_t addr) {
117530fdc8d8SChris Lattner   MachProcessSP procSP;
117630fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
1177d8cf1a11SGreg Clayton     return procSP->DisableWatchpoint(addr, true);
117830fdc8d8SChris Lattner   return false; // Failed
117930fdc8d8SChris Lattner }
118030fdc8d8SChris Lattner 
118164637205SJohnny Chen // Return the number of supported hardware watchpoints.
DNBWatchpointGetNumSupportedHWP(nub_process_t pid)1182b9c1b51eSKate Stone uint32_t DNBWatchpointGetNumSupportedHWP(nub_process_t pid) {
118364637205SJohnny Chen   MachProcessSP procSP;
118464637205SJohnny Chen   if (GetProcessSP(pid, procSP))
118564637205SJohnny Chen     return procSP->GetNumSupportedHardwareWatchpoints();
118664637205SJohnny Chen   return 0;
118764637205SJohnny Chen }
118864637205SJohnny Chen 
118930fdc8d8SChris Lattner // Read memory in the address space of process PID. This call will take
119030fdc8d8SChris Lattner // care of setting and restoring permissions and breaking up the memory
119130fdc8d8SChris Lattner // read into multiple chunks as required.
119230fdc8d8SChris Lattner //
119330fdc8d8SChris Lattner // RETURNS: number of bytes actually read
DNBProcessMemoryRead(nub_process_t pid,nub_addr_t addr,nub_size_t size,void * buf)1194b9c1b51eSKate Stone nub_size_t DNBProcessMemoryRead(nub_process_t pid, nub_addr_t addr,
1195b9c1b51eSKate Stone                                 nub_size_t size, void *buf) {
119630fdc8d8SChris Lattner   MachProcessSP procSP;
119730fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
119830fdc8d8SChris Lattner     return procSP->ReadMemory(addr, size, buf);
119930fdc8d8SChris Lattner   return 0;
120030fdc8d8SChris Lattner }
120130fdc8d8SChris Lattner 
DNBProcessMemoryReadInteger(nub_process_t pid,nub_addr_t addr,nub_size_t integer_size,uint64_t fail_value)1202b9c1b51eSKate Stone uint64_t DNBProcessMemoryReadInteger(nub_process_t pid, nub_addr_t addr,
1203b9c1b51eSKate Stone                                      nub_size_t integer_size,
1204b9c1b51eSKate Stone                                      uint64_t fail_value) {
1205b9c1b51eSKate Stone   union Integers {
12060b90be1cSGreg Clayton     uint8_t u8;
12070b90be1cSGreg Clayton     uint16_t u16;
12080b90be1cSGreg Clayton     uint32_t u32;
12090b90be1cSGreg Clayton     uint64_t u64;
12100b90be1cSGreg Clayton   };
12110b90be1cSGreg Clayton 
1212b9c1b51eSKate Stone   if (integer_size <= sizeof(uint64_t)) {
12130b90be1cSGreg Clayton     Integers ints;
1214b9c1b51eSKate Stone     if (DNBProcessMemoryRead(pid, addr, integer_size, &ints) == integer_size) {
1215b9c1b51eSKate Stone       switch (integer_size) {
1216b9c1b51eSKate Stone       case 1:
1217b9c1b51eSKate Stone         return ints.u8;
1218b9c1b51eSKate Stone       case 2:
1219b9c1b51eSKate Stone         return ints.u16;
1220b9c1b51eSKate Stone       case 3:
1221b9c1b51eSKate Stone         return ints.u32 & 0xffffffu;
1222b9c1b51eSKate Stone       case 4:
1223b9c1b51eSKate Stone         return ints.u32;
1224b9c1b51eSKate Stone       case 5:
1225b9c1b51eSKate Stone         return ints.u32 & 0x000000ffffffffffull;
1226b9c1b51eSKate Stone       case 6:
1227b9c1b51eSKate Stone         return ints.u32 & 0x0000ffffffffffffull;
1228b9c1b51eSKate Stone       case 7:
1229b9c1b51eSKate Stone         return ints.u32 & 0x00ffffffffffffffull;
1230b9c1b51eSKate Stone       case 8:
1231b9c1b51eSKate Stone         return ints.u64;
12320b90be1cSGreg Clayton       }
12330b90be1cSGreg Clayton     }
12340b90be1cSGreg Clayton   }
12350b90be1cSGreg Clayton   return fail_value;
12360b90be1cSGreg Clayton }
12370b90be1cSGreg Clayton 
DNBProcessMemoryReadPointer(nub_process_t pid,nub_addr_t addr)1238b9c1b51eSKate Stone nub_addr_t DNBProcessMemoryReadPointer(nub_process_t pid, nub_addr_t addr) {
12390b90be1cSGreg Clayton   cpu_type_t cputype = DNBProcessGetCPUType(pid);
1240b9c1b51eSKate Stone   if (cputype) {
12410b90be1cSGreg Clayton     const nub_size_t pointer_size = (cputype & CPU_ARCH_ABI64) ? 8 : 4;
12420b90be1cSGreg Clayton     return DNBProcessMemoryReadInteger(pid, addr, pointer_size, 0);
12430b90be1cSGreg Clayton   }
12440b90be1cSGreg Clayton   return 0;
12450b90be1cSGreg Clayton }
12460b90be1cSGreg Clayton 
DNBProcessMemoryReadCString(nub_process_t pid,nub_addr_t addr)1247b9c1b51eSKate Stone std::string DNBProcessMemoryReadCString(nub_process_t pid, nub_addr_t addr) {
12480b90be1cSGreg Clayton   std::string cstr;
12490b90be1cSGreg Clayton   char buffer[256];
12500b90be1cSGreg Clayton   const nub_size_t max_buffer_cstr_length = sizeof(buffer) - 1;
12510b90be1cSGreg Clayton   buffer[max_buffer_cstr_length] = '\0';
12520b90be1cSGreg Clayton   nub_size_t length = 0;
12530b90be1cSGreg Clayton   nub_addr_t curr_addr = addr;
1254b9c1b51eSKate Stone   do {
1255b9c1b51eSKate Stone     nub_size_t bytes_read =
1256b9c1b51eSKate Stone         DNBProcessMemoryRead(pid, curr_addr, max_buffer_cstr_length, buffer);
12570b90be1cSGreg Clayton     if (bytes_read == 0)
12580b90be1cSGreg Clayton       break;
12590b90be1cSGreg Clayton     length = strlen(buffer);
12600b90be1cSGreg Clayton     cstr.append(buffer, length);
12610b90be1cSGreg Clayton     curr_addr += length;
12620b90be1cSGreg Clayton   } while (length == max_buffer_cstr_length);
12630b90be1cSGreg Clayton   return cstr;
12640b90be1cSGreg Clayton }
12650b90be1cSGreg Clayton 
DNBProcessMemoryReadCStringFixed(nub_process_t pid,nub_addr_t addr,nub_size_t fixed_length)1266b9c1b51eSKate Stone std::string DNBProcessMemoryReadCStringFixed(nub_process_t pid, nub_addr_t addr,
1267b9c1b51eSKate Stone                                              nub_size_t fixed_length) {
12680b90be1cSGreg Clayton   std::string cstr;
12690b90be1cSGreg Clayton   char buffer[fixed_length + 1];
12700b90be1cSGreg Clayton   buffer[fixed_length] = '\0';
12710b90be1cSGreg Clayton   nub_size_t bytes_read = DNBProcessMemoryRead(pid, addr, fixed_length, buffer);
12720b90be1cSGreg Clayton   if (bytes_read > 0)
12730b90be1cSGreg Clayton     cstr.assign(buffer);
12740b90be1cSGreg Clayton   return cstr;
12750b90be1cSGreg Clayton }
12760b90be1cSGreg Clayton 
127730fdc8d8SChris Lattner // Write memory to the address space of process PID. This call will take
127830fdc8d8SChris Lattner // care of setting and restoring permissions and breaking up the memory
127930fdc8d8SChris Lattner // write into multiple chunks as required.
128030fdc8d8SChris Lattner //
128130fdc8d8SChris Lattner // RETURNS: number of bytes actually written
DNBProcessMemoryWrite(nub_process_t pid,nub_addr_t addr,nub_size_t size,const void * buf)1282b9c1b51eSKate Stone nub_size_t DNBProcessMemoryWrite(nub_process_t pid, nub_addr_t addr,
1283b9c1b51eSKate Stone                                  nub_size_t size, const void *buf) {
128430fdc8d8SChris Lattner   MachProcessSP procSP;
128530fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
128630fdc8d8SChris Lattner     return procSP->WriteMemory(addr, size, buf);
128730fdc8d8SChris Lattner   return 0;
128830fdc8d8SChris Lattner }
128930fdc8d8SChris Lattner 
DNBProcessMemoryAllocate(nub_process_t pid,nub_size_t size,uint32_t permissions)1290b9c1b51eSKate Stone nub_addr_t DNBProcessMemoryAllocate(nub_process_t pid, nub_size_t size,
1291b9c1b51eSKate Stone                                     uint32_t permissions) {
129230fdc8d8SChris Lattner   MachProcessSP procSP;
129330fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
129430fdc8d8SChris Lattner     return procSP->Task().AllocateMemory(size, permissions);
129530fdc8d8SChris Lattner   return 0;
129630fdc8d8SChris Lattner }
129730fdc8d8SChris Lattner 
DNBProcessMemoryDeallocate(nub_process_t pid,nub_addr_t addr)1298b9c1b51eSKate Stone nub_bool_t DNBProcessMemoryDeallocate(nub_process_t pid, nub_addr_t addr) {
129930fdc8d8SChris Lattner   MachProcessSP procSP;
130030fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
130130fdc8d8SChris Lattner     return procSP->Task().DeallocateMemory(addr);
130230fdc8d8SChris Lattner   return 0;
130330fdc8d8SChris Lattner }
130430fdc8d8SChris Lattner 
13053dc8583cSJason Molenda // Find attributes of the memory region that contains ADDR for process PID,
13063dc8583cSJason Molenda // if possible, and return a string describing those attributes.
13071f3966beSJason Molenda //
13083dc8583cSJason Molenda // Returns 1 if we could find attributes for this region and OUTBUF can
13093dc8583cSJason Molenda // be sent to the remote debugger.
13101f3966beSJason Molenda //
13113dc8583cSJason Molenda // Returns 0 if we couldn't find the attributes for a region of memory at
13123dc8583cSJason Molenda // that address and OUTBUF should not be sent.
13133dc8583cSJason Molenda //
13143dc8583cSJason Molenda // Returns -1 if this platform cannot look up information about memory regions
13153dc8583cSJason Molenda // or if we do not yet have a valid launched process.
13163dc8583cSJason Molenda //
DNBProcessMemoryRegionInfo(nub_process_t pid,nub_addr_t addr,DNBRegionInfo * region_info)1317b9c1b51eSKate Stone int DNBProcessMemoryRegionInfo(nub_process_t pid, nub_addr_t addr,
1318b9c1b51eSKate Stone                                DNBRegionInfo *region_info) {
13191f3966beSJason Molenda   MachProcessSP procSP;
13201f3966beSJason Molenda   if (GetProcessSP(pid, procSP))
132146fb558dSGreg Clayton     return procSP->Task().GetMemoryRegionInfo(addr, region_info);
132246fb558dSGreg Clayton 
13231f3966beSJason Molenda   return -1;
13241f3966beSJason Molenda }
13251f3966beSJason Molenda 
DNBProcessGetProfileData(nub_process_t pid,DNBProfileDataScanType scanType)1326b9c1b51eSKate Stone std::string DNBProcessGetProfileData(nub_process_t pid,
1327b9c1b51eSKate Stone                                      DNBProfileDataScanType scanType) {
1328ab3b8b22SHan Ming Ong   MachProcessSP procSP;
1329ab3b8b22SHan Ming Ong   if (GetProcessSP(pid, procSP))
13308764fe7dSHan Ming Ong     return procSP->Task().GetProfileData(scanType);
1331ab3b8b22SHan Ming Ong 
1332929a94f0SHan Ming Ong   return std::string("");
1333ab3b8b22SHan Ming Ong }
1334ab3b8b22SHan Ming Ong 
DNBProcessSetEnableAsyncProfiling(nub_process_t pid,nub_bool_t enable,uint64_t interval_usec,DNBProfileDataScanType scan_type)1335b9c1b51eSKate Stone nub_bool_t DNBProcessSetEnableAsyncProfiling(nub_process_t pid,
1336b9c1b51eSKate Stone                                              nub_bool_t enable,
1337b9c1b51eSKate Stone                                              uint64_t interval_usec,
1338b9c1b51eSKate Stone                                              DNBProfileDataScanType scan_type) {
1339ab3b8b22SHan Ming Ong   MachProcessSP procSP;
1340b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
13418764fe7dSHan Ming Ong     procSP->SetEnableAsyncProfiling(enable, interval_usec, scan_type);
1342ab3b8b22SHan Ming Ong     return true;
1343ab3b8b22SHan Ming Ong   }
1344ab3b8b22SHan Ming Ong 
1345ab3b8b22SHan Ming Ong   return false;
1346ab3b8b22SHan Ming Ong }
134730fdc8d8SChris Lattner 
134830fdc8d8SChris Lattner // Get the number of threads for the specified process.
DNBProcessGetNumThreads(nub_process_t pid)1349b9c1b51eSKate Stone nub_size_t DNBProcessGetNumThreads(nub_process_t pid) {
135030fdc8d8SChris Lattner   MachProcessSP procSP;
135130fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
135230fdc8d8SChris Lattner     return procSP->GetNumThreads();
135330fdc8d8SChris Lattner   return 0;
135430fdc8d8SChris Lattner }
135530fdc8d8SChris Lattner 
135630fdc8d8SChris Lattner // Get the thread ID of the current thread.
DNBProcessGetCurrentThread(nub_process_t pid)1357b9c1b51eSKate Stone nub_thread_t DNBProcessGetCurrentThread(nub_process_t pid) {
135830fdc8d8SChris Lattner   MachProcessSP procSP;
135930fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
136030fdc8d8SChris Lattner     return procSP->GetCurrentThread();
136130fdc8d8SChris Lattner   return 0;
136230fdc8d8SChris Lattner }
136330fdc8d8SChris Lattner 
1364d5318c0cSJason Molenda // Get the mach port number of the current thread.
DNBProcessGetCurrentThreadMachPort(nub_process_t pid)1365b9c1b51eSKate Stone nub_thread_t DNBProcessGetCurrentThreadMachPort(nub_process_t pid) {
1366d5318c0cSJason Molenda   MachProcessSP procSP;
1367d5318c0cSJason Molenda   if (GetProcessSP(pid, procSP))
1368d5318c0cSJason Molenda     return procSP->GetCurrentThreadMachPort();
1369d5318c0cSJason Molenda   return 0;
1370d5318c0cSJason Molenda }
1371d5318c0cSJason Molenda 
137230fdc8d8SChris Lattner // Change the current thread.
DNBProcessSetCurrentThread(nub_process_t pid,nub_thread_t tid)1373b9c1b51eSKate Stone nub_thread_t DNBProcessSetCurrentThread(nub_process_t pid, nub_thread_t tid) {
137430fdc8d8SChris Lattner   MachProcessSP procSP;
137530fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
137630fdc8d8SChris Lattner     return procSP->SetCurrentThread(tid);
137730fdc8d8SChris Lattner   return INVALID_NUB_THREAD;
137830fdc8d8SChris Lattner }
137930fdc8d8SChris Lattner 
138030fdc8d8SChris Lattner // Dump a string describing a thread's stop reason to the specified file
138130fdc8d8SChris Lattner // handle
DNBThreadGetStopReason(nub_process_t pid,nub_thread_t tid,struct DNBThreadStopInfo * stop_info)1382b9c1b51eSKate Stone nub_bool_t DNBThreadGetStopReason(nub_process_t pid, nub_thread_t tid,
1383b9c1b51eSKate Stone                                   struct DNBThreadStopInfo *stop_info) {
138430fdc8d8SChris Lattner   MachProcessSP procSP;
138530fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
138630fdc8d8SChris Lattner     return procSP->GetThreadStoppedReason(tid, stop_info);
138730fdc8d8SChris Lattner   return false;
138830fdc8d8SChris Lattner }
138930fdc8d8SChris Lattner 
139030fdc8d8SChris Lattner // Return string description for the specified thread.
139130fdc8d8SChris Lattner //
139230fdc8d8SChris Lattner // RETURNS: NULL if the thread isn't valid, else a NULL terminated C
139330fdc8d8SChris Lattner // string from a static buffer that must be copied prior to subsequent
139430fdc8d8SChris Lattner // calls.
DNBThreadGetInfo(nub_process_t pid,nub_thread_t tid)1395b9c1b51eSKate Stone const char *DNBThreadGetInfo(nub_process_t pid, nub_thread_t tid) {
139630fdc8d8SChris Lattner   MachProcessSP procSP;
139730fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
139830fdc8d8SChris Lattner     return procSP->GetThreadInfo(tid);
139930fdc8d8SChris Lattner   return NULL;
140030fdc8d8SChris Lattner }
140130fdc8d8SChris Lattner 
140230fdc8d8SChris Lattner // Get the thread ID given a thread index.
DNBProcessGetThreadAtIndex(nub_process_t pid,size_t thread_idx)1403b9c1b51eSKate Stone nub_thread_t DNBProcessGetThreadAtIndex(nub_process_t pid, size_t thread_idx) {
140430fdc8d8SChris Lattner   MachProcessSP procSP;
140530fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
140630fdc8d8SChris Lattner     return procSP->GetThreadAtIndex(thread_idx);
140730fdc8d8SChris Lattner   return INVALID_NUB_THREAD;
140830fdc8d8SChris Lattner }
140930fdc8d8SChris Lattner 
1410b9c1b51eSKate Stone // Do whatever is needed to sync the thread's register state with it's kernel
1411b9c1b51eSKate Stone // values.
DNBProcessSyncThreadState(nub_process_t pid,nub_thread_t tid)1412b9c1b51eSKate Stone nub_bool_t DNBProcessSyncThreadState(nub_process_t pid, nub_thread_t tid) {
1413279ceecfSJim Ingham   MachProcessSP procSP;
1414279ceecfSJim Ingham   if (GetProcessSP(pid, procSP))
1415279ceecfSJim Ingham     return procSP->SyncThreadState(tid);
1416279ceecfSJim Ingham   return false;
1417279ceecfSJim Ingham }
1418279ceecfSJim Ingham 
DNBProcessGetSharedLibraryInfoAddress(nub_process_t pid)1419b9c1b51eSKate Stone nub_addr_t DNBProcessGetSharedLibraryInfoAddress(nub_process_t pid) {
142030fdc8d8SChris Lattner   MachProcessSP procSP;
142130fdc8d8SChris Lattner   DNBError err;
142230fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
142330fdc8d8SChris Lattner     return procSP->Task().GetDYLDAllImageInfosAddress(err);
142430fdc8d8SChris Lattner   return INVALID_NUB_ADDRESS;
142530fdc8d8SChris Lattner }
142630fdc8d8SChris Lattner 
DNBProcessSharedLibrariesUpdated(nub_process_t pid)1427b9c1b51eSKate Stone nub_bool_t DNBProcessSharedLibrariesUpdated(nub_process_t pid) {
142830fdc8d8SChris Lattner   MachProcessSP procSP;
1429b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
143030fdc8d8SChris Lattner     procSP->SharedLibrariesUpdated();
143130fdc8d8SChris Lattner     return true;
143230fdc8d8SChris Lattner   }
143330fdc8d8SChris Lattner   return false;
143430fdc8d8SChris Lattner }
143530fdc8d8SChris Lattner 
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)14367e9bab6aSAdrian Prantl const char *DNBGetDeploymentInfo(nub_process_t pid, bool is_executable,
1437cd90f878SFrederic Riss                                  const struct load_command &lc,
1438cd90f878SFrederic Riss                                  uint64_t load_command_address,
1439cd90f878SFrederic Riss                                  uint32_t &major_version,
1440cd90f878SFrederic Riss                                  uint32_t &minor_version,
1441cd90f878SFrederic Riss                                  uint32_t &patch_version) {
1442cd90f878SFrederic Riss   MachProcessSP procSP;
1443116b1033SAdrian Prantl   if (GetProcessSP(pid, procSP)) {
144458d84eb5SAdrian Prantl     // FIXME: This doesn't return the correct result when xctest (a
144558d84eb5SAdrian Prantl     // macOS binary) is loaded with the macCatalyst dyld platform
144658d84eb5SAdrian Prantl     // override. The image info corrects for this, but qProcessInfo
144758d84eb5SAdrian Prantl     // will return what is in the binary.
14487e9bab6aSAdrian Prantl     auto info =
14497e9bab6aSAdrian Prantl         procSP->GetDeploymentInfo(lc, load_command_address, is_executable);
1450116b1033SAdrian Prantl     major_version = info.major_version;
1451116b1033SAdrian Prantl     minor_version = info.minor_version;
1452116b1033SAdrian Prantl     patch_version = info.patch_version;
1453116b1033SAdrian Prantl     return procSP->GetPlatformString(info.platform);
1454116b1033SAdrian Prantl   }
1455cd90f878SFrederic Riss   return nullptr;
1456cd90f878SFrederic Riss }
1457cd90f878SFrederic Riss 
145830fdc8d8SChris Lattner // Get the current shared library information for a process. Only return
145930fdc8d8SChris Lattner // the shared libraries that have changed since the last shared library
146030fdc8d8SChris Lattner // state changed event if only_changed is non-zero.
146130fdc8d8SChris Lattner nub_size_t
DNBProcessGetSharedLibraryInfo(nub_process_t pid,nub_bool_t only_changed,struct DNBExecutableImageInfo ** image_infos)1462b9c1b51eSKate Stone DNBProcessGetSharedLibraryInfo(nub_process_t pid, nub_bool_t only_changed,
1463b9c1b51eSKate Stone                                struct DNBExecutableImageInfo **image_infos) {
146430fdc8d8SChris Lattner   MachProcessSP procSP;
146530fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
146630fdc8d8SChris Lattner     return procSP->CopyImageInfos(image_infos, only_changed);
146730fdc8d8SChris Lattner 
146830fdc8d8SChris Lattner   // If we have no process, then return NULL for the shared library info
146930fdc8d8SChris Lattner   // and zero for shared library count
147030fdc8d8SChris Lattner   *image_infos = NULL;
147130fdc8d8SChris Lattner   return 0;
147230fdc8d8SChris Lattner }
147330fdc8d8SChris Lattner 
DNBGetRegisterCPUType()1474b9c1b51eSKate Stone uint32_t DNBGetRegisterCPUType() {
1475d04f0edaSGreg Clayton   return DNBArchProtocol::GetRegisterCPUType();
1476d04f0edaSGreg Clayton }
147730fdc8d8SChris Lattner // Get the register set information for a specific thread.
DNBGetRegisterSetInfo(nub_size_t * num_reg_sets)1478b9c1b51eSKate Stone const DNBRegisterSetInfo *DNBGetRegisterSetInfo(nub_size_t *num_reg_sets) {
14793af9ea56SGreg Clayton   return DNBArchProtocol::GetRegisterSetInfo(num_reg_sets);
148030fdc8d8SChris Lattner }
148130fdc8d8SChris Lattner 
148230fdc8d8SChris Lattner // 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)1483b9c1b51eSKate Stone nub_bool_t DNBThreadGetRegisterValueByID(nub_process_t pid, nub_thread_t tid,
1484b9c1b51eSKate Stone                                          uint32_t set, uint32_t reg,
1485b9c1b51eSKate Stone                                          DNBRegisterValue *value) {
148630fdc8d8SChris Lattner   MachProcessSP procSP;
148730fdc8d8SChris Lattner   ::bzero(value, sizeof(DNBRegisterValue));
1488b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
148930fdc8d8SChris Lattner     if (tid != INVALID_NUB_THREAD)
149030fdc8d8SChris Lattner       return procSP->GetRegisterValue(tid, set, reg, value);
149130fdc8d8SChris Lattner   }
149230fdc8d8SChris Lattner   return false;
149330fdc8d8SChris Lattner }
149430fdc8d8SChris Lattner 
DNBThreadSetRegisterValueByID(nub_process_t pid,nub_thread_t tid,uint32_t set,uint32_t reg,const DNBRegisterValue * value)1495b9c1b51eSKate Stone nub_bool_t DNBThreadSetRegisterValueByID(nub_process_t pid, nub_thread_t tid,
1496b9c1b51eSKate Stone                                          uint32_t set, uint32_t reg,
1497b9c1b51eSKate Stone                                          const DNBRegisterValue *value) {
1498b9c1b51eSKate Stone   if (tid != INVALID_NUB_THREAD) {
149930fdc8d8SChris Lattner     MachProcessSP procSP;
150030fdc8d8SChris Lattner     if (GetProcessSP(pid, procSP))
150130fdc8d8SChris Lattner       return procSP->SetRegisterValue(tid, set, reg, value);
150230fdc8d8SChris Lattner   }
150330fdc8d8SChris Lattner   return false;
150430fdc8d8SChris Lattner }
150530fdc8d8SChris Lattner 
DNBThreadGetRegisterContext(nub_process_t pid,nub_thread_t tid,void * buf,size_t buf_len)1506b9c1b51eSKate Stone nub_size_t DNBThreadGetRegisterContext(nub_process_t pid, nub_thread_t tid,
1507b9c1b51eSKate Stone                                        void *buf, size_t buf_len) {
150830fdc8d8SChris Lattner   MachProcessSP procSP;
1509b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
151030fdc8d8SChris Lattner     if (tid != INVALID_NUB_THREAD)
151130fdc8d8SChris Lattner       return procSP->GetThreadList().GetRegisterContext(tid, buf, buf_len);
151230fdc8d8SChris Lattner   }
151330fdc8d8SChris Lattner   ::bzero(buf, buf_len);
151430fdc8d8SChris Lattner   return 0;
151530fdc8d8SChris Lattner }
151630fdc8d8SChris Lattner 
DNBThreadSetRegisterContext(nub_process_t pid,nub_thread_t tid,const void * buf,size_t buf_len)1517b9c1b51eSKate Stone nub_size_t DNBThreadSetRegisterContext(nub_process_t pid, nub_thread_t tid,
1518b9c1b51eSKate Stone                                        const void *buf, size_t buf_len) {
151930fdc8d8SChris Lattner   MachProcessSP procSP;
1520b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
152130fdc8d8SChris Lattner     if (tid != INVALID_NUB_THREAD)
152230fdc8d8SChris Lattner       return procSP->GetThreadList().SetRegisterContext(tid, buf, buf_len);
152330fdc8d8SChris Lattner   }
152430fdc8d8SChris Lattner   return 0;
152530fdc8d8SChris Lattner }
152630fdc8d8SChris Lattner 
DNBThreadSaveRegisterState(nub_process_t pid,nub_thread_t tid)1527b9c1b51eSKate Stone uint32_t DNBThreadSaveRegisterState(nub_process_t pid, nub_thread_t tid) {
1528b9c1b51eSKate Stone   if (tid != INVALID_NUB_THREAD) {
1529f74cf86bSGreg Clayton     MachProcessSP procSP;
1530f74cf86bSGreg Clayton     if (GetProcessSP(pid, procSP))
1531f74cf86bSGreg Clayton       return procSP->GetThreadList().SaveRegisterState(tid);
1532f74cf86bSGreg Clayton   }
1533f74cf86bSGreg Clayton   return 0;
1534f74cf86bSGreg Clayton }
DNBThreadRestoreRegisterState(nub_process_t pid,nub_thread_t tid,uint32_t save_id)1535b9c1b51eSKate Stone nub_bool_t DNBThreadRestoreRegisterState(nub_process_t pid, nub_thread_t tid,
1536b9c1b51eSKate Stone                                          uint32_t save_id) {
1537b9c1b51eSKate Stone   if (tid != INVALID_NUB_THREAD) {
1538f74cf86bSGreg Clayton     MachProcessSP procSP;
1539f74cf86bSGreg Clayton     if (GetProcessSP(pid, procSP))
1540f74cf86bSGreg Clayton       return procSP->GetThreadList().RestoreRegisterState(tid, save_id);
1541f74cf86bSGreg Clayton   }
1542f74cf86bSGreg Clayton   return false;
1543f74cf86bSGreg Clayton }
1544f74cf86bSGreg Clayton 
154530fdc8d8SChris Lattner // 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)1546b9c1b51eSKate Stone nub_bool_t DNBThreadGetRegisterValueByName(nub_process_t pid, nub_thread_t tid,
1547b9c1b51eSKate Stone                                            uint32_t reg_set,
1548b9c1b51eSKate Stone                                            const char *reg_name,
1549b9c1b51eSKate Stone                                            DNBRegisterValue *value) {
155030fdc8d8SChris Lattner   MachProcessSP procSP;
155130fdc8d8SChris Lattner   ::bzero(value, sizeof(DNBRegisterValue));
1552b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
155330fdc8d8SChris Lattner     const struct DNBRegisterSetInfo *set_info;
155430fdc8d8SChris Lattner     nub_size_t num_reg_sets = 0;
155530fdc8d8SChris Lattner     set_info = DNBGetRegisterSetInfo(&num_reg_sets);
1556b9c1b51eSKate Stone     if (set_info) {
155730fdc8d8SChris Lattner       uint32_t set = reg_set;
155830fdc8d8SChris Lattner       uint32_t reg;
1559b9c1b51eSKate Stone       if (set == REGISTER_SET_ALL) {
1560b9c1b51eSKate Stone         for (set = 1; set < num_reg_sets; ++set) {
1561b9c1b51eSKate Stone           for (reg = 0; reg < set_info[set].num_registers; ++reg) {
156230fdc8d8SChris Lattner             if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
156330fdc8d8SChris Lattner               return procSP->GetRegisterValue(tid, set, reg, value);
156430fdc8d8SChris Lattner           }
156530fdc8d8SChris Lattner         }
1566b9c1b51eSKate Stone       } else {
1567b9c1b51eSKate Stone         for (reg = 0; reg < set_info[set].num_registers; ++reg) {
156830fdc8d8SChris Lattner           if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
156930fdc8d8SChris Lattner             return procSP->GetRegisterValue(tid, set, reg, value);
157030fdc8d8SChris Lattner         }
157130fdc8d8SChris Lattner       }
157230fdc8d8SChris Lattner     }
157330fdc8d8SChris Lattner   }
157430fdc8d8SChris Lattner   return false;
157530fdc8d8SChris Lattner }
157630fdc8d8SChris Lattner 
157730fdc8d8SChris Lattner // Read a register set and register number from the register name.
DNBGetRegisterInfoByName(const char * reg_name,DNBRegisterInfo * info)1578b9c1b51eSKate Stone nub_bool_t DNBGetRegisterInfoByName(const char *reg_name,
1579b9c1b51eSKate Stone                                     DNBRegisterInfo *info) {
158030fdc8d8SChris Lattner   const struct DNBRegisterSetInfo *set_info;
158130fdc8d8SChris Lattner   nub_size_t num_reg_sets = 0;
158230fdc8d8SChris Lattner   set_info = DNBGetRegisterSetInfo(&num_reg_sets);
1583b9c1b51eSKate Stone   if (set_info) {
158430fdc8d8SChris Lattner     uint32_t set, reg;
1585b9c1b51eSKate Stone     for (set = 1; set < num_reg_sets; ++set) {
1586b9c1b51eSKate Stone       for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1587b9c1b51eSKate Stone         if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) {
158830fdc8d8SChris Lattner           *info = set_info[set].registers[reg];
158930fdc8d8SChris Lattner           return true;
159030fdc8d8SChris Lattner         }
159130fdc8d8SChris Lattner       }
159230fdc8d8SChris Lattner     }
159330fdc8d8SChris Lattner 
1594b9c1b51eSKate Stone     for (set = 1; set < num_reg_sets; ++set) {
159530fdc8d8SChris Lattner       uint32_t reg;
1596b9c1b51eSKate Stone       for (reg = 0; reg < set_info[set].num_registers; ++reg) {
159730fdc8d8SChris Lattner         if (set_info[set].registers[reg].alt == NULL)
159830fdc8d8SChris Lattner           continue;
159930fdc8d8SChris Lattner 
1600b9c1b51eSKate Stone         if (strcasecmp(reg_name, set_info[set].registers[reg].alt) == 0) {
160130fdc8d8SChris Lattner           *info = set_info[set].registers[reg];
160230fdc8d8SChris Lattner           return true;
160330fdc8d8SChris Lattner         }
160430fdc8d8SChris Lattner       }
160530fdc8d8SChris Lattner     }
160630fdc8d8SChris Lattner   }
160730fdc8d8SChris Lattner 
160830fdc8d8SChris Lattner   ::bzero(info, sizeof(DNBRegisterInfo));
160930fdc8d8SChris Lattner   return false;
161030fdc8d8SChris Lattner }
161130fdc8d8SChris Lattner 
161230fdc8d8SChris Lattner // Set the name to address callback function that this nub can use
161330fdc8d8SChris Lattner // for any name to address lookups that are needed.
DNBProcessSetNameToAddressCallback(nub_process_t pid,DNBCallbackNameToAddress callback,void * baton)1614b9c1b51eSKate Stone nub_bool_t DNBProcessSetNameToAddressCallback(nub_process_t pid,
1615b9c1b51eSKate Stone                                               DNBCallbackNameToAddress callback,
1616b9c1b51eSKate Stone                                               void *baton) {
161730fdc8d8SChris Lattner   MachProcessSP procSP;
1618b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
161930fdc8d8SChris Lattner     procSP->SetNameToAddressCallback(callback, baton);
162030fdc8d8SChris Lattner     return true;
162130fdc8d8SChris Lattner   }
162230fdc8d8SChris Lattner   return false;
162330fdc8d8SChris Lattner }
162430fdc8d8SChris Lattner 
162530fdc8d8SChris Lattner // Set the name to address callback function that this nub can use
162630fdc8d8SChris Lattner // for any name to address lookups that are needed.
DNBProcessSetSharedLibraryInfoCallback(nub_process_t pid,DNBCallbackCopyExecutableImageInfos callback,void * baton)1627b9c1b51eSKate Stone nub_bool_t DNBProcessSetSharedLibraryInfoCallback(
1628b9c1b51eSKate Stone     nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback,
1629b9c1b51eSKate Stone     void *baton) {
163030fdc8d8SChris Lattner   MachProcessSP procSP;
1631b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
163230fdc8d8SChris Lattner     procSP->SetSharedLibraryInfoCallback(callback, baton);
163330fdc8d8SChris Lattner     return true;
163430fdc8d8SChris Lattner   }
163530fdc8d8SChris Lattner   return false;
163630fdc8d8SChris Lattner }
163730fdc8d8SChris Lattner 
DNBProcessLookupAddress(nub_process_t pid,const char * name,const char * shlib)1638b9c1b51eSKate Stone nub_addr_t DNBProcessLookupAddress(nub_process_t pid, const char *name,
1639b9c1b51eSKate Stone                                    const char *shlib) {
164030fdc8d8SChris Lattner   MachProcessSP procSP;
1641b9c1b51eSKate Stone   if (GetProcessSP(pid, procSP)) {
164230fdc8d8SChris Lattner     return procSP->LookupSymbol(name, shlib);
164330fdc8d8SChris Lattner   }
164430fdc8d8SChris Lattner   return INVALID_NUB_ADDRESS;
164530fdc8d8SChris Lattner }
164630fdc8d8SChris Lattner 
DNBProcessGetAvailableSTDOUT(nub_process_t pid,char * buf,nub_size_t buf_size)1647b9c1b51eSKate Stone nub_size_t DNBProcessGetAvailableSTDOUT(nub_process_t pid, char *buf,
1648b9c1b51eSKate Stone                                         nub_size_t buf_size) {
164930fdc8d8SChris Lattner   MachProcessSP procSP;
165030fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
165130fdc8d8SChris Lattner     return procSP->GetAvailableSTDOUT(buf, buf_size);
165230fdc8d8SChris Lattner   return 0;
165330fdc8d8SChris Lattner }
165430fdc8d8SChris Lattner 
DNBProcessGetAvailableSTDERR(nub_process_t pid,char * buf,nub_size_t buf_size)1655b9c1b51eSKate Stone nub_size_t DNBProcessGetAvailableSTDERR(nub_process_t pid, char *buf,
1656b9c1b51eSKate Stone                                         nub_size_t buf_size) {
165730fdc8d8SChris Lattner   MachProcessSP procSP;
165830fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
165930fdc8d8SChris Lattner     return procSP->GetAvailableSTDERR(buf, buf_size);
166030fdc8d8SChris Lattner   return 0;
166130fdc8d8SChris Lattner }
166230fdc8d8SChris Lattner 
DNBProcessGetAvailableProfileData(nub_process_t pid,char * buf,nub_size_t buf_size)1663b9c1b51eSKate Stone nub_size_t DNBProcessGetAvailableProfileData(nub_process_t pid, char *buf,
1664b9c1b51eSKate Stone                                              nub_size_t buf_size) {
1665ab3b8b22SHan Ming Ong   MachProcessSP procSP;
1666ab3b8b22SHan Ming Ong   if (GetProcessSP(pid, procSP))
1667ab3b8b22SHan Ming Ong     return procSP->GetAsyncProfileData(buf, buf_size);
1668ab3b8b22SHan Ming Ong   return 0;
1669ab3b8b22SHan Ming Ong }
1670ab3b8b22SHan Ming Ong 
DNBProcessGetStopCount(nub_process_t pid)1671b9c1b51eSKate Stone nub_size_t DNBProcessGetStopCount(nub_process_t pid) {
167230fdc8d8SChris Lattner   MachProcessSP procSP;
167330fdc8d8SChris Lattner   if (GetProcessSP(pid, procSP))
167430fdc8d8SChris Lattner     return procSP->StopCount();
167530fdc8d8SChris Lattner   return 0;
167630fdc8d8SChris Lattner }
167730fdc8d8SChris Lattner 
DNBProcessGetCPUType(nub_process_t pid)1678b9c1b51eSKate Stone uint32_t DNBProcessGetCPUType(nub_process_t pid) {
167971337622SGreg Clayton   MachProcessSP procSP;
168071337622SGreg Clayton   if (GetProcessSP(pid, procSP))
168171337622SGreg Clayton     return procSP->GetCPUType();
168271337622SGreg Clayton   return 0;
168371337622SGreg Clayton }
168471337622SGreg Clayton 
DNBResolveExecutablePath(const char * path,char * resolved_path,size_t resolved_path_size)1685b9c1b51eSKate Stone nub_bool_t DNBResolveExecutablePath(const char *path, char *resolved_path,
1686b9c1b51eSKate Stone                                     size_t resolved_path_size) {
168730fdc8d8SChris Lattner   if (path == NULL || path[0] == '\0')
168830fdc8d8SChris Lattner     return false;
168930fdc8d8SChris Lattner 
169030fdc8d8SChris Lattner   char max_path[PATH_MAX];
169130fdc8d8SChris Lattner   std::string result;
169230fdc8d8SChris Lattner   CFString::GlobPath(path, result);
169330fdc8d8SChris Lattner 
169430fdc8d8SChris Lattner   if (result.empty())
169530fdc8d8SChris Lattner     result = path;
169630fdc8d8SChris Lattner 
169748baf7a7SGreg Clayton   struct stat path_stat;
1698b9c1b51eSKate Stone   if (::stat(path, &path_stat) == 0) {
1699b9c1b51eSKate Stone     if ((path_stat.st_mode & S_IFMT) == S_IFDIR) {
170048baf7a7SGreg Clayton       CFBundle bundle(path);
170148baf7a7SGreg Clayton       CFReleaser<CFURLRef> url(bundle.CopyExecutableURL());
1702b9c1b51eSKate Stone       if (url.get()) {
1703b9c1b51eSKate Stone         if (::CFURLGetFileSystemRepresentation(
1704b9c1b51eSKate Stone                 url.get(), true, (UInt8 *)resolved_path, resolved_path_size))
170548baf7a7SGreg Clayton           return true;
170648baf7a7SGreg Clayton       }
170748baf7a7SGreg Clayton     }
170848baf7a7SGreg Clayton   }
170948baf7a7SGreg Clayton 
1710b9c1b51eSKate Stone   if (realpath(path, max_path)) {
171130fdc8d8SChris Lattner     // Found the path relatively...
1712aae5b690SJason Molenda     ::strlcpy(resolved_path, max_path, resolved_path_size);
171330fdc8d8SChris Lattner     return strlen(resolved_path) + 1 < resolved_path_size;
1714b9c1b51eSKate Stone   } else {
171530fdc8d8SChris Lattner     // Not a relative path, check the PATH environment variable if the
171630fdc8d8SChris Lattner     const char *PATH = getenv("PATH");
1717b9c1b51eSKate Stone     if (PATH) {
171830fdc8d8SChris Lattner       const char *curr_path_start = PATH;
171930fdc8d8SChris Lattner       const char *curr_path_end;
1720b9c1b51eSKate Stone       while (curr_path_start && *curr_path_start) {
172130fdc8d8SChris Lattner         curr_path_end = strchr(curr_path_start, ':');
1722b9c1b51eSKate Stone         if (curr_path_end == NULL) {
172330fdc8d8SChris Lattner           result.assign(curr_path_start);
172430fdc8d8SChris Lattner           curr_path_start = NULL;
1725b9c1b51eSKate Stone         } else if (curr_path_end > curr_path_start) {
172630fdc8d8SChris Lattner           size_t len = curr_path_end - curr_path_start;
172730fdc8d8SChris Lattner           result.assign(curr_path_start, len);
172830fdc8d8SChris Lattner           curr_path_start += len + 1;
1729b9c1b51eSKate Stone         } else
173030fdc8d8SChris Lattner           break;
173130fdc8d8SChris Lattner 
173230fdc8d8SChris Lattner         result += '/';
173330fdc8d8SChris Lattner         result += path;
173430fdc8d8SChris Lattner         struct stat s;
1735b9c1b51eSKate Stone         if (stat(result.c_str(), &s) == 0) {
1736aae5b690SJason Molenda           ::strlcpy(resolved_path, result.c_str(), resolved_path_size);
173730fdc8d8SChris Lattner           return result.size() + 1 < resolved_path_size;
173830fdc8d8SChris Lattner         }
173930fdc8d8SChris Lattner       }
174030fdc8d8SChris Lattner     }
174130fdc8d8SChris Lattner   }
174230fdc8d8SChris Lattner   return false;
174330fdc8d8SChris Lattner }
174430fdc8d8SChris Lattner 
DNBGetOSVersionNumbers(uint64_t * major,uint64_t * minor,uint64_t * patch)1745b9c1b51eSKate Stone bool DNBGetOSVersionNumbers(uint64_t *major, uint64_t *minor, uint64_t *patch) {
17466acc86c3SJason Molenda   return MachProcess::GetOSVersionNumbers(major, minor, patch);
17476acc86c3SJason Molenda }
17486acc86c3SJason Molenda 
DNBGetMacCatalystVersionString()17496cebeafaSJason Molenda std::string DNBGetMacCatalystVersionString() {
17506cebeafaSJason Molenda   return MachProcess::GetMacCatalystVersionString();
17516cebeafaSJason Molenda }
17526cebeafaSJason Molenda 
DNBInitialize()1753b9c1b51eSKate Stone void DNBInitialize() {
17543af9ea56SGreg Clayton   DNBLogThreadedIf(LOG_PROCESS, "DNBInitialize ()");
17553af9ea56SGreg Clayton #if defined(__i386__) || defined(__x86_64__)
17563af9ea56SGreg Clayton   DNBArchImplI386::Initialize();
17573af9ea56SGreg Clayton   DNBArchImplX86_64::Initialize();
1758013434e5STodd Fiala #elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
17593af9ea56SGreg Clayton   DNBArchMachARM::Initialize();
1760a332978bSJason Molenda   DNBArchMachARM64::Initialize();
17613af9ea56SGreg Clayton #endif
17623af9ea56SGreg Clayton }
17633af9ea56SGreg Clayton 
DNBTerminate()1764b9c1b51eSKate Stone void DNBTerminate() {}
17653c14438fSGreg Clayton 
DNBSetArchitecture(const char * arch)1766b9c1b51eSKate Stone nub_bool_t DNBSetArchitecture(const char *arch) {
1767b9c1b51eSKate Stone   if (arch && arch[0]) {
17683c14438fSGreg Clayton     if (strcasecmp(arch, "i386") == 0)
17693c14438fSGreg Clayton       return DNBArchProtocol::SetArchitecture(CPU_TYPE_I386);
17700db37576SJonas Devlieghere     else if (strcasecmp(arch, "x86_64") == 0)
17710db37576SJonas Devlieghere       return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64,
17720db37576SJonas Devlieghere                                               CPU_SUBTYPE_X86_64_ALL);
17730db37576SJonas Devlieghere     else if (strcasecmp(arch, "x86_64h") == 0)
17740db37576SJonas Devlieghere       return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64,
17750db37576SJonas Devlieghere                                               CPU_SUBTYPE_X86_64_H);
17767dd7a360SJason Molenda     else if (strstr(arch, "arm64_32") == arch ||
17777dd7a360SJason Molenda              strstr(arch, "aarch64_32") == arch)
17786cebeafaSJason Molenda       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64_32);
1779e11df585SJason Molenda     else if (strstr(arch, "arm64e") == arch)
17800db37576SJonas Devlieghere       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64,
17810db37576SJonas Devlieghere                                               CPU_SUBTYPE_ARM64E);
17820db37576SJonas Devlieghere     else if (strstr(arch, "arm64") == arch || strstr(arch, "aarch64") == arch)
17830db37576SJonas Devlieghere       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64,
17840db37576SJonas Devlieghere                                               CPU_SUBTYPE_ARM64_ALL);
17850db37576SJonas Devlieghere     else if (strstr(arch, "armv8") == arch)
17860db37576SJonas Devlieghere       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64,
17870db37576SJonas Devlieghere                                               CPU_SUBTYPE_ARM64_V8);
17880db37576SJonas Devlieghere     else if (strstr(arch, "armv7em") == arch)
17890db37576SJonas Devlieghere       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
17900db37576SJonas Devlieghere                                               CPU_SUBTYPE_ARM_V7EM);
17910db37576SJonas Devlieghere     else if (strstr(arch, "armv7m") == arch)
17920db37576SJonas Devlieghere       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
17930db37576SJonas Devlieghere                                               CPU_SUBTYPE_ARM_V7M);
17940db37576SJonas Devlieghere     else if (strstr(arch, "armv7k") == arch)
17950db37576SJonas Devlieghere       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
17960db37576SJonas Devlieghere                                               CPU_SUBTYPE_ARM_V7K);
17970db37576SJonas Devlieghere     else if (strstr(arch, "armv7s") == arch)
17980db37576SJonas Devlieghere       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
17990db37576SJonas Devlieghere                                               CPU_SUBTYPE_ARM_V7S);
18000db37576SJonas Devlieghere     else if (strstr(arch, "armv7") == arch)
18010db37576SJonas Devlieghere       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7);
18020db37576SJonas Devlieghere     else if (strstr(arch, "armv6m") == arch)
18030db37576SJonas Devlieghere       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
18040db37576SJonas Devlieghere                                               CPU_SUBTYPE_ARM_V6M);
18050db37576SJonas Devlieghere     else if (strstr(arch, "armv6") == arch)
18060db37576SJonas Devlieghere       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6);
18070db37576SJonas Devlieghere     else if (strstr(arch, "armv5") == arch)
18080db37576SJonas Devlieghere       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
18090db37576SJonas Devlieghere                                               CPU_SUBTYPE_ARM_V5TEJ);
18100db37576SJonas Devlieghere     else if (strstr(arch, "armv4t") == arch)
18110db37576SJonas Devlieghere       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
18120db37576SJonas Devlieghere                                               CPU_SUBTYPE_ARM_V4T);
18133c14438fSGreg Clayton     else if (strstr(arch, "arm") == arch)
18140db37576SJonas Devlieghere       return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
18150db37576SJonas Devlieghere                                               CPU_SUBTYPE_ARM_ALL);
18163c14438fSGreg Clayton   }
18173c14438fSGreg Clayton   return false;
18183c14438fSGreg Clayton }
18190c443e92SJason Molenda 
DNBDebugserverIsTranslated()18200c443e92SJason Molenda bool DNBDebugserverIsTranslated() {
18210c443e92SJason Molenda   int ret = 0;
18220c443e92SJason Molenda   size_t size = sizeof(ret);
18230c443e92SJason Molenda   if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1)
18240c443e92SJason Molenda     return false;
18250c443e92SJason Molenda   return ret == 1;
18260c443e92SJason Molenda }
1827