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 <inttypes.h>
15 #include <libproc.h>
16 #include <map>
17 #include <signal.h>
18 #include <stdio.h>
19 #include <stdlib.h>
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/DarwinLog/DarwinLogCollector.h"
50 #include "MacOSX/Genealogy.h"
51 #include "MacOSX/MachProcess.h"
52 #include "MacOSX/MachTask.h"
53 #include "MacOSX/ThreadInfo.h"
54
55 typedef std::shared_ptr<MachProcess> MachProcessSP;
56 typedef std::map<nub_process_t, MachProcessSP> ProcessMap;
57 typedef ProcessMap::iterator ProcessMapIter;
58 typedef ProcessMap::const_iterator ProcessMapConstIter;
59
60 size_t GetAllInfos(std::vector<struct kinfo_proc> &proc_infos);
61 static size_t
62 GetAllInfosMatchingName(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.
GetProcessMap(bool can_create)69 static 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 pthread_mutex_t g_process_map_mutex = PTHREAD_MUTEX_INITIALIZER;
74 PTHREAD_MUTEX_LOCKER(locker, &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.
AddProcessToMap(nub_process_t pid,MachProcessSP & procSP)86 static nub_bool_t AddProcessToMap(nub_process_t pid, MachProcessSP &procSP) {
87 ProcessMap *process_map = GetProcessMap(true);
88 if (process_map) {
89 process_map->insert(std::make_pair(pid, 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.
GetProcessSP(nub_process_t pid,MachProcessSP & procSP)113 static nub_bool_t GetProcessSP(nub_process_t pid, MachProcessSP &procSP) {
114 ProcessMap *process_map = GetProcessMap(false);
115 if (process_map != NULL) {
116 ProcessMapIter pos = process_map->find(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
kqueue_thread(void * arg)127 void *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
spawn_kqueue_thread(pid_t pid)218 static 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(®_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, ®_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
waitpid_thread(void * arg)253 static 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, &status, 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(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, -1);
302 return NULL;
303 }
spawn_waitpid_thread(pid_t pid)304 static 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(&thread, NULL, waitpid_thread, (void *)(intptr_t)pid);
314 // pthread_create returns 0 if successful
315 if (ret == 0) {
316 ::pthread_detach(thread);
317 return true;
318 }
319 return false;
320 }
321
DNBProcessLaunch(const char * path,char const * argv[],const char * envp[],const char * working_directory,const char * stdin_path,const char * stdout_path,const char * stderr_path,bool no_stdio,nub_launch_flavor_t launch_flavor,int disable_aslr,const char * event_data,char * err_str,size_t err_len)322 nub_process_t DNBProcessLaunch(
323 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, nub_launch_flavor_t launch_flavor, int disable_aslr,
328 const char *event_data, char *err_str, size_t err_len) {
329 DNBLogThreadedIf(LOG_PROCESS, "%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, launch_flavor,
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(path, &path_stat) == -1) {
344 char stat_error[256];
345 ::strerror_r(errno, stat_error, sizeof(stat_error));
346 snprintf(err_str, err_len, "%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(path, argv, envp, working_directory,
354 stdin_path, stdout_path, stderr_path,
355 no_stdio, launch_flavor, disable_aslr,
356 event_data, 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, pid);
382
383 if (err_str && err_len > 0) {
384 if (launch_err.AsString()) {
385 ::snprintf(err_str, err_len,
386 "failed to get the task for process %i (%s)", pid,
387 launch_err.AsString());
388 } else {
389 ::snprintf(err_str, err_len,
390 "failed to get the task for process %i", pid);
391 }
392 }
393 } else {
394 bool res = AddProcessToMap(pid, processSP);
395 UNUSED_IF_ASSERT_DISABLED(res);
396 assert(res && "Couldn't add process to map!");
397 return pid;
398 }
399 }
400 }
401 return INVALID_NUB_PROCESS;
402 }
403
404 // If there is one process with a given name, return the pid for that process.
DNBProcessGetPIDByName(const char * name)405 nub_process_t DNBProcessGetPIDByName(const char *name) {
406 std::vector<struct kinfo_proc> matching_proc_infos;
407 size_t num_matching_proc_infos =
408 GetAllInfosMatchingName(name, matching_proc_infos);
409 if (num_matching_proc_infos == 1) {
410 return matching_proc_infos[0].kp_proc.p_pid;
411 }
412 return INVALID_NUB_PROCESS;
413 }
414
DNBProcessAttachByName(const char * name,struct timespec * timeout,char * err_str,size_t err_len)415 nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout,
416 char *err_str, size_t err_len) {
417 if (err_str && err_len > 0)
418 err_str[0] = '\0';
419 std::vector<struct kinfo_proc> matching_proc_infos;
420 size_t num_matching_proc_infos =
421 GetAllInfosMatchingName(name, matching_proc_infos);
422 if (num_matching_proc_infos == 0) {
423 DNBLogError("error: no processes match '%s'\n", name);
424 return INVALID_NUB_PROCESS;
425 } else if (num_matching_proc_infos > 1) {
426 DNBLogError("error: %llu processes match '%s':\n",
427 (uint64_t)num_matching_proc_infos, name);
428 size_t i;
429 for (i = 0; i < num_matching_proc_infos; ++i)
430 DNBLogError("%6u - %s\n", matching_proc_infos[i].kp_proc.p_pid,
431 matching_proc_infos[i].kp_proc.p_comm);
432 return INVALID_NUB_PROCESS;
433 }
434
435 return DNBProcessAttach(matching_proc_infos[0].kp_proc.p_pid, timeout,
436 err_str, err_len);
437 }
438
DNBProcessAttach(nub_process_t attach_pid,struct timespec * timeout,char * err_str,size_t err_len)439 nub_process_t DNBProcessAttach(nub_process_t attach_pid,
440 struct timespec *timeout, char *err_str,
441 size_t err_len) {
442 if (err_str && err_len > 0)
443 err_str[0] = '\0';
444
445 pid_t pid = INVALID_NUB_PROCESS;
446 MachProcessSP processSP(new MachProcess);
447 if (processSP.get()) {
448 DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...",
449 attach_pid);
450 pid = processSP->AttachForDebug(attach_pid, err_str, err_len);
451
452 if (pid != INVALID_NUB_PROCESS) {
453 bool res = AddProcessToMap(pid, processSP);
454 UNUSED_IF_ASSERT_DISABLED(res);
455 assert(res && "Couldn't add process to map!");
456 spawn_waitpid_thread(pid);
457 }
458 }
459
460 while (pid != INVALID_NUB_PROCESS) {
461 // Wait for process to start up and hit entry point
462 DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, "
463 "eEventProcessRunningStateChanged | "
464 "eEventProcessStoppedStateChanged, true, "
465 "INFINITE)...",
466 __FUNCTION__, pid);
467 nub_event_t set_events =
468 DNBProcessWaitForEvents(pid, eEventProcessRunningStateChanged |
469 eEventProcessStoppedStateChanged,
470 true, timeout);
471
472 DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, "
473 "eEventProcessRunningStateChanged | "
474 "eEventProcessStoppedStateChanged, true, "
475 "INFINITE) => 0x%8.8x",
476 __FUNCTION__, pid, set_events);
477
478 if (set_events == 0) {
479 if (err_str && err_len > 0)
480 snprintf(err_str, err_len, "operation timed out");
481 pid = INVALID_NUB_PROCESS;
482 } else {
483 if (set_events & (eEventProcessRunningStateChanged |
484 eEventProcessStoppedStateChanged)) {
485 nub_state_t pid_state = DNBProcessGetState(pid);
486 DNBLogThreadedIf(
487 LOG_PROCESS,
488 "%s process %4.4x state changed (eEventProcessStateChanged): %s",
489 __FUNCTION__, pid, DNBStateAsString(pid_state));
490
491 switch (pid_state) {
492 case eStateInvalid:
493 case eStateUnloaded:
494 case eStateAttaching:
495 case eStateLaunching:
496 case eStateSuspended:
497 break; // Ignore
498
499 case eStateRunning:
500 case eStateStepping:
501 // Still waiting to stop at entry point...
502 break;
503
504 case eStateStopped:
505 case eStateCrashed:
506 return pid;
507
508 case eStateDetached:
509 case eStateExited:
510 if (err_str && err_len > 0)
511 snprintf(err_str, err_len, "process exited");
512 return INVALID_NUB_PROCESS;
513 }
514 }
515
516 DNBProcessResetEvents(pid, set_events);
517 }
518 }
519
520 return INVALID_NUB_PROCESS;
521 }
522
GetAllInfos(std::vector<struct kinfo_proc> & proc_infos)523 size_t GetAllInfos(std::vector<struct kinfo_proc> &proc_infos) {
524 size_t size = 0;
525 int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
526 u_int namelen = sizeof(name) / sizeof(int);
527 int err;
528
529 // Try to find out how many processes are around so we can
530 // size the buffer appropriately. sysctl's man page specifically suggests
531 // this approach, and says it returns a bit larger size than needed to
532 // handle any new processes created between then and now.
533
534 err = ::sysctl(name, namelen, NULL, &size, NULL, 0);
535
536 if ((err < 0) && (err != ENOMEM)) {
537 proc_infos.clear();
538 perror("sysctl (mib, miblen, NULL, &num_processes, NULL, 0)");
539 return 0;
540 }
541
542 // Increase the size of the buffer by a few processes in case more have
543 // been spawned
544 proc_infos.resize(size / sizeof(struct kinfo_proc));
545 size = proc_infos.size() *
546 sizeof(struct kinfo_proc); // Make sure we don't exceed our resize...
547 err = ::sysctl(name, namelen, &proc_infos[0], &size, NULL, 0);
548 if (err < 0) {
549 proc_infos.clear();
550 return 0;
551 }
552
553 // Trim down our array to fit what we actually got back
554 proc_infos.resize(size / sizeof(struct kinfo_proc));
555 return proc_infos.size();
556 }
557
558 static size_t
GetAllInfosMatchingName(const char * full_process_name,std::vector<struct kinfo_proc> & matching_proc_infos)559 GetAllInfosMatchingName(const char *full_process_name,
560 std::vector<struct kinfo_proc> &matching_proc_infos) {
561
562 matching_proc_infos.clear();
563 if (full_process_name && full_process_name[0]) {
564 // We only get the process name, not the full path, from the proc_info. So
565 // just take the
566 // base name of the process name...
567 const char *process_name;
568 process_name = strrchr(full_process_name, '/');
569 if (process_name == NULL)
570 process_name = full_process_name;
571 else
572 process_name++;
573
574 const size_t process_name_len = strlen(process_name);
575 std::vector<struct kinfo_proc> proc_infos;
576 const size_t num_proc_infos = GetAllInfos(proc_infos);
577 if (num_proc_infos > 0) {
578 uint32_t i;
579 for (i = 0; i < num_proc_infos; i++) {
580 // Skip zombie processes and processes with unset status
581 if (proc_infos[i].kp_proc.p_stat == 0 ||
582 proc_infos[i].kp_proc.p_stat == SZOMB)
583 continue;
584
585 // Check for process by name. We only check the first MAXCOMLEN
586 // chars as that is all that kp_proc.p_comm holds.
587
588 if (::strncasecmp(process_name, proc_infos[i].kp_proc.p_comm,
589 MAXCOMLEN) == 0) {
590 if (process_name_len > MAXCOMLEN) {
591 // We found a matching process name whose first MAXCOMLEN
592 // characters match, but there is more to the name than
593 // this. We need to get the full process name. Use proc_pidpath,
594 // which will get
595 // us the full path to the executed process.
596
597 char proc_path_buf[PATH_MAX];
598
599 int return_val = proc_pidpath(proc_infos[i].kp_proc.p_pid,
600 proc_path_buf, PATH_MAX);
601 if (return_val > 0) {
602 // Okay, now search backwards from that to see if there is a
603 // slash in the name. Note, even though we got all the args we
604 // don't care
605 // because the list data is just a bunch of concatenated null
606 // terminated strings
607 // so strrchr will start from the end of argv0.
608
609 const char *argv_basename = strrchr(proc_path_buf, '/');
610 if (argv_basename) {
611 // Skip the '/'
612 ++argv_basename;
613 } else {
614 // We didn't find a directory delimiter in the process argv[0],
615 // just use what was in there
616 argv_basename = proc_path_buf;
617 }
618
619 if (argv_basename) {
620 if (::strncasecmp(process_name, argv_basename, PATH_MAX) == 0) {
621 matching_proc_infos.push_back(proc_infos[i]);
622 }
623 }
624 }
625 } else {
626 // We found a matching process, add it to our list
627 matching_proc_infos.push_back(proc_infos[i]);
628 }
629 }
630 }
631 }
632 }
633 // return the newly added matches.
634 return matching_proc_infos.size();
635 }
636
DNBProcessAttachWait(const char * waitfor_process_name,nub_launch_flavor_t launch_flavor,bool ignore_existing,struct timespec * timeout_abstime,useconds_t waitfor_interval,char * err_str,size_t err_len,DNBShouldCancelCallback should_cancel_callback,void * callback_data)637 nub_process_t DNBProcessAttachWait(
638 const char *waitfor_process_name, nub_launch_flavor_t launch_flavor,
639 bool ignore_existing, struct timespec *timeout_abstime,
640 useconds_t waitfor_interval, char *err_str, size_t err_len,
641 DNBShouldCancelCallback should_cancel_callback, void *callback_data) {
642 DNBError prepare_error;
643 std::vector<struct kinfo_proc> exclude_proc_infos;
644 size_t num_exclude_proc_infos;
645
646 // If the PrepareForAttach returns a valid token, use MachProcess to check
647 // for the process, otherwise scan the process table.
648
649 const void *attach_token = MachProcess::PrepareForAttach(
650 waitfor_process_name, launch_flavor, true, prepare_error);
651
652 if (prepare_error.Fail()) {
653 DNBLogError("Error in PrepareForAttach: %s", prepare_error.AsString());
654 return INVALID_NUB_PROCESS;
655 }
656
657 if (attach_token == NULL) {
658 if (ignore_existing)
659 num_exclude_proc_infos =
660 GetAllInfosMatchingName(waitfor_process_name, exclude_proc_infos);
661 else
662 num_exclude_proc_infos = 0;
663 }
664
665 DNBLogThreadedIf(LOG_PROCESS, "Waiting for '%s' to appear...\n",
666 waitfor_process_name);
667
668 // Loop and try to find the process by name
669 nub_process_t waitfor_pid = INVALID_NUB_PROCESS;
670
671 while (waitfor_pid == INVALID_NUB_PROCESS) {
672 if (attach_token != NULL) {
673 nub_process_t pid;
674 pid = MachProcess::CheckForProcess(attach_token, launch_flavor);
675 if (pid != INVALID_NUB_PROCESS) {
676 waitfor_pid = pid;
677 break;
678 }
679 } else {
680
681 // Get the current process list, and check for matches that
682 // aren't in our original list. If anyone wants to attach
683 // to an existing process by name, they should do it with
684 // --attach=PROCNAME. Else we will wait for the first matching
685 // process that wasn't in our exclusion list.
686 std::vector<struct kinfo_proc> proc_infos;
687 const size_t num_proc_infos =
688 GetAllInfosMatchingName(waitfor_process_name, proc_infos);
689 for (size_t i = 0; i < num_proc_infos; i++) {
690 nub_process_t curr_pid = proc_infos[i].kp_proc.p_pid;
691 for (size_t j = 0; j < num_exclude_proc_infos; j++) {
692 if (curr_pid == exclude_proc_infos[j].kp_proc.p_pid) {
693 // This process was in our exclusion list, don't use it.
694 curr_pid = INVALID_NUB_PROCESS;
695 break;
696 }
697 }
698
699 // If we didn't find CURR_PID in our exclusion list, then use it.
700 if (curr_pid != INVALID_NUB_PROCESS) {
701 // We found our process!
702 waitfor_pid = curr_pid;
703 break;
704 }
705 }
706 }
707
708 // If we haven't found our process yet, check for a timeout
709 // and then sleep for a bit until we poll again.
710 if (waitfor_pid == INVALID_NUB_PROCESS) {
711 if (timeout_abstime != NULL) {
712 // Check to see if we have a waitfor-duration option that
713 // has timed out?
714 if (DNBTimer::TimeOfDayLaterThan(*timeout_abstime)) {
715 if (err_str && err_len > 0)
716 snprintf(err_str, err_len, "operation timed out");
717 DNBLogError("error: waiting for process '%s' timed out.\n",
718 waitfor_process_name);
719 return INVALID_NUB_PROCESS;
720 }
721 }
722
723 // Call the should cancel callback as well...
724
725 if (should_cancel_callback != NULL &&
726 should_cancel_callback(callback_data)) {
727 DNBLogThreadedIf(
728 LOG_PROCESS,
729 "DNBProcessAttachWait cancelled by should_cancel callback.");
730 waitfor_pid = INVALID_NUB_PROCESS;
731 break;
732 }
733
734 ::usleep(waitfor_interval); // Sleep for WAITFOR_INTERVAL, then poll again
735 }
736 }
737
738 if (waitfor_pid != INVALID_NUB_PROCESS) {
739 DNBLogThreadedIf(LOG_PROCESS, "Attaching to %s with pid %i...\n",
740 waitfor_process_name, waitfor_pid);
741 waitfor_pid =
742 DNBProcessAttach(waitfor_pid, timeout_abstime, err_str, err_len);
743 }
744
745 bool success = waitfor_pid != INVALID_NUB_PROCESS;
746 MachProcess::CleanupAfterAttach(attach_token, launch_flavor, success,
747 prepare_error);
748
749 return waitfor_pid;
750 }
751
DNBProcessDetach(nub_process_t pid)752 nub_bool_t DNBProcessDetach(nub_process_t pid) {
753 MachProcessSP procSP;
754 if (GetProcessSP(pid, procSP)) {
755 const bool remove = true;
756 DNBLogThreaded(
757 "Disabling breakpoints and watchpoints, and detaching from %d.", pid);
758 procSP->DisableAllBreakpoints(remove);
759 procSP->DisableAllWatchpoints(remove);
760 return procSP->Detach();
761 }
762 return false;
763 }
764
DNBProcessKill(nub_process_t pid)765 nub_bool_t DNBProcessKill(nub_process_t pid) {
766 MachProcessSP procSP;
767 if (GetProcessSP(pid, procSP)) {
768 return procSP->Kill();
769 }
770 return false;
771 }
772
DNBProcessSignal(nub_process_t pid,int signal)773 nub_bool_t DNBProcessSignal(nub_process_t pid, int signal) {
774 MachProcessSP procSP;
775 if (GetProcessSP(pid, procSP)) {
776 return procSP->Signal(signal);
777 }
778 return false;
779 }
780
DNBProcessInterrupt(nub_process_t pid)781 nub_bool_t DNBProcessInterrupt(nub_process_t pid) {
782 MachProcessSP procSP;
783 if (GetProcessSP(pid, procSP))
784 return procSP->Interrupt();
785 return false;
786 }
787
DNBProcessSendEvent(nub_process_t pid,const char * event)788 nub_bool_t DNBProcessSendEvent(nub_process_t pid, const char *event) {
789 MachProcessSP procSP;
790 if (GetProcessSP(pid, procSP)) {
791 // FIXME: Do something with the error...
792 DNBError send_error;
793 return procSP->SendEvent(event, send_error);
794 }
795 return false;
796 }
797
DNBProcessIsAlive(nub_process_t pid)798 nub_bool_t DNBProcessIsAlive(nub_process_t pid) {
799 MachProcessSP procSP;
800 if (GetProcessSP(pid, procSP)) {
801 return MachTask::IsValid(procSP->Task().TaskPort());
802 }
803 return eStateInvalid;
804 }
805
806 // Process and Thread state information
DNBProcessGetState(nub_process_t pid)807 nub_state_t DNBProcessGetState(nub_process_t pid) {
808 MachProcessSP procSP;
809 if (GetProcessSP(pid, procSP)) {
810 return procSP->GetState();
811 }
812 return eStateInvalid;
813 }
814
815 // Process and Thread state information
DNBProcessGetExitStatus(nub_process_t pid,int * status)816 nub_bool_t DNBProcessGetExitStatus(nub_process_t pid, int *status) {
817 MachProcessSP procSP;
818 if (GetProcessSP(pid, procSP)) {
819 return procSP->GetExitStatus(status);
820 }
821 return false;
822 }
823
DNBProcessSetExitStatus(nub_process_t pid,int status)824 nub_bool_t DNBProcessSetExitStatus(nub_process_t pid, int status) {
825 MachProcessSP procSP;
826 if (GetProcessSP(pid, procSP)) {
827 procSP->SetExitStatus(status);
828 return true;
829 }
830 return false;
831 }
832
DNBProcessGetExitInfo(nub_process_t pid)833 const char *DNBProcessGetExitInfo(nub_process_t pid) {
834 MachProcessSP procSP;
835 if (GetProcessSP(pid, procSP)) {
836 return procSP->GetExitInfo();
837 }
838 return NULL;
839 }
840
DNBProcessSetExitInfo(nub_process_t pid,const char * info)841 nub_bool_t DNBProcessSetExitInfo(nub_process_t pid, const char *info) {
842 MachProcessSP procSP;
843 if (GetProcessSP(pid, procSP)) {
844 procSP->SetExitInfo(info);
845 return true;
846 }
847 return false;
848 }
849
DNBThreadGetName(nub_process_t pid,nub_thread_t tid)850 const char *DNBThreadGetName(nub_process_t pid, nub_thread_t tid) {
851 MachProcessSP procSP;
852 if (GetProcessSP(pid, procSP))
853 return procSP->ThreadGetName(tid);
854 return NULL;
855 }
856
857 nub_bool_t
DNBThreadGetIdentifierInfo(nub_process_t pid,nub_thread_t tid,thread_identifier_info_data_t * ident_info)858 DNBThreadGetIdentifierInfo(nub_process_t pid, nub_thread_t tid,
859 thread_identifier_info_data_t *ident_info) {
860 MachProcessSP procSP;
861 if (GetProcessSP(pid, procSP))
862 return procSP->GetThreadList().GetIdentifierInfo(tid, ident_info);
863 return false;
864 }
865
DNBThreadGetState(nub_process_t pid,nub_thread_t tid)866 nub_state_t DNBThreadGetState(nub_process_t pid, nub_thread_t tid) {
867 MachProcessSP procSP;
868 if (GetProcessSP(pid, procSP)) {
869 return procSP->ThreadGetState(tid);
870 }
871 return eStateInvalid;
872 }
873
DNBStateAsString(nub_state_t state)874 const char *DNBStateAsString(nub_state_t state) {
875 switch (state) {
876 case eStateInvalid:
877 return "Invalid";
878 case eStateUnloaded:
879 return "Unloaded";
880 case eStateAttaching:
881 return "Attaching";
882 case eStateLaunching:
883 return "Launching";
884 case eStateStopped:
885 return "Stopped";
886 case eStateRunning:
887 return "Running";
888 case eStateStepping:
889 return "Stepping";
890 case eStateCrashed:
891 return "Crashed";
892 case eStateDetached:
893 return "Detached";
894 case eStateExited:
895 return "Exited";
896 case eStateSuspended:
897 return "Suspended";
898 }
899 return "nub_state_t ???";
900 }
901
DNBGetGenealogyInfoForThread(nub_process_t pid,nub_thread_t tid,bool & timed_out)902 Genealogy::ThreadActivitySP DNBGetGenealogyInfoForThread(nub_process_t pid,
903 nub_thread_t tid,
904 bool &timed_out) {
905 Genealogy::ThreadActivitySP thread_activity_sp;
906 MachProcessSP procSP;
907 if (GetProcessSP(pid, procSP))
908 thread_activity_sp = procSP->GetGenealogyInfoForThread(tid, timed_out);
909 return thread_activity_sp;
910 }
911
DNBGetGenealogyImageInfo(nub_process_t pid,size_t idx)912 Genealogy::ProcessExecutableInfoSP DNBGetGenealogyImageInfo(nub_process_t pid,
913 size_t idx) {
914 Genealogy::ProcessExecutableInfoSP image_info_sp;
915 MachProcessSP procSP;
916 if (GetProcessSP(pid, procSP)) {
917 image_info_sp = procSP->GetGenealogyImageInfo(idx);
918 }
919 return image_info_sp;
920 }
921
DNBGetRequestedQoSForThread(nub_process_t pid,nub_thread_t tid,nub_addr_t tsd,uint64_t dti_qos_class_index)922 ThreadInfo::QoS DNBGetRequestedQoSForThread(nub_process_t pid, nub_thread_t tid,
923 nub_addr_t tsd,
924 uint64_t dti_qos_class_index) {
925 MachProcessSP procSP;
926 if (GetProcessSP(pid, procSP)) {
927 return procSP->GetRequestedQoS(tid, tsd, dti_qos_class_index);
928 }
929 return ThreadInfo::QoS();
930 }
931
DNBGetPThreadT(nub_process_t pid,nub_thread_t tid)932 nub_addr_t DNBGetPThreadT(nub_process_t pid, nub_thread_t tid) {
933 MachProcessSP procSP;
934 if (GetProcessSP(pid, procSP)) {
935 return procSP->GetPThreadT(tid);
936 }
937 return INVALID_NUB_ADDRESS;
938 }
939
DNBGetDispatchQueueT(nub_process_t pid,nub_thread_t tid)940 nub_addr_t DNBGetDispatchQueueT(nub_process_t pid, nub_thread_t tid) {
941 MachProcessSP procSP;
942 if (GetProcessSP(pid, procSP)) {
943 return procSP->GetDispatchQueueT(tid);
944 }
945 return INVALID_NUB_ADDRESS;
946 }
947
948 nub_addr_t
DNBGetTSDAddressForThread(nub_process_t pid,nub_thread_t tid,uint64_t plo_pthread_tsd_base_address_offset,uint64_t plo_pthread_tsd_base_offset,uint64_t plo_pthread_tsd_entry_size)949 DNBGetTSDAddressForThread(nub_process_t pid, nub_thread_t tid,
950 uint64_t plo_pthread_tsd_base_address_offset,
951 uint64_t plo_pthread_tsd_base_offset,
952 uint64_t plo_pthread_tsd_entry_size) {
953 MachProcessSP procSP;
954 if (GetProcessSP(pid, procSP)) {
955 return procSP->GetTSDAddressForThread(
956 tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset,
957 plo_pthread_tsd_entry_size);
958 }
959 return INVALID_NUB_ADDRESS;
960 }
961
DNBGetLoadedDynamicLibrariesInfos(nub_process_t pid,nub_addr_t image_list_address,nub_addr_t image_count)962 JSONGenerator::ObjectSP DNBGetLoadedDynamicLibrariesInfos(
963 nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count) {
964 MachProcessSP procSP;
965 if (GetProcessSP(pid, procSP)) {
966 return procSP->GetLoadedDynamicLibrariesInfos(pid, image_list_address,
967 image_count);
968 }
969 return JSONGenerator::ObjectSP();
970 }
971
DNBGetAllLoadedLibrariesInfos(nub_process_t pid)972 JSONGenerator::ObjectSP DNBGetAllLoadedLibrariesInfos(nub_process_t pid) {
973 MachProcessSP procSP;
974 if (GetProcessSP(pid, procSP)) {
975 return procSP->GetAllLoadedLibrariesInfos(pid);
976 }
977 return JSONGenerator::ObjectSP();
978 }
979
980 JSONGenerator::ObjectSP
DNBGetLibrariesInfoForAddresses(nub_process_t pid,std::vector<uint64_t> & macho_addresses)981 DNBGetLibrariesInfoForAddresses(nub_process_t pid,
982 std::vector<uint64_t> &macho_addresses) {
983 MachProcessSP procSP;
984 if (GetProcessSP(pid, procSP)) {
985 return procSP->GetLibrariesInfoForAddresses(pid, macho_addresses);
986 }
987 return JSONGenerator::ObjectSP();
988 }
989
DNBGetSharedCacheInfo(nub_process_t pid)990 JSONGenerator::ObjectSP DNBGetSharedCacheInfo(nub_process_t pid) {
991 MachProcessSP procSP;
992 if (GetProcessSP(pid, procSP)) {
993 return procSP->GetSharedCacheInfo(pid);
994 }
995 return JSONGenerator::ObjectSP();
996 }
997
DNBProcessGetExecutablePath(nub_process_t pid)998 const char *DNBProcessGetExecutablePath(nub_process_t pid) {
999 MachProcessSP procSP;
1000 if (GetProcessSP(pid, procSP)) {
1001 return procSP->Path();
1002 }
1003 return NULL;
1004 }
1005
DNBProcessGetArgumentCount(nub_process_t pid)1006 nub_size_t DNBProcessGetArgumentCount(nub_process_t pid) {
1007 MachProcessSP procSP;
1008 if (GetProcessSP(pid, procSP)) {
1009 return procSP->ArgumentCount();
1010 }
1011 return 0;
1012 }
1013
DNBProcessGetArgumentAtIndex(nub_process_t pid,nub_size_t idx)1014 const char *DNBProcessGetArgumentAtIndex(nub_process_t pid, nub_size_t idx) {
1015 MachProcessSP procSP;
1016 if (GetProcessSP(pid, procSP)) {
1017 return procSP->ArgumentAtIndex(idx);
1018 }
1019 return NULL;
1020 }
1021
1022 // Execution control
DNBProcessResume(nub_process_t pid,const DNBThreadResumeAction * actions,size_t num_actions)1023 nub_bool_t DNBProcessResume(nub_process_t pid,
1024 const DNBThreadResumeAction *actions,
1025 size_t num_actions) {
1026 DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
1027 MachProcessSP procSP;
1028 if (GetProcessSP(pid, procSP)) {
1029 DNBThreadResumeActions thread_actions(actions, num_actions);
1030
1031 // Below we add a default thread plan just in case one wasn't
1032 // provided so all threads always know what they were supposed to do
1033 if (thread_actions.IsEmpty()) {
1034 // No thread plans were given, so the default it to run all threads
1035 thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, 0);
1036 } else {
1037 // Some thread plans were given which means anything that wasn't
1038 // specified should remain stopped.
1039 thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);
1040 }
1041 return procSP->Resume(thread_actions);
1042 }
1043 return false;
1044 }
1045
DNBProcessHalt(nub_process_t pid)1046 nub_bool_t DNBProcessHalt(nub_process_t pid) {
1047 DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
1048 MachProcessSP procSP;
1049 if (GetProcessSP(pid, procSP))
1050 return procSP->Signal(SIGSTOP);
1051 return false;
1052 }
1053 //
1054 // nub_bool_t
1055 // DNBThreadResume (nub_process_t pid, nub_thread_t tid, nub_bool_t step)
1056 //{
1057 // DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u)",
1058 // __FUNCTION__, pid, tid, (uint32_t)step);
1059 // MachProcessSP procSP;
1060 // if (GetProcessSP (pid, procSP))
1061 // {
1062 // return procSP->Resume(tid, step, 0);
1063 // }
1064 // return false;
1065 //}
1066 //
1067 // nub_bool_t
1068 // DNBThreadResumeWithSignal (nub_process_t pid, nub_thread_t tid, nub_bool_t
1069 // step, int signal)
1070 //{
1071 // DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u,
1072 // signal = %i)", __FUNCTION__, pid, tid, (uint32_t)step, signal);
1073 // MachProcessSP procSP;
1074 // if (GetProcessSP (pid, procSP))
1075 // {
1076 // return procSP->Resume(tid, step, signal);
1077 // }
1078 // return false;
1079 //}
1080
DNBProcessWaitForEvents(nub_process_t pid,nub_event_t event_mask,bool wait_for_set,struct timespec * timeout)1081 nub_event_t DNBProcessWaitForEvents(nub_process_t pid, nub_event_t event_mask,
1082 bool wait_for_set,
1083 struct timespec *timeout) {
1084 nub_event_t result = 0;
1085 MachProcessSP procSP;
1086 if (GetProcessSP(pid, procSP)) {
1087 if (wait_for_set)
1088 result = procSP->Events().WaitForSetEvents(event_mask, timeout);
1089 else
1090 result = procSP->Events().WaitForEventsToReset(event_mask, timeout);
1091 }
1092 return result;
1093 }
1094
DNBProcessResetEvents(nub_process_t pid,nub_event_t event_mask)1095 void DNBProcessResetEvents(nub_process_t pid, nub_event_t event_mask) {
1096 MachProcessSP procSP;
1097 if (GetProcessSP(pid, procSP))
1098 procSP->Events().ResetEvents(event_mask);
1099 }
1100
1101 // Breakpoints
DNBBreakpointSet(nub_process_t pid,nub_addr_t addr,nub_size_t size,nub_bool_t hardware)1102 nub_bool_t DNBBreakpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size,
1103 nub_bool_t hardware) {
1104 MachProcessSP procSP;
1105 if (GetProcessSP(pid, procSP))
1106 return procSP->CreateBreakpoint(addr, size, hardware) != NULL;
1107 return false;
1108 }
1109
DNBBreakpointClear(nub_process_t pid,nub_addr_t addr)1110 nub_bool_t DNBBreakpointClear(nub_process_t pid, nub_addr_t addr) {
1111 MachProcessSP procSP;
1112 if (GetProcessSP(pid, procSP))
1113 return procSP->DisableBreakpoint(addr, true);
1114 return false; // Failed
1115 }
1116
1117 // Watchpoints
DNBWatchpointSet(nub_process_t pid,nub_addr_t addr,nub_size_t size,uint32_t watch_flags,nub_bool_t hardware)1118 nub_bool_t DNBWatchpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size,
1119 uint32_t watch_flags, nub_bool_t hardware) {
1120 MachProcessSP procSP;
1121 if (GetProcessSP(pid, procSP))
1122 return procSP->CreateWatchpoint(addr, size, watch_flags, hardware) != NULL;
1123 return false;
1124 }
1125
DNBWatchpointClear(nub_process_t pid,nub_addr_t addr)1126 nub_bool_t DNBWatchpointClear(nub_process_t pid, nub_addr_t addr) {
1127 MachProcessSP procSP;
1128 if (GetProcessSP(pid, procSP))
1129 return procSP->DisableWatchpoint(addr, true);
1130 return false; // Failed
1131 }
1132
1133 // Return the number of supported hardware watchpoints.
DNBWatchpointGetNumSupportedHWP(nub_process_t pid)1134 uint32_t DNBWatchpointGetNumSupportedHWP(nub_process_t pid) {
1135 MachProcessSP procSP;
1136 if (GetProcessSP(pid, procSP))
1137 return procSP->GetNumSupportedHardwareWatchpoints();
1138 return 0;
1139 }
1140
1141 // Read memory in the address space of process PID. This call will take
1142 // care of setting and restoring permissions and breaking up the memory
1143 // read into multiple chunks as required.
1144 //
1145 // RETURNS: number of bytes actually read
DNBProcessMemoryRead(nub_process_t pid,nub_addr_t addr,nub_size_t size,void * buf)1146 nub_size_t DNBProcessMemoryRead(nub_process_t pid, nub_addr_t addr,
1147 nub_size_t size, void *buf) {
1148 MachProcessSP procSP;
1149 if (GetProcessSP(pid, procSP))
1150 return procSP->ReadMemory(addr, size, buf);
1151 return 0;
1152 }
1153
DNBProcessMemoryReadInteger(nub_process_t pid,nub_addr_t addr,nub_size_t integer_size,uint64_t fail_value)1154 uint64_t DNBProcessMemoryReadInteger(nub_process_t pid, nub_addr_t addr,
1155 nub_size_t integer_size,
1156 uint64_t fail_value) {
1157 union Integers {
1158 uint8_t u8;
1159 uint16_t u16;
1160 uint32_t u32;
1161 uint64_t u64;
1162 };
1163
1164 if (integer_size <= sizeof(uint64_t)) {
1165 Integers ints;
1166 if (DNBProcessMemoryRead(pid, addr, integer_size, &ints) == integer_size) {
1167 switch (integer_size) {
1168 case 1:
1169 return ints.u8;
1170 case 2:
1171 return ints.u16;
1172 case 3:
1173 return ints.u32 & 0xffffffu;
1174 case 4:
1175 return ints.u32;
1176 case 5:
1177 return ints.u32 & 0x000000ffffffffffull;
1178 case 6:
1179 return ints.u32 & 0x0000ffffffffffffull;
1180 case 7:
1181 return ints.u32 & 0x00ffffffffffffffull;
1182 case 8:
1183 return ints.u64;
1184 }
1185 }
1186 }
1187 return fail_value;
1188 }
1189
DNBProcessMemoryReadPointer(nub_process_t pid,nub_addr_t addr)1190 nub_addr_t DNBProcessMemoryReadPointer(nub_process_t pid, nub_addr_t addr) {
1191 cpu_type_t cputype = DNBProcessGetCPUType(pid);
1192 if (cputype) {
1193 const nub_size_t pointer_size = (cputype & CPU_ARCH_ABI64) ? 8 : 4;
1194 return DNBProcessMemoryReadInteger(pid, addr, pointer_size, 0);
1195 }
1196 return 0;
1197 }
1198
DNBProcessMemoryReadCString(nub_process_t pid,nub_addr_t addr)1199 std::string DNBProcessMemoryReadCString(nub_process_t pid, nub_addr_t addr) {
1200 std::string cstr;
1201 char buffer[256];
1202 const nub_size_t max_buffer_cstr_length = sizeof(buffer) - 1;
1203 buffer[max_buffer_cstr_length] = '\0';
1204 nub_size_t length = 0;
1205 nub_addr_t curr_addr = addr;
1206 do {
1207 nub_size_t bytes_read =
1208 DNBProcessMemoryRead(pid, curr_addr, max_buffer_cstr_length, buffer);
1209 if (bytes_read == 0)
1210 break;
1211 length = strlen(buffer);
1212 cstr.append(buffer, length);
1213 curr_addr += length;
1214 } while (length == max_buffer_cstr_length);
1215 return cstr;
1216 }
1217
DNBProcessMemoryReadCStringFixed(nub_process_t pid,nub_addr_t addr,nub_size_t fixed_length)1218 std::string DNBProcessMemoryReadCStringFixed(nub_process_t pid, nub_addr_t addr,
1219 nub_size_t fixed_length) {
1220 std::string cstr;
1221 char buffer[fixed_length + 1];
1222 buffer[fixed_length] = '\0';
1223 nub_size_t bytes_read = DNBProcessMemoryRead(pid, addr, fixed_length, buffer);
1224 if (bytes_read > 0)
1225 cstr.assign(buffer);
1226 return cstr;
1227 }
1228
1229 // Write memory to the address space of process PID. This call will take
1230 // care of setting and restoring permissions and breaking up the memory
1231 // write into multiple chunks as required.
1232 //
1233 // RETURNS: number of bytes actually written
DNBProcessMemoryWrite(nub_process_t pid,nub_addr_t addr,nub_size_t size,const void * buf)1234 nub_size_t DNBProcessMemoryWrite(nub_process_t pid, nub_addr_t addr,
1235 nub_size_t size, const void *buf) {
1236 MachProcessSP procSP;
1237 if (GetProcessSP(pid, procSP))
1238 return procSP->WriteMemory(addr, size, buf);
1239 return 0;
1240 }
1241
DNBProcessMemoryAllocate(nub_process_t pid,nub_size_t size,uint32_t permissions)1242 nub_addr_t DNBProcessMemoryAllocate(nub_process_t pid, nub_size_t size,
1243 uint32_t permissions) {
1244 MachProcessSP procSP;
1245 if (GetProcessSP(pid, procSP))
1246 return procSP->Task().AllocateMemory(size, permissions);
1247 return 0;
1248 }
1249
DNBProcessMemoryDeallocate(nub_process_t pid,nub_addr_t addr)1250 nub_bool_t DNBProcessMemoryDeallocate(nub_process_t pid, nub_addr_t addr) {
1251 MachProcessSP procSP;
1252 if (GetProcessSP(pid, procSP))
1253 return procSP->Task().DeallocateMemory(addr);
1254 return 0;
1255 }
1256
1257 // Find attributes of the memory region that contains ADDR for process PID,
1258 // if possible, and return a string describing those attributes.
1259 //
1260 // Returns 1 if we could find attributes for this region and OUTBUF can
1261 // be sent to the remote debugger.
1262 //
1263 // Returns 0 if we couldn't find the attributes for a region of memory at
1264 // that address and OUTBUF should not be sent.
1265 //
1266 // Returns -1 if this platform cannot look up information about memory regions
1267 // or if we do not yet have a valid launched process.
1268 //
DNBProcessMemoryRegionInfo(nub_process_t pid,nub_addr_t addr,DNBRegionInfo * region_info)1269 int DNBProcessMemoryRegionInfo(nub_process_t pid, nub_addr_t addr,
1270 DNBRegionInfo *region_info) {
1271 MachProcessSP procSP;
1272 if (GetProcessSP(pid, procSP))
1273 return procSP->Task().GetMemoryRegionInfo(addr, region_info);
1274
1275 return -1;
1276 }
1277
DNBProcessGetProfileData(nub_process_t pid,DNBProfileDataScanType scanType)1278 std::string DNBProcessGetProfileData(nub_process_t pid,
1279 DNBProfileDataScanType scanType) {
1280 MachProcessSP procSP;
1281 if (GetProcessSP(pid, procSP))
1282 return procSP->Task().GetProfileData(scanType);
1283
1284 return std::string("");
1285 }
1286
DNBProcessSetEnableAsyncProfiling(nub_process_t pid,nub_bool_t enable,uint64_t interval_usec,DNBProfileDataScanType scan_type)1287 nub_bool_t DNBProcessSetEnableAsyncProfiling(nub_process_t pid,
1288 nub_bool_t enable,
1289 uint64_t interval_usec,
1290 DNBProfileDataScanType scan_type) {
1291 MachProcessSP procSP;
1292 if (GetProcessSP(pid, procSP)) {
1293 procSP->SetEnableAsyncProfiling(enable, interval_usec, scan_type);
1294 return true;
1295 }
1296
1297 return false;
1298 }
1299
1300 // Get the number of threads for the specified process.
DNBProcessGetNumThreads(nub_process_t pid)1301 nub_size_t DNBProcessGetNumThreads(nub_process_t pid) {
1302 MachProcessSP procSP;
1303 if (GetProcessSP(pid, procSP))
1304 return procSP->GetNumThreads();
1305 return 0;
1306 }
1307
1308 // Get the thread ID of the current thread.
DNBProcessGetCurrentThread(nub_process_t pid)1309 nub_thread_t DNBProcessGetCurrentThread(nub_process_t pid) {
1310 MachProcessSP procSP;
1311 if (GetProcessSP(pid, procSP))
1312 return procSP->GetCurrentThread();
1313 return 0;
1314 }
1315
1316 // Get the mach port number of the current thread.
DNBProcessGetCurrentThreadMachPort(nub_process_t pid)1317 nub_thread_t DNBProcessGetCurrentThreadMachPort(nub_process_t pid) {
1318 MachProcessSP procSP;
1319 if (GetProcessSP(pid, procSP))
1320 return procSP->GetCurrentThreadMachPort();
1321 return 0;
1322 }
1323
1324 // Change the current thread.
DNBProcessSetCurrentThread(nub_process_t pid,nub_thread_t tid)1325 nub_thread_t DNBProcessSetCurrentThread(nub_process_t pid, nub_thread_t tid) {
1326 MachProcessSP procSP;
1327 if (GetProcessSP(pid, procSP))
1328 return procSP->SetCurrentThread(tid);
1329 return INVALID_NUB_THREAD;
1330 }
1331
1332 // Dump a string describing a thread's stop reason to the specified file
1333 // handle
DNBThreadGetStopReason(nub_process_t pid,nub_thread_t tid,struct DNBThreadStopInfo * stop_info)1334 nub_bool_t DNBThreadGetStopReason(nub_process_t pid, nub_thread_t tid,
1335 struct DNBThreadStopInfo *stop_info) {
1336 MachProcessSP procSP;
1337 if (GetProcessSP(pid, procSP))
1338 return procSP->GetThreadStoppedReason(tid, stop_info);
1339 return false;
1340 }
1341
1342 // Return string description for the specified thread.
1343 //
1344 // RETURNS: NULL if the thread isn't valid, else a NULL terminated C
1345 // string from a static buffer that must be copied prior to subsequent
1346 // calls.
DNBThreadGetInfo(nub_process_t pid,nub_thread_t tid)1347 const char *DNBThreadGetInfo(nub_process_t pid, nub_thread_t tid) {
1348 MachProcessSP procSP;
1349 if (GetProcessSP(pid, procSP))
1350 return procSP->GetThreadInfo(tid);
1351 return NULL;
1352 }
1353
1354 // Get the thread ID given a thread index.
DNBProcessGetThreadAtIndex(nub_process_t pid,size_t thread_idx)1355 nub_thread_t DNBProcessGetThreadAtIndex(nub_process_t pid, size_t thread_idx) {
1356 MachProcessSP procSP;
1357 if (GetProcessSP(pid, procSP))
1358 return procSP->GetThreadAtIndex(thread_idx);
1359 return INVALID_NUB_THREAD;
1360 }
1361
1362 // Do whatever is needed to sync the thread's register state with it's kernel
1363 // values.
DNBProcessSyncThreadState(nub_process_t pid,nub_thread_t tid)1364 nub_bool_t DNBProcessSyncThreadState(nub_process_t pid, nub_thread_t tid) {
1365 MachProcessSP procSP;
1366 if (GetProcessSP(pid, procSP))
1367 return procSP->SyncThreadState(tid);
1368 return false;
1369 }
1370
DNBProcessGetSharedLibraryInfoAddress(nub_process_t pid)1371 nub_addr_t DNBProcessGetSharedLibraryInfoAddress(nub_process_t pid) {
1372 MachProcessSP procSP;
1373 DNBError err;
1374 if (GetProcessSP(pid, procSP))
1375 return procSP->Task().GetDYLDAllImageInfosAddress(err);
1376 return INVALID_NUB_ADDRESS;
1377 }
1378
DNBProcessSharedLibrariesUpdated(nub_process_t pid)1379 nub_bool_t DNBProcessSharedLibrariesUpdated(nub_process_t pid) {
1380 MachProcessSP procSP;
1381 if (GetProcessSP(pid, procSP)) {
1382 procSP->SharedLibrariesUpdated();
1383 return true;
1384 }
1385 return false;
1386 }
1387
DNBGetDeploymentInfo(nub_process_t pid,const struct load_command & lc,uint64_t load_command_address,uint32_t & major_version,uint32_t & minor_version,uint32_t & patch_version)1388 const char *DNBGetDeploymentInfo(nub_process_t pid,
1389 const struct load_command& lc,
1390 uint64_t load_command_address,
1391 uint32_t& major_version,
1392 uint32_t& minor_version,
1393 uint32_t& patch_version) {
1394 MachProcessSP procSP;
1395 if (GetProcessSP(pid, procSP))
1396 return procSP->GetDeploymentInfo(lc, load_command_address,
1397 major_version, minor_version,
1398 patch_version);
1399 return nullptr;
1400 }
1401
1402
1403 // Get the current shared library information for a process. Only return
1404 // the shared libraries that have changed since the last shared library
1405 // state changed event if only_changed is non-zero.
1406 nub_size_t
DNBProcessGetSharedLibraryInfo(nub_process_t pid,nub_bool_t only_changed,struct DNBExecutableImageInfo ** image_infos)1407 DNBProcessGetSharedLibraryInfo(nub_process_t pid, nub_bool_t only_changed,
1408 struct DNBExecutableImageInfo **image_infos) {
1409 MachProcessSP procSP;
1410 if (GetProcessSP(pid, procSP))
1411 return procSP->CopyImageInfos(image_infos, only_changed);
1412
1413 // If we have no process, then return NULL for the shared library info
1414 // and zero for shared library count
1415 *image_infos = NULL;
1416 return 0;
1417 }
1418
DNBGetRegisterCPUType()1419 uint32_t DNBGetRegisterCPUType() {
1420 return DNBArchProtocol::GetRegisterCPUType();
1421 }
1422 // Get the register set information for a specific thread.
DNBGetRegisterSetInfo(nub_size_t * num_reg_sets)1423 const DNBRegisterSetInfo *DNBGetRegisterSetInfo(nub_size_t *num_reg_sets) {
1424 return DNBArchProtocol::GetRegisterSetInfo(num_reg_sets);
1425 }
1426
1427 // Read a register value by register set and register index.
DNBThreadGetRegisterValueByID(nub_process_t pid,nub_thread_t tid,uint32_t set,uint32_t reg,DNBRegisterValue * value)1428 nub_bool_t DNBThreadGetRegisterValueByID(nub_process_t pid, nub_thread_t tid,
1429 uint32_t set, uint32_t reg,
1430 DNBRegisterValue *value) {
1431 MachProcessSP procSP;
1432 ::bzero(value, sizeof(DNBRegisterValue));
1433 if (GetProcessSP(pid, procSP)) {
1434 if (tid != INVALID_NUB_THREAD)
1435 return procSP->GetRegisterValue(tid, set, reg, value);
1436 }
1437 return false;
1438 }
1439
DNBThreadSetRegisterValueByID(nub_process_t pid,nub_thread_t tid,uint32_t set,uint32_t reg,const DNBRegisterValue * value)1440 nub_bool_t DNBThreadSetRegisterValueByID(nub_process_t pid, nub_thread_t tid,
1441 uint32_t set, uint32_t reg,
1442 const DNBRegisterValue *value) {
1443 if (tid != INVALID_NUB_THREAD) {
1444 MachProcessSP procSP;
1445 if (GetProcessSP(pid, procSP))
1446 return procSP->SetRegisterValue(tid, set, reg, value);
1447 }
1448 return false;
1449 }
1450
DNBThreadGetRegisterContext(nub_process_t pid,nub_thread_t tid,void * buf,size_t buf_len)1451 nub_size_t DNBThreadGetRegisterContext(nub_process_t pid, nub_thread_t tid,
1452 void *buf, size_t buf_len) {
1453 MachProcessSP procSP;
1454 if (GetProcessSP(pid, procSP)) {
1455 if (tid != INVALID_NUB_THREAD)
1456 return procSP->GetThreadList().GetRegisterContext(tid, buf, buf_len);
1457 }
1458 ::bzero(buf, buf_len);
1459 return 0;
1460 }
1461
DNBThreadSetRegisterContext(nub_process_t pid,nub_thread_t tid,const void * buf,size_t buf_len)1462 nub_size_t DNBThreadSetRegisterContext(nub_process_t pid, nub_thread_t tid,
1463 const void *buf, size_t buf_len) {
1464 MachProcessSP procSP;
1465 if (GetProcessSP(pid, procSP)) {
1466 if (tid != INVALID_NUB_THREAD)
1467 return procSP->GetThreadList().SetRegisterContext(tid, buf, buf_len);
1468 }
1469 return 0;
1470 }
1471
DNBThreadSaveRegisterState(nub_process_t pid,nub_thread_t tid)1472 uint32_t DNBThreadSaveRegisterState(nub_process_t pid, nub_thread_t tid) {
1473 if (tid != INVALID_NUB_THREAD) {
1474 MachProcessSP procSP;
1475 if (GetProcessSP(pid, procSP))
1476 return procSP->GetThreadList().SaveRegisterState(tid);
1477 }
1478 return 0;
1479 }
DNBThreadRestoreRegisterState(nub_process_t pid,nub_thread_t tid,uint32_t save_id)1480 nub_bool_t DNBThreadRestoreRegisterState(nub_process_t pid, nub_thread_t tid,
1481 uint32_t save_id) {
1482 if (tid != INVALID_NUB_THREAD) {
1483 MachProcessSP procSP;
1484 if (GetProcessSP(pid, procSP))
1485 return procSP->GetThreadList().RestoreRegisterState(tid, save_id);
1486 }
1487 return false;
1488 }
1489
1490 // Read a register value by name.
DNBThreadGetRegisterValueByName(nub_process_t pid,nub_thread_t tid,uint32_t reg_set,const char * reg_name,DNBRegisterValue * value)1491 nub_bool_t DNBThreadGetRegisterValueByName(nub_process_t pid, nub_thread_t tid,
1492 uint32_t reg_set,
1493 const char *reg_name,
1494 DNBRegisterValue *value) {
1495 MachProcessSP procSP;
1496 ::bzero(value, sizeof(DNBRegisterValue));
1497 if (GetProcessSP(pid, procSP)) {
1498 const struct DNBRegisterSetInfo *set_info;
1499 nub_size_t num_reg_sets = 0;
1500 set_info = DNBGetRegisterSetInfo(&num_reg_sets);
1501 if (set_info) {
1502 uint32_t set = reg_set;
1503 uint32_t reg;
1504 if (set == REGISTER_SET_ALL) {
1505 for (set = 1; set < num_reg_sets; ++set) {
1506 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1507 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
1508 return procSP->GetRegisterValue(tid, set, reg, value);
1509 }
1510 }
1511 } else {
1512 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1513 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
1514 return procSP->GetRegisterValue(tid, set, reg, value);
1515 }
1516 }
1517 }
1518 }
1519 return false;
1520 }
1521
1522 // Read a register set and register number from the register name.
DNBGetRegisterInfoByName(const char * reg_name,DNBRegisterInfo * info)1523 nub_bool_t DNBGetRegisterInfoByName(const char *reg_name,
1524 DNBRegisterInfo *info) {
1525 const struct DNBRegisterSetInfo *set_info;
1526 nub_size_t num_reg_sets = 0;
1527 set_info = DNBGetRegisterSetInfo(&num_reg_sets);
1528 if (set_info) {
1529 uint32_t set, reg;
1530 for (set = 1; set < num_reg_sets; ++set) {
1531 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1532 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) {
1533 *info = set_info[set].registers[reg];
1534 return true;
1535 }
1536 }
1537 }
1538
1539 for (set = 1; set < num_reg_sets; ++set) {
1540 uint32_t reg;
1541 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1542 if (set_info[set].registers[reg].alt == NULL)
1543 continue;
1544
1545 if (strcasecmp(reg_name, set_info[set].registers[reg].alt) == 0) {
1546 *info = set_info[set].registers[reg];
1547 return true;
1548 }
1549 }
1550 }
1551 }
1552
1553 ::bzero(info, sizeof(DNBRegisterInfo));
1554 return false;
1555 }
1556
1557 // Set the name to address callback function that this nub can use
1558 // for any name to address lookups that are needed.
DNBProcessSetNameToAddressCallback(nub_process_t pid,DNBCallbackNameToAddress callback,void * baton)1559 nub_bool_t DNBProcessSetNameToAddressCallback(nub_process_t pid,
1560 DNBCallbackNameToAddress callback,
1561 void *baton) {
1562 MachProcessSP procSP;
1563 if (GetProcessSP(pid, procSP)) {
1564 procSP->SetNameToAddressCallback(callback, baton);
1565 return true;
1566 }
1567 return false;
1568 }
1569
1570 // Set the name to address callback function that this nub can use
1571 // for any name to address lookups that are needed.
DNBProcessSetSharedLibraryInfoCallback(nub_process_t pid,DNBCallbackCopyExecutableImageInfos callback,void * baton)1572 nub_bool_t DNBProcessSetSharedLibraryInfoCallback(
1573 nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback,
1574 void *baton) {
1575 MachProcessSP procSP;
1576 if (GetProcessSP(pid, procSP)) {
1577 procSP->SetSharedLibraryInfoCallback(callback, baton);
1578 return true;
1579 }
1580 return false;
1581 }
1582
DNBProcessLookupAddress(nub_process_t pid,const char * name,const char * shlib)1583 nub_addr_t DNBProcessLookupAddress(nub_process_t pid, const char *name,
1584 const char *shlib) {
1585 MachProcessSP procSP;
1586 if (GetProcessSP(pid, procSP)) {
1587 return procSP->LookupSymbol(name, shlib);
1588 }
1589 return INVALID_NUB_ADDRESS;
1590 }
1591
DNBProcessGetAvailableSTDOUT(nub_process_t pid,char * buf,nub_size_t buf_size)1592 nub_size_t DNBProcessGetAvailableSTDOUT(nub_process_t pid, char *buf,
1593 nub_size_t buf_size) {
1594 MachProcessSP procSP;
1595 if (GetProcessSP(pid, procSP))
1596 return procSP->GetAvailableSTDOUT(buf, buf_size);
1597 return 0;
1598 }
1599
DNBProcessGetAvailableSTDERR(nub_process_t pid,char * buf,nub_size_t buf_size)1600 nub_size_t DNBProcessGetAvailableSTDERR(nub_process_t pid, char *buf,
1601 nub_size_t buf_size) {
1602 MachProcessSP procSP;
1603 if (GetProcessSP(pid, procSP))
1604 return procSP->GetAvailableSTDERR(buf, buf_size);
1605 return 0;
1606 }
1607
DNBProcessGetAvailableProfileData(nub_process_t pid,char * buf,nub_size_t buf_size)1608 nub_size_t DNBProcessGetAvailableProfileData(nub_process_t pid, char *buf,
1609 nub_size_t buf_size) {
1610 MachProcessSP procSP;
1611 if (GetProcessSP(pid, procSP))
1612 return procSP->GetAsyncProfileData(buf, buf_size);
1613 return 0;
1614 }
1615
DNBProcessGetAvailableDarwinLogEvents(nub_process_t pid)1616 DarwinLogEventVector DNBProcessGetAvailableDarwinLogEvents(nub_process_t pid) {
1617 return DarwinLogCollector::GetEventsForProcess(pid);
1618 }
1619
DNBProcessGetStopCount(nub_process_t pid)1620 nub_size_t DNBProcessGetStopCount(nub_process_t pid) {
1621 MachProcessSP procSP;
1622 if (GetProcessSP(pid, procSP))
1623 return procSP->StopCount();
1624 return 0;
1625 }
1626
DNBProcessGetCPUType(nub_process_t pid)1627 uint32_t DNBProcessGetCPUType(nub_process_t pid) {
1628 MachProcessSP procSP;
1629 if (GetProcessSP(pid, procSP))
1630 return procSP->GetCPUType();
1631 return 0;
1632 }
1633
DNBResolveExecutablePath(const char * path,char * resolved_path,size_t resolved_path_size)1634 nub_bool_t DNBResolveExecutablePath(const char *path, char *resolved_path,
1635 size_t resolved_path_size) {
1636 if (path == NULL || path[0] == '\0')
1637 return false;
1638
1639 char max_path[PATH_MAX];
1640 std::string result;
1641 CFString::GlobPath(path, result);
1642
1643 if (result.empty())
1644 result = path;
1645
1646 struct stat path_stat;
1647 if (::stat(path, &path_stat) == 0) {
1648 if ((path_stat.st_mode & S_IFMT) == S_IFDIR) {
1649 CFBundle bundle(path);
1650 CFReleaser<CFURLRef> url(bundle.CopyExecutableURL());
1651 if (url.get()) {
1652 if (::CFURLGetFileSystemRepresentation(
1653 url.get(), true, (UInt8 *)resolved_path, resolved_path_size))
1654 return true;
1655 }
1656 }
1657 }
1658
1659 if (realpath(path, max_path)) {
1660 // Found the path relatively...
1661 ::strlcpy(resolved_path, max_path, resolved_path_size);
1662 return strlen(resolved_path) + 1 < resolved_path_size;
1663 } else {
1664 // Not a relative path, check the PATH environment variable if the
1665 const char *PATH = getenv("PATH");
1666 if (PATH) {
1667 const char *curr_path_start = PATH;
1668 const char *curr_path_end;
1669 while (curr_path_start && *curr_path_start) {
1670 curr_path_end = strchr(curr_path_start, ':');
1671 if (curr_path_end == NULL) {
1672 result.assign(curr_path_start);
1673 curr_path_start = NULL;
1674 } else if (curr_path_end > curr_path_start) {
1675 size_t len = curr_path_end - curr_path_start;
1676 result.assign(curr_path_start, len);
1677 curr_path_start += len + 1;
1678 } else
1679 break;
1680
1681 result += '/';
1682 result += path;
1683 struct stat s;
1684 if (stat(result.c_str(), &s) == 0) {
1685 ::strlcpy(resolved_path, result.c_str(), resolved_path_size);
1686 return result.size() + 1 < resolved_path_size;
1687 }
1688 }
1689 }
1690 }
1691 return false;
1692 }
1693
DNBGetOSVersionNumbers(uint64_t * major,uint64_t * minor,uint64_t * patch)1694 bool DNBGetOSVersionNumbers(uint64_t *major, uint64_t *minor, uint64_t *patch) {
1695 return MachProcess::GetOSVersionNumbers(major, minor, patch);
1696 }
1697
DNBGetMacCatalystVersionString()1698 std::string DNBGetMacCatalystVersionString() {
1699 return MachProcess::GetMacCatalystVersionString();
1700 }
1701
DNBInitialize()1702 void DNBInitialize() {
1703 DNBLogThreadedIf(LOG_PROCESS, "DNBInitialize ()");
1704 #if defined(__i386__) || defined(__x86_64__)
1705 DNBArchImplI386::Initialize();
1706 DNBArchImplX86_64::Initialize();
1707 #elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
1708 DNBArchMachARM::Initialize();
1709 DNBArchMachARM64::Initialize();
1710 #endif
1711 }
1712
DNBTerminate()1713 void DNBTerminate() {}
1714
DNBSetArchitecture(const char * arch)1715 nub_bool_t DNBSetArchitecture(const char *arch) {
1716 if (arch && arch[0]) {
1717 if (strcasecmp(arch, "i386") == 0)
1718 return DNBArchProtocol::SetArchitecture(CPU_TYPE_I386);
1719 else if ((strcasecmp(arch, "x86_64") == 0) ||
1720 (strcasecmp(arch, "x86_64h") == 0))
1721 return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64);
1722 else if (strstr(arch, "arm64_32") == arch ||
1723 strstr(arch, "aarch64_32") == arch)
1724 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64_32);
1725 else if (strstr(arch, "arm64e") == arch)
1726 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64);
1727 else if (strstr(arch, "arm64") == arch || strstr(arch, "armv8") == arch ||
1728 strstr(arch, "aarch64") == arch)
1729 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64);
1730 else if (strstr(arch, "arm") == arch)
1731 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM);
1732 }
1733 return false;
1734 }
1735