[Lldb-commits] [lldb] r189295 - merge lldb-platform-work branch (and assorted fixes) into trunk

Daniel Malea daniel.malea at intel.com
Mon Aug 26 16:57:53 PDT 2013


Author: dmalea
Date: Mon Aug 26 18:57:52 2013
New Revision: 189295

URL: http://llvm.org/viewvc/llvm-project?rev=189295&view=rev
Log:
merge lldb-platform-work branch (and assorted fixes) into trunk

    Summary:
    This merge brings in the improved 'platform' command that knows how to
    interface with remote machines; that is, query OS/kernel information, push
    and pull files, run shell commands, etc... and implementation for the new
    communication packets that back that interface, at least on Darwin based
    operating systems via the POSIXPlatform class. Linux support is coming soon.

    Verified the test suite runs cleanly on Linux (x86_64), build OK on Mac OS
    X Mountain Lion.

    Additional improvements (not in the source SVN branch 'lldb-platform-work'):
    - cmake build scripts for lldb-platform
    - cleanup test suite
    - documentation stub for qPlatform_RunCommand
    - use log class instead of printf() directly
    - reverted work-in-progress-looking changes from test/types/TestAbstract.py that work towards running the test suite remotely.
    - add new logging category 'platform'

    Reviewers: Matt Kopec, Greg Clayton

    Review: http://llvm-reviews.chandlerc.com/D1493



Added:
    lldb/trunk/include/lldb/Core/StreamGDBRemote.h
    lldb/trunk/source/Core/StreamGDBRemote.cpp
    lldb/trunk/source/Plugins/Platform/POSIX/
    lldb/trunk/source/Plugins/Platform/POSIX/CMakeLists.txt
    lldb/trunk/source/Plugins/Platform/POSIX/Makefile
    lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
    lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.h
    lldb/trunk/tools/lldb-platform/CMakeLists.txt
Modified:
    lldb/trunk/docs/lldb-gdb-remote.txt
    lldb/trunk/include/lldb/Host/File.h
    lldb/trunk/include/lldb/Host/FileSpec.h
    lldb/trunk/include/lldb/Host/Host.h
    lldb/trunk/include/lldb/Interpreter/Options.h
    lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h
    lldb/trunk/include/lldb/Target/Platform.h
    lldb/trunk/include/lldb/Target/Process.h
    lldb/trunk/include/lldb/lldb-enumerations.h
    lldb/trunk/include/lldb/lldb-forward.h
    lldb/trunk/include/lldb/lldb-private-log.h
    lldb/trunk/lib/Makefile
    lldb/trunk/lldb.xcodeproj/project.pbxproj
    lldb/trunk/scripts/Python/python-wrapper.swig
    lldb/trunk/source/API/SBValue.cpp
    lldb/trunk/source/CMakeLists.txt
    lldb/trunk/source/Commands/CommandObjectPlatform.cpp
    lldb/trunk/source/Commands/CommandObjectTarget.cpp
    lldb/trunk/source/Core/CMakeLists.txt
    lldb/trunk/source/Core/Error.cpp
    lldb/trunk/source/Host/common/File.cpp
    lldb/trunk/source/Host/common/FileSpec.cpp
    lldb/trunk/source/Host/common/Host.cpp
    lldb/trunk/source/Host/freebsd/Host.cpp
    lldb/trunk/source/Host/macosx/Host.mm
    lldb/trunk/source/Interpreter/CommandObject.cpp
    lldb/trunk/source/Interpreter/Options.cpp
    lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp
    lldb/trunk/source/Plugins/Platform/CMakeLists.txt
    lldb/trunk/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
    lldb/trunk/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
    lldb/trunk/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
    lldb/trunk/source/Plugins/Platform/MacOSX/PlatformDarwin.h
    lldb/trunk/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp
    lldb/trunk/source/Plugins/Platform/MacOSX/PlatformMacOSX.h
    lldb/trunk/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp
    lldb/trunk/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h
    lldb/trunk/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp
    lldb/trunk/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h
    lldb/trunk/source/Plugins/Platform/Makefile
    lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
    lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
    lldb/trunk/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
    lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
    lldb/trunk/source/Target/Platform.cpp
    lldb/trunk/source/Utility/StringExtractor.cpp
    lldb/trunk/source/Utility/StringExtractor.h
    lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp
    lldb/trunk/source/Utility/StringExtractorGDBRemote.h
    lldb/trunk/source/lldb-log.cpp
    lldb/trunk/source/lldb.cpp
    lldb/trunk/test/api/check_public_api_headers/TestPublicAPIHeaders.py
    lldb/trunk/test/api/multithreaded/TestMultithreaded.py
    lldb/trunk/test/dotest.py
    lldb/trunk/test/functionalities/abbreviation/TestAbbreviations.py
    lldb/trunk/test/functionalities/conditional_break/.lldb
    lldb/trunk/test/functionalities/conditional_break/TestConditionalBreak.py
    lldb/trunk/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py
    lldb/trunk/test/functionalities/inferior-changed/TestInferiorChanged.py
    lldb/trunk/test/functionalities/load_unload/TestLoadUnload.py
    lldb/trunk/test/functionalities/process_launch/TestProcessLaunch.py
    lldb/trunk/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py
    lldb/trunk/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py
    lldb/trunk/test/lang/c/blocks/TestBlocks.py
    lldb/trunk/test/lldbtest.py
    lldb/trunk/test/macosx/universal/TestUniversal.py
    lldb/trunk/test/python_api/hello_world/TestHelloWorld.py
    lldb/trunk/test/python_api/process/TestProcessAPI.py
    lldb/trunk/test/python_api/target/TestTargetAPI.py
    lldb/trunk/test/settings/TestSettings.py
    lldb/trunk/tools/CMakeLists.txt
    lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj
    lldb/trunk/tools/lldb-platform/lldb-platform.cpp

Modified: lldb/trunk/docs/lldb-gdb-remote.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/docs/lldb-gdb-remote.txt?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/docs/lldb-gdb-remote.txt (original)
+++ lldb/trunk/docs/lldb-gdb-remote.txt Mon Aug 26 18:57:52 2013
@@ -421,6 +421,20 @@ invalidate-regs
             change depending on if the mode has changed. 
 
 //----------------------------------------------------------------------
+// "qPlatform_RunCommand"
+//
+// BRIEF
+//  Run a command in a shell on the connected remote machine.
+//
+// PRIORITY TO IMPLEMENT
+//  TODO
+//----------------------------------------------------------------------
+
+send packet: TODO (see GDBRemoteCommunicationClient::RunShellCommand)
+read packet: TODO (see GDBRemoteCommunicationServer::Handle_qPlatform_RunCommand)
+
+
+//----------------------------------------------------------------------
 // "qHostInfo"
 //
 // BRIEF
@@ -848,3 +862,123 @@ for this region.
 //  your debug session more reliable and informative.
 //----------------------------------------------------------------------
  
+
+//----------------------------------------------------------------------
+// PLATFORM EXTENSION - for use as a GDB remote platform
+//----------------------------------------------------------------------
+// "qfProcessInfo"
+// "qsProcessInfo"
+//
+// BRIEF
+//  Get the first process info (qfProcessInfo) or subsequent processs
+//  info (qsProcessInfo) for one or more processes on the remote 
+//  platform. The first call gets the first match and subsequent calls
+//  to qsProcessInfo gets the subsequent matches. Return an error EXX,
+//  where XX are two hex digits, when no more matches are available.
+//
+// PRIORITY TO IMPLEMENT
+//  Required. The qfProcessInfo packet can be followed by a ':' and
+//  some key value pairs. The key value pairs in the command are:
+//
+//  KEY           VALUE     DESCRIPTION
+//  ===========   ========  ================================================
+//  "name"        ascii-hex An ASCII hex string that contains the name of 
+//                          the process that will be matched.
+//  "name_match"  enum      One of: "equals", "starts_with", "ends_with", 
+//                          "contains" or "regex"
+//  "pid"         integer   A string value containing the decimal process ID
+//  "parent_pid"  integer   A string value containing the decimal parent 
+//                          process ID
+//  "uid"         integer   A string value containing the decimal user ID
+//  "gid"         integer   A string value containing the decimal group ID
+//  "euid"        integer   A string value containing the decimal effective user ID
+//  "egid"        integer   A string value containing the decimal effective group ID
+//  "all_users"   bool      A boolean value that specifies if processes should
+//                          be listed for all users, not just the user that the 
+//                          platform is running as
+//  "triple"      ascii-hex An ASCII hex target triple string ("x86_64", 
+//                          "x86_64-apple-macosx", "armv7-apple-ios")
+//
+// The response consists of key/value pairs where the key is separated from the
+// values with colons and each pair is terminated with a semi colon. For a list
+// of the key/value pairs in the response see the "qProcessInfoPID" packet
+// documentation.
+//
+// Sample packet/response:
+// send packet: $qfProcessInfo#00
+// read packet: $pid:60001;ppid:59948;uid:7746;gid:11;euid:7746;egid:11;name:6c6c6462;triple:7838365f36342d6170706c652d6d61636f7378;#00
+// send packet: $qsProcessInfo#00
+// read packet: $pid:59992;ppid:192;uid:7746;gid:11;euid:7746;egid:11;name:6d64776f726b6572;triple:7838365f36342d6170706c652d6d61636f7378;#00
+// send packet: $qsProcessInfo#00
+// read packet: $E04#00
+//----------------------------------------------------------------------
+
+
+//----------------------------------------------------------------------
+// PLATFORM EXTENSION - for use as a GDB remote platform
+//----------------------------------------------------------------------
+// "qLaunchGDBServer"
+//
+// BRIEF
+//  Have the remote platform launch a GDB server.
+//
+// PRIORITY TO IMPLEMENT
+//  Required. The qLaunchGDBServer packet must be followed by a ':' and
+//  some key value pairs. The key value pairs in the command are:
+//
+//  KEY           VALUE     DESCRIPTION
+//  ===========   ========  ================================================
+//  "port"        integer   A string value containing the decimal port ID or
+//                          zero if the port should be bound and returned
+//
+//  "host"        integer   The host that connections should be limited to
+//                          when the GDB server is connected to.
+//
+// The response consists of key/value pairs where the key is separated from the
+// values with colons and each pair is terminated with a semi colon.
+//
+// Sample packet/response:
+// send packet: $qLaunchGDBServer:port:0;host:lldb.apple.com;#00
+// read packet: $pid:60025;port:50776;#00
+//
+// The "pid" key/value pair is only specified if the remote platform launched
+// a separate process for the GDB remote server and can be omitted if no
+// process was separately launched.
+//
+// The "port" key/value pair in the response lets clients know what port number
+// to attach to in case zero was specified as the "port" in the sent command.
+//----------------------------------------------------------------------
+
+
+//----------------------------------------------------------------------
+// PLATFORM EXTENSION - for use as a GDB remote platform
+//----------------------------------------------------------------------
+// "qProcessInfoPID:PID"
+//
+// BRIEF
+//  Have the remote platform get detailed information on a process by
+//  ID. PID is specified as a decimal integer.
+//
+// PRIORITY TO IMPLEMENT
+//  Optional. 
+//
+// The response consists of key/value pairs where the key is separated from the
+// values with colons and each pair is terminated with a semi colon.
+//
+// The key value pairs in the response are:
+//
+//  KEY           VALUE     DESCRIPTION
+//  ===========   ========  ================================================
+//  "pid"         integer   Process ID as a decimal integer string
+//  "ppid"        integer   Parent process ID as a decimal integer string
+//  "uid"         integer   A string value containing the decimal user ID
+//  "gid"         integer   A string value containing the decimal group ID
+//  "euid"        integer   A string value containing the decimal effective user ID
+//  "egid"        integer   A string value containing the decimal effective group ID
+//  "name"        ascii-hex An ASCII hex string that contains the name of the process
+//  "triple"      ascii-hex A target triple ("x86_64-apple-macosx", "armv7-apple-ios")
+//
+// Sample packet/response:
+// send packet: $qProcessInfoPID:60050#00
+// read packet: $pid:60050;ppid:59948;uid:7746;gid:11;euid:7746;egid:11;name:6c6c6462;triple:7838365f36342d6170706c652d6d61636f7378;#00
+//----------------------------------------------------------------------

Added: lldb/trunk/include/lldb/Core/StreamGDBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/StreamGDBRemote.h?rev=189295&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Core/StreamGDBRemote.h (added)
+++ lldb/trunk/include/lldb/Core/StreamGDBRemote.h Mon Aug 26 18:57:52 2013
@@ -0,0 +1,54 @@
+//===-- StreamGDBRemote.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_StreamGDBRemote_h_
+#define liblldb_StreamGDBRemote_h_
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Core/StreamString.h"
+
+namespace lldb_private {
+    
+    class StreamGDBRemote : public StreamString
+    {
+        public:
+        StreamGDBRemote ();
+        
+        StreamGDBRemote (uint32_t flags,
+                         uint32_t addr_size,
+                         lldb::ByteOrder byte_order);
+        
+        virtual
+        ~StreamGDBRemote ();
+        
+        //------------------------------------------------------------------
+        /// Output a block of data to the stream performing GDB-remote escaping.
+        ///
+        /// @param[in] s
+        ///     A block of data.
+        ///
+        /// @param[in] src_len
+        ///     The amount of data to write.
+        ///
+        /// @return
+        ///     Number of bytes written.
+        //------------------------------------------------------------------
+        int
+        PutEscapedBytes (const void* s,
+                         size_t src_len);
+    };
+
+} // namespace lldb_private
+
+#endif  // liblldb_StreamGDBRemote_h_

Modified: lldb/trunk/include/lldb/Host/File.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/File.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/File.h (original)
+++ lldb/trunk/include/lldb/Host/File.h Mon Aug 26 18:57:52 2013
@@ -41,17 +41,20 @@ public:
         eOpenOptionCanCreateNewOnly     = (1u << 6)     // Can create file only if it doesn't already exist
     };
     
+    static mode_t
+    ConvertOpenOptionsForPOSIXOpen (uint32_t open_options);
+    
     enum Permissions
     {
-        ePermissionsUserRead        = (1u << 0),
-        ePermissionsUserWrite       = (1u << 1),
-        ePermissionsUserExecute     = (1u << 2),
-        ePermissionsGroupRead       = (1u << 3),
+        ePermissionsUserRead        = (1u << 8),
+        ePermissionsUserWrite       = (1u << 7),
+        ePermissionsUserExecute     = (1u << 6),
+        ePermissionsGroupRead       = (1u << 5),
         ePermissionsGroupWrite      = (1u << 4),
-        ePermissionsGroupExecute    = (1u << 5),
-        ePermissionsWorldRead       = (1u << 6),
-        ePermissionsWorldWrite      = (1u << 7),
-        ePermissionsWorldExecute    = (1u << 8),
+        ePermissionsGroupExecute    = (1u << 3),
+        ePermissionsWorldRead       = (1u << 2),
+        ePermissionsWorldWrite      = (1u << 1),
+        ePermissionsWorldExecute    = (1u << 0),
 
         ePermissionsUserRW      = (ePermissionsUserRead    | ePermissionsUserWrite    | 0                        ),
         ePermissionsUserRX      = (ePermissionsUserRead    | 0                        | ePermissionsUserExecute  ),
@@ -117,6 +120,27 @@ public:
           uint32_t options,
           uint32_t permissions = ePermissionsDefault);
 
+    //------------------------------------------------------------------
+    /// Constructor with FileSpec.
+    ///
+    /// Takes a FileSpec pointing to a file which can be just a filename, or a full
+    /// path. If \a path is not NULL or empty, this function will call
+    /// File::Open (const char *path, uint32_t options, uint32_t permissions).
+    ///
+    /// @param[in] path
+    ///     The FileSpec for this file.
+    ///
+    /// @param[in] options
+    ///     Options to use when opening (see File::OpenOptions)
+    ///
+    /// @param[in] permissions
+    ///     Options to use when opening (see File::Permissions)
+    ///
+    /// @see File::Open (const char *path, uint32_t options, uint32_t permissions)
+    //------------------------------------------------------------------
+    File (const FileSpec& filespec,
+          uint32_t options,
+          uint32_t permissions = ePermissionsDefault);
     
     File (int fd, bool tranfer_ownership) : 
         m_descriptor (fd),
@@ -451,6 +475,19 @@ public:
     //------------------------------------------------------------------
     Error
     Sync ();
+    
+    //------------------------------------------------------------------
+    /// Get the permissions for a this file.
+    ///
+    /// @return
+    ///     Bits logical OR'ed together from the permission bits defined
+    ///     in lldb_private::File::Permissions.
+    //------------------------------------------------------------------
+    uint32_t
+    GetPermissions(Error &error) const;
+    
+    static uint32_t
+    GetPermissions (const char *path, Error &error);
 
     //------------------------------------------------------------------
     /// Output printf formatted output to the stream.

Modified: lldb/trunk/include/lldb/Host/FileSpec.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/FileSpec.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/FileSpec.h (original)
+++ lldb/trunk/include/lldb/Host/FileSpec.h Mon Aug 26 18:57:52 2013
@@ -624,6 +624,21 @@ public:
     static size_t
     Resolve (const char *src_path, char *dst_path, size_t dst_len);
 
+    FileSpec
+    CopyByAppendingPathComponent (const char *new_path) const;
+    
+    FileSpec
+    CopyByRemovingLastPathComponent () const;
+    
+    void
+    AppendPathComponent (const char *new_path);
+    
+    void
+    RemoveLastPathComponent ();
+    
+    const char*
+    GetLastPathComponent () const;
+    
     //------------------------------------------------------------------
     /// Resolves the user name at the beginning of \a src_path, and writes the output
     /// to \a dst_path.  Note, \a src_path can contain other path components after the

Modified: lldb/trunk/include/lldb/Host/Host.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/Host.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/Host.h (original)
+++ lldb/trunk/include/lldb/Host/Host.h Mon Aug 26 18:57:52 2013
@@ -18,6 +18,7 @@
 
 #include "lldb/lldb-private.h"
 #include "lldb/Core/StringList.h"
+#include "lldb/Host/File.h"
 
 namespace lldb_private {
 
@@ -508,6 +509,45 @@ public:
     DynamicLibraryGetSymbol (void *dynamic_library_handle, 
                              const char *symbol_name, 
                              Error &error);
+    
+    static uint32_t
+    MakeDirectory (const char* path, mode_t mode);
+    
+    static lldb::user_id_t
+    OpenFile (const FileSpec& file_spec,
+              uint32_t flags,
+              mode_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

Modified: lldb/trunk/include/lldb/Interpreter/Options.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/Options.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/Options.h (original)
+++ lldb/trunk/include/lldb/Interpreter/Options.h Mon Aug 26 18:57:52 2013
@@ -448,6 +448,12 @@ protected:
         void
         Finalize ();
         
+        bool
+        DidFinalize ()
+        {
+            return m_did_finalize;
+        }
+        
         virtual Error
         SetOptionValue (uint32_t option_idx, 
                         const char *option_arg);
@@ -464,6 +470,10 @@ protected:
             assert (m_did_finalize);
             return &m_option_defs[0];
         }
+        
+        const OptionGroup*
+        GetGroupWithOption (char short_opt);
+        
         struct OptionInfo
         {
             OptionInfo (OptionGroup* g, uint32_t i) :

Modified: lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h (original)
+++ lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h Mon Aug 26 18:57:52 2013
@@ -112,6 +112,7 @@ public:
     typedef void*          (*SWIGPythonGetChildAtIndex)                        (void *implementor, uint32_t idx);
     typedef int            (*SWIGPythonGetIndexOfChildWithName)                (void *implementor, const char* child_name);
     typedef void*          (*SWIGPythonCastPyObjectToSBValue)                  (void* data);
+    typedef lldb::ValueObjectSP  (*SWIGPythonGetValueObjectSPFromSBValue)      (void* data);
     typedef bool           (*SWIGPythonUpdateSynthProviderInstance)            (void* data);
     typedef bool           (*SWIGPythonMightHaveChildrenSynthProviderInstance) (void* data);
 

Modified: lldb/trunk/include/lldb/Target/Platform.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Platform.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Platform.h (original)
+++ lldb/trunk/include/lldb/Target/Platform.h Mon Aug 26 18:57:52 2013
@@ -22,6 +22,7 @@
 #include "lldb/Core/ArchSpec.h"
 #include "lldb/Core/ConstString.h"
 #include "lldb/Core/PluginInterface.h"
+#include "lldb/Interpreter/Options.h"
 #include "lldb/Host/Mutex.h"
 
 namespace lldb_private {
@@ -542,9 +543,190 @@ namespace lldb_private {
             return false;
         }
         
+        virtual uint32_t
+        MakeDirectory (const std::string &path,
+                       mode_t mode)
+        {
+            return UINT32_MAX;
+        }
+        
+        // this need not be virtual: the core behavior is in
+        // MakeDirectory(std::string,mode_t)
+        uint32_t
+        MakeDirectory (const FileSpec &spec,
+                       mode_t mode);
+        
+        virtual lldb::user_id_t
+        OpenFile (const FileSpec& file_spec,
+                  uint32_t flags,
+                  mode_t mode,
+                  Error &error)
+        {
+            return UINT64_MAX;
+        }
+        
+        virtual bool
+        CloseFile (lldb::user_id_t fd,
+                   Error &error)
+        {
+            return false;
+        }
+        
+        virtual lldb::user_id_t
+        GetFileSize (const FileSpec& file_spec)
+        {
+            return UINT64_MAX;
+        }
+
+        virtual uint64_t
+        ReadFile (lldb::user_id_t fd,
+                  uint64_t offset,
+                  void *dst,
+                  uint64_t dst_len,
+                  Error &error)
+        {
+            error.SetErrorStringWithFormat ("Platform::ReadFile() is not supported in the %s platform", GetName().GetCString());
+            return -1;
+        }
+        
+        virtual uint64_t
+        WriteFile (lldb::user_id_t fd,
+                   uint64_t offset,
+                   const void* src,
+                   uint64_t src_len,
+                   Error &error)
+        {
+            error.SetErrorStringWithFormat ("Platform::ReadFile() is not supported in the %s platform", GetName().GetCString());
+            return -1;
+        }
+        
+        virtual Error
+        PutFile (const FileSpec& source,
+                 const FileSpec& destination,
+                 uint32_t uid = UINT32_MAX,
+                 uint32_t gid = UINT32_MAX);
+                
         virtual size_t
         GetEnvironment (StringList &environment);
         
+        virtual Error
+        GetFile (const FileSpec& source,
+                 const FileSpec& destination);
+        
+        virtual bool
+        GetFileExists (const lldb_private::FileSpec& file_spec);
+        
+        virtual uint32_t
+        GetFilePermissions (const lldb_private::FileSpec &file_spec,
+                            Error &error)
+        {
+            error.SetErrorStringWithFormat ("Platform::GetFilePermissions() is not supported in the %s platform", GetName().GetCString());
+            return 0;
+        }
+
+        virtual bool
+        GetSupportsRSync ()
+        {
+            return m_supports_rsync;
+        }
+        
+        virtual void
+        SetSupportsRSync(bool flag)
+        {
+            m_supports_rsync = flag;
+        }
+        
+        virtual const char*
+        GetRSyncOpts ()
+        {
+            return m_rsync_opts.c_str();
+        }
+        
+        virtual void
+        SetRSyncOpts (const char* opts)
+        {
+            m_rsync_opts.assign(opts);
+        }
+        
+        virtual const char*
+        GetRSyncPrefix ()
+        {
+            return m_rsync_prefix.c_str();
+        }
+        
+        virtual void
+        SetRSyncPrefix (const char* prefix)
+        {
+            m_rsync_prefix.assign(prefix);
+        }
+        
+        virtual bool
+        GetSupportsSSH ()
+        {
+            return m_supports_ssh;
+        }
+        
+        virtual void
+        SetSupportsSSH(bool flag)
+        {
+            m_supports_ssh = flag;
+        }
+        
+        virtual const char*
+        GetSSHOpts ()
+        {
+            return m_ssh_opts.c_str();
+        }
+        
+        virtual void
+        SetSSHOpts (const char* opts)
+        {
+            m_ssh_opts.assign(opts);
+        }
+        
+        virtual bool
+        GetIgnoresRemoteHostname ()
+        {
+            return m_ignores_remote_hostname;
+        }
+        
+        virtual void
+        SetIgnoresRemoteHostname(bool flag)
+        {
+            m_ignores_remote_hostname = flag;
+        }
+        
+        virtual lldb_private::OptionGroupOptions *
+        GetConnectionOptions (CommandInterpreter& interpreter)
+        {
+            return NULL;
+        }
+        
+        virtual lldb_private::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);         // Timeout in seconds to wait for shell program to finish
+        
+        virtual void
+        SetLocalCacheDirectory (const char* local);
+        
+        virtual const char*
+        GetLocalCacheDirectory ();
+        
+        virtual std::string
+        GetPlatformSpecificConnectionInformation()
+        {
+            return "";
+        }
+        
+        virtual bool
+        CalculateMD5 (const FileSpec& file_spec,
+                      uint64_t &low,
+                      uint64_t &high);
+                
     protected:
         bool m_is_host;
         // Set to true when we are able to actually set the OS version while 
@@ -569,7 +751,14 @@ namespace lldb_private {
         IDToNameMap m_gid_map;
         size_t m_max_uid_name_len;
         size_t m_max_gid_name_len;
-        
+        bool m_supports_rsync;
+        std::string m_rsync_opts;
+        std::string m_rsync_prefix;
+        bool m_supports_ssh;
+        std::string m_ssh_opts;
+        bool m_ignores_remote_hostname;
+        std::string m_local_cache_directory;
+
         const char *
         GetCachedUserName (uint32_t uid)
         {
@@ -750,6 +939,110 @@ namespace lldb_private {
     private:
         DISALLOW_COPY_AND_ASSIGN (PlatformList);
     };
+    
+    class OptionGroupPlatformRSync : public lldb_private::OptionGroup
+    {
+    public:
+        OptionGroupPlatformRSync ();
+        
+        virtual
+        ~OptionGroupPlatformRSync ();
+        
+        virtual lldb_private::Error
+        SetOptionValue (CommandInterpreter &interpreter,
+                        uint32_t option_idx,
+                        const char *option_value);
+        
+        void
+        OptionParsingStarting (CommandInterpreter &interpreter);
+        
+        const lldb_private::OptionDefinition*
+        GetDefinitions ();
+        
+        virtual uint32_t
+        GetNumDefinitions ();
+        
+        // Options table: Required for subclasses of Options.
+        
+        static lldb_private::OptionDefinition g_option_table[];
+        
+        // Instance variables to hold the values for command options.
+        
+        bool m_rsync;
+        std::string m_rsync_opts;
+        std::string m_rsync_prefix;
+        bool m_ignores_remote_hostname;
+    private:
+        DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformRSync);
+    };
+    
+    class OptionGroupPlatformSSH : public lldb_private::OptionGroup
+    {
+    public:
+        OptionGroupPlatformSSH ();
+        
+        virtual
+        ~OptionGroupPlatformSSH ();
+        
+        virtual lldb_private::Error
+        SetOptionValue (CommandInterpreter &interpreter,
+                        uint32_t option_idx,
+                        const char *option_value);
+        
+        void
+        OptionParsingStarting (CommandInterpreter &interpreter);
+        
+        virtual uint32_t
+        GetNumDefinitions ();
+        
+        const lldb_private::OptionDefinition*
+        GetDefinitions ();
+        
+        // Options table: Required for subclasses of Options.
+        
+        static lldb_private::OptionDefinition g_option_table[];
+        
+        // Instance variables to hold the values for command options.
+        
+        bool m_ssh;
+        std::string m_ssh_opts;
+    private:
+        DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformSSH);
+    };
+    
+    class OptionGroupPlatformCaching : public lldb_private::OptionGroup
+    {
+    public:
+        OptionGroupPlatformCaching ();
+        
+        virtual
+        ~OptionGroupPlatformCaching ();
+        
+        virtual lldb_private::Error
+        SetOptionValue (CommandInterpreter &interpreter,
+                        uint32_t option_idx,
+                        const char *option_value);
+        
+        void
+        OptionParsingStarting (CommandInterpreter &interpreter);
+        
+        virtual uint32_t
+        GetNumDefinitions ();
+        
+        const lldb_private::OptionDefinition*
+        GetDefinitions ();
+        
+        // Options table: Required for subclasses of Options.
+        
+        static lldb_private::OptionDefinition g_option_table[];
+        
+        // Instance variables to hold the values for command options.
+        
+        std::string m_cache_dir;
+    private:
+        DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformCaching);
+    };
+    
 } // namespace lldb_private
 
 #endif  // liblldb_Platform_h_

Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Mon Aug 26 18:57:52 2013
@@ -243,6 +243,12 @@ public:
         return m_arch;
     }
     
+    void
+    SetArchitecture (ArchSpec arch)
+    {
+        m_arch = arch;
+    }
+    
     lldb::pid_t
     GetProcessID () const
     {

Modified: lldb/trunk/include/lldb/lldb-enumerations.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-enumerations.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-enumerations.h (original)
+++ lldb/trunk/include/lldb/lldb-enumerations.h Mon Aug 26 18:57:52 2013
@@ -406,6 +406,9 @@ namespace lldb {
         eArgTypeOffset,
         eArgTypeOldPathPrefix,
         eArgTypeOneLiner,
+        eArgTypePath,
+        eArgTypePermissionsNumber,
+        eArgTypePermissionsString,
         eArgTypePid,
         eArgTypePlugin,
         eArgTypeProcessName,

Modified: lldb/trunk/include/lldb/lldb-forward.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-forward.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-forward.h (original)
+++ lldb/trunk/include/lldb/lldb-forward.h Mon Aug 26 18:57:52 2013
@@ -90,6 +90,7 @@ class   ExecutionContext;
 class   ExecutionContextRef;
 class   ExecutionContextRefLocker;
 class   ExecutionContextScope;
+class   File;
 class   FileSpec;
 class   FileSpecList;
 class   Flags;
@@ -119,6 +120,7 @@ struct  NameSearchContext;
 class   ObjCLanguageRuntime;
 class   ObjectContainer;
 class   OptionGroup;
+class   OptionGroupOptions;
 class   OptionGroupPlatform;
 class   ObjectFile;
 class   OperatingSystem;
@@ -285,6 +287,7 @@ namespace lldb {
     typedef std::shared_ptr<lldb_private::DynamicLoader> DynamicLoaderSP;
     typedef std::shared_ptr<lldb_private::Event> EventSP;
     typedef std::shared_ptr<lldb_private::ExecutionContextRef> ExecutionContextRefSP;
+    typedef std::shared_ptr<lldb_private::File> FileSP;
     typedef std::shared_ptr<lldb_private::Function> FunctionSP;
     typedef std::shared_ptr<lldb_private::FuncUnwinders> FuncUnwindersSP;
     typedef std::shared_ptr<lldb_private::InlineFunctionInfo> InlineFunctionInfoSP;

Modified: lldb/trunk/include/lldb/lldb-private-log.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-private-log.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-private-log.h (original)
+++ lldb/trunk/include/lldb/lldb-private-log.h Mon Aug 26 18:57:52 2013
@@ -44,6 +44,7 @@
 #define LIBLLDB_LOG_TARGET              (1u << 22)
 #define LIBLLDB_LOG_MMAP                (1u << 23)
 #define LIBLLDB_LOG_OS                  (1u << 24)
+#define LIBLLDB_LOG_PLATFORM            (1u << 25)
 #define LIBLLDB_LOG_ALL                 (UINT32_MAX)
 #define LIBLLDB_LOG_DEFAULT             (LIBLLDB_LOG_PROCESS              |\
                                          LIBLLDB_LOG_THREAD               |\

Modified: lldb/trunk/lib/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lib/Makefile?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/lib/Makefile (original)
+++ lldb/trunk/lib/Makefile Mon Aug 26 18:57:52 2013
@@ -69,7 +69,8 @@ USEDLIBS = lldbAPI.a \
 	LLVMMCDisassembler.a \
 	lldbPluginPlatformMacOSX.a \
 	lldbPluginPlatformLinux.a \
-	lldbPluginPlatformFreeBSD.a
+	lldbPluginPlatformFreeBSD.a \
+	lldbPluginPlatformPOSIX.a
 
 # Because GCC requires RTTI enabled for lldbCore (see source/Core/Makefile) it is
 # necessary to also link the clang rewriter libraries so vtable references can

Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Mon Aug 26 18:57:52 2013
@@ -531,6 +531,9 @@
 		944372DD171F6B4300E57C32 /* RegisterContextDummy.h in Headers */ = {isa = PBXBuildFile; fileRef = 944372DB171F6B4300E57C32 /* RegisterContextDummy.h */; };
 		9443B122140C18C40013457C /* SBData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9443B121140C18C10013457C /* SBData.cpp */; };
 		9443B123140C26AB0013457C /* SBData.h in Headers */ = {isa = PBXBuildFile; fileRef = 9443B120140C18A90013457C /* SBData.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		945759671534941F005A9070 /* PlatformPOSIX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 945759651534941F005A9070 /* PlatformPOSIX.cpp */; };
+		945759681534941F005A9070 /* PlatformPOSIX.h in Headers */ = {isa = PBXBuildFile; fileRef = 945759661534941F005A9070 /* PlatformPOSIX.h */; };
+		945E8D80152F6AB40019BCCD /* StreamGDBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 945E8D7F152F6AB40019BCCD /* StreamGDBRemote.cpp */; };
 		9452573A16262D0200325455 /* SBDeclaration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9452573916262D0200325455 /* SBDeclaration.cpp */; };
 		9456F2241616671900656F91 /* DynamicLibrary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9456F2211616644B00656F91 /* DynamicLibrary.cpp */; };
 		94611EB213CCA4A4003A22AF /* RefCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94611EB113CCA4A4003A22AF /* RefCounter.cpp */; };
@@ -547,6 +550,7 @@
 		947A1D651616476B0017C8D1 /* CommandObjectPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 947A1D631616476A0017C8D1 /* CommandObjectPlugin.h */; };
 		949ADF031406F648004833E1 /* ValueObjectConstResultImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 949ADF021406F648004833E1 /* ValueObjectConstResultImpl.cpp */; };
 		94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94B6E76113D88362005F417F /* ValueObjectSyntheticFilter.cpp */; };
+		94E829CA152D33C1006F96A3 /* lldb-platform in Resources */ = {isa = PBXBuildFile; fileRef = 26DC6A101337FE6900FF7998 /* lldb-platform */; };
 		94BA8B6D176F8C9B005A91B5 /* Range.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94BA8B6C176F8C9B005A91B5 /* Range.cpp */; };
 		94BA8B70176F97CE005A91B5 /* CommandHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94BA8B6F176F97CE005A91B5 /* CommandHistory.cpp */; };
 		94CB255B16B069770059775D /* CXXFormatterFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CB255716B069770059775D /* CXXFormatterFunctions.cpp */; };
@@ -712,6 +716,13 @@
 			remoteGlobalIDString = 2689FFC913353D7A00698AC0;
 			remoteInfo = "lldb-core";
 		};
+		94E829C8152D33B4006F96A3 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 26DC6A0F1337FE6900FF7998;
+			remoteInfo = "lldb-platform";
+		};
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -1562,6 +1573,10 @@
 		944372DB171F6B4300E57C32 /* RegisterContextDummy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextDummy.h; path = Utility/RegisterContextDummy.h; sourceTree = "<group>"; };
 		9443B120140C18A90013457C /* SBData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBData.h; path = include/lldb/API/SBData.h; sourceTree = "<group>"; };
 		9443B121140C18C10013457C /* SBData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBData.cpp; path = source/API/SBData.cpp; sourceTree = "<group>"; };
+		945759651534941F005A9070 /* PlatformPOSIX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformPOSIX.cpp; path = POSIX/PlatformPOSIX.cpp; sourceTree = "<group>"; };
+		945759661534941F005A9070 /* PlatformPOSIX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlatformPOSIX.h; path = POSIX/PlatformPOSIX.h; sourceTree = "<group>"; };
+		945E8D7D152F6AA80019BCCD /* StreamGDBRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StreamGDBRemote.h; path = include/lldb/Core/StreamGDBRemote.h; sourceTree = "<group>"; };
+		945E8D7F152F6AB40019BCCD /* StreamGDBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StreamGDBRemote.cpp; path = source/Core/StreamGDBRemote.cpp; sourceTree = "<group>"; };
 		944DC3481774C99000D7D884 /* python-swigsafecast.swig */ = {isa = PBXFileReference; lastKnownFileType = text; path = "python-swigsafecast.swig"; sourceTree = "<group>"; };
 		9452573616262CD000325455 /* SBDeclaration.i */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBDeclaration.i; sourceTree = "<group>"; };
 		9452573816262CEF00325455 /* SBDeclaration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBDeclaration.h; path = include/lldb/API/SBDeclaration.h; sourceTree = "<group>"; };
@@ -2656,6 +2671,8 @@
 				4C6649A214EEE81000B0316F /* StreamCallback.cpp */,
 				26BC7D7A10F1B77400F91463 /* StreamFile.h */,
 				26BC7E9210F1B85900F91463 /* StreamFile.cpp */,
+				945E8D7D152F6AA80019BCCD /* StreamGDBRemote.h */,
+				945E8D7F152F6AB40019BCCD /* StreamGDBRemote.cpp */,
 				26BC7D7B10F1B77400F91463 /* StreamString.h */,
 				26BC7E9310F1B85900F91463 /* StreamString.cpp */,
 				4C626533130F1B0A00C889F6 /* StreamTee.h */,
