1 //===-- DNB.cpp -------------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Created by Greg Clayton on 3/23/07.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "DNB.h"
14 #include <cinttypes>
15 #include <csignal>
16 #include <cstdio>
17 #include <cstdlib>
18 #include <libproc.h>
19 #include <map>
20 #include <sys/resource.h>
21 #include <sys/stat.h>
22 #include <sys/sysctl.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <unistd.h>
26 #include <vector>
27
28 #if defined(__APPLE__)
29 #include <pthread.h>
30 #include <sched.h>
31 #endif
32
33 #define TRY_KQUEUE 1
34
35 #ifdef TRY_KQUEUE
36 #include <sys/event.h>
37 #include <sys/time.h>
38 #ifdef NOTE_EXIT_DETAIL
39 #define USE_KQUEUE
40 #endif
41 #endif
42
43 #include "CFBundle.h"
44 #include "CFString.h"
45 #include "DNBDataRef.h"
46 #include "DNBLog.h"
47 #include "DNBThreadResumeActions.h"
48 #include "DNBTimer.h"
49 #include "MacOSX/Genealogy.h"
50 #include "MacOSX/MachProcess.h"
51 #include "MacOSX/MachTask.h"
52 #include "MacOSX/ThreadInfo.h"
53
54 typedef std::shared_ptr<MachProcess> MachProcessSP;
55 typedef std::map<nub_process_t, MachProcessSP> ProcessMap;
56 typedef ProcessMap::iterator ProcessMapIter;
57 typedef ProcessMap::const_iterator ProcessMapConstIter;
58
59 static size_t
60 GetAllInfosMatchingName(const char *process_name,
61 std::vector<struct kinfo_proc> &matching_proc_infos);
62
63 // A Thread safe singleton to get a process map pointer.
64 //
65 // Returns a pointer to the existing process map, or a pointer to a
66 // newly created process map if CAN_CREATE is non-zero.
GetProcessMap(bool can_create)67 static ProcessMap *GetProcessMap(bool can_create) {
68 static ProcessMap *g_process_map_ptr = NULL;
69
70 if (can_create && g_process_map_ptr == NULL) {
71 static pthread_mutex_t g_process_map_mutex = PTHREAD_MUTEX_INITIALIZER;
72 PTHREAD_MUTEX_LOCKER(locker, &g_process_map_mutex);
73 if (g_process_map_ptr == NULL)
74 g_process_map_ptr = new ProcessMap;
75 }
76 return g_process_map_ptr;
77 }
78
79 // Add PID to the shared process pointer map.
80 //
81 // Return non-zero value if we succeed in adding the process to the map.
82 // The only time this should fail is if we run out of memory and can't
83 // allocate a ProcessMap.
AddProcessToMap(nub_process_t pid,MachProcessSP & procSP)84 static nub_bool_t AddProcessToMap(nub_process_t pid, MachProcessSP &procSP) {
85 ProcessMap *process_map = GetProcessMap(true);
86 if (process_map) {
87 process_map->insert(std::make_pair(pid, procSP));
88 return true;
89 }
90 return false;
91 }
92
93 // Remove the shared pointer for PID from the process map.
94 //
95 // Returns the number of items removed from the process map.
96 // static size_t
97 // RemoveProcessFromMap (nub_process_t pid)
98 //{
99 // ProcessMap* process_map = GetProcessMap(false);
100 // if (process_map)
101 // {
102 // return process_map->erase(pid);
103 // }
104 // return 0;
105 //}
106
107 // Get the shared pointer for PID from the existing process map.
108 //
109 // Returns true if we successfully find a shared pointer to a
110 // MachProcess object.
GetProcessSP(nub_process_t pid,MachProcessSP & procSP)111 static nub_bool_t GetProcessSP(nub_process_t pid, MachProcessSP &procSP) {
112 ProcessMap *process_map = GetProcessMap(false);
113 if (process_map != NULL) {
114 ProcessMapIter pos = process_map->find(pid);
115 if (pos != process_map->end()) {
116 procSP = pos->second;
117 return true;
118 }
119 }
120 procSP.reset();
121 return false;
122 }
123
124 #ifdef USE_KQUEUE
kqueue_thread(void * arg)125 void *kqueue_thread(void *arg) {
126 int kq_id = (int)(intptr_t)arg;
127
128 #if defined(__APPLE__)
129 pthread_setname_np("kqueue thread");
130 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
131 struct sched_param thread_param;
132 int thread_sched_policy;
133 if (pthread_getschedparam(pthread_self(), &thread_sched_policy,
134 &thread_param) == 0) {
135 thread_param.sched_priority = 47;
136 pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
137 }
138 #endif
139 #endif
140
141 struct kevent death_event;
142 while (true) {
143 int n_events = kevent(kq_id, NULL, 0, &death_event, 1, NULL);
144 if (n_events == -1) {
145 if (errno == EINTR)
146 continue;
147 else {
148 DNBLogError("kqueue failed with error: (%d): %s", errno,
149 strerror(errno));
150 return NULL;
151 }
152 } else if (death_event.flags & EV_ERROR) {
153 int error_no = static_cast<int>(death_event.data);
154 const char *error_str = strerror(error_no);
155 if (error_str == NULL)
156 error_str = "Unknown error";
157 DNBLogError("Failed to initialize kqueue event: (%d): %s", error_no,
158 error_str);
159 return NULL;
160 } else {
161 int status;
162 const pid_t pid = (pid_t)death_event.ident;
163 const pid_t child_pid = waitpid(pid, &status, 0);
164
165 bool exited = false;
166 int signal = 0;
167 int exit_status = 0;
168 if (WIFSTOPPED(status)) {
169 signal = WSTOPSIG(status);
170 DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> STOPPED (signal = %i)",
171 child_pid, signal);
172 } else if (WIFEXITED(status)) {
173 exit_status = WEXITSTATUS(status);
174 exited = true;
175 DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> EXITED (status = %i)",
176 child_pid, exit_status);
177 } else if (WIFSIGNALED(status)) {
178 signal = WTERMSIG(status);
179 if (child_pid == abs(pid)) {
180 DNBLogThreadedIf(LOG_PROCESS,
181 "waitpid (%i) -> SIGNALED and EXITED (signal = %i)",
182 child_pid, signal);
183 char exit_info[64];
184 ::snprintf(exit_info, sizeof(exit_info),
185 "Terminated due to signal %i", signal);
186 DNBProcessSetExitInfo(child_pid, exit_info);
187 exited = true;
188 exit_status = INT8_MAX;
189 } else {
190 DNBLogThreadedIf(LOG_PROCESS,
191 "waitpid (%i) -> SIGNALED (signal = %i)", child_pid,
192 signal);
193 }
194 }
195
196 if (exited) {
197 if (death_event.data & NOTE_EXIT_MEMORY)
198 DNBProcessSetExitInfo(child_pid, "Terminated due to memory issue");
199 else if (death_event.data & NOTE_EXIT_DECRYPTFAIL)
200 DNBProcessSetExitInfo(child_pid, "Terminated due to decrypt failure");
201 else if (death_event.data & NOTE_EXIT_CSERROR)
202 DNBProcessSetExitInfo(child_pid,
203 "Terminated due to code signing error");
204
205 DNBLogThreadedIf(
206 LOG_PROCESS,
207 "waitpid_process_thread (): setting exit status for pid = %i to %i",
208 child_pid, exit_status);
209 DNBProcessSetExitStatus(child_pid, status);
210 return NULL;
211 }
212 }
213 }
214 }
215
spawn_kqueue_thread(pid_t pid)216 static bool spawn_kqueue_thread(pid_t pid) {
217 pthread_t thread;
218 int kq_id;
219
220 kq_id = kqueue();
221 if (kq_id == -1) {
222 DNBLogError("Could not get kqueue for pid = %i.", pid);
223 return false;
224 }
225
226 struct kevent reg_event;
227
228 EV_SET(®_event, pid, EVFILT_PROC, EV_ADD,
229 NOTE_EXIT | NOTE_EXITSTATUS | NOTE_EXIT_DETAIL, 0, NULL);
230 // Register the event:
231 int result = kevent(kq_id, ®_event, 1, NULL, 0, NULL);
232 if (result != 0) {
233 DNBLogError(
234 "Failed to register kqueue NOTE_EXIT event for pid %i, error: %d.", pid,
235 result);
236 return false;
237 }
238
239 int ret =
240 ::pthread_create(&thread, NULL, kqueue_thread, (void *)(intptr_t)kq_id);
241
242 // pthread_create returns 0 if successful
243 if (ret == 0) {
244 ::pthread_detach(thread);
245 return true;
246 }
247 return false;
248 }
249 #endif // #if USE_KQUEUE
250
waitpid_thread(void * arg)251 static void *waitpid_thread(void *arg) {
252 const pid_t pid = (pid_t)(intptr_t)arg;
253 int status;
254
255 #if defined(__APPLE__)
256 pthread_setname_np("waitpid thread");
257 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
258 struct sched_param thread_param;
259 int thread_sched_policy;
260 if (pthread_getschedparam(pthread_self(), &thread_sched_policy,
261 &thread_param) == 0) {
262 thread_param.sched_priority = 47;
263 pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
264 }
265 #endif
266 #endif
267
268 while (true) {
269 pid_t child_pid = waitpid(pid, &status, 0);
270 DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): waitpid (pid = %i, "
271 "&status, 0) => %i, status = %i, errno = %i",
272 pid, child_pid, status, errno);
273
274 if (child_pid < 0) {
275 if (errno == EINTR)
276 continue;
277 break;
278 } else {
279 if (WIFSTOPPED(status)) {
280 continue;
281 } else // if (WIFEXITED(status) || WIFSIGNALED(status))
282 {
283 DNBLogThreadedIf(
284 LOG_PROCESS,
285 "waitpid_thread (): setting exit status for pid = %i to %i",
286 child_pid, status);
287 DNBProcessSetExitStatus(child_pid, status);
288 return NULL;
289 }
290 }
291 }
292
293 // We should never exit as long as our child process is alive, so if we
294 // do something else went wrong and we should exit...
295 DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): main loop exited, setting "
296 "exit status to an invalid value (-1) for pid "
297 "%i",
298 pid);
299 DNBProcessSetExitStatus(pid, -1);
300 return NULL;
301 }
spawn_waitpid_thread(pid_t pid)302 static bool spawn_waitpid_thread(pid_t pid) {
303 #ifdef USE_KQUEUE
304 bool success = spawn_kqueue_thread(pid);
305 if (success)
306 return true;
307 #endif
308
309 pthread_t thread;
310 int ret =
311 ::pthread_create(&thread, NULL, waitpid_thread, (void *)(intptr_t)pid);
312 // pthread_create returns 0 if successful
313 if (ret == 0) {
314 ::pthread_detach(thread);
315 return true;
316 }
317 return false;
318 }
319
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)320 nub_process_t DNBProcessLaunch(
321 RNBContext *ctx, const char *path, char const *argv[], const char *envp[],
322 const char *working_directory, // NULL => don't change, non-NULL => set
323 // working directory for inferior to this
324 const char *stdin_path, const char *stdout_path, const char *stderr_path,
325 bool no_stdio, int disable_aslr, const char *event_data, char *err_str,
326 size_t err_len) {
327 DNBLogThreadedIf(LOG_PROCESS,
328 "%s ( path='%s', argv = %p, envp = %p, "
329 "working_dir=%s, stdin=%s, stdout=%s, "
330 "stderr=%s, no-stdio=%i, launch_flavor = %u, "
331 "disable_aslr = %d, err = %p, err_len = "
332 "%llu) called...",
333 __FUNCTION__, path, static_cast<void *>(argv),
334 static_cast<void *>(envp), working_directory, stdin_path,
335 stdout_path, stderr_path, no_stdio, ctx->LaunchFlavor(),
336 disable_aslr, static_cast<void *>(err_str),
337 static_cast<uint64_t>(err_len));
338
339 if (err_str && err_len > 0)
340 err_str[0] = '\0';
341 struct stat path_stat;
342 if (::stat(path, &path_stat) == -1) {
343 char stat_error[256];
344 ::strerror_r(errno, stat_error, sizeof(stat_error));
345 snprintf(err_str, err_len, "%s (%s)", stat_error, path);
346 return INVALID_NUB_PROCESS;
347 }
348
349 MachProcessSP processSP(new MachProcess);
350 if (processSP.get()) {
351 DNBError launch_err;
352 pid_t pid = processSP->LaunchForDebug(
353 path, argv, envp, working_directory, stdin_path, stdout_path,
354 stderr_path, no_stdio, ctx->LaunchFlavor(), disable_aslr, event_data,
355 ctx->GetIgnoredExceptions(), launch_err);
356 if (err_str) {
357 *err_str = '\0';
358 if (launch_err.Fail()) {
359 const char *launch_err_str = launch_err.AsString();
360 if (launch_err_str) {
361 strlcpy(err_str, launch_err_str, err_len - 1);
362 err_str[err_len - 1] =
363 '\0'; // Make sure the error string is terminated
364 }
365 }
366 }
367
368 DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) new pid is %d...", pid);
369
370 if (pid != INVALID_NUB_PROCESS) {
371 // Spawn a thread to reap our child inferior process...
372 spawn_waitpid_thread(pid);
373
374 if (processSP->Task().TaskPortForProcessID(launch_err) == TASK_NULL) {
375 // We failed to get the task for our process ID which is bad.
376 // Kill our process otherwise it will be stopped at the entry
377 // point and get reparented to someone else and never go away.
378 DNBLog("Could not get task port for process, sending SIGKILL and "
379 "exiting.");
380 kill(SIGKILL, pid);
381
382 if (err_str && err_len > 0) {
383 if (launch_err.AsString()) {
384 ::snprintf(err_str, err_len,
385 "failed to get the task for process %i (%s)", pid,
386 launch_err.AsString());
387 } else {
388 ::snprintf(err_str, err_len,
389 "failed to get the task for process %i", pid);
390 }
391 }
392 } else {
393 bool res = AddProcessToMap(pid, processSP);
394 UNUSED_IF_ASSERT_DISABLED(res);
395 assert(res && "Couldn't add process to map!");
396 return pid;
397 }
398 }
399 }
400 return INVALID_NUB_PROCESS;
401 }
402
403 // If there is one process with a given name, return the pid for that process.
DNBProcessGetPIDByName(const char * name)404 nub_process_t DNBProcessGetPIDByName(const char *name) {
405 std::vector<struct kinfo_proc> matching_proc_infos;
406 size_t num_matching_proc_infos =
407 GetAllInfosMatchingName(name, matching_proc_infos);
408 if (num_matching_proc_infos == 1) {
409 return matching_proc_infos[0].kp_proc.p_pid;
410 }
411 return INVALID_NUB_PROCESS;
412 }
413
DNBProcessAttachByName(const char * name,struct timespec * timeout,const RNBContext::IgnoredExceptions & ignored_exceptions,char * err_str,size_t err_len)414 nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout,
415 const RNBContext::IgnoredExceptions
416 &ignored_exceptions, char *err_str,
417 size_t err_len) {
418 if (err_str && err_len > 0)
419 err_str[0] = '\0';
420 std::vector<struct kinfo_proc> matching_proc_infos;
421 size_t num_matching_proc_infos =
422 GetAllInfosMatchingName(name, matching_proc_infos);
423 if (num_matching_proc_infos == 0) {
424 DNBLogError("error: no processes match '%s'\n", name);
425 return INVALID_NUB_PROCESS;
426 }
427 if (num_matching_proc_infos > 1) {
428 DNBLogError("error: %llu processes match '%s':\n",
429 (uint64_t)num_matching_proc_infos, name);
430 size_t i;
431 for (i = 0; i < num_matching_proc_infos; ++i)
432 DNBLogError("%6u - %s\n", matching_proc_infos[i].kp_proc.p_pid,
433 matching_proc_infos[i].kp_proc.p_comm);
434 return INVALID_NUB_PROCESS;
435 }
436
437 return DNBProcessAttach(matching_proc_infos[0].kp_proc.p_pid, timeout,
438 ignored_exceptions, err_str, err_len);
439 }
440
DNBProcessAttach(nub_process_t attach_pid,struct timespec * timeout,const RNBContext::IgnoredExceptions & ignored_exceptions,char * err_str,size_t err_len)441 nub_process_t DNBProcessAttach(nub_process_t attach_pid,
442 struct timespec *timeout,
443 const RNBContext::IgnoredExceptions
444 &ignored_exceptions,
445 char *err_str, size_t err_len) {
446 if (err_str && err_len > 0)
447 err_str[0] = '\0';
448
449 if (getenv("LLDB_DEBUGSERVER_PATH") == NULL) {
450 int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID,
451 static_cast<int>(attach_pid)};
452 struct kinfo_proc processInfo;
453 size_t bufsize = sizeof(processInfo);
454 if (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo,
455 &bufsize, NULL, 0) == 0 &&
456 bufsize > 0) {
457
458 if ((processInfo.kp_proc.p_flag & P_TRANSLATED) == P_TRANSLATED) {
459 const char *translated_debugserver =
460 "/Library/Apple/usr/libexec/oah/debugserver";
461 char fdstr[16];
462 char pidstr[16];
463 extern int communication_fd;
464
465 if (communication_fd == -1) {
466 fprintf(stderr, "Trying to attach to a translated process with the "
467 "native debugserver, exiting...\n");
468 exit(1);
469 }
470
471 snprintf(fdstr, sizeof(fdstr), "--fd=%d", communication_fd);
472 snprintf(pidstr, sizeof(pidstr), "--attach=%d", attach_pid);
473 execl(translated_debugserver, translated_debugserver, "--native-regs",
474 "--setsid", fdstr, "--handoff-attach-from-native", pidstr,
475 (char *)0);
476 DNBLogThreadedIf(LOG_PROCESS, "Failed to launch debugserver for "
477 "translated process: ", errno, strerror(errno));
478 __builtin_trap();
479 }
480 }
481 }
482
483 if (DNBDebugserverIsTranslated()) {
484 return INVALID_NUB_PROCESS_ARCH;
485 }
486
487 pid_t pid = INVALID_NUB_PROCESS;
488 MachProcessSP processSP(new MachProcess);
489 if (processSP.get()) {
490 DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...",
491 attach_pid);
492 pid =
493 processSP->AttachForDebug(attach_pid, ignored_exceptions, err_str,
494 err_len);
495
496 if (pid != INVALID_NUB_PROCESS) {
497 bool res = AddProcessToMap(pid, processSP);
498 UNUSED_IF_ASSERT_DISABLED(res);
499 assert(res && "Couldn't add process to map!");
500 spawn_waitpid_thread(pid);
501 }
502 }
503
504 while (pid != INVALID_NUB_PROCESS) {
505 // Wait for process to start up and hit entry point
506 DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, "
507 "eEventProcessRunningStateChanged | "
508 "eEventProcessStoppedStateChanged, true, "
509 "INFINITE)...",
510 __FUNCTION__, pid);
511 nub_event_t set_events =
512 DNBProcessWaitForEvents(pid, eEventProcessRunningStateChanged |
513 eEventProcessStoppedStateChanged,
514 true, timeout);
515
516 DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, "
517 "eEventProcessRunningStateChanged | "
518 "eEventProcessStoppedStateChanged, true, "
519 "INFINITE) => 0x%8.8x",
520 __FUNCTION__, pid, set_events);
521
522 if (set_events == 0) {
523 if (err_str && err_len > 0)
524 snprintf(err_str, err_len, "operation timed out");
525 pid = INVALID_NUB_PROCESS;
526 } else {
527 if (set_events & (eEventProcessRunningStateChanged |
528 eEventProcessStoppedStateChanged)) {
529 nub_state_t pid_state = DNBProcessGetState(pid);
530 DNBLogThreadedIf(
531 LOG_PROCESS,
532 "%s process %4.4x state changed (eEventProcessStateChanged): %s",
533 __FUNCTION__, pid, DNBStateAsString(pid_state));
534
535 switch (pid_state) {
536 case eStateInvalid:
537 case eStateUnloaded:
538 case eStateAttaching:
539 case eStateLaunching:
540 case eStateSuspended:
541 break; // Ignore
542
543 case eStateRunning:
544 case eStateStepping:
545 // Still waiting to stop at entry point...
546 break;
547
548 case eStateStopped:
549 case eStateCrashed:
550 return pid;
551
552 case eStateDetached:
553 case eStateExited:
554 if (err_str && err_len > 0)
555 snprintf(err_str, err_len, "process exited");
556 return INVALID_NUB_PROCESS;
557 }
558 }
559
560 DNBProcessResetEvents(pid, set_events);
561 }
562 }
563
564 return INVALID_NUB_PROCESS;
565 }
566
DNBGetAllInfos(std::vector<struct kinfo_proc> & proc_infos)567 size_t DNBGetAllInfos(std::vector<struct kinfo_proc> &proc_infos) {
568 size_t size = 0;
569 int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
570 u_int namelen = sizeof(name) / sizeof(int);
571 int err;
572
573 // Try to find out how many processes are around so we can
574 // size the buffer appropriately. sysctl's man page specifically suggests
575 // this approach, and says it returns a bit larger size than needed to
576 // handle any new processes created between then and now.
577
578 err = ::sysctl(name, namelen, NULL, &size, NULL, 0);
579
580 if ((err < 0) && (err != ENOMEM)) {
581 proc_infos.clear();
582 perror("sysctl (mib, miblen, NULL, &num_processes, NULL, 0)");
583 return 0;
584 }
585
586 // Increase the size of the buffer by a few processes in case more have
587 // been spawned
588 proc_infos.resize(size / sizeof(struct kinfo_proc));
589 size = proc_infos.size() *
590 sizeof(struct kinfo_proc); // Make sure we don't exceed our resize...
591 err = ::sysctl(name, namelen, &proc_infos[0], &size, NULL, 0);
592 if (err < 0) {
593 proc_infos.clear();
594 return 0;
595 }
596
597 // Trim down our array to fit what we actually got back
598 proc_infos.resize(size / sizeof(struct kinfo_proc));
599 return proc_infos.size();
600 }
601
602 static size_t
GetAllInfosMatchingName(const char * full_process_name,std::vector<struct kinfo_proc> & matching_proc_infos)603 GetAllInfosMatchingName(const char *full_process_name,
604 std::vector<struct kinfo_proc> &matching_proc_infos) {
605
606 matching_proc_infos.clear();
607 if (full_process_name && full_process_name[0]) {
608 // We only get the process name, not the full path, from the proc_info. So
609 // just take the
610 // base name of the process name...
611 const char *process_name;
612 process_name = strrchr(full_process_name, '/');
613 if (process_name == NULL)
614 process_name = full_process_name;
615 else
616 process_name++;
617
618 const size_t process_name_len = strlen(process_name);
619 std::vector<struct kinfo_proc> proc_infos;
620 const size_t num_proc_infos = DNBGetAllInfos(proc_infos);
621 if (num_proc_infos > 0) {
622 uint32_t i;
623 for (i = 0; i < num_proc_infos; i++) {
624 // Skip zombie processes and processes with unset status
625 if (proc_infos[i].kp_proc.p_stat == 0 ||
626 proc_infos[i].kp_proc.p_stat == SZOMB)
627 continue;
628
629 // Check for process by name. We only check the first MAXCOMLEN
630 // chars as that is all that kp_proc.p_comm holds.
631
632 if (::strncasecmp(process_name, proc_infos[i].kp_proc.p_comm,
633 MAXCOMLEN) == 0) {
634 if (process_name_len > MAXCOMLEN) {
635 // We found a matching process name whose first MAXCOMLEN
636 // characters match, but there is more to the name than
637 // this. We need to get the full process name. Use proc_pidpath,
638 // which will get
639 // us the full path to the executed process.
640
641 char proc_path_buf[PATH_MAX];
642
643 int return_val = proc_pidpath(proc_infos[i].kp_proc.p_pid,
644 proc_path_buf, PATH_MAX);
645 if (return_val > 0) {
646 // Okay, now search backwards from that to see if there is a
647 // slash in the name. Note, even though we got all the args we
648 // don't care
649 // because the list data is just a bunch of concatenated null
650 // terminated strings
651 // so strrchr will start from the end of argv0.
652
653 const char *argv_basename = strrchr(proc_path_buf, '/');
654 if (argv_basename) {
655 // Skip the '/'
656 ++argv_basename;
657 } else {
658 // We didn't find a directory delimiter in the process argv[0],
659 // just use what was in there
660 argv_basename = proc_path_buf;
661 }
662
663 if (argv_basename) {
664 if (::strncasecmp(process_name, argv_basename, PATH_MAX) == 0) {
665 matching_proc_infos.push_back(proc_infos[i]);
666 }
667 }
668 }
669 } else {
670 // We found a matching process, add it to our list
671 matching_proc_infos.push_back(proc_infos[i]);
672 }
673 }
674 }
675 }
676 }
677 // return the newly added matches.
678 return matching_proc_infos.size();
679 }
680
681 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)682 DNBProcessAttachWait(RNBContext *ctx, const char *waitfor_process_name,
683 bool ignore_existing, struct timespec *timeout_abstime,
684 useconds_t waitfor_interval, char *err_str, size_t err_len,
685 DNBShouldCancelCallback should_cancel_callback,
686 void *callback_data) {
687 DNBError prepare_error;
688 std::vector<struct kinfo_proc> exclude_proc_infos;
689 size_t num_exclude_proc_infos;
690
691 nub_launch_flavor_t launch_flavor = ctx->LaunchFlavor();
692
693 // If the PrepareForAttach returns a valid token, use MachProcess to check
694 // for the process, otherwise scan the process table.
695
696 const void *attach_token = MachProcess::PrepareForAttach(
697 waitfor_process_name, launch_flavor, true, prepare_error);
698
699 if (prepare_error.Fail()) {
700 DNBLogError("Error in PrepareForAttach: %s", prepare_error.AsString());
701 return INVALID_NUB_PROCESS;
702 }
703
704 if (attach_token == NULL) {
705 if (ignore_existing)
706 num_exclude_proc_infos =
707 GetAllInfosMatchingName(waitfor_process_name, exclude_proc_infos);
708 else
709 num_exclude_proc_infos = 0;
710 }
711
712 DNBLogThreadedIf(LOG_PROCESS, "Waiting for '%s' to appear...\n",
713 waitfor_process_name);
714
715 // Loop and try to find the process by name
716 nub_process_t waitfor_pid = INVALID_NUB_PROCESS;
717
718 while (waitfor_pid == INVALID_NUB_PROCESS) {
719 if (attach_token != NULL) {
720 nub_process_t pid;
721 pid = MachProcess::CheckForProcess(attach_token, launch_flavor);
722 if (pid != INVALID_NUB_PROCESS) {
723 waitfor_pid = pid;
724 break;
725 }
726 } else {
727
728 // Get the current process list, and check for matches that
729 // aren't in our original list. If anyone wants to attach
730 // to an existing process by name, they should do it with
731 // --attach=PROCNAME. Else we will wait for the first matching
732 // process that wasn't in our exclusion list.
733 std::vector<struct kinfo_proc> proc_infos;
734 const size_t num_proc_infos =
735 GetAllInfosMatchingName(waitfor_process_name, proc_infos);
736 for (size_t i = 0; i < num_proc_infos; i++) {
737 nub_process_t curr_pid = proc_infos[i].kp_proc.p_pid;
738 for (size_t j = 0; j < num_exclude_proc_infos; j++) {
739 if (curr_pid == exclude_proc_infos[j].kp_proc.p_pid) {
740 // This process was in our exclusion list, don't use it.
741 curr_pid = INVALID_NUB_PROCESS;
742 break;
743 }
744 }
745
746 // If we didn't find CURR_PID in our exclusion list, then use it.
747 if (curr_pid != INVALID_NUB_PROCESS) {
748 // We found our process!
749 waitfor_pid = curr_pid;
750 break;
751 }
752 }
753 }
754
755 // If we haven't found our process yet, check for a timeout
756 // and then sleep for a bit until we poll again.
757 if (waitfor_pid == INVALID_NUB_PROCESS) {
758 if (timeout_abstime != NULL) {
759 // Check to see if we have a waitfor-duration option that
760 // has timed out?
761 if (DNBTimer::TimeOfDayLaterThan(*timeout_abstime)) {
762 if (err_str && err_len > 0)
763 snprintf(err_str, err_len, "operation timed out");
764 DNBLogError("error: waiting for process '%s' timed out.\n",
765 waitfor_process_name);
766 return INVALID_NUB_PROCESS;
767 }
768 }
769
770 // Call the should cancel callback as well...
771
772 if (should_cancel_callback != NULL &&
773 should_cancel_callback(callback_data)) {
774 DNBLogThreadedIf(
775 LOG_PROCESS,
776 "DNBProcessAttachWait cancelled by should_cancel callback.");
777 waitfor_pid = INVALID_NUB_PROCESS;
778 break;
779 }
780
781 ::usleep(waitfor_interval); // Sleep for WAITFOR_INTERVAL, then poll again
782 }
783 }
784
785 if (waitfor_pid != INVALID_NUB_PROCESS) {
786 DNBLogThreadedIf(LOG_PROCESS, "Attaching to %s with pid %i...\n",
787 waitfor_process_name, waitfor_pid);
788 waitfor_pid = DNBProcessAttach(waitfor_pid, timeout_abstime,
789 ctx->GetIgnoredExceptions(), err_str,
790 err_len);
791 }
792
793 bool success = waitfor_pid != INVALID_NUB_PROCESS;
794 MachProcess::CleanupAfterAttach(attach_token, launch_flavor, success,
795 prepare_error);
796
797 return waitfor_pid;
798 }
799
DNBProcessDetach(nub_process_t pid)800 nub_bool_t DNBProcessDetach(nub_process_t pid) {
801 MachProcessSP procSP;
802 if (GetProcessSP(pid, procSP)) {
803 const bool remove = true;
804 DNBLogThreaded(
805 "Disabling breakpoints and watchpoints, and detaching from %d.", pid);
806 procSP->DisableAllBreakpoints(remove);
807 procSP->DisableAllWatchpoints(remove);
808 return procSP->Detach();
809 }
810 return false;
811 }
812
DNBProcessKill(nub_process_t pid)813 nub_bool_t DNBProcessKill(nub_process_t pid) {
814 MachProcessSP procSP;
815 if (GetProcessSP(pid, procSP)) {
816 return procSP->Kill();
817 }
818 return false;
819 }
820
DNBProcessSignal(nub_process_t pid,int signal)821 nub_bool_t DNBProcessSignal(nub_process_t pid, int signal) {
822 MachProcessSP procSP;
823 if (GetProcessSP(pid, procSP)) {
824 return procSP->Signal(signal);
825 }
826 return false;
827 }
828
DNBProcessInterrupt(nub_process_t pid)829 nub_bool_t DNBProcessInterrupt(nub_process_t pid) {
830 MachProcessSP procSP;
831 if (GetProcessSP(pid, procSP))
832 return procSP->Interrupt();
833 return false;
834 }
835
DNBProcessSendEvent(nub_process_t pid,const char * event)836 nub_bool_t DNBProcessSendEvent(nub_process_t pid, const char *event) {
837 MachProcessSP procSP;
838 if (GetProcessSP(pid, procSP)) {
839 // FIXME: Do something with the error...
840 DNBError send_error;
841 return procSP->SendEvent(event, send_error);
842 }
843 return false;
844 }
845
DNBProcessIsAlive(nub_process_t pid)846 nub_bool_t DNBProcessIsAlive(nub_process_t pid) {
847 MachProcessSP procSP;
848 if (GetProcessSP(pid, procSP)) {
849 return MachTask::IsValid(procSP->Task().TaskPort());
850 }
851 return eStateInvalid;
852 }
853
854 // Process and Thread state information
DNBProcessGetState(nub_process_t pid)855 nub_state_t DNBProcessGetState(nub_process_t pid) {
856 MachProcessSP procSP;
857 if (GetProcessSP(pid, procSP)) {
858 return procSP->GetState();
859 }
860 return eStateInvalid;
861 }
862
863 // Process and Thread state information
DNBProcessGetExitStatus(nub_process_t pid,int * status)864 nub_bool_t DNBProcessGetExitStatus(nub_process_t pid, int *status) {
865 MachProcessSP procSP;
866 if (GetProcessSP(pid, procSP)) {
867 return procSP->GetExitStatus(status);
868 }
869 return false;
870 }
871
DNBProcessSetExitStatus(nub_process_t pid,int status)872 nub_bool_t DNBProcessSetExitStatus(nub_process_t pid, int status) {
873 MachProcessSP procSP;
874 if (GetProcessSP(pid, procSP)) {
875 procSP->SetExitStatus(status);
876 return true;
877 }
878 return false;
879 }
880
DNBProcessGetExitInfo(nub_process_t pid)881 const char *DNBProcessGetExitInfo(nub_process_t pid) {
882 MachProcessSP procSP;
883 if (GetProcessSP(pid, procSP)) {
884 return procSP->GetExitInfo();
885 }
886 return NULL;
887 }
888
DNBProcessSetExitInfo(nub_process_t pid,const char * info)889 nub_bool_t DNBProcessSetExitInfo(nub_process_t pid, const char *info) {
890 MachProcessSP procSP;
891 if (GetProcessSP(pid, procSP)) {
892 procSP->SetExitInfo(info);
893 return true;
894 }
895 return false;
896 }
897
DNBThreadGetName(nub_process_t pid,nub_thread_t tid)898 const char *DNBThreadGetName(nub_process_t pid, nub_thread_t tid) {
899 MachProcessSP procSP;
900 if (GetProcessSP(pid, procSP))
901 return procSP->ThreadGetName(tid);
902 return NULL;
903 }
904
905 nub_bool_t
DNBThreadGetIdentifierInfo(nub_process_t pid,nub_thread_t tid,thread_identifier_info_data_t * ident_info)906 DNBThreadGetIdentifierInfo(nub_process_t pid, nub_thread_t tid,
907 thread_identifier_info_data_t *ident_info) {
908 MachProcessSP procSP;
909 if (GetProcessSP(pid, procSP))
910 return procSP->GetThreadList().GetIdentifierInfo(tid, ident_info);
911 return false;
912 }
913
DNBThreadGetState(nub_process_t pid,nub_thread_t tid)914 nub_state_t DNBThreadGetState(nub_process_t pid, nub_thread_t tid) {
915 MachProcessSP procSP;
916 if (GetProcessSP(pid, procSP)) {
917 return procSP->ThreadGetState(tid);
918 }
919 return eStateInvalid;
920 }
921
DNBStateAsString(nub_state_t state)922 const char *DNBStateAsString(nub_state_t state) {
923 switch (state) {
924 case eStateInvalid:
925 return "Invalid";
926 case eStateUnloaded:
927 return "Unloaded";
928 case eStateAttaching:
929 return "Attaching";
930 case eStateLaunching:
931 return "Launching";
932 case eStateStopped:
933 return "Stopped";
934 case eStateRunning:
935 return "Running";
936 case eStateStepping:
937 return "Stepping";
938 case eStateCrashed:
939 return "Crashed";
940 case eStateDetached:
941 return "Detached";
942 case eStateExited:
943 return "Exited";
944 case eStateSuspended:
945 return "Suspended";
946 }
947 return "nub_state_t ???";
948 }
949
DNBGetGenealogyInfoForThread(nub_process_t pid,nub_thread_t tid,bool & timed_out)950 Genealogy::ThreadActivitySP DNBGetGenealogyInfoForThread(nub_process_t pid,
951 nub_thread_t tid,
952 bool &timed_out) {
953 Genealogy::ThreadActivitySP thread_activity_sp;
954 MachProcessSP procSP;
955 if (GetProcessSP(pid, procSP))
956 thread_activity_sp = procSP->GetGenealogyInfoForThread(tid, timed_out);
957 return thread_activity_sp;
958 }
959
DNBGetGenealogyImageInfo(nub_process_t pid,size_t idx)960 Genealogy::ProcessExecutableInfoSP DNBGetGenealogyImageInfo(nub_process_t pid,
961 size_t idx) {
962 Genealogy::ProcessExecutableInfoSP image_info_sp;
963 MachProcessSP procSP;
964 if (GetProcessSP(pid, procSP)) {
965 image_info_sp = procSP->GetGenealogyImageInfo(idx);
966 }
967 return image_info_sp;
968 }
969
DNBGetRequestedQoSForThread(nub_process_t pid,nub_thread_t tid,nub_addr_t tsd,uint64_t dti_qos_class_index)970 ThreadInfo::QoS DNBGetRequestedQoSForThread(nub_process_t pid, nub_thread_t tid,
971 nub_addr_t tsd,
972 uint64_t dti_qos_class_index) {
973 MachProcessSP procSP;
974 if (GetProcessSP(pid, procSP)) {
975 return procSP->GetRequestedQoS(tid, tsd, dti_qos_class_index);
976 }
977 return ThreadInfo::QoS();
978 }
979
DNBGetPThreadT(nub_process_t pid,nub_thread_t tid)980 nub_addr_t DNBGetPThreadT(nub_process_t pid, nub_thread_t tid) {
981 MachProcessSP procSP;
982 if (GetProcessSP(pid, procSP)) {
983 return procSP->GetPThreadT(tid);
984 }
985 return INVALID_NUB_ADDRESS;
986 }
987
DNBGetDispatchQueueT(nub_process_t pid,nub_thread_t tid)988 nub_addr_t DNBGetDispatchQueueT(nub_process_t pid, nub_thread_t tid) {
989 MachProcessSP procSP;
990 if (GetProcessSP(pid, procSP)) {
991 return procSP->GetDispatchQueueT(tid);
992 }
993 return INVALID_NUB_ADDRESS;
994 }
995
996 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)997 DNBGetTSDAddressForThread(nub_process_t pid, nub_thread_t tid,
998 uint64_t plo_pthread_tsd_base_address_offset,
999 uint64_t plo_pthread_tsd_base_offset,
1000 uint64_t plo_pthread_tsd_entry_size) {
1001 MachProcessSP procSP;
1002 if (GetProcessSP(pid, procSP)) {
1003 return procSP->GetTSDAddressForThread(
1004 tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset,
1005 plo_pthread_tsd_entry_size);
1006 }
1007 return INVALID_NUB_ADDRESS;
1008 }
1009
DNBGetLoadedDynamicLibrariesInfos(nub_process_t pid,nub_addr_t image_list_address,nub_addr_t image_count)1010 JSONGenerator::ObjectSP DNBGetLoadedDynamicLibrariesInfos(
1011 nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count) {
1012 MachProcessSP procSP;
1013 if (GetProcessSP(pid, procSP)) {
1014 return procSP->GetLoadedDynamicLibrariesInfos(pid, image_list_address,
1015 image_count);
1016 }
1017 return JSONGenerator::ObjectSP();
1018 }
1019
DNBGetAllLoadedLibrariesInfos(nub_process_t pid)1020 JSONGenerator::ObjectSP DNBGetAllLoadedLibrariesInfos(nub_process_t pid) {
1021 MachProcessSP procSP;
1022 if (GetProcessSP(pid, procSP)) {
1023 return procSP->GetAllLoadedLibrariesInfos(pid);
1024 }
1025 return JSONGenerator::ObjectSP();
1026 }
1027
1028 JSONGenerator::ObjectSP
DNBGetLibrariesInfoForAddresses(nub_process_t pid,std::vector<uint64_t> & macho_addresses)1029 DNBGetLibrariesInfoForAddresses(nub_process_t pid,
1030 std::vector<uint64_t> &macho_addresses) {
1031 MachProcessSP procSP;
1032 if (GetProcessSP(pid, procSP)) {
1033 return procSP->GetLibrariesInfoForAddresses(pid, macho_addresses);
1034 }
1035 return JSONGenerator::ObjectSP();
1036 }
1037
DNBGetSharedCacheInfo(nub_process_t pid)1038 JSONGenerator::ObjectSP DNBGetSharedCacheInfo(nub_process_t pid) {
1039 MachProcessSP procSP;
1040 if (GetProcessSP(pid, procSP)) {
1041 return procSP->GetSharedCacheInfo(pid);
1042 }
1043 return JSONGenerator::ObjectSP();
1044 }
1045
DNBProcessGetExecutablePath(nub_process_t pid)1046 const char *DNBProcessGetExecutablePath(nub_process_t pid) {
1047 MachProcessSP procSP;
1048 if (GetProcessSP(pid, procSP)) {
1049 return procSP->Path();
1050 }
1051 return NULL;
1052 }
1053
DNBProcessGetArgumentCount(nub_process_t pid)1054 nub_size_t DNBProcessGetArgumentCount(nub_process_t pid) {
1055 MachProcessSP procSP;
1056 if (GetProcessSP(pid, procSP)) {
1057 return procSP->ArgumentCount();
1058 }
1059 return 0;
1060 }
1061
DNBProcessGetArgumentAtIndex(nub_process_t pid,nub_size_t idx)1062 const char *DNBProcessGetArgumentAtIndex(nub_process_t pid, nub_size_t idx) {
1063 MachProcessSP procSP;
1064 if (GetProcessSP(pid, procSP)) {
1065 return procSP->ArgumentAtIndex(idx);
1066 }
1067 return NULL;
1068 }
1069
1070 // Execution control
DNBProcessResume(nub_process_t pid,const DNBThreadResumeAction * actions,size_t num_actions)1071 nub_bool_t DNBProcessResume(nub_process_t pid,
1072 const DNBThreadResumeAction *actions,
1073 size_t num_actions) {
1074 DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
1075 MachProcessSP procSP;
1076 if (GetProcessSP(pid, procSP)) {
1077 DNBThreadResumeActions thread_actions(actions, num_actions);
1078
1079 // Below we add a default thread plan just in case one wasn't
1080 // provided so all threads always know what they were supposed to do
1081 if (thread_actions.IsEmpty()) {
1082 // No thread plans were given, so the default it to run all threads
1083 thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, 0);
1084 } else {
1085 // Some thread plans were given which means anything that wasn't
1086 // specified should remain stopped.
1087 thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);
1088 }
1089 return procSP->Resume(thread_actions);
1090 }
1091 return false;
1092 }
1093
DNBProcessHalt(nub_process_t pid)1094 nub_bool_t DNBProcessHalt(nub_process_t pid) {
1095 DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
1096 MachProcessSP procSP;
1097 if (GetProcessSP(pid, procSP))
1098 return procSP->Signal(SIGSTOP);
1099 return false;
1100 }
1101 //
1102 // nub_bool_t
1103 // DNBThreadResume (nub_process_t pid, nub_thread_t tid, nub_bool_t step)
1104 //{
1105 // DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u)",
1106 // __FUNCTION__, pid, tid, (uint32_t)step);
1107 // MachProcessSP procSP;
1108 // if (GetProcessSP (pid, procSP))
1109 // {
1110 // return procSP->Resume(tid, step, 0);
1111 // }
1112 // return false;
1113 //}
1114 //
1115 // nub_bool_t
1116 // DNBThreadResumeWithSignal (nub_process_t pid, nub_thread_t tid, nub_bool_t
1117 // step, int signal)
1118 //{
1119 // DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u,
1120 // signal = %i)", __FUNCTION__, pid, tid, (uint32_t)step, signal);
1121 // MachProcessSP procSP;
1122 // if (GetProcessSP (pid, procSP))
1123 // {
1124 // return procSP->Resume(tid, step, signal);
1125 // }
1126 // return false;
1127 //}
1128
DNBProcessWaitForEvents(nub_process_t pid,nub_event_t event_mask,bool wait_for_set,struct timespec * timeout)1129 nub_event_t DNBProcessWaitForEvents(nub_process_t pid, nub_event_t event_mask,
1130 bool wait_for_set,
1131 struct timespec *timeout) {
1132 nub_event_t result = 0;
1133 MachProcessSP procSP;
1134 if (GetProcessSP(pid, procSP)) {
1135 if (wait_for_set)
1136 result = procSP->Events().WaitForSetEvents(event_mask, timeout);
1137 else
1138 result = procSP->Events().WaitForEventsToReset(event_mask, timeout);
1139 }
1140 return result;
1141 }
1142
DNBProcessResetEvents(nub_process_t pid,nub_event_t event_mask)1143 void DNBProcessResetEvents(nub_process_t pid, nub_event_t event_mask) {
1144 MachProcessSP procSP;
1145 if (GetProcessSP(pid, procSP))
1146 procSP->Events().ResetEvents(event_mask);
1147 }
1148
1149 // Breakpoints
DNBBreakpointSet(nub_process_t pid,nub_addr_t addr,nub_size_t size,nub_bool_t hardware)1150 nub_bool_t DNBBreakpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size,
1151 nub_bool_t hardware) {
1152 MachProcessSP procSP;
1153 if (GetProcessSP(pid, procSP))
1154 return procSP->CreateBreakpoint(addr, size, hardware) != NULL;
1155 return false;
1156 }
1157
DNBBreakpointClear(nub_process_t pid,nub_addr_t addr)1158 nub_bool_t DNBBreakpointClear(nub_process_t pid, nub_addr_t addr) {
1159 MachProcessSP procSP;
1160 if (GetProcessSP(pid, procSP))
1161 return procSP->DisableBreakpoint(addr, true);
1162 return false; // Failed
1163 }
1164
1165 // Watchpoints
DNBWatchpointSet(nub_process_t pid,nub_addr_t addr,nub_size_t size,uint32_t watch_flags,nub_bool_t hardware)1166 nub_bool_t DNBWatchpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size,
1167 uint32_t watch_flags, nub_bool_t hardware) {
1168 MachProcessSP procSP;
1169 if (GetProcessSP(pid, procSP))
1170 return procSP->CreateWatchpoint(addr, size, watch_flags, hardware) != NULL;
1171 return false;
1172 }
1173
DNBWatchpointClear(nub_process_t pid,nub_addr_t addr)1174 nub_bool_t DNBWatchpointClear(nub_process_t pid, nub_addr_t addr) {
1175 MachProcessSP procSP;
1176 if (GetProcessSP(pid, procSP))
1177 return procSP->DisableWatchpoint(addr, true);
1178 return false; // Failed
1179 }
1180
1181 // Return the number of supported hardware watchpoints.
DNBWatchpointGetNumSupportedHWP(nub_process_t pid)1182 uint32_t DNBWatchpointGetNumSupportedHWP(nub_process_t pid) {
1183 MachProcessSP procSP;
1184 if (GetProcessSP(pid, procSP))
1185 return procSP->GetNumSupportedHardwareWatchpoints();
1186 return 0;
1187 }
1188
1189 // Read memory in the address space of process PID. This call will take
1190 // care of setting and restoring permissions and breaking up the memory
1191 // read into multiple chunks as required.
1192 //
1193 // RETURNS: number of bytes actually read
DNBProcessMemoryRead(nub_process_t pid,nub_addr_t addr,nub_size_t size,void * buf)1194 nub_size_t DNBProcessMemoryRead(nub_process_t pid, nub_addr_t addr,
1195 nub_size_t size, void *buf) {
1196 MachProcessSP procSP;
1197 if (GetProcessSP(pid, procSP))
1198 return procSP->ReadMemory(addr, size, buf);
1199 return 0;
1200 }
1201
DNBProcessMemoryReadInteger(nub_process_t pid,nub_addr_t addr,nub_size_t integer_size,uint64_t fail_value)1202 uint64_t DNBProcessMemoryReadInteger(nub_process_t pid, nub_addr_t addr,
1203 nub_size_t integer_size,
1204 uint64_t fail_value) {
1205 union Integers {
1206 uint8_t u8;
1207 uint16_t u16;
1208 uint32_t u32;
1209 uint64_t u64;
1210 };
1211
1212 if (integer_size <= sizeof(uint64_t)) {
1213 Integers ints;
1214 if (DNBProcessMemoryRead(pid, addr, integer_size, &ints) == integer_size) {
1215 switch (integer_size) {
1216 case 1:
1217 return ints.u8;
1218 case 2:
1219 return ints.u16;
1220 case 3:
1221 return ints.u32 & 0xffffffu;
1222 case 4:
1223 return ints.u32;
1224 case 5:
1225 return ints.u32 & 0x000000ffffffffffull;
1226 case 6:
1227 return ints.u32 & 0x0000ffffffffffffull;
1228 case 7:
1229 return ints.u32 & 0x00ffffffffffffffull;
1230 case 8:
1231 return ints.u64;
1232 }
1233 }
1234 }
1235 return fail_value;
1236 }
1237
DNBProcessMemoryReadPointer(nub_process_t pid,nub_addr_t addr)1238 nub_addr_t DNBProcessMemoryReadPointer(nub_process_t pid, nub_addr_t addr) {
1239 cpu_type_t cputype = DNBProcessGetCPUType(pid);
1240 if (cputype) {
1241 const nub_size_t pointer_size = (cputype & CPU_ARCH_ABI64) ? 8 : 4;
1242 return DNBProcessMemoryReadInteger(pid, addr, pointer_size, 0);
1243 }
1244 return 0;
1245 }
1246
DNBProcessMemoryReadCString(nub_process_t pid,nub_addr_t addr)1247 std::string DNBProcessMemoryReadCString(nub_process_t pid, nub_addr_t addr) {
1248 std::string cstr;
1249 char buffer[256];
1250 const nub_size_t max_buffer_cstr_length = sizeof(buffer) - 1;
1251 buffer[max_buffer_cstr_length] = '\0';
1252 nub_size_t length = 0;
1253 nub_addr_t curr_addr = addr;
1254 do {
1255 nub_size_t bytes_read =
1256 DNBProcessMemoryRead(pid, curr_addr, max_buffer_cstr_length, buffer);
1257 if (bytes_read == 0)
1258 break;
1259 length = strlen(buffer);
1260 cstr.append(buffer, length);
1261 curr_addr += length;
1262 } while (length == max_buffer_cstr_length);
1263 return cstr;
1264 }
1265
DNBProcessMemoryReadCStringFixed(nub_process_t pid,nub_addr_t addr,nub_size_t fixed_length)1266 std::string DNBProcessMemoryReadCStringFixed(nub_process_t pid, nub_addr_t addr,
1267 nub_size_t fixed_length) {
1268 std::string cstr;
1269 char buffer[fixed_length + 1];
1270 buffer[fixed_length] = '\0';
1271 nub_size_t bytes_read = DNBProcessMemoryRead(pid, addr, fixed_length, buffer);
1272 if (bytes_read > 0)
1273 cstr.assign(buffer);
1274 return cstr;
1275 }
1276
1277 // Write memory to the address space of process PID. This call will take
1278 // care of setting and restoring permissions and breaking up the memory
1279 // write into multiple chunks as required.
1280 //
1281 // RETURNS: number of bytes actually written
DNBProcessMemoryWrite(nub_process_t pid,nub_addr_t addr,nub_size_t size,const void * buf)1282 nub_size_t DNBProcessMemoryWrite(nub_process_t pid, nub_addr_t addr,
1283 nub_size_t size, const void *buf) {
1284 MachProcessSP procSP;
1285 if (GetProcessSP(pid, procSP))
1286 return procSP->WriteMemory(addr, size, buf);
1287 return 0;
1288 }
1289
DNBProcessMemoryAllocate(nub_process_t pid,nub_size_t size,uint32_t permissions)1290 nub_addr_t DNBProcessMemoryAllocate(nub_process_t pid, nub_size_t size,
1291 uint32_t permissions) {
1292 MachProcessSP procSP;
1293 if (GetProcessSP(pid, procSP))
1294 return procSP->Task().AllocateMemory(size, permissions);
1295 return 0;
1296 }
1297
DNBProcessMemoryDeallocate(nub_process_t pid,nub_addr_t addr)1298 nub_bool_t DNBProcessMemoryDeallocate(nub_process_t pid, nub_addr_t addr) {
1299 MachProcessSP procSP;
1300 if (GetProcessSP(pid, procSP))
1301 return procSP->Task().DeallocateMemory(addr);
1302 return 0;
1303 }
1304
1305 // Find attributes of the memory region that contains ADDR for process PID,
1306 // if possible, and return a string describing those attributes.
1307 //
1308 // Returns 1 if we could find attributes for this region and OUTBUF can
1309 // be sent to the remote debugger.
1310 //
1311 // Returns 0 if we couldn't find the attributes for a region of memory at
1312 // that address and OUTBUF should not be sent.
1313 //
1314 // Returns -1 if this platform cannot look up information about memory regions
1315 // or if we do not yet have a valid launched process.
1316 //
DNBProcessMemoryRegionInfo(nub_process_t pid,nub_addr_t addr,DNBRegionInfo * region_info)1317 int DNBProcessMemoryRegionInfo(nub_process_t pid, nub_addr_t addr,
1318 DNBRegionInfo *region_info) {
1319 MachProcessSP procSP;
1320 if (GetProcessSP(pid, procSP))
1321 return procSP->Task().GetMemoryRegionInfo(addr, region_info);
1322
1323 return -1;
1324 }
1325
DNBProcessGetProfileData(nub_process_t pid,DNBProfileDataScanType scanType)1326 std::string DNBProcessGetProfileData(nub_process_t pid,
1327 DNBProfileDataScanType scanType) {
1328 MachProcessSP procSP;
1329 if (GetProcessSP(pid, procSP))
1330 return procSP->Task().GetProfileData(scanType);
1331
1332 return std::string("");
1333 }
1334
DNBProcessSetEnableAsyncProfiling(nub_process_t pid,nub_bool_t enable,uint64_t interval_usec,DNBProfileDataScanType scan_type)1335 nub_bool_t DNBProcessSetEnableAsyncProfiling(nub_process_t pid,
1336 nub_bool_t enable,
1337 uint64_t interval_usec,
1338 DNBProfileDataScanType scan_type) {
1339 MachProcessSP procSP;
1340 if (GetProcessSP(pid, procSP)) {
1341 procSP->SetEnableAsyncProfiling(enable, interval_usec, scan_type);
1342 return true;
1343 }
1344
1345 return false;
1346 }
1347
1348 // Get the number of threads for the specified process.
DNBProcessGetNumThreads(nub_process_t pid)1349 nub_size_t DNBProcessGetNumThreads(nub_process_t pid) {
1350 MachProcessSP procSP;
1351 if (GetProcessSP(pid, procSP))
1352 return procSP->GetNumThreads();
1353 return 0;
1354 }
1355
1356 // Get the thread ID of the current thread.
DNBProcessGetCurrentThread(nub_process_t pid)1357 nub_thread_t DNBProcessGetCurrentThread(nub_process_t pid) {
1358 MachProcessSP procSP;
1359 if (GetProcessSP(pid, procSP))
1360 return procSP->GetCurrentThread();
1361 return 0;
1362 }
1363
1364 // Get the mach port number of the current thread.
DNBProcessGetCurrentThreadMachPort(nub_process_t pid)1365 nub_thread_t DNBProcessGetCurrentThreadMachPort(nub_process_t pid) {
1366 MachProcessSP procSP;
1367 if (GetProcessSP(pid, procSP))
1368 return procSP->GetCurrentThreadMachPort();
1369 return 0;
1370 }
1371
1372 // Change the current thread.
DNBProcessSetCurrentThread(nub_process_t pid,nub_thread_t tid)1373 nub_thread_t DNBProcessSetCurrentThread(nub_process_t pid, nub_thread_t tid) {
1374 MachProcessSP procSP;
1375 if (GetProcessSP(pid, procSP))
1376 return procSP->SetCurrentThread(tid);
1377 return INVALID_NUB_THREAD;
1378 }
1379
1380 // Dump a string describing a thread's stop reason to the specified file
1381 // handle
DNBThreadGetStopReason(nub_process_t pid,nub_thread_t tid,struct DNBThreadStopInfo * stop_info)1382 nub_bool_t DNBThreadGetStopReason(nub_process_t pid, nub_thread_t tid,
1383 struct DNBThreadStopInfo *stop_info) {
1384 MachProcessSP procSP;
1385 if (GetProcessSP(pid, procSP))
1386 return procSP->GetThreadStoppedReason(tid, stop_info);
1387 return false;
1388 }
1389
1390 // Return string description for the specified thread.
1391 //
1392 // RETURNS: NULL if the thread isn't valid, else a NULL terminated C
1393 // string from a static buffer that must be copied prior to subsequent
1394 // calls.
DNBThreadGetInfo(nub_process_t pid,nub_thread_t tid)1395 const char *DNBThreadGetInfo(nub_process_t pid, nub_thread_t tid) {
1396 MachProcessSP procSP;
1397 if (GetProcessSP(pid, procSP))
1398 return procSP->GetThreadInfo(tid);
1399 return NULL;
1400 }
1401
1402 // Get the thread ID given a thread index.
DNBProcessGetThreadAtIndex(nub_process_t pid,size_t thread_idx)1403 nub_thread_t DNBProcessGetThreadAtIndex(nub_process_t pid, size_t thread_idx) {
1404 MachProcessSP procSP;
1405 if (GetProcessSP(pid, procSP))
1406 return procSP->GetThreadAtIndex(thread_idx);
1407 return INVALID_NUB_THREAD;
1408 }
1409
1410 // Do whatever is needed to sync the thread's register state with it's kernel
1411 // values.
DNBProcessSyncThreadState(nub_process_t pid,nub_thread_t tid)1412 nub_bool_t DNBProcessSyncThreadState(nub_process_t pid, nub_thread_t tid) {
1413 MachProcessSP procSP;
1414 if (GetProcessSP(pid, procSP))
1415 return procSP->SyncThreadState(tid);
1416 return false;
1417 }
1418
DNBProcessGetSharedLibraryInfoAddress(nub_process_t pid)1419 nub_addr_t DNBProcessGetSharedLibraryInfoAddress(nub_process_t pid) {
1420 MachProcessSP procSP;
1421 DNBError err;
1422 if (GetProcessSP(pid, procSP))
1423 return procSP->Task().GetDYLDAllImageInfosAddress(err);
1424 return INVALID_NUB_ADDRESS;
1425 }
1426
DNBProcessSharedLibrariesUpdated(nub_process_t pid)1427 nub_bool_t DNBProcessSharedLibrariesUpdated(nub_process_t pid) {
1428 MachProcessSP procSP;
1429 if (GetProcessSP(pid, procSP)) {
1430 procSP->SharedLibrariesUpdated();
1431 return true;
1432 }
1433 return false;
1434 }
1435
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)1436 const char *DNBGetDeploymentInfo(nub_process_t pid, bool is_executable,
1437 const struct load_command &lc,
1438 uint64_t load_command_address,
1439 uint32_t &major_version,
1440 uint32_t &minor_version,
1441 uint32_t &patch_version) {
1442 MachProcessSP procSP;
1443 if (GetProcessSP(pid, procSP)) {
1444 // FIXME: This doesn't return the correct result when xctest (a
1445 // macOS binary) is loaded with the macCatalyst dyld platform
1446 // override. The image info corrects for this, but qProcessInfo
1447 // will return what is in the binary.
1448 auto info =
1449 procSP->GetDeploymentInfo(lc, load_command_address, is_executable);
1450 major_version = info.major_version;
1451 minor_version = info.minor_version;
1452 patch_version = info.patch_version;
1453 return procSP->GetPlatformString(info.platform);
1454 }
1455 return nullptr;
1456 }
1457
1458 // Get the current shared library information for a process. Only return
1459 // the shared libraries that have changed since the last shared library
1460 // state changed event if only_changed is non-zero.
1461 nub_size_t
DNBProcessGetSharedLibraryInfo(nub_process_t pid,nub_bool_t only_changed,struct DNBExecutableImageInfo ** image_infos)1462 DNBProcessGetSharedLibraryInfo(nub_process_t pid, nub_bool_t only_changed,
1463 struct DNBExecutableImageInfo **image_infos) {
1464 MachProcessSP procSP;
1465 if (GetProcessSP(pid, procSP))
1466 return procSP->CopyImageInfos(image_infos, only_changed);
1467
1468 // If we have no process, then return NULL for the shared library info
1469 // and zero for shared library count
1470 *image_infos = NULL;
1471 return 0;
1472 }
1473
DNBGetRegisterCPUType()1474 uint32_t DNBGetRegisterCPUType() {
1475 return DNBArchProtocol::GetRegisterCPUType();
1476 }
1477 // Get the register set information for a specific thread.
DNBGetRegisterSetInfo(nub_size_t * num_reg_sets)1478 const DNBRegisterSetInfo *DNBGetRegisterSetInfo(nub_size_t *num_reg_sets) {
1479 return DNBArchProtocol::GetRegisterSetInfo(num_reg_sets);
1480 }
1481
1482 // 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)1483 nub_bool_t DNBThreadGetRegisterValueByID(nub_process_t pid, nub_thread_t tid,
1484 uint32_t set, uint32_t reg,
1485 DNBRegisterValue *value) {
1486 MachProcessSP procSP;
1487 ::bzero(value, sizeof(DNBRegisterValue));
1488 if (GetProcessSP(pid, procSP)) {
1489 if (tid != INVALID_NUB_THREAD)
1490 return procSP->GetRegisterValue(tid, set, reg, value);
1491 }
1492 return false;
1493 }
1494
DNBThreadSetRegisterValueByID(nub_process_t pid,nub_thread_t tid,uint32_t set,uint32_t reg,const DNBRegisterValue * value)1495 nub_bool_t DNBThreadSetRegisterValueByID(nub_process_t pid, nub_thread_t tid,
1496 uint32_t set, uint32_t reg,
1497 const DNBRegisterValue *value) {
1498 if (tid != INVALID_NUB_THREAD) {
1499 MachProcessSP procSP;
1500 if (GetProcessSP(pid, procSP))
1501 return procSP->SetRegisterValue(tid, set, reg, value);
1502 }
1503 return false;
1504 }
1505
DNBThreadGetRegisterContext(nub_process_t pid,nub_thread_t tid,void * buf,size_t buf_len)1506 nub_size_t DNBThreadGetRegisterContext(nub_process_t pid, nub_thread_t tid,
1507 void *buf, size_t buf_len) {
1508 MachProcessSP procSP;
1509 if (GetProcessSP(pid, procSP)) {
1510 if (tid != INVALID_NUB_THREAD)
1511 return procSP->GetThreadList().GetRegisterContext(tid, buf, buf_len);
1512 }
1513 ::bzero(buf, buf_len);
1514 return 0;
1515 }
1516
DNBThreadSetRegisterContext(nub_process_t pid,nub_thread_t tid,const void * buf,size_t buf_len)1517 nub_size_t DNBThreadSetRegisterContext(nub_process_t pid, nub_thread_t tid,
1518 const void *buf, size_t buf_len) {
1519 MachProcessSP procSP;
1520 if (GetProcessSP(pid, procSP)) {
1521 if (tid != INVALID_NUB_THREAD)
1522 return procSP->GetThreadList().SetRegisterContext(tid, buf, buf_len);
1523 }
1524 return 0;
1525 }
1526
DNBThreadSaveRegisterState(nub_process_t pid,nub_thread_t tid)1527 uint32_t DNBThreadSaveRegisterState(nub_process_t pid, nub_thread_t tid) {
1528 if (tid != INVALID_NUB_THREAD) {
1529 MachProcessSP procSP;
1530 if (GetProcessSP(pid, procSP))
1531 return procSP->GetThreadList().SaveRegisterState(tid);
1532 }
1533 return 0;
1534 }
DNBThreadRestoreRegisterState(nub_process_t pid,nub_thread_t tid,uint32_t save_id)1535 nub_bool_t DNBThreadRestoreRegisterState(nub_process_t pid, nub_thread_t tid,
1536 uint32_t save_id) {
1537 if (tid != INVALID_NUB_THREAD) {
1538 MachProcessSP procSP;
1539 if (GetProcessSP(pid, procSP))
1540 return procSP->GetThreadList().RestoreRegisterState(tid, save_id);
1541 }
1542 return false;
1543 }
1544
1545 // 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)1546 nub_bool_t DNBThreadGetRegisterValueByName(nub_process_t pid, nub_thread_t tid,
1547 uint32_t reg_set,
1548 const char *reg_name,
1549 DNBRegisterValue *value) {
1550 MachProcessSP procSP;
1551 ::bzero(value, sizeof(DNBRegisterValue));
1552 if (GetProcessSP(pid, procSP)) {
1553 const struct DNBRegisterSetInfo *set_info;
1554 nub_size_t num_reg_sets = 0;
1555 set_info = DNBGetRegisterSetInfo(&num_reg_sets);
1556 if (set_info) {
1557 uint32_t set = reg_set;
1558 uint32_t reg;
1559 if (set == REGISTER_SET_ALL) {
1560 for (set = 1; set < num_reg_sets; ++set) {
1561 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1562 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
1563 return procSP->GetRegisterValue(tid, set, reg, value);
1564 }
1565 }
1566 } else {
1567 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1568 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
1569 return procSP->GetRegisterValue(tid, set, reg, value);
1570 }
1571 }
1572 }
1573 }
1574 return false;
1575 }
1576
1577 // Read a register set and register number from the register name.
DNBGetRegisterInfoByName(const char * reg_name,DNBRegisterInfo * info)1578 nub_bool_t DNBGetRegisterInfoByName(const char *reg_name,
1579 DNBRegisterInfo *info) {
1580 const struct DNBRegisterSetInfo *set_info;
1581 nub_size_t num_reg_sets = 0;
1582 set_info = DNBGetRegisterSetInfo(&num_reg_sets);
1583 if (set_info) {
1584 uint32_t set, reg;
1585 for (set = 1; set < num_reg_sets; ++set) {
1586 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1587 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) {
1588 *info = set_info[set].registers[reg];
1589 return true;
1590 }
1591 }
1592 }
1593
1594 for (set = 1; set < num_reg_sets; ++set) {
1595 uint32_t reg;
1596 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1597 if (set_info[set].registers[reg].alt == NULL)
1598 continue;
1599
1600 if (strcasecmp(reg_name, set_info[set].registers[reg].alt) == 0) {
1601 *info = set_info[set].registers[reg];
1602 return true;
1603 }
1604 }
1605 }
1606 }
1607
1608 ::bzero(info, sizeof(DNBRegisterInfo));
1609 return false;
1610 }
1611
1612 // Set the name to address callback function that this nub can use
1613 // for any name to address lookups that are needed.
DNBProcessSetNameToAddressCallback(nub_process_t pid,DNBCallbackNameToAddress callback,void * baton)1614 nub_bool_t DNBProcessSetNameToAddressCallback(nub_process_t pid,
1615 DNBCallbackNameToAddress callback,
1616 void *baton) {
1617 MachProcessSP procSP;
1618 if (GetProcessSP(pid, procSP)) {
1619 procSP->SetNameToAddressCallback(callback, baton);
1620 return true;
1621 }
1622 return false;
1623 }
1624
1625 // Set the name to address callback function that this nub can use
1626 // for any name to address lookups that are needed.
DNBProcessSetSharedLibraryInfoCallback(nub_process_t pid,DNBCallbackCopyExecutableImageInfos callback,void * baton)1627 nub_bool_t DNBProcessSetSharedLibraryInfoCallback(
1628 nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback,
1629 void *baton) {
1630 MachProcessSP procSP;
1631 if (GetProcessSP(pid, procSP)) {
1632 procSP->SetSharedLibraryInfoCallback(callback, baton);
1633 return true;
1634 }
1635 return false;
1636 }
1637
DNBProcessLookupAddress(nub_process_t pid,const char * name,const char * shlib)1638 nub_addr_t DNBProcessLookupAddress(nub_process_t pid, const char *name,
1639 const char *shlib) {
1640 MachProcessSP procSP;
1641 if (GetProcessSP(pid, procSP)) {
1642 return procSP->LookupSymbol(name, shlib);
1643 }
1644 return INVALID_NUB_ADDRESS;
1645 }
1646
DNBProcessGetAvailableSTDOUT(nub_process_t pid,char * buf,nub_size_t buf_size)1647 nub_size_t DNBProcessGetAvailableSTDOUT(nub_process_t pid, char *buf,
1648 nub_size_t buf_size) {
1649 MachProcessSP procSP;
1650 if (GetProcessSP(pid, procSP))
1651 return procSP->GetAvailableSTDOUT(buf, buf_size);
1652 return 0;
1653 }
1654
DNBProcessGetAvailableSTDERR(nub_process_t pid,char * buf,nub_size_t buf_size)1655 nub_size_t DNBProcessGetAvailableSTDERR(nub_process_t pid, char *buf,
1656 nub_size_t buf_size) {
1657 MachProcessSP procSP;
1658 if (GetProcessSP(pid, procSP))
1659 return procSP->GetAvailableSTDERR(buf, buf_size);
1660 return 0;
1661 }
1662
DNBProcessGetAvailableProfileData(nub_process_t pid,char * buf,nub_size_t buf_size)1663 nub_size_t DNBProcessGetAvailableProfileData(nub_process_t pid, char *buf,
1664 nub_size_t buf_size) {
1665 MachProcessSP procSP;
1666 if (GetProcessSP(pid, procSP))
1667 return procSP->GetAsyncProfileData(buf, buf_size);
1668 return 0;
1669 }
1670
DNBProcessGetStopCount(nub_process_t pid)1671 nub_size_t DNBProcessGetStopCount(nub_process_t pid) {
1672 MachProcessSP procSP;
1673 if (GetProcessSP(pid, procSP))
1674 return procSP->StopCount();
1675 return 0;
1676 }
1677
DNBProcessGetCPUType(nub_process_t pid)1678 uint32_t DNBProcessGetCPUType(nub_process_t pid) {
1679 MachProcessSP procSP;
1680 if (GetProcessSP(pid, procSP))
1681 return procSP->GetCPUType();
1682 return 0;
1683 }
1684
DNBResolveExecutablePath(const char * path,char * resolved_path,size_t resolved_path_size)1685 nub_bool_t DNBResolveExecutablePath(const char *path, char *resolved_path,
1686 size_t resolved_path_size) {
1687 if (path == NULL || path[0] == '\0')
1688 return false;
1689
1690 char max_path[PATH_MAX];
1691 std::string result;
1692 CFString::GlobPath(path, result);
1693
1694 if (result.empty())
1695 result = path;
1696
1697 struct stat path_stat;
1698 if (::stat(path, &path_stat) == 0) {
1699 if ((path_stat.st_mode & S_IFMT) == S_IFDIR) {
1700 CFBundle bundle(path);
1701 CFReleaser<CFURLRef> url(bundle.CopyExecutableURL());
1702 if (url.get()) {
1703 if (::CFURLGetFileSystemRepresentation(
1704 url.get(), true, (UInt8 *)resolved_path, resolved_path_size))
1705 return true;
1706 }
1707 }
1708 }
1709
1710 if (realpath(path, max_path)) {
1711 // Found the path relatively...
1712 ::strlcpy(resolved_path, max_path, resolved_path_size);
1713 return strlen(resolved_path) + 1 < resolved_path_size;
1714 } else {
1715 // Not a relative path, check the PATH environment variable if the
1716 const char *PATH = getenv("PATH");
1717 if (PATH) {
1718 const char *curr_path_start = PATH;
1719 const char *curr_path_end;
1720 while (curr_path_start && *curr_path_start) {
1721 curr_path_end = strchr(curr_path_start, ':');
1722 if (curr_path_end == NULL) {
1723 result.assign(curr_path_start);
1724 curr_path_start = NULL;
1725 } else if (curr_path_end > curr_path_start) {
1726 size_t len = curr_path_end - curr_path_start;
1727 result.assign(curr_path_start, len);
1728 curr_path_start += len + 1;
1729 } else
1730 break;
1731
1732 result += '/';
1733 result += path;
1734 struct stat s;
1735 if (stat(result.c_str(), &s) == 0) {
1736 ::strlcpy(resolved_path, result.c_str(), resolved_path_size);
1737 return result.size() + 1 < resolved_path_size;
1738 }
1739 }
1740 }
1741 }
1742 return false;
1743 }
1744
DNBGetOSVersionNumbers(uint64_t * major,uint64_t * minor,uint64_t * patch)1745 bool DNBGetOSVersionNumbers(uint64_t *major, uint64_t *minor, uint64_t *patch) {
1746 return MachProcess::GetOSVersionNumbers(major, minor, patch);
1747 }
1748
DNBGetMacCatalystVersionString()1749 std::string DNBGetMacCatalystVersionString() {
1750 return MachProcess::GetMacCatalystVersionString();
1751 }
1752
DNBInitialize()1753 void DNBInitialize() {
1754 DNBLogThreadedIf(LOG_PROCESS, "DNBInitialize ()");
1755 #if defined(__i386__) || defined(__x86_64__)
1756 DNBArchImplI386::Initialize();
1757 DNBArchImplX86_64::Initialize();
1758 #elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
1759 DNBArchMachARM::Initialize();
1760 DNBArchMachARM64::Initialize();
1761 #endif
1762 }
1763
DNBTerminate()1764 void DNBTerminate() {}
1765
DNBSetArchitecture(const char * arch)1766 nub_bool_t DNBSetArchitecture(const char *arch) {
1767 if (arch && arch[0]) {
1768 if (strcasecmp(arch, "i386") == 0)
1769 return DNBArchProtocol::SetArchitecture(CPU_TYPE_I386);
1770 else if (strcasecmp(arch, "x86_64") == 0)
1771 return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64,
1772 CPU_SUBTYPE_X86_64_ALL);
1773 else if (strcasecmp(arch, "x86_64h") == 0)
1774 return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64,
1775 CPU_SUBTYPE_X86_64_H);
1776 else if (strstr(arch, "arm64_32") == arch ||
1777 strstr(arch, "aarch64_32") == arch)
1778 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64_32);
1779 else if (strstr(arch, "arm64e") == arch)
1780 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64,
1781 CPU_SUBTYPE_ARM64E);
1782 else if (strstr(arch, "arm64") == arch || strstr(arch, "aarch64") == arch)
1783 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64,
1784 CPU_SUBTYPE_ARM64_ALL);
1785 else if (strstr(arch, "armv8") == arch)
1786 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64,
1787 CPU_SUBTYPE_ARM64_V8);
1788 else if (strstr(arch, "armv7em") == arch)
1789 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1790 CPU_SUBTYPE_ARM_V7EM);
1791 else if (strstr(arch, "armv7m") == arch)
1792 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1793 CPU_SUBTYPE_ARM_V7M);
1794 else if (strstr(arch, "armv7k") == arch)
1795 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1796 CPU_SUBTYPE_ARM_V7K);
1797 else if (strstr(arch, "armv7s") == arch)
1798 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1799 CPU_SUBTYPE_ARM_V7S);
1800 else if (strstr(arch, "armv7") == arch)
1801 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7);
1802 else if (strstr(arch, "armv6m") == arch)
1803 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1804 CPU_SUBTYPE_ARM_V6M);
1805 else if (strstr(arch, "armv6") == arch)
1806 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6);
1807 else if (strstr(arch, "armv5") == arch)
1808 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1809 CPU_SUBTYPE_ARM_V5TEJ);
1810 else if (strstr(arch, "armv4t") == arch)
1811 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1812 CPU_SUBTYPE_ARM_V4T);
1813 else if (strstr(arch, "arm") == arch)
1814 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM,
1815 CPU_SUBTYPE_ARM_ALL);
1816 }
1817 return false;
1818 }
1819
DNBDebugserverIsTranslated()1820 bool DNBDebugserverIsTranslated() {
1821 int ret = 0;
1822 size_t size = sizeof(ret);
1823 if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1)
1824 return false;
1825 return ret == 1;
1826 }
1827