diff options
56 files changed, 2911 insertions, 550 deletions
diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h index 518cbf67c93..80e6969cbd3 100644 --- a/lldb/include/lldb/API/SBDebugger.h +++ b/lldb/include/lldb/API/SBDebugger.h @@ -10,9 +10,11 @@ #ifndef LLDB_SBDebugger_h_ #define LLDB_SBDebugger_h_ -#include "lldb/API/SBDefines.h" #include <stdio.h> +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBPlatform.h" + namespace lldb { class SBDebugger @@ -153,6 +155,12 @@ public: void SetSelectedTarget (SBTarget& target); + lldb::SBPlatform + GetSelectedPlatform(); + + void + SetSelectedPlatform(lldb::SBPlatform &platform); + lldb::SBSourceManager GetSourceManager (); diff --git a/lldb/include/lldb/API/SBError.h b/lldb/include/lldb/API/SBError.h index a6d3dacb454..12b34ec6dbc 100644 --- a/lldb/include/lldb/API/SBError.h +++ b/lldb/include/lldb/API/SBError.h @@ -72,6 +72,7 @@ protected: friend class SBCommunication; friend class SBHostOS; friend class SBInputReader; + friend class SBPlatform; friend class SBProcess; friend class SBThread; friend class SBTarget; diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index e44abe4759c..5d4447f74e6 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -45,6 +45,12 @@ public: const char * GetDirectory() const; + void + SetFilename(const char *filename); + + void + SetDirectory(const char *directory); + uint32_t GetPath (char *dst_path, size_t dst_len) const; @@ -65,6 +71,7 @@ private: friend class SBLineEntry; friend class SBModule; friend class SBModuleSpec; + friend class SBPlatform; friend class SBProcess; friend class SBSourceManager; friend class SBThread; diff --git a/lldb/include/lldb/API/SBModule.h b/lldb/include/lldb/API/SBModule.h index a3c4879aa2f..f5955b39734 100644 --- a/lldb/include/lldb/API/SBModule.h +++ b/lldb/include/lldb/API/SBModule.h @@ -76,6 +76,42 @@ public: bool SetPlatformFileSpec (const lldb::SBFileSpec &platform_file); + //------------------------------------------------------------------ + /// Get accessor for the remote install path for a module. + /// + /// When debugging to a remote platform by connecting to a remote + /// platform, the install path of the module can be set. If the + /// install path is set, every time the process is about to launch + /// the target will install this module on the remote platform prior + /// to launching. + /// + /// @return + /// A file specification object. + //------------------------------------------------------------------ + lldb::SBFileSpec + GetRemoteInstallFileSpec (); + + //------------------------------------------------------------------ + /// Set accessor for the remote install path for a module. + /// + /// When debugging to a remote platform by connecting to a remote + /// platform, the install path of the module can be set. If the + /// install path is set, every time the process is about to launch + /// the target will install this module on the remote platform prior + /// to launching. + /// + /// If \a file specifies a full path to an install location, the + /// module will be installed to this path. If the path is relative + /// (no directory specified, or the path is partial like "usr/lib" + /// or "./usr/lib", then the install path will be resolved using + /// the platform's current working directory as the base path. + /// + /// @param[in] + /// A file specification object. + //------------------------------------------------------------------ + bool + SetRemoteInstallFileSpec (lldb::SBFileSpec &file); + lldb::ByteOrder GetByteOrder (); diff --git a/lldb/include/lldb/API/SBPlatform.h b/lldb/include/lldb/API/SBPlatform.h new file mode 100644 index 00000000000..16a546d81f9 --- /dev/null +++ b/lldb/include/lldb/API/SBPlatform.h @@ -0,0 +1,198 @@ +//===-- SBPlatform.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBPlatform_h_ +#define LLDB_SBPlatform_h_ + +#include "lldb/API/SBDefines.h" + +struct PlatformConnectOptions; +struct PlatformShellCommand; + +namespace lldb { + + class SBPlatformConnectOptions + { + public: + SBPlatformConnectOptions (const char *url); + + SBPlatformConnectOptions (const SBPlatformConnectOptions &rhs); + + ~SBPlatformConnectOptions (); + + void + operator=(const SBPlatformConnectOptions &rhs); + + const char * + GetURL(); + + void + SetURL(const char *url); + + bool + GetRsyncEnabled(); + + void + EnableRsync (const char *options, + const char *remote_path_prefix, + bool omit_remote_hostname); + + void + DisableRsync (); + + const char * + GetLocalCacheDirectory(); + + void + SetLocalCacheDirectory(const char *path); + protected: + PlatformConnectOptions *m_opaque_ptr; + }; + + class SBPlatformShellCommand + { + public: + SBPlatformShellCommand (const char *shell_command); + + SBPlatformShellCommand (const SBPlatformShellCommand &rhs); + + ~SBPlatformShellCommand(); + + void + Clear(); + + const char * + GetCommand(); + + void + SetCommand(const char *shell_command); + + const char * + GetWorkingDirectory (); + + void + SetWorkingDirectory (const char *path); + + uint32_t + GetTimeoutSeconds (); + + void + SetTimeoutSeconds (uint32_t sec); + + int + GetSignal (); + + int + GetStatus (); + + const char * + GetOutput (); + + protected: + friend class SBPlatform; + + PlatformShellCommand *m_opaque_ptr; + }; + + class SBPlatform + { + public: + + SBPlatform (); + + SBPlatform (const char *platform_name); + + ~SBPlatform(); + + bool + IsValid () const; + + void + Clear (); + + const char * + GetWorkingDirectory(); + + bool + SetWorkingDirectory(const char *path); + + const char * + GetName (); + + SBError + ConnectRemote (SBPlatformConnectOptions &connect_options); + + void + DisconnectRemote (); + + bool + IsConnected(); + + //---------------------------------------------------------------------- + // The following functions will work if the platform is connected + //---------------------------------------------------------------------- + const char * + GetTriple(); + + const char * + GetHostname (); + + const char * + GetOSBuild (); + + const char * + GetOSDescription (); + + uint32_t + GetOSMajorVersion (); + + uint32_t + GetOSMinorVersion (); + + uint32_t + GetOSUpdateVersion (); + + SBError + Put (SBFileSpec &src, SBFileSpec &dst); + + SBError + Get (SBFileSpec &src, SBFileSpec &dst); + + SBError + Install (SBFileSpec& src, SBFileSpec& dst); + + SBError + Run (SBPlatformShellCommand &shell_command); + + SBError + MakeDirectory (const char *path, uint32_t file_permissions = eFilePermissionsDirectoryDefault); + + uint32_t + GetFilePermissions (const char *path); + + SBError + SetFilePermissions (const char *path, uint32_t file_permissions); + + protected: + + friend class SBDebugger; + friend class SBTarget; + + lldb::PlatformSP + GetSP () const; + + void + SetSP (const lldb::PlatformSP& platform_sp); + + lldb::PlatformSP m_opaque_sp; + }; + +} // namespace lldb + +#endif // LLDB_SBPlatform_h_ diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index 7bcf91c16d7..b41c1181154 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -268,6 +268,23 @@ public: GetProcess (); //------------------------------------------------------------------ + /// Install any binaries that need to be installed. + /// + /// This function does nothing when debugging on the host system. + /// When connected to remote platforms, the target's main executable + /// and any modules that have their remote install path set will be + /// installed on the remote platform. If the main executable doesn't + /// have an install location set, it will be installed in the remote + /// platform's working directory. + /// + /// @return + /// An error describing anything that went wrong during + /// installation. + //------------------------------------------------------------------ + SBError + Install(); + + //------------------------------------------------------------------ /// Launch a new process. /// /// Launch a new process by spawning a new process using the diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 1473fb90cf8..cae5a30be70 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -570,6 +570,18 @@ public: } const FileSpec & + GetRemoteInstallFileSpec () const + { + return m_remote_install_file; + } + + void + SetRemoteInstallFileSpec (const FileSpec &file) + { + m_remote_install_file = file; + } + + const FileSpec & GetSymbolFileFileSpec () const { return m_symfile_spec; @@ -1059,6 +1071,7 @@ protected: lldb_private::UUID m_uuid; ///< Each module is assumed to have a unique identifier to help match it up to debug symbols. FileSpec m_file; ///< The file representation on disk for this module (if there is one). FileSpec m_platform_file;///< The path to the module on the platform on which it is being debugged + FileSpec m_remote_install_file; ///< If set when debugging on remote platforms, this module will be installed at this location FileSpec m_symfile_spec; ///< If this path is valid, then this is the file that _will_ be used as the symbol file for this module ConstString m_object_name; ///< The name an object within this module that is selected, or empty of the module is represented by \a m_file. uint64_t m_object_offset; diff --git a/lldb/include/lldb/Host/File.h b/lldb/include/lldb/Host/File.h index 7ca582402b3..607efa029c0 100644 --- a/lldb/include/lldb/Host/File.h +++ b/lldb/include/lldb/Host/File.h @@ -40,46 +40,13 @@ public: eOpenOptionTruncate = (1u << 3), // Truncate file when opening eOpenOptionNonBlocking = (1u << 4), // File reads eOpenOptionCanCreate = (1u << 5), // Create file if doesn't already exist - eOpenOptionCanCreateNewOnly = (1u << 6) // Can create file only if it doesn't already exist + eOpenOptionCanCreateNewOnly = (1u << 6), // Can create file only if it doesn't already exist + eOpenoptionDontFollowSymlinks = (1u << 7) }; static mode_t ConvertOpenOptionsForPOSIXOpen (uint32_t open_options); - enum Permissions - { - ePermissionsUserRead = (1u << 8), - ePermissionsUserWrite = (1u << 7), - ePermissionsUserExecute = (1u << 6), - ePermissionsGroupRead = (1u << 5), - ePermissionsGroupWrite = (1u << 4), - ePermissionsGroupExecute = (1u << 3), - ePermissionsWorldRead = (1u << 2), - ePermissionsWorldWrite = (1u << 1), - ePermissionsWorldExecute = (1u << 0), - - ePermissionsUserRW = (ePermissionsUserRead | ePermissionsUserWrite | 0 ), - ePermissionsUserRX = (ePermissionsUserRead | 0 | ePermissionsUserExecute ), - ePermissionsUserRWX = (ePermissionsUserRead | ePermissionsUserWrite | ePermissionsUserExecute ), - - ePermissionsGroupRW = (ePermissionsGroupRead | ePermissionsGroupWrite | 0 ), - ePermissionsGroupRX = (ePermissionsGroupRead | 0 | ePermissionsGroupExecute ), - ePermissionsGroupRWX = (ePermissionsGroupRead | ePermissionsGroupWrite | ePermissionsGroupExecute ), - - ePermissionsWorldRW = (ePermissionsWorldRead | ePermissionsWorldWrite | 0 ), - ePermissionsWorldRX = (ePermissionsWorldRead | 0 | ePermissionsWorldExecute ), - ePermissionsWorldRWX = (ePermissionsWorldRead | ePermissionsWorldWrite | ePermissionsWorldExecute ), - - ePermissionsEveryoneR = (ePermissionsUserRead | ePermissionsGroupRead | ePermissionsWorldRead ), - ePermissionsEveryoneW = (ePermissionsUserWrite | ePermissionsGroupWrite | ePermissionsWorldWrite ), - ePermissionsEveryoneX = (ePermissionsUserExecute | ePermissionsGroupExecute | ePermissionsWorldExecute ), - - ePermissionsEveryoneRW = (ePermissionsEveryoneR | ePermissionsEveryoneW | 0 ), - ePermissionsEveryoneRX = (ePermissionsEveryoneR | 0 | ePermissionsEveryoneX ), - ePermissionsEveryoneRWX = (ePermissionsEveryoneR | ePermissionsEveryoneW | ePermissionsEveryoneX ), - ePermissionsDefault = (ePermissionsUserRW | ePermissionsGroupRead) - }; - File() : m_descriptor (kInvalidDescriptor), m_stream (kInvalidStream), @@ -120,7 +87,7 @@ public: //------------------------------------------------------------------ File (const char *path, uint32_t options, - uint32_t permissions = ePermissionsDefault); + uint32_t permissions = lldb::eFilePermissionsFileDefault); //------------------------------------------------------------------ /// Constructor with FileSpec. @@ -142,7 +109,7 @@ public: //------------------------------------------------------------------ File (const FileSpec& filespec, uint32_t options, - uint32_t permissions = ePermissionsDefault); + uint32_t permissions = lldb::eFilePermissionsFileDefault); File (int fd, bool tranfer_ownership) : m_descriptor (fd), @@ -236,7 +203,7 @@ public: Error Open (const char *path, uint32_t options, - uint32_t permissions = ePermissionsDefault); + uint32_t permissions = lldb::eFilePermissionsFileDefault); Error Close (); diff --git a/lldb/include/lldb/Host/FileSpec.h b/lldb/include/lldb/Host/FileSpec.h index dfc6b711ae4..086c8f20056 100644 --- a/lldb/include/lldb/Host/FileSpec.h +++ b/lldb/include/lldb/Host/FileSpec.h @@ -420,6 +420,21 @@ public: FileType GetFileType () const; + //------------------------------------------------------------------ + /// Return the current permissions of the path. + /// + /// Returns a bitmask for the current permissions of the file + /// ( zero or more of the permission bits defined in + /// File::Permissions). + /// + /// @return + /// Zero if the file doesn't exist or we are unable to get + /// information for the file, otherwise one or more permission + /// bits from the File::Permissions enumeration. + //------------------------------------------------------------------ + uint32_t + GetPermissions () const; + bool IsDirectory () const { @@ -636,7 +651,7 @@ public: void RemoveLastPathComponent (); - const char* + ConstString GetLastPathComponent () const; //------------------------------------------------------------------ diff --git a/lldb/include/lldb/Host/Host.h b/lldb/include/lldb/Host/Host.h index 1d667dee5a2..fe0f6f62b3b 100644 --- a/lldb/include/lldb/Host/Host.h +++ b/lldb/include/lldb/Host/Host.h @@ -510,13 +510,28 @@ public: const char *symbol_name, Error &error); - static uint32_t - MakeDirectory (const char* path, mode_t mode); + static Error + MakeDirectory (const char* path, uint32_t mode); + + static Error + GetFilePermissions (const char* path, uint32_t &file_permissions); + + static Error + SetFilePermissions (const char* path, uint32_t file_permissions); + static Error + Symlink (const char *src, const char *dst); + + static Error + Readlink (const char *path, char *buf, size_t buf_len); + + static Error + Unlink (const char *path); + static lldb::user_id_t OpenFile (const FileSpec& file_spec, uint32_t flags, - mode_t mode, + uint32_t mode, Error &error); static bool diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h index 93cd67d6665..23903a669f7 100644 --- a/lldb/include/lldb/Target/Platform.h +++ b/lldb/include/lldb/Target/Platform.h @@ -40,7 +40,8 @@ namespace lldb_private { /// @li listing and getting info for existing processes /// @li attaching and possibly debugging the platform's kernel //---------------------------------------------------------------------- - class Platform : public PluginInterface + class Platform : + public PluginInterface { public: @@ -214,8 +215,7 @@ namespace lldb_private { bool GetOSKernelDescription (std::string &s); - // Returns the the hostname if we are connected, else the short plugin - // name. + // Returns the the name of the platform ConstString GetName (); @@ -269,6 +269,19 @@ namespace lldb_private { { return ArchSpec(); // Return an invalid architecture } + + virtual ConstString + GetRemoteWorkingDirectory() + { + return m_working_dir; + } + + virtual bool + SetRemoteWorkingDirectory(const ConstString &path) + { + m_working_dir = path; + return true; + } virtual const char * GetUserName (uint32_t uid); @@ -384,10 +397,13 @@ namespace lldb_private { } //------------------------------------------------------------------ - /// Subclasses should NOT need to implement this function as it uses - /// the Platform::LaunchProcess() followed by Platform::Attach () + /// Subclasses do not need to implement this function as it uses + /// the Platform::LaunchProcess() followed by Platform::Attach (). + /// Remote platforms will want to subclass this function in order + /// to be able to intercept STDIO and possibly launch a separate + /// process that will debug the debuggee. //------------------------------------------------------------------ - lldb::ProcessSP + virtual lldb::ProcessSP DebugProcess (ProcessLaunchInfo &launch_info, Debugger &debugger, Target *target, // Can be NULL, if NULL create a new target, else use existing one @@ -542,6 +558,12 @@ namespace lldb_private { { m_sdk_build = sdk_build; } + + ConstString + GetWorkingDirectory (); + + bool + SetWorkingDirectory (const ConstString &path); // There may be modules that we don't want to find by default for operations like "setting breakpoint by name". // The platform will return "true" from this call if the passed in module happens to be one of these. @@ -552,23 +574,19 @@ 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 Error + MakeDirectory (const char *path, uint32_t permissions); + virtual Error + GetFilePermissions (const char *path, uint32_t &file_permissions); + + virtual Error + SetFilePermissions (const char *path, uint32_t file_permissions); + virtual lldb::user_id_t OpenFile (const FileSpec& file_spec, uint32_t flags, - mode_t mode, + uint32_t mode, Error &error) { return UINT64_MAX; @@ -610,28 +628,54 @@ namespace lldb_private { } virtual Error + GetFile (const FileSpec& source, + const FileSpec& destination); + + virtual Error PutFile (const FileSpec& source, const FileSpec& destination, uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX); - + + virtual Error + CreateSymlink (const char *src, // The name of the link is in src + const char *dst);// The symlink points to dst + + //---------------------------------------------------------------------- + /// Install a file or directory to the remote system. + /// + /// Install is similar to Platform::PutFile(), but it differs in that if + /// an application/framework/shared library is installed on a remote + /// platform and the remote platform requires something to be done to + /// register the application/framework/shared library, then this extra + /// registration can be done. + /// + /// @param[in] src + /// The source file/directory to install on the remote system. + /// + /// @param[in] dst + /// The destination file/directory where \a src will be installed. + /// If \a dst has no filename specified, then its filename will + /// be set from \a src. It \a dst has no directory specified, it + /// will use the platform working directory. If \a dst has a + /// directory specified, but the directory path is relative, the + /// platform working directory will be prepended to the relative + /// directory. + /// + /// @return + /// An error object that describes anything that went wrong. + //---------------------------------------------------------------------- + virtual Error + Install (const FileSpec& src, const FileSpec& dst); + 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 Error + Unlink (const char *path); virtual bool GetSupportsRSync () @@ -806,6 +850,7 @@ namespace lldb_private { bool m_system_arch_set_while_connected; ConstString m_sdk_sysroot; // the root location of where the SDK files are all located ConstString m_sdk_build; + ConstString m_working_dir; // The working directory which is used when installing modules that have no install path set std::string m_remote_url; std::string m_name; uint32_t m_major_os_version; diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index aac525119ab..cda9b4f5711 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -1745,7 +1745,7 @@ public: /// the error object is success. //------------------------------------------------------------------ virtual Error - Launch (const ProcessLaunchInfo &launch_info); + Launch (ProcessLaunchInfo &launch_info); virtual Error LoadCore (); diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index e877057f1c7..d874891a6af 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -1041,6 +1041,12 @@ public: ClangASTImporter * GetClangASTImporter(); + //---------------------------------------------------------------------- + // Install any files through the platform that need be to installed + // prior to launching or attaching. + //---------------------------------------------------------------------- + Error + Install(ProcessLaunchInfo *launch_info); // Since expressions results can persist beyond the lifetime of a process, // and the const expression results are available after a process is gone, diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index ae8c92be900..0b341575be4 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -684,6 +684,48 @@ namespace lldb { eAddressClassRuntime } AddressClass; + //---------------------------------------------------------------------- + // File Permissions + // + // Designed to mimic the unix file permission bits so they can be + // used with functions that set 'mode_t' to certain values for + // permissions. + //---------------------------------------------------------------------- + typedef enum FilePermissions + { + eFilePermissionsUserRead = (1u << 8), + eFilePermissionsUserWrite = (1u << 7), + eFilePermissionsUserExecute = (1u << 6), + eFilePermissionsGroupRead = (1u << 5), + eFilePermissionsGroupWrite = (1u << 4), + eFilePermissionsGroupExecute = (1u << 3), + eFilePermissionsWorldRead = (1u << 2), + eFilePermissionsWorldWrite = (1u << 1), + eFilePermissionsWorldExecute = (1u << 0), + + eFilePermissionsUserRW = (eFilePermissionsUserRead | eFilePermissionsUserWrite | 0 ), + eFileFilePermissionsUserRX = (eFilePermissionsUserRead | 0 | eFilePermissionsUserExecute ), + eFilePermissionsUserRWX = (eFilePermissionsUserRead | eFilePermissionsUserWrite | eFilePermissionsUserExecute ), + + eFilePermissionsGroupRW = (eFilePermissionsGroupRead | eFilePermissionsGroupWrite | 0 ), + eFilePermissionsGroupRX = (eFilePermissionsGroupRead | 0 | eFilePermissionsGroupExecute ), + eFilePermissionsGroupRWX = (eFilePermissionsGroupRead | eFilePermissionsGroupWrite | eFilePermissionsGroupExecute ), + + eFilePermissionsWorldRW = (eFilePermissionsWorldRead | eFilePermissionsWorldWrite | 0 ), + eFilePermissionsWorldRX = (eFilePermissionsWorldRead | 0 | eFilePermissionsWorldExecute ), + eFilePermissionsWorldRWX = (eFilePermissionsWorldRead | eFilePermissionsWorldWrite | eFilePermissionsWorldExecute ), + + eFilePermissionsEveryoneR = (eFilePermissionsUserRead | eFilePermissionsGroupRead | eFilePermissionsWorldRead ), + eFilePermissionsEveryoneW = (eFilePermissionsUserWrite | eFilePermissionsGroupWrite | eFilePermissionsWorldWrite ), + eFilePermissionsEveryoneX = (eFilePermissionsUserExecute | eFilePermissionsGroupExecute | eFilePermissionsWorldExecute ), + + eFilePermissionsEveryoneRW = (eFilePermissionsEveryoneR | eFilePermissionsEveryoneW | 0 ), + eFilePermissionsEveryoneRX = (eFilePermissionsEveryoneR | 0 | eFilePermissionsEveryoneX ), + eFilePermissionsEveryoneRWX = (eFilePermissionsEveryoneR | eFilePermissionsEveryoneW | eFilePermissionsEveryoneX ), + eFilePermissionsFileDefault = eFilePermissionsUserRW, + eFilePermissionsDirectoryDefault = eFilePermissionsUserRWX, + } FilePermissions; + } // namespace lldb diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index b7702d70b41..f73b59c61b9 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -89,6 +89,8 @@ 262D24E613FB8710002D1960 /* RegisterContextMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 262D24E413FB8710002D1960 /* RegisterContextMemory.cpp */; }; 262ED0051631FA2800879631 /* OptionGroupString.h in Headers */ = {isa = PBXBuildFile; fileRef = 262ED0041631FA2800879631 /* OptionGroupString.h */; }; 262ED0081631FA3A00879631 /* OptionGroupString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 262ED0071631FA3A00879631 /* OptionGroupString.cpp */; }; + 262F12B51835468600AEB384 /* SBPlatform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 262F12B41835468600AEB384 /* SBPlatform.cpp */; }; + 262F12B71835469C00AEB384 /* SBPlatform.h in Headers */ = {isa = PBXBuildFile; fileRef = 262F12B61835469C00AEB384 /* SBPlatform.h */; }; 2635879417822FC2004C30BA /* SymbolVendorELF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2635879017822E56004C30BA /* SymbolVendorELF.cpp */; }; 26368A3C126B697600E8659F /* darwin-debug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26368A3B126B697600E8659F /* darwin-debug.cpp */; }; 26368AF7126B960500E8659F /* darwin-debug in Resources */ = {isa = PBXBuildFile; fileRef = 26579F68126A25920007C5CB /* darwin-debug */; }; @@ -947,6 +949,9 @@ 262D24E513FB8710002D1960 /* RegisterContextMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextMemory.h; path = Utility/RegisterContextMemory.h; sourceTree = "<group>"; }; 262ED0041631FA2800879631 /* OptionGroupString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OptionGroupString.h; path = include/lldb/Interpreter/OptionGroupString.h; sourceTree = "<group>"; }; 262ED0071631FA3A00879631 /* OptionGroupString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OptionGroupString.cpp; path = source/Interpreter/OptionGroupString.cpp; sourceTree = "<group>"; }; + 262F12B41835468600AEB384 /* SBPlatform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBPlatform.cpp; path = source/API/SBPlatform.cpp; sourceTree = "<group>"; }; + 262F12B61835469C00AEB384 /* SBPlatform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBPlatform.h; path = include/lldb/API/SBPlatform.h; sourceTree = "<group>"; }; + 262F12B8183546C900AEB384 /* SBPlatform.i */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBPlatform.i; sourceTree = "<group>"; }; 2635879017822E56004C30BA /* SymbolVendorELF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolVendorELF.cpp; sourceTree = "<group>"; }; 2635879117822E56004C30BA /* SymbolVendorELF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolVendorELF.h; sourceTree = "<group>"; }; 263664921140A4930075843B /* Debugger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = Debugger.cpp; path = source/Core/Debugger.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; @@ -2169,6 +2174,7 @@ 2611FF05142D83060017FEA3 /* SBListener.i */, 2611FF06142D83060017FEA3 /* SBModule.i */, 263C493B178B61CC0070F12D /* SBModuleSpec.i */, + 262F12B8183546C900AEB384 /* SBPlatform.i */, 2611FF07142D83060017FEA3 /* SBProcess.i */, 2611FF08142D83060017FEA3 /* SBSection.i */, 2611FF09142D83060017FEA3 /* SBSourceManager.i */, @@ -2269,6 +2275,8 @@ 26DE204C11618E7A00A093E2 /* SBModule.cpp */, 263C4939178B50CF0070F12D /* SBModuleSpec.h */, 263C4937178B50C40070F12D /* SBModuleSpec.cpp */, + 262F12B61835469C00AEB384 /* SBPlatform.h */, + 262F12B41835468600AEB384 /* SBPlatform.cpp */, 9A9831041125FC5800A56CB0 /* SBProcess.h */, 9A9831031125FC5800A56CB0 /* SBProcess.cpp */, 26B8283C142D01E9002DBC64 /* SBSection.h */, @@ -3600,6 +3608,7 @@ 26C72C94124322890068DC16 /* SBStream.h in Headers */, 9A357671116E7B5200E8ED2F /* SBStringList.h in Headers */, 26DE205B11618FF600A093E2 /* SBSymbol.h in Headers */, + 262F12B71835469C00AEB384 /* SBPlatform.h in Headers */, 26DE204111618AB900A093E2 /* SBSymbolContext.h in Headers */, 268F9D53123AA15200B91E9B /* SBSymbolContextList.h in Headers */, 2668022C115FD13D008E1FE4 /* SBTarget.h in Headers */, @@ -3981,6 +3990,7 @@ files = ( 9461569A14E358A6003A195C /* SBTypeFilter.cpp in Sources */, 9461569B14E358A6003A195C /* SBTypeFormat.cpp in Sources */, + 262F12B51835468600AEB384 /* SBPlatform.cpp in Sources */, 9461569C14E358A6003A195C /* SBTypeSummary.cpp in Sources */, 9461569D14E358A6003A195C /* SBTypeSynthetic.cpp in Sources */, 26680324116005D9008E1FE4 /* SBThread.cpp in Sources */, diff --git a/lldb/scripts/Python/build-swig-Python.sh b/lldb/scripts/Python/build-swig-Python.sh index 28e7df91c1c..efa35e8bc4a 100755 --- a/lldb/scripts/Python/build-swig-Python.sh +++ b/lldb/scripts/Python/build-swig-Python.sh @@ -152,6 +152,7 @@ INTERFACE_FILES="${SRC_ROOT}/scripts/Python/interface/SBAddress.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBListener.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBModule.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBModuleSpec.i"\ +" ${SRC_ROOT}/scripts/Python/interface/SBPlatform.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBProcess.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBSourceManager.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBStream.i"\ diff --git a/lldb/scripts/Python/interface/SBDebugger.i b/lldb/scripts/Python/interface/SBDebugger.i index 43cc16e7394..6d075ace791 100644 --- a/lldb/scripts/Python/interface/SBDebugger.i +++ b/lldb/scripts/Python/interface/SBDebugger.i @@ -231,6 +231,12 @@ public: void SetSelectedTarget (lldb::SBTarget &target); + lldb::SBPlatform + GetSelectedPlatform(); + + void + SetSelectedPlatform(lldb::SBPlatform &platform); + lldb::SBSourceManager GetSourceManager (); diff --git a/lldb/scripts/Python/interface/SBFileSpec.i b/lldb/scripts/Python/interface/SBFileSpec.i index 07d97babbee..2195434922c 100644 --- a/lldb/scripts/Python/interface/SBFileSpec.i +++ b/lldb/scripts/Python/interface/SBFileSpec.i @@ -58,6 +58,12 @@ public: const char * GetDirectory() const; + void + SetFilename(const char *filename); + + void + SetDirectory(const char *directory); + uint32_t GetPath (char *dst_path, size_t dst_len) const; diff --git a/lldb/scripts/Python/interface/SBModule.i b/lldb/scripts/Python/interface/SBModule.i index fdf017754d0..21f9dcc4055 100644 --- a/lldb/scripts/Python/interface/SBModule.i +++ b/lldb/scripts/Python/interface/SBModule.i @@ -148,6 +148,12 @@ public: bool SetPlatformFileSpec (const lldb::SBFileSpec &platform_file); + + lldb::SBFileSpec + GetRemoteInstallFileSpec (); + + bool + SetRemoteInstallFileSpec (lldb::SBFileSpec &file); %feature("docstring", "Returns the UUID of the module as a Python string." ) GetUUIDString; diff --git a/lldb/scripts/Python/interface/SBPlatform.i b/lldb/scripts/Python/interface/SBPlatform.i new file mode 100644 index 00000000000..ef03b0c11c4 --- /dev/null +++ b/lldb/scripts/Python/interface/SBPlatform.i @@ -0,0 +1,187 @@ +//===-- SWIG Interface for SBPlatform ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + + +class SBPlatformConnectOptions +{ +public: + SBPlatformConnectOptions (const char *url); + + SBPlatformConnectOptions (const SBPlatformConnectOptions &rhs); + + ~SBPlatformConnectOptions (); + + const char * + GetURL(); + + void + SetURL(const char *url); + + bool + GetRsyncEnabled(); + + void + EnableRsync (const char *options, + const char *remote_path_prefix, + bool omit_remote_hostname); + + void + DisableRsync (); + + const char * + GetLocalCacheDirectory(); + + void + SetLocalCacheDirectory(const char *path); +}; + +class SBPlatformShellCommand +{ +public: + SBPlatformShellCommand (const char *shell_command); + + SBPlatformShellCommand (const SBPlatformShellCommand &rhs); + + ~SBPlatformShellCommand(); + + void + Clear(); + + const char * + GetCommand(); + + void + SetCommand(const char *shell_command); + + const char * + GetWorkingDirectory (); + + void + SetWorkingDirectory (const char *path); + + uint32_t + GetTimeoutSeconds (); + + void + SetTimeoutSeconds (uint32_t sec); + + int + GetSignal (); + + int + GetStatus (); + + const char * + GetOutput (); +}; + +%feature("docstring", +"A class that represents the a platform that can represent the current host or a remote host debug platform. + +The SBPlatform class represents the current host, or a remote host. +It can be connected to a remote platform in order to provide ways +to remotely launch and attach to processes, upload/download files, +create directories, run remote shell commands, find locally cached +versions of files from the remote system, and much more. + +SBPlatform objects can be created and then used to connect to a remote +platform which allows the SBPlatform to be used to get a list of the +current processes on the remote host, attach to one of those processes, +install programs on the remote system, attach and launch processes, +and much more. + +Every SBTarget has a corresponding SBPlatform. The platform can be +specified upon target creation, or the currently selected platform +will attempt to be used when creating the target automatically as long +as the currently selected platform matches the target architecture +and executable type. If the architecture or executable type do not match, +a suitable platform will be found automatically." + +) SBPlatform; +class SBPlatform +{ +public: + + SBPlatform (); + + SBPlatform (const char *); + + ~SBPlatform(); + + bool + IsValid () const; + + void + Clear (); + + const char * + GetWorkingDirectory(); + + bool + SetWorkingDirectory(const char *); + + const char * + GetName (); + + SBError + ConnectRemote (lldb::SBPlatformConnectOptions &connect_options); + + void + DisconnectRemote (); + + bool + IsConnected(); + + const char * + GetTriple(); + + const char * + GetHostname (); + + const char * + GetOSBuild (); + + const char * + GetOSDescription (); + + uint32_t + GetOSMajorVersion (); + + uint32_t + GetOSMinorVersion (); + + uint32_t + GetOSUpdateVersion (); + + lldb::SBError + Get (lldb::SBFileSpec &src, lldb::SBFileSpec &dst); + + lldb::SBError + Put (lldb::SBFileSpec &src, lldb::SBFileSpec &dst); + + lldb::SBError + Install (lldb::SBFileSpec &src, lldb::SBFileSpec &dst); + + lldb::SBError + Run (lldb::SBPlatformShellCommand &shell_command); + + lldb::SBError + MakeDirectory (const char *path, uint32_t file_permissions = lldb::eFilePermissionsDirectoryDefault); + + uint32_t + GetFilePermissions (const char *path); + + lldb::SBError + SetFilePermissions (const char *path, uint32_t file_permissions); + +}; + +} // namespace lldb diff --git a/lldb/scripts/Python/interface/SBTarget.i b/lldb/scripts/Python/interface/SBTarget.i index d259d924854..92518fee602 100644 --- a/lldb/scripts/Python/interface/SBTarget.i +++ b/lldb/scripts/Python/interface/SBTarget.i @@ -266,6 +266,25 @@ public: %feature("docstring", " //------------------------------------------------------------------ + /// Install any binaries that need to be installed. + /// + /// This function does nothing when debugging on the host system. + /// When connected to remote platforms, the target's main executable + /// and any modules that have their install path set will be + /// installed on the remote platform. If the main executable doesn't + /// have an install location set, it will be installed in the remote + /// platform's working directory. + /// + /// @return + /// An error describing anything that went wrong during + /// installation. + //------------------------------------------------------------------ + ") Install; + lldb::SBError + Install(); + + %feature("docstring", " + //------------------------------------------------------------------ /// Launch a new process. /// /// Launch a new process by spawning a new process using the diff --git a/lldb/scripts/lldb.swig b/lldb/scripts/lldb.swig index 42448211747..acf8492bcee 100644 --- a/lldb/scripts/lldb.swig +++ b/lldb/scripts/lldb.swig @@ -79,6 +79,7 @@ import os #include "lldb/API/SBListener.h" #include "lldb/API/SBModule.h" #include "lldb/API/SBModuleSpec.h" +#include "lldb/API/SBPlatform.h" #include "lldb/API/SBProcess.h" #include "lldb/API/SBSection.h" #include "lldb/API/SBSourceManager.h" @@ -143,6 +144,7 @@ import os %include "./Python/interface/SBListener.i" %include "./Python/interface/SBModule.i" %include "./Python/interface/SBModuleSpec.i" +%include "./Python/interface/SBPlatform.i" %include "./Python/interface/SBProcess.i" %include "./Python/interface/SBSection.i" %include "./Python/interface/SBSourceManager.i" diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp index 88c991b7205..5aa5c133a16 100644 --- a/lldb/source/API/SBDebugger.cpp +++ b/lldb/source/API/SBDebugger.cpp @@ -804,6 +804,42 @@ SBDebugger::SetSelectedTarget (SBTarget &sb_target) } } +SBPlatform +SBDebugger::GetSelectedPlatform() +{ + Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + SBPlatform sb_platform; + DebuggerSP debugger_sp(m_opaque_sp); + if (debugger_sp) + { + sb_platform.SetSP(debugger_sp->GetPlatformList().GetSelectedPlatform()); + } + if (log) + { + log->Printf ("SBDebugger(%p)::GetSelectedPlatform () => SBPlatform(%p): %s", m_opaque_sp.get(), + sb_platform.GetSP().get(), sb_platform.GetName()); + } + return sb_platform; +} + +void +SBDebugger::SetSelectedPlatform(SBPlatform &sb_platform) +{ + Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + DebuggerSP debugger_sp(m_opaque_sp); + if (debugger_sp) + { + debugger_sp->GetPlatformList().SetSelectedPlatform(sb_platform.GetSP()); + } + if (log) + { + log->Printf ("SBDebugger(%p)::SetSelectedPlatform (SBPlatform(%p) %s)", m_opaque_sp.get(), + sb_platform.GetSP().get(), sb_platform.GetName()); + } +} + void SBDebugger::DispatchInput (void* baton, const void *data, size_t data_len) { diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp index fc207d071db..4fd2866c9b0 100644 --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -121,6 +121,24 @@ SBFileSpec::GetDirectory() const return s; } +void +SBFileSpec::SetFilename(const char *filename) +{ + if (filename && filename[0]) + m_opaque_ap->GetFilename().SetCString(filename); + else + m_opaque_ap->GetFilename().Clear(); +} + +void +SBFileSpec::SetDirectory(const char *directory) +{ + if (directory && directory[0]) + m_opaque_ap->GetDirectory().SetCString(directory); + else + m_opaque_ap->GetDirectory().Clear(); +} + uint32_t SBFileSpec::GetPath (char *dst_path, size_t dst_len) const { diff --git a/lldb/source/API/SBModule.cpp b/lldb/source/API/SBModule.cpp index 5f5fc9292cd..0285cf304d4 100644 --- a/lldb/source/API/SBModule.cpp +++ b/lldb/source/API/SBModule.cpp @@ -162,6 +162,27 @@ SBModule::SetPlatformFileSpec (const lldb::SBFileSpec &platform_file) return result; } +lldb::SBFileSpec +SBModule::GetRemoteInstallFileSpec () +{ + SBFileSpec sb_file_spec; + ModuleSP module_sp (GetSP ()); + if (module_sp) + sb_file_spec.SetFileSpec (module_sp->GetRemoteInstallFileSpec()); + return sb_file_spec; +} + +bool +SBModule::SetRemoteInstallFileSpec (lldb::SBFileSpec &file) +{ + ModuleSP module_sp (GetSP ()); + if (module_sp) + { + module_sp->SetRemoteInstallFileSpec(file.ref()); + return true; + } + return false; +} const uint8_t * diff --git a/lldb/source/API/SBPlatform.cpp b/lldb/source/API/SBPlatform.cpp new file mode 100644 index 00000000000..9914852cead --- /dev/null +++ b/lldb/source/API/SBPlatform.cpp @@ -0,0 +1,632 @@ +//===-- SBPlatform.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/API/SBPlatform.h" +#include "lldb/API/SBError.h" +#include "lldb/API/SBFileSpec.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Error.h" +#include "lldb/Host/File.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Platform.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// PlatformConnectOptions +//---------------------------------------------------------------------- +struct PlatformConnectOptions { + PlatformConnectOptions(const char *url = NULL) : + m_url(), + m_rsync_options(), + m_rsync_remote_path_prefix(), + m_rsync_enabled(false), + m_rsync_omit_hostname_from_remote_path(false), + m_local_cache_directory () + { + if (url && url[0]) + m_url = url; + } + + ~PlatformConnectOptions() + { + } + + std::string m_url; + std::string m_rsync_options; + std::string m_rsync_remote_path_prefix; + bool m_rsync_enabled; + bool m_rsync_omit_hostname_from_remote_path; + ConstString m_local_cache_directory; +}; + +//---------------------------------------------------------------------- +// PlatformShellCommand +//---------------------------------------------------------------------- +struct PlatformShellCommand { + PlatformShellCommand(const char *shell_command = NULL) : + m_command(), + m_working_dir(), + m_status(0), + m_signo(0), + m_timeout_sec(UINT32_MAX) + { + if (shell_command && shell_command[0]) + m_command = shell_command; + } + + ~PlatformShellCommand() + { + } + + std::string m_command; + std::string m_working_dir; + std::string m_output; + int m_status; + int m_signo; + uint32_t m_timeout_sec; +}; +//---------------------------------------------------------------------- +// SBPlatformConnectOptions +//---------------------------------------------------------------------- +SBPlatformConnectOptions::SBPlatformConnectOptions (const char *url) : + m_opaque_ptr(new PlatformConnectOptions(url)) +{ + +} + +SBPlatformConnectOptions::SBPlatformConnectOptions(const SBPlatformConnectOptions &rhs) : + m_opaque_ptr(new PlatformConnectOptions()) +{ + *m_opaque_ptr = *rhs.m_opaque_ptr; +} + +SBPlatformConnectOptions::~SBPlatformConnectOptions () +{ + delete m_opaque_ptr; +} + +void +SBPlatformConnectOptions::operator=(const SBPlatformConnectOptions &rhs) +{ + *m_opaque_ptr = *rhs.m_opaque_ptr; +} + +const char * +SBPlatformConnectOptions::GetURL() +{ + if (m_opaque_ptr->m_url.empty()) + return NULL; + return m_opaque_ptr->m_url.c_str(); +} + +void +SBPlatformConnectOptions::SetURL(const char *url) +{ + if (url && url[0]) + m_opaque_ptr->m_url = url; + else + m_opaque_ptr->m_url.clear(); +} + +bool +SBPlatformConnectOptions::GetRsyncEnabled() +{ + return m_opaque_ptr->m_rsync_enabled; +} + +void +SBPlatformConnectOptions::EnableRsync (const char *options, + const char *remote_path_prefix, + bool omit_hostname_from_remote_path) +{ + m_opaque_ptr->m_rsync_enabled = true; + m_opaque_ptr->m_rsync_omit_hostname_from_remote_path = omit_hostname_from_remote_path; + if (remote_path_prefix && remote_path_prefix[0]) + m_opaque_ptr->m_rsync_remote_path_prefix = remote_path_prefix; + else + m_opaque_ptr->m_rsync_remote_path_prefix.clear(); + + if (options && options[0]) + m_opaque_ptr->m_rsync_options = options; + else + m_opaque_ptr->m_rsync_options.clear(); + +} + +void +SBPlatformConnectOptions::DisableRsync () +{ + m_opaque_ptr->m_rsync_enabled = false; +} + +const char * +SBPlatformConnectOptions::GetLocalCacheDirectory() +{ + return m_opaque_ptr->m_local_cache_directory.GetCString(); +} + +void +SBPlatformConnectOptions::SetLocalCacheDirectory(const char *path) +{ + if (path && path[0]) + m_opaque_ptr->m_local_cache_directory.SetCString(path); + else + m_opaque_ptr->m_local_cache_directory = ConstString(); +} + +//---------------------------------------------------------------------- +// SBPlatformShellCommand +//---------------------------------------------------------------------- +SBPlatformShellCommand::SBPlatformShellCommand (const char *shell_command) : + m_opaque_ptr(new PlatformShellCommand(shell_command)) +{ +} + +SBPlatformShellCommand::SBPlatformShellCommand (const SBPlatformShellCommand &rhs) : + m_opaque_ptr(new PlatformShellCommand()) +{ + *m_opaque_ptr = *rhs.m_opaque_ptr; +} + +SBPlatformShellCommand::~SBPlatformShellCommand() +{ + delete m_opaque_ptr; +} + +void +SBPlatformShellCommand::Clear() +{ + m_opaque_ptr->m_output = std::move(std::string()); + m_opaque_ptr->m_status = 0; + m_opaque_ptr->m_signo = 0; +} + +const char * +SBPlatformShellCommand::GetCommand() +{ + if (m_opaque_ptr->m_command.empty()) + return NULL; + return m_opaque_ptr->m_command.c_str(); +} + +void +SBPlatformShellCommand::SetCommand(const char *shell_command) +{ + if (shell_command && shell_command[0]) + m_opaque_ptr->m_command = shell_command; + else + m_opaque_ptr->m_command.clear(); +} + +const char * +SBPlatformShellCommand::GetWorkingDirectory () +{ + if (m_opaque_ptr->m_working_dir.empty()) + return NULL; + return m_opaque_ptr->m_working_dir.c_str(); +} + +void +SBPlatformShellCommand::SetWorkingDirectory (const char *path) +{ + if (path && path[0]) + m_opaque_ptr->m_working_dir = path; + else + m_opaque_ptr->m_working_dir.clear(); +} + +uint32_t +SBPlatformShellCommand::GetTimeoutSeconds () +{ + return m_opaque_ptr->m_timeout_sec; +} + +void +SBPlatformShellCommand::SetTimeoutSeconds (uint32_t sec) +{ + m_opaque_ptr->m_timeout_sec = sec; +} + +int +SBPlatformShellCommand::GetSignal () +{ + return m_opaque_ptr->m_signo; +} + +int +SBPlatformShellCommand::GetStatus () +{ + return m_opaque_ptr->m_status; +} + +const char * +SBPlatformShellCommand::GetOutput () +{ + if (m_opaque_ptr->m_output.empty()) + return NULL; + return m_opaque_ptr->m_output.c_str(); +} + +//---------------------------------------------------------------------- +// SBPlatform +//---------------------------------------------------------------------- +SBPlatform::SBPlatform () : + m_opaque_sp () +{ + +} + +SBPlatform::SBPlatform (const char *platform_name) : + m_opaque_sp () +{ + Error error; + m_opaque_sp = Platform::Create (platform_name, error); +} + +SBPlatform::~SBPlatform() +{ +} + +bool +SBPlatform::IsValid () const +{ + return m_opaque_sp.get() != NULL; +} + +void +SBPlatform::Clear () +{ + m_opaque_sp.reset(); +} + +const char * +SBPlatform::GetName () +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + return platform_sp->GetName().GetCString(); + return NULL; +} + +lldb::PlatformSP +SBPlatform::GetSP () const +{ + return m_opaque_sp; +} + +void +SBPlatform::SetSP (const lldb::PlatformSP& platform_sp) +{ + m_opaque_sp = platform_sp; +} + +const char * +SBPlatform::GetWorkingDirectory() +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + return platform_sp->GetWorkingDirectory().GetCString(); + return NULL; +} + +bool +SBPlatform::SetWorkingDirectory(const char *path) +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + if (path) + platform_sp->SetWorkingDirectory(ConstString(path)); + else + platform_sp->SetWorkingDirectory(ConstString()); + return true; + } + return false; +} + +SBError +SBPlatform::ConnectRemote (SBPlatformConnectOptions &connect_options) +{ + SBError sb_error; + PlatformSP platform_sp(GetSP()); + if (platform_sp && connect_options.GetURL()) + { + Args args; + args.AppendArgument(connect_options.GetURL()); + sb_error.ref() = platform_sp->ConnectRemote(args); + } + else + { + sb_error.SetErrorString("invalid platform"); + } + return sb_error; +} + +void +SBPlatform::DisconnectRemote () +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + platform_sp->DisconnectRemote(); +} + +bool +SBPlatform::IsConnected() +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + platform_sp->IsConnected(); + return false; +} + +const char * +SBPlatform::GetTriple() +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + ArchSpec arch(platform_sp->GetRemoteSystemArchitecture()); + if (arch.IsValid()) + { + // Const-ify the string so we don't need to worry about the lifetime of the string + return ConstString(arch.GetTriple().getTriple().c_str()).GetCString(); + } + } + return NULL; +} + +const char * +SBPlatform::GetOSBuild() +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + std::string s; + if (platform_sp->GetOSBuildString(s)) + { + if (!s.empty()) + { + // Const-ify the string so we don't need to worry about the lifetime of the string + return ConstString(s.c_str()).GetCString(); + } + } + } + return NULL; +} + +const char * +SBPlatform::GetOSDescription() +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + std::string s; + if (platform_sp->GetOSKernelDescription(s)) + { + if (!s.empty()) + { + // Const-ify the string so we don't need to worry about the lifetime of the string + return ConstString(s.c_str()).GetCString(); + } + } + } + return NULL; +} + +const char * +SBPlatform::GetHostname () +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + return platform_sp->GetHostname(); + return NULL; +} + +uint32_t +SBPlatform::GetOSMajorVersion () +{ + uint32_t major, minor, update; + PlatformSP platform_sp(GetSP()); + if (platform_sp && platform_sp->GetOSVersion(major, minor, update)) + return major; + return UINT32_MAX; + +} + +uint32_t +SBPlatform::GetOSMinorVersion () +{ + uint32_t major, minor, update; + PlatformSP platform_sp(GetSP()); + if (platform_sp && platform_sp->GetOSVersion(major, minor, update)) + return minor; + return UINT32_MAX; +} + +uint32_t +SBPlatform::GetOSUpdateVersion () +{ + uint32_t major, minor, update; + PlatformSP platform_sp(GetSP()); + if (platform_sp && platform_sp->GetOSVersion(major, minor, update)) + return update; + return UINT32_MAX; +} + +SBError +SBPlatform::Get (SBFileSpec &src, + SBFileSpec &dst) +{ + SBError sb_error; + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + sb_error.ref() = platform_sp->GetFile(src.ref(), dst.ref()); + } + else + { + sb_error.SetErrorString("invalid platform"); + } + return sb_error; +} + +SBError +SBPlatform::Put (SBFileSpec &src, + SBFileSpec &dst) +{ + SBError sb_error; + + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + if (src.Exists()) + { + uint32_t permissions = src.ref().GetPermissions(); + if (permissions == 0) + { + if (src.ref().GetFileType() == FileSpec::eFileTypeDirectory) + permissions = eFilePermissionsDirectoryDefault; + else + permissions = eFilePermissionsFileDefault; + } + + sb_error.ref() = platform_sp->PutFile(src.ref(), + dst.ref(), + permissions); + } + else + { + sb_error.ref().SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", src.ref().GetPath().c_str()); + } + } + else + { + sb_error.SetErrorString("invalid platform"); + } + return sb_error; +} + +SBError +SBPlatform::Install (SBFileSpec &src, + SBFileSpec &dst) +{ + SBError sb_error; + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + if (src.Exists()) + { + sb_error.ref() = platform_sp->Install(src.ref(), dst.ref()); + } + else + { + sb_error.ref().SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", src.ref().GetPath().c_str()); + } + } + else + { + sb_error.SetErrorString("invalid platform"); + } + return sb_error; +} + + +SBError +SBPlatform::Run (SBPlatformShellCommand &shell_command) +{ + SBError sb_error; + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + if (platform_sp->IsConnected()) + { + const char *command = shell_command.GetCommand(); + if (command) + { + const char *working_dir = shell_command.GetWorkingDirectory(); + if (working_dir == NULL) + { + working_dir = platform_sp->GetWorkingDirectory().GetCString(); + if (working_dir) + shell_command.SetWorkingDirectory(working_dir); + } + sb_error.ref() = platform_sp->RunShellCommand(command, + working_dir, + &shell_command.m_opaque_ptr->m_status, + &shell_command.m_opaque_ptr->m_signo, + &shell_command.m_opaque_ptr->m_output, + shell_command.m_opaque_ptr->m_timeout_sec); + } + else + { + sb_error.SetErrorString("invalid shell command (empty)"); + } + } + else + { + sb_error.SetErrorString("not connected"); + } + } + else + { + sb_error.SetErrorString("invalid platform"); + } + return sb_error; +} + +SBError +SBPlatform::MakeDirectory (const char *path, uint32_t file_permissions) +{ + SBError sb_error; + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + sb_error.ref() = platform_sp->MakeDirectory(path, file_permissions); + } + else + { + sb_error.SetErrorString("invalid platform"); + } + return sb_error; +} + +uint32_t +SBPlatform::GetFilePermissions (const char *path) +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + uint32_t file_permissions = 0; + platform_sp->GetFilePermissions(path, file_permissions); + return file_permissions; + } + return 0; + +} + +SBError +SBPlatform::SetFilePermissions (const char *path, uint32_t file_permissions) +{ + SBError sb_error; + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + sb_error.ref() = platform_sp->SetFilePermissions(path, file_permissions); + } + else + { + sb_error.SetErrorString("invalid platform"); + } + return sb_error; + +} + diff --git a/lldb/source/API/SBStream.cpp b/lldb/source/API/SBStream.cpp index dc8eb05ab0b..531ab9f463c 100644 --- a/lldb/source/API/SBStream.cpp +++ b/lldb/source/API/SBStream.cpp @@ -82,7 +82,7 @@ SBStream::RedirectToFile (const char *path, bool append) uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate; if (append) open_options |= File::eOpenOptionAppend; - stream_file->GetFile().Open (path, open_options, File::ePermissionsDefault); + stream_file->GetFile().Open (path, open_options, lldb::eFilePermissionsFileDefault); m_opaque_ap.reset (stream_file); diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index cff6e4e2de3..c8bc2171436 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -605,6 +605,19 @@ SBTarget::LaunchSimple error); } +SBError +SBTarget::Install() +{ + SBError sb_error; + TargetSP target_sp(GetSP()); + if (target_sp) + { + Mutex::Locker api_locker (target_sp->GetAPIMutex()); + sb_error.ref() = target_sp->Install(NULL); + } + return sb_error; +} + SBProcess SBTarget::Launch ( diff --git a/lldb/source/Commands/CommandObjectPlatform.cpp b/lldb/source/Commands/CommandObjectPlatform.cpp index ace1ef5b53f..5e842bf848a 100644 --- a/lldb/source/Commands/CommandObjectPlatform.cpp +++ b/lldb/source/Commands/CommandObjectPlatform.cpp @@ -22,6 +22,7 @@ #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionGroupFile.h" #include "lldb/Interpreter/OptionGroupPlatform.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Platform.h" @@ -119,31 +120,31 @@ public: m_permissions = perms; } case 'r': - m_permissions |= File::ePermissionsUserRead; + m_permissions |= lldb::eFilePermissionsUserRead; break; case 'w': - m_permissions |= File::ePermissionsUserWrite; + m_permissions |= lldb::eFilePermissionsUserWrite; break; case 'x': - m_permissions |= File::ePermissionsUserExecute; + m_permissions |= lldb::eFilePermissionsUserExecute; break; case 'R': - m_permissions |= File::ePermissionsGroupRead; + m_permissions |= lldb::eFilePermissionsGroupRead; break; case 'W': - m_permissions |= File::ePermissionsGroupWrite; + m_permissions |= lldb::eFilePermissionsGroupWrite; break; case 'X': - m_permissions |= File::ePermissionsGroupExecute; + m_permissions |= lldb::eFilePermissionsGroupExecute; break; case 'd': - m_permissions |= File::ePermissionsWorldRead; + m_permissions |= lldb::eFilePermissionsWorldRead; break; case 't': - m_permissions |= File::ePermissionsWorldWrite; + m_permissions |= lldb::eFilePermissionsWorldWrite; break; case 'e': - m_permissions |= File::ePermissionsWorldExecute; + m_permissions |= lldb::eFilePermissionsWorldExecute; break; default: @@ -524,6 +525,65 @@ protected: }; //---------------------------------------------------------------------- +// "platform settings" +//---------------------------------------------------------------------- +class CommandObjectPlatformSettings : public CommandObjectParsed +{ +public: + CommandObjectPlatformSettings (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "platform settings", + "Set settings for the current target's platform, or for a platform by name.", + "platform settings", + 0), + m_options (interpreter), + m_option_working_dir (LLDB_OPT_SET_1, false, "working-dir", 'w', 0, eArgTypePath, "The working directory for the platform.") + { + m_options.Append (&m_option_working_dir, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + } + + virtual + ~CommandObjectPlatformSettings () + { + } + +protected: + virtual bool + DoExecute (Args& args, CommandReturnObject &result) + { + PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); + if (platform_sp) + { + if (m_option_working_dir.GetOptionValue().OptionWasSet()) + platform_sp->SetWorkingDirectory (ConstString(m_option_working_dir.GetOptionValue().GetCurrentValue().GetPath().c_str())); + } + else + { + result.AppendError ("no platform is currently selected"); + 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; + } +protected: + + OptionGroupOptions m_options; + OptionGroupFile m_option_working_dir; + +}; + + +//---------------------------------------------------------------------- // "platform mkdir" //---------------------------------------------------------------------- class CommandObjectPlatformMkDir : public CommandObjectParsed @@ -552,15 +612,22 @@ public: { std::string cmd_line; args.GetCommandString(cmd_line); - mode_t perms; + uint32_t mode; const OptionPermissions* options_permissions = (OptionPermissions*)m_options.GetGroupWithOption('r'); if (options_permissions) - perms = options_permissions->m_permissions; + mode = 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); + mode = lldb::eFilePermissionsUserRWX | lldb::eFilePermissionsGroupRWX | lldb::eFilePermissionsWorldRX; + Error error = platform_sp->MakeDirectory(cmd_line.c_str(), mode); + if (error.Success()) + { + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendError(error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } } else { @@ -619,7 +686,7 @@ public: if (options_permissions) perms = options_permissions->m_permissions; else - perms = 0000700 | 0000070 | 0000007; + perms = lldb::eFilePermissionsUserRW | lldb::eFilePermissionsGroupRW | lldb::eFilePermissionsWorldRead; lldb::user_id_t fd = platform_sp->OpenFile(FileSpec(cmd_line.c_str(),false), File::eOpenOptionRead | File::eOpenOptionWrite | File::eOpenOptionAppend | File::eOpenOptionCanCreate, @@ -2129,82 +2196,6 @@ CommandObjectPlatformShell::CommandOptions::g_option_table[] = { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } }; -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: - 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 @@ -2236,10 +2227,9 @@ public: 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) + FileSpec src(args.GetArgumentAtIndex(0), true); + FileSpec dst(args.GetArgumentAtIndex(1), false); + if (src.Exists() == false) { result.AppendError("source location does not exist or is not accessible"); result.SetStatus(eReturnStatusFailed); @@ -2252,75 +2242,21 @@ public: 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) + + Error error = platform_sp->Install(src, dst); + if (error.Success()) { - // 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(); + result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { - result.AppendError("source is not a known type of file"); + result.AppendErrorWithFormat("install failed: %s", error.AsCString()); result.SetStatus(eReturnStatusFailed); - return result.Succeeded(); } + 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; - } + }; //---------------------------------------------------------------------- @@ -2332,21 +2268,22 @@ CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter) : "A set of commands to manage and create platforms.", "platform [connect|disconnect|info|list|status|select] ...") { - LoadSubCommand ("select", CommandObjectSP (new CommandObjectPlatformSelect (interpreter))); - LoadSubCommand ("list" , CommandObjectSP (new CommandObjectPlatformList (interpreter))); - LoadSubCommand ("status", CommandObjectSP (new CommandObjectPlatformStatus (interpreter))); - LoadSubCommand ("connect", CommandObjectSP (new CommandObjectPlatformConnect (interpreter))); - LoadSubCommand ("disconnect", CommandObjectSP (new CommandObjectPlatformDisconnect (interpreter))); + LoadSubCommand ("select", CommandObjectSP (new CommandObjectPlatformSelect (interpreter))); + LoadSubCommand ("list" , CommandObjectSP (new CommandObjectPlatformList (interpreter))); + LoadSubCommand ("status", CommandObjectSP (new CommandObjectPlatformStatus (interpreter))); + LoadSubCommand ("connect", CommandObjectSP (new CommandObjectPlatformConnect (interpreter))); + LoadSubCommand ("disconnect", CommandObjectSP (new CommandObjectPlatformDisconnect (interpreter))); + LoadSubCommand ("settings", CommandObjectSP (new CommandObjectPlatformSettings (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))); + 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))); + LoadSubCommand ("process", CommandObjectSP (new CommandObjectPlatformProcess (interpreter))); + LoadSubCommand ("shell", CommandObjectSP (new CommandObjectPlatformShell (interpreter))); + LoadSubCommand ("target-install", CommandObjectSP (new CommandObjectPlatformInstall (interpreter))); } diff --git a/lldb/source/Core/ConnectionFileDescriptor.cpp b/lldb/source/Core/ConnectionFileDescriptor.cpp index 8e80543b857..5764a212ab4 100644 --- a/lldb/source/Core/ConnectionFileDescriptor.cpp +++ b/lldb/source/Core/ConnectionFileDescriptor.cpp @@ -53,6 +53,8 @@ #include "lldb/Core/Log.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Core/Timer.h" +#include "lldb/Host/Host.h" + using namespace lldb; using namespace lldb_private; @@ -1209,6 +1211,7 @@ ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *err saddr_un.sun_len = SUN_LEN (&saddr_un); #endif + Host::Unlink (socket_name); if (::bind (listen_socket, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) == 0) { if (::listen (listen_socket, 5) == 0) diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 3f3be9360ef..f90a097416d 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -135,6 +135,7 @@ Module::Module (const ModuleSpec &module_spec) : m_uuid (), m_file (module_spec.GetFileSpec()), m_platform_file(module_spec.GetPlatformFileSpec()), + m_remote_install_file(), m_symfile_spec (module_spec.GetSymbolFileSpec()), m_object_name (module_spec.GetObjectName()), m_object_offset (module_spec.GetObjectOffset()), @@ -179,6 +180,7 @@ Module::Module(const FileSpec& file_spec, m_uuid (), m_file (file_spec), m_platform_file(), + m_remote_install_file (), m_symfile_spec (), m_object_name (), m_object_offset (object_offset), diff --git a/lldb/source/Core/StreamFile.cpp b/lldb/source/Core/StreamFile.cpp index 9a4eb796dbe..2285ca95445 100644 --- a/lldb/source/Core/StreamFile.cpp +++ b/lldb/source/Core/StreamFile.cpp @@ -49,7 +49,7 @@ StreamFile::StreamFile (FILE *fh, bool transfer_ownership) : StreamFile::StreamFile (const char *path) : Stream (), - m_file (path, File::eOpenOptionWrite | File::eOpenOptionCanCreate, File::ePermissionsDefault) + m_file (path, File::eOpenOptionWrite | File::eOpenOptionCanCreate, lldb::eFilePermissionsFileDefault) { } diff --git a/lldb/source/Host/common/File.cpp b/lldb/source/Host/common/File.cpp index addd4351540..c8dff198cb7 100644 --- a/lldb/source/Host/common/File.cpp +++ b/lldb/source/Host/common/File.cpp @@ -1,4 +1,4 @@ -//===-- FileSpec.cpp --------------------------------------------*- C++ -*-===// +//===-- File.cpp ------------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// - #include "lldb/Host/File.h" #include <errno.h> @@ -237,6 +236,9 @@ File::Open (const char *path, uint32_t options, uint32_t permissions) else if (read) { oflag |= O_RDONLY; + + if (options & eOpenoptionDontFollowSymlinks) + oflag |= O_NOFOLLOW; } #ifndef _WIN32 @@ -249,15 +251,15 @@ File::Open (const char *path, uint32_t options, uint32_t permissions) mode_t mode = 0; if (oflag & O_CREAT) { - if (permissions & ePermissionsUserRead) mode |= S_IRUSR; - if (permissions & ePermissionsUserWrite) mode |= S_IWUSR; - if (permissions & ePermissionsUserExecute) mode |= S_IXUSR; - if (permissions & ePermissionsGroupRead) mode |= S_IRGRP; - if (permissions & ePermissionsGroupWrite) mode |= S_IWGRP; - if (permissions & ePermissionsGroupExecute) mode |= S_IXGRP; - if (permissions & ePermissionsWorldRead) mode |= S_IROTH; - if (permissions & ePermissionsWorldWrite) mode |= S_IWOTH; - if (permissions & ePermissionsWorldExecute) mode |= S_IXOTH; + if (permissions & lldb::eFilePermissionsUserRead) mode |= S_IRUSR; + if (permissions & lldb::eFilePermissionsUserWrite) mode |= S_IWUSR; + if (permissions & lldb::eFilePermissionsUserExecute) mode |= S_IXUSR; + if (permissions & lldb::eFilePermissionsGroupRead) mode |= S_IRGRP; + if (permissions & lldb::eFilePermissionsGroupWrite) mode |= S_IWGRP; + if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP; + if (permissions & lldb::eFilePermissionsWorldRead) mode |= S_IROTH; + if (permissions & lldb::eFilePermissionsWorldWrite) mode |= S_IWOTH; + if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH; } do diff --git a/lldb/source/Host/common/FileSpec.cpp b/lldb/source/Host/common/FileSpec.cpp index 33de198072d..48f1ac78d92 100644 --- a/lldb/source/Host/common/FileSpec.cpp +++ b/lldb/source/Host/common/FileSpec.cpp @@ -34,6 +34,7 @@ #include "lldb/Core/StreamString.h" #include "lldb/Host/File.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Host/Host.h" #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataBufferMemoryMap.h" #include "lldb/Core/RegularExpression.h" @@ -646,6 +647,15 @@ FileSpec::GetFileType () const return eFileTypeInvalid; } +uint32_t +FileSpec::GetPermissions () const +{ + uint32_t file_permissions = 0; + if (*this) + Host::GetFilePermissions(GetPath().c_str(), file_permissions); + return file_permissions; +} + TimeValue FileSpec::GetModificationTime () const { @@ -1161,26 +1171,26 @@ FileSpec::CopyByRemovingLastPathComponent () const return FileSpec(m_directory.GetCString(),resolve); } -const char* +ConstString FileSpec::GetLastPathComponent () const { - if (m_filename.IsEmpty() && m_directory.IsEmpty()) - return NULL; - if (m_filename.IsEmpty()) + if (m_filename) + return m_filename; + if (m_directory) { const char* dir_cstr = m_directory.GetCString(); const char* last_slash_ptr = ::strrchr(dir_cstr, '/'); if (last_slash_ptr == NULL) - return m_directory.GetCString(); + return m_directory; if (last_slash_ptr == dir_cstr) { if (last_slash_ptr[1] == 0) - return last_slash_ptr; + return ConstString(last_slash_ptr); else - return last_slash_ptr+1; + return ConstString(last_slash_ptr+1); } if (last_slash_ptr[1] != 0) - return last_slash_ptr+1; + return ConstString(last_slash_ptr+1); const char* penultimate_slash_ptr = last_slash_ptr; while (*penultimate_slash_ptr) { @@ -1190,10 +1200,10 @@ FileSpec::GetLastPathComponent () const if (*penultimate_slash_ptr == '/') break; } - ConstString new_path(penultimate_slash_ptr+1,last_slash_ptr-penultimate_slash_ptr); - return new_path.AsCString(); + ConstString result(penultimate_slash_ptr+1,last_slash_ptr-penultimate_slash_ptr); + return result; } - return m_filename.GetCString(); + return ConstString(); } void diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 296e4b40bf0..c095e6b46d2 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -1826,11 +1826,130 @@ Host::LaunchApplication (const FileSpec &app_file_spec) return LLDB_INVALID_PROCESS_ID; } -uint32_t -Host::MakeDirectory (const char* path, mode_t mode) +#endif + + +#ifdef LLDB_DISABLE_POSIX + +Error +Host::MakeDirectory (const char* path, uint32_t mode) +{ + Error error; + error.SetErrorString("%s in not implemented on this host", __PRETTY_FUNCTION__); + return error; +} + +Error +Host::GetFilePermissions (const char* path, uint32_t &file_permissions) +{ + Error error; + error.SetErrorString("%s is not supported on this host", __PRETTY_FUNCTION__); + return error; +} + +Error +Host::SetFilePermissions (const char* path, uint32_t file_permissions) +{ + Error error; + error.SetErrorString("%s is not supported on this host", __PRETTY_FUNCTION__); + return error; +} + +Error +Host::Symlink (const char *src, const char *dst) +{ + Error error; + error.SetErrorString("%s is not supported on this host", __PRETTY_FUNCTION__); + return error; +} + +Error +Host::Readlink (const char *path, char *buf, size_t buf_len) +{ + Error error; + error.SetErrorString("%s is not supported on this host", __PRETTY_FUNCTION__); + return error; +} + +Error +Host::Unlink (const char *path) +{ + Error error; + error.SetErrorString("%s is not supported on this host", __PRETTY_FUNCTION__); + return error; +} + +#else + +Error +Host::MakeDirectory (const char* path, uint32_t file_permissions) +{ + Error error; + if (::mkdir(path, file_permissions) != 0) + error.SetErrorToErrno(); + return error; +} + +Error +Host::GetFilePermissions (const char* path, uint32_t &file_permissions) +{ + Error error; + struct stat file_stats; + if (::stat (path, &file_stats) == 0) + { + // The bits in "st_mode" currently match the definitions + // for the file mode bits in unix. + file_permissions = file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + } + else + { + error.SetErrorToErrno(); + } + return error; +} + +Error +Host::SetFilePermissions (const char* path, uint32_t file_permissions) +{ + Error error; + if (::chmod(path, file_permissions) != 0) + error.SetErrorToErrno(); + return error; +} + +Error +Host::Symlink (const char *src, const char *dst) { - return UINT32_MAX; + Error error; + if (::symlink(dst, src) == -1) + error.SetErrorToErrno(); + return error; } + +Error +Host::Unlink (const char *path) +{ + Error error; + if (::unlink(path) == -1) + error.SetErrorToErrno(); + return error; +} + +Error +Host::Readlink (const char *path, char *buf, size_t buf_len) +{ + Error error; + ssize_t count = ::readlink(path, buf, buf_len); + if (count < 0) + error.SetErrorToErrno(); + else if (count < (buf_len-1)) + buf[count] = '\0'; // Success + else + error.SetErrorString("'buf' buffer is too small to contain link contents"); + return error; +} + + #endif typedef std::map<lldb::user_id_t, lldb::FileSP> FDToFileMap; @@ -1843,7 +1962,7 @@ FDToFileMap& GetFDToFileMap() lldb::user_id_t Host::OpenFile (const FileSpec& file_spec, uint32_t flags, - mode_t mode, + uint32_t mode, Error &error) { std::string path (file_spec.GetPath()); diff --git a/lldb/source/Host/macosx/Host.mm b/lldb/source/Host/macosx/Host.mm index 7b3b1d0233d..2d502716179 100644 --- a/lldb/source/Host/macosx/Host.mm +++ b/lldb/source/Host/macosx/Host.mm @@ -363,7 +363,7 @@ WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds) // StreamFile command_file; // command_file.GetFile().Open (temp_file_path, // File::eOpenOptionWrite | File::eOpenOptionCanCreate, -// File::ePermissionsDefault); +// lldb::eFilePermissionsDefault); // // if (!command_file.GetFile().IsValid()) // return LLDB_INVALID_PROCESS_ID; @@ -1984,10 +1984,3 @@ Host::GetAuxvData(lldb_private::Process *process) { return lldb::DataBufferSP(); } - -uint32_t -Host::MakeDirectory (const char* path, mode_t mode) -{ - return ::mkdir(path,mode); -} - diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 841d5405e1a..0a484d8cc40 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -761,6 +761,31 @@ PlatformDarwin::LaunchProcess (ProcessLaunchInfo &launch_info) } lldb::ProcessSP +PlatformDarwin::DebugProcess (ProcessLaunchInfo &launch_info, + Debugger &debugger, + Target *target, // Can be NULL, if NULL create a new target, else use existing one + Listener &listener, + Error &error) +{ + ProcessSP process_sp; + + if (IsHost()) + { + process_sp = Platform::DebugProcess (launch_info, debugger, target, listener, error); + } + else + { + if (m_remote_platform_sp) + process_sp = m_remote_platform_sp->DebugProcess (launch_info, debugger, target, listener, error); + else + error.SetErrorString ("the platform is not currently connected"); + } + return process_sp; + +} + + +lldb::ProcessSP PlatformDarwin::Attach (ProcessAttachInfo &attach_info, Debugger &debugger, Target *target, diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h index 64598c93f6b..7a28d3c7e6e 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h @@ -99,6 +99,13 @@ public: LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info); virtual lldb::ProcessSP + DebugProcess (lldb_private::ProcessLaunchInfo &launch_info, + lldb_private::Debugger &debugger, + lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one + lldb_private::Listener &listener, + lldb_private::Error &error); + + virtual lldb::ProcessSP Attach (lldb_private::ProcessAttachInfo &attach_info, lldb_private::Debugger &debugger, lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index 34316c48427..b5f92dcc3dc 100644 --- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -76,44 +76,56 @@ PlatformPOSIX::RunShellCommand (const char *command, // Shouldn't be N } } -uint32_t -PlatformPOSIX::MakeDirectory (const std::string &path, - mode_t mode) +Error +PlatformPOSIX::MakeDirectory (const char *path, uint32_t file_permissions) { - 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); + if (m_remote_platform_sp) + return m_remote_platform_sp->MakeDirectory(path, file_permissions); + else + return Platform::MakeDirectory(path ,file_permissions); +} + +Error +PlatformPOSIX::GetFilePermissions (const char *path, uint32_t &file_permissions) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetFilePermissions(path, file_permissions); + else + return Platform::GetFilePermissions(path ,file_permissions); +} + +Error +PlatformPOSIX::SetFilePermissions (const char *path, uint32_t file_permissions) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->MakeDirectory(path, file_permissions); + else + return Platform::SetFilePermissions(path ,file_permissions); } lldb::user_id_t PlatformPOSIX::OpenFile (const FileSpec& file_spec, uint32_t flags, - mode_t mode, + uint32_t mode, Error &error) { if (IsHost()) - { return Host::OpenFile(file_spec, flags, mode, error); - } - if (IsRemote() && m_remote_platform_sp) + else if (m_remote_platform_sp) return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error); - return Platform::OpenFile(file_spec, flags, mode, error); + else + 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) + else if (m_remote_platform_sp) return m_remote_platform_sp->CloseFile(fd, error); - return Platform::CloseFile(fd, error); + else + return Platform::CloseFile(fd, error); } uint64_t @@ -124,12 +136,11 @@ PlatformPOSIX::ReadFile (lldb::user_id_t fd, Error &error) { if (IsHost()) - { return Host::ReadFile(fd, offset, dst, dst_len, error); - } - if (IsRemote() && m_remote_platform_sp) + else if (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); + else + return Platform::ReadFile(fd, offset, dst, dst_len, error); } uint64_t @@ -140,13 +151,11 @@ PlatformPOSIX::WriteFile (lldb::user_id_t fd, Error &error) { if (IsHost()) - { return Host::WriteFile(fd, offset, src, src_len, error); - } - if (IsRemote() && m_remote_platform_sp) + else if (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); + else + return Platform::WriteFile(fd, offset, src, src_len, error); } static uint32_t @@ -184,6 +193,8 @@ PlatformPOSIX::PutFile (const lldb_private::FileSpec& source, uint32_t uid, uint32_t gid) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (IsHost()) { if (FileSpec::Equal(source, destination, true)) @@ -213,7 +224,7 @@ PlatformPOSIX::PutFile (const lldb_private::FileSpec& source, return Error("unable to perform chown"); return Error(); } - else if (IsRemote() && m_remote_platform_sp) + else if (m_remote_platform_sp) { if (GetSupportsRSync()) { @@ -244,7 +255,6 @@ PlatformPOSIX::PutFile (const lldb_private::FileSpec& source, 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; @@ -263,20 +273,35 @@ PlatformPOSIX::PutFile (const lldb_private::FileSpec& source, } // if we are still here rsync has failed - let's try the slow way before giving up } + + if (log) + log->Printf ("PlatformPOSIX::PutFile(src='%s', dst='%s', uid=%u, gid=%u)", + source.GetPath().c_str(), + destination.GetPath().c_str(), + uid, + gid); // REMOVE THIS PRINTF PRIOR TO CHECKIN // 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 (log) + log->Printf("[PutFile] Using block by block transfer....\n"); + + uint32_t source_open_options = File::eOpenOptionRead; + if (source.GetFileType() == FileSpec::eFileTypeSymbolicLink) + source_open_options |= File::eOpenoptionDontFollowSymlinks; + + File source_file(source, source_open_options, lldb::eFilePermissionsUserRW); + Error error; + uint32_t permissions = source_file.GetPermissions(error); + if (permissions == 0) + permissions = lldb::eFilePermissionsFileDefault; + 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, + permissions, error); if (log) log->Printf ("dest_file = %" PRIu64 "\n", dest_file); @@ -314,45 +339,52 @@ lldb::user_id_t PlatformPOSIX::GetFileSize (const FileSpec& file_spec) { if (IsHost()) - { return Host::GetFileSize(file_spec); - } - if (IsRemote() && m_remote_platform_sp) + else if (m_remote_platform_sp) return m_remote_platform_sp->GetFileSize(file_spec); - return Platform::GetFileSize(file_spec); + else + return Platform::GetFileSize(file_spec); +} + +Error +PlatformPOSIX::CreateSymlink(const char *src, const char *dst) +{ + if (IsHost()) + return Host::Symlink(src, dst); + else if (m_remote_platform_sp) + return m_remote_platform_sp->CreateSymlink(src, dst); + else + return Platform::CreateSymlink(src, dst); } bool PlatformPOSIX::GetFileExists (const FileSpec& file_spec) { if (IsHost()) - { return file_spec.Exists(); - } - if (IsRemote() && m_remote_platform_sp) + else if (m_remote_platform_sp) return m_remote_platform_sp->GetFileExists(file_spec); - return Platform::GetFileExists(file_spec); + else + return Platform::GetFileExists(file_spec); } -uint32_t -PlatformPOSIX::GetFilePermissions (const lldb_private::FileSpec &file_spec, - lldb_private::Error &error) +Error +PlatformPOSIX::Unlink (const char *path) { 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); - + return Host::Unlink (path); + else if (m_remote_platform_sp) + return m_remote_platform_sp->Unlink(path); + else + return Platform::Unlink(path); } - lldb_private::Error PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path */, - const lldb_private::FileSpec& destination /* local file path */) + const lldb_private::FileSpec& destination /* local file path */) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + // Check the args, first. std::string src_path (source.GetPath()); if (src_path.empty()) @@ -378,7 +410,7 @@ PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path return Error("unable to perform copy"); return Error(); } - else if (IsRemote() && m_remote_platform_sp) + else if (m_remote_platform_sp) { if (GetSupportsRSync()) { @@ -403,7 +435,6 @@ PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path 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; @@ -421,22 +452,22 @@ PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path // 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"); + if (log) + log->Printf("[GetFile] Using block by block transfer....\n"); Error error; user_id_t fd_src = OpenFile (source, File::eOpenOptionRead, - File::ePermissionsDefault, + lldb::eFilePermissionsFileDefault, error); if (fd_src == UINT64_MAX) return Error("unable to open source file"); - uint32_t permissions = GetFilePermissions(source, error); + uint32_t permissions = 0; + error = GetFilePermissions(source.GetPath().c_str(), permissions); if (permissions == 0) - permissions = File::ePermissionsDefault; + permissions = lldb::eFilePermissionsFileDefault; user_id_t fd_dst = Host::OpenFile(destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate, @@ -539,3 +570,22 @@ PlatformPOSIX::CalculateMD5 (const FileSpec& file_spec, return m_remote_platform_sp->CalculateMD5(file_spec, low, high); return false; } + +lldb_private::ConstString +PlatformPOSIX::GetRemoteWorkingDirectory() +{ + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->GetRemoteWorkingDirectory(); + else + return Platform::GetRemoteWorkingDirectory(); +} + +bool +PlatformPOSIX::SetRemoteWorkingDirectory(const lldb_private::ConstString &path) +{ + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->SetRemoteWorkingDirectory(path); + else + return Platform::SetRemoteWorkingDirectory(path); +} + diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h index 4119e452bf7..336e0f90fca 100644 --- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -43,7 +43,7 @@ public: virtual lldb::user_id_t OpenFile (const lldb_private::FileSpec& file_spec, uint32_t flags, - mode_t mode, + uint32_t mode, lldb_private::Error &error); virtual bool @@ -68,9 +68,18 @@ public: GetFileSize (const lldb_private::FileSpec& file_spec); virtual lldb_private::Error + CreateSymlink(const char *src, const char *dst); + + virtual lldb_private::Error GetFile (const lldb_private::FileSpec& source, const lldb_private::FileSpec& destination); + virtual lldb_private::ConstString + GetRemoteWorkingDirectory(); + + virtual bool + SetRemoteWorkingDirectory(const lldb_private::ConstString &path); + virtual lldb_private::Error RunShellCommand (const char *command, // Shouldn't be NULL const char *working_dir, // Pass NULL to use the current working directory @@ -79,16 +88,20 @@ public: 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 lldb_private::Error + MakeDirectory (const char *path, uint32_t mode); + virtual lldb_private::Error + GetFilePermissions (const char *path, uint32_t &file_permissions); + + virtual lldb_private::Error + SetFilePermissions (const char *path, uint32_t file_permissions); + 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 + Unlink (const char *path); virtual std::string GetPlatformSpecificConnectionInformation(); diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index 4aeec032d71..752b56c3efb 100644 --- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -194,6 +194,39 @@ PlatformRemoteGDBServer::GetRemoteSystemArchitecture () return m_gdb_client.GetSystemArchitecture(); } +lldb_private::ConstString +PlatformRemoteGDBServer::GetRemoteWorkingDirectory() +{ + if (IsConnected()) + { + if (!m_working_dir) + { + std::string cwd; + if (m_gdb_client.GetWorkingDir(cwd)) + m_working_dir = ConstString(cwd.c_str()); + } + return m_working_dir; + } + else + { + return Platform::GetRemoteWorkingDirectory(); + } +} + +bool +PlatformRemoteGDBServer::SetRemoteWorkingDirectory(const lldb_private::ConstString &path) +{ + if (IsConnected()) + { + // Clear the working directory it case it doesn't get set correctly. This will + // for use to re-read it + m_working_dir.Clear(); + return m_gdb_client.SetWorkingDir(path.GetCString()) == 0; + } + else + return Platform::SetRemoteWorkingDirectory(path); +} + bool PlatformRemoteGDBServer::IsConnected () const { @@ -222,6 +255,9 @@ PlatformRemoteGDBServer::ConnectRemote (Args& args) { m_gdb_client.QueryNoAckModeSupported(); m_gdb_client.GetHostInfo(); + // If a working directory was set prior to connecting, send it down now + if (m_working_dir) + m_gdb_client.SetWorkingDir(m_working_dir.GetCString()); #if 0 m_gdb_client.TestPacketSpeed(10000); #endif @@ -324,7 +360,6 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info) } // Send the environment and the program + arguments after we connect - const char **argv = launch_info.GetArguments().GetConstArgumentVector(); const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector(); if (envp) @@ -343,7 +378,7 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info) 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); + int arg_packet_err = m_gdb_client.SendArgumentsPacket (launch_info); m_gdb_client.SetPacketTimeout (old_packet_timeout); if (arg_packet_err == 0) { @@ -367,6 +402,80 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info) } lldb::ProcessSP +PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_info, + lldb_private::Debugger &debugger, + lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one + lldb_private::Listener &listener, + lldb_private::Error &error) +{ + lldb::ProcessSP process_sp; + if (IsRemote()) + { + if (IsConnected()) + { + lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; + uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid); + + if (port == 0) + { + error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ()); + } + else + { + if (target == NULL) + { + TargetSP new_target_sp; + + error = debugger.GetTargetList().CreateTarget (debugger, + NULL, + NULL, + false, + NULL, + new_target_sp); + target = new_target_sp.get(); + } + else + error.Clear(); + + if (target && error.Success()) + { + debugger.GetTargetList().SetSelectedTarget(target); + + // The darwin always currently uses the GDB remote debugger plug-in + // so even when debugging locally we are debugging remotely! + process_sp = target->CreateProcess (listener, "gdb-remote", NULL); + + 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", + 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->Launch(launch_info); + else if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + m_gdb_client.KillSpawnedProcess(debugserver_pid); + } + } + } + } + else + { + error.SetErrorString("not connected to remote gdb server"); + } + } + return process_sp; + +} + +lldb::ProcessSP PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info, Debugger &debugger, Target *target, // Can be NULL, if NULL create a new target, else use existing one @@ -441,17 +550,42 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info, return process_sp; } -uint32_t -PlatformRemoteGDBServer::MakeDirectory (const std::string &path, - mode_t mode) +Error +PlatformRemoteGDBServer::MakeDirectory (const char *path, uint32_t mode) +{ + Error error = m_gdb_client.MakeDirectory(path,mode); + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf ("PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) error = %u (%s)", path, mode, error.GetError(), error.AsCString()); + return error; +} + + +Error +PlatformRemoteGDBServer::GetFilePermissions (const char *path, uint32_t &file_permissions) { - return m_gdb_client.MakeDirectory(path,mode); + Error error = m_gdb_client.GetFilePermissions(path, file_permissions); + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf ("PlatformRemoteGDBServer::GetFilePermissions(path='%s', file_permissions=%o) error = %u (%s)", path, file_permissions, error.GetError(), error.AsCString()); + return error; } +Error +PlatformRemoteGDBServer::SetFilePermissions (const char *path, uint32_t file_permissions) +{ + Error error = m_gdb_client.SetFilePermissions(path, file_permissions); + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf ("PlatformRemoteGDBServer::SetFilePermissions(path='%s', file_permissions=%o) error = %u (%s)", path, file_permissions, error.GetError(), error.AsCString()); + return error; +} + + lldb::user_id_t PlatformRemoteGDBServer::OpenFile (const lldb_private::FileSpec& file_spec, uint32_t flags, - mode_t mode, + uint32_t mode, Error &error) { return m_gdb_client.OpenFile (file_spec, flags, mode, error); @@ -469,13 +603,6 @@ 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, @@ -505,6 +632,27 @@ PlatformRemoteGDBServer::PutFile (const lldb_private::FileSpec& source, return Platform::PutFile(source,destination,uid,gid); } +Error +PlatformRemoteGDBServer::CreateSymlink (const char *src, // The name of the link is in src + const char *dst) // The symlink points to dst +{ + Error error = m_gdb_client.CreateSymlink (src, dst); + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf ("PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') error = %u (%s)", src, dst, error.GetError(), error.AsCString()); + return error; +} + +Error +PlatformRemoteGDBServer::Unlink (const char *path) +{ + Error error = m_gdb_client.Unlink (path); + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf ("PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)", path, error.GetError(), error.AsCString()); + return error; +} + bool PlatformRemoteGDBServer::GetFileExists (const lldb_private::FileSpec& file_spec) { diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h index 70db6bafacd..808fb5ed61c 100644 --- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -89,6 +89,13 @@ public: LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info); virtual lldb::ProcessSP + DebugProcess (lldb_private::ProcessLaunchInfo &launch_info, + lldb_private::Debugger &debugger, + lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one + lldb_private::Listener &listener, + lldb_private::Error &error); + + virtual lldb::ProcessSP Attach (lldb_private::ProcessAttachInfo &attach_info, lldb_private::Debugger &debugger, lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one @@ -115,6 +122,13 @@ public: virtual lldb_private::ArchSpec GetRemoteSystemArchitecture (); + virtual lldb_private::ConstString + GetRemoteWorkingDirectory(); + + virtual bool + SetRemoteWorkingDirectory(const lldb_private::ConstString &path); + + // Remote subclasses should override this and return a valid instance // name if connected. virtual const char * @@ -135,14 +149,20 @@ public: virtual lldb_private::Error DisconnectRemote (); - virtual uint32_t - MakeDirectory (const std::string &path, - mode_t mode); + virtual lldb_private::Error + MakeDirectory (const char *path, uint32_t file_permissions); + + virtual lldb_private::Error + GetFilePermissions (const char *path, uint32_t &file_permissions); + + virtual lldb_private::Error + SetFilePermissions (const char *path, uint32_t file_permissions); + virtual lldb::user_id_t OpenFile (const lldb_private::FileSpec& file_spec, uint32_t flags, - mode_t mode, + uint32_t mode, lldb_private::Error &error); virtual bool @@ -172,12 +192,14 @@ public: uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX); + virtual lldb_private::Error + CreateSymlink (const char *src, const char *dst); + 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 + Unlink (const char *path); virtual lldb_private::Error RunShellCommand (const char *command, // Shouldn't be NULL diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index da2299a408c..7cd77e58f52 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -989,19 +989,43 @@ GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str) } int -GDBRemoteCommunicationClient::SendArgumentsPacket (char const *argv[]) -{ - if (argv && argv[0]) +GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &launch_info) +{ + // Since we don't get the send argv0 separate from the executable path, we need to + // make sure to use the actual exectuable path found in the launch_info... + std::vector<const char *> argv; + FileSpec exe_file = launch_info.GetExecutableFile(); + std::string exe_path; + const char *arg = NULL; + const Args &launch_args = launch_info.GetArguments(); + if (exe_file) + exe_path = exe_file.GetPath(); + else + { + arg = launch_args.GetArgumentAtIndex(0); + if (arg) + exe_path = arg; + } + if (!exe_path.empty()) + { + argv.push_back(exe_path.c_str()); + for (uint32_t i=1; (arg = launch_args.GetArgumentAtIndex(i)) != NULL; ++i) + { + if (arg) + argv.push_back(arg); + } + } + if (!argv.empty()) { StreamString packet; packet.PutChar('A'); - const char *arg; - for (uint32_t i = 0; (arg = argv[i]) != NULL; ++i) + for (size_t i = 0, n = argv.size(); i < n; ++i) { + arg = argv[i]; const int arg_len = strlen(arg); if (i > 0) packet.PutChar(','); - packet.Printf("%i,%i,", arg_len * 2, i); + packet.Printf("%i,%i,", arg_len * 2, (int)i); packet.PutBytesAsRawHex8 (arg, arg_len); } @@ -1785,6 +1809,22 @@ GDBRemoteCommunicationClient::SetSTDERR (char const *path) return -1; } +bool +GDBRemoteCommunicationClient::GetWorkingDir (std::string &cwd) +{ + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false)) + { + if (response.IsUnsupportedResponse()) + return false; + if (response.IsErrorResponse()) + return false; + response.GetHexByteString (cwd); + return !cwd.empty(); + } + return false; +} + int GDBRemoteCommunicationClient::SetWorkingDir (char const *path) { @@ -2497,7 +2537,7 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command, // uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish { lldb_private::StreamString stream; - stream.PutCString("qPlatform_RunCommand:"); + stream.PutCString("qPlatform_shell:"); stream.PutBytesAsRawHex8(command, strlen(command)); stream.PutChar(','); stream.PutHex32(timeout_sec); @@ -2536,26 +2576,46 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command, // return Error("unable to send packet"); } -uint32_t -GDBRemoteCommunicationClient::MakeDirectory (const std::string &path, - mode_t mode) +Error +GDBRemoteCommunicationClient::MakeDirectory (const char *path, + uint32_t file_permissions) { lldb_private::StreamString stream; - stream.PutCString("qPlatform_IO_MkDir:"); - stream.PutHex32(mode); + stream.PutCString("qPlatform_mkdir:"); + stream.PutHex32(file_permissions); stream.PutChar(','); - stream.PutBytesAsRawHex8(path.c_str(), path.size()); + stream.PutBytesAsRawHex8(path, strlen(path)); 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 Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); } - return UINT32_MAX; + return Error(); } +Error +GDBRemoteCommunicationClient::SetFilePermissions (const char *path, + uint32_t file_permissions) +{ + lldb_private::StreamString stream; + stream.PutCString("qPlatform_chmod:"); + stream.PutHex32(file_permissions); + stream.PutChar(','); + stream.PutBytesAsRawHex8(path, strlen(path)); + const char *packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); + } + return Error(); + +} + static uint64_t ParseHostIOPacketResponse (StringExtractorGDBRemote &response, uint64_t fail_result, @@ -2643,13 +2703,13 @@ GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_sp return UINT64_MAX; } -uint32_t -GDBRemoteCommunicationClient::GetFilePermissions(const lldb_private::FileSpec& file_spec, Error &error) +Error +GDBRemoteCommunicationClient::GetFilePermissions(const char *path, uint32_t &file_permissions) { + Error error; lldb_private::StreamString stream; stream.PutCString("vFile:mode:"); - std::string path (file_spec.GetPath()); - stream.PutCStringAsRawHex8(path.c_str()); + stream.PutCStringAsRawHex8(path); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; @@ -2658,29 +2718,34 @@ GDBRemoteCommunicationClient::GetFilePermissions(const lldb_private::FileSpec& f if (response.GetChar() != 'F') { error.SetErrorStringWithFormat ("invalid response to '%s' packet", packet); - return 0; } - const uint32_t mode = response.GetS32(-1); - if (mode == -1) + else { - if (response.GetChar() == ',') + const uint32_t mode = response.GetS32(-1); + if (mode == -1) { - int response_errno = response.GetS32(-1); - if (response_errno > 0) - error.SetError(response_errno, lldb::eErrorTypePOSIX); + if (response.GetChar() == ',') + { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + else + error.SetErrorToGenericError(); + } else error.SetErrorToGenericError(); } + else + { + file_permissions = mode & (S_IRWXU|S_IRWXG|S_IRWXO); + } } - else - error.Clear(); - return mode & (S_IRWXU|S_IRWXG|S_IRWXO); } else { error.SetErrorStringWithFormat ("failed to send '%s' packet", packet); } - return 0; + return error; } uint64_t @@ -2762,6 +2827,90 @@ GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd, return 0; } +Error +GDBRemoteCommunicationClient::CreateSymlink (const char *src, const char *dst) +{ + Error error; + lldb_private::StreamGDBRemote stream; + stream.PutCString("vFile:symlink:"); + // the unix symlink() command reverses its parameters where the dst if first, + // so we follow suit here + stream.PutCStringAsRawHex8(dst); + stream.PutChar(','); + stream.PutCStringAsRawHex8(src); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() == 'F') + { + uint32_t result = response.GetU32(UINT32_MAX); + if (result != 0) + { + error.SetErrorToGenericError(); + if (response.GetChar() == ',') + { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + } + } + } + else + { + // Should have returned with 'F<result>[,<errno>]' + error.SetErrorStringWithFormat("symlink failed"); + } + } + else + { + error.SetErrorString ("failed to send vFile:symlink packet"); + } + return error; +} + +Error +GDBRemoteCommunicationClient::Unlink (const char *path) +{ + Error error; + lldb_private::StreamGDBRemote stream; + stream.PutCString("vFile:unlink:"); + // the unix symlink() command reverses its parameters where the dst if first, + // so we follow suit here + stream.PutCStringAsRawHex8(path); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() == 'F') + { + uint32_t result = response.GetU32(UINT32_MAX); + if (result != 0) + { + error.SetErrorToGenericError(); + if (response.GetChar() == ',') + { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + } + } + } + else + { + // Should have returned with 'F<result>[,<errno>]' + error.SetErrorStringWithFormat("unlink failed"); + } + } + else + { + error.SetErrorString ("failed to send vFile:unlink packet"); + } + return error; +} + // Extension of host I/O packets to get whether a file exists. bool GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 530655bab6e..7d4d9a29729 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -38,7 +38,6 @@ public: //------------------------------------------------------------------ GDBRemoteCommunicationClient(bool is_platform); - virtual ~GDBRemoteCommunicationClient(); //------------------------------------------------------------------ @@ -65,7 +64,7 @@ public: size_t packet_length, StringExtractorGDBRemote &response); - virtual bool + bool GetThreadSuffixSupported (); void @@ -109,7 +108,7 @@ public: /// response was received. //------------------------------------------------------------------ int - SendArgumentsPacket (char const *argv[]); + SendArgumentsPacket (const lldb_private::ProcessLaunchInfo &launch_info); //------------------------------------------------------------------ /// Sends a "QEnvironment:NAME=VALUE" packet that will build up the @@ -185,7 +184,10 @@ public: //------------------------------------------------------------------ /// Sets the working directory to \a path for a process that will - /// be launched with the 'A' packet. + /// be launched with the 'A' packet for non platform based + /// connections. If this packet is sent to a GDB server that + /// implements the platform, it will change the current working + /// directory for the platform process. /// /// @param[in] path /// The path to a directory to use when launching our processs @@ -196,6 +198,19 @@ public: int SetWorkingDir (char const *path); + //------------------------------------------------------------------ + /// Gets the current working directory of a remote platform GDB + /// server. + /// + /// @param[out] cwd + /// The current working directory on the remote platform. + /// + /// @return + /// Boolean for success + //------------------------------------------------------------------ + bool + GetWorkingDir (std::string &cwd); + lldb::addr_t AllocateMemory (size_t size, uint32_t permissions); @@ -356,45 +371,54 @@ public: return m_interrupt_sent; } - virtual lldb::user_id_t + lldb::user_id_t OpenFile (const lldb_private::FileSpec& file_spec, uint32_t flags, mode_t mode, lldb_private::Error &error); - virtual bool + bool CloseFile (lldb::user_id_t fd, lldb_private::Error &error); - virtual lldb::user_id_t + 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); + lldb_private::Error + GetFilePermissions(const char *path, uint32_t &file_permissions); - virtual uint64_t + lldb_private::Error + SetFilePermissions(const char *path, uint32_t file_permissions); + + uint64_t ReadFile (lldb::user_id_t fd, uint64_t offset, void *dst, uint64_t dst_len, lldb_private::Error &error); - virtual uint64_t + 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); + lldb_private::Error + CreateSymlink (const char *src, + const char *dst); + + lldb_private::Error + Unlink (const char *path); + + lldb_private::Error + MakeDirectory (const char *path, + uint32_t mode); - virtual bool + bool GetFileExists (const lldb_private::FileSpec& file_spec); - virtual lldb_private::Error + 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 @@ -402,7 +426,7 @@ public: 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 + bool CalculateMD5 (const lldb_private::FileSpec& file_spec, uint64_t &high, uint64_t &low); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index df036cdcc8e..77cc6408a92 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -166,6 +166,9 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, case StringExtractorGDBRemote::eServerPacketType_qUserName: return Handle_qUserName (packet); + case StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir: + return Handle_qGetWorkingDir(packet); + case StringExtractorGDBRemote::eServerPacketType_QEnvironment: return Handle_QEnvironment (packet); @@ -190,38 +193,47 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode: return Handle_QStartNoAckMode (packet); - case StringExtractorGDBRemote::eServerPacketType_qPlatform_IO_MkDir: - return Handle_qPlatform_IO_MkDir (packet); + case StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir: + return Handle_qPlatform_mkdir (packet); - case StringExtractorGDBRemote::eServerPacketType_qPlatform_RunCommand: - return Handle_qPlatform_RunCommand (packet); + case StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod: + return Handle_qPlatform_chmod (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Open: + case StringExtractorGDBRemote::eServerPacketType_qPlatform_shell: + return Handle_qPlatform_shell (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_open: return Handle_vFile_Open (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Close: + case StringExtractorGDBRemote::eServerPacketType_vFile_close: return Handle_vFile_Close (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_pRead: + case StringExtractorGDBRemote::eServerPacketType_vFile_pread: return Handle_vFile_pRead (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_pWrite: + case StringExtractorGDBRemote::eServerPacketType_vFile_pwrite: return Handle_vFile_pWrite (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Size: + case StringExtractorGDBRemote::eServerPacketType_vFile_size: return Handle_vFile_Size (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Mode: + case StringExtractorGDBRemote::eServerPacketType_vFile_mode: return Handle_vFile_Mode (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Exists: + case StringExtractorGDBRemote::eServerPacketType_vFile_exists: return Handle_vFile_Exists (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Stat: + case StringExtractorGDBRemote::eServerPacketType_vFile_stat: return Handle_vFile_Stat (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_MD5: + case StringExtractorGDBRemote::eServerPacketType_vFile_md5: return Handle_vFile_MD5 (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_symlink: + return Handle_vFile_symlink (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_unlink: + return Handle_vFile_unlink (packet); } return true; } @@ -810,19 +822,20 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr); + + debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); + 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); + Mutex::Locker locker (m_spawned_pids_mutex); + m_spawned_pids.insert(debugserver_pid); } if (error.Success()) @@ -979,11 +992,56 @@ GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &p packet.SetFilePos(::strlen ("QSetWorkingDir:")); std::string path; packet.GetHexByteString(path); - m_process_launch_info.SwapWorkingDirectory (path); + if (m_is_platform) + { + // If this packet is sent to a platform, then change the current working directory + if (::chdir(path.c_str()) != 0) + return SendErrorResponse(errno); + } + else + { + m_process_launch_info.SwapWorkingDirectory (path); + } return SendOKResponse (); } bool +GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet) +{ + StreamString response; + + if (m_is_platform) + { + // If this packet is sent to a platform, then change the current working directory + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) == NULL) + { + return SendErrorResponse(errno); + } + else + { + response.PutBytesAsRawHex8(cwd, strlen(cwd)); + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; + } + } + else + { + const char *working_dir = m_process_launch_info.GetWorkingDirectory(); + if (working_dir && working_dir[0]) + { + response.PutBytesAsRawHex8(working_dir, strlen(working_dir)); + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; + } + else + { + return SendErrorResponse(1); + } + } +} + +bool GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDIN:")); @@ -1044,18 +1102,37 @@ GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote & } bool -GDBRemoteCommunicationServer::Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet) +GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet) { - packet.SetFilePos(::strlen("qPlatform_IO_MkDir:")); + packet.SetFilePos(::strlen("qPlatform_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()); + Error error = Host::MakeDirectory(path.c_str(),mode); + if (error.Success()) + return SendPacketNoLock ("OK", 2); + else + return SendErrorResponse(error.GetError()); + return true; +} + +bool +GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("qPlatform_chmod:")); + + mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); + if (packet.GetChar() != ',') + return false; + std::string path; + packet.GetHexByteString(path); + Error error = Host::SetFilePermissions (path.c_str(), mode); + if (error.Success()) + return SendPacketNoLock ("OK", 2); + else + return SendErrorResponse(error.GetError()); return true; } @@ -1247,9 +1324,37 @@ GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &pac } bool -GDBRemoteCommunicationServer::Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet) +GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("vFile:symlink:")); + std::string dst, src; + packet.GetHexByteStringTerminatedBy(dst, ','); + packet.GetChar(); // Skip ',' char + packet.GetHexByteString(src); + Error error = Host::Symlink(src.c_str(), dst.c_str()); + StreamString response; + response.Printf("F%u,%u", error.GetError(), error.GetError()); + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; +} + +bool +GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("vFile:unlink:")); + std::string path; + packet.GetHexByteString(path); + Error error = Host::Unlink(path.c_str()); + StreamString response; + response.Printf("F%u,%u", error.GetError(), error.GetError()); + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; +} + +bool +GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &packet) { - packet.SetFilePos(::strlen("qPlatform_RunCommand:")); + packet.SetFilePos(::strlen("qPlatform_shell:")); std::string path; std::string working_dir; packet.GetHexByteStringTerminatedBy(path,','); @@ -1257,7 +1362,7 @@ GDBRemoteCommunicationServer::Handle_qPlatform_RunCommand (StringExtractorGDBRem return false; if (packet.GetChar() != ',') return false; - // FIXME: add timeout to qPlatform_RunCommand packet + // FIXME: add timeout to qPlatform_shell packet // uint32_t timeout = packet.GetHexMaxU32(false, 32); uint32_t timeout = 10; if (packet.GetChar() == ',') diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 64f6f8de1a2..57c34d5c153 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -121,7 +121,10 @@ protected: Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet); bool - Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet); + Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet); + + bool + Handle_qPlatform_chmod (StringExtractorGDBRemote &packet); bool Handle_qProcessInfoPID (StringExtractorGDBRemote &packet); @@ -155,6 +158,9 @@ protected: bool Handle_QSetWorkingDir (StringExtractorGDBRemote &packet); + + bool + Handle_qGetWorkingDir (StringExtractorGDBRemote &packet); bool Handle_QStartNoAckMode (StringExtractorGDBRemote &packet); @@ -188,6 +194,12 @@ protected: bool Handle_vFile_Exists (StringExtractorGDBRemote &packet); + + bool + Handle_vFile_symlink (StringExtractorGDBRemote &packet); + + bool + Handle_vFile_unlink (StringExtractorGDBRemote &packet); bool Handle_vFile_Stat (StringExtractorGDBRemote &packet); @@ -196,7 +208,7 @@ protected: Handle_vFile_MD5 (StringExtractorGDBRemote &packet); bool - Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet); + Handle_qPlatform_shell (StringExtractorGDBRemote &packet); private: bool diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index aff9c7bc977..6618b071f54 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -820,7 +820,7 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_ } const uint32_t old_packet_timeout = m_gdb_comm.SetPacketTimeout (10); - int arg_packet_err = m_gdb_comm.SendArgumentsPacket (launch_info.GetArguments().GetConstArgumentVector()); + int arg_packet_err = m_gdb_comm.SendArgumentsPacket (launch_info); if (arg_packet_err == 0) { std::string error_str; @@ -1158,6 +1158,13 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait } +bool +ProcessGDBRemote::SetExitStatus (int exit_status, const char *cstr) +{ + m_gdb_comm.Disconnect(); + return Process::SetExitStatus (exit_status, cstr); +} + void ProcessGDBRemote::DidAttach () { @@ -2787,6 +2794,7 @@ ProcessGDBRemote::MonitorDebugserverProcess void ProcessGDBRemote::KillDebugserverProcess () { + m_gdb_comm.Disconnect(); if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) { Host::Kill (m_debugserver_pid, SIGINT); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index b18ac5b1723..35244074bab 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -222,6 +222,13 @@ public: { return m_gdb_comm; } + + //---------------------------------------------------------------------- + // Override SetExitStatus so we can disconnect from the remote GDB server + //---------------------------------------------------------------------- + virtual bool + SetExitStatus (int exit_status, const char *cstr); + protected: friend class ThreadGDBRemote; diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp index 75d94bd91ce..1bf9f10855f 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -237,6 +237,7 @@ Platform::Platform (bool is_host) : m_system_arch_set_while_connected (false), m_sdk_sysroot (), m_sdk_build (), + m_working_dir (), m_remote_url (), m_name (), m_major_os_version (UINT32_MAX), @@ -319,6 +320,10 @@ Platform::GetStatus (Stream &strm) strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no"); } + if (GetWorkingDirectory()) + { + strm.Printf("WorkingDir: %s\n", GetWorkingDirectory().GetCString()); + } if (!IsConnected()) return; @@ -405,12 +410,323 @@ Platform::GetOSKernelDescription (std::string &s) } ConstString +Platform::GetWorkingDirectory () +{ + if (IsHost()) + { + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd))) + return ConstString(cwd); + else + return ConstString(); + } + else + { + if (!m_working_dir) + m_working_dir = GetRemoteWorkingDirectory(); + return m_working_dir; + } +} + + +struct RecurseCopyBaton +{ + const FileSpec& dst; + Platform *platform_ptr; + Error error; +}; + + +static FileSpec::EnumerateDirectoryResult +RecurseCopy_Callback (void *baton, + FileSpec::FileType file_type, + const FileSpec &src) +{ + 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::eFileTypeDirectory: + { + // make the new directory and get in there + FileSpec dst_dir = rc_baton->dst; + if (!dst_dir.GetFilename()) + dst_dir.GetFilename() = src.GetLastPathComponent(); + std::string dst_dir_path (dst_dir.GetPath()); + Error error = rc_baton->platform_ptr->MakeDirectory(dst_dir_path.c_str(), lldb::eFilePermissionsDirectoryDefault); + if (error.Fail()) + { + rc_baton->error.SetErrorStringWithFormat("unable to setup directory %s on remote end", dst_dir_path.c_str()); + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out + } + + // now recurse + std::string src_dir_path (src.GetPath()); + + // Make a filespec that only fills in the directory of a FileSpec so + // when we enumerate we can quickly fill in the filename for dst copies + FileSpec recurse_dst; + recurse_dst.GetDirectory().SetCString(dst_dir.GetPath().c_str()); + RecurseCopyBaton rc_baton2 = { recurse_dst, rc_baton->platform_ptr, Error() }; + FileSpec::EnumerateDirectory(src_dir_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::eFileTypeSymbolicLink: + { + // copy the file and keep going + FileSpec dst_file = rc_baton->dst; + if (!dst_file.GetFilename()) + dst_file.GetFilename() = src.GetFilename(); + + char buf[PATH_MAX]; + + rc_baton->error = Host::Readlink (src.GetPath().c_str(), buf, sizeof(buf)); + + if (rc_baton->error.Fail()) + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out + + rc_baton->error = rc_baton->platform_ptr->CreateSymlink(dst_file.GetPath().c_str(), buf); + + if (rc_baton->error.Fail()) + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out + + return FileSpec::eEnumerateDirectoryResultNext; + } + break; + case FileSpec::eFileTypeRegular: + { + // copy the file and keep going + FileSpec dst_file = rc_baton->dst; + if (!dst_file.GetFilename()) + dst_file.GetFilename() = src.GetFilename(); + Error err = rc_baton->platform_ptr->PutFile(src, dst_file); + 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: + rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s", src.GetPath().c_str()); + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out + break; + } +} + +Error +Platform::Install (const FileSpec& src, const FileSpec& dst) +{ + Error error; + + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf ("Platform::Install (src='%s', dst='%s')", src.GetPath().c_str(), dst.GetPath().c_str()); + FileSpec fixed_dst(dst); + + if (!fixed_dst.GetFilename()) + fixed_dst.GetFilename() = src.GetFilename(); + + ConstString working_dir = GetWorkingDirectory(); + + if (dst) + { + if (dst.GetDirectory()) + { + const char first_dst_dir_char = dst.GetDirectory().GetCString()[0]; + if (first_dst_dir_char == '/' || first_dst_dir_char == '\\') + { + fixed_dst.GetDirectory() = dst.GetDirectory(); + } + // If the fixed destination file doesn't have a directory yet, + // then we must have a relative path. We will resolve this relative + // path against the platform's working directory + if (!fixed_dst.GetDirectory()) + { + FileSpec relative_spec; + std::string path; + if (working_dir) + { + relative_spec.SetFile(working_dir.GetCString(), false); + relative_spec.AppendPathComponent(dst.GetPath().c_str()); + fixed_dst.GetDirectory() = relative_spec.GetDirectory(); + } + else + { + error.SetErrorStringWithFormat("platform working directory must be valid for relative path '%s'", dst.GetPath().c_str()); + return error; + } + } + } + else + { + if (working_dir) + { + fixed_dst.GetDirectory() = working_dir; + } + else + { + error.SetErrorStringWithFormat("platform working directory must be valid for relative path '%s'", dst.GetPath().c_str()); + return error; + } + } + } + else + { + if (working_dir) + { + fixed_dst.GetDirectory() = working_dir; + } + else + { + error.SetErrorStringWithFormat("platform working directory must be valid when destination directory is empty"); + return error; + } + } + + if (log) + log->Printf ("Platform::Install (src='%s', dst='%s') fixed_dst='%s'", src.GetPath().c_str(), dst.GetPath().c_str(), fixed_dst.GetPath().c_str()); + + if (GetSupportsRSync()) + { + error = PutFile(src, dst); + } + else + { + switch (src.GetFileType()) + { + case FileSpec::eFileTypeDirectory: + { + if (GetFileExists (fixed_dst)) + Unlink (fixed_dst.GetPath().c_str()); + uint32_t permissions = src.GetPermissions(); + if (permissions == 0) + permissions = eFilePermissionsDirectoryDefault; + std::string dst_dir_path(fixed_dst.GetPath()); + error = MakeDirectory(dst_dir_path.c_str(), permissions); + if (error.Success()) + { + // Make a filespec that only fills in the directory of a FileSpec so + // when we enumerate we can quickly fill in the filename for dst copies + FileSpec recurse_dst; + recurse_dst.GetDirectory().SetCString(dst_dir_path.c_str()); + std::string src_dir_path (src.GetPath()); + RecurseCopyBaton baton = { recurse_dst, this, Error() }; + FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, RecurseCopy_Callback, &baton); + return baton.error; + } + } + break; + + case FileSpec::eFileTypeRegular: + if (GetFileExists (fixed_dst)) + Unlink (fixed_dst.GetPath().c_str()); + error = PutFile(src, fixed_dst); + break; + + case FileSpec::eFileTypeSymbolicLink: + { + if (GetFileExists (fixed_dst)) + Unlink (fixed_dst.GetPath().c_str()); + char buf[PATH_MAX]; + error = Host::Readlink(src.GetPath().c_str(), buf, sizeof(buf)); + if (error.Success()) + error = CreateSymlink(dst.GetPath().c_str(), buf); + } + break; + case FileSpec::eFileTypePipe: + error.SetErrorString("platform install doesn't handle pipes"); + break; + case FileSpec::eFileTypeSocket: + error.SetErrorString("platform install doesn't handle sockets"); + break; + case FileSpec::eFileTypeInvalid: + case FileSpec::eFileTypeUnknown: + case FileSpec::eFileTypeOther: + error.SetErrorString("platform install doesn't handle non file or directory items"); + break; + } + } + return error; +} + +bool +Platform::SetWorkingDirectory (const ConstString &path) +{ + if (IsHost()) + { + if (path) + { + if (chdir(path.GetCString()) == 0) + return true; + } + return false; + } + else + { + return SetRemoteWorkingDirectory(path); + } +} + +Error +Platform::MakeDirectory (const char *path, uint32_t permissions) +{ + if (IsHost()) + return Host::MakeDirectory (path, permissions); + else + { + Error error; + error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), __PRETTY_FUNCTION__); + return error; + } +} + +Error +Platform::GetFilePermissions (const char *path, uint32_t &file_permissions) +{ + if (IsHost()) + return Host::GetFilePermissions(path, file_permissions); + else + { + Error error; + error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), __PRETTY_FUNCTION__); + return error; + } +} + +Error +Platform::SetFilePermissions (const char *path, uint32_t file_permissions) +{ + if (IsHost()) + return Host::SetFilePermissions(path, file_permissions); + else + { + Error error; + error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), __PRETTY_FUNCTION__); + return error; + } +} + +ConstString Platform::GetName () { - const char *name = GetHostname(); - if (name == NULL || name[0] == '\0') - return GetPluginName(); - return ConstString (name); + return GetPluginName(); } const char * @@ -779,14 +1095,6 @@ Platform::IsCompatibleArchitecture (const ArchSpec &arch, bool exact_arch_match, 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, @@ -805,12 +1113,29 @@ Platform::GetFile (const FileSpec& source, return error; } +Error +Platform::CreateSymlink (const char *src, // The name of the link is in src + const char *dst)// The symlink points to dst +{ + Error error("unimplemented"); + return error; +} + bool Platform::GetFileExists (const lldb_private::FileSpec& file_spec) { return false; } +Error +Platform::Unlink (const char *path) +{ + Error error("unimplemented"); + return error; +} + + + lldb_private::Error Platform::RunShellCommand (const char *command, // Shouldn't be NULL const char *working_dir, // Pass NULL to use the current working directory diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 390365847d6..1de322aee14 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -2113,12 +2113,37 @@ Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardw } else { - // Report error for setting breakpoint... - m_target.GetDebugger().GetErrorFile().Printf ("warning: failed to set breakpoint site at 0x%" PRIx64 " for breakpoint %i.%i: %s\n", - load_addr, - owner->GetBreakpoint().GetID(), - owner->GetID(), - error.AsCString() ? error.AsCString() : "unkown error"); + bool show_error = true; + switch (GetState()) + { + case eStateInvalid: + case eStateUnloaded: + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateDetached: + case eStateExited: + show_error = false; + break; + + case eStateStopped: + case eStateRunning: + case eStateStepping: + case eStateCrashed: + case eStateSuspended: + show_error = IsAlive(); + break; + } + + if (show_error) + { + // Report error for setting breakpoint... + m_target.GetDebugger().GetErrorFile().Printf ("warning: failed to set breakpoint site at 0x%" PRIx64 " for breakpoint %i.%i: %s\n", + load_addr, + owner->GetBreakpoint().GetID(), + owner->GetID(), + error.AsCString() ? error.AsCString() : "unkown error"); + } } } } @@ -2884,7 +2909,7 @@ Process::WaitForProcessStopPrivate (const TimeValue *timeout, EventSP &event_sp) } Error -Process::Launch (const ProcessLaunchInfo &launch_info) +Process::Launch (ProcessLaunchInfo &launch_info) { Error error; m_abi_sp.reset(); @@ -2902,6 +2927,13 @@ Process::Launch (const ProcessLaunchInfo &launch_info) exe_module->GetPlatformFileSpec().GetPath(platform_exec_file_path, sizeof(platform_exec_file_path)); if (exe_module->GetFileSpec().Exists()) { + // Install anything that might need to be installed prior to launching. + // For host systems, this will do nothing, but if we are connected to a + // remote platform it will install any needed binaries + error = GetTarget().Install(&launch_info); + if (error.Fail()) + return error; + if (PrivateStateThreadIsValid ()) PausePrivateStateThread (); diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 178e276d56c..fd9626a5de8 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -2190,12 +2190,78 @@ Target::RunStopHooks () result.GetImmediateErrorStream()->Flush(); } +const TargetPropertiesSP & +Target::GetGlobalProperties() +{ + static TargetPropertiesSP g_settings_sp; + if (!g_settings_sp) + { + g_settings_sp.reset (new TargetProperties (NULL)); + } + return g_settings_sp; +} + +Error +Target::Install (ProcessLaunchInfo *launch_info) +{ + Error error; + PlatformSP platform_sp (GetPlatform()); + if (platform_sp) + { + if (platform_sp->IsRemote()) + { + if (platform_sp->IsConnected()) + { + // Install all files that have an install path, and always install the + // main executable when connected to a remote platform + const ModuleList& modules = GetImages(); + const size_t num_images = modules.GetSize(); + for (size_t idx = 0; idx < num_images; ++idx) + { + const bool is_main_executable = idx == 0; + ModuleSP module_sp(modules.GetModuleAtIndex(idx)); + if (module_sp) + { + FileSpec local_file (module_sp->GetFileSpec()); + if (local_file) + { + FileSpec remote_file (module_sp->GetRemoteInstallFileSpec()); + if (!remote_file) + { + if (is_main_executable) // TODO: add setting for always installing main executable??? + { + // Always install the main executable + remote_file.GetDirectory() = platform_sp->GetWorkingDirectory(); + remote_file.GetFilename() = module_sp->GetFileSpec().GetFilename(); + } + } + if (remote_file) + { + error = platform_sp->Install(local_file, remote_file); + if (error.Success()) + { + module_sp->SetPlatformFileSpec(remote_file); + if (is_main_executable) + { + if (launch_info) + launch_info->SetExecutableFile(remote_file, false); + } + } + else + break; + } + } + } + } + } + } + } + return error; +} //-------------------------------------------------------------- -// class Target::StopHook +// Target::StopHook //-------------------------------------------------------------- - - Target::StopHook::StopHook (lldb::TargetSP target_sp, lldb::user_id_t uid) : UserID (uid), m_target_sp (target_sp), @@ -2527,6 +2593,9 @@ protected: mutable bool m_got_host_env; }; +//---------------------------------------------------------------------- +// TargetProperties +//---------------------------------------------------------------------- TargetProperties::TargetProperties (Target *target) : Properties () { @@ -2815,17 +2884,10 @@ TargetProperties::GetMemoryModuleLoadLevel() const } -const TargetPropertiesSP & -Target::GetGlobalProperties() -{ - static TargetPropertiesSP g_settings_sp; - if (!g_settings_sp) - { - g_settings_sp.reset (new TargetProperties (NULL)); - } - return g_settings_sp; -} +//---------------------------------------------------------------------- +// Target::TargetEventData +//---------------------------------------------------------------------- const ConstString & Target::TargetEventData::GetFlavorString () { diff --git a/lldb/source/Utility/StringExtractor.cpp b/lldb/source/Utility/StringExtractor.cpp index d4ce470d56f..9d231570882 100644 --- a/lldb/source/Utility/StringExtractor.cpp +++ b/lldb/source/Utility/StringExtractor.cpp @@ -145,11 +145,10 @@ StringExtractor::GetChar (char fail_value) uint8_t StringExtractor::GetHexU8 (uint8_t fail_value, bool set_eof_on_fail) { - uint32_t i = m_index; - if ((i + 2) <= m_packet.size()) + if (GetBytesLeft() >= 2) { - const uint8_t hi_nibble = g_hex_ascii_to_hex_integer[static_cast<uint8_t>(m_packet[i])]; - const uint8_t lo_nibble = g_hex_ascii_to_hex_integer[static_cast<uint8_t>(m_packet[i+1])]; + const uint8_t hi_nibble = g_hex_ascii_to_hex_integer[static_cast<uint8_t>(m_packet[m_index])]; + const uint8_t lo_nibble = g_hex_ascii_to_hex_integer[static_cast<uint8_t>(m_packet[m_index+1])]; if (hi_nibble < 16 && lo_nibble < 16) { m_index += 2; diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp index 6e32481ccc5..08e7af72565 100644 --- a/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -117,6 +117,7 @@ StringExtractorGDBRemote::GetServerPacketType () const case 'G': if (PACKET_STARTS_WITH ("qGroupName:")) return eServerPacketType_qGroupName; + if (PACKET_MATCHES ("qGetWorkingDir")) return eServerPacketType_qGetWorkingDir; break; case 'H': @@ -133,9 +134,10 @@ StringExtractorGDBRemote::GetServerPacketType () const break; case 'P': - 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; + if (PACKET_STARTS_WITH ("qProcessInfoPID:")) return eServerPacketType_qProcessInfoPID; + if (PACKET_STARTS_WITH ("qPlatform_shell:")) return eServerPacketType_qPlatform_shell; + if (PACKET_STARTS_WITH ("qPlatform_mkdir:")) return eServerPacketType_qPlatform_mkdir; + if (PACKET_STARTS_WITH ("qPlatform_chmod:")) return eServerPacketType_qPlatform_chmod; break; @@ -151,15 +153,17 @@ StringExtractorGDBRemote::GetServerPacketType () const 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; + 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; + else if (PACKET_STARTS_WITH("vFile:symlink")) return eServerPacketType_vFile_symlink; + else if (PACKET_STARTS_WITH("vFile:unlink")) return eServerPacketType_vFile_unlink; } break; diff --git a/lldb/source/Utility/StringExtractorGDBRemote.h b/lldb/source/Utility/StringExtractorGDBRemote.h index fe500ecda5d..2379882e8bf 100644 --- a/lldb/source/Utility/StringExtractorGDBRemote.h +++ b/lldb/source/Utility/StringExtractorGDBRemote.h @@ -58,6 +58,7 @@ public: eServerPacketType_qProcessInfoPID, eServerPacketType_qSpeedTest, eServerPacketType_qUserName, + eServerPacketType_qGetWorkingDir, eServerPacketType_QEnvironment, eServerPacketType_QLaunchArch, eServerPacketType_QSetDisableASLR, @@ -66,17 +67,20 @@ public: eServerPacketType_QSetSTDERR, eServerPacketType_QSetWorkingDir, 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 + eServerPacketType_qPlatform_shell, + eServerPacketType_qPlatform_mkdir, + eServerPacketType_qPlatform_chmod, + 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, + eServerPacketType_vFile_symlink, + eServerPacketType_vFile_unlink }; ServerPacketType diff --git a/lldb/tools/debugserver/debugserver.xcodeproj/xcshareddata/xcschemes/debugserver.xcscheme b/lldb/tools/debugserver/debugserver.xcodeproj/xcshareddata/xcschemes/debugserver.xcscheme index dafd28f08a0..898e82ee3e9 100644 --- a/lldb/tools/debugserver/debugserver.xcodeproj/xcshareddata/xcschemes/debugserver.xcscheme +++ b/lldb/tools/debugserver/debugserver.xcodeproj/xcshareddata/xcschemes/debugserver.xcscheme @@ -66,6 +66,12 @@ ReferencedContainer = "container:debugserver.xcodeproj"> </BuildableReference> </BuildableProductRunnable> + <CommandLineArguments> + <CommandLineArgument + argument = "lldb.apple.com:0 --native-regs --setsid --unix-socket /tmp/gtJlji" + isEnabled = "YES"> + </CommandLineArgument> + </CommandLineArguments> <EnvironmentVariables> <EnvironmentVariable key = "UBBY" diff --git a/lldb/tools/lldb-platform/lldb-platform.cpp b/lldb/tools/lldb-platform/lldb-platform.cpp index 007e69c9281..21063f9a0f7 100644 --- a/lldb/tools/lldb-platform/lldb-platform.cpp +++ b/lldb/tools/lldb-platform/lldb-platform.cpp @@ -21,6 +21,7 @@ // C++ Includes // Other libraries and framework includes +#include "lldb/lldb-private-log.h" #include "lldb/Core/Error.h" #include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Core/ConnectionMachPort.h" @@ -96,44 +97,9 @@ main (int argc, char *argv[]) int ch; Debugger::Initialize(); -// ConnectionMachPort a; -// ConnectionMachPort b; -// -// lldb::ConnectionStatus status; -// const char *bootstrap_service_name = "HelloWorld"; -// status = a.BootstrapCheckIn(bootstrap_service_name, &error); -// -// if (status != eConnectionStatusSuccess) -// { -// fprintf(stderr, "%s", error.AsCString()); -// return 1; -// } -// status = b.BootstrapLookup (bootstrap_service_name, &error); -// if (status != eConnectionStatusSuccess) -// { -// fprintf(stderr, "%s", error.AsCString()); -// return 2; -// } -// -// if (a.Write ("hello", 5, status, &error) == 5) -// { -// char buf[32]; -// memset(buf, 0, sizeof(buf)); -// if (b.Read (buf, 5, status, &error)) -// { -// printf("read returned bytes: %s", buf); -// } -// else -// { -// fprintf(stderr, "%s", error.AsCString()); -// return 4; -// } -// } -// else -// { -// fprintf(stderr, "%s", error.AsCString()); -// return 3; -// } +// StreamSP stream_sp (new StreamFile(stdout, false)); +// const char *log_channels[] = { "host", "process", NULL }; +// EnableLog (stream_sp, 0, log_channels, NULL); while ((ch = getopt_long_only(argc, argv, "l:f:L:", g_long_options, &long_option_index)) != -1) { |