@@ -3154,6 +3171,7 @@
 		26C5577E132575B6008FD8FE /* Platform */ = {
 			isa = PBXGroup;
 			children = (
+				9457596415349416005A9070 /* POSIX */,
 				2694E99814FC0BB30076DE67 /* FreeBSD */,
 				264A97BC133918A30017F0BE /* GDB Server */,
 				2694E99F14FC0BBD0076DE67 /* Linux */,
@@ -3402,6 +3420,69 @@
 			path = source/Host/common;
 			sourceTree = "<group>";
 		};
+		9457596415349416005A9070 /* POSIX */ = {
+			isa = PBXGroup;
+			children = (
+				945759651534941F005A9070 /* PlatformPOSIX.cpp */,
+				945759661534941F005A9070 /* PlatformPOSIX.h */,
+			);
+			name = POSIX;
+			sourceTree = "<group>";
+		};
+		940DB8C416EA64D400D3C2F1 /* lldb-perf */ = {
+			isa = PBXGroup;
+			children = (
+				940DB8C616EA654E00D3C2F1 /* darwin */,
+				940DB8C516EA654900D3C2F1 /* lib */,
+			);
+			name = "lldb-perf";
+			path = "tools/lldb-perf";
+			sourceTree = "<group>";
+		};
+		940DB8C516EA654900D3C2F1 /* lib */ = {
+			isa = PBXGroup;
+			children = (
+				940DB8CA16EA66FB00D3C2F1 /* Gauge.h */,
+				940DB8CE16EA670C00D3C2F1 /* Measurement.h */,
+				940DB8D116EA671800D3C2F1 /* MemoryGauge.cpp */,
+				940DB8D216EA671800D3C2F1 /* MemoryGauge.h */,
+				940DB8D516EA672200D3C2F1 /* Metric.cpp */,
+				940DB8D616EA672200D3C2F1 /* Metric.h */,
+				940DB8D916EA672D00D3C2F1 /* TestCase.cpp */,
+				940DB8DA16EA672D00D3C2F1 /* TestCase.h */,
+				940DB8DD16EA673800D3C2F1 /* Timer.cpp */,
+				940DB8DE16EA673800D3C2F1 /* Timer.h */,
+				940DB8E116EA674000D3C2F1 /* Xcode.cpp */,
+				940DB8E216EA674000D3C2F1 /* Xcode.h */,
+			);
+			path = lib;
+			sourceTree = "<group>";
+		};
+		940DB8C616EA654E00D3C2F1 /* darwin */ = {
+			isa = PBXGroup;
+			children = (
+				940DB8FB16EA84BF00D3C2F1 /* formatters */,
+				940DB8C716EA655400D3C2F1 /* sketch */,
+			);
+			path = darwin;
+			sourceTree = "<group>";
+		};
+		940DB8C716EA655400D3C2F1 /* sketch */ = {
+			isa = PBXGroup;
+			children = (
+				940DB8E616EA709400D3C2F1 /* main.cpp */,
+			);
+			path = sketch;
+			sourceTree = "<group>";
+		};
+		940DB8FB16EA84BF00D3C2F1 /* formatters */ = {
+			isa = PBXGroup;
+			children = (
+				94DB60F016EA888A00459D9E /* main.cpp */,
+			);
+			path = formatters;
+			sourceTree = "<group>";
+		};
 		94CB255616B0683B0059775D /* DataFormatters */ = {
 			isa = PBXGroup;
 			children = (
@@ -3536,6 +3617,7 @@
 				2694E99E14FC0BB30076DE67 /* PlatformFreeBSD.h in Headers */,
 				2694E9A514FC0BBD0076DE67 /* PlatformLinux.h in Headers */,
 				2663E379152BD1890091EC22 /* ReadWriteLock.h in Headers */,
+				945759681534941F005A9070 /* PlatformPOSIX.h in Headers */,
 				26B1EFAF154638AF00E2DAC7 /* DWARFDeclContext.h in Headers */,
 				260CC62E15D04377002BF2E0 /* OptionValueArgs.h in Headers */,
 				260CC62F15D04377002BF2E0 /* OptionValueArray.h in Headers */,
@@ -3616,6 +3698,7 @@
 			buildRules = (
 			);
 			dependencies = (
+				94E829C9152D33B4006F96A3 /* PBXTargetDependency */,
 				2689011513353E9B00698AC0 /* PBXTargetDependency */,
 				262CFC7211A450CB00946C6C /* PBXTargetDependency */,
 				26368AF6126B95FA00E8659F /* PBXTargetDependency */,
@@ -3766,6 +3849,7 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				94E829CA152D33C1006F96A3 /* lldb-platform in Resources */,
 				262CFC7711A4510000946C6C /* debugserver in Resources */,
 				26368AF7126B960500E8659F /* darwin-debug in Resources */,
 			);
@@ -4269,6 +4353,8 @@
 				26FFC19D14FC072100087D58 /* DynamicLoaderPOSIXDYLD.cpp in Sources */,
 				2694E99D14FC0BB30076DE67 /* PlatformFreeBSD.cpp in Sources */,
 				2694E9A414FC0BBD0076DE67 /* PlatformLinux.cpp in Sources */,
+				945E8D80152F6AB40019BCCD /* StreamGDBRemote.cpp in Sources */,
+				945759671534941F005A9070 /* PlatformPOSIX.cpp in Sources */,
 				26B1EFAE154638AF00E2DAC7 /* DWARFDeclContext.cpp in Sources */,
 				260CC64815D0440D002BF2E0 /* OptionValueArgs.cpp in Sources */,
 				260CC64915D0440D002BF2E0 /* OptionValueArray.cpp in Sources */,
@@ -4416,6 +4502,11 @@
 			target = 2689FFC913353D7A00698AC0 /* lldb-core */;
 			targetProxy = 26DC6A151337FE7300FF7998 /* PBXContainerItemProxy */;
 		};
+		94E829C9152D33B4006F96A3 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 26DC6A0F1337FE6900FF7998 /* lldb-platform */;
+			targetProxy = 94E829C8152D33B4006F96A3 /* PBXContainerItemProxy */;
+		};
 /* End PBXTargetDependency section */
 
 /* Begin XCBuildConfiguration section */
@@ -5127,6 +5218,7 @@
 				OTHER_LDFLAGS = (
 					"-lllvmclang",
 					"-lpython",
+					"-lxml2",
 					"-framework",
 					DebugSymbols,
 					"-framework",
@@ -5190,6 +5282,7 @@
 				OTHER_LDFLAGS = (
 					"-lllvmclang",
 					"-lpython",
+					"-lxml2",
 					"-framework",
 					DebugSymbols,
 					"-framework",
@@ -5252,6 +5345,7 @@
 				OTHER_LDFLAGS = (
 					"-lllvmclang",
 					"-lpython",
+					"-lxml2",
 					"-framework",
 					DebugSymbols,
 					"-framework",

Modified: lldb/trunk/scripts/Python/python-wrapper.swig
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/Python/python-wrapper.swig?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/scripts/Python/python-wrapper.swig (original)
+++ lldb/trunk/scripts/Python/python-wrapper.swig Mon Aug 26 18:57:52 2013
@@ -912,6 +912,19 @@ LLDBSwigPythonCallModuleInit
 // typemaps and in the extensions (SBInputReader.__del__()).
 #include "lldb/API/SBInputReader.h"
 #include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBValue.h"
+ 
+SWIGEXPORT lldb::ValueObjectSP
+LLDBSWIGPython_GetValueObjectSPFromSBValue (void* data)
+{
+    lldb::ValueObjectSP valobj_sp;
+    if (data)
+    {
+        lldb::SBValue* sb_ptr = (lldb::SBValue *)data;
+        valobj_sp = sb_ptr->GetSP();
+    }
+    return valobj_sp;
+}
 
 #ifdef __cplusplus
 extern "C" {

Modified: lldb/trunk/source/API/SBValue.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBValue.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/API/SBValue.cpp (original)
+++ lldb/trunk/source/API/SBValue.cpp Mon Aug 26 18:57:52 2013
@@ -63,20 +63,20 @@ public:
                lldb::DynamicValueType use_dynamic,
                bool use_synthetic,
                const char *name = NULL) :
-        m_valobj_sp(in_valobj_sp),
-        m_use_dynamic(use_dynamic),
-        m_use_synthetic(use_synthetic),
-        m_name (name)
+    m_valobj_sp(in_valobj_sp),
+    m_use_dynamic(use_dynamic),
+    m_use_synthetic(use_synthetic),
+    m_name (name)
     {
         if (!m_name.IsEmpty() && m_valobj_sp)
             m_valobj_sp->SetName(m_name);
     }
     
     ValueImpl (const ValueImpl& rhs) :
-        m_valobj_sp(rhs.m_valobj_sp),
-        m_use_dynamic(rhs.m_use_dynamic),
-        m_use_synthetic(rhs.m_use_synthetic),
-        m_name (rhs.m_name)
+    m_valobj_sp(rhs.m_valobj_sp),
+    m_use_dynamic(rhs.m_use_dynamic),
+    m_use_synthetic(rhs.m_use_synthetic),
+    m_name (rhs.m_name)
     {
     }
     
@@ -120,7 +120,7 @@ public:
         Target *target = value_sp->GetTargetSP().get();
         if (target)
             api_locker.Lock(target->GetAPIMutex());
-
+        
         ProcessSP process_sp(value_sp->GetProcessSP());
         if (process_sp && !stop_locker.TryLock (&process_sp->GetRunLock()))
         {
@@ -131,7 +131,7 @@ public:
             error.SetErrorString ("process must be stopped.");
             return ValueObjectSP();
         }
-
+        
         if (value_sp->GetDynamicValue(m_use_dynamic))
             value_sp = value_sp->GetDynamicValue(m_use_dynamic);
         if (value_sp->GetSyntheticValue(m_use_synthetic))
@@ -167,7 +167,7 @@ public:
     {
         return m_use_synthetic;
     }
-
+    
     // All the derived values that we would make from the m_valobj_sp will share
     // the ExecutionContext with m_valobj_sp, so we don't need to do the calculations
     // in GetSP to return the Target, Process, Thread or Frame.  It is convenient to
@@ -207,7 +207,7 @@ public:
         else
             return StackFrameSP();
     }
-
+    
 private:
     lldb::ValueObjectSP m_valobj_sp;
     lldb::DynamicValueType m_use_dynamic;
@@ -227,7 +227,7 @@ public:
     {
         return in_value.GetSP(m_stop_locker, m_api_locker, m_lock_error);
     }
-
+    
     Error &
     GetError()
     {
@@ -238,11 +238,11 @@ private:
     Process::StopLocker m_stop_locker;
     Mutex::Locker m_api_locker;
     Error m_lock_error;
-
+    
 };
 
 SBValue::SBValue () :
-    m_opaque_sp ()
+m_opaque_sp ()
 {
 }
 
@@ -318,7 +318,7 @@ SBValue::GetName()
     lldb::ValueObjectSP value_sp(GetSP(locker));
     if (value_sp)
         name = value_sp->GetName().GetCString();
-
+    
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
     if (log)
     {
@@ -327,7 +327,7 @@ SBValue::GetName()
         else
             log->Printf ("SBValue(%p)::GetName () => NULL", value_sp.get());
     }
-
+    
     return name;
 }
 
@@ -350,7 +350,7 @@ SBValue::GetTypeName ()
         else
             log->Printf ("SBValue(%p)::GetTypeName () => NULL", value_sp.get());
     }
-
+    
     return name;
 }
 
@@ -359,17 +359,17 @@ SBValue::GetByteSize ()
 {
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
     size_t result = 0;
-
+    
     ValueLocker locker;
     lldb::ValueObjectSP value_sp(GetSP(locker));
     if (value_sp)
     {
         result = value_sp->GetByteSize();
     }
-
+    
     if (log)
         log->Printf ("SBValue(%p)::GetByteSize () => %" PRIu64, value_sp.get(), (uint64_t)result);
-
+    
     return result;
 }
 
@@ -377,18 +377,18 @@ bool
 SBValue::IsInScope ()
 {
     bool result = false;
-
+    
     ValueLocker locker;
     lldb::ValueObjectSP value_sp(GetSP(locker));
     if (value_sp)
     {
         result = value_sp->IsInScope ();
     }
-
+    
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
     if (log)
         log->Printf ("SBValue(%p)::IsInScope () => %i", value_sp.get(), result);
-
+    
     return result;
 }
 
@@ -396,7 +396,7 @@ const char *
 SBValue::GetValue ()
 {
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+    
     const char *cstr = NULL;
     ValueLocker locker;
     lldb::ValueObjectSP value_sp(GetSP(locker));
@@ -411,7 +411,7 @@ SBValue::GetValue ()
         else
             log->Printf ("SBValue(%p)::GetValue() => NULL", value_sp.get());
     }
-
+    
     return cstr;
 }
 
@@ -429,14 +429,14 @@ SBValue::GetValueType ()
     {
         switch (result)
         {
-        case eValueTypeInvalid:         log->Printf ("SBValue(%p)::GetValueType () => eValueTypeInvalid", value_sp.get()); break;
-        case eValueTypeVariableGlobal:  log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableGlobal", value_sp.get()); break;
-        case eValueTypeVariableStatic:  log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableStatic", value_sp.get()); break;
-        case eValueTypeVariableArgument:log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableArgument", value_sp.get()); break;
-        case eValueTypeVariableLocal:   log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableLocal", value_sp.get()); break;
-        case eValueTypeRegister:        log->Printf ("SBValue(%p)::GetValueType () => eValueTypeRegister", value_sp.get()); break;
-        case eValueTypeRegisterSet:     log->Printf ("SBValue(%p)::GetValueType () => eValueTypeRegisterSet", value_sp.get()); break;
-        case eValueTypeConstResult:     log->Printf ("SBValue(%p)::GetValueType () => eValueTypeConstResult", value_sp.get()); break;
+            case eValueTypeInvalid:         log->Printf ("SBValue(%p)::GetValueType () => eValueTypeInvalid", value_sp.get()); break;
+            case eValueTypeVariableGlobal:  log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableGlobal", value_sp.get()); break;
+            case eValueTypeVariableStatic:  log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableStatic", value_sp.get()); break;
+            case eValueTypeVariableArgument:log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableArgument", value_sp.get()); break;
+            case eValueTypeVariableLocal:   log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableLocal", value_sp.get()); break;
+            case eValueTypeRegister:        log->Printf ("SBValue(%p)::GetValueType () => eValueTypeRegister", value_sp.get()); break;
+            case eValueTypeRegisterSet:     log->Printf ("SBValue(%p)::GetValueType () => eValueTypeRegisterSet", value_sp.get()); break;
+            case eValueTypeConstResult:     log->Printf ("SBValue(%p)::GetValueType () => eValueTypeConstResult", value_sp.get()); break;
         }
     }
     return result;
@@ -499,7 +499,7 @@ SBValue::GetValueDidChange ()
     }
     if (log)
         log->Printf ("SBValue(%p)::GetValueDidChange() => %i", value_sp.get(), result);
-
+    
     return result;
 }
 
@@ -571,7 +571,7 @@ SBValue::SetValueFromCString (const char
     
     if (log)
         log->Printf ("SBValue(%p)::SetValueFromCString(\"%s\") => %i", value_sp.get(), value_str, success);
-
+    
     return success;
 }
 
@@ -765,15 +765,15 @@ SBValue::CreateValueFromAddress(const ch
         if (pointee_ast_type)
         {
             lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(&address,sizeof(lldb::addr_t)));
-        
+            
             ExecutionContext exe_ctx (value_sp->GetExecutionContextRef());
             ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
                                                                                pointee_ast_type,
                                                                                ConstString(name),
                                                                                buffer,
-                                                                               lldb::endian::InlHostByteOrder(), 
+                                                                               lldb::endian::InlHostByteOrder(),
                                                                                exe_ctx.GetAddressByteSize()));
