merge lldb-platform-work branch (and assorted fixes) into trunk

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

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

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

    Reviewers: Matt Kopec, Greg Clayton

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

llvm-svn: 189295
This commit is contained in:
Daniel Malea 2013-08-26 23:57:52 +00:00
parent 6b16b43ef9
commit e0f8f574c7
85 changed files with 5865 additions and 333 deletions

View File

@ -420,6 +420,20 @@ invalidate-regs
modifying the CPSR register can cause the r8 - r14 and cpsr value to
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"
//
@ -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
//----------------------------------------------------------------------

View File

@ -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_

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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) :

View File

@ -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);

View File

@ -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_

View File

@ -243,6 +243,12 @@ public:
return m_arch;
}
void
SetArchitecture (ArchSpec arch)
{
m_arch = arch;
}
lldb::pid_t
GetProcessID () const
{

View File

@ -406,6 +406,9 @@ namespace lldb {
eArgTypeOffset,
eArgTypeOldPathPrefix,
eArgTypeOneLiner,
eArgTypePath,
eArgTypePermissionsNumber,
eArgTypePermissionsString,
eArgTypePid,
eArgTypePlugin,
eArgTypeProcessName,

View File

@ -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;

View File

@ -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 |\

View File

@ -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

View File

@ -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",

View File

@ -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" {

View File

@ -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.

View File

@ -58,6 +58,7 @@ set( LLDB_USED_LIBS
lldbPluginPlatformGDB
lldbPluginPlatformFreeBSD
lldbPluginPlatformLinux
lldbPluginPlatformPOSIX
lldbPluginObjectFileMachO
lldbPluginObjectContainerMachOArchive
lldbPluginObjectContainerBSDArchive

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -51,6 +51,7 @@ add_lldb_library(lldbCore
StreamAsynchronousIO.cpp
StreamCallback.cpp
StreamFile.cpp
StreamGDBRemote.cpp
StreamString.cpp
StringList.cpp
Timer.cpp

View File

@ -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());

View File

@ -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;
}

View File

@ -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 */

View File

@ -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)

View File

@ -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
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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." },

View File

@ -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,

View File

@ -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;

View File

@ -8,4 +8,5 @@
# add_subdirectory(Windows)
#endif()
add_subdirectory(POSIX)
add_subdirectory(gdb-server)

View File

@ -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

View File

@ -71,6 +71,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,

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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)
{

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -0,0 +1,5 @@
set(LLVM_NO_RTTI 1)
add_lldb_library(lldbPluginPlatformPOSIX
PlatformPOSIX.cpp
)

View File

@ -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

View File

@ -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;
}

View File

@ -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_

View File

@ -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);
}

View File

@ -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;

View File

@ -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
}

View File

@ -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

View File

@ -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),

View File

@ -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,27 +2138,60 @@ 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;
}
return 0;
}
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)
{
@ -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;
}

View File

@ -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

View File

@ -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;
}
@ -665,6 +726,24 @@ GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet)
return SendPacketNoLock (response.GetData(), response.GetSize());
}
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)
{
@ -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,10 +863,63 @@ 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)
{
@ -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;
}

View File

@ -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,7 +116,13 @@ protected:
bool
Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet);
bool
Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet);
bool
Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet);
bool
Handle_qProcessInfoPID (StringExtractorGDBRemote &packet);
@ -119,6 +147,9 @@ protected:
bool
Handle_QEnvironment (StringExtractorGDBRemote &packet);
bool
Handle_QLaunchArch (StringExtractorGDBRemote &packet);
bool
Handle_QSetDisableASLR (StringExtractorGDBRemote &packet);
@ -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
//------------------------------------------------------------------

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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 ()
{

View File

@ -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();
}

View File

@ -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_

View File

@ -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"

View File

@ -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"

View File

@ -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.")

View File

@ -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)

View File

@ -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

View File

@ -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.

View File

@ -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))

View File

@ -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")

View File

@ -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',

View File

@ -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")

View File

@ -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."""

View File

@ -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")

View File

@ -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.

View File

@ -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.

View File

@ -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 = []

View File

@ -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):

View File

@ -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)."])

View File

@ -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):

View File

@ -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)

View File

@ -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")

View File

@ -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()

View File

@ -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()

View File

@ -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;

View File

@ -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)

View File

@ -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());
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 (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;
}
if (error.Fail())
{
fprintf(stderr, "error: %s\n", error.AsCString());
}
}
else
{
fprintf(stderr, "error: handshake with client failed\n");
}
}
}
}
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;
}
if (error.Fail())
{
fprintf(stderr, "error: %s\n", error.AsCString());
}
}
else
{
fprintf(stderr, "error: handshake with client failed\n");
}
}
} while (g_stay_alive);
Debugger::Terminate();
fprintf(stderr, "lldb-platform exiting...\n");
return 0;
}