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