-        
+            
             if (ptr_result_valobj_sp)
             {
                 ptr_result_valobj_sp->GetValue().SetValueType(Value::eValueTypeLoadAddress);
@@ -806,7 +806,7 @@ SBValue::CreateValueFromData (const char
     if (value_sp)
     {
         ExecutionContext exe_ctx (value_sp->GetExecutionContextRef());
-
+        
         new_value_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
                                                        type.m_opaque_sp->GetClangASTType(),
                                                        ConstString(name),
@@ -837,7 +837,7 @@ SBValue::GetChildAtIndex (uint32_t idx)
     
     if (target_sp)
         use_dynamic = target_sp->GetPreferDynamicValue();
-
+    
     return GetChildAtIndex (idx, use_dynamic, can_create_synthetic);
 }
 
@@ -846,7 +846,7 @@ SBValue::GetChildAtIndex (uint32_t idx,
 {
     lldb::ValueObjectSP child_sp;
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+    
     ValueLocker locker;
     lldb::ValueObjectSP value_sp(GetSP(locker));
     if (value_sp)
@@ -870,7 +870,7 @@ SBValue::GetChildAtIndex (uint32_t idx,
     sb_value.SetSP (child_sp, use_dynamic, GetPreferSyntheticValue());
     if (log)
         log->Printf ("SBValue(%p)::GetChildAtIndex (%u) => SBValue(%p)", value_sp.get(), idx, value_sp.get());
-
+    
     return sb_value;
 }
 
@@ -913,9 +913,9 @@ SBValue::GetChildMemberWithName (const c
 {
     lldb::ValueObjectSP child_sp;
     const ConstString str_name (name);
-
+    
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+    
     ValueLocker locker;
     lldb::ValueObjectSP value_sp(GetSP(locker));
     if (value_sp)
@@ -925,10 +925,10 @@ SBValue::GetChildMemberWithName (const c
     
     SBValue sb_value;
     sb_value.SetSP(child_sp, use_dynamic_value, GetPreferSyntheticValue());
-
+    
     if (log)
         log->Printf ("SBValue(%p)::GetChildMemberWithName (name=\"%s\") => SBValue(%p)", value_sp.get(), name, value_sp.get());
-
+    
     return sb_value;
 }
 
@@ -1117,7 +1117,7 @@ SBValue::MightHaveChildren ()
     lldb::ValueObjectSP value_sp(GetSP(locker));
     if (value_sp)
         has_children = value_sp->MightHaveChildren();
-
+    
     if (log)
         log->Printf ("SBValue(%p)::MightHaveChildren() => %i", value_sp.get(), has_children);
     return has_children;
@@ -1127,16 +1127,16 @@ uint32_t
 SBValue::GetNumChildren ()
 {
     uint32_t num_children = 0;
-
+    
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
     ValueLocker locker;
     lldb::ValueObjectSP value_sp(GetSP(locker));
     if (value_sp)
         num_children = value_sp->GetNumChildren();
-
+    
     if (log)
         log->Printf ("SBValue(%p)::GetNumChildren () => %u", value_sp.get(), num_children);
-
+    
     return num_children;
 }
 
@@ -1149,13 +1149,13 @@ SBValue::Dereference ()
     lldb::ValueObjectSP value_sp(GetSP(locker));
     if (value_sp)
     {
-            Error error;
-            sb_value = value_sp->Dereference (error);
+        Error error;
+        sb_value = value_sp->Dereference (error);
     }
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
     if (log)
         log->Printf ("SBValue(%p)::Dereference () => SBValue(%p)", value_sp.get(), value_sp.get());
-
+    
     return sb_value;
 }
 
@@ -1163,17 +1163,17 @@ bool
 SBValue::TypeIsPointerType ()
 {
     bool is_ptr_type = false;
-
+    
     ValueLocker locker;
     lldb::ValueObjectSP value_sp(GetSP(locker));
     if (value_sp)
         is_ptr_type = value_sp->IsPointerType();
-
+    
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
     if (log)
         log->Printf ("SBValue(%p)::TypeIsPointerType () => %i", value_sp.get(), is_ptr_type);
-
-
+    
+    
     return is_ptr_type;
 }
 
@@ -1390,7 +1390,7 @@ bool
 SBValue::GetDescription (SBStream &description)
 {
     Stream &strm = description.ref();
-
+    
     ValueLocker locker;
     lldb::ValueObjectSP value_sp(GetSP(locker));
     if (value_sp)
@@ -1399,7 +1399,7 @@ SBValue::GetDescription (SBStream &descr
     }
     else
         strm.PutCString ("No value");
-
+    
     return true;
 }
 
@@ -1653,7 +1653,7 @@ SBValue::Watch (bool resolve_location, b
         size_t byte_size = GetByteSize();
         if (byte_size == 0)
             return sb_watchpoint;
-                
+        
         uint32_t watch_type = 0;
         if (read)
             watch_type |= LLDB_WATCH_TYPE_READ;
@@ -1664,14 +1664,14 @@ SBValue::Watch (bool resolve_location, b
         ClangASTType type (value_sp->GetClangType());
         WatchpointSP watchpoint_sp = target_sp->CreateWatchpoint(addr, byte_size, &type, watch_type, rc);
         error.SetError(rc);
-                
-        if (watchpoint_sp) 
+        
+        if (watchpoint_sp)
         {
             sb_watchpoint.SetSP (watchpoint_sp);
             Declaration decl;
             if (value_sp->GetDeclaration (decl))
             {
-                if (decl.GetFile()) 
+                if (decl.GetFile())
                 {
                     StreamString ss;
                     // True to show fullpath for declaration file.

Modified: lldb/trunk/source/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/CMakeLists.txt?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/CMakeLists.txt (original)
+++ lldb/trunk/source/CMakeLists.txt Mon Aug 26 18:57:52 2013
@@ -58,6 +58,7 @@ set( LLDB_USED_LIBS
   lldbPluginPlatformGDB
   lldbPluginPlatformFreeBSD
   lldbPluginPlatformLinux
+  lldbPluginPlatformPOSIX
   lldbPluginObjectFileMachO
   lldbPluginObjectContainerMachOArchive
   lldbPluginObjectContainerBSDArchive

Modified: lldb/trunk/source/Commands/CommandObjectPlatform.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectPlatform.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectPlatform.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectPlatform.cpp Mon Aug 26 18:57:52 2013
@@ -26,10 +26,158 @@
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/Platform.h"
 #include "lldb/Target/Process.h"
+#include "lldb/Utility/Utils.h"
 
 using namespace lldb;
 using namespace lldb_private;
 
+static mode_t
+ParsePermissionString(const char* permissions)
+{
+    if (strlen(permissions) != 9)
+        return (mode_t)(-1);
+    bool user_r,user_w,user_x,
+    group_r,group_w,group_x,
+    world_r,world_w,world_x;
+    
+    user_r = (permissions[0] == 'r');
+    user_w = (permissions[1] == 'w');
+    user_x = (permissions[2] == 'x');
+    
+    group_r = (permissions[3] == 'r');
+    group_w = (permissions[4] == 'w');
+    group_x = (permissions[5] == 'x');
+    
+    world_r = (permissions[6] == 'r');
+    world_w = (permissions[7] == 'w');
+    world_x = (permissions[8] == 'x');
+    
+    mode_t user,group,world;
+    user = (user_r ? 4 : 0) | (user_w ? 2 : 0) | (user_x ? 1 : 0);
+    group = (group_r ? 4 : 0) | (group_w ? 2 : 0) | (group_x ? 1 : 0);
+    world = (world_r ? 4 : 0) | (world_w ? 2 : 0) | (world_x ? 1 : 0);
+    
+    return user | group | world;
+}
+
+static OptionDefinition
+g_permissions_options[] =
+{
+    {   LLDB_OPT_SET_ALL, false, "permissions-value", 'v', required_argument,       NULL, 0, eArgTypePermissionsNumber         , "Give out the numeric value for permissions (e.g. 757)" },
+    {   LLDB_OPT_SET_ALL, false, "permissions-string",'s', required_argument, NULL, 0, eArgTypePermissionsString  , "Give out the string value for permissions (e.g. rwxr-xr--)." },
+    {   LLDB_OPT_SET_ALL, false, "user-read", 'r', no_argument,       NULL, 0, eArgTypeNone         , "Allow user to read." },
+    {   LLDB_OPT_SET_ALL, false, "user-write", 'w', no_argument,       NULL, 0, eArgTypeNone         , "Allow user to write." },
+    {   LLDB_OPT_SET_ALL, false, "user-exec", 'x', no_argument,       NULL, 0, eArgTypeNone         , "Allow user to execute." },
+
+    {   LLDB_OPT_SET_ALL, false, "group-read", 'R', no_argument,       NULL, 0, eArgTypeNone         , "Allow group to read." },
+    {   LLDB_OPT_SET_ALL, false, "group-write", 'W', no_argument,       NULL, 0, eArgTypeNone         , "Allow group to write." },
+    {   LLDB_OPT_SET_ALL, false, "group-exec", 'X', no_argument,       NULL, 0, eArgTypeNone         , "Allow group to execute." },
+
+    {   LLDB_OPT_SET_ALL, false, "world-read", 'd', no_argument,       NULL, 0, eArgTypeNone         , "Allow world to read." },
+    {   LLDB_OPT_SET_ALL, false, "world-write", 't', no_argument,       NULL, 0, eArgTypeNone         , "Allow world to write." },
+    {   LLDB_OPT_SET_ALL, false, "world-exec", 'e', no_argument,       NULL, 0, eArgTypeNone         , "Allow world to execute." },
+
+};
+
+class OptionPermissions : public lldb_private::OptionGroup
+{
+public:
+    OptionPermissions ()
+    {
+    }
+    
+    virtual
+    ~OptionPermissions ()
+    {
+    }
+    
+    virtual lldb_private::Error
+    SetOptionValue (CommandInterpreter &interpreter,
+                    uint32_t option_idx,
+                    const char *option_arg)
+    {
+        Error error;
+        char short_option = (char) GetDefinitions()[option_idx].short_option;
+        switch (short_option)
+        {
+            case 'v':
+            {
+                bool ok;
+                uint32_t perms = Args::StringToUInt32(option_arg, 777, 8, &ok);
+                if (!ok)
+                    error.SetErrorStringWithFormat("invalid value for permissions: %s", option_arg);
+                else
+                    m_permissions = perms;
+            }
+                break;
+            case 's':
+            {
+                mode_t perms = ParsePermissionString(option_arg);
+                if (perms == (mode_t)-1)
+                    error.SetErrorStringWithFormat("invalid value for permissions: %s", option_arg);
+                else
+                    m_permissions = perms;
+            }
+            case 'r':
+                m_permissions |= File::ePermissionsUserRead;
+                break;
+            case 'w':
+                m_permissions |= File::ePermissionsUserWrite;
+                break;
+            case 'x':
+                m_permissions |= File::ePermissionsUserExecute;
+                break;
+            case 'R':
+                m_permissions |= File::ePermissionsGroupRead;
+                break;
+            case 'W':
+                m_permissions |= File::ePermissionsGroupWrite;
+                break;
+            case 'X':
+                m_permissions |= File::ePermissionsGroupExecute;
+                break;
+            case 'd':
+                m_permissions |= File::ePermissionsWorldRead;
+                break;
+            case 't':
+                m_permissions |= File::ePermissionsWorldWrite;
+                break;
+            case 'e':
+                m_permissions |= File::ePermissionsWorldExecute;
+                break;
+
+            default:
+                error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+                break;
+        }
+        
+        return error;
+    }
+    
+    void
+    OptionParsingStarting (CommandInterpreter &interpreter)
+    {
+        m_permissions = 0;
+    }
+    
+    virtual uint32_t
+    GetNumDefinitions ()
+    {
+        return llvm::array_lengthof(g_permissions_options);
+    }
+    
+    const lldb_private::OptionDefinition*
+    GetDefinitions ()
+    {
+        return g_permissions_options;
+    }
+        
+    // Instance variables to hold the values for command options.
+    
+    uint32_t m_permissions;
+private:
+    DISALLOW_COPY_AND_ASSIGN(OptionPermissions);
+};
 
 //----------------------------------------------------------------------
 // "platform select <platform-name>"
@@ -274,11 +422,26 @@ protected:
         }
         else
         {
-            result.AppendError ("no platform us currently selected\n");
+            result.AppendError ("no platform is currently selected\n");
             result.SetStatus (eReturnStatusFailed);            
         }
         return result.Succeeded();
     }
+    
+    virtual Options *
+    GetOptions ()
+    {
+        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+        OptionGroupOptions* m_platform_options = NULL;
+        if (platform_sp)
+        {
+            m_platform_options = platform_sp->GetConnectionOptions(m_interpreter);
+            if (m_platform_options != NULL && !m_platform_options->m_did_finalize)
+                m_platform_options->Finalize();
+        }
+        return m_platform_options;
+    }
+
 };
 
 //----------------------------------------------------------------------
@@ -359,145 +522,235 @@ protected:
         return result.Succeeded();
     }
 };
+
 //----------------------------------------------------------------------
-// "platform process launch"
+// "platform mkdir"
 //----------------------------------------------------------------------
-class CommandObjectPlatformProcessLaunch : public CommandObjectParsed
+class CommandObjectPlatformMkDir : public CommandObjectParsed
 {
 public:
-    CommandObjectPlatformProcessLaunch (CommandInterpreter &interpreter) :
-        CommandObjectParsed (interpreter,
-                             "platform process launch",
-                             "Launch a new process on a remote platform.",
-                             "platform process launch program",
-                             eFlagRequiresTarget | eFlagTryTargetAPILock),
-        m_options (interpreter)
+    CommandObjectPlatformMkDir (CommandInterpreter &interpreter) :
+    CommandObjectParsed (interpreter,
+                         "platform shell",
+                         "Make a new directory on the remote end.",
+                         NULL,
+                         0),
+    m_options(interpreter)
     {
     }
     
     virtual
-    ~CommandObjectPlatformProcessLaunch ()
+    ~CommandObjectPlatformMkDir ()
+    {
+    }
+    
+    virtual bool
+    DoExecute (Args& args, CommandReturnObject &result)
     {
+        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+        if (platform_sp)
+        {
+            std::string cmd_line;
+            args.GetCommandString(cmd_line);
+            mode_t perms;
+            const OptionPermissions* options_permissions = (OptionPermissions*)m_options.GetGroupWithOption('r');
+            if (options_permissions)
+                perms = options_permissions->m_permissions;
+            else
+                perms = 0000700 | 0000070 | 0000007;
+            uint32_t retcode = platform_sp->MakeDirectory(cmd_line,perms);
+            result.AppendMessageWithFormat("Status = %d\n",retcode);
+            result.SetStatus (eReturnStatusSuccessFinishResult);
+        }
+        else
+        {
+            result.AppendError ("no platform currently selected\n");
+            result.SetStatus (eReturnStatusFailed);
+        }
+        return result.Succeeded();
     }
     
     virtual Options *
     GetOptions ()
     {
+        if (m_options.DidFinalize() == false)
+        {
+            m_options.Append(new OptionPermissions());
+            m_options.Finalize();
+        }
         return &m_options;
     }
+    OptionGroupOptions m_options;
+    
+};
+
+//----------------------------------------------------------------------
+// "platform fopen"
+//----------------------------------------------------------------------
+class CommandObjectPlatformFOpen : public CommandObjectParsed
+{
+public:
+    CommandObjectPlatformFOpen (CommandInterpreter &interpreter) :
+    CommandObjectParsed (interpreter,
+                         "platform file open",
+                         "Open a file on the remote end.",
+                         NULL,
+                         0),
+    m_options(interpreter)
+    {
+    }
+    
+    virtual
+    ~CommandObjectPlatformFOpen ()
+    {
+    }
     
-protected:
     virtual bool
     DoExecute (Args& args, CommandReturnObject &result)
     {
-        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
-        PlatformSP platform_sp;
-        if (target)
-        {   
-            platform_sp = target->GetPlatform();
-        }   
-        if (!platform_sp)
-        {
-            platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
-        }   
-
+        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
         if (platform_sp)
         {
             Error error;
-            const size_t argc = args.GetArgumentCount();
-            Target *target = m_exe_ctx.GetTargetPtr();
-            Module *exe_module = target->GetExecutableModulePointer();
-            if (exe_module)
+            std::string cmd_line;
+            args.GetCommandString(cmd_line);
+            mode_t perms;
+            const OptionPermissions* options_permissions = (OptionPermissions*)m_options.GetGroupWithOption('r');
+            if (options_permissions)
+                perms = options_permissions->m_permissions;
+            else
+                perms = 0000700 | 0000070 | 0000007;
+            lldb::user_id_t fd = platform_sp->OpenFile(FileSpec(cmd_line.c_str(),false),
+                                                       File::eOpenOptionRead | File::eOpenOptionWrite |
+                                                       File::eOpenOptionAppend | File::eOpenOptionCanCreate,
+                                                       perms,
+                                                       error);
+            if (error.Success())
             {
-                m_options.launch_info.GetExecutableFile () = exe_module->GetFileSpec();
-                char exe_path[PATH_MAX];
-                if (m_options.launch_info.GetExecutableFile ().GetPath (exe_path, sizeof(exe_path)))
-                    m_options.launch_info.GetArguments().AppendArgument (exe_path);
-                m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture();
+                result.AppendMessageWithFormat("File Descriptor = %" PRIu64 "\n",fd);
+                result.SetStatus (eReturnStatusSuccessFinishResult);
             }
-
-            if (argc > 0)
+            else
             {
-                if (m_options.launch_info.GetExecutableFile ())
-                {
-                    // We already have an executable file, so we will use this
-                    // and all arguments to this function are extra arguments
-                    m_options.launch_info.GetArguments().AppendArguments (args);
-                }
-                else
-                {
-                    // We don't have any file yet, so the first argument is our
-                    // executable, and the rest are program arguments
-                    const bool first_arg_is_executable = true;
-                    m_options.launch_info.SetArguments (args, first_arg_is_executable);
-                }
+                result.AppendError(error.AsCString());
+                result.SetStatus (eReturnStatusFailed);
             }
-            
-            if (m_options.launch_info.GetExecutableFile ())
-            {
-                Debugger &debugger = m_interpreter.GetDebugger();
-
-                if (argc == 0)
-                    target->GetRunArguments(m_options.launch_info.GetArguments());
+        }
+        else
+        {
+            result.AppendError ("no platform currently selected\n");
+            result.SetStatus (eReturnStatusFailed);
+        }
+        return result.Succeeded();
+    }
+    virtual Options *
+    GetOptions ()
+    {
+        if (m_options.DidFinalize() == false)
+        {
+            m_options.Append(new OptionPermissions());
+            m_options.Finalize();
+        }
+        return &m_options;
+    }
+    OptionGroupOptions m_options;
+};
 
-                ProcessSP process_sp (platform_sp->DebugProcess (m_options.launch_info, 
-                                                                 debugger,
-                                                                 target,
-                                                                 debugger.GetListener(),
-                                                                 error));
-                if (process_sp && process_sp->IsAlive())
-                {
-                    result.SetStatus (eReturnStatusSuccessFinishNoResult);
-                    return true;
-                }
-                
-                if (error.Success())
-                    result.AppendError ("process launch failed");
-                else
-                    result.AppendError (error.AsCString());
-                result.SetStatus (eReturnStatusFailed);
+//----------------------------------------------------------------------
+// "platform fclose"
+//----------------------------------------------------------------------
+class CommandObjectPlatformFClose : public CommandObjectParsed
+{
+public:
+    CommandObjectPlatformFClose (CommandInterpreter &interpreter) :
+    CommandObjectParsed (interpreter,
+                         "platform file close",
+                         "Close a file on the remote end.",
+                         NULL,
+                         0)
+    {
+    }
+    
+    virtual
+    ~CommandObjectPlatformFClose ()
+    {
+    }
+    
+    virtual bool
+    DoExecute (Args& args, CommandReturnObject &result)
+    {
+        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+        if (platform_sp)
+        {
+            std::string cmd_line;
+            args.GetCommandString(cmd_line);
+            const lldb::user_id_t fd = Args::StringToUInt64(cmd_line.c_str(), UINT64_MAX);
+            Error error;
+            bool success = platform_sp->CloseFile(fd, error);
+            if (success)
+            {
+                result.AppendMessageWithFormat("file %" PRIu64 " closed.\n", fd);
+                result.SetStatus (eReturnStatusSuccessFinishResult);
             }
             else
             {
-                result.AppendError ("'platform process launch' uses the current target file and arguments, or the executable and its arguments can be specified in this command");
+                result.AppendError(error.AsCString());
                 result.SetStatus (eReturnStatusFailed);
-                return false;
             }
         }
         else
         {
-            result.AppendError ("no platform is selected\n");
+            result.AppendError ("no platform currently selected\n");
+            result.SetStatus (eReturnStatusFailed);
         }
         return result.Succeeded();
     }
-    
-protected:
-    ProcessLaunchCommandOptions m_options;
 };
 
-
-
 //----------------------------------------------------------------------
-// "platform process list"
+// "platform fread"
 //----------------------------------------------------------------------
-class CommandObjectPlatformProcessList : public CommandObjectParsed
+class CommandObjectPlatformFRead : public CommandObjectParsed
 {
 public:
-    CommandObjectPlatformProcessList (CommandInterpreter &interpreter) :
-        CommandObjectParsed (interpreter, 
-                             "platform process list",
-                             "List processes on a remote platform by name, pid, or many other matching attributes.",
-                             "platform process list",
-                             0),
-        m_options (interpreter)
+    CommandObjectPlatformFRead (CommandInterpreter &interpreter) :
+    CommandObjectParsed (interpreter,
+                         "platform file read",
+                         "Read data from a file on the remote end.",
+                         NULL,
+                         0),
+    m_options (interpreter)
     {
     }
     
     virtual
-    ~CommandObjectPlatformProcessList ()
+    ~CommandObjectPlatformFRead ()
     {
     }
     
+    virtual bool
+    DoExecute (Args& args, CommandReturnObject &result)
+    {
+        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+        if (platform_sp)
+        {
+            std::string cmd_line;
+            args.GetCommandString(cmd_line);
+            const lldb::user_id_t fd = Args::StringToUInt64(cmd_line.c_str(), UINT64_MAX);
+            std::string buffer(m_options.m_count,0);
+            Error error;
+            uint32_t retcode = platform_sp->ReadFile(fd, m_options.m_offset, &buffer[0], m_options.m_count, error);
+            result.AppendMessageWithFormat("Return = %d\n",retcode);
+            result.AppendMessageWithFormat("Data = \"%s\"\n",buffer.c_str());
+            result.SetStatus (eReturnStatusSuccessFinishResult);
+        }
+        else
+        {
+            result.AppendError ("no platform currently selected\n");
+            result.SetStatus (eReturnStatusFailed);
+        }
+        return result.Succeeded();
+    }
     virtual Options *
     GetOptions ()
     {
@@ -505,16 +758,600 @@ public:
     }
     
 protected:
-    virtual bool
-    DoExecute (Args& args, CommandReturnObject &result)
+    class CommandOptions : public Options
     {
-        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
-        PlatformSP platform_sp;
-        if (target)
-        {   
-            platform_sp = target->GetPlatform();
-        }   
-        if (!platform_sp)
+    public:
+        
+        CommandOptions (CommandInterpreter &interpreter) :
+        Options (interpreter)
+        {
+        }
+        
+        virtual
+        ~CommandOptions ()
+        {
+        }
+        
+        virtual Error
+        SetOptionValue (uint32_t option_idx, const char *option_arg)
+        {
+            Error error;
+            char short_option = (char) m_getopt_table[option_idx].val;
+            bool success = false;
+            
+            switch (short_option)
+            {
+                case 'o':
+                    m_offset = Args::StringToUInt32(option_arg, 0, 0, &success);
+                    if (!success)
+                        error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg);
+                    break;
+                case 'c':
+                    m_count = Args::StringToUInt32(option_arg, 0, 0, &success);
+                    if (!success)
+                        error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg);
+                    break;
+
+                default:
+                    error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+                    break;
+            }
+            
+            return error;
+        }
+        
+        void
+        OptionParsingStarting ()
+        {
+            m_offset = 0;
+            m_count = 1;
+        }
+        
+        const OptionDefinition*
+        GetDefinitions ()
+        {
+            return g_option_table;
+        }
+        
+        // Options table: Required for subclasses of Options.
+        
+        static OptionDefinition g_option_table[];
+        
+        // Instance variables to hold the values for command options.
+        
+        uint32_t m_offset;
+        uint32_t m_count;
+    };
+    CommandOptions m_options;
+};
+OptionDefinition
+CommandObjectPlatformFRead::CommandOptions::g_option_table[] =
+{
+    {   LLDB_OPT_SET_1, false, "offset"           , 'o', required_argument, NULL, 0, eArgTypeIndex        , "Offset into the file at which to start reading." },
+    {   LLDB_OPT_SET_1, false, "count"            , 'c', required_argument, NULL, 0, eArgTypeCount        , "Number of bytes to read from the file." },
+    {  0              , false, NULL               ,  0 , 0                , NULL, 0, eArgTypeNone         , NULL }
+};
+
+
+//----------------------------------------------------------------------
+// "platform fwrite"
+//----------------------------------------------------------------------
+class CommandObjectPlatformFWrite : public CommandObjectParsed
+{
+public:
+    CommandObjectPlatformFWrite (CommandInterpreter &interpreter) :
+    CommandObjectParsed (interpreter,
+                         "platform file write",
+                         "Write data to a file on the remote end.",
+                         NULL,
+                         0),
+    m_options (interpreter)
+    {
+    }
+    
+    virtual
+    ~CommandObjectPlatformFWrite ()
+    {
+    }
+    
+    virtual bool
+    DoExecute (Args& args, CommandReturnObject &result)
+    {
+        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+        if (platform_sp)
+        {
+            std::string cmd_line;
+            args.GetCommandString(cmd_line);
+            Error error;
+            const lldb::user_id_t fd = Args::StringToUInt64(cmd_line.c_str(), UINT64_MAX);
+            uint32_t retcode = platform_sp->WriteFile (fd,
+                                                       m_options.m_offset,
+                                                       &m_options.m_data[0],
+                                                       m_options.m_data.size(),
+                                                       error);
+            result.AppendMessageWithFormat("Return = %d\n",retcode);
+            result.SetStatus (eReturnStatusSuccessFinishResult);
+        }
+        else
+        {
+            result.AppendError ("no platform currently selected\n");
+            result.SetStatus (eReturnStatusFailed);
+        }
+        return result.Succeeded();
+    }
+    virtual Options *
+    GetOptions ()
+    {
+        return &m_options;
+    }
+    
+protected:
+    class CommandOptions : public Options
+    {
+    public:
+        
+        CommandOptions (CommandInterpreter &interpreter) :
+        Options (interpreter)
+        {
+        }
+        
+        virtual
+        ~CommandOptions ()
+        {
+        }
+        
+        virtual Error
+        SetOptionValue (uint32_t option_idx, const char *option_arg)
+        {
+            Error error;
+            char short_option = (char) m_getopt_table[option_idx].val;
+            bool success = false;
+            
+            switch (short_option)
+            {
+                case 'o':
+                    m_offset = Args::StringToUInt32(option_arg, 0, 0, &success);
+                    if (!success)
+                        error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg);
+                    break;
+                case 'd':
+                    m_data.assign(option_arg);
+                    break;
+                    
+                default:
+                    error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+                    break;
+            }
+            
+            return error;
+        }
+        
+        void
+        OptionParsingStarting ()
+        {
+            m_offset = 0;
+            m_data.clear();
+        }
+        
+        const OptionDefinition*
+        GetDefinitions ()
+        {
+            return g_option_table;
+        }
+        
+        // Options table: Required for subclasses of Options.
+        
+        static OptionDefinition g_option_table[];
+        
+        // Instance variables to hold the values for command options.
+        
+        uint32_t m_offset;
+        std::string m_data;
+    };
+    CommandOptions m_options;
+};
+OptionDefinition
+CommandObjectPlatformFWrite::CommandOptions::g_option_table[] =
+{
+    {   LLDB_OPT_SET_1, false, "offset"           , 'o', required_argument, NULL, 0, eArgTypeIndex        , "Offset into the file at which to start reading." },
+    {   LLDB_OPT_SET_1, false, "data"            , 'd', required_argument, NULL, 0, eArgTypeValue        , "Text to write to the file." },
+    {  0              , false, NULL               ,  0 , 0                , NULL, 0, eArgTypeNone         , NULL }
+};
+
+class CommandObjectPlatformFile : public CommandObjectMultiword
+{
+public:
+    //------------------------------------------------------------------
+    // Constructors and Destructors
+    //------------------------------------------------------------------
+    CommandObjectPlatformFile (CommandInterpreter &interpreter) :
+    CommandObjectMultiword (interpreter,
+                            "platform file",
+                            "A set of commands to manage file access through a platform",
+                            "platform file [open|close|read|write] ...")
+    {
+        LoadSubCommand ("open", CommandObjectSP (new CommandObjectPlatformFOpen  (interpreter)));
+        LoadSubCommand ("close", CommandObjectSP (new CommandObjectPlatformFClose  (interpreter)));
+        LoadSubCommand ("read", CommandObjectSP (new CommandObjectPlatformFRead  (interpreter)));
+        LoadSubCommand ("write", CommandObjectSP (new CommandObjectPlatformFWrite  (interpreter)));
+    }
+    
+    virtual
+    ~CommandObjectPlatformFile ()
+    {
+    }
+    
+private:
+    //------------------------------------------------------------------
+    // For CommandObjectPlatform only
+    //------------------------------------------------------------------
+    DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatformFile);
+};
+
+//----------------------------------------------------------------------
+// "platform get-file remote-file-path host-file-path"
+//----------------------------------------------------------------------
+class CommandObjectPlatformGetFile : public CommandObjectParsed
+{
+public:
+    CommandObjectPlatformGetFile (CommandInterpreter &interpreter) :
+    CommandObjectParsed (interpreter,
+                         "platform get-file",
+                         "Transfer a file from the remote end to the local host.",
+                         "platform get-file <remote-file-spec> <local-file-spec>",
+                         0)
+    {
+        SetHelpLong(
+"Examples: \n\
+\n\
+    platform get-file /the/remote/file/path /the/local/file/path\n\
+    # Transfer a file from the remote end with file path /the/remote/file/path to the local host.\n");
+
+        CommandArgumentEntry arg1, arg2;
+        CommandArgumentData file_arg_remote, file_arg_host;
+    
+        // Define the first (and only) variant of this arg.
+        file_arg_remote.arg_type = eArgTypeFilename;
+        file_arg_remote.arg_repetition = eArgRepeatPlain;
+        // There is only one variant this argument could be; put it into the argument entry.
+        arg1.push_back (file_arg_remote);
+        
+        // Define the second (and only) variant of this arg.
+        file_arg_host.arg_type = eArgTypeFilename;
+        file_arg_host.arg_repetition = eArgRepeatPlain;
+        // There is only one variant this argument could be; put it into the argument entry.
+        arg2.push_back (file_arg_host);
+
+        // Push the data for the first and the second arguments into the m_arguments vector.
+        m_arguments.push_back (arg1);
+        m_arguments.push_back (arg2);
+    }
+    
+    virtual
+    ~CommandObjectPlatformGetFile ()
+    {
+    }
+    
+    virtual bool
+    DoExecute (Args& args, CommandReturnObject &result)
+    {
+        // If the number of arguments is incorrect, issue an error message.
+        if (args.GetArgumentCount() != 2)
+        {
+            result.GetErrorStream().Printf("error: required arguments missing; specify both the source and destination file paths\n");
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+
+        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+        if (platform_sp)
+        {
+            const char *remote_file_path = args.GetArgumentAtIndex(0);
+            const char *local_file_path = args.GetArgumentAtIndex(1);
+            Error error = platform_sp->GetFile(FileSpec(remote_file_path, false),
+                                               FileSpec(local_file_path, false));
+            if (error.Success())
+            {
+                result.AppendMessageWithFormat("successfully get-file from %s (remote) to %s (host)\n",
+                                               remote_file_path, local_file_path);
+                result.SetStatus (eReturnStatusSuccessFinishResult);
+            }
+            else
+            {
+                result.AppendMessageWithFormat("get-file failed: %s\n", error.AsCString());
+                result.SetStatus (eReturnStatusFailed);
+            }
+        }
+        else
+        {
+            result.AppendError ("no platform currently selected\n");
+            result.SetStatus (eReturnStatusFailed);
+        }
+        return result.Succeeded();
+    }
+};
+
+//----------------------------------------------------------------------
+// "platform get-size remote-file-path"
+//----------------------------------------------------------------------
+class CommandObjectPlatformGetSize : public CommandObjectParsed
+{
+public:
+    CommandObjectPlatformGetSize (CommandInterpreter &interpreter) :
+    CommandObjectParsed (interpreter,
+                         "platform get-size",
+                         "Get the file size from the remote end.",
+                         "platform get-size <remote-file-spec>",
+                         0)
+    {
+        SetHelpLong(
+"Examples: \n\
+\n\
+    platform get-size /the/remote/file/path\n\
+    # Get the file size from the remote end with path /the/remote/file/path.\n");
+
+        CommandArgumentEntry arg1;
+        CommandArgumentData file_arg_remote;
+    
+        // Define the first (and only) variant of this arg.
+        file_arg_remote.arg_type = eArgTypeFilename;
+        file_arg_remote.arg_repetition = eArgRepeatPlain;
+        // There is only one variant this argument could be; put it into the argument entry.
+        arg1.push_back (file_arg_remote);
+        
+        // Push the data for the first argument into the m_arguments vector.
+        m_arguments.push_back (arg1);
+    }
+    
+    virtual
+    ~CommandObjectPlatformGetSize ()
+    {
+    }
+    
+    virtual bool
+    DoExecute (Args& args, CommandReturnObject &result)
+    {
+        // If the number of arguments is incorrect, issue an error message.
+        if (args.GetArgumentCount() != 1)
+        {
+            result.GetErrorStream().Printf("error: required argument missing; specify the source file path as the only argument\n");
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+
+        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+        if (platform_sp)
+        {
+            std::string remote_file_path(args.GetArgumentAtIndex(0));
+            user_id_t size = platform_sp->GetFileSize(FileSpec(remote_file_path.c_str(), false));
+            if (size != UINT64_MAX)
+            {
+                result.AppendMessageWithFormat("File size of %s (remote): %" PRIu64 "\n", remote_file_path.c_str(), size);
+                result.SetStatus (eReturnStatusSuccessFinishResult);
+            }
+            else
+            {
+                result.AppendMessageWithFormat("Eroor getting file size of %s (remote)\n", remote_file_path.c_str());
+                result.SetStatus (eReturnStatusFailed);
+            }
+        }
+        else
+        {
+            result.AppendError ("no platform currently selected\n");
+            result.SetStatus (eReturnStatusFailed);
+        }
+        return result.Succeeded();
+    }
+};
+
+//----------------------------------------------------------------------
+// "platform put-file"
+//----------------------------------------------------------------------
+class CommandObjectPlatformPutFile : public CommandObjectParsed
+{
+public:
+    CommandObjectPlatformPutFile (CommandInterpreter &interpreter) :
+    CommandObjectParsed (interpreter,
+                         "platform put-file",
+                         "Transfer a file from this system to the remote end.",
+                         NULL,
+                         0)
+    {
+    }
+    
+    virtual
+    ~CommandObjectPlatformPutFile ()
+    {
+    }
+    
+    virtual bool
+    DoExecute (Args& args, CommandReturnObject &result)
+    {
+        const char* src = args.GetArgumentAtIndex(0);
+        const char* dst = args.GetArgumentAtIndex(1);
+
+        FileSpec src_fs(src, true);
+        FileSpec dst_fs(dst, false);
+        
+        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+        if (platform_sp)
+        {
+            Error error (platform_sp->PutFile(src_fs, dst_fs));
+            if (error.Success())
+            {
+                result.SetStatus (eReturnStatusSuccessFinishNoResult);
+            }
+            else
+            {
+                result.AppendError (error.AsCString());
+                result.SetStatus (eReturnStatusFailed);
+            }
+        }
+        else
+        {
+            result.AppendError ("no platform currently selected\n");
+            result.SetStatus (eReturnStatusFailed);
+        }
+        return result.Succeeded();
+    }
+};
+
+//----------------------------------------------------------------------
+// "platform process launch"
+//----------------------------------------------------------------------
+class CommandObjectPlatformProcessLaunch : public CommandObjectParsed
+{
+public:
+    CommandObjectPlatformProcessLaunch (CommandInterpreter &interpreter) :
+        CommandObjectParsed (interpreter,
+                             "platform process launch",
+                             "Launch a new process on a remote platform.",
+                             "platform process launch program",
+                             eFlagRequiresTarget | eFlagTryTargetAPILock),
+        m_options (interpreter)
+    {
+    }
+    
+    virtual
+    ~CommandObjectPlatformProcessLaunch ()
+    {
+    }
+    
+    virtual Options *
+    GetOptions ()
+    {
+        return &m_options;
+    }
+    
+protected:
+    virtual bool
+    DoExecute (Args& args, CommandReturnObject &result)
+    {
+        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+        PlatformSP platform_sp;
+        if (target)
+        {   
+            platform_sp = target->GetPlatform();
+        }   
+        if (!platform_sp)
+        {
+            platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
+        }   
+
+        if (platform_sp)
+        {
+            Error error;
+            const size_t argc = args.GetArgumentCount();
+            Target *target = m_exe_ctx.GetTargetPtr();
+            Module *exe_module = target->GetExecutableModulePointer();
+            if (exe_module)
+            {
+                m_options.launch_info.GetExecutableFile () = exe_module->GetFileSpec();
+                char exe_path[PATH_MAX];
+                if (m_options.launch_info.GetExecutableFile ().GetPath (exe_path, sizeof(exe_path)))
+                    m_options.launch_info.GetArguments().AppendArgument (exe_path);
+                m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture();
+            }
+
+            if (argc > 0)
+            {
+                if (m_options.launch_info.GetExecutableFile ())
+                {
+                    // We already have an executable file, so we will use this
+                    // and all arguments to this function are extra arguments
+                    m_options.launch_info.GetArguments().AppendArguments (args);
+                }
+                else
+                {
+                    // We don't have any file yet, so the first argument is our
+                    // executable, and the rest are program arguments
+                    const bool first_arg_is_executable = true;
+                    m_options.launch_info.SetArguments (args, first_arg_is_executable);
+                }
+            }
+            
+            if (m_options.launch_info.GetExecutableFile ())
+            {
+                Debugger &debugger = m_interpreter.GetDebugger();
+
+                if (argc == 0)
+                    target->GetRunArguments(m_options.launch_info.GetArguments());
+
+                ProcessSP process_sp (platform_sp->DebugProcess (m_options.launch_info, 
+                                                                 debugger,
+                                                                 target,
+                                                                 debugger.GetListener(),
+                                                                 error));
+                if (process_sp && process_sp->IsAlive())
+                {
+                    result.SetStatus (eReturnStatusSuccessFinishNoResult);
+                    return true;
+                }
+                
+                if (error.Success())
+                    result.AppendError ("process launch failed");
+                else
+                    result.AppendError (error.AsCString());
+                result.SetStatus (eReturnStatusFailed);
+            }
+            else
+            {
+                result.AppendError ("'platform process launch' uses the current target file and arguments, or the executable and its arguments can be specified in this command");
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+        }
+        else
+        {
+            result.AppendError ("no platform is selected\n");
+        }
+        return result.Succeeded();
+    }
+    
+protected:
+    ProcessLaunchCommandOptions m_options;
+};
+
+
+
+//----------------------------------------------------------------------
+// "platform process list"
+//----------------------------------------------------------------------
+class CommandObjectPlatformProcessList : public CommandObjectParsed
+{
+public:
+    CommandObjectPlatformProcessList (CommandInterpreter &interpreter) :
+        CommandObjectParsed (interpreter, 
+                             "platform process list",
+                             "List processes on a remote platform by name, pid, or many other matching attributes.",
+                             "platform process list",
+                             0),
+        m_options (interpreter)
+    {
+    }
+    
+    virtual
+    ~CommandObjectPlatformProcessList ()
+    {
+    }
+    
+    virtual Options *
+    GetOptions ()
+    {
+        return &m_options;
+    }
+    
+protected:
+    virtual bool
+    DoExecute (Args& args, CommandReturnObject &result)
+    {
+        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+        PlatformSP platform_sp;
+        if (target)
+        {   
+            platform_sp = target->GetPlatform();
+        }   
+        if (!platform_sp)
         {
             platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
         }   
@@ -777,87 +1614,266 @@ public:
         CommandArgumentEntry arg;
         CommandArgumentData pid_args;
         
-        // Define the first (and only) variant of this arg.
-        pid_args.arg_type = eArgTypePid;
-        pid_args.arg_repetition = eArgRepeatStar;
+        // Define the first (and only) variant of this arg.
+        pid_args.arg_type = eArgTypePid;
+        pid_args.arg_repetition = eArgRepeatStar;
+        
+        // There is only one variant this argument could be; put it into the argument entry.
+        arg.push_back (pid_args);
+        
+        // Push the data for the first argument into the m_arguments vector.
+        m_arguments.push_back (arg);
+    }
+    
+    virtual
+    ~CommandObjectPlatformProcessInfo ()
+    {
+    }
+    
+protected:
+    virtual bool
+    DoExecute (Args& args, CommandReturnObject &result)
+    {
+        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+        PlatformSP platform_sp;
+        if (target)
+        {   
+            platform_sp = target->GetPlatform();
+        }   
+        if (!platform_sp)
+        {
+            platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
+        }   
+
+        if (platform_sp)
+        {
+            const size_t argc = args.GetArgumentCount();
+            if (argc > 0)
+            {
+                Error error;
+                
+                if (platform_sp->IsConnected())
+                {
+                    Stream &ostrm = result.GetOutputStream();      
+                    bool success;
+                    for (size_t i=0; i<argc; ++ i)
+                    {
+                        const char *arg = args.GetArgumentAtIndex(i);
+                        lldb::pid_t pid = Args::StringToUInt32 (arg, LLDB_INVALID_PROCESS_ID, 0, &success);
+                        if (success)
+                        {
+                            ProcessInstanceInfo proc_info;
+                            if (platform_sp->GetProcessInfo (pid, proc_info))
+                            {
+                                ostrm.Printf ("Process information for process %" PRIu64 ":\n", pid);
+                                proc_info.Dump (ostrm, platform_sp.get());
+                            }
+                            else
+                            {
+                                ostrm.Printf ("error: no process information is available for process %" PRIu64 "\n", pid);
+                            }
+                            ostrm.EOL();
+                        }
+                        else
+                        {
+                            result.AppendErrorWithFormat ("invalid process ID argument '%s'", arg);
+                            result.SetStatus (eReturnStatusFailed);            
+                            break;
+                        }
+                    }
+                }
+                else
+                {
+                    // Not connected...
+                    result.AppendErrorWithFormat ("not connected to '%s'", platform_sp->GetPluginName().GetCString());
+                    result.SetStatus (eReturnStatusFailed);            
+                }
+            }
+            else
+            {
+                // No args
+                result.AppendError ("one or more process id(s) must be specified");
+                result.SetStatus (eReturnStatusFailed);            
+            }
+        }
+        else
+        {
+            result.AppendError ("no platform is currently selected");
+            result.SetStatus (eReturnStatusFailed);            
+        }
+        return result.Succeeded();
+    }
+};
+
+class CommandObjectPlatformProcessAttach : public CommandObjectParsed
+{
+public:
+    
+    class CommandOptions : public Options
+    {
+    public:
+        
+        CommandOptions (CommandInterpreter &interpreter) :
+        Options(interpreter)
+        {
+            // Keep default values of all options in one place: OptionParsingStarting ()
+            OptionParsingStarting ();
+        }
+        
+        ~CommandOptions ()
+        {
+        }
+        
+        Error
+        SetOptionValue (uint32_t option_idx, const char *option_arg)
+        {
+            Error error;
+            char short_option = (char) m_getopt_table[option_idx].val;
+            bool success = false;
+            switch (short_option)
+            {
+                case 'p':   
+                {
+                    lldb::pid_t pid = Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success);
+                    if (!success || pid == LLDB_INVALID_PROCESS_ID)
+                    {
+                        error.SetErrorStringWithFormat("invalid process ID '%s'", option_arg);
+                    }
+                    else
+                    {
+                        attach_info.SetProcessID (pid);
+                    }
+                }
+                    break;
+                    
+                case 'P':
+                    attach_info.SetProcessPluginName (option_arg);
+                    break;
+                    
+                case 'n': 
+                    attach_info.GetExecutableFile().SetFile(option_arg, false);
+                    break;
+                    
+                case 'w':   
+                    attach_info.SetWaitForLaunch(true);
+                    break;
+                    
+                default:
+                    error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+                    break;
+            }
+            return error;
+        }
+        
+        void
+        OptionParsingStarting ()
+        {
+            attach_info.Clear();
+        }
+        
+        const OptionDefinition*
+        GetDefinitions ()
+        {
+            return g_option_table;
+        }
+        
+        virtual bool
+        HandleOptionArgumentCompletion (Args &input,
+                                        int cursor_index,
+                                        int char_pos,
+                                        OptionElementVector &opt_element_vector,
+                                        int opt_element_index,
+                                        int match_start_point,
+                                        int max_return_elements,
+                                        bool &word_complete,
+                                        StringList &matches)
+        {
+            int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
+            int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
+            
+            // We are only completing the name option for now...
+            
+            const OptionDefinition *opt_defs = GetDefinitions();
+            if (opt_defs[opt_defs_index].short_option == 'n')
+            {
+                // Are we in the name?
+                
+                // Look to see if there is a -P argument provided, and if so use that plugin, otherwise
+                // use the default plugin.
+                
+                const char *partial_name = NULL;
+                partial_name = input.GetArgumentAtIndex(opt_arg_pos);
+                
+                PlatformSP platform_sp (m_interpreter.GetPlatform (true));
+                if (platform_sp)
+                {
+                    ProcessInstanceInfoList process_infos;
+                    ProcessInstanceInfoMatch match_info;
+                    if (partial_name)
+                    {
+                        match_info.GetProcessInfo().GetExecutableFile().SetFile(partial_name, false);
+                        match_info.SetNameMatchType(eNameMatchStartsWith);
+                    }
+                    platform_sp->FindProcesses (match_info, process_infos);
+                    const uint32_t num_matches = process_infos.GetSize();
+                    if (num_matches > 0)
+                    {
+                        for (uint32_t i=0; i<num_matches; ++i)
+                        {
+                            matches.AppendString (process_infos.GetProcessNameAtIndex(i), 
+                                                  process_infos.GetProcessNameLengthAtIndex(i));
+                        }
+                    }
+                }
+            }
+            
+            return false;
+        }
+        
+        // Options table: Required for subclasses of Options.
         
-        // There is only one variant this argument could be; put it into the argument entry.
-        arg.push_back (pid_args);
+        static OptionDefinition g_option_table[];
         
-        // Push the data for the first argument into the m_arguments vector.
-        m_arguments.push_back (arg);
+        // Instance variables to hold the values for command options.
+        
+        ProcessAttachInfo attach_info;
+    };
+    
+    CommandObjectPlatformProcessAttach (CommandInterpreter &interpreter) :
+    CommandObjectParsed (interpreter,
+                         "platform process attach",
+                         "Attach to a process.",
+                         "platform process attach <cmd-options>"),
+    m_options (interpreter)
+    {
     }
     
-    virtual
-    ~CommandObjectPlatformProcessInfo ()
+    ~CommandObjectPlatformProcessAttach ()
     {
     }
     
-protected:
-    virtual bool
-    DoExecute (Args& args, CommandReturnObject &result)
+    bool
+    DoExecute (Args& command,
+             CommandReturnObject &result)
     {
-        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
-        PlatformSP platform_sp;
-        if (target)
-        {   
-            platform_sp = target->GetPlatform();
-        }   
-        if (!platform_sp)
-        {
-            platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
-        }   
-
+        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
         if (platform_sp)
         {
-            const size_t argc = args.GetArgumentCount();
-            if (argc > 0)
+            Error err;
+            ProcessSP remote_process_sp =
+            platform_sp->Attach(m_options.attach_info, m_interpreter.GetDebugger(), NULL, m_interpreter.GetDebugger().GetListener(), err);
+            if (err.Fail())
             {
-                Error error;
-                
-                if (platform_sp->IsConnected())
-                {
-                    Stream &ostrm = result.GetOutputStream();      
-                    bool success;
-                    for (size_t i=0; i<argc; ++ i)
-                    {
-                        const char *arg = args.GetArgumentAtIndex(i);
-                        lldb::pid_t pid = Args::StringToUInt32 (arg, LLDB_INVALID_PROCESS_ID, 0, &success);
-                        if (success)
-                        {
-                            ProcessInstanceInfo proc_info;
-                            if (platform_sp->GetProcessInfo (pid, proc_info))
-                            {
-                                ostrm.Printf ("Process information for process %" PRIu64 ":\n", pid);
-                                proc_info.Dump (ostrm, platform_sp.get());
-                            }
-                            else
-                            {
-                                ostrm.Printf ("error: no process information is available for process %" PRIu64 "\n", pid);
-                            }
-                            ostrm.EOL();
-                        }
-                        else
-                        {
-                            result.AppendErrorWithFormat ("invalid process ID argument '%s'", arg);
-                            result.SetStatus (eReturnStatusFailed);            
-                            break;
-                        }
-                    }
-                }
-                else
-                {
-                    // Not connected...
-                    result.AppendErrorWithFormat ("not connected to '%s'", platform_sp->GetPluginName().GetCString());
-                    result.SetStatus (eReturnStatusFailed);            
-                }
+                result.AppendError(err.AsCString());
+                result.SetStatus (eReturnStatusFailed);
             }
-            else
+            else if (remote_process_sp.get() == NULL)
             {
-                // No args
-                result.AppendError ("one or more process id(s) must be specified");
-                result.SetStatus (eReturnStatusFailed);            
+                result.AppendError("could not attach: unknown reason");
+                result.SetStatus (eReturnStatusFailed);
             }
+            else
+                result.SetStatus (eReturnStatusSuccessFinishResult);
         }
         else
         {
@@ -866,9 +1882,28 @@ protected:
         }
         return result.Succeeded();
     }
+    
+    Options *
+    GetOptions ()
+    {
+        return &m_options;
+    }
+    
+protected:
+    
+    CommandOptions m_options;
 };
 
 
+OptionDefinition
+CommandObjectPlatformProcessAttach::CommandOptions::g_option_table[] =
+{
+    { LLDB_OPT_SET_ALL, false, "plugin", 'P', required_argument, NULL, 0, eArgTypePlugin,        "Name of the process plugin you want to use."},
+    { LLDB_OPT_SET_1,   false, "pid",    'p', required_argument, NULL, 0, eArgTypePid,           "The process ID of an existing process to attach to."},
+    { LLDB_OPT_SET_2,   false, "name",   'n', required_argument, NULL, 0, eArgTypeProcessName,  "The name of the process to attach to."},
+    { LLDB_OPT_SET_2,   false, "waitfor",'w', no_argument,       NULL, 0, eArgTypeNone,              "Wait for the the process with <process-name> to launch."},
+    { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
 
 
 class CommandObjectPlatformProcess : public CommandObjectMultiword
@@ -883,7 +1918,7 @@ public:
                                 "A set of commands to query, launch and attach to platform processes",
                                 "platform process [attach|launch|list] ...")
     {
-//        LoadSubCommand ("attach", CommandObjectSP (new CommandObjectPlatformProcessAttach (interpreter)));
+        LoadSubCommand ("attach", CommandObjectSP (new CommandObjectPlatformProcessAttach (interpreter)));
         LoadSubCommand ("launch", CommandObjectSP (new CommandObjectPlatformProcessLaunch (interpreter)));
         LoadSubCommand ("info"  , CommandObjectSP (new CommandObjectPlatformProcessInfo (interpreter)));
         LoadSubCommand ("list"  , CommandObjectSP (new CommandObjectPlatformProcessList (interpreter)));
@@ -902,16 +1937,84 @@ private:
     DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatformProcess);
 };
 
-
+//----------------------------------------------------------------------
+// "platform shell"
+//----------------------------------------------------------------------
 class CommandObjectPlatformShell : public CommandObjectRaw
 {
 public:
+    
+    class CommandOptions : public Options
+    {
+    public:
+        
+        CommandOptions (CommandInterpreter &interpreter) :
+        Options(interpreter)
+        {
+        }
+        
+        virtual
+        ~CommandOptions ()
+        {
+        }
+        
+        virtual uint32_t
+        GetNumDefinitions ()
+        {
+            return 1;
+        }
+        
+        virtual const OptionDefinition*
+        GetDefinitions ()
+        {
+            return g_option_table;
+        }
+        
+        virtual Error
+        SetOptionValue (uint32_t option_idx,
+                        const char *option_value)
+        {
+            Error error;
+            
+            const char short_option = (char) g_option_table[option_idx].short_option;
+            
+            switch (short_option)
+            {
+                case 't':
+                {
+                    bool success;
+                    timeout = Args::StringToUInt32(option_value, 10, 10, &success);
+                    if (!success)
+                        error.SetErrorStringWithFormat("could not convert \"%s\" to a numeric value.", option_value);
+                    break;
+                }
+                default:
+                    error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+                    break;
+            }
+            
+            return error;
+        }
+        
+        virtual void
+        OptionParsingStarting ()
+        {
+            timeout = 10;
+        }
+        
+        // Options table: Required for subclasses of Options.
+        
+        static OptionDefinition g_option_table[];
+        uint32_t timeout;
+    };
+    
     CommandObjectPlatformShell (CommandInterpreter &interpreter) :
-        CommandObjectRaw (interpreter, 
-                         "platform shell",
-                         "Run a shell command on a the selected platform.",
-                         "platform shell <shell-command>",
-                         0)
+    CommandObjectRaw (interpreter, 
+                      "platform shell",
+                      "Run a shell command on a the selected platform.",
+                      "platform shell <shell-command>",
+                      0),
+    m_options(interpreter)
     {
     }
     
@@ -920,31 +2023,80 @@ public:
     {
     }
     
-protected:
     virtual bool
     DoExecute (const char *raw_command_line, CommandReturnObject &result)
     {
-        // TODO: Implement "Platform::RunShellCommand()" and switch over to using
-        // the current platform when it is in the interface. 
-        const char *working_dir = NULL;
-        std::string output;
-        int status = -1;
-        int signo = -1;
-        Error error (Host::RunShellCommand (raw_command_line, working_dir, &status, &signo, &output, 10));
-        if (!output.empty())
-            result.GetOutputStream().PutCString(output.c_str());
-        if (status > 0)
-        {
-            if (signo > 0)
-            {
-                const char *signo_cstr = Host::GetSignalAsCString(signo);
-                if (signo_cstr)
-                    result.GetOutputStream().Printf("error: command returned with status %i and signal %s\n", status, signo_cstr);
+        const char* expr = NULL;
+
+        // Print out an usage syntax on an empty command line.
+        if (raw_command_line[0] == '\0')
+        {
+            result.GetOutputStream().Printf("%s\n", this->GetSyntax());
+            return true;
+        }
+
+        if (raw_command_line[0] == '-')
+        {
+            // We have some options and these options MUST end with --.
+            const char *end_options = NULL;
+            const char *s = raw_command_line;
+            while (s && s[0])
+            {
+                end_options = ::strstr (s, "--");
+                if (end_options)
+                {
+                    end_options += 2; // Get past the "--"
+                    if (::isspace (end_options[0]))
+                    {
+                        expr = end_options;
+                        while (::isspace (*expr))
+                            ++expr;
+                        break;
+                    }
+                }
+                s = end_options;
+            }
+            
+            if (end_options)
+            {
+                Args args (raw_command_line, end_options - raw_command_line);
+                if (!ParseOptions (args, result))
+                    return false;
+            }
+        }
+        
+        if (expr == NULL)
+            expr = raw_command_line;
+        
+        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+        Error error;
+        if (platform_sp)
+        {
+            const char *working_dir = NULL;
+            std::string output;
+            int status = -1;
+            int signo = -1;
+            error = (platform_sp->RunShellCommand (expr, working_dir, &status, &signo, &output, m_options.timeout));
+            if (!output.empty())
+                result.GetOutputStream().PutCString(output.c_str());
+            if (status > 0)
+            {
+                if (signo > 0)
+                {
+                    const char *signo_cstr = Host::GetSignalAsCString(signo);
+                    if (signo_cstr)
+                        result.GetOutputStream().Printf("error: command returned with status %i and signal %s\n", status, signo_cstr);
+                    else
+                        result.GetOutputStream().Printf("error: command returned with status %i and signal %i\n", status, signo);
+                }
                 else
-                    result.GetOutputStream().Printf("error: command returned with status %i and signal %i\n", status, signo);
+                    result.GetOutputStream().Printf("error: command returned with status %i\n", status);
             }
-            else
-                result.GetOutputStream().Printf("error: command returned with status %i\n", status);
+        }
+        else
+        {
+            result.GetOutputStream().Printf("error: cannot run remote shell commands without a platform\n");
+            error.SetErrorString("error: cannot run remote shell commands without a platform");
         }
 
         if (error.Fail())
@@ -958,6 +2110,208 @@ protected:
         }
         return true;
     }
+    CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectPlatformShell::CommandOptions::g_option_table[] =
+{
+    { LLDB_OPT_SET_ALL, false, "timeout",      't', required_argument, NULL, 0, eArgTypeValue,    "Seconds to wait for the remote host to finish running the command."},
+};
+
+struct RecurseCopyBaton
+{
+    const std::string& destination;
+    const PlatformSP& platform_sp;
+    Error error;
+};
+
+
+static FileSpec::EnumerateDirectoryResult
+RecurseCopy_Callback (void *baton,
+                      FileSpec::FileType file_type,
+                      const FileSpec &spec)
+{
+    RecurseCopyBaton* rc_baton = (RecurseCopyBaton*)baton;
+    switch (file_type)
+    {
+        case FileSpec::eFileTypePipe:
+        case FileSpec::eFileTypeSocket:
+            // we have no way to copy pipes and sockets - ignore them and continue
+            return FileSpec::eEnumerateDirectoryResultNext;
+            break;
+            
+        case FileSpec::eFileTypeSymbolicLink:
+            // what to do for symlinks?
+            return FileSpec::eEnumerateDirectoryResultNext;
+            break;
+            
+        case FileSpec::eFileTypeDirectory:
+        {
+            // make the new directory and get in there
+            FileSpec new_directory(rc_baton->destination.c_str(),false);
+            new_directory.AppendPathComponent(spec.GetLastPathComponent());
+            uint32_t errcode = rc_baton->platform_sp->MakeDirectory(new_directory, 0777);
+            std::string new_directory_path (new_directory.GetPath());
+            if (errcode != 0)
+            {
+                rc_baton->error.SetErrorStringWithFormat("unable to setup directory %s on remote end",new_directory_path.c_str());
+                return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
+            }
+            
+            // now recurse
+            std::string local_path (spec.GetPath());
+            RecurseCopyBaton rc_baton2 = { new_directory_path, rc_baton->platform_sp, Error() };
+            FileSpec::EnumerateDirectory(local_path.c_str(), true, true, true, RecurseCopy_Callback, &rc_baton2);
+            if (rc_baton2.error.Fail())
+            {
+                rc_baton->error.SetErrorString(rc_baton2.error.AsCString());
+                return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
+            }
+            return FileSpec::eEnumerateDirectoryResultNext;
+        }
+            break;
+            
+        case FileSpec::eFileTypeRegular:
+        {
+            // copy the file and keep going
+            std::string dest(rc_baton->destination);
+            dest.append(spec.GetFilename().GetCString());
+            Error err = rc_baton->platform_sp->PutFile(spec, FileSpec(dest.c_str(), false));
+            if (err.Fail())
+            {
+                rc_baton->error.SetErrorString(err.AsCString());
+                return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
+            }
+            return FileSpec::eEnumerateDirectoryResultNext;
+        }
+            break;
+            
+        case FileSpec::eFileTypeInvalid:
+        case FileSpec::eFileTypeOther:
+        case FileSpec::eFileTypeUnknown:
+        default:
+            rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s/%s", spec.GetDirectory().GetCString(), spec.GetFilename().GetCString());
+            return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
+            break;
+    }
+}
+
+//----------------------------------------------------------------------
+// "platform install" - install a target to a remote end
+//----------------------------------------------------------------------
+class CommandObjectPlatformInstall : public CommandObjectParsed
+{
+public:
+    CommandObjectPlatformInstall (CommandInterpreter &interpreter) :
+    CommandObjectParsed (interpreter,
+                         "platform target-install",
+                         "Install a target (bundle or executable file) to the remote end.",
+                         "platform target-install <local-thing> <remote-sandbox>",
+                         0)
+    {
+    }
+    
+    virtual
+    ~CommandObjectPlatformInstall ()
+    {
+    }
+    
+    virtual bool
+    DoExecute (Args& args, CommandReturnObject &result)
+    {
+        if (args.GetArgumentCount() != 2)
+        {
+            result.AppendError("platform target-install takes two arguments");
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+        // TODO: move the bulk of this code over to the platform itself
+        std::string local_thing(args.GetArgumentAtIndex(0));
+        std::string remote_sandbox(args.GetArgumentAtIndex(1));
+        FileSpec source(local_thing.c_str(), true);
+        if (source.Exists() == false)
+        {
+            result.AppendError("source location does not exist or is not accessible");
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+        PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+        if (!platform_sp)
+        {
+            result.AppendError ("no platform currently selected");
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+        FileSpec::FileType source_type(source.GetFileType());
+        if (source_type == FileSpec::eFileTypeDirectory)
+        {
+            if (platform_sp->GetSupportsRSync())
+            {
+                FileSpec remote_folder(remote_sandbox.c_str(), false);
+                Error rsync_err = platform_sp->PutFile(source, remote_folder);
+                if (rsync_err.Success())
+                {
+                    result.SetStatus(eReturnStatusSuccessFinishResult);
+                    return result.Succeeded();
+                }
+            }
+            FileSpec remote_folder(remote_sandbox.c_str(), false);
+            remote_folder.AppendPathComponent(source.GetLastPathComponent());
+            // TODO: default permissions are bad
+            uint32_t errcode = platform_sp->MakeDirectory(remote_folder, 0777);
+            if (errcode != 0)
+            {
+                result.AppendError("unable to setup target directory on remote end");
+                result.SetStatus(eReturnStatusSuccessFinishNoResult);
+                return result.Succeeded();
+            }
+            // now recurse
+            std::string remote_folder_path (remote_folder.GetPath());
+            Error err = RecurseCopy(source,remote_folder_path,platform_sp);
+            if (err.Fail())
+            {
+                result.AppendError(err.AsCString());
+                result.SetStatus(eReturnStatusFailed);
+            }
+            else
+                result.SetStatus(eReturnStatusSuccessFinishResult);
+            return result.Succeeded();
+        }
+        else if (source_type == FileSpec::eFileTypeRegular)
+        {
+            // just a plain file - push it to remote and be done
+            remote_sandbox.append(source.GetFilename().GetCString());
+            FileSpec destination(remote_sandbox.c_str(),false);
+            Error err = platform_sp->PutFile(source, destination);
+            if (err.Success())
+                result.SetStatus(eReturnStatusSuccessFinishResult);
+            else
+            {
+                result.AppendError(err.AsCString());
+                result.SetStatus(eReturnStatusFailed);
+            }
+            return result.Succeeded();
+        }
+        else
+        {
+            result.AppendError("source is not a known type of file");
+            result.SetStatus(eReturnStatusFailed);
+            return result.Succeeded();
+        }
+    }
+private:
+    
+    Error
+    RecurseCopy (const FileSpec& source,
+                 const std::string& destination,
+                 const PlatformSP& platform_sp)
+    {
+        std::string source_path (source.GetPath());
+        RecurseCopyBaton baton = { destination, platform_sp, Error() };
+        FileSpec::EnumerateDirectory(source_path.c_str(), true, true, true, RecurseCopy_Callback, &baton);
+        return baton.error;
+    }
 };
 
 //----------------------------------------------------------------------
@@ -974,8 +2328,16 @@ CommandObjectPlatform::CommandObjectPlat
     LoadSubCommand ("status", CommandObjectSP (new CommandObjectPlatformStatus  (interpreter)));
     LoadSubCommand ("connect", CommandObjectSP (new CommandObjectPlatformConnect  (interpreter)));
     LoadSubCommand ("disconnect", CommandObjectSP (new CommandObjectPlatformDisconnect  (interpreter)));
+#ifdef LLDB_CONFIGURATION_DEBUG
+    LoadSubCommand ("mkdir", CommandObjectSP (new CommandObjectPlatformMkDir  (interpreter)));
+    LoadSubCommand ("file", CommandObjectSP (new CommandObjectPlatformFile  (interpreter)));
+    LoadSubCommand ("get-file", CommandObjectSP (new CommandObjectPlatformGetFile  (interpreter)));
+    LoadSubCommand ("get-size", CommandObjectSP (new CommandObjectPlatformGetSize  (interpreter)));
+    LoadSubCommand ("put-file", CommandObjectSP (new CommandObjectPlatformPutFile  (interpreter)));
+#endif
     LoadSubCommand ("process", CommandObjectSP (new CommandObjectPlatformProcess  (interpreter)));
     LoadSubCommand ("shell", CommandObjectSP (new CommandObjectPlatformShell  (interpreter)));
+    LoadSubCommand ("target-install", CommandObjectSP (new CommandObjectPlatformInstall  (interpreter)));
 }
 
 

Modified: lldb/trunk/source/Commands/CommandObjectTarget.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectTarget.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectTarget.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectTarget.cpp Mon Aug 26 18:57:52 2013
@@ -158,6 +158,7 @@ public:
         m_arch_option (),
         m_platform_options(true), // Do include the "--platform" option in the platform settings by passing true
         m_core_file (LLDB_OPT_SET_1, false, "core", 'c', 0, eArgTypeFilename, "Fullpath to a core file to use for this target."),
+        m_platform_path (LLDB_OPT_SET_1, false, "platform-path", 'P', 0, eArgTypePath, "Path to the remote file to use for this target."),
         m_symbol_file (LLDB_OPT_SET_1, false, "symfile", 's', 0, eArgTypeFilename, "Fullpath to a stand alone debug symbols file for when debug symbols are not in the executable."),
         m_remote_file (LLDB_OPT_SET_1, false, "remote-file", 'r', 0, eArgTypeFilename, "Fullpath to the file on the remote host if debugging remotely."),
         m_add_dependents (LLDB_OPT_SET_1, false, "no-dependents", 'd', "Don't load dependent files when creating the target, just add the specified executable.", true, true)
@@ -178,6 +179,7 @@ public:
         m_option_group.Append (&m_arch_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
         m_option_group.Append (&m_platform_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
         m_option_group.Append (&m_core_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+        m_option_group.Append (&m_platform_path, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
         m_option_group.Append (&m_symbol_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
         m_option_group.Append (&m_remote_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
         m_option_group.Append (&m_add_dependents, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
@@ -226,7 +228,7 @@ protected:
         FileSpec core_file (m_core_file.GetOptionValue().GetCurrentValue());
         FileSpec remote_file (m_remote_file.GetOptionValue().GetCurrentValue());
 
-        if (argc == 1 || core_file)
+        if (argc == 1 || core_file || remote_file)
         {
             FileSpec symfile (m_symbol_file.GetOptionValue().GetCurrentValue());
             if (symfile)
@@ -243,11 +245,70 @@ protected:
 
             const char *file_path = command.GetArgumentAtIndex(0);
             Timer scoped_timer(__PRETTY_FUNCTION__, "(lldb) target create '%s'", file_path);
-            TargetSP target_sp;
+            FileSpec file_spec;
+            
+            if (file_path)
+                file_spec.SetFile (file_path, true);
+            
+            bool must_set_platform_path = false;
+            
             Debugger &debugger = m_interpreter.GetDebugger();
+            PlatformSP platform_sp(debugger.GetPlatformList().GetSelectedPlatform ());
+
+            if (remote_file)
+            {
+                // I have a remote file.. two possible cases
+                if (file_spec && file_spec.Exists())
+                {
+                    // if the remote file does not exist, push it there
+                    if (!platform_sp->GetFileExists (remote_file))
+                    {
+                        Error err = platform_sp->PutFile(file_spec, remote_file);
+                        if (err.Fail())
+                        {
+                            result.AppendError(err.AsCString());
+                            result.SetStatus (eReturnStatusFailed);
+                            return false;
+                        }
+                    }
+                }
+                else
+                {
+                    // there is no local file and we need one
+                    // in order to make the remote ---> local transfer we need a platform
+                    // TODO: if the user has passed in a --platform argument, use it to fetch the right platform
+                    if (!platform_sp)
+                    {
+                        result.AppendError("unable to perform remote debugging without a platform");
+                        result.SetStatus (eReturnStatusFailed);
+                        return false;
+                    }
+                    if (file_path)
+                    {
+                        // copy the remote file to the local file
+                        Error err = platform_sp->GetFile(remote_file, file_spec);
+                        if (err.Fail())
+                        {
+                            result.AppendError(err.AsCString());
+                            result.SetStatus (eReturnStatusFailed);
+                            return false;
+                        }
+                    }
+                    else
+                    {
+                        // make up a local file
+                        result.AppendError("remote --> local transfer without local path is not implemented yet");
+                        result.SetStatus (eReturnStatusFailed);
+                        return false;
+                    }
+                }
+            }
+
+            TargetSP target_sp;
             const char *arch_cstr = m_arch_option.GetArchitectureName();
             const bool get_dependent_files = m_add_dependents.GetOptionValue().GetCurrentValue();
             Error error (debugger.GetTargetList().CreateTarget (debugger,
+//                                                                remote_file ? remote_file : file_spec,
                                                                 file_path,
                                                                 arch_cstr,
                                                                 get_dependent_files,
@@ -273,6 +334,13 @@ protected:
                 }
                 
                 debugger.GetTargetList().SetSelectedTarget(target_sp.get());
+                if (must_set_platform_path)
+                {
+                    ModuleSpec main_module_spec(file_spec);
+                    ModuleSP module_sp = target_sp->GetSharedModule(main_module_spec);
+                    if (module_sp)
+                        module_sp->SetPlatformFileSpec(remote_file);
+                }
                 if (core_file)
                 {
                     char core_path[PATH_MAX];
@@ -341,6 +409,7 @@ private:
     OptionGroupArchitecture m_arch_option;
     OptionGroupPlatform m_platform_options;
     OptionGroupFile m_core_file;
+    OptionGroupFile m_platform_path;
     OptionGroupFile m_symbol_file;
     OptionGroupFile m_remote_file;
     OptionGroupBoolean m_add_dependents;

Modified: lldb/trunk/source/Core/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/CMakeLists.txt?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Core/CMakeLists.txt (original)
+++ lldb/trunk/source/Core/CMakeLists.txt Mon Aug 26 18:57:52 2013
@@ -51,6 +51,7 @@ add_lldb_library(lldbCore
   StreamAsynchronousIO.cpp
   StreamCallback.cpp
   StreamFile.cpp
+  StreamGDBRemote.cpp
   StreamString.cpp
   StringList.cpp
   Timer.cpp

Modified: lldb/trunk/source/Core/Error.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Error.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Core/Error.cpp (original)
+++ lldb/trunk/source/Core/Error.cpp Mon Aug 26 18:57:52 2013
@@ -238,7 +238,7 @@ Error::LogIfError (Log *log, const char
             if (err_str == NULL)
                 err_str = "???";
 
-            SetErrorStringWithFormat("error: %s err = %s (0x%8.8x)", arg_msg, err_str, m_code);
+            SetErrorStringWithFormat("%s err = %s (0x%8.8x)", arg_msg, err_str, m_code);
             if (log)
                 log->Error("%s", m_string.c_str());
 

Added: lldb/trunk/source/Core/StreamGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/StreamGDBRemote.cpp?rev=189295&view=auto
==============================================================================
--- lldb/trunk/source/Core/StreamGDBRemote.cpp (added)
+++ lldb/trunk/source/Core/StreamGDBRemote.cpp Mon Aug 26 18:57:52 2013
@@ -0,0 +1,54 @@
+//===-- StreamGDBRemote.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/Core/StreamGDBRemote.h"
+#include <stdio.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+StreamGDBRemote::StreamGDBRemote () :
+StreamString ()
+{
+}
+
+StreamGDBRemote::StreamGDBRemote(uint32_t flags, uint32_t addr_size, ByteOrder byte_order) :
+StreamString (flags, addr_size, byte_order)
+{
+}
+
+StreamGDBRemote::~StreamGDBRemote()
+{
+}
+
+
+int
+StreamGDBRemote::PutEscapedBytes (const void* s,
+                                  size_t src_len)
+{
+    int bytes_written = 0;
+    const uint8_t *src = (const uint8_t *)s;
+    bool binary_is_set = m_flags.Test(eBinary);
+    m_flags.Clear(eBinary);
+    while (src_len)
+    {
+        uint8_t byte = *src;
+        src++; src_len--;
+        if (byte == 0x23 || byte == 0x24 || byte == 0x7d || byte == 0x2a)
+        {
+            bytes_written += PutChar(0x7d);
+            byte ^= 0x20;
+        }
+        bytes_written += PutChar(byte);
+    };
+    if (binary_is_set)
+        m_flags.Set(eBinary);
+    return bytes_written;
+}
+

Modified: lldb/trunk/source/Host/common/File.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/File.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/File.cpp (original)
+++ lldb/trunk/source/Host/common/File.cpp Mon Aug 26 18:57:52 2013
@@ -83,6 +83,20 @@ File::File(const char *path, uint32_t op
     Open (path, options, permissions);
 }
 
+File::File (const FileSpec& filespec,
+            uint32_t options,
+            uint32_t permissions) :
+    m_descriptor (kInvalidDescriptor),
+    m_stream (kInvalidStream),
+    m_options (0),
+    m_owned (false)
+{
+    if (filespec)
+    {
+        Open (filespec.GetPath().c_str(), options, permissions);
+    }
+}
+
 File::File (const File &rhs) :
     m_descriptor (kInvalidDescriptor),
     m_stream (kInvalidStream),
@@ -261,6 +275,53 @@ File::Open (const char *path, uint32_t o
     return error;
 }
 
+uint32_t
+File::GetPermissions (const char *path, Error &error)
+{
+    if (path && path[0])
+    {
+        struct stat file_stats;
+        if (::stat (path, &file_stats) == -1)
+            error.SetErrorToErrno();
+        else
+        {
+            error.Clear();
+            return file_stats.st_mode; // All bits from lldb_private::File::Permissions match those in POSIX mode bits
+        }
+    }
+    else
+    {
+        if (path)
+            error.SetErrorString ("invalid path");
+        else
+            error.SetErrorString ("empty path");        
+    }
+    return 0;
+}
+
+uint32_t
+File::GetPermissions(Error &error) const
+{
+    int fd = GetDescriptor();
+    if (fd != kInvalidDescriptor)
+    {
+        struct stat file_stats;
+        if (::fstat (fd, &file_stats) == -1)
+            error.SetErrorToErrno();
+        else
+        {
+            error.Clear();
+            return file_stats.st_mode; // All bits from lldb_private::File::Permissions match those in POSIX mode bits
+        }
+    }
+    else
+    {
+        error.SetErrorString ("invalid file descriptor");
+    }
+    return 0;
+}
+
+
 Error
 File::Close ()
 {
@@ -755,3 +816,51 @@ File::PrintfVarArg (const char *format,
     }
     return result;
 }
+
+mode_t
+File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
+{
+    mode_t mode = 0;
+    if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
+        mode |= O_RDWR;
+    else if (open_options & eOpenOptionWrite)
+        mode |= O_WRONLY;
+    
+    if (open_options & eOpenOptionAppend)
+        mode |= O_APPEND;
+
+    if (open_options & eOpenOptionTruncate)
+        mode |= O_TRUNC;
+
+    if (open_options & eOpenOptionNonBlocking)
+        mode |= O_NONBLOCK;
+
+    if (open_options & eOpenOptionCanCreateNewOnly)
+        mode |= O_CREAT | O_EXCL;
+    else if (open_options & eOpenOptionCanCreate)
+        mode |= O_CREAT;
+
+    return mode;
+}
+
+#define	O_RDONLY	0x0000		/* open for reading only */
+#define	O_WRONLY	0x0001		/* open for writing only */
+#define	O_RDWR		0x0002		/* open for reading and writing */
+#define	O_ACCMODE	0x0003		/* mask for above modes */
+#define	O_NONBLOCK	0x0004		/* no delay */
+#define	O_APPEND	0x0008		/* set append mode */
+#define	O_SYNC		0x0080		/* synch I/O file integrity */
+#define	O_SHLOCK	0x0010		/* open with shared file lock */
+#define	O_EXLOCK	0x0020		/* open with exclusive file lock */
+#define	O_ASYNC		0x0040		/* signal pgrp when data ready */
+#define	O_FSYNC		O_SYNC		/* source compatibility: do not use */
+#define O_NOFOLLOW  0x0100      /* don't follow symlinks */
+#define	O_CREAT		0x0200		/* create if nonexistant */
+#define	O_TRUNC		0x0400		/* truncate to zero length */
+#define	O_EXCL		0x0800		/* error if already exists */
+#define	O_EVTONLY	0x8000		/* descriptor requested for event notifications only */
+#define	O_NOCTTY	0x20000		/* don't assign controlling terminal */
+#define O_DIRECTORY	0x100000
+#define O_SYMLINK	0x200000	/* allow open of a symlink */
+#define O_DSYNC 	0x400000	/* synch I/O data integrity */
+#define	O_CLOEXEC	0x1000000	/* implicitly set FD_CLOEXEC */

Modified: lldb/trunk/source/Host/common/FileSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/FileSpec.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/FileSpec.cpp (original)
+++ lldb/trunk/source/Host/common/FileSpec.cpp Mon Aug 26 18:57:52 2013
@@ -29,6 +29,7 @@
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Program.h"
 
+#include "lldb/Core/StreamString.h"
 #include "lldb/Host/File.h"
 #include "lldb/Host/FileSpec.h"
 #include "lldb/Core/DataBufferHeap.h"
@@ -1106,6 +1107,140 @@ FileSpec::EnumerateDirectory
     return eEnumerateDirectoryResultNext;    
 }
 
+FileSpec
+FileSpec::CopyByAppendingPathComponent (const char *new_path)  const
+{
+    const bool resolve = false;
+    if (m_filename.IsEmpty() && m_directory.IsEmpty())
+        return FileSpec(new_path,resolve);
+    StreamString stream;
+    if (m_filename.IsEmpty())
+        stream.Printf("%s/%s",m_directory.GetCString(),new_path);
+    else if (m_directory.IsEmpty())
+        stream.Printf("%s/%s",m_filename.GetCString(),new_path);
+    else
+        stream.Printf("%s/%s/%s",m_directory.GetCString(), m_filename.GetCString(),new_path);
+    return FileSpec(stream.GetData(),resolve);
+}
+
+FileSpec
+FileSpec::CopyByRemovingLastPathComponent ()  const
+{
+    const bool resolve = false;
+    if (m_filename.IsEmpty() && m_directory.IsEmpty())
+        return FileSpec("",resolve);
+    if (m_directory.IsEmpty())
+        return FileSpec("",resolve);
+    if (m_filename.IsEmpty())
+    {
+        const char* dir_cstr = m_directory.GetCString();
+        const char* last_slash_ptr = ::strrchr(dir_cstr, '/');
+        
+        // check for obvious cases before doing the full thing
+        if (!last_slash_ptr)
+            return FileSpec("",resolve);
+        if (last_slash_ptr == dir_cstr)
+            return FileSpec("/",resolve);
+        
+        size_t last_slash_pos = last_slash_ptr - dir_cstr+1;
+        ConstString new_path(dir_cstr,last_slash_pos);
+        return FileSpec(new_path.GetCString(),resolve);
+    }
+    else
+        return FileSpec(m_directory.GetCString(),resolve);
+}
+
+const char*
+FileSpec::GetLastPathComponent () const
+{
+    if (m_filename.IsEmpty() && m_directory.IsEmpty())
+        return NULL;
+    if (m_filename.IsEmpty())
+    {
+        const char* dir_cstr = m_directory.GetCString();
+        const char* last_slash_ptr = ::strrchr(dir_cstr, '/');
+        if (last_slash_ptr == NULL)
+            return m_directory.GetCString();
+        if (last_slash_ptr == dir_cstr)
+        {
+            if (last_slash_ptr[1] == 0)
+                return last_slash_ptr;
+            else
+                return last_slash_ptr+1;
+        }
+        if (last_slash_ptr[1] != 0)
+            return last_slash_ptr+1;
+        const char* penultimate_slash_ptr = last_slash_ptr;
+        while (*penultimate_slash_ptr)
+        {
+            --penultimate_slash_ptr;
+            if (penultimate_slash_ptr == dir_cstr)
+                break;
+            if (*penultimate_slash_ptr == '/')
+                break;
+        }
+        ConstString new_path(penultimate_slash_ptr+1,last_slash_ptr-penultimate_slash_ptr);
+        return new_path.AsCString();
+    }
+    return m_filename.GetCString();
+}
+
+void
+FileSpec::AppendPathComponent (const char *new_path)
+{
+    const bool resolve = false;
+    if (m_filename.IsEmpty() && m_directory.IsEmpty())
+    {
+        SetFile(new_path,resolve);
+        return;
+    }
+    StreamString stream;
+    if (m_filename.IsEmpty())
+        stream.Printf("%s/%s",m_directory.GetCString(),new_path);
+    else if (m_directory.IsEmpty())
+        stream.Printf("%s/%s",m_filename.GetCString(),new_path);
+    else
+        stream.Printf("%s/%s/%s",m_directory.GetCString(), m_filename.GetCString(),new_path);
+    SetFile(stream.GetData(), resolve);
+}
+
+void
+FileSpec::RemoveLastPathComponent ()
+{
+    const bool resolve = false;
+    if (m_filename.IsEmpty() && m_directory.IsEmpty())
+    {
+        SetFile("",resolve);
+        return;
+    }
+    if (m_directory.IsEmpty())
+    {
+        SetFile("",resolve);
+        return;
+    }
+    if (m_filename.IsEmpty())
+    {
+        const char* dir_cstr = m_directory.GetCString();
+        const char* last_slash_ptr = ::strrchr(dir_cstr, '/');
+        
+        // check for obvious cases before doing the full thing
+        if (!last_slash_ptr)
+        {
+            SetFile("",resolve);
+            return;
+        }
+        if (last_slash_ptr == dir_cstr)
+        {
+            SetFile("/",resolve);
+            return;
+        }        
+        size_t last_slash_pos = last_slash_ptr - dir_cstr+1;
+        ConstString new_path(dir_cstr,last_slash_pos);
+        SetFile(new_path.GetCString(),resolve);
+    }
+    else
+        SetFile(m_directory.GetCString(),resolve);
+}
 //------------------------------------------------------------------
 /// Returns true if the filespec represents an implementation source
 /// file (files with a ".c", ".cpp", ".m", ".mm" (many more)

Modified: lldb/trunk/source/Host/common/Host.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/Host.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/Host.cpp (original)
+++ lldb/trunk/source/Host/common/Host.cpp Mon Aug 26 18:57:52 2013
@@ -1472,7 +1472,11 @@ Host::RunShellCommand (const char *comma
     
     error = LaunchProcess (launch_info);
     const lldb::pid_t pid = launch_info.GetProcessID();
-    if (pid != LLDB_INVALID_PROCESS_ID)
+
+    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
@@ -1524,10 +1528,6 @@ Host::RunShellCommand (const char *comma
         }
         shell_info->can_delete.SetValue(true, eBroadcastAlways);
     }
-    else
-    {
-        error.SetErrorString("failed to get process ID");
-    }
 
     if (output_file_path)
         ::unlink (output_file_path);
@@ -1613,9 +1613,169 @@ Host::SetCrashDescription (const char *d
 }
 
 lldb::pid_t
-LaunchApplication (const FileSpec &app_file_spec)
+Host::LaunchApplication (const FileSpec &app_file_spec)
 {
     return LLDB_INVALID_PROCESS_ID;
 }
 
+uint32_t
+Host::MakeDirectory (const char* path, mode_t mode)
+{
+    return UINT32_MAX;
+}
 #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,
+                mode_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 (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 (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
+}

Modified: lldb/trunk/source/Host/freebsd/Host.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/freebsd/Host.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Host/freebsd/Host.cpp (original)
+++ lldb/trunk/source/Host/freebsd/Host.cpp Mon Aug 26 18:57:52 2013
@@ -15,11 +15,13 @@
 #include <sys/user.h>
 #include <sys/utsname.h>
 #include <sys/sysctl.h>
+#include <sys/proc.h>
 
 #include <sys/ptrace.h>
 #include <sys/exec.h>
 #include <machine/elf.h>
 
+#include <spawn.h>
 
 // C++ Includes
 // Other libraries and framework includes
@@ -27,13 +29,17 @@
 #include "lldb/Core/Error.h"
 #include "lldb/Host/Endian.h"
 #include "lldb/Host/Host.h"
+#include "lldb/Core/Module.h"
 #include "lldb/Core/DataExtractor.h"
 #include "lldb/Core/StreamFile.h"
 #include "lldb/Core/StreamString.h"
 #include "lldb/Target/Process.h"
+#include "lldb/Target/Platform.h"
 
 #include "lldb/Core/DataBufferHeap.h"
 #include "lldb/Core/DataExtractor.h"
+#include "lldb/Utility/CleanUp.h"
+
 #include "llvm/Support/Host.h"
 
 
@@ -44,7 +50,6 @@ extern "C" {
 using namespace lldb;
 using namespace lldb_private;
 
-
 class FreeBSDThread
 {
 public:
@@ -120,7 +125,8 @@ Host::GetEnvironment (StringList &env)
 {
     char *v;
     char **var = environ;
-    for (; var != NULL && *var != NULL; ++var) {
+    for (; var != NULL && *var != NULL; ++var)
+    {
         v = strchr(*var, (int)'-');
         if (v == NULL)
             continue;
@@ -135,8 +141,8 @@ Host::GetOSVersion(uint32_t &major,
                    uint32_t &update)
 {
     struct utsname un;
-    int status;
 
+    ::memset(&un, 0, sizeof(utsname));
     if (uname(&un) < 0)
         return false;
 
@@ -144,11 +150,196 @@ Host::GetOSVersion(uint32_t &major,
     return status == 2;
 }
 
+// The posix_spawn() and posix_spawnp() functions first appeared in FreeBSD 8.0.
+static Error
+LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, ::pid_t &pid)
+{
+    Error error;
+    LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
+
+    assert(exe_path);
+    assert(!launch_info.GetFlags().Test (eLaunchFlagDebug));
+
+    posix_spawnattr_t attr;
+
+    error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX);
+    error.LogIfError(log.get(), "::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, &all_signals);
+    ::posix_spawnattr_setsigdefault(&attr, &no_signals);
+
+    short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
+
+    error.SetError( ::posix_spawnattr_setflags (&attr, flags), eErrorTypePOSIX);
+    error.LogIfError(log.get(), "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", flags);
+    if (error.Fail())
+        return error;
+
+    const size_t num_file_actions = launch_info.GetNumFileActions ();
+    posix_spawn_file_actions_t file_actions, *file_action_ptr = NULL;
+    // 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_action_ptr, NULL, posix_spawn_file_actions_destroy);
+
+    if (num_file_actions > 0)
+    {
+        error.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX);
+        error.LogIfError(log.get(), "::posix_spawn_file_actions_init ( &file_actions )");
+        if (error.Fail())
+            return error;
+
+        file_action_ptr = &file_actions;
+        posix_spawn_file_actions_cleanup.set(file_action_ptr);
+
+        for (size_t i = 0; i < num_file_actions; ++i)
+        {
+            const ProcessLaunchInfo::FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i);
+            if (launch_file_action &&
+                !ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (&file_actions,
+                                                                         launch_file_action,
+                                                                         log.get(),
+                                                                         error))
+                return error;
+        }
+    }
+
+    // Change working directory if neccessary.
+    char current_dir[PATH_MAX];
+    current_dir[0] = '\0';
+
+    const char *working_dir = launch_info.GetWorkingDirectory();
+    if (working_dir != NULL)
+    {
+        if (::getcwd(current_dir, sizeof(current_dir)) == NULL)
+        {
+            error.SetError(errno, eErrorTypePOSIX);
+            error.LogIfError(log.get(), "unable to save the current directory");
+            return error;
+        }
+
+        if (::chdir(working_dir) == -1)
+        {
+            error.SetError(errno, eErrorTypePOSIX);
+            error.LogIfError(log.get(), "unable to change working directory to %s", working_dir);
+            return error;
+        }
+    }
+
+    const char *tmp_argv[2];
+    char * const *argv = (char * const*)launch_info.GetArguments().GetConstArgumentVector();
+    char * const *envp = (char * const*)launch_info.GetEnvironmentEntries().GetConstArgumentVector();
+
+    // Prepare minimal argument list if we didn't get it from the launch_info structure.
+    // We must pass argv into posix_spawnp and it must contain at least two items -
+    // pointer to an executable and NULL.
+    if (argv == NULL)
+    {
+        tmp_argv[0] = exe_path;
+        tmp_argv[1] = NULL;
+        argv = (char * const*)tmp_argv;
+    }
+
+    error.SetError (::posix_spawnp (&pid,
+                                    exe_path,
+                                    (num_file_actions > 0) ? &file_actions : NULL,
+                                    &attr,
+                                    argv,
+                                    envp),
+                    eErrorTypePOSIX);
+
+    error.LogIfError(log.get(), "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )",
+                     pid, exe_path, file_action_ptr, &attr, argv, envp);
+
+    // Change back the current directory.
+    // NOTE: do not override previously established error from posix_spawnp.
+    if (working_dir != NULL && ::chdir(current_dir) == -1 && error.Success())
+    {
+        error.SetError(errno, eErrorTypePOSIX);
+        error.LogIfError(log.get(), "unable to change current directory back to %s",
+                         current_dir);
+    }
+
+    return error;
+}
+
+
 Error
 Host::LaunchProcess (ProcessLaunchInfo &launch_info)
 {
     Error error;
-    assert(!"Not implemented yet!!!");
+    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);
+
+        // 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);
+        }
+    }
+    else
+    {
+        // Invalid process ID, something didn't go well
+        if (error.Success())
+            error.SetErrorString ("process launch failed for unknown reasons");
+    }
     return error;
 }
 
@@ -156,13 +347,17 @@ bool
 Host::GetOSBuildString (std::string &s)
 {
     int mib[2] = { CTL_KERN, KERN_OSREV };
-    char cstr[PATH_MAX];
-    size_t cstr_len = sizeof(cstr);
-    if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
+    char osrev_str[12];
+    uint32_t osrev = 0;
+    size_t osrev_len = sizeof(osrev);
+
+    if (::sysctl (mib, 2, &osrev, &osrev_len, NULL, 0) == 0)
     {
-        s.assign (cstr, cstr_len);
+        ::snprintf(osrev_str, sizeof(osrev_str), "%-8.8u", osrev);
+        s.assign (osrev_str);
         return true;
     }
+
     s.clear();
     return false;
 }
@@ -170,23 +365,25 @@ Host::GetOSBuildString (std::string &s)
 bool
 Host::GetOSKernelDescription (std::string &s)
 {
-    int mib[2] = { CTL_KERN, KERN_VERSION };
-    char cstr[PATH_MAX];
-    size_t cstr_len = sizeof(cstr);
-    if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
-    {
-        s.assign (cstr, cstr_len);
-        return true;
-    }
+    struct utsname un;
+
+    ::memset(&un, 0, sizeof(utsname));
     s.clear();
+
+    if (uname(&un) < 0)
     return false;
+
+    s.assign (un.version);
+
+    return true;
 }
 
 static bool
 GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
                       ProcessInstanceInfo &process_info)
 {
-    if (process_info.ProcessIDIsValid()) {
+    if (process_info.ProcessIDIsValid())
+    {
         int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, (int)process_info.GetProcessID() };
 
         char arg_data[8192];
@@ -235,7 +432,8 @@ GetFreeBSDProcessArgs (const ProcessInst
 static bool
 GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info)
 {
-    if (process_info.ProcessIDIsValid()) {
+    if (process_info.ProcessIDIsValid())
+    {
         process_info.GetArchitecture() = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
         return true;
     }
@@ -279,16 +477,95 @@ GetFreeBSDProcessUserAndGroup(ProcessIns
     return false;
 }
 
+uint32_t
+Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
+{
+    std::vector<struct kinfo_proc> kinfos;
+
+    int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
+
+    size_t pid_data_size = 0;
+    if (::sysctl (mib, 3, NULL, &pid_data_size, NULL, 0) != 0)
+        return 0;
+
+    // Add a few extra in case a few more show up
+    const size_t estimated_pid_count = (pid_data_size / sizeof(struct kinfo_proc)) + 10;
+
+    kinfos.resize (estimated_pid_count);
+    pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
+
+    if (::sysctl (mib, 3, &kinfos[0], &pid_data_size, NULL, 0) != 0)
+        return 0;
+
+    const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
+
+    bool all_users = match_info.GetMatchAllUsers();
+    const lldb::pid_t our_pid = getpid();
+    const uid_t our_uid = getuid();
+    for (int i = 0; i < actual_pid_count; i++)
+    {
+        const struct kinfo_proc &kinfo = kinfos[i];
+        const bool kinfo_user_matches = (all_users ||
+                                         (kinfo.ki_ruid == our_uid) ||
+                                         // Special case, if lldb is being run as root we can attach to anything.
+                                         (our_uid == 0)
+                                         );
+
+        if (kinfo_user_matches == false      || // Make sure the user is acceptable
+            kinfo.ki_pid == our_pid          || // Skip this process
+            kinfo.ki_pid == 0                || // Skip kernel (kernel pid is zero)
+            kinfo.ki_stat == SZOMB    || // Zombies are bad, they like brains...
+            kinfo.ki_flag & P_TRACED  || // Being debugged?
+            kinfo.ki_flag & P_WEXIT)     // Working on exiting
+            continue;
+
+        // Every thread is a process in FreeBSD, but all the threads of a single process
+        // have the same pid. Do not store the process info in the result list if a process
+        // with given identifier is already registered there.
+        bool already_registered = false;
+        for (uint32_t pi = 0;
+             !already_registered &&
+             (const int)kinfo.ki_numthreads > 1 &&
+             pi < (const uint32_t)process_infos.GetSize(); pi++)
+            already_registered = (process_infos.GetProcessIDAtIndex(pi) == (uint32_t)kinfo.ki_pid);
+
+        if (already_registered)
+            continue;
+
+        ProcessInstanceInfo process_info;
+        process_info.SetProcessID (kinfo.ki_pid);
+        process_info.SetParentProcessID (kinfo.ki_ppid);
+        process_info.SetUserID (kinfo.ki_ruid);
+        process_info.SetGroupID (kinfo.ki_rgid);
+        process_info.SetEffectiveUserID (kinfo.ki_svuid);
+        process_info.SetEffectiveGroupID (kinfo.ki_svgid);
+
+        // Make sure our info matches before we go fetch the name and cpu type
+        if (match_info.Matches (process_info) &&
+            GetFreeBSDProcessArgs (&match_info, process_info))
+        {
+            GetFreeBSDProcessCPUType (process_info);
+            if (match_info.Matches (process_info))
+                process_infos.Append (process_info);
+        }
+    }
+
+    return process_infos.GetSize();
+}
+
 bool
 Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
 {
     process_info.SetProcessID(pid);
-    if (GetFreeBSDProcessArgs(NULL, process_info)) {
+
+    if (GetFreeBSDProcessArgs(NULL, process_info))
+    {
         // should use libprocstat instead of going right into sysctl?
         GetFreeBSDProcessCPUType(process_info);
         GetFreeBSDProcessUserAndGroup(process_info);
         return true;
     }
+
     process_info.Clear();
     return false;
 }

Modified: lldb/trunk/source/Host/macosx/Host.mm
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/macosx/Host.mm?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Host/macosx/Host.mm (original)
+++ lldb/trunk/source/Host/macosx/Host.mm Mon Aug 26 18:57:52 2013
@@ -1984,3 +1984,10 @@ Host::GetAuxvData(lldb_private::Process
 {
     return lldb::DataBufferSP();
 }
+
+uint32_t
+Host::MakeDirectory (const char* path, mode_t mode)
+{
+    return ::mkdir(path,mode);
+}
+

Modified: lldb/trunk/source/Interpreter/CommandObject.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandObject.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/CommandObject.cpp (original)
+++ lldb/trunk/source/Interpreter/CommandObject.cpp Mon Aug 26 18:57:52 2013
@@ -1123,6 +1123,9 @@ CommandObject::g_arguments_data[] =
     { eArgTypeOffset, "offset", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
     { eArgTypeOldPathPrefix, "old-path-prefix", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
     { eArgTypeOneLiner, "one-line-command", CommandCompletions::eNoCompletion, { NULL, false }, "A command that is entered as a single line of text." },
+    { eArgTypePath, "path", CommandCompletions::eDiskFileCompletion, { NULL, false }, "Path." },
+    { eArgTypePermissionsNumber, "perms-numeric", CommandCompletions::eNoCompletion, { NULL, false }, "Permissions given as an octal number (e.g. 755)." },
+    { eArgTypePermissionsString, "perms=string", CommandCompletions::eNoCompletion, { NULL, false }, "Permissions given as a string value (e.g. rw-r-xr--)." },
     { eArgTypePid, "pid", CommandCompletions::eNoCompletion, { NULL, false }, "The process ID number." },
     { eArgTypePlugin, "plugin", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
     { eArgTypeProcessName, "process-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of the process." },

Modified: lldb/trunk/source/Interpreter/Options.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/Options.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/Options.cpp (original)
+++ lldb/trunk/source/Interpreter/Options.cpp Mon Aug 26 18:57:52 2013
@@ -992,6 +992,18 @@ OptionGroupOptions::Append (OptionGroup*
     }
 }
 
+const OptionGroup*
+OptionGroupOptions::GetGroupWithOption (char short_opt)
+{
+    for (uint32_t i = 0; i < m_option_defs.size(); i++)
+    {
+        OptionDefinition opt_def = m_option_defs[i];
+        if (opt_def.short_option == short_opt)
+            return m_option_infos[i].option_group;
+    }
+    return NULL;
+}
+
 void
 OptionGroupOptions::Append (OptionGroup* group, 
                             uint32_t src_mask, 

Modified: lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp (original)
+++ lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp Mon Aug 26 18:57:52 2013
@@ -52,6 +52,7 @@ static ScriptInterpreter::SWIGPythonCalc
 static ScriptInterpreter::SWIGPythonGetChildAtIndex g_swig_get_child_index = NULL;
 static ScriptInterpreter::SWIGPythonGetIndexOfChildWithName g_swig_get_index_child = NULL;
 static ScriptInterpreter::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue  = NULL;
+static ScriptInterpreter::SWIGPythonGetValueObjectSPFromSBValue g_swig_get_valobj_sp_from_sbvalue = NULL;
 static ScriptInterpreter::SWIGPythonUpdateSynthProviderInstance g_swig_update_provider = NULL;
 static ScriptInterpreter::SWIGPythonMightHaveChildrenSynthProviderInstance g_swig_mighthavechildren_provider = NULL;
 static ScriptInterpreter::SWIGPythonCallCommand g_swig_call_command = NULL;
@@ -104,6 +105,9 @@ LLDBSwigPython_GetIndexOfChildWithName (
 extern "C" void *
 LLDBSWIGPython_CastPyObjectToSBValue (void* data);
 
+extern lldb::ValueObjectSP
+LLDBSWIGPython_GetValueObjectSPFromSBValue (void* data);
+
 extern "C" bool
 LLDBSwigPython_UpdateSynthProviderInstance (void* implementor);
 
@@ -2451,20 +2455,18 @@ ScriptInterpreterPython::GetChildAtIndex
     if (!g_swig_get_child_index || !g_swig_cast_to_sbvalue)
         return lldb::ValueObjectSP();
     
-    void* child_ptr = NULL;
-    lldb::SBValue* value_sb = NULL;
     lldb::ValueObjectSP ret_val;
     
     {
         Locker py_lock(this);
-        child_ptr = g_swig_get_child_index (implementor,idx);
+        void* child_ptr = g_swig_get_child_index (implementor,idx);
         if (child_ptr != NULL && child_ptr != Py_None)
         {
-            value_sb = (lldb::SBValue*)g_swig_cast_to_sbvalue(child_ptr);
-            if (value_sb == NULL)
+            lldb::SBValue* sb_value_ptr = (lldb::SBValue*)g_swig_cast_to_sbvalue(child_ptr);
+            if (sb_value_ptr == NULL)
                 Py_XDECREF(child_ptr);
             else
-                ret_val = value_sb->GetSP();
+                ret_val = g_swig_get_valobj_sp_from_sbvalue (sb_value_ptr);
         }
         else
         {
@@ -3058,6 +3060,7 @@ ScriptInterpreterPython::InitializeInter
     g_swig_get_child_index = LLDBSwigPython_GetChildAtIndex;
     g_swig_get_index_child = LLDBSwigPython_GetIndexOfChildWithName;
     g_swig_cast_to_sbvalue = LLDBSWIGPython_CastPyObjectToSBValue;
+    g_swig_get_valobj_sp_from_sbvalue = LLDBSWIGPython_GetValueObjectSPFromSBValue;
     g_swig_update_provider = LLDBSwigPython_UpdateSynthProviderInstance;
     g_swig_mighthavechildren_provider = LLDBSwigPython_MightHaveChildrenSynthProviderInstance;
     g_swig_call_command = LLDBSwigPythonCallCommand;

Modified: lldb/trunk/source/Plugins/Platform/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/CMakeLists.txt?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/Platform/CMakeLists.txt Mon Aug 26 18:57:52 2013
@@ -8,4 +8,5 @@
 #  add_subdirectory(Windows)
 #endif()
 
+add_subdirectory(POSIX)
 add_subdirectory(gdb-server)

Modified: lldb/trunk/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp (original)
+++ lldb/trunk/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp Mon Aug 26 18:57:52 2013
@@ -156,6 +156,26 @@ PlatformFreeBSD::~PlatformFreeBSD()
 {
 }
 
+//TODO:VK: inherit PlatformPOSIX
+lldb_private::Error
+PlatformFreeBSD::RunShellCommand (const char *command,
+                                  const char *working_dir,
+                                  int *status_ptr,
+                                  int *signo_ptr,
+                                  std::string *command_output,
+                                  uint32_t timeout_sec)
+{
+    if (IsHost())
+        return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
+    else
+    {
+        if (m_remote_platform_sp)
+            return m_remote_platform_sp->RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
+        else
+            return Error("unable to run a remote command without a platform");
+    }
+}
+
 
 Error
 PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
@@ -165,10 +185,10 @@ PlatformFreeBSD::ResolveExecutable (cons
 {
     Error error;
     // Nothing special to do here, just use the actual file and architecture
-
+    
     char exe_path[PATH_MAX];
     FileSpec resolved_exe_file (exe_file);
-
+    
     if (IsHost())
     {
         // If we have "ls" as the exe_file, resolve the executable location based on
@@ -178,10 +198,10 @@ PlatformFreeBSD::ResolveExecutable (cons
             exe_file.GetPath(exe_path, sizeof(exe_path));
             resolved_exe_file.SetFile(exe_path, true);
         }
-
+        
         if (!resolved_exe_file.Exists())
             resolved_exe_file.ResolveExecutableLocation ();
-
+        
         if (resolved_exe_file.Exists())
             error.Clear();
         else
@@ -216,8 +236,8 @@ PlatformFreeBSD::ResolveExecutable (cons
             }
         }
     }
-
-
+    
+    
     if (error.Success())
     {
         ModuleSpec module_spec (resolved_exe_file, exe_arch);
@@ -228,7 +248,7 @@ PlatformFreeBSD::ResolveExecutable (cons
                                                  module_search_paths_ptr,
                                                  NULL,
                                                  NULL);
-
+            
             if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL)
             {
                 exe_module_sp.reset();
@@ -259,12 +279,12 @@ PlatformFreeBSD::ResolveExecutable (cons
                     else
                         error.SetErrorToGenericError();
                 }
-
+                
                 if (idx > 0)
                     arch_names.PutCString (", ");
                 arch_names.PutCString (platform_arch.GetArchitectureName());
             }
-
+            
             if (error.Fail() || !exe_module_sp)
             {
                 error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
@@ -279,7 +299,7 @@ PlatformFreeBSD::ResolveExecutable (cons
         error.SetErrorStringWithFormat ("'%s' does not exist",
                                         exe_file.GetPath().c_str());
     }
-
+    
     return error;
 }
 
@@ -642,11 +662,18 @@ PlatformFreeBSD::GetStatus (Stream &strm
 #ifndef LLDB_DISABLE_POSIX
     struct utsname un;
 
-    if (uname(&un)) {
-        strm << "FreeBSD";
-        return;
-    }
+    strm << "      Host: ";
+
+    ::memset(&un, 0, sizeof(utsname));
+    if (uname(&un) == -1)
+        strm << "FreeBSD" << '\n';
+
+    strm << un.sysname << ' ' << un.release;
+    if (un.nodename[0] != '\0')
+        strm << " (" << un.nodename << ')';
+    strm << '\n';
 
+    // Dump a common information about the platform status.
     strm << "Host: " << un.sysname << ' ' << un.release << ' ' << un.version << '\n';
 #endif
 

Modified: lldb/trunk/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h (original)
+++ lldb/trunk/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h Mon Aug 26 18:57:52 2013
@@ -72,6 +72,14 @@ public:
     // lldb_private::Platform functions
     //------------------------------------------------------------
     virtual lldb_private::Error
+    RunShellCommand (const char *command,
+                     const char *working_dir,
+                     int *status_ptr,
+                     int *signo_ptr,
+                     std::string *command_output,
+                     uint32_t timeout_sec);
+
+    virtual lldb_private::Error
     ResolveExecutable (const lldb_private::FileSpec &exe_file,
                        const lldb_private::ArchSpec &arch,
                        lldb::ModuleSP &module_sp,

Modified: lldb/trunk/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp (original)
+++ lldb/trunk/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp Mon Aug 26 18:57:52 2013
@@ -18,6 +18,7 @@
 #include "lldb/Breakpoint/BreakpointLocation.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleSpec.h"
 #include "lldb/Core/Timer.h"
@@ -36,8 +37,7 @@ using namespace lldb_private;
 /// Default Constructor
 //------------------------------------------------------------------
 PlatformDarwin::PlatformDarwin (bool is_host) :
-    Platform(is_host),  // This is the local host platform
-    m_remote_platform_sp (),
+    PlatformPOSIX(is_host),  // This is the local host platform
     m_developer_directory ()
 {
 }
@@ -209,11 +209,11 @@ PlatformDarwin::ResolveExecutable (const
             StreamString arch_names;
             for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, module_spec.GetArchitecture()); ++idx)
             {
-                error = ModuleList::GetSharedModule (module_spec, 
-                                                     exe_module_sp, 
-                                                     module_search_paths_ptr,
-                                                     NULL, 
-                                                     NULL);
+                error = GetSharedModule (module_spec, 
+                                         exe_module_sp, 
+                                         module_search_paths_ptr,
+                                         NULL, 
+                                         NULL);
                 // Did we find an executable using one of the 
                 if (error.Success())
                 {
@@ -268,7 +268,144 @@ PlatformDarwin::ResolveSymbolFile (Targe
     
 }
 
+static lldb_private::Error
+MakeCacheFolderForFile (const FileSpec& module_cache_spec)
+{
+    FileSpec module_cache_folder = module_cache_spec.CopyByRemovingLastPathComponent();
+    StreamString mkdir_folder_cmd;
+    mkdir_folder_cmd.Printf("mkdir -p %s/%s", module_cache_folder.GetDirectory().AsCString(), module_cache_folder.GetFilename().AsCString());
+    return Host::RunShellCommand(mkdir_folder_cmd.GetData(),
+                          NULL,
+                          NULL,
+                          NULL,
+                          NULL,
+                          60);
+}
+
+static lldb_private::Error
+BringInRemoteFile (Platform* platform,
+                   const lldb_private::ModuleSpec &module_spec,
+                   const FileSpec& module_cache_spec)
+{
+    MakeCacheFolderForFile(module_cache_spec);
+    Error err = platform->GetFile(module_spec.GetFileSpec(), module_cache_spec);
+    return err;
+}
+
+lldb_private::Error
+PlatformDarwin::GetSharedModuleWithLocalCache (const lldb_private::ModuleSpec &module_spec,
+                                               lldb::ModuleSP &module_sp,
+                                               const lldb_private::FileSpecList *module_search_paths_ptr,
+                                               lldb::ModuleSP *old_module_sp_ptr,
+                                               bool *did_create_ptr)
+{
+
+    Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+    if (log)
+        log->Printf("[%s] Trying to find module %s/%s - platform path %s/%s symbol path %s/%s\n",
+                     (IsHost() ? "host" : "remote"),
+                     module_spec.GetFileSpec().GetDirectory().AsCString(),
+                     module_spec.GetFileSpec().GetFilename().AsCString(),
+                     module_spec.GetPlatformFileSpec().GetDirectory().AsCString(),
+                     module_spec.GetPlatformFileSpec().GetFilename().AsCString(),
+                     module_spec.GetSymbolFileSpec().GetDirectory().AsCString(),
+                     module_spec.GetSymbolFileSpec().GetFilename().AsCString());
+
+    std::string cache_path(GetLocalCacheDirectory());
+    std::string module_path (module_spec.GetFileSpec().GetPath());
+    cache_path.append(module_path);
+    FileSpec module_cache_spec(cache_path.c_str(),false);
+    
+    // if rsync is supported, always bring in the file - rsync will be very efficient
+    // when files are the same on the local and remote end of the connection
+    if (this->GetSupportsRSync())
+    {
+        Error err = BringInRemoteFile (this, module_spec, module_cache_spec);
+        if (err.Fail())
+            return err;
+        if (module_cache_spec.Exists())
+        {
+            Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+            if (log)
+                log->Printf("[%s] module %s/%s was rsynced and is now there\n",
+                             (IsHost() ? "host" : "remote"),
+                             module_spec.GetFileSpec().GetDirectory().AsCString(),
+                             module_spec.GetFileSpec().GetFilename().AsCString());
+            ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
+            module_sp.reset(new Module(local_spec));
+            module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
+            return Error();
+        }
+    }
 
+    if (module_spec.GetFileSpec().Exists() && !module_sp)
+    {
+        module_sp.reset(new Module(module_spec));
+        return Error();
+    }
+    
+    // try to find the module in the cache
+    if (module_cache_spec.Exists())
+    {
+        // get the local and remote MD5 and compare
+        {
+            // when going over the *slow* GDB remote transfer mechanism we first check
+            // the hashes of the files - and only do the actual transfer if they differ
+            uint64_t high_local,high_remote,low_local,low_remote;
+            Host::CalculateMD5 (module_cache_spec, low_local, high_local);
+            m_remote_platform_sp->CalculateMD5(module_spec.GetFileSpec(), low_remote, high_remote);
+            if (low_local != low_remote || high_local != high_remote)
+            {
+                // bring in the remote file
+                Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+                if (log)
+                    log->Printf("[%s] module %s/%s needs to be replaced from remote copy\n",
+                                 (IsHost() ? "host" : "remote"),
+                                 module_spec.GetFileSpec().GetDirectory().AsCString(),
+                                 module_spec.GetFileSpec().GetFilename().AsCString());
+                Error err = BringInRemoteFile (this, module_spec, module_cache_spec);
+                if (err.Fail())
+                    return err;
+            }
+        }
+        
+        ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
+        module_sp.reset(new Module(local_spec));
+        module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
+        Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+            if (log)
+                log->Printf("[%s] module %s/%s was found in the cache\n",
+                             (IsHost() ? "host" : "remote"),
+                             module_spec.GetFileSpec().GetDirectory().AsCString(),
+                             module_spec.GetFileSpec().GetFilename().AsCString());
+        return Error();
+    }
+    
+    // bring in the remote module file
+    if (log)
+        log->Printf("[%s] module %s/%s needs to come in remotely\n",
+                     (IsHost() ? "host" : "remote"),
+                     module_spec.GetFileSpec().GetDirectory().AsCString(),
+                     module_spec.GetFileSpec().GetFilename().AsCString());
+    Error err = BringInRemoteFile (this, module_spec, module_cache_spec);
+    if (err.Fail())
+        return err;
+    if (module_cache_spec.Exists())
+    {
+        Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+        if (log)
+            log->Printf("[%s] module %s/%s is now cached and fine\n",
+                         (IsHost() ? "host" : "remote"),
+                         module_spec.GetFileSpec().GetDirectory().AsCString(),
+                         module_spec.GetFileSpec().GetFilename().AsCString());
+        ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
+        module_sp.reset(new Module(local_spec));
+        module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
+        return Error();
+    }
+    else
+        return Error("unable to obtain valid module file");
+}
 
 Error
 PlatformDarwin::GetSharedModule (const ModuleSpec &module_spec,
@@ -508,26 +645,39 @@ PlatformDarwin::ConnectRemote (Args& arg
         if (!m_remote_platform_sp)
             m_remote_platform_sp = Platform::Create ("remote-gdb-server", error);
 
-        if (m_remote_platform_sp)
-        {
-            if (error.Success())
-            {
-                if (m_remote_platform_sp)
-                {
-                    error = m_remote_platform_sp->ConnectRemote (args);
-                }
-                else
-                {
-                    error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
-                }
-            }
-        }
+        if (m_remote_platform_sp && error.Success())
+            error = m_remote_platform_sp->ConnectRemote (args);
         else
             error.SetErrorString ("failed to create a 'remote-gdb-server' platform");
         
         if (error.Fail())
             m_remote_platform_sp.reset();
     }
+    
+    if (error.Success() && m_remote_platform_sp)
+    {
+        if (m_options.get())
+        {
+            OptionGroupOptions* options = m_options.get();
+            OptionGroupPlatformRSync* m_rsync_options = (OptionGroupPlatformRSync*)options->GetGroupWithOption('r');
+            OptionGroupPlatformSSH* m_ssh_options = (OptionGroupPlatformSSH*)options->GetGroupWithOption('s');
+            OptionGroupPlatformCaching* m_cache_options = (OptionGroupPlatformCaching*)options->GetGroupWithOption('c');
+            
+            if (m_rsync_options->m_rsync)
+            {
+                SetSupportsRSync(true);
+                SetRSyncOpts(m_rsync_options->m_rsync_opts.c_str());
+                SetRSyncPrefix(m_rsync_options->m_rsync_prefix.c_str());
+                SetIgnoresRemoteHostname(m_rsync_options->m_ignores_remote_hostname);
+            }
+            if (m_ssh_options->m_ssh)
+            {
+                SetSupportsSSH(true);
+                SetSSHOpts(m_ssh_options->m_ssh_opts.c_str());
+            }
+            SetLocalCacheDirectory(m_cache_options->m_cache_dir.c_str());
+        }
+    }
 
     return error;
 }

Modified: lldb/trunk/source/Plugins/Platform/MacOSX/PlatformDarwin.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/MacOSX/PlatformDarwin.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/MacOSX/PlatformDarwin.h (original)
+++ lldb/trunk/source/Plugins/Platform/MacOSX/PlatformDarwin.h Mon Aug 26 18:57:52 2013
@@ -14,9 +14,9 @@
 // C++ Includes
 // Other libraries and framework includes
 // Project includes
-#include "lldb/Target/Platform.h"
+#include "Plugins/Platform/POSIX/PlatformPOSIX.h"
 
-class PlatformDarwin : public lldb_private::Platform
+class PlatformDarwin : public PlatformPOSIX
 {
 public:
     PlatformDarwin (bool is_host);
@@ -118,12 +118,18 @@ public:
     x86GetSupportedArchitectureAtIndex (uint32_t idx, lldb_private::ArchSpec &arch);
 
 protected:
-    lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote darwin OS
+    virtual lldb_private::Error
+    GetSharedModuleWithLocalCache (const lldb_private::ModuleSpec &module_spec,
+                                   lldb::ModuleSP &module_sp,
+                                   const lldb_private::FileSpecList *module_search_paths_ptr,
+                                   lldb::ModuleSP *old_module_sp_ptr,
+                                   bool *did_create_ptr);
+
     std::string m_developer_directory;
     
     const char *
     GetDeveloperDirectory();
-
+    
 private:
     DISALLOW_COPY_AND_ASSIGN (PlatformDarwin);
 

Modified: lldb/trunk/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp (original)
+++ lldb/trunk/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp Mon Aug 26 18:57:52 2013
@@ -12,14 +12,19 @@
 
 // C Includes
 #ifndef LLDB_DISABLE_POSIX
+#include <sys/stat.h>
 #include <sys/sysctl.h>
 #endif
 
 // C++ Includes
+
+#include <sstream>
+
 // Other libraries and framework includes
 // Project includes
 #include "lldb/Core/Error.h"
 #include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/DataBufferHeap.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleList.h"
 #include "lldb/Core/PluginManager.h"
@@ -161,9 +166,9 @@ PlatformMacOSX::~PlatformMacOSX()
 }
 
 Error
-PlatformMacOSX::GetFile (const FileSpec &platform_file, 
-                         const UUID *uuid_ptr,
-                         FileSpec &local_file)
+PlatformMacOSX::GetSymbolFile (const FileSpec &platform_file, 
+                               const UUID *uuid_ptr,
+                               FileSpec &local_file)
 {
     if (IsRemote())
     {
@@ -176,6 +181,62 @@ PlatformMacOSX::GetFile (const FileSpec
     return Error();
 }
 
+lldb_private::Error
+PlatformMacOSX::GetFile (const lldb_private::FileSpec &platform_file,
+                         const lldb_private::UUID *uuid_ptr,
+                         lldb_private::FileSpec &local_file)
+{
+    if (IsRemote() && m_remote_platform_sp)
+    {
+        std::string local_os_build;
+        Host::GetOSBuildString(local_os_build);
+        std::string remote_os_build;
+        m_remote_platform_sp->GetOSBuildString(remote_os_build);
+        if (local_os_build.compare(remote_os_build) == 0)
+        {
+            // same OS version: the local file is good enough
+            local_file = platform_file;
+            return Error();
+        }
+        else
+        {
+            // try to find the file in the cache
+            std::string cache_path(GetLocalCacheDirectory());
+            std::string module_path (platform_file.GetPath());
+            cache_path.append(module_path);
+            FileSpec module_cache_spec(cache_path.c_str(),false);
+            if (module_cache_spec.Exists())
+            {
+                local_file = module_cache_spec;
+                return Error();
+            }
+            // bring in the remote module file
+            FileSpec module_cache_folder = module_cache_spec.CopyByRemovingLastPathComponent();
+            StreamString mkdir_folder_cmd;
+            // try to make the local directory first
+            mkdir_folder_cmd.Printf("mkdir -p %s/%s", module_cache_folder.GetDirectory().AsCString(), module_cache_folder.GetFilename().AsCString());
+            Host::RunShellCommand(mkdir_folder_cmd.GetData(),
+                                  NULL,
+                                  NULL,
+                                  NULL,
+                                  NULL,
+                                  60);
+            Error err = GetFile(platform_file, module_cache_spec);
+            if (err.Fail())
+                return err;
+            if (module_cache_spec.Exists())
+            {
+                local_file = module_cache_spec;
+                return Error();
+            }
+            else
+                return Error("unable to obtain valid module file");
+        }
+    }
+    local_file = platform_file;
+    return Error();
+}
+
 bool
 PlatformMacOSX::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
 {
@@ -186,3 +247,12 @@ PlatformMacOSX::GetSupportedArchitecture
 #endif
 }
 
+lldb_private::Error
+PlatformMacOSX::GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+                                 lldb::ModuleSP &module_sp,
+                                 const lldb_private::FileSpecList *module_search_paths_ptr,
+                                 lldb::ModuleSP *old_module_sp_ptr,
+                                 bool *did_create_ptr)
+{
+    return GetSharedModuleWithLocalCache(module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr);
+}

Modified: lldb/trunk/source/Plugins/Platform/MacOSX/PlatformMacOSX.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/MacOSX/PlatformMacOSX.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/MacOSX/PlatformMacOSX.h (original)
+++ lldb/trunk/source/Plugins/Platform/MacOSX/PlatformMacOSX.h Mon Aug 26 18:57:52 2013
@@ -61,17 +61,36 @@ public:
         return 1;
     }
     
+    virtual lldb_private::Error
+    GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+                     lldb::ModuleSP &module_sp,
+                     const lldb_private::FileSpecList *module_search_paths_ptr,
+                     lldb::ModuleSP *old_module_sp_ptr,
+                     bool *did_create_ptr);
+    
     virtual const char *
     GetDescription ()
     {
         return GetDescriptionStatic (IsHost());
     }
 
+    lldb_private::Error
+    GetSymbolFile (const lldb_private::FileSpec &platform_file, 
+                   const lldb_private::UUID *uuid_ptr,
+                   lldb_private::FileSpec &local_file);
+    
+    virtual lldb_private::Error
+    GetFile (const lldb_private::FileSpec& source,
+             const lldb_private::FileSpec& destination)
+    {
+        return PlatformDarwin::GetFile (source,destination);
+    }
+    
     virtual lldb_private::Error
     GetFile (const lldb_private::FileSpec &platform_file, 
              const lldb_private::UUID *uuid_ptr,
              lldb_private::FileSpec &local_file);
-
+    
     virtual bool
     GetSupportedArchitectureAtIndex (uint32_t idx, 
                                      lldb_private::ArchSpec &arch);

Modified: lldb/trunk/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp (original)
+++ lldb/trunk/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp Mon Aug 26 18:57:52 2013
@@ -749,6 +749,15 @@ PlatformRemoteiOS::GetSharedModule (cons
         // Not the module we are looking for... Nothing to see here...
         module_sp.reset();
     }
+    else
+    {
+        // This may not be an SDK-related module.  Try whether we can bring in the thing to our local cache.
+        error = GetSharedModuleWithLocalCache(module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr);
+        if (error.Success())
+            return error;
+        else
+            error.Clear(); // Clear the error and fall-through.
+    }
 
     const bool always_create = false;
     error = ModuleList::GetSharedModule (module_spec, 
@@ -764,24 +773,6 @@ PlatformRemoteiOS::GetSharedModule (cons
     return error;
 }
 
-
-uint32_t
-PlatformRemoteiOS::FindProcesses (const ProcessInstanceInfoMatch &match_info,
-                                  ProcessInstanceInfoList &process_infos)
-{
-    // TODO: if connected, send a packet to get the remote process infos by name
-    process_infos.Clear();
-    return 0;
-}
-
-bool
-PlatformRemoteiOS::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
-{
-    // TODO: if connected, send a packet to get the remote process info
-    process_info.Clear();
-    return false;
-}
-
 bool
 PlatformRemoteiOS::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
 {

Modified: lldb/trunk/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h (original)
+++ lldb/trunk/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h Mon Aug 26 18:57:52 2013
@@ -93,14 +93,6 @@ public:
                      lldb::ModuleSP *old_module_sp_ptr,
                      bool *did_create_ptr);
 
-    virtual uint32_t
-    FindProcesses (const lldb_private::ProcessInstanceInfoMatch &match_info,
-                   lldb_private::ProcessInstanceInfoList &process_infos);
-
-    virtual bool
-    GetProcessInfo (lldb::pid_t pid, 
-                    lldb_private::ProcessInstanceInfo &proc_info);
-
     virtual bool
     GetSupportedArchitectureAtIndex (uint32_t idx, 
                                      lldb_private::ArchSpec &arch);

Modified: lldb/trunk/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp (original)
+++ lldb/trunk/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp Mon Aug 26 18:57:52 2013
@@ -315,9 +315,9 @@ PlatformiOSSimulator::GetSDKDirectory()
 }
 
 Error
-PlatformiOSSimulator::GetFile (const FileSpec &platform_file, 
-                               const UUID *uuid_ptr,
-                               FileSpec &local_file)
+PlatformiOSSimulator::GetSymbolFile (const FileSpec &platform_file, 
+                                     const UUID *uuid_ptr,
+                                     FileSpec &local_file)
 {
     Error error;
     char platform_file_path[PATH_MAX];
@@ -370,7 +370,7 @@ PlatformiOSSimulator::GetSharedModule (c
     Error error;
     FileSpec local_file;
     const FileSpec &platform_file = module_spec.GetFileSpec();
-    error = GetFile (platform_file, module_spec.GetUUIDPtr(), local_file);
+    error = GetSymbolFile (platform_file, module_spec.GetUUIDPtr(), local_file);
     if (error.Success())
     {
         error = ResolveExecutable (local_file, module_spec.GetArchitecture(), module_sp, module_search_paths_ptr);

Modified: lldb/trunk/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h (original)
+++ lldb/trunk/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h Mon Aug 26 18:57:52 2013
@@ -80,9 +80,9 @@ public:
     GetStatus (lldb_private::Stream &strm);
 
     virtual lldb_private::Error
-    GetFile (const lldb_private::FileSpec &platform_file, 
-             const lldb_private::UUID *uuid_ptr,
-             lldb_private::FileSpec &local_file);
+    GetSymbolFile (const lldb_private::FileSpec &platform_file, 
+                   const lldb_private::UUID *uuid_ptr,
+                   lldb_private::FileSpec &local_file);
 
     virtual lldb_private::Error
     GetSharedModule (const lldb_private::ModuleSpec &module_spec,

Modified: lldb/trunk/source/Plugins/Platform/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/Makefile?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/Makefile (original)
+++ lldb/trunk/source/Plugins/Platform/Makefile Mon Aug 26 18:57:52 2013
@@ -1,26 +1,26 @@
 ##===- source/Plugins/Platform/Makefile --------------------*- Makefile -*-===##
-# 
+#
 #                     The LLVM Compiler Infrastructure
 #
 # This file is distributed under the University of Illinois Open Source
 # License. See LICENSE.TXT for details.
-# 
+#
 ##===----------------------------------------------------------------------===##
 
 LLDB_LEVEL := ../../..
 
 include $(LLDB_LEVEL)/../../Makefile.config
 
-DIRS := gdb-server MacOSX Linux FreeBSD
+DIRS := gdb-server MacOSX Linux FreeBSD POSIX
 
 # ifeq ($(HOST_OS),Darwin)
 #   DIRS += MacOSX
 # endif
-# 
+#
 # ifeq ($(HOST_OS),Linux)
 #   DIRS += Linux
 # endif
-# 
+#
 # ifeq ($(HOST_OS),FreeBSD)
 #   DIRS += FreeBSD
 # endif

Added: lldb/trunk/source/Plugins/Platform/POSIX/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/POSIX/CMakeLists.txt?rev=189295&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Platform/POSIX/CMakeLists.txt (added)
+++ lldb/trunk/source/Plugins/Platform/POSIX/CMakeLists.txt Mon Aug 26 18:57:52 2013
@@ -0,0 +1,5 @@
+set(LLVM_NO_RTTI 1)
+
+add_lldb_library(lldbPluginPlatformPOSIX
+  PlatformPOSIX.cpp
+  )

Added: lldb/trunk/source/Plugins/Platform/POSIX/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/POSIX/Makefile?rev=189295&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Platform/POSIX/Makefile (added)
+++ lldb/trunk/source/Plugins/Platform/POSIX/Makefile Mon Aug 26 18:57:52 2013
@@ -0,0 +1,14 @@
+##===- source/Plugins/Platform/POSIX/Makefile --------------*- Makefile -*-===##
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginPlatformPOSIX
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile

Added: lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp?rev=189295&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp (added)
+++ lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp Mon Aug 26 18:57:52 2013
@@ -0,0 +1,541 @@
+//===-- PlatformPOSIX.cpp ---------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformPOSIX.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformPOSIX::PlatformPOSIX (bool is_host) :
+Platform(is_host),  // This is the local host platform
+m_remote_platform_sp ()
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformPOSIX::~PlatformPOSIX()
+{
+}
+
+lldb_private::OptionGroupOptions*
+PlatformPOSIX::GetConnectionOptions (lldb_private::CommandInterpreter& interpreter)
+{
+    if (m_options.get() == NULL)
+    {
+        m_options.reset(new OptionGroupOptions(interpreter));
+        m_options->Append(new OptionGroupPlatformRSync());
+        m_options->Append(new OptionGroupPlatformSSH());
+        m_options->Append(new OptionGroupPlatformCaching());
+    }
+    return m_options.get();
+}
+
+lldb_private::Error
+PlatformPOSIX::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)         // Timeout in seconds to wait for shell program to finish
+{
+    if (IsHost())
+        return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
+    else
+    {
+        if (m_remote_platform_sp)
+            return m_remote_platform_sp->RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
+        else
+            return Error("unable to run a remote command without a platform");
+    }
+}
+
+uint32_t
+PlatformPOSIX::MakeDirectory (const std::string &path,
+                               mode_t mode)
+{
+    if (IsHost())
+    {
+        return Host::MakeDirectory (path.c_str(), mode);
+    }
+    if (IsRemote() && m_remote_platform_sp)
+        return m_remote_platform_sp->MakeDirectory(path, mode);
+    return Platform::MakeDirectory(path,mode);
+}
+
+lldb::user_id_t
+PlatformPOSIX::OpenFile (const FileSpec& file_spec,
+                         uint32_t flags,
+                         mode_t mode,
+                         Error &error)
+{
+    if (IsHost())
+    {
+        return Host::OpenFile(file_spec, flags, mode, error);
+    }
+    if (IsRemote() && m_remote_platform_sp)
+        return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error);
+    return Platform::OpenFile(file_spec, flags, mode, error);
+}
+
+bool
+PlatformPOSIX::CloseFile (lldb::user_id_t fd, Error &error)
+{
+    if (IsHost())
+    {
+        return Host::CloseFile(fd, error);
+    }
+    if (IsRemote() && m_remote_platform_sp)
+        return m_remote_platform_sp->CloseFile(fd, error);
+    return Platform::CloseFile(fd, error);
+}
+
+uint64_t
+PlatformPOSIX::ReadFile (lldb::user_id_t fd,
+                         uint64_t offset,
+                         void *dst,
+                         uint64_t dst_len,
+                         Error &error)
+{
+    if (IsHost())
+    {
+        return Host::ReadFile(fd, offset, dst, dst_len, error);
+    }
+    if (IsRemote() && m_remote_platform_sp)
+        return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error);
+    return Platform::ReadFile(fd, offset, dst, dst_len, error);
+}
+
+uint64_t
+PlatformPOSIX::WriteFile (lldb::user_id_t fd,
+                          uint64_t offset,
+                          const void* src,
+                          uint64_t src_len,
+                          Error &error)
+{
+    if (IsHost())
+    {
+        return Host::WriteFile(fd, offset, src, src_len, error);
+    }
+    if (IsRemote() && m_remote_platform_sp)
+        return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error);
+
+    return Platform::WriteFile(fd, offset, src, src_len, error);
+}
+
+static uint32_t
+chown_file(Platform *platform,
+           const char* path,
+           uint32_t uid = UINT32_MAX,
+           uint32_t gid = UINT32_MAX)
+{
+    if (!platform || !path || *path == 0)
+        return UINT32_MAX;
+    
+    if (uid == UINT32_MAX && gid == UINT32_MAX)
+        return 0;   // pretend I did chown correctly - actually I just didn't care
+    
+    StreamString command;
+    command.PutCString("chown ");
+    if (uid != UINT32_MAX)
+        command.Printf("%d",uid);
+    if (gid != UINT32_MAX)
+        command.Printf(":%d",gid);
+    command.Printf("%s",path);
+    int status;
+    platform->RunShellCommand(command.GetData(),
+                              NULL,
+                              &status,
+                              NULL,
+                              NULL,
+                              10);
+    return status;
+}
+
+lldb_private::Error
+PlatformPOSIX::PutFile (const lldb_private::FileSpec& source,
+                         const lldb_private::FileSpec& destination,
+                         uint32_t uid,
+                         uint32_t gid)
+{
+    if (IsHost())
+    {
+        if (FileSpec::Equal(source, destination, true))
+            return Error();
+        // cp src dst
+        // chown uid:gid dst
+        std::string src_path (source.GetPath());
+        if (src_path.empty())
+            return Error("unable to get file path for source");
+        std::string dst_path (destination.GetPath());
+        if (dst_path.empty())
+            return Error("unable to get file path for destination");
+        StreamString command;
+        command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
+        int status;
+        RunShellCommand(command.GetData(),
+                        NULL,
+                        &status,
+                        NULL,
+                        NULL,
+                        10);
+        if (status != 0)
+            return Error("unable to perform copy");
+        if (uid == UINT32_MAX && gid == UINT32_MAX)
+            return Error();
+        if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
+            return Error("unable to perform chown");
+        return Error();
+    }
+    else if (IsRemote() && m_remote_platform_sp)
+    {
+        if (GetSupportsRSync())
+        {
+            std::string src_path (source.GetPath());
+            if (src_path.empty())
+                return Error("unable to get file path for source");
+            std::string dst_path (destination.GetPath());
+            if (dst_path.empty())
+                return Error("unable to get file path for destination");
+            StreamString command;
+            if (GetIgnoresRemoteHostname())
+            {
+                if (!GetRSyncPrefix())
+                    command.Printf("rsync %s %s %s",
+                                   GetRSyncOpts(),
+                                   src_path.c_str(),
+                                   dst_path.c_str());
+                else
+                    command.Printf("rsync %s %s %s%s",
+                                   GetRSyncOpts(),
+                                   src_path.c_str(),
+                                   GetRSyncPrefix(),
+                                   dst_path.c_str());
+            }
+            else
+                command.Printf("rsync %s %s %s:%s",
+                               GetRSyncOpts(),
+                               src_path.c_str(),
+                               GetHostname(),
+                               dst_path.c_str());
+            Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+            if (log)
+                log->Printf("[PutFile] Running command: %s\n", command.GetData());
+            int retcode;
+            Host::RunShellCommand(command.GetData(),
+                                  NULL,
+                                  &retcode,
+                                  NULL,
+                                  NULL,
+                                  60);
+            if (retcode == 0)
+            {
+                // Don't chown a local file for a remote system
+//                if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
+//                    return Error("unable to perform chown");
+                return Error();
+            }
+            // if we are still here rsync has failed - let's try the slow way before giving up
+        }
+        // open
+        // read, write, read, write, ...
+        // close
+        // chown uid:gid dst
+        Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+            if (log)
+                log->Printf("[PutFile] Using block by block transfer....\n");
+        File source_file(source, File::eOpenOptionRead, File::ePermissionsUserRW);
+        if (!source_file.IsValid())
+            return Error("unable to open source file");
+        Error error;
+        lldb::user_id_t dest_file = OpenFile (destination,
+                                              File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate,
+                                              File::ePermissionsUserRWX | File::ePermissionsGroupRX | File::ePermissionsWorldRX,
+                                              error);
+        if (log)
+            log->Printf ("dest_file = %" PRIu64 "\n", dest_file);
+        if (error.Fail())
+            return error;
+        if (dest_file == UINT64_MAX)
+            return Error("unable to open target file");
+        lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
+        uint64_t offset = 0;
+        while (error.Success())
+        {
+            size_t bytes_read = buffer_sp->GetByteSize();
+            error = source_file.Read(buffer_sp->GetBytes(), bytes_read);
+            if (bytes_read)
+            {
+                WriteFile(dest_file, offset, buffer_sp->GetBytes(), bytes_read, error);
+                offset += bytes_read;
+            }
+            else
+                break;
+        }
+        CloseFile(dest_file, error);
+        if (uid == UINT32_MAX && gid == UINT32_MAX)
+            return error;
+        // This is remopve, don't chown a local file...
+//        std::string dst_path (destination.GetPath());
+//        if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
+//            return Error("unable to perform chown");
+        return error;
+    }
+    return Platform::PutFile(source,destination,uid,gid);
+}
+
+lldb::user_id_t
+PlatformPOSIX::GetFileSize (const FileSpec& file_spec)
+{
+    if (IsHost())
+    {
+        return Host::GetFileSize(file_spec);
+    }
+    if (IsRemote() && m_remote_platform_sp)
+        return m_remote_platform_sp->GetFileSize(file_spec);
+    return Platform::GetFileSize(file_spec);
+}
+
+bool
+PlatformPOSIX::GetFileExists (const FileSpec& file_spec)
+{
+    if (IsHost())
+    {
+        return file_spec.Exists();
+    }
+    if (IsRemote() && m_remote_platform_sp)
+        return m_remote_platform_sp->GetFileExists(file_spec);
+    return Platform::GetFileExists(file_spec);
+}
+
+uint32_t
+PlatformPOSIX::GetFilePermissions (const lldb_private::FileSpec &file_spec,
+                                   lldb_private::Error &error)
+{
+    if (IsHost())
+    {
+        return File::GetPermissions(file_spec.GetPath().c_str(), error);
+    }
+    if (IsRemote() && m_remote_platform_sp)
+        return m_remote_platform_sp->GetFilePermissions(file_spec, error);
+    return Platform::GetFilePermissions(file_spec, error);
+    
+}
+
+
+lldb_private::Error
+PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path */,
+                         const lldb_private::FileSpec& destination /* local file path */)
+{
+    // Check the args, first.
+    std::string src_path (source.GetPath());
+    if (src_path.empty())
+        return Error("unable to get file path for source");
+    std::string dst_path (destination.GetPath());
+    if (dst_path.empty())
+        return Error("unable to get file path for destination");
+    if (IsHost())
+    {
+        if (FileSpec::Equal(source, destination, true))
+            return Error("local scenario->source and destination are the same file path: no operation performed");
+        // cp src dst
+        StreamString cp_command;
+        cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
+        int status;
+        RunShellCommand(cp_command.GetData(),
+                        NULL,
+                        &status,
+                        NULL,
+                        NULL,
+                        10);
+        if (status != 0)
+            return Error("unable to perform copy");
+        return Error();
+    }
+    else if (IsRemote() && m_remote_platform_sp)
+    {
+        if (GetSupportsRSync())
+        {
+            StreamString command;
+            if (GetIgnoresRemoteHostname())
+            {
+                if (!GetRSyncPrefix())
+                    command.Printf("rsync %s %s %s",
+                                   GetRSyncOpts(),
+                                   src_path.c_str(),
+                                   dst_path.c_str());
+                else
+                    command.Printf("rsync %s %s%s %s",
+                                   GetRSyncOpts(),
+                                   GetRSyncPrefix(),
+                                   src_path.c_str(),
+                                   dst_path.c_str());
+            }
+            else
+                command.Printf("rsync %s %s:%s %s",
+                               GetRSyncOpts(),
+                               m_remote_platform_sp->GetHostname(),
+                               src_path.c_str(),
+                               dst_path.c_str());
+            Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+            if (log)
+                log->Printf("[GetFile] Running command: %s\n", command.GetData());
+            int retcode;
+            Host::RunShellCommand(command.GetData(),
+                                  NULL,
+                                  &retcode,
+                                  NULL,
+                                  NULL,
+                                  60);
+            if (retcode == 0)
+                return Error();
+            // If we are here, rsync has failed - let's try the slow way before giving up
+        }
+        // open src and dst
+        // read/write, read/write, read/write, ...
+        // close src
+        // close dst
+        Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+            if (log)
+                log->Printf("[GetFile] Using block by block transfer....\n");
+        Error error;
+        user_id_t fd_src = OpenFile (source,
+                                     File::eOpenOptionRead,
+                                     File::ePermissionsDefault,
+                                     error);
+
+        if (fd_src == UINT64_MAX)
+            return Error("unable to open source file");
+
+        uint32_t permissions = GetFilePermissions(source, error);
+        
+        if (permissions == 0)
+            permissions = File::ePermissionsDefault;
+
+        user_id_t fd_dst = Host::OpenFile(destination,
+                                          File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate,
+                                          permissions,
+                                          error);
+
+        if (fd_dst == UINT64_MAX)
+        {
+            if (error.Success())
+                error.SetErrorString("unable to open destination file");
+        }
+
+        if (error.Success())
+        {
+            lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
+            uint64_t offset = 0;
+            error.Clear();
+            while (error.Success())
+            {
+                const uint64_t n_read = ReadFile (fd_src,
+                                                  offset,
+                                                  buffer_sp->GetBytes(),
+                                                  buffer_sp->GetByteSize(),
+                                                  error);
+                if (error.Fail())
+                    break;
+                if (n_read == 0)
+                    break;
+                if (Host::WriteFile(fd_dst,
+                                    offset,
+                                    buffer_sp->GetBytes(),
+                                    n_read,
+                                    error) != n_read)
+                {
+                    if (!error.Fail())
+                        error.SetErrorString("unable to write to destination file");
+                        break;
+                }
+                offset += n_read;
+            }
+        }
+        // Ignore the close error of src.
+        if (fd_src != UINT64_MAX)
+            CloseFile(fd_src, error);
+        // And close the dst file descriptot.
+        if (fd_dst != UINT64_MAX && !Host::CloseFile(fd_dst, error))
+        {
+            if (!error.Fail())
+                error.SetErrorString("unable to close destination file");
+
+        }
+        return error;
+    }
+    return Platform::GetFile(source,destination);
+}
+
+std::string
+PlatformPOSIX::GetPlatformSpecificConnectionInformation()
+{
+    StreamString stream;
+    if (GetSupportsRSync())
+    {
+        stream.PutCString("rsync");
+        if ( (GetRSyncOpts() && *GetRSyncOpts()) ||
+             (GetRSyncPrefix() && *GetRSyncPrefix()) ||
+             GetIgnoresRemoteHostname())
+        {
+            stream.Printf(", options: ");
+            if (GetRSyncOpts() && *GetRSyncOpts())
+                stream.Printf("'%s' ",GetRSyncOpts());
+            stream.Printf(", prefix: ");
+            if (GetRSyncPrefix() && *GetRSyncPrefix())
+                stream.Printf("'%s' ",GetRSyncPrefix());
+            if (GetIgnoresRemoteHostname())
+                stream.Printf("ignore remote-hostname ");
+        }
+    }
+    if (GetSupportsSSH())
+    {
+        stream.PutCString("ssh");
+        if (GetSSHOpts() && *GetSSHOpts())
+            stream.Printf(", options: '%s' ",GetSSHOpts());
+    }
+    if (GetLocalCacheDirectory() && *GetLocalCacheDirectory())
+        stream.Printf("cache dir: %s",GetLocalCacheDirectory());
+    if (stream.GetSize())
+        return stream.GetData();
+    else
+        return "";
+}
+
+bool
+PlatformPOSIX::CalculateMD5 (const FileSpec& file_spec,
+                            uint64_t &low,
+                            uint64_t &high)
+{
+    if (IsHost())
+        return Platform::CalculateMD5 (file_spec, low, high);
+    if (m_remote_platform_sp)
+        return m_remote_platform_sp->CalculateMD5(file_spec, low, high);
+    return false;
+}

Added: lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.h?rev=189295&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.h (added)
+++ lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.h Mon Aug 26 18:57:52 2013
@@ -0,0 +1,111 @@
+//===-- PlatformPOSIX.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_PlatformPOSIX_h_
+#define liblldb_PlatformPOSIX_h_
+
+// C Includes
+// C++ Includes
+
+#include <memory>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Target/Platform.h"
+
+class PlatformPOSIX : public lldb_private::Platform
+{
+public:
+    PlatformPOSIX (bool is_host);
+    
+    virtual
+    ~PlatformPOSIX();
+    
+    //------------------------------------------------------------
+    // lldb_private::Platform functions
+    //------------------------------------------------------------
+    virtual lldb_private::OptionGroupOptions*
+    GetConnectionOptions (lldb_private::CommandInterpreter& interpreter);
+    
+    virtual lldb_private::Error
+    PutFile (const lldb_private::FileSpec& source,
+             const lldb_private::FileSpec& destination,
+             uint32_t uid = UINT32_MAX,
+             uint32_t gid = UINT32_MAX);
+    
+    virtual lldb::user_id_t
+    OpenFile (const lldb_private::FileSpec& file_spec,
+              uint32_t flags,
+              mode_t mode,
+              lldb_private::Error &error);
+    
+    virtual bool
+    CloseFile (lldb::user_id_t fd,
+               lldb_private::Error &error);
+    
+    virtual uint64_t
+    ReadFile (lldb::user_id_t fd,
+              uint64_t offset,
+              void *dst,
+              uint64_t dst_len,
+              lldb_private::Error &error);
+    
+    virtual uint64_t
+    WriteFile (lldb::user_id_t fd,
+               uint64_t offset,
+               const void* src,
+               uint64_t src_len,
+               lldb_private::Error &error);
+    
+    virtual lldb::user_id_t
+    GetFileSize (const lldb_private::FileSpec& file_spec);
+
+    virtual lldb_private::Error
+    GetFile (const lldb_private::FileSpec& source,
+             const lldb_private::FileSpec& destination);
+    
+    virtual lldb_private::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);         // Timeout in seconds to wait for shell program to finish
+    
+    virtual uint32_t
+    MakeDirectory (const std::string &path,
+                   mode_t mode);
+    
+    virtual bool
+    GetFileExists (const lldb_private::FileSpec& file_spec);
+    
+    virtual uint32_t
+    GetFilePermissions (const lldb_private::FileSpec &file_spec,
+                        lldb_private::Error &error);
+
+    virtual std::string
+    GetPlatformSpecificConnectionInformation();
+    
+    virtual bool
+    CalculateMD5 (const lldb_private::FileSpec& file_spec,
+                  uint64_t &low,
+                  uint64_t &high);
+
+protected:
+    std::auto_ptr<lldb_private::OptionGroupOptions> m_options;
+        
+    lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote POSIX-compliant OS
+    
+private:
+    DISALLOW_COPY_AND_ASSIGN (PlatformPOSIX);
+    
+};
+
+#endif  // liblldb_PlatformPOSIX_h_

Modified: lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp (original)
+++ lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp Mon Aug 26 18:57:52 2013
@@ -110,7 +110,11 @@ PlatformRemoteGDBServer::ResolveExecutab
                                             const FileSpecList *module_search_paths_ptr)
 {
     Error error;
-    error.SetErrorString ("PlatformRemoteGDBServer::ResolveExecutable() is unimplemented");
+    //error.SetErrorString ("PlatformRemoteGDBServer::ResolveExecutable() is unimplemented");
+    if (m_gdb_client.GetFileExists(exe_file))
+        return error;
+    // TODO: get the remote end to somehow resolve this file
+    error.SetErrorString("file not found on remote end");
     return error;
 }
 
@@ -233,6 +237,11 @@ PlatformRemoteGDBServer::ConnectRemote (
             error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
         }
     }
+    
+    if (error.Success())
+    {
+        
+    }
 
     return error;
 }
@@ -327,6 +336,12 @@ PlatformRemoteGDBServer::LaunchProcess (
                 break;
         }
     }
+    
+    ArchSpec arch_spec = launch_info.GetArchitecture();
+    const char *arch_triple = arch_spec.GetTriple().str().c_str();
+    
+    m_gdb_client.SendLaunchArchPacket(arch_triple);
+    
     const uint32_t old_packet_timeout = m_gdb_client.SetPacketTimeout (5);
     int arg_packet_err = m_gdb_client.SendArgumentsPacket (argv);
     m_gdb_client.SetPacketTimeout (old_packet_timeout);
@@ -363,7 +378,8 @@ PlatformRemoteGDBServer::Attach (lldb_pr
     {
         if (IsConnected())
         {
-            uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort();
+            lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
+            uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid);
             
             if (port == 0)
             {
@@ -397,15 +413,22 @@ PlatformRemoteGDBServer::Attach (lldb_pr
                     if (process_sp)
                     {
                         char connect_url[256];
+                        const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
+                        const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
+                        int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
                         const int connect_url_len = ::snprintf (connect_url, 
                                                                 sizeof(connect_url), 
                                                                 "connect://%s:%u", 
-                                                                GetHostname (), 
-                                                                port);
+                                                                override_hostname ? override_hostname : GetHostname (), 
+                                                                port + port_offset);
                         assert (connect_url_len < (int)sizeof(connect_url));
                         error = process_sp->ConnectRemote (NULL, connect_url);
                         if (error.Success())
                             error = process_sp->Attach(attach_info);
+                        else if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+                        {
+                            m_gdb_client.KillSpawnedProcess(debugserver_pid);
+                        }
                     }
                 }
             }
@@ -418,4 +441,83 @@ PlatformRemoteGDBServer::Attach (lldb_pr
     return process_sp;
 }
 
+uint32_t
+PlatformRemoteGDBServer::MakeDirectory (const std::string &path,
+                                        mode_t mode)
+{
+    return m_gdb_client.MakeDirectory(path,mode);
+}
+
+lldb::user_id_t
+PlatformRemoteGDBServer::OpenFile (const lldb_private::FileSpec& file_spec,
+                                   uint32_t flags,
+                                   mode_t mode,
+                                   Error &error)
+{
+    return m_gdb_client.OpenFile (file_spec, flags, mode, error);
+}
+
+bool
+PlatformRemoteGDBServer::CloseFile (lldb::user_id_t fd, Error &error)
+{
+    return m_gdb_client.CloseFile (fd, error);
+}
+
+lldb::user_id_t
+PlatformRemoteGDBServer::GetFileSize (const lldb_private::FileSpec& file_spec)
+{
+    return m_gdb_client.GetFileSize(file_spec);
+}
+
+uint32_t
+PlatformRemoteGDBServer::GetFilePermissions (const lldb_private::FileSpec &file_spec,
+                                             lldb_private::Error &error)
+{
+    return m_gdb_client.GetFilePermissions(file_spec, error);
+}
+
+uint64_t
+PlatformRemoteGDBServer::ReadFile (lldb::user_id_t fd,
+                                   uint64_t offset,
+                                   void *dst,
+                                   uint64_t dst_len,
+                                   Error &error)
+{
+    return m_gdb_client.ReadFile (fd, offset, dst, dst_len, error);
+}
+
+uint64_t
+PlatformRemoteGDBServer::WriteFile (lldb::user_id_t fd,
+                                    uint64_t offset,
+                                    const void* src,
+                                    uint64_t src_len,
+                                    Error &error)
+{
+    return m_gdb_client.WriteFile (fd, offset, src, src_len, error);
+}
 
+lldb_private::Error
+PlatformRemoteGDBServer::PutFile (const lldb_private::FileSpec& source,
+         const lldb_private::FileSpec& destination,
+         uint32_t uid,
+         uint32_t gid)
+{
+    return Platform::PutFile(source,destination,uid,gid);
+}
+
+bool
+PlatformRemoteGDBServer::GetFileExists (const lldb_private::FileSpec& file_spec)
+{
+    return m_gdb_client.GetFileExists (file_spec);
+}
+
+lldb_private::Error
+PlatformRemoteGDBServer::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)          // Timeout in seconds to wait for shell program to finish
+{
+    return m_gdb_client.RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
+}

Modified: lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h (original)
+++ lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h Mon Aug 26 18:57:52 2013
@@ -134,6 +134,58 @@ public:
 
     virtual lldb_private::Error
     DisconnectRemote ();
+    
+    virtual uint32_t
+    MakeDirectory (const std::string &path,
+                   mode_t mode);
+    
+    virtual lldb::user_id_t
+    OpenFile (const lldb_private::FileSpec& file_spec,
+              uint32_t flags,
+              mode_t mode,
+              lldb_private::Error &error);
+    
+    virtual bool
+    CloseFile (lldb::user_id_t fd,
+               lldb_private::Error &error);
+    
+    virtual uint64_t
+    ReadFile (lldb::user_id_t fd,
+              uint64_t offset,
+              void *data_ptr,
+              uint64_t len,
+              lldb_private::Error &error);
+    
+    virtual uint64_t
+    WriteFile (lldb::user_id_t fd,
+               uint64_t offset,
+               const void* data,
+               uint64_t len,
+               lldb_private::Error &error);
+
+    virtual lldb::user_id_t
+    GetFileSize (const lldb_private::FileSpec& file_spec);
+
+    virtual lldb_private::Error
+    PutFile (const lldb_private::FileSpec& source,
+             const lldb_private::FileSpec& destination,
+             uint32_t uid = UINT32_MAX,
+             uint32_t gid = UINT32_MAX);
+    
+    virtual bool
+    GetFileExists (const lldb_private::FileSpec& file_spec);
+    
+    virtual uint32_t
+    GetFilePermissions (const lldb_private::FileSpec &file_spec,
+                        lldb_private::Error &error);
+
+    virtual lldb_private::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);         // Timeout in seconds to wait for shell program to finish
 
 protected:
     GDBRemoteCommunicationClient m_gdb_client;

Modified: lldb/trunk/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp (original)
+++ lldb/trunk/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp Mon Aug 26 18:57:52 2013
@@ -125,8 +125,27 @@ ProcessFreeBSD::Terminate()
 bool
 ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
 {
-    // XXX haxx
-    new_thread_list = old_thread_list;
-  
-    return false;
+    LogSP log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+    if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+        log->Printf ("ProcessFreeBSD::%s() (pid = %i)", __FUNCTION__, GetID());
+
+    bool has_updated = false;
+    const tid_t tid = Host::GetCurrentThreadID();
+    const lldb::pid_t pid = GetID();
+    // Update the process thread list with this new thread.
+    // FIXME: We should be using tid, not pid.
+    assert(m_monitor);
+    ThreadSP thread_sp (old_thread_list.FindThreadByID (pid, false));
+    if (!thread_sp) {
+        ProcessSP me = this->shared_from_this();
+        thread_sp.reset(new POSIXThread(me, pid));
+        has_updated = true;
+    }
+
+    if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+        log->Printf ("ProcessFreeBSD::%s() updated tid = %i", __FUNCTION__, pid);
+
+    new_thread_list.AddThread(thread_sp);
+
+    return has_updated; // the list has been updated
 }

Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp Mon Aug 26 18:57:52 2013
@@ -813,19 +813,21 @@ ProcessPOSIX::UpdateThreadList(ThreadLis
     if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
         log->Printf ("ProcessPOSIX::%s() (pid = %" PRIi64 ")", __FUNCTION__, GetID());
 
+    bool has_updated = false;
     // Update the process thread list with this new thread.
     // FIXME: We should be using tid, not pid.
     assert(m_monitor);
     ThreadSP thread_sp (old_thread_list.FindThreadByID (GetID(), false));
     if (!thread_sp) {
         thread_sp.reset(CreateNewPOSIXThread(*this, GetID()));
+        has_updated = true;
     }
 
     if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
         log->Printf ("ProcessPOSIX::%s() updated pid = %" PRIi64, __FUNCTION__, GetID());
     new_thread_list.AddThread(thread_sp);
 
-    return new_thread_list.GetSize(false) > 0;
+    return has_updated; // the list has been updated
 }
 
 ByteOrder

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp Mon Aug 26 18:57:52 2013
@@ -133,7 +133,11 @@ GDBRemoteCommunication::GDBRemoteCommuni
                                                const char *listener_name, 
                                                bool is_platform) :
     Communication(comm_name),
+#ifdef LLDB_CONFIGURATION_DEBUG
+    m_packet_timeout (1000),
+#else
     m_packet_timeout (1),
+#endif
     m_sequence_mutex (Mutex::eMutexTypeRecursive),
     m_public_is_running (false),
     m_private_is_running (false),

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp Mon Aug 26 18:57:52 2013
@@ -20,6 +20,7 @@
 #include "lldb/Core/ConnectionFileDescriptor.h"
 #include "lldb/Core/Log.h"
 #include "lldb/Core/State.h"
+#include "lldb/Core/StreamGDBRemote.h"
 #include "lldb/Core/StreamString.h"
 #include "lldb/Host/Endian.h"
 #include "lldb/Host/Host.h"
@@ -2137,21 +2138,37 @@ GDBRemoteCommunicationClient::SendSpeedT
 }
 
 uint16_t
-GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort ()
+GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid)
 {
+    pid = LLDB_INVALID_PROCESS_ID;
     StringExtractorGDBRemote response;
-    if (SendPacketAndWaitForResponse("qLaunchGDBServer", strlen("qLaunchGDBServer"), response, false))
+    StreamString stream;
+    stream.PutCString("qLaunchGDBServer:port:0;");
+    std::string hostname;
+    if (Host::GetHostname (hostname))
+    {
+        // Make the GDB server we launch only accept connections from this host
+        stream.Printf("host:%s;", hostname.c_str());
+    }
+    else
+    {
+        // Make the GDB server we launch accept connections from any host since we can't figure out the hostname
+        stream.Printf("host:*;");
+    }
+    const char *packet = stream.GetData();
+    int packet_len = stream.GetSize();
+
+    if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
     {
         std::string name;
         std::string value;
         uint16_t port = 0;
-        //lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
         while (response.GetNameColonValue(name, value))
         {
-            if (name.size() == 4 && name.compare("port") == 0)
+            if (name.compare("port") == 0)
                 port = Args::StringToUInt32(value.c_str(), 0, 0);
-//            if (name.size() == 3 && name.compare("pid") == 0)
-//                pid = Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0);
+            else if (name.compare("pid") == 0)
+                pid = Args::StringToUInt64(value.c_str(), LLDB_INVALID_PROCESS_ID, 0);
         }
         return port;
     }
@@ -2159,6 +2176,23 @@ GDBRemoteCommunicationClient::LaunchGDBs
 }
 
 bool
+GDBRemoteCommunicationClient::KillSpawnedProcess (lldb::pid_t pid)
+{
+    StreamString stream;
+    stream.Printf ("qKillSpawnedProcess:%" PRId64 , pid);
+    const char *packet = stream.GetData();
+    int packet_len = stream.GetSize();
+    pid = LLDB_INVALID_PROCESS_ID;
+    StringExtractorGDBRemote response;
+    if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+    {
+        if (response.IsOKResponse())
+            return true;
+    }
+    return false;
+}
+
+bool
 GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid)
 {
     if (m_curr_tid == tid)
@@ -2351,3 +2385,326 @@ GDBRemoteCommunicationClient::GetShlibIn
     return LLDB_INVALID_ADDRESS;
 }
 
+lldb_private::Error
+GDBRemoteCommunicationClient::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)          // Timeout in seconds to wait for shell program to finish
+{
+    lldb_private::StreamString stream;
+    stream.PutCString("qPlatform_RunCommand:");
+    stream.PutBytesAsRawHex8(command, strlen(command));
+    stream.PutChar(',');
+    stream.PutHex32(timeout_sec);
+    if (working_dir && *working_dir)
+    {
+        stream.PutChar(',');
+        stream.PutBytesAsRawHex8(working_dir, strlen(working_dir));
+    }
+    const char *packet = stream.GetData();
+    int packet_len = stream.GetSize();
+    StringExtractorGDBRemote response;
+    if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+    {
+        if (response.GetChar() != 'F')
+            return Error("malformed reply");
+        if (response.GetChar() != ',')
+            return Error("malformed reply");
+        uint32_t exitcode = response.GetHexMaxU32(false, UINT32_MAX);
+        if (exitcode == UINT32_MAX)
+            return Error("unable to run remote process");
+        else if (status_ptr)
+            *status_ptr = exitcode;
+        if (response.GetChar() != ',')
+            return Error("malformed reply");
+        uint32_t signo = response.GetHexMaxU32(false, UINT32_MAX);
+        if (signo_ptr)
+            *signo_ptr = signo;
+        if (response.GetChar() != ',')
+            return Error("malformed reply");
+        std::string output;
+        response.GetEscapedBinaryData(output);
+        if (command_output)
+            command_output->assign(output);
+        return Error();
+    }
+    return Error("unable to send packet");
+}
+
+uint32_t
+GDBRemoteCommunicationClient::MakeDirectory (const std::string &path,
+                                             mode_t mode)
+{
+    lldb_private::StreamString stream;
+    stream.PutCString("qPlatform_IO_MkDir:");
+    stream.PutHex32(mode);
+    stream.PutChar(',');
+    stream.PutBytesAsRawHex8(path.c_str(), path.size());
+    const char *packet = stream.GetData();
+    int packet_len = stream.GetSize();
+    StringExtractorGDBRemote response;
+    if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+    {
+        return response.GetHexMaxU32(false, UINT32_MAX);
+    }
+    return UINT32_MAX;
+
+}
+
+static uint64_t
+ParseHostIOPacketResponse (StringExtractorGDBRemote &response,
+                           uint64_t fail_result,
+                           Error &error)
+{
+    response.SetFilePos(0);
+    if (response.GetChar() != 'F')
+        return fail_result;
+    int32_t result = response.GetS32 (-2);
+    if (result == -2)
+        return fail_result;
+    if (response.GetChar() == ',')
+    {
+        int result_errno = response.GetS32 (-2);
+        if (result_errno != -2)
+            error.SetError(result_errno, eErrorTypePOSIX);
+        else
+            error.SetError(-1, eErrorTypeGeneric);
+    }
+    else
+        error.Clear();
+    return  result;
+}
+lldb::user_id_t
+GDBRemoteCommunicationClient::OpenFile (const lldb_private::FileSpec& file_spec,
+                                        uint32_t flags,
+                                        mode_t mode,
+                                        Error &error)
+{
+    lldb_private::StreamString stream;
+    stream.PutCString("vFile:open:");
+    std::string path (file_spec.GetPath());
+    if (path.empty())
+        return UINT64_MAX;
+    stream.PutCStringAsRawHex8(path.c_str());
+    stream.PutChar(',');
+    const uint32_t posix_open_flags = File::ConvertOpenOptionsForPOSIXOpen(flags);
+    stream.PutHex32(posix_open_flags);
+    stream.PutChar(',');
+    stream.PutHex32(mode);
+    const char* packet = stream.GetData();
+    int packet_len = stream.GetSize();
+    StringExtractorGDBRemote response;
+    if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+    {
+        return ParseHostIOPacketResponse (response, UINT64_MAX, error);
+    }
+    return UINT64_MAX;
+}
+
+bool
+GDBRemoteCommunicationClient::CloseFile (lldb::user_id_t fd,
+                                         Error &error)
+{
+    lldb_private::StreamString stream;
+    stream.Printf("vFile:close:%i", (int)fd);
+    const char* packet = stream.GetData();
+    int packet_len = stream.GetSize();
+    StringExtractorGDBRemote response;
+    if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+    {
+        return ParseHostIOPacketResponse (response, -1, error) == 0;
+    }
+    return UINT64_MAX;
+}
+
+// Extension of host I/O packets to get the file size.
+lldb::user_id_t
+GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_spec)
+{
+    lldb_private::StreamString stream;
+    stream.PutCString("vFile:size:");
+    std::string path (file_spec.GetPath());
+    stream.PutCStringAsRawHex8(path.c_str());
+    const char* packet = stream.GetData();
+    int packet_len = stream.GetSize();
+    StringExtractorGDBRemote response;
+    if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+    {
+        if (response.GetChar() != 'F')
+            return UINT64_MAX;
+        uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX);
+        return retcode;
+    }
+    return UINT64_MAX;
+}
+
+uint32_t
+GDBRemoteCommunicationClient::GetFilePermissions(const lldb_private::FileSpec& file_spec, Error &error)
+{
+    lldb_private::StreamString stream;
+    stream.PutCString("vFile:mode:");
+    std::string path (file_spec.GetPath());
+    stream.PutCStringAsRawHex8(path.c_str());
+    const char* packet = stream.GetData();
+    int packet_len = stream.GetSize();
+    StringExtractorGDBRemote response;
+    if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+    {
+        if (response.GetChar() != 'F')
+        {
+            error.SetErrorStringWithFormat ("invalid response to '%s' packet", packet);
+            return 0;
+        }
+        const uint32_t mode = response.GetS32(-1);
+        if (mode == -1)
+        {
+            if (response.GetChar() == ',')
+            {
+                int response_errno = response.GetS32(-1);
+                if (response_errno > 0)
+                    error.SetError(response_errno, lldb::eErrorTypePOSIX);
+                else
+                    error.SetErrorToGenericError();
+            }
+        }
+        else
+            error.Clear();
+        return mode & (S_IRWXU|S_IRWXG|S_IRWXO);
+    }
+    else
+    {
+        error.SetErrorStringWithFormat ("failed to send '%s' packet", packet);
+    }
+    return 0;
+}
+
+uint64_t
+GDBRemoteCommunicationClient::ReadFile (lldb::user_id_t fd,
+                                        uint64_t offset,
+                                        void *dst,
+                                        uint64_t dst_len,
+                                        Error &error)
+{
+    lldb_private::StreamString stream;
+    stream.Printf("vFile:pread:%i,%" PRId64 ",%" PRId64, (int)fd, dst_len, offset);
+    const char* packet = stream.GetData();
+    int packet_len = stream.GetSize();
+    StringExtractorGDBRemote response;
+    if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+    {
+        if (response.GetChar() != 'F')
+            return 0;
+        uint32_t retcode = response.GetHexMaxU32(false, UINT32_MAX);
+        if (retcode == UINT32_MAX)
+            return retcode;
+        const char next = (response.Peek() ? *response.Peek() : 0);
+        if (next == ',')
+            return 0;
+        if (next == ';')
+        {
+            response.GetChar(); // skip the semicolon
+            std::string buffer;
+            if (response.GetEscapedBinaryData(buffer))
+            {
+                const uint64_t data_to_write = std::min<uint64_t>(dst_len, buffer.size());
+                if (data_to_write > 0)
+                    memcpy(dst, &buffer[0], data_to_write);
+                return data_to_write;
+            }
+        }
+    }
+    return 0;
+}
+
+uint64_t
+GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd,
+                                         uint64_t offset,
+                                         const void* src,
+                                         uint64_t src_len,
+                                         Error &error)
+{
+    lldb_private::StreamGDBRemote stream;
+    stream.Printf("vFile:pwrite:%i,%" PRId64 ",", (int)fd, offset);
+    stream.PutEscapedBytes(src, src_len);
+    const char* packet = stream.GetData();
+    int packet_len = stream.GetSize();
+    StringExtractorGDBRemote response;
+    if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+    {
+        if (response.GetChar() != 'F')
+        {
+            error.SetErrorStringWithFormat("write file failed");
+            return 0;
+        }
+        uint64_t bytes_written = response.GetU64(UINT64_MAX);
+        if (bytes_written == UINT64_MAX)
+        {
+            error.SetErrorToGenericError();
+            if (response.GetChar() == ',')
+            {
+                int response_errno = response.GetS32(-1);
+                if (response_errno > 0)
+                    error.SetError(response_errno, lldb::eErrorTypePOSIX);
+            }
+            return 0;
+        }
+        return bytes_written;
+    }
+    else
+    {
+        error.SetErrorString ("failed to send vFile:pwrite packet");
+    }
+    return 0;
+}
+
+// Extension of host I/O packets to get whether a file exists.
+bool
+GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec)
+{
+    lldb_private::StreamString stream;
+    stream.PutCString("vFile:exists:");
+    std::string path (file_spec.GetPath());
+    stream.PutCStringAsRawHex8(path.c_str());
+    const char* packet = stream.GetData();
+    int packet_len = stream.GetSize();
+    StringExtractorGDBRemote response;
+    if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+    {
+        if (response.GetChar() != 'F')
+            return false;
+        if (response.GetChar() != ',')
+            return false;
+        bool retcode = (response.GetChar() != '0');
+        return retcode;
+    }
+    return false;
+}
+
+bool
+GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_spec,
+                                            uint64_t &high,
+                                            uint64_t &low)
+{
+    lldb_private::StreamString stream;
+    stream.PutCString("vFile:MD5:");
+    std::string path (file_spec.GetPath());
+    stream.PutCStringAsRawHex8(path.c_str());
+    const char* packet = stream.GetData();
+    int packet_len = stream.GetSize();
+    StringExtractorGDBRemote response;
+    if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+    {
+        if (response.GetChar() != 'F')
+            return false;
+        if (response.GetChar() != ',')
+            return false;
+        if (response.Peek() && *response.Peek() == 'x')
+            return false;
+        low = response.GetHexMaxU64(false, UINT64_MAX);
+        high = response.GetHexMaxU64(false, UINT64_MAX);
+        return true;
+    }
+    return false;
+}

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h Mon Aug 26 18:57:52 2013
@@ -89,7 +89,10 @@ public:
     GetLaunchSuccess (std::string &error_str);
 
     uint16_t
-    LaunchGDBserverAndGetPort ();
+    LaunchGDBserverAndGetPort (lldb::pid_t &pid);
+    
+    bool
+    KillSpawnedProcess (lldb::pid_t pid);
 
     //------------------------------------------------------------------
     /// Sends a GDB remote protocol 'A' packet that delivers program
@@ -347,10 +350,61 @@ public:
         return m_interrupt_sent;
     }
     
+    virtual lldb::user_id_t
+    OpenFile (const lldb_private::FileSpec& file_spec,
+              uint32_t flags,
+              mode_t mode,
+              lldb_private::Error &error);
+    
+    virtual bool
+    CloseFile (lldb::user_id_t fd,
+               lldb_private::Error &error);
+    
+    virtual lldb::user_id_t
+    GetFileSize (const lldb_private::FileSpec& file_spec);
+    
+    virtual uint32_t
+    GetFilePermissions(const lldb_private::FileSpec& file_spec,
+                       lldb_private::Error &error);
+
+    virtual uint64_t
+    ReadFile (lldb::user_id_t fd,
+              uint64_t offset,
+              void *dst,
+              uint64_t dst_len,
+              lldb_private::Error &error);
+    
+    virtual uint64_t
+    WriteFile (lldb::user_id_t fd,
+               uint64_t offset,
+               const void* src,
+               uint64_t src_len,
+               lldb_private::Error &error);
+    
+    virtual uint32_t
+    MakeDirectory (const std::string &path,
+                   mode_t mode);
+    
+    virtual bool
+    GetFileExists (const lldb_private::FileSpec& file_spec);
+    
+    virtual lldb_private::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);         // Timeout in seconds to wait for shell program to finish
+    
+    virtual bool
+    CalculateMD5 (const lldb_private::FileSpec& file_spec,
+                  uint64_t &high,
+                  uint64_t &low);
+    
     std::string
     HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process,
                                       StringExtractorGDBRemote &inputStringExtractor);
-    
+
 protected:
 
     bool

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp Mon Aug 26 18:57:52 2013
@@ -9,6 +9,7 @@
 
 
 #include "GDBRemoteCommunicationServer.h"
+#include "lldb/Core/StreamGDBRemote.h"
 
 // C Includes
 // C++ Includes
@@ -20,6 +21,7 @@
 #include "lldb/Core/State.h"
 #include "lldb/Core/StreamString.h"
 #include "lldb/Host/Endian.h"
+#include "lldb/Host/File.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Host/TimeValue.h"
 #include "lldb/Target/Process.h"
@@ -40,11 +42,31 @@ GDBRemoteCommunicationServer::GDBRemoteC
     m_async_thread (LLDB_INVALID_HOST_THREAD),
     m_process_launch_info (),
     m_process_launch_error (),
+    m_spawned_pids (),
+    m_spawned_pids_mutex (Mutex::eMutexTypeRecursive),
     m_proc_infos (),
     m_proc_infos_index (0),
     m_lo_port_num (0),
-    m_hi_port_num (0)
-{
+    m_hi_port_num (0),
+    m_next_port (0),
+    m_use_port_range (false)
+{
+    // We seldom need to override the port number that the debugserver process
+    // starts with.  We just pass in 0 to let the system choose a random port.
+    // In rare situation where the need arises, use two environment variables
+    // to override.
+    uint16_t lo_port_num = 0;
+    uint16_t hi_port_num = 0;
+    const char *lo_port_c_str = getenv("LLDB_PLATFORM_START_DEBUG_SERVER_LO_PORT");
+    if (lo_port_c_str)
+        lo_port_num = ::atoi(lo_port_c_str);
+    const char *hi_port_c_str = getenv("LLDB_PLATFORM_START_DEBUG_SERVER_HI_PORT");
+    if (hi_port_c_str)
+        hi_port_num = ::atoi(hi_port_c_str);
+    if (lo_port_num && hi_port_num && lo_port_num < hi_port_num)
+    {
+        SetPortRange(lo_port_num, hi_port_num);
+    }
 }
 
 //----------------------------------------------------------------------
@@ -125,6 +147,9 @@ GDBRemoteCommunicationServer::GetPacketA
             case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer:
                 return Handle_qLaunchGDBServer (packet);
                 
+            case StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess:
+                return Handle_qKillSpawnedProcess (packet);
+                
             case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess:
                 return Handle_qLaunchSuccess (packet);
                 
@@ -142,6 +167,9 @@ GDBRemoteCommunicationServer::GetPacketA
 
             case StringExtractorGDBRemote::eServerPacketType_QEnvironment:
                 return Handle_QEnvironment (packet);
+                
+            case StringExtractorGDBRemote::eServerPacketType_QLaunchArch:
+                return Handle_QLaunchArch (packet);
             
             case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR:
                 return Handle_QSetDisableASLR (packet);
@@ -160,6 +188,39 @@ GDBRemoteCommunicationServer::GetPacketA
 
             case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode:
                 return Handle_QStartNoAckMode (packet);
+                
+            case StringExtractorGDBRemote::eServerPacketType_qPlatform_IO_MkDir:
+                return Handle_qPlatform_IO_MkDir (packet);
+                
+            case StringExtractorGDBRemote::eServerPacketType_qPlatform_RunCommand:
+                return Handle_qPlatform_RunCommand (packet);
+                
+            case StringExtractorGDBRemote::eServerPacketType_vFile_Open:
+                return Handle_vFile_Open (packet);
+                
+            case StringExtractorGDBRemote::eServerPacketType_vFile_Close:
+                return Handle_vFile_Close (packet);
+                
+            case StringExtractorGDBRemote::eServerPacketType_vFile_pRead:
+                return Handle_vFile_pRead (packet);
+                
+            case StringExtractorGDBRemote::eServerPacketType_vFile_pWrite:
+                return Handle_vFile_pWrite (packet);
+
+            case StringExtractorGDBRemote::eServerPacketType_vFile_Size:
+                return Handle_vFile_Size (packet);
+
+            case StringExtractorGDBRemote::eServerPacketType_vFile_Mode:
+                return Handle_vFile_Mode (packet);
+
+            case StringExtractorGDBRemote::eServerPacketType_vFile_Exists:
+                return Handle_vFile_Exists (packet);
+                
+            case StringExtractorGDBRemote::eServerPacketType_vFile_Stat:
+                return Handle_vFile_Stat (packet);
+                
+            case StringExtractorGDBRemote::eServerPacketType_vFile_MD5:
+                return Handle_vFile_MD5 (packet);
         }
         return true;
     }
@@ -666,6 +727,24 @@ GDBRemoteCommunicationServer::Handle_qC
 }
 
 bool
+GDBRemoteCommunicationServer::DebugserverProcessReaped (lldb::pid_t pid)
+{
+    Mutex::Locker locker (m_spawned_pids_mutex);
+    return m_spawned_pids.erase(pid) > 0;
+}
+bool
+GDBRemoteCommunicationServer::ReapDebugserverProcess (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
+{
+    GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton;
+    server->DebugserverProcessReaped (pid);
+    return true;
+}
+
+bool
 GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
 {
 #ifdef _WIN32
@@ -681,47 +760,97 @@ GDBRemoteCommunicationServer::Handle_qLa
         ConnectionFileDescriptor file_conn;
         char connect_url[PATH_MAX];
         Error error;
-        char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";    
+        std::string hostname;
+        char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
         if (::mktemp (unix_socket_name) == NULL)
         {
             error.SetErrorString ("failed to make temporary path for a unix socket");
         }
         else
         {
+            packet.SetFilePos(::strlen ("qLaunchGDBServer:"));
+            std::string name;
+            std::string value;
+            uint16_t port = UINT16_MAX;
+            while (packet.GetNameColonValue(name, value))
+            {
+                if (name.compare ("host") == 0)
+                    hostname.swap(value);
+                else if (name.compare ("port") == 0)
+                    port = Args::StringToUInt32(value.c_str(), 0, 0);
+            }
+            if (port == UINT16_MAX)
+                port = GetAndUpdateNextPort();
+
             ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name);
             // Spawn a new thread to accept the port that gets bound after
             // binding to port 0 (zero).
-            lldb::thread_t accept_thread = Host::ThreadCreate (unix_socket_name,
-                                                               AcceptPortFromInferior,
-                                                               connect_url,
-                                                               &error);
+            lldb::thread_t accept_thread = NULL;
+            
+            if (port == 0)
+            {
+                accept_thread = Host::ThreadCreate (unix_socket_name,
+                                                    AcceptPortFromInferior,
+                                                    connect_url,
+                                                    &error);
+            }
             
             if (IS_VALID_LLDB_HOST_THREAD(accept_thread))
             {
-                // Spawn a debugserver and try to get
+                // Spawn a debugserver and try to get the port it listens to.
                 ProcessLaunchInfo debugserver_launch_info;
-                error = StartDebugserverProcess ("localhost:0", 
+                StreamString host_and_port;
+                if (hostname.empty())
+                    hostname = "localhost";
+                host_and_port.Printf("%s:%u", hostname.c_str(), port);
+                const char *host_and_port_cstr = host_and_port.GetString().c_str();
+                Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+                if (log)
+                    log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr);
+                error = StartDebugserverProcess (host_and_port_cstr,
                                                  unix_socket_name, 
                                                  debugserver_launch_info);
                 
                 lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
+                
+                if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+                {
+                    {
+                        Mutex::Locker locker (m_spawned_pids_mutex);
+                        m_spawned_pids.insert(debugserver_pid);
+                    }
+                    Host::StartMonitoringChildProcess (ReapDebugserverProcess, this, debugserver_pid, false);
+                }
+
                 if (error.Success())
                 {
                     bool success = false;
                     
-                    thread_result_t accept_thread_result = NULL;
-                    if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error))
+                    if (accept_thread)
                     {
-                        if (accept_thread_result)
+                        thread_result_t accept_thread_result = NULL;
+                        if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error))
                         {
-                            uint16_t port = (intptr_t)accept_thread_result;
-                            char response[256];
-                            const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port);
-                            assert (response_len < (int)sizeof(response));
-                            //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
-                            success = SendPacketNoLock (response, response_len) > 0;
+                            if (accept_thread_result)
+                            {
+                                port = (intptr_t)accept_thread_result;
+                                char response[256];
+                                const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port);
+                                assert (response_len < sizeof(response));
+                                //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
+                                success = SendPacketNoLock (response, response_len) > 0;
+                            }
                         }
                     }
+                    else
+                    {
+                        char response[256];
+                        const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port);
+                        assert (response_len < sizeof(response));
+                        //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
+                        success = SendPacketNoLock (response, response_len) > 0;
+                        
+                    }
                     ::unlink (unix_socket_name);
                     
                     if (!success)
@@ -734,11 +863,64 @@ GDBRemoteCommunicationServer::Handle_qLa
             }
         }
     }
-    return SendErrorResponse (13);
+    return SendErrorResponse (9);
 #endif
 }
 
 bool
+GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
+{
+    // Spawn a local debugserver as a platform so we can then attach or launch
+    // a process...
+    
+    if (m_is_platform)
+    {
+        packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
+        
+        lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
+
+        // Scope for locker
+        {
+            Mutex::Locker locker (m_spawned_pids_mutex);
+            if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+                return SendErrorResponse (10);
+        }
+        kill (pid, SIGTERM);
+        
+        for (size_t i=0; i<10; ++i)
+        {
+            // Scope for locker
+            {
+                Mutex::Locker locker (m_spawned_pids_mutex);
+                if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+                    return true;
+            }
+            usleep (10000);
+        }
+
+        // Scope for locker
+        {
+            Mutex::Locker locker (m_spawned_pids_mutex);
+            if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+                return true;
+        }
+        kill (pid, SIGKILL);
+        
+        for (size_t i=0; i<10; ++i)
+        {
+            // Scope for locker
+            {
+                Mutex::Locker locker (m_spawned_pids_mutex);
+                if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+                    return true;
+            }
+            usleep (10000);
+        }
+    }
+    return SendErrorResponse (10);
+}
+
+bool
 GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet)
 {
     if (m_process_launch_error.Success())
@@ -759,7 +941,22 @@ GDBRemoteCommunicationServer::Handle_QEn
         m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek());
         return SendOKResponse ();
     }
-    return SendErrorResponse (9);
+    return SendErrorResponse (11);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen ("QLaunchArch:"));
+    const uint32_t bytes_left = packet.GetBytesLeft();
+    if (bytes_left > 0)
+    {
+        const char* arch_triple = packet.Peek();
+        ArchSpec arch_spec(arch_triple,NULL);
+        m_process_launch_info.SetArchitecture(arch_spec);
+        return SendOKResponse();
+    }
+    return SendErrorResponse(12);
 }
 
 bool
@@ -797,7 +994,7 @@ GDBRemoteCommunicationServer::Handle_QSe
         m_process_launch_info.AppendFileAction(file_action);
         return SendOKResponse ();
     }
-    return SendErrorResponse (10);
+    return SendErrorResponse (13);
 }
 
 bool
