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

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