[Lldb-commits] Remove the use of mkstemp, as it's not portable

Zachary Turner zturner at google.com
Thu Jul 31 13:45:45 PDT 2014


mkstemp doesn't exist on Windows.  LLVM already has a support function
which is the same in spirit as mkstemp.  This patch adds a method to the
host layer to create a temporary file, and the implementation of this
method on the private side delegates to the corresponding LLVM support
function.

This fixes the build on Windows and should have identical semantics on
other platforms, but please verify.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20140731/cf978668/attachment.html>
-------------- next part --------------
diff --git a/include/lldb/API/SBHostOS.h b/include/lldb/API/SBHostOS.h
index 7ab22ca..0239d11 100644
--- a/include/lldb/API/SBHostOS.h
+++ b/include/lldb/API/SBHostOS.h
@@ -1,60 +1,65 @@
 //===-- SBHostOS.h ----------------------------------------------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 
 #ifndef LLDB_SBHostOS_h_
 #define LLDB_SBHostOS_h_
 
 #include "lldb/API/SBDefines.h"
 #include "lldb/API/SBFileSpec.h"
 
 namespace lldb {
 
 class SBHostOS
 {
 public:
 
     static lldb::SBFileSpec
     GetProgramFileSpec ();
     
     static lldb::SBFileSpec
     GetLLDBPythonPath ();
 
     static lldb::SBFileSpec
     GetLLDBPath (lldb::PathType path_type);
 
     static void
     ThreadCreated (const char *name);
 
+    static int
+    CreateTemporaryFile (const char *directory,
+                         const char *pathTemplate,
+                         lldb::SBFileSpec &result);
+
     static lldb::thread_t
     ThreadCreate (const char *name,
                   lldb::thread_func_t thread_function,
                   void *thread_arg,
                   lldb::SBError *err);
 
     static bool
     ThreadCancel (lldb::thread_t thread,
                   lldb::SBError *err);
 
     static bool
     ThreadDetach (lldb::thread_t thread,
                   lldb::SBError *err);
     static bool
     ThreadJoin (lldb::thread_t thread,
                 lldb::thread_result_t *result,
                 lldb::SBError *err);
 
 
 private:
 
 };
 
 
 } // namespace lldb
 
 #endif // LLDB_SBHostOS_h_
diff --git a/include/lldb/Host/Host.h b/include/lldb/Host/Host.h
index aa934d9..e3be3b5 100644
--- a/include/lldb/Host/Host.h
+++ b/include/lldb/Host/Host.h
@@ -1,618 +1,646 @@
 //===-- Host.h --------------------------------------------------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 
 #ifndef liblldb_Host_h_
 #define liblldb_Host_h_
 #if defined(__cplusplus)
 
 #include <stdarg.h>
 
 #include <map>
 #include <string>
 
 #include "lldb/lldb-private.h"
 #include "lldb/Core/StringList.h"
 #include "lldb/Host/File.h"
 #include "lldb/Host/FileSpec.h"
 
 namespace lldb_private {
 
 //----------------------------------------------------------------------
 /// @class Host Host.h "lldb/Host/Host.h"
 /// @brief A class that provides host computer information.
 ///
 /// Host is a class that answers information about the host operating
 /// system.
 //----------------------------------------------------------------------
 class Host
 {
 public:
 
     /// A value of std::numeric_limits<uint32_t>::max() is used if there is no practical limit.
     static const uint32_t MAX_THREAD_NAME_LENGTH;
 
     typedef bool (*MonitorChildProcessCallback) (void *callback_baton,
                                                  lldb::pid_t pid,
                                                  bool exited,
                                                  int signal,    // Zero for no signal
                                                  int status);   // Exit value of process if signal is zero
 
     //------------------------------------------------------------------
     /// Start monitoring a child process.
     ///
     /// Allows easy monitoring of child processes. \a callback will be
     /// called when the child process exits or if it gets a signal. The
     /// callback will only be called with signals if \a monitor_signals
     /// is \b true. \a callback will usually be called from another
     /// thread so the callback function must be thread safe.
     ///
     /// When the callback gets called, the return value indicates if
     /// monitoring should stop. If \b true is returned from \a callback
     /// the information will be removed. If \b false is returned then
     /// monitoring will continue. If the child process exits, the
     /// monitoring will automatically stop after the callback returned
     /// regardless of the callback return value.
     ///
     /// @param[in] callback
     ///     A function callback to call when a child receives a signal
     ///     (if \a monitor_signals is true) or a child exits.
     ///
     /// @param[in] callback_baton
     ///     A void * of user data that will be pass back when
     ///     \a callback is called.
     ///
     /// @param[in] pid
     ///     The process ID of a child process to monitor, -1 for all
     ///     processes.
     ///
     /// @param[in] monitor_signals
     ///     If \b true the callback will get called when the child
     ///     process gets a signal. If \b false, the callback will only
     ///     get called if the child process exits.
     ///
     /// @return
     ///     A thread handle that can be used to cancel the thread that
     ///     was spawned to monitor \a pid.
     ///
     /// @see static void Host::StopMonitoringChildProcess (uint32_t)
     //------------------------------------------------------------------
     static lldb::thread_t
     StartMonitoringChildProcess (MonitorChildProcessCallback callback,
                                  void *callback_baton,
                                  lldb::pid_t pid,
                                  bool monitor_signals);
 
     //------------------------------------------------------------------
     /// Get the host page size.
     ///
     /// @return
     ///     The size in bytes of a VM page on the host system.
     //------------------------------------------------------------------
     static size_t
     GetPageSize();
 
     //------------------------------------------------------------------
     /// Returns the endianness of the host system.
     ///
     /// @return
     ///     Returns the endianness of the host system as a lldb::ByteOrder
     ///     enumeration.
     //------------------------------------------------------------------
     static lldb::ByteOrder
     GetByteOrder ();
 
     //------------------------------------------------------------------
     /// Returns the number of CPUs on this current host.
     ///
     /// @return
     ///     Number of CPUs on this current host, or zero if the number
     ///     of CPUs can't be determined on this host.
     //------------------------------------------------------------------
     static uint32_t
     GetNumberCPUS ();
 
     static bool
     GetOSVersion (uint32_t &major, 
                   uint32_t &minor, 
                   uint32_t &update);
 
     static bool
     GetOSBuildString (std::string &s);
     
     static bool
     GetOSKernelDescription (std::string &s);
 
     static bool
     GetHostname (std::string &s);
 
     static const char *
     GetUserName (uint32_t uid, std::string &user_name);
     
     static const char *
     GetGroupName (uint32_t gid, std::string &group_name);
     
     static uint32_t
     GetUserID ();
     
     static uint32_t
     GetGroupID ();
 
     static uint32_t
     GetEffectiveUserID ();
 
     static uint32_t
     GetEffectiveGroupID ();
 
 
     enum SystemLogType
     {
         eSystemLogWarning,
         eSystemLogError
     };
 
     static void
     SystemLog (SystemLogType type, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
 
     static void
     SystemLog (SystemLogType type, const char *format, va_list args);
 
     //------------------------------------------------------------------
     /// Gets the host architecture.
     ///
     /// @return
     ///     A const architecture object that represents the host
     ///     architecture.
     //------------------------------------------------------------------
     enum SystemDefaultArchitecture
     {
         eSystemDefaultArchitecture,     // The overall default architecture that applications will run on this host
         eSystemDefaultArchitecture32,   // If this host supports 32 bit programs, return the default 32 bit arch
         eSystemDefaultArchitecture64    // If this host supports 64 bit programs, return the default 64 bit arch
     };
 
     static const ArchSpec &
     GetArchitecture (SystemDefaultArchitecture arch_kind = eSystemDefaultArchitecture);
 
     //------------------------------------------------------------------
     /// Gets the host vendor string.
     ///
     /// @return
     ///     A const string object containing the host vendor name.
     //------------------------------------------------------------------
     static const ConstString &
     GetVendorString ();
 
     //------------------------------------------------------------------
     /// Gets the host Operating System (OS) string.
     ///
     /// @return
     ///     A const string object containing the host OS name.
     //------------------------------------------------------------------
     static const ConstString &
     GetOSString ();
 
     //------------------------------------------------------------------
     /// Gets the host target triple as a const string.
     ///
     /// @return
     ///     A const string object containing the host target triple.
     //------------------------------------------------------------------
     static const ConstString &
     GetTargetTriple ();
 
     //------------------------------------------------------------------
     /// Gets the name of the distribution (i.e. distributor id).
     ///
     /// On Linux, this will return the equivalent of lsb_release -i.
     /// Android will return 'android'.  Other systems may return
     /// nothing.
     ///
     /// @return
     ///     A ConstString reference containing the OS distribution id.
     ///     The return string will be all lower case, with whitespace
     ///     replaced with underscores.  The return string will be
     ///     empty (result.AsCString() will return NULL) if the distribution
     ///     cannot be obtained.
     //------------------------------------------------------------------
     static const ConstString &
     GetDistributionId ();
 
     //------------------------------------------------------------------
     /// Get the process ID for the calling process.
     ///
     /// @return
     ///     The process ID for the current process.
     //------------------------------------------------------------------
     static lldb::pid_t
     GetCurrentProcessID ();
 
     static void
     Kill(lldb::pid_t pid, int signo);
 
     //------------------------------------------------------------------
     /// Get the thread ID for the calling thread in the current process.
     ///
     /// @return
     ///     The thread ID for the calling thread in the current process.
     //------------------------------------------------------------------
     static lldb::tid_t
     GetCurrentThreadID ();
 
     //------------------------------------------------------------------
     /// Get the thread token (the one returned by ThreadCreate when the thread was created) for the
     /// calling thread in the current process.
     ///
     /// @return
     ///     The thread token for the calling thread in the current process.
     //------------------------------------------------------------------
     static lldb::thread_t
     GetCurrentThread ();
 
     static const char *
     GetSignalAsCString (int signo);
 
     static void
     WillTerminate ();
     //------------------------------------------------------------------
     /// Host specific thread created function call.
     ///
     /// This function call lets the current host OS do any thread
     /// specific initialization that it needs, including naming the
     /// thread. No cleanup routine is expected to be called
     ///
     /// @param[in] name
     ///     The current thread's name in the current process.
     //------------------------------------------------------------------
     static void
     ThreadCreated (const char *name);
 
     static lldb::thread_t
     ThreadCreate (const char *name,
                   lldb::thread_func_t function,
                   lldb::thread_arg_t thread_arg,
                   Error *err);
 
     static bool
     ThreadCancel (lldb::thread_t thread,
                   Error *error);
 
     static bool
     ThreadDetach (lldb::thread_t thread,
                   Error *error);
     static bool
     ThreadJoin (lldb::thread_t thread,
                 lldb::thread_result_t *thread_result_ptr,
                 Error *error);
 
     typedef void (*ThreadLocalStorageCleanupCallback) (void *p);
 
     static lldb::thread_key_t
     ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback);
 
     static void*
     ThreadLocalStorageGet(lldb::thread_key_t key);
 
     static void
     ThreadLocalStorageSet(lldb::thread_key_t key, void *value);
 
     //------------------------------------------------------------------
     /// Gets the name of a thread in a process.
     ///
     /// This function will name a thread in a process using it's own
     /// thread name pool, and also will attempt to set a thread name
     /// using any supported host OS APIs.
     ///
     /// @param[in] pid
     ///     The process ID in which we are trying to get the name of
     ///     a thread.
     ///
     /// @param[in] tid
     ///     The thread ID for which we are trying retrieve the name of.
     ///
     /// @return
     ///     A std::string containing the thread name.
     //------------------------------------------------------------------
     static std::string
     GetThreadName (lldb::pid_t pid, lldb::tid_t tid);
 
     //------------------------------------------------------------------
     /// Sets the name of a thread in the current process.
     ///
     /// @param[in] pid
     ///     The process ID in which we are trying to name a thread.
     ///
     /// @param[in] tid
     ///     The thread ID which we are trying to name.
     ///
     /// @param[in] name
     ///     The current thread's name in the current process to \a name.
     ///
     /// @return
     ///     \b true if the thread name was able to be set, \b false
     ///     otherwise.
     //------------------------------------------------------------------
     static bool
     SetThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *name);
 
     //------------------------------------------------------------------
     /// Sets a shortened name of a thread in the current process.
     ///
     /// @param[in] pid
     ///     The process ID in which we are trying to name a thread.
     ///
     /// @param[in] tid
     ///     The thread ID which we are trying to name.
     ///
     /// @param[in] name
     ///     The current thread's name in the current process to \a name.
     ///
     /// @param[in] len
     ///     The maximum length for the thread's shortened name.
     ///
     /// @return
     ///     \b true if the thread name was able to be set, \b false
     ///     otherwise.
     static bool
     SetShortThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *name, size_t len);
 
     //------------------------------------------------------------------
     /// Gets the FileSpec of the user profile directory.  On Posix-platforms
     /// this is ~, and on windows this is generally something like
     /// C:\Users\Alice.
     ///
     /// @return
     ///     \b A file spec with the path to the user's home directory.
     //------------------------------------------------------------------
     static FileSpec
     GetUserProfileFileSpec ();
 
     //------------------------------------------------------------------
     /// Gets the FileSpec of the current process (the process that
     /// that is running the LLDB code).
     ///
     /// @return
     ///     \b A file spec with the program name.
     //------------------------------------------------------------------
     static FileSpec
     GetProgramFileSpec ();
 
     //------------------------------------------------------------------
     /// Given an address in the current process (the process that
     /// is running the LLDB code), return the name of the module that
     /// it comes from. This can be useful when you need to know the
     /// path to the shared library that your code is running in for
     /// loading resources that are relative to your binary.
     ///
     /// @param[in] host_addr
     ///     The pointer to some code in the current process.
     ///
     /// @return
     ///     \b A file spec with the module that contains \a host_addr,
     ///     which may be invalid if \a host_addr doesn't fall into
     ///     any valid module address range.
     //------------------------------------------------------------------
     static FileSpec
     GetModuleFileSpecForHostAddress (const void *host_addr);
 
 
     
     //------------------------------------------------------------------
     /// If you have an executable that is in a bundle and want to get
     /// back to the bundle directory from the path itself, this 
     /// function will change a path to a file within a bundle to the
     /// bundle directory itself.
     ///
     /// @param[in] file
     ///     A file spec that might point to a file in a bundle. 
     ///
     /// @param[out] bundle_directory
     ///     An object will be filled in with the bundle directory for
     ///     the bundle when \b true is returned. Otherwise \a file is 
     ///     left untouched and \b false is returned.
     ///
     /// @return
     ///     \b true if \a file was resolved in \a bundle_directory,
     ///     \b false otherwise.
     //------------------------------------------------------------------
     static bool
     GetBundleDirectory (const FileSpec &file, FileSpec &bundle_directory);
 
     //------------------------------------------------------------------
     /// When executable files may live within a directory, where the 
     /// directory represents an executable bundle (like the MacOSX 
     /// app bundles), then locate the executable within the containing
     /// bundle.
     ///
     /// @param[in,out] file
     ///     A file spec that currently points to the bundle that will
     ///     be filled in with the executable path within the bundle
     ///     if \b true is returned. Otherwise \a file is left untouched.
     ///
     /// @return
     ///     \b true if \a file was resolved, \b false if this function
     ///     was not able to resolve the path.
     //------------------------------------------------------------------
     static bool
     ResolveExecutableInBundle (FileSpec &file);
 
     //------------------------------------------------------------------
     /// Find a resource files that are related to LLDB.
     ///
     /// Operating systems have different ways of storing shared 
     /// libraries and related resources. This function abstracts the
     /// access to these paths.
     ///
     /// @param[in] path_type
     ///     The type of LLDB resource path you are looking for. If the
     ///     enumeration ends with "Dir", then only the \a file_spec's 
     ///     directory member gets filled in.
     ///
     /// @param[in] file_spec
     ///     A file spec that gets filled in with the appropriate path.
     ///
     /// @return
     ///     \b true if \a resource_path was resolved, \a false otherwise.
     //------------------------------------------------------------------
     static bool
     GetLLDBPath (lldb::PathType path_type,
                  FileSpec &file_spec);
 
     //------------------------------------------------------------------