@@ -814,7 +1011,7 @@ GDBRemoteCommunicationServer::Handle_QSe
         m_process_launch_info.AppendFileAction(file_action);
         return SendOKResponse ();
     }
-    return SendErrorResponse (11);
+    return SendErrorResponse (14);
 }
 
 bool
@@ -831,7 +1028,7 @@ GDBRemoteCommunicationServer::Handle_QSe
         m_process_launch_info.AppendFileAction(file_action);
         return SendOKResponse ();
     }
-    return SendErrorResponse (12);
+    return SendErrorResponse (15);
 }
 
 bool
@@ -842,3 +1039,265 @@ GDBRemoteCommunicationServer::Handle_QSt
     m_send_acks = false;
     return true;
 }
+
+bool
+GDBRemoteCommunicationServer::Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("qPlatform_IO_MkDir:"));
+    mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
+    if (packet.GetChar() != ',')
+        return false;
+    std::string path;
+    packet.GetHexByteString(path);
+    uint32_t retcode = Host::MakeDirectory(path.c_str(),mode);
+    StreamString response;
+    response.PutHex32(retcode);
+    SendPacketNoLock(response.GetData(), response.GetSize());
+    return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("vFile:open:"));
+    std::string path;
+    packet.GetHexByteStringTerminatedBy(path,',');
+    if (path.size() == 0)
+        return false;
+    if (packet.GetChar() != ',')
+        return false;
+    uint32_t flags = packet.GetHexMaxU32(false, UINT32_MAX);
+    if (packet.GetChar() != ',')
+        return false;
+    mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
+    Error error;
+    int fd = ::open (path.c_str(), flags, mode);
+    const int save_errno = fd == -1 ? errno : 0;
+    StreamString response;
+    response.PutChar('F');
+    response.Printf("%i", fd);
+    if (save_errno)
+        response.Printf(",%i", save_errno);
+    SendPacketNoLock(response.GetData(), response.GetSize());
+    return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("vFile:close:"));
+    int fd = packet.GetS32(-1);
+    Error error;
+    int err = -1;
+    int save_errno = 0;
+    if (fd >= 0)
+    {
+        err = close(fd);
+        save_errno = err == -1 ? errno : 0;
+    }
+    else
+    {
+        save_errno = EINVAL;
+    }
+    StreamString response;
+    response.PutChar('F');
+    response.Printf("%i", err);
+    if (save_errno)
+        response.Printf(",%i", save_errno);
+    SendPacketNoLock(response.GetData(), response.GetSize());
+    return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &packet)
+{
+    StreamGDBRemote response;
+    packet.SetFilePos(::strlen("vFile:pread:"));
+    int fd = packet.GetS32(-1);
+    if (packet.GetChar() != ',')
+        return false;
+    uint64_t count = packet.GetU64(UINT64_MAX);
+    if (packet.GetChar() != ',')
+        return false;
+    uint64_t offset = packet.GetU64(UINT32_MAX);
+    if (count == UINT64_MAX)
+    {
+        response.Printf("F-1:%i", EINVAL);
+        SendPacketNoLock(response.GetData(), response.GetSize());
+        return true;
+    }
+    std::string buffer(count, 0);
+    const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset);
+    const int save_errno = bytes_read == -1 ? errno : 0;
+    response.PutChar('F');
+    response.Printf("%zi", bytes_read);
+    if (save_errno)
+        response.Printf(",%i", save_errno);
+    else
+    {
+        response.PutChar(';');
+        response.PutEscapedBytes(&buffer[0], bytes_read);
+    }
+    SendPacketNoLock(response.GetData(), response.GetSize());
+    return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("vFile:pwrite:"));
+
+    StreamGDBRemote response;
+    response.PutChar('F');
+
+    int fd = packet.GetU32(UINT32_MAX);
+    if (packet.GetChar() != ',')
+        return false;
+    off_t offset = packet.GetU64(UINT32_MAX);
+    if (packet.GetChar() != ',')
+        return false;
+    std::string buffer;
+    if (packet.GetEscapedBinaryData(buffer))
+    {
+        const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset);
+        const int save_errno = bytes_written == -1 ? errno : 0;
+        response.Printf("%zi", bytes_written);
+        if (save_errno)
+            response.Printf(",%i", save_errno);
+    }
+    else
+    {
+        response.Printf ("-1,%i", EINVAL);
+    }
+
+    SendPacketNoLock(response.GetData(), response.GetSize());
+    return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("vFile:size:"));
+    std::string path;
+    packet.GetHexByteString(path);
+    if (path.empty())
+        return false;
+    lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false));
+    StreamString response;
+    response.PutChar('F');
+    response.PutHex64(retcode);
+    if (retcode == UINT64_MAX)
+    {
+        response.PutChar(',');
+        response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode()
+    }
+    SendPacketNoLock(response.GetData(), response.GetSize());
+    return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("vFile:mode:"));
+    std::string path;
+    packet.GetHexByteString(path);
+    if (path.empty())
+        return false;
+    Error error;
+    const uint32_t mode = File::GetPermissions(path.c_str(), error);
+    StreamString response;
+    response.Printf("F%u", mode);
+    if (mode == 0 || error.Fail())
+        response.Printf(",%i", (int)error.GetError());
+    SendPacketNoLock(response.GetData(), response.GetSize());
+    return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("vFile:exists:"));
+    std::string path;
+    packet.GetHexByteString(path);
+    if (path.empty())
+        return false;
+    bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false));
+    StreamString response;
+    response.PutChar('F');
+    response.PutChar(',');
+    if (retcode)
+        response.PutChar('1');
+    else
+        response.PutChar('0');
+    SendPacketNoLock(response.GetData(), response.GetSize());
+    return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("qPlatform_RunCommand:"));
+    std::string path;
+    std::string working_dir;
+    packet.GetHexByteStringTerminatedBy(path,',');
+    if (path.size() == 0)
+        return false;
+    if (packet.GetChar() != ',')
+        return false;
+    uint32_t timeout = packet.GetHexMaxU32(false, 32);
+    if (packet.GetChar() == ',')
+        packet.GetHexByteString(working_dir);
+    int status, signo;
+    std::string output;
+    Error err = Host::RunShellCommand(path.c_str(),
+                                      working_dir.empty() ? NULL : working_dir.c_str(),
+                                      &status, &signo, &output, timeout);
+    StreamGDBRemote response;
+    if (err.Fail())
+    {
+        response.PutCString("F,");
+        response.PutHex32(UINT32_MAX);
+    }
+    else
+    {
+        response.PutCString("F,");
+        response.PutHex32(status);
+        response.PutChar(',');
+        response.PutHex32(signo);
+        response.PutChar(',');
+        response.PutEscapedBytes(output.c_str(), output.size());
+    }
+    SendPacketNoLock(response.GetData(), response.GetSize());
+    return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet)
+{
+    return false;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("vFile:exists:"));
+    std::string path;
+    packet.GetHexByteString(path);
+    if (path.size() == 0)
+        return false;
+    uint64_t a,b;
+    StreamGDBRemote response;
+    if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false)
+    {
+        response.PutCString("F,");
+        response.PutCString("x");
+    }
+    else
+    {
+        response.PutCString("F,");
+        response.PutHex64(a);
+        response.PutHex64(b);
+    }
+    SendPacketNoLock(response.GetData(), response.GetSize());
+    return true;
+}

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h Mon Aug 26 18:57:52 2013
@@ -12,10 +12,12 @@
 
 // C Includes
 // C++ Includes
