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