summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/docs/lldb-gdb-remote.txt134
-rw-r--r--lldb/include/lldb/Core/StreamGDBRemote.h54
-rw-r--r--lldb/include/lldb/Host/File.h53
-rw-r--r--lldb/include/lldb/Host/FileSpec.h15
-rw-r--r--lldb/include/lldb/Host/Host.h40
-rw-r--r--lldb/include/lldb/Interpreter/Options.h10
-rw-r--r--lldb/include/lldb/Interpreter/ScriptInterpreter.h1
-rw-r--r--lldb/include/lldb/Target/Platform.h295
-rw-r--r--lldb/include/lldb/Target/Process.h6
-rw-r--r--lldb/include/lldb/lldb-enumerations.h3
-rw-r--r--lldb/include/lldb/lldb-forward.h3
-rw-r--r--lldb/include/lldb/lldb-private-log.h1
-rw-r--r--lldb/lib/Makefile3
-rw-r--r--lldb/lldb.xcodeproj/project.pbxproj94
-rw-r--r--lldb/scripts/Python/python-wrapper.swig13
-rw-r--r--lldb/source/API/SBValue.cpp128
-rw-r--r--lldb/source/CMakeLists.txt1
-rw-r--r--lldb/source/Commands/CommandObjectPlatform.cpp1418
-rw-r--r--lldb/source/Commands/CommandObjectTarget.cpp73
-rw-r--r--lldb/source/Core/CMakeLists.txt1
-rw-r--r--lldb/source/Core/Error.cpp2
-rw-r--r--lldb/source/Core/StreamGDBRemote.cpp54
-rw-r--r--lldb/source/Host/common/File.cpp109
-rw-r--r--lldb/source/Host/common/FileSpec.cpp135
-rw-r--r--lldb/source/Host/common/Host.cpp172
-rw-r--r--lldb/source/Host/freebsd/Host.cpp315
-rw-r--r--lldb/source/Host/macosx/Host.mm7
-rw-r--r--lldb/source/Interpreter/CommandObject.cpp3
-rw-r--r--lldb/source/Interpreter/Options.cpp12
-rw-r--r--lldb/source/Interpreter/ScriptInterpreterPython.cpp15
-rw-r--r--lldb/source/Plugins/Platform/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp55
-rw-r--r--lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h8
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp192
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h14
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp76
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h21
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp27
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h8
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp8
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h6
-rw-r--r--lldb/source/Plugins/Platform/Makefile10
-rw-r--r--lldb/source/Plugins/Platform/POSIX/CMakeLists.txt5
-rw-r--r--lldb/source/Plugins/Platform/POSIX/Makefile14
-rw-r--r--lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp541
-rw-r--r--lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h111
-rw-r--r--lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp110
-rw-r--r--lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h52
-rw-r--r--lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp27
-rw-r--r--lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp4
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp4
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp369
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h58
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp503
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h75
-rw-r--r--lldb/source/Target/Platform.cpp269
-rw-r--r--lldb/source/Utility/StringExtractor.cpp78
-rw-r--r--lldb/source/Utility/StringExtractor.h13
-rw-r--r--lldb/source/Utility/StringExtractorGDBRemote.cpp45
-rw-r--r--lldb/source/Utility/StringExtractorGDBRemote.h19
-rw-r--r--lldb/source/lldb-log.cpp3
-rw-r--r--lldb/source/lldb.cpp1
-rw-r--r--lldb/test/api/check_public_api_headers/TestPublicAPIHeaders.py3
-rw-r--r--lldb/test/api/multithreaded/TestMultithreaded.py9
-rwxr-xr-xlldb/test/dotest.py22
-rw-r--r--lldb/test/functionalities/abbreviation/TestAbbreviations.py5
-rw-r--r--lldb/test/functionalities/conditional_break/.lldb2
-rw-r--r--lldb/test/functionalities/conditional_break/TestConditionalBreak.py4
-rw-r--r--lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py2
-rw-r--r--lldb/test/functionalities/inferior-changed/TestInferiorChanged.py7
-rw-r--r--lldb/test/functionalities/load_unload/TestLoadUnload.py5
-rw-r--r--lldb/test/functionalities/process_launch/TestProcessLaunch.py2
-rw-r--r--lldb/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py8
-rw-r--r--lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py7
-rw-r--r--lldb/test/lang/c/blocks/TestBlocks.py2
-rw-r--r--lldb/test/lldbtest.py74
-rw-r--r--lldb/test/macosx/universal/TestUniversal.py3
-rw-r--r--lldb/test/python_api/hello_world/TestHelloWorld.py4
-rw-r--r--lldb/test/python_api/process/TestProcessAPI.py4
-rw-r--r--lldb/test/python_api/target/TestTargetAPI.py2
-rw-r--r--lldb/test/settings/TestSettings.py3
-rw-r--r--lldb/tools/CMakeLists.txt2
-rw-r--r--lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj2
-rw-r--r--lldb/tools/lldb-platform/CMakeLists.txt14
-rw-r--r--lldb/tools/lldb-platform/lldb-platform.cpp109
85 files changed, 5862 insertions, 330 deletions
diff --git a/lldb/docs/lldb-gdb-remote.txt b/lldb/docs/lldb-gdb-remote.txt
index 1ceda81a174..c857a3306d2 100644
--- a/lldb/docs/lldb-gdb-remote.txt
+++ b/lldb/docs/lldb-gdb-remote.txt
@@ -421,6 +421,20 @@ invalidate-regs
change depending on if the mode has changed.
//----------------------------------------------------------------------
+// "qPlatform_RunCommand"
+//
+// BRIEF
+// Run a command in a shell on the connected remote machine.
+//
+// PRIORITY TO IMPLEMENT
+// TODO
+//----------------------------------------------------------------------
+
+send packet: TODO (see GDBRemoteCommunicationClient::RunShellCommand)
+read packet: TODO (see GDBRemoteCommunicationServer::Handle_qPlatform_RunCommand)
+
+
+//----------------------------------------------------------------------
// "qHostInfo"
//
// BRIEF
@@ -848,3 +862,123 @@ for this region.
// your debug session more reliable and informative.
//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// PLATFORM EXTENSION - for use as a GDB remote platform
+//----------------------------------------------------------------------
+// "qfProcessInfo"
+// "qsProcessInfo"
+//
+// BRIEF
+// Get the first process info (qfProcessInfo) or subsequent processs
+// info (qsProcessInfo) for one or more processes on the remote
+// platform. The first call gets the first match and subsequent calls
+// to qsProcessInfo gets the subsequent matches. Return an error EXX,
+// where XX are two hex digits, when no more matches are available.
+//
+// PRIORITY TO IMPLEMENT
+// Required. The qfProcessInfo packet can be followed by a ':' and
+// some key value pairs. The key value pairs in the command are:
+//
+// KEY VALUE DESCRIPTION
+// =========== ======== ================================================
+// "name" ascii-hex An ASCII hex string that contains the name of
+// the process that will be matched.
+// "name_match" enum One of: "equals", "starts_with", "ends_with",
+// "contains" or "regex"
+// "pid" integer A string value containing the decimal process ID
+// "parent_pid" integer A string value containing the decimal parent
+// process ID
+// "uid" integer A string value containing the decimal user ID
+// "gid" integer A string value containing the decimal group ID
+// "euid" integer A string value containing the decimal effective user ID
+// "egid" integer A string value containing the decimal effective group ID
+// "all_users" bool A boolean value that specifies if processes should
+// be listed for all users, not just the user that the
+// platform is running as
+// "triple" ascii-hex An ASCII hex target triple string ("x86_64",
+// "x86_64-apple-macosx", "armv7-apple-ios")
+//
+// The response consists of key/value pairs where the key is separated from the
+// values with colons and each pair is terminated with a semi colon. For a list
+// of the key/value pairs in the response see the "qProcessInfoPID" packet
+// documentation.
+//
+// Sample packet/response:
+// send packet: $qfProcessInfo#00
+// read packet: $pid:60001;ppid:59948;uid:7746;gid:11;euid:7746;egid:11;name:6c6c6462;triple:7838365f36342d6170706c652d6d61636f7378;#00
+// send packet: $qsProcessInfo#00
+// read packet: $pid:59992;ppid:192;uid:7746;gid:11;euid:7746;egid:11;name:6d64776f726b6572;triple:7838365f36342d6170706c652d6d61636f7378;#00
+// send packet: $qsProcessInfo#00
+// read packet: $E04#00
+//----------------------------------------------------------------------
+
+
+//----------------------------------------------------------------------
+// PLATFORM EXTENSION - for use as a GDB remote platform
+//----------------------------------------------------------------------
+// "qLaunchGDBServer"
+//
+// BRIEF
+// Have the remote platform launch a GDB server.
+//
+// PRIORITY TO IMPLEMENT
+// Required. The qLaunchGDBServer packet must be followed by a ':' and
+// some key value pairs. The key value pairs in the command are:
+//
+// KEY VALUE DESCRIPTION
+// =========== ======== ================================================
+// "port" integer A string value containing the decimal port ID or
+// zero if the port should be bound and returned
+//
+// "host" integer The host that connections should be limited to
+// when the GDB server is connected to.
+//
+// The response consists of key/value pairs where the key is separated from the
+// values with colons and each pair is terminated with a semi colon.
+//
+// Sample packet/response:
+// send packet: $qLaunchGDBServer:port:0;host:lldb.apple.com;#00
+// read packet: $pid:60025;port:50776;#00
+//
+// The "pid" key/value pair is only specified if the remote platform launched
+// a separate process for the GDB remote server and can be omitted if no
+// process was separately launched.
+//
+// The "port" key/value pair in the response lets clients know what port number
+// to attach to in case zero was specified as the "port" in the sent command.
+//----------------------------------------------------------------------
+
+
+//----------------------------------------------------------------------
+// PLATFORM EXTENSION - for use as a GDB remote platform
+//----------------------------------------------------------------------
+// "qProcessInfoPID:PID"
+//
+// BRIEF
+// Have the remote platform get detailed information on a process by
+// ID. PID is specified as a decimal integer.
+//
+// PRIORITY TO IMPLEMENT
+// Optional.
+//
+// The response consists of key/value pairs where the key is separated from the
+// values with colons and each pair is terminated with a semi colon.
+//
+// The key value pairs in the response are:
+//
+// KEY VALUE DESCRIPTION
+// =========== ======== ================================================
+// "pid" integer Process ID as a decimal integer string
+// "ppid" integer Parent process ID as a decimal integer string
+// "uid" integer A string value containing the decimal user ID
+// "gid" integer A string value containing the decimal group ID
+// "euid" integer A string value containing the decimal effective user ID
+// "egid" integer A string value containing the decimal effective group ID
+// "name" ascii-hex An ASCII hex string that contains the name of the process
+// "triple" ascii-hex A target triple ("x86_64-apple-macosx", "armv7-apple-ios")
+//
+// Sample packet/response:
+// send packet: $qProcessInfoPID:60050#00
+// read packet: $pid:60050;ppid:59948;uid:7746;gid:11;euid:7746;egid:11;name:6c6c6462;triple:7838365f36342d6170706c652d6d61636f7378;#00
+//----------------------------------------------------------------------
diff --git a/lldb/include/lldb/Core/StreamGDBRemote.h b/lldb/include/lldb/Core/StreamGDBRemote.h
new file mode 100644
index 00000000000..3fdb6f6e701
--- /dev/null
+++ b/lldb/include/lldb/Core/StreamGDBRemote.h
@@ -0,0 +1,54 @@
+//===-- StreamGDBRemote.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_StreamGDBRemote_h_
+#define liblldb_StreamGDBRemote_h_
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Core/StreamString.h"
+
+namespace lldb_private {
+
+ class StreamGDBRemote : public StreamString
+ {
+ public:
+ StreamGDBRemote ();
+
+ StreamGDBRemote (uint32_t flags,
+ uint32_t addr_size,
+ lldb::ByteOrder byte_order);
+
+ virtual
+ ~StreamGDBRemote ();
+
+ //------------------------------------------------------------------
+ /// Output a block of data to the stream performing GDB-remote escaping.
+ ///
+ /// @param[in] s
+ /// A block of data.
+ ///
+ /// @param[in] src_len
+ /// The amount of data to write.
+ ///
+ /// @return
+ /// Number of bytes written.
+ //------------------------------------------------------------------
+ int
+ PutEscapedBytes (const void* s,
+ size_t src_len);
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_StreamGDBRemote_h_
diff --git a/lldb/include/lldb/Host/File.h b/lldb/include/lldb/Host/File.h
index df7fe92cccb..bb04784a2fe 100644
--- a/lldb/include/lldb/Host/File.h
+++ b/lldb/include/lldb/Host/File.h
@@ -41,17 +41,20 @@ public:
eOpenOptionCanCreateNewOnly = (1u << 6) // Can create file only if it doesn't already exist
};
+ static mode_t
+ ConvertOpenOptionsForPOSIXOpen (uint32_t open_options);
+
enum Permissions
{
- ePermissionsUserRead = (1u << 0),
- ePermissionsUserWrite = (1u << 1),
- ePermissionsUserExecute = (1u << 2),
- ePermissionsGroupRead = (1u << 3),
+ ePermissionsUserRead = (1u << 8),
+ ePermissionsUserWrite = (1u << 7),
+ ePermissionsUserExecute = (1u << 6),
+ ePermissionsGroupRead = (1u << 5),
ePermissionsGroupWrite = (1u << 4),
- ePermissionsGroupExecute = (1u << 5),
- ePermissionsWorldRead = (1u << 6),
- ePermissionsWorldWrite = (1u << 7),
- ePermissionsWorldExecute = (1u << 8),
+ ePermissionsGroupExecute = (1u << 3),
+ ePermissionsWorldRead = (1u << 2),
+ ePermissionsWorldWrite = (1u << 1),
+ ePermissionsWorldExecute = (1u << 0),
ePermissionsUserRW = (ePermissionsUserRead | ePermissionsUserWrite | 0 ),
ePermissionsUserRX = (ePermissionsUserRead | 0 | ePermissionsUserExecute ),
@@ -117,6 +120,27 @@ public:
uint32_t options,
uint32_t permissions = ePermissionsDefault);
+ //------------------------------------------------------------------
+ /// Constructor with FileSpec.
+ ///
+ /// Takes a FileSpec pointing to a file which can be just a filename, or a full
+ /// path. If \a path is not NULL or empty, this function will call
+ /// File::Open (const char *path, uint32_t options, uint32_t permissions).
+ ///
+ /// @param[in] path
+ /// The FileSpec for this file.
+ ///
+ /// @param[in] options
+ /// Options to use when opening (see File::OpenOptions)
+ ///
+ /// @param[in] permissions
+ /// Options to use when opening (see File::Permissions)
+ ///
+ /// @see File::Open (const char *path, uint32_t options, uint32_t permissions)
+ //------------------------------------------------------------------
+ File (const FileSpec& filespec,
+ uint32_t options,
+ uint32_t permissions = ePermissionsDefault);
File (int fd, bool tranfer_ownership) :
m_descriptor (fd),
@@ -451,6 +475,19 @@ public:
//------------------------------------------------------------------
Error
Sync ();
+
+ //------------------------------------------------------------------
+ /// Get the permissions for a this file.
+ ///
+ /// @return
+ /// Bits logical OR'ed together from the permission bits defined
+ /// in lldb_private::File::Permissions.
+ //------------------------------------------------------------------
+ uint32_t
+ GetPermissions(Error &error) const;
+
+ static uint32_t
+ GetPermissions (const char *path, Error &error);
//------------------------------------------------------------------
/// Output printf formatted output to the stream.
diff --git a/lldb/include/lldb/Host/FileSpec.h b/lldb/include/lldb/Host/FileSpec.h
index c58be9ec09d..f4618c14c4c 100644
--- a/lldb/include/lldb/Host/FileSpec.h
+++ b/lldb/include/lldb/Host/FileSpec.h
@@ -624,6 +624,21 @@ public:
static size_t
Resolve (const char *src_path, char *dst_path, size_t dst_len);
+ FileSpec
+ CopyByAppendingPathComponent (const char *new_path) const;
+
+ FileSpec
+ CopyByRemovingLastPathComponent () const;
+
+ void
+ AppendPathComponent (const char *new_path);
+
+ void
+ RemoveLastPathComponent ();
+
+ const char*
+ GetLastPathComponent () const;
+
//------------------------------------------------------------------
/// Resolves the user name at the beginning of \a src_path, and writes the output
/// to \a dst_path. Note, \a src_path can contain other path components after the
diff --git a/lldb/include/lldb/Host/Host.h b/lldb/include/lldb/Host/Host.h
index bb3bc4a495e..5f459e7a07c 100644
--- a/lldb/include/lldb/Host/Host.h
+++ b/lldb/include/lldb/Host/Host.h
@@ -18,6 +18,7 @@
#include "lldb/lldb-private.h"
#include "lldb/Core/StringList.h"
+#include "lldb/Host/File.h"
namespace lldb_private {
@@ -508,6 +509,45 @@ public:
DynamicLibraryGetSymbol (void *dynamic_library_handle,
const char *symbol_name,
Error &error);
+
+ static uint32_t
+ MakeDirectory (const char* path, mode_t mode);
+
+ static lldb::user_id_t
+ OpenFile (const FileSpec& file_spec,
+ uint32_t flags,
+ mode_t mode,
+ Error &error);
+
+ static bool
+ CloseFile (lldb::user_id_t fd,
+ Error &error);
+
+ static uint64_t
+ WriteFile (lldb::user_id_t fd,
+ uint64_t offset,
+ const void* src,
+ uint64_t src_len,
+ Error &error);
+
+ static uint64_t
+ ReadFile (lldb::user_id_t fd,
+ uint64_t offset,
+ void* dst,
+ uint64_t dst_len,
+ Error &error);
+
+ static lldb::user_id_t
+ GetFileSize (const FileSpec& file_spec);
+
+ static bool
+ GetFileExists (const FileSpec& file_spec);
+
+ static bool
+ CalculateMD5 (const FileSpec& file_spec,
+ uint64_t &low,
+ uint64_t &high);
+
};
} // namespace lldb_private
diff --git a/lldb/include/lldb/Interpreter/Options.h b/lldb/include/lldb/Interpreter/Options.h
index ac4daa8f579..ad4e283ba7f 100644
--- a/lldb/include/lldb/Interpreter/Options.h
+++ b/lldb/include/lldb/Interpreter/Options.h
@@ -448,6 +448,12 @@ protected:
void
Finalize ();
+ bool
+ DidFinalize ()
+ {
+ return m_did_finalize;
+ }
+
virtual Error
SetOptionValue (uint32_t option_idx,
const char *option_arg);
@@ -464,6 +470,10 @@ protected:
assert (m_did_finalize);
return &m_option_defs[0];
}
+
+ const OptionGroup*
+ GetGroupWithOption (char short_opt);
+
struct OptionInfo
{
OptionInfo (OptionGroup* g, uint32_t i) :
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index 9a66c775d47..6f003daf8c4 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -112,6 +112,7 @@ public:
typedef void* (*SWIGPythonGetChildAtIndex) (void *implementor, uint32_t idx);
typedef int (*SWIGPythonGetIndexOfChildWithName) (void *implementor, const char* child_name);
typedef void* (*SWIGPythonCastPyObjectToSBValue) (void* data);
+ typedef lldb::ValueObjectSP (*SWIGPythonGetValueObjectSPFromSBValue) (void* data);
typedef bool (*SWIGPythonUpdateSynthProviderInstance) (void* data);
typedef bool (*SWIGPythonMightHaveChildrenSynthProviderInstance) (void* data);
diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h
index b0a07946e74..115f09c34d3 100644
--- a/lldb/include/lldb/Target/Platform.h
+++ b/lldb/include/lldb/Target/Platform.h
@@ -22,6 +22,7 @@
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/ConstString.h"
#include "lldb/Core/PluginInterface.h"
+#include "lldb/Interpreter/Options.h"
#include "lldb/Host/Mutex.h"
namespace lldb_private {
@@ -542,9 +543,190 @@ namespace lldb_private {
return false;
}
+ virtual uint32_t
+ MakeDirectory (const std::string &path,
+ mode_t mode)
+ {
+ return UINT32_MAX;
+ }
+
+ // this need not be virtual: the core behavior is in
+ // MakeDirectory(std::string,mode_t)
+ uint32_t
+ MakeDirectory (const FileSpec &spec,
+ mode_t mode);
+
+ virtual lldb::user_id_t
+ OpenFile (const FileSpec& file_spec,
+ uint32_t flags,
+ mode_t mode,
+ Error &error)
+ {
+ return UINT64_MAX;
+ }
+
+ virtual bool
+ CloseFile (lldb::user_id_t fd,
+ Error &error)
+ {
+ return false;
+ }
+
+ virtual lldb::user_id_t
+ GetFileSize (const FileSpec& file_spec)
+ {
+ return UINT64_MAX;
+ }
+
+ virtual uint64_t
+ ReadFile (lldb::user_id_t fd,
+ uint64_t offset,
+ void *dst,
+ uint64_t dst_len,
+ Error &error)
+ {
+ error.SetErrorStringWithFormat ("Platform::ReadFile() is not supported in the %s platform", GetName().GetCString());
+ return -1;
+ }
+
+ virtual uint64_t
+ WriteFile (lldb::user_id_t fd,
+ uint64_t offset,
+ const void* src,
+ uint64_t src_len,
+ Error &error)
+ {
+ error.SetErrorStringWithFormat ("Platform::ReadFile() is not supported in the %s platform", GetName().GetCString());
+ return -1;
+ }
+
+ virtual Error
+ PutFile (const FileSpec& source,
+ const FileSpec& destination,
+ uint32_t uid = UINT32_MAX,
+ uint32_t gid = UINT32_MAX);
+
virtual size_t
GetEnvironment (StringList &environment);
+ virtual Error
+ GetFile (const FileSpec& source,
+ const FileSpec& destination);
+
+ virtual bool
+ GetFileExists (const lldb_private::FileSpec& file_spec);
+
+ virtual uint32_t
+ GetFilePermissions (const lldb_private::FileSpec &file_spec,
+ Error &error)
+ {
+ error.SetErrorStringWithFormat ("Platform::GetFilePermissions() is not supported in the %s platform", GetName().GetCString());
+ return 0;
+ }
+
+ virtual bool
+ GetSupportsRSync ()
+ {
+ return m_supports_rsync;
+ }
+
+ virtual void
+ SetSupportsRSync(bool flag)
+ {
+ m_supports_rsync = flag;
+ }
+
+ virtual const char*
+ GetRSyncOpts ()
+ {
+ return m_rsync_opts.c_str();
+ }
+
+ virtual void
+ SetRSyncOpts (const char* opts)
+ {
+ m_rsync_opts.assign(opts);
+ }
+
+ virtual const char*
+ GetRSyncPrefix ()
+ {
+ return m_rsync_prefix.c_str();
+ }
+
+ virtual void
+ SetRSyncPrefix (const char* prefix)
+ {
+ m_rsync_prefix.assign(prefix);
+ }
+
+ virtual bool
+ GetSupportsSSH ()
+ {
+ return m_supports_ssh;
+ }
+
+ virtual void
+ SetSupportsSSH(bool flag)
+ {
+ m_supports_ssh = flag;
+ }
+
+ virtual const char*
+ GetSSHOpts ()
+ {
+ return m_ssh_opts.c_str();
+ }
+
+ virtual void
+ SetSSHOpts (const char* opts)
+ {
+ m_ssh_opts.assign(opts);
+ }
+
+ virtual bool
+ GetIgnoresRemoteHostname ()
+ {
+ return m_ignores_remote_hostname;
+ }
+
+ virtual void
+ SetIgnoresRemoteHostname(bool flag)
+ {
+ m_ignores_remote_hostname = flag;
+ }
+
+ virtual lldb_private::OptionGroupOptions *
+ GetConnectionOptions (CommandInterpreter& interpreter)
+ {
+ return NULL;
+ }
+
+ virtual lldb_private::Error
+ RunShellCommand (const char *command, // Shouldn't be NULL
+ const char *working_dir, // Pass NULL to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish
+
+ virtual void
+ SetLocalCacheDirectory (const char* local);
+
+ virtual const char*
+ GetLocalCacheDirectory ();
+
+ virtual std::string
+ GetPlatformSpecificConnectionInformation()
+ {
+ return "";
+ }
+
+ virtual bool
+ CalculateMD5 (const FileSpec& file_spec,
+ uint64_t &low,
+ uint64_t &high);
+
protected:
bool m_is_host;
// Set to true when we are able to actually set the OS version while
@@ -569,7 +751,14 @@ namespace lldb_private {
IDToNameMap m_gid_map;
size_t m_max_uid_name_len;
size_t m_max_gid_name_len;
-
+ bool m_supports_rsync;
+ std::string m_rsync_opts;
+ std::string m_rsync_prefix;
+ bool m_supports_ssh;
+ std::string m_ssh_opts;
+ bool m_ignores_remote_hostname;
+ std::string m_local_cache_directory;
+
const char *
GetCachedUserName (uint32_t uid)
{
@@ -750,6 +939,110 @@ namespace lldb_private {
private:
DISALLOW_COPY_AND_ASSIGN (PlatformList);
};
+
+ class OptionGroupPlatformRSync : public lldb_private::OptionGroup
+ {
+ public:
+ OptionGroupPlatformRSync ();
+
+ virtual
+ ~OptionGroupPlatformRSync ();
+
+ virtual lldb_private::Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ const lldb_private::OptionDefinition*
+ GetDefinitions ();
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb_private::OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_rsync;
+ std::string m_rsync_opts;
+ std::string m_rsync_prefix;
+ bool m_ignores_remote_hostname;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformRSync);
+ };
+
+ class OptionGroupPlatformSSH : public lldb_private::OptionGroup
+ {
+ public:
+ OptionGroupPlatformSSH ();
+
+ virtual
+ ~OptionGroupPlatformSSH ();
+
+ virtual lldb_private::Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ const lldb_private::OptionDefinition*
+ GetDefinitions ();
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb_private::OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_ssh;
+ std::string m_ssh_opts;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformSSH);
+ };
+
+ class OptionGroupPlatformCaching : public lldb_private::OptionGroup
+ {
+ public:
+ OptionGroupPlatformCaching ();
+
+ virtual
+ ~OptionGroupPlatformCaching ();
+
+ virtual lldb_private::Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ const lldb_private::OptionDefinition*
+ GetDefinitions ();
+
+ // Options table: Required for subclasses of Options.
+
+ static lldb_private::OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ std::string m_cache_dir;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformCaching);
+ };
+
} // namespace lldb_private
#endif // liblldb_Platform_h_
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index a76228c1e17..169eca60e9a 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -243,6 +243,12 @@ public:
return m_arch;
}
+ void
+ SetArchitecture (ArchSpec arch)
+ {
+ m_arch = arch;
+ }
+
lldb::pid_t
GetProcessID () const
{
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 6ec5ed6a35e..9ef342e3e98 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -406,6 +406,9 @@ namespace lldb {
eArgTypeOffset,
eArgTypeOldPathPrefix,
eArgTypeOneLiner,
+ eArgTypePath,
+ eArgTypePermissionsNumber,
+ eArgTypePermissionsString,
eArgTypePid,
eArgTypePlugin,
eArgTypeProcessName,
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index 84af8b64690..d8bc42c9212 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -90,6 +90,7 @@ class ExecutionContext;
class ExecutionContextRef;
class ExecutionContextRefLocker;
class ExecutionContextScope;
+class File;
class FileSpec;
class FileSpecList;
class Flags;
@@ -119,6 +120,7 @@ struct NameSearchContext;
class ObjCLanguageRuntime;
class ObjectContainer;
class OptionGroup;
+class OptionGroupOptions;
class OptionGroupPlatform;
class ObjectFile;
class OperatingSystem;
@@ -285,6 +287,7 @@ namespace lldb {
typedef std::shared_ptr<lldb_private::DynamicLoader> DynamicLoaderSP;
typedef std::shared_ptr<lldb_private::Event> EventSP;
typedef std::shared_ptr<lldb_private::ExecutionContextRef> ExecutionContextRefSP;
+ typedef std::shared_ptr<lldb_private::File> FileSP;
typedef std::shared_ptr<lldb_private::Function> FunctionSP;
typedef std::shared_ptr<lldb_private::FuncUnwinders> FuncUnwindersSP;
typedef std::shared_ptr<lldb_private::InlineFunctionInfo> InlineFunctionInfoSP;
diff --git a/lldb/include/lldb/lldb-private-log.h b/lldb/include/lldb/lldb-private-log.h
index 31a1c23c5e6..48cce69d36c 100644
--- a/lldb/include/lldb/lldb-private-log.h
+++ b/lldb/include/lldb/lldb-private-log.h
@@ -44,6 +44,7 @@
#define LIBLLDB_LOG_TARGET (1u << 22)
#define LIBLLDB_LOG_MMAP (1u << 23)
#define LIBLLDB_LOG_OS (1u << 24)
+#define LIBLLDB_LOG_PLATFORM (1u << 25)
#define LIBLLDB_LOG_ALL (UINT32_MAX)
#define LIBLLDB_LOG_DEFAULT (LIBLLDB_LOG_PROCESS |\
LIBLLDB_LOG_THREAD |\
diff --git a/lldb/lib/Makefile b/lldb/lib/Makefile
index 30ed3340b6b..85850e607e2 100644
--- a/lldb/lib/Makefile
+++ b/lldb/lib/Makefile
@@ -69,7 +69,8 @@ USEDLIBS = lldbAPI.a \
LLVMMCDisassembler.a \
lldbPluginPlatformMacOSX.a \
lldbPluginPlatformLinux.a \
- lldbPluginPlatformFreeBSD.a
+ lldbPluginPlatformFreeBSD.a \
+ lldbPluginPlatformPOSIX.a
# Because GCC requires RTTI enabled for lldbCore (see source/Core/Makefile) it is
# necessary to also link the clang rewriter libraries so vtable references can
diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj
index b2e034306c7..2bf84fd28e6 100644
--- a/lldb/lldb.xcodeproj/project.pbxproj
+++ b/lldb/lldb.xcodeproj/project.pbxproj
@@ -531,6 +531,9 @@
944372DD171F6B4300E57C32 /* RegisterContextDummy.h in Headers */ = {isa = PBXBuildFile; fileRef = 944372DB171F6B4300E57C32 /* RegisterContextDummy.h */; };
9443B122140C18C40013457C /* SBData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9443B121140C18C10013457C /* SBData.cpp */; };
9443B123140C26AB0013457C /* SBData.h in Headers */ = {isa = PBXBuildFile; fileRef = 9443B120140C18A90013457C /* SBData.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 945759671534941F005A9070 /* PlatformPOSIX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 945759651534941F005A9070 /* PlatformPOSIX.cpp */; };
+ 945759681534941F005A9070 /* PlatformPOSIX.h in Headers */ = {isa = PBXBuildFile; fileRef = 945759661534941F005A9070 /* PlatformPOSIX.h */; };
+ 945E8D80152F6AB40019BCCD /* StreamGDBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 945E8D7F152F6AB40019BCCD /* StreamGDBRemote.cpp */; };
9452573A16262D0200325455 /* SBDeclaration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9452573916262D0200325455 /* SBDeclaration.cpp */; };
9456F2241616671900656F91 /* DynamicLibrary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9456F2211616644B00656F91 /* DynamicLibrary.cpp */; };
94611EB213CCA4A4003A22AF /* RefCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94611EB113CCA4A4003A22AF /* RefCounter.cpp */; };
@@ -547,6 +550,7 @@
947A1D651616476B0017C8D1 /* CommandObjectPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 947A1D631616476A0017C8D1 /* CommandObjectPlugin.h */; };
949ADF031406F648004833E1 /* ValueObjectConstResultImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 949ADF021406F648004833E1 /* ValueObjectConstResultImpl.cpp */; };
94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94B6E76113D88362005F417F /* ValueObjectSyntheticFilter.cpp */; };
+ 94E829CA152D33C1006F96A3 /* lldb-platform in Resources */ = {isa = PBXBuildFile; fileRef = 26DC6A101337FE6900FF7998 /* lldb-platform */; };
94BA8B6D176F8C9B005A91B5 /* Range.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94BA8B6C176F8C9B005A91B5 /* Range.cpp */; };
94BA8B70176F97CE005A91B5 /* CommandHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94BA8B6F176F97CE005A91B5 /* CommandHistory.cpp */; };
94CB255B16B069770059775D /* CXXFormatterFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CB255716B069770059775D /* CXXFormatterFunctions.cpp */; };
@@ -712,6 +716,13 @@
remoteGlobalIDString = 2689FFC913353D7A00698AC0;
remoteInfo = "lldb-core";
};
+ 94E829C8152D33B4006F96A3 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 26DC6A0F1337FE6900FF7998;
+ remoteInfo = "lldb-platform";
+ };
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -1562,6 +1573,10 @@
944372DB171F6B4300E57C32 /* RegisterContextDummy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextDummy.h; path = Utility/RegisterContextDummy.h; sourceTree = "<group>"; };
9443B120140C18A90013457C /* SBData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBData.h; path = include/lldb/API/SBData.h; sourceTree = "<group>"; };
9443B121140C18C10013457C /* SBData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBData.cpp; path = source/API/SBData.cpp; sourceTree = "<group>"; };
+ 945759651534941F005A9070 /* PlatformPOSIX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformPOSIX.cpp; path = POSIX/PlatformPOSIX.cpp; sourceTree = "<group>"; };
+ 945759661534941F005A9070 /* PlatformPOSIX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlatformPOSIX.h; path = POSIX/PlatformPOSIX.h; sourceTree = "<group>"; };
+ 945E8D7D152F6AA80019BCCD /* StreamGDBRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StreamGDBRemote.h; path = include/lldb/Core/StreamGDBRemote.h; sourceTree = "<group>"; };
+ 945E8D7F152F6AB40019BCCD /* StreamGDBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StreamGDBRemote.cpp; path = source/Core/StreamGDBRemote.cpp; sourceTree = "<group>"; };
944DC3481774C99000D7D884 /* python-swigsafecast.swig */ = {isa = PBXFileReference; lastKnownFileType = text; path = "python-swigsafecast.swig"; sourceTree = "<group>"; };
9452573616262CD000325455 /* SBDeclaration.i */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBDeclaration.i; sourceTree = "<group>"; };
9452573816262CEF00325455 /* SBDeclaration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBDeclaration.h; path = include/lldb/API/SBDeclaration.h; sourceTree = "<group>"; };
@@ -2656,6 +2671,8 @@
4C6649A214EEE81000B0316F /* StreamCallback.cpp */,
26BC7D7A10F1B77400F91463 /* StreamFile.h */,
26BC7E9210F1B85900F91463 /* StreamFile.cpp */,
+ 945E8D7D152F6AA80019BCCD /* StreamGDBRemote.h */,
+ 945E8D7F152F6AB40019BCCD /* StreamGDBRemote.cpp */,
26BC7D7B10F1B77400F91463 /* StreamString.h */,
26BC7E9310F1B85900F91463 /* StreamString.cpp */,
4C626533130F1B0A00C889F6 /* StreamTee.h */,
@@ -3154,6 +3171,7 @@
26C5577E132575B6008FD8FE /* Platform */ = {
isa = PBXGroup;
children = (
+ 9457596415349416005A9070 /* POSIX */,
2694E99814FC0BB30076DE67 /* FreeBSD */,
264A97BC133918A30017F0BE /* GDB Server */,
2694E99F14FC0BBD0076DE67 /* Linux */,
@@ -3402,6 +3420,69 @@
path = source/Host/common;
sourceTree = "<group>";
};
+ 9457596415349416005A9070 /* POSIX */ = {
+ isa = PBXGroup;
+ children = (
+ 945759651534941F005A9070 /* PlatformPOSIX.cpp */,
+ 945759661534941F005A9070 /* PlatformPOSIX.h */,
+ );
+ name = POSIX;
+ sourceTree = "<group>";
+ };
+ 940DB8C416EA64D400D3C2F1 /* lldb-perf */ = {
+ isa = PBXGroup;
+ children = (
+ 940DB8C616EA654E00D3C2F1 /* darwin */,
+ 940DB8C516EA654900D3C2F1 /* lib */,
+ );
+ name = "lldb-perf";
+ path = "tools/lldb-perf";
+ sourceTree = "<group>";
+ };
+ 940DB8C516EA654900D3C2F1 /* lib */ = {
+ isa = PBXGroup;
+ children = (
+ 940DB8CA16EA66FB00D3C2F1 /* Gauge.h */,
+ 940DB8CE16EA670C00D3C2F1 /* Measurement.h */,
+ 940DB8D116EA671800D3C2F1 /* MemoryGauge.cpp */,
+ 940DB8D216EA671800D3C2F1 /* MemoryGauge.h */,
+ 940DB8D516EA672200D3C2F1 /* Metric.cpp */,
+ 940DB8D616EA672200D3C2F1 /* Metric.h */,
+ 940DB8D916EA672D00D3C2F1 /* TestCase.cpp */,
+ 940DB8DA16EA672D00D3C2F1 /* TestCase.h */,
+ 940DB8DD16EA673800D3C2F1 /* Timer.cpp */,
+ 940DB8DE16EA673800D3C2F1 /* Timer.h */,
+ 940DB8E116EA674000D3C2F1 /* Xcode.cpp */,
+ 940DB8E216EA674000D3C2F1 /* Xcode.h */,
+ );
+ path = lib;
+ sourceTree = "<group>";
+ };
+ 940DB8C616EA654E00D3C2F1 /* darwin */ = {
+ isa = PBXGroup;
+ children = (
+ 940DB8FB16EA84BF00D3C2F1 /* formatters */,
+ 940DB8C716EA655400D3C2F1 /* sketch */,
+ );
+ path = darwin;
+ sourceTree = "<group>";
+ };
+ 940DB8C716EA655400D3C2F1 /* sketch */ = {
+ isa = PBXGroup;
+ children = (
+ 940DB8E616EA709400D3C2F1 /* main.cpp */,
+ );
+ path = sketch;
+ sourceTree = "<group>";
+ };
+ 940DB8FB16EA84BF00D3C2F1 /* formatters */ = {
+ isa = PBXGroup;
+ children = (
+ 94DB60F016EA888A00459D9E /* main.cpp */,
+ );
+ path = formatters;
+ sourceTree = "<group>";
+ };
94CB255616B0683B0059775D /* DataFormatters */ = {
isa = PBXGroup;
children = (
@@ -3536,6 +3617,7 @@
2694E99E14FC0BB30076DE67 /* PlatformFreeBSD.h in Headers */,
2694E9A514FC0BBD0076DE67 /* PlatformLinux.h in Headers */,
2663E379152BD1890091EC22 /* ReadWriteLock.h in Headers */,
+ 945759681534941F005A9070 /* PlatformPOSIX.h in Headers */,
26B1EFAF154638AF00E2DAC7 /* DWARFDeclContext.h in Headers */,
260CC62E15D04377002BF2E0 /* OptionValueArgs.h in Headers */,
260CC62F15D04377002BF2E0 /* OptionValueArray.h in Headers */,
@@ -3616,6 +3698,7 @@
buildRules = (
);
dependencies = (
+ 94E829C9152D33B4006F96A3 /* PBXTargetDependency */,
2689011513353E9B00698AC0 /* PBXTargetDependency */,
262CFC7211A450CB00946C6C /* PBXTargetDependency */,
26368AF6126B95FA00E8659F /* PBXTargetDependency */,
@@ -3766,6 +3849,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 94E829CA152D33C1006F96A3 /* lldb-platform in Resources */,
262CFC7711A4510000946C6C /* debugserver in Resources */,
26368AF7126B960500E8659F /* darwin-debug in Resources */,
);
@@ -4269,6 +4353,8 @@
26FFC19D14FC072100087D58 /* DynamicLoaderPOSIXDYLD.cpp in Sources */,
2694E99D14FC0BB30076DE67 /* PlatformFreeBSD.cpp in Sources */,
2694E9A414FC0BBD0076DE67 /* PlatformLinux.cpp in Sources */,
+ 945E8D80152F6AB40019BCCD /* StreamGDBRemote.cpp in Sources */,
+ 945759671534941F005A9070 /* PlatformPOSIX.cpp in Sources */,
26B1EFAE154638AF00E2DAC7 /* DWARFDeclContext.cpp in Sources */,
260CC64815D0440D002BF2E0 /* OptionValueArgs.cpp in Sources */,
260CC64915D0440D002BF2E0 /* OptionValueArray.cpp in Sources */,
@@ -4416,6 +4502,11 @@
target = 2689FFC913353D7A00698AC0 /* lldb-core */;
targetProxy = 26DC6A151337FE7300FF7998 /* PBXContainerItemProxy */;
};
+ 94E829C9152D33B4006F96A3 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 26DC6A0F1337FE6900FF7998 /* lldb-platform */;
+ targetProxy = 94E829C8152D33B4006F96A3 /* PBXContainerItemProxy */;
+ };
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
@@ -5127,6 +5218,7 @@
OTHER_LDFLAGS = (
"-lllvmclang",
"-lpython",
+ "-lxml2",
"-framework",
DebugSymbols,
"-framework",
@@ -5190,6 +5282,7 @@
OTHER_LDFLAGS = (
"-lllvmclang",
"-lpython",
+ "-lxml2",
"-framework",
DebugSymbols,
"-framework",
@@ -5252,6 +5345,7 @@
OTHER_LDFLAGS = (
"-lllvmclang",
"-lpython",
+ "-lxml2",
"-framework",
DebugSymbols,
"-framework",
diff --git a/lldb/scripts/Python/python-wrapper.swig b/lldb/scripts/Python/python-wrapper.swig
index f3cbf5f1c83..444b9c3e395 100644
--- a/lldb/scripts/Python/python-wrapper.swig
+++ b/lldb/scripts/Python/python-wrapper.swig
@@ -912,6 +912,19 @@ LLDBSwigPythonCallModuleInit
// typemaps and in the extensions (SBInputReader.__del__()).
#include "lldb/API/SBInputReader.h"
#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBValue.h"
+
+SWIGEXPORT lldb::ValueObjectSP
+LLDBSWIGPython_GetValueObjectSPFromSBValue (void* data)
+{
+ lldb::ValueObjectSP valobj_sp;
+ if (data)
+ {
+ lldb::SBValue* sb_ptr = (lldb::SBValue *)data;
+ valobj_sp = sb_ptr->GetSP();
+ }
+ return valobj_sp;
+}
#ifdef __cplusplus
extern "C" {
diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
index aa9b23ac7c6..f13b6722d99 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -63,20 +63,20 @@ public:
lldb::DynamicValueType use_dynamic,
bool use_synthetic,
const char *name = NULL) :
- m_valobj_sp(in_valobj_sp),
- m_use_dynamic(use_dynamic),
- m_use_synthetic(use_synthetic),
- m_name (name)
+ m_valobj_sp(in_valobj_sp),
+ m_use_dynamic(use_dynamic),
+ m_use_synthetic(use_synthetic),
+ m_name (name)
{
if (!m_name.IsEmpty() && m_valobj_sp)
m_valobj_sp->SetName(m_name);
}
ValueImpl (const ValueImpl& rhs) :
- m_valobj_sp(rhs.m_valobj_sp),
- m_use_dynamic(rhs.m_use_dynamic),
- m_use_synthetic(rhs.m_use_synthetic),
- m_name (rhs.m_name)
+ m_valobj_sp(rhs.m_valobj_sp),
+ m_use_dynamic(rhs.m_use_dynamic),
+ m_use_synthetic(rhs.m_use_synthetic),
+ m_name (rhs.m_name)
{
}
@@ -120,7 +120,7 @@ public:
Target *target = value_sp->GetTargetSP().get();
if (target)
api_locker.Lock(target->GetAPIMutex());
-
+
ProcessSP process_sp(value_sp->GetProcessSP());
if (process_sp && !stop_locker.TryLock (&process_sp->GetRunLock()))
{
@@ -131,7 +131,7 @@ public:
error.SetErrorString ("process must be stopped.");
return ValueObjectSP();
}
-
+
if (value_sp->GetDynamicValue(m_use_dynamic))
value_sp = value_sp->GetDynamicValue(m_use_dynamic);
if (value_sp->GetSyntheticValue(m_use_synthetic))
@@ -167,7 +167,7 @@ public:
{
return m_use_synthetic;
}
-
+
// All the derived values that we would make from the m_valobj_sp will share
// the ExecutionContext with m_valobj_sp, so we don't need to do the calculations
// in GetSP to return the Target, Process, Thread or Frame. It is convenient to
@@ -207,7 +207,7 @@ public:
else
return StackFrameSP();
}
-
+
private:
lldb::ValueObjectSP m_valobj_sp;
lldb::DynamicValueType m_use_dynamic;
@@ -227,7 +227,7 @@ public:
{
return in_value.GetSP(m_stop_locker, m_api_locker, m_lock_error);
}
-
+
Error &
GetError()
{
@@ -238,11 +238,11 @@ private:
Process::StopLocker m_stop_locker;
Mutex::Locker m_api_locker;
Error m_lock_error;
-
+
};
SBValue::SBValue () :
- m_opaque_sp ()
+m_opaque_sp ()
{
}
@@ -318,7 +318,7 @@ SBValue::GetName()
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
name = value_sp->GetName().GetCString();
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
{
@@ -327,7 +327,7 @@ SBValue::GetName()
else
log->Printf ("SBValue(%p)::GetName () => NULL", value_sp.get());
}
-
+
return name;
}
@@ -350,7 +350,7 @@ SBValue::GetTypeName ()
else
log->Printf ("SBValue(%p)::GetTypeName () => NULL", value_sp.get());
}
-
+
return name;
}
@@ -359,17 +359,17 @@ SBValue::GetByteSize ()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
size_t result = 0;
-
+
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
{
result = value_sp->GetByteSize();
}
-
+
if (log)
log->Printf ("SBValue(%p)::GetByteSize () => %" PRIu64, value_sp.get(), (uint64_t)result);
-
+
return result;
}
@@ -377,18 +377,18 @@ bool
SBValue::IsInScope ()
{
bool result = false;
-
+
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
{
result = value_sp->IsInScope ();
}
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
log->Printf ("SBValue(%p)::IsInScope () => %i", value_sp.get(), result);
-
+
return result;
}
@@ -396,7 +396,7 @@ const char *
SBValue::GetValue ()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
const char *cstr = NULL;
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
@@ -411,7 +411,7 @@ SBValue::GetValue ()
else
log->Printf ("SBValue(%p)::GetValue() => NULL", value_sp.get());
}
-
+
return cstr;
}
@@ -429,14 +429,14 @@ SBValue::GetValueType ()
{
switch (result)
{
- case eValueTypeInvalid: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeInvalid", value_sp.get()); break;
- case eValueTypeVariableGlobal: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableGlobal", value_sp.get()); break;
- case eValueTypeVariableStatic: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableStatic", value_sp.get()); break;
- case eValueTypeVariableArgument:log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableArgument", value_sp.get()); break;
- case eValueTypeVariableLocal: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableLocal", value_sp.get()); break;
- case eValueTypeRegister: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeRegister", value_sp.get()); break;
- case eValueTypeRegisterSet: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeRegisterSet", value_sp.get()); break;
- case eValueTypeConstResult: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeConstResult", value_sp.get()); break;
+ case eValueTypeInvalid: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeInvalid", value_sp.get()); break;
+ case eValueTypeVariableGlobal: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableGlobal", value_sp.get()); break;
+ case eValueTypeVariableStatic: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableStatic", value_sp.get()); break;
+ case eValueTypeVariableArgument:log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableArgument", value_sp.get()); break;
+ case eValueTypeVariableLocal: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableLocal", value_sp.get()); break;
+ case eValueTypeRegister: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeRegister", value_sp.get()); break;
+ case eValueTypeRegisterSet: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeRegisterSet", value_sp.get()); break;
+ case eValueTypeConstResult: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeConstResult", value_sp.get()); break;
}
}
return result;
@@ -499,7 +499,7 @@ SBValue::GetValueDidChange ()
}
if (log)
log->Printf ("SBValue(%p)::GetValueDidChange() => %i", value_sp.get(), result);
-
+
return result;
}
@@ -571,7 +571,7 @@ SBValue::SetValueFromCString (const char *value_str, lldb::SBError& error)
if (log)
log->Printf ("SBValue(%p)::SetValueFromCString(\"%s\") => %i", value_sp.get(), value_str, success);
-
+
return success;
}
@@ -765,15 +765,15 @@ SBValue::CreateValueFromAddress(const char* name, lldb::addr_t address, SBType s
if (pointee_ast_type)
{
lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(&address,sizeof(lldb::addr_t)));
-
+
ExecutionContext exe_ctx (value_sp->GetExecutionContextRef());
ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
pointee_ast_type,
ConstString(name),
buffer,
- lldb::endian::InlHostByteOrder(),
+ lldb::endian::InlHostByteOrder(),
exe_ctx.GetAddressByteSize()));
-
+
if (ptr_result_valobj_sp)
{
ptr_result_valobj_sp->GetValue().SetValueType(Value::eValueTypeLoadAddress);
@@ -806,7 +806,7 @@ SBValue::CreateValueFromData (const char* name, SBData data, SBType type)
if (value_sp)
{
ExecutionContext exe_ctx (value_sp->GetExecutionContextRef());
-
+
new_value_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
type.m_opaque_sp->GetClangASTType(),
ConstString(name),
@@ -837,7 +837,7 @@ SBValue::GetChildAtIndex (uint32_t idx)
if (target_sp)
use_dynamic = target_sp->GetPreferDynamicValue();
-
+
return GetChildAtIndex (idx, use_dynamic, can_create_synthetic);
}
@@ -846,7 +846,7 @@ SBValue::GetChildAtIndex (uint32_t idx, lldb::DynamicValueType use_dynamic, bool
{
lldb::ValueObjectSP child_sp;
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
@@ -870,7 +870,7 @@ SBValue::GetChildAtIndex (uint32_t idx, lldb::DynamicValueType use_dynamic, bool
sb_value.SetSP (child_sp, use_dynamic, GetPreferSyntheticValue());
if (log)
log->Printf ("SBValue(%p)::GetChildAtIndex (%u) => SBValue(%p)", value_sp.get(), idx, value_sp.get());
-
+
return sb_value;
}
@@ -913,9 +913,9 @@ SBValue::GetChildMemberWithName (const char *name, lldb::DynamicValueType use_dy
{
lldb::ValueObjectSP child_sp;
const ConstString str_name (name);
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
@@ -925,10 +925,10 @@ SBValue::GetChildMemberWithName (const char *name, lldb::DynamicValueType use_dy
SBValue sb_value;
sb_value.SetSP(child_sp, use_dynamic_value, GetPreferSyntheticValue());
-
+
if (log)
log->Printf ("SBValue(%p)::GetChildMemberWithName (name=\"%s\") => SBValue(%p)", value_sp.get(), name, value_sp.get());
-
+
return sb_value;
}
@@ -1117,7 +1117,7 @@ SBValue::MightHaveChildren ()
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
has_children = value_sp->MightHaveChildren();
-
+
if (log)
log->Printf ("SBValue(%p)::MightHaveChildren() => %i", value_sp.get(), has_children);
return has_children;
@@ -1127,16 +1127,16 @@ uint32_t
SBValue::GetNumChildren ()
{
uint32_t num_children = 0;
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
num_children = value_sp->GetNumChildren();
-
+
if (log)
log->Printf ("SBValue(%p)::GetNumChildren () => %u", value_sp.get(), num_children);
-
+
return num_children;
}
@@ -1149,13 +1149,13 @@ SBValue::Dereference ()
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
{
- Error error;
- sb_value = value_sp->Dereference (error);
+ Error error;
+ sb_value = value_sp->Dereference (error);
}
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
log->Printf ("SBValue(%p)::Dereference () => SBValue(%p)", value_sp.get(), value_sp.get());
-
+
return sb_value;
}
@@ -1163,17 +1163,17 @@ bool
SBValue::TypeIsPointerType ()
{
bool is_ptr_type = false;
-
+
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
is_ptr_type = value_sp->IsPointerType();
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
log->Printf ("SBValue(%p)::TypeIsPointerType () => %i", value_sp.get(), is_ptr_type);
-
-
+
+
return is_ptr_type;
}
@@ -1390,7 +1390,7 @@ bool
SBValue::GetDescription (SBStream &description)
{
Stream &strm = description.ref();
-
+
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
@@ -1399,7 +1399,7 @@ SBValue::GetDescription (SBStream &description)
}
else
strm.PutCString ("No value");
-
+
return true;
}
@@ -1653,7 +1653,7 @@ SBValue::Watch (bool resolve_location, bool read, bool write, SBError &error)
size_t byte_size = GetByteSize();
if (byte_size == 0)
return sb_watchpoint;
-
+
uint32_t watch_type = 0;
if (read)
watch_type |= LLDB_WATCH_TYPE_READ;
@@ -1664,14 +1664,14 @@ SBValue::Watch (bool resolve_location, bool read, bool write, SBError &error)
ClangASTType type (value_sp->GetClangType());
WatchpointSP watchpoint_sp = target_sp->CreateWatchpoint(addr, byte_size, &type, watch_type, rc);
error.SetError(rc);
-
- if (watchpoint_sp)
+
+ if (watchpoint_sp)
{
sb_watchpoint.SetSP (watchpoint_sp);
Declaration decl;
if (value_sp->GetDeclaration (decl))
{
- if (decl.GetFile())
+ if (decl.GetFile())
{
StreamString ss;
// True to show fullpath for declaration file.
diff --git a/lldb/source/CMakeLists.txt b/lldb/source/CMakeLists.txt
index eddd8cb095a..2a1292a80d1 100644
--- a/lldb/source/CMakeLists.txt
+++ b/lldb/source/CMakeLists.txt
@@ -58,6 +58,7 @@ set( LLDB_USED_LIBS
lldbPluginPlatformGDB
lldbPluginPlatformFreeBSD
lldbPluginPlatformLinux
+ lldbPluginPlatformPOSIX
lldbPluginObjectFileMachO
lldbPluginObjectContainerMachOArchive
lldbPluginObjectContainerBSDArchive
diff --git a/lldb/source/Commands/CommandObjectPlatform.cpp b/lldb/source/Commands/CommandObjectPlatform.cpp
index c2185e598ad..68a1dec1cb9 100644
--- a/lldb/source/Commands/CommandObjectPlatform.cpp
+++ b/lldb/source/Commands/CommandObjectPlatform.cpp
@@ -26,10 +26,158 @@
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/Utils.h"
using namespace lldb;
using namespace lldb_private;
+static mode_t
+ParsePermissionString(const char* permissions)
+{
+ if (strlen(permissions) != 9)
+ return (mode_t)(-1);
+ bool user_r,user_w,user_x,
+ group_r,group_w,group_x,
+ world_r,world_w,world_x;
+
+ user_r = (permissions[0] == 'r');
+ user_w = (permissions[1] == 'w');
+ user_x = (permissions[2] == 'x');
+
+ group_r = (permissions[3] == 'r');
+ group_w = (permissions[4] == 'w');
+ group_x = (permissions[5] == 'x');
+
+ world_r = (permissions[6] == 'r');
+ world_w = (permissions[7] == 'w');
+ world_x = (permissions[8] == 'x');
+
+ mode_t user,group,world;
+ user = (user_r ? 4 : 0) | (user_w ? 2 : 0) | (user_x ? 1 : 0);
+ group = (group_r ? 4 : 0) | (group_w ? 2 : 0) | (group_x ? 1 : 0);
+ world = (world_r ? 4 : 0) | (world_w ? 2 : 0) | (world_x ? 1 : 0);
+
+ return user | group | world;
+}
+
+static OptionDefinition
+g_permissions_options[] =
+{
+ { LLDB_OPT_SET_ALL, false, "permissions-value", 'v', required_argument, NULL, 0, eArgTypePermissionsNumber , "Give out the numeric value for permissions (e.g. 757)" },
+ { LLDB_OPT_SET_ALL, false, "permissions-string",'s', required_argument, NULL, 0, eArgTypePermissionsString , "Give out the string value for permissions (e.g. rwxr-xr--)." },
+ { LLDB_OPT_SET_ALL, false, "user-read", 'r', no_argument, NULL, 0, eArgTypeNone , "Allow user to read." },
+ { LLDB_OPT_SET_ALL, false, "user-write", 'w', no_argument, NULL, 0, eArgTypeNone , "Allow user to write." },
+ { LLDB_OPT_SET_ALL, false, "user-exec", 'x', no_argument, NULL, 0, eArgTypeNone , "Allow user to execute." },
+
+ { LLDB_OPT_SET_ALL, false, "group-read", 'R', no_argument, NULL, 0, eArgTypeNone , "Allow group to read." },
+ { LLDB_OPT_SET_ALL, false, "group-write", 'W', no_argument, NULL, 0, eArgTypeNone , "Allow group to write." },
+ { LLDB_OPT_SET_ALL, false, "group-exec", 'X', no_argument, NULL, 0, eArgTypeNone , "Allow group to execute." },
+
+ { LLDB_OPT_SET_ALL, false, "world-read", 'd', no_argument, NULL, 0, eArgTypeNone , "Allow world to read." },
+ { LLDB_OPT_SET_ALL, false, "world-write", 't', no_argument, NULL, 0, eArgTypeNone , "Allow world to write." },
+ { LLDB_OPT_SET_ALL, false, "world-exec", 'e', no_argument, NULL, 0, eArgTypeNone , "Allow world to execute." },
+
+};
+
+class OptionPermissions : public lldb_private::OptionGroup
+{
+public:
+ OptionPermissions ()
+ {
+ }
+
+ virtual
+ ~OptionPermissions ()
+ {
+ }
+
+ virtual lldb_private::Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+ {
+ Error error;
+ char short_option = (char) GetDefinitions()[option_idx].short_option;
+ switch (short_option)
+ {
+ case 'v':
+ {
+ bool ok;
+ uint32_t perms = Args::StringToUInt32(option_arg, 777, 8, &ok);
+ if (!ok)
+ error.SetErrorStringWithFormat("invalid value for permissions: %s", option_arg);
+ else
+ m_permissions = perms;
+ }
+ break;
+ case 's':
+ {
+ mode_t perms = ParsePermissionString(option_arg);
+ if (perms == (mode_t)-1)
+ error.SetErrorStringWithFormat("invalid value for permissions: %s", option_arg);
+ else
+ m_permissions = perms;
+ }
+ case 'r':
+ m_permissions |= File::ePermissionsUserRead;
+ break;
+ case 'w':
+ m_permissions |= File::ePermissionsUserWrite;
+ break;
+ case 'x':
+ m_permissions |= File::ePermissionsUserExecute;
+ break;
+ case 'R':
+ m_permissions |= File::ePermissionsGroupRead;
+ break;
+ case 'W':
+ m_permissions |= File::ePermissionsGroupWrite;
+ break;
+ case 'X':
+ m_permissions |= File::ePermissionsGroupExecute;
+ break;
+ case 'd':
+ m_permissions |= File::ePermissionsWorldRead;
+ break;
+ case 't':
+ m_permissions |= File::ePermissionsWorldWrite;
+ break;
+ case 'e':
+ m_permissions |= File::ePermissionsWorldExecute;
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting (CommandInterpreter &interpreter)
+ {
+ m_permissions = 0;
+ }
+
+ virtual uint32_t
+ GetNumDefinitions ()
+ {
+ return llvm::array_lengthof(g_permissions_options);
+ }
+
+ const lldb_private::OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_permissions_options;
+ }
+
+ // Instance variables to hold the values for command options.
+
+ uint32_t m_permissions;
+private:
+ DISALLOW_COPY_AND_ASSIGN(OptionPermissions);
+};
//----------------------------------------------------------------------
// "platform select <platform-name>"
@@ -274,11 +422,26 @@ protected:
}
else
{
- result.AppendError ("no platform us currently selected\n");
+ result.AppendError ("no platform is currently selected\n");
result.SetStatus (eReturnStatusFailed);
}
return result.Succeeded();
}
+
+ virtual Options *
+ GetOptions ()
+ {
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ OptionGroupOptions* m_platform_options = NULL;
+ if (platform_sp)
+ {
+ m_platform_options = platform_sp->GetConnectionOptions(m_interpreter);
+ if (m_platform_options != NULL && !m_platform_options->m_did_finalize)
+ m_platform_options->Finalize();
+ }
+ return m_platform_options;
+ }
+
};
//----------------------------------------------------------------------
@@ -359,6 +522,680 @@ protected:
return result.Succeeded();
}
};
+
+//----------------------------------------------------------------------
+// "platform mkdir"
+//----------------------------------------------------------------------
+class CommandObjectPlatformMkDir : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformMkDir (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform shell",
+ "Make a new directory on the remote end.",
+ NULL,
+ 0),
+ m_options(interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformMkDir ()
+ {
+ }
+
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ if (platform_sp)
+ {
+ std::string cmd_line;
+ args.GetCommandString(cmd_line);
+ mode_t perms;
+ const OptionPermissions* options_permissions = (OptionPermissions*)m_options.GetGroupWithOption('r');
+ if (options_permissions)
+ perms = options_permissions->m_permissions;
+ else
+ perms = 0000700 | 0000070 | 0000007;
+ uint32_t retcode = platform_sp->MakeDirectory(cmd_line,perms);
+ result.AppendMessageWithFormat("Status = %d\n",retcode);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError ("no platform currently selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ if (m_options.DidFinalize() == false)
+ {
+ m_options.Append(new OptionPermissions());
+ m_options.Finalize();
+ }
+ return &m_options;
+ }
+ OptionGroupOptions m_options;
+
+};
+
+//----------------------------------------------------------------------
+// "platform fopen"
+//----------------------------------------------------------------------
+class CommandObjectPlatformFOpen : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformFOpen (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform file open",
+ "Open a file on the remote end.",
+ NULL,
+ 0),
+ m_options(interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformFOpen ()
+ {
+ }
+
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ if (platform_sp)
+ {
+ Error error;
+ std::string cmd_line;
+ args.GetCommandString(cmd_line);
+ mode_t perms;
+ const OptionPermissions* options_permissions = (OptionPermissions*)m_options.GetGroupWithOption('r');
+ if (options_permissions)
+ perms = options_permissions->m_permissions;
+ else
+ perms = 0000700 | 0000070 | 0000007;
+ lldb::user_id_t fd = platform_sp->OpenFile(FileSpec(cmd_line.c_str(),false),
+ File::eOpenOptionRead | File::eOpenOptionWrite |
+ File::eOpenOptionAppend | File::eOpenOptionCanCreate,
+ perms,
+ error);
+ if (error.Success())
+ {
+ result.AppendMessageWithFormat("File Descriptor = %" PRIu64 "\n",fd);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("no platform currently selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+ virtual Options *
+ GetOptions ()
+ {
+ if (m_options.DidFinalize() == false)
+ {
+ m_options.Append(new OptionPermissions());
+ m_options.Finalize();
+ }
+ return &m_options;
+ }
+ OptionGroupOptions m_options;
+};
+
+//----------------------------------------------------------------------
+// "platform fclose"
+//----------------------------------------------------------------------
+class CommandObjectPlatformFClose : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformFClose (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform file close",
+ "Close a file on the remote end.",
+ NULL,
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformFClose ()
+ {
+ }
+
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ if (platform_sp)
+ {
+ std::string cmd_line;
+ args.GetCommandString(cmd_line);
+ const lldb::user_id_t fd = Args::StringToUInt64(cmd_line.c_str(), UINT64_MAX);
+ Error error;
+ bool success = platform_sp->CloseFile(fd, error);
+ if (success)
+ {
+ result.AppendMessageWithFormat("file %" PRIu64 " closed.\n", fd);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("no platform currently selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+//----------------------------------------------------------------------
+// "platform fread"
+//----------------------------------------------------------------------
+class CommandObjectPlatformFRead : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformFRead (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform file read",
+ "Read data from a file on the remote end.",
+ NULL,
+ 0),
+ m_options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformFRead ()
+ {
+ }
+
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ if (platform_sp)
+ {
+ std::string cmd_line;
+ args.GetCommandString(cmd_line);
+ const lldb::user_id_t fd = Args::StringToUInt64(cmd_line.c_str(), UINT64_MAX);
+ std::string buffer(m_options.m_count,0);
+ Error error;
+ uint32_t retcode = platform_sp->ReadFile(fd, m_options.m_offset, &buffer[0], m_options.m_count, error);
+ result.AppendMessageWithFormat("Return = %d\n",retcode);
+ result.AppendMessageWithFormat("Data = \"%s\"\n",buffer.c_str());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError ("no platform currently selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ char short_option = (char) m_getopt_table[option_idx].val;
+ bool success = false;
+
+ switch (short_option)
+ {
+ case 'o':
+ m_offset = Args::StringToUInt32(option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg);
+ break;
+ case 'c':
+ m_count = Args::StringToUInt32(option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_offset = 0;
+ m_count = 1;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ uint32_t m_offset;
+ uint32_t m_count;
+ };
+ CommandOptions m_options;
+};
+OptionDefinition
+CommandObjectPlatformFRead::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "offset" , 'o', required_argument, NULL, 0, eArgTypeIndex , "Offset into the file at which to start reading." },
+ { LLDB_OPT_SET_1, false, "count" , 'c', required_argument, NULL, 0, eArgTypeCount , "Number of bytes to read from the file." },
+ { 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone , NULL }
+};
+
+
+//----------------------------------------------------------------------
+// "platform fwrite"
+//----------------------------------------------------------------------
+class CommandObjectPlatformFWrite : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformFWrite (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform file write",
+ "Write data to a file on the remote end.",
+ NULL,
+ 0),
+ m_options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformFWrite ()
+ {
+ }
+
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ if (platform_sp)
+ {
+ std::string cmd_line;
+ args.GetCommandString(cmd_line);
+ Error error;
+ const lldb::user_id_t fd = Args::StringToUInt64(cmd_line.c_str(), UINT64_MAX);
+ uint32_t retcode = platform_sp->WriteFile (fd,
+ m_options.m_offset,
+ &m_options.m_data[0],
+ m_options.m_data.size(),
+ error);
+ result.AppendMessageWithFormat("Return = %d\n",retcode);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError ("no platform currently selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ char short_option = (char) m_getopt_table[option_idx].val;
+ bool success = false;
+
+ switch (short_option)
+ {
+ case 'o':
+ m_offset = Args::StringToUInt32(option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg);
+ break;
+ case 'd':
+ m_data.assign(option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_offset = 0;
+ m_data.clear();
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ uint32_t m_offset;
+ std::string m_data;
+ };
+ CommandOptions m_options;
+};
+OptionDefinition
+CommandObjectPlatformFWrite::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "offset" , 'o', required_argument, NULL, 0, eArgTypeIndex , "Offset into the file at which to start reading." },
+ { LLDB_OPT_SET_1, false, "data" , 'd', required_argument, NULL, 0, eArgTypeValue , "Text to write to the file." },
+ { 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone , NULL }
+};
+
+class CommandObjectPlatformFile : public CommandObjectMultiword
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectPlatformFile (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "platform file",
+ "A set of commands to manage file access through a platform",
+ "platform file [open|close|read|write] ...")
+ {
+ LoadSubCommand ("open", CommandObjectSP (new CommandObjectPlatformFOpen (interpreter)));
+ LoadSubCommand ("close", CommandObjectSP (new CommandObjectPlatformFClose (interpreter)));
+ LoadSubCommand ("read", CommandObjectSP (new CommandObjectPlatformFRead (interpreter)));
+ LoadSubCommand ("write", CommandObjectSP (new CommandObjectPlatformFWrite (interpreter)));
+ }
+
+ virtual
+ ~CommandObjectPlatformFile ()
+ {
+ }
+
+private:
+ //------------------------------------------------------------------
+ // For CommandObjectPlatform only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatformFile);
+};
+
+//----------------------------------------------------------------------
+// "platform get-file remote-file-path host-file-path"
+//----------------------------------------------------------------------
+class CommandObjectPlatformGetFile : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformGetFile (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform get-file",
+ "Transfer a file from the remote end to the local host.",
+ "platform get-file <remote-file-spec> <local-file-spec>",
+ 0)
+ {
+ SetHelpLong(
+"Examples: \n\
+\n\
+ platform get-file /the/remote/file/path /the/local/file/path\n\
+ # Transfer a file from the remote end with file path /the/remote/file/path to the local host.\n");
+
+ CommandArgumentEntry arg1, arg2;
+ CommandArgumentData file_arg_remote, file_arg_host;
+
+ // Define the first (and only) variant of this arg.
+ file_arg_remote.arg_type = eArgTypeFilename;
+ file_arg_remote.arg_repetition = eArgRepeatPlain;
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (file_arg_remote);
+
+ // Define the second (and only) variant of this arg.
+ file_arg_host.arg_type = eArgTypeFilename;
+ file_arg_host.arg_repetition = eArgRepeatPlain;
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (file_arg_host);
+
+ // Push the data for the first and the second arguments into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ }
+
+ virtual
+ ~CommandObjectPlatformGetFile ()
+ {
+ }
+
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ // If the number of arguments is incorrect, issue an error message.
+ if (args.GetArgumentCount() != 2)
+ {
+ result.GetErrorStream().Printf("error: required arguments missing; specify both the source and destination file paths\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ if (platform_sp)
+ {
+ const char *remote_file_path = args.GetArgumentAtIndex(0);
+ const char *local_file_path = args.GetArgumentAtIndex(1);
+ Error error = platform_sp->GetFile(FileSpec(remote_file_path, false),
+ FileSpec(local_file_path, false));
+ if (error.Success())
+ {
+ result.AppendMessageWithFormat("successfully get-file from %s (remote) to %s (host)\n",
+ remote_file_path, local_file_path);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendMessageWithFormat("get-file failed: %s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("no platform currently selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+//----------------------------------------------------------------------
+// "platform get-size remote-file-path"
+//----------------------------------------------------------------------
+class CommandObjectPlatformGetSize : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformGetSize (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform get-size",
+ "Get the file size from the remote end.",
+ "platform get-size <remote-file-spec>",
+ 0)
+ {
+ SetHelpLong(
+"Examples: \n\
+\n\
+ platform get-size /the/remote/file/path\n\
+ # Get the file size from the remote end with path /the/remote/file/path.\n");
+
+ CommandArgumentEntry arg1;
+ CommandArgumentData file_arg_remote;
+
+ // Define the first (and only) variant of this arg.
+ file_arg_remote.arg_type = eArgTypeFilename;
+ file_arg_remote.arg_repetition = eArgRepeatPlain;
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (file_arg_remote);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ }
+
+ virtual
+ ~CommandObjectPlatformGetSize ()
+ {
+ }
+
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ // If the number of arguments is incorrect, issue an error message.
+ if (args.GetArgumentCount() != 1)
+ {
+ result.GetErrorStream().Printf("error: required argument missing; specify the source file path as the only argument\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ if (platform_sp)
+ {
+ std::string remote_file_path(args.GetArgumentAtIndex(0));
+ user_id_t size = platform_sp->GetFileSize(FileSpec(remote_file_path.c_str(), false));
+ if (size != UINT64_MAX)
+ {
+ result.AppendMessageWithFormat("File size of %s (remote): %" PRIu64 "\n", remote_file_path.c_str(), size);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendMessageWithFormat("Eroor getting file size of %s (remote)\n", remote_file_path.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("no platform currently selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+//----------------------------------------------------------------------
+// "platform put-file"
+//----------------------------------------------------------------------
+class CommandObjectPlatformPutFile : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformPutFile (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform put-file",
+ "Transfer a file from this system to the remote end.",
+ NULL,
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformPutFile ()
+ {
+ }
+
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ const char* src = args.GetArgumentAtIndex(0);
+ const char* dst = args.GetArgumentAtIndex(1);
+
+ FileSpec src_fs(src, true);
+ FileSpec dst_fs(dst, false);
+
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ if (platform_sp)
+ {
+ Error error (platform_sp->PutFile(src_fs, dst_fs));
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("no platform currently selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
//----------------------------------------------------------------------
// "platform process launch"
//----------------------------------------------------------------------
@@ -868,7 +1705,205 @@ protected:
}
};
+class CommandObjectPlatformProcessAttach : public CommandObjectParsed
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ // Keep default values of all options in one place: OptionParsingStarting ()
+ OptionParsingStarting ();
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ char short_option = (char) m_getopt_table[option_idx].val;
+ bool success = false;
+ switch (short_option)
+ {
+ case 'p':
+ {
+ lldb::pid_t pid = Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success);
+ if (!success || pid == LLDB_INVALID_PROCESS_ID)
+ {
+ error.SetErrorStringWithFormat("invalid process ID '%s'", option_arg);
+ }
+ else
+ {
+ attach_info.SetProcessID (pid);
+ }
+ }
+ break;
+
+ case 'P':
+ attach_info.SetProcessPluginName (option_arg);
+ break;
+
+ case 'n':
+ attach_info.GetExecutableFile().SetFile(option_arg, false);
+ break;
+
+ case 'w':
+ attach_info.SetWaitForLaunch(true);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ attach_info.Clear();
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ virtual bool
+ HandleOptionArgumentCompletion (Args &input,
+ int cursor_index,
+ int char_pos,
+ OptionElementVector &opt_element_vector,
+ int opt_element_index,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
+ int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
+
+ // We are only completing the name option for now...
+
+ const OptionDefinition *opt_defs = GetDefinitions();
+ if (opt_defs[opt_defs_index].short_option == 'n')
+ {
+ // Are we in the name?
+
+ // Look to see if there is a -P argument provided, and if so use that plugin, otherwise
+ // use the default plugin.
+
+ const char *partial_name = NULL;
+ partial_name = input.GetArgumentAtIndex(opt_arg_pos);
+
+ PlatformSP platform_sp (m_interpreter.GetPlatform (true));
+ if (platform_sp)
+ {
+ ProcessInstanceInfoList process_infos;
+ ProcessInstanceInfoMatch match_info;
+ if (partial_name)
+ {
+ match_info.GetProcessInfo().GetExecutableFile().SetFile(partial_name, false);
+ match_info.SetNameMatchType(eNameMatchStartsWith);
+ }
+ platform_sp->FindProcesses (match_info, process_infos);
+ const uint32_t num_matches = process_infos.GetSize();
+ if (num_matches > 0)
+ {
+ for (uint32_t i=0; i<num_matches; ++i)
+ {
+ matches.AppendString (process_infos.GetProcessNameAtIndex(i),
+ process_infos.GetProcessNameLengthAtIndex(i));
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ ProcessAttachInfo attach_info;
+ };
+
+ CommandObjectPlatformProcessAttach (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform process attach",
+ "Attach to a process.",
+ "platform process attach <cmd-options>"),
+ m_options (interpreter)
+ {
+ }
+
+ ~CommandObjectPlatformProcessAttach ()
+ {
+ }
+
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ if (platform_sp)
+ {
+ Error err;
+ ProcessSP remote_process_sp =
+ platform_sp->Attach(m_options.attach_info, m_interpreter.GetDebugger(), NULL, m_interpreter.GetDebugger().GetListener(), err);
+ if (err.Fail())
+ {
+ result.AppendError(err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else if (remote_process_sp.get() == NULL)
+ {
+ result.AppendError("could not attach: unknown reason");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError ("no platform is currently selected");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectPlatformProcessAttach::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "plugin", 'P', required_argument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
+ { LLDB_OPT_SET_1, false, "pid", 'p', required_argument, NULL, 0, eArgTypePid, "The process ID of an existing process to attach to."},
+ { LLDB_OPT_SET_2, false, "name", 'n', required_argument, NULL, 0, eArgTypeProcessName, "The name of the process to attach to."},
+ { LLDB_OPT_SET_2, false, "waitfor",'w', no_argument, NULL, 0, eArgTypeNone, "Wait for the the process with <process-name> to launch."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
class CommandObjectPlatformProcess : public CommandObjectMultiword
@@ -883,7 +1918,7 @@ public:
"A set of commands to query, launch and attach to platform processes",
"platform process [attach|launch|list] ...")
{
-// LoadSubCommand ("attach", CommandObjectSP (new CommandObjectPlatformProcessAttach (interpreter)));
+ LoadSubCommand ("attach", CommandObjectSP (new CommandObjectPlatformProcessAttach (interpreter)));
LoadSubCommand ("launch", CommandObjectSP (new CommandObjectPlatformProcessLaunch (interpreter)));
LoadSubCommand ("info" , CommandObjectSP (new CommandObjectPlatformProcessInfo (interpreter)));
LoadSubCommand ("list" , CommandObjectSP (new CommandObjectPlatformProcessList (interpreter)));
@@ -902,16 +1937,84 @@ private:
DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatformProcess);
};
-
+//----------------------------------------------------------------------
+// "platform shell"
+//----------------------------------------------------------------------
class CommandObjectPlatformShell : public CommandObjectRaw
{
public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual uint32_t
+ GetNumDefinitions ()
+ {
+ return 1;
+ }
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx,
+ const char *option_value)
+ {
+ Error error;
+
+ const char short_option = (char) g_option_table[option_idx].short_option;
+
+ switch (short_option)
+ {
+ case 't':
+ {
+ bool success;
+ timeout = Args::StringToUInt32(option_value, 10, 10, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("could not convert \"%s\" to a numeric value.", option_value);
+ break;
+ }
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ virtual void
+ OptionParsingStarting ()
+ {
+ timeout = 10;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+ uint32_t timeout;
+ };
+
CommandObjectPlatformShell (CommandInterpreter &interpreter) :
- CommandObjectRaw (interpreter,
- "platform shell",
- "Run a shell command on a the selected platform.",
- "platform shell <shell-command>",
- 0)
+ CommandObjectRaw (interpreter,
+ "platform shell",
+ "Run a shell command on a the selected platform.",
+ "platform shell <shell-command>",
+ 0),
+ m_options(interpreter)
{
}
@@ -920,31 +2023,80 @@ public:
{
}
-protected:
virtual bool
DoExecute (const char *raw_command_line, CommandReturnObject &result)
{
- // TODO: Implement "Platform::RunShellCommand()" and switch over to using
- // the current platform when it is in the interface.
- const char *working_dir = NULL;
- std::string output;
- int status = -1;
- int signo = -1;
- Error error (Host::RunShellCommand (raw_command_line, working_dir, &status, &signo, &output, 10));
- if (!output.empty())
- result.GetOutputStream().PutCString(output.c_str());
- if (status > 0)
- {
- if (signo > 0)
- {
- const char *signo_cstr = Host::GetSignalAsCString(signo);
- if (signo_cstr)
- result.GetOutputStream().Printf("error: command returned with status %i and signal %s\n", status, signo_cstr);
+ const char* expr = NULL;
+
+ // Print out an usage syntax on an empty command line.
+ if (raw_command_line[0] == '\0')
+ {
+ result.GetOutputStream().Printf("%s\n", this->GetSyntax());
+ return true;
+ }
+
+ if (raw_command_line[0] == '-')
+ {
+ // We have some options and these options MUST end with --.
+ const char *end_options = NULL;
+ const char *s = raw_command_line;
+ while (s && s[0])
+ {
+ end_options = ::strstr (s, "--");
+ if (end_options)
+ {
+ end_options += 2; // Get past the "--"
+ if (::isspace (end_options[0]))
+ {
+ expr = end_options;
+ while (::isspace (*expr))
+ ++expr;
+ break;
+ }
+ }
+ s = end_options;
+ }
+
+ if (end_options)
+ {
+ Args args (raw_command_line, end_options - raw_command_line);
+ if (!ParseOptions (args, result))
+ return false;
+ }
+ }
+
+ if (expr == NULL)
+ expr = raw_command_line;
+
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ Error error;
+ if (platform_sp)
+ {
+ const char *working_dir = NULL;
+ std::string output;
+ int status = -1;
+ int signo = -1;
+ error = (platform_sp->RunShellCommand (expr, working_dir, &status, &signo, &output, m_options.timeout));
+ if (!output.empty())
+ result.GetOutputStream().PutCString(output.c_str());
+ if (status > 0)
+ {
+ if (signo > 0)
+ {
+ const char *signo_cstr = Host::GetSignalAsCString(signo);
+ if (signo_cstr)
+ result.GetOutputStream().Printf("error: command returned with status %i and signal %s\n", status, signo_cstr);
+ else
+ result.GetOutputStream().Printf("error: command returned with status %i and signal %i\n", status, signo);
+ }
else
- result.GetOutputStream().Printf("error: command returned with status %i and signal %i\n", status, signo);
+ result.GetOutputStream().Printf("error: command returned with status %i\n", status);
}
- else
- result.GetOutputStream().Printf("error: command returned with status %i\n", status);
+ }
+ else
+ {
+ result.GetOutputStream().Printf("error: cannot run remote shell commands without a platform\n");
+ error.SetErrorString("error: cannot run remote shell commands without a platform");
}
if (error.Fail())
@@ -958,6 +2110,208 @@ protected:
}
return true;
}
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectPlatformShell::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "timeout", 't', required_argument, NULL, 0, eArgTypeValue, "Seconds to wait for the remote host to finish running the command."},
+};
+
+struct RecurseCopyBaton
+{
+ const std::string& destination;
+ const PlatformSP& platform_sp;
+ Error error;
+};
+
+
+static FileSpec::EnumerateDirectoryResult
+RecurseCopy_Callback (void *baton,
+ FileSpec::FileType file_type,
+ const FileSpec &spec)
+{
+ RecurseCopyBaton* rc_baton = (RecurseCopyBaton*)baton;
+ switch (file_type)
+ {
+ case FileSpec::eFileTypePipe:
+ case FileSpec::eFileTypeSocket:
+ // we have no way to copy pipes and sockets - ignore them and continue
+ return FileSpec::eEnumerateDirectoryResultNext;
+ break;
+
+ case FileSpec::eFileTypeSymbolicLink:
+ // what to do for symlinks?
+ return FileSpec::eEnumerateDirectoryResultNext;
+ break;
+
+ case FileSpec::eFileTypeDirectory:
+ {
+ // make the new directory and get in there
+ FileSpec new_directory(rc_baton->destination.c_str(),false);
+ new_directory.AppendPathComponent(spec.GetLastPathComponent());
+ uint32_t errcode = rc_baton->platform_sp->MakeDirectory(new_directory, 0777);
+ std::string new_directory_path (new_directory.GetPath());
+ if (errcode != 0)
+ {
+ rc_baton->error.SetErrorStringWithFormat("unable to setup directory %s on remote end",new_directory_path.c_str());
+ return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
+ }
+
+ // now recurse
+ std::string local_path (spec.GetPath());
+ RecurseCopyBaton rc_baton2 = { new_directory_path, rc_baton->platform_sp, Error() };
+ FileSpec::EnumerateDirectory(local_path.c_str(), true, true, true, RecurseCopy_Callback, &rc_baton2);
+ if (rc_baton2.error.Fail())
+ {
+ rc_baton->error.SetErrorString(rc_baton2.error.AsCString());
+ return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
+ }
+ return FileSpec::eEnumerateDirectoryResultNext;
+ }
+ break;
+
+ case FileSpec::eFileTypeRegular:
+ {
+ // copy the file and keep going
+ std::string dest(rc_baton->destination);
+ dest.append(spec.GetFilename().GetCString());
+ Error err = rc_baton->platform_sp->PutFile(spec, FileSpec(dest.c_str(), false));
+ if (err.Fail())
+ {
+ rc_baton->error.SetErrorString(err.AsCString());
+ return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
+ }
+ return FileSpec::eEnumerateDirectoryResultNext;
+ }
+ break;
+
+ case FileSpec::eFileTypeInvalid:
+ case FileSpec::eFileTypeOther:
+ case FileSpec::eFileTypeUnknown:
+ default:
+ rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s/%s", spec.GetDirectory().GetCString(), spec.GetFilename().GetCString());
+ return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
+ break;
+ }
+}
+
+//----------------------------------------------------------------------
+// "platform install" - install a target to a remote end
+//----------------------------------------------------------------------
+class CommandObjectPlatformInstall : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformInstall (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform target-install",
+ "Install a target (bundle or executable file) to the remote end.",
+ "platform target-install <local-thing> <remote-sandbox>",
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformInstall ()
+ {
+ }
+
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ if (args.GetArgumentCount() != 2)
+ {
+ result.AppendError("platform target-install takes two arguments");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ // TODO: move the bulk of this code over to the platform itself
+ std::string local_thing(args.GetArgumentAtIndex(0));
+ std::string remote_sandbox(args.GetArgumentAtIndex(1));
+ FileSpec source(local_thing.c_str(), true);
+ if (source.Exists() == false)
+ {
+ result.AppendError("source location does not exist or is not accessible");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ if (!platform_sp)
+ {
+ result.AppendError ("no platform currently selected");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ FileSpec::FileType source_type(source.GetFileType());
+ if (source_type == FileSpec::eFileTypeDirectory)
+ {
+ if (platform_sp->GetSupportsRSync())
+ {
+ FileSpec remote_folder(remote_sandbox.c_str(), false);
+ Error rsync_err = platform_sp->PutFile(source, remote_folder);
+ if (rsync_err.Success())
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+ }
+ FileSpec remote_folder(remote_sandbox.c_str(), false);
+ remote_folder.AppendPathComponent(source.GetLastPathComponent());
+ // TODO: default permissions are bad
+ uint32_t errcode = platform_sp->MakeDirectory(remote_folder, 0777);
+ if (errcode != 0)
+ {
+ result.AppendError("unable to setup target directory on remote end");
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+ // now recurse
+ std::string remote_folder_path (remote_folder.GetPath());
+ Error err = RecurseCopy(source,remote_folder_path,platform_sp);
+ if (err.Fail())
+ {
+ result.AppendError(err.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ }
+ else
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+ else if (source_type == FileSpec::eFileTypeRegular)
+ {
+ // just a plain file - push it to remote and be done
+ remote_sandbox.append(source.GetFilename().GetCString());
+ FileSpec destination(remote_sandbox.c_str(),false);
+ Error err = platform_sp->PutFile(source, destination);
+ if (err.Success())
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ else
+ {
+ result.AppendError(err.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+ else
+ {
+ result.AppendError("source is not a known type of file");
+ result.SetStatus(eReturnStatusFailed);
+ return result.Succeeded();
+ }
+ }
+private:
+
+ Error
+ RecurseCopy (const FileSpec& source,
+ const std::string& destination,
+ const PlatformSP& platform_sp)
+ {
+ std::string source_path (source.GetPath());
+ RecurseCopyBaton baton = { destination, platform_sp, Error() };
+ FileSpec::EnumerateDirectory(source_path.c_str(), true, true, true, RecurseCopy_Callback, &baton);
+ return baton.error;
+ }
};
//----------------------------------------------------------------------
@@ -974,8 +2328,16 @@ CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter) :
LoadSubCommand ("status", CommandObjectSP (new CommandObjectPlatformStatus (interpreter)));
LoadSubCommand ("connect", CommandObjectSP (new CommandObjectPlatformConnect (interpreter)));
LoadSubCommand ("disconnect", CommandObjectSP (new CommandObjectPlatformDisconnect (interpreter)));
+#ifdef LLDB_CONFIGURATION_DEBUG
+ LoadSubCommand ("mkdir", CommandObjectSP (new CommandObjectPlatformMkDir (interpreter)));
+ LoadSubCommand ("file", CommandObjectSP (new CommandObjectPlatformFile (interpreter)));
+ LoadSubCommand ("get-file", CommandObjectSP (new CommandObjectPlatformGetFile (interpreter)));
+ LoadSubCommand ("get-size", CommandObjectSP (new CommandObjectPlatformGetSize (interpreter)));
+ LoadSubCommand ("put-file", CommandObjectSP (new CommandObjectPlatformPutFile (interpreter)));
+#endif
LoadSubCommand ("process", CommandObjectSP (new CommandObjectPlatformProcess (interpreter)));
LoadSubCommand ("shell", CommandObjectSP (new CommandObjectPlatformShell (interpreter)));
+ LoadSubCommand ("target-install", CommandObjectSP (new CommandObjectPlatformInstall (interpreter)));
}
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index 27c6702f8f3..945199eb729 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -158,6 +158,7 @@ public:
m_arch_option (),
m_platform_options(true), // Do include the "--platform" option in the platform settings by passing true
m_core_file (LLDB_OPT_SET_1, false, "core", 'c', 0, eArgTypeFilename, "Fullpath to a core file to use for this target."),
+ m_platform_path (LLDB_OPT_SET_1, false, "platform-path", 'P', 0, eArgTypePath, "Path to the remote file to use for this target."),
m_symbol_file (LLDB_OPT_SET_1, false, "symfile", 's', 0, eArgTypeFilename, "Fullpath to a stand alone debug symbols file for when debug symbols are not in the executable."),
m_remote_file (LLDB_OPT_SET_1, false, "remote-file", 'r', 0, eArgTypeFilename, "Fullpath to the file on the remote host if debugging remotely."),
m_add_dependents (LLDB_OPT_SET_1, false, "no-dependents", 'd', "Don't load dependent files when creating the target, just add the specified executable.", true, true)
@@ -178,6 +179,7 @@ public:
m_option_group.Append (&m_arch_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Append (&m_platform_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Append (&m_core_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_platform_path, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Append (&m_symbol_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Append (&m_remote_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Append (&m_add_dependents, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
@@ -226,7 +228,7 @@ protected:
FileSpec core_file (m_core_file.GetOptionValue().GetCurrentValue());
FileSpec remote_file (m_remote_file.GetOptionValue().GetCurrentValue());
- if (argc == 1 || core_file)
+ if (argc == 1 || core_file || remote_file)
{
FileSpec symfile (m_symbol_file.GetOptionValue().GetCurrentValue());
if (symfile)
@@ -243,11 +245,70 @@ protected:
const char *file_path = command.GetArgumentAtIndex(0);
Timer scoped_timer(__PRETTY_FUNCTION__, "(lldb) target create '%s'", file_path);
- TargetSP target_sp;
+ FileSpec file_spec;
+
+ if (file_path)
+ file_spec.SetFile (file_path, true);
+
+ bool must_set_platform_path = false;
+
Debugger &debugger = m_interpreter.GetDebugger();
+ PlatformSP platform_sp(debugger.GetPlatformList().GetSelectedPlatform ());
+
+ if (remote_file)
+ {
+ // I have a remote file.. two possible cases
+ if (file_spec && file_spec.Exists())
+ {
+ // if the remote file does not exist, push it there
+ if (!platform_sp->GetFileExists (remote_file))
+ {
+ Error err = platform_sp->PutFile(file_spec, remote_file);
+ if (err.Fail())
+ {
+ result.AppendError(err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // there is no local file and we need one
+ // in order to make the remote ---> local transfer we need a platform
+ // TODO: if the user has passed in a --platform argument, use it to fetch the right platform
+ if (!platform_sp)
+ {
+ result.AppendError("unable to perform remote debugging without a platform");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ if (file_path)
+ {
+ // copy the remote file to the local file
+ Error err = platform_sp->GetFile(remote_file, file_spec);
+ if (err.Fail())
+ {
+ result.AppendError(err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ // make up a local file
+ result.AppendError("remote --> local transfer without local path is not implemented yet");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+
+ TargetSP target_sp;
const char *arch_cstr = m_arch_option.GetArchitectureName();
const bool get_dependent_files = m_add_dependents.GetOptionValue().GetCurrentValue();
Error error (debugger.GetTargetList().CreateTarget (debugger,
+// remote_file ? remote_file : file_spec,
file_path,
arch_cstr,
get_dependent_files,
@@ -273,6 +334,13 @@ protected:
}
debugger.GetTargetList().SetSelectedTarget(target_sp.get());
+ if (must_set_platform_path)
+ {
+ ModuleSpec main_module_spec(file_spec);
+ ModuleSP module_sp = target_sp->GetSharedModule(main_module_spec);
+ if (module_sp)
+ module_sp->SetPlatformFileSpec(remote_file);
+ }
if (core_file)
{
char core_path[PATH_MAX];
@@ -341,6 +409,7 @@ private:
OptionGroupArchitecture m_arch_option;
OptionGroupPlatform m_platform_options;
OptionGroupFile m_core_file;
+ OptionGroupFile m_platform_path;
OptionGroupFile m_symbol_file;
OptionGroupFile m_remote_file;
OptionGroupBoolean m_add_dependents;
diff --git a/lldb/source/Core/CMakeLists.txt b/lldb/source/Core/CMakeLists.txt
index f2946ce1be1..165fb1de640 100644
--- a/lldb/source/Core/CMakeLists.txt
+++ b/lldb/source/Core/CMakeLists.txt
@@ -51,6 +51,7 @@ add_lldb_library(lldbCore
StreamAsynchronousIO.cpp
StreamCallback.cpp
StreamFile.cpp
+ StreamGDBRemote.cpp
StreamString.cpp
StringList.cpp
Timer.cpp
diff --git a/lldb/source/Core/Error.cpp b/lldb/source/Core/Error.cpp
index e29f12f0b2c..9ba4b1ef5f2 100644
--- a/lldb/source/Core/Error.cpp
+++ b/lldb/source/Core/Error.cpp
@@ -238,7 +238,7 @@ Error::LogIfError (Log *log, const char *format, ...)
if (err_str == NULL)
err_str = "???";
- SetErrorStringWithFormat("error: %s err = %s (0x%8.8x)", arg_msg, err_str, m_code);
+ SetErrorStringWithFormat("%s err = %s (0x%8.8x)", arg_msg, err_str, m_code);
if (log)
log->Error("%s", m_string.c_str());
diff --git a/lldb/source/Core/StreamGDBRemote.cpp b/lldb/source/Core/StreamGDBRemote.cpp
new file mode 100644
index 00000000000..46cb99ce98a
--- /dev/null
+++ b/lldb/source/Core/StreamGDBRemote.cpp
@@ -0,0 +1,54 @@
+//===-- StreamGDBRemote.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/StreamGDBRemote.h"
+#include <stdio.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+StreamGDBRemote::StreamGDBRemote () :
+StreamString ()
+{
+}
+
+StreamGDBRemote::StreamGDBRemote(uint32_t flags, uint32_t addr_size, ByteOrder byte_order) :
+StreamString (flags, addr_size, byte_order)
+{
+}
+
+StreamGDBRemote::~StreamGDBRemote()
+{
+}
+
+
+int
+StreamGDBRemote::PutEscapedBytes (const void* s,
+ size_t src_len)
+{
+ int bytes_written = 0;
+ const uint8_t *src = (const uint8_t *)s;
+ bool binary_is_set = m_flags.Test(eBinary);
+ m_flags.Clear(eBinary);
+ while (src_len)
+ {
+ uint8_t byte = *src;
+ src++; src_len--;
+ if (byte == 0x23 || byte == 0x24 || byte == 0x7d || byte == 0x2a)
+ {
+ bytes_written += PutChar(0x7d);
+ byte ^= 0x20;
+ }
+ bytes_written += PutChar(byte);
+ };
+ if (binary_is_set)
+ m_flags.Set(eBinary);
+ return bytes_written;
+}
+
diff --git a/lldb/source/Host/common/File.cpp b/lldb/source/Host/common/File.cpp
index 343312fb484..ec33bca4905 100644
--- a/lldb/source/Host/common/File.cpp
+++ b/lldb/source/Host/common/File.cpp
@@ -83,6 +83,20 @@ File::File(const char *path, uint32_t options, uint32_t permissions) :
Open (path, options, permissions);
}
+File::File (const FileSpec& filespec,
+ uint32_t options,
+ uint32_t permissions) :
+ m_descriptor (kInvalidDescriptor),
+ m_stream (kInvalidStream),
+ m_options (0),
+ m_owned (false)
+{
+ if (filespec)
+ {
+ Open (filespec.GetPath().c_str(), options, permissions);
+ }
+}
+
File::File (const File &rhs) :
m_descriptor (kInvalidDescriptor),
m_stream (kInvalidStream),
@@ -261,6 +275,53 @@ File::Open (const char *path, uint32_t options, uint32_t permissions)
return error;
}
+uint32_t
+File::GetPermissions (const char *path, Error &error)
+{
+ if (path && path[0])
+ {
+ struct stat file_stats;
+ if (::stat (path, &file_stats) == -1)
+ error.SetErrorToErrno();
+ else
+ {
+ error.Clear();
+ return file_stats.st_mode; // All bits from lldb_private::File::Permissions match those in POSIX mode bits
+ }
+ }
+ else
+ {
+ if (path)
+ error.SetErrorString ("invalid path");
+ else
+ error.SetErrorString ("empty path");
+ }
+ return 0;
+}
+
+uint32_t
+File::GetPermissions(Error &error) const
+{
+ int fd = GetDescriptor();
+ if (fd != kInvalidDescriptor)
+ {
+ struct stat file_stats;
+ if (::fstat (fd, &file_stats) == -1)
+ error.SetErrorToErrno();
+ else
+ {
+ error.Clear();
+ return file_stats.st_mode; // All bits from lldb_private::File::Permissions match those in POSIX mode bits
+ }
+ }
+ else
+ {
+ error.SetErrorString ("invalid file descriptor");
+ }
+ return 0;
+}
+
+
Error
File::Close ()
{
@@ -755,3 +816,51 @@ File::PrintfVarArg (const char *format, va_list args)
}
return result;
}
+
+mode_t
+File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
+{
+ mode_t mode = 0;
+ if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
+ mode |= O_RDWR;
+ else if (open_options & eOpenOptionWrite)
+ mode |= O_WRONLY;
+
+ if (open_options & eOpenOptionAppend)
+ mode |= O_APPEND;
+
+ if (open_options & eOpenOptionTruncate)
+ mode |= O_TRUNC;
+
+ if (open_options & eOpenOptionNonBlocking)
+ mode |= O_NONBLOCK;
+
+ if (open_options & eOpenOptionCanCreateNewOnly)
+ mode |= O_CREAT | O_EXCL;
+ else if (open_options & eOpenOptionCanCreate)
+ mode |= O_CREAT;
+
+ return mode;
+}
+
+#define O_RDONLY 0x0000 /* open for reading only */
+#define O_WRONLY 0x0001 /* open for writing only */
+#define O_RDWR 0x0002 /* open for reading and writing */
+#define O_ACCMODE 0x0003 /* mask for above modes */
+#define O_NONBLOCK 0x0004 /* no delay */
+#define O_APPEND 0x0008 /* set append mode */
+#define O_SYNC 0x0080 /* synch I/O file integrity */
+#define O_SHLOCK 0x0010 /* open with shared file lock */
+#define O_EXLOCK 0x0020 /* open with exclusive file lock */
+#define O_ASYNC 0x0040 /* signal pgrp when data ready */
+#define O_FSYNC O_SYNC /* source compatibility: do not use */
+#define O_NOFOLLOW 0x0100 /* don't follow symlinks */
+#define O_CREAT 0x0200 /* create if nonexistant */
+#define O_TRUNC 0x0400 /* truncate to zero length */
+#define O_EXCL 0x0800 /* error if already exists */
+#define O_EVTONLY 0x8000 /* descriptor requested for event notifications only */
+#define O_NOCTTY 0x20000 /* don't assign controlling terminal */
+#define O_DIRECTORY 0x100000
+#define O_SYMLINK 0x200000 /* allow open of a symlink */
+#define O_DSYNC 0x400000 /* synch I/O data integrity */
+#define O_CLOEXEC 0x1000000 /* implicitly set FD_CLOEXEC */
diff --git a/lldb/source/Host/common/FileSpec.cpp b/lldb/source/Host/common/FileSpec.cpp
index 0bf7681aa48..66818453bc0 100644
--- a/lldb/source/Host/common/FileSpec.cpp
+++ b/lldb/source/Host/common/FileSpec.cpp
@@ -29,6 +29,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
+#include "lldb/Core/StreamString.h"
#include "lldb/Host/File.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Core/DataBufferHeap.h"
@@ -1106,6 +1107,140 @@ FileSpec::EnumerateDirectory
return eEnumerateDirectoryResultNext;
}
+FileSpec
+FileSpec::CopyByAppendingPathComponent (const char *new_path) const
+{
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ return FileSpec(new_path,resolve);
+ StreamString stream;
+ if (m_filename.IsEmpty())
+ stream.Printf("%s/%s",m_directory.GetCString(),new_path);
+ else if (m_directory.IsEmpty())
+ stream.Printf("%s/%s",m_filename.GetCString(),new_path);
+ else
+ stream.Printf("%s/%s/%s",m_directory.GetCString(), m_filename.GetCString(),new_path);
+ return FileSpec(stream.GetData(),resolve);
+}
+
+FileSpec
+FileSpec::CopyByRemovingLastPathComponent () const
+{
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ return FileSpec("",resolve);
+ if (m_directory.IsEmpty())
+ return FileSpec("",resolve);
+ if (m_filename.IsEmpty())
+ {
+ const char* dir_cstr = m_directory.GetCString();
+ const char* last_slash_ptr = ::strrchr(dir_cstr, '/');
+
+ // check for obvious cases before doing the full thing
+ if (!last_slash_ptr)
+ return FileSpec("",resolve);
+ if (last_slash_ptr == dir_cstr)
+ return FileSpec("/",resolve);
+
+ size_t last_slash_pos = last_slash_ptr - dir_cstr+1;
+ ConstString new_path(dir_cstr,last_slash_pos);
+ return FileSpec(new_path.GetCString(),resolve);
+ }
+ else
+ return FileSpec(m_directory.GetCString(),resolve);
+}
+
+const char*
+FileSpec::GetLastPathComponent () const
+{
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ return NULL;
+ if (m_filename.IsEmpty())
+ {
+ const char* dir_cstr = m_directory.GetCString();
+ const char* last_slash_ptr = ::strrchr(dir_cstr, '/');
+ if (last_slash_ptr == NULL)
+ return m_directory.GetCString();
+ if (last_slash_ptr == dir_cstr)
+ {
+ if (last_slash_ptr[1] == 0)
+ return last_slash_ptr;
+ else
+ return last_slash_ptr+1;
+ }
+ if (last_slash_ptr[1] != 0)
+ return last_slash_ptr+1;
+ const char* penultimate_slash_ptr = last_slash_ptr;
+ while (*penultimate_slash_ptr)
+ {
+ --penultimate_slash_ptr;
+ if (penultimate_slash_ptr == dir_cstr)
+ break;
+ if (*penultimate_slash_ptr == '/')
+ break;
+ }
+ ConstString new_path(penultimate_slash_ptr+1,last_slash_ptr-penultimate_slash_ptr);
+ return new_path.AsCString();
+ }
+ return m_filename.GetCString();
+}
+
+void
+FileSpec::AppendPathComponent (const char *new_path)
+{
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ {
+ SetFile(new_path,resolve);
+ return;
+ }
+ StreamString stream;
+ if (m_filename.IsEmpty())
+ stream.Printf("%s/%s",m_directory.GetCString(),new_path);
+ else if (m_directory.IsEmpty())
+ stream.Printf("%s/%s",m_filename.GetCString(),new_path);
+ else
+ stream.Printf("%s/%s/%s",m_directory.GetCString(), m_filename.GetCString(),new_path);
+ SetFile(stream.GetData(), resolve);
+}
+
+void
+FileSpec::RemoveLastPathComponent ()
+{
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ {
+ SetFile("",resolve);
+ return;
+ }
+ if (m_directory.IsEmpty())
+ {
+ SetFile("",resolve);
+ return;
+ }
+ if (m_filename.IsEmpty())
+ {
+ const char* dir_cstr = m_directory.GetCString();
+ const char* last_slash_ptr = ::strrchr(dir_cstr, '/');
+
+ // check for obvious cases before doing the full thing
+ if (!last_slash_ptr)
+ {
+ SetFile("",resolve);
+ return;
+ }
+ if (last_slash_ptr == dir_cstr)
+ {
+ SetFile("/",resolve);
+ return;
+ }
+ size_t last_slash_pos = last_slash_ptr - dir_cstr+1;
+ ConstString new_path(dir_cstr,last_slash_pos);
+ SetFile(new_path.GetCString(),resolve);
+ }
+ else
+ SetFile(m_directory.GetCString(),resolve);
+}
//------------------------------------------------------------------
/// Returns true if the filespec represents an implementation source
/// file (files with a ".c", ".cpp", ".m", ".mm" (many more)
diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp
index 826069b358c..efe97237d42 100644
--- a/lldb/source/Host/common/Host.cpp
+++ b/lldb/source/Host/common/Host.cpp
@@ -1472,7 +1472,11 @@ Host::RunShellCommand (const char *command,
error = LaunchProcess (launch_info);
const lldb::pid_t pid = launch_info.GetProcessID();
- if (pid != LLDB_INVALID_PROCESS_ID)
+
+ if (error.Success() && pid == LLDB_INVALID_PROCESS_ID)
+ error.SetErrorString("failed to get process ID");
+
+ if (error.Success())
{
// The process successfully launched, so we can defer ownership of
// "shell_info" to the MonitorShellCommand callback function that will
@@ -1524,10 +1528,6 @@ Host::RunShellCommand (const char *command,
}
shell_info->can_delete.SetValue(true, eBroadcastAlways);
}
- else
- {
- error.SetErrorString("failed to get process ID");
- }
if (output_file_path)
::unlink (output_file_path);
@@ -1613,9 +1613,169 @@ Host::SetCrashDescription (const char *description)
}
lldb::pid_t
-LaunchApplication (const FileSpec &app_file_spec)
+Host::LaunchApplication (const FileSpec &app_file_spec)
{
return LLDB_INVALID_PROCESS_ID;
}
+uint32_t
+Host::MakeDirectory (const char* path, mode_t mode)
+{
+ return UINT32_MAX;
+}
+#endif
+
+typedef std::map<lldb::user_id_t, lldb::FileSP> FDToFileMap;
+FDToFileMap& GetFDToFileMap()
+{
+ static FDToFileMap g_fd2filemap;
+ return g_fd2filemap;
+}
+
+lldb::user_id_t
+Host::OpenFile (const FileSpec& file_spec,
+ uint32_t flags,
+ mode_t mode,
+ Error &error)
+{
+ std::string path (file_spec.GetPath());
+ if (path.empty())
+ {
+ error.SetErrorString("empty path");
+ return UINT64_MAX;
+ }
+ FileSP file_sp(new File());
+ error = file_sp->Open(path.c_str(),flags,mode);
+ if (file_sp->IsValid() == false)
+ return UINT64_MAX;
+ lldb::user_id_t fd = file_sp->GetDescriptor();
+ GetFDToFileMap()[fd] = file_sp;
+ return fd;
+}
+
+bool
+Host::CloseFile (lldb::user_id_t fd, Error &error)
+{
+ if (fd == UINT64_MAX)
+ {
+ error.SetErrorString ("invalid file descriptor");
+ return false;
+ }
+ FDToFileMap& file_map = GetFDToFileMap();
+ FDToFileMap::iterator pos = file_map.find(fd);
+ if (pos == file_map.end())
+ {
+ error.SetErrorStringWithFormat ("invalid host file descriptor %" PRIu64, fd);
+ return false;
+ }
+ FileSP file_sp = pos->second;
+ if (!file_sp)
+ {
+ error.SetErrorString ("invalid host backing file");
+ return false;
+ }
+ error = file_sp->Close();
+ file_map.erase(pos);
+ return error.Success();
+}
+
+uint64_t
+Host::WriteFile (lldb::user_id_t fd, uint64_t offset, const void* src, uint64_t src_len, Error &error)
+{
+ if (fd == UINT64_MAX)
+ {
+ error.SetErrorString ("invalid file descriptor");
+ return UINT64_MAX;
+ }
+ FDToFileMap& file_map = GetFDToFileMap();
+ FDToFileMap::iterator pos = file_map.find(fd);
+ if (pos == file_map.end())
+ {
+ error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64 , fd);
+ return false;
+ }
+ FileSP file_sp = pos->second;
+ if (!file_sp)
+ {
+ error.SetErrorString ("invalid host backing file");
+ return UINT64_MAX;
+ }
+ if (file_sp->SeekFromStart(offset, &error) != offset || error.Fail())
+ return UINT64_MAX;
+ size_t bytes_written = src_len;
+ error = file_sp->Write(src, bytes_written);
+ if (error.Fail())
+ return UINT64_MAX;
+ return bytes_written;
+}
+
+uint64_t
+Host::ReadFile (lldb::user_id_t fd, uint64_t offset, void* dst, uint64_t dst_len, Error &error)
+{
+ if (fd == UINT64_MAX)
+ {
+ error.SetErrorString ("invalid file descriptor");
+ return UINT64_MAX;
+ }
+ FDToFileMap& file_map = GetFDToFileMap();
+ FDToFileMap::iterator pos = file_map.find(fd);
+ if (pos == file_map.end())
+ {
+ error.SetErrorStringWithFormat ("invalid host file descriptor %" PRIu64, fd);
+ return false;
+ }
+ FileSP file_sp = pos->second;
+ if (!file_sp)
+ {
+ error.SetErrorString ("invalid host backing file");
+ return UINT64_MAX;
+ }
+ if (file_sp->SeekFromStart(offset, &error) != offset || error.Fail())
+ return UINT64_MAX;
+ size_t bytes_read = dst_len;
+ error = file_sp->Read(dst ,bytes_read);
+ if (error.Fail())
+ return UINT64_MAX;
+ return bytes_read;
+}
+
+lldb::user_id_t
+Host::GetFileSize (const FileSpec& file_spec)
+{
+ return file_spec.GetByteSize();
+}
+
+bool
+Host::GetFileExists (const FileSpec& file_spec)
+{
+ return file_spec.Exists();
+}
+
+bool
+Host::CalculateMD5 (const FileSpec& file_spec,
+ uint64_t &low,
+ uint64_t &high)
+{
+#if defined (__APPLE__)
+ StreamString md5_cmd_line;
+ md5_cmd_line.Printf("md5 -q '%s'", file_spec.GetPath().c_str());
+ std::string hash_string;
+ Error err = Host::RunShellCommand(md5_cmd_line.GetData(), NULL, NULL, NULL, &hash_string, 60);
+ if (err.Fail())
+ return false;
+ // a correctly formed MD5 is 16-bytes, that is 32 hex digits
+ // if the output is any other length it is probably wrong
+ if (hash_string.size() != 32)
+ return false;
+ std::string part1(hash_string,0,16);
+ std::string part2(hash_string,16);
+ const char* part1_cstr = part1.c_str();
+ const char* part2_cstr = part2.c_str();
+ high = ::strtoull(part1_cstr, NULL, 16);
+ low = ::strtoull(part2_cstr, NULL, 16);
+ return true;
+#else
+ // your own MD5 implementation here
+ return false;
#endif
+}
diff --git a/lldb/source/Host/freebsd/Host.cpp b/lldb/source/Host/freebsd/Host.cpp
index 405e7eacf5a..b748cdfa4da 100644
--- a/lldb/source/Host/freebsd/Host.cpp
+++ b/lldb/source/Host/freebsd/Host.cpp
@@ -15,11 +15,13 @@
#include <sys/user.h>
#include <sys/utsname.h>
#include <sys/sysctl.h>
+#include <sys/proc.h>
#include <sys/ptrace.h>
#include <sys/exec.h>
#include <machine/elf.h>
+#include <spawn.h>
// C++ Includes
// Other libraries and framework includes
@@ -27,13 +29,17 @@
#include "lldb/Core/Error.h"
#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
+#include "lldb/Core/Module.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/Platform.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataExtractor.h"
+#include "lldb/Utility/CleanUp.h"
+
#include "llvm/Support/Host.h"
@@ -44,7 +50,6 @@ extern "C" {
using namespace lldb;
using namespace lldb_private;
-
class FreeBSDThread
{
public:
@@ -120,7 +125,8 @@ Host::GetEnvironment (StringList &env)
{
char *v;
char **var = environ;
- for (; var != NULL && *var != NULL; ++var) {
+ for (; var != NULL && *var != NULL; ++var)
+ {
v = strchr(*var, (int)'-');
if (v == NULL)
continue;
@@ -135,8 +141,8 @@ Host::GetOSVersion(uint32_t &major,
uint32_t &update)
{
struct utsname un;
- int status;
+ ::memset(&un, 0, sizeof(utsname));
if (uname(&un) < 0)
return false;
@@ -144,11 +150,196 @@ Host::GetOSVersion(uint32_t &major,
return status == 2;
}
+// The posix_spawn() and posix_spawnp() functions first appeared in FreeBSD 8.0.
+static Error
+LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, ::pid_t &pid)
+{
+ Error error;
+ LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
+
+ assert(exe_path);
+ assert(!launch_info.GetFlags().Test (eLaunchFlagDebug));
+
+ posix_spawnattr_t attr;
+
+ error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX);
+ error.LogIfError(log.get(), "::posix_spawnattr_init ( &attr )");
+ if (error.Fail())
+ return error;
+
+ // Make a quick class that will cleanup the posix spawn attributes in case
+ // we return in the middle of this function.
+ lldb_utility::CleanUp <posix_spawnattr_t *, int> posix_spawnattr_cleanup(&attr, posix_spawnattr_destroy);
+
+ sigset_t no_signals;
+ sigset_t all_signals;
+ sigemptyset (&no_signals);
+ sigfillset (&all_signals);
+ ::posix_spawnattr_setsigmask(&attr, &all_signals);
+ ::posix_spawnattr_setsigdefault(&attr, &no_signals);
+
+ short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
+
+ error.SetError( ::posix_spawnattr_setflags (&attr, flags), eErrorTypePOSIX);
+ error.LogIfError(log.get(), "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", flags);
+ if (error.Fail())
+ return error;
+
+ const size_t num_file_actions = launch_info.GetNumFileActions ();
+ posix_spawn_file_actions_t file_actions, *file_action_ptr = NULL;
+ // Make a quick class that will cleanup the posix spawn attributes in case
+ // we return in the middle of this function.
+ lldb_utility::CleanUp <posix_spawn_file_actions_t *, int>
+ posix_spawn_file_actions_cleanup (file_action_ptr, NULL, posix_spawn_file_actions_destroy);
+
+ if (num_file_actions > 0)
+ {
+ error.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX);
+ error.LogIfError(log.get(), "::posix_spawn_file_actions_init ( &file_actions )");
+ if (error.Fail())
+ return error;
+
+ file_action_ptr = &file_actions;
+ posix_spawn_file_actions_cleanup.set(file_action_ptr);
+
+ for (size_t i = 0; i < num_file_actions; ++i)
+ {
+ const ProcessLaunchInfo::FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i);
+ if (launch_file_action &&
+ !ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (&file_actions,
+ launch_file_action,
+ log.get(),
+ error))
+ return error;
+ }
+ }
+
+ // Change working directory if neccessary.
+ char current_dir[PATH_MAX];
+ current_dir[0] = '\0';
+
+ const char *working_dir = launch_info.GetWorkingDirectory();
+ if (working_dir != NULL)
+ {
+ if (::getcwd(current_dir, sizeof(current_dir)) == NULL)
+ {
+ error.SetError(errno, eErrorTypePOSIX);
+ error.LogIfError(log.get(), "unable to save the current directory");
+ return error;
+ }
+
+ if (::chdir(working_dir) == -1)
+ {
+ error.SetError(errno, eErrorTypePOSIX);
+ error.LogIfError(log.get(), "unable to change working directory to %s", working_dir);
+ return error;
+ }
+ }
+
+ const char *tmp_argv[2];
+ char * const *argv = (char * const*)launch_info.GetArguments().GetConstArgumentVector();
+ char * const *envp = (char * const*)launch_info.GetEnvironmentEntries().GetConstArgumentVector();
+
+ // Prepare minimal argument list if we didn't get it from the launch_info structure.
+ // We must pass argv into posix_spawnp and it must contain at least two items -
+ // pointer to an executable and NULL.
+ if (argv == NULL)
+ {
+ tmp_argv[0] = exe_path;
+ tmp_argv[1] = NULL;
+ argv = (char * const*)tmp_argv;
+ }
+
+ error.SetError (::posix_spawnp (&pid,
+ exe_path,
+ (num_file_actions > 0) ? &file_actions : NULL,
+ &attr,
+ argv,
+ envp),
+ eErrorTypePOSIX);
+
+ error.LogIfError(log.get(), "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )",
+ pid, exe_path, file_action_ptr, &attr, argv, envp);
+
+ // Change back the current directory.
+ // NOTE: do not override previously established error from posix_spawnp.
+ if (working_dir != NULL && ::chdir(current_dir) == -1 && error.Success())
+ {
+ error.SetError(errno, eErrorTypePOSIX);
+ error.LogIfError(log.get(), "unable to change current directory back to %s",
+ current_dir);
+ }
+
+ return error;
+}
+
+
Error
Host::LaunchProcess (ProcessLaunchInfo &launch_info)
{
Error error;
- assert(!"Not implemented yet!!!");
+ char exe_path[PATH_MAX];
+
+ PlatformSP host_platform_sp (Platform::GetDefaultPlatform ());
+
+ const ArchSpec &arch_spec = launch_info.GetArchitecture();
+
+ FileSpec exe_spec(launch_info.GetExecutableFile());
+
+ FileSpec::FileType file_type = exe_spec.GetFileType();
+ if (file_type != FileSpec::eFileTypeRegular)
+ {
+ lldb::ModuleSP exe_module_sp;
+ error = host_platform_sp->ResolveExecutable (exe_spec,
+ arch_spec,
+ exe_module_sp,
+ NULL);
+
+ if (error.Fail())
+ return error;
+
+ if (exe_module_sp)
+ exe_spec = exe_module_sp->GetFileSpec();
+}
+
+ if (exe_spec.Exists())
+ {
+ exe_spec.GetPath (exe_path, sizeof(exe_path));
+ }
+ else
+ {
+ launch_info.GetExecutableFile().GetPath (exe_path, sizeof(exe_path));
+ error.SetErrorStringWithFormat ("executable doesn't exist: '%s'", exe_path);
+ return error;
+ }
+
+ assert(!launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY));
+
+ ::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ error = LaunchProcessPosixSpawn(exe_path, launch_info, pid);
+
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ // If all went well, then set the process ID into the launch info
+ launch_info.SetProcessID(pid);
+
+ // Make sure we reap any processes we spawn or we will have zombies.
+ if (!launch_info.MonitorProcess())
+ {
+ const bool monitor_signals = false;
+ StartMonitoringChildProcess (Process::SetProcessExitStatus,
+ NULL,
+ pid,
+ monitor_signals);
+ }
+ }
+ else
+ {
+ // Invalid process ID, something didn't go well
+ if (error.Success())
+ error.SetErrorString ("process launch failed for unknown reasons");
+ }
return error;
}
@@ -156,13 +347,17 @@ bool
Host::GetOSBuildString (std::string &s)
{
int mib[2] = { CTL_KERN, KERN_OSREV };
- char cstr[PATH_MAX];
- size_t cstr_len = sizeof(cstr);
- if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
+ char osrev_str[12];
+ uint32_t osrev = 0;
+ size_t osrev_len = sizeof(osrev);
+
+ if (::sysctl (mib, 2, &osrev, &osrev_len, NULL, 0) == 0)
{
- s.assign (cstr, cstr_len);
+ ::snprintf(osrev_str, sizeof(osrev_str), "%-8.8u", osrev);
+ s.assign (osrev_str);
return true;
}
+
s.clear();
return false;
}
@@ -170,23 +365,25 @@ Host::GetOSBuildString (std::string &s)
bool
Host::GetOSKernelDescription (std::string &s)
{
- int mib[2] = { CTL_KERN, KERN_VERSION };
- char cstr[PATH_MAX];
- size_t cstr_len = sizeof(cstr);
- if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
- {
- s.assign (cstr, cstr_len);
- return true;
- }
+ struct utsname un;
+
+ ::memset(&un, 0, sizeof(utsname));
s.clear();
+
+ if (uname(&un) < 0)
return false;
+
+ s.assign (un.version);
+
+ return true;
}
static bool
GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
ProcessInstanceInfo &process_info)
{
- if (process_info.ProcessIDIsValid()) {
+ if (process_info.ProcessIDIsValid())
+ {
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, (int)process_info.GetProcessID() };
char arg_data[8192];
@@ -235,7 +432,8 @@ GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
static bool
GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info)
{
- if (process_info.ProcessIDIsValid()) {
+ if (process_info.ProcessIDIsValid())
+ {
process_info.GetArchitecture() = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
return true;
}
@@ -279,16 +477,95 @@ GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info)
return false;
}
+uint32_t
+Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
+{
+ std::vector<struct kinfo_proc> kinfos;
+
+ int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
+
+ size_t pid_data_size = 0;
+ if (::sysctl (mib, 3, NULL, &pid_data_size, NULL, 0) != 0)
+ return 0;
+
+ // Add a few extra in case a few more show up
+ const size_t estimated_pid_count = (pid_data_size / sizeof(struct kinfo_proc)) + 10;
+
+ kinfos.resize (estimated_pid_count);
+ pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
+
+ if (::sysctl (mib, 3, &kinfos[0], &pid_data_size, NULL, 0) != 0)
+ return 0;
+
+ const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
+
+ bool all_users = match_info.GetMatchAllUsers();
+ const lldb::pid_t our_pid = getpid();
+ const uid_t our_uid = getuid();
+ for (int i = 0; i < actual_pid_count; i++)
+ {
+ const struct kinfo_proc &kinfo = kinfos[i];
+ const bool kinfo_user_matches = (all_users ||
+ (kinfo.ki_ruid == our_uid) ||
+ // Special case, if lldb is being run as root we can attach to anything.
+ (our_uid == 0)
+ );
+
+ if (kinfo_user_matches == false || // Make sure the user is acceptable
+ kinfo.ki_pid == our_pid || // Skip this process
+ kinfo.ki_pid == 0 || // Skip kernel (kernel pid is zero)
+ kinfo.ki_stat == SZOMB || // Zombies are bad, they like brains...
+ kinfo.ki_flag & P_TRACED || // Being debugged?
+ kinfo.ki_flag & P_WEXIT) // Working on exiting
+ continue;
+
+ // Every thread is a process in FreeBSD, but all the threads of a single process
+ // have the same pid. Do not store the process info in the result list if a process
+ // with given identifier is already registered there.
+ bool already_registered = false;
+ for (uint32_t pi = 0;
+ !already_registered &&
+ (const int)kinfo.ki_numthreads > 1 &&
+ pi < (const uint32_t)process_infos.GetSize(); pi++)
+ already_registered = (process_infos.GetProcessIDAtIndex(pi) == (uint32_t)kinfo.ki_pid);
+
+ if (already_registered)
+ continue;
+
+ ProcessInstanceInfo process_info;
+ process_info.SetProcessID (kinfo.ki_pid);
+ process_info.SetParentProcessID (kinfo.ki_ppid);
+ process_info.SetUserID (kinfo.ki_ruid);
+ process_info.SetGroupID (kinfo.ki_rgid);
+ process_info.SetEffectiveUserID (kinfo.ki_svuid);
+ process_info.SetEffectiveGroupID (kinfo.ki_svgid);
+
+ // Make sure our info matches before we go fetch the name and cpu type
+ if (match_info.Matches (process_info) &&
+ GetFreeBSDProcessArgs (&match_info, process_info))
+ {
+ GetFreeBSDProcessCPUType (process_info);
+ if (match_info.Matches (process_info))
+ process_infos.Append (process_info);
+ }
+ }
+
+ return process_infos.GetSize();
+}
+
bool
Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
{
process_info.SetProcessID(pid);
- if (GetFreeBSDProcessArgs(NULL, process_info)) {
+
+ if (GetFreeBSDProcessArgs(NULL, process_info))
+ {
// should use libprocstat instead of going right into sysctl?
GetFreeBSDProcessCPUType(process_info);
GetFreeBSDProcessUserAndGroup(process_info);
return true;
}
+
process_info.Clear();
return false;
}
diff --git a/lldb/source/Host/macosx/Host.mm b/lldb/source/Host/macosx/Host.mm
index 47a9b0aac6b..2a1891bf3fe 100644
--- a/lldb/source/Host/macosx/Host.mm
+++ b/lldb/source/Host/macosx/Host.mm
@@ -1984,3 +1984,10 @@ 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/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp
index 291dc401357..fa5a9a0b2e8 100644
--- a/lldb/source/Interpreter/CommandObject.cpp
+++ b/lldb/source/Interpreter/CommandObject.cpp
@@ -1123,6 +1123,9 @@ CommandObject::g_arguments_data[] =
{ eArgTypeOffset, "offset", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
{ eArgTypeOldPathPrefix, "old-path-prefix", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
{ eArgTypeOneLiner, "one-line-command", CommandCompletions::eNoCompletion, { NULL, false }, "A command that is entered as a single line of text." },
+ { eArgTypePath, "path", CommandCompletions::eDiskFileCompletion, { NULL, false }, "Path." },
+ { eArgTypePermissionsNumber, "perms-numeric", CommandCompletions::eNoCompletion, { NULL, false }, "Permissions given as an octal number (e.g. 755)." },
+ { eArgTypePermissionsString, "perms=string", CommandCompletions::eNoCompletion, { NULL, false }, "Permissions given as a string value (e.g. rw-r-xr--)." },
{ eArgTypePid, "pid", CommandCompletions::eNoCompletion, { NULL, false }, "The process ID number." },
{ eArgTypePlugin, "plugin", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
{ eArgTypeProcessName, "process-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of the process." },
diff --git a/lldb/source/Interpreter/Options.cpp b/lldb/source/Interpreter/Options.cpp
index 293d7535663..af700ea9a95 100644
--- a/lldb/source/Interpreter/Options.cpp
+++ b/lldb/source/Interpreter/Options.cpp
@@ -992,6 +992,18 @@ OptionGroupOptions::Append (OptionGroup* group)
}
}
+const OptionGroup*
+OptionGroupOptions::GetGroupWithOption (char short_opt)
+{
+ for (uint32_t i = 0; i < m_option_defs.size(); i++)
+ {
+ OptionDefinition opt_def = m_option_defs[i];
+ if (opt_def.short_option == short_opt)
+ return m_option_infos[i].option_group;
+ }
+ return NULL;
+}
+
void
OptionGroupOptions::Append (OptionGroup* group,
uint32_t src_mask,
diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp
index 9d9b8d93fb4..73619371ba9 100644
--- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp
@@ -52,6 +52,7 @@ static ScriptInterpreter::SWIGPythonCalculateNumChildren g_swig_calc_children =
static ScriptInterpreter::SWIGPythonGetChildAtIndex g_swig_get_child_index = NULL;
static ScriptInterpreter::SWIGPythonGetIndexOfChildWithName g_swig_get_index_child = NULL;
static ScriptInterpreter::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue = NULL;
+static ScriptInterpreter::SWIGPythonGetValueObjectSPFromSBValue g_swig_get_valobj_sp_from_sbvalue = NULL;
static ScriptInterpreter::SWIGPythonUpdateSynthProviderInstance g_swig_update_provider = NULL;
static ScriptInterpreter::SWIGPythonMightHaveChildrenSynthProviderInstance g_swig_mighthavechildren_provider = NULL;
static ScriptInterpreter::SWIGPythonCallCommand g_swig_call_command = NULL;
@@ -104,6 +105,9 @@ LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_nam
extern "C" void *
LLDBSWIGPython_CastPyObjectToSBValue (void* data);
+extern lldb::ValueObjectSP
+LLDBSWIGPython_GetValueObjectSPFromSBValue (void* data);
+
extern "C" bool
LLDBSwigPython_UpdateSynthProviderInstance (void* implementor);
@@ -2451,20 +2455,18 @@ ScriptInterpreterPython::GetChildAtIndex (const lldb::ScriptInterpreterObjectSP&
if (!g_swig_get_child_index || !g_swig_cast_to_sbvalue)
return lldb::ValueObjectSP();
- void* child_ptr = NULL;
- lldb::SBValue* value_sb = NULL;
lldb::ValueObjectSP ret_val;
{
Locker py_lock(this);
- child_ptr = g_swig_get_child_index (implementor,idx);
+ void* child_ptr = g_swig_get_child_index (implementor,idx);
if (child_ptr != NULL && child_ptr != Py_None)
{
- value_sb = (lldb::SBValue*)g_swig_cast_to_sbvalue(child_ptr);
- if (value_sb == NULL)
+ lldb::SBValue* sb_value_ptr = (lldb::SBValue*)g_swig_cast_to_sbvalue(child_ptr);
+ if (sb_value_ptr == NULL)
Py_XDECREF(child_ptr);
else
- ret_val = value_sb->GetSP();
+ ret_val = g_swig_get_valobj_sp_from_sbvalue (sb_value_ptr);
}
else
{
@@ -3058,6 +3060,7 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback python_swig_ini
g_swig_get_child_index = LLDBSwigPython_GetChildAtIndex;
g_swig_get_index_child = LLDBSwigPython_GetIndexOfChildWithName;
g_swig_cast_to_sbvalue = LLDBSWIGPython_CastPyObjectToSBValue;
+ g_swig_get_valobj_sp_from_sbvalue = LLDBSWIGPython_GetValueObjectSPFromSBValue;
g_swig_update_provider = LLDBSwigPython_UpdateSynthProviderInstance;
g_swig_mighthavechildren_provider = LLDBSwigPython_MightHaveChildrenSynthProviderInstance;
g_swig_call_command = LLDBSwigPythonCallCommand;
diff --git a/lldb/source/Plugins/Platform/CMakeLists.txt b/lldb/source/Plugins/Platform/CMakeLists.txt
index 1770a64f728..3576d86bceb 100644
--- a/lldb/source/Plugins/Platform/CMakeLists.txt
+++ b/lldb/source/Plugins/Platform/CMakeLists.txt
@@ -8,4 +8,5 @@
# add_subdirectory(Windows)
#endif()
+add_subdirectory(POSIX)
add_subdirectory(gdb-server)
diff --git a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
index cdca4463fff..0da54d44ecb 100644
--- a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
+++ b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
@@ -156,6 +156,26 @@ PlatformFreeBSD::~PlatformFreeBSD()
{
}
+//TODO:VK: inherit PlatformPOSIX
+lldb_private::Error
+PlatformFreeBSD::RunShellCommand (const char *command,
+ const char *working_dir,
+ int *status_ptr,
+ int *signo_ptr,
+ std::string *command_output,
+ uint32_t timeout_sec)
+{
+ if (IsHost())
+ return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
+ else
+ {
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
+ else
+ return Error("unable to run a remote command without a platform");
+ }
+}
+
Error
PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
@@ -165,10 +185,10 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
{
Error error;
// Nothing special to do here, just use the actual file and architecture
-
+
char exe_path[PATH_MAX];
FileSpec resolved_exe_file (exe_file);
-
+
if (IsHost())
{
// If we have "ls" as the exe_file, resolve the executable location based on
@@ -178,10 +198,10 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
exe_file.GetPath(exe_path, sizeof(exe_path));
resolved_exe_file.SetFile(exe_path, true);
}
-
+
if (!resolved_exe_file.Exists())
resolved_exe_file.ResolveExecutableLocation ();
-
+
if (resolved_exe_file.Exists())
error.Clear();
else
@@ -216,8 +236,8 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
}
}
}
-
-
+
+
if (error.Success())
{
ModuleSpec module_spec (resolved_exe_file, exe_arch);
@@ -228,7 +248,7 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
module_search_paths_ptr,
NULL,
NULL);
-
+
if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL)
{
exe_module_sp.reset();
@@ -259,12 +279,12 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
else
error.SetErrorToGenericError();
}
-
+
if (idx > 0)
arch_names.PutCString (", ");
arch_names.PutCString (platform_arch.GetArchitectureName());
}
-
+
if (error.Fail() || !exe_module_sp)
{
error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
@@ -279,7 +299,7 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
error.SetErrorStringWithFormat ("'%s' does not exist",
exe_file.GetPath().c_str());
}
-
+
return error;
}
@@ -642,11 +662,18 @@ PlatformFreeBSD::GetStatus (Stream &strm)
#ifndef LLDB_DISABLE_POSIX
struct utsname un;
- if (uname(&un)) {
- strm << "FreeBSD";
- return;
- }
+ strm << " Host: ";
+
+ ::memset(&un, 0, sizeof(utsname));
+ if (uname(&un) == -1)
+ strm << "FreeBSD" << '\n';
+
+ strm << un.sysname << ' ' << un.release;
+ if (un.nodename[0] != '\0')
+ strm << " (" << un.nodename << ')';
+ strm << '\n';
+ // Dump a common information about the platform status.
strm << "Host: " << un.sysname << ' ' << un.release << ' ' << un.version << '\n';
#endif
diff --git a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
index 4aa158eb6e8..11d1cd60977 100644
--- a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
+++ b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
@@ -72,6 +72,14 @@ public:
// lldb_private::Platform functions
//------------------------------------------------------------
virtual lldb_private::Error
+ RunShellCommand (const char *command,
+ const char *working_dir,
+ int *status_ptr,
+ int *signo_ptr,
+ std::string *command_output,
+ uint32_t timeout_sec);
+
+ virtual lldb_private::Error
ResolveExecutable (const lldb_private::FileSpec &exe_file,
const lldb_private::ArchSpec &arch,
lldb::ModuleSP &module_sp,
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
index 4d85a7312e3..f055597d141 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -18,6 +18,7 @@
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/Timer.h"
@@ -36,8 +37,7 @@ using namespace lldb_private;
/// Default Constructor
//------------------------------------------------------------------
PlatformDarwin::PlatformDarwin (bool is_host) :
- Platform(is_host), // This is the local host platform
- m_remote_platform_sp (),
+ PlatformPOSIX(is_host), // This is the local host platform
m_developer_directory ()
{
}
@@ -209,11 +209,11 @@ PlatformDarwin::ResolveExecutable (const FileSpec &exe_file,
StreamString arch_names;
for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, module_spec.GetArchitecture()); ++idx)
{
- error = ModuleList::GetSharedModule (module_spec,
- exe_module_sp,
- module_search_paths_ptr,
- NULL,
- NULL);
+ error = GetSharedModule (module_spec,
+ exe_module_sp,
+ module_search_paths_ptr,
+ NULL,
+ NULL);
// Did we find an executable using one of the
if (error.Success())
{
@@ -268,7 +268,144 @@ PlatformDarwin::ResolveSymbolFile (Target &target,
}
+static lldb_private::Error
+MakeCacheFolderForFile (const FileSpec& module_cache_spec)
+{
+ FileSpec module_cache_folder = module_cache_spec.CopyByRemovingLastPathComponent();
+ StreamString mkdir_folder_cmd;
+ mkdir_folder_cmd.Printf("mkdir -p %s/%s", module_cache_folder.GetDirectory().AsCString(), module_cache_folder.GetFilename().AsCString());
+ return Host::RunShellCommand(mkdir_folder_cmd.GetData(),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 60);
+}
+
+static lldb_private::Error
+BringInRemoteFile (Platform* platform,
+ const lldb_private::ModuleSpec &module_spec,
+ const FileSpec& module_cache_spec)
+{
+ MakeCacheFolderForFile(module_cache_spec);
+ Error err = platform->GetFile(module_spec.GetFileSpec(), module_cache_spec);
+ return err;
+}
+
+lldb_private::Error
+PlatformDarwin::GetSharedModuleWithLocalCache (const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("[%s] Trying to find module %s/%s - platform path %s/%s symbol path %s/%s\n",
+ (IsHost() ? "host" : "remote"),
+ module_spec.GetFileSpec().GetDirectory().AsCString(),
+ module_spec.GetFileSpec().GetFilename().AsCString(),
+ module_spec.GetPlatformFileSpec().GetDirectory().AsCString(),
+ module_spec.GetPlatformFileSpec().GetFilename().AsCString(),
+ module_spec.GetSymbolFileSpec().GetDirectory().AsCString(),
+ module_spec.GetSymbolFileSpec().GetFilename().AsCString());
+
+ std::string cache_path(GetLocalCacheDirectory());
+ std::string module_path (module_spec.GetFileSpec().GetPath());
+ cache_path.append(module_path);
+ FileSpec module_cache_spec(cache_path.c_str(),false);
+
+ // if rsync is supported, always bring in the file - rsync will be very efficient
+ // when files are the same on the local and remote end of the connection
+ if (this->GetSupportsRSync())
+ {
+ Error err = BringInRemoteFile (this, module_spec, module_cache_spec);
+ if (err.Fail())
+ return err;
+ if (module_cache_spec.Exists())
+ {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("[%s] module %s/%s was rsynced and is now there\n",
+ (IsHost() ? "host" : "remote"),
+ module_spec.GetFileSpec().GetDirectory().AsCString(),
+ module_spec.GetFileSpec().GetFilename().AsCString());
+ ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
+ module_sp.reset(new Module(local_spec));
+ module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
+ return Error();
+ }
+ }
+ if (module_spec.GetFileSpec().Exists() && !module_sp)
+ {
+ module_sp.reset(new Module(module_spec));
+ return Error();
+ }
+
+ // try to find the module in the cache
+ if (module_cache_spec.Exists())
+ {
+ // get the local and remote MD5 and compare
+ {
+ // when going over the *slow* GDB remote transfer mechanism we first check
+ // the hashes of the files - and only do the actual transfer if they differ
+ uint64_t high_local,high_remote,low_local,low_remote;
+ Host::CalculateMD5 (module_cache_spec, low_local, high_local);
+ m_remote_platform_sp->CalculateMD5(module_spec.GetFileSpec(), low_remote, high_remote);
+ if (low_local != low_remote || high_local != high_remote)
+ {
+ // bring in the remote file
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("[%s] module %s/%s needs to be replaced from remote copy\n",
+ (IsHost() ? "host" : "remote"),
+ module_spec.GetFileSpec().GetDirectory().AsCString(),
+ module_spec.GetFileSpec().GetFilename().AsCString());
+ Error err = BringInRemoteFile (this, module_spec, module_cache_spec);
+ if (err.Fail())
+ return err;
+ }
+ }
+
+ ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
+ module_sp.reset(new Module(local_spec));
+ module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("[%s] module %s/%s was found in the cache\n",
+ (IsHost() ? "host" : "remote"),
+ module_spec.GetFileSpec().GetDirectory().AsCString(),
+ module_spec.GetFileSpec().GetFilename().AsCString());
+ return Error();
+ }
+
+ // bring in the remote module file
+ if (log)
+ log->Printf("[%s] module %s/%s needs to come in remotely\n",
+ (IsHost() ? "host" : "remote"),
+ module_spec.GetFileSpec().GetDirectory().AsCString(),
+ module_spec.GetFileSpec().GetFilename().AsCString());
+ Error err = BringInRemoteFile (this, module_spec, module_cache_spec);
+ if (err.Fail())
+ return err;
+ if (module_cache_spec.Exists())
+ {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("[%s] module %s/%s is now cached and fine\n",
+ (IsHost() ? "host" : "remote"),
+ module_spec.GetFileSpec().GetDirectory().AsCString(),
+ module_spec.GetFileSpec().GetFilename().AsCString());
+ ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
+ module_sp.reset(new Module(local_spec));
+ module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
+ return Error();
+ }
+ else
+ return Error("unable to obtain valid module file");
+}
Error
PlatformDarwin::GetSharedModule (const ModuleSpec &module_spec,
@@ -508,26 +645,39 @@ PlatformDarwin::ConnectRemote (Args& args)
if (!m_remote_platform_sp)
m_remote_platform_sp = Platform::Create ("remote-gdb-server", error);
- if (m_remote_platform_sp)
- {
- if (error.Success())
- {
- if (m_remote_platform_sp)
- {
- error = m_remote_platform_sp->ConnectRemote (args);
- }
- else
- {
- error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
- }
- }
- }
+ if (m_remote_platform_sp && error.Success())
+ error = m_remote_platform_sp->ConnectRemote (args);
else
error.SetErrorString ("failed to create a 'remote-gdb-server' platform");
if (error.Fail())
m_remote_platform_sp.reset();
}
+
+ if (error.Success() && m_remote_platform_sp)
+ {
+ if (m_options.get())
+ {
+ OptionGroupOptions* options = m_options.get();
+ OptionGroupPlatformRSync* m_rsync_options = (OptionGroupPlatformRSync*)options->GetGroupWithOption('r');
+ OptionGroupPlatformSSH* m_ssh_options = (OptionGroupPlatformSSH*)options->GetGroupWithOption('s');
+ OptionGroupPlatformCaching* m_cache_options = (OptionGroupPlatformCaching*)options->GetGroupWithOption('c');
+
+ if (m_rsync_options->m_rsync)
+ {
+ SetSupportsRSync(true);
+ SetRSyncOpts(m_rsync_options->m_rsync_opts.c_str());
+ SetRSyncPrefix(m_rsync_options->m_rsync_prefix.c_str());
+ SetIgnoresRemoteHostname(m_rsync_options->m_ignores_remote_hostname);
+ }
+ if (m_ssh_options->m_ssh)
+ {
+ SetSupportsSSH(true);
+ SetSSHOpts(m_ssh_options->m_ssh_opts.c_str());
+ }
+ SetLocalCacheDirectory(m_cache_options->m_cache_dir.c_str());
+ }
+ }
return error;
}
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
index a37ae29b8c2..326203cc010 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
@@ -14,9 +14,9 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Target/Platform.h"
+#include "Plugins/Platform/POSIX/PlatformPOSIX.h"
-class PlatformDarwin : public lldb_private::Platform
+class PlatformDarwin : public PlatformPOSIX
{
public:
PlatformDarwin (bool is_host);
@@ -118,12 +118,18 @@ public:
x86GetSupportedArchitectureAtIndex (uint32_t idx, lldb_private::ArchSpec &arch);
protected:
- lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote darwin OS
+ virtual lldb_private::Error
+ GetSharedModuleWithLocalCache (const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr);
+
std::string m_developer_directory;
const char *
GetDeveloperDirectory();
-
+
private:
DISALLOW_COPY_AND_ASSIGN (PlatformDarwin);
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp
index 3b0e159e454..9ca49731ee9 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp
@@ -12,14 +12,19 @@
// C Includes
#ifndef LLDB_DISABLE_POSIX
+#include <sys/stat.h>
#include <sys/sysctl.h>
#endif
// C++ Includes
+
+#include <sstream>
+
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Error.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/PluginManager.h"
@@ -161,9 +166,9 @@ PlatformMacOSX::~PlatformMacOSX()
}
Error
-PlatformMacOSX::GetFile (const FileSpec &platform_file,
- const UUID *uuid_ptr,
- FileSpec &local_file)
+PlatformMacOSX::GetSymbolFile (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
{
if (IsRemote())
{
@@ -176,6 +181,62 @@ PlatformMacOSX::GetFile (const FileSpec &platform_file,
return Error();
}
+lldb_private::Error
+PlatformMacOSX::GetFile (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID *uuid_ptr,
+ lldb_private::FileSpec &local_file)
+{
+ if (IsRemote() && m_remote_platform_sp)
+ {
+ std::string local_os_build;
+ Host::GetOSBuildString(local_os_build);
+ std::string remote_os_build;
+ m_remote_platform_sp->GetOSBuildString(remote_os_build);
+ if (local_os_build.compare(remote_os_build) == 0)
+ {
+ // same OS version: the local file is good enough
+ local_file = platform_file;
+ return Error();
+ }
+ else
+ {
+ // try to find the file in the cache
+ std::string cache_path(GetLocalCacheDirectory());
+ std::string module_path (platform_file.GetPath());
+ cache_path.append(module_path);
+ FileSpec module_cache_spec(cache_path.c_str(),false);
+ if (module_cache_spec.Exists())
+ {
+ local_file = module_cache_spec;
+ return Error();
+ }
+ // bring in the remote module file
+ FileSpec module_cache_folder = module_cache_spec.CopyByRemovingLastPathComponent();
+ StreamString mkdir_folder_cmd;
+ // try to make the local directory first
+ mkdir_folder_cmd.Printf("mkdir -p %s/%s", module_cache_folder.GetDirectory().AsCString(), module_cache_folder.GetFilename().AsCString());
+ Host::RunShellCommand(mkdir_folder_cmd.GetData(),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 60);
+ Error err = GetFile(platform_file, module_cache_spec);
+ if (err.Fail())
+ return err;
+ if (module_cache_spec.Exists())
+ {
+ local_file = module_cache_spec;
+ return Error();
+ }
+ else
+ return Error("unable to obtain valid module file");
+ }
+ }
+ local_file = platform_file;
+ return Error();
+}
+
bool
PlatformMacOSX::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
{
@@ -186,3 +247,12 @@ PlatformMacOSX::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
#endif
}
+lldb_private::Error
+PlatformMacOSX::GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+ return GetSharedModuleWithLocalCache(module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr);
+}
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h
index b93c5fa6921..57a5a25981a 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h
@@ -61,17 +61,36 @@ public:
return 1;
}
+ virtual lldb_private::Error
+ GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr);
+
virtual const char *
GetDescription ()
{
return GetDescriptionStatic (IsHost());
}
+ lldb_private::Error
+ GetSymbolFile (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID *uuid_ptr,
+ lldb_private::FileSpec &local_file);
+
+ virtual lldb_private::Error
+ GetFile (const lldb_private::FileSpec& source,
+ const lldb_private::FileSpec& destination)
+ {
+ return PlatformDarwin::GetFile (source,destination);
+ }
+
virtual lldb_private::Error
GetFile (const lldb_private::FileSpec &platform_file,
const lldb_private::UUID *uuid_ptr,
lldb_private::FileSpec &local_file);
-
+
virtual bool
GetSupportedArchitectureAtIndex (uint32_t idx,
lldb_private::ArchSpec &arch);
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp
index 7969aa819cf..7b5ab9aec41 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp
@@ -749,6 +749,15 @@ PlatformRemoteiOS::GetSharedModule (const ModuleSpec &module_spec,
// Not the module we are looking for... Nothing to see here...
module_sp.reset();
}
+ else
+ {
+ // This may not be an SDK-related module. Try whether we can bring in the thing to our local cache.
+ error = GetSharedModuleWithLocalCache(module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr);
+ if (error.Success())
+ return error;
+ else
+ error.Clear(); // Clear the error and fall-through.
+ }
const bool always_create = false;
error = ModuleList::GetSharedModule (module_spec,
@@ -764,24 +773,6 @@ PlatformRemoteiOS::GetSharedModule (const ModuleSpec &module_spec,
return error;
}
-
-uint32_t
-PlatformRemoteiOS::FindProcesses (const ProcessInstanceInfoMatch &match_info,
- ProcessInstanceInfoList &process_infos)
-{
- // TODO: if connected, send a packet to get the remote process infos by name
- process_infos.Clear();
- return 0;
-}
-
-bool
-PlatformRemoteiOS::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
-{
- // TODO: if connected, send a packet to get the remote process info
- process_info.Clear();
- return false;
-}
-
bool
PlatformRemoteiOS::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
{
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h
index ef59b124d8e..7eb2660dc6f 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h
@@ -93,14 +93,6 @@ public:
lldb::ModuleSP *old_module_sp_ptr,
bool *did_create_ptr);
- virtual uint32_t
- FindProcesses (const lldb_private::ProcessInstanceInfoMatch &match_info,
- lldb_private::ProcessInstanceInfoList &process_infos);
-
- virtual bool
- GetProcessInfo (lldb::pid_t pid,
- lldb_private::ProcessInstanceInfo &proc_info);
-
virtual bool
GetSupportedArchitectureAtIndex (uint32_t idx,
lldb_private::ArchSpec &arch);
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp
index 806eb7d60ea..f12843965a1 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp
@@ -315,9 +315,9 @@ PlatformiOSSimulator::GetSDKDirectory()
}
Error
-PlatformiOSSimulator::GetFile (const FileSpec &platform_file,
- const UUID *uuid_ptr,
- FileSpec &local_file)
+PlatformiOSSimulator::GetSymbolFile (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
{
Error error;
char platform_file_path[PATH_MAX];
@@ -370,7 +370,7 @@ PlatformiOSSimulator::GetSharedModule (const ModuleSpec &module_spec,
Error error;
FileSpec local_file;
const FileSpec &platform_file = module_spec.GetFileSpec();
- error = GetFile (platform_file, module_spec.GetUUIDPtr(), local_file);
+ error = GetSymbolFile (platform_file, module_spec.GetUUIDPtr(), local_file);
if (error.Success())
{
error = ResolveExecutable (local_file, module_spec.GetArchitecture(), module_sp, module_search_paths_ptr);
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h
index ce818c431a7..e75cf894904 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h
@@ -80,9 +80,9 @@ public:
GetStatus (lldb_private::Stream &strm);
virtual lldb_private::Error
- GetFile (const lldb_private::FileSpec &platform_file,
- const lldb_private::UUID *uuid_ptr,
- lldb_private::FileSpec &local_file);
+ GetSymbolFile (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID *uuid_ptr,
+ lldb_private::FileSpec &local_file);
virtual lldb_private::Error
GetSharedModule (const lldb_private::ModuleSpec &module_spec,
diff --git a/lldb/source/Plugins/Platform/Makefile b/lldb/source/Plugins/Platform/Makefile
index ceecfaad771..f709362841e 100644
--- a/lldb/source/Plugins/Platform/Makefile
+++ b/lldb/source/Plugins/Platform/Makefile
@@ -1,26 +1,26 @@
##===- source/Plugins/Platform/Makefile --------------------*- Makefile -*-===##
-#
+#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
-#
+#
##===----------------------------------------------------------------------===##
LLDB_LEVEL := ../../..
include $(LLDB_LEVEL)/../../Makefile.config
-DIRS := gdb-server MacOSX Linux FreeBSD
+DIRS := gdb-server MacOSX Linux FreeBSD POSIX
# ifeq ($(HOST_OS),Darwin)
# DIRS += MacOSX
# endif
-#
+#
# ifeq ($(HOST_OS),Linux)
# DIRS += Linux
# endif
-#
+#
# ifeq ($(HOST_OS),FreeBSD)
# DIRS += FreeBSD
# endif
diff --git a/lldb/source/Plugins/Platform/POSIX/CMakeLists.txt b/lldb/source/Plugins/Platform/POSIX/CMakeLists.txt
new file mode 100644
index 00000000000..6802d2e8029
--- /dev/null
+++ b/lldb/source/Plugins/Platform/POSIX/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(LLVM_NO_RTTI 1)
+
+add_lldb_library(lldbPluginPlatformPOSIX
+ PlatformPOSIX.cpp
+ )
diff --git a/lldb/source/Plugins/Platform/POSIX/Makefile b/lldb/source/Plugins/Platform/POSIX/Makefile
new file mode 100644
index 00000000000..eca927720ba
--- /dev/null
+++ b/lldb/source/Plugins/Platform/POSIX/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Platform/POSIX/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginPlatformPOSIX
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
new file mode 100644
index 00000000000..34316c48427
--- /dev/null
+++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
@@ -0,0 +1,541 @@
+//===-- PlatformPOSIX.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformPOSIX.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformPOSIX::PlatformPOSIX (bool is_host) :
+Platform(is_host), // This is the local host platform
+m_remote_platform_sp ()
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformPOSIX::~PlatformPOSIX()
+{
+}
+
+lldb_private::OptionGroupOptions*
+PlatformPOSIX::GetConnectionOptions (lldb_private::CommandInterpreter& interpreter)
+{
+ if (m_options.get() == NULL)
+ {
+ m_options.reset(new OptionGroupOptions(interpreter));
+ m_options->Append(new OptionGroupPlatformRSync());
+ m_options->Append(new OptionGroupPlatformSSH());
+ m_options->Append(new OptionGroupPlatformCaching());
+ }
+ return m_options.get();
+}
+
+lldb_private::Error
+PlatformPOSIX::RunShellCommand (const char *command, // Shouldn't be NULL
+ const char *working_dir, // Pass NULL to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish
+{
+ if (IsHost())
+ return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
+ else
+ {
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
+ else
+ return Error("unable to run a remote command without a platform");
+ }
+}
+
+uint32_t
+PlatformPOSIX::MakeDirectory (const std::string &path,
+ mode_t mode)
+{
+ if (IsHost())
+ {
+ return Host::MakeDirectory (path.c_str(), mode);
+ }
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->MakeDirectory(path, mode);
+ return Platform::MakeDirectory(path,mode);
+}
+
+lldb::user_id_t
+PlatformPOSIX::OpenFile (const FileSpec& file_spec,
+ uint32_t flags,
+ mode_t mode,
+ Error &error)
+{
+ if (IsHost())
+ {
+ return Host::OpenFile(file_spec, flags, mode, error);
+ }
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error);
+ return Platform::OpenFile(file_spec, flags, mode, error);
+}
+
+bool
+PlatformPOSIX::CloseFile (lldb::user_id_t fd, Error &error)
+{
+ if (IsHost())
+ {
+ return Host::CloseFile(fd, error);
+ }
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->CloseFile(fd, error);
+ return Platform::CloseFile(fd, error);
+}
+
+uint64_t
+PlatformPOSIX::ReadFile (lldb::user_id_t fd,
+ uint64_t offset,
+ void *dst,
+ uint64_t dst_len,
+ Error &error)
+{
+ if (IsHost())
+ {
+ return Host::ReadFile(fd, offset, dst, dst_len, error);
+ }
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error);
+ return Platform::ReadFile(fd, offset, dst, dst_len, error);
+}
+
+uint64_t
+PlatformPOSIX::WriteFile (lldb::user_id_t fd,
+ uint64_t offset,
+ const void* src,
+ uint64_t src_len,
+ Error &error)
+{
+ if (IsHost())
+ {
+ return Host::WriteFile(fd, offset, src, src_len, error);
+ }
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error);
+
+ return Platform::WriteFile(fd, offset, src, src_len, error);
+}
+
+static uint32_t
+chown_file(Platform *platform,
+ const char* path,
+ uint32_t uid = UINT32_MAX,
+ uint32_t gid = UINT32_MAX)
+{
+ if (!platform || !path || *path == 0)
+ return UINT32_MAX;
+
+ if (uid == UINT32_MAX && gid == UINT32_MAX)
+ return 0; // pretend I did chown correctly - actually I just didn't care
+
+ StreamString command;
+ command.PutCString("chown ");
+ if (uid != UINT32_MAX)
+ command.Printf("%d",uid);
+ if (gid != UINT32_MAX)
+ command.Printf(":%d",gid);
+ command.Printf("%s",path);
+ int status;
+ platform->RunShellCommand(command.GetData(),
+ NULL,
+ &status,
+ NULL,
+ NULL,
+ 10);
+ return status;
+}
+
+lldb_private::Error
+PlatformPOSIX::PutFile (const lldb_private::FileSpec& source,
+ const lldb_private::FileSpec& destination,
+ uint32_t uid,
+ uint32_t gid)
+{
+ if (IsHost())
+ {
+ if (FileSpec::Equal(source, destination, true))
+ return Error();
+ // cp src dst
+ // chown uid:gid dst
+ std::string src_path (source.GetPath());
+ if (src_path.empty())
+ return Error("unable to get file path for source");
+ std::string dst_path (destination.GetPath());
+ if (dst_path.empty())
+ return Error("unable to get file path for destination");
+ StreamString command;
+ command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
+ int status;
+ RunShellCommand(command.GetData(),
+ NULL,
+ &status,
+ NULL,
+ NULL,
+ 10);
+ if (status != 0)
+ return Error("unable to perform copy");
+ if (uid == UINT32_MAX && gid == UINT32_MAX)
+ return Error();
+ if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
+ return Error("unable to perform chown");
+ return Error();
+ }
+ else if (IsRemote() && m_remote_platform_sp)
+ {
+ if (GetSupportsRSync())
+ {
+ std::string src_path (source.GetPath());
+ if (src_path.empty())
+ return Error("unable to get file path for source");
+ std::string dst_path (destination.GetPath());
+ if (dst_path.empty())
+ return Error("unable to get file path for destination");
+ StreamString command;
+ if (GetIgnoresRemoteHostname())
+ {
+ if (!GetRSyncPrefix())
+ command.Printf("rsync %s %s %s",
+ GetRSyncOpts(),
+ src_path.c_str(),
+ dst_path.c_str());
+ else
+ command.Printf("rsync %s %s %s%s",
+ GetRSyncOpts(),
+ src_path.c_str(),
+ GetRSyncPrefix(),
+ dst_path.c_str());
+ }
+ else
+ command.Printf("rsync %s %s %s:%s",
+ GetRSyncOpts(),
+ src_path.c_str(),
+ GetHostname(),
+ dst_path.c_str());
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("[PutFile] Running command: %s\n", command.GetData());
+ int retcode;
+ Host::RunShellCommand(command.GetData(),
+ NULL,
+ &retcode,
+ NULL,
+ NULL,
+ 60);
+ if (retcode == 0)
+ {
+ // Don't chown a local file for a remote system
+// if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
+// return Error("unable to perform chown");
+ return Error();
+ }
+ // if we are still here rsync has failed - let's try the slow way before giving up
+ }
+ // open
+ // read, write, read, write, ...
+ // close
+ // chown uid:gid dst
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("[PutFile] Using block by block transfer....\n");
+ File source_file(source, File::eOpenOptionRead, File::ePermissionsUserRW);
+ if (!source_file.IsValid())
+ return Error("unable to open source file");
+ Error error;
+ lldb::user_id_t dest_file = OpenFile (destination,
+ File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate,
+ File::ePermissionsUserRWX | File::ePermissionsGroupRX | File::ePermissionsWorldRX,
+ error);
+ if (log)
+ log->Printf ("dest_file = %" PRIu64 "\n", dest_file);
+ if (error.Fail())
+ return error;
+ if (dest_file == UINT64_MAX)
+ return Error("unable to open target file");
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
+ uint64_t offset = 0;
+ while (error.Success())
+ {
+ size_t bytes_read = buffer_sp->GetByteSize();
+ error = source_file.Read(buffer_sp->GetBytes(), bytes_read);
+ if (bytes_read)
+ {
+ WriteFile(dest_file, offset, buffer_sp->GetBytes(), bytes_read, error);
+ offset += bytes_read;
+ }
+ else
+ break;
+ }
+ CloseFile(dest_file, error);
+ if (uid == UINT32_MAX && gid == UINT32_MAX)
+ return error;
+ // This is remopve, don't chown a local file...
+// std::string dst_path (destination.GetPath());
+// if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
+// return Error("unable to perform chown");
+ return error;
+ }
+ return Platform::PutFile(source,destination,uid,gid);
+}
+
+lldb::user_id_t
+PlatformPOSIX::GetFileSize (const FileSpec& file_spec)
+{
+ if (IsHost())
+ {
+ return Host::GetFileSize(file_spec);
+ }
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->GetFileSize(file_spec);
+ return Platform::GetFileSize(file_spec);
+}
+
+bool
+PlatformPOSIX::GetFileExists (const FileSpec& file_spec)
+{
+ if (IsHost())
+ {
+ return file_spec.Exists();
+ }
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->GetFileExists(file_spec);
+ return Platform::GetFileExists(file_spec);
+}
+
+uint32_t
+PlatformPOSIX::GetFilePermissions (const lldb_private::FileSpec &file_spec,
+ lldb_private::Error &error)
+{
+ if (IsHost())
+ {
+ return File::GetPermissions(file_spec.GetPath().c_str(), error);
+ }
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->GetFilePermissions(file_spec, error);
+ return Platform::GetFilePermissions(file_spec, error);
+
+}
+
+
+lldb_private::Error
+PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path */,
+ const lldb_private::FileSpec& destination /* local file path */)
+{
+ // Check the args, first.
+ std::string src_path (source.GetPath());
+ if (src_path.empty())
+ return Error("unable to get file path for source");
+ std::string dst_path (destination.GetPath());
+ if (dst_path.empty())
+ return Error("unable to get file path for destination");
+ if (IsHost())
+ {
+ if (FileSpec::Equal(source, destination, true))
+ return Error("local scenario->source and destination are the same file path: no operation performed");
+ // cp src dst
+ StreamString cp_command;
+ cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
+ int status;
+ RunShellCommand(cp_command.GetData(),
+ NULL,
+ &status,
+ NULL,
+ NULL,
+ 10);
+ if (status != 0)
+ return Error("unable to perform copy");
+ return Error();
+ }
+ else if (IsRemote() && m_remote_platform_sp)
+ {
+ if (GetSupportsRSync())
+ {
+ StreamString command;
+ if (GetIgnoresRemoteHostname())
+ {
+ if (!GetRSyncPrefix())
+ command.Printf("rsync %s %s %s",
+ GetRSyncOpts(),
+ src_path.c_str(),
+ dst_path.c_str());
+ else
+ command.Printf("rsync %s %s%s %s",
+ GetRSyncOpts(),
+ GetRSyncPrefix(),
+ src_path.c_str(),
+ dst_path.c_str());
+ }
+ else
+ command.Printf("rsync %s %s:%s %s",
+ GetRSyncOpts(),
+ m_remote_platform_sp->GetHostname(),
+ src_path.c_str(),
+ dst_path.c_str());
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("[GetFile] Running command: %s\n", command.GetData());
+ int retcode;
+ Host::RunShellCommand(command.GetData(),
+ NULL,
+ &retcode,
+ NULL,
+ NULL,
+ 60);
+ if (retcode == 0)
+ return Error();
+ // If we are here, rsync has failed - let's try the slow way before giving up
+ }
+ // open src and dst
+ // read/write, read/write, read/write, ...
+ // close src
+ // close dst
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("[GetFile] Using block by block transfer....\n");
+ Error error;
+ user_id_t fd_src = OpenFile (source,
+ File::eOpenOptionRead,
+ File::ePermissionsDefault,
+ error);
+
+ if (fd_src == UINT64_MAX)
+ return Error("unable to open source file");
+
+ uint32_t permissions = GetFilePermissions(source, error);
+
+ if (permissions == 0)
+ permissions = File::ePermissionsDefault;
+
+ user_id_t fd_dst = Host::OpenFile(destination,
+ File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate,
+ permissions,
+ error);
+
+ if (fd_dst == UINT64_MAX)
+ {
+ if (error.Success())
+ error.SetErrorString("unable to open destination file");
+ }
+
+ if (error.Success())
+ {
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
+ uint64_t offset = 0;
+ error.Clear();
+ while (error.Success())
+ {
+ const uint64_t n_read = ReadFile (fd_src,
+ offset,
+ buffer_sp->GetBytes(),
+ buffer_sp->GetByteSize(),
+ error);
+ if (error.Fail())
+ break;
+ if (n_read == 0)
+ break;
+ if (Host::WriteFile(fd_dst,
+ offset,
+ buffer_sp->GetBytes(),
+ n_read,
+ error) != n_read)
+ {
+ if (!error.Fail())
+ error.SetErrorString("unable to write to destination file");
+ break;
+ }
+ offset += n_read;
+ }
+ }
+ // Ignore the close error of src.
+ if (fd_src != UINT64_MAX)
+ CloseFile(fd_src, error);
+ // And close the dst file descriptot.
+ if (fd_dst != UINT64_MAX && !Host::CloseFile(fd_dst, error))
+ {
+ if (!error.Fail())
+ error.SetErrorString("unable to close destination file");
+
+ }
+ return error;
+ }
+ return Platform::GetFile(source,destination);
+}
+
+std::string
+PlatformPOSIX::GetPlatformSpecificConnectionInformation()
+{
+ StreamString stream;
+ if (GetSupportsRSync())
+ {
+ stream.PutCString("rsync");
+ if ( (GetRSyncOpts() && *GetRSyncOpts()) ||
+ (GetRSyncPrefix() && *GetRSyncPrefix()) ||
+ GetIgnoresRemoteHostname())
+ {
+ stream.Printf(", options: ");
+ if (GetRSyncOpts() && *GetRSyncOpts())
+ stream.Printf("'%s' ",GetRSyncOpts());
+ stream.Printf(", prefix: ");
+ if (GetRSyncPrefix() && *GetRSyncPrefix())
+ stream.Printf("'%s' ",GetRSyncPrefix());
+ if (GetIgnoresRemoteHostname())
+ stream.Printf("ignore remote-hostname ");
+ }
+ }
+ if (GetSupportsSSH())
+ {
+ stream.PutCString("ssh");
+ if (GetSSHOpts() && *GetSSHOpts())
+ stream.Printf(", options: '%s' ",GetSSHOpts());
+ }
+ if (GetLocalCacheDirectory() && *GetLocalCacheDirectory())
+ stream.Printf("cache dir: %s",GetLocalCacheDirectory());
+ if (stream.GetSize())
+ return stream.GetData();
+ else
+ return "";
+}
+
+bool
+PlatformPOSIX::CalculateMD5 (const FileSpec& file_spec,
+ uint64_t &low,
+ uint64_t &high)
+{
+ if (IsHost())
+ return Platform::CalculateMD5 (file_spec, low, high);
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->CalculateMD5(file_spec, low, high);
+ return false;
+}
diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h
new file mode 100644
index 00000000000..4119e452bf7
--- /dev/null
+++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h
@@ -0,0 +1,111 @@
+//===-- PlatformPOSIX.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_PlatformPOSIX_h_
+#define liblldb_PlatformPOSIX_h_
+
+// C Includes
+// C++ Includes
+
+#include <memory>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Target/Platform.h"
+
+class PlatformPOSIX : public lldb_private::Platform
+{
+public:
+ PlatformPOSIX (bool is_host);
+
+ virtual
+ ~PlatformPOSIX();
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ virtual lldb_private::OptionGroupOptions*
+ GetConnectionOptions (lldb_private::CommandInterpreter& interpreter);
+
+ virtual lldb_private::Error
+ PutFile (const lldb_private::FileSpec& source,
+ const lldb_private::FileSpec& destination,
+ uint32_t uid = UINT32_MAX,
+ uint32_t gid = UINT32_MAX);
+
+ virtual lldb::user_id_t
+ OpenFile (const lldb_private::FileSpec& file_spec,
+ uint32_t flags,
+ mode_t mode,
+ lldb_private::Error &error);
+
+ virtual bool
+ CloseFile (lldb::user_id_t fd,
+ lldb_private::Error &error);
+
+ virtual uint64_t
+ ReadFile (lldb::user_id_t fd,
+ uint64_t offset,
+ void *dst,
+ uint64_t dst_len,
+ lldb_private::Error &error);
+
+ virtual uint64_t
+ WriteFile (lldb::user_id_t fd,
+ uint64_t offset,
+ const void* src,
+ uint64_t src_len,
+ lldb_private::Error &error);
+
+ virtual lldb::user_id_t
+ GetFileSize (const lldb_private::FileSpec& file_spec);
+
+ virtual lldb_private::Error
+ GetFile (const lldb_private::FileSpec& source,
+ const lldb_private::FileSpec& destination);
+
+ virtual lldb_private::Error
+ RunShellCommand (const char *command, // Shouldn't be NULL
+ const char *working_dir, // Pass NULL to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish
+
+ virtual uint32_t
+ MakeDirectory (const std::string &path,
+ mode_t mode);
+
+ virtual bool
+ GetFileExists (const lldb_private::FileSpec& file_spec);
+
+ virtual uint32_t
+ GetFilePermissions (const lldb_private::FileSpec &file_spec,
+ lldb_private::Error &error);
+
+ virtual std::string
+ GetPlatformSpecificConnectionInformation();
+
+ virtual bool
+ CalculateMD5 (const lldb_private::FileSpec& file_spec,
+ uint64_t &low,
+ uint64_t &high);
+
+protected:
+ std::auto_ptr<lldb_private::OptionGroupOptions> m_options;
+
+ lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote POSIX-compliant OS
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformPOSIX);
+
+};
+
+#endif // liblldb_PlatformPOSIX_h_
diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
index 5d15db53de7..4aeec032d71 100644
--- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
+++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
@@ -110,7 +110,11 @@ PlatformRemoteGDBServer::ResolveExecutable (const FileSpec &exe_file,
const FileSpecList *module_search_paths_ptr)
{
Error error;
- error.SetErrorString ("PlatformRemoteGDBServer::ResolveExecutable() is unimplemented");
+ //error.SetErrorString ("PlatformRemoteGDBServer::ResolveExecutable() is unimplemented");
+ if (m_gdb_client.GetFileExists(exe_file))
+ return error;
+ // TODO: get the remote end to somehow resolve this file
+ error.SetErrorString("file not found on remote end");
return error;
}
@@ -233,6 +237,11 @@ PlatformRemoteGDBServer::ConnectRemote (Args& args)
error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
}
}
+
+ if (error.Success())
+ {
+
+ }
return error;
}
@@ -327,6 +336,12 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
break;
}
}
+
+ ArchSpec arch_spec = launch_info.GetArchitecture();
+ const char *arch_triple = arch_spec.GetTriple().str().c_str();
+
+ m_gdb_client.SendLaunchArchPacket(arch_triple);
+
const uint32_t old_packet_timeout = m_gdb_client.SetPacketTimeout (5);
int arg_packet_err = m_gdb_client.SendArgumentsPacket (argv);
m_gdb_client.SetPacketTimeout (old_packet_timeout);
@@ -363,7 +378,8 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
{
if (IsConnected())
{
- uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort();
+ lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
+ uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid);
if (port == 0)
{
@@ -397,15 +413,22 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
if (process_sp)
{
char connect_url[256];
+ const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
+ const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
+ int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
const int connect_url_len = ::snprintf (connect_url,
sizeof(connect_url),
"connect://%s:%u",
- GetHostname (),
- port);
+ override_hostname ? override_hostname : GetHostname (),
+ port + port_offset);
assert (connect_url_len < (int)sizeof(connect_url));
error = process_sp->ConnectRemote (NULL, connect_url);
if (error.Success())
error = process_sp->Attach(attach_info);
+ else if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ m_gdb_client.KillSpawnedProcess(debugserver_pid);
+ }
}
}
}
@@ -418,4 +441,83 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
return process_sp;
}
+uint32_t
+PlatformRemoteGDBServer::MakeDirectory (const std::string &path,
+ mode_t mode)
+{
+ return m_gdb_client.MakeDirectory(path,mode);
+}
+
+lldb::user_id_t
+PlatformRemoteGDBServer::OpenFile (const lldb_private::FileSpec& file_spec,
+ uint32_t flags,
+ mode_t mode,
+ Error &error)
+{
+ return m_gdb_client.OpenFile (file_spec, flags, mode, error);
+}
+
+bool
+PlatformRemoteGDBServer::CloseFile (lldb::user_id_t fd, Error &error)
+{
+ return m_gdb_client.CloseFile (fd, error);
+}
+
+lldb::user_id_t
+PlatformRemoteGDBServer::GetFileSize (const lldb_private::FileSpec& file_spec)
+{
+ return m_gdb_client.GetFileSize(file_spec);
+}
+
+uint32_t
+PlatformRemoteGDBServer::GetFilePermissions (const lldb_private::FileSpec &file_spec,
+ lldb_private::Error &error)
+{
+ return m_gdb_client.GetFilePermissions(file_spec, error);
+}
+
+uint64_t
+PlatformRemoteGDBServer::ReadFile (lldb::user_id_t fd,
+ uint64_t offset,
+ void *dst,
+ uint64_t dst_len,
+ Error &error)
+{
+ return m_gdb_client.ReadFile (fd, offset, dst, dst_len, error);
+}
+
+uint64_t
+PlatformRemoteGDBServer::WriteFile (lldb::user_id_t fd,
+ uint64_t offset,
+ const void* src,
+ uint64_t src_len,
+ Error &error)
+{
+ return m_gdb_client.WriteFile (fd, offset, src, src_len, error);
+}
+lldb_private::Error
+PlatformRemoteGDBServer::PutFile (const lldb_private::FileSpec& source,
+ const lldb_private::FileSpec& destination,
+ uint32_t uid,
+ uint32_t gid)
+{
+ return Platform::PutFile(source,destination,uid,gid);
+}
+
+bool
+PlatformRemoteGDBServer::GetFileExists (const lldb_private::FileSpec& file_spec)
+{
+ return m_gdb_client.GetFileExists (file_spec);
+}
+
+lldb_private::Error
+PlatformRemoteGDBServer::RunShellCommand (const char *command, // Shouldn't be NULL
+ const char *working_dir, // Pass NULL to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish
+{
+ return m_gdb_client.RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
+}
diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
index 22b3dd49be5..70db6bafacd 100644
--- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
+++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
@@ -134,6 +134,58 @@ public:
virtual lldb_private::Error
DisconnectRemote ();
+
+ virtual uint32_t
+ MakeDirectory (const std::string &path,
+ mode_t mode);
+
+ virtual lldb::user_id_t
+ OpenFile (const lldb_private::FileSpec& file_spec,
+ uint32_t flags,
+ mode_t mode,
+ lldb_private::Error &error);
+
+ virtual bool
+ CloseFile (lldb::user_id_t fd,
+ lldb_private::Error &error);
+
+ virtual uint64_t
+ ReadFile (lldb::user_id_t fd,
+ uint64_t offset,
+ void *data_ptr,
+ uint64_t len,
+ lldb_private::Error &error);
+
+ virtual uint64_t
+ WriteFile (lldb::user_id_t fd,
+ uint64_t offset,
+ const void* data,
+ uint64_t len,
+ lldb_private::Error &error);
+
+ virtual lldb::user_id_t
+ GetFileSize (const lldb_private::FileSpec& file_spec);
+
+ virtual lldb_private::Error
+ PutFile (const lldb_private::FileSpec& source,
+ const lldb_private::FileSpec& destination,
+ uint32_t uid = UINT32_MAX,
+ uint32_t gid = UINT32_MAX);
+
+ virtual bool
+ GetFileExists (const lldb_private::FileSpec& file_spec);
+
+ virtual uint32_t
+ GetFilePermissions (const lldb_private::FileSpec &file_spec,
+ lldb_private::Error &error);
+
+ virtual lldb_private::Error
+ RunShellCommand (const char *command, // Shouldn't be NULL
+ const char *working_dir, // Pass NULL to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish
protected:
GDBRemoteCommunicationClient m_gdb_client;
diff --git a/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
index ea26d972b86..23fcfa62563 100644
--- a/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
@@ -125,8 +125,27 @@ ProcessFreeBSD::Terminate()
bool
ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
{
- // XXX haxx
- new_thread_list = old_thread_list;
-
- return false;
+ LogSP log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessFreeBSD::%s() (pid = %i)", __FUNCTION__, GetID());
+
+ bool has_updated = false;
+ const tid_t tid = Host::GetCurrentThreadID();
+ const lldb::pid_t pid = GetID();
+ // Update the process thread list with this new thread.
+ // FIXME: We should be using tid, not pid.
+ assert(m_monitor);
+ ThreadSP thread_sp (old_thread_list.FindThreadByID (pid, false));
+ if (!thread_sp) {
+ ProcessSP me = this->shared_from_this();
+ thread_sp.reset(new POSIXThread(me, pid));
+ has_updated = true;
+ }
+
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessFreeBSD::%s() updated tid = %i", __FUNCTION__, pid);
+
+ new_thread_list.AddThread(thread_sp);
+
+ return has_updated; // the list has been updated
}
diff --git a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
index f04631ddf91..5a78b874e1e 100644
--- a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
+++ b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
@@ -813,19 +813,21 @@ ProcessPOSIX::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thre
if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
log->Printf ("ProcessPOSIX::%s() (pid = %" PRIi64 ")", __FUNCTION__, GetID());
+ bool has_updated = false;
// Update the process thread list with this new thread.
// FIXME: We should be using tid, not pid.
assert(m_monitor);
ThreadSP thread_sp (old_thread_list.FindThreadByID (GetID(), false));
if (!thread_sp) {
thread_sp.reset(CreateNewPOSIXThread(*this, GetID()));
+ has_updated = true;
}
if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
log->Printf ("ProcessPOSIX::%s() updated pid = %" PRIi64, __FUNCTION__, GetID());
new_thread_list.AddThread(thread_sp);
- return new_thread_list.GetSize(false) > 0;
+ return has_updated; // the list has been updated
}
ByteOrder
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index d7efdf2302d..46bd9ca8069 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -133,7 +133,11 @@ GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name,
const char *listener_name,
bool is_platform) :
Communication(comm_name),
+#ifdef LLDB_CONFIGURATION_DEBUG
+ m_packet_timeout (1000),
+#else
m_packet_timeout (1),
+#endif
m_sequence_mutex (Mutex::eMutexTypeRecursive),
m_public_is_running (false),
m_private_is_running (false),
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 6a6e063e35b..e3183fca1db 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -20,6 +20,7 @@
#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/State.h"
+#include "lldb/Core/StreamGDBRemote.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
@@ -2137,21 +2138,37 @@ GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t
}
uint16_t
-GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort ()
+GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid)
{
+ pid = LLDB_INVALID_PROCESS_ID;
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse("qLaunchGDBServer", strlen("qLaunchGDBServer"), response, false))
+ StreamString stream;
+ stream.PutCString("qLaunchGDBServer:port:0;");
+ std::string hostname;
+ if (Host::GetHostname (hostname))
+ {
+ // Make the GDB server we launch only accept connections from this host
+ stream.Printf("host:%s;", hostname.c_str());
+ }
+ else
+ {
+ // Make the GDB server we launch accept connections from any host since we can't figure out the hostname
+ stream.Printf("host:*;");
+ }
+ const char *packet = stream.GetData();
+ int packet_len = stream.GetSize();
+
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
{
std::string name;
std::string value;
uint16_t port = 0;
- //lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
while (response.GetNameColonValue(name, value))
{
- if (name.size() == 4 && name.compare("port") == 0)
+ if (name.compare("port") == 0)
port = Args::StringToUInt32(value.c_str(), 0, 0);
-// if (name.size() == 3 && name.compare("pid") == 0)
-// pid = Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0);
+ else if (name.compare("pid") == 0)
+ pid = Args::StringToUInt64(value.c_str(), LLDB_INVALID_PROCESS_ID, 0);
}
return port;
}
@@ -2159,6 +2176,23 @@ GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort ()
}
bool
+GDBRemoteCommunicationClient::KillSpawnedProcess (lldb::pid_t pid)
+{
+ StreamString stream;
+ stream.Printf ("qKillSpawnedProcess:%" PRId64 , pid);
+ const char *packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ pid = LLDB_INVALID_PROCESS_ID;
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.IsOKResponse())
+ return true;
+ }
+ return false;
+}
+
+bool
GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid)
{
if (m_curr_tid == tid)
@@ -2351,3 +2385,326 @@ GDBRemoteCommunicationClient::GetShlibInfoAddr()
return LLDB_INVALID_ADDRESS;
}
+lldb_private::Error
+GDBRemoteCommunicationClient::RunShellCommand (const char *command, // Shouldn't be NULL
+ const char *working_dir, // Pass NULL to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("qPlatform_RunCommand:");
+ stream.PutBytesAsRawHex8(command, strlen(command));
+ stream.PutChar(',');
+ stream.PutHex32(timeout_sec);
+ if (working_dir && *working_dir)
+ {
+ stream.PutChar(',');
+ stream.PutBytesAsRawHex8(working_dir, strlen(working_dir));
+ }
+ const char *packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() != 'F')
+ return Error("malformed reply");
+ if (response.GetChar() != ',')
+ return Error("malformed reply");
+ uint32_t exitcode = response.GetHexMaxU32(false, UINT32_MAX);
+ if (exitcode == UINT32_MAX)
+ return Error("unable to run remote process");
+ else if (status_ptr)
+ *status_ptr = exitcode;
+ if (response.GetChar() != ',')
+ return Error("malformed reply");
+ uint32_t signo = response.GetHexMaxU32(false, UINT32_MAX);
+ if (signo_ptr)
+ *signo_ptr = signo;
+ if (response.GetChar() != ',')
+ return Error("malformed reply");
+ std::string output;
+ response.GetEscapedBinaryData(output);
+ if (command_output)
+ command_output->assign(output);
+ return Error();
+ }
+ return Error("unable to send packet");
+}
+
+uint32_t
+GDBRemoteCommunicationClient::MakeDirectory (const std::string &path,
+ mode_t mode)
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("qPlatform_IO_MkDir:");
+ stream.PutHex32(mode);
+ stream.PutChar(',');
+ stream.PutBytesAsRawHex8(path.c_str(), path.size());
+ const char *packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ return response.GetHexMaxU32(false, UINT32_MAX);
+ }
+ return UINT32_MAX;
+
+}
+
+static uint64_t
+ParseHostIOPacketResponse (StringExtractorGDBRemote &response,
+ uint64_t fail_result,
+ Error &error)
+{
+ response.SetFilePos(0);
+ if (response.GetChar() != 'F')
+ return fail_result;
+ int32_t result = response.GetS32 (-2);
+ if (result == -2)
+ return fail_result;
+ if (response.GetChar() == ',')
+ {
+ int result_errno = response.GetS32 (-2);
+ if (result_errno != -2)
+ error.SetError(result_errno, eErrorTypePOSIX);
+ else
+ error.SetError(-1, eErrorTypeGeneric);
+ }
+ else
+ error.Clear();
+ return result;
+}
+lldb::user_id_t
+GDBRemoteCommunicationClient::OpenFile (const lldb_private::FileSpec& file_spec,
+ uint32_t flags,
+ mode_t mode,
+ Error &error)
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:open:");
+ std::string path (file_spec.GetPath());
+ if (path.empty())
+ return UINT64_MAX;
+ stream.PutCStringAsRawHex8(path.c_str());
+ stream.PutChar(',');
+ const uint32_t posix_open_flags = File::ConvertOpenOptionsForPOSIXOpen(flags);
+ stream.PutHex32(posix_open_flags);
+ stream.PutChar(',');
+ stream.PutHex32(mode);
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ return ParseHostIOPacketResponse (response, UINT64_MAX, error);
+ }
+ return UINT64_MAX;
+}
+
+bool
+GDBRemoteCommunicationClient::CloseFile (lldb::user_id_t fd,
+ Error &error)
+{
+ lldb_private::StreamString stream;
+ stream.Printf("vFile:close:%i", (int)fd);
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ return ParseHostIOPacketResponse (response, -1, error) == 0;
+ }
+ return UINT64_MAX;
+}
+
+// Extension of host I/O packets to get the file size.
+lldb::user_id_t
+GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_spec)
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:size:");
+ std::string path (file_spec.GetPath());
+ stream.PutCStringAsRawHex8(path.c_str());
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() != 'F')
+ return UINT64_MAX;
+ uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX);
+ return retcode;
+ }
+ return UINT64_MAX;
+}
+
+uint32_t
+GDBRemoteCommunicationClient::GetFilePermissions(const lldb_private::FileSpec& file_spec, Error &error)
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:mode:");
+ std::string path (file_spec.GetPath());
+ stream.PutCStringAsRawHex8(path.c_str());
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() != 'F')
+ {
+ error.SetErrorStringWithFormat ("invalid response to '%s' packet", packet);
+ return 0;
+ }
+ const uint32_t mode = response.GetS32(-1);
+ if (mode == -1)
+ {
+ if (response.GetChar() == ',')
+ {
+ int response_errno = response.GetS32(-1);
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ else
+ error.SetErrorToGenericError();
+ }
+ }
+ else
+ error.Clear();
+ return mode & (S_IRWXU|S_IRWXG|S_IRWXO);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("failed to send '%s' packet", packet);
+ }
+ return 0;
+}
+
+uint64_t
+GDBRemoteCommunicationClient::ReadFile (lldb::user_id_t fd,
+ uint64_t offset,
+ void *dst,
+ uint64_t dst_len,
+ Error &error)
+{
+ lldb_private::StreamString stream;
+ stream.Printf("vFile:pread:%i,%" PRId64 ",%" PRId64, (int)fd, dst_len, offset);
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() != 'F')
+ return 0;
+ uint32_t retcode = response.GetHexMaxU32(false, UINT32_MAX);
+ if (retcode == UINT32_MAX)
+ return retcode;
+ const char next = (response.Peek() ? *response.Peek() : 0);
+ if (next == ',')
+ return 0;
+ if (next == ';')
+ {
+ response.GetChar(); // skip the semicolon
+ std::string buffer;
+ if (response.GetEscapedBinaryData(buffer))
+ {
+ const uint64_t data_to_write = std::min<uint64_t>(dst_len, buffer.size());
+ if (data_to_write > 0)
+ memcpy(dst, &buffer[0], data_to_write);
+ return data_to_write;
+ }
+ }
+ }
+ return 0;
+}
+
+uint64_t
+GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd,
+ uint64_t offset,
+ const void* src,
+ uint64_t src_len,
+ Error &error)
+{
+ lldb_private::StreamGDBRemote stream;
+ stream.Printf("vFile:pwrite:%i,%" PRId64 ",", (int)fd, offset);
+ stream.PutEscapedBytes(src, src_len);
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() != 'F')
+ {
+ error.SetErrorStringWithFormat("write file failed");
+ return 0;
+ }
+ uint64_t bytes_written = response.GetU64(UINT64_MAX);
+ if (bytes_written == UINT64_MAX)
+ {
+ error.SetErrorToGenericError();
+ if (response.GetChar() == ',')
+ {
+ int response_errno = response.GetS32(-1);
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ }
+ return 0;
+ }
+ return bytes_written;
+ }
+ else
+ {
+ error.SetErrorString ("failed to send vFile:pwrite packet");
+ }
+ return 0;
+}
+
+// Extension of host I/O packets to get whether a file exists.
+bool
+GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec)
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:exists:");
+ std::string path (file_spec.GetPath());
+ stream.PutCStringAsRawHex8(path.c_str());
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() != 'F')
+ return false;
+ if (response.GetChar() != ',')
+ return false;
+ bool retcode = (response.GetChar() != '0');
+ return retcode;
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_spec,
+ uint64_t &high,
+ uint64_t &low)
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:MD5:");
+ std::string path (file_spec.GetPath());
+ stream.PutCStringAsRawHex8(path.c_str());
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() != 'F')
+ return false;
+ if (response.GetChar() != ',')
+ return false;
+ if (response.Peek() && *response.Peek() == 'x')
+ return false;
+ low = response.GetHexMaxU64(false, UINT64_MAX);
+ high = response.GetHexMaxU64(false, UINT64_MAX);
+ return true;
+ }
+ return false;
+}
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 5bb8387b909..c8809cbf445 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -89,7 +89,10 @@ public:
GetLaunchSuccess (std::string &error_str);
uint16_t
- LaunchGDBserverAndGetPort ();
+ LaunchGDBserverAndGetPort (lldb::pid_t &pid);
+
+ bool
+ KillSpawnedProcess (lldb::pid_t pid);
//------------------------------------------------------------------
/// Sends a GDB remote protocol 'A' packet that delivers program
@@ -347,10 +350,61 @@ public:
return m_interrupt_sent;
}
+ virtual lldb::user_id_t
+ OpenFile (const lldb_private::FileSpec& file_spec,
+ uint32_t flags,
+ mode_t mode,
+ lldb_private::Error &error);
+
+ virtual bool
+ CloseFile (lldb::user_id_t fd,
+ lldb_private::Error &error);
+
+ virtual lldb::user_id_t
+ GetFileSize (const lldb_private::FileSpec& file_spec);
+
+ virtual uint32_t
+ GetFilePermissions(const lldb_private::FileSpec& file_spec,
+ lldb_private::Error &error);
+
+ virtual uint64_t
+ ReadFile (lldb::user_id_t fd,
+ uint64_t offset,
+ void *dst,
+ uint64_t dst_len,
+ lldb_private::Error &error);
+
+ virtual uint64_t
+ WriteFile (lldb::user_id_t fd,
+ uint64_t offset,
+ const void* src,
+ uint64_t src_len,
+ lldb_private::Error &error);
+
+ virtual uint32_t
+ MakeDirectory (const std::string &path,
+ mode_t mode);
+
+ virtual bool
+ GetFileExists (const lldb_private::FileSpec& file_spec);
+
+ virtual lldb_private::Error
+ RunShellCommand (const char *command, // Shouldn't be NULL
+ const char *working_dir, // Pass NULL to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish
+
+ virtual bool
+ CalculateMD5 (const lldb_private::FileSpec& file_spec,
+ uint64_t &high,
+ uint64_t &low);
+
std::string
HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process,
StringExtractorGDBRemote &inputStringExtractor);
-
+
protected:
bool
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index 050ed00ff6d..f6fdf1513eb 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -9,6 +9,7 @@
#include "GDBRemoteCommunicationServer.h"
+#include "lldb/Core/StreamGDBRemote.h"
// C Includes
// C++ Includes
@@ -20,6 +21,7 @@
#include "lldb/Core/State.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Host/Endian.h"
+#include "lldb/Host/File.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/TimeValue.h"
#include "lldb/Target/Process.h"
@@ -40,11 +42,31 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) :
m_async_thread (LLDB_INVALID_HOST_THREAD),
m_process_launch_info (),
m_process_launch_error (),
+ m_spawned_pids (),
+ m_spawned_pids_mutex (Mutex::eMutexTypeRecursive),
m_proc_infos (),
m_proc_infos_index (0),
m_lo_port_num (0),
- m_hi_port_num (0)
+ m_hi_port_num (0),
+ m_next_port (0),
+ m_use_port_range (false)
{
+ // We seldom need to override the port number that the debugserver process
+ // starts with. We just pass in 0 to let the system choose a random port.
+ // In rare situation where the need arises, use two environment variables
+ // to override.
+ uint16_t lo_port_num = 0;
+ uint16_t hi_port_num = 0;
+ const char *lo_port_c_str = getenv("LLDB_PLATFORM_START_DEBUG_SERVER_LO_PORT");
+ if (lo_port_c_str)
+ lo_port_num = ::atoi(lo_port_c_str);
+ const char *hi_port_c_str = getenv("LLDB_PLATFORM_START_DEBUG_SERVER_HI_PORT");
+ if (hi_port_c_str)
+ hi_port_num = ::atoi(hi_port_c_str);
+ if (lo_port_num && hi_port_num && lo_port_num < hi_port_num)
+ {
+ SetPortRange(lo_port_num, hi_port_num);
+ }
}
//----------------------------------------------------------------------
@@ -125,6 +147,9 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer:
return Handle_qLaunchGDBServer (packet);
+ case StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess:
+ return Handle_qKillSpawnedProcess (packet);
+
case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess:
return Handle_qLaunchSuccess (packet);
@@ -142,6 +167,9 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
case StringExtractorGDBRemote::eServerPacketType_QEnvironment:
return Handle_QEnvironment (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QLaunchArch:
+ return Handle_QLaunchArch (packet);
case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR:
return Handle_QSetDisableASLR (packet);
@@ -160,6 +188,39 @@ GDBRemoteCommunicationServer::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_RunCommand:
+ return Handle_qPlatform_RunCommand (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_Open:
+ return Handle_vFile_Open (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_Close:
+ return Handle_vFile_Close (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_pRead:
+ return Handle_vFile_pRead (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_pWrite:
+ return Handle_vFile_pWrite (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_Size:
+ return Handle_vFile_Size (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_Mode:
+ return Handle_vFile_Mode (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_Exists:
+ return Handle_vFile_Exists (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_Stat:
+ return Handle_vFile_Stat (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_MD5:
+ return Handle_vFile_MD5 (packet);
}
return true;
}
@@ -666,6 +727,24 @@ GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet)
}
bool
+GDBRemoteCommunicationServer::DebugserverProcessReaped (lldb::pid_t pid)
+{
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ return m_spawned_pids.erase(pid) > 0;
+}
+bool
+GDBRemoteCommunicationServer::ReapDebugserverProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal, // Zero for no signal
+ int status) // Exit value of process if signal is zero
+{
+ GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton;
+ server->DebugserverProcessReaped (pid);
+ return true;
+}
+
+bool
GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
{
#ifdef _WIN32
@@ -681,47 +760,97 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote
ConnectionFileDescriptor file_conn;
char connect_url[PATH_MAX];
Error error;
- char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
+ std::string hostname;
+ char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
if (::mktemp (unix_socket_name) == NULL)
{
error.SetErrorString ("failed to make temporary path for a unix socket");
}
else
{
+ packet.SetFilePos(::strlen ("qLaunchGDBServer:"));
+ std::string name;
+ std::string value;
+ uint16_t port = UINT16_MAX;
+ while (packet.GetNameColonValue(name, value))
+ {
+ if (name.compare ("host") == 0)
+ hostname.swap(value);
+ else if (name.compare ("port") == 0)
+ port = Args::StringToUInt32(value.c_str(), 0, 0);
+ }
+ if (port == UINT16_MAX)
+ port = GetAndUpdateNextPort();
+
::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name);
// Spawn a new thread to accept the port that gets bound after
// binding to port 0 (zero).
- lldb::thread_t accept_thread = Host::ThreadCreate (unix_socket_name,
- AcceptPortFromInferior,
- connect_url,
- &error);
+ lldb::thread_t accept_thread = NULL;
+
+ if (port == 0)
+ {
+ accept_thread = Host::ThreadCreate (unix_socket_name,
+ AcceptPortFromInferior,
+ connect_url,
+ &error);
+ }
if (IS_VALID_LLDB_HOST_THREAD(accept_thread))
{
- // Spawn a debugserver and try to get
+ // Spawn a debugserver and try to get the port it listens to.
ProcessLaunchInfo debugserver_launch_info;
- error = StartDebugserverProcess ("localhost:0",
+ StreamString host_and_port;
+ if (hostname.empty())
+ hostname = "localhost";
+ host_and_port.Printf("%s:%u", hostname.c_str(), port);
+ const char *host_and_port_cstr = host_and_port.GetString().c_str();
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr);
+ error = StartDebugserverProcess (host_and_port_cstr,
unix_socket_name,
debugserver_launch_info);
lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
+
+ if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ m_spawned_pids.insert(debugserver_pid);
+ }
+ Host::StartMonitoringChildProcess (ReapDebugserverProcess, this, debugserver_pid, false);
+ }
+
if (error.Success())
{
bool success = false;
- thread_result_t accept_thread_result = NULL;
- if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error))
+ if (accept_thread)
{
- if (accept_thread_result)
+ thread_result_t accept_thread_result = NULL;
+ if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error))
{
- uint16_t port = (intptr_t)accept_thread_result;
- char response[256];
- const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port);
- assert (response_len < (int)sizeof(response));
- //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
- success = SendPacketNoLock (response, response_len) > 0;
+ if (accept_thread_result)
+ {
+ port = (intptr_t)accept_thread_result;
+ char response[256];
+ const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port);
+ assert (response_len < sizeof(response));
+ //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
+ success = SendPacketNoLock (response, response_len) > 0;
+ }
}
}
+ else
+ {
+ char response[256];
+ const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port);
+ assert (response_len < sizeof(response));
+ //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
+ success = SendPacketNoLock (response, response_len) > 0;
+
+ }
::unlink (unix_socket_name);
if (!success)
@@ -734,11 +863,64 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote
}
}
}
- return SendErrorResponse (13);
+ return SendErrorResponse (9);
#endif
}
bool
+GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
+{
+ // Spawn a local debugserver as a platform so we can then attach or launch
+ // a process...
+
+ if (m_is_platform)
+ {
+ packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
+
+ lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
+
+ // Scope for locker
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return SendErrorResponse (10);
+ }
+ kill (pid, SIGTERM);
+
+ for (size_t i=0; i<10; ++i)
+ {
+ // Scope for locker
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return true;
+ }
+ usleep (10000);
+ }
+
+ // Scope for locker
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return true;
+ }
+ kill (pid, SIGKILL);
+
+ for (size_t i=0; i<10; ++i)
+ {
+ // Scope for locker
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return true;
+ }
+ usleep (10000);
+ }
+ }
+ return SendErrorResponse (10);
+}
+
+bool
GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet)
{
if (m_process_launch_error.Success())
@@ -759,7 +941,22 @@ GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &pa
m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek());
return SendOKResponse ();
}
- return SendErrorResponse (9);
+ return SendErrorResponse (11);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QLaunchArch:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0)
+ {
+ const char* arch_triple = packet.Peek();
+ ArchSpec arch_spec(arch_triple,NULL);
+ m_process_launch_info.SetArchitecture(arch_spec);
+ return SendOKResponse();
+ }
+ return SendErrorResponse(12);
}
bool
@@ -797,7 +994,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet
m_process_launch_info.AppendFileAction(file_action);
return SendOKResponse ();
}
- return SendErrorResponse (10);
+ return SendErrorResponse (13);
}
bool
@@ -814,7 +1011,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packe
m_process_launch_info.AppendFileAction(file_action);
return SendOKResponse ();
}
- return SendErrorResponse (11);
+ return SendErrorResponse (14);
}
bool
@@ -831,7 +1028,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packe
m_process_launch_info.AppendFileAction(file_action);
return SendOKResponse ();
}
- return SendErrorResponse (12);
+ return SendErrorResponse (15);
}
bool
@@ -842,3 +1039,265 @@ GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &
m_send_acks = false;
return true;
}
+
+bool
+GDBRemoteCommunicationServer::Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("qPlatform_IO_MkDir:"));
+ mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
+ if (packet.GetChar() != ',')
+ return false;
+ std::string path;
+ packet.GetHexByteString(path);
+ uint32_t retcode = Host::MakeDirectory(path.c_str(),mode);
+ StreamString response;
+ response.PutHex32(retcode);
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:open:"));
+ std::string path;
+ packet.GetHexByteStringTerminatedBy(path,',');
+ if (path.size() == 0)
+ return false;
+ if (packet.GetChar() != ',')
+ return false;
+ uint32_t flags = packet.GetHexMaxU32(false, UINT32_MAX);
+ if (packet.GetChar() != ',')
+ return false;
+ mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
+ Error error;
+ int fd = ::open (path.c_str(), flags, mode);
+ const int save_errno = fd == -1 ? errno : 0;
+ StreamString response;
+ response.PutChar('F');
+ response.Printf("%i", fd);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:close:"));
+ int fd = packet.GetS32(-1);
+ Error error;
+ int err = -1;
+ int save_errno = 0;
+ if (fd >= 0)
+ {
+ err = close(fd);
+ save_errno = err == -1 ? errno : 0;
+ }
+ else
+ {
+ save_errno = EINVAL;
+ }
+ StreamString response;
+ response.PutChar('F');
+ response.Printf("%i", err);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &packet)
+{
+ StreamGDBRemote response;
+ packet.SetFilePos(::strlen("vFile:pread:"));
+ int fd = packet.GetS32(-1);
+ if (packet.GetChar() != ',')
+ return false;
+ uint64_t count = packet.GetU64(UINT64_MAX);
+ if (packet.GetChar() != ',')
+ return false;
+ uint64_t offset = packet.GetU64(UINT32_MAX);
+ if (count == UINT64_MAX)
+ {
+ response.Printf("F-1:%i", EINVAL);
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+ }
+ std::string buffer(count, 0);
+ const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset);
+ const int save_errno = bytes_read == -1 ? errno : 0;
+ response.PutChar('F');
+ response.Printf("%zi", bytes_read);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ else
+ {
+ response.PutChar(';');
+ response.PutEscapedBytes(&buffer[0], bytes_read);
+ }
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:pwrite:"));
+
+ StreamGDBRemote response;
+ response.PutChar('F');
+
+ int fd = packet.GetU32(UINT32_MAX);
+ if (packet.GetChar() != ',')
+ return false;
+ off_t offset = packet.GetU64(UINT32_MAX);
+ if (packet.GetChar() != ',')
+ return false;
+ std::string buffer;
+ if (packet.GetEscapedBinaryData(buffer))
+ {
+ const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset);
+ const int save_errno = bytes_written == -1 ? errno : 0;
+ response.Printf("%zi", bytes_written);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ }
+ else
+ {
+ response.Printf ("-1,%i", EINVAL);
+ }
+
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:size:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (path.empty())
+ return false;
+ lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false));
+ StreamString response;
+ response.PutChar('F');
+ response.PutHex64(retcode);
+ if (retcode == UINT64_MAX)
+ {
+ response.PutChar(',');
+ response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode()
+ }
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:mode:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (path.empty())
+ return false;
+ Error error;
+ const uint32_t mode = File::GetPermissions(path.c_str(), error);
+ StreamString response;
+ response.Printf("F%u", mode);
+ if (mode == 0 || error.Fail())
+ response.Printf(",%i", (int)error.GetError());
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:exists:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (path.empty())
+ return false;
+ bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false));
+ StreamString response;
+ response.PutChar('F');
+ response.PutChar(',');
+ if (retcode)
+ response.PutChar('1');
+ else
+ response.PutChar('0');
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("qPlatform_RunCommand:"));
+ std::string path;
+ std::string working_dir;
+ packet.GetHexByteStringTerminatedBy(path,',');
+ if (path.size() == 0)
+ return false;
+ if (packet.GetChar() != ',')
+ return false;
+ uint32_t timeout = packet.GetHexMaxU32(false, 32);
+ if (packet.GetChar() == ',')
+ packet.GetHexByteString(working_dir);
+ int status, signo;
+ std::string output;
+ Error err = Host::RunShellCommand(path.c_str(),
+ working_dir.empty() ? NULL : working_dir.c_str(),
+ &status, &signo, &output, timeout);
+ StreamGDBRemote response;
+ if (err.Fail())
+ {
+ response.PutCString("F,");
+ response.PutHex32(UINT32_MAX);
+ }
+ else
+ {
+ response.PutCString("F,");
+ response.PutHex32(status);
+ response.PutChar(',');
+ response.PutHex32(signo);
+ response.PutChar(',');
+ response.PutEscapedBytes(output.c_str(), output.size());
+ }
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet)
+{
+ return false;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:exists:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (path.size() == 0)
+ return false;
+ uint64_t a,b;
+ StreamGDBRemote response;
+ if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false)
+ {
+ response.PutCString("F,");
+ response.PutCString("x");
+ }
+ else
+ {
+ response.PutCString("F,");
+ response.PutHex64(a);
+ response.PutHex64(b);
+ }
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
index cce0e4e64c1..64f6f8de1a2 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
@@ -12,10 +12,12 @@
// C Includes
// C++ Includes
+#include <vector>
+#include <set>
// Other libraries and framework includes
// Project includes
+#include "lldb/Host/Mutex.h"
#include "lldb/Target/Process.h"
-
#include "GDBRemoteCommunication.h"
class ProcessGDBRemote;
@@ -60,6 +62,21 @@ public:
{
m_lo_port_num = lo_port_num;
m_hi_port_num = hi_port_num;
+ m_next_port = m_lo_port_num;
+ m_use_port_range = true;
+ }
+
+ // If we are using a port range, get and update the next port to be used variable.
+ // Otherwise, just return 0.
+ uint16_t
+ GetAndUpdateNextPort ()
+ {
+ if (!m_use_port_range)
+ return 0;
+ uint16_t val = m_next_port;
+ if (++m_next_port > m_hi_port_num)
+ m_next_port = m_lo_port_num;
+ return val;
}
protected:
@@ -68,11 +85,16 @@ protected:
lldb::thread_t m_async_thread;
lldb_private::ProcessLaunchInfo m_process_launch_info;
lldb_private::Error m_process_launch_error;
+ std::set<lldb::pid_t> m_spawned_pids;
+ lldb_private::Mutex m_spawned_pids_mutex;
lldb_private::ProcessInstanceInfoList m_proc_infos;
uint32_t m_proc_infos_index;
uint16_t m_lo_port_num;
uint16_t m_hi_port_num;
//PortToPIDMap m_port_to_pid_map;
+ uint16_t m_next_port;
+ bool m_use_port_range;
+
size_t
SendUnimplementedResponse (const char *packet);
@@ -85,7 +107,7 @@ protected:
bool
Handle_A (StringExtractorGDBRemote &packet);
-
+
bool
Handle_qLaunchSuccess (StringExtractorGDBRemote &packet);
@@ -94,8 +116,14 @@ protected:
bool
Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet);
bool
+ Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet);
+
+ bool
Handle_qProcessInfoPID (StringExtractorGDBRemote &packet);
bool
@@ -120,6 +148,9 @@ protected:
Handle_QEnvironment (StringExtractorGDBRemote &packet);
bool
+ Handle_QLaunchArch (StringExtractorGDBRemote &packet);
+
+ bool
Handle_QSetDisableASLR (StringExtractorGDBRemote &packet);
bool
@@ -137,7 +168,47 @@ protected:
bool
Handle_QSetSTDERR (StringExtractorGDBRemote &packet);
+ bool
+ Handle_vFile_Open (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_Close (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_pRead (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_pWrite (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_Size (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_Mode (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_Exists (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_Stat (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_MD5 (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet);
+
private:
+ bool
+ DebugserverProcessReaped (lldb::pid_t pid);
+
+ static bool
+ ReapDebugserverProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal,
+ int status);
+
//------------------------------------------------------------------
// For GDBRemoteCommunicationServer only
//------------------------------------------------------------------
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index e6d3bc7a55d..eaedbffe6f1 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -22,6 +22,7 @@
#include "lldb/Host/Host.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Utils.h"
using namespace lldb;
using namespace lldb_private;
@@ -247,7 +248,13 @@ Platform::Platform (bool is_host) :
m_uid_map(),
m_gid_map(),
m_max_uid_name_len (0),
- m_max_gid_name_len (0)
+ m_max_gid_name_len (0),
+ m_supports_rsync (false),
+ m_rsync_opts (),
+ m_rsync_prefix (),
+ m_supports_ssh (false),
+ m_ssh_opts (),
+ m_ignores_remote_hostname (false)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
@@ -311,6 +318,14 @@ Platform::GetStatus (Stream &strm)
strm.Printf(" Hostname: %s\n", GetHostname());
strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no");
}
+
+ if (!IsConnected())
+ return;
+
+ std::string specific_info(GetPlatformSpecificConnectionInformation());
+
+ if (specific_info.empty() == false)
+ strm.Printf("Platform-specific connection: %s\n", specific_info.c_str());
}
@@ -760,9 +775,161 @@ Platform::IsCompatibleArchitecture (const ArchSpec &arch, bool exact_arch_match,
if (compatible_arch_ptr)
compatible_arch_ptr->Clear();
return false;
+}
+
+uint32_t
+Platform::MakeDirectory (const FileSpec &spec,
+ mode_t mode)
+{
+ std::string path(spec.GetPath());
+ return this->MakeDirectory(path,mode);
+}
+
+Error
+Platform::PutFile (const FileSpec& source,
+ const FileSpec& destination,
+ uint32_t uid,
+ uint32_t gid)
+{
+ Error error("unimplemented");
+ return error;
+}
+
+Error
+Platform::GetFile (const FileSpec& source,
+ const FileSpec& destination)
+{
+ Error error("unimplemented");
+ return error;
+}
+
+bool
+Platform::GetFileExists (const lldb_private::FileSpec& file_spec)
+{
+ return false;
+}
+
+lldb_private::Error
+Platform::RunShellCommand (const char *command, // Shouldn't be NULL
+ const char *working_dir, // Pass NULL to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish
+{
+ if (IsHost())
+ return Host::RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
+ else
+ return Error("unimplemented");
+}
+
+
+bool
+Platform::CalculateMD5 (const FileSpec& file_spec,
+ uint64_t &low,
+ uint64_t &high)
+{
+ if (IsHost())
+ return Host::CalculateMD5(file_spec, low, high);
+ else
+ return false;
+}
+
+void
+Platform::SetLocalCacheDirectory (const char* local)
+{
+ m_local_cache_directory.assign(local);
+}
+
+const char*
+Platform::GetLocalCacheDirectory ()
+{
+ return m_local_cache_directory.c_str();
+}
+
+static OptionDefinition
+g_rsync_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "rsync" , 'r', no_argument, NULL, 0, eArgTypeNone , "Enable rsync." },
+ { LLDB_OPT_SET_ALL, false, "rsync-opts" , 'R', required_argument, NULL, 0, eArgTypeCommandName , "Platform-specific options required for rsync to work." },
+ { LLDB_OPT_SET_ALL, false, "rsync-prefix" , 'P', required_argument, NULL, 0, eArgTypeCommandName , "Platform-specific rsync prefix put before the remote path." },
+ { LLDB_OPT_SET_ALL, false, "ignore-remote-hostname" , 'i', no_argument, NULL, 0, eArgTypeNone , "Do not automatically fill in the remote hostname when composing the rsync command." },
+};
+
+static OptionDefinition
+g_ssh_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "ssh" , 's', no_argument, NULL, 0, eArgTypeNone , "Enable SSH." },
+ { LLDB_OPT_SET_ALL, false, "ssh-opts" , 'S', required_argument, NULL, 0, eArgTypeCommandName , "Platform-specific options required for SSH to work." },
+};
+
+static OptionDefinition
+g_caching_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "local-cache-dir" , 'c', required_argument, NULL, 0, eArgTypePath , "Path in which to store local copies of files." },
+};
+
+OptionGroupPlatformRSync::OptionGroupPlatformRSync ()
+{
+}
+
+OptionGroupPlatformRSync::~OptionGroupPlatformRSync ()
+{
+}
+
+const lldb_private::OptionDefinition*
+OptionGroupPlatformRSync::GetDefinitions ()
+{
+ return g_rsync_option_table;
+}
+
+void
+OptionGroupPlatformRSync::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ m_rsync = false;
+ m_rsync_opts.clear();
+ m_rsync_prefix.clear();
+ m_ignores_remote_hostname = false;
+}
+
+lldb_private::Error
+OptionGroupPlatformRSync::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error;
+ char short_option = (char) GetDefinitions()[option_idx].short_option;
+ switch (short_option)
+ {
+ case 'r':
+ m_rsync = true;
+ break;
+
+ case 'R':
+ m_rsync_opts.assign(option_arg);
+ break;
+
+ case 'P':
+ m_rsync_prefix.assign(option_arg);
+ break;
+
+ case 'i':
+ m_ignores_remote_hostname = true;
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+ return error;
}
+uint32_t
+OptionGroupPlatformRSync::GetNumDefinitions ()
+{
+ return llvm::array_lengthof(g_rsync_option_table);
+}
lldb::BreakpointSP
Platform::SetThreadCreationBreakpoint (lldb_private::Target &target)
@@ -770,10 +937,108 @@ Platform::SetThreadCreationBreakpoint (lldb_private::Target &target)
return lldb::BreakpointSP();
}
+OptionGroupPlatformSSH::OptionGroupPlatformSSH ()
+{
+}
+
+OptionGroupPlatformSSH::~OptionGroupPlatformSSH ()
+{
+}
+
+const lldb_private::OptionDefinition*
+OptionGroupPlatformSSH::GetDefinitions ()
+{
+ return g_ssh_option_table;
+}
+
+void
+OptionGroupPlatformSSH::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ m_ssh = false;
+ m_ssh_opts.clear();
+}
+
+lldb_private::Error
+OptionGroupPlatformSSH::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error;
+ char short_option = (char) GetDefinitions()[option_idx].short_option;
+ switch (short_option)
+ {
+ case 's':
+ m_ssh = true;
+ break;
+
+ case 'S':
+ m_ssh_opts.assign(option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+uint32_t
+OptionGroupPlatformSSH::GetNumDefinitions ()
+{
+ return llvm::array_lengthof(g_ssh_option_table);
+}
+
+OptionGroupPlatformCaching::OptionGroupPlatformCaching ()
+{
+}
+
+OptionGroupPlatformCaching::~OptionGroupPlatformCaching ()
+{
+}
+
+const lldb_private::OptionDefinition*
+OptionGroupPlatformCaching::GetDefinitions ()
+{
+ return g_caching_option_table;
+}
+
+void
+OptionGroupPlatformCaching::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ m_cache_dir.clear();
+}
+
+lldb_private::Error
+OptionGroupPlatformCaching::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error;
+ char short_option = (char) GetDefinitions()[option_idx].short_option;
+ switch (short_option)
+ {
+ case 'c':
+ m_cache_dir.assign(option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+uint32_t
+OptionGroupPlatformCaching::GetNumDefinitions ()
+{
+ return llvm::array_lengthof(g_caching_option_table);
+}
+
size_t
Platform::GetEnvironment (StringList &environment)
{
environment.Clear();
return false;
}
-
diff --git a/lldb/source/Utility/StringExtractor.cpp b/lldb/source/Utility/StringExtractor.cpp
index 2f4bcecda8f..d4ce470d56f 100644
--- a/lldb/source/Utility/StringExtractor.cpp
+++ b/lldb/source/Utility/StringExtractor.cpp
@@ -168,10 +168,68 @@ StringExtractor::GetU32 (uint32_t fail_value, int base)
{
char *end = NULL;
const char *start = m_packet.c_str();
- const char *uint_cstr = start + m_index;
- uint32_t result = ::strtoul (uint_cstr, &end, base);
+ const char *cstr = start + m_index;
+ uint32_t result = ::strtoul (cstr, &end, base);
- if (end && end != uint_cstr)
+ if (end && end != cstr)
+ {
+ m_index = end - start;
+ return result;
+ }
+ }
+ return fail_value;
+}
+
+int32_t
+StringExtractor::GetS32 (int32_t fail_value, int base)
+{
+ if (m_index < m_packet.size())
+ {
+ char *end = NULL;
+ const char *start = m_packet.c_str();
+ const char *cstr = start + m_index;
+ int32_t result = ::strtol (cstr, &end, base);
+
+ if (end && end != cstr)
+ {
+ m_index = end - start;
+ return result;
+ }
+ }
+ return fail_value;
+}
+
+
+uint64_t
+StringExtractor::GetU64 (uint64_t fail_value, int base)
+{
+ if (m_index < m_packet.size())
+ {
+ char *end = NULL;
+ const char *start = m_packet.c_str();
+ const char *cstr = start + m_index;
+ uint64_t result = ::strtoull (cstr, &end, base);
+
+ if (end && end != cstr)
+ {
+ m_index = end - start;
+ return result;
+ }
+ }
+ return fail_value;
+}
+
+int64_t
+StringExtractor::GetS64 (int64_t fail_value, int base)
+{
+ if (m_index < m_packet.size())
+ {
+ char *end = NULL;
+ const char *start = m_packet.c_str();
+ const char *cstr = start + m_index;
+ int64_t result = ::strtoll (cstr, &end, base);
+
+ if (end && end != cstr)
{
m_index = end - start;
return result;
@@ -371,6 +429,20 @@ StringExtractor::GetHexByteString (std::string &str)
return str.size();
}
+size_t
+StringExtractor::GetHexByteStringTerminatedBy (std::string &str,
+ char terminator)
+{
+ str.clear();
+ char ch;
+ while ((ch = GetHexU8(0,false)) != '\0')
+ str.append(1, ch);
+ if (Peek() && *Peek() == terminator)
+ return str.size();
+ str.clear();
+ return str.size();
+}
+
bool
StringExtractor::GetNameColonValue (std::string &name, std::string &value)
{
diff --git a/lldb/source/Utility/StringExtractor.h b/lldb/source/Utility/StringExtractor.h
index 0ded3101fcc..2aab3b09f47 100644
--- a/lldb/source/Utility/StringExtractor.h
+++ b/lldb/source/Utility/StringExtractor.h
@@ -101,9 +101,18 @@ public:
bool
GetNameColonValue (std::string &name, std::string &value);
+ int32_t
+ GetS32 (int32_t fail_value, int base = 0);
+
uint32_t
GetU32 (uint32_t fail_value, int base = 0);
+ int64_t
+ GetS64 (int64_t fail_value, int base = 0);
+
+ uint64_t
+ GetU64 (uint64_t fail_value, int base = 0);
+
uint32_t
GetHexMaxU32 (bool little_endian, uint32_t fail_value);
@@ -119,6 +128,10 @@ public:
size_t
GetHexByteString (std::string &str);
+ size_t
+ GetHexByteStringTerminatedBy (std::string &str,
+ char terminator);
+
const char *
Peek ()
{
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp
index 7e06a0f59bc..6e32481ccc5 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -94,6 +94,9 @@ StringExtractorGDBRemote::GetServerPacketType () const
else if (PACKET_STARTS_WITH ("QSetSTDERR:")) return eServerPacketType_QSetSTDERR;
else if (PACKET_STARTS_WITH ("QSetWorkingDir:")) return eServerPacketType_QSetWorkingDir;
break;
+ case 'L':
+ if (PACKET_STARTS_WITH ("QLaunchArch:")) return eServerPacketType_QLaunchArch;
+ break;
}
break;
@@ -120,14 +123,21 @@ StringExtractorGDBRemote::GetServerPacketType () const
if (PACKET_MATCHES ("qHostInfo")) return eServerPacketType_qHostInfo;
break;
+ case 'K':
+ if (PACKET_STARTS_WITH ("qKillSpawnedProcess")) return eServerPacketType_qKillSpawnedProcess;
+ break;
+
case 'L':
- if (PACKET_MATCHES ("qLaunchGDBServer")) return eServerPacketType_qLaunchGDBServer;
+ if (PACKET_STARTS_WITH ("qLaunchGDBServer")) return eServerPacketType_qLaunchGDBServer;
if (PACKET_MATCHES ("qLaunchSuccess")) return eServerPacketType_qLaunchSuccess;
break;
case 'P':
- if (PACKET_STARTS_WITH ("qProcessInfoPID:")) return eServerPacketType_qProcessInfoPID;
+ if (PACKET_STARTS_WITH ("qProcessInfoPID:")) return eServerPacketType_qProcessInfoPID;
+ if (PACKET_STARTS_WITH ("qPlatform_RunCommand:")) return eServerPacketType_qPlatform_RunCommand;
+ if (PACKET_STARTS_WITH ("qPlatform_IO_MkDir:")) return eServerPacketType_qPlatform_IO_MkDir;
break;
+
case 'S':
if (PACKET_STARTS_WITH ("qSpeedTest:")) return eServerPacketType_qSpeedTest;
@@ -138,6 +148,21 @@ StringExtractorGDBRemote::GetServerPacketType () const
break;
}
break;
+ case 'v':
+ if (PACKET_STARTS_WITH("vFile:"))
+ {
+ if (PACKET_STARTS_WITH("vFile:open:")) return eServerPacketType_vFile_Open;
+ else if (PACKET_STARTS_WITH("vFile:close:")) return eServerPacketType_vFile_Close;
+ else if (PACKET_STARTS_WITH("vFile:pread")) return eServerPacketType_vFile_pRead;
+ else if (PACKET_STARTS_WITH("vFile:pwrite")) return eServerPacketType_vFile_pWrite;
+ else if (PACKET_STARTS_WITH("vFile:size")) return eServerPacketType_vFile_Size;
+ else if (PACKET_STARTS_WITH("vFile:exists")) return eServerPacketType_vFile_Exists;
+ else if (PACKET_STARTS_WITH("vFile:stat")) return eServerPacketType_vFile_Stat;
+ else if (PACKET_STARTS_WITH("vFile:mode")) return eServerPacketType_vFile_Mode;
+ else if (PACKET_STARTS_WITH("vFile:MD5")) return eServerPacketType_vFile_MD5;
+
+ }
+ break;
}
return eServerPacketType_unimplemented;
}
@@ -180,3 +205,19 @@ StringExtractorGDBRemote::GetError ()
}
return 0;
}
+
+size_t
+StringExtractorGDBRemote::GetEscapedBinaryData (std::string &str)
+{
+ str.clear();
+ char ch;
+ while (GetBytesLeft())
+ {
+ ch = GetChar();
+ if (ch == 0x7d)
+ ch = (GetChar() ^ 0x20);
+ str.append(1,ch);
+ }
+ return str.size();
+}
+
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.h b/lldb/source/Utility/StringExtractorGDBRemote.h
index 5a24d894b10..fe500ecda5d 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.h
+++ b/lldb/source/Utility/StringExtractorGDBRemote.h
@@ -53,17 +53,30 @@ public:
eServerPacketType_qGroupName,
eServerPacketType_qHostInfo,
eServerPacketType_qLaunchGDBServer,
+ eServerPacketType_qKillSpawnedProcess,
eServerPacketType_qLaunchSuccess,
eServerPacketType_qProcessInfoPID,
eServerPacketType_qSpeedTest,
eServerPacketType_qUserName,
eServerPacketType_QEnvironment,
+ eServerPacketType_QLaunchArch,
eServerPacketType_QSetDisableASLR,
eServerPacketType_QSetSTDIN,
eServerPacketType_QSetSTDOUT,
eServerPacketType_QSetSTDERR,
eServerPacketType_QSetWorkingDir,
- eServerPacketType_QStartNoAckMode
+ eServerPacketType_QStartNoAckMode,
+ eServerPacketType_qPlatform_RunCommand,
+ eServerPacketType_qPlatform_IO_MkDir,
+ eServerPacketType_vFile_Open,
+ eServerPacketType_vFile_Close,
+ eServerPacketType_vFile_pRead,
+ eServerPacketType_vFile_pWrite,
+ eServerPacketType_vFile_Size,
+ eServerPacketType_vFile_Mode,
+ eServerPacketType_vFile_Exists,
+ eServerPacketType_vFile_MD5,
+ eServerPacketType_vFile_Stat
};
ServerPacketType
@@ -98,6 +111,10 @@ public:
// digits. Otherwise the error encoded in XX is returned.
uint8_t
GetError();
+
+ size_t
+ GetEscapedBinaryData (std::string &str);
+
};
#endif // utility_StringExtractorGDBRemote_h_
diff --git a/lldb/source/lldb-log.cpp b/lldb/source/lldb-log.cpp
index c53fa56ef01..78355a8eefa 100644
--- a/lldb/source/lldb-log.cpp
+++ b/lldb/source/lldb-log.cpp
@@ -126,6 +126,7 @@ lldb_private::DisableLog (const char **categories, Stream *feedback_strm)
else if (0 == ::strncasecmp(arg, "expr", 4)) flag_bits &= ~LIBLLDB_LOG_EXPRESSIONS;
else if (0 == ::strncasecmp(arg, "object", 6)) flag_bits &= ~LIBLLDB_LOG_OBJECT;
else if (0 == ::strcasecmp(arg, "process")) flag_bits &= ~LIBLLDB_LOG_PROCESS;
+ else if (0 == ::strcasecmp(arg, "platform")) flag_bits &= ~LIBLLDB_LOG_PLATFORM;
else if (0 == ::strcasecmp(arg, "script")) flag_bits &= ~LIBLLDB_LOG_SCRIPT;
else if (0 == ::strcasecmp(arg, "state")) flag_bits &= ~LIBLLDB_LOG_STATE;
else if (0 == ::strcasecmp(arg, "step")) flag_bits &= ~LIBLLDB_LOG_STEP;
@@ -196,6 +197,7 @@ lldb_private::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const ch
else if (0 == ::strncasecmp(arg, "expr", 4)) flag_bits |= LIBLLDB_LOG_EXPRESSIONS;
else if (0 == ::strncasecmp(arg, "object", 6)) flag_bits |= LIBLLDB_LOG_OBJECT;
else if (0 == ::strcasecmp(arg, "process")) flag_bits |= LIBLLDB_LOG_PROCESS;
+ else if (0 == ::strcasecmp(arg, "platform")) flag_bits |= LIBLLDB_LOG_PLATFORM;
else if (0 == ::strcasecmp(arg, "script")) flag_bits |= LIBLLDB_LOG_SCRIPT;
else if (0 == ::strcasecmp(arg, "state")) flag_bits |= LIBLLDB_LOG_STATE;
else if (0 == ::strcasecmp(arg, "step")) flag_bits |= LIBLLDB_LOG_STEP;
@@ -244,6 +246,7 @@ lldb_private::ListLogCategories (Stream *strm)
" object - log object construction/destruction for important objects\n"
" module - log module activities such as when modules are created, detroyed, replaced, and more\n"
" process - log process events and activities\n"
+ " platform - log platform events and activities\n"
" script - log events about the script interpreter\n"
" state - log private and public process state changes\n"
" step - log step related activities\n"
diff --git a/lldb/source/lldb.cpp b/lldb/source/lldb.cpp
index 1ac03f4f190..aefa5516637 100644
--- a/lldb/source/lldb.cpp
+++ b/lldb/source/lldb.cpp
@@ -42,6 +42,7 @@
#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
#include "Plugins/Platform/FreeBSD/PlatformFreeBSD.h"
#include "Plugins/Platform/Linux/PlatformLinux.h"
+#include "Plugins/Platform/POSIX/PlatformPOSIX.h"
#include "Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h"
#ifndef LLDB_DISABLE_PYTHON
#include "Plugins/OperatingSystem/Python/OperatingSystemPython.h"
diff --git a/lldb/test/api/check_public_api_headers/TestPublicAPIHeaders.py b/lldb/test/api/check_public_api_headers/TestPublicAPIHeaders.py
index 9df567c3f3a..63618e05c36 100644
--- a/lldb/test/api/check_public_api_headers/TestPublicAPIHeaders.py
+++ b/lldb/test/api/check_public_api_headers/TestPublicAPIHeaders.py
@@ -22,6 +22,9 @@ class SBDirCheckerCase(TestBase):
def test_sb_api_directory(self):
"""Test the SB API directory and make sure there's no unwanted stuff."""
+ # Only proceed if this is "darwin", "x86_64", and local platform.
+ if not (sys.platform.startswith("darwin") and self.getArchitecture() == "x86_64" and not lldb.test_remote):
+ self.skipTest("This test is only for LLDB.framework built 64-bit and !lldb.test_remote")
if self.getArchitecture() == "i386":
self.skipTest("LLDB is 64-bit and cannot be linked to 32-bit test program.")
diff --git a/lldb/test/api/multithreaded/TestMultithreaded.py b/lldb/test/api/multithreaded/TestMultithreaded.py
index bb5c26271e5..b8d74ef7655 100644
--- a/lldb/test/api/multithreaded/TestMultithreaded.py
+++ b/lldb/test/api/multithreaded/TestMultithreaded.py
@@ -61,12 +61,13 @@ class SBBreakpointCallbackCase(TestBase):
exe = [os.path.join(os.getcwd(), test_name), self.inferior]
+ env = {self.dylibPath : self.getLLDBLibraryEnvVal()}
if self.TraceOn():
print "Running test %s" % " ".join(exe)
-
- check_call(exe, env={self.dylibPath : self.getLLDBLibraryEnvVal()})
-
-
+ check_call(exe, env=env)
+ else:
+ with open(os.devnull, 'w') as fnull:
+ check_call(exe, env=env, stdout=fnull, stderr=fnull)
def build_program(self, sources, program):
return self.buildDriver(sources, program)
diff --git a/lldb/test/dotest.py b/lldb/test/dotest.py
index 4bc4dab2dd6..1c412f4c2fe 100755
--- a/lldb/test/dotest.py
+++ b/lldb/test/dotest.py
@@ -154,6 +154,9 @@ config = {}
# The pre_flight and post_flight functions come from reading a config file.
pre_flight = None
post_flight = None
+# So do the lldbtest_remote_sandbox and lldbtest_remote_shell_template variables.
+lldbtest_remote_sandbox = None
+lldbtest_remote_shell_template = None
# The 'archs' and 'compilers' can be specified via either command line or configFile,
# with the command line overriding the configFile. The corresponding options can be
@@ -745,11 +748,11 @@ def parseOptionsAndInitTestdirs():
# respectively.
#
# See also lldb-trunk/examples/test/usage-config.
- global config, pre_flight, post_flight
+ global config, pre_flight, post_flight, lldbtest_remote_sandbox, lldbtest_remote_shell_template
if configFile:
# Pass config (a dictionary) as the locals namespace for side-effect.
execfile(configFile, globals(), config)
- print "config:", config
+ #print "config:", config
if "pre_flight" in config:
pre_flight = config["pre_flight"]
if not callable(pre_flight):
@@ -760,6 +763,10 @@ def parseOptionsAndInitTestdirs():
if not callable(post_flight):
print "fatal error: post_flight is not callable, exiting."
sys.exit(1)
+ if "lldbtest_remote_sandbox" in config:
+ lldbtest_remote_sandbox = config["lldbtest_remote_sandbox"]
+ if "lldbtest_remote_shell_template" in config:
+ lldbtest_remote_shell_template = config["lldbtest_remote_shell_template"]
#print "sys.stderr:", sys.stderr
#print "sys.stdout:", sys.stdout
@@ -1199,6 +1206,17 @@ if not noHeaders:
print "lldb.pre_flight:", getsource_if_available(lldb.pre_flight)
print "lldb.post_flight:", getsource_if_available(lldb.post_flight)
+# If either pre_flight or post_flight is defined, set lldb.test_remote to True.
+if lldb.pre_flight or lldb.post_flight:
+ lldb.test_remote = True
+else:
+ lldb.test_remote = False
+
+# So do the lldbtest_remote_sandbox and lldbtest_remote_shell_template variables.
+lldb.lldbtest_remote_sandbox = lldbtest_remote_sandbox
+lldb.lldbtest_remote_sandboxed_executable = None
+lldb.lldbtest_remote_shell_template = lldbtest_remote_shell_template
+
# Put all these test decorators in the lldb namespace.
lldb.dont_do_python_api_test = dont_do_python_api_test
lldb.just_do_python_api_test = just_do_python_api_test
diff --git a/lldb/test/functionalities/abbreviation/TestAbbreviations.py b/lldb/test/functionalities/abbreviation/TestAbbreviations.py
index 4df8cbc006a..38b9005537a 100644
--- a/lldb/test/functionalities/abbreviation/TestAbbreviations.py
+++ b/lldb/test/functionalities/abbreviation/TestAbbreviations.py
@@ -90,7 +90,10 @@ class AbbreviationsTestCase(TestBase):
def running_abbreviations (self):
exe = os.path.join (os.getcwd(), "a.out")
- self.expect("fil " + exe,
+ # Use "file", i.e., no abbreviation. We're exactly matching the command
+ # verbatim when dealing with remote testsuite execution.
+ # For more details, see TestBase.runCmd().
+ self.expect("file " + exe,
patterns = [ "Current executable set to .*a.out.*" ])
# By default, the setting interpreter.expand-regex-aliases is false.
diff --git a/lldb/test/functionalities/conditional_break/.lldb b/lldb/test/functionalities/conditional_break/.lldb
index 52fc2ddd647..d077db551cb 100644
--- a/lldb/test/functionalities/conditional_break/.lldb
+++ b/lldb/test/functionalities/conditional_break/.lldb
@@ -1,4 +1,4 @@
-file a.out
+#file a.out
breakpoint set -n c
#script import sys, os
#script sys.path.append(os.path.join(os.getcwd(), os.pardir))
diff --git a/lldb/test/functionalities/conditional_break/TestConditionalBreak.py b/lldb/test/functionalities/conditional_break/TestConditionalBreak.py
index b9625cff09b..806cb436fd6 100644
--- a/lldb/test/functionalities/conditional_break/TestConditionalBreak.py
+++ b/lldb/test/functionalities/conditional_break/TestConditionalBreak.py
@@ -114,6 +114,10 @@ class ConditionalBreakTestCase(TestBase):
if not self.TraceOn():
self.HideStdout()
+
+ # Separate out the "file a.out" command from .lldb file, for the sake of
+ # remote testsuite.
+ self.runCmd("file a.out")
self.runCmd("command source .lldb")
self.runCmd ("break list")
diff --git a/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py b/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py
index dcab8c1a009..2d5f2965f02 100644
--- a/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py
+++ b/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py
@@ -447,7 +447,7 @@ class ObjCDataFormatterTestCase(TestBase):
self.expect('frame variable bundle_string bundle_url main_bundle',
substrs = ['(NSBundle *) bundle_string = ',' @"/System/Library/Frameworks/Accelerate.framework"',
'(NSBundle *) bundle_url = ',' @"/System/Library/Frameworks/Cocoa.framework"',
- '(NSBundle *) main_bundle = ','test/functionalities/data-formatter/data-formatter-objc'])
+ '(NSBundle *) main_bundle = ','data-formatter-objc'])
def nsexception_data_formatter_commands(self):
self.expect('frame variable except0 except1 except2 except3',
diff --git a/lldb/test/functionalities/inferior-changed/TestInferiorChanged.py b/lldb/test/functionalities/inferior-changed/TestInferiorChanged.py
index b51f4ca13de..58b9ffa7fd7 100644
--- a/lldb/test/functionalities/inferior-changed/TestInferiorChanged.py
+++ b/lldb/test/functionalities/inferior-changed/TestInferiorChanged.py
@@ -44,8 +44,8 @@ class ChangedInferiorTestCase(TestBase):
def inferior_crashing(self):
"""Inferior crashes upon launching; lldb should catch the event and stop."""
- exe = os.path.join(os.getcwd(), "a.out")
- self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+ self.exe = os.path.join(os.getcwd(), "a.out")
+ self.runCmd("file " + self.exe, CURRENT_EXECUTABLE_SET)
self.runCmd("run", RUN_SUCCEEDED)
@@ -67,6 +67,9 @@ class ChangedInferiorTestCase(TestBase):
def inferior_not_crashing(self):
"""Test lldb reloads the inferior after it was changed during the session."""
self.runCmd("process kill")
+ # Prod the lldb-platform that we have a newly built inferior ready.
+ if lldb.lldbtest_remote_sandbox:
+ self.runCmd("file " + self.exe, CURRENT_EXECUTABLE_SET)
self.runCmd("run", RUN_SUCCEEDED)
self.runCmd("process status")
diff --git a/lldb/test/functionalities/load_unload/TestLoadUnload.py b/lldb/test/functionalities/load_unload/TestLoadUnload.py
index 6fc1124a4f7..e6015a8cebe 100644
--- a/lldb/test/functionalities/load_unload/TestLoadUnload.py
+++ b/lldb/test/functionalities/load_unload/TestLoadUnload.py
@@ -27,6 +27,7 @@ class LoadUnloadTestCase(TestBase):
@skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
@skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
+ @not_remote_testsuite_ready
def test_modules_search_paths(self):
"""Test target modules list after loading a different copy of the library libd.dylib, and verifies that it works with 'target modules search-paths add'."""
@@ -81,6 +82,7 @@ class LoadUnloadTestCase(TestBase):
@skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
@skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
+ @not_remote_testsuite_ready
def test_dyld_library_path(self):
"""Test DYLD_LIBRARY_PATH after moving libd.dylib, which defines d_function, somewhere else."""
@@ -135,6 +137,7 @@ class LoadUnloadTestCase(TestBase):
substrs = [special_dir, os.path.basename(new_dylib)])
@skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
+ @not_remote_testsuite_ready
@skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
def test_lldb_process_load_and_unload_commands(self):
"""Test that lldb process load/unload command work correctly."""
@@ -183,6 +186,7 @@ class LoadUnloadTestCase(TestBase):
self.runCmd("process continue")
@skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
+ @not_remote_testsuite_ready
@skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
def test_load_unload(self):
"""Test breakpoint by name works correctly with dlopen'ing."""
@@ -224,6 +228,7 @@ class LoadUnloadTestCase(TestBase):
substrs = [' resolved, hit count = 2'])
@skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
+ @not_remote_testsuite_ready
@skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
def test_step_over_load (self):
"""Test stepping over code that loads a shared library works correctly."""
diff --git a/lldb/test/functionalities/process_launch/TestProcessLaunch.py b/lldb/test/functionalities/process_launch/TestProcessLaunch.py
index 82ab22f452e..e7f83d1818b 100644
--- a/lldb/test/functionalities/process_launch/TestProcessLaunch.py
+++ b/lldb/test/functionalities/process_launch/TestProcessLaunch.py
@@ -31,6 +31,7 @@ class ProcessLaunchTestCase(TestBase):
self.buildDwarf ()
self.process_io_test ()
+ @not_remote_testsuite_ready
def process_io_test (self):
"""Test that process launch I/O redirection flags work properly."""
exe = os.path.join (os.getcwd(), "a.out")
@@ -127,6 +128,7 @@ class ProcessLaunchTestCase(TestBase):
# rdar://problem/9056462
# The process launch flag '-w' for setting the current working directory not working?
+ @not_remote_testsuite_ready
def my_working_dir_test (self):
"""Test that '-w dir' sets the working dir when running the inferior."""
exe = os.path.join (os.getcwd(), "a.out")
diff --git a/lldb/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py b/lldb/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py
index bba5990cc1d..61541dc44e8 100644
--- a/lldb/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py
+++ b/lldb/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py
@@ -90,15 +90,13 @@ class HelloWatchLocationTestCase(TestBase):
# only once. The stop reason of the thread should be watchpoint.
self.expect("thread list", STOPPED_DUE_TO_WATCHPOINT,
substrs = ['stopped',
- 'stop reason = watchpoint %d' % expected_wp_id,
- self.violating_func])
+ 'stop reason = watchpoint %d' % expected_wp_id])
# Switch to the thread stopped due to watchpoint and issue some commands.
self.switch_to_thread_with_stop_reason(lldb.eStopReasonWatchpoint)
self.runCmd("thread backtrace")
- self.runCmd("expr unsigned val = *g_char_ptr; val")
- self.expect(self.res.GetOutput().splitlines()[0], exe=False,
- endstr = ' = 1')
+ self.expect("frame info",
+ substrs = [self.violating_func])
# Use the '-v' option to do verbose listing of the watchpoint.
# The hit count should now be 1.
diff --git a/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py b/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py
index 4a65baad5e4..4b4bdad2720 100644
--- a/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py
+++ b/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py
@@ -80,10 +80,11 @@ class HelloWatchpointTestCase(TestBase):
'stop reason = watchpoint'])
self.runCmd("process continue")
+
# Don't expect the read of 'global' to trigger a stop exception.
- # The process status should be 'exited'.
- self.expect("process status",
- substrs = ['exited'])
+ process = self.dbg.GetSelectedTarget().GetProcess()
+ if process.GetState() == lldb.eStateStopped:
+ self.assertFalse(lldbutil.get_stopped_thread(process, lldb.eStopReasonWatchpoint))
# Use the '-v' option to do verbose listing of the watchpoint.
# The hit count should now be 1.
diff --git a/lldb/test/lang/c/blocks/TestBlocks.py b/lldb/test/lang/c/blocks/TestBlocks.py
index 5cd5bd010d6..124f5f2ed5e 100644
--- a/lldb/test/lang/c/blocks/TestBlocks.py
+++ b/lldb/test/lang/c/blocks/TestBlocks.py
@@ -6,7 +6,7 @@ import lldb
from lldbtest import *
import lldbutil
-class AnonymousTestCase(TestBase):
+class BlocksTestCase(TestBase):
mydir = os.path.join("lang", "c", "blocks")
lines = []
diff --git a/lldb/test/lldbtest.py b/lldb/test/lldbtest.py
index c6fb79860a3..a696157427f 100644
--- a/lldb/test/lldbtest.py
+++ b/lldb/test/lldbtest.py
@@ -373,6 +373,23 @@ def dwarf_test(func):
wrapper.__dwarf_test__ = True
return wrapper
+def not_remote_testsuite_ready(func):
+ """Decorate the item as a test which is not ready yet for remote testsuite."""
+ if isinstance(func, type) and issubclass(func, unittest2.TestCase):
+ raise Exception("@not_remote_testsuite_ready can only be used to decorate a test method")
+ @wraps(func)
+ def wrapper(self, *args, **kwargs):
+ try:
+ if lldb.lldbtest_remote_sandbox:
+ self.skipTest("not ready for remote testsuite")
+ except AttributeError:
+ pass
+ return func(self, *args, **kwargs)
+
+ # Mark this function as such to separate them from the regular tests.
+ wrapper.__not_ready_for_remote_testsuite_test__ = True
+ return wrapper
+
def expectedFailureGcc(bugnumber=None, compiler_version=["=", None]):
if callable(bugnumber):
@wraps(bugnumber)
@@ -1556,6 +1573,31 @@ class TestBase(Base):
if not self.dbg:
raise Exception('Invalid debugger instance')
+ #
+ # Warning: MAJOR HACK AHEAD!
+ # If we are running testsuite remotely (by checking lldb.lldbtest_remote_sandbox),
+ # redefine the self.dbg.CreateTarget(filename) method to execute a "file filename"
+ # command, instead. See also runCmd() where it decorates the "file filename" call
+ # with additional functionality when running testsuite remotely.
+ #
+ if lldb.lldbtest_remote_sandbox:
+ def DecoratedCreateTarget(arg):
+ self.runCmd("file %s" % arg)
+ target = self.dbg.GetSelectedTarget()
+ #
+ # SBTarget.LaunchSimple() currently not working for remote platform?
+ # johnny @ 04/23/2012
+ #
+ def DecoratedLaunchSimple(argv, envp, wd):
+ self.runCmd("run")
+ return target.GetProcess()
+ target.LaunchSimple = DecoratedLaunchSimple
+
+ return target
+ self.dbg.CreateTarget = DecoratedCreateTarget
+ if self.TraceOn():
+ print "self.dbg.Create is redefined to:\n%s" % getsource_if_available(DecoratedCreateTarget)
+
# We want our debugger to be synchronous.
self.dbg.SetAsync(False)
@@ -1645,6 +1687,38 @@ class TestBase(Base):
trace = (True if traceAlways else trace)
+ # This is an opportunity to insert the 'platform target-install' command if we are told so
+ # via the settig of lldb.lldbtest_remote_sandbox.
+ if cmd.startswith("target create "):
+ cmd = cmd.replace("target create ", "file ")
+ if cmd.startswith("file ") and lldb.lldbtest_remote_sandbox:
+ with recording(self, trace) as sbuf:
+ the_rest = cmd.split("file ")[1]
+ # Split the rest of the command line.
+ atoms = the_rest.split()
+ #
+ # NOTE: This assumes that the options, if any, follow the file command,
+ # instead of follow the specified target.
+ #
+ target = atoms[-1]
+ # Now let's get the absolute pathname of our target.
+ abs_target = os.path.abspath(target)
+ print >> sbuf, "Found a file command, target (with absolute pathname)=%s" % abs_target
+ fpath, fname = os.path.split(abs_target)
+ parent_dir = os.path.split(fpath)[0]
+ platform_target_install_command = 'platform target-install %s %s' % (fpath, lldb.lldbtest_remote_sandbox)
+ print >> sbuf, "Insert this command to be run first: %s" % platform_target_install_command
+ self.ci.HandleCommand(platform_target_install_command, self.res)
+ # And this is the file command we want to execute, instead.
+ #
+ # Warning: SIDE EFFECT AHEAD!!!
+ # Populate the remote executable pathname into the lldb namespace,
+ # so that test cases can grab this thing out of the namespace.
+ #
+ lldb.lldbtest_remote_sandboxed_executable = abs_target.replace(parent_dir, lldb.lldbtest_remote_sandbox)
+ cmd = "file -P %s %s %s" % (lldb.lldbtest_remote_sandboxed_executable, the_rest.replace(target, ''), abs_target)
+ print >> sbuf, "And this is the replaced file command: %s" % cmd
+
running = (cmd.startswith("run") or cmd.startswith("process launch"))
for i in range(self.maxLaunchCount if running else 1):
diff --git a/lldb/test/macosx/universal/TestUniversal.py b/lldb/test/macosx/universal/TestUniversal.py
index 0a5cf9c1d02..59c21e11e60 100644
--- a/lldb/test/macosx/universal/TestUniversal.py
+++ b/lldb/test/macosx/universal/TestUniversal.py
@@ -35,7 +35,6 @@ class UniversalTestCase(TestBase):
process = target.LaunchSimple(None, None, os.getcwd())
self.assertTrue(process, PROCESS_IS_VALID)
- # rdar://problem/8972204 AddressByteSize of 32-bit process should be 4, got 8 instead.
@unittest2.skipUnless(sys.platform.startswith("darwin") and os.uname()[4] in ['i386', 'x86_64'],
"requires Darwin & i386")
def test_process_launch_for_universal(self):
@@ -74,7 +73,7 @@ class UniversalTestCase(TestBase):
self.runCmd("continue")
# Now specify i386 as the architecture for "testit".
- self.expect("file " + exe + " -a i386", CURRENT_EXECUTABLE_SET,
+ self.expect("file -a i386 " + exe, CURRENT_EXECUTABLE_SET,
startstr = "Current executable set to ",
substrs = ["testit' (i386)."])
diff --git a/lldb/test/python_api/hello_world/TestHelloWorld.py b/lldb/test/python_api/hello_world/TestHelloWorld.py
index d4fabbbb25d..d1e7d89114d 100644
--- a/lldb/test/python_api/hello_world/TestHelloWorld.py
+++ b/lldb/test/python_api/hello_world/TestHelloWorld.py
@@ -33,6 +33,7 @@ class HelloWorldTestCase(TestBase):
self.setTearDownCleanup(dictionary=self.d)
self.hello_world_python()
+ @not_remote_testsuite_ready
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
@python_api_test
@dsym_test
@@ -45,6 +46,7 @@ class HelloWorldTestCase(TestBase):
self.setTearDownCleanup(dictionary=self.d)
self.hello_world_attach_with_id_api()
+ @not_remote_testsuite_ready
@python_api_test
@dwarf_test
def test_with_dwarf_and_attach_to_process_with_id_api(self):
@@ -56,6 +58,7 @@ class HelloWorldTestCase(TestBase):
self.setTearDownCleanup(dictionary=self.d)
self.hello_world_attach_with_id_api()
+ @not_remote_testsuite_ready
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
@python_api_test
@dsym_test
@@ -69,6 +72,7 @@ class HelloWorldTestCase(TestBase):
self.hello_world_attach_with_name_api()
@expectedFailureFreeBSD('llvm.org/pr16699') # attach by name not on FreeBSD yet
+ @not_remote_testsuite_ready
@python_api_test
@dwarf_test
def test_with_dwarf_and_attach_to_process_with_name_api(self):
diff --git a/lldb/test/python_api/process/TestProcessAPI.py b/lldb/test/python_api/process/TestProcessAPI.py
index 1d8c9e16847..016fc1271cd 100644
--- a/lldb/test/python_api/process/TestProcessAPI.py
+++ b/lldb/test/python_api/process/TestProcessAPI.py
@@ -78,7 +78,6 @@ class ProcessAPITestCase(TestBase):
def read_memory(self):
"""Test Python SBProcess.ReadMemory() API."""
exe = os.path.join(os.getcwd(), "a.out")
- self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
@@ -160,7 +159,6 @@ class ProcessAPITestCase(TestBase):
def write_memory(self):
"""Test Python SBProcess.WriteMemory() API."""
exe = os.path.join(os.getcwd(), "a.out")
- self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
@@ -211,7 +209,6 @@ class ProcessAPITestCase(TestBase):
def access_my_int(self):
"""Test access 'my_int' using Python SBProcess.GetByteOrder() and other APIs."""
exe = os.path.join(os.getcwd(), "a.out")
- self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
@@ -300,7 +297,6 @@ class ProcessAPITestCase(TestBase):
def remote_launch_should_fail(self):
"""Test SBProcess.RemoteLaunch() API with a process not in eStateConnected, and it should fail."""
exe = os.path.join(os.getcwd(), "a.out")
- self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
diff --git a/lldb/test/python_api/target/TestTargetAPI.py b/lldb/test/python_api/target/TestTargetAPI.py
index 27dd3799709..8f2a6dee01b 100644
--- a/lldb/test/python_api/target/TestTargetAPI.py
+++ b/lldb/test/python_api/target/TestTargetAPI.py
@@ -195,7 +195,7 @@ class TargetAPITestCase(TestBase):
self.expect(desc, exe=False,
substrs = ['a.out', 'Target', 'Module', 'Breakpoint'])
-
+ @not_remote_testsuite_ready
def launch_new_process_and_redirect_stdout(self):
"""Exercise SBTaget.Launch() API with redirected stdout."""
exe = os.path.join(os.getcwd(), "a.out")
diff --git a/lldb/test/settings/TestSettings.py b/lldb/test/settings/TestSettings.py
index fe75afc6b3b..b3642c4eb1e 100644
--- a/lldb/test/settings/TestSettings.py
+++ b/lldb/test/settings/TestSettings.py
@@ -205,6 +205,7 @@ class SettingsCommandTestCase(TestBase):
self.buildDwarf()
self.pass_run_args_and_env_vars()
+ @not_remote_testsuite_ready
def pass_run_args_and_env_vars(self):
"""Test that run-args and env-vars are passed to the launched process."""
exe = os.path.join(os.getcwd(), "a.out")
@@ -231,6 +232,7 @@ class SettingsCommandTestCase(TestBase):
"argv[3] matches",
"Environment variable 'MY_ENV_VAR' successfully passed."])
+ @not_remote_testsuite_ready
def test_pass_host_env_vars(self):
"""Test that the host env vars are passed to the launched process."""
self.buildDefault()
@@ -262,6 +264,7 @@ class SettingsCommandTestCase(TestBase):
substrs = ["The host environment variable 'MY_HOST_ENV_VAR1' successfully passed.",
"The host environment variable 'MY_HOST_ENV_VAR2' successfully passed."])
+ @not_remote_testsuite_ready
def test_set_error_output_path(self):
"""Test that setting target.error/output-path for the launched process works."""
self.buildDefault()
diff --git a/lldb/tools/CMakeLists.txt b/lldb/tools/CMakeLists.txt
index 960ac22ea9c..b1989f81551 100644
--- a/lldb/tools/CMakeLists.txt
+++ b/lldb/tools/CMakeLists.txt
@@ -3,5 +3,5 @@ if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
endif()
if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
add_subdirectory(driver)
+ add_subdirectory(lldb-platform)
endif()
-
diff --git a/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj
index 90500c5e722..7354f62488e 100644
--- a/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj
+++ b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj
@@ -606,7 +606,7 @@
CLANG_CXX_LIBRARY = "libc++";
"CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "source/debugserver-entitlements.plist";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
- "CODE_SIGN_IDENTITY[sdk=macosx*]" = lldb_codesign;
+ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "";
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 310.99.0;
FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks;
diff --git a/lldb/tools/lldb-platform/CMakeLists.txt b/lldb/tools/lldb-platform/CMakeLists.txt
new file mode 100644
index 00000000000..97ccde10199
--- /dev/null
+++ b/lldb/tools/lldb-platform/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(LLVM_NO_RTTI 1)
+
+include_directories(../../source)
+
+add_lldb_executable(lldb-platform
+ lldb-platform.cpp
+ )
+
+target_link_libraries(lldb-platform liblldb)
+
+set_target_properties(lldb-platform PROPERTIES VERSION ${LLDB_VERSION})
+
+install(TARGETS lldb-platform
+ RUNTIME DESTINATION bin)
diff --git a/lldb/tools/lldb-platform/lldb-platform.cpp b/lldb/tools/lldb-platform/lldb-platform.cpp
index 112dc9ed04c..007e69c9281 100644
--- a/lldb/tools/lldb-platform/lldb-platform.cpp
+++ b/lldb/tools/lldb-platform/lldb-platform.cpp
@@ -37,11 +37,13 @@ using namespace lldb_private;
int g_debug = 0;
int g_verbose = 0;
+int g_stay_alive = 0;
static struct option g_long_options[] =
{
{ "debug", no_argument, &g_debug, 1 },
{ "verbose", no_argument, &g_verbose, 1 },
+ { "stay-alive", no_argument, &g_stay_alive, 1 },
{ "log-file", required_argument, NULL, 'l' },
{ "log-flags", required_argument, NULL, 'f' },
{ "listen", required_argument, NULL, 'L' },
@@ -60,16 +62,32 @@ signal_handler(int signo)
case SIGPIPE:
g_sigpipe_received = 1;
break;
+ case SIGHUP:
+ // Use SIGINT first, if that does not work, use SIGHUP as a last resort.
+ // And we should not call exit() here because it results in the global destructors
+ // to be invoked and wreaking havoc on the threads still running.
+ Host::SystemLog(Host::eSystemLogWarning, "SIGHUP received, exiting lldb-platform...\n");
+ abort();
+ break;
}
}
+static void
+display_usage (const char *progname)
+{
+ fprintf(stderr, "Usage:\n %s [--log-file log-file-path] [--log-flags flags] --listen port\n", progname);
+ exit(0);
+}
+
//----------------------------------------------------------------------
// main
//----------------------------------------------------------------------
int
main (int argc, char *argv[])
{
+ const char *progname = argv[0];
signal (SIGPIPE, signal_handler);
+ signal (SIGHUP, signal_handler);
int long_option_index = 0;
StreamSP log_stream_sp;
Args log_args;
@@ -167,8 +185,16 @@ main (int argc, char *argv[])
case 'L':
listen_host_port.append (optarg);
break;
+
+ case 'h': /* fall-through is intentional */
+ case '?':
+ display_usage(progname);
+ break;
}
}
+ // Print usage and exit if no listening port is specified.
+ if (listen_host_port.empty())
+ display_usage(progname);
if (log_stream_sp)
{
@@ -182,50 +208,63 @@ main (int argc, char *argv[])
argv += optind;
- GDBRemoteCommunicationServer gdb_server (true);
- if (!listen_host_port.empty())
- {
- std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
- if (conn_ap.get())
+ do {
+ GDBRemoteCommunicationServer gdb_server (true);
+ if (!listen_host_port.empty())
{
- std::string connect_url ("listen://");
- connect_url.append(listen_host_port.c_str());
-
- printf ("Listening for a connection on %s...\n", listen_host_port.c_str());
- if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
+ std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+ if (conn_ap.get())
{
- printf ("Connection established.\n");
- gdb_server.SetConnection (conn_ap.release());
- }
- }
- }
-
+ for (int j = 0; j < listen_host_port.size(); j++)
+ {
+ char c = listen_host_port[j];
+ if (c > '9' || c < '0')
+ printf("WARNING: passing anything but a number as argument to --listen will most probably make connecting impossible.\n");
+ }
+ std::auto_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+ if (conn_ap.get())
+ {
+ std::string connect_url ("listen://");
+ connect_url.append(listen_host_port.c_str());
- if (gdb_server.IsConnected())
- {
- // After we connected, we need to get an initial ack from...
- if (gdb_server.HandshakeWithClient(&error))
- {
- bool interrupt = false;
- bool done = false;
- while (!interrupt && !done)
- {
- if (!gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done))
- break;
+ printf ("Listening for a connection on %s...\n", listen_host_port.c_str());
+ if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
+ {
+ printf ("Connection established.\n");
+ gdb_server.SetConnection (conn_ap.release());
+ }
+ }
}
-
- if (error.Fail())
+
+ if (gdb_server.IsConnected())
{
- fprintf(stderr, "error: %s\n", error.AsCString());
+ // After we connected, we need to get an initial ack from...
+ if (gdb_server.HandshakeWithClient(&error))
+ {
+ bool interrupt = false;
+ bool done = false;
+ while (!interrupt && !done)
+ {
+ if (!gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done))
+ break;
+ }
+
+ if (error.Fail())
+ {
+ fprintf(stderr, "error: %s\n", error.AsCString());
+ }
+ }
+ else
+ {
+ fprintf(stderr, "error: handshake with client failed\n");
+ }
}
}
- else
- {
- fprintf(stderr, "error: handshake with client failed\n");
- }
- }
+ } while (g_stay_alive);
Debugger::Terminate();
+ fprintf(stderr, "lldb-platform exiting...\n");
+
return 0;
}
OpenPOWER on IntegriCloud