+#include <vector>
+#include <set>
 // Other libraries and framework includes
 // Project includes
+#include "lldb/Host/Mutex.h"
 #include "lldb/Target/Process.h"
-
 #include "GDBRemoteCommunication.h"
 
 class ProcessGDBRemote;
@@ -60,6 +62,21 @@ public:
     {
         m_lo_port_num = lo_port_num;
         m_hi_port_num = hi_port_num;
+        m_next_port = m_lo_port_num;
+        m_use_port_range = true;
+    }
+
+    // If we are using a port range, get and update the next port to be used variable.
+    // Otherwise, just return 0.
+    uint16_t
+    GetAndUpdateNextPort ()
+    {
+        if (!m_use_port_range)
+            return 0;
+        uint16_t val = m_next_port;
+        if (++m_next_port > m_hi_port_num)
+            m_next_port = m_lo_port_num;
+        return val;
     }
 
 protected:
@@ -68,11 +85,16 @@ protected:
     lldb::thread_t m_async_thread;
     lldb_private::ProcessLaunchInfo m_process_launch_info;
     lldb_private::Error m_process_launch_error;
+    std::set<lldb::pid_t> m_spawned_pids;
+    lldb_private::Mutex m_spawned_pids_mutex;
     lldb_private::ProcessInstanceInfoList m_proc_infos;
     uint32_t m_proc_infos_index;
     uint16_t m_lo_port_num;
     uint16_t m_hi_port_num;
     //PortToPIDMap m_port_to_pid_map;