+    /// Creates a temporary file in the specified directory.
+    ///
+    /// Operating systems provide different levels of support when it
+    /// comes to creating temporary files.  This function abstracts
+    /// that logic into a platform-agnostic interface.
+    ///
+    /// @param[in] directory
+    ///     The folder in which to create the temporary file.
+    ///
+    /// @param[in] pathTemplate
+    ///     A templated used to determine how to name the file.  Occurrences
+    ///     of the character '%' are replaced with random symbols in [0-9a-f]
+    ///
+    /// @param[out] result
+    ///     A FileSpec representing the path that was created.  The caller
+    ///     should check the resulting path to get the actual filename that
+    ///     was created.
+    ///
+    /// @return
+    ///     A file descriptor referring to the newly created temporary file,
+    ///     or -1 if the file could not be created.
+    //------------------------------------------------------------------
+    static int
+    CreateTemporaryFile (const char *directory,
+                         const char *pathTemplate,
+                         FileSpec &result);
+
+    //------------------------------------------------------------------
     /// Set a string that can be displayed if host application crashes.
     ///
     /// Some operating systems have the ability to print a description
     /// for shared libraries when a program crashes. If the host OS
     /// supports such a mechanism, it should be implemented to help
     /// with crash triage.
     ///
     /// @param[in] format
     ///     A printf format that will be used to form a new crash
     ///     description string.
     //------------------------------------------------------------------
     static void
     SetCrashDescriptionWithFormat (const char *format, ...)  __attribute__ ((format (printf, 1, 2)));
 
     static void
     SetCrashDescription (const char *description);
 
     static uint32_t
     FindProcesses (const ProcessInstanceInfoMatch &match_info,
                    ProcessInstanceInfoList &proc_infos);
 
     typedef std::map<lldb::pid_t, bool> TidMap;
     typedef std::pair<lldb::pid_t, bool> TidPair;
     static bool
     FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach);
 
     static bool
     GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &proc_info);
 
 #if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined (__NetBSD__)
     static short
     GetPosixspawnFlags (ProcessLaunchInfo &launch_info);
 
     static Error
     LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, ::pid_t &pid);
 #endif
 
     static lldb::pid_t
     LaunchApplication (const FileSpec &app_file_spec);
 
     static Error
     LaunchProcess (ProcessLaunchInfo &launch_info);
 
     static Error
     RunShellCommand (const char *command,           // Shouldn't be NULL
                      const char *working_dir,       // Pass NULL to use the current working directory
                      int *status_ptr,               // Pass NULL if you don't want the process exit status
                      int *signo_ptr,                // Pass NULL if you don't want the signal that caused the process to exit
                      std::string *command_output,   // Pass NULL if you don't want the command output
                      uint32_t timeout_sec,
                      const char *shell = LLDB_DEFAULT_SHELL);
     
     static lldb::DataBufferSP
     GetAuxvData (lldb_private::Process *process);
 
     static lldb::DataBufferSP
     GetAuxvData (lldb::pid_t pid);
 
     static lldb::TargetSP
     GetDummyTarget (Debugger &debugger);
     
     static bool
     OpenFileInExternalEditor (const FileSpec &file_spec, 
                               uint32_t line_no);
 
     static void
     Backtrace (Stream &strm, uint32_t max_frames);
     
     static size_t
     GetEnvironment (StringList &env);
 
     enum DynamicLibraryOpenOptions 
     {
         eDynamicLibraryOpenOptionLazy           = (1u << 0),  // Lazily resolve symbols in this dynamic library
         eDynamicLibraryOpenOptionLocal          = (1u << 1),  // Only open a shared library with local access (hide it from the global symbol namespace)
         eDynamicLibraryOpenOptionLimitGetSymbol = (1u << 2)   // DynamicLibraryGetSymbol calls on this handle will only return matches from this shared library
     };
     static void *
     DynamicLibraryOpen (const FileSpec &file_spec, 
                         uint32_t options,
                         Error &error);
 
     static Error
     DynamicLibraryClose (void *dynamic_library_handle);
 
     static void *
     DynamicLibraryGetSymbol (void *dynamic_library_handle, 
                              const char *symbol_name, 
                              Error &error);
     
     static Error
     MakeDirectory (const char* path, uint32_t mode);
     
     static Error
     RemoveDirectory (const char* path, bool recurse);
     
     static Error
     GetFilePermissions (const char* path, uint32_t &file_permissions);
 
     static Error
     SetFilePermissions (const char* path, uint32_t file_permissions);
     
     static Error
     Symlink (const char *src, const char *dst);
     
     static Error
     Readlink (const char *path, char *buf, size_t buf_len);
 
     static Error
     Unlink (const char *path);
 
     static lldb::user_id_t
     OpenFile (const FileSpec& file_spec,
               uint32_t flags,
               uint32_t mode,
               Error &error);
     
     static bool
     CloseFile (lldb::user_id_t fd,
                Error &error);
     
     static uint64_t
     WriteFile (lldb::user_id_t fd,
                uint64_t offset,
                const void* src,
                uint64_t src_len,
                Error &error);
     
     static uint64_t
     ReadFile (lldb::user_id_t fd,
               uint64_t offset,
               void* dst,
               uint64_t dst_len,
               Error &error);
 
     static lldb::user_id_t
     GetFileSize (const FileSpec& file_spec);
     
     static bool
     GetFileExists (const FileSpec& file_spec);
     
     static bool
     CalculateMD5 (const FileSpec& file_spec,
                   uint64_t &low,
                   uint64_t &high);
 
 };
 
 } // namespace lldb_private
 
 #endif  // #if defined(__cplusplus)
 #endif  // liblldb_Host_h_
diff --git a/source/API/SBHostOS.cpp b/source/API/SBHostOS.cpp
index b3c7bc5..2d0c855 100644
--- a/source/API/SBHostOS.cpp
+++ b/source/API/SBHostOS.cpp
@@ -1,98 +1,109 @@
 //===-- SBHostOS.cpp --------------------------------------------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 
 #include "lldb/API/SBHostOS.h"
 #include "lldb/API/SBError.h"
 #include "lldb/Host/FileSpec.h"
 #include "lldb/Core/Log.h"
 #include "lldb/Host/Host.h"
 
 using namespace lldb;
 using namespace lldb_private;
 
 
 
 SBFileSpec
 SBHostOS::GetProgramFileSpec ()
 {
     SBFileSpec sb_filespec;
     sb_filespec.SetFileSpec (Host::GetProgramFileSpec ());
     return sb_filespec;
 }
 
 SBFileSpec
 SBHostOS::GetLLDBPythonPath ()
 {
     SBFileSpec sb_lldb_python_filespec;
     FileSpec lldb_python_spec;
     if (Host::GetLLDBPath (ePathTypePythonDir, lldb_python_spec))
     {
         sb_lldb_python_filespec.SetFileSpec (lldb_python_spec);
     }
     return sb_lldb_python_filespec;
 }
 
 
 SBFileSpec
 SBHostOS::GetLLDBPath (lldb::PathType path_type)
 {
     SBFileSpec sb_fspec;
     FileSpec fspec;
     if (Host::GetLLDBPath (path_type, fspec))
         sb_fspec.SetFileSpec (fspec);
     return sb_fspec;
 }
 
+int
+SBHostOS::CreateTemporaryFile (const char *directory,
+                               const char *pathTemplate,
+                               lldb::SBFileSpec &result)
+{
+    FileSpec fsresult;
+    return Host::CreateTemporaryFile(directory, pathTemplate, fsresult);
+    result.SetFileSpec(fsresult);
+}
+
+
 lldb::thread_t
 SBHostOS::ThreadCreate
 (
     const char *name,
     lldb::thread_func_t thread_function,
     void *thread_arg,
     SBError *error_ptr
 )
 {
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
 
     if (log)
         log->Printf ("SBHostOS::ThreadCreate (name=\"%s\", thread_function=%p, thread_arg=%p, error_ptr=%p)",
                      name, reinterpret_cast<void*>(reinterpret_cast<intptr_t>(thread_function)),
                      static_cast<void*>(thread_arg),
                      static_cast<void*>(error_ptr));
 
     // FIXME: You should log the return value?
 
     return Host::ThreadCreate (name, thread_function, thread_arg, error_ptr ? error_ptr->get() : NULL);
 }
 
 void
 SBHostOS::ThreadCreated (const char *name)
 {
     Host::ThreadCreated (name);
 }
 
 bool
 SBHostOS::ThreadCancel (lldb::thread_t thread, SBError *error_ptr)
 {
     return Host::ThreadCancel (thread, error_ptr ? error_ptr->get() : NULL);
 }
 
 bool
 SBHostOS::ThreadDetach (lldb::thread_t thread, SBError *error_ptr)
 {
     return Host::ThreadDetach (thread, error_ptr ? error_ptr->get() : NULL);
 }
 
 bool
 SBHostOS::ThreadJoin (lldb::thread_t thread, lldb::thread_result_t *result, SBError *error_ptr)
 {
     return Host::ThreadJoin (thread, result, error_ptr ? error_ptr->get() : NULL);
 }
 
 
diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp
index df1c787..2f582ef 100644
--- a/source/Host/common/Host.cpp
+++ b/source/Host/common/Host.cpp
@@ -1,2547 +1,2562 @@
 //===-- Host.cpp ------------------------------------------------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 
 #include "lldb/lldb-python.h"
 
 // C includes
 #include <errno.h>
 #include <limits.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #ifdef _WIN32
 #include "lldb/Host/windows/windows.h"
 #include <winsock2.h>
 #include <ws2tcpip.h>
 #else
 #include <unistd.h>
 #include <dlfcn.h>
 #include <grp.h>
 #include <netdb.h>
 #include <pwd.h>
 #include <sys/stat.h>
 #endif
 
 #if !defined (__GNU__) && !defined (_WIN32)
 // Does not exist under GNU/HURD or Windows
 #include <sys/sysctl.h>
 #endif
 
 #if defined (__APPLE__)
 #include <mach/mach_port.h>
 #include <mach/mach_init.h>
 #include <mach-o/dyld.h>
 #include <AvailabilityMacros.h>
 #ifndef CPU_SUBTYPE_X86_64_H
 #define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8)
 #endif
 #endif
 
 #if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__) || defined(__NetBSD__)
 #include <spawn.h>
 #include <sys/wait.h>
 #include <sys/syscall.h>
 #endif
 
 #if defined (__FreeBSD__)
 #include <pthread_np.h>
 #endif
 
 // C++ includes
 #include <limits>
 
 #include "lldb/Host/Host.h"
 #include "lldb/Core/ArchSpec.h"
 #include "lldb/Core/ConstString.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/Error.h"
 #include "lldb/Core/Log.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/StreamString.h"
 #include "lldb/Core/ThreadSafeSTLMap.h"
 #include "lldb/Host/Config.h"
 #include "lldb/Host/Endian.h"
 #include "lldb/Host/FileSpec.h"
 #include "lldb/Host/Mutex.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/TargetList.h"
 #include "lldb/Utility/CleanUp.h"
 
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/Host.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
 
 #if defined (__APPLE__)
 #ifndef _POSIX_SPAWN_DISABLE_ASLR
 #define _POSIX_SPAWN_DISABLE_ASLR       0x0100
 #endif
 
 extern "C"
 {
     int __pthread_chdir(const char *path);
     int __pthread_fchdir (int fildes);
 }
 
 #endif
 
 using namespace lldb;
 using namespace lldb_private;
 
 // Define maximum thread name length
 #if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__NetBSD__)
 uint32_t const Host::MAX_THREAD_NAME_LENGTH = 16;
 #else
 uint32_t const Host::MAX_THREAD_NAME_LENGTH = std::numeric_limits<uint32_t>::max ();
 #endif
 
 #if !defined (__APPLE__) && !defined (_WIN32)
 struct MonitorInfo
 {
     lldb::pid_t pid;                            // The process ID to monitor
     Host::MonitorChildProcessCallback callback; // The callback function to call when "pid" exits or signals
     void *callback_baton;                       // The callback baton for the callback function
     bool monitor_signals;                       // If true, call the callback when "pid" gets signaled.
 };
 
 static thread_result_t
 MonitorChildProcessThreadFunction (void *arg);
 
 lldb::thread_t
 Host::StartMonitoringChildProcess
 (
     Host::MonitorChildProcessCallback callback,
     void *callback_baton,
     lldb::pid_t pid,
     bool monitor_signals
 )
 {
     lldb::thread_t thread = LLDB_INVALID_HOST_THREAD;
     MonitorInfo * info_ptr = new MonitorInfo();
 
     info_ptr->pid = pid;
     info_ptr->callback = callback;
     info_ptr->callback_baton = callback_baton;
     info_ptr->monitor_signals = monitor_signals;
     
     char thread_name[256];
     ::snprintf (thread_name, sizeof(thread_name), "<lldb.host.wait4(pid=%" PRIu64 ")>", pid);
     thread = ThreadCreate (thread_name,
                            MonitorChildProcessThreadFunction,
                            info_ptr,
                            NULL);
                            
     return thread;
 }
 
 //------------------------------------------------------------------
 // Scoped class that will disable thread canceling when it is
 // constructed, and exception safely restore the previous value it
 // when it goes out of scope.
 //------------------------------------------------------------------
 class ScopedPThreadCancelDisabler
 {
 public:
     ScopedPThreadCancelDisabler()
     {
         // Disable the ability for this thread to be cancelled
         int err = ::pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &m_old_state);
         if (err != 0)
             m_old_state = -1;
 
     }
 
     ~ScopedPThreadCancelDisabler()
     {
         // Restore the ability for this thread to be cancelled to what it
         // previously was.
         if (m_old_state != -1)
             ::pthread_setcancelstate (m_old_state, 0);
     }
 private:
     int m_old_state;    // Save the old cancelability state.
 };
 
 static thread_result_t
 MonitorChildProcessThreadFunction (void *arg)
 {
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
     const char *function = __FUNCTION__;
     if (log)
         log->Printf ("%s (arg = %p) thread starting...", function, arg);
 
     MonitorInfo *info = (MonitorInfo *)arg;
 
     const Host::MonitorChildProcessCallback callback = info->callback;
     void * const callback_baton = info->callback_baton;
     const bool monitor_signals = info->monitor_signals;
 
     assert (info->pid <= UINT32_MAX);
     const ::pid_t pid = monitor_signals ? -1 * getpgid(info->pid) : info->pid;
 
     delete info;
 
     int status = -1;
 #if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
     #define __WALL 0
 #endif
     const int options = __WALL;
 
     while (1)
     {
         log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
         if (log)
             log->Printf("%s ::wait_pid (pid = %" PRIi32 ", &status, options = %i)...", function, pid, options);
 
         // Wait for all child processes
         ::pthread_testcancel ();
         // Get signals from all children with same process group of pid
         const ::pid_t wait_pid = ::waitpid (pid, &status, options);
         ::pthread_testcancel ();
 
         if (wait_pid == -1)
         {
             if (errno == EINTR)
                 continue;
             else
             {
                 if (log)
                     log->Printf ("%s (arg = %p) thread exiting because waitpid failed (%s)...", __FUNCTION__, arg, strerror(errno));
                 break;
             }
         }
         else if (wait_pid > 0)
         {
             bool exited = false;
             int signal = 0;
             int exit_status = 0;
             const char *status_cstr = NULL;
             if (WIFSTOPPED(status))
             {
                 signal = WSTOPSIG(status);
                 status_cstr = "STOPPED";
             }
             else if (WIFEXITED(status))
             {
                 exit_status = WEXITSTATUS(status);
                 status_cstr = "EXITED";
                 exited = true;
             }
             else if (WIFSIGNALED(status))
             {
                 signal = WTERMSIG(status);
                 status_cstr = "SIGNALED";
                 if (wait_pid == abs(pid)) {
                     exited = true;
                     exit_status = -1;
                 }
             }
             else
             {
                 status_cstr = "(\?\?\?)";
             }
 
             // Scope for pthread_cancel_disabler
             {
                 ScopedPThreadCancelDisabler pthread_cancel_disabler;
 
                 log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
                 if (log)
                     log->Printf ("%s ::waitpid (pid = %" PRIi32 ", &status, options = %i) => pid = %" PRIi32 ", status = 0x%8.8x (%s), signal = %i, exit_state = %i",
                                  function,
                                  wait_pid,
                                  options,
                                  pid,
                                  status,
                                  status_cstr,
                                  signal,
                                  exit_status);
 
                 if (exited || (signal != 0 && monitor_signals))
                 {
                     bool callback_return = false;
                     if (callback)
                         callback_return = callback (callback_baton, wait_pid, exited, signal, exit_status);
                     
                     // If our process exited, then this thread should exit
                     if (exited && wait_pid == abs(pid))
                     {
                         if (log)
                             log->Printf ("%s (arg = %p) thread exiting because pid received exit signal...", __FUNCTION__, arg);
                         break;
                     }
                     // If the callback returns true, it means this process should
                     // exit
                     if (callback_return)
                     {
                         if (log)
                             log->Printf ("%s (arg = %p) thread exiting because callback returned true...", __FUNCTION__, arg);
                         break;
                     }
                 }
             }
         }
     }
 
     log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
     if (log)
         log->Printf ("%s (arg = %p) thread exiting...", __FUNCTION__, arg);
 
     return NULL;
 }
 
 #endif // #if !defined (__APPLE__) && !defined (_WIN32)
 
 #if !defined (__APPLE__)
 
 void
 Host::SystemLog (SystemLogType type, const char *format, va_list args)
 {
     vfprintf (stderr, format, args);
 }
 
 #endif
 
 void
 Host::SystemLog (SystemLogType type, const char *format, ...)
 {
     va_list args;
     va_start (args, format);
     SystemLog (type, format, args);
     va_end (args);
 }
 
 const ArchSpec &
 Host::GetArchitecture (SystemDefaultArchitecture arch_kind)
 {
     static bool g_supports_32 = false;
     static bool g_supports_64 = false;
     static ArchSpec g_host_arch_32;
     static ArchSpec g_host_arch_64;
 
 #if defined (__APPLE__)
 
     // Apple is different in that it can support both 32 and 64 bit executables
     // in the same operating system running concurrently. Here we detect the
     // correct host architectures for both 32 and 64 bit including if 64 bit
     // executables are supported on the system.
 
     if (g_supports_32 == false && g_supports_64 == false)
     {
         // All apple systems support 32 bit execution.
         g_supports_32 = true;
         uint32_t cputype, cpusubtype;
         uint32_t is_64_bit_capable = false;
         size_t len = sizeof(cputype);
         ArchSpec host_arch;
         // These will tell us about the kernel architecture, which even on a 64
         // bit machine can be 32 bit...
         if  (::sysctlbyname("hw.cputype", &cputype, &len, NULL, 0) == 0)
         {
             len = sizeof (cpusubtype);
             if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) != 0)
                 cpusubtype = CPU_TYPE_ANY;
                 
             len = sizeof (is_64_bit_capable);
             if  (::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0) == 0)
             {
                 if (is_64_bit_capable)
                     g_supports_64 = true;
             }
             
             if (is_64_bit_capable)
             {
                 if (cputype & CPU_ARCH_ABI64)
                 {
                     // We have a 64 bit kernel on a 64 bit system
                     g_host_arch_64.SetArchitecture (eArchTypeMachO, cputype, cpusubtype);
                 }
                 else
                 {
                     // We have a 64 bit kernel that is returning a 32 bit cputype, the
                     // cpusubtype will be correct as if it were for a 64 bit architecture
                     g_host_arch_64.SetArchitecture (eArchTypeMachO, cputype | CPU_ARCH_ABI64, cpusubtype);
                 }
                 
                 // Now we need modify the cpusubtype for the 32 bit slices.
                 uint32_t cpusubtype32 = cpusubtype;
 #if defined (__i386__) || defined (__x86_64__)
                 if (cpusubtype == CPU_SUBTYPE_486 || cpusubtype == CPU_SUBTYPE_X86_64_H)
                     cpusubtype32 = CPU_SUBTYPE_I386_ALL;
 #elif defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
                 if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64)
                     cpusubtype32 = CPU_SUBTYPE_ARM_V7S;
 #endif
                 g_host_arch_32.SetArchitecture (eArchTypeMachO, cputype & ~(CPU_ARCH_MASK), cpusubtype32);
                 
                 if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64)
                 {
                     g_host_arch_32.GetTriple().setOS(llvm::Triple::IOS);
                     g_host_arch_64.GetTriple().setOS(llvm::Triple::IOS);
                 }
                 else
                 {
                     g_host_arch_32.GetTriple().setOS(llvm::Triple::MacOSX);
                     g_host_arch_64.GetTriple().setOS(llvm::Triple::MacOSX);
                 }
             }
             else
             {
                 // We have a 32 bit kernel on a 32 bit system
                 g_host_arch_32.SetArchitecture (eArchTypeMachO, cputype, cpusubtype);
                 g_host_arch_64.Clear();
             }
         }
     }
     
 #else // #if defined (__APPLE__)
 
     if (g_supports_32 == false && g_supports_64 == false)
     {
         llvm::Triple triple(llvm::sys::getDefaultTargetTriple());
 
         g_host_arch_32.Clear();
         g_host_arch_64.Clear();
 
         // If the OS is Linux, "unknown" in the vendor slot isn't what we want
         // for the default triple.  It's probably an artifact of config.guess.
         if (triple.getOS() == llvm::Triple::Linux && triple.getVendor() == llvm::Triple::UnknownVendor)
             triple.setVendorName ("");
 
         const char* distribution_id = GetDistributionId ().AsCString();
 
         switch (triple.getArch())
         {
         default:
             g_host_arch_32.SetTriple(triple);
             g_host_arch_32.SetDistributionId (distribution_id);
             g_supports_32 = true;
             break;
 
         case llvm::Triple::x86_64:
             g_host_arch_64.SetTriple(triple);
             g_host_arch_64.SetDistributionId (distribution_id);
             g_supports_64 = true;
             g_host_arch_32.SetTriple(triple.get32BitArchVariant());
             g_host_arch_32.SetDistributionId (distribution_id);
             g_supports_32 = true;
             break;
 
         case llvm::Triple::mips64:
         case llvm::Triple::sparcv9:
         case llvm::Triple::ppc64:
             g_host_arch_64.SetTriple(triple);
             g_host_arch_64.SetDistributionId (distribution_id);
             g_supports_64 = true;
             break;
         }
 
         g_supports_32 = g_host_arch_32.IsValid();
         g_supports_64 = g_host_arch_64.IsValid();
     }
     
 #endif // #else for #if defined (__APPLE__)
     
     if (arch_kind == eSystemDefaultArchitecture32)
         return g_host_arch_32;
     else if (arch_kind == eSystemDefaultArchitecture64)
         return g_host_arch_64;
 
     if (g_supports_64)
         return g_host_arch_64;
         
     return g_host_arch_32;
 }
 
 const ConstString &
 Host::GetVendorString()
 {
     static ConstString g_vendor;
     if (!g_vendor)
     {
         const ArchSpec &host_arch = GetArchitecture (eSystemDefaultArchitecture);
         const llvm::StringRef &str_ref = host_arch.GetTriple().getVendorName();
         g_vendor.SetCStringWithLength(str_ref.data(), str_ref.size());
     }
     return g_vendor;
 }
 
 const ConstString &
 Host::GetOSString()
 {
     static ConstString g_os_string;
     if (!g_os_string)
     {
         const ArchSpec &host_arch = GetArchitecture (eSystemDefaultArchitecture);
         const llvm::StringRef &str_ref = host_arch.GetTriple().getOSName();
         g_os_string.SetCStringWithLength(str_ref.data(), str_ref.size());
     }
     return g_os_string;
 }
 
 const ConstString &
 Host::GetTargetTriple()
 {
     static ConstString g_host_triple;
     if (!(g_host_triple))
     {
         const ArchSpec &host_arch = GetArchitecture (eSystemDefaultArchitecture);
         g_host_triple.SetCString(host_arch.GetTriple().getTriple().c_str());
     }
     return g_host_triple;
 }
 
 // See linux/Host.cpp for Linux-based implementations of this.
 // Add your platform-specific implementation to the appropriate host file.
 #if !defined(__linux__)
 
 const ConstString &
     Host::GetDistributionId ()
 {
     static ConstString s_distribution_id;
     return s_distribution_id;
 }
 
 #endif // #if !defined(__linux__)
 
 lldb::pid_t
 Host::GetCurrentProcessID()
 {
     return ::getpid();
 }
 
 #ifndef _WIN32
 
 lldb::tid_t
 Host::GetCurrentThreadID()
 {
 #if defined (__APPLE__)
     // Calling "mach_thread_self()" bumps the reference count on the thread
     // port, so we need to deallocate it. mach_task_self() doesn't bump the ref
     // count.
     thread_port_t thread_self = mach_thread_self();
     mach_port_deallocate(mach_task_self(), thread_self);
     return thread_self;
 #elif defined(__FreeBSD__)
     return lldb::tid_t(pthread_getthreadid_np());
 #elif defined(__linux__)
     return lldb::tid_t(syscall(SYS_gettid));
 #else
     return lldb::tid_t(pthread_self());
 #endif
 }
 
 lldb::thread_t
 Host::GetCurrentThread ()
 {
     return lldb::thread_t(pthread_self());
 }
 
 const char *
 Host::GetSignalAsCString (int signo)
 {
     switch (signo)
     {
     case SIGHUP:    return "SIGHUP";    // 1    hangup
     case SIGINT:    return "SIGINT";    // 2    interrupt
     case SIGQUIT:   return "SIGQUIT";   // 3    quit
     case SIGILL:    return "SIGILL";    // 4    illegal instruction (not reset when caught)
     case SIGTRAP:   return "SIGTRAP";   // 5    trace trap (not reset when caught)
     case SIGABRT:   return "SIGABRT";   // 6    abort()
 #if  defined(SIGPOLL)
 #if !defined(SIGIO) || (SIGPOLL != SIGIO)
 // Under some GNU/Linux, SIGPOLL and SIGIO are the same. Causing the build to
 // fail with 'multiple define cases with same value'
     case SIGPOLL:   return "SIGPOLL";   // 7    pollable event ([XSR] generated, not supported)
 #endif
 #endif
 #if  defined(SIGEMT)
     case SIGEMT:    return "SIGEMT";    // 7    EMT instruction
 #endif
     case SIGFPE:    return "SIGFPE";    // 8    floating point exception
     case SIGKILL:   return "SIGKILL";   // 9    kill (cannot be caught or ignored)
     case SIGBUS:    return "SIGBUS";    // 10    bus error
     case SIGSEGV:   return "SIGSEGV";   // 11    segmentation violation
     case SIGSYS:    return "SIGSYS";    // 12    bad argument to system call
     case SIGPIPE:   return "SIGPIPE";   // 13    write on a pipe with no one to read it
     case SIGALRM:   return "SIGALRM";   // 14    alarm clock
     case SIGTERM:   return "SIGTERM";   // 15    software termination signal from kill
     case SIGURG:    return "SIGURG";    // 16    urgent condition on IO channel
     case SIGSTOP:   return "SIGSTOP";   // 17    sendable stop signal not from tty
     case SIGTSTP:   return "SIGTSTP";   // 18    stop signal from tty
     case SIGCONT:   return "SIGCONT";   // 19    continue a stopped process
     case SIGCHLD:   return "SIGCHLD";   // 20    to parent on child stop or exit
     case SIGTTIN:   return "SIGTTIN";   // 21    to readers pgrp upon background tty read
     case SIGTTOU:   return "SIGTTOU";   // 22    like TTIN for output if (tp->t_local&LTOSTOP)
 #if  defined(SIGIO)
     case SIGIO:     return "SIGIO";     // 23    input/output possible signal
 #endif
     case SIGXCPU:   return "SIGXCPU";   // 24    exceeded CPU time limit
     case SIGXFSZ:   return "SIGXFSZ";   // 25    exceeded file size limit
     case SIGVTALRM: return "SIGVTALRM"; // 26    virtual time alarm
     case SIGPROF:   return "SIGPROF";   // 27    profiling time alarm
 #if  defined(SIGWINCH)
     case SIGWINCH:  return "SIGWINCH";  // 28    window size changes
 #endif
 #if  defined(SIGINFO)
     case SIGINFO:   return "SIGINFO";   // 29    information request
 #endif
     case SIGUSR1:   return "SIGUSR1";   // 30    user defined signal 1
     case SIGUSR2:   return "SIGUSR2";   // 31    user defined signal 2
     default:
         break;
     }
     return NULL;
 }
 
 #endif
 
 void
 Host::WillTerminate ()
 {
 }
 
 #if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) && !defined (__linux__) // see macosx/Host.mm
 
 void
 Host::ThreadCreated (const char *thread_name)
 {
 }
 
 void
 Host::Backtrace (Stream &strm, uint32_t max_frames)
 {
     // TODO: Is there a way to backtrace the current process on other systems?
 }
 
 size_t
 Host::GetEnvironment (StringList &env)
 {
     // TODO: Is there a way to the host environment for this process on other systems?
     return 0;
 }
 
 #endif // #if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) && !defined (__linux__)
 
 struct HostThreadCreateInfo
 {
     std::string thread_name;
     thread_func_t thread_fptr;
     thread_arg_t thread_arg;
     
     HostThreadCreateInfo (const char *name, thread_func_t fptr, thread_arg_t arg) :
         thread_name (name ? name : ""),
         thread_fptr (fptr),
         thread_arg (arg)
     {
     }
 };
 
 static thread_result_t
 #ifdef _WIN32
 __stdcall
 #endif
 ThreadCreateTrampoline (thread_arg_t arg)
 {
     HostThreadCreateInfo *info = (HostThreadCreateInfo *)arg;
     Host::ThreadCreated (info->thread_name.c_str());
     thread_func_t thread_fptr = info->thread_fptr;
     thread_arg_t thread_arg = info->thread_arg;
     
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
     if (log)
         log->Printf("thread created");
     
     delete info;
     return thread_fptr (thread_arg);
 }
 
 lldb::thread_t
 Host::ThreadCreate
 (
     const char *thread_name,
     thread_func_t thread_fptr,
     thread_arg_t thread_arg,
     Error *error
 )
 {
     lldb::thread_t thread = LLDB_INVALID_HOST_THREAD;
     
     // Host::ThreadCreateTrampoline will delete this pointer for us.
     HostThreadCreateInfo *info_ptr = new HostThreadCreateInfo (thread_name, thread_fptr, thread_arg);
     
 #ifdef _WIN32
     thread = ::_beginthreadex(0, 0, ThreadCreateTrampoline, info_ptr, 0, NULL);
     int err = thread <= 0 ? GetLastError() : 0;
 #else
     int err = ::pthread_create (&thread, NULL, ThreadCreateTrampoline, info_ptr);
 #endif
     if (err == 0)
     {
         if (error)
             error->Clear();
         return thread;
     }
     
     if (error)
         error->SetError (err, eErrorTypePOSIX);
     
     return LLDB_INVALID_HOST_THREAD;
 }
 
 #ifndef _WIN32
 
 bool
 Host::ThreadCancel (lldb::thread_t thread, Error *error)
 {
     int err = ::pthread_cancel (thread);
     if (error)
         error->SetError(err, eErrorTypePOSIX);
     return err == 0;
 }
 
 bool
 Host::ThreadDetach (lldb::thread_t thread, Error *error)
 {
     int err = ::pthread_detach (thread);
     if (error)
         error->SetError(err, eErrorTypePOSIX);
     return err == 0;
 }
 
 bool
 Host::ThreadJoin (lldb::thread_t thread, thread_result_t *thread_result_ptr, Error *error)
 {
     int err = ::pthread_join (thread, thread_result_ptr);
     if (error)
         error->SetError(err, eErrorTypePOSIX);
     return err == 0;
 }
 
 lldb::thread_key_t
 Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback)
 {
     pthread_key_t key;
     ::pthread_key_create (&key, callback);
     return key;
 }
 
 void*
 Host::ThreadLocalStorageGet(lldb::thread_key_t key)
 {
     return ::pthread_getspecific (key);
 }
 
 void
 Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value)
 {
    ::pthread_setspecific (key, value);
 }
 
 bool
 Host::SetThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *name)
 {
 #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
     lldb::pid_t curr_pid = Host::GetCurrentProcessID();
     lldb::tid_t curr_tid = Host::GetCurrentThreadID();
     if (pid == LLDB_INVALID_PROCESS_ID)
         pid = curr_pid;
 
     if (tid == LLDB_INVALID_THREAD_ID)
         tid = curr_tid;
 
     // Set the pthread name if possible
     if (pid == curr_pid && tid == curr_tid)
     {
         if (::pthread_setname_np (name) == 0)
             return true;
     }
     return false;
 #elif defined (__FreeBSD__)
     lldb::pid_t curr_pid = Host::GetCurrentProcessID();
     lldb::tid_t curr_tid = Host::GetCurrentThreadID();
     if (pid == LLDB_INVALID_PROCESS_ID)
         pid = curr_pid;
 
     if (tid == LLDB_INVALID_THREAD_ID)
         tid = curr_tid;
 
     // Set the pthread name if possible
     if (pid == curr_pid && tid == curr_tid)
     {
         ::pthread_set_name_np (::pthread_self(), name);
         return true;
     }
     return false;
 #elif defined (__linux__) || defined (__GLIBC__)
     void *fn = dlsym (RTLD_DEFAULT, "pthread_setname_np");
     if (fn)
     {
         lldb::pid_t curr_pid = Host::GetCurrentProcessID();
         lldb::tid_t curr_tid = Host::GetCurrentThreadID();
         if (pid == LLDB_INVALID_PROCESS_ID)
             pid = curr_pid;
 
         if (tid == LLDB_INVALID_THREAD_ID)
             tid = curr_tid;
 
         if (pid == curr_pid && tid == curr_tid)
         {
             int (*pthread_setname_np_func)(pthread_t thread, const char *name);
             *reinterpret_cast<void **> (&pthread_setname_np_func) = fn;
 
             if (pthread_setname_np_func (::pthread_self(), name) == 0)
                 return true;
         }
     }
     return false;
 #else
     return false;
 #endif
 }
 
 bool
 Host::SetShortThreadName (lldb::pid_t pid, lldb::tid_t tid,
                           const char *thread_name, size_t len)
 {
     std::unique_ptr<char[]> namebuf(new char[len+1]);
     
     // Thread names are coming in like '<lldb.comm.debugger.edit>' and
     // '<lldb.comm.debugger.editline>'.  So just chopping the end of the string
     // off leads to a lot of similar named threads.  Go through the thread name
     // and search for the last dot and use that.
     const char *lastdot = ::strrchr (thread_name, '.');
 
     if (lastdot && lastdot != thread_name)
         thread_name = lastdot + 1;
     ::strncpy (namebuf.get(), thread_name, len);
     namebuf[len] = 0;
 
     int namebuflen = strlen(namebuf.get());
     if (namebuflen > 0)
     {
         if (namebuf[namebuflen - 1] == '(' || namebuf[namebuflen - 1] == '>')
         {
             // Trim off trailing '(' and '>' characters for a bit more cleanup.
             namebuflen--;
             namebuf[namebuflen] = 0;
         }
         return Host::SetThreadName (pid, tid, namebuf.get());
     }
     return false;
 }
 
 #endif
 
 FileSpec
 Host::GetUserProfileFileSpec ()
 {
     static FileSpec g_profile_filespec;
     if (!g_profile_filespec)
     {
         llvm::SmallString<64> path;
         llvm::sys::path::home_directory(path);
         return FileSpec(path.c_str(), false);
     }
     return g_profile_filespec;
 }
 
 FileSpec
 Host::GetProgramFileSpec ()
 {
     static FileSpec g_program_filespec;
     if (!g_program_filespec)
     {
 #if defined (__APPLE__)
         char program_fullpath[PATH_MAX];
         // If DST is NULL, then return the number of bytes needed.
         uint32_t len = sizeof(program_fullpath);
         int err = _NSGetExecutablePath (program_fullpath, &len);
         if (err == 0)
             g_program_filespec.SetFile (program_fullpath, false);
         else if (err == -1)
         {
             char *large_program_fullpath = (char *)::malloc (len + 1);
 
             err = _NSGetExecutablePath (large_program_fullpath, &len);
             if (err == 0)
                 g_program_filespec.SetFile (large_program_fullpath, false);
 
             ::free (large_program_fullpath);
         }
 #elif defined (__linux__)
         char exe_path[PATH_MAX];
         ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
         if (len > 0) {
             exe_path[len] = 0;
             g_program_filespec.SetFile(exe_path, false);
         }
 #elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
         int exe_path_mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, getpid() };
         size_t exe_path_size;
         if (sysctl(exe_path_mib, 4, NULL, &exe_path_size, NULL, 0) == 0)
         {
             char *exe_path = new char[exe_path_size];
             if (sysctl(exe_path_mib, 4, exe_path, &exe_path_size, NULL, 0) == 0)
                 g_program_filespec.SetFile(exe_path, false);
             delete[] exe_path;
         }
 #elif defined(_WIN32)
         std::vector<char> buffer(PATH_MAX);
         ::GetModuleFileName(NULL, &buffer[0], buffer.size());
         g_program_filespec.SetFile(&buffer[0], false);
 #endif
     }
     return g_program_filespec;
 }
 
 #if !defined (__APPLE__) // see Host.mm
 
 bool
 Host::GetBundleDirectory (const FileSpec &file, FileSpec &bundle)
 {
     bundle.Clear();
     return false;
 }
 
 bool
 Host::ResolveExecutableInBundle (FileSpec &file)
 {
     return false;
 }
 #endif
 
 #ifndef _WIN32
 
 // Opaque info that tracks a dynamic library that was loaded
 struct DynamicLibraryInfo
 {
     DynamicLibraryInfo (const FileSpec &fs, int o, void *h) :
         file_spec (fs),
         open_options (o),
         handle (h)
     {
     }
 
     const FileSpec file_spec;
     uint32_t open_options;
     void * handle;
 };
 
 void *
 Host::DynamicLibraryOpen (const FileSpec &file_spec, uint32_t options, Error &error)
 {
     char path[PATH_MAX];
     if (file_spec.GetPath(path, sizeof(path)))
     {
         int mode = 0;
         
         if (options & eDynamicLibraryOpenOptionLazy)
             mode |= RTLD_LAZY;
         else
             mode |= RTLD_NOW;
 
     
         if (options & eDynamicLibraryOpenOptionLocal)
             mode |= RTLD_LOCAL;
         else
             mode |= RTLD_GLOBAL;
 
 #ifdef LLDB_CONFIG_DLOPEN_RTLD_FIRST_SUPPORTED
         if (options & eDynamicLibraryOpenOptionLimitGetSymbol)
             mode |= RTLD_FIRST;
 #endif
         
         void * opaque = ::dlopen (path, mode);
 
         if (opaque)
         {
             error.Clear();
             return new DynamicLibraryInfo (file_spec, options, opaque);
         }
         else
         {
             error.SetErrorString(::dlerror());
         }
     }
     else 
     {
         error.SetErrorString("failed to extract path");
     }
     return NULL;
 }
 
 Error
 Host::DynamicLibraryClose (void *opaque)
 {
     Error error;
     if (opaque == NULL)
     {
         error.SetErrorString ("invalid dynamic library handle");
     }
     else
     {
         DynamicLibraryInfo *dylib_info = (DynamicLibraryInfo *) opaque;
         if (::dlclose (dylib_info->handle) != 0)
         {
             error.SetErrorString(::dlerror());
         }
         
         dylib_info->open_options = 0;
         dylib_info->handle = 0;
         delete dylib_info;
     }
     return error;
 }
 
 void *
 Host::DynamicLibraryGetSymbol (void *opaque, const char *symbol_name, Error &error)
 {
     if (opaque == NULL)
     {
         error.SetErrorString ("invalid dynamic library handle");
     }
     else
     {
         DynamicLibraryInfo *dylib_info = (DynamicLibraryInfo *) opaque;
 
         void *symbol_addr = ::dlsym (dylib_info->handle, symbol_name);
         if (symbol_addr)
         {
 #ifndef LLDB_CONFIG_DLOPEN_RTLD_FIRST_SUPPORTED
             // This host doesn't support limiting searches to this shared library
             // so we need to verify that the match came from this shared library
             // if it was requested in the Host::DynamicLibraryOpen() function.
             if (dylib_info->open_options & eDynamicLibraryOpenOptionLimitGetSymbol)
             {
                 FileSpec match_dylib_spec (Host::GetModuleFileSpecForHostAddress (symbol_addr));
                 if (match_dylib_spec != dylib_info->file_spec)
                 {
                     char dylib_path[PATH_MAX];
                     if (dylib_info->file_spec.GetPath (dylib_path, sizeof(dylib_path)))
                         error.SetErrorStringWithFormat ("symbol not found in \"%s\"", dylib_path);
                     else
                         error.SetErrorString ("symbol not found");
                     return NULL;
                 }
             }
 #endif
             error.Clear();
             return symbol_addr;
         }
         else
         {
             error.SetErrorString(::dlerror());
         }
     }
     return NULL;
 }
 
 FileSpec
 Host::GetModuleFileSpecForHostAddress (const void *host_addr)
 {
     FileSpec module_filespec;
     Dl_info info;
     if (::dladdr (host_addr, &info))
     {
         if (info.dli_fname)
             module_filespec.SetFile(info.dli_fname, true);
     }
     return module_filespec;
 }
 
 #endif
 
 
 static void CleanupProcessSpecificLLDBTempDir ()
 {
     // Get the process specific LLDB temporary directory and delete it.
     FileSpec tmpdir_file_spec;
     if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
     {
         // Remove the LLDB temporary directory if we have one. Set "recurse" to
         // true to all files that were created for the LLDB process can be cleaned up.
         const bool recurse = true;
         Host::RemoveDirectory(tmpdir_file_spec.GetDirectory().GetCString(), recurse);
     }
 }
 
 bool
 Host::GetLLDBPath (PathType path_type, FileSpec &file_spec)
 {
     // To get paths related to LLDB we get the path to the executable that
     // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB",
     // on linux this is assumed to be the "lldb" main executable. If LLDB on
     // linux is actually in a shared library (liblldb.so) then this function will
     // need to be modified to "do the right thing".
     Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST);
 
     switch (path_type)
     {
     case ePathTypeLLDBShlibDir:
         {
             static ConstString g_lldb_so_dir;
             if (!g_lldb_so_dir)
             {
                 FileSpec lldb_file_spec(Host::GetModuleFileSpecForHostAddress(
                     reinterpret_cast<void *>(reinterpret_cast<intptr_t>(Host::GetLLDBPath))));
                 g_lldb_so_dir = lldb_file_spec.GetDirectory();
                 if (log)
                     log->Printf("Host::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_lldb_so_dir.GetCString());
             }
             file_spec.GetDirectory() = g_lldb_so_dir;
             return (bool)file_spec.GetDirectory();
         }
         break;
 
     case ePathTypeSupportExecutableDir:  
         {
             static ConstString g_lldb_support_exe_dir;
             if (!g_lldb_support_exe_dir)
             {
                 FileSpec lldb_file_spec;
                 if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
                 {
                     char raw_path[PATH_MAX];
                     char resolved_path[PATH_MAX];
                     lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
 
 #if defined (__APPLE__)
                     char *framework_pos = ::strstr (raw_path, "LLDB.framework");
                     if (framework_pos)
                     {
                         framework_pos += strlen("LLDB.framework");
 #if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
                         // Shallow bundle
                         *framework_pos = '\0';
 #else
                         // Normal bundle
                         ::strncpy (framework_pos, "/Resources", PATH_MAX - (framework_pos - raw_path));
 #endif
                     }
 #elif defined (__linux__) || defined (__FreeBSD__) || defined (__NetBSD__)
                     // Linux/*BSD will attempt to replace a */lib with */bin as the base directory for
                     // helper exe programs.  This will fail if the /lib and /bin directories are rooted in entirely
                     // different trees.
                     if (log)
                         log->Printf ("Host::%s() attempting to derive the bin path (ePathTypeSupportExecutableDir) from this path: %s", __FUNCTION__, raw_path);
                     char *lib_pos = ::strstr (raw_path, "/lib");
                     if (lib_pos != nullptr)
                     {
                         // First terminate the raw path at the start of lib.
                         *lib_pos = '\0';
 
                         // Now write in bin in place of lib.
                         ::strncpy (lib_pos, "/bin", PATH_MAX - (lib_pos - raw_path));
 
                         if (log)
                             log->Printf ("Host::%s() derived the bin path as: %s", __FUNCTION__, raw_path);
                     }
                     else
                     {
                         if (log)
                             log->Printf ("Host::%s() failed to find /lib/liblldb within the shared lib path, bailing on bin path construction", __FUNCTION__);
                     }
 #endif  // #if defined (__APPLE__)
                     FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
                     g_lldb_support_exe_dir.SetCString(resolved_path);
                 }
                 if (log)
                     log->Printf("Host::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", g_lldb_support_exe_dir.GetCString());
             }
             file_spec.GetDirectory() = g_lldb_support_exe_dir;
             return (bool)file_spec.GetDirectory();
         }
         break;
 
     case ePathTypeHeaderDir:
         {
             static ConstString g_lldb_headers_dir;
             if (!g_lldb_headers_dir)
             {
 #if defined (__APPLE__)
                 FileSpec lldb_file_spec;
                 if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
                 {
                     char raw_path[PATH_MAX];
                     char resolved_path[PATH_MAX];
                     lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
 
                     char *framework_pos = ::strstr (raw_path, "LLDB.framework");
                     if (framework_pos)
                     {
                         framework_pos += strlen("LLDB.framework");
                         ::strncpy (framework_pos, "/Headers", PATH_MAX - (framework_pos - raw_path));
                     }
                     FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
                     g_lldb_headers_dir.SetCString(resolved_path);
                 }
 #else
                 // TODO: Anyone know how we can determine this for linux? Other systems??
                 g_lldb_headers_dir.SetCString ("/opt/local/include/lldb");
 #endif
                 if (log)
                     log->Printf("Host::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_lldb_headers_dir.GetCString());
             }
             file_spec.GetDirectory() = g_lldb_headers_dir;
             return (bool)file_spec.GetDirectory();
         }
         break;
 
 #ifdef LLDB_DISABLE_PYTHON
     case ePathTypePythonDir:
         return false;
 #else
     case ePathTypePythonDir:
         {
             static ConstString g_lldb_python_dir;
             if (!g_lldb_python_dir)
             {
                 FileSpec lldb_file_spec;
                 if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
                 {
                     char raw_path[PATH_MAX];
                     char resolved_path[PATH_MAX];
 #if defined(_WIN32)
                     lldb_file_spec.AppendPathComponent("../lib/site-packages");
                     lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
 #else
                     lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
 
 #if defined (__APPLE__)
                     char *framework_pos = ::strstr (raw_path, "LLDB.framework");
                     if (framework_pos)
                     {
                         framework_pos += strlen("LLDB.framework");
                         ::strncpy (framework_pos, "/Resources/Python", PATH_MAX - (framework_pos - raw_path));
                     } 
                     else 
                     {
 #endif
                         llvm::SmallString<256> python_version_dir;
                         llvm::raw_svector_ostream os(python_version_dir);
                         os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION << "/site-packages";
                         os.flush();
 
                         // We may get our string truncated. Should we protect
                         // this with an assert?
 
                         ::strncat(raw_path, python_version_dir.c_str(),
                                   sizeof(raw_path) - strlen(raw_path) - 1);
 #endif
 #if defined (__APPLE__)
                     }
 #endif
                     FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
                     g_lldb_python_dir.SetCString(resolved_path);
                 }
                 
                 if (log)
                     log->Printf("Host::GetLLDBPath(ePathTypePythonDir) => '%s'", g_lldb_python_dir.GetCString());
 
             }
             file_spec.GetDirectory() = g_lldb_python_dir;
             return (bool)file_spec.GetDirectory();
         }
         break;
 #endif
 
     case ePathTypeLLDBSystemPlugins:    // System plug-ins directory
         {
 #if defined (__APPLE__) || defined(__linux__)
             static ConstString g_lldb_system_plugin_dir;
             static bool g_lldb_system_plugin_dir_located = false;
             if (!g_lldb_system_plugin_dir_located)
             {
                 g_lldb_system_plugin_dir_located = true;
 #if defined (__APPLE__)
                 FileSpec lldb_file_spec;
                 if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
                 {
                     char raw_path[PATH_MAX];
                     char resolved_path[PATH_MAX];
                     lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
 
                     char *framework_pos = ::strstr (raw_path, "LLDB.framework");
                     if (framework_pos)
                     {
                         framework_pos += strlen("LLDB.framework");
                         ::strncpy (framework_pos, "/Resources/PlugIns", PATH_MAX - (framework_pos - raw_path));
                         FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
                         g_lldb_system_plugin_dir.SetCString(resolved_path);
                     }
                     return false;
                 }
 #elif defined (__linux__)
                 FileSpec lldb_file_spec("/usr/lib/lldb", true);
                 if (lldb_file_spec.Exists())
                 {
                     g_lldb_system_plugin_dir.SetCString(lldb_file_spec.GetPath().c_str());
                 }
 #endif // __APPLE__ || __linux__
                 
                 if (log)
                     log->Printf("Host::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", g_lldb_system_plugin_dir.GetCString());
 
             }
             
             if (g_lldb_system_plugin_dir)
             {
                 file_spec.GetDirectory() = g_lldb_system_plugin_dir;
                 return true;
             }
 #else
             // TODO: where would system LLDB plug-ins be located on other systems?
             return false;
 #endif
         }
         break;
 
     case ePathTypeLLDBUserPlugins:      // User plug-ins directory
         {
 #if defined (__APPLE__)
             static ConstString g_lldb_user_plugin_dir;
             if (!g_lldb_user_plugin_dir)
             {
                 char user_plugin_path[PATH_MAX];
                 if (FileSpec::Resolve ("~/Library/Application Support/LLDB/PlugIns", 
                                        user_plugin_path, 
                                        sizeof(user_plugin_path)))
                 {
                     g_lldb_user_plugin_dir.SetCString(user_plugin_path);
                 }
             }
             file_spec.GetDirectory() = g_lldb_user_plugin_dir;
             return (bool)file_spec.GetDirectory();
 #elif defined (__linux__)
             static ConstString g_lldb_user_plugin_dir;
             if (!g_lldb_user_plugin_dir)
             {
                 // XDG Base Directory Specification
                 // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
                 // If XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb.
                 FileSpec lldb_file_spec;
                 const char *xdg_data_home = getenv("XDG_DATA_HOME");
                 if (xdg_data_home && xdg_data_home[0])
                 {
                     std::string user_plugin_dir (xdg_data_home);
                     user_plugin_dir += "/lldb";
                     lldb_file_spec.SetFile (user_plugin_dir.c_str(), true);
                 }
                 else
                 {
                     const char *home_dir = getenv("HOME");
                     if (home_dir && home_dir[0])
                     {
                         std::string user_plugin_dir (home_dir);
                         user_plugin_dir += "/.local/share/lldb";
                         lldb_file_spec.SetFile (user_plugin_dir.c_str(), true);
                     }
                 }
 
                 if (lldb_file_spec.Exists())
                     g_lldb_user_plugin_dir.SetCString(lldb_file_spec.GetPath().c_str());
                 if (log)
                     log->Printf("Host::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", g_lldb_user_plugin_dir.GetCString());
             }
             file_spec.GetDirectory() = g_lldb_user_plugin_dir;
             return (bool)file_spec.GetDirectory();
 #endif
             // TODO: where would user LLDB plug-ins be located on other systems?
             return false;
         }
             
     case ePathTypeLLDBTempSystemDir:
         {
             static ConstString g_lldb_tmp_dir;
             if (!g_lldb_tmp_dir)
             {
                 const char *tmpdir_cstr = getenv("TMPDIR");
                 if (tmpdir_cstr == NULL)
                 {
                     tmpdir_cstr = getenv("TMP");
                     if (tmpdir_cstr == NULL)
                         tmpdir_cstr = getenv("TEMP");
                 }
                 if (tmpdir_cstr)
                 {
                     StreamString pid_tmpdir;
                     pid_tmpdir.Printf("%s/lldb", tmpdir_cstr);
                     if (Host::MakeDirectory(pid_tmpdir.GetString().c_str(), eFilePermissionsDirectoryDefault).Success())
                     {
                         pid_tmpdir.Printf("/%" PRIu64, Host::GetCurrentProcessID());
                         if (Host::MakeDirectory(pid_tmpdir.GetString().c_str(), eFilePermissionsDirectoryDefault).Success())
                         {
                             // Make an atexit handler to clean up the process specify LLDB temp dir
                             // and all of its contents.
                             ::atexit (CleanupProcessSpecificLLDBTempDir);
                             g_lldb_tmp_dir.SetCString(pid_tmpdir.GetString().c_str());
                             if (log)
                                 log->Printf("Host::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_lldb_tmp_dir.GetCString());
                             
                         }
                     }
                 }
             }
             file_spec.GetDirectory() = g_lldb_tmp_dir;
             return (bool)file_spec.GetDirectory();
         }
     }
 
     return false;
 }
 
+int
+Host::CreateTemporaryFile (const char *directory,
+                           const char *pathTemplate,
+                           FileSpec &result)
+{
+    FileSpec templateFileSpec(directory, false);
+    templateFileSpec.AppendPathComponent(pathTemplate);
+    int result_fd = -1;
+    llvm::SmallString<64> result_path;
+    std::error_code error = llvm::sys::fs::createUniqueFile(templateFileSpec.GetPath(), result_fd, result_path);
+    return (error) ? -1 : result_fd;
+}
+
+
 
 bool
 Host::GetHostname (std::string &s)
 {
     char hostname[PATH_MAX];
     hostname[sizeof(hostname) - 1] = '\0';
     if (::gethostname (hostname, sizeof(hostname) - 1) == 0)
     {
         struct hostent* h = ::gethostbyname (hostname);
         if (h)
             s.assign (h->h_name);
         else
             s.assign (hostname);
         return true;
     }
     return false;
 }
 
 #ifndef _WIN32
 
 const char *
 Host::GetUserName (uint32_t uid, std::string &user_name)
 {
     struct passwd user_info;
     struct passwd *user_info_ptr = &user_info;
     char user_buffer[PATH_MAX];
     size_t user_buffer_size = sizeof(user_buffer);
     if (::getpwuid_r (uid,
                       &user_info,
                       user_buffer,
                       user_buffer_size,
                       &user_info_ptr) == 0)
     {
         if (user_info_ptr)
         {
             user_name.assign (user_info_ptr->pw_name);
             return user_name.c_str();
         }
     }
     user_name.clear();
     return NULL;
 }
 
 const char *
 Host::GetGroupName (uint32_t gid, std::string &group_name)
 {
     char group_buffer[PATH_MAX];
     size_t group_buffer_size = sizeof(group_buffer);
     struct group group_info;
     struct group *group_info_ptr = &group_info;
     // Try the threadsafe version first
     if (::getgrgid_r (gid,
                       &group_info,
                       group_buffer,
                       group_buffer_size,
                       &group_info_ptr) == 0)
     {
         if (group_info_ptr)
         {
             group_name.assign (group_info_ptr->gr_name);
             return group_name.c_str();
         }
     }
     else
     {
         // The threadsafe version isn't currently working
         // for me on darwin, but the non-threadsafe version 
         // is, so I am calling it below.
         group_info_ptr = ::getgrgid (gid);
         if (group_info_ptr)
         {
             group_name.assign (group_info_ptr->gr_name);
             return group_name.c_str();
         }
     }
     group_name.clear();
     return NULL;
 }
 
 uint32_t
 Host::GetUserID ()
 {
     return getuid();
 }
 
 uint32_t
 Host::GetGroupID ()
 {
     return getgid();
 }
 
 uint32_t
 Host::GetEffectiveUserID ()
 {
     return geteuid();
 }
 
 uint32_t
 Host::GetEffectiveGroupID ()
 {
     return getegid();
 }
 
 #endif
 
 #if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) // see macosx/Host.mm
 bool
 Host::GetOSBuildString (std::string &s)
 {
     s.clear();
     return false;
 }
 
 bool
 Host::GetOSKernelDescription (std::string &s)
 {
     s.clear();
     return false;
 }
 #endif
 
 #if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) \
     && !defined(__linux__) && !defined(_WIN32)
 uint32_t
 Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
 {
     process_infos.Clear();
     return process_infos.GetSize();
 }
 
 bool
 Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
 {
     process_info.Clear();
     return false;
 }
 #endif
 
 #if !defined(__linux__)
 bool
 Host::FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach)
 {
     return false;
 }
 #endif
 
 lldb::TargetSP
 Host::GetDummyTarget (lldb_private::Debugger &debugger)
 {
     static TargetSP g_dummy_target_sp;
 
     // FIXME: Maybe the dummy target should be per-Debugger
     if (!g_dummy_target_sp || !g_dummy_target_sp->IsValid())
     {
         ArchSpec arch(Target::GetDefaultArchitecture());
         if (!arch.IsValid())
             arch = Host::GetArchitecture ();
         Error err = debugger.GetTargetList().CreateTarget(debugger, 
                                                           NULL,
                                                           arch.GetTriple().getTriple().c_str(),
                                                           false, 
                                                           NULL, 
                                                           g_dummy_target_sp);
     }
 
     return g_dummy_target_sp;
 }
 
 struct ShellInfo
 {
     ShellInfo () :
         process_reaped (false),
         can_delete (false),
         pid (LLDB_INVALID_PROCESS_ID),
         signo(-1),
         status(-1)
     {
     }
 
     lldb_private::Predicate<bool> process_reaped;
     lldb_private::Predicate<bool> can_delete;
     lldb::pid_t pid;
     int signo;
     int status;
 };
 
 static bool
 MonitorShellCommand (void *callback_baton,
                      lldb::pid_t pid,
                      bool exited,       // True if the process did exit
                      int signo,         // Zero for no signal
                      int status)   // Exit value of process if signal is zero
 {
     ShellInfo *shell_info = (ShellInfo *)callback_baton;
     shell_info->pid = pid;
     shell_info->signo = signo;
     shell_info->status = status;
     // Let the thread running Host::RunShellCommand() know that the process
     // exited and that ShellInfo has been filled in by broadcasting to it
     shell_info->process_reaped.SetValue(1, eBroadcastAlways);
     // Now wait for a handshake back from that thread running Host::RunShellCommand
     // so we know that we can delete shell_info_ptr
     shell_info->can_delete.WaitForValueEqualTo(true);
     // Sleep a bit to allow the shell_info->can_delete.SetValue() to complete...
     usleep(1000);
     // Now delete the shell info that was passed into this function
     delete shell_info;
     return true;
 }
 
 Error
 Host::RunShellCommand (const char *command,
                        const char *working_dir,
                        int *status_ptr,
                        int *signo_ptr,
                        std::string *command_output_ptr,
                        uint32_t timeout_sec,
                        const char *shell)
 {
     Error error;
     ProcessLaunchInfo launch_info;
     if (shell && shell[0])
     {
         // Run the command in a shell
         launch_info.SetShell(shell);
         launch_info.GetArguments().AppendArgument(command);
         const bool localhost = true;
         const bool will_debug = false;
         const bool first_arg_is_full_shell_command = true;
         launch_info.ConvertArgumentsForLaunchingInShell (error,
                                                          localhost,
                                                          will_debug,
                                                          first_arg_is_full_shell_command,
                                                          0);
     }
     else
     {
         // No shell, just run it
         Args args (command);
         const bool first_arg_is_executable = true;
         launch_info.SetArguments(args, first_arg_is_executable);
     }
     
     if (working_dir)
         launch_info.SetWorkingDirectory(working_dir);
     char output_file_path_buffer[PATH_MAX];
     const char *output_file_path = NULL;
     
     if (command_output_ptr)
     {
         // Create a temporary file to get the stdout/stderr and redirect the
         // output of the command into this file. We will later read this file
         // if all goes well and fill the data into "command_output_ptr"
         FileSpec tmpdir_file_spec;
         if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
         {
             tmpdir_file_spec.GetFilename().SetCString("lldb-shell-output.XXXXXX");
             strncpy(output_file_path_buffer, tmpdir_file_spec.GetPath().c_str(), sizeof(output_file_path_buffer));
         }
         else
         {
             strncpy(output_file_path_buffer, "/tmp/lldb-shell-output.XXXXXX", sizeof(output_file_path_buffer));
         }
         
         output_file_path = ::mktemp(output_file_path_buffer);
     }
     
     launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false);
     if (output_file_path)
     {
         launch_info.AppendOpenFileAction(STDOUT_FILENO, output_file_path, false, true);
         launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO);
     }
     else
     {
         launch_info.AppendSuppressFileAction (STDOUT_FILENO, false, true);
         launch_info.AppendSuppressFileAction (STDERR_FILENO, false, true);
     }
     
     // The process monitor callback will delete the 'shell_info_ptr' below...
     std::unique_ptr<ShellInfo> shell_info_ap (new ShellInfo());
     
     const bool monitor_signals = false;
     launch_info.SetMonitorProcessCallback(MonitorShellCommand, shell_info_ap.get(), monitor_signals);
     
     error = LaunchProcess (launch_info);
     const lldb::pid_t pid = launch_info.GetProcessID();
 
     if (error.Success() && pid == LLDB_INVALID_PROCESS_ID)
         error.SetErrorString("failed to get process ID");
 
     if (error.Success())
     {
         // The process successfully launched, so we can defer ownership of
         // "shell_info" to the MonitorShellCommand callback function that will
         // get called when the process dies. We release the unique pointer as it
         // doesn't need to delete the ShellInfo anymore.
         ShellInfo *shell_info = shell_info_ap.release();
         TimeValue *timeout_ptr = nullptr;
         TimeValue timeout_time(TimeValue::Now());
         if (timeout_sec > 0) {
             timeout_time.OffsetWithSeconds(timeout_sec);
             timeout_ptr = &timeout_time;
         }
         bool timed_out = false;
         shell_info->process_reaped.WaitForValueEqualTo(true, timeout_ptr, &timed_out);
         if (timed_out)
         {
             error.SetErrorString("timed out waiting for shell command to complete");
 
             // Kill the process since it didn't complete within the timeout specified
             Kill (pid, SIGKILL);
             // Wait for the monitor callback to get the message
             timeout_time = TimeValue::Now();
             timeout_time.OffsetWithSeconds(1);
             timed_out = false;
             shell_info->process_reaped.WaitForValueEqualTo(true, &timeout_time, &timed_out);
         }
         else
         {
             if (status_ptr)
                 *status_ptr = shell_info->status;
 
             if (signo_ptr)
                 *signo_ptr = shell_info->signo;
 
             if (command_output_ptr)
             {
                 command_output_ptr->clear();
                 FileSpec file_spec(output_file_path, File::eOpenOptionRead);
                 uint64_t file_size = file_spec.GetByteSize();
                 if (file_size > 0)
                 {
                     if (file_size > command_output_ptr->max_size())
                     {
                         error.SetErrorStringWithFormat("shell command output is too large to fit into a std::string");
                     }
                     else
                     {
                         command_output_ptr->resize(file_size);
                         file_spec.ReadFileContents(0, &((*command_output_ptr)[0]), command_output_ptr->size(), &error);
                     }
                 }
             }
         }
         shell_info->can_delete.SetValue(true, eBroadcastAlways);
     }
 
     if (output_file_path)
         ::unlink (output_file_path);
     // Handshake with the monitor thread, or just let it know in advance that
     // it can delete "shell_info" in case we timed out and were not able to kill
     // the process...
     return error;
 }
 
 
 // LaunchProcessPosixSpawn for Apple, Linux, FreeBSD and other GLIBC
 // systems
 
 #if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__)
 
 // this method needs to be visible to macosx/Host.cpp and
 // common/Host.cpp.
 
 short
 Host::GetPosixspawnFlags (ProcessLaunchInfo &launch_info)
 {
     short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
 
 #if defined (__APPLE__)
     if (launch_info.GetFlags().Test (eLaunchFlagExec))
         flags |= POSIX_SPAWN_SETEXEC;           // Darwin specific posix_spawn flag
     
     if (launch_info.GetFlags().Test (eLaunchFlagDebug))
         flags |= POSIX_SPAWN_START_SUSPENDED;   // Darwin specific posix_spawn flag
     
     if (launch_info.GetFlags().Test (eLaunchFlagDisableASLR))
         flags |= _POSIX_SPAWN_DISABLE_ASLR;     // Darwin specific posix_spawn flag
         
     if (launch_info.GetLaunchInSeparateProcessGroup())
         flags |= POSIX_SPAWN_SETPGROUP;
     
 #ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
 #if defined (__APPLE__) && (defined (__x86_64__) || defined (__i386__))
     static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate;
     if (g_use_close_on_exec_flag == eLazyBoolCalculate)
     {
         g_use_close_on_exec_flag = eLazyBoolNo;
         
         uint32_t major, minor, update;
         if (Host::GetOSVersion(major, minor, update))
         {
             // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or earlier
             if (major > 10 || (major == 10 && minor > 7))
             {
                 // Only enable for 10.8 and later OS versions
                 g_use_close_on_exec_flag = eLazyBoolYes;
             }
         }
     }
 #else
     static LazyBool g_use_close_on_exec_flag = eLazyBoolYes;
 #endif
     // Close all files exception those with file actions if this is supported.
     if (g_use_close_on_exec_flag == eLazyBoolYes)
         flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;
 #endif
 #endif // #if defined (__APPLE__)
     return flags;
 }
 
 Error
 Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, ::pid_t &pid)
 {
     Error error;
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
 
     posix_spawnattr_t attr;
     error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX);
 
     if (error.Fail() || log)
         error.PutToLog(log, "::posix_spawnattr_init ( &attr )");
     if (error.Fail())
         return error;
 
     // Make a quick class that will cleanup the posix spawn attributes in case
     // we return in the middle of this function.
     lldb_utility::CleanUp <posix_spawnattr_t *, int> posix_spawnattr_cleanup(&attr, posix_spawnattr_destroy);
 
     sigset_t no_signals;
     sigset_t all_signals;
     sigemptyset (&no_signals);
     sigfillset (&all_signals);
     ::posix_spawnattr_setsigmask(&attr, &no_signals);
 #if defined (__linux__)  || defined (__FreeBSD__)
     ::posix_spawnattr_setsigdefault(&attr, &no_signals);
 #else
     ::posix_spawnattr_setsigdefault(&attr, &all_signals);
 #endif
 
     short flags = GetPosixspawnFlags(launch_info);
 
     error.SetError( ::posix_spawnattr_setflags (&attr, flags), eErrorTypePOSIX);
     if (error.Fail() || log)
         error.PutToLog(log, "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", flags);
     if (error.Fail())
         return error;
 
     // posix_spawnattr_setbinpref_np appears to be an Apple extension per:
     // http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/
 #if defined (__APPLE__) && !defined (__arm__)
     
     // Don't set the binpref if a shell was provided.  After all, that's only going to affect what version of the shell
     // is launched, not what fork of the binary is launched.  We insert "arch --arch <ARCH> as part of the shell invocation
     // to do that job on OSX.
     
     if (launch_info.GetShell() == nullptr)
     {
         // We don't need to do this for ARM, and we really shouldn't now that we
         // have multiple CPU subtypes and no posix_spawnattr call that allows us
         // to set which CPU subtype to launch...
         const ArchSpec &arch_spec = launch_info.GetArchitecture();
         cpu_type_t cpu = arch_spec.GetMachOCPUType();
         cpu_type_t sub = arch_spec.GetMachOCPUSubType();
         if (cpu != 0 &&
             cpu != static_cast<cpu_type_t>(UINT32_MAX) &&
             cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE) &&
             !(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try to set the CPU type or we will fail 
         {
             size_t ocount = 0;
             error.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &ocount), eErrorTypePOSIX);
             if (error.Fail() || log)
                 error.PutToLog(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %llu )", cpu, (uint64_t)ocount);
 
             if (error.Fail() || ocount != 1)
                 return error;
         }
     }
 
 #endif
 
     const char *tmp_argv[2];
     char * const *argv = (char * const*)launch_info.GetArguments().GetConstArgumentVector();
     char * const *envp = (char * const*)launch_info.GetEnvironmentEntries().GetConstArgumentVector();
     if (argv == NULL)
     {
         // posix_spawn gets very unhappy if it doesn't have at least the program
         // name in argv[0]. One of the side affects I have noticed is the environment
         // variables don't make it into the child process if "argv == NULL"!!!
         tmp_argv[0] = exe_path;
         tmp_argv[1] = NULL;
         argv = (char * const*)tmp_argv;
     }
 
 #if !defined (__APPLE__)
     // manage the working directory
     char current_dir[PATH_MAX];
     current_dir[0] = '\0';
 #endif
 
     const char *working_dir = launch_info.GetWorkingDirectory();
     if (working_dir)
     {
 #if defined (__APPLE__)
         // Set the working directory on this thread only
         if (__pthread_chdir (working_dir) < 0) {
             if (errno == ENOENT) {
                 error.SetErrorStringWithFormat("No such file or directory: %s", working_dir);
             } else if (errno == ENOTDIR) {
                 error.SetErrorStringWithFormat("Path doesn't name a directory: %s", working_dir);
             } else {
                 error.SetErrorStringWithFormat("An unknown error occurred when changing directory for process execution.");
             }
             return error;
         }
 #else
         if (::getcwd(current_dir, sizeof(current_dir)) == NULL)
         {
             error.SetError(errno, eErrorTypePOSIX);
             error.LogIfError(log, "unable to save the current directory");
             return error;
         }
 
         if (::chdir(working_dir) == -1)
         {
             error.SetError(errno, eErrorTypePOSIX);
             error.LogIfError(log, "unable to change working directory to %s", working_dir);
             return error;
         }
 #endif
     }
 
     const size_t num_file_actions = launch_info.GetNumFileActions ();
     if (num_file_actions > 0)
     {
         posix_spawn_file_actions_t file_actions;
         error.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX);
         if (error.Fail() || log)
             error.PutToLog(log, "::posix_spawn_file_actions_init ( &file_actions )");
         if (error.Fail())
             return error;
 
         // Make a quick class that will cleanup the posix spawn attributes in case
         // we return in the middle of this function.
         lldb_utility::CleanUp <posix_spawn_file_actions_t *, int> posix_spawn_file_actions_cleanup (&file_actions, posix_spawn_file_actions_destroy);
 
         for (size_t i=0; i<num_file_actions; ++i)
         {
             const ProcessLaunchInfo::FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i);
             if (launch_file_action)
             {
                 if (!ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (&file_actions,
                                                                              launch_file_action,
                                                                              log,
                                                                              error))
                     return error;
             }
         }
 
         error.SetError (::posix_spawnp (&pid,
                                         exe_path,
                                         &file_actions,
                                         &attr,
                                         argv,
                                         envp),
                         eErrorTypePOSIX);
 
         if (error.Fail() || log)
         {
             error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )",
                            pid, exe_path, static_cast<void*>(&file_actions),
                            static_cast<void*>(&attr),
                            reinterpret_cast<const void*>(argv),
                            reinterpret_cast<const void*>(envp));
             if (log)
             {
                 for (int ii=0; argv[ii]; ++ii)
                     log->Printf("argv[%i] = '%s'", ii, argv[ii]);
             }
         }
 
     }
     else
     {
         error.SetError (::posix_spawnp (&pid,
                                         exe_path,
                                         NULL,
                                         &attr,
                                         argv,
                                         envp),
                         eErrorTypePOSIX);
 
         if (error.Fail() || log)
         {
             error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = NULL, attr = %p, argv = %p, envp = %p )",
                            pid, exe_path, static_cast<void*>(&attr),
                            reinterpret_cast<const void*>(argv),
                            reinterpret_cast<const void*>(envp));
             if (log)
             {
                 for (int ii=0; argv[ii]; ++ii)
                     log->Printf("argv[%i] = '%s'", ii, argv[ii]);
             }
         }
     }
 
     if (working_dir)
     {
 #if defined (__APPLE__)
         // No more thread specific current working directory
         __pthread_fchdir (-1);
 #else
         if (::chdir(current_dir) == -1 && error.Success())
         {
             error.SetError(errno, eErrorTypePOSIX);
             error.LogIfError(log, "unable to change current directory back to %s",
                     current_dir);
         }
 #endif
     }
 
     return error;
 }
 
 #endif // LaunchProcedssPosixSpawn: Apple, Linux, FreeBSD and other GLIBC systems
 
 
 #if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) || defined(__NetBSD__)
 // The functions below implement process launching via posix_spawn() for Linux,
 // FreeBSD and NetBSD.
 
 Error
 Host::LaunchProcess (ProcessLaunchInfo &launch_info)
 {
     Error error;
     char exe_path[PATH_MAX];
 
     PlatformSP host_platform_sp (Platform::GetDefaultPlatform ());
 
     const ArchSpec &arch_spec = launch_info.GetArchitecture();
 
     FileSpec exe_spec(launch_info.GetExecutableFile());
 
     FileSpec::FileType file_type = exe_spec.GetFileType();
     if (file_type != FileSpec::eFileTypeRegular)
     {
         lldb::ModuleSP exe_module_sp;
         error = host_platform_sp->ResolveExecutable (exe_spec,
                                                      arch_spec,
                                                      exe_module_sp,
                                                      NULL);
 
         if (error.Fail())
             return error;
 
         if (exe_module_sp)
             exe_spec = exe_module_sp->GetFileSpec();
     }
 
     if (exe_spec.Exists())
     {
         exe_spec.GetPath (exe_path, sizeof(exe_path));
     }
     else
     {
         launch_info.GetExecutableFile().GetPath (exe_path, sizeof(exe_path));
         error.SetErrorStringWithFormat ("executable doesn't exist: '%s'", exe_path);
         return error;
     }
 
     assert(!launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY));
 
     ::pid_t pid = LLDB_INVALID_PROCESS_ID;
 
     error = LaunchProcessPosixSpawn(exe_path, launch_info, pid);
 
     if (pid != LLDB_INVALID_PROCESS_ID)
     {
         // If all went well, then set the process ID into the launch info
         launch_info.SetProcessID(pid);
 
         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
 
         // Make sure we reap any processes we spawn or we will have zombies.
         if (!launch_info.MonitorProcess())
         {
             const bool monitor_signals = false;
             StartMonitoringChildProcess (Process::SetProcessExitStatus,
                                          NULL,
                                          pid,
                                          monitor_signals);
             if (log)
                 log->PutCString ("monitored child process with default Process::SetProcessExitStatus.");
         }
         else
         {
             if (log)
                 log->PutCString ("monitored child process with user-specified process monitor.");
         }
     }
     else
     {
         // Invalid process ID, something didn't go well
         if (error.Success())
             error.SetErrorString ("process launch failed for unknown reasons");
     }
     return error;
 }
 
 #endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
 
 #ifndef _WIN32
 
 size_t
 Host::GetPageSize()
 {
     return ::getpagesize();
 }
 
 uint32_t
 Host::GetNumberCPUS ()
 {
     static uint32_t g_num_cores = UINT32_MAX;
     if (g_num_cores == UINT32_MAX)
     {
 #if defined(__APPLE__) or defined (__linux__) or defined (__FreeBSD__) or defined (__FreeBSD_kernel__)
 
         g_num_cores = ::sysconf(_SC_NPROCESSORS_ONLN);
 
 #else
         
         // Assume POSIX support if a host specific case has not been supplied above
         g_num_cores = 0;
         int num_cores = 0;
         size_t num_cores_len = sizeof(num_cores);
 #ifdef HW_AVAILCPU
         int mib[] = { CTL_HW, HW_AVAILCPU };
 #else
         int mib[] = { CTL_HW, HW_NCPU };
 #endif
         
         /* get the number of CPUs from the system */
         if (sysctl(mib, llvm::array_lengthof(mib), &num_cores, &num_cores_len, NULL, 0) == 0 && (num_cores > 0))
         {
             g_num_cores = num_cores;
         }
         else
         {
             mib[1] = HW_NCPU;
             num_cores_len = sizeof(num_cores);
             if (sysctl(mib, llvm::array_lengthof(mib), &num_cores, &num_cores_len, NULL, 0) == 0 && (num_cores > 0))
             {
                 if (num_cores > 0)
                     g_num_cores = num_cores;
             }
         }
 #endif
     }
     return g_num_cores;
 }
 
 void
 Host::Kill(lldb::pid_t pid, int signo)
 {
     ::kill(pid, signo);
 }
 
 #endif
 
 #if !defined (__APPLE__)
 bool
 Host::OpenFileInExternalEditor (const FileSpec &file_spec, uint32_t line_no)
 {
     return false;
 }
 
 void
 Host::SetCrashDescriptionWithFormat (const char *format, ...)
 {
 }
 
 void
 Host::SetCrashDescription (const char *description)
 {
 }
 
 lldb::pid_t
 Host::LaunchApplication (const FileSpec &app_file_spec)
 {
     return LLDB_INVALID_PROCESS_ID;
 }
 
 #endif
 
 
 #ifdef LLDB_DISABLE_POSIX
 
 Error
 Host::MakeDirectory (const char* path, uint32_t mode)
 {
     Error error;
     error.SetErrorStringWithFormat("%s in not implemented on this host", __PRETTY_FUNCTION__);
     return error;
 }
 
 Error
 Host::GetFilePermissions (const char* path, uint32_t &file_permissions)
 {
     Error error;
     error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
     return error;
 }
 
 Error
 Host::SetFilePermissions (const char* path, uint32_t file_permissions)
 {
     Error error;
     error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
     return error;
 }
 
 Error
 Host::Symlink (const char *src, const char *dst)
 {
     Error error;
     error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
     return error;
 }
 
 Error
 Host::Readlink (const char *path, char *buf, size_t buf_len)
 {
     Error error;
     error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
     return error;
 }
 
 Error
 Host::Unlink (const char *path)
 {
     Error error;
     error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
     return error;
 }
 
 Error
 Host::RemoveDirectory (const char* path, bool recurse)
 {
     Error error;
     error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
     return error;
 }
 
 #else
 
 Error
 Host::MakeDirectory (const char* path, uint32_t file_permissions)
 {
     Error error;
     if (path && path[0])
     {
         if (::mkdir(path, file_permissions) != 0)
         {
             error.SetErrorToErrno();
             switch (error.GetError())
             {
             case ENOENT:
                 {
                     // Parent directory doesn't exist, so lets make it if we can
                     FileSpec spec(path, false);
                     if (spec.GetDirectory() && spec.GetFilename())
                     {
                         // Make the parent directory and try again
                         Error error2 = Host::MakeDirectory(spec.GetDirectory().GetCString(), file_permissions);
                         if (error2.Success())
                         {
                             // Try and make the directory again now that the parent directory was made successfully
                             if (::mkdir(path, file_permissions) == 0)
                                 error.Clear();
                             else
                                 error.SetErrorToErrno();
                         }
                     }
                 }
                 break;
             case EEXIST:
                 {
                     FileSpec path_spec(path, false);
                     if (path_spec.IsDirectory())
                         error.Clear(); // It is a directory and it already exists
                 }
                 break;
             }
         }
     }
     else
     {
         error.SetErrorString("empty path");
     }
     return error;
 }
                                                                     
 Error
 Host::RemoveDirectory (const char* path, bool recurse)
 {
     Error error;
     if (path && path[0])
     {
         if (recurse)
         {
             StreamString command;
             command.Printf("rm -rf \"%s\"", path);
             int status = ::system(command.GetString().c_str());
             if (status != 0)
                 error.SetError(status, eErrorTypeGeneric);
         }
         else
         {
             if (::rmdir(path) != 0)
                 error.SetErrorToErrno();
         }
     }
     else
     {
         error.SetErrorString("empty path");
     }
     return error;
 }
 
 Error
 Host::GetFilePermissions (const char* path, uint32_t &file_permissions)
 {
     Error error;
     struct stat file_stats;
     if (::stat (path, &file_stats) == 0)
     {
         // The bits in "st_mode" currently match the definitions
         // for the file mode bits in unix.
         file_permissions = file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
     }
     else
     {
         error.SetErrorToErrno();
     }
     return error;
 }
 
 Error
 Host::SetFilePermissions (const char* path, uint32_t file_permissions)
 {
     Error error;
     if (::chmod(path, file_permissions) != 0)
         error.SetErrorToErrno();
     return error;
 }
 
 Error
 Host::Symlink (const char *src, const char *dst)
 {
     Error error;
     if (::symlink(dst, src) == -1)
         error.SetErrorToErrno();
     return error;
 }
 
 Error
 Host::Unlink (const char *path)
 {
     Error error;
     if (::unlink(path) == -1)
         error.SetErrorToErrno();
     return error;
 }
 
 Error
 Host::Readlink (const char *path, char *buf, size_t buf_len)
 {
     Error error;
     ssize_t count = ::readlink(path, buf, buf_len);
     if (count < 0)
         error.SetErrorToErrno();
     else if (static_cast<size_t>(count) < (buf_len-1))
         buf[count] = '\0'; // Success
     else
         error.SetErrorString("'buf' buffer is too small to contain link contents");
     return error;
 }
 
 
 #endif
 
 typedef std::map<lldb::user_id_t, lldb::FileSP> FDToFileMap;
 FDToFileMap& GetFDToFileMap()
 {
     static FDToFileMap g_fd2filemap;
     return g_fd2filemap;
 }
 
 lldb::user_id_t
 Host::OpenFile (const FileSpec& file_spec,
                 uint32_t flags,
                 uint32_t mode,
                 Error &error)
 {
     std::string path (file_spec.GetPath());
     if (path.empty())
     {
         error.SetErrorString("empty path");
         return UINT64_MAX;
     }
     FileSP file_sp(new File());
     error = file_sp->Open(path.c_str(),flags,mode);
     if (file_sp->IsValid() == false)
         return UINT64_MAX;
     lldb::user_id_t fd = file_sp->GetDescriptor();
     GetFDToFileMap()[fd] = file_sp;
     return fd;
 }
 
 bool
 Host::CloseFile (lldb::user_id_t fd, Error &error)
 {
     if (fd == UINT64_MAX)
     {
         error.SetErrorString ("invalid file descriptor");
         return false;
     }
     FDToFileMap& file_map = GetFDToFileMap();
     FDToFileMap::iterator pos = file_map.find(fd);
     if (pos == file_map.end())
     {
         error.SetErrorStringWithFormat ("invalid host file descriptor %" PRIu64, fd);
         return false;
     }
     FileSP file_sp = pos->second;
     if (!file_sp)
     {
         error.SetErrorString ("invalid host backing file");
         return false;
     }
     error = file_sp->Close();
     file_map.erase(pos);
     return error.Success();
 }
 
 uint64_t
 Host::WriteFile (lldb::user_id_t fd, uint64_t offset, const void* src, uint64_t src_len, Error &error)
 {
     if (fd == UINT64_MAX)
     {
         error.SetErrorString ("invalid file descriptor");
         return UINT64_MAX;
     }
     FDToFileMap& file_map = GetFDToFileMap();
     FDToFileMap::iterator pos = file_map.find(fd);
     if (pos == file_map.end())
     {
         error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64 , fd);
         return false;
     }
     FileSP file_sp = pos->second;
     if (!file_sp)
     {
         error.SetErrorString ("invalid host backing file");
         return UINT64_MAX;
     }
     if (static_cast<uint64_t>(file_sp->SeekFromStart(offset, &error)) != offset ||
         error.Fail())
         return UINT64_MAX;
     size_t bytes_written = src_len;
     error = file_sp->Write(src, bytes_written);
     if (error.Fail())
         return UINT64_MAX;
     return bytes_written;
 }
 
 uint64_t
 Host::ReadFile (lldb::user_id_t fd, uint64_t offset, void* dst, uint64_t dst_len, Error &error)
 {
     if (fd == UINT64_MAX)
     {
         error.SetErrorString ("invalid file descriptor");
         return UINT64_MAX;
     }
     FDToFileMap& file_map = GetFDToFileMap();
     FDToFileMap::iterator pos = file_map.find(fd);
     if (pos == file_map.end())
     {
         error.SetErrorStringWithFormat ("invalid host file descriptor %" PRIu64, fd);
         return false;
     }
     FileSP file_sp = pos->second;
     if (!file_sp)
     {
         error.SetErrorString ("invalid host backing file");
         return UINT64_MAX;
     }
     if (static_cast<uint64_t>(file_sp->SeekFromStart(offset, &error)) != offset ||
         error.Fail())
         return UINT64_MAX;
     size_t bytes_read = dst_len;
     error = file_sp->Read(dst ,bytes_read);
     if (error.Fail())
         return UINT64_MAX;
     return bytes_read;
 }
 
 lldb::user_id_t
 Host::GetFileSize (const FileSpec& file_spec)
 {
     return file_spec.GetByteSize();
 }
 
 bool
 Host::GetFileExists (const FileSpec& file_spec)
 {
     return file_spec.Exists();
 }
 
 bool
 Host::CalculateMD5 (const FileSpec& file_spec,
                     uint64_t &low,
                     uint64_t &high)
 {
 #if defined (__APPLE__)
     StreamString md5_cmd_line;
     md5_cmd_line.Printf("md5 -q '%s'", file_spec.GetPath().c_str());
     std::string hash_string;
     Error err = Host::RunShellCommand(md5_cmd_line.GetData(), NULL, NULL, NULL, &hash_string, 60);
     if (err.Fail())
         return false;
     // a correctly formed MD5 is 16-bytes, that is 32 hex digits
     // if the output is any other length it is probably wrong
     if (hash_string.size() != 32)
         return false;
     std::string part1(hash_string,0,16);
     std::string part2(hash_string,16);
     const char* part1_cstr = part1.c_str();
     const char* part2_cstr = part2.c_str();
     high = ::strtoull(part1_cstr, NULL, 16);
     low = ::strtoull(part2_cstr, NULL, 16);
     return true;
 #else
     // your own MD5 implementation here
     return false;
 #endif
 }
