130fdc8d8SChris Lattner //===-- DNB.cpp -------------------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner //
1030fdc8d8SChris Lattner //  Created by Greg Clayton on 3/23/07.
1130fdc8d8SChris Lattner //
1230fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
1330fdc8d8SChris Lattner 
1430fdc8d8SChris Lattner #include "DNB.h"
151c73911dSJason Molenda #include <inttypes.h>
1630fdc8d8SChris Lattner #include <signal.h>
1730fdc8d8SChris Lattner #include <stdio.h>
1830fdc8d8SChris Lattner #include <stdlib.h>
1930fdc8d8SChris Lattner #include <sys/resource.h>
2030fdc8d8SChris Lattner #include <sys/stat.h>
2130fdc8d8SChris Lattner #include <sys/types.h>
2230fdc8d8SChris Lattner #include <sys/wait.h>
2330fdc8d8SChris Lattner #include <unistd.h>
2430fdc8d8SChris Lattner #include <sys/sysctl.h>
2530fdc8d8SChris Lattner #include <map>
2630fdc8d8SChris Lattner #include <vector>
27490bccd6SJim Ingham #include <libproc.h>
2830fdc8d8SChris Lattner 
2936a216eeSJason Molenda #if defined (__APPLE__)
3036a216eeSJason Molenda #include <pthread.h>
3136a216eeSJason Molenda #include <sched.h>
3236a216eeSJason Molenda #endif
3336a216eeSJason Molenda 
34a332978bSJason Molenda #define TRY_KQUEUE 1
35a332978bSJason Molenda 
36a332978bSJason Molenda #ifdef TRY_KQUEUE
37a332978bSJason Molenda     #include <sys/event.h>
38a332978bSJason Molenda     #include <sys/time.h>
39a332978bSJason Molenda     #ifdef NOTE_EXIT_DETAIL
40a332978bSJason Molenda         #define USE_KQUEUE
41a332978bSJason Molenda     #endif
42a332978bSJason Molenda #endif
43a332978bSJason Molenda 
4430fdc8d8SChris Lattner #include "MacOSX/MachProcess.h"
4530fdc8d8SChris Lattner #include "MacOSX/MachTask.h"
46705b1809SJason Molenda #include "MacOSX/Genealogy.h"
47705b1809SJason Molenda #include "MacOSX/ThreadInfo.h"
4830fdc8d8SChris Lattner #include "CFString.h"
4930fdc8d8SChris Lattner #include "DNBLog.h"
5030fdc8d8SChris Lattner #include "DNBDataRef.h"
5130fdc8d8SChris Lattner #include "DNBThreadResumeActions.h"
5230fdc8d8SChris Lattner #include "DNBTimer.h"
5348baf7a7SGreg Clayton #include "CFBundle.h"
5448baf7a7SGreg Clayton 
5530fdc8d8SChris Lattner 
567b0992d9SGreg Clayton typedef std::shared_ptr<MachProcess> MachProcessSP;
5730fdc8d8SChris Lattner typedef std::map<nub_process_t, MachProcessSP> ProcessMap;
5830fdc8d8SChris Lattner typedef ProcessMap::iterator ProcessMapIter;
5930fdc8d8SChris Lattner typedef ProcessMap::const_iterator ProcessMapConstIter;
6030fdc8d8SChris Lattner 
619eb4e038SGreg Clayton size_t GetAllInfos (std::vector<struct kinfo_proc>& proc_infos);
6230fdc8d8SChris Lattner static size_t GetAllInfosMatchingName (const char *process_name, std::vector<struct kinfo_proc>& matching_proc_infos);
6330fdc8d8SChris Lattner 
6430fdc8d8SChris Lattner //----------------------------------------------------------------------
6530fdc8d8SChris Lattner // A Thread safe singleton to get a process map pointer.
6630fdc8d8SChris Lattner //
6730fdc8d8SChris Lattner // Returns a pointer to the existing process map, or a pointer to a
6830fdc8d8SChris Lattner // newly created process map if CAN_CREATE is non-zero.
6930fdc8d8SChris Lattner //----------------------------------------------------------------------
7030fdc8d8SChris Lattner static ProcessMap*
7130fdc8d8SChris Lattner GetProcessMap(bool can_create)
7230fdc8d8SChris Lattner {
7330fdc8d8SChris Lattner     static ProcessMap* g_process_map_ptr = NULL;
7430fdc8d8SChris Lattner 
7530fdc8d8SChris Lattner     if (can_create && g_process_map_ptr == NULL)
7630fdc8d8SChris Lattner     {
7730fdc8d8SChris Lattner         static pthread_mutex_t g_process_map_mutex = PTHREAD_MUTEX_INITIALIZER;
7830fdc8d8SChris Lattner         PTHREAD_MUTEX_LOCKER (locker, &g_process_map_mutex);
7930fdc8d8SChris Lattner         if (g_process_map_ptr == NULL)
8030fdc8d8SChris Lattner             g_process_map_ptr = new ProcessMap;
8130fdc8d8SChris Lattner     }
8230fdc8d8SChris Lattner     return g_process_map_ptr;
8330fdc8d8SChris Lattner }
8430fdc8d8SChris Lattner 
8530fdc8d8SChris Lattner //----------------------------------------------------------------------
8630fdc8d8SChris Lattner // Add PID to the shared process pointer map.
8730fdc8d8SChris Lattner //
8830fdc8d8SChris Lattner // Return non-zero value if we succeed in adding the process to the map.
8930fdc8d8SChris Lattner // The only time this should fail is if we run out of memory and can't
9030fdc8d8SChris Lattner // allocate a ProcessMap.
9130fdc8d8SChris Lattner //----------------------------------------------------------------------
9230fdc8d8SChris Lattner static nub_bool_t
9330fdc8d8SChris Lattner AddProcessToMap (nub_process_t pid, MachProcessSP& procSP)
9430fdc8d8SChris Lattner {
9530fdc8d8SChris Lattner     ProcessMap* process_map = GetProcessMap(true);
9630fdc8d8SChris Lattner     if (process_map)
9730fdc8d8SChris Lattner     {
9830fdc8d8SChris Lattner         process_map->insert(std::make_pair(pid, procSP));
9930fdc8d8SChris Lattner         return true;
10030fdc8d8SChris Lattner     }
10130fdc8d8SChris Lattner     return false;
10230fdc8d8SChris Lattner }
10330fdc8d8SChris Lattner 
10430fdc8d8SChris Lattner //----------------------------------------------------------------------
10530fdc8d8SChris Lattner // Remove the shared pointer for PID from the process map.
10630fdc8d8SChris Lattner //
10730fdc8d8SChris Lattner // Returns the number of items removed from the process map.
10830fdc8d8SChris Lattner //----------------------------------------------------------------------
109ee2ed525SGreg Clayton //static size_t
110ee2ed525SGreg Clayton //RemoveProcessFromMap (nub_process_t pid)
111ee2ed525SGreg Clayton //{
112ee2ed525SGreg Clayton //    ProcessMap* process_map = GetProcessMap(false);
113ee2ed525SGreg Clayton //    if (process_map)
114ee2ed525SGreg Clayton //    {
115ee2ed525SGreg Clayton //        return process_map->erase(pid);
116ee2ed525SGreg Clayton //    }
117ee2ed525SGreg Clayton //    return 0;
118ee2ed525SGreg Clayton //}
11930fdc8d8SChris Lattner 
12030fdc8d8SChris Lattner //----------------------------------------------------------------------
12130fdc8d8SChris Lattner // Get the shared pointer for PID from the existing process map.
12230fdc8d8SChris Lattner //
12330fdc8d8SChris Lattner // Returns true if we successfully find a shared pointer to a
12430fdc8d8SChris Lattner // MachProcess object.
12530fdc8d8SChris Lattner //----------------------------------------------------------------------
12630fdc8d8SChris Lattner static nub_bool_t
12730fdc8d8SChris Lattner GetProcessSP (nub_process_t pid, MachProcessSP& procSP)
12830fdc8d8SChris Lattner {
12930fdc8d8SChris Lattner     ProcessMap* process_map = GetProcessMap(false);
13030fdc8d8SChris Lattner     if (process_map != NULL)
13130fdc8d8SChris Lattner     {
13230fdc8d8SChris Lattner         ProcessMapIter pos = process_map->find(pid);
13330fdc8d8SChris Lattner         if (pos != process_map->end())
13430fdc8d8SChris Lattner         {
13530fdc8d8SChris Lattner             procSP = pos->second;
13630fdc8d8SChris Lattner             return true;
13730fdc8d8SChris Lattner         }
13830fdc8d8SChris Lattner     }
13930fdc8d8SChris Lattner     procSP.reset();
14030fdc8d8SChris Lattner     return false;
14130fdc8d8SChris Lattner }
14230fdc8d8SChris Lattner 
143a332978bSJason Molenda #ifdef USE_KQUEUE
144a332978bSJason Molenda void *
145a332978bSJason Molenda kqueue_thread (void *arg)
146a332978bSJason Molenda {
147a332978bSJason Molenda     int kq_id = (int) (intptr_t) arg;
148a332978bSJason Molenda 
14936a216eeSJason Molenda #if defined (__APPLE__)
15036a216eeSJason Molenda     pthread_setname_np ("kqueue thread");
15136a216eeSJason Molenda #if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
15236a216eeSJason Molenda     struct sched_param thread_param;
15336a216eeSJason Molenda     int thread_sched_policy;
15436a216eeSJason Molenda     if (pthread_getschedparam(pthread_self(), &thread_sched_policy, &thread_param) == 0)
15536a216eeSJason Molenda     {
15636a216eeSJason Molenda         thread_param.sched_priority = 47;
15736a216eeSJason Molenda         pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
15836a216eeSJason Molenda     }
15936a216eeSJason Molenda #endif
16036a216eeSJason Molenda #endif
16136a216eeSJason Molenda 
162a332978bSJason Molenda     struct kevent death_event;
163a332978bSJason Molenda     while (1)
164a332978bSJason Molenda     {
165a332978bSJason Molenda         int n_events = kevent (kq_id, NULL, 0, &death_event, 1, NULL);
166a332978bSJason Molenda         if (n_events == -1)
167a332978bSJason Molenda         {
168a332978bSJason Molenda             if (errno == EINTR)
169a332978bSJason Molenda                 continue;
170a332978bSJason Molenda             else
171a332978bSJason Molenda             {
172a332978bSJason Molenda                 DNBLogError ("kqueue failed with error: (%d): %s", errno, strerror(errno));
173a332978bSJason Molenda                 return NULL;
174a332978bSJason Molenda             }
175a332978bSJason Molenda         }
176a332978bSJason Molenda         else if (death_event.flags & EV_ERROR)
177a332978bSJason Molenda         {
178ee2ed525SGreg Clayton             int error_no = static_cast<int>(death_event.data);
179ee2ed525SGreg Clayton             const char *error_str = strerror(error_no);
180a332978bSJason Molenda             if (error_str == NULL)
181a332978bSJason Molenda                 error_str = "Unknown error";
182a332978bSJason Molenda             DNBLogError ("Failed to initialize kqueue event: (%d): %s", error_no, error_str );
183a332978bSJason Molenda             return NULL;
184a332978bSJason Molenda         }
185a332978bSJason Molenda         else
186a332978bSJason Molenda         {
187a332978bSJason Molenda             int status;
188040c560fSGreg Clayton             const pid_t pid = (pid_t)death_event.ident;
189040c560fSGreg Clayton             const pid_t child_pid = waitpid (pid, &status, 0);
190040c560fSGreg Clayton 
191040c560fSGreg Clayton 
192040c560fSGreg Clayton             bool exited = false;
193040c560fSGreg Clayton             int signal = 0;
194040c560fSGreg Clayton             int exit_status = 0;
195040c560fSGreg Clayton             if (WIFSTOPPED(status))
196040c560fSGreg Clayton             {
197040c560fSGreg Clayton                 signal = WSTOPSIG(status);
198040c560fSGreg Clayton                 DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> STOPPED (signal = %i)", child_pid, signal);
199040c560fSGreg Clayton             }
200040c560fSGreg Clayton             else if (WIFEXITED(status))
201040c560fSGreg Clayton             {
202040c560fSGreg Clayton                 exit_status = WEXITSTATUS(status);
203040c560fSGreg Clayton                 exited = true;
204040c560fSGreg Clayton                 DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> EXITED (status = %i)", child_pid, exit_status);
205040c560fSGreg Clayton             }
206040c560fSGreg Clayton             else if (WIFSIGNALED(status))
207040c560fSGreg Clayton             {
208040c560fSGreg Clayton                 signal = WTERMSIG(status);
209040c560fSGreg Clayton                 if (child_pid == abs(pid))
210040c560fSGreg Clayton                 {
211040c560fSGreg Clayton                     DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> SIGNALED and EXITED (signal = %i)", child_pid, signal);
212040c560fSGreg Clayton                     char exit_info[64];
213040c560fSGreg Clayton                     ::snprintf (exit_info, sizeof(exit_info), "Terminated due to signal %i", signal);
214040c560fSGreg Clayton                     DNBProcessSetExitInfo (child_pid, exit_info);
215040c560fSGreg Clayton                     exited = true;
216040c560fSGreg Clayton                     exit_status = INT8_MAX;
217040c560fSGreg Clayton                 }
218040c560fSGreg Clayton                 else
219040c560fSGreg Clayton                 {
220040c560fSGreg Clayton                     DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> SIGNALED (signal = %i)", child_pid, signal);
221040c560fSGreg Clayton                 }
222040c560fSGreg Clayton             }
223040c560fSGreg Clayton 
224040c560fSGreg Clayton             if (exited)
225040c560fSGreg Clayton             {
226a332978bSJason Molenda                 if (death_event.data & NOTE_EXIT_MEMORY)
2270c7ebe96SJim Ingham                     DNBProcessSetExitInfo (child_pid, "Terminated due to memory issue");
228a332978bSJason Molenda                 else if (death_event.data & NOTE_EXIT_DECRYPTFAIL)
229a332978bSJason Molenda                     DNBProcessSetExitInfo (child_pid, "Terminated due to decrypt failure");
230a332978bSJason Molenda                 else if (death_event.data & NOTE_EXIT_CSERROR)
231a332978bSJason Molenda                     DNBProcessSetExitInfo (child_pid, "Terminated due to code signing error");
232a332978bSJason Molenda 
233040c560fSGreg Clayton                 DNBLogThreadedIf(LOG_PROCESS, "waitpid_process_thread (): setting exit status for pid = %i to %i", child_pid, exit_status);
234a332978bSJason Molenda                 DNBProcessSetExitStatus (child_pid, status);
235a332978bSJason Molenda                 return NULL;
236a332978bSJason Molenda             }
237a332978bSJason Molenda         }
238a332978bSJason Molenda     }
239040c560fSGreg Clayton }
240a332978bSJason Molenda 
241a332978bSJason Molenda static bool
242a332978bSJason Molenda spawn_kqueue_thread (pid_t pid)
243a332978bSJason Molenda {
244a332978bSJason Molenda     pthread_t thread;
245a332978bSJason Molenda     int kq_id;
246a332978bSJason Molenda 
247a332978bSJason Molenda     kq_id = kqueue();
248a332978bSJason Molenda     if (kq_id == -1)
249a332978bSJason Molenda     {
250a332978bSJason Molenda         DNBLogError ("Could not get kqueue for pid = %i.", pid);
251a332978bSJason Molenda         return false;
252a332978bSJason Molenda     }
253a332978bSJason Molenda 
254a332978bSJason Molenda     struct kevent reg_event;
255a332978bSJason Molenda 
25660089245SJim Ingham     EV_SET(&reg_event, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT|NOTE_EXITSTATUS|NOTE_EXIT_DETAIL, 0, NULL);
257a332978bSJason Molenda     // Register the event:
258a332978bSJason Molenda     int result = kevent (kq_id, &reg_event, 1, NULL, 0, NULL);
259a332978bSJason Molenda     if (result != 0)
260a332978bSJason Molenda     {
261a332978bSJason Molenda         DNBLogError ("Failed to register kqueue NOTE_EXIT event for pid %i, error: %d.", pid, result);
262a332978bSJason Molenda         return false;
263a332978bSJason Molenda     }
264a332978bSJason Molenda 
265a332978bSJason Molenda     int ret = ::pthread_create (&thread, NULL, kqueue_thread, (void *)(intptr_t)kq_id);
266a332978bSJason Molenda 
267a332978bSJason Molenda     // pthread_create returns 0 if successful
268a332978bSJason Molenda     if (ret == 0)
269a332978bSJason Molenda     {
270a332978bSJason Molenda         ::pthread_detach (thread);
271a332978bSJason Molenda         return true;
272a332978bSJason Molenda     }
273a332978bSJason Molenda     return false;
274a332978bSJason Molenda }
275a332978bSJason Molenda #endif // #if USE_KQUEUE
27630fdc8d8SChris Lattner 
27730fdc8d8SChris Lattner static void *
27830fdc8d8SChris Lattner waitpid_thread (void *arg)
27930fdc8d8SChris Lattner {
28030fdc8d8SChris Lattner     const pid_t pid = (pid_t)(intptr_t)arg;
28130fdc8d8SChris Lattner     int status;
28236a216eeSJason Molenda 
28336a216eeSJason Molenda #if defined (__APPLE__)
28436a216eeSJason Molenda     pthread_setname_np ("waitpid thread");
28536a216eeSJason Molenda #if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
28636a216eeSJason Molenda     struct sched_param thread_param;
28736a216eeSJason Molenda     int thread_sched_policy;
28836a216eeSJason Molenda     if (pthread_getschedparam(pthread_self(), &thread_sched_policy, &thread_param) == 0)
28936a216eeSJason Molenda     {
29036a216eeSJason Molenda         thread_param.sched_priority = 47;
29136a216eeSJason Molenda         pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
29236a216eeSJason Molenda     }
29336a216eeSJason Molenda #endif
29436a216eeSJason Molenda #endif
29536a216eeSJason Molenda 
29630fdc8d8SChris Lattner     while (1)
29730fdc8d8SChris Lattner     {
29830fdc8d8SChris Lattner         pid_t child_pid = waitpid(pid, &status, 0);
2996467ff9aSGreg Clayton         DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): waitpid (pid = %i, &status, 0) => %i, status = %i, errno = %i", pid, child_pid, status, errno);
30030fdc8d8SChris Lattner 
30130fdc8d8SChris Lattner         if (child_pid < 0)
30230fdc8d8SChris Lattner         {
30330fdc8d8SChris Lattner             if (errno == EINTR)
30430fdc8d8SChris Lattner                 continue;
30530fdc8d8SChris Lattner             break;
30630fdc8d8SChris Lattner         }
30730fdc8d8SChris Lattner         else
30830fdc8d8SChris Lattner         {
30930fdc8d8SChris Lattner             if (WIFSTOPPED(status))
31030fdc8d8SChris Lattner             {
31130fdc8d8SChris Lattner                 continue;
31230fdc8d8SChris Lattner             }
31330fdc8d8SChris Lattner             else// if (WIFEXITED(status) || WIFSIGNALED(status))
31430fdc8d8SChris Lattner             {
3156467ff9aSGreg Clayton                 DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): setting exit status for pid = %i to %i", child_pid, status);
31630fdc8d8SChris Lattner                 DNBProcessSetExitStatus (child_pid, status);
31730fdc8d8SChris Lattner                 return NULL;
31830fdc8d8SChris Lattner             }
31930fdc8d8SChris Lattner         }
32030fdc8d8SChris Lattner     }
32130fdc8d8SChris Lattner 
32230fdc8d8SChris Lattner     // We should never exit as long as our child process is alive, so if we
32330fdc8d8SChris Lattner     // do something else went wrong and we should exit...
3246467ff9aSGreg Clayton     DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): main loop exited, setting exit status to an invalid value (-1) for pid %i", pid);
32530fdc8d8SChris Lattner     DNBProcessSetExitStatus (pid, -1);
32630fdc8d8SChris Lattner     return NULL;
32730fdc8d8SChris Lattner }
32830fdc8d8SChris Lattner static bool
32930fdc8d8SChris Lattner spawn_waitpid_thread (pid_t pid)
33030fdc8d8SChris Lattner {
331a332978bSJason Molenda #ifdef USE_KQUEUE
332a332978bSJason Molenda     bool success = spawn_kqueue_thread (pid);
333a332978bSJason Molenda     if (success)
334a332978bSJason Molenda         return true;
335a332978bSJason Molenda #endif
336a332978bSJason Molenda 
33727148b3dSJason Molenda     pthread_t thread;
33827148b3dSJason Molenda     int ret = ::pthread_create (&thread, NULL, waitpid_thread, (void *)(intptr_t)pid);
33927148b3dSJason Molenda     // pthread_create returns 0 if successful
34027148b3dSJason Molenda     if (ret == 0)
34130fdc8d8SChris Lattner     {
34230fdc8d8SChris Lattner         ::pthread_detach (thread);
34330fdc8d8SChris Lattner         return true;
34430fdc8d8SChris Lattner     }
34530fdc8d8SChris Lattner     return false;
34630fdc8d8SChris Lattner }
34730fdc8d8SChris Lattner 
34830fdc8d8SChris Lattner nub_process_t
34930fdc8d8SChris Lattner DNBProcessLaunch (const char *path,
35030fdc8d8SChris Lattner                   char const *argv[],
35130fdc8d8SChris Lattner                   const char *envp[],
352aaa0ba31SBruce Mitchener                   const char *working_directory, // NULL => don't change, non-NULL => set working directory for inferior to this
3536779606aSGreg Clayton                   const char *stdin_path,
3546779606aSGreg Clayton                   const char *stdout_path,
3556779606aSGreg Clayton                   const char *stderr_path,
356f8da8631SCaroline Tice                   bool no_stdio,
35730fdc8d8SChris Lattner                   nub_launch_flavor_t launch_flavor,
358f681b94fSGreg Clayton                   int disable_aslr,
359a332978bSJason Molenda                   const char *event_data,
36030fdc8d8SChris Lattner                   char *err_str,
36130fdc8d8SChris Lattner                   size_t err_len)
36230fdc8d8SChris Lattner {
36343e0af06SGreg Clayton     DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv = %p, envp = %p, working_dir=%s, stdin=%s, stdout=%s, stderr=%s, no-stdio=%i, launch_flavor = %u, disable_aslr = %d, err = %p, err_len = %llu) called...",
364bd82a5d2SGreg Clayton                      __FUNCTION__,
365bd82a5d2SGreg Clayton                      path,
366bd82a5d2SGreg Clayton                      argv,
367bd82a5d2SGreg Clayton                      envp,
368bd82a5d2SGreg Clayton                      working_directory,
369bd82a5d2SGreg Clayton                      stdin_path,
370bd82a5d2SGreg Clayton                      stdout_path,
371bd82a5d2SGreg Clayton                      stderr_path,
372bd82a5d2SGreg Clayton                      no_stdio,
373bd82a5d2SGreg Clayton                      launch_flavor,
374bd82a5d2SGreg Clayton                      disable_aslr,
375bd82a5d2SGreg Clayton                      err_str,
37643e0af06SGreg Clayton                      (uint64_t)err_len);
37730fdc8d8SChris Lattner 
37830fdc8d8SChris Lattner     if (err_str && err_len > 0)
37930fdc8d8SChris Lattner         err_str[0] = '\0';
38030fdc8d8SChris Lattner     struct stat path_stat;
38130fdc8d8SChris Lattner     if (::stat(path, &path_stat) == -1)
38230fdc8d8SChris Lattner     {
38330fdc8d8SChris Lattner         char stat_error[256];
38430fdc8d8SChris Lattner         ::strerror_r (errno, stat_error, sizeof(stat_error));
38530fdc8d8SChris Lattner         snprintf(err_str, err_len, "%s (%s)", stat_error, path);
38630fdc8d8SChris Lattner         return INVALID_NUB_PROCESS;
38730fdc8d8SChris Lattner     }
38830fdc8d8SChris Lattner 
38930fdc8d8SChris Lattner     MachProcessSP processSP (new MachProcess);
39030fdc8d8SChris Lattner     if (processSP.get())
39130fdc8d8SChris Lattner     {
39230fdc8d8SChris Lattner         DNBError launch_err;
3936779606aSGreg Clayton         pid_t pid = processSP->LaunchForDebug (path,
3946779606aSGreg Clayton                                                argv,
3956779606aSGreg Clayton                                                envp,
3966779606aSGreg Clayton                                                working_directory,
3976779606aSGreg Clayton                                                stdin_path,
3986779606aSGreg Clayton                                                stdout_path,
3996779606aSGreg Clayton                                                stderr_path,
4006779606aSGreg Clayton                                                no_stdio,
4016779606aSGreg Clayton                                                launch_flavor,
4026779606aSGreg Clayton                                                disable_aslr,
403a332978bSJason Molenda                                                event_data,
4046779606aSGreg Clayton                                                launch_err);
40530fdc8d8SChris Lattner         if (err_str)
40630fdc8d8SChris Lattner         {
40730fdc8d8SChris Lattner             *err_str = '\0';
40830fdc8d8SChris Lattner             if (launch_err.Fail())
40930fdc8d8SChris Lattner             {
41030fdc8d8SChris Lattner                 const char *launch_err_str = launch_err.AsString();
41130fdc8d8SChris Lattner                 if (launch_err_str)
41230fdc8d8SChris Lattner                 {
41330fdc8d8SChris Lattner                     strncpy(err_str, launch_err_str, err_len-1);
41430fdc8d8SChris Lattner                     err_str[err_len-1] = '\0';  // Make sure the error string is terminated
41530fdc8d8SChris Lattner                 }
41630fdc8d8SChris Lattner             }
41730fdc8d8SChris Lattner         }
41830fdc8d8SChris Lattner 
41930fdc8d8SChris Lattner         DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) new pid is %d...", pid);
42030fdc8d8SChris Lattner 
42130fdc8d8SChris Lattner         if (pid != INVALID_NUB_PROCESS)
42230fdc8d8SChris Lattner         {
42330fdc8d8SChris Lattner             // Spawn a thread to reap our child inferior process...
42430fdc8d8SChris Lattner             spawn_waitpid_thread (pid);
42530fdc8d8SChris Lattner 
42630fdc8d8SChris Lattner             if (processSP->Task().TaskPortForProcessID (launch_err) == TASK_NULL)
42730fdc8d8SChris Lattner             {
42830fdc8d8SChris Lattner                 // We failed to get the task for our process ID which is bad.
429fb640c2dSGreg Clayton                 // Kill our process otherwise it will be stopped at the entry
430fb640c2dSGreg Clayton                 // point and get reparented to someone else and never go away.
431153c8e0cSJason Molenda                 DNBLog ("Could not get task port for process, sending SIGKILL and exiting.");
432fb640c2dSGreg Clayton                 kill (SIGKILL, pid);
433fb640c2dSGreg Clayton 
43430fdc8d8SChris Lattner                 if (err_str && err_len > 0)
43530fdc8d8SChris Lattner                 {
43630fdc8d8SChris Lattner                     if (launch_err.AsString())
43730fdc8d8SChris Lattner                     {
43830fdc8d8SChris Lattner                         ::snprintf (err_str, err_len, "failed to get the task for process %i (%s)", pid, launch_err.AsString());
43930fdc8d8SChris Lattner                     }
44030fdc8d8SChris Lattner                     else
44130fdc8d8SChris Lattner                     {
44230fdc8d8SChris Lattner                         ::snprintf (err_str, err_len, "failed to get the task for process %i", pid);
44330fdc8d8SChris Lattner                     }
44430fdc8d8SChris Lattner                 }
44530fdc8d8SChris Lattner             }
44630fdc8d8SChris Lattner             else
44730fdc8d8SChris Lattner             {
448b786e7d0SCharles Davis                 bool res = AddProcessToMap(pid, processSP);
449*8a67bf72SBruce Mitchener                 UNUSED_IF_ASSERT_DISABLED(res);
450b786e7d0SCharles Davis                 assert(res && "Couldn't add process to map!");
45130fdc8d8SChris Lattner                 return pid;
45230fdc8d8SChris Lattner             }
45330fdc8d8SChris Lattner         }
45430fdc8d8SChris Lattner     }
45530fdc8d8SChris Lattner     return INVALID_NUB_PROCESS;
45630fdc8d8SChris Lattner }
45730fdc8d8SChris Lattner 
45830fdc8d8SChris Lattner nub_process_t
45930fdc8d8SChris Lattner DNBProcessAttachByName (const char *name, struct timespec *timeout, char *err_str, size_t err_len)
46030fdc8d8SChris Lattner {
46130fdc8d8SChris Lattner     if (err_str && err_len > 0)
46230fdc8d8SChris Lattner         err_str[0] = '\0';
46330fdc8d8SChris Lattner     std::vector<struct kinfo_proc> matching_proc_infos;
46430fdc8d8SChris Lattner     size_t num_matching_proc_infos = GetAllInfosMatchingName(name, matching_proc_infos);
46530fdc8d8SChris Lattner     if (num_matching_proc_infos == 0)
46630fdc8d8SChris Lattner     {
46730fdc8d8SChris Lattner         DNBLogError ("error: no processes match '%s'\n", name);
46830fdc8d8SChris Lattner         return INVALID_NUB_PROCESS;
46930fdc8d8SChris Lattner     }
47030fdc8d8SChris Lattner     else if (num_matching_proc_infos > 1)
47130fdc8d8SChris Lattner     {
47243e0af06SGreg Clayton         DNBLogError ("error: %llu processes match '%s':\n", (uint64_t)num_matching_proc_infos, name);
47330fdc8d8SChris Lattner         size_t i;
47430fdc8d8SChris Lattner         for (i=0; i<num_matching_proc_infos; ++i)
47530fdc8d8SChris Lattner             DNBLogError ("%6u - %s\n", matching_proc_infos[i].kp_proc.p_pid, matching_proc_infos[i].kp_proc.p_comm);
47630fdc8d8SChris Lattner         return INVALID_NUB_PROCESS;
47730fdc8d8SChris Lattner     }
4783af9ea56SGreg Clayton 
47930fdc8d8SChris Lattner     return DNBProcessAttach (matching_proc_infos[0].kp_proc.p_pid, timeout, err_str, err_len);
48030fdc8d8SChris Lattner }
48130fdc8d8SChris Lattner 
48230fdc8d8SChris Lattner nub_process_t
48330fdc8d8SChris Lattner DNBProcessAttach (nub_process_t attach_pid, struct timespec *timeout, char *err_str, size_t err_len)
48430fdc8d8SChris Lattner {
48530fdc8d8SChris Lattner     if (err_str && err_len > 0)
48630fdc8d8SChris Lattner         err_str[0] = '\0';
48730fdc8d8SChris Lattner 
48864503c81SJohnny Chen     pid_t pid = INVALID_NUB_PROCESS;
48930fdc8d8SChris Lattner     MachProcessSP processSP(new MachProcess);
49030fdc8d8SChris Lattner     if (processSP.get())
49130fdc8d8SChris Lattner     {
49230fdc8d8SChris Lattner         DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...", attach_pid);
49330fdc8d8SChris Lattner         pid = processSP->AttachForDebug (attach_pid, err_str,  err_len);
49430fdc8d8SChris Lattner 
49530fdc8d8SChris Lattner         if (pid != INVALID_NUB_PROCESS)
49630fdc8d8SChris Lattner         {
497b786e7d0SCharles Davis             bool res = AddProcessToMap(pid, processSP);
498*8a67bf72SBruce 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 
50430fdc8d8SChris Lattner     while (pid != INVALID_NUB_PROCESS)
50530fdc8d8SChris Lattner     {
50630fdc8d8SChris Lattner         // Wait for process to start up and hit entry point
5073af9ea56SGreg Clayton         DNBLogThreadedIf (LOG_PROCESS,
5083af9ea56SGreg Clayton                           "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...",
5093af9ea56SGreg Clayton                           __FUNCTION__,
5103af9ea56SGreg Clayton                           pid);
51130fdc8d8SChris Lattner         nub_event_t set_events = DNBProcessWaitForEvents (pid,
51230fdc8d8SChris Lattner                                                           eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged,
5133af9ea56SGreg Clayton                                                           true,
5143af9ea56SGreg Clayton                                                           timeout);
5153af9ea56SGreg Clayton 
5163af9ea56SGreg Clayton         DNBLogThreadedIf (LOG_PROCESS,
5173af9ea56SGreg Clayton                           "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x",
5183af9ea56SGreg Clayton                           __FUNCTION__,
5193af9ea56SGreg Clayton                           pid,
5203af9ea56SGreg Clayton                           set_events);
52130fdc8d8SChris Lattner 
52230fdc8d8SChris Lattner         if (set_events == 0)
52330fdc8d8SChris Lattner         {
52430fdc8d8SChris Lattner             if (err_str && err_len > 0)
52530fdc8d8SChris Lattner                 snprintf(err_str, err_len, "operation timed out");
52630fdc8d8SChris Lattner             pid = INVALID_NUB_PROCESS;
52730fdc8d8SChris Lattner         }
52830fdc8d8SChris Lattner         else
52930fdc8d8SChris Lattner         {
53030fdc8d8SChris Lattner             if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
53130fdc8d8SChris Lattner             {
53230fdc8d8SChris Lattner                 nub_state_t pid_state = DNBProcessGetState (pid);
53330fdc8d8SChris Lattner                 DNBLogThreadedIf (LOG_PROCESS, "%s process %4.4x state changed (eEventProcessStateChanged): %s",
53430fdc8d8SChris Lattner                         __FUNCTION__, pid, DNBStateAsString(pid_state));
53530fdc8d8SChris Lattner 
53630fdc8d8SChris Lattner                 switch (pid_state)
53730fdc8d8SChris Lattner                 {
53830fdc8d8SChris Lattner                     default:
53930fdc8d8SChris Lattner                     case eStateInvalid:
54030fdc8d8SChris Lattner                     case eStateUnloaded:
54130fdc8d8SChris Lattner                     case eStateAttaching:
54230fdc8d8SChris Lattner                     case eStateLaunching:
54330fdc8d8SChris Lattner                     case eStateSuspended:
54430fdc8d8SChris Lattner                         break;  // Ignore
54530fdc8d8SChris Lattner 
54630fdc8d8SChris Lattner                     case eStateRunning:
54730fdc8d8SChris Lattner                     case eStateStepping:
54830fdc8d8SChris Lattner                         // Still waiting to stop at entry point...
54930fdc8d8SChris Lattner                         break;
55030fdc8d8SChris Lattner 
55130fdc8d8SChris Lattner                     case eStateStopped:
55230fdc8d8SChris Lattner                     case eStateCrashed:
55330fdc8d8SChris Lattner                         return pid;
5543af9ea56SGreg Clayton 
55530fdc8d8SChris Lattner                     case eStateDetached:
55630fdc8d8SChris Lattner                     case eStateExited:
55730fdc8d8SChris Lattner                         if (err_str && err_len > 0)
55830fdc8d8SChris Lattner                             snprintf(err_str, err_len, "process exited");
55930fdc8d8SChris Lattner                         return INVALID_NUB_PROCESS;
56030fdc8d8SChris Lattner                 }
56130fdc8d8SChris Lattner             }
56230fdc8d8SChris Lattner 
56330fdc8d8SChris Lattner             DNBProcessResetEvents(pid, set_events);
56430fdc8d8SChris Lattner         }
56530fdc8d8SChris Lattner     }
56630fdc8d8SChris Lattner 
56730fdc8d8SChris Lattner     return INVALID_NUB_PROCESS;
56830fdc8d8SChris Lattner }
56930fdc8d8SChris Lattner 
5709eb4e038SGreg Clayton size_t
57130fdc8d8SChris Lattner GetAllInfos (std::vector<struct kinfo_proc>& proc_infos)
57230fdc8d8SChris Lattner {
5739eb4e038SGreg Clayton     size_t size = 0;
57430fdc8d8SChris Lattner     int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
575c1fdb889SJim Ingham     u_int namelen = sizeof(name)/sizeof(int);
57630fdc8d8SChris Lattner     int err;
57730fdc8d8SChris Lattner 
57830fdc8d8SChris Lattner     // Try to find out how many processes are around so we can
57930fdc8d8SChris Lattner     // size the buffer appropriately.  sysctl's man page specifically suggests
58030fdc8d8SChris Lattner     // this approach, and says it returns a bit larger size than needed to
58130fdc8d8SChris Lattner     // handle any new processes created between then and now.
58230fdc8d8SChris Lattner 
58330fdc8d8SChris Lattner     err = ::sysctl (name, namelen, NULL, &size, NULL, 0);
58430fdc8d8SChris Lattner 
58530fdc8d8SChris Lattner     if ((err < 0) && (err != ENOMEM))
58630fdc8d8SChris Lattner     {
58730fdc8d8SChris Lattner         proc_infos.clear();
58830fdc8d8SChris Lattner         perror("sysctl (mib, miblen, NULL, &num_processes, NULL, 0)");
58930fdc8d8SChris Lattner         return 0;
59030fdc8d8SChris Lattner     }
59130fdc8d8SChris Lattner 
59230fdc8d8SChris Lattner 
59330fdc8d8SChris Lattner     // Increase the size of the buffer by a few processes in case more have
59430fdc8d8SChris Lattner     // been spawned
59530fdc8d8SChris Lattner     proc_infos.resize (size / sizeof(struct kinfo_proc));
59630fdc8d8SChris Lattner     size = proc_infos.size() * sizeof(struct kinfo_proc);   // Make sure we don't exceed our resize...
59730fdc8d8SChris Lattner     err = ::sysctl (name, namelen, &proc_infos[0], &size, NULL, 0);
59830fdc8d8SChris Lattner     if (err < 0)
59930fdc8d8SChris Lattner     {
60030fdc8d8SChris Lattner         proc_infos.clear();
60130fdc8d8SChris Lattner         return 0;
60230fdc8d8SChris Lattner     }
60330fdc8d8SChris Lattner 
60430fdc8d8SChris Lattner     // Trim down our array to fit what we actually got back
60530fdc8d8SChris Lattner     proc_infos.resize(size / sizeof(struct kinfo_proc));
60630fdc8d8SChris Lattner     return proc_infos.size();
60730fdc8d8SChris Lattner }
60830fdc8d8SChris Lattner 
60930fdc8d8SChris Lattner static size_t
61030fdc8d8SChris Lattner GetAllInfosMatchingName(const char *full_process_name, std::vector<struct kinfo_proc>& matching_proc_infos)
61130fdc8d8SChris Lattner {
61230fdc8d8SChris Lattner 
61330fdc8d8SChris Lattner     matching_proc_infos.clear();
61430fdc8d8SChris Lattner     if (full_process_name && full_process_name[0])
61530fdc8d8SChris Lattner     {
61630fdc8d8SChris Lattner         // We only get the process name, not the full path, from the proc_info.  So just take the
61730fdc8d8SChris Lattner         // base name of the process name...
61830fdc8d8SChris Lattner         const char *process_name;
61930fdc8d8SChris Lattner         process_name = strrchr (full_process_name, '/');
62030fdc8d8SChris Lattner         if (process_name == NULL)
62130fdc8d8SChris Lattner             process_name = full_process_name;
62230fdc8d8SChris Lattner         else
62330fdc8d8SChris Lattner             process_name++;
62430fdc8d8SChris Lattner 
625ee2ed525SGreg Clayton         const size_t process_name_len = strlen(process_name);
62630fdc8d8SChris Lattner         std::vector<struct kinfo_proc> proc_infos;
62730fdc8d8SChris Lattner         const size_t num_proc_infos = GetAllInfos(proc_infos);
62830fdc8d8SChris Lattner         if (num_proc_infos > 0)
62930fdc8d8SChris Lattner         {
63030fdc8d8SChris Lattner             uint32_t i;
63130fdc8d8SChris Lattner             for (i=0; i<num_proc_infos; i++)
63230fdc8d8SChris Lattner             {
63330fdc8d8SChris Lattner                 // Skip zombie processes and processes with unset status
63430fdc8d8SChris Lattner                 if (proc_infos[i].kp_proc.p_stat == 0 || proc_infos[i].kp_proc.p_stat == SZOMB)
63530fdc8d8SChris Lattner                     continue;
63630fdc8d8SChris Lattner 
63730fdc8d8SChris Lattner                 // Check for process by name. We only check the first MAXCOMLEN
63830fdc8d8SChris Lattner                 // chars as that is all that kp_proc.p_comm holds.
639490bccd6SJim Ingham 
6407dab2be2SGreg Clayton                 if (::strncasecmp(process_name, proc_infos[i].kp_proc.p_comm, MAXCOMLEN) == 0)
6417dab2be2SGreg Clayton                 {
6427dab2be2SGreg Clayton                     if (process_name_len > MAXCOMLEN)
6437dab2be2SGreg Clayton                     {
6447dab2be2SGreg Clayton                         // We found a matching process name whose first MAXCOMLEN
6457dab2be2SGreg Clayton                         // characters match, but there is more to the name than
646490bccd6SJim Ingham                         // this. We need to get the full process name.  Use proc_pidpath, which will get
647490bccd6SJim Ingham                         // us the full path to the executed process.
6487dab2be2SGreg Clayton 
649490bccd6SJim Ingham                         char proc_path_buf[PATH_MAX];
6507dab2be2SGreg Clayton 
651490bccd6SJim Ingham                         int return_val = proc_pidpath (proc_infos[i].kp_proc.p_pid, proc_path_buf, PATH_MAX);
652490bccd6SJim Ingham                         if (return_val > 0)
6537dab2be2SGreg Clayton                         {
654490bccd6SJim Ingham                             // Okay, now search backwards from that to see if there is a
655490bccd6SJim Ingham                             // slash in the name.  Note, even though we got all the args we don't care
656490bccd6SJim Ingham                             // because the list data is just a bunch of concatenated null terminated strings
657490bccd6SJim Ingham                             // so strrchr will start from the end of argv0.
658490bccd6SJim Ingham 
659490bccd6SJim Ingham                             const char *argv_basename = strrchr(proc_path_buf, '/');
6607dab2be2SGreg Clayton                             if (argv_basename)
6617dab2be2SGreg Clayton                             {
6627dab2be2SGreg Clayton                                 // Skip the '/'
6637dab2be2SGreg Clayton                                 ++argv_basename;
6647dab2be2SGreg Clayton                             }
6657dab2be2SGreg Clayton                             else
6667dab2be2SGreg Clayton                             {
6677dab2be2SGreg Clayton                                 // We didn't find a directory delimiter in the process argv[0], just use what was in there
668490bccd6SJim Ingham                                 argv_basename = proc_path_buf;
6697dab2be2SGreg Clayton                             }
6707dab2be2SGreg Clayton 
6717dab2be2SGreg Clayton                             if (argv_basename)
6727dab2be2SGreg Clayton                             {
6737dab2be2SGreg Clayton                                 if (::strncasecmp(process_name, argv_basename, PATH_MAX) == 0)
6747dab2be2SGreg Clayton                                 {
6757dab2be2SGreg Clayton                                     matching_proc_infos.push_back(proc_infos[i]);
6767dab2be2SGreg Clayton                                 }
6777dab2be2SGreg Clayton                             }
6787dab2be2SGreg Clayton                         }
6797dab2be2SGreg Clayton                     }
6807dab2be2SGreg Clayton                     else
68130fdc8d8SChris Lattner                     {
68230fdc8d8SChris Lattner                         // We found a matching process, add it to our list
68330fdc8d8SChris Lattner                         matching_proc_infos.push_back(proc_infos[i]);
68430fdc8d8SChris Lattner                     }
68530fdc8d8SChris Lattner                 }
68630fdc8d8SChris Lattner             }
68730fdc8d8SChris Lattner         }
6887dab2be2SGreg Clayton     }
68930fdc8d8SChris Lattner     // return the newly added matches.
69030fdc8d8SChris Lattner     return matching_proc_infos.size();
69130fdc8d8SChris Lattner }
69230fdc8d8SChris Lattner 
69330fdc8d8SChris Lattner nub_process_t
69419388cfcSGreg Clayton DNBProcessAttachWait (const char *waitfor_process_name,
69519388cfcSGreg Clayton                       nub_launch_flavor_t launch_flavor,
696cd16df91SJim Ingham                       bool ignore_existing,
69719388cfcSGreg Clayton                       struct timespec *timeout_abstime,
69819388cfcSGreg Clayton                       useconds_t waitfor_interval,
69919388cfcSGreg Clayton                       char *err_str,
70019388cfcSGreg Clayton                       size_t err_len,
70130fdc8d8SChris Lattner                       DNBShouldCancelCallback should_cancel_callback,
70230fdc8d8SChris Lattner                       void *callback_data)
70330fdc8d8SChris Lattner {
70430fdc8d8SChris Lattner     DNBError prepare_error;
70530fdc8d8SChris Lattner     std::vector<struct kinfo_proc> exclude_proc_infos;
70630fdc8d8SChris Lattner     size_t num_exclude_proc_infos;
70730fdc8d8SChris Lattner 
70830fdc8d8SChris Lattner     // If the PrepareForAttach returns a valid token, use  MachProcess to check
70930fdc8d8SChris Lattner     // for the process, otherwise scan the process table.
71030fdc8d8SChris Lattner 
71130fdc8d8SChris Lattner     const void *attach_token = MachProcess::PrepareForAttach (waitfor_process_name, launch_flavor, true, prepare_error);
71230fdc8d8SChris Lattner 
71330fdc8d8SChris Lattner     if (prepare_error.Fail())
71430fdc8d8SChris Lattner     {
71530fdc8d8SChris Lattner         DNBLogError ("Error in PrepareForAttach: %s", prepare_error.AsString());
71630fdc8d8SChris Lattner         return INVALID_NUB_PROCESS;
71730fdc8d8SChris Lattner     }
71830fdc8d8SChris Lattner 
71930fdc8d8SChris Lattner     if (attach_token == NULL)
720cd16df91SJim Ingham     {
721cd16df91SJim Ingham         if (ignore_existing)
72230fdc8d8SChris Lattner             num_exclude_proc_infos = GetAllInfosMatchingName (waitfor_process_name, exclude_proc_infos);
723cd16df91SJim Ingham         else
724cd16df91SJim Ingham             num_exclude_proc_infos = 0;
725cd16df91SJim Ingham     }
72630fdc8d8SChris Lattner 
72730fdc8d8SChris Lattner     DNBLogThreadedIf (LOG_PROCESS, "Waiting for '%s' to appear...\n", waitfor_process_name);
72830fdc8d8SChris Lattner 
72930fdc8d8SChris Lattner     // Loop and try to find the process by name
73030fdc8d8SChris Lattner     nub_process_t waitfor_pid = INVALID_NUB_PROCESS;
73130fdc8d8SChris Lattner 
73230fdc8d8SChris Lattner     while (waitfor_pid == INVALID_NUB_PROCESS)
73330fdc8d8SChris Lattner     {
73430fdc8d8SChris Lattner         if (attach_token != NULL)
73530fdc8d8SChris Lattner         {
73630fdc8d8SChris Lattner             nub_process_t pid;
73730fdc8d8SChris Lattner             pid = MachProcess::CheckForProcess(attach_token);
73830fdc8d8SChris Lattner             if (pid != INVALID_NUB_PROCESS)
73930fdc8d8SChris Lattner             {
74030fdc8d8SChris Lattner                 waitfor_pid = pid;
74130fdc8d8SChris Lattner                 break;
74230fdc8d8SChris Lattner             }
74330fdc8d8SChris Lattner         }
74430fdc8d8SChris Lattner         else
74530fdc8d8SChris Lattner         {
74630fdc8d8SChris Lattner 
74730fdc8d8SChris Lattner             // Get the current process list, and check for matches that
74830fdc8d8SChris Lattner             // aren't in our original list. If anyone wants to attach
74930fdc8d8SChris Lattner             // to an existing process by name, they should do it with
75030fdc8d8SChris Lattner             // --attach=PROCNAME. Else we will wait for the first matching
75130fdc8d8SChris Lattner             // process that wasn't in our exclusion list.
75230fdc8d8SChris Lattner             std::vector<struct kinfo_proc> proc_infos;
75330fdc8d8SChris Lattner             const size_t num_proc_infos = GetAllInfosMatchingName (waitfor_process_name, proc_infos);
75430fdc8d8SChris Lattner             for (size_t i=0; i<num_proc_infos; i++)
75530fdc8d8SChris Lattner             {
75630fdc8d8SChris Lattner                 nub_process_t curr_pid = proc_infos[i].kp_proc.p_pid;
75730fdc8d8SChris Lattner                 for (size_t j=0; j<num_exclude_proc_infos; j++)
75830fdc8d8SChris Lattner                 {
75930fdc8d8SChris Lattner                     if (curr_pid == exclude_proc_infos[j].kp_proc.p_pid)
76030fdc8d8SChris Lattner                     {
76130fdc8d8SChris Lattner                         // This process was in our exclusion list, don't use it.
76230fdc8d8SChris Lattner                         curr_pid = INVALID_NUB_PROCESS;
76330fdc8d8SChris Lattner                         break;
76430fdc8d8SChris Lattner                     }
76530fdc8d8SChris Lattner                 }
76630fdc8d8SChris Lattner 
76730fdc8d8SChris Lattner                 // If we didn't find CURR_PID in our exclusion list, then use it.
76830fdc8d8SChris Lattner                 if (curr_pid != INVALID_NUB_PROCESS)
76930fdc8d8SChris Lattner                 {
77030fdc8d8SChris Lattner                     // We found our process!
77130fdc8d8SChris Lattner                     waitfor_pid = curr_pid;
77230fdc8d8SChris Lattner                     break;
77330fdc8d8SChris Lattner                 }
77430fdc8d8SChris Lattner             }
77530fdc8d8SChris Lattner         }
77630fdc8d8SChris Lattner 
77730fdc8d8SChris Lattner         // If we haven't found our process yet, check for a timeout
77830fdc8d8SChris Lattner         // and then sleep for a bit until we poll again.
77930fdc8d8SChris Lattner         if (waitfor_pid == INVALID_NUB_PROCESS)
78030fdc8d8SChris Lattner         {
78130fdc8d8SChris Lattner             if (timeout_abstime != NULL)
78230fdc8d8SChris Lattner             {
78330fdc8d8SChris Lattner                 // Check to see if we have a waitfor-duration option that
78430fdc8d8SChris Lattner                 // has timed out?
78530fdc8d8SChris Lattner                 if (DNBTimer::TimeOfDayLaterThan(*timeout_abstime))
78630fdc8d8SChris Lattner                 {
78730fdc8d8SChris Lattner                     if (err_str && err_len > 0)
78830fdc8d8SChris Lattner                         snprintf(err_str, err_len, "operation timed out");
78930fdc8d8SChris Lattner                     DNBLogError ("error: waiting for process '%s' timed out.\n", waitfor_process_name);
79030fdc8d8SChris Lattner                     return INVALID_NUB_PROCESS;
79130fdc8d8SChris Lattner                 }
79230fdc8d8SChris Lattner             }
79330fdc8d8SChris Lattner 
79430fdc8d8SChris Lattner             // Call the should cancel callback as well...
79530fdc8d8SChris Lattner 
79630fdc8d8SChris Lattner             if (should_cancel_callback != NULL
79730fdc8d8SChris Lattner                 && should_cancel_callback (callback_data))
79830fdc8d8SChris Lattner             {
79930fdc8d8SChris Lattner                 DNBLogThreadedIf (LOG_PROCESS, "DNBProcessAttachWait cancelled by should_cancel callback.");
80030fdc8d8SChris Lattner                 waitfor_pid = INVALID_NUB_PROCESS;
80130fdc8d8SChris Lattner                 break;
80230fdc8d8SChris Lattner             }
80330fdc8d8SChris Lattner 
80430fdc8d8SChris Lattner             ::usleep (waitfor_interval);    // Sleep for WAITFOR_INTERVAL, then poll again
80530fdc8d8SChris Lattner         }
80630fdc8d8SChris Lattner     }
80730fdc8d8SChris Lattner 
80830fdc8d8SChris Lattner     if (waitfor_pid != INVALID_NUB_PROCESS)
80930fdc8d8SChris Lattner     {
81030fdc8d8SChris Lattner         DNBLogThreadedIf (LOG_PROCESS, "Attaching to %s with pid %i...\n", waitfor_process_name, waitfor_pid);
81130fdc8d8SChris Lattner         waitfor_pid = DNBProcessAttach (waitfor_pid, timeout_abstime, err_str, err_len);
81230fdc8d8SChris Lattner     }
81330fdc8d8SChris Lattner 
81430fdc8d8SChris Lattner     bool success = waitfor_pid != INVALID_NUB_PROCESS;
81530fdc8d8SChris Lattner     MachProcess::CleanupAfterAttach (attach_token, success, prepare_error);
81630fdc8d8SChris Lattner 
81730fdc8d8SChris Lattner     return waitfor_pid;
81830fdc8d8SChris Lattner }
81930fdc8d8SChris Lattner 
82030fdc8d8SChris Lattner nub_bool_t
82130fdc8d8SChris Lattner DNBProcessDetach (nub_process_t pid)
82230fdc8d8SChris Lattner {
82330fdc8d8SChris Lattner     MachProcessSP procSP;
82430fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
82530fdc8d8SChris Lattner     {
8265881318cSJim Ingham         const bool remove = true;
8275881318cSJim Ingham         DNBLogThreaded("Disabling breakpoints and watchpoints, and detaching from %d.", pid);
8285881318cSJim Ingham         procSP->DisableAllBreakpoints(remove);
8295881318cSJim Ingham         procSP->DisableAllWatchpoints (remove);
83030fdc8d8SChris Lattner         return procSP->Detach();
83130fdc8d8SChris Lattner     }
83230fdc8d8SChris Lattner     return false;
83330fdc8d8SChris Lattner }
83430fdc8d8SChris Lattner 
83530fdc8d8SChris Lattner nub_bool_t
83630fdc8d8SChris Lattner DNBProcessKill (nub_process_t pid)
83730fdc8d8SChris Lattner {
83830fdc8d8SChris Lattner     MachProcessSP procSP;
83930fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
84030fdc8d8SChris Lattner     {
84130fdc8d8SChris Lattner         return procSP->Kill ();
84230fdc8d8SChris Lattner     }
84330fdc8d8SChris Lattner     return false;
84430fdc8d8SChris Lattner }
84530fdc8d8SChris Lattner 
84630fdc8d8SChris Lattner nub_bool_t
84730fdc8d8SChris Lattner DNBProcessSignal (nub_process_t pid, int signal)
84830fdc8d8SChris Lattner {
84930fdc8d8SChris Lattner     MachProcessSP procSP;
85030fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
85130fdc8d8SChris Lattner     {
85230fdc8d8SChris Lattner         return procSP->Signal (signal);
85330fdc8d8SChris Lattner     }
85430fdc8d8SChris Lattner     return false;
85530fdc8d8SChris Lattner }
85630fdc8d8SChris Lattner 
8574296c221SGreg Clayton 
8584296c221SGreg Clayton nub_bool_t
8594296c221SGreg Clayton DNBProcessInterrupt(nub_process_t pid)
8604296c221SGreg Clayton {
8614296c221SGreg Clayton     MachProcessSP procSP;
8624296c221SGreg Clayton     if (GetProcessSP (pid, procSP))
8634296c221SGreg Clayton         return procSP->Interrupt();
8644296c221SGreg Clayton     return false;
8654296c221SGreg Clayton }
8664296c221SGreg Clayton 
867a332978bSJason Molenda nub_bool_t
868a332978bSJason Molenda DNBProcessSendEvent (nub_process_t pid, const char *event)
869a332978bSJason Molenda {
870a332978bSJason Molenda     MachProcessSP procSP;
871a332978bSJason Molenda     if (GetProcessSP (pid, procSP))
872a332978bSJason Molenda     {
873a332978bSJason Molenda         // FIXME: Do something with the error...
874a332978bSJason Molenda         DNBError send_error;
875a332978bSJason Molenda         return procSP->SendEvent (event, send_error);
876a332978bSJason Molenda     }
877a332978bSJason Molenda     return false;
878a332978bSJason Molenda }
879a332978bSJason Molenda 
88030fdc8d8SChris Lattner 
88130fdc8d8SChris Lattner nub_bool_t
88230fdc8d8SChris Lattner DNBProcessIsAlive (nub_process_t pid)
88330fdc8d8SChris Lattner {
88430fdc8d8SChris Lattner     MachProcessSP procSP;
88530fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
88630fdc8d8SChris Lattner     {
88730fdc8d8SChris Lattner         return MachTask::IsValid (procSP->Task().TaskPort());
88830fdc8d8SChris Lattner     }
88930fdc8d8SChris Lattner     return eStateInvalid;
89030fdc8d8SChris Lattner }
89130fdc8d8SChris Lattner 
89230fdc8d8SChris Lattner //----------------------------------------------------------------------
89330fdc8d8SChris Lattner // Process and Thread state information
89430fdc8d8SChris Lattner //----------------------------------------------------------------------
89530fdc8d8SChris Lattner nub_state_t
89630fdc8d8SChris Lattner DNBProcessGetState (nub_process_t pid)
89730fdc8d8SChris Lattner {
89830fdc8d8SChris Lattner     MachProcessSP procSP;
89930fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
90030fdc8d8SChris Lattner     {
90130fdc8d8SChris Lattner         return procSP->GetState();
90230fdc8d8SChris Lattner     }
90330fdc8d8SChris Lattner     return eStateInvalid;
90430fdc8d8SChris Lattner }
90530fdc8d8SChris Lattner 
90630fdc8d8SChris Lattner //----------------------------------------------------------------------
90730fdc8d8SChris Lattner // Process and Thread state information
90830fdc8d8SChris Lattner //----------------------------------------------------------------------
90930fdc8d8SChris Lattner nub_bool_t
91030fdc8d8SChris Lattner DNBProcessGetExitStatus (nub_process_t pid, int* status)
91130fdc8d8SChris Lattner {
91230fdc8d8SChris Lattner     MachProcessSP procSP;
91330fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
91430fdc8d8SChris Lattner     {
91530fdc8d8SChris Lattner         return procSP->GetExitStatus(status);
91630fdc8d8SChris Lattner     }
91730fdc8d8SChris Lattner     return false;
91830fdc8d8SChris Lattner }
91930fdc8d8SChris Lattner 
92030fdc8d8SChris Lattner nub_bool_t
92130fdc8d8SChris Lattner DNBProcessSetExitStatus (nub_process_t pid, int status)
92230fdc8d8SChris Lattner {
92330fdc8d8SChris Lattner     MachProcessSP procSP;
92430fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
92530fdc8d8SChris Lattner     {
92630fdc8d8SChris Lattner         procSP->SetExitStatus(status);
92730fdc8d8SChris Lattner         return true;
92830fdc8d8SChris Lattner     }
92930fdc8d8SChris Lattner     return false;
93030fdc8d8SChris Lattner }
93130fdc8d8SChris Lattner 
932a332978bSJason Molenda const char *
933a332978bSJason Molenda DNBProcessGetExitInfo (nub_process_t pid)
934a332978bSJason Molenda {
935a332978bSJason Molenda     MachProcessSP procSP;
936a332978bSJason Molenda     if (GetProcessSP (pid, procSP))
937a332978bSJason Molenda     {
938a332978bSJason Molenda         return procSP->GetExitInfo();
939a332978bSJason Molenda     }
940a332978bSJason Molenda     return NULL;
941a332978bSJason Molenda }
942a332978bSJason Molenda 
943a332978bSJason Molenda nub_bool_t
944a332978bSJason Molenda DNBProcessSetExitInfo (nub_process_t pid, const char *info)
945a332978bSJason Molenda {
946a332978bSJason Molenda     MachProcessSP procSP;
947a332978bSJason Molenda     if (GetProcessSP (pid, procSP))
948a332978bSJason Molenda     {
949a332978bSJason Molenda         procSP->SetExitInfo(info);
950a332978bSJason Molenda         return true;
951a332978bSJason Molenda     }
952a332978bSJason Molenda     return false;
953a332978bSJason Molenda }
95430fdc8d8SChris Lattner 
95530fdc8d8SChris Lattner const char *
95630fdc8d8SChris Lattner DNBThreadGetName (nub_process_t pid, nub_thread_t tid)
95730fdc8d8SChris Lattner {
95830fdc8d8SChris Lattner     MachProcessSP procSP;
95930fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
96030fdc8d8SChris Lattner         return procSP->ThreadGetName(tid);
96130fdc8d8SChris Lattner     return NULL;
96230fdc8d8SChris Lattner }
96330fdc8d8SChris Lattner 
96430fdc8d8SChris Lattner 
96530fdc8d8SChris Lattner nub_bool_t
96630fdc8d8SChris Lattner DNBThreadGetIdentifierInfo (nub_process_t pid, nub_thread_t tid, thread_identifier_info_data_t *ident_info)
96730fdc8d8SChris Lattner {
96830fdc8d8SChris Lattner     MachProcessSP procSP;
96930fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
97030fdc8d8SChris Lattner         return procSP->GetThreadList().GetIdentifierInfo(tid, ident_info);
97130fdc8d8SChris Lattner     return false;
97230fdc8d8SChris Lattner }
97330fdc8d8SChris Lattner 
97430fdc8d8SChris Lattner nub_state_t
97530fdc8d8SChris Lattner DNBThreadGetState (nub_process_t pid, nub_thread_t tid)
97630fdc8d8SChris Lattner {
97730fdc8d8SChris Lattner     MachProcessSP procSP;
97830fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
97930fdc8d8SChris Lattner     {
98030fdc8d8SChris Lattner         return procSP->ThreadGetState(tid);
98130fdc8d8SChris Lattner     }
98230fdc8d8SChris Lattner     return eStateInvalid;
98330fdc8d8SChris Lattner }
98430fdc8d8SChris Lattner 
98530fdc8d8SChris Lattner const char *
98630fdc8d8SChris Lattner DNBStateAsString(nub_state_t state)
98730fdc8d8SChris Lattner {
98830fdc8d8SChris Lattner     switch (state)
98930fdc8d8SChris Lattner     {
990effe5c95SGreg Clayton     case eStateInvalid:     return "Invalid";
99130fdc8d8SChris Lattner     case eStateUnloaded:    return "Unloaded";
99230fdc8d8SChris Lattner     case eStateAttaching:   return "Attaching";
99330fdc8d8SChris Lattner     case eStateLaunching:   return "Launching";
99430fdc8d8SChris Lattner     case eStateStopped:     return "Stopped";
99530fdc8d8SChris Lattner     case eStateRunning:     return "Running";
99630fdc8d8SChris Lattner     case eStateStepping:    return "Stepping";
99730fdc8d8SChris Lattner     case eStateCrashed:     return "Crashed";
99830fdc8d8SChris Lattner     case eStateDetached:    return "Detached";
99930fdc8d8SChris Lattner     case eStateExited:      return "Exited";
100030fdc8d8SChris Lattner     case eStateSuspended:   return "Suspended";
100130fdc8d8SChris Lattner     }
100230fdc8d8SChris Lattner     return "nub_state_t ???";
100330fdc8d8SChris Lattner }
100430fdc8d8SChris Lattner 
1005705b1809SJason Molenda Genealogy::ThreadActivitySP
1006705b1809SJason Molenda DNBGetGenealogyInfoForThread (nub_process_t pid, nub_thread_t tid, bool &timed_out)
1007705b1809SJason Molenda {
1008705b1809SJason Molenda     Genealogy::ThreadActivitySP thread_activity_sp;
1009705b1809SJason Molenda     MachProcessSP procSP;
1010705b1809SJason Molenda     if (GetProcessSP (pid, procSP))
1011705b1809SJason Molenda         thread_activity_sp = procSP->GetGenealogyInfoForThread (tid, timed_out);
1012705b1809SJason Molenda     return thread_activity_sp;
1013705b1809SJason Molenda }
1014705b1809SJason Molenda 
1015705b1809SJason Molenda Genealogy::ProcessExecutableInfoSP
1016705b1809SJason Molenda DNBGetGenealogyImageInfo (nub_process_t pid, size_t idx)
1017705b1809SJason Molenda {
1018705b1809SJason Molenda     Genealogy::ProcessExecutableInfoSP image_info_sp;
1019705b1809SJason Molenda     MachProcessSP procSP;
1020705b1809SJason Molenda     if (GetProcessSP (pid, procSP))
1021705b1809SJason Molenda     {
1022705b1809SJason Molenda         image_info_sp = procSP->GetGenealogyImageInfo (idx);
1023705b1809SJason Molenda     }
1024705b1809SJason Molenda     return image_info_sp;
1025705b1809SJason Molenda }
1026705b1809SJason Molenda 
1027705b1809SJason Molenda ThreadInfo::QoS
1028705b1809SJason Molenda DNBGetRequestedQoSForThread (nub_process_t pid, nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index)
1029705b1809SJason Molenda {
1030705b1809SJason Molenda     MachProcessSP procSP;
1031705b1809SJason Molenda     if (GetProcessSP (pid, procSP))
1032705b1809SJason Molenda     {
1033705b1809SJason Molenda         return procSP->GetRequestedQoS (tid, tsd, dti_qos_class_index);
1034705b1809SJason Molenda     }
1035705b1809SJason Molenda     return ThreadInfo::QoS();
1036705b1809SJason Molenda }
1037705b1809SJason Molenda 
1038705b1809SJason Molenda nub_addr_t
1039705b1809SJason Molenda DNBGetPThreadT (nub_process_t pid, nub_thread_t tid)
1040705b1809SJason Molenda {
1041705b1809SJason Molenda     MachProcessSP procSP;
1042705b1809SJason Molenda     if (GetProcessSP (pid, procSP))
1043705b1809SJason Molenda     {
1044705b1809SJason Molenda         return procSP->GetPThreadT (tid);
1045705b1809SJason Molenda     }
1046705b1809SJason Molenda     return INVALID_NUB_ADDRESS;
1047705b1809SJason Molenda }
1048705b1809SJason Molenda 
1049705b1809SJason Molenda nub_addr_t
1050705b1809SJason Molenda DNBGetDispatchQueueT (nub_process_t pid, nub_thread_t tid)
1051705b1809SJason Molenda {
1052705b1809SJason Molenda     MachProcessSP procSP;
1053705b1809SJason Molenda     if (GetProcessSP (pid, procSP))
1054705b1809SJason Molenda     {
1055705b1809SJason Molenda         return procSP->GetDispatchQueueT (tid);
1056705b1809SJason Molenda     }
1057705b1809SJason Molenda     return INVALID_NUB_ADDRESS;
1058705b1809SJason Molenda }
1059705b1809SJason Molenda 
1060705b1809SJason Molenda nub_addr_t
1061705b1809SJason Molenda 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)
1062705b1809SJason Molenda {
1063705b1809SJason Molenda     MachProcessSP procSP;
1064705b1809SJason Molenda     if (GetProcessSP (pid, procSP))
1065705b1809SJason Molenda     {
1066705b1809SJason Molenda         return procSP->GetTSDAddressForThread (tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size);
1067705b1809SJason Molenda     }
1068705b1809SJason Molenda     return INVALID_NUB_ADDRESS;
1069705b1809SJason Molenda }
1070705b1809SJason Molenda 
107120ee21bdSJason Molenda JSONGenerator::ObjectSP
107220ee21bdSJason Molenda DNBGetLoadedDynamicLibrariesInfos (nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count)
107320ee21bdSJason Molenda {
107420ee21bdSJason Molenda     MachProcessSP procSP;
107520ee21bdSJason Molenda     if (GetProcessSP (pid, procSP))
107620ee21bdSJason Molenda     {
107720ee21bdSJason Molenda         return procSP->GetLoadedDynamicLibrariesInfos (pid, image_list_address, image_count);
107820ee21bdSJason Molenda     }
107920ee21bdSJason Molenda     return JSONGenerator::ObjectSP();
108020ee21bdSJason Molenda }
108120ee21bdSJason Molenda 
108220ee21bdSJason Molenda 
1083705b1809SJason Molenda 
108430fdc8d8SChris Lattner const char *
108530fdc8d8SChris Lattner DNBProcessGetExecutablePath (nub_process_t pid)
108630fdc8d8SChris Lattner {
108730fdc8d8SChris Lattner     MachProcessSP procSP;
108830fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
108930fdc8d8SChris Lattner     {
109030fdc8d8SChris Lattner         return procSP->Path();
109130fdc8d8SChris Lattner     }
109230fdc8d8SChris Lattner     return NULL;
109330fdc8d8SChris Lattner }
109430fdc8d8SChris Lattner 
109530fdc8d8SChris Lattner nub_size_t
109630fdc8d8SChris Lattner DNBProcessGetArgumentCount (nub_process_t pid)
109730fdc8d8SChris Lattner {
109830fdc8d8SChris Lattner     MachProcessSP procSP;
109930fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
110030fdc8d8SChris Lattner     {
110130fdc8d8SChris Lattner         return procSP->ArgumentCount();
110230fdc8d8SChris Lattner     }
110330fdc8d8SChris Lattner     return 0;
110430fdc8d8SChris Lattner }
110530fdc8d8SChris Lattner 
110630fdc8d8SChris Lattner const char *
110730fdc8d8SChris Lattner DNBProcessGetArgumentAtIndex (nub_process_t pid, nub_size_t idx)
110830fdc8d8SChris Lattner {
110930fdc8d8SChris Lattner     MachProcessSP procSP;
111030fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
111130fdc8d8SChris Lattner     {
111230fdc8d8SChris Lattner         return procSP->ArgumentAtIndex (idx);
111330fdc8d8SChris Lattner     }
111430fdc8d8SChris Lattner     return NULL;
111530fdc8d8SChris Lattner }
111630fdc8d8SChris Lattner 
111730fdc8d8SChris Lattner 
111830fdc8d8SChris Lattner //----------------------------------------------------------------------
111930fdc8d8SChris Lattner // Execution control
112030fdc8d8SChris Lattner //----------------------------------------------------------------------
112130fdc8d8SChris Lattner nub_bool_t
112230fdc8d8SChris Lattner DNBProcessResume (nub_process_t pid, const DNBThreadResumeAction *actions, size_t num_actions)
112330fdc8d8SChris Lattner {
112430fdc8d8SChris Lattner     DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
112530fdc8d8SChris Lattner     MachProcessSP procSP;
112630fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
112730fdc8d8SChris Lattner     {
112830fdc8d8SChris Lattner         DNBThreadResumeActions thread_actions (actions, num_actions);
112930fdc8d8SChris Lattner 
113030fdc8d8SChris Lattner         // Below we add a default thread plan just in case one wasn't
113130fdc8d8SChris Lattner         // provided so all threads always know what they were supposed to do
113230fdc8d8SChris Lattner         if (thread_actions.IsEmpty())
113330fdc8d8SChris Lattner         {
113430fdc8d8SChris Lattner             // No thread plans were given, so the default it to run all threads
113530fdc8d8SChris Lattner             thread_actions.SetDefaultThreadActionIfNeeded (eStateRunning, 0);
113630fdc8d8SChris Lattner         }
113730fdc8d8SChris Lattner         else
113830fdc8d8SChris Lattner         {
113930fdc8d8SChris Lattner             // Some thread plans were given which means anything that wasn't
114030fdc8d8SChris Lattner             // specified should remain stopped.
114130fdc8d8SChris Lattner             thread_actions.SetDefaultThreadActionIfNeeded (eStateStopped, 0);
114230fdc8d8SChris Lattner         }
114330fdc8d8SChris Lattner         return procSP->Resume (thread_actions);
114430fdc8d8SChris Lattner     }
114530fdc8d8SChris Lattner     return false;
114630fdc8d8SChris Lattner }
114730fdc8d8SChris Lattner 
114830fdc8d8SChris Lattner nub_bool_t
114930fdc8d8SChris Lattner DNBProcessHalt (nub_process_t pid)
115030fdc8d8SChris Lattner {
115130fdc8d8SChris Lattner     DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
115230fdc8d8SChris Lattner     MachProcessSP procSP;
115330fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
115430fdc8d8SChris Lattner         return procSP->Signal (SIGSTOP);
115530fdc8d8SChris Lattner     return false;
115630fdc8d8SChris Lattner }
115730fdc8d8SChris Lattner //
115830fdc8d8SChris Lattner //nub_bool_t
115930fdc8d8SChris Lattner //DNBThreadResume (nub_process_t pid, nub_thread_t tid, nub_bool_t step)
116030fdc8d8SChris Lattner //{
116130fdc8d8SChris Lattner //    DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u)", __FUNCTION__, pid, tid, (uint32_t)step);
116230fdc8d8SChris Lattner //    MachProcessSP procSP;
116330fdc8d8SChris Lattner //    if (GetProcessSP (pid, procSP))
116430fdc8d8SChris Lattner //    {
116530fdc8d8SChris Lattner //        return procSP->Resume(tid, step, 0);
116630fdc8d8SChris Lattner //    }
116730fdc8d8SChris Lattner //    return false;
116830fdc8d8SChris Lattner //}
116930fdc8d8SChris Lattner //
117030fdc8d8SChris Lattner //nub_bool_t
117130fdc8d8SChris Lattner //DNBThreadResumeWithSignal (nub_process_t pid, nub_thread_t tid, nub_bool_t step, int signal)
117230fdc8d8SChris Lattner //{
117330fdc8d8SChris Lattner //    DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u, signal = %i)", __FUNCTION__, pid, tid, (uint32_t)step, signal);
117430fdc8d8SChris Lattner //    MachProcessSP procSP;
117530fdc8d8SChris Lattner //    if (GetProcessSP (pid, procSP))
117630fdc8d8SChris Lattner //    {
117730fdc8d8SChris Lattner //        return procSP->Resume(tid, step, signal);
117830fdc8d8SChris Lattner //    }
117930fdc8d8SChris Lattner //    return false;
118030fdc8d8SChris Lattner //}
118130fdc8d8SChris Lattner 
118230fdc8d8SChris Lattner nub_event_t
118330fdc8d8SChris Lattner DNBProcessWaitForEvents (nub_process_t pid, nub_event_t event_mask, bool wait_for_set, struct timespec* timeout)
118430fdc8d8SChris Lattner {
118530fdc8d8SChris Lattner     nub_event_t result = 0;
118630fdc8d8SChris Lattner     MachProcessSP procSP;
118730fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
118830fdc8d8SChris Lattner     {
118930fdc8d8SChris Lattner         if (wait_for_set)
119030fdc8d8SChris Lattner             result = procSP->Events().WaitForSetEvents(event_mask, timeout);
119130fdc8d8SChris Lattner         else
119230fdc8d8SChris Lattner             result = procSP->Events().WaitForEventsToReset(event_mask, timeout);
119330fdc8d8SChris Lattner     }
119430fdc8d8SChris Lattner     return result;
119530fdc8d8SChris Lattner }
119630fdc8d8SChris Lattner 
119730fdc8d8SChris Lattner void
119830fdc8d8SChris Lattner DNBProcessResetEvents (nub_process_t pid, nub_event_t event_mask)
119930fdc8d8SChris Lattner {
120030fdc8d8SChris Lattner     MachProcessSP procSP;
120130fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
120230fdc8d8SChris Lattner         procSP->Events().ResetEvents(event_mask);
120330fdc8d8SChris Lattner }
120430fdc8d8SChris Lattner 
120530fdc8d8SChris Lattner // Breakpoints
1206d8cf1a11SGreg Clayton nub_bool_t
120730fdc8d8SChris Lattner DNBBreakpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, nub_bool_t hardware)
120830fdc8d8SChris Lattner {
120930fdc8d8SChris Lattner     MachProcessSP procSP;
121030fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
1211d8cf1a11SGreg Clayton         return procSP->CreateBreakpoint(addr, size, hardware) != NULL;
1212d8cf1a11SGreg Clayton     return false;
121330fdc8d8SChris Lattner }
121430fdc8d8SChris Lattner 
121530fdc8d8SChris Lattner nub_bool_t
1216d8cf1a11SGreg Clayton DNBBreakpointClear (nub_process_t pid, nub_addr_t addr)
121730fdc8d8SChris Lattner {
121830fdc8d8SChris Lattner     MachProcessSP procSP;
121930fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
1220d8cf1a11SGreg Clayton         return procSP->DisableBreakpoint(addr, true);
122130fdc8d8SChris Lattner     return false; // Failed
122230fdc8d8SChris Lattner }
122330fdc8d8SChris Lattner 
122430fdc8d8SChris Lattner 
122530fdc8d8SChris Lattner //----------------------------------------------------------------------
122630fdc8d8SChris Lattner // Watchpoints
122730fdc8d8SChris Lattner //----------------------------------------------------------------------
1228d8cf1a11SGreg Clayton nub_bool_t
122930fdc8d8SChris Lattner DNBWatchpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, uint32_t watch_flags, nub_bool_t hardware)
123030fdc8d8SChris Lattner {
123130fdc8d8SChris Lattner     MachProcessSP procSP;
123230fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
1233d8cf1a11SGreg Clayton         return procSP->CreateWatchpoint(addr, size, watch_flags, hardware) != NULL;
1234d8cf1a11SGreg Clayton     return false;
123530fdc8d8SChris Lattner }
123630fdc8d8SChris Lattner 
123730fdc8d8SChris Lattner nub_bool_t
1238d8cf1a11SGreg Clayton DNBWatchpointClear (nub_process_t pid, nub_addr_t addr)
123930fdc8d8SChris Lattner {
124030fdc8d8SChris Lattner     MachProcessSP procSP;
124130fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
1242d8cf1a11SGreg Clayton         return procSP->DisableWatchpoint(addr, true);
124330fdc8d8SChris Lattner     return false; // Failed
124430fdc8d8SChris Lattner }
124530fdc8d8SChris Lattner 
124630fdc8d8SChris Lattner //----------------------------------------------------------------------
124764637205SJohnny Chen // Return the number of supported hardware watchpoints.
124864637205SJohnny Chen //----------------------------------------------------------------------
124964637205SJohnny Chen uint32_t
125064637205SJohnny Chen DNBWatchpointGetNumSupportedHWP (nub_process_t pid)
125164637205SJohnny Chen {
125264637205SJohnny Chen     MachProcessSP procSP;
125364637205SJohnny Chen     if (GetProcessSP (pid, procSP))
125464637205SJohnny Chen         return procSP->GetNumSupportedHardwareWatchpoints();
125564637205SJohnny Chen     return 0;
125664637205SJohnny Chen }
125764637205SJohnny Chen 
125864637205SJohnny Chen //----------------------------------------------------------------------
125930fdc8d8SChris Lattner // Read memory in the address space of process PID. This call will take
126030fdc8d8SChris Lattner // care of setting and restoring permissions and breaking up the memory
126130fdc8d8SChris Lattner // read into multiple chunks as required.
126230fdc8d8SChris Lattner //
126330fdc8d8SChris Lattner // RETURNS: number of bytes actually read
126430fdc8d8SChris Lattner //----------------------------------------------------------------------
126530fdc8d8SChris Lattner nub_size_t
126630fdc8d8SChris Lattner DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub_size_t size, void *buf)
126730fdc8d8SChris Lattner {
126830fdc8d8SChris Lattner     MachProcessSP procSP;
126930fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
127030fdc8d8SChris Lattner         return procSP->ReadMemory(addr, size, buf);
127130fdc8d8SChris Lattner     return 0;
127230fdc8d8SChris Lattner }
127330fdc8d8SChris Lattner 
12740b90be1cSGreg Clayton uint64_t
12750b90be1cSGreg Clayton DNBProcessMemoryReadInteger (nub_process_t pid, nub_addr_t addr, nub_size_t integer_size, uint64_t fail_value)
12760b90be1cSGreg Clayton {
12770b90be1cSGreg Clayton     union Integers
12780b90be1cSGreg Clayton     {
12790b90be1cSGreg Clayton         uint8_t     u8;
12800b90be1cSGreg Clayton         uint16_t    u16;
12810b90be1cSGreg Clayton         uint32_t    u32;
12820b90be1cSGreg Clayton         uint64_t    u64;
12830b90be1cSGreg Clayton     };
12840b90be1cSGreg Clayton 
12850b90be1cSGreg Clayton     if (integer_size <= sizeof(uint64_t))
12860b90be1cSGreg Clayton     {
12870b90be1cSGreg Clayton         Integers ints;
12880b90be1cSGreg Clayton         if (DNBProcessMemoryRead(pid, addr, integer_size, &ints) == integer_size)
12890b90be1cSGreg Clayton         {
12900b90be1cSGreg Clayton             switch (integer_size)
12910b90be1cSGreg Clayton             {
12920b90be1cSGreg Clayton                 case 1: return ints.u8;
12930b90be1cSGreg Clayton                 case 2: return ints.u16;
12940b90be1cSGreg Clayton                 case 3: return ints.u32 & 0xffffffu;
12950b90be1cSGreg Clayton                 case 4: return ints.u32;
12960b90be1cSGreg Clayton                 case 5: return ints.u32 & 0x000000ffffffffffull;
12970b90be1cSGreg Clayton                 case 6: return ints.u32 & 0x0000ffffffffffffull;
12980b90be1cSGreg Clayton                 case 7: return ints.u32 & 0x00ffffffffffffffull;
12990b90be1cSGreg Clayton                 case 8: return ints.u64;
13000b90be1cSGreg Clayton             }
13010b90be1cSGreg Clayton         }
13020b90be1cSGreg Clayton     }
13030b90be1cSGreg Clayton     return fail_value;
13040b90be1cSGreg Clayton 
13050b90be1cSGreg Clayton }
13060b90be1cSGreg Clayton 
13070b90be1cSGreg Clayton nub_addr_t
13080b90be1cSGreg Clayton DNBProcessMemoryReadPointer (nub_process_t pid, nub_addr_t addr)
13090b90be1cSGreg Clayton {
13100b90be1cSGreg Clayton     cpu_type_t cputype = DNBProcessGetCPUType (pid);
13110b90be1cSGreg Clayton     if (cputype)
13120b90be1cSGreg Clayton     {
13130b90be1cSGreg Clayton         const nub_size_t pointer_size = (cputype & CPU_ARCH_ABI64) ? 8 : 4;
13140b90be1cSGreg Clayton         return DNBProcessMemoryReadInteger(pid, addr, pointer_size, 0);
13150b90be1cSGreg Clayton     }
13160b90be1cSGreg Clayton     return 0;
13170b90be1cSGreg Clayton 
13180b90be1cSGreg Clayton }
13190b90be1cSGreg Clayton 
13200b90be1cSGreg Clayton std::string
13210b90be1cSGreg Clayton DNBProcessMemoryReadCString (nub_process_t pid, nub_addr_t addr)
13220b90be1cSGreg Clayton {
13230b90be1cSGreg Clayton     std::string cstr;
13240b90be1cSGreg Clayton     char buffer[256];
13250b90be1cSGreg Clayton     const nub_size_t max_buffer_cstr_length = sizeof(buffer)-1;
13260b90be1cSGreg Clayton     buffer[max_buffer_cstr_length] = '\0';
13270b90be1cSGreg Clayton     nub_size_t length = 0;
13280b90be1cSGreg Clayton     nub_addr_t curr_addr = addr;
13290b90be1cSGreg Clayton     do
13300b90be1cSGreg Clayton     {
13310b90be1cSGreg Clayton         nub_size_t bytes_read = DNBProcessMemoryRead(pid, curr_addr, max_buffer_cstr_length, buffer);
13320b90be1cSGreg Clayton         if (bytes_read == 0)
13330b90be1cSGreg Clayton             break;
13340b90be1cSGreg Clayton         length = strlen(buffer);
13350b90be1cSGreg Clayton         cstr.append(buffer, length);
13360b90be1cSGreg Clayton         curr_addr += length;
13370b90be1cSGreg Clayton     } while (length == max_buffer_cstr_length);
13380b90be1cSGreg Clayton     return cstr;
13390b90be1cSGreg Clayton }
13400b90be1cSGreg Clayton 
13410b90be1cSGreg Clayton std::string
13420b90be1cSGreg Clayton DNBProcessMemoryReadCStringFixed (nub_process_t pid, nub_addr_t addr, nub_size_t fixed_length)
13430b90be1cSGreg Clayton {
13440b90be1cSGreg Clayton     std::string cstr;
13450b90be1cSGreg Clayton     char buffer[fixed_length+1];
13460b90be1cSGreg Clayton     buffer[fixed_length] = '\0';
13470b90be1cSGreg Clayton     nub_size_t bytes_read = DNBProcessMemoryRead(pid, addr, fixed_length, buffer);
13480b90be1cSGreg Clayton     if (bytes_read > 0)
13490b90be1cSGreg Clayton         cstr.assign(buffer);
13500b90be1cSGreg Clayton     return cstr;
13510b90be1cSGreg Clayton }
13520b90be1cSGreg Clayton 
13530b90be1cSGreg Clayton 
135430fdc8d8SChris Lattner //----------------------------------------------------------------------
135530fdc8d8SChris Lattner // Write memory to the address space of process PID. This call will take
135630fdc8d8SChris Lattner // care of setting and restoring permissions and breaking up the memory
135730fdc8d8SChris Lattner // write into multiple chunks as required.
135830fdc8d8SChris Lattner //
135930fdc8d8SChris Lattner // RETURNS: number of bytes actually written
136030fdc8d8SChris Lattner //----------------------------------------------------------------------
136130fdc8d8SChris Lattner nub_size_t
136230fdc8d8SChris Lattner DNBProcessMemoryWrite (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf)
136330fdc8d8SChris Lattner {
136430fdc8d8SChris Lattner     MachProcessSP procSP;
136530fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
136630fdc8d8SChris Lattner         return procSP->WriteMemory(addr, size, buf);
136730fdc8d8SChris Lattner     return 0;
136830fdc8d8SChris Lattner }
136930fdc8d8SChris Lattner 
137030fdc8d8SChris Lattner nub_addr_t
137130fdc8d8SChris Lattner DNBProcessMemoryAllocate (nub_process_t pid, nub_size_t size, uint32_t permissions)
137230fdc8d8SChris Lattner {
137330fdc8d8SChris Lattner     MachProcessSP procSP;
137430fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
137530fdc8d8SChris Lattner         return procSP->Task().AllocateMemory (size, permissions);
137630fdc8d8SChris Lattner     return 0;
137730fdc8d8SChris Lattner }
137830fdc8d8SChris Lattner 
137930fdc8d8SChris Lattner nub_bool_t
138030fdc8d8SChris Lattner DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr)
138130fdc8d8SChris Lattner {
138230fdc8d8SChris Lattner     MachProcessSP procSP;
138330fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
138430fdc8d8SChris Lattner         return procSP->Task().DeallocateMemory (addr);
138530fdc8d8SChris Lattner     return 0;
138630fdc8d8SChris Lattner }
138730fdc8d8SChris Lattner 
13881f3966beSJason Molenda //----------------------------------------------------------------------
13893dc8583cSJason Molenda // Find attributes of the memory region that contains ADDR for process PID,
13903dc8583cSJason Molenda // if possible, and return a string describing those attributes.
13911f3966beSJason Molenda //
13923dc8583cSJason Molenda // Returns 1 if we could find attributes for this region and OUTBUF can
13933dc8583cSJason Molenda // be sent to the remote debugger.
13941f3966beSJason Molenda //
13953dc8583cSJason Molenda // Returns 0 if we couldn't find the attributes for a region of memory at
13963dc8583cSJason Molenda // that address and OUTBUF should not be sent.
13973dc8583cSJason Molenda //
13983dc8583cSJason Molenda // Returns -1 if this platform cannot look up information about memory regions
13993dc8583cSJason Molenda // or if we do not yet have a valid launched process.
14003dc8583cSJason Molenda //
14011f3966beSJason Molenda //----------------------------------------------------------------------
14021f3966beSJason Molenda int
1403fc5dd29eSGreg Clayton DNBProcessMemoryRegionInfo (nub_process_t pid, nub_addr_t addr, DNBRegionInfo *region_info)
14041f3966beSJason Molenda {
14051f3966beSJason Molenda     MachProcessSP procSP;
14061f3966beSJason Molenda     if (GetProcessSP (pid, procSP))
140746fb558dSGreg Clayton         return procSP->Task().GetMemoryRegionInfo (addr, region_info);
140846fb558dSGreg Clayton 
14091f3966beSJason Molenda     return -1;
14101f3966beSJason Molenda }
14111f3966beSJason Molenda 
1412929a94f0SHan Ming Ong std::string
14138764fe7dSHan Ming Ong DNBProcessGetProfileData (nub_process_t pid, DNBProfileDataScanType scanType)
1414ab3b8b22SHan Ming Ong {
1415ab3b8b22SHan Ming Ong     MachProcessSP procSP;
1416ab3b8b22SHan Ming Ong     if (GetProcessSP (pid, procSP))
14178764fe7dSHan Ming Ong         return procSP->Task().GetProfileData(scanType);
1418ab3b8b22SHan Ming Ong 
1419929a94f0SHan Ming Ong     return std::string("");
1420ab3b8b22SHan Ming Ong }
1421ab3b8b22SHan Ming Ong 
1422ab3b8b22SHan Ming Ong nub_bool_t
14238764fe7dSHan Ming Ong DNBProcessSetEnableAsyncProfiling (nub_process_t pid, nub_bool_t enable, uint64_t interval_usec, DNBProfileDataScanType scan_type)
1424ab3b8b22SHan Ming Ong {
1425ab3b8b22SHan Ming Ong     MachProcessSP procSP;
1426ab3b8b22SHan Ming Ong     if (GetProcessSP (pid, procSP))
1427ab3b8b22SHan Ming Ong     {
14288764fe7dSHan Ming Ong         procSP->SetEnableAsyncProfiling(enable, interval_usec, scan_type);
1429ab3b8b22SHan Ming Ong         return true;
1430ab3b8b22SHan Ming Ong     }
1431ab3b8b22SHan Ming Ong 
1432ab3b8b22SHan Ming Ong     return false;
1433ab3b8b22SHan Ming Ong }
143430fdc8d8SChris Lattner 
143530fdc8d8SChris Lattner //----------------------------------------------------------------------
143630fdc8d8SChris Lattner // Get the number of threads for the specified process.
143730fdc8d8SChris Lattner //----------------------------------------------------------------------
143830fdc8d8SChris Lattner nub_size_t
143930fdc8d8SChris Lattner DNBProcessGetNumThreads (nub_process_t pid)
144030fdc8d8SChris Lattner {
144130fdc8d8SChris Lattner     MachProcessSP procSP;
144230fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
144330fdc8d8SChris Lattner         return procSP->GetNumThreads();
144430fdc8d8SChris Lattner     return 0;
144530fdc8d8SChris Lattner }
144630fdc8d8SChris Lattner 
144730fdc8d8SChris Lattner //----------------------------------------------------------------------
144830fdc8d8SChris Lattner // Get the thread ID of the current thread.
144930fdc8d8SChris Lattner //----------------------------------------------------------------------
145030fdc8d8SChris Lattner nub_thread_t
145130fdc8d8SChris Lattner DNBProcessGetCurrentThread (nub_process_t pid)
145230fdc8d8SChris Lattner {
145330fdc8d8SChris Lattner     MachProcessSP procSP;
145430fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
145530fdc8d8SChris Lattner         return procSP->GetCurrentThread();
145630fdc8d8SChris Lattner     return 0;
145730fdc8d8SChris Lattner }
145830fdc8d8SChris Lattner 
145930fdc8d8SChris Lattner //----------------------------------------------------------------------
1460d5318c0cSJason Molenda // Get the mach port number of the current thread.
1461d5318c0cSJason Molenda //----------------------------------------------------------------------
1462d5318c0cSJason Molenda nub_thread_t
1463d5318c0cSJason Molenda DNBProcessGetCurrentThreadMachPort (nub_process_t pid)
1464d5318c0cSJason Molenda {
1465d5318c0cSJason Molenda     MachProcessSP procSP;
1466d5318c0cSJason Molenda     if (GetProcessSP (pid, procSP))
1467d5318c0cSJason Molenda         return procSP->GetCurrentThreadMachPort();
1468d5318c0cSJason Molenda     return 0;
1469d5318c0cSJason Molenda }
1470d5318c0cSJason Molenda 
1471d5318c0cSJason Molenda //----------------------------------------------------------------------
147230fdc8d8SChris Lattner // Change the current thread.
147330fdc8d8SChris Lattner //----------------------------------------------------------------------
147430fdc8d8SChris Lattner nub_thread_t
147530fdc8d8SChris Lattner DNBProcessSetCurrentThread (nub_process_t pid, nub_thread_t tid)
147630fdc8d8SChris Lattner {
147730fdc8d8SChris Lattner     MachProcessSP procSP;
147830fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
147930fdc8d8SChris Lattner         return procSP->SetCurrentThread (tid);
148030fdc8d8SChris Lattner     return INVALID_NUB_THREAD;
148130fdc8d8SChris Lattner }
148230fdc8d8SChris Lattner 
148330fdc8d8SChris Lattner 
148430fdc8d8SChris Lattner //----------------------------------------------------------------------
148530fdc8d8SChris Lattner // Dump a string describing a thread's stop reason to the specified file
148630fdc8d8SChris Lattner // handle
148730fdc8d8SChris Lattner //----------------------------------------------------------------------
148830fdc8d8SChris Lattner nub_bool_t
148930fdc8d8SChris Lattner DNBThreadGetStopReason (nub_process_t pid, nub_thread_t tid, struct DNBThreadStopInfo *stop_info)
149030fdc8d8SChris Lattner {
149130fdc8d8SChris Lattner     MachProcessSP procSP;
149230fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
149330fdc8d8SChris Lattner         return procSP->GetThreadStoppedReason (tid, stop_info);
149430fdc8d8SChris Lattner     return false;
149530fdc8d8SChris Lattner }
149630fdc8d8SChris Lattner 
149730fdc8d8SChris Lattner //----------------------------------------------------------------------
149830fdc8d8SChris Lattner // Return string description for the specified thread.
149930fdc8d8SChris Lattner //
150030fdc8d8SChris Lattner // RETURNS: NULL if the thread isn't valid, else a NULL terminated C
150130fdc8d8SChris Lattner // string from a static buffer that must be copied prior to subsequent
150230fdc8d8SChris Lattner // calls.
150330fdc8d8SChris Lattner //----------------------------------------------------------------------
150430fdc8d8SChris Lattner const char *
150530fdc8d8SChris Lattner DNBThreadGetInfo (nub_process_t pid, nub_thread_t tid)
150630fdc8d8SChris Lattner {
150730fdc8d8SChris Lattner     MachProcessSP procSP;
150830fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
150930fdc8d8SChris Lattner         return procSP->GetThreadInfo (tid);
151030fdc8d8SChris Lattner     return NULL;
151130fdc8d8SChris Lattner }
151230fdc8d8SChris Lattner 
151330fdc8d8SChris Lattner //----------------------------------------------------------------------
151430fdc8d8SChris Lattner // Get the thread ID given a thread index.
151530fdc8d8SChris Lattner //----------------------------------------------------------------------
151630fdc8d8SChris Lattner nub_thread_t
151730fdc8d8SChris Lattner DNBProcessGetThreadAtIndex (nub_process_t pid, size_t thread_idx)
151830fdc8d8SChris Lattner {
151930fdc8d8SChris Lattner     MachProcessSP procSP;
152030fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
152130fdc8d8SChris Lattner         return procSP->GetThreadAtIndex (thread_idx);
152230fdc8d8SChris Lattner     return INVALID_NUB_THREAD;
152330fdc8d8SChris Lattner }
152430fdc8d8SChris Lattner 
1525279ceecfSJim Ingham //----------------------------------------------------------------------
1526279ceecfSJim Ingham // Do whatever is needed to sync the thread's register state with it's kernel values.
1527279ceecfSJim Ingham //----------------------------------------------------------------------
1528279ceecfSJim Ingham nub_bool_t
1529279ceecfSJim Ingham DNBProcessSyncThreadState (nub_process_t pid, nub_thread_t tid)
1530279ceecfSJim Ingham {
1531279ceecfSJim Ingham     MachProcessSP procSP;
1532279ceecfSJim Ingham     if (GetProcessSP (pid, procSP))
1533279ceecfSJim Ingham         return procSP->SyncThreadState (tid);
1534279ceecfSJim Ingham     return false;
1535279ceecfSJim Ingham 
1536279ceecfSJim Ingham }
1537279ceecfSJim Ingham 
153830fdc8d8SChris Lattner nub_addr_t
153930fdc8d8SChris Lattner DNBProcessGetSharedLibraryInfoAddress (nub_process_t pid)
154030fdc8d8SChris Lattner {
154130fdc8d8SChris Lattner     MachProcessSP procSP;
154230fdc8d8SChris Lattner     DNBError err;
154330fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
154430fdc8d8SChris Lattner         return procSP->Task().GetDYLDAllImageInfosAddress (err);
154530fdc8d8SChris Lattner     return INVALID_NUB_ADDRESS;
154630fdc8d8SChris Lattner }
154730fdc8d8SChris Lattner 
154830fdc8d8SChris Lattner 
154930fdc8d8SChris Lattner nub_bool_t
155030fdc8d8SChris Lattner DNBProcessSharedLibrariesUpdated(nub_process_t pid)
155130fdc8d8SChris Lattner {
155230fdc8d8SChris Lattner     MachProcessSP procSP;
155330fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
155430fdc8d8SChris Lattner     {
155530fdc8d8SChris Lattner         procSP->SharedLibrariesUpdated ();
155630fdc8d8SChris Lattner         return true;
155730fdc8d8SChris Lattner     }
155830fdc8d8SChris Lattner     return false;
155930fdc8d8SChris Lattner }
156030fdc8d8SChris Lattner 
156130fdc8d8SChris Lattner //----------------------------------------------------------------------
156230fdc8d8SChris Lattner // Get the current shared library information for a process. Only return
156330fdc8d8SChris Lattner // the shared libraries that have changed since the last shared library
156430fdc8d8SChris Lattner // state changed event if only_changed is non-zero.
156530fdc8d8SChris Lattner //----------------------------------------------------------------------
156630fdc8d8SChris Lattner nub_size_t
156730fdc8d8SChris Lattner DNBProcessGetSharedLibraryInfo (nub_process_t pid, nub_bool_t only_changed, struct DNBExecutableImageInfo **image_infos)
156830fdc8d8SChris Lattner {
156930fdc8d8SChris Lattner     MachProcessSP procSP;
157030fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
157130fdc8d8SChris Lattner         return procSP->CopyImageInfos (image_infos, only_changed);
157230fdc8d8SChris Lattner 
157330fdc8d8SChris Lattner     // If we have no process, then return NULL for the shared library info
157430fdc8d8SChris Lattner     // and zero for shared library count
157530fdc8d8SChris Lattner     *image_infos = NULL;
157630fdc8d8SChris Lattner     return 0;
157730fdc8d8SChris Lattner }
157830fdc8d8SChris Lattner 
1579d04f0edaSGreg Clayton uint32_t
1580d04f0edaSGreg Clayton DNBGetRegisterCPUType()
1581d04f0edaSGreg Clayton {
1582d04f0edaSGreg Clayton     return DNBArchProtocol::GetRegisterCPUType ();
1583d04f0edaSGreg Clayton 
1584d04f0edaSGreg Clayton }
158530fdc8d8SChris Lattner //----------------------------------------------------------------------
158630fdc8d8SChris Lattner // Get the register set information for a specific thread.
158730fdc8d8SChris Lattner //----------------------------------------------------------------------
158830fdc8d8SChris Lattner const DNBRegisterSetInfo *
158930fdc8d8SChris Lattner DNBGetRegisterSetInfo (nub_size_t *num_reg_sets)
159030fdc8d8SChris Lattner {
15913af9ea56SGreg Clayton     return DNBArchProtocol::GetRegisterSetInfo (num_reg_sets);
159230fdc8d8SChris Lattner }
159330fdc8d8SChris Lattner 
159430fdc8d8SChris Lattner 
159530fdc8d8SChris Lattner //----------------------------------------------------------------------
159630fdc8d8SChris Lattner // Read a register value by register set and register index.
159730fdc8d8SChris Lattner //----------------------------------------------------------------------
159830fdc8d8SChris Lattner nub_bool_t
159930fdc8d8SChris Lattner DNBThreadGetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *value)
160030fdc8d8SChris Lattner {
160130fdc8d8SChris Lattner     MachProcessSP procSP;
160230fdc8d8SChris Lattner     ::bzero (value, sizeof(DNBRegisterValue));
160330fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
160430fdc8d8SChris Lattner     {
160530fdc8d8SChris Lattner         if (tid != INVALID_NUB_THREAD)
160630fdc8d8SChris Lattner             return procSP->GetRegisterValue (tid, set, reg, value);
160730fdc8d8SChris Lattner     }
160830fdc8d8SChris Lattner     return false;
160930fdc8d8SChris Lattner }
161030fdc8d8SChris Lattner 
161130fdc8d8SChris Lattner nub_bool_t
161230fdc8d8SChris Lattner DNBThreadSetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value)
161330fdc8d8SChris Lattner {
161430fdc8d8SChris Lattner     if (tid != INVALID_NUB_THREAD)
161530fdc8d8SChris Lattner     {
161630fdc8d8SChris Lattner         MachProcessSP procSP;
161730fdc8d8SChris Lattner         if (GetProcessSP (pid, procSP))
161830fdc8d8SChris Lattner             return procSP->SetRegisterValue (tid, set, reg, value);
161930fdc8d8SChris Lattner     }
162030fdc8d8SChris Lattner     return false;
162130fdc8d8SChris Lattner }
162230fdc8d8SChris Lattner 
162330fdc8d8SChris Lattner nub_size_t
162430fdc8d8SChris Lattner DNBThreadGetRegisterContext (nub_process_t pid, nub_thread_t tid, void *buf, size_t buf_len)
162530fdc8d8SChris Lattner {
162630fdc8d8SChris Lattner     MachProcessSP procSP;
162730fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
162830fdc8d8SChris Lattner     {
162930fdc8d8SChris Lattner         if (tid != INVALID_NUB_THREAD)
163030fdc8d8SChris Lattner             return procSP->GetThreadList().GetRegisterContext (tid, buf, buf_len);
163130fdc8d8SChris Lattner     }
163230fdc8d8SChris Lattner     ::bzero (buf, buf_len);
163330fdc8d8SChris Lattner     return 0;
163430fdc8d8SChris Lattner 
163530fdc8d8SChris Lattner }
163630fdc8d8SChris Lattner 
163730fdc8d8SChris Lattner nub_size_t
163830fdc8d8SChris Lattner DNBThreadSetRegisterContext (nub_process_t pid, nub_thread_t tid, const void *buf, size_t buf_len)
163930fdc8d8SChris Lattner {
164030fdc8d8SChris Lattner     MachProcessSP procSP;
164130fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
164230fdc8d8SChris Lattner     {
164330fdc8d8SChris Lattner         if (tid != INVALID_NUB_THREAD)
164430fdc8d8SChris Lattner             return procSP->GetThreadList().SetRegisterContext (tid, buf, buf_len);
164530fdc8d8SChris Lattner     }
164630fdc8d8SChris Lattner     return 0;
164730fdc8d8SChris Lattner }
164830fdc8d8SChris Lattner 
1649f74cf86bSGreg Clayton uint32_t
1650f74cf86bSGreg Clayton DNBThreadSaveRegisterState (nub_process_t pid, nub_thread_t tid)
1651f74cf86bSGreg Clayton {
1652f74cf86bSGreg Clayton     if (tid != INVALID_NUB_THREAD)
1653f74cf86bSGreg Clayton     {
1654f74cf86bSGreg Clayton         MachProcessSP procSP;
1655f74cf86bSGreg Clayton         if (GetProcessSP (pid, procSP))
1656f74cf86bSGreg Clayton             return procSP->GetThreadList().SaveRegisterState (tid);
1657f74cf86bSGreg Clayton     }
1658f74cf86bSGreg Clayton     return 0;
1659f74cf86bSGreg Clayton }
1660f74cf86bSGreg Clayton nub_bool_t
1661f74cf86bSGreg Clayton DNBThreadRestoreRegisterState (nub_process_t pid, nub_thread_t tid, uint32_t save_id)
1662f74cf86bSGreg Clayton {
1663f74cf86bSGreg Clayton     if (tid != INVALID_NUB_THREAD)
1664f74cf86bSGreg Clayton     {
1665f74cf86bSGreg Clayton         MachProcessSP procSP;
1666f74cf86bSGreg Clayton         if (GetProcessSP (pid, procSP))
1667f74cf86bSGreg Clayton             return procSP->GetThreadList().RestoreRegisterState (tid, save_id);
1668f74cf86bSGreg Clayton     }
1669f74cf86bSGreg Clayton     return false;
1670f74cf86bSGreg Clayton }
1671f74cf86bSGreg Clayton 
1672f74cf86bSGreg Clayton 
1673f74cf86bSGreg Clayton 
167430fdc8d8SChris Lattner //----------------------------------------------------------------------
167530fdc8d8SChris Lattner // Read a register value by name.
167630fdc8d8SChris Lattner //----------------------------------------------------------------------
167730fdc8d8SChris Lattner nub_bool_t
167830fdc8d8SChris Lattner DNBThreadGetRegisterValueByName (nub_process_t pid, nub_thread_t tid, uint32_t reg_set, const char *reg_name, DNBRegisterValue *value)
167930fdc8d8SChris Lattner {
168030fdc8d8SChris Lattner     MachProcessSP procSP;
168130fdc8d8SChris Lattner     ::bzero (value, sizeof(DNBRegisterValue));
168230fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
168330fdc8d8SChris Lattner     {
168430fdc8d8SChris Lattner         const struct DNBRegisterSetInfo *set_info;
168530fdc8d8SChris Lattner         nub_size_t num_reg_sets = 0;
168630fdc8d8SChris Lattner         set_info = DNBGetRegisterSetInfo (&num_reg_sets);
168730fdc8d8SChris Lattner         if (set_info)
168830fdc8d8SChris Lattner         {
168930fdc8d8SChris Lattner             uint32_t set = reg_set;
169030fdc8d8SChris Lattner             uint32_t reg;
169130fdc8d8SChris Lattner             if (set == REGISTER_SET_ALL)
169230fdc8d8SChris Lattner             {
169330fdc8d8SChris Lattner                 for (set = 1; set < num_reg_sets; ++set)
169430fdc8d8SChris Lattner                 {
169530fdc8d8SChris Lattner                     for (reg = 0; reg < set_info[set].num_registers; ++reg)
169630fdc8d8SChris Lattner                     {
169730fdc8d8SChris Lattner                         if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
169830fdc8d8SChris Lattner                             return procSP->GetRegisterValue (tid, set, reg, value);
169930fdc8d8SChris Lattner                     }
170030fdc8d8SChris Lattner                 }
170130fdc8d8SChris Lattner             }
170230fdc8d8SChris Lattner             else
170330fdc8d8SChris Lattner             {
170430fdc8d8SChris Lattner                 for (reg = 0; reg < set_info[set].num_registers; ++reg)
170530fdc8d8SChris Lattner                 {
170630fdc8d8SChris Lattner                     if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
170730fdc8d8SChris Lattner                         return procSP->GetRegisterValue (tid, set, reg, value);
170830fdc8d8SChris Lattner                 }
170930fdc8d8SChris Lattner             }
171030fdc8d8SChris Lattner         }
171130fdc8d8SChris Lattner     }
171230fdc8d8SChris Lattner     return false;
171330fdc8d8SChris Lattner }
171430fdc8d8SChris Lattner 
171530fdc8d8SChris Lattner 
171630fdc8d8SChris Lattner //----------------------------------------------------------------------
171730fdc8d8SChris Lattner // Read a register set and register number from the register name.
171830fdc8d8SChris Lattner //----------------------------------------------------------------------
171930fdc8d8SChris Lattner nub_bool_t
172030fdc8d8SChris Lattner DNBGetRegisterInfoByName (const char *reg_name, DNBRegisterInfo* info)
172130fdc8d8SChris Lattner {
172230fdc8d8SChris Lattner     const struct DNBRegisterSetInfo *set_info;
172330fdc8d8SChris Lattner     nub_size_t num_reg_sets = 0;
172430fdc8d8SChris Lattner     set_info = DNBGetRegisterSetInfo (&num_reg_sets);
172530fdc8d8SChris Lattner     if (set_info)
172630fdc8d8SChris Lattner     {
172730fdc8d8SChris Lattner         uint32_t set, reg;
172830fdc8d8SChris Lattner         for (set = 1; set < num_reg_sets; ++set)
172930fdc8d8SChris Lattner         {
173030fdc8d8SChris Lattner             for (reg = 0; reg < set_info[set].num_registers; ++reg)
173130fdc8d8SChris Lattner             {
173230fdc8d8SChris Lattner                 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
173330fdc8d8SChris Lattner                 {
173430fdc8d8SChris Lattner                     *info = set_info[set].registers[reg];
173530fdc8d8SChris Lattner                     return true;
173630fdc8d8SChris Lattner                 }
173730fdc8d8SChris Lattner             }
173830fdc8d8SChris Lattner         }
173930fdc8d8SChris Lattner 
174030fdc8d8SChris Lattner         for (set = 1; set < num_reg_sets; ++set)
174130fdc8d8SChris Lattner         {
174230fdc8d8SChris Lattner             uint32_t reg;
174330fdc8d8SChris Lattner             for (reg = 0; reg < set_info[set].num_registers; ++reg)
174430fdc8d8SChris Lattner             {
174530fdc8d8SChris Lattner                 if (set_info[set].registers[reg].alt == NULL)
174630fdc8d8SChris Lattner                     continue;
174730fdc8d8SChris Lattner 
174830fdc8d8SChris Lattner                 if (strcasecmp(reg_name, set_info[set].registers[reg].alt) == 0)
174930fdc8d8SChris Lattner                 {
175030fdc8d8SChris Lattner                     *info = set_info[set].registers[reg];
175130fdc8d8SChris Lattner                     return true;
175230fdc8d8SChris Lattner                 }
175330fdc8d8SChris Lattner             }
175430fdc8d8SChris Lattner         }
175530fdc8d8SChris Lattner     }
175630fdc8d8SChris Lattner 
175730fdc8d8SChris Lattner     ::bzero (info, sizeof(DNBRegisterInfo));
175830fdc8d8SChris Lattner     return false;
175930fdc8d8SChris Lattner }
176030fdc8d8SChris Lattner 
176130fdc8d8SChris Lattner 
176230fdc8d8SChris Lattner //----------------------------------------------------------------------
176330fdc8d8SChris Lattner // Set the name to address callback function that this nub can use
176430fdc8d8SChris Lattner // for any name to address lookups that are needed.
176530fdc8d8SChris Lattner //----------------------------------------------------------------------
176630fdc8d8SChris Lattner nub_bool_t
176730fdc8d8SChris Lattner DNBProcessSetNameToAddressCallback (nub_process_t pid, DNBCallbackNameToAddress callback, void *baton)
176830fdc8d8SChris Lattner {
176930fdc8d8SChris Lattner     MachProcessSP procSP;
177030fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
177130fdc8d8SChris Lattner     {
177230fdc8d8SChris Lattner         procSP->SetNameToAddressCallback (callback, baton);
177330fdc8d8SChris Lattner         return true;
177430fdc8d8SChris Lattner     }
177530fdc8d8SChris Lattner     return false;
177630fdc8d8SChris Lattner }
177730fdc8d8SChris Lattner 
177830fdc8d8SChris Lattner 
177930fdc8d8SChris Lattner //----------------------------------------------------------------------
178030fdc8d8SChris Lattner // Set the name to address callback function that this nub can use
178130fdc8d8SChris Lattner // for any name to address lookups that are needed.
178230fdc8d8SChris Lattner //----------------------------------------------------------------------
178330fdc8d8SChris Lattner nub_bool_t
178430fdc8d8SChris Lattner DNBProcessSetSharedLibraryInfoCallback (nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, void  *baton)
178530fdc8d8SChris Lattner {
178630fdc8d8SChris Lattner     MachProcessSP procSP;
178730fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
178830fdc8d8SChris Lattner     {
178930fdc8d8SChris Lattner         procSP->SetSharedLibraryInfoCallback (callback, baton);
179030fdc8d8SChris Lattner         return true;
179130fdc8d8SChris Lattner     }
179230fdc8d8SChris Lattner     return false;
179330fdc8d8SChris Lattner }
179430fdc8d8SChris Lattner 
179530fdc8d8SChris Lattner nub_addr_t
179630fdc8d8SChris Lattner DNBProcessLookupAddress (nub_process_t pid, const char *name, const char *shlib)
179730fdc8d8SChris Lattner {
179830fdc8d8SChris Lattner     MachProcessSP procSP;
179930fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
180030fdc8d8SChris Lattner     {
180130fdc8d8SChris Lattner         return procSP->LookupSymbol (name, shlib);
180230fdc8d8SChris Lattner     }
180330fdc8d8SChris Lattner     return INVALID_NUB_ADDRESS;
180430fdc8d8SChris Lattner }
180530fdc8d8SChris Lattner 
180630fdc8d8SChris Lattner 
180730fdc8d8SChris Lattner nub_size_t
180830fdc8d8SChris Lattner DNBProcessGetAvailableSTDOUT (nub_process_t pid, char *buf, nub_size_t buf_size)
180930fdc8d8SChris Lattner {
181030fdc8d8SChris Lattner     MachProcessSP procSP;
181130fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
181230fdc8d8SChris Lattner         return procSP->GetAvailableSTDOUT (buf, buf_size);
181330fdc8d8SChris Lattner     return 0;
181430fdc8d8SChris Lattner }
181530fdc8d8SChris Lattner 
181630fdc8d8SChris Lattner nub_size_t
181730fdc8d8SChris Lattner DNBProcessGetAvailableSTDERR (nub_process_t pid, char *buf, nub_size_t buf_size)
181830fdc8d8SChris Lattner {
181930fdc8d8SChris Lattner     MachProcessSP procSP;
182030fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
182130fdc8d8SChris Lattner         return procSP->GetAvailableSTDERR (buf, buf_size);
182230fdc8d8SChris Lattner     return 0;
182330fdc8d8SChris Lattner }
182430fdc8d8SChris Lattner 
182530fdc8d8SChris Lattner nub_size_t
1826ab3b8b22SHan Ming Ong DNBProcessGetAvailableProfileData (nub_process_t pid, char *buf, nub_size_t buf_size)
1827ab3b8b22SHan Ming Ong {
1828ab3b8b22SHan Ming Ong     MachProcessSP procSP;
1829ab3b8b22SHan Ming Ong     if (GetProcessSP (pid, procSP))
1830ab3b8b22SHan Ming Ong         return procSP->GetAsyncProfileData (buf, buf_size);
1831ab3b8b22SHan Ming Ong     return 0;
1832ab3b8b22SHan Ming Ong }
1833ab3b8b22SHan Ming Ong 
1834ab3b8b22SHan Ming Ong nub_size_t
183530fdc8d8SChris Lattner DNBProcessGetStopCount (nub_process_t pid)
183630fdc8d8SChris Lattner {
183730fdc8d8SChris Lattner     MachProcessSP procSP;
183830fdc8d8SChris Lattner     if (GetProcessSP (pid, procSP))
183930fdc8d8SChris Lattner         return procSP->StopCount();
184030fdc8d8SChris Lattner     return 0;
184130fdc8d8SChris Lattner }
184230fdc8d8SChris Lattner 
184371337622SGreg Clayton uint32_t
184471337622SGreg Clayton DNBProcessGetCPUType (nub_process_t pid)
184571337622SGreg Clayton {
184671337622SGreg Clayton     MachProcessSP procSP;
184771337622SGreg Clayton     if (GetProcessSP (pid, procSP))
184871337622SGreg Clayton         return procSP->GetCPUType ();
184971337622SGreg Clayton     return 0;
185071337622SGreg Clayton 
185171337622SGreg Clayton }
185271337622SGreg Clayton 
185330fdc8d8SChris Lattner nub_bool_t
185430fdc8d8SChris Lattner DNBResolveExecutablePath (const char *path, char *resolved_path, size_t resolved_path_size)
185530fdc8d8SChris Lattner {
185630fdc8d8SChris Lattner     if (path == NULL || path[0] == '\0')
185730fdc8d8SChris Lattner         return false;
185830fdc8d8SChris Lattner 
185930fdc8d8SChris Lattner     char max_path[PATH_MAX];
186030fdc8d8SChris Lattner     std::string result;
186130fdc8d8SChris Lattner     CFString::GlobPath(path, result);
186230fdc8d8SChris Lattner 
186330fdc8d8SChris Lattner     if (result.empty())
186430fdc8d8SChris Lattner         result = path;
186530fdc8d8SChris Lattner 
186648baf7a7SGreg Clayton     struct stat path_stat;
186748baf7a7SGreg Clayton     if (::stat(path, &path_stat) == 0)
186848baf7a7SGreg Clayton     {
186948baf7a7SGreg Clayton         if ((path_stat.st_mode & S_IFMT) == S_IFDIR)
187048baf7a7SGreg Clayton         {
187148baf7a7SGreg Clayton             CFBundle bundle (path);
187248baf7a7SGreg Clayton             CFReleaser<CFURLRef> url(bundle.CopyExecutableURL ());
187348baf7a7SGreg Clayton             if (url.get())
187448baf7a7SGreg Clayton             {
187548baf7a7SGreg Clayton                 if (::CFURLGetFileSystemRepresentation (url.get(), true, (UInt8*)resolved_path, resolved_path_size))
187648baf7a7SGreg Clayton                     return true;
187748baf7a7SGreg Clayton             }
187848baf7a7SGreg Clayton         }
187948baf7a7SGreg Clayton     }
188048baf7a7SGreg Clayton 
188130fdc8d8SChris Lattner     if (realpath(path, max_path))
188230fdc8d8SChris Lattner     {
188330fdc8d8SChris Lattner         // Found the path relatively...
188430fdc8d8SChris Lattner         ::strncpy(resolved_path, max_path, resolved_path_size);
188530fdc8d8SChris Lattner         return strlen(resolved_path) + 1 < resolved_path_size;
188630fdc8d8SChris Lattner     }
188730fdc8d8SChris Lattner     else
188830fdc8d8SChris Lattner     {
188930fdc8d8SChris Lattner         // Not a relative path, check the PATH environment variable if the
189030fdc8d8SChris Lattner         const char *PATH = getenv("PATH");
189130fdc8d8SChris Lattner         if (PATH)
189230fdc8d8SChris Lattner         {
189330fdc8d8SChris Lattner             const char *curr_path_start = PATH;
189430fdc8d8SChris Lattner             const char *curr_path_end;
189530fdc8d8SChris Lattner             while (curr_path_start && *curr_path_start)
189630fdc8d8SChris Lattner             {
189730fdc8d8SChris Lattner                 curr_path_end = strchr(curr_path_start, ':');
189830fdc8d8SChris Lattner                 if (curr_path_end == NULL)
189930fdc8d8SChris Lattner                 {
190030fdc8d8SChris Lattner                     result.assign(curr_path_start);
190130fdc8d8SChris Lattner                     curr_path_start = NULL;
190230fdc8d8SChris Lattner                 }
190330fdc8d8SChris Lattner                 else if (curr_path_end > curr_path_start)
190430fdc8d8SChris Lattner                 {
190530fdc8d8SChris Lattner                     size_t len = curr_path_end - curr_path_start;
190630fdc8d8SChris Lattner                     result.assign(curr_path_start, len);
190730fdc8d8SChris Lattner                     curr_path_start += len + 1;
190830fdc8d8SChris Lattner                 }
190930fdc8d8SChris Lattner                 else
191030fdc8d8SChris Lattner                     break;
191130fdc8d8SChris Lattner 
191230fdc8d8SChris Lattner                 result += '/';
191330fdc8d8SChris Lattner                 result += path;
191430fdc8d8SChris Lattner                 struct stat s;
191530fdc8d8SChris Lattner                 if (stat(result.c_str(), &s) == 0)
191630fdc8d8SChris Lattner                 {
191730fdc8d8SChris Lattner                     ::strncpy(resolved_path, result.c_str(), resolved_path_size);
191830fdc8d8SChris Lattner                     return result.size() + 1 < resolved_path_size;
191930fdc8d8SChris Lattner                 }
192030fdc8d8SChris Lattner             }
192130fdc8d8SChris Lattner         }
192230fdc8d8SChris Lattner     }
192330fdc8d8SChris Lattner     return false;
192430fdc8d8SChris Lattner }
192530fdc8d8SChris Lattner 
19263af9ea56SGreg Clayton 
19273af9ea56SGreg Clayton void
19283af9ea56SGreg Clayton DNBInitialize()
19293af9ea56SGreg Clayton {
19303af9ea56SGreg Clayton     DNBLogThreadedIf (LOG_PROCESS, "DNBInitialize ()");
19313af9ea56SGreg Clayton #if defined (__i386__) || defined (__x86_64__)
19323af9ea56SGreg Clayton     DNBArchImplI386::Initialize();
19333af9ea56SGreg Clayton     DNBArchImplX86_64::Initialize();
1934013434e5STodd Fiala #elif defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
19353af9ea56SGreg Clayton     DNBArchMachARM::Initialize();
1936a332978bSJason Molenda     DNBArchMachARM64::Initialize();
19373af9ea56SGreg Clayton #endif
19383af9ea56SGreg Clayton }
19393af9ea56SGreg Clayton 
19403af9ea56SGreg Clayton void
19413af9ea56SGreg Clayton DNBTerminate()
19423af9ea56SGreg Clayton {
19433af9ea56SGreg Clayton }
19443c14438fSGreg Clayton 
19453c14438fSGreg Clayton nub_bool_t
19463c14438fSGreg Clayton DNBSetArchitecture (const char *arch)
19473c14438fSGreg Clayton {
19483c14438fSGreg Clayton     if (arch && arch[0])
19493c14438fSGreg Clayton     {
19503c14438fSGreg Clayton         if (strcasecmp (arch, "i386") == 0)
19513c14438fSGreg Clayton             return DNBArchProtocol::SetArchitecture (CPU_TYPE_I386);
1952a86dc433SGreg Clayton         else if ((strcasecmp (arch, "x86_64") == 0) || (strcasecmp (arch, "x86_64h") == 0))
19533c14438fSGreg Clayton             return DNBArchProtocol::SetArchitecture (CPU_TYPE_X86_64);
1954013434e5STodd Fiala         else if (strstr (arch, "arm64") == arch || strstr (arch, "armv8") == arch || strstr (arch, "aarch64") == arch)
1955a332978bSJason Molenda             return DNBArchProtocol::SetArchitecture (CPU_TYPE_ARM64);
19563c14438fSGreg Clayton         else if (strstr (arch, "arm") == arch)
19573c14438fSGreg Clayton             return DNBArchProtocol::SetArchitecture (CPU_TYPE_ARM);
19583c14438fSGreg Clayton     }
19593c14438fSGreg Clayton     return false;
19603c14438fSGreg Clayton }
1961