+    uint16_t m_next_port;
+    bool m_use_port_range;
+    
 
     size_t
     SendUnimplementedResponse (const char *packet);
@@ -85,7 +107,7 @@ protected:
 
     bool
     Handle_A (StringExtractorGDBRemote &packet);
-
+    
     bool
     Handle_qLaunchSuccess (StringExtractorGDBRemote &packet);
 
@@ -94,8 +116,14 @@ protected:
     
     bool
     Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet);
+    
+    bool
+    Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet);
 
     bool
+    Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet);
+    
+    bool
     Handle_qProcessInfoPID (StringExtractorGDBRemote &packet);
     
     bool
@@ -120,6 +148,9 @@ protected:
     Handle_QEnvironment  (StringExtractorGDBRemote &packet);
     
     bool
+    Handle_QLaunchArch (StringExtractorGDBRemote &packet);
+    
+    bool
     Handle_QSetDisableASLR (StringExtractorGDBRemote &packet);
 
     bool
@@ -137,7 +168,47 @@ protected:
     bool
     Handle_QSetSTDERR (StringExtractorGDBRemote &packet);
     
+    bool
+    Handle_vFile_Open (StringExtractorGDBRemote &packet);
+
+    bool
+    Handle_vFile_Close (StringExtractorGDBRemote &packet);
+
+    bool
+    Handle_vFile_pRead (StringExtractorGDBRemote &packet);
+
+    bool
+    Handle_vFile_pWrite (StringExtractorGDBRemote &packet);
+
+    bool
+    Handle_vFile_Size (StringExtractorGDBRemote &packet);
+    
+    bool
+    Handle_vFile_Mode (StringExtractorGDBRemote &packet);
+
+    bool
+    Handle_vFile_Exists (StringExtractorGDBRemote &packet);
+
+    bool
+    Handle_vFile_Stat (StringExtractorGDBRemote &packet);
+    
+    bool
+    Handle_vFile_MD5 (StringExtractorGDBRemote &packet);
+    
+    bool
+    Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet);
+
 private:
