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