1 //===-- DNB.cpp -------------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  Created by Greg Clayton on 3/23/07.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "DNB.h"
15 #include <signal.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <sys/resource.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <sys/wait.h>
22 #include <unistd.h>
23 #include <sys/sysctl.h>
24 #include <map>
25 #include <vector>
26 
27 #include "MacOSX/MachProcess.h"
28 #include "MacOSX/MachTask.h"
29 #include "CFString.h"
30 #include "DNBLog.h"
31 #include "DNBDataRef.h"
32 #include "DNBThreadResumeActions.h"
33 #include "DNBTimer.h"
34 
35 typedef STD_SHARED_PTR(MachProcess) MachProcessSP;
36 typedef std::map<nub_process_t, MachProcessSP> ProcessMap;
37 typedef ProcessMap::iterator ProcessMapIter;
38 typedef ProcessMap::const_iterator ProcessMapConstIter;
39 
40 static size_t          GetAllInfos                  (std::vector<struct kinfo_proc>& proc_infos);
41 static size_t          GetAllInfosMatchingName      (const char *process_name, std::vector<struct kinfo_proc>& matching_proc_infos);
42 
43 //----------------------------------------------------------------------
44 // A Thread safe singleton to get a process map pointer.
45 //
46 // Returns a pointer to the existing process map, or a pointer to a
47 // newly created process map if CAN_CREATE is non-zero.
48 //----------------------------------------------------------------------
49 static ProcessMap*
50 GetProcessMap(bool can_create)
51 {
52     static ProcessMap* g_process_map_ptr = NULL;
53 
54     if (can_create && g_process_map_ptr == NULL)
55     {
56         static pthread_mutex_t g_process_map_mutex = PTHREAD_MUTEX_INITIALIZER;
57         PTHREAD_MUTEX_LOCKER (locker, &g_process_map_mutex);
58         if (g_process_map_ptr == NULL)
59             g_process_map_ptr = new ProcessMap;
60     }
61     return g_process_map_ptr;
62 }
63 
64 //----------------------------------------------------------------------
65 // Add PID to the shared process pointer map.
66 //
67 // Return non-zero value if we succeed in adding the process to the map.
68 // The only time this should fail is if we run out of memory and can't
69 // allocate a ProcessMap.
70 //----------------------------------------------------------------------
71 static nub_bool_t
72 AddProcessToMap (nub_process_t pid, MachProcessSP& procSP)
73 {
74     ProcessMap* process_map = GetProcessMap(true);
75     if (process_map)
76     {
77         process_map->insert(std::make_pair(pid, procSP));
78         return true;
79     }
80     return false;
81 }
82 
83 //----------------------------------------------------------------------
84 // Remove the shared pointer for PID from the process map.
85 //
86 // Returns the number of items removed from the process map.
87 //----------------------------------------------------------------------
88 static size_t
89 RemoveProcessFromMap (nub_process_t pid)
90 {
91     ProcessMap* process_map = GetProcessMap(false);
92     if (process_map)
93     {
94         return process_map->erase(pid);
95     }
96     return 0;
97 }
98 
99 //----------------------------------------------------------------------
100 // Get the shared pointer for PID from the existing process map.
101 //
102 // Returns true if we successfully find a shared pointer to a
103 // MachProcess object.
104 //----------------------------------------------------------------------
105 static nub_bool_t
106 GetProcessSP (nub_process_t pid, MachProcessSP& procSP)
107 {
108     ProcessMap* process_map = GetProcessMap(false);
109     if (process_map != NULL)
110     {
111         ProcessMapIter pos = process_map->find(pid);
112         if (pos != process_map->end())
113         {
114             procSP = pos->second;
115             return true;
116         }
117     }
118     procSP.reset();
119     return false;
120 }
121 
122 
123 static void *
124 waitpid_thread (void *arg)
125 {
126     const pid_t pid = (pid_t)(intptr_t)arg;
127     int status;
128     while (1)
129     {
130         pid_t child_pid = waitpid(pid, &status, 0);
131         DNBLogThreadedIf(LOG_PROCESS, "waitpid_process_thread (): waitpid (pid = %i, &status, 0) => %i, status = %i, errno = %i", pid, child_pid, status, errno);
132 
133         if (child_pid < 0)
134         {
135             if (errno == EINTR)
136                 continue;
137             break;
138         }
139         else
140         {
141             if (WIFSTOPPED(status))
142             {
143                 continue;
144             }
145             else// if (WIFEXITED(status) || WIFSIGNALED(status))
146             {
147                 DNBLogThreadedIf(LOG_PROCESS, "waitpid_process_thread (): setting exit status for pid = %i to %i", child_pid, status);
148                 DNBProcessSetExitStatus (child_pid, status);
149                 return NULL;
150             }
151         }
152     }
153 
154     // We should never exit as long as our child process is alive, so if we
155     // do something else went wrong and we should exit...
156     DNBLogThreadedIf(LOG_PROCESS, "waitpid_process_thread (): main loop exited, setting exit status to an invalid value (-1) for pid %i", pid);
157     DNBProcessSetExitStatus (pid, -1);
158     return NULL;
159 }
160 
161 static bool
162 spawn_waitpid_thread (pid_t pid)
163 {
164     pthread_t thread = THREAD_NULL;
165     ::pthread_create (&thread, NULL, waitpid_thread, (void *)(intptr_t)pid);
166     if (thread != THREAD_NULL)
167     {
168         ::pthread_detach (thread);
169         return true;
170     }
171     return false;
172 }
173 
174 nub_process_t
175 DNBProcessLaunch (const char *path,
176                   char const *argv[],
177                   const char *envp[],
178                   const char *working_directory, // NULL => dont' change, non-NULL => set working directory for inferior to this
179                   const char *stdin_path,
180                   const char *stdout_path,
181                   const char *stderr_path,
182                   bool no_stdio,
183                   nub_launch_flavor_t launch_flavor,
184                   int disable_aslr,
185                   char *err_str,
186                   size_t err_len)
187 {
188     DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv = %p, envp = %p, working_dir=%s, stdin=%s, stdout=%s, stderr=%s, no-stdio=%i, launch_flavor = %u, disable_aslr = %d, err = %p, err_len = %zu) called...",
189                      __FUNCTION__,
190                      path,
191                      argv,
192                      envp,
193                      working_directory,
194                      stdin_path,
195                      stdout_path,
196                      stderr_path,
197                      no_stdio,
198                      launch_flavor,
199                      disable_aslr,
200                      err_str,
201                      err_len);
202 
203     if (err_str && err_len > 0)
204         err_str[0] = '\0';
205     struct stat path_stat;
206     if (::stat(path, &path_stat) == -1)
207     {
208         char stat_error[256];
209         ::strerror_r (errno, stat_error, sizeof(stat_error));
210         snprintf(err_str, err_len, "%s (%s)", stat_error, path);
211         return INVALID_NUB_PROCESS;
212     }
213 
214     MachProcessSP processSP (new MachProcess);
215     if (processSP.get())
216     {
217         DNBError launch_err;
218         pid_t pid = processSP->LaunchForDebug (path,
219                                                argv,
220                                                envp,
221                                                working_directory,
222                                                stdin_path,
223                                                stdout_path,
224                                                stderr_path,
225                                                no_stdio,
226                                                launch_flavor,
227                                                disable_aslr,
228                                                launch_err);
229         if (err_str)
230         {
231             *err_str = '\0';
232             if (launch_err.Fail())
233             {
234                 const char *launch_err_str = launch_err.AsString();
235                 if (launch_err_str)
236                 {
237                     strncpy(err_str, launch_err_str, err_len-1);
238                     err_str[err_len-1] = '\0';  // Make sure the error string is terminated
239                 }
240             }
241         }
242 
243         DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) new pid is %d...", pid);
244 
245         if (pid != INVALID_NUB_PROCESS)
246         {
247             // Spawn a thread to reap our child inferior process...
248             spawn_waitpid_thread (pid);
249 
250             if (processSP->Task().TaskPortForProcessID (launch_err) == TASK_NULL)
251             {
252                 // We failed to get the task for our process ID which is bad.
253                 // Kill our process otherwise it will be stopped at the entry
254                 // point and get reparented to someone else and never go away.
255                 kill (SIGKILL, pid);
256 
257                 if (err_str && err_len > 0)
258                 {
259                     if (launch_err.AsString())
260                     {
261                         ::snprintf (err_str, err_len, "failed to get the task for process %i (%s)", pid, launch_err.AsString());
262                     }
263                     else
264                     {
265                         ::snprintf (err_str, err_len, "failed to get the task for process %i", pid);
266                     }
267                 }
268             }
269             else
270             {
271                 bool res = AddProcessToMap(pid, processSP);
272                 assert(res && "Couldn't add process to map!");
273                 return pid;
274             }
275         }
276     }
277     return INVALID_NUB_PROCESS;
278 }
279 
280 nub_process_t
281 DNBProcessAttachByName (const char *name, struct timespec *timeout, char *err_str, size_t err_len)
282 {
283     if (err_str && err_len > 0)
284         err_str[0] = '\0';
285     std::vector<struct kinfo_proc> matching_proc_infos;
286     size_t num_matching_proc_infos = GetAllInfosMatchingName(name, matching_proc_infos);
287     if (num_matching_proc_infos == 0)
288     {
289         DNBLogError ("error: no processes match '%s'\n", name);
290         return INVALID_NUB_PROCESS;
291     }
292     else if (num_matching_proc_infos > 1)
293     {
294         DNBLogError ("error: %zu processes match '%s':\n", num_matching_proc_infos, name);
295         size_t i;
296         for (i=0; i<num_matching_proc_infos; ++i)
297             DNBLogError ("%6u - %s\n", matching_proc_infos[i].kp_proc.p_pid, matching_proc_infos[i].kp_proc.p_comm);
298         return INVALID_NUB_PROCESS;
299     }
300 
301     return DNBProcessAttach (matching_proc_infos[0].kp_proc.p_pid, timeout, err_str, err_len);
302 }
303 
304 nub_process_t
305 DNBProcessAttach (nub_process_t attach_pid, struct timespec *timeout, char *err_str, size_t err_len)
306 {
307     if (err_str && err_len > 0)
308         err_str[0] = '\0';
309 
310     pid_t pid = INVALID_NUB_PROCESS;
311     MachProcessSP processSP(new MachProcess);
312     if (processSP.get())
313     {
314         DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...", attach_pid);
315         pid = processSP->AttachForDebug (attach_pid, err_str,  err_len);
316 
317         if (pid != INVALID_NUB_PROCESS)
318         {
319             bool res = AddProcessToMap(pid, processSP);
320             assert(res && "Couldn't add process to map!");
321             spawn_waitpid_thread(pid);
322         }
323     }
324 
325     while (pid != INVALID_NUB_PROCESS)
326     {
327         // Wait for process to start up and hit entry point
328         DNBLogThreadedIf (LOG_PROCESS,
329                           "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...",
330                           __FUNCTION__,
331                           pid);
332         nub_event_t set_events = DNBProcessWaitForEvents (pid,
333                                                           eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged,
334                                                           true,
335                                                           timeout);
336 
337         DNBLogThreadedIf (LOG_PROCESS,
338                           "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x",
339                           __FUNCTION__,
340                           pid,
341                           set_events);
342 
343         if (set_events == 0)
344         {
345             if (err_str && err_len > 0)
346                 snprintf(err_str, err_len, "operation timed out");
347             pid = INVALID_NUB_PROCESS;
348         }
349         else
350         {
351             if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
352             {
353                 nub_state_t pid_state = DNBProcessGetState (pid);
354                 DNBLogThreadedIf (LOG_PROCESS, "%s process %4.4x state changed (eEventProcessStateChanged): %s",
355                         __FUNCTION__, pid, DNBStateAsString(pid_state));
356 
357                 switch (pid_state)
358                 {
359                     default:
360                     case eStateInvalid:
361                     case eStateUnloaded:
362                     case eStateAttaching:
363                     case eStateLaunching:
364                     case eStateSuspended:
365                         break;  // Ignore
366 
367                     case eStateRunning:
368                     case eStateStepping:
369                         // Still waiting to stop at entry point...
370                         break;
371 
372                     case eStateStopped:
373                     case eStateCrashed:
374                         return pid;
375 
376                     case eStateDetached:
377                     case eStateExited:
378                         if (err_str && err_len > 0)
379                             snprintf(err_str, err_len, "process exited");
380                         return INVALID_NUB_PROCESS;
381                 }
382             }
383 
384             DNBProcessResetEvents(pid, set_events);
385         }
386     }
387 
388     return INVALID_NUB_PROCESS;
389 }
390 
391 static size_t
392 GetAllInfos (std::vector<struct kinfo_proc>& proc_infos)
393 {
394     size_t size;
395     int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
396     u_int namelen = sizeof(name)/sizeof(int);
397     int err;
398 
399     // Try to find out how many processes are around so we can
400     // size the buffer appropriately.  sysctl's man page specifically suggests
401     // this approach, and says it returns a bit larger size than needed to
402     // handle any new processes created between then and now.
403 
404     err = ::sysctl (name, namelen, NULL, &size, NULL, 0);
405 
406     if ((err < 0) && (err != ENOMEM))
407     {
408         proc_infos.clear();
409         perror("sysctl (mib, miblen, NULL, &num_processes, NULL, 0)");
410         return 0;
411     }
412 
413 
414     // Increase the size of the buffer by a few processes in case more have
415     // been spawned
416     proc_infos.resize (size / sizeof(struct kinfo_proc));
417     size = proc_infos.size() * sizeof(struct kinfo_proc);   // Make sure we don't exceed our resize...
418     err = ::sysctl (name, namelen, &proc_infos[0], &size, NULL, 0);
419     if (err < 0)
420     {
421         proc_infos.clear();
422         return 0;
423     }
424 
425     // Trim down our array to fit what we actually got back
426     proc_infos.resize(size / sizeof(struct kinfo_proc));
427     return proc_infos.size();
428 }
429 
430 
431 static size_t
432 GetAllInfosMatchingName(const char *full_process_name, std::vector<struct kinfo_proc>& matching_proc_infos)
433 {
434 
435     matching_proc_infos.clear();
436     if (full_process_name && full_process_name[0])
437     {
438         // We only get the process name, not the full path, from the proc_info.  So just take the
439         // base name of the process name...
440         const char *process_name;
441         process_name = strrchr (full_process_name, '/');
442         if (process_name == NULL)
443             process_name = full_process_name;
444         else
445             process_name++;
446 
447         const int process_name_len = strlen(process_name);
448         std::vector<struct kinfo_proc> proc_infos;
449         const size_t num_proc_infos = GetAllInfos(proc_infos);
450         if (num_proc_infos > 0)
451         {
452             uint32_t i;
453             for (i=0; i<num_proc_infos; i++)
454             {
455                 // Skip zombie processes and processes with unset status
456                 if (proc_infos[i].kp_proc.p_stat == 0 || proc_infos[i].kp_proc.p_stat == SZOMB)
457                     continue;
458 
459                 // Check for process by name. We only check the first MAXCOMLEN
460                 // chars as that is all that kp_proc.p_comm holds.
461                 if (::strncasecmp(process_name, proc_infos[i].kp_proc.p_comm, MAXCOMLEN) == 0)
462                 {
463                     if (process_name_len > MAXCOMLEN)
464                     {
465                         // We found a matching process name whose first MAXCOMLEN
466                         // characters match, but there is more to the name than
467                         // this. We need to get the full process name.
468 
469                         int proc_args_mib[3] = { CTL_KERN, KERN_PROCARGS2, proc_infos[i].kp_proc.p_pid };
470 
471                         // Get PATH_MAX for argv[0] plus 4 bytes for the argc
472                         char arg_data[PATH_MAX+4];
473                         size_t arg_data_size = sizeof(arg_data);
474                          // Skip the 4 byte argc integer value to get to argv[0]
475                         const char *argv0 = arg_data + 4;
476                         if (::sysctl (proc_args_mib, 3, arg_data, &arg_data_size , NULL, 0) == 0)
477                         {
478                             const char *argv_basename = strrchr(argv0, '/');
479                             if (argv_basename)
480                             {
481                                 // Skip the '/'
482                                 ++argv_basename;
483                             }
484                             else
485                             {
486                                 // We didn't find a directory delimiter in the process argv[0], just use what was in there
487                                 argv_basename = argv0;
488                             }
489 
490                             if (argv_basename)
491                             {
492                                 if (::strncasecmp(process_name, argv_basename, PATH_MAX) == 0)
493                                 {
494                                     matching_proc_infos.push_back(proc_infos[i]);
495                                 }
496                             }
497                         }
498                     }
499                     else
500                     {
501                         // We found a matching process, add it to our list
502                         matching_proc_infos.push_back(proc_infos[i]);
503                     }
504                 }
505             }
506         }
507     }
508     // return the newly added matches.
509     return matching_proc_infos.size();
510 }
511 
512 nub_process_t
513 DNBProcessAttachWait (const char *waitfor_process_name,
514                       nub_launch_flavor_t launch_flavor,
515                       bool ignore_existing,
516                       struct timespec *timeout_abstime,
517                       useconds_t waitfor_interval,
518                       char *err_str,
519                       size_t err_len,
520                       DNBShouldCancelCallback should_cancel_callback,
521                       void *callback_data)
522 {
523     DNBError prepare_error;
524     std::vector<struct kinfo_proc> exclude_proc_infos;
525     size_t num_exclude_proc_infos;
526 
527     // If the PrepareForAttach returns a valid token, use  MachProcess to check
528     // for the process, otherwise scan the process table.
529 
530     const void *attach_token = MachProcess::PrepareForAttach (waitfor_process_name, launch_flavor, true, prepare_error);
531 
532     if (prepare_error.Fail())
533     {
534         DNBLogError ("Error in PrepareForAttach: %s", prepare_error.AsString());
535         return INVALID_NUB_PROCESS;
536     }
537 
538     if (attach_token == NULL)
539     {
540         if (ignore_existing)
541             num_exclude_proc_infos = GetAllInfosMatchingName (waitfor_process_name, exclude_proc_infos);
542         else
543             num_exclude_proc_infos = 0;
544     }
545 
546     DNBLogThreadedIf (LOG_PROCESS, "Waiting for '%s' to appear...\n", waitfor_process_name);
547 
548     // Loop and try to find the process by name
549     nub_process_t waitfor_pid = INVALID_NUB_PROCESS;
550 
551     while (waitfor_pid == INVALID_NUB_PROCESS)
552     {
553         if (attach_token != NULL)
554         {
555             nub_process_t pid;
556             pid = MachProcess::CheckForProcess(attach_token);
557             if (pid != INVALID_NUB_PROCESS)
558             {
559                 waitfor_pid = pid;
560                 break;
561             }
562         }
563         else
564         {
565 
566             // Get the current process list, and check for matches that
567             // aren't in our original list. If anyone wants to attach
568             // to an existing process by name, they should do it with
569             // --attach=PROCNAME. Else we will wait for the first matching
570             // process that wasn't in our exclusion list.
571             std::vector<struct kinfo_proc> proc_infos;
572             const size_t num_proc_infos = GetAllInfosMatchingName (waitfor_process_name, proc_infos);
573             for (size_t i=0; i<num_proc_infos; i++)
574             {
575                 nub_process_t curr_pid = proc_infos[i].kp_proc.p_pid;
576                 for (size_t j=0; j<num_exclude_proc_infos; j++)
577                 {
578                     if (curr_pid == exclude_proc_infos[j].kp_proc.p_pid)
579                     {
580                         // This process was in our exclusion list, don't use it.
581                         curr_pid = INVALID_NUB_PROCESS;
582                         break;
583                     }
584                 }
585 
586                 // If we didn't find CURR_PID in our exclusion list, then use it.
587                 if (curr_pid != INVALID_NUB_PROCESS)
588                 {
589                     // We found our process!
590                     waitfor_pid = curr_pid;
591                     break;
592                 }
593             }
594         }
595 
596         // If we haven't found our process yet, check for a timeout
597         // and then sleep for a bit until we poll again.
598         if (waitfor_pid == INVALID_NUB_PROCESS)
599         {
600             if (timeout_abstime != NULL)
601             {
602                 // Check to see if we have a waitfor-duration option that
603                 // has timed out?
604                 if (DNBTimer::TimeOfDayLaterThan(*timeout_abstime))
605                 {
606                     if (err_str && err_len > 0)
607                         snprintf(err_str, err_len, "operation timed out");
608                     DNBLogError ("error: waiting for process '%s' timed out.\n", waitfor_process_name);
609                     return INVALID_NUB_PROCESS;
610                 }
611             }
612 
613             // Call the should cancel callback as well...
614 
615             if (should_cancel_callback != NULL
616                 && should_cancel_callback (callback_data))
617             {
618                 DNBLogThreadedIf (LOG_PROCESS, "DNBProcessAttachWait cancelled by should_cancel callback.");
619                 waitfor_pid = INVALID_NUB_PROCESS;
620                 break;
621             }
622 
623             ::usleep (waitfor_interval);    // Sleep for WAITFOR_INTERVAL, then poll again
624         }
625     }
626 
627     if (waitfor_pid != INVALID_NUB_PROCESS)
628     {
629         DNBLogThreadedIf (LOG_PROCESS, "Attaching to %s with pid %i...\n", waitfor_process_name, waitfor_pid);
630         waitfor_pid = DNBProcessAttach (waitfor_pid, timeout_abstime, err_str, err_len);
631     }
632 
633     bool success = waitfor_pid != INVALID_NUB_PROCESS;
634     MachProcess::CleanupAfterAttach (attach_token, success, prepare_error);
635 
636     return waitfor_pid;
637 }
638 
639 nub_bool_t
640 DNBProcessDetach (nub_process_t pid)
641 {
642     MachProcessSP procSP;
643     if (GetProcessSP (pid, procSP))
644     {
645         return procSP->Detach();
646     }
647     return false;
648 }
649 
650 nub_bool_t
651 DNBProcessKill (nub_process_t pid)
652 {
653     MachProcessSP procSP;
654     if (GetProcessSP (pid, procSP))
655     {
656         return procSP->Kill ();
657     }
658     return false;
659 }
660 
661 nub_bool_t
662 DNBProcessSignal (nub_process_t pid, int signal)
663 {
664     MachProcessSP procSP;
665     if (GetProcessSP (pid, procSP))
666     {
667         return procSP->Signal (signal);
668     }
669     return false;
670 }
671 
672 
673 nub_bool_t
674 DNBProcessIsAlive (nub_process_t pid)
675 {
676     MachProcessSP procSP;
677     if (GetProcessSP (pid, procSP))
678     {
679         return MachTask::IsValid (procSP->Task().TaskPort());
680     }
681     return eStateInvalid;
682 }
683 
684 //----------------------------------------------------------------------
685 // Process and Thread state information
686 //----------------------------------------------------------------------
687 nub_state_t
688 DNBProcessGetState (nub_process_t pid)
689 {
690     MachProcessSP procSP;
691     if (GetProcessSP (pid, procSP))
692     {
693         return procSP->GetState();
694     }
695     return eStateInvalid;
696 }
697 
698 //----------------------------------------------------------------------
699 // Process and Thread state information
700 //----------------------------------------------------------------------
701 nub_bool_t
702 DNBProcessGetExitStatus (nub_process_t pid, int* status)
703 {
704     MachProcessSP procSP;
705     if (GetProcessSP (pid, procSP))
706     {
707         return procSP->GetExitStatus(status);
708     }
709     return false;
710 }
711 
712 nub_bool_t
713 DNBProcessSetExitStatus (nub_process_t pid, int status)
714 {
715     MachProcessSP procSP;
716     if (GetProcessSP (pid, procSP))
717     {
718         procSP->SetExitStatus(status);
719         return true;
720     }
721     return false;
722 }
723 
724 
725 const char *
726 DNBThreadGetName (nub_process_t pid, nub_thread_t tid)
727 {
728     MachProcessSP procSP;
729     if (GetProcessSP (pid, procSP))
730         return procSP->ThreadGetName(tid);
731     return NULL;
732 }
733 
734 
735 nub_bool_t
736 DNBThreadGetIdentifierInfo (nub_process_t pid, nub_thread_t tid, thread_identifier_info_data_t *ident_info)
737 {
738     MachProcessSP procSP;
739     if (GetProcessSP (pid, procSP))
740         return procSP->GetThreadList().GetIdentifierInfo(tid, ident_info);
741     return false;
742 }
743 
744 nub_state_t
745 DNBThreadGetState (nub_process_t pid, nub_thread_t tid)
746 {
747     MachProcessSP procSP;
748     if (GetProcessSP (pid, procSP))
749     {
750         return procSP->ThreadGetState(tid);
751     }
752     return eStateInvalid;
753 }
754 
755 const char *
756 DNBStateAsString(nub_state_t state)
757 {
758     switch (state)
759     {
760     case eStateInvalid:     return "Invalid";
761     case eStateUnloaded:    return "Unloaded";
762     case eStateAttaching:   return "Attaching";
763     case eStateLaunching:   return "Launching";
764     case eStateStopped:     return "Stopped";
765     case eStateRunning:     return "Running";
766     case eStateStepping:    return "Stepping";
767     case eStateCrashed:     return "Crashed";
768     case eStateDetached:    return "Detached";
769     case eStateExited:      return "Exited";
770     case eStateSuspended:   return "Suspended";
771     }
772     return "nub_state_t ???";
773 }
774 
775 const char *
776 DNBProcessGetExecutablePath (nub_process_t pid)
777 {
778     MachProcessSP procSP;
779     if (GetProcessSP (pid, procSP))
780     {
781         return procSP->Path();
782     }
783     return NULL;
784 }
785 
786 nub_size_t
787 DNBProcessGetArgumentCount (nub_process_t pid)
788 {
789     MachProcessSP procSP;
790     if (GetProcessSP (pid, procSP))
791     {
792         return procSP->ArgumentCount();
793     }
794     return 0;
795 }
796 
797 const char *
798 DNBProcessGetArgumentAtIndex (nub_process_t pid, nub_size_t idx)
799 {
800     MachProcessSP procSP;
801     if (GetProcessSP (pid, procSP))
802     {
803         return procSP->ArgumentAtIndex (idx);
804     }
805     return NULL;
806 }
807 
808 
809 //----------------------------------------------------------------------
810 // Execution control
811 //----------------------------------------------------------------------
812 nub_bool_t
813 DNBProcessResume (nub_process_t pid, const DNBThreadResumeAction *actions, size_t num_actions)
814 {
815     DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
816     MachProcessSP procSP;
817     if (GetProcessSP (pid, procSP))
818     {
819         DNBThreadResumeActions thread_actions (actions, num_actions);
820 
821         // Below we add a default thread plan just in case one wasn't
822         // provided so all threads always know what they were supposed to do
823         if (thread_actions.IsEmpty())
824         {
825             // No thread plans were given, so the default it to run all threads
826             thread_actions.SetDefaultThreadActionIfNeeded (eStateRunning, 0);
827         }
828         else
829         {
830             // Some thread plans were given which means anything that wasn't
831             // specified should remain stopped.
832             thread_actions.SetDefaultThreadActionIfNeeded (eStateStopped, 0);
833         }
834         return procSP->Resume (thread_actions);
835     }
836     return false;
837 }
838 
839 nub_bool_t
840 DNBProcessHalt (nub_process_t pid)
841 {
842     DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
843     MachProcessSP procSP;
844     if (GetProcessSP (pid, procSP))
845         return procSP->Signal (SIGSTOP);
846     return false;
847 }
848 //
849 //nub_bool_t
850 //DNBThreadResume (nub_process_t pid, nub_thread_t tid, nub_bool_t step)
851 //{
852 //    DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u)", __FUNCTION__, pid, tid, (uint32_t)step);
853 //    MachProcessSP procSP;
854 //    if (GetProcessSP (pid, procSP))
855 //    {
856 //        return procSP->Resume(tid, step, 0);
857 //    }
858 //    return false;
859 //}
860 //
861 //nub_bool_t
862 //DNBThreadResumeWithSignal (nub_process_t pid, nub_thread_t tid, nub_bool_t step, int signal)
863 //{
864 //    DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u, signal = %i)", __FUNCTION__, pid, tid, (uint32_t)step, signal);
865 //    MachProcessSP procSP;
866 //    if (GetProcessSP (pid, procSP))
867 //    {
868 //        return procSP->Resume(tid, step, signal);
869 //    }
870 //    return false;
871 //}
872 
873 nub_event_t
874 DNBProcessWaitForEvents (nub_process_t pid, nub_event_t event_mask, bool wait_for_set, struct timespec* timeout)
875 {
876     nub_event_t result = 0;
877     MachProcessSP procSP;
878     if (GetProcessSP (pid, procSP))
879     {
880         if (wait_for_set)
881             result = procSP->Events().WaitForSetEvents(event_mask, timeout);
882         else
883             result = procSP->Events().WaitForEventsToReset(event_mask, timeout);
884     }
885     return result;
886 }
887 
888 void
889 DNBProcessResetEvents (nub_process_t pid, nub_event_t event_mask)
890 {
891     MachProcessSP procSP;
892     if (GetProcessSP (pid, procSP))
893         procSP->Events().ResetEvents(event_mask);
894 }
895 
896 void
897 DNBProcessInterruptEvents (nub_process_t pid)
898 {
899     MachProcessSP procSP;
900     if (GetProcessSP (pid, procSP))
901         procSP->Events().SetEvents(eEventProcessAsyncInterrupt);
902 }
903 
904 
905 // Breakpoints
906 nub_break_t
907 DNBBreakpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, nub_bool_t hardware)
908 {
909     MachProcessSP procSP;
910     if (GetProcessSP (pid, procSP))
911     {
912         return procSP->CreateBreakpoint(addr, size, hardware, THREAD_NULL);
913     }
914     return INVALID_NUB_BREAK_ID;
915 }
916 
917 nub_bool_t
918 DNBBreakpointClear (nub_process_t pid, nub_break_t breakID)
919 {
920     if (NUB_BREAK_ID_IS_VALID(breakID))
921     {
922         MachProcessSP procSP;
923         if (GetProcessSP (pid, procSP))
924         {
925             return procSP->DisableBreakpoint(breakID, true);
926         }
927     }
928     return false; // Failed
929 }
930 
931 nub_ssize_t
932 DNBBreakpointGetHitCount (nub_process_t pid, nub_break_t breakID)
933 {
934     if (NUB_BREAK_ID_IS_VALID(breakID))
935     {
936         MachProcessSP procSP;
937         if (GetProcessSP (pid, procSP))
938         {
939             DNBBreakpoint *bp = procSP->Breakpoints().FindByID(breakID);
940             if (bp)
941                 return bp->GetHitCount();
942         }
943     }
944     return 0;
945 }
946 
947 nub_ssize_t
948 DNBBreakpointGetIgnoreCount (nub_process_t pid, nub_break_t breakID)
949 {
950     if (NUB_BREAK_ID_IS_VALID(breakID))
951     {
952         MachProcessSP procSP;
953         if (GetProcessSP (pid, procSP))
954         {
955             DNBBreakpoint *bp = procSP->Breakpoints().FindByID(breakID);
956             if (bp)
957                 return bp->GetIgnoreCount();
958         }
959     }
960     return 0;
961 }
962 
963 nub_bool_t
964 DNBBreakpointSetIgnoreCount (nub_process_t pid, nub_break_t breakID, nub_size_t ignore_count)
965 {
966     if (NUB_BREAK_ID_IS_VALID(breakID))
967     {
968         MachProcessSP procSP;
969         if (GetProcessSP (pid, procSP))
970         {
971             DNBBreakpoint *bp = procSP->Breakpoints().FindByID(breakID);
972             if (bp)
973             {
974                 bp->SetIgnoreCount(ignore_count);
975                 return true;
976             }
977         }
978     }
979     return false;
980 }
981 
982 // Set the callback function for a given breakpoint. The callback function will
983 // get called as soon as the breakpoint is hit. The function will be called
984 // with the process ID, thread ID, breakpoint ID and the baton, and can return
985 //
986 nub_bool_t
987 DNBBreakpointSetCallback (nub_process_t pid, nub_break_t breakID, DNBCallbackBreakpointHit callback, void *baton)
988 {
989     if (NUB_BREAK_ID_IS_VALID(breakID))
990     {
991         MachProcessSP procSP;
992         if (GetProcessSP (pid, procSP))
993         {
994             DNBBreakpoint *bp = procSP->Breakpoints().FindByID(breakID);
995             if (bp)
996             {
997                 bp->SetCallback(callback, baton);
998                 return true;
999             }
1000         }
1001     }
1002     return false;
1003 }
1004 
1005 //----------------------------------------------------------------------
1006 // Dump the breakpoints stats for process PID for a breakpoint by ID.
1007 //----------------------------------------------------------------------
1008 void
1009 DNBBreakpointPrint (nub_process_t pid, nub_break_t breakID)
1010 {
1011     MachProcessSP procSP;
1012     if (GetProcessSP (pid, procSP))
1013         procSP->DumpBreakpoint(breakID);
1014 }
1015 
1016 //----------------------------------------------------------------------
1017 // Watchpoints
1018 //----------------------------------------------------------------------
1019 nub_watch_t
1020 DNBWatchpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, uint32_t watch_flags, nub_bool_t hardware)
1021 {
1022     MachProcessSP procSP;
1023     if (GetProcessSP (pid, procSP))
1024     {
1025         return procSP->CreateWatchpoint(addr, size, watch_flags, hardware, THREAD_NULL);
1026     }
1027     return INVALID_NUB_WATCH_ID;
1028 }
1029 
1030 nub_bool_t
1031 DNBWatchpointClear (nub_process_t pid, nub_watch_t watchID)
1032 {
1033     if (NUB_WATCH_ID_IS_VALID(watchID))
1034     {
1035         MachProcessSP procSP;
1036         if (GetProcessSP (pid, procSP))
1037         {
1038             return procSP->DisableWatchpoint(watchID, true);
1039         }
1040     }
1041     return false; // Failed
1042 }
1043 
1044 nub_ssize_t
1045 DNBWatchpointGetHitCount (nub_process_t pid, nub_watch_t watchID)
1046 {
1047     if (NUB_WATCH_ID_IS_VALID(watchID))
1048     {
1049         MachProcessSP procSP;
1050         if (GetProcessSP (pid, procSP))
1051         {
1052             DNBBreakpoint *bp = procSP->Watchpoints().FindByID(watchID);
1053             if (bp)
1054                 return bp->GetHitCount();
1055         }
1056     }
1057     return 0;
1058 }
1059 
1060 nub_ssize_t
1061 DNBWatchpointGetIgnoreCount (nub_process_t pid, nub_watch_t watchID)
1062 {
1063     if (NUB_WATCH_ID_IS_VALID(watchID))
1064     {
1065         MachProcessSP procSP;
1066         if (GetProcessSP (pid, procSP))
1067         {
1068             DNBBreakpoint *bp = procSP->Watchpoints().FindByID(watchID);
1069             if (bp)
1070                 return bp->GetIgnoreCount();
1071         }
1072     }
1073     return 0;
1074 }
1075 
1076 nub_bool_t
1077 DNBWatchpointSetIgnoreCount (nub_process_t pid, nub_watch_t watchID, nub_size_t ignore_count)
1078 {
1079     if (NUB_WATCH_ID_IS_VALID(watchID))
1080     {
1081         MachProcessSP procSP;
1082         if (GetProcessSP (pid, procSP))
1083         {
1084             DNBBreakpoint *bp = procSP->Watchpoints().FindByID(watchID);
1085             if (bp)
1086             {
1087                 bp->SetIgnoreCount(ignore_count);
1088                 return true;
1089             }
1090         }
1091     }
1092     return false;
1093 }
1094 
1095 // Set the callback function for a given watchpoint. The callback function will
1096 // get called as soon as the watchpoint is hit. The function will be called
1097 // with the process ID, thread ID, watchpoint ID and the baton, and can return
1098 //
1099 nub_bool_t
1100 DNBWatchpointSetCallback (nub_process_t pid, nub_watch_t watchID, DNBCallbackBreakpointHit callback, void *baton)
1101 {
1102     if (NUB_WATCH_ID_IS_VALID(watchID))
1103     {
1104         MachProcessSP procSP;
1105         if (GetProcessSP (pid, procSP))
1106         {
1107             DNBBreakpoint *bp = procSP->Watchpoints().FindByID(watchID);
1108             if (bp)
1109             {
1110                 bp->SetCallback(callback, baton);
1111                 return true;
1112             }
1113         }
1114     }
1115     return false;
1116 }
1117 
1118 //----------------------------------------------------------------------
1119 // Dump the watchpoints stats for process PID for a watchpoint by ID.
1120 //----------------------------------------------------------------------
1121 void
1122 DNBWatchpointPrint (nub_process_t pid, nub_watch_t watchID)
1123 {
1124     MachProcessSP procSP;
1125     if (GetProcessSP (pid, procSP))
1126         procSP->DumpWatchpoint(watchID);
1127 }
1128 
1129 //----------------------------------------------------------------------
1130 // Return the number of supported hardware watchpoints.
1131 //----------------------------------------------------------------------
1132 uint32_t
1133 DNBWatchpointGetNumSupportedHWP (nub_process_t pid)
1134 {
1135     MachProcessSP procSP;
1136     if (GetProcessSP (pid, procSP))
1137         return procSP->GetNumSupportedHardwareWatchpoints();
1138     return 0;
1139 }
1140 
1141 //----------------------------------------------------------------------
1142 // Read memory in the address space of process PID. This call will take
1143 // care of setting and restoring permissions and breaking up the memory
1144 // read into multiple chunks as required.
1145 //
1146 // RETURNS: number of bytes actually read
1147 //----------------------------------------------------------------------
1148 nub_size_t
1149 DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub_size_t size, void *buf)
1150 {
1151     MachProcessSP procSP;
1152     if (GetProcessSP (pid, procSP))
1153         return procSP->ReadMemory(addr, size, buf);
1154     return 0;
1155 }
1156 
1157 //----------------------------------------------------------------------
1158 // Write memory to the address space of process PID. This call will take
1159 // care of setting and restoring permissions and breaking up the memory
1160 // write into multiple chunks as required.
1161 //
1162 // RETURNS: number of bytes actually written
1163 //----------------------------------------------------------------------
1164 nub_size_t
1165 DNBProcessMemoryWrite (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf)
1166 {
1167     MachProcessSP procSP;
1168     if (GetProcessSP (pid, procSP))
1169         return procSP->WriteMemory(addr, size, buf);
1170     return 0;
1171 }
1172 
1173 nub_addr_t
1174 DNBProcessMemoryAllocate (nub_process_t pid, nub_size_t size, uint32_t permissions)
1175 {
1176     MachProcessSP procSP;
1177     if (GetProcessSP (pid, procSP))
1178         return procSP->Task().AllocateMemory (size, permissions);
1179     return 0;
1180 }
1181 
1182 nub_bool_t
1183 DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr)
1184 {
1185     MachProcessSP procSP;
1186     if (GetProcessSP (pid, procSP))
1187         return procSP->Task().DeallocateMemory (addr);
1188     return 0;
1189 }
1190 
1191 //----------------------------------------------------------------------
1192 // Find attributes of the memory region that contains ADDR for process PID,
1193 // if possible, and return a string describing those attributes.
1194 //
1195 // Returns 1 if we could find attributes for this region and OUTBUF can
1196 // be sent to the remote debugger.
1197 //
1198 // Returns 0 if we couldn't find the attributes for a region of memory at
1199 // that address and OUTBUF should not be sent.
1200 //
1201 // Returns -1 if this platform cannot look up information about memory regions
1202 // or if we do not yet have a valid launched process.
1203 //
1204 //----------------------------------------------------------------------
1205 int
1206 DNBProcessMemoryRegionInfo (nub_process_t pid, nub_addr_t addr, DNBRegionInfo *region_info)
1207 {
1208     MachProcessSP procSP;
1209     if (GetProcessSP (pid, procSP))
1210         return procSP->Task().GetMemoryRegionInfo (addr, region_info);
1211 
1212     return -1;
1213 }
1214 
1215 
1216 //----------------------------------------------------------------------
1217 // Formatted output that uses memory and registers from process and
1218 // thread in place of arguments.
1219 //----------------------------------------------------------------------
1220 nub_size_t
1221 DNBPrintf (nub_process_t pid, nub_thread_t tid, nub_addr_t base_addr, FILE *file, const char *format)
1222 {
1223     if (file == NULL)
1224         return 0;
1225     enum printf_flags
1226     {
1227         alternate_form          = (1 << 0),
1228         zero_padding            = (1 << 1),
1229         negative_field_width    = (1 << 2),
1230         blank_space             = (1 << 3),
1231         show_sign               = (1 << 4),
1232         show_thousands_separator= (1 << 5),
1233     };
1234 
1235     enum printf_length_modifiers
1236     {
1237         length_mod_h            = (1 << 0),
1238         length_mod_hh           = (1 << 1),
1239         length_mod_l            = (1 << 2),
1240         length_mod_ll           = (1 << 3),
1241         length_mod_L            = (1 << 4),
1242         length_mod_j            = (1 << 5),
1243         length_mod_t            = (1 << 6),
1244         length_mod_z            = (1 << 7),
1245         length_mod_q            = (1 << 8),
1246     };
1247 
1248     nub_addr_t addr = base_addr;
1249     char *end_format = (char*)format + strlen(format);
1250     char *end = NULL;    // For strtoXXXX calls;
1251     std::basic_string<uint8_t> buf;
1252     nub_size_t total_bytes_read = 0;
1253     DNBDataRef data;
1254     const char *f;
1255     for (f = format; *f != '\0' && f < end_format; f++)
1256     {
1257         char ch = *f;
1258         switch (ch)
1259         {
1260         case '%':
1261             {
1262                 f++;    // Skip the '%' character
1263 //                int min_field_width = 0;
1264 //                int precision = 0;
1265                 //uint32_t flags = 0;
1266                 uint32_t length_modifiers = 0;
1267                 uint32_t byte_size = 0;
1268                 uint32_t actual_byte_size = 0;
1269                 bool is_string = false;
1270                 bool is_register = false;
1271                 DNBRegisterValue register_value;
1272                 int64_t    register_offset = 0;
1273                 nub_addr_t register_addr = INVALID_NUB_ADDRESS;
1274 
1275                 // Create the format string to use for this conversion specification
1276                 // so we can remove and mprintf specific flags and formatters.
1277                 std::string fprintf_format("%");
1278 
1279                 // Decode any flags
1280                 switch (*f)
1281                 {
1282                 case '#': fprintf_format += *f++; break; //flags |= alternate_form;          break;
1283                 case '0': fprintf_format += *f++; break; //flags |= zero_padding;            break;
1284                 case '-': fprintf_format += *f++; break; //flags |= negative_field_width;    break;
1285                 case ' ': fprintf_format += *f++; break; //flags |= blank_space;             break;
1286                 case '+': fprintf_format += *f++; break; //flags |= show_sign;               break;
1287                 case ',': fprintf_format += *f++; break; //flags |= show_thousands_separator;break;
1288                 case '{':
1289                 case '[':
1290                     {
1291                         // We have a register name specification that can take two forms:
1292                         // ${regname} or ${regname+offset}
1293                         //        The action is to read the register value and add the signed offset
1294                         //        (if any) and use that as the value to format.
1295                         // $[regname] or $[regname+offset]
1296                         //        The action is to read the register value and add the signed offset
1297                         //        (if any) and use the result as an address to dereference. The size
1298                         //        of what is dereferenced is specified by the actual byte size that
1299                         //        follows the minimum field width and precision (see comments below).
1300                         switch (*f)
1301                         {
1302                         case '{':
1303                         case '[':
1304                             {
1305                                 char open_scope_ch = *f;
1306                                 f++;
1307                                 const char *reg_name = f;
1308                                 size_t reg_name_length = strcspn(f, "+-}]");
1309                                 if (reg_name_length > 0)
1310                                 {
1311                                     std::string register_name(reg_name, reg_name_length);
1312                                     f += reg_name_length;
1313                                     register_offset = strtoll(f, &end, 0);
1314                                     if (f < end)
1315                                         f = end;
1316                                     if ((open_scope_ch == '{' && *f != '}') || (open_scope_ch == '[' && *f != ']'))
1317                                     {
1318                                         fprintf(file, "error: Invalid register format string. Valid formats are %%{regname} or %%{regname+offset}, %%[regname] or %%[regname+offset]\n");
1319                                         return total_bytes_read;
1320                                     }
1321                                     else
1322                                     {
1323                                         f++;
1324                                         if (DNBThreadGetRegisterValueByName(pid, tid, REGISTER_SET_ALL, register_name.c_str(), &register_value))
1325                                         {
1326                                             // Set the address to dereference using the register value plus the offset
1327                                             switch (register_value.info.size)
1328                                             {
1329                                             default:
1330                                             case 0:
1331                                                 fprintf (file, "error: unsupported register size of %u.\n", register_value.info.size);
1332                                                 return total_bytes_read;
1333 
1334                                             case 1:        register_addr = register_value.value.uint8  + register_offset; break;
1335                                             case 2:        register_addr = register_value.value.uint16 + register_offset; break;
1336                                             case 4:        register_addr = register_value.value.uint32 + register_offset; break;
1337                                             case 8:        register_addr = register_value.value.uint64 + register_offset; break;
1338                                             case 16:
1339                                                 if (open_scope_ch == '[')
1340                                                 {
1341                                                     fprintf (file, "error: register size (%u) too large for address.\n", register_value.info.size);
1342                                                     return total_bytes_read;
1343                                                 }
1344                                                 break;
1345                                             }
1346 
1347                                             if (open_scope_ch == '{')
1348                                             {
1349                                                 byte_size = register_value.info.size;
1350                                                 is_register = true;    // value is in a register
1351 
1352                                             }
1353                                             else
1354                                             {
1355                                                 addr = register_addr;    // Use register value and offset as the address
1356                                             }
1357                                         }
1358                                         else
1359                                         {
1360                                             fprintf(file, "error: unable to read register '%s' for process %#.4x and thread %#.4x\n", register_name.c_str(), pid, tid);
1361                                             return total_bytes_read;
1362                                         }
1363                                     }
1364                                 }
1365                             }
1366                             break;
1367 
1368                         default:
1369                             fprintf(file, "error: %%$ must be followed by (regname + n) or [regname + n]\n");
1370                             return total_bytes_read;
1371                         }
1372                     }
1373                     break;
1374                 }
1375 
1376                 // Check for a minimum field width
1377                 if (isdigit(*f))
1378                 {
1379                     //min_field_width = strtoul(f, &end, 10);
1380                     strtoul(f, &end, 10);
1381                     if (end > f)
1382                     {
1383                         fprintf_format.append(f, end - f);
1384                         f = end;
1385                     }
1386                 }
1387 
1388 
1389                 // Check for a precision
1390                 if (*f == '.')
1391                 {
1392                     f++;
1393                     if (isdigit(*f))
1394                     {
1395                         fprintf_format += '.';
1396                         //precision = strtoul(f, &end, 10);
1397                         strtoul(f, &end, 10);
1398                         if (end > f)
1399                         {
1400                             fprintf_format.append(f, end - f);
1401                             f = end;
1402                         }
1403                     }
1404                 }
1405 
1406 
1407                 // mprintf specific: read the optional actual byte size (abs)
1408                 // after the standard minimum field width (mfw) and precision (prec).
1409                 // Standard printf calls you can have "mfw.prec" or ".prec", but
1410                 // mprintf can have "mfw.prec.abs", ".prec.abs" or "..abs". This is nice
1411                 // for strings that may be in a fixed size buffer, but may not use all bytes
1412                 // in that buffer for printable characters.
1413                 if (*f == '.')
1414                 {
1415                     f++;
1416                     actual_byte_size = strtoul(f, &end, 10);
1417                     if (end > f)
1418                     {
1419                         byte_size = actual_byte_size;
1420                         f = end;
1421                     }
1422                 }
1423 
1424                 // Decode the length modifiers
1425                 switch (*f)
1426                 {
1427                 case 'h':    // h and hh length modifiers
1428                     fprintf_format += *f++;
1429                     length_modifiers |= length_mod_h;
1430                     if (*f == 'h')
1431                     {
1432                         fprintf_format += *f++;
1433                         length_modifiers |= length_mod_hh;
1434                     }
1435                     break;
1436 
1437                 case 'l': // l and ll length modifiers
1438                     fprintf_format += *f++;
1439                     length_modifiers |= length_mod_l;
1440                     if (*f == 'h')
1441                     {
1442                         fprintf_format += *f++;
1443                         length_modifiers |= length_mod_ll;
1444                     }
1445                     break;
1446 
1447                 case 'L':    fprintf_format += *f++;    length_modifiers |= length_mod_L;    break;
1448                 case 'j':    fprintf_format += *f++;    length_modifiers |= length_mod_j;    break;
1449                 case 't':    fprintf_format += *f++;    length_modifiers |= length_mod_t;    break;
1450                 case 'z':    fprintf_format += *f++;    length_modifiers |= length_mod_z;    break;
1451                 case 'q':    fprintf_format += *f++;    length_modifiers |= length_mod_q;    break;
1452                 }
1453 
1454                 // Decode the conversion specifier
1455                 switch (*f)
1456                 {
1457                 case '_':
1458                     // mprintf specific format items
1459                     {
1460                         ++f;    // Skip the '_' character
1461                         switch (*f)
1462                         {
1463                         case 'a':    // Print the current address
1464                             ++f;
1465                             fprintf_format += "ll";
1466                             fprintf_format += *f;    // actual format to show address with folows the 'a' ("%_ax")
1467                             fprintf (file, fprintf_format.c_str(), addr);
1468                             break;
1469                         case 'o':    // offset from base address
1470                             ++f;
1471                             fprintf_format += "ll";
1472                             fprintf_format += *f;    // actual format to show address with folows the 'a' ("%_ox")
1473                             fprintf(file, fprintf_format.c_str(), addr - base_addr);
1474                             break;
1475                         default:
1476                             fprintf (file, "error: unsupported mprintf specific format character '%c'.\n", *f);
1477                             break;
1478                         }
1479                         continue;
1480                     }
1481                     break;
1482 
1483                 case 'D':
1484                 case 'O':
1485                 case 'U':
1486                     fprintf_format += *f;
1487                     if (byte_size == 0)
1488                         byte_size = sizeof(long int);
1489                     break;
1490 
1491                 case 'd':
1492                 case 'i':
1493                 case 'o':
1494                 case 'u':
1495                 case 'x':
1496                 case 'X':
1497                     fprintf_format += *f;
1498                     if (byte_size == 0)
1499                     {
1500                         if (length_modifiers & length_mod_hh)
1501                             byte_size = sizeof(char);
1502                         else if (length_modifiers & length_mod_h)
1503                             byte_size = sizeof(short);
1504                         else if (length_modifiers & length_mod_ll)
1505                             byte_size = sizeof(long long);
1506                         else if (length_modifiers & length_mod_l)
1507                             byte_size = sizeof(long);
1508                         else
1509                             byte_size = sizeof(int);
1510                     }
1511                     break;
1512 
1513                 case 'a':
1514                 case 'A':
1515                 case 'f':
1516                 case 'F':
1517                 case 'e':
1518                 case 'E':
1519                 case 'g':
1520                 case 'G':
1521                     fprintf_format += *f;
1522                     if (byte_size == 0)
1523                     {
1524                         if (length_modifiers & length_mod_L)
1525                             byte_size = sizeof(long double);
1526                         else
1527                             byte_size = sizeof(double);
1528                     }
1529                     break;
1530 
1531                 case 'c':
1532                     if ((length_modifiers & length_mod_l) == 0)
1533                     {
1534                         fprintf_format += *f;
1535                         if (byte_size == 0)
1536                             byte_size = sizeof(char);
1537                         break;
1538                     }
1539                     // Fall through to 'C' modifier below...
1540 
1541                 case 'C':
1542                     fprintf_format += *f;
1543                     if (byte_size == 0)
1544                         byte_size = sizeof(wchar_t);
1545                     break;
1546 
1547                 case 's':
1548                     fprintf_format += *f;
1549                     if (is_register || byte_size == 0)
1550                         is_string = 1;
1551                     break;
1552 
1553                 case 'p':
1554                     fprintf_format += *f;
1555                     if (byte_size == 0)
1556                         byte_size = sizeof(void*);
1557                     break;
1558                 }
1559 
1560                 if (is_string)
1561                 {
1562                     std::string mem_string;
1563                     const size_t string_buf_len = 4;
1564                     char string_buf[string_buf_len+1];
1565                     char *string_buf_end = string_buf + string_buf_len;
1566                     string_buf[string_buf_len] = '\0';
1567                     nub_size_t bytes_read;
1568                     nub_addr_t str_addr = is_register ? register_addr : addr;
1569                     while ((bytes_read = DNBProcessMemoryRead(pid, str_addr, string_buf_len, &string_buf[0])) > 0)
1570                     {
1571                         // Did we get a NULL termination character yet?
1572                         if (strchr(string_buf, '\0') == string_buf_end)
1573                         {
1574                             // no NULL terminator yet, append as a std::string
1575                             mem_string.append(string_buf, string_buf_len);
1576                             str_addr += string_buf_len;
1577                         }
1578                         else
1579                         {
1580                             // yep
1581                             break;
1582                         }
1583                     }
1584                     // Append as a C-string so we don't get the extra NULL
1585                     // characters in the temp buffer (since it was resized)
1586                     mem_string += string_buf;
1587                     size_t mem_string_len = mem_string.size() + 1;
1588                     fprintf(file, fprintf_format.c_str(), mem_string.c_str());
1589                     if (mem_string_len > 0)
1590                     {
1591                         if (!is_register)
1592                         {
1593                             addr += mem_string_len;
1594                             total_bytes_read += mem_string_len;
1595                         }
1596                     }
1597                     else
1598                         return total_bytes_read;
1599                 }
1600                 else
1601                 if (byte_size > 0)
1602                 {
1603                     buf.resize(byte_size);
1604                     nub_size_t bytes_read = 0;
1605                     if (is_register)
1606                         bytes_read = register_value.info.size;
1607                     else
1608                         bytes_read = DNBProcessMemoryRead(pid, addr, buf.size(), &buf[0]);
1609                     if (bytes_read > 0)
1610                     {
1611                         if (!is_register)
1612                             total_bytes_read += bytes_read;
1613 
1614                         if (bytes_read == byte_size)
1615                         {
1616                             switch (*f)
1617                             {
1618                             case 'd':
1619                             case 'i':
1620                             case 'o':
1621                             case 'u':
1622                             case 'X':
1623                             case 'x':
1624                             case 'a':
1625                             case 'A':
1626                             case 'f':
1627                             case 'F':
1628                             case 'e':
1629                             case 'E':
1630                             case 'g':
1631                             case 'G':
1632                             case 'p':
1633                             case 'c':
1634                             case 'C':
1635                                 {
1636                                     if (is_register)
1637                                         data.SetData(&register_value.value.v_uint8[0], register_value.info.size);
1638                                     else
1639                                         data.SetData(&buf[0], bytes_read);
1640                                     DNBDataRef::offset_t data_offset = 0;
1641                                     if (byte_size <= 4)
1642                                     {
1643                                         uint32_t u32 = data.GetMax32(&data_offset, byte_size);
1644                                         // Show the actual byte width when displaying hex
1645                                         fprintf(file, fprintf_format.c_str(), u32);
1646                                     }
1647                                     else if (byte_size <= 8)
1648                                     {
1649                                         uint64_t u64 = data.GetMax64(&data_offset, byte_size);
1650                                         // Show the actual byte width when displaying hex
1651                                         fprintf(file, fprintf_format.c_str(), u64);
1652                                     }
1653                                     else
1654                                     {
1655                                         fprintf(file, "error: integer size not supported, must be 8 bytes or less (%u bytes).\n", byte_size);
1656                                     }
1657                                     if (!is_register)
1658                                         addr += byte_size;
1659                                 }
1660                                 break;
1661 
1662                             case 's':
1663                                 fprintf(file, fprintf_format.c_str(), buf.c_str());
1664                                 addr += byte_size;
1665                                 break;
1666 
1667                             default:
1668                                 fprintf(file, "error: unsupported conversion specifier '%c'.\n", *f);
1669                                 break;
1670                             }
1671                         }
1672                     }
1673                 }
1674                 else
1675                     return total_bytes_read;
1676             }
1677             break;
1678 
1679         case '\\':
1680             {
1681                 f++;
1682                 switch (*f)
1683                 {
1684                 case 'e': ch = '\e'; break;
1685                 case 'a': ch = '\a'; break;
1686                 case 'b': ch = '\b'; break;
1687                 case 'f': ch = '\f'; break;
1688                 case 'n': ch = '\n'; break;
1689                 case 'r': ch = '\r'; break;
1690                 case 't': ch = '\t'; break;
1691                 case 'v': ch = '\v'; break;
1692                 case '\'': ch = '\''; break;
1693                 case '\\': ch = '\\'; break;
1694                 case '0':
1695                 case '1':
1696                 case '2':
1697                 case '3':
1698                 case '4':
1699                 case '5':
1700                 case '6':
1701                 case '7':
1702                     ch = strtoul(f, &end, 8);
1703                     f = end;
1704                     break;
1705                 default:
1706                     ch = *f;
1707                     break;
1708                 }
1709                 fputc(ch, file);
1710             }
1711             break;
1712 
1713         default:
1714             fputc(ch, file);
1715             break;
1716         }
1717     }
1718     return total_bytes_read;
1719 }
1720 
1721 
1722 //----------------------------------------------------------------------
1723 // Get the number of threads for the specified process.
1724 //----------------------------------------------------------------------
1725 nub_size_t
1726 DNBProcessGetNumThreads (nub_process_t pid)
1727 {
1728     MachProcessSP procSP;
1729     if (GetProcessSP (pid, procSP))
1730         return procSP->GetNumThreads();
1731     return 0;
1732 }
1733 
1734 //----------------------------------------------------------------------
1735 // Get the thread ID of the current thread.
1736 //----------------------------------------------------------------------
1737 nub_thread_t
1738 DNBProcessGetCurrentThread (nub_process_t pid)
1739 {
1740     MachProcessSP procSP;
1741     if (GetProcessSP (pid, procSP))
1742         return procSP->GetCurrentThread();
1743     return 0;
1744 }
1745 
1746 //----------------------------------------------------------------------
1747 // Change the current thread.
1748 //----------------------------------------------------------------------
1749 nub_thread_t
1750 DNBProcessSetCurrentThread (nub_process_t pid, nub_thread_t tid)
1751 {
1752     MachProcessSP procSP;
1753     if (GetProcessSP (pid, procSP))
1754         return procSP->SetCurrentThread (tid);
1755     return INVALID_NUB_THREAD;
1756 }
1757 
1758 
1759 //----------------------------------------------------------------------
1760 // Dump a string describing a thread's stop reason to the specified file
1761 // handle
1762 //----------------------------------------------------------------------
1763 nub_bool_t
1764 DNBThreadGetStopReason (nub_process_t pid, nub_thread_t tid, struct DNBThreadStopInfo *stop_info)
1765 {
1766     MachProcessSP procSP;
1767     if (GetProcessSP (pid, procSP))
1768         return procSP->GetThreadStoppedReason (tid, stop_info);
1769     return false;
1770 }
1771 
1772 //----------------------------------------------------------------------
1773 // Return string description for the specified thread.
1774 //
1775 // RETURNS: NULL if the thread isn't valid, else a NULL terminated C
1776 // string from a static buffer that must be copied prior to subsequent
1777 // calls.
1778 //----------------------------------------------------------------------
1779 const char *
1780 DNBThreadGetInfo (nub_process_t pid, nub_thread_t tid)
1781 {
1782     MachProcessSP procSP;
1783     if (GetProcessSP (pid, procSP))
1784         return procSP->GetThreadInfo (tid);
1785     return NULL;
1786 }
1787 
1788 //----------------------------------------------------------------------
1789 // Get the thread ID given a thread index.
1790 //----------------------------------------------------------------------
1791 nub_thread_t
1792 DNBProcessGetThreadAtIndex (nub_process_t pid, size_t thread_idx)
1793 {
1794     MachProcessSP procSP;
1795     if (GetProcessSP (pid, procSP))
1796         return procSP->GetThreadAtIndex (thread_idx);
1797     return INVALID_NUB_THREAD;
1798 }
1799 
1800 //----------------------------------------------------------------------
1801 // Do whatever is needed to sync the thread's register state with it's kernel values.
1802 //----------------------------------------------------------------------
1803 nub_bool_t
1804 DNBProcessSyncThreadState (nub_process_t pid, nub_thread_t tid)
1805 {
1806     MachProcessSP procSP;
1807     if (GetProcessSP (pid, procSP))
1808         return procSP->SyncThreadState (tid);
1809     return false;
1810 
1811 }
1812 
1813 nub_addr_t
1814 DNBProcessGetSharedLibraryInfoAddress (nub_process_t pid)
1815 {
1816     MachProcessSP procSP;
1817     DNBError err;
1818     if (GetProcessSP (pid, procSP))
1819         return procSP->Task().GetDYLDAllImageInfosAddress (err);
1820     return INVALID_NUB_ADDRESS;
1821 }
1822 
1823 
1824 nub_bool_t
1825 DNBProcessSharedLibrariesUpdated(nub_process_t pid)
1826 {
1827     MachProcessSP procSP;
1828     if (GetProcessSP (pid, procSP))
1829     {
1830         procSP->SharedLibrariesUpdated ();
1831         return true;
1832     }
1833     return false;
1834 }
1835 
1836 //----------------------------------------------------------------------
1837 // Get the current shared library information for a process. Only return
1838 // the shared libraries that have changed since the last shared library
1839 // state changed event if only_changed is non-zero.
1840 //----------------------------------------------------------------------
1841 nub_size_t
1842 DNBProcessGetSharedLibraryInfo (nub_process_t pid, nub_bool_t only_changed, struct DNBExecutableImageInfo **image_infos)
1843 {
1844     MachProcessSP procSP;
1845     if (GetProcessSP (pid, procSP))
1846         return procSP->CopyImageInfos (image_infos, only_changed);
1847 
1848     // If we have no process, then return NULL for the shared library info
1849     // and zero for shared library count
1850     *image_infos = NULL;
1851     return 0;
1852 }
1853 
1854 //----------------------------------------------------------------------
1855 // Get the register set information for a specific thread.
1856 //----------------------------------------------------------------------
1857 const DNBRegisterSetInfo *
1858 DNBGetRegisterSetInfo (nub_size_t *num_reg_sets)
1859 {
1860     return DNBArchProtocol::GetRegisterSetInfo (num_reg_sets);
1861 }
1862 
1863 
1864 //----------------------------------------------------------------------
1865 // Read a register value by register set and register index.
1866 //----------------------------------------------------------------------
1867 nub_bool_t
1868 DNBThreadGetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *value)
1869 {
1870     MachProcessSP procSP;
1871     ::bzero (value, sizeof(DNBRegisterValue));
1872     if (GetProcessSP (pid, procSP))
1873     {
1874         if (tid != INVALID_NUB_THREAD)
1875             return procSP->GetRegisterValue (tid, set, reg, value);
1876     }
1877     return false;
1878 }
1879 
1880 nub_bool_t
1881 DNBThreadSetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value)
1882 {
1883     if (tid != INVALID_NUB_THREAD)
1884     {
1885         MachProcessSP procSP;
1886         if (GetProcessSP (pid, procSP))
1887             return procSP->SetRegisterValue (tid, set, reg, value);
1888     }
1889     return false;
1890 }
1891 
1892 nub_size_t
1893 DNBThreadGetRegisterContext (nub_process_t pid, nub_thread_t tid, void *buf, size_t buf_len)
1894 {
1895     MachProcessSP procSP;
1896     if (GetProcessSP (pid, procSP))
1897     {
1898         if (tid != INVALID_NUB_THREAD)
1899             return procSP->GetThreadList().GetRegisterContext (tid, buf, buf_len);
1900     }
1901     ::bzero (buf, buf_len);
1902     return 0;
1903 
1904 }
1905 
1906 nub_size_t
1907 DNBThreadSetRegisterContext (nub_process_t pid, nub_thread_t tid, const void *buf, size_t buf_len)
1908 {
1909     MachProcessSP procSP;
1910     if (GetProcessSP (pid, procSP))
1911     {
1912         if (tid != INVALID_NUB_THREAD)
1913             return procSP->GetThreadList().SetRegisterContext (tid, buf, buf_len);
1914     }
1915     return 0;
1916 }
1917 
1918 //----------------------------------------------------------------------
1919 // Read a register value by name.
1920 //----------------------------------------------------------------------
1921 nub_bool_t
1922 DNBThreadGetRegisterValueByName (nub_process_t pid, nub_thread_t tid, uint32_t reg_set, const char *reg_name, DNBRegisterValue *value)
1923 {
1924     MachProcessSP procSP;
1925     ::bzero (value, sizeof(DNBRegisterValue));
1926     if (GetProcessSP (pid, procSP))
1927     {
1928         const struct DNBRegisterSetInfo *set_info;
1929         nub_size_t num_reg_sets = 0;
1930         set_info = DNBGetRegisterSetInfo (&num_reg_sets);
1931         if (set_info)
1932         {
1933             uint32_t set = reg_set;
1934             uint32_t reg;
1935             if (set == REGISTER_SET_ALL)
1936             {
1937                 for (set = 1; set < num_reg_sets; ++set)
1938                 {
1939                     for (reg = 0; reg < set_info[set].num_registers; ++reg)
1940                     {
1941                         if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
1942                             return procSP->GetRegisterValue (tid, set, reg, value);
1943                     }
1944                 }
1945             }
1946             else
1947             {
1948                 for (reg = 0; reg < set_info[set].num_registers; ++reg)
1949                 {
1950                     if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
1951                         return procSP->GetRegisterValue (tid, set, reg, value);
1952                 }
1953             }
1954         }
1955     }
1956     return false;
1957 }
1958 
1959 
1960 //----------------------------------------------------------------------
1961 // Read a register set and register number from the register name.
1962 //----------------------------------------------------------------------
1963 nub_bool_t
1964 DNBGetRegisterInfoByName (const char *reg_name, DNBRegisterInfo* info)
1965 {
1966     const struct DNBRegisterSetInfo *set_info;
1967     nub_size_t num_reg_sets = 0;
1968     set_info = DNBGetRegisterSetInfo (&num_reg_sets);
1969     if (set_info)
1970     {
1971         uint32_t set, reg;
1972         for (set = 1; set < num_reg_sets; ++set)
1973         {
1974             for (reg = 0; reg < set_info[set].num_registers; ++reg)
1975             {
1976                 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
1977                 {
1978                     *info = set_info[set].registers[reg];
1979                     return true;
1980                 }
1981             }
1982         }
1983 
1984         for (set = 1; set < num_reg_sets; ++set)
1985         {
1986             uint32_t reg;
1987             for (reg = 0; reg < set_info[set].num_registers; ++reg)
1988             {
1989                 if (set_info[set].registers[reg].alt == NULL)
1990                     continue;
1991 
1992                 if (strcasecmp(reg_name, set_info[set].registers[reg].alt) == 0)
1993                 {
1994                     *info = set_info[set].registers[reg];
1995                     return true;
1996                 }
1997             }
1998         }
1999     }
2000 
2001     ::bzero (info, sizeof(DNBRegisterInfo));
2002     return false;
2003 }
2004 
2005 
2006 //----------------------------------------------------------------------
2007 // Set the name to address callback function that this nub can use
2008 // for any name to address lookups that are needed.
2009 //----------------------------------------------------------------------
2010 nub_bool_t
2011 DNBProcessSetNameToAddressCallback (nub_process_t pid, DNBCallbackNameToAddress callback, void *baton)
2012 {
2013     MachProcessSP procSP;
2014     if (GetProcessSP (pid, procSP))
2015     {
2016         procSP->SetNameToAddressCallback (callback, baton);
2017         return true;
2018     }
2019     return false;
2020 }
2021 
2022 
2023 //----------------------------------------------------------------------
2024 // Set the name to address callback function that this nub can use
2025 // for any name to address lookups that are needed.
2026 //----------------------------------------------------------------------
2027 nub_bool_t
2028 DNBProcessSetSharedLibraryInfoCallback (nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, void  *baton)
2029 {
2030     MachProcessSP procSP;
2031     if (GetProcessSP (pid, procSP))
2032     {
2033         procSP->SetSharedLibraryInfoCallback (callback, baton);
2034         return true;
2035     }
2036     return false;
2037 }
2038 
2039 nub_addr_t
2040 DNBProcessLookupAddress (nub_process_t pid, const char *name, const char *shlib)
2041 {
2042     MachProcessSP procSP;
2043     if (GetProcessSP (pid, procSP))
2044     {
2045         return procSP->LookupSymbol (name, shlib);
2046     }
2047     return INVALID_NUB_ADDRESS;
2048 }
2049 
2050 
2051 nub_size_t
2052 DNBProcessGetAvailableSTDOUT (nub_process_t pid, char *buf, nub_size_t buf_size)
2053 {
2054     MachProcessSP procSP;
2055     if (GetProcessSP (pid, procSP))
2056         return procSP->GetAvailableSTDOUT (buf, buf_size);
2057     return 0;
2058 }
2059 
2060 nub_size_t
2061 DNBProcessGetAvailableSTDERR (nub_process_t pid, char *buf, nub_size_t buf_size)
2062 {
2063     MachProcessSP procSP;
2064     if (GetProcessSP (pid, procSP))
2065         return procSP->GetAvailableSTDERR (buf, buf_size);
2066     return 0;
2067 }
2068 
2069 nub_size_t
2070 DNBProcessGetStopCount (nub_process_t pid)
2071 {
2072     MachProcessSP procSP;
2073     if (GetProcessSP (pid, procSP))
2074         return procSP->StopCount();
2075     return 0;
2076 }
2077 
2078 uint32_t
2079 DNBProcessGetCPUType (nub_process_t pid)
2080 {
2081     MachProcessSP procSP;
2082     if (GetProcessSP (pid, procSP))
2083         return procSP->GetCPUType ();
2084     return 0;
2085 
2086 }
2087 
2088 nub_bool_t
2089 DNBResolveExecutablePath (const char *path, char *resolved_path, size_t resolved_path_size)
2090 {
2091     if (path == NULL || path[0] == '\0')
2092         return false;
2093 
2094     char max_path[PATH_MAX];
2095     std::string result;
2096     CFString::GlobPath(path, result);
2097 
2098     if (result.empty())
2099         result = path;
2100 
2101     if (realpath(path, max_path))
2102     {
2103         // Found the path relatively...
2104         ::strncpy(resolved_path, max_path, resolved_path_size);
2105         return strlen(resolved_path) + 1 < resolved_path_size;
2106     }
2107     else
2108     {
2109         // Not a relative path, check the PATH environment variable if the
2110         const char *PATH = getenv("PATH");
2111         if (PATH)
2112         {
2113             const char *curr_path_start = PATH;
2114             const char *curr_path_end;
2115             while (curr_path_start && *curr_path_start)
2116             {
2117                 curr_path_end = strchr(curr_path_start, ':');
2118                 if (curr_path_end == NULL)
2119                 {
2120                     result.assign(curr_path_start);
2121                     curr_path_start = NULL;
2122                 }
2123                 else if (curr_path_end > curr_path_start)
2124                 {
2125                     size_t len = curr_path_end - curr_path_start;
2126                     result.assign(curr_path_start, len);
2127                     curr_path_start += len + 1;
2128                 }
2129                 else
2130                     break;
2131 
2132                 result += '/';
2133                 result += path;
2134                 struct stat s;
2135                 if (stat(result.c_str(), &s) == 0)
2136                 {
2137                     ::strncpy(resolved_path, result.c_str(), resolved_path_size);
2138                     return result.size() + 1 < resolved_path_size;
2139                 }
2140             }
2141         }
2142     }
2143     return false;
2144 }
2145 
2146 
2147 void
2148 DNBInitialize()
2149 {
2150     DNBLogThreadedIf (LOG_PROCESS, "DNBInitialize ()");
2151 #if defined (__i386__) || defined (__x86_64__)
2152     DNBArchImplI386::Initialize();
2153     DNBArchImplX86_64::Initialize();
2154 #elif defined (__arm__)
2155     DNBArchMachARM::Initialize();
2156 #endif
2157 }
2158 
2159 void
2160 DNBTerminate()
2161 {
2162 }
2163 
2164 nub_bool_t
2165 DNBSetArchitecture (const char *arch)
2166 {
2167     if (arch && arch[0])
2168     {
2169         if (strcasecmp (arch, "i386") == 0)
2170             return DNBArchProtocol::SetArchitecture (CPU_TYPE_I386);
2171         else if (strcasecmp (arch, "x86_64") == 0)
2172             return DNBArchProtocol::SetArchitecture (CPU_TYPE_X86_64);
2173         else if (strstr (arch, "arm") == arch)
2174             return DNBArchProtocol::SetArchitecture (CPU_TYPE_ARM);
2175     }
2176     return false;
2177 }
2178