+    bool
+    DebugserverProcessReaped (lldb::pid_t pid);
+    
+    static bool
+    ReapDebugserverProcess (void *callback_baton,
+                            lldb::pid_t pid,
+                            bool exited,
+                            int signal,
+                            int status);
+
     //------------------------------------------------------------------
     // For GDBRemoteCommunicationServer only
     //------------------------------------------------------------------

Modified: lldb/trunk/source/Target/Platform.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Platform.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Target/Platform.cpp (original)
+++ lldb/trunk/source/Target/Platform.cpp Mon Aug 26 18:57:52 2013
@@ -22,6 +22,7 @@
 #include "lldb/Host/Host.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/Target.h"
+#include "lldb/Utility/Utils.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -247,7 +248,13 @@ Platform::Platform (bool is_host) :
     m_uid_map(),
     m_gid_map(),
     m_max_uid_name_len (0),
-    m_max_gid_name_len (0)
+    m_max_gid_name_len (0),
+    m_supports_rsync (false),
+    m_rsync_opts (),
+    m_rsync_prefix (),
+    m_supports_ssh (false),
+    m_ssh_opts (),
+    m_ignores_remote_hostname (false)
 {
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
     if (log)
@@ -311,6 +318,14 @@ Platform::GetStatus (Stream &strm)
             strm.Printf("  Hostname: %s\n", GetHostname());
         strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no");
     }
+
+    if (!IsConnected())
+        return;
+
+    std::string specific_info(GetPlatformSpecificConnectionInformation());
+    
+    if (specific_info.empty() == false)
+        strm.Printf("Platform-specific connection: %s\n", specific_info.c_str());
 }
 
 
@@ -760,9 +775,161 @@ Platform::IsCompatibleArchitecture (cons
     if (compatible_arch_ptr)
         compatible_arch_ptr->Clear();
     return false;
+}
+
+uint32_t
+Platform::MakeDirectory (const FileSpec &spec,
+                         mode_t mode)
+{
+    std::string path(spec.GetPath());
+    return this->MakeDirectory(path,mode);
+}
+
+Error
+Platform::PutFile (const FileSpec& source,
+                   const FileSpec& destination,
+                   uint32_t uid,
+                   uint32_t gid)
+{
+    Error error("unimplemented");
+    return error;
+}
+
+Error
+Platform::GetFile (const FileSpec& source,
+                   const FileSpec& destination)
+{
+    Error error("unimplemented");
+    return error;
+}
+
+bool
+Platform::GetFileExists (const lldb_private::FileSpec& file_spec)
+{
+    return false;
+}
+
+lldb_private::Error
+Platform::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)          // Timeout in seconds to wait for shell program to finish
+{
+    if (IsHost())
+        return Host::RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
+    else
+        return Error("unimplemented");
+}
+
+
+bool
+Platform::CalculateMD5 (const FileSpec& file_spec,
+                        uint64_t &low,
+                        uint64_t &high)
+{
+    if (IsHost())
+        return Host::CalculateMD5(file_spec, low, high);
+    else
+        return false;
+}
+
+void
+Platform::SetLocalCacheDirectory (const char* local)
+{
+    m_local_cache_directory.assign(local);
+}
+
+const char*
+Platform::GetLocalCacheDirectory ()
+{
+    return m_local_cache_directory.c_str();
+}
+
+static OptionDefinition
+g_rsync_option_table[] =
+{
+    {   LLDB_OPT_SET_ALL, false, "rsync"                  , 'r', no_argument,       NULL, 0, eArgTypeNone         , "Enable rsync." },
+    {   LLDB_OPT_SET_ALL, false, "rsync-opts"             , 'R', required_argument, NULL, 0, eArgTypeCommandName  , "Platform-specific options required for rsync to work." },
+    {   LLDB_OPT_SET_ALL, false, "rsync-prefix"           , 'P', required_argument, NULL, 0, eArgTypeCommandName  , "Platform-specific rsync prefix put before the remote path." },
+    {   LLDB_OPT_SET_ALL, false, "ignore-remote-hostname" , 'i', no_argument,       NULL, 0, eArgTypeNone         , "Do not automatically fill in the remote hostname when composing the rsync command." },
+};
+
+static OptionDefinition
+g_ssh_option_table[] =
+{
+    {   LLDB_OPT_SET_ALL, false, "ssh"                    , 's', no_argument,       NULL, 0, eArgTypeNone         , "Enable SSH." },
+    {   LLDB_OPT_SET_ALL, false, "ssh-opts"               , 'S', required_argument, NULL, 0, eArgTypeCommandName  , "Platform-specific options required for SSH to work." },
+};
+
+static OptionDefinition
+g_caching_option_table[] =
+{
+    {   LLDB_OPT_SET_ALL, false, "local-cache-dir"        , 'c', required_argument, NULL, 0, eArgTypePath         , "Path in which to store local copies of files." },
+};
+
+OptionGroupPlatformRSync::OptionGroupPlatformRSync ()
+{
+}
+
+OptionGroupPlatformRSync::~OptionGroupPlatformRSync ()
+{
+}
+
+const lldb_private::OptionDefinition*
+OptionGroupPlatformRSync::GetDefinitions ()
+{
+    return g_rsync_option_table;
+}
+
+void
+OptionGroupPlatformRSync::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+    m_rsync = false;
+    m_rsync_opts.clear();
+    m_rsync_prefix.clear();
+    m_ignores_remote_hostname = false;
+}
+
+lldb_private::Error
+OptionGroupPlatformRSync::SetOptionValue (CommandInterpreter &interpreter,
+                uint32_t option_idx,
+                const char *option_arg)
+{
+    Error error;
+    char short_option = (char) GetDefinitions()[option_idx].short_option;
+    switch (short_option)
+    {
+        case 'r':
+            m_rsync = true;
+            break;
+            
+        case 'R':
+            m_rsync_opts.assign(option_arg);
+            break;
+            
+        case 'P':
+            m_rsync_prefix.assign(option_arg);
+            break;
+            
+        case 'i':
+            m_ignores_remote_hostname = true;
+            break;
+            
+        default:
+            error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+            break;
+    }
     
+    return error;
 }
 
+uint32_t
+OptionGroupPlatformRSync::GetNumDefinitions ()
+{
+    return llvm::array_lengthof(g_rsync_option_table);
+}
 
 lldb::BreakpointSP
 Platform::SetThreadCreationBreakpoint (lldb_private::Target &target)
@@ -770,10 +937,108 @@ Platform::SetThreadCreationBreakpoint (l
     return lldb::BreakpointSP();
 }
 
+OptionGroupPlatformSSH::OptionGroupPlatformSSH ()
+{
+}
+
+OptionGroupPlatformSSH::~OptionGroupPlatformSSH ()
+{
+}
+
+const lldb_private::OptionDefinition*
+OptionGroupPlatformSSH::GetDefinitions ()
+{
+    return g_ssh_option_table;
+}
+
+void
+OptionGroupPlatformSSH::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+    m_ssh = false;
+    m_ssh_opts.clear();
+}
+
+lldb_private::Error
+OptionGroupPlatformSSH::SetOptionValue (CommandInterpreter &interpreter,
+                                          uint32_t option_idx,
+                                          const char *option_arg)
+{
+    Error error;
+    char short_option = (char) GetDefinitions()[option_idx].short_option;
+    switch (short_option)
+    {
+        case 's':
+            m_ssh = true;
+            break;
+            
+        case 'S':
+            m_ssh_opts.assign(option_arg);
+            break;
+            
+        default:
+            error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+            break;
+    }
+    
+    return error;
+}
+
+uint32_t
+OptionGroupPlatformSSH::GetNumDefinitions ()
+{
+    return llvm::array_lengthof(g_ssh_option_table);
+}
+
+OptionGroupPlatformCaching::OptionGroupPlatformCaching ()
+{
+}
+
+OptionGroupPlatformCaching::~OptionGroupPlatformCaching ()
+{
+}
+
+const lldb_private::OptionDefinition*
+OptionGroupPlatformCaching::GetDefinitions ()
+{
+    return g_caching_option_table;
+}
+
+void
+OptionGroupPlatformCaching::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+    m_cache_dir.clear();
+}
+
+lldb_private::Error
+OptionGroupPlatformCaching::SetOptionValue (CommandInterpreter &interpreter,
+                                        uint32_t option_idx,
+                                        const char *option_arg)
+{
+    Error error;
+    char short_option = (char) GetDefinitions()[option_idx].short_option;
+    switch (short_option)
+    {
+        case 'c':
+            m_cache_dir.assign(option_arg);
+            break;
+            
+        default:
+            error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+            break;
+    }
+    
+    return error;
+}
+
+uint32_t
+OptionGroupPlatformCaching::GetNumDefinitions ()
+{
+    return llvm::array_lengthof(g_caching_option_table);
+}
+
 size_t
 Platform::GetEnvironment (StringList &environment)
 {
     environment.Clear();
     return false;
 }
-

Modified: lldb/trunk/source/Utility/StringExtractor.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/StringExtractor.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Utility/StringExtractor.cpp (original)
+++ lldb/trunk/source/Utility/StringExtractor.cpp Mon Aug 26 18:57:52 2013
@@ -168,10 +168,68 @@ StringExtractor::GetU32 (uint32_t fail_v
     {
         char *end = NULL;
         const char *start = m_packet.c_str();
-        const char *uint_cstr = start + m_index;
-        uint32_t result = ::strtoul (uint_cstr, &end, base);
+        const char *cstr = start + m_index;
+        uint32_t result = ::strtoul (cstr, &end, base);
 
-        if (end && end != uint_cstr)
+        if (end && end != cstr)
+        {
+            m_index = end - start;
+            return result;
+        }
+    }
+    return fail_value;
+}
+
+int32_t
+StringExtractor::GetS32 (int32_t fail_value, int base)
+{
+    if (m_index < m_packet.size())
+    {
+        char *end = NULL;
+        const char *start = m_packet.c_str();
+        const char *cstr = start + m_index;
+        int32_t result = ::strtol (cstr, &end, base);
+        
+        if (end && end != cstr)
+        {
+            m_index = end - start;
+            return result;
+        }
+    }
+    return fail_value;
+}
+
+
+uint64_t
+StringExtractor::GetU64 (uint64_t fail_value, int base)
+{
+    if (m_index < m_packet.size())
+    {
+        char *end = NULL;
+        const char *start = m_packet.c_str();
+        const char *cstr = start + m_index;
+        uint64_t result = ::strtoull (cstr, &end, base);
+        
+        if (end && end != cstr)
+        {
+            m_index = end - start;
+            return result;
+        }
+    }
+    return fail_value;
+}
+
+int64_t
+StringExtractor::GetS64 (int64_t fail_value, int base)
+{
+    if (m_index < m_packet.size())
+    {
+        char *end = NULL;
+        const char *start = m_packet.c_str();
+        const char *cstr = start + m_index;
+        int64_t result = ::strtoll (cstr, &end, base);
+        
+        if (end && end != cstr)
         {
             m_index = end - start;
             return result;
@@ -371,6 +429,20 @@ StringExtractor::GetHexByteString (std::
     return str.size();
 }
 
+size_t
+StringExtractor::GetHexByteStringTerminatedBy (std::string &str,
+                                               char terminator)
+{
+    str.clear();
+    char ch;
+    while ((ch = GetHexU8(0,false)) != '\0')
+        str.append(1, ch);
+    if (Peek() && *Peek() == terminator)
+        return str.size();
+    str.clear();
+    return str.size();
+}
+
 bool
 StringExtractor::GetNameColonValue (std::string &name, std::string &value)
 {

Modified: lldb/trunk/source/Utility/StringExtractor.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/StringExtractor.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Utility/StringExtractor.h (original)
+++ lldb/trunk/source/Utility/StringExtractor.h Mon Aug 26 18:57:52 2013
@@ -101,9 +101,18 @@ public:
     bool
     GetNameColonValue (std::string &name, std::string &value);
 
+    int32_t
+    GetS32 (int32_t fail_value, int base = 0);
+
     uint32_t
     GetU32 (uint32_t fail_value, int base = 0);
 
+    int64_t
+    GetS64 (int64_t fail_value, int base = 0);
+    
+    uint64_t
+    GetU64 (uint64_t fail_value, int base = 0);
+
     uint32_t
     GetHexMaxU32 (bool little_endian, uint32_t fail_value);
 
@@ -119,6 +128,10 @@ public:
     size_t
     GetHexByteString (std::string &str);
 
+    size_t
+    GetHexByteStringTerminatedBy (std::string &str,
+                                  char terminator);
+    
     const char *
     Peek ()
     {

Modified: lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp (original)
+++ lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp Mon Aug 26 18:57:52 2013
@@ -94,6 +94,9 @@ StringExtractorGDBRemote::GetServerPacke
             else if (PACKET_STARTS_WITH ("QSetSTDERR:"))        return eServerPacketType_QSetSTDERR;
             else if (PACKET_STARTS_WITH ("QSetWorkingDir:"))    return eServerPacketType_QSetWorkingDir;
             break;
+        case 'L':
+            if (PACKET_STARTS_WITH ("QLaunchArch:"))            return eServerPacketType_QLaunchArch;
+            break;
         }
         break;
             
@@ -120,14 +123,21 @@ StringExtractorGDBRemote::GetServerPacke
             if (PACKET_MATCHES ("qHostInfo"))                   return eServerPacketType_qHostInfo;
             break;
 
+        case 'K':
+            if (PACKET_STARTS_WITH ("qKillSpawnedProcess"))     return eServerPacketType_qKillSpawnedProcess;
+            break;
+        
         case 'L':
-            if (PACKET_MATCHES ("qLaunchGDBServer"))            return eServerPacketType_qLaunchGDBServer;
+            if (PACKET_STARTS_WITH ("qLaunchGDBServer"))        return eServerPacketType_qLaunchGDBServer;
             if (PACKET_MATCHES ("qLaunchSuccess"))              return eServerPacketType_qLaunchSuccess;
             break;
             
         case 'P':
-            if (PACKET_STARTS_WITH ("qProcessInfoPID:"))        return eServerPacketType_qProcessInfoPID;
+            if (PACKET_STARTS_WITH ("qProcessInfoPID:"))                 return eServerPacketType_qProcessInfoPID;
+            if (PACKET_STARTS_WITH ("qPlatform_RunCommand:"))            return eServerPacketType_qPlatform_RunCommand;
+            if (PACKET_STARTS_WITH ("qPlatform_IO_MkDir:"))              return eServerPacketType_qPlatform_IO_MkDir;
             break;
+                
 
         case 'S':
             if (PACKET_STARTS_WITH ("qSpeedTest:"))             return eServerPacketType_qSpeedTest;
@@ -138,6 +148,21 @@ StringExtractorGDBRemote::GetServerPacke
             break;
         }
         break;
+    case 'v':
+            if (PACKET_STARTS_WITH("vFile:"))
+            {
+                if (PACKET_STARTS_WITH("vFile:open:"))               return eServerPacketType_vFile_Open;
+                else if (PACKET_STARTS_WITH("vFile:close:"))         return eServerPacketType_vFile_Close;
+                else if (PACKET_STARTS_WITH("vFile:pread"))          return eServerPacketType_vFile_pRead;
+                else if (PACKET_STARTS_WITH("vFile:pwrite"))         return eServerPacketType_vFile_pWrite;
+                else if (PACKET_STARTS_WITH("vFile:size"))           return eServerPacketType_vFile_Size;
+                else if (PACKET_STARTS_WITH("vFile:exists"))         return eServerPacketType_vFile_Exists;
+                else if (PACKET_STARTS_WITH("vFile:stat"))           return eServerPacketType_vFile_Stat;
+                else if (PACKET_STARTS_WITH("vFile:mode"))           return eServerPacketType_vFile_Mode;
+                else if (PACKET_STARTS_WITH("vFile:MD5"))            return eServerPacketType_vFile_MD5;
+
+            }
+            break;
     }
     return eServerPacketType_unimplemented;
 }
@@ -180,3 +205,19 @@ StringExtractorGDBRemote::GetError ()
     }
     return 0;
 }
