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

source code of lldb/tools/debugserver/source/DNB.cpp