diff --git a/tools/driver/Driver.cpp b/tools/driver/Driver.cpp
index 0d0d03d..7f79e69 100644
--- a/tools/driver/Driver.cpp
+++ b/tools/driver/Driver.cpp
@@ -1,1057 +1,1058 @@
 //===-- Driver.cpp ----------------------------------------------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 
 #include "Driver.h"
 
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <limits.h>
 #include <fcntl.h>
 
 #include <string>
 
 #include <thread>
 #include "lldb/API/SBBreakpoint.h"
 #include "lldb/API/SBCommandInterpreter.h"
 #include "lldb/API/SBCommandReturnObject.h"
 #include "lldb/API/SBCommunication.h"
 #include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBEvent.h"
 #include "lldb/API/SBHostOS.h"
 #include "lldb/API/SBListener.h"
 #include "lldb/API/SBStream.h"
 #include "lldb/API/SBTarget.h"
 #include "lldb/API/SBThread.h"
 #include "lldb/API/SBProcess.h"
 
 using namespace lldb;
 
 static void reset_stdin_termios ();
 static bool g_old_stdin_termios_is_valid = false;
 static struct termios g_old_stdin_termios;
 
 static char *g_debugger_name =  (char *) "";
 static Driver *g_driver = NULL;
 
 // In the Driver::MainLoop, we change the terminal settings.  This function is
 // added as an atexit handler to make sure we clean them up.
 static void
 reset_stdin_termios ()
 {
     if (g_old_stdin_termios_is_valid)
     {
         g_old_stdin_termios_is_valid = false;
         ::tcsetattr (STDIN_FILENO, TCSANOW, &g_old_stdin_termios);
     }
 }
 
 typedef struct
 {
     uint32_t usage_mask;                     // Used to mark options that can be used together.  If (1 << n & usage_mask) != 0
                                              // then this option belongs to option set n.
     bool required;                           // This option is required (in the current usage level)
     const char * long_option;                // Full name for this option.
     int short_option;                        // Single character for this option.
     int option_has_arg;                      // no_argument, required_argument or optional_argument
     uint32_t completion_type;                // Cookie the option class can use to do define the argument completion.
     lldb::CommandArgumentType argument_type; // Type of argument this option takes
     const char *  usage_text;                // Full text explaining what this options does and what (if any) argument to
                                              // pass it.
 } OptionDefinition;
 
 #define LLDB_3_TO_5 LLDB_OPT_SET_3|LLDB_OPT_SET_4|LLDB_OPT_SET_5
 #define LLDB_4_TO_5 LLDB_OPT_SET_4|LLDB_OPT_SET_5
 
 static OptionDefinition g_options[] =
 {
     { LLDB_OPT_SET_1,    true , "help"           , 'h', no_argument      , 0,  eArgTypeNone,
         "Prints out the usage information for the LLDB debugger." },
     { LLDB_OPT_SET_2,    true , "version"        , 'v', no_argument      , 0,  eArgTypeNone,
         "Prints out the current version number of the LLDB debugger." },
     { LLDB_OPT_SET_3,    true , "arch"           , 'a', required_argument, 0,  eArgTypeArchitecture,
         "Tells the debugger to use the specified architecture when starting and running the program.  <architecture> must "
         "be one of the architectures for which the program was compiled." },
     { LLDB_OPT_SET_3,    true , "file"           , 'f', required_argument, 0,  eArgTypeFilename,
         "Tells the debugger to use the file <filename> as the program to be debugged." },
     { LLDB_OPT_SET_3,    false, "core"           , 'c', required_argument, 0,  eArgTypeFilename,
         "Tells the debugger to use the fullpath to <path> as the core file." },
     { LLDB_OPT_SET_5,    true , "attach-pid"     , 'p', required_argument, 0,  eArgTypePid,
         "Tells the debugger to attach to a process with the given pid." },
     { LLDB_OPT_SET_4,    true , "attach-name"    , 'n', required_argument, 0,  eArgTypeProcessName,
         "Tells the debugger to attach to a process with the given name." },
     { LLDB_OPT_SET_4,    true , "wait-for"       , 'w', no_argument      , 0,  eArgTypeNone,
         "Tells the debugger to wait for a process with the given pid or name to launch before attaching." },
     { LLDB_3_TO_5,       false, "source"         , 's', required_argument, 0,  eArgTypeFilename,
         "Tells the debugger to read in and execute the lldb commands in the given file, after any file provided on the command line has been loaded." },
     { LLDB_3_TO_5,       false, "one-line"         , 'o', required_argument, 0,  eArgTypeNone,
         "Tells the debugger to execute this one-line lldb command after any file provided on the command line has been loaded." },
     { LLDB_3_TO_5,       false, "source-before-file"         , 'S', required_argument, 0,  eArgTypeFilename,
         "Tells the debugger to read in and execute the lldb commands in the given file, before any file provided on the command line has been loaded." },
     { LLDB_3_TO_5,       false, "one-line-before-file"         , 'O', required_argument, 0,  eArgTypeNone,
         "Tells the debugger to execute this one-line lldb command before any file provided on the command line has been loaded." },
     { LLDB_3_TO_5,       false, "source-quietly"          , 'Q', no_argument      , 0,  eArgTypeNone,
         "Tells the debugger suppress output from commands provided in the -s, -S, -O and -o commands." },
     { LLDB_3_TO_5,       false, "editor"         , 'e', no_argument      , 0,  eArgTypeNone,
         "Tells the debugger to open source files using the host's \"external editor\" mechanism." },
     { LLDB_3_TO_5,       false, "no-lldbinit"    , 'x', no_argument      , 0,  eArgTypeNone,
         "Do not automatically parse any '.lldbinit' files." },
     { LLDB_3_TO_5,       false, "no-use-colors"  , 'X', no_argument      , 0,  eArgTypeNone,
         "Do not use colors." },
     { LLDB_OPT_SET_6,    true , "python-path"    , 'P', no_argument      , 0,  eArgTypeNone,
         "Prints out the path to the lldb.py file for this version of lldb." },
     { LLDB_3_TO_5,       false, "script-language", 'l', required_argument, 0,  eArgTypeScriptLang,
         "Tells the debugger to use the specified scripting language for user-defined scripts, rather than the default.  "
         "Valid scripting languages that can be specified include Python, Perl, Ruby and Tcl.  Currently only the Python "
         "extensions have been implemented." },
     { LLDB_3_TO_5,       false, "debug"          , 'd', no_argument      , 0,  eArgTypeNone,
         "Tells the debugger to print out extra information for debugging itself." },
     { 0,                 false, NULL             , 0  , 0                , 0,  eArgTypeNone,         NULL }
 };
 
 static const uint32_t last_option_set_with_args = 2;
 
 Driver::Driver () :
     SBBroadcaster ("Driver"),
     m_debugger (SBDebugger::Create(false)),
     m_option_data ()
 {
     // We want to be able to handle CTRL+D in the terminal to have it terminate
     // certain input
     m_debugger.SetCloseInputOnEOF (false);
     g_debugger_name = (char *) m_debugger.GetInstanceName();
     if (g_debugger_name == NULL)
         g_debugger_name = (char *) "";
     g_driver = this;
 }
 
 Driver::~Driver ()
 {
     g_driver = NULL;
     g_debugger_name = NULL;
 }
 
 
 // This function takes INDENT, which tells how many spaces to output at the front
 // of each line; TEXT, which is the text that is to be output. It outputs the 
 // text, on multiple lines if necessary, to RESULT, with INDENT spaces at the 
 // front of each line.  It breaks lines on spaces, tabs or newlines, shortening 
 // the line if necessary to not break in the middle of a word. It assumes that 
 // each output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
 
 void
 OutputFormattedUsageText (FILE *out, int indent, const char *text, int output_max_columns)
 {
     int len = strlen (text);
     std::string text_string (text);
 
     // Force indentation to be reasonable.
     if (indent >= output_max_columns)
         indent = 0;
 
     // Will it all fit on one line?
 
     if (len + indent < output_max_columns)
         // Output as a single line
         fprintf (out, "%*s%s\n", indent, "", text);
     else
     {
         // We need to break it up into multiple lines.
         int text_width = output_max_columns - indent - 1;
         int start = 0;
         int end = start;
         int final_end = len;
         int sub_len;
 
         while (end < final_end)
         {
               // Dont start the 'text' on a space, since we're already outputting the indentation.
               while ((start < final_end) && (text[start] == ' '))
                   start++;
 
               end = start + text_width;
               if (end > final_end)
                   end = final_end;
               else
               {
                   // If we're not at the end of the text, make sure we break the line on white space.
                   while (end > start
                          && text[end] != ' ' && text[end] != '\t' && text[end] != '\n')
                       end--;
               }
               sub_len = end - start;
               std::string substring = text_string.substr (start, sub_len);
               fprintf (out, "%*s%s\n", indent, "", substring.c_str());
               start = end + 1;
         }
     }
 }
 
 void
 ShowUsage (FILE *out, OptionDefinition *option_table, Driver::OptionData data)
 {
     uint32_t screen_width = 80;
     uint32_t indent_level = 0;
     const char *name = "lldb";
     
     fprintf (out, "\nUsage:\n\n");
 
     indent_level += 2;
 
 
     // First, show each usage level set of options, e.g. <cmd> [options-for-level-0]
     //                                                   <cmd> [options-for-level-1]
     //                                                   etc.
 
     uint32_t num_options;
     uint32_t num_option_sets = 0;
     
     for (num_options = 0; option_table[num_options].long_option != NULL; ++num_options)
     {
         uint32_t this_usage_mask = option_table[num_options].usage_mask;
         if (this_usage_mask == LLDB_OPT_SET_ALL)
         {
             if (num_option_sets == 0)
                 num_option_sets = 1;
         }
         else
         {
             for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++)
             {
                 if (this_usage_mask & 1 << j)
                 {
                     if (num_option_sets <= j)
                         num_option_sets = j + 1;
                 }
             }
         }
     }
 
     for (uint32_t opt_set = 0; opt_set < num_option_sets; opt_set++)
     {
         uint32_t opt_set_mask;
         
         opt_set_mask = 1 << opt_set;
         
         if (opt_set > 0)
             fprintf (out, "\n");
         fprintf (out, "%*s%s", indent_level, "", name);
         bool is_help_line = false;
         
         for (uint32_t i = 0; i < num_options; ++i)
         {
             if (option_table[i].usage_mask & opt_set_mask)
             {
                 CommandArgumentType arg_type = option_table[i].argument_type;
                 const char *arg_name = SBCommandInterpreter::GetArgumentTypeAsCString (arg_type);
                 // This is a bit of a hack, but there's no way to say certain options don't have arguments yet...
                 // so we do it by hand here.
                 if (option_table[i].short_option == 'h')
                     is_help_line = true;
                     
                 if (option_table[i].required)
                 {
                     if (option_table[i].option_has_arg == required_argument)
                         fprintf (out, " -%c <%s>", option_table[i].short_option, arg_name);
                     else if (option_table[i].option_has_arg == optional_argument)
                         fprintf (out, " -%c [<%s>]", option_table[i].short_option, arg_name);
                     else
                         fprintf (out, " -%c", option_table[i].short_option);
                 }
                 else
                 {
                     if (option_table[i].option_has_arg == required_argument)
                         fprintf (out, " [-%c <%s>]", option_table[i].short_option, arg_name);
                     else if (option_table[i].option_has_arg == optional_argument)
                         fprintf (out, " [-%c [<%s>]]", option_table[i].short_option, arg_name);
                     else
                         fprintf (out, " [-%c]", option_table[i].short_option);
                 }
             }
         }
         if (!is_help_line && (opt_set <= last_option_set_with_args))
             fprintf (out, " [[--] <PROGRAM-ARG-1> [<PROGRAM_ARG-2> ...]]");
     }
 
     fprintf (out, "\n\n");
 
     // Now print out all the detailed information about the various options:  long form, short form and help text:
     //   -- long_name <argument>
     //   - short <argument>
     //   help text
 
     // This variable is used to keep track of which options' info we've printed out, because some options can be in
     // more than one usage level, but we only want to print the long form of its information once.
 
     Driver::OptionData::OptionSet options_seen;
     Driver::OptionData::OptionSet::iterator pos;
 
     indent_level += 5;
 
     for (uint32_t i = 0; i < num_options; ++i)
     {
         // Only print this option if we haven't already seen it.
         pos = options_seen.find (option_table[i].short_option);
         if (pos == options_seen.end())
         {
             CommandArgumentType arg_type = option_table[i].argument_type;
             const char *arg_name = SBCommandInterpreter::GetArgumentTypeAsCString (arg_type);
 
             options_seen.insert (option_table[i].short_option);
             fprintf (out, "%*s-%c ", indent_level, "", option_table[i].short_option);
             if (arg_type != eArgTypeNone)
                 fprintf (out, "<%s>", arg_name);
             fprintf (out, "\n");
             fprintf (out, "%*s--%s ", indent_level, "", option_table[i].long_option);
             if (arg_type != eArgTypeNone)
                 fprintf (out, "<%s>", arg_name);
             fprintf (out, "\n");
             indent_level += 5;
             OutputFormattedUsageText (out, indent_level, option_table[i].usage_text, screen_width);
             indent_level -= 5;
             fprintf (out, "\n");
         }
     }
 
     indent_level -= 5;
     
     fprintf (out, "\n%*sNotes:\n",
              indent_level, "");
     indent_level += 5;
     
     fprintf (out, "\n%*sMultiple \"-s\" and \"-o\" options can be provided.  They will be processed from left to right in order, "
                   "\n%*swith the source files and commands interleaved.  The same is true of the \"-S\" and \"-O\" options."
                   "\n%*sThe before file and after file sets can intermixed freely, the command parser will sort them out."
                   "\n%*sThe order of the file specifiers (\"-c\", \"-f\", etc.) is not significant in this regard.\n\n",
              indent_level, "", 
              indent_level, "", 
              indent_level, "",
              indent_level, "");
     
     fprintf (out, "\n%*sIf you don't provide -f then the first argument will be the file to be debugged"
                   "\n%*swhich means that '%s -- <filename> [<ARG1> [<ARG2>]]' also works."
                   "\n%*sBut remember to end the options with \"--\" if any of your arguments have a \"-\" in them.\n\n",
              indent_level, "", 
              indent_level, "",
              name, 
              indent_level, "");
 }
 
 void
 BuildGetOptTable (OptionDefinition *expanded_option_table, std::vector<struct option> &getopt_table, 
                   uint32_t num_options)
 {
     if (num_options == 0)
         return;
 
     uint32_t i;
     uint32_t j;
     std::bitset<256> option_seen;
 
     getopt_table.resize (num_options + 1);
 
     for (i = 0, j = 0; i < num_options; ++i)
     {
         char short_opt = expanded_option_table[i].short_option;
         
         if (option_seen.test(short_opt) == false)
         {
             getopt_table[j].name    = expanded_option_table[i].long_option;
             getopt_table[j].has_arg = expanded_option_table[i].option_has_arg;
             getopt_table[j].flag    = NULL;
             getopt_table[j].val     = expanded_option_table[i].short_option;
             option_seen.set(short_opt);
             ++j;
         }
     }
 
     getopt_table[j].name    = NULL;
     getopt_table[j].has_arg = 0;
     getopt_table[j].flag    = NULL;
     getopt_table[j].val     = 0;
 
 }
 
 Driver::OptionData::OptionData () :
     m_args(),
     m_script_lang (lldb::eScriptLanguageDefault),
     m_core_file (),
     m_crash_log (),
     m_initial_commands (),
     m_after_file_commands (),
     m_debug_mode (false),
     m_source_quietly(false),
     m_print_version (false),
     m_print_python_path (false),
     m_print_help (false),
     m_wait_for(false),
     m_process_name(),
     m_process_pid(LLDB_INVALID_PROCESS_ID),
     m_use_external_editor(false),
     m_seen_options()
 {
 }
 
 Driver::OptionData::~OptionData ()
 {
 }
 
 void
 Driver::OptionData::Clear ()
 {
     m_args.clear ();
     m_script_lang = lldb::eScriptLanguageDefault;
     m_initial_commands.clear ();
     m_after_file_commands.clear ();
     m_debug_mode = false;
     m_source_quietly = false;
     m_print_help = false;
     m_print_version = false;
     m_print_python_path = false;
     m_use_external_editor = false;
     m_wait_for = false;
     m_process_name.erase();
     m_process_pid = LLDB_INVALID_PROCESS_ID;
 }
 
 void
 Driver::OptionData::AddInitialCommand (const char *command, bool before_file, bool is_file, SBError &error)
 {
     std::vector<std::pair<bool, std::string> > *command_set;
     if (before_file)
         command_set = &(m_initial_commands);
     else
         command_set = &(m_after_file_commands);
 
     if (is_file)
     {
         SBFileSpec file(command);
         if (file.Exists())
             command_set->push_back (std::pair<bool, std::string> (true, optarg));
         else if (file.ResolveExecutableLocation())
         {
             char final_path[PATH_MAX];
             file.GetPath (final_path, sizeof(final_path));
             std::string path_str (final_path);
             command_set->push_back (std::pair<bool, std::string> (true, path_str));
         }
         else
             error.SetErrorStringWithFormat("file specified in --source (-s) option doesn't exist: '%s'", optarg);
     }
     else
         command_set->push_back (std::pair<bool, std::string> (false, optarg));
 }
 
 void
 Driver::ResetOptionValues ()
 {
     m_option_data.Clear ();
 }
 
 const char *
 Driver::GetFilename() const
 {
     if (m_option_data.m_args.empty())
         return NULL;
     return m_option_data.m_args.front().c_str();
 }
 
 const char *
 Driver::GetCrashLogFilename() const
 {
     if (m_option_data.m_crash_log.empty())
         return NULL;
     return m_option_data.m_crash_log.c_str();
 }
 
 lldb::ScriptLanguage
 Driver::GetScriptLanguage() const
 {
     return m_option_data.m_script_lang;
 }
 
 void
 Driver::WriteInitialCommands (bool before_file, SBStream &strm)
 {
     std::vector<std::pair<bool, std::string> > &command_set = before_file ? m_option_data.m_initial_commands :
                                                                             m_option_data.m_after_file_commands;
     
     for (const auto &command_pair : command_set)
     {
         const char *command = command_pair.second.c_str();
         if (command_pair.first)
             strm.Printf("command source -s %i '%s'\n", m_option_data.m_source_quietly, command);
         else
             strm.Printf("%s\n", command);
     }
 }
 
 bool
 Driver::GetDebugMode() const
 {
     return m_option_data.m_debug_mode;
 }
 
 
 // Check the arguments that were passed to this program to make sure they are valid and to get their
 // argument values (if any).  Return a boolean value indicating whether or not to start up the full
 // debugger (i.e. the Command Interpreter) or not.  Return FALSE if the arguments were invalid OR
 // if the user only wanted help or version information.
 
 SBError
 Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exiting)
 {
     ResetOptionValues ();
 
     SBCommandReturnObject result;
 
     SBError error;
     std::string option_string;
     struct option *long_options = NULL;
     std::vector<struct option> long_options_vector;
     uint32_t num_options;
 
     for (num_options = 0; g_options[num_options].long_option != NULL; ++num_options)
         /* Do Nothing. */;
 
     if (num_options == 0)
     {
         if (argc > 1)
             error.SetErrorStringWithFormat ("invalid number of options");
         return error;
     }
 
     BuildGetOptTable (g_options, long_options_vector, num_options);
 
     if (long_options_vector.empty())
         long_options = NULL;
     else
         long_options = &long_options_vector.front();
 
     if (long_options == NULL)
     {
         error.SetErrorStringWithFormat ("invalid long options");
         return error;
     }
 
     // Build the option_string argument for call to getopt_long_only.
 
     for (int i = 0; long_options[i].name != NULL; ++i)
     {
         if (long_options[i].flag == NULL)
         {
             option_string.push_back ((char) long_options[i].val);
             switch (long_options[i].has_arg)
             {
                 default:
                 case no_argument:
                     break;
                 case required_argument:
                     option_string.push_back (':');
                     break;
                 case optional_argument:
                     option_string.append ("::");
                     break;
             }
         }
     }
 
     // This is kind of a pain, but since we make the debugger in the Driver's constructor, we can't
     // know at that point whether we should read in init files yet.  So we don't read them in in the
     // Driver constructor, then set the flags back to "read them in" here, and then if we see the
     // "-n" flag, we'll turn it off again.  Finally we have to read them in by hand later in the
     // main loop.
     
     m_debugger.SkipLLDBInitFiles (false);
     m_debugger.SkipAppInitFiles (false);
 
     // Prepare for & make calls to getopt_long_only.
 #if __GLIBC__
     optind = 0;
 #else
     optreset = 1;
     optind = 1;
 #endif
     int val;
     while (1)
     {
         int long_options_index = -1;
         val = ::getopt_long_only (argc, const_cast<char **>(argv), option_string.c_str(), long_options, &long_options_index);
 
         if (val == -1)
             break;
         else if (val == '?')
         {
             m_option_data.m_print_help = true;
             error.SetErrorStringWithFormat ("unknown or ambiguous option");
             break;
         }
         else if (val == 0)
             continue;
         else
         {
             m_option_data.m_seen_options.insert ((char) val);
             if (long_options_index == -1)
             {
                 for (int i = 0;
                      long_options[i].name || long_options[i].has_arg || long_options[i].flag || long_options[i].val;
                      ++i)
                 {
                     if (long_options[i].val == val)
                     {
                         long_options_index = i;
                         break;
                     }
                 }
             }
 
             if (long_options_index >= 0)
             {
                 const int short_option = g_options[long_options_index].short_option;
 
                 switch (short_option)
                 {
                     case 'h':
                         m_option_data.m_print_help = true;
                         break;
 
                     case 'v':
                         m_option_data.m_print_version = true;
                         break;
 
                     case 'P':
                         m_option_data.m_print_python_path = true;
                         break;
 
                     case 'c':
                         {
                             SBFileSpec file(optarg);
                             if (file.Exists())
                             {
                                 m_option_data.m_core_file = optarg;
                             }
                             else
                                 error.SetErrorStringWithFormat("file specified in --core (-c) option doesn't exist: '%s'", optarg);
                         }
                         break;
                     
                     case 'e':
                         m_option_data.m_use_external_editor = true;
                         break;
 
                     case 'x':
                         m_debugger.SkipLLDBInitFiles (true);
                         m_debugger.SkipAppInitFiles (true);
                         break;
 
                     case 'X':
                         m_debugger.SetUseColor (false);
                         break;
 
                     case 'f':
                         {
                             SBFileSpec file(optarg);
                             if (file.Exists())
                             {
                                 m_option_data.m_args.push_back (optarg);
                             }
                             else if (file.ResolveExecutableLocation())
                             {
                                 char path[PATH_MAX];
                                 file.GetPath (path, sizeof(path));
                                 m_option_data.m_args.push_back (path);
                             }
                             else
                                 error.SetErrorStringWithFormat("file specified in --file (-f) option doesn't exist: '%s'", optarg);
                         }
                         break;
 
                     case 'a':
                         if (!m_debugger.SetDefaultArchitecture (optarg))
                             error.SetErrorStringWithFormat("invalid architecture in the -a or --arch option: '%s'", optarg);
                         break;
 
                     case 'l':
                         m_option_data.m_script_lang = m_debugger.GetScriptingLanguage (optarg);
                         break;
 
                     case 'd':
                         m_option_data.m_debug_mode = true;
                         break;
 
                     case 'Q':
                         m_option_data.m_source_quietly = true;
                         break;
 
                     case 'n':
                         m_option_data.m_process_name = optarg;
                         break;
                     
                     case 'w':
                         m_option_data.m_wait_for = true;
                         break;
                         
                     case 'p':
                         {
                             char *remainder;
                             m_option_data.m_process_pid = strtol (optarg, &remainder, 0);
                             if (remainder == optarg || *remainder != '\0')
                                 error.SetErrorStringWithFormat ("Could not convert process PID: \"%s\" into a pid.",
                                                                 optarg);
                         }
                         break;
                     case 's':
                         m_option_data.AddInitialCommand(optarg, false, true, error);
                         break;
                     case 'o':
                         m_option_data.AddInitialCommand(optarg, false, false, error);
                         break;
                     case 'S':
                         m_option_data.AddInitialCommand(optarg, true, true, error);
                         break;
                     case 'O':
                         m_option_data.AddInitialCommand(optarg, true, false, error);
                         break;
                     default:
                         m_option_data.m_print_help = true;
                         error.SetErrorStringWithFormat ("unrecognized option %c", short_option);
                         break;
                 }
             }
             else
             {
                 error.SetErrorStringWithFormat ("invalid option with value %i", val);
             }
             if (error.Fail())
             {
                 return error;
             }
         }
     }
     
     if (error.Fail() || m_option_data.m_print_help)
     {
         ShowUsage (out_fh, g_options, m_option_data);
         exiting = true;
     }
     else if (m_option_data.m_print_version)
     {
         ::fprintf (out_fh, "%s\n", m_debugger.GetVersionString());
         exiting = true;
     }
     else if (m_option_data.m_print_python_path)
     {
         SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();
         if (python_file_spec.IsValid())
         {
             char python_path[PATH_MAX];
             size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX);
             if (num_chars < PATH_MAX)
             {
                 ::fprintf (out_fh, "%s\n", python_path);
             }
             else
                 ::fprintf (out_fh, "<PATH TOO LONG>\n");
         }
         else
             ::fprintf (out_fh, "<COULD NOT FIND PATH>\n");
         exiting = true;
     }
     else if (m_option_data.m_process_name.empty() && m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID)
     {
         // Any arguments that are left over after option parsing are for
         // the program. If a file was specified with -f then the filename
         // is already in the m_option_data.m_args array, and any remaining args
         // are arguments for the inferior program. If no file was specified with
         // -f, then what is left is the program name followed by any arguments.
 
         // Skip any options we consumed with getopt_long_only
         argc -= optind;
         argv += optind;
 
         if (argc > 0)
         {
             for (int arg_idx=0; arg_idx<argc; ++arg_idx)
             {
                 const char *arg = argv[arg_idx];
                 if (arg)
                     m_option_data.m_args.push_back (arg);
             }
         }
         
     }
     else
     {
         // Skip any options we consumed with getopt_long_only
         argc -= optind;
         //argv += optind; // Commented out to keep static analyzer happy
 
         if (argc > 0)
             ::fprintf (out_fh, "Warning: program arguments are ignored when attaching.\n");
     }
 
     return error;
 }
 
 void
 Driver::MainLoop ()
 {
     if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0)
     {
         g_old_stdin_termios_is_valid = true;
         atexit (reset_stdin_termios);
     }
 
     ::setbuf (stdin, NULL);
     ::setbuf (stdout, NULL);
 
     m_debugger.SetErrorFileHandle (stderr, false);
     m_debugger.SetOutputFileHandle (stdout, false);
     m_debugger.SetInputFileHandle (stdin, false); // Don't take ownership of STDIN yet...
 
     m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
 
     struct winsize window_size;
     if (isatty (STDIN_FILENO)
         && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
     {
         if (window_size.ws_col > 0)
             m_debugger.SetTerminalWidth (window_size.ws_col);
     }
 
     SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
     
     // Before we handle any options from the command line, we parse the
     // .lldbinit file in the user's home directory.
     SBCommandReturnObject result;
     sb_interpreter.SourceInitFileInHomeDirectory(result);
     if (GetDebugMode())
     {
         result.PutError (m_debugger.GetErrorFileHandle());
         result.PutOutput (m_debugger.GetOutputFileHandle());
     }
 
     // Now we handle options we got from the command line
     SBStream commands_stream;
     
     // First source in the commands specified to be run before the file arguments are processed.
     WriteInitialCommands(true, commands_stream);
         
     const size_t num_args = m_option_data.m_args.size();
     if (num_args > 0)
     {
         commands_stream.Printf("target create \"%s\"", m_option_data.m_args[0].c_str());
         if (!m_option_data.m_core_file.empty())
         {
             commands_stream.Printf(" --core \"%s\"", m_option_data.m_core_file.c_str());
         }
         commands_stream.Printf("\n");
         
         if (num_args > 1)
         {
             commands_stream.Printf ("settings set -- target.run-args ");
             for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
             {
                 const char *arg_cstr = m_option_data.m_args[arg_idx].c_str();
                 if (strchr(arg_cstr, '"') == NULL)
                     commands_stream.Printf(" \"%s\"", arg_cstr);
                 else
                     commands_stream.Printf(" '%s'", arg_cstr);
             }
             commands_stream.Printf("\n");
         }
     }
     else if (!m_option_data.m_core_file.empty())
     {
         commands_stream.Printf("target create --core \"%s\"\n", m_option_data.m_core_file.c_str());
     }
     else if (!m_option_data.m_process_name.empty())
     {
         commands_stream.Printf ("process attach --name \"%s\"", m_option_data.m_process_name.c_str());
         
         if (m_option_data.m_wait_for)
             commands_stream.Printf(" --waitfor");
 
         commands_stream.Printf("\n");
 
     }
     else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid)
     {
         commands_stream.Printf ("process attach --pid %" PRIu64 "\n", m_option_data.m_process_pid);
     }
 
     WriteInitialCommands(false, commands_stream);
     
     // Now that all option parsing is done, we try and parse the .lldbinit
     // file in the current working directory
     sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result);
     if (GetDebugMode())
     {
         result.PutError(m_debugger.GetErrorFileHandle());
         result.PutOutput(m_debugger.GetOutputFileHandle());
     }
     
     bool handle_events = true;
     bool spawn_thread = false;
 
     // Check if we have any data in the commands stream, and if so, save it to a temp file
     // so we can then run the command interpreter using the file contents. 
     if (commands_stream.GetData() && commands_stream.GetSize())
     {
-        char lldb_cmds_file[PATH_MAX];
+        char lldb_cmds_dir[PATH_MAX];
         SBFileSpec lldb_temp_dir_spec = SBHostOS::GetLLDBPath (lldb::ePathTypeLLDBTempSystemDir);
-        lldb_temp_dir_spec.SetFilename("lldb-cmds.XXXXXX");
         
-        if (lldb_temp_dir_spec.GetPath(lldb_cmds_file, sizeof(lldb_cmds_file)))
+        if (lldb_temp_dir_spec.GetPath(lldb_cmds_dir, sizeof(lldb_cmds_dir)))
         {
-            int fd = mkstemp(lldb_cmds_file);
+            SBFileSpec lldb_cmds_file_spec;
+            int fd = SBHostOS::CreateTemporaryFile(lldb_cmds_dir, "lldb-cmds.%%%%%%", lldb_cmds_file_spec);
             if (fd == -1)
             {
                 fprintf(stderr, "error: can't create temporary file for LLDB commands\n");
                 exit (1);
             }
             FILE *file = fdopen(fd, "r+");
             if (file == NULL)
             {
                 fprintf(stderr, "error: fdopen(%i, \"r+\") failed (errno = %i)\n", fd, errno);
                 exit (2);
             }
             // Redirect the stream to a file and it will save its temp buffer out to the file on disk
             commands_stream.RedirectToFileHandle(file, true);
 
             // Close the stream which will close the file and flush it to disk
             commands_stream.Clear();
             
             // Now re-open the file so we can use it as an input file handle for the real
             // command interpreter
-            FILE *commands_file = ::fopen(lldb_cmds_file, "r");
+            lldb_cmds_file_spec.GetPath(lldb_cmds_dir, sizeof(lldb_cmds_dir));
+            FILE *commands_file = ::fopen(lldb_cmds_dir, "r");
             if (commands_file)
             {
                 // Hand ownership over to the debugger for "commands_file".
                 m_debugger.SetInputFileHandle (commands_file, true);
                 m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
             }
             else
             {
-                fprintf(stderr, "error: fopen(\"%s\", \"r\") failed (errno = %i) when trying to open LLDB commands file\n", lldb_cmds_file, errno);
+                fprintf(stderr, "error: fopen(\"%s\", \"r\") failed (errno = %i) when trying to open LLDB commands file\n", lldb_cmds_dir, errno);
                 exit (3);
             }
         }
     }
 
     // Now set the input file handle to STDIN and run the command
     // interpreter again in interactive mode and let the debugger
     // take ownership of stdin
     m_debugger.SetInputFileHandle (stdin, true);
     m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
     
     reset_stdin_termios();
     fclose (stdin);
     
     SBDebugger::Destroy (m_debugger);
 }
 
 
 void
 Driver::ResizeWindow (unsigned short col)
 {
     GetDebugger().SetTerminalWidth (col);
 }
 
 void
 sigwinch_handler (int signo)
 {
     struct winsize window_size;
     if (isatty (STDIN_FILENO)
         && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
     {
         if ((window_size.ws_col > 0) && g_driver != NULL)
         {
             g_driver->ResizeWindow (window_size.ws_col);
         }
     }
 }
 
 void
 sigint_handler (int signo)
 {
 	static bool g_interrupt_sent = false;
     if (g_driver)
 	{
 		if (!g_interrupt_sent)
 		{
 			g_interrupt_sent = true;
         	g_driver->GetDebugger().DispatchInputInterrupt();
 			g_interrupt_sent = false;
 			return;
 		}
 	}
     
 	exit (signo);
 }
 
 void
 sigtstp_handler (int signo)
 {
     g_driver->GetDebugger().SaveInputTerminalState();
     signal (signo, SIG_DFL);
     kill (getpid(), signo);
     signal (signo, sigtstp_handler);
 }
 
 void
 sigcont_handler (int signo)
 {
     g_driver->GetDebugger().RestoreInputTerminalState();
     signal (signo, SIG_DFL);
     kill (getpid(), signo);
     signal (signo, sigcont_handler);
 }
 
 int
 main (int argc, char const *argv[], const char *envp[])
 {
 #ifdef _MSC_VER
 	// disable buffering on windows
 	setvbuf(stdout, NULL, _IONBF, 0);
 	setvbuf(stdin , NULL, _IONBF, 0);
 #endif
 
     SBDebugger::Initialize();
     
     SBHostOS::ThreadCreated ("<lldb.driver.main-thread>");
 
     signal (SIGPIPE, SIG_IGN);
     signal (SIGWINCH, sigwinch_handler);
     signal (SIGINT, sigint_handler);
     signal (SIGTSTP, sigtstp_handler);
     signal (SIGCONT, sigcont_handler);
 
     // Create a scope for driver so that the driver object will destroy itself
     // before SBDebugger::Terminate() is called.
     {
         Driver driver;
 
         bool exiting = false;
         SBError error (driver.ParseArgs (argc, argv, stdout, exiting));
         if (error.Fail())
         {
             const char *error_cstr = error.GetCString ();
             if (error_cstr)
                 ::fprintf (stderr, "error: %s\n", error_cstr);
         }
         else if (!exiting)
         {
             driver.MainLoop ();
         }
     }
 
     SBDebugger::Terminate();
     return 0;
 }


More information about the lldb-commits mailing list