+
+size_t
+StringExtractorGDBRemote::GetEscapedBinaryData (std::string &str)
+{
+    str.clear();
+    char ch;
+    while (GetBytesLeft())
+    {
+        ch = GetChar();
+        if (ch == 0x7d)
+            ch = (GetChar() ^ 0x20);
+        str.append(1,ch);
+    }
+    return str.size();
+}
+

Modified: lldb/trunk/source/Utility/StringExtractorGDBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/StringExtractorGDBRemote.h?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/Utility/StringExtractorGDBRemote.h (original)
+++ lldb/trunk/source/Utility/StringExtractorGDBRemote.h Mon Aug 26 18:57:52 2013
@@ -53,17 +53,30 @@ public:
         eServerPacketType_qGroupName,
         eServerPacketType_qHostInfo,
         eServerPacketType_qLaunchGDBServer,
+        eServerPacketType_qKillSpawnedProcess,
         eServerPacketType_qLaunchSuccess,
         eServerPacketType_qProcessInfoPID,
         eServerPacketType_qSpeedTest,
         eServerPacketType_qUserName,
         eServerPacketType_QEnvironment,
+        eServerPacketType_QLaunchArch,
         eServerPacketType_QSetDisableASLR,
         eServerPacketType_QSetSTDIN,
         eServerPacketType_QSetSTDOUT,
         eServerPacketType_QSetSTDERR,
         eServerPacketType_QSetWorkingDir,
-        eServerPacketType_QStartNoAckMode
+        eServerPacketType_QStartNoAckMode,
+        eServerPacketType_qPlatform_RunCommand,
+        eServerPacketType_qPlatform_IO_MkDir,
+        eServerPacketType_vFile_Open,
+        eServerPacketType_vFile_Close,
+        eServerPacketType_vFile_pRead,
+        eServerPacketType_vFile_pWrite,
+        eServerPacketType_vFile_Size,
+        eServerPacketType_vFile_Mode,
+        eServerPacketType_vFile_Exists,
+        eServerPacketType_vFile_MD5,
+        eServerPacketType_vFile_Stat
     };
     
     ServerPacketType
@@ -98,6 +111,10 @@ public:
     // digits. Otherwise the error encoded in XX is returned.
     uint8_t
     GetError();
+    
+    size_t
+    GetEscapedBinaryData (std::string &str);
+
 };
 
 #endif  // utility_StringExtractorGDBRemote_h_

Modified: lldb/trunk/source/lldb-log.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/lldb-log.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/lldb-log.cpp (original)
+++ lldb/trunk/source/lldb-log.cpp Mon Aug 26 18:57:52 2013
@@ -126,6 +126,7 @@ lldb_private::DisableLog (const char **c
                 else if (0 == ::strncasecmp(arg, "expr", 4))    flag_bits &= ~LIBLLDB_LOG_EXPRESSIONS;
                 else if (0 == ::strncasecmp(arg, "object", 6))  flag_bits &= ~LIBLLDB_LOG_OBJECT;
                 else if (0 == ::strcasecmp(arg, "process"))     flag_bits &= ~LIBLLDB_LOG_PROCESS;
+                else if (0 == ::strcasecmp(arg, "platform"))    flag_bits &= ~LIBLLDB_LOG_PLATFORM;
                 else if (0 == ::strcasecmp(arg, "script"))      flag_bits &= ~LIBLLDB_LOG_SCRIPT;
                 else if (0 == ::strcasecmp(arg, "state"))       flag_bits &= ~LIBLLDB_LOG_STATE;
                 else if (0 == ::strcasecmp(arg, "step"))        flag_bits &= ~LIBLLDB_LOG_STEP;
@@ -196,6 +197,7 @@ lldb_private::EnableLog (StreamSP &log_s
             else if (0 == ::strncasecmp(arg, "expr", 4))    flag_bits |= LIBLLDB_LOG_EXPRESSIONS;
             else if (0 == ::strncasecmp(arg, "object", 6))  flag_bits |= LIBLLDB_LOG_OBJECT;
             else if (0 == ::strcasecmp(arg, "process"))     flag_bits |= LIBLLDB_LOG_PROCESS;
+            else if (0 == ::strcasecmp(arg, "platform"))    flag_bits |= LIBLLDB_LOG_PLATFORM;
             else if (0 == ::strcasecmp(arg, "script"))      flag_bits |= LIBLLDB_LOG_SCRIPT;
             else if (0 == ::strcasecmp(arg, "state"))       flag_bits |= LIBLLDB_LOG_STATE;
             else if (0 == ::strcasecmp(arg, "step"))        flag_bits |= LIBLLDB_LOG_STEP;
@@ -244,6 +246,7 @@ lldb_private::ListLogCategories (Stream
                  "  object - log object construction/destruction for important objects\n"
                  "  module - log module activities such as when modules are created, detroyed, replaced, and more\n"
                  "  process - log process events and activities\n"
+                 "  platform - log platform events and activities\n"
                  "  script - log events about the script interpreter\n"
                  "  state - log private and public process state changes\n"
                  "  step - log step related activities\n"

Modified: lldb/trunk/source/lldb.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/lldb.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/source/lldb.cpp (original)
+++ lldb/trunk/source/lldb.cpp Mon Aug 26 18:57:52 2013
@@ -42,6 +42,7 @@
 #include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
 #include "Plugins/Platform/FreeBSD/PlatformFreeBSD.h"
 #include "Plugins/Platform/Linux/PlatformLinux.h"
+#include "Plugins/Platform/POSIX/PlatformPOSIX.h"
 #include "Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h"
 #ifndef LLDB_DISABLE_PYTHON
 #include "Plugins/OperatingSystem/Python/OperatingSystemPython.h"

Modified: lldb/trunk/test/api/check_public_api_headers/TestPublicAPIHeaders.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/api/check_public_api_headers/TestPublicAPIHeaders.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/api/check_public_api_headers/TestPublicAPIHeaders.py (original)
+++ lldb/trunk/test/api/check_public_api_headers/TestPublicAPIHeaders.py Mon Aug 26 18:57:52 2013
@@ -22,6 +22,9 @@ class SBDirCheckerCase(TestBase):
     def test_sb_api_directory(self):
         """Test the SB API directory and make sure there's no unwanted stuff."""
 
+        # Only proceed if this is "darwin", "x86_64", and local platform.
+        if not (sys.platform.startswith("darwin") and self.getArchitecture() == "x86_64" and not lldb.test_remote):
+            self.skipTest("This test is only for LLDB.framework built 64-bit and !lldb.test_remote")
         if self.getArchitecture() == "i386":
             self.skipTest("LLDB is 64-bit and cannot be linked to 32-bit test program.")
 

Modified: lldb/trunk/test/api/multithreaded/TestMultithreaded.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/api/multithreaded/TestMultithreaded.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/api/multithreaded/TestMultithreaded.py (original)
+++ lldb/trunk/test/api/multithreaded/TestMultithreaded.py Mon Aug 26 18:57:52 2013
@@ -61,12 +61,13 @@ class SBBreakpointCallbackCase(TestBase)
 
         exe = [os.path.join(os.getcwd(), test_name), self.inferior]
 
+        env = {self.dylibPath : self.getLLDBLibraryEnvVal()}
         if self.TraceOn():
             print "Running test %s" % " ".join(exe)
-
-        check_call(exe, env={self.dylibPath : self.getLLDBLibraryEnvVal()})
-
-
+            check_call(exe, env=env)
+        else:
+            with open(os.devnull, 'w') as fnull:
+                check_call(exe, env=env, stdout=fnull, stderr=fnull)
 
     def build_program(self, sources, program):
         return self.buildDriver(sources, program)

Modified: lldb/trunk/test/dotest.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/dotest.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/dotest.py (original)
+++ lldb/trunk/test/dotest.py Mon Aug 26 18:57:52 2013
@@ -154,6 +154,9 @@ config = {}
 # The pre_flight and post_flight functions come from reading a config file.
 pre_flight = None
 post_flight = None
+# So do the lldbtest_remote_sandbox and lldbtest_remote_shell_template variables.
+lldbtest_remote_sandbox = None
+lldbtest_remote_shell_template = None
 
 # The 'archs' and 'compilers' can be specified via either command line or configFile,
 # with the command line overriding the configFile.  The corresponding options can be
@@ -745,11 +748,11 @@ def parseOptionsAndInitTestdirs():
     # respectively.
     #
     # See also lldb-trunk/examples/test/usage-config.
-    global config, pre_flight, post_flight
+    global config, pre_flight, post_flight, lldbtest_remote_sandbox, lldbtest_remote_shell_template
     if configFile:
         # Pass config (a dictionary) as the locals namespace for side-effect.
         execfile(configFile, globals(), config)
-        print "config:", config
+        #print "config:", config
         if "pre_flight" in config:
             pre_flight = config["pre_flight"]
             if not callable(pre_flight):
@@ -760,6 +763,10 @@ def parseOptionsAndInitTestdirs():
             if not callable(post_flight):
                 print "fatal error: post_flight is not callable, exiting."
                 sys.exit(1)
+        if "lldbtest_remote_sandbox" in config:
+            lldbtest_remote_sandbox = config["lldbtest_remote_sandbox"]
+        if "lldbtest_remote_shell_template" in config:
+            lldbtest_remote_shell_template = config["lldbtest_remote_shell_template"]
         #print "sys.stderr:", sys.stderr
         #print "sys.stdout:", sys.stdout
 
@@ -1199,6 +1206,17 @@ if not noHeaders:
     print "lldb.pre_flight:", getsource_if_available(lldb.pre_flight)
     print "lldb.post_flight:", getsource_if_available(lldb.post_flight)
 
+# If either pre_flight or post_flight is defined, set lldb.test_remote to True.
+if lldb.pre_flight or lldb.post_flight:
+    lldb.test_remote = True
+else:
+    lldb.test_remote = False
+
+# So do the lldbtest_remote_sandbox and lldbtest_remote_shell_template variables.
+lldb.lldbtest_remote_sandbox = lldbtest_remote_sandbox
+lldb.lldbtest_remote_sandboxed_executable = None
+lldb.lldbtest_remote_shell_template = lldbtest_remote_shell_template
+
 # Put all these test decorators in the lldb namespace.
 lldb.dont_do_python_api_test = dont_do_python_api_test
 lldb.just_do_python_api_test = just_do_python_api_test

Modified: lldb/trunk/test/functionalities/abbreviation/TestAbbreviations.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/abbreviation/TestAbbreviations.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/abbreviation/TestAbbreviations.py (original)
+++ lldb/trunk/test/functionalities/abbreviation/TestAbbreviations.py Mon Aug 26 18:57:52 2013
@@ -90,7 +90,10 @@ class AbbreviationsTestCase(TestBase):
 
     def running_abbreviations (self):
         exe = os.path.join (os.getcwd(), "a.out")
-        self.expect("fil " + exe,
+        # Use "file", i.e., no abbreviation.  We're exactly matching the command
+        # verbatim when dealing with remote testsuite execution.
+        # For more details, see TestBase.runCmd().
+        self.expect("file " + exe,
                     patterns = [ "Current executable set to .*a.out.*" ])
 
         # By default, the setting interpreter.expand-regex-aliases is false.

Modified: lldb/trunk/test/functionalities/conditional_break/.lldb
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/conditional_break/.lldb?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/conditional_break/.lldb (original)
+++ lldb/trunk/test/functionalities/conditional_break/.lldb Mon Aug 26 18:57:52 2013
@@ -1,4 +1,4 @@
-file a.out
+#file a.out
 breakpoint set -n c
 #script import sys, os
 #script sys.path.append(os.path.join(os.getcwd(), os.pardir))

Modified: lldb/trunk/test/functionalities/conditional_break/TestConditionalBreak.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/conditional_break/TestConditionalBreak.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/conditional_break/TestConditionalBreak.py (original)
+++ lldb/trunk/test/functionalities/conditional_break/TestConditionalBreak.py Mon Aug 26 18:57:52 2013
@@ -114,6 +114,10 @@ class ConditionalBreakTestCase(TestBase)
 
         if not self.TraceOn():
             self.HideStdout()
+
+        # Separate out the "file a.out" command from .lldb file, for the sake of
+        # remote testsuite.
+        self.runCmd("file a.out")
         self.runCmd("command source .lldb")
 
         self.runCmd ("break list")

Modified: lldb/trunk/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py (original)
+++ lldb/trunk/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py Mon Aug 26 18:57:52 2013
@@ -447,7 +447,7 @@ class ObjCDataFormatterTestCase(TestBase
         self.expect('frame variable bundle_string bundle_url main_bundle',
                     substrs = ['(NSBundle *) bundle_string = ',' @"/System/Library/Frameworks/Accelerate.framework"',
                     '(NSBundle *) bundle_url = ',' @"/System/Library/Frameworks/Cocoa.framework"',
-                    '(NSBundle *) main_bundle = ','test/functionalities/data-formatter/data-formatter-objc'])
+                    '(NSBundle *) main_bundle = ','data-formatter-objc'])
 
     def nsexception_data_formatter_commands(self):
         self.expect('frame variable except0 except1 except2 except3',

Modified: lldb/trunk/test/functionalities/inferior-changed/TestInferiorChanged.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/inferior-changed/TestInferiorChanged.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/inferior-changed/TestInferiorChanged.py (original)
+++ lldb/trunk/test/functionalities/inferior-changed/TestInferiorChanged.py Mon Aug 26 18:57:52 2013
@@ -44,8 +44,8 @@ class ChangedInferiorTestCase(TestBase):
 
     def inferior_crashing(self):
         """Inferior crashes upon launching; lldb should catch the event and stop."""
-        exe = os.path.join(os.getcwd(), "a.out")
-        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+        self.exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + self.exe, CURRENT_EXECUTABLE_SET)
 
         self.runCmd("run", RUN_SUCCEEDED)
 
@@ -67,6 +67,9 @@ class ChangedInferiorTestCase(TestBase):
     def inferior_not_crashing(self):
         """Test lldb reloads the inferior after it was changed during the session."""
         self.runCmd("process kill")
+        # Prod the lldb-platform that we have a newly built inferior ready.
+        if lldb.lldbtest_remote_sandbox:
+            self.runCmd("file " + self.exe, CURRENT_EXECUTABLE_SET)
         self.runCmd("run", RUN_SUCCEEDED)
         self.runCmd("process status")
 

Modified: lldb/trunk/test/functionalities/load_unload/TestLoadUnload.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/load_unload/TestLoadUnload.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/load_unload/TestLoadUnload.py (original)
+++ lldb/trunk/test/functionalities/load_unload/TestLoadUnload.py Mon Aug 26 18:57:52 2013
@@ -27,6 +27,7 @@ class LoadUnloadTestCase(TestBase):
 
     @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
     @skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
+    @not_remote_testsuite_ready
     def test_modules_search_paths(self):
         """Test target modules list after loading a different copy of the library libd.dylib, and verifies that it works with 'target modules search-paths add'."""
 
@@ -81,6 +82,7 @@ class LoadUnloadTestCase(TestBase):
 
     @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
     @skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
+    @not_remote_testsuite_ready
     def test_dyld_library_path(self):
         """Test DYLD_LIBRARY_PATH after moving libd.dylib, which defines d_function, somewhere else."""
 
@@ -135,6 +137,7 @@ class LoadUnloadTestCase(TestBase):
             substrs = [special_dir, os.path.basename(new_dylib)])
 
     @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
+    @not_remote_testsuite_ready
     @skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
     def test_lldb_process_load_and_unload_commands(self):
         """Test that lldb process load/unload command work correctly."""
@@ -183,6 +186,7 @@ class LoadUnloadTestCase(TestBase):
         self.runCmd("process continue")
 
     @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
+    @not_remote_testsuite_ready
     @skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
     def test_load_unload(self):
         """Test breakpoint by name works correctly with dlopen'ing."""
@@ -224,6 +228,7 @@ class LoadUnloadTestCase(TestBase):
             substrs = [' resolved, hit count = 2'])
 
     @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
+    @not_remote_testsuite_ready
     @skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
     def test_step_over_load (self):
         """Test stepping over code that loads a shared library works correctly."""

Modified: lldb/trunk/test/functionalities/process_launch/TestProcessLaunch.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/process_launch/TestProcessLaunch.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/process_launch/TestProcessLaunch.py (original)
+++ lldb/trunk/test/functionalities/process_launch/TestProcessLaunch.py Mon Aug 26 18:57:52 2013
@@ -31,6 +31,7 @@ class ProcessLaunchTestCase(TestBase):
         self.buildDwarf ()
         self.process_io_test ()
 
+    @not_remote_testsuite_ready
     def process_io_test (self):
         """Test that process launch I/O redirection flags work properly."""
         exe = os.path.join (os.getcwd(), "a.out")
@@ -127,6 +128,7 @@ class ProcessLaunchTestCase(TestBase):
 
     # rdar://problem/9056462
     # The process launch flag '-w' for setting the current working directory not working?
+    @not_remote_testsuite_ready
     def my_working_dir_test (self):
         """Test that '-w dir' sets the working dir when running the inferior."""
         exe = os.path.join (os.getcwd(), "a.out")

Modified: lldb/trunk/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py Mon Aug 26 18:57:52 2013
@@ -90,15 +90,13 @@ class HelloWatchLocationTestCase(TestBas
         # only once.  The stop reason of the thread should be watchpoint.
         self.expect("thread list", STOPPED_DUE_TO_WATCHPOINT,
             substrs = ['stopped',
-                       'stop reason = watchpoint %d' % expected_wp_id,
-                       self.violating_func])
+                       'stop reason = watchpoint %d' % expected_wp_id])
 
         # Switch to the thread stopped due to watchpoint and issue some commands.
         self.switch_to_thread_with_stop_reason(lldb.eStopReasonWatchpoint)
         self.runCmd("thread backtrace")
-        self.runCmd("expr unsigned val = *g_char_ptr; val")
-        self.expect(self.res.GetOutput().splitlines()[0], exe=False,
-            endstr = ' = 1')
+        self.expect("frame info",
+            substrs = [self.violating_func])
 
         # Use the '-v' option to do verbose listing of the watchpoint.
         # The hit count should now be 1.

Modified: lldb/trunk/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py Mon Aug 26 18:57:52 2013
@@ -80,10 +80,11 @@ class HelloWatchpointTestCase(TestBase):
                        'stop reason = watchpoint'])
 
         self.runCmd("process continue")
+
         # Don't expect the read of 'global' to trigger a stop exception.
-        # The process status should be 'exited'.
-        self.expect("process status",
-            substrs = ['exited'])
+        process = self.dbg.GetSelectedTarget().GetProcess()
+        if process.GetState() == lldb.eStateStopped:
+            self.assertFalse(lldbutil.get_stopped_thread(process, lldb.eStopReasonWatchpoint))
 
         # Use the '-v' option to do verbose listing of the watchpoint.
         # The hit count should now be 1.

Modified: lldb/trunk/test/lang/c/blocks/TestBlocks.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/c/blocks/TestBlocks.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/lang/c/blocks/TestBlocks.py (original)
+++ lldb/trunk/test/lang/c/blocks/TestBlocks.py Mon Aug 26 18:57:52 2013
@@ -6,7 +6,7 @@ import lldb
 from lldbtest import *
 import lldbutil
 
-class AnonymousTestCase(TestBase):
+class BlocksTestCase(TestBase):
 
     mydir = os.path.join("lang", "c", "blocks")
     lines = []

Modified: lldb/trunk/test/lldbtest.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lldbtest.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/lldbtest.py (original)
+++ lldb/trunk/test/lldbtest.py Mon Aug 26 18:57:52 2013
@@ -373,6 +373,23 @@ def dwarf_test(func):
     wrapper.__dwarf_test__ = True
     return wrapper
 
+def not_remote_testsuite_ready(func):
+    """Decorate the item as a test which is not ready yet for remote testsuite."""
+    if isinstance(func, type) and issubclass(func, unittest2.TestCase):
+        raise Exception("@not_remote_testsuite_ready can only be used to decorate a test method")
+    @wraps(func)
+    def wrapper(self, *args, **kwargs):
+        try:
+            if lldb.lldbtest_remote_sandbox:
+                self.skipTest("not ready for remote testsuite")
+        except AttributeError:
+            pass
+        return func(self, *args, **kwargs)
+
+    # Mark this function as such to separate them from the regular tests.
+    wrapper.__not_ready_for_remote_testsuite_test__ = True
+    return wrapper
+
 def expectedFailureGcc(bugnumber=None, compiler_version=["=", None]):
      if callable(bugnumber):
         @wraps(bugnumber)
@@ -1556,6 +1573,31 @@ class TestBase(Base):
         if not self.dbg:
             raise Exception('Invalid debugger instance')
 
+        #
+        # Warning: MAJOR HACK AHEAD!
+        # If we are running testsuite remotely (by checking lldb.lldbtest_remote_sandbox),
+        # redefine the self.dbg.CreateTarget(filename) method to execute a "file filename"
+        # command, instead.  See also runCmd() where it decorates the "file filename" call
+        # with additional functionality when running testsuite remotely.
+        #
+        if lldb.lldbtest_remote_sandbox:
+            def DecoratedCreateTarget(arg):
+                self.runCmd("file %s" % arg)
+                target = self.dbg.GetSelectedTarget()
+                #
+                # SBTarget.LaunchSimple() currently not working for remote platform?
+                # johnny @ 04/23/2012
+                #
+                def DecoratedLaunchSimple(argv, envp, wd):
+                    self.runCmd("run")
+                    return target.GetProcess()
+                target.LaunchSimple = DecoratedLaunchSimple
+
+                return target
+            self.dbg.CreateTarget = DecoratedCreateTarget
+            if self.TraceOn():
+                print "self.dbg.Create is redefined to:\n%s" % getsource_if_available(DecoratedCreateTarget)
+
         # We want our debugger to be synchronous.
         self.dbg.SetAsync(False)
 
@@ -1645,6 +1687,38 @@ class TestBase(Base):
 
         trace = (True if traceAlways else trace)
 
+        # This is an opportunity to insert the 'platform target-install' command if we are told so
+        # via the settig of lldb.lldbtest_remote_sandbox.
+        if cmd.startswith("target create "):
+            cmd = cmd.replace("target create ", "file ")
+        if cmd.startswith("file ") and lldb.lldbtest_remote_sandbox:
+            with recording(self, trace) as sbuf:
+                the_rest = cmd.split("file ")[1]
+                # Split the rest of the command line.
+                atoms = the_rest.split()
+                #
+                # NOTE: This assumes that the options, if any, follow the file command,
+                # instead of follow the specified target.
+                #
+                target = atoms[-1]
+                # Now let's get the absolute pathname of our target.
+                abs_target = os.path.abspath(target)
+                print >> sbuf, "Found a file command, target (with absolute pathname)=%s" % abs_target
+                fpath, fname = os.path.split(abs_target)
+                parent_dir = os.path.split(fpath)[0]
+                platform_target_install_command = 'platform target-install %s %s' % (fpath, lldb.lldbtest_remote_sandbox)
+                print >> sbuf, "Insert this command to be run first: %s" % platform_target_install_command
+                self.ci.HandleCommand(platform_target_install_command, self.res)
+                # And this is the file command we want to execute, instead.
+                #
+                # Warning: SIDE EFFECT AHEAD!!!
+                # Populate the remote executable pathname into the lldb namespace,
+                # so that test cases can grab this thing out of the namespace.
+                #
+                lldb.lldbtest_remote_sandboxed_executable = abs_target.replace(parent_dir, lldb.lldbtest_remote_sandbox)
+                cmd = "file -P %s %s %s" % (lldb.lldbtest_remote_sandboxed_executable, the_rest.replace(target, ''), abs_target)
+                print >> sbuf, "And this is the replaced file command: %s" % cmd
+
         running = (cmd.startswith("run") or cmd.startswith("process launch"))
 
         for i in range(self.maxLaunchCount if running else 1):

Modified: lldb/trunk/test/macosx/universal/TestUniversal.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/macosx/universal/TestUniversal.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/macosx/universal/TestUniversal.py (original)
+++ lldb/trunk/test/macosx/universal/TestUniversal.py Mon Aug 26 18:57:52 2013
@@ -35,7 +35,6 @@ class UniversalTestCase(TestBase):
         process = target.LaunchSimple(None, None, os.getcwd())
         self.assertTrue(process, PROCESS_IS_VALID)
 
-    # rdar://problem/8972204 AddressByteSize of 32-bit process should be 4, got 8 instead.
     @unittest2.skipUnless(sys.platform.startswith("darwin") and os.uname()[4] in ['i386', 'x86_64'],
                           "requires Darwin & i386")
     def test_process_launch_for_universal(self):
@@ -74,7 +73,7 @@ class UniversalTestCase(TestBase):
         self.runCmd("continue")
 
         # Now specify i386 as the architecture for "testit".
-        self.expect("file " + exe + " -a i386", CURRENT_EXECUTABLE_SET,
+        self.expect("file -a i386 " + exe, CURRENT_EXECUTABLE_SET,
             startstr = "Current executable set to ",
             substrs = ["testit' (i386)."])
 

Modified: lldb/trunk/test/python_api/hello_world/TestHelloWorld.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/python_api/hello_world/TestHelloWorld.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/python_api/hello_world/TestHelloWorld.py (original)
+++ lldb/trunk/test/python_api/hello_world/TestHelloWorld.py Mon Aug 26 18:57:52 2013
@@ -33,6 +33,7 @@ class HelloWorldTestCase(TestBase):
         self.setTearDownCleanup(dictionary=self.d)
         self.hello_world_python()
 
+    @not_remote_testsuite_ready
     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     @python_api_test
     @dsym_test
@@ -45,6 +46,7 @@ class HelloWorldTestCase(TestBase):
         self.setTearDownCleanup(dictionary=self.d)
         self.hello_world_attach_with_id_api()
 
+    @not_remote_testsuite_ready
     @python_api_test
     @dwarf_test
     def test_with_dwarf_and_attach_to_process_with_id_api(self):
@@ -56,6 +58,7 @@ class HelloWorldTestCase(TestBase):
         self.setTearDownCleanup(dictionary=self.d)
         self.hello_world_attach_with_id_api()
 
+    @not_remote_testsuite_ready
     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     @python_api_test
     @dsym_test
@@ -69,6 +72,7 @@ class HelloWorldTestCase(TestBase):
         self.hello_world_attach_with_name_api()
 
     @expectedFailureFreeBSD('llvm.org/pr16699') # attach by name not on FreeBSD yet
+    @not_remote_testsuite_ready
     @python_api_test
     @dwarf_test
     def test_with_dwarf_and_attach_to_process_with_name_api(self):

Modified: lldb/trunk/test/python_api/process/TestProcessAPI.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/python_api/process/TestProcessAPI.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/python_api/process/TestProcessAPI.py (original)
+++ lldb/trunk/test/python_api/process/TestProcessAPI.py Mon Aug 26 18:57:52 2013
@@ -78,7 +78,6 @@ class ProcessAPITestCase(TestBase):
     def read_memory(self):
         """Test Python SBProcess.ReadMemory() API."""
         exe = os.path.join(os.getcwd(), "a.out")
-        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
 
         target = self.dbg.CreateTarget(exe)
         self.assertTrue(target, VALID_TARGET)
@@ -160,7 +159,6 @@ class ProcessAPITestCase(TestBase):
     def write_memory(self):
         """Test Python SBProcess.WriteMemory() API."""
         exe = os.path.join(os.getcwd(), "a.out")
-        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
 
         target = self.dbg.CreateTarget(exe)
         self.assertTrue(target, VALID_TARGET)
@@ -211,7 +209,6 @@ class ProcessAPITestCase(TestBase):
     def access_my_int(self):
         """Test access 'my_int' using Python SBProcess.GetByteOrder() and other APIs."""
         exe = os.path.join(os.getcwd(), "a.out")
-        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
 
         target = self.dbg.CreateTarget(exe)
         self.assertTrue(target, VALID_TARGET)
@@ -300,7 +297,6 @@ class ProcessAPITestCase(TestBase):
     def remote_launch_should_fail(self):
         """Test SBProcess.RemoteLaunch() API with a process not in eStateConnected, and it should fail."""
         exe = os.path.join(os.getcwd(), "a.out")
-        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
 
         target = self.dbg.CreateTarget(exe)
         self.assertTrue(target, VALID_TARGET)

Modified: lldb/trunk/test/python_api/target/TestTargetAPI.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/python_api/target/TestTargetAPI.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/python_api/target/TestTargetAPI.py (original)
+++ lldb/trunk/test/python_api/target/TestTargetAPI.py Mon Aug 26 18:57:52 2013
@@ -195,7 +195,7 @@ class TargetAPITestCase(TestBase):
         self.expect(desc, exe=False,
             substrs = ['a.out', 'Target', 'Module', 'Breakpoint'])
 
-
+    @not_remote_testsuite_ready
     def launch_new_process_and_redirect_stdout(self):
         """Exercise SBTaget.Launch() API with redirected stdout."""
         exe = os.path.join(os.getcwd(), "a.out")

Modified: lldb/trunk/test/settings/TestSettings.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/settings/TestSettings.py?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/test/settings/TestSettings.py (original)
+++ lldb/trunk/test/settings/TestSettings.py Mon Aug 26 18:57:52 2013
@@ -205,6 +205,7 @@ class SettingsCommandTestCase(TestBase):
         self.buildDwarf()
         self.pass_run_args_and_env_vars()
 
+    @not_remote_testsuite_ready
     def pass_run_args_and_env_vars(self):
         """Test that run-args and env-vars are passed to the launched process."""
         exe = os.path.join(os.getcwd(), "a.out")
@@ -231,6 +232,7 @@ class SettingsCommandTestCase(TestBase):
                        "argv[3] matches",
                        "Environment variable 'MY_ENV_VAR' successfully passed."])
 
+    @not_remote_testsuite_ready
     def test_pass_host_env_vars(self):
         """Test that the host env vars are passed to the launched process."""
         self.buildDefault()
@@ -262,6 +264,7 @@ class SettingsCommandTestCase(TestBase):
             substrs = ["The host environment variable 'MY_HOST_ENV_VAR1' successfully passed.",
                        "The host environment variable 'MY_HOST_ENV_VAR2' successfully passed."])
 
+    @not_remote_testsuite_ready
     def test_set_error_output_path(self):
         """Test that setting target.error/output-path for the launched process works."""
         self.buildDefault()

Modified: lldb/trunk/tools/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/CMakeLists.txt?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/tools/CMakeLists.txt (original)
+++ lldb/trunk/tools/CMakeLists.txt Mon Aug 26 18:57:52 2013
@@ -3,5 +3,5 @@ if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
 endif()
 if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
   add_subdirectory(driver)
+  add_subdirectory(lldb-platform)
 endif()
-

Modified: lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj Mon Aug 26 18:57:52 2013
@@ -606,7 +606,7 @@
 				CLANG_CXX_LIBRARY = "libc++";
 				"CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "source/debugserver-entitlements.plist";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
-				"CODE_SIGN_IDENTITY[sdk=macosx*]" = lldb_codesign;
+				"CODE_SIGN_IDENTITY[sdk=macosx*]" = "";
 				COPY_PHASE_STRIP = YES;
 				CURRENT_PROJECT_VERSION = 310.99.0;
 				FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks;

Added: lldb/trunk/tools/lldb-platform/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-platform/CMakeLists.txt?rev=189295&view=auto
==============================================================================
--- lldb/trunk/tools/lldb-platform/CMakeLists.txt (added)
+++ lldb/trunk/tools/lldb-platform/CMakeLists.txt Mon Aug 26 18:57:52 2013
@@ -0,0 +1,14 @@
+set(LLVM_NO_RTTI 1)
+
+include_directories(../../source)
+
+add_lldb_executable(lldb-platform
+  lldb-platform.cpp
+  )
+
+target_link_libraries(lldb-platform liblldb)
+
+set_target_properties(lldb-platform PROPERTIES VERSION ${LLDB_VERSION})
+
+install(TARGETS lldb-platform
+  RUNTIME DESTINATION bin)

Modified: lldb/trunk/tools/lldb-platform/lldb-platform.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-platform/lldb-platform.cpp?rev=189295&r1=189294&r2=189295&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-platform/lldb-platform.cpp (original)
+++ lldb/trunk/tools/lldb-platform/lldb-platform.cpp Mon Aug 26 18:57:52 2013
@@ -37,11 +37,13 @@ using namespace lldb_private;
 
 int g_debug = 0;
 int g_verbose = 0;
+int g_stay_alive = 0;
 
 static struct option g_long_options[] =
 {
     { "debug",              no_argument,        &g_debug,           1   },
     { "verbose",            no_argument,        &g_verbose,         1   },
+    { "stay-alive",         no_argument,        &g_stay_alive,      1   },
     { "log-file",           required_argument,  NULL,               'l' },
     { "log-flags",          required_argument,  NULL,               'f' },
     { "listen",             required_argument,  NULL,               'L' },
@@ -60,16 +62,32 @@ signal_handler(int signo)
     case SIGPIPE:
         g_sigpipe_received = 1;
         break;
+    case SIGHUP:
+        // Use SIGINT first, if that does not work, use SIGHUP as a last resort.
+        // And we should not call exit() here because it results in the global destructors
+        // to be invoked and wreaking havoc on the threads still running.
+        Host::SystemLog(Host::eSystemLogWarning, "SIGHUP received, exiting lldb-platform...\n");
+        abort();
+        break;
     }
 }
 
+static void
+display_usage (const char *progname)
+{
+    fprintf(stderr, "Usage:\n  %s [--log-file log-file-path] [--log-flags flags] --listen port\n", progname);
+    exit(0);
+}
+
 //----------------------------------------------------------------------
 // main
 //----------------------------------------------------------------------
 int
 main (int argc, char *argv[])
 {
+    const char *progname = argv[0];
     signal (SIGPIPE, signal_handler);
+    signal (SIGHUP, signal_handler);
     int long_option_index = 0;
     StreamSP log_stream_sp;
     Args log_args;
@@ -167,8 +185,16 @@ main (int argc, char *argv[])
         case 'L':
             listen_host_port.append (optarg);
             break;
+
+        case 'h':   /* fall-through is intentional */
+        case '?':
+            display_usage(progname);
+            break;
         }
     }
+    // Print usage and exit if no listening port is specified.
+    if (listen_host_port.empty())
+        display_usage(progname);
     
     if (log_stream_sp)
     {
@@ -182,50 +208,63 @@ main (int argc, char *argv[])
     argv += optind;
 
 
-    GDBRemoteCommunicationServer gdb_server (true);
-    if (!listen_host_port.empty())
-    {
-        std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
-        if (conn_ap.get())
+    do {
+        GDBRemoteCommunicationServer gdb_server (true);
+        if (!listen_host_port.empty())
         {
-            std::string connect_url ("listen://");
-            connect_url.append(listen_host_port.c_str());
-
-            printf ("Listening for a connection on %s...\n", listen_host_port.c_str());
-            if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
+            std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+            if (conn_ap.get())
             {
-                printf ("Connection established.\n");
-                gdb_server.SetConnection (conn_ap.release());
-            }
-        }
-    }
-
+                for (int j = 0; j < listen_host_port.size(); j++)
+                {
+                    char c = listen_host_port[j];
+                    if (c > '9' || c < '0')
+                        printf("WARNING: passing anything but a number as argument to --listen will most probably make connecting impossible.\n");
+                }
+                std::auto_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+                if (conn_ap.get())
+                {
+                    std::string connect_url ("listen://");
+                    connect_url.append(listen_host_port.c_str());
 
-    if (gdb_server.IsConnected())
-    {
-        // After we connected, we need to get an initial ack from...
-        if (gdb_server.HandshakeWithClient(&error))
-        {
-            bool interrupt = false;
-            bool done = false;
-            while (!interrupt && !done)
-            {
-                if (!gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done))
-                    break;
+                    printf ("Listening for a connection on %s...\n", listen_host_port.c_str());
+                    if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
+                    {
+                        printf ("Connection established.\n");
+                        gdb_server.SetConnection (conn_ap.release());
+                    }
+                }
             }
-            
-            if (error.Fail())
+
+            if (gdb_server.IsConnected())
             {
-                fprintf(stderr, "error: %s\n", error.AsCString());
+                // After we connected, we need to get an initial ack from...
+                if (gdb_server.HandshakeWithClient(&error))
+                {
+                    bool interrupt = false;
+                    bool done = false;
+                    while (!interrupt && !done)
+                    {
+                        if (!gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done))
+                            break;
+                    }
+                    
+                    if (error.Fail())
+                    {
+                        fprintf(stderr, "error: %s\n", error.AsCString());
+                    }
+                }
+                else
+                {
+                    fprintf(stderr, "error: handshake with client failed\n");
+                }
             }
         }
-        else
-        {
-            fprintf(stderr, "error: handshake with client failed\n");
-        }
-    }
+    } while (g_stay_alive);
 
     Debugger::Terminate();
 
+    fprintf(stderr, "lldb-platform exiting...\n");
+
     return 0;
 }





More information about the lldb-commits mailing list