diff options
69 files changed, 3408 insertions, 1256 deletions
diff --git a/lldb/include/lldb/Core/ConnectionFileDescriptor.h b/lldb/include/lldb/Core/ConnectionFileDescriptor.h index b679892d203..84b084d4638 100644 --- a/lldb/include/lldb/Core/ConnectionFileDescriptor.h +++ b/lldb/include/lldb/Core/ConnectionFileDescriptor.h @@ -59,6 +59,9 @@ protected: NamedSocketAccept (const char *socket_name, Error *error_ptr); lldb::ConnectionStatus + NamedSocketConnect (const char *socket_name, Error *error_ptr); + + lldb::ConnectionStatus Close (int& fd, Error *error); int m_fd; // Socket we use to communicate once conn established diff --git a/lldb/include/lldb/Core/ConnectionMachPort.h b/lldb/include/lldb/Core/ConnectionMachPort.h index 80adac79ba8..4339758c5c4 100644 --- a/lldb/include/lldb/Core/ConnectionMachPort.h +++ b/lldb/include/lldb/Core/ConnectionMachPort.h @@ -88,4 +88,4 @@ private: #endif // liblldb_ConnectionMachPort_h_ -#endif // #if defined(__APPLE__)
\ No newline at end of file +#endif // #if defined(__APPLE__) diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h index c9833919278..6d7a29a3974 100644 --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -388,15 +388,6 @@ public: bool PopInputReader (const lldb::InputReaderSP& reader_sp); - ExecutionContext & - GetExecutionContext() - { - return m_exe_ctx; - } - - void - UpdateExecutionContext (ExecutionContext *override_context); - static lldb::DebuggerSP FindDebuggerWithID (lldb::user_id_t id); @@ -447,7 +438,6 @@ protected: Listener m_listener; SourceManager m_source_manager; std::auto_ptr<CommandInterpreter> m_command_interpreter_ap; - ExecutionContext m_exe_ctx; std::stack<lldb::InputReaderSP> m_input_readers; std::string m_input_reader_data; diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index d4caf735f01..424908ec64d 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -391,8 +391,11 @@ public: const ConstString & GetObjectName() const; - off_t - GetObjectOffset() const; + uint64_t + GetObjectOffset() const + { + return m_object_offset; + } //------------------------------------------------------------------ /// Get the object file representation for the current architecture. @@ -598,6 +601,7 @@ protected: FileSpec m_file; ///< The file representation on disk for this module (if there is one). FileSpec m_platform_file;///< The path to the module on the platform on which it is being debugged ConstString m_object_name; ///< The name an object within this module that is selected, or empty of the module is represented by \a m_file. + uint64_t m_object_offset; std::auto_ptr<ObjectFile> m_objfile_ap; ///< A pointer to the object file parser for this module. std::auto_ptr<SymbolVendor> m_symfile_ap; ///< A pointer to the symbol vendor for this module. ClangASTContext m_ast; ///< The AST context for this module. diff --git a/lldb/include/lldb/Host/Host.h b/lldb/include/lldb/Host/Host.h index a4ec50aa489..db154a8effd 100644 --- a/lldb/include/lldb/Host/Host.h +++ b/lldb/include/lldb/Host/Host.h @@ -343,23 +343,17 @@ public: SetCrashDescription (const char *description); static uint32_t - FindProcesses (const ProcessInfoMatch &match_info, - ProcessInfoList &proc_infos); + FindProcesses (const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &proc_infos); static bool - GetProcessInfo (lldb::pid_t pid, ProcessInfo &proc_info); + GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &proc_info); static lldb::pid_t LaunchApplication (const FileSpec &app_file_spec); - static lldb::pid_t - LaunchInNewTerminal (const char *tty_name, // Optional partial or full tty name ("/dev/ttys000" or "ttys000") - const char **argv, // argv[0] is executable, argv[1] and on are the arguments - const char **envp, - const char *working_dir, - const ArchSpec *arch_spec, - bool stop_at_entry, - bool disable_aslr); + static Error + LaunchProcess (ProcessLaunchInfo &launch_info); static bool OpenFileInExternalEditor (const FileSpec &file_spec, diff --git a/lldb/include/lldb/Interpreter/Args.h b/lldb/include/lldb/Interpreter/Args.h index 0b9c909ecaf..e706194a83e 100644 --- a/lldb/include/lldb/Interpreter/Args.h +++ b/lldb/include/lldb/Interpreter/Args.h @@ -82,6 +82,11 @@ public: Args (const char *command, size_t len); + Args (const Args &rhs); + + const Args & + operator= (const Args &rhs); + //------------------------------------------------------------------ /// Destructor. //------------------------------------------------------------------ diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h b/lldb/include/lldb/Interpreter/CommandInterpreter.h index b96d1e3ee49..ae3260a2910 100644 --- a/lldb/include/lldb/Interpreter/CommandInterpreter.h +++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -39,7 +39,8 @@ public: }; void - SourceInitFile (bool in_cwd, CommandReturnObject &result); + SourceInitFile (bool in_cwd, + CommandReturnObject &result); CommandInterpreter (Debugger &debugger, lldb::ScriptLanguage script_language, @@ -49,13 +50,16 @@ public: ~CommandInterpreter (); lldb::CommandObjectSP - GetCommandSPExact (const char *cmd, bool include_aliases); + GetCommandSPExact (const char *cmd, + bool include_aliases); CommandObject * - GetCommandObjectExact (const char *cmd_cstr, bool include_aliases); + GetCommandObjectExact (const char *cmd_cstr, + bool include_aliases); CommandObject * - GetCommandObject (const char *cmd, StringList *matches = NULL); + GetCommandObject (const char *cmd, + StringList *matches = NULL); bool CommandExists (const char *cmd); @@ -67,7 +71,8 @@ public: UserCommandExists (const char *cmd); void - AddAlias (const char *alias_name, lldb::CommandObjectSP& command_obj_sp); + AddAlias (const char *alias_name, + lldb::CommandObjectSP& command_obj_sp); bool RemoveAlias (const char *alias_name); @@ -82,14 +87,19 @@ public: RemoveAliasOptions (const char *alias_name); void - AddOrReplaceAliasOptions (const char *alias_name, OptionArgVectorSP &option_arg_vector_sp); + AddOrReplaceAliasOptions (const char *alias_name, + OptionArgVectorSP &option_arg_vector_sp); bool - StripFirstWord (std::string &command_string, std::string &next_word); + StripFirstWord (std::string &command_string, + std::string &next_word); void - BuildAliasResult (const char *alias_name, std::string &raw_input_string, std::string &alias_result, - CommandObject *&alias_cmd_obj, CommandReturnObject &result); + BuildAliasResult (const char *alias_name, + std::string &raw_input_string, + std::string &alias_result, + CommandObject *&alias_cmd_obj, + CommandReturnObject &result); bool HandleCommand (const char *command_line, @@ -151,12 +161,12 @@ public: //------------------------------------------------------------------ void HandleCommandsFromFile (FileSpec &file, - ExecutionContext *context, - bool stop_on_continue, - bool stop_on_error, - bool echo_commands, - bool print_results, - CommandReturnObject &result); + ExecutionContext *context, + bool stop_on_continue, + bool stop_on_error, + bool echo_commands, + bool print_results, + CommandReturnObject &result); CommandObject * GetCommandObjectForCommand (std::string &command_line); @@ -177,11 +187,11 @@ public: int HandleCompletion (const char *current_line, - const char *cursor, - const char *last_char, - int match_start_point, - int max_return_elements, - StringList &matches); + const char *cursor, + const char *last_char, + int match_start_point, + int max_return_elements, + StringList &matches); // This version just returns matches, and doesn't compute the substring. It is here so the // Help command can call it for the first argument. @@ -190,22 +200,26 @@ public: int HandleCompletionMatches (Args &input, - int &cursor_index, - int &cursor_char_position, - int match_start_point, - int max_return_elements, - bool &word_complete, - StringList &matches); + int &cursor_index, + int &cursor_char_position, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches); int - GetCommandNamesMatchingPartialString (const char *cmd_cstr, bool include_aliases, StringList &matches); + GetCommandNamesMatchingPartialString (const char *cmd_cstr, + bool include_aliases, + StringList &matches); void GetHelp (CommandReturnObject &result); void - GetAliasHelp (const char *alias_name, const char *command_name, StreamString &help_string); + GetAliasHelp (const char *alias_name, + const char *command_name, + StreamString &help_string); void OutputFormattedHelpText (Stream &stream, @@ -219,6 +233,18 @@ public: { return m_debugger; } + + ExecutionContext & + GetExecutionContext() + { + return m_exe_ctx; + } + + void + UpdateExecutionContext (ExecutionContext *override_context); + + lldb::PlatformSP + GetPlatform (bool prefer_target_platform); const char * ProcessEmbeddedScriptCommands (const char *arg); @@ -245,7 +271,8 @@ public: Initialize (); void - CrossRegisterCommand (const char * dest_cmd, const char * object_type); + CrossRegisterCommand (const char *dest_cmd, + const char *object_type); void SetScriptLanguage (lldb::ScriptLanguage lang); @@ -264,8 +291,11 @@ public: HasAliasOptions (); void - BuildAliasCommandArgs (CommandObject *alias_cmd_obj, const char *alias_name, Args &cmd_args, - std::string &raw_input_string, CommandReturnObject &result); + BuildAliasCommandArgs (CommandObject *alias_cmd_obj, + const char *alias_name, + Args &cmd_args, + std::string &raw_input_string, + CommandReturnObject &result); int GetOptionArgumentPosition (const char *in_string); @@ -284,10 +314,12 @@ public: #ifndef SWIG void - AddLogChannel (const char *name, const Log::Callbacks &log_callbacks); + AddLogChannel (const char *name, + const Log::Callbacks &log_callbacks); bool - GetLogChannelCallbacks (const char *channel, Log::Callbacks &log_callbacks); + GetLogChannelCallbacks (const char *channel, + Log::Callbacks &log_callbacks); bool RemoveLogChannel (const char *name); @@ -297,11 +329,16 @@ public: FindLongestCommandWord (CommandObject::CommandMap &dict); void - FindCommandsForApropos (const char *word, StringList &commands_found, StringList &commands_help); + FindCommandsForApropos (const char *word, + StringList &commands_found, + StringList &commands_help); void - AproposAllSubCommands (CommandObject *cmd_obj, const char *prefix, const char *search_word, - StringList &commands_found, StringList &commands_help); + AproposAllSubCommands (CommandObject *cmd_obj, + const char *prefix, + const char *search_word, + StringList &commands_found, + StringList &commands_help); protected: friend class Debugger; @@ -314,15 +351,16 @@ protected: private: - Debugger &m_debugger; // The debugger session that this interpreter is associated with + Debugger &m_debugger; // The debugger session that this interpreter is associated with + ExecutionContext m_exe_ctx; // The current execution context to use when handling commands bool m_synchronous_execution; bool m_skip_lldbinit_files; - CommandObject::CommandMap m_command_dict; // Stores basic built-in commands (they cannot be deleted, removed or overwritten). - CommandObject::CommandMap m_alias_dict; // Stores user aliases/abbreviations for commands - CommandObject::CommandMap m_user_dict; // Stores user-defined commands - OptionArgMap m_alias_options; // Stores any options (with or without arguments) that go with any alias. + CommandObject::CommandMap m_command_dict; // Stores basic built-in commands (they cannot be deleted, removed or overwritten). + CommandObject::CommandMap m_alias_dict; // Stores user aliases/abbreviations for commands + CommandObject::CommandMap m_user_dict; // Stores user-defined commands + OptionArgMap m_alias_options; // Stores any options (with or without arguments) that go with any alias. std::vector<std::string> m_command_history; - std::string m_repeat_command; // Stores the command that will be executed for an empty command string. + std::string m_repeat_command; // Stores the command that will be executed for an empty command string. std::auto_ptr<ScriptInterpreter> m_script_interpreter_ap; char m_comment_char; }; diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h index 60af2c93185..0da89f20631 100644 --- a/lldb/include/lldb/Target/Platform.h +++ b/lldb/include/lldb/Target/Platform.h @@ -123,6 +123,11 @@ namespace lldb_private { bool GetOSKernelDescription (std::string &s); + // Returns the the hostname if we are connected, else the short plugin + // name. + const char * + GetName (); + virtual const char * GetHostname (); @@ -252,83 +257,47 @@ namespace lldb_private { BreakpointSite *bp_site) = 0; //------------------------------------------------------------------ - /// Launch a new process. - /// - /// Launch a new process by spawning a new process using the - /// target object's executable module's file as the file to launch. - /// Arguments are given in \a argv, and the environment variables - /// are in \a envp. Standard input and output files can be - /// optionally re-directed to \a stdin_path, \a stdout_path, and - /// \a stderr_path. - /// - /// This function is not meant to be overridden by Process - /// subclasses. It will first call Process::WillLaunch (Module *) - /// and if that returns \b true, Process::DoLaunch (Module*, - /// char const *[],char const *[],const char *,const char *, - /// const char *) will be called to actually do the launching. If - /// DoLaunch returns \b true, then Process::DidLaunch() will be - /// called. - /// - /// @param[in] argv - /// The argument array. - /// - /// @param[in] envp - /// The environment array. - /// - /// @param[in] launch_flags - /// Flags to modify the launch (@see lldb::LaunchFlags) - /// - /// @param[in] stdin_path - /// The path to use when re-directing the STDIN of the new - /// process. If all stdXX_path arguments are NULL, a pseudo - /// terminal will be used. - /// - /// @param[in] stdout_path - /// The path to use when re-directing the STDOUT of the new - /// process. If all stdXX_path arguments are NULL, a pseudo - /// terminal will be used. - /// - /// @param[in] stderr_path - /// The path to use when re-directing the STDERR of the new - /// process. If all stdXX_path arguments are NULL, a pseudo - /// terminal will be used. - /// - /// @param[in] working_directory - /// The working directory to have the child process run in - /// - /// @return - /// An error object. Call GetID() to get the process ID if - /// the error object is success. + /// Launch a new process on a platform, not necessarily for + /// debugging, it could be just for running the process. //------------------------------------------------------------------ -// virtual lldb::ProcessSP -// Launch (char const *argv[], -// char const *envp[], -// uint32_t launch_flags, -// const char *stdin_path, -// const char *stdout_path, -// const char *stderr_path, -// const char *working_directory, -// Error &error) = 0; + virtual Error + LaunchProcess (ProcessLaunchInfo &launch_info); + + //------------------------------------------------------------------ + /// Subclasses should NOT need to implement this function as it uses + /// the Platform::LaunchProcess() followed by Platform::Attach () + //------------------------------------------------------------------ + lldb::ProcessSP + DebugProcess (ProcessLaunchInfo &launch_info, + Debugger &debugger, + Target *target, // Can be NULL, if NULL create a new target, else use existing one + Listener &listener, + Error &error); //------------------------------------------------------------------ /// Attach to an existing process using a process ID. /// - /// This function is not meant to be overridden by Process - /// subclasses. It will first call Process::WillAttach (lldb::pid_t) - /// and if that returns \b true, Process::DoAttach (lldb::pid_t) will - /// be called to actually do the attach. If DoAttach returns \b - /// true, then Process::DidAttach() will be called. + /// Each platform subclass needs to implement this function and + /// attempt to attach to the process with the process ID of \a pid. + /// The platform subclass should return an appropriate ProcessSP + /// subclass that is attached to the process, or an empty shared + /// pointer with an appriopriate error. /// /// @param[in] pid /// The process ID that we should attempt to attach to. /// /// @return - /// Returns \a pid if attaching was successful, or - /// LLDB_INVALID_PROCESS_ID if attaching fails. + /// An appropriate ProcessSP containing a valid shared pointer + /// to the default Process subclass for the platform that is + /// attached to the process, or an empty shared pointer with an + /// appriopriate error fill into the \a error object. //------------------------------------------------------------------ -// virtual lldb::ProcessSP -// Attach (lldb::pid_t pid, -// Error &error) = 0; + virtual lldb::ProcessSP + Attach (lldb::pid_t pid, + Debugger &debugger, + Target *target, // Can be NULL, if NULL create a new target, else use existing one + Listener &listener, + Error &error) = 0; //------------------------------------------------------------------ /// Attach to an existing process by process name. @@ -357,11 +326,11 @@ namespace lldb_private { // Subclasses will need to fill in the remote case. //------------------------------------------------------------------ virtual uint32_t - FindProcesses (const ProcessInfoMatch &match_info, - ProcessInfoList &proc_infos); + FindProcesses (const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &proc_infos); virtual bool - GetProcessInfo (lldb::pid_t pid, ProcessInfo &proc_info); + GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &proc_info); const std::string & GetRemoteURL () const @@ -529,7 +498,8 @@ namespace lldb_private { public: PlatformList() : m_mutex (Mutex::eMutexTypeRecursive), - m_platforms () + m_platforms (), + m_selected_platform_sp() { } diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index cee05307a18..98612ff23ae 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -11,8 +11,11 @@ #define liblldb_Process_h_ // C Includes +#include <spawn.h> + // C++ Includes #include <list> +#include <iosfwd> #include <vector> // Other libraries and framework includes @@ -39,7 +42,9 @@ namespace lldb_private { - +//---------------------------------------------------------------------- +// ProcessInstanceSettings +//---------------------------------------------------------------------- class ProcessInstanceSettings : public InstanceSettings { public: @@ -224,35 +229,38 @@ private: bool m_got_host_env; }; - +//---------------------------------------------------------------------- +// ProcessInfo +// +// A base class for information for a process. This can be used to fill +// out information for a process prior to launching it, or it can be +// used for an instance of a process and can be filled in with the +// existing values for that process. +//---------------------------------------------------------------------- class ProcessInfo { public: ProcessInfo () : m_executable (), - m_args (), - m_real_uid (UINT32_MAX), - m_real_gid (UINT32_MAX), - m_effective_uid (UINT32_MAX), - m_effective_gid (UINT32_MAX), + m_arguments (), + m_environment (), + m_uid (LLDB_INVALID_UID), + m_gid (LLDB_INVALID_UID), m_arch(), - m_pid (LLDB_INVALID_PROCESS_ID), - m_parent_pid (LLDB_INVALID_PROCESS_ID) + m_pid (LLDB_INVALID_PROCESS_ID) { } - + ProcessInfo (const char *name, const ArchSpec &arch, lldb::pid_t pid) : - m_executable (), - m_args (), - m_real_uid (UINT32_MAX), - m_real_gid (UINT32_MAX), - m_effective_uid (UINT32_MAX), - m_effective_gid (UINT32_MAX), + m_executable (name, false), + m_arguments (), + m_environment(), + m_uid (LLDB_INVALID_UID), + m_gid (LLDB_INVALID_UID), m_arch (arch), - m_pid (pid), - m_parent_pid (LLDB_INVALID_PROCESS_ID) + m_pid (pid) { } @@ -260,14 +268,12 @@ public: Clear () { m_executable.Clear(); - m_args.Clear(); - m_real_uid = UINT32_MAX; - m_real_gid = UINT32_MAX; - m_effective_uid = UINT32_MAX; - m_effective_gid = UINT32_MAX; + m_arguments.Clear(); + m_environment.Clear(); + m_uid = LLDB_INVALID_UID; + m_gid = LLDB_INVALID_UID; m_arch.Clear(); m_pid = LLDB_INVALID_PROCESS_ID; - m_parent_pid = LLDB_INVALID_PROCESS_ID; } const char * @@ -275,7 +281,7 @@ public: { return m_executable.GetFilename().GetCString(); } - + size_t GetNameLength() const { @@ -293,97 +299,61 @@ public: { return m_executable; } - + const FileSpec & GetExecutableFile () const { return m_executable; } - - uint32_t - GetRealUserID() const - { - return m_real_uid; - } uint32_t - GetRealGroupID() const - { - return m_real_gid; - } - - uint32_t - GetEffectiveUserID() const + GetUserID() const { - return m_effective_uid; + return m_uid; } - + uint32_t - GetEffectiveGroupID() const + GetGroupID() const { - return m_effective_gid; + return m_gid; } bool - RealUserIDIsValid () const + UserIDIsValid () const { - return m_real_uid != UINT32_MAX; + return m_uid != UINT32_MAX; } bool - RealGroupIDIsValid () const + GroupIDIsValid () const { - return m_real_gid != UINT32_MAX; + return m_gid != UINT32_MAX; } - bool - EffectiveUserIDIsValid () const - { - return m_effective_uid != UINT32_MAX; - } - - bool - EffectiveGroupIDIsValid () const - { - return m_effective_gid != UINT32_MAX; - } - void - SetRealUserID (uint32_t uid) + SetUserID (uint32_t uid) { - m_real_uid = uid; - } - - void - SetRealGroupID (uint32_t gid) - { - m_real_gid = gid; - } - - void - SetEffectiveUserID (uint32_t uid) - { - m_effective_uid = uid; + m_uid = uid; } void - SetEffectiveGroupID (uint32_t gid) + SetGroupID (uint32_t gid) { - m_effective_gid = gid; + m_gid = gid; } - + ArchSpec & GetArchitecture () { return m_arch; } - + const ArchSpec & GetArchitecture () const { return m_arch; } - + lldb::pid_t GetProcessID () const { @@ -401,6 +371,120 @@ public: { return m_pid != LLDB_INVALID_PROCESS_ID; } + + void + Dump (Stream &s, Platform *platform) const; + + Args & + GetArguments () + { + return m_arguments; + } + + const Args & + GetArguments () const + { + return m_arguments; + } + + void + SetArgumentsFromArgs (const Args& args, + bool first_arg_is_executable, + bool first_arg_is_executable_and_argument); + + Args & + GetEnvironmentEntries () + { + return m_environment; + } + + const Args & + GetEnvironmentEntries () const + { + return m_environment; + } + +protected: + FileSpec m_executable; + Args m_arguments; + Args m_environment; + uint32_t m_uid; + uint32_t m_gid; + ArchSpec m_arch; + lldb::pid_t m_pid; +}; + +//---------------------------------------------------------------------- +// ProcessInstanceInfo +// +// Describes an existing process and any discoverable information that +// pertains to that process. +//---------------------------------------------------------------------- +class ProcessInstanceInfo : public ProcessInfo +{ +public: + ProcessInstanceInfo () : + ProcessInfo (), + m_euid (UINT32_MAX), + m_egid (UINT32_MAX), + m_parent_pid (LLDB_INVALID_PROCESS_ID) + { + } + + ProcessInstanceInfo (const char *name, + const ArchSpec &arch, + lldb::pid_t pid) : + ProcessInfo (name, arch, pid), + m_euid (UINT32_MAX), + m_egid (UINT32_MAX), + m_parent_pid (LLDB_INVALID_PROCESS_ID) + { + } + + void + Clear () + { + ProcessInfo::Clear(); + m_euid = UINT32_MAX; + m_egid = UINT32_MAX; + m_parent_pid = LLDB_INVALID_PROCESS_ID; + } + + uint32_t + GetEffectiveUserID() const + { + return m_euid; + } + + uint32_t + GetEffectiveGroupID() const + { + return m_egid; + } + + bool + EffectiveUserIDIsValid () const + { + return m_euid != UINT32_MAX; + } + + bool + EffectiveGroupIDIsValid () const + { + return m_egid != UINT32_MAX; + } + + void + SetEffectiveUserID (uint32_t uid) + { + m_euid = uid; + } + + void + SetEffectiveGroupID (uint32_t gid) + { + m_egid = gid; + } lldb::pid_t GetParentProcessID () const @@ -424,46 +508,272 @@ public: Dump (Stream &s, Platform *platform) const; static void - DumpTableHeader (Stream &s, Platform *platform, bool verbose = false); + DumpTableHeader (Stream &s, Platform *platform, bool show_args, bool verbose); + + void + DumpAsTableRow (Stream &s, Platform *platform, bool show_args, bool verbose) const; + +protected: + uint32_t m_euid; + uint32_t m_egid; + lldb::pid_t m_parent_pid; +}; + + +//---------------------------------------------------------------------- +// ProcessLaunchInfo +// +// Describes any information that is required to launch a process. +//---------------------------------------------------------------------- + +class ProcessLaunchInfo : public ProcessInfo +{ +public: + + class FileAction + { + public: + + FileAction () : + m_action (eFileActionNone), + m_fd (-1), + m_arg (-1), + m_path () + { + } + + void + Clear() + { + m_action = eFileActionNone; + m_fd = -1; + m_arg = -1; + m_path.clear(); + } + + bool + Close (int fd); + + bool + Duplicate (int fd, int dup_fd); + + bool + Open (int fd, const char *path, bool read, bool write); + + static bool + AddPosixSpawnFileAction (posix_spawn_file_actions_t *file_actions, + const FileAction *info, + Log *log, + Error& error); + + protected: + enum Action + { + eFileActionNone, + eFileActionClose, + eFileActionDuplicate, + eFileActionOpen + }; + + Action m_action; // The action for this file + int m_fd; // An existing file descriptor + int m_arg; // oflag for eFileActionOpen*, dup_fd for eFileActionDuplicate + std::string m_path; // A file path to use for opening after fork or posix_spawn + }; + + ProcessLaunchInfo () : + ProcessInfo(), + m_flags (), + m_stdin_info (), + m_stdout_info (), + m_stderr_info () + { + } + + void + AppendFileAction (const FileAction &info) + { + m_file_actions.push_back(info); + } + + void + AppendCloseFileAction (int fd) + { + FileAction file_action; + file_action.Close (fd); + AppendFileAction (file_action); + } + + void + AppendDuplciateFileAction (int fd, int dup_fd) + { + FileAction file_action; + file_action.Duplicate (fd, dup_fd); + AppendFileAction (file_action); + } + + void + AppendOpenFileAction (int fd, const char *path, bool read, bool write) + { + FileAction file_action; + file_action.Open (fd, path, read, write); + AppendFileAction (file_action); + } + + void + AppendSuppressFileAction (int fd, bool read, bool write) + { + FileAction file_action; + file_action.Open (fd, "/dev/null", read, write); + AppendFileAction (file_action); + } + + size_t + GetNumFileActions () const + { + return m_file_actions.size(); + } + + const FileAction * + GetFileActionAtIndex (size_t idx) const + { + if (idx < m_file_actions.size()) + return &m_file_actions[idx]; + return NULL; + } + + Flags & + GetFlags () + { + return m_flags; + } + + const Flags & + GetFlags () const + { + return m_flags; + } + + const char * + GetWorkingDirectory () const + { + if (m_working_dir.empty()) + return NULL; + return m_working_dir.c_str(); + } void - DumpAsTableRow (Stream &s, Platform *platform, bool verbose = false) const; + SetWorkingDirectory (const char *working_dir) + { + if (working_dir && working_dir[0]) + m_working_dir.assign (working_dir); + else + m_working_dir.clear(); + } - StringList & - GetArguments() + void + SwapWorkingDirectory (std::string &working_dir) { - return m_args; + m_working_dir.swap (working_dir); + } + + + const char * + GetProcessPluginName () const + { + if (m_plugin_name.empty()) + return NULL; + return m_plugin_name.c_str(); + } + + void + SetProcessPluginName (const char *plugin) + { + if (plugin && plugin[0]) + m_plugin_name.assign (plugin); + else + m_plugin_name.clear(); } - const StringList & - GetArguments() const + void + Clear () { - return m_args; + ProcessInfo::Clear(); + m_working_dir.clear(); + m_plugin_name.clear(); + m_flags.Clear(); + m_stdin_info.Clear(); + m_stdout_info.Clear(); + m_stderr_info.Clear(); + m_file_actions.clear(); } protected: - FileSpec m_executable; - StringList m_args; - uint32_t m_real_uid; - uint32_t m_real_gid; - uint32_t m_effective_uid; - uint32_t m_effective_gid; - ArchSpec m_arch; - lldb::pid_t m_pid; - lldb::pid_t m_parent_pid; + std::string m_working_dir; + std::string m_plugin_name; + Flags m_flags; // Bitwise OR of bits from lldb::LaunchFlags + FileAction m_stdin_info; // File action for stdin + FileAction m_stdout_info; // File action for stdout + FileAction m_stderr_info; // File action for stderr + std::vector<FileAction> m_file_actions; // File actions for any other files }; -class ProcessInfoMatch +class ProcessLaunchCommandOptions : public Options { public: - ProcessInfoMatch () : + + ProcessLaunchCommandOptions (CommandInterpreter &interpreter) : + Options(interpreter) + { + // Keep default values of all options in one place: ResetOptionValues () + ResetOptionValues (); + } + + ~ProcessLaunchCommandOptions () + { + } + + Error + SetOptionValue (int option_idx, const char *option_arg); + + void + ResetOptionValues () + { + launch_info.Clear(); + } + + const OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + // Options table: Required for subclasses of Options. + + static OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + ProcessLaunchInfo launch_info; +}; + +//---------------------------------------------------------------------- +// ProcessInstanceInfoMatch +// +// A class to help matching one ProcessInstanceInfo to another. +//---------------------------------------------------------------------- + +class ProcessInstanceInfoMatch +{ +public: + ProcessInstanceInfoMatch () : m_match_info (), m_name_match_type (lldb_private::eNameMatchIgnore), m_match_all_users (false) { } - ProcessInfoMatch (const char *process_name, + ProcessInstanceInfoMatch (const char *process_name, lldb_private::NameMatchType process_name_match_type) : m_match_info (), m_name_match_type (process_name_match_type), @@ -472,13 +782,13 @@ public: m_match_info.SetName (process_name); } - ProcessInfo & + ProcessInstanceInfo & GetProcessInfo () { return m_match_info; } - const ProcessInfo & + const ProcessInstanceInfo & GetProcessInfo () const { return m_match_info; @@ -512,7 +822,7 @@ public: NameMatches (const char *process_name) const; bool - Matches (const ProcessInfo &proc_info) const; + Matches (const ProcessInstanceInfo &proc_info) const; bool MatchAllProcesses () const; @@ -520,15 +830,15 @@ public: Clear (); protected: - ProcessInfo m_match_info; + ProcessInstanceInfo m_match_info; lldb_private::NameMatchType m_name_match_type; bool m_match_all_users; }; -class ProcessInfoList +class ProcessInstanceInfoList { public: - ProcessInfoList () : + ProcessInstanceInfoList () : m_infos() { } @@ -546,7 +856,7 @@ public: } void - Append (const ProcessInfo &info) + Append (const ProcessInstanceInfo &info) { m_infos.push_back (info); } @@ -576,7 +886,7 @@ public: } bool - GetInfoAtIndex (uint32_t idx, ProcessInfo &info) + GetInfoAtIndex (uint32_t idx, ProcessInstanceInfo &info) { if (idx < m_infos.size()) { @@ -587,7 +897,7 @@ public: } // You must ensure "idx" is valid before calling this function - const ProcessInfo & + const ProcessInstanceInfo & GetProcessInfoAtIndex (uint32_t idx) const { assert (idx < m_infos.size()); @@ -595,7 +905,7 @@ public: } protected: - typedef std::vector<ProcessInfo> collection; + typedef std::vector<ProcessInstanceInfo> collection; collection m_infos; }; @@ -1732,6 +2042,20 @@ public: size_t size, Error &error); + //------------------------------------------------------------------ + /// Read a NULL terminated C string from memory + /// + /// This function will read a cache page at a time until the NULL + /// C stirng terminator is found. It will stop reading if the NULL + /// termination byte isn't found before reading \a cstr_max_len + /// bytes, and the results are always guaranteed to be NULL + /// terminated (at most cstr_max_len - 1 bytes will be read). + //------------------------------------------------------------------ + size_t + ReadCStringFromMemory (lldb::addr_t vm_addr, + char *cstr, + size_t cstr_max_len); + size_t ReadMemoryFromInferior (lldb::addr_t vm_addr, void *buf, @@ -2292,6 +2616,11 @@ protected: size_t dst_len, Error &error); + uint32_t + GetMemoryCacheLineSize() const + { + return m_cache_line_byte_size ; + } protected: typedef std::map<lldb::addr_t, lldb::DataBufferSP> collection; //------------------------------------------------------------------ diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index 454893f1370..6e055ab751d 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -39,9 +39,12 @@ namespace lldb { typedef enum LaunchFlags { eLaunchFlagNone = 0u, - eLaunchFlagDisableASLR = (1u << 0), ///< Disable Address Space Layout Randomization - eLaunchFlagDisableSTDIO = (1u << 1), ///< Disable stdio for inferior process (e.g. for a GUI app) - eLaunchFlagLaunchInTTY = (1u << 2) ///< Launch the process in a new TTY if supported by the host + eLaunchFlagExec = (1u << 0), ///< Exec when launching and turn the calling process into a new process + eLaunchFlagDebug = (1u << 1), ///< Stop as soon as the process launches to allow the process to be debugged + eLaunchFlagStopAtEntry = (1u << 2), ///< Stop at the program entry point instead of auto-continuing when launching or attaching at entry point + eLaunchFlagDisableASLR = (1u << 3), ///< Disable Address Space Layout Randomization + eLaunchFlagDisableSTDIO = (1u << 4), ///< Disable stdio for inferior process (e.g. for a GUI app) + eLaunchFlagLaunchInTTY = (1u << 5) ///< Launch the process in a new TTY if supported by the host } LaunchFlags; //---------------------------------------------------------------------- diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index a4251c21468..ed6e8b36d3b 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -103,8 +103,10 @@ class PathMappingList; class Platform; class Process; class ProcessInfo; -class ProcessInfoList; -class ProcessInfoMatch; +class ProcessInstanceInfo; +class ProcessInstanceInfoList; +class ProcessInstanceInfoMatch; +class ProcessLaunchInfo; class RegisterContext; class RegisterLocation; class RegisterLocationList; diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 0019e971159..92250ab243d 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -62,6 +62,7 @@ 26680336116005EF008E1FE4 /* SBBreakpointLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AF16CC7114086A1007A7B3F /* SBBreakpointLocation.cpp */; }; 26680337116005F1008E1FE4 /* SBBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AF16A9C11402D5B007A7B3F /* SBBreakpoint.cpp */; }; 2668035C11601108008E1FE4 /* LLDB.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26680207115FD0ED008E1FE4 /* LLDB.framework */; }; + 266E8C6A13528ABC000C2042 /* lldb-platform in Resources */ = {isa = PBXBuildFile; fileRef = 26DC6A101337FE6900FF7998 /* lldb-platform */; }; 2671A0CE134825F6003A87BB /* ConnectionMachPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 2671A0CD134825F6003A87BB /* ConnectionMachPort.h */; }; 2671A0D013482601003A87BB /* ConnectionMachPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2671A0CF13482601003A87BB /* ConnectionMachPort.cpp */; }; 26744EF11338317700EF765A /* GDBRemoteCommunicationClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26744EED1338317700EF765A /* GDBRemoteCommunicationClient.cpp */; }; @@ -446,6 +447,13 @@ remoteGlobalIDString = 26680206115FD0ED008E1FE4; remoteInfo = LLDB; }; + 266E8C6C13528AD2000C2042 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 26DC6A0F1337FE6900FF7998; + remoteInfo = "lldb-platform"; + }; 2689011413353E9B00698AC0 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; @@ -2579,6 +2587,7 @@ buildRules = ( ); dependencies = ( + 266E8C6D13528AD2000C2042 /* PBXTargetDependency */, 2689011513353E9B00698AC0 /* PBXTargetDependency */, 262CFC7211A450CB00946C6C /* PBXTargetDependency */, 26368AF6126B95FA00E8659F /* PBXTargetDependency */, @@ -2688,6 +2697,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 266E8C6A13528ABC000C2042 /* lldb-platform in Resources */, 262CFC7711A4510000946C6C /* debugserver in Resources */, 26368AF7126B960500E8659F /* darwin-debug in Resources */, ); @@ -3143,6 +3153,11 @@ target = 26680206115FD0ED008E1FE4 /* LLDB */; targetProxy = 266803611160110D008E1FE4 /* PBXContainerItemProxy */; }; + 266E8C6D13528AD2000C2042 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 26DC6A0F1337FE6900FF7998 /* lldb-platform */; + targetProxy = 266E8C6C13528AD2000C2042 /* PBXContainerItemProxy */; + }; 2689011513353E9B00698AC0 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 2689FFC913353D7A00698AC0 /* lldb-core */; diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index a54a15ec936..551a49680e1 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -204,65 +204,65 @@ SBTarget::Launch } } - if ((launch_flags & eLaunchFlagLaunchInTTY) || g_launch_tty) - { - ArchSpec arch (m_opaque_sp->GetArchitecture ()); - - Module *exe_module = m_opaque_sp->GetExecutableModule().get(); - if (exe_module) - { - char exec_file_path[PATH_MAX]; - exe_module->GetFileSpec().GetPath(exec_file_path, sizeof(exec_file_path)); - if (exe_module->GetFileSpec().Exists()) - { - // Make a new argument vector - std::vector<const char *> exec_path_plus_argv; - // Append the resolved executable path - exec_path_plus_argv.push_back (exec_file_path); - - // Push all args if there are any - if (argv) - { - for (int i = 0; argv[i]; ++i) - exec_path_plus_argv.push_back(argv[i]); - } - - // Push a NULL to terminate the args. - exec_path_plus_argv.push_back(NULL); - - - const char *tty_name = NULL; - if (g_launch_tty && g_launch_tty[0] == '/') - tty_name = g_launch_tty; - - lldb::pid_t pid = Host::LaunchInNewTerminal (tty_name, - &exec_path_plus_argv[0], - envp, - working_directory, - &arch, - true, - launch_flags & eLaunchFlagDisableASLR); - - if (pid != LLDB_INVALID_PROCESS_ID) - { - sb_process = AttachToProcessWithID(listener, pid, error); - } - else - { - error.SetErrorStringWithFormat("failed to launch process in terminal"); - } - } - else - { - error.SetErrorStringWithFormat("executable doesn't exist: \"%s\"", exec_file_path); - } - } - else - { - error.SetErrorStringWithFormat("invalid executable"); - } - } - else +// if ((launch_flags & eLaunchFlagLaunchInTTY) || g_launch_tty) +// { +// ArchSpec arch (m_opaque_sp->GetArchitecture ()); +// +// Module *exe_module = m_opaque_sp->GetExecutableModule().get(); +// if (exe_module) +// { +// char exec_file_path[PATH_MAX]; +// exe_module->GetFileSpec().GetPath(exec_file_path, sizeof(exec_file_path)); +// if (exe_module->GetFileSpec().Exists()) +// { +// // Make a new argument vector +// std::vector<const char *> exec_path_plus_argv; +// // Append the resolved executable path +// exec_path_plus_argv.push_back (exec_file_path); +// +// // Push all args if there are any +// if (argv) +// { +// for (int i = 0; argv[i]; ++i) +// exec_path_plus_argv.push_back(argv[i]); +// } +// +// // Push a NULL to terminate the args. +// exec_path_plus_argv.push_back(NULL); +// +// +// const char *tty_name = NULL; +// if (g_launch_tty && g_launch_tty[0] == '/') +// tty_name = g_launch_tty; +// +// lldb::pid_t pid = Host::LaunchInNewTerminal (tty_name, +// &exec_path_plus_argv[0], +// envp, +// working_directory, +// &arch, +// true, +// launch_flags & eLaunchFlagDisableASLR); +// +// if (pid != LLDB_INVALID_PROCESS_ID) +// { +// sb_process = AttachToProcessWithID(listener, pid, error); +// } +// else +// { +// error.SetErrorStringWithFormat("failed to launch process in terminal"); +// } +// } +// else +// { +// error.SetErrorStringWithFormat("executable doesn't exist: \"%s\"", exec_file_path); +// } +// } +// else +// { +// error.SetErrorStringWithFormat("invalid executable"); +// } +// } +// else { if (listener.IsValid()) sb_process.SetProcess (m_opaque_sp->CreateProcess (listener.ref())); diff --git a/lldb/source/Commands/CommandObjectArgs.cpp b/lldb/source/Commands/CommandObjectArgs.cpp index 6064ec8dbc6..0ed4a06e564 100644 --- a/lldb/source/Commands/CommandObjectArgs.cpp +++ b/lldb/source/Commands/CommandObjectArgs.cpp @@ -105,7 +105,7 @@ CommandObjectArgs::Execute ConstString target_triple; - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; if (!process) { result.AppendError ("Args found no process."); @@ -131,7 +131,7 @@ CommandObjectArgs::Execute return false; } - Thread *thread = m_interpreter.GetDebugger().GetExecutionContext ().thread; + Thread *thread = m_interpreter.GetExecutionContext ().thread; if (!thread) { diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp index c8287015643..d5a4345ba2e 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -322,7 +322,7 @@ CommandObjectBreakpointSet::Execute FileSpec file; if (m_options.m_filename.empty()) { - StackFrame *cur_frame = m_interpreter.GetDebugger().GetExecutionContext().frame; + StackFrame *cur_frame = m_interpreter.GetExecutionContext().frame; if (cur_frame == NULL) { result.AppendError ("Attempting to set breakpoint by line number alone with no selected frame."); diff --git a/lldb/source/Commands/CommandObjectDisassemble.cpp b/lldb/source/Commands/CommandObjectDisassemble.cpp index 1301fd9f4da..dea764074e1 100644 --- a/lldb/source/Commands/CommandObjectDisassemble.cpp +++ b/lldb/source/Commands/CommandObjectDisassemble.cpp @@ -128,7 +128,7 @@ CommandObjectDisassemble::CommandOptions::SetOptionValue (int option_idx, const break; case 'a': - arch.SetTriple (option_arg, m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform().get()); + arch.SetTriple (option_arg, m_interpreter.GetPlatform (true).get()); break; default: @@ -257,7 +257,7 @@ CommandObjectDisassemble::Execute if (m_options.show_mixed && m_options.num_lines_context == 0) m_options.num_lines_context = 1; - ExecutionContext exe_ctx(m_interpreter.GetDebugger().GetExecutionContext()); + ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); if (!m_options.func_name.empty()) { diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index 31ecaf106d2..c96b247ce12 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -295,7 +295,7 @@ CommandObjectExpression::ExecuteRawCommandString CommandReturnObject &result ) { - m_exe_ctx = m_interpreter.GetDebugger().GetExecutionContext(); + m_exe_ctx = m_interpreter.GetExecutionContext(); m_options.Reset(); diff --git a/lldb/source/Commands/CommandObjectFile.cpp b/lldb/source/Commands/CommandObjectFile.cpp index e0c81bbf983..1177f5aafbc 100644 --- a/lldb/source/Commands/CommandObjectFile.cpp +++ b/lldb/source/Commands/CommandObjectFile.cpp @@ -58,7 +58,7 @@ CommandObjectFile::CommandOptions::SetOptionValue (int option_idx, const char *o { case 'a': { - PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); + PlatformSP platform_sp (m_interpreter.GetPlatform (false)); ArchSpec option_arch (option_arg, platform_sp.get()); if (option_arch.IsValid()) m_arch = option_arch; diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp index aaaee06c4be..57286ac3014 100644 --- a/lldb/source/Commands/CommandObjectFrame.cpp +++ b/lldb/source/Commands/CommandObjectFrame.cpp @@ -69,7 +69,7 @@ public: Execute (Args& command, CommandReturnObject &result) { - ExecutionContext exe_ctx(m_interpreter.GetDebugger().GetExecutionContext()); + ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); if (exe_ctx.frame) { exe_ctx.frame->DumpUsingSettingsFormat (&result.GetOutputStream()); @@ -188,7 +188,7 @@ public: Execute (Args& command, CommandReturnObject &result) { - ExecutionContext exe_ctx (m_interpreter.GetDebugger().GetExecutionContext()); + ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); if (exe_ctx.thread) { const uint32_t num_frames = exe_ctx.thread->GetStackFrameCount(); @@ -445,7 +445,7 @@ public: CommandReturnObject &result ) { - ExecutionContext exe_ctx(m_interpreter.GetDebugger().GetExecutionContext()); + ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); if (exe_ctx.frame == NULL) { result.AppendError ("you must be stopped in a valid stack frame to view frame variables."); diff --git a/lldb/source/Commands/CommandObjectImage.cpp b/lldb/source/Commands/CommandObjectImage.cpp index 3d005a80526..ca109d59576 100644 --- a/lldb/source/Commands/CommandObjectImage.cpp +++ b/lldb/source/Commands/CommandObjectImage.cpp @@ -87,7 +87,7 @@ DumpCompileUnitLineTable LineTable *line_table = sc.comp_unit->GetLineTable(); if (line_table) line_table->GetDescription (&strm, - interpreter.GetDebugger().GetExecutionContext().target, + interpreter.GetExecutionContext().target, lldb::eDescriptionLevelBrief); else strm << "No line table"; @@ -165,7 +165,7 @@ DumpModuleSymtab (CommandInterpreter &interpreter, Stream &strm, Module *module, { Symtab *symtab = objfile->GetSymtab(); if (symtab) - symtab->Dump(&strm, interpreter.GetDebugger().GetExecutionContext().target, sort_order); + symtab->Dump(&strm, interpreter.GetExecutionContext().target, sort_order); } } } @@ -183,9 +183,11 @@ DumpModuleSections (CommandInterpreter &interpreter, Stream &strm, Module *modul { strm.PutCString ("Sections for '"); strm << module->GetFileSpec(); + if (module->GetObjectName()) + strm << '(' << module->GetObjectName() << ')'; strm.Printf ("' (%s):\n", module->GetArchitecture().GetArchitectureName()); strm.IndentMore(); - section_list->Dump(&strm, interpreter.GetDebugger().GetExecutionContext().target, true, UINT32_MAX); + section_list->Dump(&strm, interpreter.GetExecutionContext().target, true, UINT32_MAX); strm.IndentLess(); } } @@ -224,7 +226,7 @@ LookupAddressInModule lldb::addr_t addr = raw_addr - offset; Address so_addr; SymbolContext sc; - Target *target = interpreter.GetDebugger().GetExecutionContext().target; + Target *target = interpreter.GetExecutionContext().target; if (target && !target->GetSectionLoadList().IsEmpty()) { if (!target->GetSectionLoadList().ResolveLoadAddress (addr, so_addr)) @@ -242,7 +244,7 @@ LookupAddressInModule if (offset) strm.Printf("File Address: 0x%llx\n", addr); - ExecutionContextScope *exe_scope = interpreter.GetDebugger().GetExecutionContext().GetBestExecutionContextScope(); + ExecutionContextScope *exe_scope = interpreter.GetExecutionContext().GetBestExecutionContextScope(); strm.IndentMore(); strm.Indent (" Address: "); so_addr.Dump (&strm, exe_scope, Address::DumpStyleSectionNameOffset); @@ -309,7 +311,7 @@ LookupSymbolInModule (CommandInterpreter &interpreter, Stream &strm, Module *mod { Symbol *symbol = symtab->SymbolAtIndex(match_indexes[i]); strm.Indent (); - symbol->Dump (&strm, interpreter.GetDebugger().GetExecutionContext().target, i); + symbol->Dump (&strm, interpreter.GetExecutionContext().target, i); } strm.IndentLess (); return num_matches; @@ -338,9 +340,9 @@ DumpSymbolContextList (CommandInterpreter &interpreter, Stream &strm, SymbolCont { if (sc.line_entry.range.GetBaseAddress().IsValid()) { - lldb::addr_t vm_addr = sc.line_entry.range.GetBaseAddress().GetLoadAddress(interpreter.GetDebugger().GetExecutionContext().target); + lldb::addr_t vm_addr = sc.line_entry.range.GetBaseAddress().GetLoadAddress(interpreter.GetExecutionContext().target); int addr_size = sizeof (addr_t); - Process *process = interpreter.GetDebugger().GetExecutionContext().process; + Process *process = interpreter.GetExecutionContext().process; if (process) addr_size = process->GetTarget().GetArchitecture().GetAddressByteSize(); if (vm_addr != LLDB_INVALID_ADDRESS) @@ -351,7 +353,7 @@ DumpSymbolContextList (CommandInterpreter &interpreter, Stream &strm, SymbolCont strm.PutCString(" in "); } } - sc.DumpStopContext(&strm, interpreter.GetDebugger().GetExecutionContext().process, sc.line_entry.range.GetBaseAddress(), true, true, false); + sc.DumpStopContext(&strm, interpreter.GetExecutionContext().process, sc.line_entry.range.GetBaseAddress(), true, true, false); } } strm.IndentLess (); @@ -1050,7 +1052,7 @@ public: } else { - ExecutionContext exe_ctx(m_interpreter.GetDebugger().GetExecutionContext()); + ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); uint32_t total_num_dumped = 0; uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); @@ -1233,9 +1235,11 @@ public: Module *module = target->GetImages().GetModulePointerAtIndex(image_idx); strm.Printf("[%3u] ", image_idx); + bool dump_object_name = false; if (m_options.m_format_array.empty()) { DumpFullpath(strm, &module->GetFileSpec(), 0); + dump_object_name = true; } else { @@ -1254,6 +1258,7 @@ public: case 'f': DumpFullpath (strm, &module->GetFileSpec(), width); + dump_object_name = true; break; case 'd': @@ -1262,6 +1267,7 @@ public: case 'b': DumpBasename (strm, &module->GetFileSpec(), width); + dump_object_name = true; break; case 's': @@ -1277,6 +1283,7 @@ public: DumpBasename(strm, &symbol_file->GetObjectFile()->GetFileSpec(), width); else DumpFullpath (strm, &symbol_file->GetObjectFile()->GetFileSpec(), width); + dump_object_name = true; break; } } @@ -1291,8 +1298,15 @@ public: default: break; } + } } + if (dump_object_name) + { + const char *object_name = module->GetObjectName().GetCString(); + if (object_name) + strm.Printf ("(%s)", object_name); + } strm.EOL(); } result.SetStatus (eReturnStatusSuccessFinishResult); @@ -1682,16 +1696,16 @@ protected: OptionDefinition CommandObjectImageLookup::CommandOptions::g_option_table[] = { -{ LLDB_OPT_SET_1, true, "address", 'a', required_argument, NULL, 0, eArgTypeAddress, "Lookup an address in one or more executable images."}, -{ LLDB_OPT_SET_1, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset, "When looking up an address subtract <offset> from any addresses before doing the lookup."}, -{ LLDB_OPT_SET_2, true, "symbol", 's', required_argument, NULL, 0, eArgTypeSymbol, "Lookup a symbol by name in the symbol tables in one or more executable images."}, -{ LLDB_OPT_SET_2, false, "regex", 'r', no_argument, NULL, 0, eArgTypeNone, "The <name> argument for name lookups are regular expressions."}, -{ LLDB_OPT_SET_3, true, "file", 'f', required_argument, NULL, 0, eArgTypeFilename, "Lookup a file by fullpath or basename in one or more executable images."}, -{ LLDB_OPT_SET_3, false, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum, "Lookup a line number in a file (must be used in conjunction with --file)."}, -{ LLDB_OPT_SET_3, false, "no-inlines", 'i', no_argument, NULL, 0, eArgTypeNone, "Check inline line entries (must be used in conjunction with --file)."}, -{ LLDB_OPT_SET_4, true, "function", 'n', required_argument, NULL, 0, eArgTypeFunctionName, "Lookup a function by name in the debug symbols in one or more executable images."}, -{ LLDB_OPT_SET_5, true, "type", 't', required_argument, NULL, 0, eArgTypeName, "Lookup a type by name in the debug symbols in one or more executable images."}, -{ LLDB_OPT_SET_ALL, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone, "Enable verbose lookup information."}, +{ LLDB_OPT_SET_1, true, "address", 'a', required_argument, NULL, 0, eArgTypeAddress, "Lookup an address in one or more executable images."}, +{ LLDB_OPT_SET_1, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset, "When looking up an address subtract <offset> from any addresses before doing the lookup."}, +{ LLDB_OPT_SET_2, true, "symbol", 's', required_argument, NULL, 0, eArgTypeSymbol, "Lookup a symbol by name in the symbol tables in one or more executable images."}, +{ LLDB_OPT_SET_2, false, "regex", 'r', no_argument, NULL, 0, eArgTypeNone, "The <name> argument for name lookups are regular expressions."}, +{ LLDB_OPT_SET_3, true, "file", 'f', required_argument, NULL, 0, eArgTypeFilename, "Lookup a file by fullpath or basename in one or more executable images."}, +{ LLDB_OPT_SET_3, false, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum, "Lookup a line number in a file (must be used in conjunction with --file)."}, +{ LLDB_OPT_SET_3, false, "no-inlines", 'i', no_argument, NULL, 0, eArgTypeNone, "Check inline line entries (must be used in conjunction with --file)."}, +{ LLDB_OPT_SET_4, true, "function", 'n', required_argument, NULL, 0, eArgTypeFunctionName, "Lookup a function by name in the debug symbols in one or more executable images."}, +{ LLDB_OPT_SET_5, true, "type", 't', required_argument, NULL, 0, eArgTypeName, "Lookup a type by name in the debug symbols in one or more executable images."}, +{ LLDB_OPT_SET_ALL, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone, "Enable verbose lookup information."}, { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } }; diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp index c731c61836c..7993f5462eb 100644 --- a/lldb/source/Commands/CommandObjectMemory.cpp +++ b/lldb/source/Commands/CommandObjectMemory.cpp @@ -240,7 +240,7 @@ public: Execute (Args& command, CommandReturnObject &result) { - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; if (process == NULL) { result.AppendError("need a process to read memory"); @@ -415,7 +415,7 @@ CommandObjectMemoryRead::CommandOptions::g_option_table[] = { SET1 , false, "format", 'f', required_argument, NULL, 0, eArgTypeFormat, "The format that will be used to display the memory. Defaults to bytes with ASCII (--format=Y)."}, { SET1 , false, "size", 's', required_argument, NULL, 0, eArgTypeByteSize, "The size in bytes to use when displaying with the selected format."}, { SET1 , false, "num-per-line", 'l', required_argument, NULL, 0, eArgTypeNumberPerLine,"The number of items per line to display."}, -{ SET1 , false, "count", 'c', required_argument, NULL, 0, eArgTypeCount, "The number of total items to display."}, +{ SET1 | SET2, false, "count", 'c', required_argument, NULL, 0, eArgTypeCount, "The number of total items to display."}, { SET1 | SET2, false, "outfile", 'o', required_argument, NULL, 0, eArgTypeFilename, "Dump memory read results into a file."}, { SET1 | SET2, false, "append", 'a', no_argument, NULL, 0, eArgTypeNone, "Append memory read results to 'outfile'."}, { SET2, false, "binary", 'b', no_argument, NULL, 0, eArgTypeNone, "If true, memory will be saved as binary. If false, the memory is saved save as an ASCII dump that uses the format, size, count and number per line settings."}, @@ -591,7 +591,7 @@ public: Execute (Args& command, CommandReturnObject &result) { - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; if (process == NULL) { result.AppendError("need a process to read memory"); diff --git a/lldb/source/Commands/CommandObjectPlatform.cpp b/lldb/source/Commands/CommandObjectPlatform.cpp index a72b0db4d14..730a1b3dd01 100644 --- a/lldb/source/Commands/CommandObjectPlatform.cpp +++ b/lldb/source/Commands/CommandObjectPlatform.cpp @@ -413,6 +413,134 @@ public: return result.Succeeded(); } }; +//---------------------------------------------------------------------- +// "platform process launch" +//---------------------------------------------------------------------- +class CommandObjectPlatformProcessLaunch : public CommandObject +{ +public: + CommandObjectPlatformProcessLaunch (CommandInterpreter &interpreter) : + CommandObject (interpreter, + "platform process launch", + "Launch a new process on a remote platform.", + "platform process launch program", + 0), + m_options (interpreter) + { + } + + virtual + ~CommandObjectPlatformProcessLaunch () + { + } + + virtual bool + Execute (Args& args, CommandReturnObject &result) + { + PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); + + if (platform_sp) + { + Error error; + const uint32_t argc = args.GetArgumentCount(); + Target *target = m_interpreter.GetExecutionContext().target; + ModuleSP exe_module_sp; + if (target) + { + exe_module_sp = target->GetExecutableModule(); + if (exe_module_sp) + { + m_options.launch_info.GetExecutableFile () = exe_module_sp->GetFileSpec(); + char exe_path[PATH_MAX]; + if (m_options.launch_info.GetExecutableFile ().GetPath (exe_path, sizeof(exe_path))) + m_options.launch_info.GetArguments().AppendArgument (exe_path); + m_options.launch_info.GetArchitecture() = exe_module_sp->GetArchitecture(); + } + } + + if (argc > 0) + { + if (m_options.launch_info.GetExecutableFile ()) + { + // We already have an executable file, so we will use this + // and all arguments to this function are extra arguments + m_options.launch_info.GetArguments().AppendArguments (args); + } + else + { + // We don't have any file yet, so the first argument is our + // executable, and the rest are program arguments + const bool first_arg_is_executable = true; + m_options.launch_info.SetArgumentsFromArgs (args, + first_arg_is_executable, + first_arg_is_executable); + } + } + + if (m_options.launch_info.GetExecutableFile ()) + { + Debugger &debugger = m_interpreter.GetDebugger(); + + if (argc == 0) + { + lldb::UserSettingsControllerSP process_usc_sp (Process::GetSettingsController ()); + if (process_usc_sp) + { + SettableVariableType type; + StringList settings_args (process_usc_sp->GetVariable ("process.run-args", + type, + m_interpreter.GetDebugger().GetInstanceName().GetCString(), + error)); + if (error.Success()) + { + const size_t num_settings_args = settings_args.GetSize(); + for (size_t i=0; i<num_settings_args; ++i) + m_options.launch_info.GetArguments().AppendArgument (settings_args.GetStringAtIndex(i)); + } + } + } + + ProcessSP process_sp (platform_sp->DebugProcess (m_options.launch_info, + debugger, + target, + debugger.GetListener(), + error)); + if (process_sp && process_sp->IsAlive()) + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + return true; + } + + if (error.Success()) + result.AppendError ("process launch failed"); + else + result.AppendError (error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + else + { + result.AppendError ("'platform process launch' uses the current target file and arguments, or the executable and its arguments can be specified in this command"); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + result.AppendError ("no platform is selected\n"); + } + return result.Succeeded(); + } + + virtual Options * + GetOptions () + { + return &m_options; + } + +protected: + ProcessLaunchCommandOptions m_options; +}; + //---------------------------------------------------------------------- @@ -454,11 +582,11 @@ public: lldb::pid_t pid = m_options.match_info.GetProcessInfo().GetProcessID(); if (pid != LLDB_INVALID_PROCESS_ID) { - ProcessInfo proc_info; + ProcessInstanceInfo proc_info; if (platform_sp->GetProcessInfo (pid, proc_info)) { - ProcessInfo::DumpTableHeader (ostrm, platform_sp.get()); - proc_info.DumpAsTableRow(ostrm, platform_sp.get()); + ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose); + proc_info.DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose); result.SetStatus (eReturnStatusSuccessFinishResult); } else @@ -469,24 +597,25 @@ public: } else { - ProcessInfoList proc_infos; + ProcessInstanceInfoList proc_infos; const uint32_t matches = platform_sp->FindProcesses (m_options.match_info, proc_infos); - if (matches == 0) + const char *match_desc = NULL; + const char *match_name = m_options.match_info.GetProcessInfo().GetName(); + if (match_name && match_name[0]) { - const char *match_desc = NULL; - const char *match_name = m_options.match_info.GetProcessInfo().GetName(); - if (match_name && match_name[0]) + switch (m_options.match_info.GetNameMatchType()) { - switch (m_options.match_info.GetNameMatchType()) - { - case eNameMatchIgnore: break; - case eNameMatchEquals: match_desc = "match"; break; - case eNameMatchContains: match_desc = "contains"; break; - case eNameMatchStartsWith: match_desc = "starts with"; break; - case eNameMatchEndsWith: match_desc = "end with"; break; - case eNameMatchRegularExpression: match_desc = "match the regular expression"; break; - } + case eNameMatchIgnore: break; + case eNameMatchEquals: match_desc = "matched"; break; + case eNameMatchContains: match_desc = "contained"; break; + case eNameMatchStartsWith: match_desc = "started with"; break; + case eNameMatchEndsWith: match_desc = "ended with"; break; + case eNameMatchRegularExpression: match_desc = "matched the regular expression"; break; } + } + + if (matches == 0) + { if (match_desc) result.AppendErrorWithFormat ("no processes were found that %s \"%s\" on the \"%s\" platform\n", match_desc, @@ -498,11 +627,19 @@ public: } else { - - ProcessInfo::DumpTableHeader (ostrm, platform_sp.get()); + result.AppendMessageWithFormat ("%u matching process%s found on \"%s\"", + matches, + matches > 1 ? "es were" : " was", + platform_sp->GetName()); + if (match_desc) + result.AppendMessageWithFormat (" whose name %s \"%s\"", + match_desc, + match_name); + result.AppendMessageWithFormat ("\n"); + ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose); for (uint32_t i=0; i<matches; ++i) { - proc_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(ostrm, platform_sp.get()); + proc_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose); } } } @@ -567,7 +704,7 @@ protected: break; case 'u': - match_info.GetProcessInfo().SetRealUserID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success)); + match_info.GetProcessInfo().SetUserID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success)); if (!success) error.SetErrorStringWithFormat("invalid user ID string: '%s'", option_arg); break; @@ -579,7 +716,7 @@ protected: break; case 'g': - match_info.GetProcessInfo().SetRealGroupID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success)); + match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success)); if (!success) error.SetErrorStringWithFormat("invalid group ID string: '%s'", option_arg); break; @@ -596,26 +733,37 @@ protected: case 'n': match_info.GetProcessInfo().SetName (option_arg); - if (match_info.GetNameMatchType() == eNameMatchIgnore) - match_info.SetNameMatchType (eNameMatchEquals); + match_info.SetNameMatchType (eNameMatchEquals); break; case 'e': + match_info.GetProcessInfo().SetName (option_arg); match_info.SetNameMatchType (eNameMatchEndsWith); break; case 's': + match_info.GetProcessInfo().SetName (option_arg); match_info.SetNameMatchType (eNameMatchStartsWith); break; case 'c': + match_info.GetProcessInfo().SetName (option_arg); match_info.SetNameMatchType (eNameMatchContains); break; case 'r': + match_info.GetProcessInfo().SetName (option_arg); match_info.SetNameMatchType (eNameMatchRegularExpression); break; + case 'A': + show_args = true; + break; + + case 'v': + verbose = true; + break; + default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; @@ -628,6 +776,8 @@ protected: ResetOptionValues () { match_info.Clear(); + show_args = false; + verbose = false; } const OptionDefinition* @@ -642,7 +792,9 @@ protected: // Instance variables to hold the values for command options. - ProcessInfoMatch match_info; + ProcessInstanceInfoMatch match_info; + bool show_args; + bool verbose; }; CommandOptions m_options; }; @@ -650,49 +802,23 @@ protected: OptionDefinition CommandObjectPlatformProcessList::CommandOptions::g_option_table[] = { -{ LLDB_OPT_SET_1, false, "pid" , 'p', required_argument, NULL, 0, eArgTypePid , "List the process info for a specific process ID." }, -{ LLDB_OPT_SET_2| - LLDB_OPT_SET_3| - LLDB_OPT_SET_4| - LLDB_OPT_SET_5, true , "name" , 'n', required_argument, NULL, 0, eArgTypeProcessName , "Find processes that match the supplied name." }, -{ LLDB_OPT_SET_2, false, "ends-with" , 'e', no_argument , NULL, 0, eArgTypeNone , "Process names must end with the name supplied with the --name option." }, -{ LLDB_OPT_SET_3, false, "starts-with" , 's', no_argument , NULL, 0, eArgTypeNone , "Process names must start with the name supplied with the --name option." }, -{ LLDB_OPT_SET_4, false, "contains" , 'c', no_argument , NULL, 0, eArgTypeNone , "Process names must contain the name supplied with the --name option." }, -{ LLDB_OPT_SET_5, false, "regex" , 'r', no_argument , NULL, 0, eArgTypeNone , "Process names must match name supplied with the --name option as a regular expression." }, -{ LLDB_OPT_SET_2| - LLDB_OPT_SET_3| - LLDB_OPT_SET_4| - LLDB_OPT_SET_5| - LLDB_OPT_SET_6, false, "parent" , 'P', required_argument, NULL, 0, eArgTypePid , "Find processes that have a matching parent process ID." }, -{ LLDB_OPT_SET_2| - LLDB_OPT_SET_3| - LLDB_OPT_SET_4| - LLDB_OPT_SET_5| - LLDB_OPT_SET_6, false, "uid" , 'u', required_argument, NULL, 0, eArgTypeNone , "Find processes that have a matching user ID." }, -{ LLDB_OPT_SET_2| - LLDB_OPT_SET_3| - LLDB_OPT_SET_4| - LLDB_OPT_SET_5| - LLDB_OPT_SET_6, false, "euid" , 'U', required_argument, NULL, 0, eArgTypeNone , "Find processes that have a matching effective user ID." }, -{ LLDB_OPT_SET_2| - LLDB_OPT_SET_3| - LLDB_OPT_SET_4| - LLDB_OPT_SET_5| - LLDB_OPT_SET_6, false, "gid" , 'g', required_argument, NULL, 0, eArgTypeNone , "Find processes that have a matching group ID." }, -{ LLDB_OPT_SET_2| - LLDB_OPT_SET_3| - LLDB_OPT_SET_4| - LLDB_OPT_SET_5| - LLDB_OPT_SET_6, false, "egid" , 'G', required_argument, NULL, 0, eArgTypeNone , "Find processes that have a matching effective group ID." }, -{ LLDB_OPT_SET_2| - LLDB_OPT_SET_3| - LLDB_OPT_SET_4| - LLDB_OPT_SET_5| - LLDB_OPT_SET_6, false, "arch" , 'a', required_argument, NULL, 0, eArgTypeArchitecture , "Find processes that have a matching architecture." }, -{ 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone , NULL } +{ LLDB_OPT_SET_1, false, "pid" , 'p', required_argument, NULL, 0, eArgTypePid , "List the process info for a specific process ID." }, +{ LLDB_OPT_SET_2, true , "name" , 'n', required_argument, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that match a string." }, +{ LLDB_OPT_SET_3, true , "ends-with" , 'e', required_argument, NULL, 0, eArgTypeNone , "Find processes with executable basenames that end with a string." }, +{ LLDB_OPT_SET_4, true , "starts-with" , 's', required_argument, NULL, 0, eArgTypeNone , "Find processes with executable basenames that start with a string." }, +{ LLDB_OPT_SET_5, true , "contains" , 'c', required_argument, NULL, 0, eArgTypeNone , "Find processes with executable basenames that contain a string." }, +{ LLDB_OPT_SET_6, true , "regex" , 'r', required_argument, NULL, 0, eArgTypeNone , "Find processes with executable basenames that match a regular expression." }, +{ ~LLDB_OPT_SET_1, false, "parent" , 'P', required_argument, NULL, 0, eArgTypePid , "Find processes that have a matching parent process ID." }, +{ ~LLDB_OPT_SET_1, false, "uid" , 'u', required_argument, NULL, 0, eArgTypeNone , "Find processes that have a matching user ID." }, +{ ~LLDB_OPT_SET_1, false, "euid" , 'U', required_argument, NULL, 0, eArgTypeNone , "Find processes that have a matching effective user ID." }, +{ ~LLDB_OPT_SET_1, false, "gid" , 'g', required_argument, NULL, 0, eArgTypeNone , "Find processes that have a matching group ID." }, +{ ~LLDB_OPT_SET_1, false, "egid" , 'G', required_argument, NULL, 0, eArgTypeNone , "Find processes that have a matching effective group ID." }, +{ ~LLDB_OPT_SET_1, false, "arch" , 'a', required_argument, NULL, 0, eArgTypeArchitecture , "Find processes that have a matching architecture." }, +{ LLDB_OPT_SET_ALL, false, "show-args" , 'A', no_argument , NULL, 0, eArgTypeNone , "Show process arguments instead of the process executable basename." }, +{ LLDB_OPT_SET_ALL, false, "verbose" , 'v', no_argument , NULL, 0, eArgTypeNone , "Enable verbose output." }, +{ 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone , NULL } }; - //---------------------------------------------------------------------- // "platform process info" //---------------------------------------------------------------------- @@ -746,7 +872,7 @@ public: lldb::pid_t pid = Args::StringToUInt32 (arg, LLDB_INVALID_PROCESS_ID, 0, &success); if (success) { - ProcessInfo proc_info; + ProcessInstanceInfo proc_info; if (platform_sp->GetProcessInfo (pid, proc_info)) { ostrm.Printf ("Process information for process %i:\n", pid); @@ -805,7 +931,7 @@ public: "platform process [attach|launch|list] ...") { // LoadSubCommand ("attach", CommandObjectSP (new CommandObjectPlatformProcessAttach (interpreter))); -// LoadSubCommand ("launch", CommandObjectSP (new CommandObjectPlatformProcessLaunch (interpreter))); + LoadSubCommand ("launch", CommandObjectSP (new CommandObjectPlatformProcessLaunch (interpreter))); LoadSubCommand ("info" , CommandObjectSP (new CommandObjectPlatformProcessInfo (interpreter))); LoadSubCommand ("list" , CommandObjectSP (new CommandObjectPlatformProcessList (interpreter))); diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp index 116309d94d5..1fc573b9266 100644 --- a/lldb/source/Commands/CommandObjectProcess.cpp +++ b/lldb/source/Commands/CommandObjectProcess.cpp @@ -175,7 +175,7 @@ public: exe_module->GetFileSpec().GetPath(filename, sizeof(filename)); StateType state = eStateInvalid; - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; if (process) { state = process->GetState(); @@ -266,7 +266,10 @@ public: if (process->GetDisableASLR()) launch_flags |= eLaunchFlagDisableASLR; - + + if (m_options.in_new_tty) + launch_flags |= eLaunchFlagLaunchInTTY; + if (m_options.no_stdio) launch_flags |= eLaunchFlagDisableSTDIO; else if (!m_options.in_new_tty @@ -287,52 +290,35 @@ public: if (!m_options.working_dir.empty()) working_dir = m_options.working_dir.c_str(); - if (m_options.in_new_tty) + const char * stdin_path = NULL; + const char * stdout_path = NULL; + const char * stderr_path = NULL; + + // Were any standard input/output/error paths given on the command line? + if (m_options.stdin_path.empty() && + m_options.stdout_path.empty() && + m_options.stderr_path.empty()) { - - lldb::pid_t pid = Host::LaunchInNewTerminal (m_options.tty_name.c_str(), - inferior_argv, - inferior_envp, - working_dir, - &exe_module->GetArchitecture(), - true, - process->GetDisableASLR()); - - if (pid != LLDB_INVALID_PROCESS_ID) - error = process->Attach (pid); + // No standard file handles were given on the command line, check + // with the process object in case they were give using "set settings" + stdin_path = process->GetStandardInputPath(); + stdout_path = process->GetStandardOutputPath(); + stderr_path = process->GetStandardErrorPath(); } else { - const char * stdin_path = NULL; - const char * stdout_path = NULL; - const char * stderr_path = NULL; - - // Were any standard input/output/error paths given on the command line? - if (m_options.stdin_path.empty() && - m_options.stdout_path.empty() && - m_options.stderr_path.empty()) - { - // No standard file handles were given on the command line, check - // with the process object in case they were give using "set settings" - stdin_path = process->GetStandardInputPath(); - stdout_path = process->GetStandardOutputPath(); - stderr_path = process->GetStandardErrorPath(); - } - else - { - stdin_path = m_options.stdin_path.empty() ? NULL : m_options.stdin_path.c_str(); - stdout_path = m_options.stdout_path.empty() ? NULL : m_options.stdout_path.c_str(); - stderr_path = m_options.stderr_path.empty() ? NULL : m_options.stderr_path.c_str(); - } - - error = process->Launch (inferior_argv, - inferior_envp, - launch_flags, - stdin_path, - stdout_path, - stderr_path, - working_dir); + stdin_path = m_options.stdin_path.empty() ? NULL : m_options.stdin_path.c_str(); + stdout_path = m_options.stdout_path.empty() ? NULL : m_options.stdout_path.c_str(); + stderr_path = m_options.stderr_path.empty() ? NULL : m_options.stderr_path.c_str(); } + + error = process->Launch (inferior_argv, + inferior_envp, + launch_flags, + stdin_path, + stdout_path, + stderr_path, + working_dir); if (error.Success()) { @@ -521,11 +507,11 @@ public: const char *partial_name = NULL; partial_name = input.GetArgumentAtIndex(opt_arg_pos); - PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform ()); + PlatformSP platform_sp (m_interpreter.GetPlatform (true)); if (platform_sp) { - ProcessInfoList process_infos; - ProcessInfoMatch match_info; + ProcessInstanceInfoList process_infos; + ProcessInstanceInfoMatch match_info; if (partial_name) { match_info.GetProcessInfo().SetName(partial_name); @@ -579,7 +565,7 @@ public: Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); bool synchronous_execution = m_interpreter.GetSynchronous (); - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; StateType state = eStateInvalid; if (process) { @@ -707,11 +693,11 @@ public: if (attach_pid == LLDB_INVALID_PROCESS_ID && wait_name != NULL) { - ProcessInfoList process_infos; - PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform ()); + ProcessInstanceInfoList process_infos; + PlatformSP platform_sp (m_interpreter.GetPlatform (true)); if (platform_sp) { - ProcessInfoMatch match_info (wait_name, eNameMatchEquals); + ProcessInstanceInfoMatch match_info (wait_name, eNameMatchEquals); platform_sp->FindProcesses (match_info, process_infos); } if (process_infos.GetSize() > 1) @@ -860,7 +846,7 @@ public: Execute (Args& command, CommandReturnObject &result) { - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; bool synchronous_execution = m_interpreter.GetSynchronous (); if (process == NULL) @@ -947,7 +933,7 @@ public: Execute (Args& command, CommandReturnObject &result) { - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; if (process == NULL) { result.AppendError ("must have a valid process in order to detach"); @@ -1057,7 +1043,7 @@ public: TargetSP target_sp (m_interpreter.GetDebugger().GetSelectedTarget()); Error error; - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; if (process) { if (process->IsAlive()) @@ -1172,7 +1158,7 @@ public: Execute (Args& command, CommandReturnObject &result) { - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; if (process == NULL) { result.AppendError ("must have a valid process in order to load a shared library"); @@ -1230,7 +1216,7 @@ public: Execute (Args& command, CommandReturnObject &result) { - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; if (process == NULL) { result.AppendError ("must have a valid process in order to load a shared library"); @@ -1307,7 +1293,7 @@ public: Execute (Args& command, CommandReturnObject &result) { - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; if (process == NULL) { result.AppendError ("no process to signal"); @@ -1382,7 +1368,7 @@ public: Execute (Args& command, CommandReturnObject &result) { - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; if (process == NULL) { result.AppendError ("no process to halt"); @@ -1444,7 +1430,7 @@ public: Execute (Args& command, CommandReturnObject &result) { - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; if (process == NULL) { result.AppendError ("no process to kill"); @@ -1507,7 +1493,7 @@ public: { Stream &output_stream = result.GetOutputStream(); result.SetStatus (eReturnStatusSuccessFinishNoResult); - ExecutionContext exe_ctx(m_interpreter.GetDebugger().GetExecutionContext()); + ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); if (exe_ctx.process) { const StateType state = exe_ctx.process->GetState(); diff --git a/lldb/source/Commands/CommandObjectRegister.cpp b/lldb/source/Commands/CommandObjectRegister.cpp index d50d7d71ecf..2607854ed2e 100644 --- a/lldb/source/Commands/CommandObjectRegister.cpp +++ b/lldb/source/Commands/CommandObjectRegister.cpp @@ -75,7 +75,7 @@ public: { Stream &output_stream = result.GetOutputStream(); DataExtractor reg_data; - ExecutionContext exe_ctx(m_interpreter.GetDebugger().GetExecutionContext()); + ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); RegisterContext *reg_context = exe_ctx.GetRegisterContext (); if (reg_context) @@ -274,7 +274,7 @@ public: ) { DataExtractor reg_data; - ExecutionContext exe_ctx(m_interpreter.GetDebugger().GetExecutionContext()); + ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); RegisterContext *reg_context = exe_ctx.GetRegisterContext (); if (reg_context) diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp index 9fbf6024a39..29b17dc1d42 100644 --- a/lldb/source/Commands/CommandObjectSource.cpp +++ b/lldb/source/Commands/CommandObjectSource.cpp @@ -272,7 +272,7 @@ public: result.SetStatus (eReturnStatusFailed); } - ExecutionContext exe_ctx(m_interpreter.GetDebugger().GetExecutionContext()); + ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); if (!m_options.symbol_name.empty()) { diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index abb6f5f1cef..f321000768d 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -362,7 +362,7 @@ public: if (command.GetArgumentCount() == 0) { - ExecutionContext exe_ctx(m_interpreter.GetDebugger().GetExecutionContext()); + ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); if (exe_ctx.thread) { if (DisplayFramesForExecutionContext (exe_ctx.thread, @@ -386,7 +386,7 @@ public: } else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0) { - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; uint32_t num_threads = process->GetThreadList().GetSize(); for (uint32_t i = 0; i < num_threads; i++) { @@ -412,7 +412,7 @@ public: else { uint32_t num_args = command.GetArgumentCount(); - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; std::vector<ThreadSP> thread_sps; for (uint32_t i = 0; i < num_args; i++) @@ -610,7 +610,7 @@ public: CommandReturnObject &result ) { - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; bool synchronous_execution = m_interpreter.GetSynchronous(); if (process == NULL) @@ -851,7 +851,7 @@ public: return false; } - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; if (process == NULL) { result.AppendError ("no process exists. Cannot continue"); @@ -1115,7 +1115,7 @@ public: return false; } - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; if (process == NULL) { result.AppendError ("need a valid process to step"); @@ -1308,7 +1308,7 @@ public: CommandReturnObject &result ) { - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; if (process == NULL) { result.AppendError ("no process"); @@ -1378,7 +1378,7 @@ public: { Stream &strm = result.GetOutputStream(); result.SetStatus (eReturnStatusSuccessFinishNoResult); - ExecutionContext exe_ctx(m_interpreter.GetDebugger().GetExecutionContext()); + ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); if (exe_ctx.process) { const StateType state = exe_ctx.process->GetState(); diff --git a/lldb/source/Core/ConnectionFileDescriptor.cpp b/lldb/source/Core/ConnectionFileDescriptor.cpp index e5b27bc8624..ce306c90e4d 100644 --- a/lldb/source/Core/ConnectionFileDescriptor.cpp +++ b/lldb/source/Core/ConnectionFileDescriptor.cpp @@ -459,6 +459,41 @@ ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *err } ConnectionStatus +ConnectionFileDescriptor::NamedSocketConnect (const char *socket_name, Error *error_ptr) +{ + Close (m_fd, NULL); + m_is_socket = true; + + // Open the socket that was passed in as an option + struct sockaddr_un saddr_un; + m_fd = ::socket (AF_UNIX, SOCK_STREAM, 0); + if (m_fd == -1) + { + if (error_ptr) + error_ptr->SetErrorToErrno(); + return eConnectionStatusError; + } + + saddr_un.sun_family = AF_UNIX; + ::strncpy(saddr_un.sun_path, socket_name, sizeof(saddr_un.sun_path) - 1); + saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; +#if defined(__APPLE__) || defined(__FreeBSD__) + saddr_un.sun_len = SUN_LEN (&saddr_un); +#endif + + if (::connect (m_fd, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0) + { + if (error_ptr) + error_ptr->SetErrorToErrno(); + Close (m_fd, NULL); + return eConnectionStatusError; + } + if (error_ptr) + error_ptr->Clear(); + return eConnectionStatusSuccess; +} + +ConnectionStatus ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_ptr) { lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index ca0dde920bd..073986ac3a9 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -229,7 +229,6 @@ Debugger::Debugger () : m_listener ("lldb.Debugger"), m_source_manager (), m_command_interpreter_ap (new CommandInterpreter (*this, eScriptLanguageDefault, false)), - m_exe_ctx (), m_input_readers (), m_input_reader_data () { @@ -556,51 +555,6 @@ Debugger::ActivateInputReader (const InputReaderSP &reader_sp) } } -void -Debugger::UpdateExecutionContext (ExecutionContext *override_context) -{ - m_exe_ctx.Clear(); - - if (override_context != NULL) - { - m_exe_ctx.target = override_context->target; - m_exe_ctx.process = override_context->process; - m_exe_ctx.thread = override_context->thread; - m_exe_ctx.frame = override_context->frame; - } - else - { - TargetSP target_sp (GetSelectedTarget()); - if (target_sp) - { - m_exe_ctx.target = target_sp.get(); - m_exe_ctx.process = target_sp->GetProcessSP().get(); - if (m_exe_ctx.process && m_exe_ctx.process->IsAlive() && !m_exe_ctx.process->IsRunning()) - { - m_exe_ctx.thread = m_exe_ctx.process->GetThreadList().GetSelectedThread().get(); - if (m_exe_ctx.thread == NULL) - { - m_exe_ctx.thread = m_exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get(); - // If we didn't have a selected thread, select one here. - if (m_exe_ctx.thread != NULL) - m_exe_ctx.process->GetThreadList().SetSelectedThreadByID(m_exe_ctx.thread->GetID()); - } - if (m_exe_ctx.thread) - { - m_exe_ctx.frame = m_exe_ctx.thread->GetSelectedFrame().get(); - if (m_exe_ctx.frame == NULL) - { - m_exe_ctx.frame = m_exe_ctx.thread->GetStackFrameAtIndex (0).get(); - // If we didn't have a selected frame select one here. - if (m_exe_ctx.frame != NULL) - m_exe_ctx.thread->SetSelectedFrame(m_exe_ctx.frame); - } - } - } - } - } -} - DebuggerSP Debugger::FindDebuggerWithID (lldb::user_id_t id) { diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 7ceff588d16..0b314651a89 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -28,6 +28,7 @@ Module::Module(const FileSpec& file_spec, const ArchSpec& arch, const ConstStrin m_file (file_spec), m_platform_file(), m_object_name (), + m_object_offset (object_offset), m_objfile_ap (), m_symfile_ap (), m_ast (), @@ -534,7 +535,7 @@ Module::GetObjectFile() m_did_load_objfile = true; Timer scoped_timer(__PRETTY_FUNCTION__, "Module::GetObjectFile () module = %s", GetFileSpec().GetFilename().AsCString("")); - m_objfile_ap.reset(ObjectFile::FindPlugin(this, &m_file, 0, m_file.GetByteSize())); + m_objfile_ap.reset(ObjectFile::FindPlugin(this, &m_file, m_object_offset, m_file.GetByteSize())); } return m_objfile_ap.get(); } diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index e2e0aa2a075..18f3bbf5bc7 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -63,36 +63,46 @@ ModuleList::~ModuleList() void ModuleList::Append (ModuleSP &module_sp) { - Mutex::Locker locker(m_modules_mutex); - m_modules.push_back(module_sp); + if (module_sp) + { + Mutex::Locker locker(m_modules_mutex); + m_modules.push_back(module_sp); + } } bool ModuleList::AppendIfNeeded (ModuleSP &module_sp) { - Mutex::Locker locker(m_modules_mutex); - collection::iterator pos, end = m_modules.end(); - for (pos = m_modules.begin(); pos != end; ++pos) + if (module_sp) { - if (pos->get() == module_sp.get()) - return false; // Already in the list + Mutex::Locker locker(m_modules_mutex); + collection::iterator pos, end = m_modules.end(); + for (pos = m_modules.begin(); pos != end; ++pos) + { + if (pos->get() == module_sp.get()) + return false; // Already in the list + } + // Only push module_sp on the list if it wasn't already in there. + m_modules.push_back(module_sp); + return true; } - // Only push module_sp on the list if it wasn't already in there. - m_modules.push_back(module_sp); - return true; + return false; } bool ModuleList::Remove (ModuleSP &module_sp) { - Mutex::Locker locker(m_modules_mutex); - collection::iterator pos, end = m_modules.end(); - for (pos = m_modules.begin(); pos != end; ++pos) + if (module_sp) { - if (pos->get() == module_sp.get()) + Mutex::Locker locker(m_modules_mutex); + collection::iterator pos, end = m_modules.end(); + for (pos = m_modules.begin(); pos != end; ++pos) { - m_modules.erase (pos); - return true; + if (pos->get() == module_sp.get()) + { + m_modules.erase (pos); + return true; + } } } return false; diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 5d984020da2..a6654722779 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -1138,14 +1138,14 @@ Host::GetOSKernelDescription (std::string &s) } uint32_t -Host::FindProcesses (const ProcessInfoMatch &match_info, ProcessInfoList &process_infos) +Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) { process_infos.Clear(); return process_infos.GetSize(); } bool -Host::GetProcessInfo (lldb::pid_t pid, ProcessInfo &process_info) +Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) { process_info.Clear(); return false; diff --git a/lldb/source/Host/macosx/Host.mm b/lldb/source/Host/macosx/Host.mm index 65d60d748ec..28d8d81bb67 100644 --- a/lldb/source/Host/macosx/Host.mm +++ b/lldb/source/Host/macosx/Host.mm @@ -14,6 +14,7 @@ #include <grp.h> #include <libproc.h> #include <pwd.h> +#include <spawn.h> #include <stdio.h> #include <sys/proc.h> #include <sys/stat.h> @@ -25,12 +26,15 @@ #include "lldb/Core/Communication.h" #include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Core/DataExtractor.h" -#include "lldb/Host/Endian.h" -#include "lldb/Host/FileSpec.h" #include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" +#include "lldb/Host/Endian.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" +#include "lldb/Utility/CleanUp.h" #include "cfcpp/CFCBundle.h" #include "cfcpp/CFCMutableArray.h" @@ -47,6 +51,10 @@ #include <Carbon/Carbon.h> #include <Foundation/Foundation.h> +#ifndef _POSIX_SPAWN_DISABLE_ASLR +#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 +#endif + using namespace lldb; using namespace lldb_private; @@ -414,57 +422,64 @@ tell application \"Terminal\"\n\ do script the_shell_script\n\ end tell\n"; -lldb::pid_t -LaunchInNewTerminalWithAppleScript -( - const char *tty_name, - const char **argv, - const char **envp, - const char *working_dir, - const ArchSpec *arch_spec, - bool stop_at_entry, - bool disable_aslr -) +static Error +LaunchInNewTerminalWithAppleScript (const char *exe_path, + ProcessLaunchInfo &launch_info) { - if (!argv || !argv[0]) - return LLDB_INVALID_PROCESS_ID; + Error error; + if (exe_path == NULL || exe_path[0] == '\0') + { + error.SetErrorString ("invalid executable path"); + return error; + } - std::string unix_socket_name; - - char temp_file_path[PATH_MAX] = "/tmp/XXXXXX"; - if (::mktemp (temp_file_path) == NULL) - return LLDB_INVALID_PROCESS_ID; - - unix_socket_name.assign (temp_file_path); + 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"); + return error; + } StreamString command; FileSpec darwin_debug_file_spec; if (!Host::GetLLDBPath (ePathTypeSupportExecutableDir, darwin_debug_file_spec)) - return LLDB_INVALID_PROCESS_ID; + { + error.SetErrorString ("can't locate the 'darwin-debug' executable"); + return error; + } + darwin_debug_file_spec.GetFilename().SetCString("darwin-debug"); if (!darwin_debug_file_spec.Exists()) - return LLDB_INVALID_PROCESS_ID; + { + error.SetErrorStringWithFormat ("the 'darwin-debug' executable doesn't exists at %s/%s", + darwin_debug_file_spec.GetDirectory().GetCString(), + darwin_debug_file_spec.GetFilename().GetCString()); + return error; + } char launcher_path[PATH_MAX]; darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path)); - if (arch_spec) - command.Printf("arch -arch %s ", arch_spec->GetArchitectureName()); + const ArchSpec &arch_spec = launch_info.GetArchitecture(); + if (arch_spec.IsValid()) + command.Printf("arch -arch %s ", arch_spec.GetArchitectureName()); - command.Printf("'%s' --unix-socket=%s", launcher_path, unix_socket_name.c_str()); + command.Printf("'%s' --unix-socket=%s", launcher_path, unix_socket_name); - if (arch_spec && arch_spec->IsValid()) - command.Printf(" --arch=%s", arch_spec->GetArchitectureName()); + if (arch_spec.IsValid()) + command.Printf(" --arch=%s", arch_spec.GetArchitectureName()); + const char *working_dir = launch_info.GetWorkingDirectory(); if (working_dir) command.Printf(" --working-dir '%s'", working_dir); - if (disable_aslr) + if (launch_info.GetFlags().Test (eLaunchFlagDisableASLR)) command.PutCString(" --disable-aslr"); - command.PutCString(" --"); + command.Printf(" -- '%s'", exe_path); + const char **argv = launch_info.GetArguments().GetConstArgumentVector (); if (argv) { for (size_t i=0; argv[i] != NULL; ++i) @@ -477,17 +492,17 @@ LaunchInNewTerminalWithAppleScript StreamString applescript_source; const char *tty_command = command.GetString().c_str(); - if (tty_name && tty_name[0]) - { - applescript_source.Printf (applscript_in_existing_tty, - tty_command, - tty_name); - } - else - { +// if (tty_name && tty_name[0]) +// { +// applescript_source.Printf (applscript_in_existing_tty, +// tty_command, +// tty_name); +// } +// else +// { applescript_source.Printf (applscript_in_new_tty, tty_command); - } +// } @@ -501,11 +516,15 @@ LaunchInNewTerminalWithAppleScript // Sleep and wait a bit for debugserver to start to listen... ConnectionFileDescriptor file_conn; char connect_url[128]; - ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name.c_str()); + ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name); // Spawn a new thread to accept incoming connection on the connect_url - // so we can grab the pid from the inferior - lldb::thread_t accept_thread = Host::ThreadCreate (unix_socket_name.c_str(), + // so we can grab the pid from the inferior. We have to do this because we + // are sending an AppleScript that will launch a process in Terminal.app, + // in a shell and the shell will fork/exec a couple of times before we get + // to the process that we wanted to launch. So when our process actually + // gets launched, we will handshake with it and get the process ID for it. + lldb::thread_t accept_thread = Host::ThreadCreate (unix_socket_name, AcceptPIDFromInferior, connect_url, &lldb_error); @@ -526,33 +545,14 @@ LaunchInNewTerminalWithAppleScript WaitForProcessToSIGSTOP (pid, 5); } } - ::unlink (unix_socket_name.c_str()); + ::unlink (unix_socket_name); [applescript release]; - return pid; + if (pid != LLDB_INVALID_PROCESS_ID) + launch_info.SetProcessID (pid); + return error; } -#define LLDB_HOST_USE_APPLESCRIPT - -lldb::pid_t -Host::LaunchInNewTerminal -( - const char *tty_name, - const char **argv, - const char **envp, - const char *working_dir, - const ArchSpec *arch_spec, - bool stop_at_entry, - bool disable_aslr -) -{ -#if defined (LLDB_HOST_USE_APPLESCRIPT) - return LaunchInNewTerminalWithAppleScript (tty_name, argv, envp, working_dir, arch_spec, stop_at_entry, disable_aslr); -#else - return LaunchInNewTerminalWithCommandFile (argv, envp, working_dir, arch_spec, stop_at_entry, disable_aslr); -#endif -} - // On MacOSX CrashReporter will display a string for each shared library if // the shared library has an exported symbol named "__crashreporter_info__". @@ -914,8 +914,8 @@ Host::GetOSVersion } static bool -GetMacOSXProcessName (const ProcessInfoMatch *match_info_ptr, - ProcessInfo &process_info) +GetMacOSXProcessName (const ProcessInstanceInfoMatch *match_info_ptr, + ProcessInstanceInfo &process_info) { if (process_info.ProcessIDIsValid()) { @@ -938,7 +938,7 @@ GetMacOSXProcessName (const ProcessInfoMatch *match_info_ptr, static bool -GetMacOSXProcessCPUType (ProcessInfo &process_info) +GetMacOSXProcessCPUType (ProcessInstanceInfo &process_info) { if (process_info.ProcessIDIsValid()) { @@ -970,8 +970,8 @@ GetMacOSXProcessCPUType (ProcessInfo &process_info) } static bool -GetMacOSXProcessArgs (const ProcessInfoMatch *match_info_ptr, - ProcessInfo &process_info) +GetMacOSXProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr, + ProcessInstanceInfo &process_info) { if (process_info.ProcessIDIsValid()) { @@ -1006,13 +1006,13 @@ GetMacOSXProcessArgs (const ProcessInfoMatch *match_info_ptr, ++offset; } // Now extract all arguments - StringList &proc_args = process_info.GetArguments(); + Args &proc_args = process_info.GetArguments(); for (int i=0; i<argc; ++i) { start_offset = offset; cstr = data.GetCStr(&offset); if (cstr) - proc_args.AppendString (cstr, offset - start_offset); + proc_args.AppendArgument(cstr); } return true; } @@ -1023,7 +1023,7 @@ GetMacOSXProcessArgs (const ProcessInfoMatch *match_info_ptr, } static bool -GetMacOSXProcessUserAndGroup (ProcessInfo &process_info) +GetMacOSXProcessUserAndGroup (ProcessInstanceInfo &process_info) { if (process_info.ProcessIDIsValid()) { @@ -1040,8 +1040,8 @@ GetMacOSXProcessUserAndGroup (ProcessInfo &process_info) if (proc_kinfo_size > 0) { process_info.SetParentProcessID (proc_kinfo.kp_eproc.e_ppid); - process_info.SetRealUserID (proc_kinfo.kp_eproc.e_pcred.p_ruid); - process_info.SetRealGroupID (proc_kinfo.kp_eproc.e_pcred.p_rgid); + process_info.SetUserID (proc_kinfo.kp_eproc.e_pcred.p_ruid); + process_info.SetGroupID (proc_kinfo.kp_eproc.e_pcred.p_rgid); process_info.SetEffectiveUserID (proc_kinfo.kp_eproc.e_ucred.cr_uid); if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0) process_info.SetEffectiveGroupID (proc_kinfo.kp_eproc.e_ucred.cr_groups[0]); @@ -1052,8 +1052,8 @@ GetMacOSXProcessUserAndGroup (ProcessInfo &process_info) } } process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID); - process_info.SetRealUserID (UINT32_MAX); - process_info.SetRealGroupID (UINT32_MAX); + process_info.SetUserID (UINT32_MAX); + process_info.SetGroupID (UINT32_MAX); process_info.SetEffectiveUserID (UINT32_MAX); process_info.SetEffectiveGroupID (UINT32_MAX); return false; @@ -1061,7 +1061,7 @@ GetMacOSXProcessUserAndGroup (ProcessInfo &process_info) uint32_t -Host::FindProcesses (const ProcessInfoMatch &match_info, ProcessInfoList &process_infos) +Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) { std::vector<struct kinfo_proc> kinfos; @@ -1104,11 +1104,11 @@ Host::FindProcesses (const ProcessInfoMatch &match_info, ProcessInfoList &proces kinfo.kp_proc.p_flag & P_TRANSLATED) // Skip translated ppc (Rosetta) continue; - ProcessInfo process_info; + ProcessInstanceInfo process_info; process_info.SetProcessID (kinfo.kp_proc.p_pid); process_info.SetParentProcessID (kinfo.kp_eproc.e_ppid); - process_info.SetRealUserID (kinfo.kp_eproc.e_pcred.p_ruid); - process_info.SetRealGroupID (kinfo.kp_eproc.e_pcred.p_rgid); + process_info.SetUserID (kinfo.kp_eproc.e_pcred.p_ruid); + process_info.SetGroupID (kinfo.kp_eproc.e_pcred.p_rgid); process_info.SetEffectiveUserID (kinfo.kp_eproc.e_ucred.cr_uid); if (kinfo.kp_eproc.e_ucred.cr_ngroups > 0) process_info.SetEffectiveGroupID (kinfo.kp_eproc.e_ucred.cr_groups[0]); @@ -1130,7 +1130,7 @@ Host::FindProcesses (const ProcessInfoMatch &match_info, ProcessInfoList &proces } bool -Host::GetProcessInfo (lldb::pid_t pid, ProcessInfo &process_info) +Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) { process_info.SetProcessID(pid); if (GetMacOSXProcessArgs (NULL, process_info)) @@ -1144,3 +1144,194 @@ Host::GetProcessInfo (lldb::pid_t pid, ProcessInfo &process_info) } +Error +Host::LaunchProcess (ProcessLaunchInfo &launch_info) +{ + Error error; + LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS)); + 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); + + 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; + } + + + if (launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY)) + { +#if !defined(__arm__) + return LaunchInNewTerminalWithAppleScript (exe_path, launch_info); +#else + error.SetErrorString ("launching a processs in a new terminal is not supported on iOS devices"); + return error; +#endif + } + + Error local_err; // Errors that don't affect the spawning. + posix_spawnattr_t attr; + error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX); + + if (error.Fail() || log) + error.PutToLog(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); + + short flags = 0; + if (launch_info.GetFlags().Test (eLaunchFlagExec)) + flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag + + if (launch_info.GetFlags().Test (eLaunchFlagDebug)) + flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag + + if (launch_info.GetFlags().Test (eLaunchFlagDisableASLR)) + flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag + + error.SetError( ::posix_spawnattr_setflags (&attr, flags), eErrorTypePOSIX); + if (error.Fail() || log) + error.PutToLog(log.get(), "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", flags); + if (error.Fail()) + return error; + +#if !defined(__arm__) + + // We don't need to do this for ARM, and we really shouldn't now that we + // have multiple CPU subtypes and no posix_spawnattr call that allows us + // to set which CPU subtype to launch... + cpu_type_t cpu = arch_spec.GetMachOCPUType(); + if (cpu != 0 && + cpu != UINT32_MAX && + cpu != LLDB_INVALID_CPUTYPE) + { + size_t ocount = 0; + error.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &ocount), eErrorTypePOSIX); + if (error.Fail() || log) + error.PutToLog(log.get(), "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %zu )", cpu, ocount); + + if (error.Fail() || ocount != 1) + return error; + } + +#endif + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + const char *tmp_argv[2]; + char * const *argv = (char * const*)launch_info.GetArguments().GetConstArgumentVector(); + char * const *envp = (char * const*)launch_info.GetEnvironmentEntries().GetConstArgumentVector(); + if (argv == NULL) + { + // posix_spawn gets very unhappy if it doesn't have at least the program + // name in argv[0]. One of the side affects I have noticed is the environment + // variables don't make it into the child process if "argv == NULL"!!! + tmp_argv[0] = exe_path; + tmp_argv[1] = NULL; + argv = (char * const*)tmp_argv; + } + + + const size_t num_file_actions = launch_info.GetNumFileActions (); + if (num_file_actions > 0) + { + posix_spawn_file_actions_t file_actions; + error.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX); + if (error.Fail() || log) + error.PutToLog(log.get(), "::posix_spawn_file_actions_init ( &file_actions )"); + if (error.Fail()) + return error; + + // Make a quick class that will cleanup the posix spawn attributes in case + // we return in the middle of this function. + lldb_utility::CleanUp <posix_spawn_file_actions_t *, int> posix_spawn_file_actions_cleanup (&file_actions, posix_spawn_file_actions_destroy); + + for (size_t i=0; i<num_file_actions; ++i) + { + const ProcessLaunchInfo::FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i); + if (launch_file_action) + { + if (!ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (&file_actions, + launch_file_action, + log.get(), + error)) + return error; + } + } + + error.SetError (::posix_spawnp (&pid, + exe_path, + &file_actions, + &attr, + argv, + envp), + eErrorTypePOSIX); + + if (error.Fail() || log) + error.PutToLog(log.get(), "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", + pid, + exe_path, + &file_actions, + &attr, + argv, + envp); + } + else + { + error.SetError (::posix_spawnp (&pid, + exe_path, + NULL, + &attr, + argv, + envp), + eErrorTypePOSIX); + + if (error.Fail() || log) + error.PutToLog(log.get(), "::posix_spawnp ( pid => %i, path = '%s', file_actions = NULL, attr = %p, argv = %p, envp = %p )", + pid, + exe_path, + &attr, + argv, + envp); + } + + if (pid != LLDB_INVALID_PROCESS_ID) + { + // If all went well, then set the process ID into the launch info + launch_info.SetProcessID(pid); + } + else + { + // Invalid process ID, something didn't go well + if (error.Success()) + error.SetErrorString ("process launch failed for unknown reasons"); + } + return error; +} + + diff --git a/lldb/source/Host/macosx/Symbols.cpp b/lldb/source/Host/macosx/Symbols.cpp index 7a32e08a476..c6d2f08db07 100644 --- a/lldb/source/Host/macosx/Symbols.cpp +++ b/lldb/source/Host/macosx/Symbols.cpp @@ -25,8 +25,8 @@ #include "lldb/Core/UUID.h" #include "lldb/Host/Endian.h" #include "lldb/Utility/CleanUp.h" - #include "Host/macosx/cfcpp/CFCReleaser.h" +#include "Host/macosx/cfcpp/CFCString.h" #include "mach/machine.h" using namespace lldb; @@ -352,11 +352,18 @@ LocateMacOSXFilesUsingDebugSymbols CFCReleaser<CFDictionaryRef> dict(::DBGCopyDSYMPropertyLists (dsym_url.get()));; if (dict.get()) { - CFStringRef exec_cf_path = static_cast<CFStringRef>(::CFDictionaryGetValue (dict.get(), CFSTR("DBGSymbolRichExecutable"))); - if (exec_cf_path && ::CFStringGetFileSystemRepresentation (exec_cf_path, path, sizeof(path))) + char uuid_cstr_buf[64]; + const char *uuid_cstr = uuid->GetAsCString (uuid_cstr_buf, sizeof(uuid_cstr_buf)); + CFCString uuid_cfstr (uuid_cstr); + CFDictionaryRef uuid_dict = static_cast<CFDictionaryRef>(::CFDictionaryGetValue (dict.get(), uuid_cfstr.get())); + if (uuid_dict) { - ++items_found; - out_dsym_fspec->SetFile(path, false); + CFStringRef exec_cf_path = static_cast<CFStringRef>(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGSymbolRichExecutable"))); + if (exec_cf_path && ::CFStringGetFileSystemRepresentation (exec_cf_path, path, sizeof(path))) + { + ++items_found; + out_exec_fspec->SetFile(path, path[0] == '~'); + } } } } diff --git a/lldb/source/Host/macosx/cfcpp/CFCString.h b/lldb/source/Host/macosx/cfcpp/CFCString.h index 521d2c0a51b..27c090313ec 100644 --- a/lldb/source/Host/macosx/cfcpp/CFCString.h +++ b/lldb/source/Host/macosx/cfcpp/CFCString.h @@ -21,7 +21,7 @@ public: // Constructors and Destructors //------------------------------------------------------------------ CFCString (CFStringRef cf_str = NULL); - CFCString (const char *s, CFStringEncoding encoding); + CFCString (const char *s, CFStringEncoding encoding = kCFStringEncodingUTF8); CFCString (const CFCString& rhs); CFCString& operator= (const CFCString& rhs); virtual ~CFCString (); diff --git a/lldb/source/Interpreter/Args.cpp b/lldb/source/Interpreter/Args.cpp index df276baff6f..13ecd116adc 100644 --- a/lldb/source/Interpreter/Args.cpp +++ b/lldb/source/Interpreter/Args.cpp @@ -28,7 +28,8 @@ using namespace lldb_private; //---------------------------------------------------------------------- Args::Args (const char *command) : m_args(), - m_argv() + m_argv(), + m_args_quote_char() { if (command) SetCommandString (command); @@ -37,13 +38,49 @@ Args::Args (const char *command) : Args::Args (const char *command, size_t len) : m_args(), - m_argv() + m_argv(), + m_args_quote_char() { if (command && len) SetCommandString (command, len); } //---------------------------------------------------------------------- +// We have to be very careful on the copy constructor of this class +// to make sure we copy all of the string values, but we can't copy the +// rhs.m_argv into m_argv since it will point to the "const char *" c +// strings in rhs.m_args. We need to copy the string list and update our +// own m_argv appropriately. +//---------------------------------------------------------------------- +Args::Args (const Args &rhs) : + m_args (rhs.m_args), + m_argv (), + m_args_quote_char(rhs.m_args_quote_char) +{ + UpdateArgvFromArgs(); +} + +//---------------------------------------------------------------------- +// We have to be very careful on the copy constructor of this class +// to make sure we copy all of the string values, but we can't copy the +// rhs.m_argv into m_argv since it will point to the "const char *" c +// strings in rhs.m_args. We need to copy the string list and update our +// own m_argv appropriately. +//---------------------------------------------------------------------- +const Args & +Args::operator= (const Args &rhs) +{ + // Make sure we aren't assigning to self + if (this != &rhs) + { + m_args = rhs.m_args; + m_args_quote_char = rhs.m_args_quote_char; + UpdateArgvFromArgs(); + } + return *this; +} + +//---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- Args::~Args () diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index 98786f7c5cc..6dcc4a1eea5 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -100,22 +100,23 @@ CommandInterpreter::Initialize () HandleCommand ("command alias continue process continue", false, result); HandleCommand ("command alias expr expression", false, result); HandleCommand ("command alias exit quit", false, result); - HandleCommand ("command alias b regexp-break", false, result); + HandleCommand ("command alias b _regexp-break", false, result); HandleCommand ("command alias bt thread backtrace", false, result); HandleCommand ("command alias si thread step-inst", false, result); HandleCommand ("command alias step thread step-in", false, result); HandleCommand ("command alias s thread step-in", false, result); HandleCommand ("command alias next thread step-over", false, result); HandleCommand ("command alias n thread step-over", false, result); + HandleCommand ("command alias f thread step-out", false, result); HandleCommand ("command alias finish thread step-out", false, result); HandleCommand ("command alias x memory read", false, result); HandleCommand ("command alias l source list", false, result); HandleCommand ("command alias list source list", false, result); - HandleCommand ("command alias p frame variable", false, result); + HandleCommand ("command alias p expression --", false, result); HandleCommand ("command alias print expression --", false, result); HandleCommand ("command alias po expression -o --", false, result); - HandleCommand ("command alias up regexp-up", false, result); - HandleCommand ("command alias down regexp-down", false, result); + HandleCommand ("command alias up _regexp-up", false, result); + HandleCommand ("command alias down _regexp-down", false, result); } @@ -183,15 +184,15 @@ CommandInterpreter::LoadCommandDictionary () std::auto_ptr<CommandObjectRegexCommand> break_regex_cmd_ap(new CommandObjectRegexCommand (*this, - "regexp-break", + "_regexp-break", "Set a breakpoint using a regular expression to specify the location.", - "regexp-break [<filename>:<linenum>]\nregexp-break [<address>]\nregexp-break <...>", 2)); + "_regexp-break [<filename>:<linenum>]\n_regexp-break [<address>]\n_regexp-break <...>", 2)); if (break_regex_cmd_ap.get()) { if (break_regex_cmd_ap->AddRegexCommand("^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", "breakpoint set --file '%1' --line %2") && break_regex_cmd_ap->AddRegexCommand("^(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1") && break_regex_cmd_ap->AddRegexCommand("^[\"']?([-+]\\[.*\\])[\"']?[[:space:]]*$", "breakpoint set --name '%1'") && - break_regex_cmd_ap->AddRegexCommand("^$", "breakpoint list") && + break_regex_cmd_ap->AddRegexCommand("^$", "breakpoint list --full") && break_regex_cmd_ap->AddRegexCommand("^(-.*)$", "breakpoint set %1") && break_regex_cmd_ap->AddRegexCommand("^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%2' --shlib '%1'") && break_regex_cmd_ap->AddRegexCommand("^(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%1'")) @@ -203,9 +204,9 @@ CommandInterpreter::LoadCommandDictionary () std::auto_ptr<CommandObjectRegexCommand> down_regex_cmd_ap(new CommandObjectRegexCommand (*this, - "regexp-down", - "Go down \"n\" frames in the stack (1 frame by default).", - "down [n]", 2)); + "_regexp-down", + "Go down \"n\" frames in the stack (1 frame by default).", + "_regexp-down [n]", 2)); if (down_regex_cmd_ap.get()) { if (down_regex_cmd_ap->AddRegexCommand("^$", "frame select -r -1") && @@ -218,9 +219,9 @@ CommandInterpreter::LoadCommandDictionary () std::auto_ptr<CommandObjectRegexCommand> up_regex_cmd_ap(new CommandObjectRegexCommand (*this, - "regexp-up", - "Go up \"n\" frames in the stack (1 frame by default).", - "up [n]", 2)); + "_regexp-up", + "Go up \"n\" frames in the stack (1 frame by default).", + "_regexp-up [n]", 2)); if (up_regex_cmd_ap.get()) { if (up_regex_cmd_ap->AddRegexCommand("^$", "frame select -r 1") && @@ -759,7 +760,7 @@ CommandInterpreter::HandleCommand (const char *command_line, Timer scoped_timer (__PRETTY_FUNCTION__, "Handling command: %s.", command_line); - m_debugger.UpdateExecutionContext (override_context); + UpdateExecutionContext (override_context); bool empty_command = false; bool comment_command = false; @@ -1542,6 +1543,18 @@ CommandInterpreter::SourceInitFile (bool in_cwd, CommandReturnObject &result) } } +PlatformSP +CommandInterpreter::GetPlatform (bool prefer_target_platform) +{ + PlatformSP platform_sp; + if (prefer_target_platform && m_exe_ctx.target) + platform_sp = m_exe_ctx.target->GetPlatform(); + + if (!platform_sp) + platform_sp = m_debugger.GetPlatformList().GetSelectedPlatform(); + return platform_sp; +} + void CommandInterpreter::HandleCommands (const StringList &commands, ExecutionContext *override_context, @@ -1562,7 +1575,7 @@ CommandInterpreter::HandleCommands (const StringList &commands, // cause series of commands that change the context, then do an operation that relies on that context to fail. if (override_context != NULL) - m_debugger.UpdateExecutionContext (override_context); + UpdateExecutionContext (override_context); if (!stop_on_continue) { @@ -1842,3 +1855,50 @@ CommandInterpreter::FindCommandsForApropos (const char *search_word, StringList } } + + +void +CommandInterpreter::UpdateExecutionContext (ExecutionContext *override_context) +{ + m_exe_ctx.Clear(); + + if (override_context != NULL) + { + m_exe_ctx.target = override_context->target; + m_exe_ctx.process = override_context->process; + m_exe_ctx.thread = override_context->thread; + m_exe_ctx.frame = override_context->frame; + } + else + { + TargetSP target_sp (m_debugger.GetSelectedTarget()); + if (target_sp) + { + m_exe_ctx.target = target_sp.get(); + m_exe_ctx.process = target_sp->GetProcessSP().get(); + if (m_exe_ctx.process && m_exe_ctx.process->IsAlive() && !m_exe_ctx.process->IsRunning()) + { + m_exe_ctx.thread = m_exe_ctx.process->GetThreadList().GetSelectedThread().get(); + if (m_exe_ctx.thread == NULL) + { + m_exe_ctx.thread = m_exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get(); + // If we didn't have a selected thread, select one here. + if (m_exe_ctx.thread != NULL) + m_exe_ctx.process->GetThreadList().SetSelectedThreadByID(m_exe_ctx.thread->GetID()); + } + if (m_exe_ctx.thread) + { + m_exe_ctx.frame = m_exe_ctx.thread->GetSelectedFrame().get(); + if (m_exe_ctx.frame == NULL) + { + m_exe_ctx.frame = m_exe_ctx.thread->GetStackFrameAtIndex (0).get(); + // If we didn't have a selected frame select one here. + if (m_exe_ctx.frame != NULL) + m_exe_ctx.thread->SetSelectedFrame(m_exe_ctx.frame); + } + } + } + } + } +} + diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp index f93ed6e0344..16c68ec1b22 100644 --- a/lldb/source/Interpreter/CommandObject.cpp +++ b/lldb/source/Interpreter/CommandObject.cpp @@ -219,7 +219,7 @@ CommandObject::ExecuteWithOptions (Args& args, CommandReturnObject &result) if (GetFlags().AnySet (CommandObject::eFlagProcessMustBeLaunched | CommandObject::eFlagProcessMustBePaused)) { - Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; + Process *process = m_interpreter.GetExecutionContext().process; if (process == NULL) { result.AppendError ("Process must exist."); diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp index 0b06b4c3bfc..104099450fa 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp @@ -295,7 +295,7 @@ DynamicLoaderMacOSXDYLD::ReadDYLDInfoFromMemoryAndSetNotificationCallback(lldb:: // it again (since Target::SetExecutableModule() will clear the // images). So append the dyld module back to the list if it is /// unique! - if (m_process->GetTarget().GetImages().AppendIfNeeded (dyld_module_sp)) + if (dyld_module_sp && m_process->GetTarget().GetImages().AppendIfNeeded (dyld_module_sp)) UpdateImageLoadAddress(dyld_module_sp.get(), m_dyld); return true; @@ -603,6 +603,7 @@ DynamicLoaderMacOSXDYLD::UpdateAllImageInfos() uint32_t idx; uint32_t i = 0; + // Since we can't downsize a vector, we must do this using the swap method DYLDImageInfo::collection old_dyld_all_image_infos; old_dyld_all_image_infos.swap(m_dyld_image_infos); @@ -639,7 +640,10 @@ DynamicLoaderMacOSXDYLD::UpdateAllImageInfos() m_dyld_image_infos[i].mod_date = info_data_ref.GetPointer(&info_data_offset); char raw_path[PATH_MAX]; - m_process->ReadMemory (path_addr, raw_path, sizeof(raw_path), error); + m_process->ReadCStringFromMemory (path_addr, raw_path, sizeof(raw_path)); + char raw_path2[PATH_MAX];// TODO: remove after assertion doesn't assert + m_process->ReadMemory (path_addr, raw_path2, sizeof(raw_path2), error);// TODO: remove after assertion doesn't assert + assert (strcmp (raw_path, raw_path2) == 0);// TODO: remove after assertion doesn't assert m_dyld_image_infos[i].file_spec.SetFile(raw_path, true); } assert(i == m_dyld_all_image_infos.dylib_info_count); @@ -653,10 +657,6 @@ DynamicLoaderMacOSXDYLD::UpdateAllImageInfos() } } } - else - { - m_dyld_image_infos.clear(); - } // If our new list is smaller than our old list, we have unloaded // some shared libraries @@ -763,9 +763,9 @@ DynamicLoaderMacOSXDYLD::UpdateAllImageInfos() { commpage_image_module_sp = m_process->GetTarget().GetSharedModule (m_dyld_image_infos[idx].file_spec, arch, - &m_dyld_image_infos[idx].uuid, + NULL, &commpage_dbstr, - objfile->GetOffset() + commpage_section->GetOffset()); + objfile->GetOffset() + commpage_section->GetFileOffset()); } if (commpage_image_module_sp) UpdateCommPageLoadAddress (commpage_image_module_sp.get()); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 63cb4ac25ee..d3a11e43e84 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -14,6 +14,7 @@ // Other libraries and framework includes // Project includes #include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Core/Debugger.h" #include "lldb/Core/Error.h" #include "lldb/Host/Host.h" #include "lldb/Target/Target.h" @@ -50,17 +51,47 @@ PlatformDarwin::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 we have "ls" as the exe_file, resolve the executable loation based on - // the current path variables - if (!resolved_exe_file.Exists()) - resolved_exe_file.ResolveExecutableLocation (); + if (IsHost()) + { + // If we have "ls" as the exe_file, resolve the executable loation based on + // the current path variables + if (!resolved_exe_file.Exists()) + { + exe_file.GetPath (exe_path, sizeof(exe_path)); + resolved_exe_file.SetFile(exe_path, true); + } - // Resolve any executable within a bundle on MacOSX - Host::ResolveExecutableInBundle (resolved_exe_file); + if (!resolved_exe_file.Exists()) + resolved_exe_file.ResolveExecutableLocation (); - if (resolved_exe_file.Exists()) + // Resolve any executable within a bundle on MacOSX + Host::ResolveExecutableInBundle (resolved_exe_file); + + if (resolved_exe_file.Exists()) + error.Clear(); + else + { + exe_file.GetPath (exe_path, sizeof(exe_path)); + error.SetErrorStringWithFormat ("enable to find executable for '%s'", exe_path); + } + } + else + { + if (m_remote_platform_sp) + { + error = m_remote_platform_sp->ResolveExecutable (exe_file, + exe_arch, + exe_module_sp); + } + else + error.SetErrorString ("the platform is not currently connected"); + } + + + if (error.Success()) { if (exe_arch.IsValid()) { @@ -321,7 +352,7 @@ PlatformDarwin::DisconnectRemote () bool -PlatformDarwin::GetProcessInfo (lldb::pid_t pid, ProcessInfo &process_info) +PlatformDarwin::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) { bool sucess = false; if (IsHost()) @@ -339,8 +370,8 @@ PlatformDarwin::GetProcessInfo (lldb::pid_t pid, ProcessInfo &process_info) uint32_t -PlatformDarwin::FindProcesses (const ProcessInfoMatch &match_info, - ProcessInfoList &process_infos) +PlatformDarwin::FindProcesses (const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { uint32_t match_count = 0; if (IsHost()) @@ -357,6 +388,71 @@ PlatformDarwin::FindProcesses (const ProcessInfoMatch &match_info, return match_count; } +Error +PlatformDarwin::LaunchProcess (ProcessLaunchInfo &launch_info) +{ + Error error; + if (IsHost()) + { + error = Platform::LaunchProcess (launch_info); + } + else + { + if (m_remote_platform_sp) + error = m_remote_platform_sp->LaunchProcess (launch_info); + else + error.SetErrorString ("the platform is not currently connected"); + } + return error; +} + +lldb::ProcessSP +PlatformDarwin::Attach (lldb::pid_t pid, + Debugger &debugger, + Target *target, + Listener &listener, + Error &error) +{ + lldb::ProcessSP process_sp; + if (IsHost()) + { + if (target == NULL) + { + TargetSP new_target_sp; + FileSpec emptyFileSpec; + ArchSpec emptyArchSpec; + + error = debugger.GetTargetList().CreateTarget (debugger, + emptyFileSpec, + emptyArchSpec, + false, + new_target_sp); + target = new_target_sp.get(); + } + else + error.Clear(); + + if (target && error.Success()) + { + debugger.GetTargetList().SetSelectedTarget(target); + // The darwin always currently uses the GDB remote debugger plug-in + // so even when debugging locally we are debugging remotely! + process_sp = target->CreateProcess (listener, "gdb-remote"); + + if (process_sp) + error = process_sp->Attach (pid); + } + } + else + { + if (m_remote_platform_sp) + process_sp = m_remote_platform_sp->Attach (pid, debugger, target, listener, error); + else + error.SetErrorString ("the platform is not currently connected"); + } + return process_sp; +} + const char * PlatformDarwin::GetUserName (uint32_t uid) { diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h index 74647360694..38804edad18 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h @@ -69,12 +69,22 @@ public: virtual bool GetProcessInfo (lldb::pid_t pid, - lldb_private::ProcessInfo &proc_info); + lldb_private::ProcessInstanceInfo &proc_info); virtual uint32_t - FindProcesses (const lldb_private::ProcessInfoMatch &match_info, - lldb_private::ProcessInfoList &process_infos); + FindProcesses (const lldb_private::ProcessInstanceInfoMatch &match_info, + lldb_private::ProcessInstanceInfoList &process_infos); + virtual lldb_private::Error + LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info); + + virtual lldb::ProcessSP + Attach (lldb::pid_t pid, + lldb_private::Debugger &debugger, + lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one + lldb_private::Listener &listener, + lldb_private::Error &error); + protected: lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote darwin OS diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp index 2ae4a903353..3e0b2b14906 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp @@ -447,8 +447,8 @@ PlatformRemoteiOS::GetSharedModule (const FileSpec &platform_file, uint32_t -PlatformRemoteiOS::FindProcesses (const ProcessInfoMatch &match_info, - ProcessInfoList &process_infos) +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(); @@ -456,7 +456,7 @@ PlatformRemoteiOS::FindProcesses (const ProcessInfoMatch &match_info, } bool -PlatformRemoteiOS::GetProcessInfo (lldb::pid_t pid, ProcessInfo &process_info) +PlatformRemoteiOS::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) { // TODO: if connected, send a packet to get the remote process info process_info.Clear(); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h index 63ac8520de4..08968f4f110 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h @@ -103,12 +103,12 @@ public: bool *did_create_ptr); virtual uint32_t - FindProcesses (const lldb_private::ProcessInfoMatch &match_info, - lldb_private::ProcessInfoList &process_infos); + FindProcesses (const lldb_private::ProcessInstanceInfoMatch &match_info, + lldb_private::ProcessInstanceInfoList &process_infos); virtual bool GetProcessInfo (lldb::pid_t pid, - lldb_private::ProcessInfo &proc_info); + lldb_private::ProcessInstanceInfo &proc_info); virtual bool GetSupportedArchitectureAtIndex (uint32_t idx, diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index a6bcb9bf07e..f8b67a31280 100644 --- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -17,6 +17,7 @@ // Project includes #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/ConnectionFileDescriptor.h" +#include "lldb/Core/Debugger.h" #include "lldb/Core/Error.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" @@ -112,7 +113,8 @@ PlatformRemoteGDBServer::GetFile (const FileSpec &platform_file, /// Default Constructor //------------------------------------------------------------------ PlatformRemoteGDBServer::PlatformRemoteGDBServer () : - Platform(false) // This is a remote platform + Platform(false), // This is a remote platform + m_gdb_client(true) { } @@ -267,17 +269,139 @@ PlatformRemoteGDBServer::GetGroupName (uint32_t gid) } uint32_t -PlatformRemoteGDBServer::FindProcesses (const ProcessInfoMatch &match_info, - ProcessInfoList &process_infos) +PlatformRemoteGDBServer::FindProcesses (const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { return m_gdb_client.FindProcesses (match_info, process_infos); } bool -PlatformRemoteGDBServer::GetProcessInfo (lldb::pid_t pid, ProcessInfo &process_info) +PlatformRemoteGDBServer::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) { return m_gdb_client.GetProcessInfo (pid, process_info); } +Error +PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info) +{ + Error error; + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + + m_gdb_client.SetSTDIN ("/dev/null"); + m_gdb_client.SetSTDOUT ("/dev/null"); + m_gdb_client.SetSTDERR ("/dev/null"); + m_gdb_client.SetDisableASLR (launch_info.GetFlags().Test (eLaunchFlagDisableASLR)); + + const char *working_dir = launch_info.GetWorkingDirectory(); + if (working_dir && working_dir[0]) + { + m_gdb_client.SetWorkingDir (working_dir); + } + + // Send the environment and the program + arguments after we connect + const char **argv = launch_info.GetArguments().GetConstArgumentVector(); + const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector(); + + if (envp) + { + const char *env_entry; + for (int i=0; (env_entry = envp[i]); ++i) + { + if (m_gdb_client.SendEnvironmentPacket(env_entry) != 0) + break; + } + } + const uint32_t old_packet_timeout = m_gdb_client.SetPacketTimeout (3000); // TODO: lower this to 5 seconds prior to checkin!!! + int arg_packet_err = m_gdb_client.SendArgumentsPacket (argv); + m_gdb_client.SetPacketTimeout (old_packet_timeout); + if (arg_packet_err == 0) + { + std::string error_str; + if (m_gdb_client.GetLaunchSuccess (error_str)) + { + pid = m_gdb_client.GetCurrentProcessID (); + if (pid != LLDB_INVALID_PROCESS_ID) + launch_info.SetProcessID (pid); + } + else + { + error.SetErrorString (error_str.c_str()); + } + } + else + { + error.SetErrorStringWithFormat("'A' packet returned an error: %i.\n", arg_packet_err); + } + return error; +} + +lldb::ProcessSP +PlatformRemoteGDBServer::Attach (lldb::pid_t pid, + Debugger &debugger, + Target *target, // Can be NULL, if NULL create a new target, else use existing one + Listener &listener, + Error &error) +{ + lldb::ProcessSP process_sp; + if (IsRemote()) + { + if (IsConnected()) + { + uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort(); + + if (port == 0) + { + error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ()); + } + else + { + if (target == NULL) + { + TargetSP new_target_sp; + FileSpec emptyFileSpec; + ArchSpec emptyArchSpec; + + error = debugger.GetTargetList().CreateTarget (debugger, + emptyFileSpec, + emptyArchSpec, + false, + new_target_sp); + target = new_target_sp.get(); + } + else + error.Clear(); + + if (target && error.Success()) + { + debugger.GetTargetList().SetSelectedTarget(target); + + // The darwin always currently uses the GDB remote debugger plug-in + // so even when debugging locally we are debugging remotely! + process_sp = target->CreateProcess (listener, "gdb-remote"); + + if (process_sp) + { + char connect_url[256]; + const int connect_url_len = ::snprintf (connect_url, + sizeof(connect_url), + "connect://%s:%u", + GetHostname (), + port); + assert (connect_url_len < sizeof(connect_url)); + error = process_sp->ConnectRemote (connect_url); + if (error.Success()) + error = process_sp->Attach(pid); + } + } + } + } + else + { + error.SetErrorString("not connected to remote gdb server"); + } + } + return process_sp; +} + diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h index a016e01d008..36c48c24b60 100644 --- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -83,11 +83,22 @@ public: lldb_private::FileSpec &local_file); virtual bool - GetProcessInfo (lldb::pid_t pid, lldb_private::ProcessInfo &proc_info); + GetProcessInfo (lldb::pid_t pid, + lldb_private::ProcessInstanceInfo &proc_info); virtual uint32_t - FindProcesses (const lldb_private::ProcessInfoMatch &match_info, - lldb_private::ProcessInfoList &process_infos); + FindProcesses (const lldb_private::ProcessInstanceInfoMatch &match_info, + lldb_private::ProcessInstanceInfoList &process_infos); + + virtual lldb_private::Error + LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info); + + virtual lldb::ProcessSP + Attach (lldb::pid_t pid, + lldb_private::Debugger &debugger, + lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one + lldb_private::Listener &listener, + lldb_private::Error &error); virtual bool GetSupportedArchitectureAtIndex (uint32_t idx, lldb_private::ArchSpec &arch); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 3b8d6056063..93e4166af2c 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -17,25 +17,33 @@ // Other libraries and framework includes #include "lldb/Core/Log.h" #include "lldb/Core/StreamString.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Host/Host.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Target/Process.h" // Project includes #include "ProcessGDBRemoteLog.h" +#define DEBUGSERVER_BASENAME "debugserver" + using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- // GDBRemoteCommunication constructor //---------------------------------------------------------------------- -GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, const char *listener_name) : +GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, + const char *listener_name, + bool is_platform) : Communication(comm_name), m_packet_timeout (60), m_rx_packet_listener (listener_name), m_sequence_mutex (Mutex::eMutexTypeRecursive), m_public_is_running (false), m_private_is_running (false), - m_send_acks (true) + m_send_acks (true), + m_is_platform (is_platform) { m_rx_packet_listener.StartListeningForEvents(this, Communication::eBroadcastBitPacketAvailable | @@ -328,3 +336,131 @@ GDBRemoteCommunication::AppendBytesToCache (const uint8_t *src, size_t src_len, } } +Error +GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, + const char *unix_socket_name, // For handshaking + lldb_private::ProcessLaunchInfo &launch_info) +{ + Error error; + // If we locate debugserver, keep that located version around + static FileSpec g_debugserver_file_spec; + + // This function will fill in the launch information for the debugserver + // instance that gets launched. + launch_info.Clear(); + + char debugserver_path[PATH_MAX]; + FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); + + // Always check to see if we have an environment override for the path + // to the debugserver to use and use it if we do. + const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); + if (env_debugserver_path) + debugserver_file_spec.SetFile (env_debugserver_path, false); + else + debugserver_file_spec = g_debugserver_file_spec; + bool debugserver_exists = debugserver_file_spec.Exists(); + if (!debugserver_exists) + { + // The debugserver binary is in the LLDB.framework/Resources + // directory. + if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec)) + { + debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME); + debugserver_exists = debugserver_file_spec.Exists(); + if (debugserver_exists) + { + g_debugserver_file_spec = debugserver_file_spec; + } + else + { + g_debugserver_file_spec.Clear(); + debugserver_file_spec.Clear(); + } + } + } + + if (debugserver_exists) + { + debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); + + Args &debugserver_args = launch_info.GetArguments(); + debugserver_args.Clear(); + char arg_cstr[PATH_MAX]; + + // Start args with "debugserver /file/path -r --" + debugserver_args.AppendArgument(debugserver_path); + debugserver_args.AppendArgument(debugserver_url); + // use native registers, not the GDB registers + debugserver_args.AppendArgument("--native-regs"); + // make debugserver run in its own session so signals generated by + // special terminal key sequences (^C) don't affect debugserver + debugserver_args.AppendArgument("--setsid"); + + if (unix_socket_name && unix_socket_name[0]) + { + debugserver_args.AppendArgument("--unix-socket"); + debugserver_args.AppendArgument(unix_socket_name); + } + + const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); + if (env_debugserver_log_file) + { + ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file); + debugserver_args.AppendArgument(arg_cstr); + } + + const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); + if (env_debugserver_log_flags) + { + ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); + debugserver_args.AppendArgument(arg_cstr); + } + // debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt"); + // debugserver_args.AppendArgument("--log-flags=0x802e0e"); + + // We currently send down all arguments, attach pids, or attach + // process names in dedicated GDB server packets, so we don't need + // to pass them as arguments. This is currently because of all the + // things we need to setup prior to launching: the environment, + // current working dir, file actions, etc. +#if 0 + // Now append the program arguments + if (inferior_argv) + { + // Terminate the debugserver args so we can now append the inferior args + debugserver_args.AppendArgument("--"); + + for (int i = 0; inferior_argv[i] != NULL; ++i) + debugserver_args.AppendArgument (inferior_argv[i]); + } + else if (attach_pid != LLDB_INVALID_PROCESS_ID) + { + ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid); + debugserver_args.AppendArgument (arg_cstr); + } + else if (attach_name && attach_name[0]) + { + if (wait_for_launch) + debugserver_args.AppendArgument ("--waitfor"); + else + debugserver_args.AppendArgument ("--attach"); + debugserver_args.AppendArgument (attach_name); + } +#endif + + // Close STDIN, STDOUT and STDERR. We might need to redirect them + // to "/dev/null" if we run into any problems. +// launch_info.AppendCloseFileAction (STDIN_FILENO); +// launch_info.AppendCloseFileAction (STDOUT_FILENO); +// launch_info.AppendCloseFileAction (STDERR_FILENO); + + error = Host::LaunchProcess(launch_info); + } + else + { + error.SetErrorStringWithFormat ("Unable to locate " DEBUGSERVER_BASENAME ".\n"); + } + return error; +} + diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index f53d036a518..77e3e1a5d7c 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -37,7 +37,9 @@ public: //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ - GDBRemoteCommunication(const char *comm_name, const char *listener_name); + GDBRemoteCommunication(const char *comm_name, + const char *listener_name, + bool is_platform); virtual ~GDBRemoteCommunication(); @@ -119,6 +121,15 @@ public: return old_packet_timeout; } + //------------------------------------------------------------------ + // Start a debugserver instance on the current host using the + // supplied connection URL. + //------------------------------------------------------------------ + lldb_private::Error + StartDebugserverProcess (const char *connect_url, + const char *unix_socket_name, + lldb_private::ProcessLaunchInfo &launch_info); + protected: typedef std::list<std::string> packet_collection; @@ -142,10 +153,13 @@ protected: lldb_private::Predicate<bool> m_public_is_running; lldb_private::Predicate<bool> m_private_is_running; bool m_send_acks; - + bool m_is_platform; // Set to true if this class represents a platform, + // false if this class represents a debug session for + // a single process + private: //------------------------------------------------------------------ // For GDBRemoteCommunication only diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 2cebb10c0fb..d4f6592f5bd 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -34,8 +34,8 @@ using namespace lldb_private; //---------------------------------------------------------------------- // GDBRemoteCommunicationClient constructor //---------------------------------------------------------------------- -GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() : - GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet"), +GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : + GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet", is_platform), m_supports_not_sending_acks (eLazyBoolCalculate), m_supports_thread_suffix (eLazyBoolCalculate), m_supports_vCont_all (eLazyBoolCalculate), @@ -49,6 +49,14 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() : m_supports_qfProcessInfo (true), m_supports_qUserName (true), m_supports_qGroupName (true), + m_supports_qThreadStopInfo (true), + m_supports_z0 (true), + m_supports_z1 (true), + m_supports_z2 (true), + m_supports_z3 (true), + m_supports_z4 (true), + m_curr_tid (LLDB_INVALID_THREAD_ID), + m_curr_tid_run (LLDB_INVALID_THREAD_ID), m_async_mutex (Mutex::eMutexTypeRecursive), m_async_packet_predicate (false), m_async_packet (), @@ -126,6 +134,12 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_qfProcessInfo = true; m_supports_qUserName = true; m_supports_qGroupName = true; + m_supports_qThreadStopInfo = true; + m_supports_z0 = true; + m_supports_z1 = true; + m_supports_z2 = true; + m_supports_z3 = true; + m_supports_z4 = true; m_host_arch.Clear(); } @@ -1119,7 +1133,7 @@ GDBRemoteCommunicationClient::SetDisableASLR (bool enable) } bool -GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemote &response, ProcessInfo &process_info) +GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info) { if (response.IsNormalResponse()) { @@ -1139,7 +1153,7 @@ GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemot } else if (name.compare("uid") == 0) { - process_info.SetRealUserID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0)); + process_info.SetUserID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0)); } else if (name.compare("euid") == 0) { @@ -1147,7 +1161,7 @@ GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemot } else if (name.compare("gid") == 0) { - process_info.SetRealGroupID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0)); + process_info.SetGroupID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0)); } else if (name.compare("egid") == 0) { @@ -1180,7 +1194,7 @@ GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemot } bool -GDBRemoteCommunicationClient::GetProcessInfo (lldb::pid_t pid, ProcessInfo &process_info) +GDBRemoteCommunicationClient::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) { process_info.Clear(); @@ -1205,8 +1219,8 @@ GDBRemoteCommunicationClient::GetProcessInfo (lldb::pid_t pid, ProcessInfo &proc } uint32_t -GDBRemoteCommunicationClient::FindProcesses (const ProcessInfoMatch &match_info, - ProcessInfoList &process_infos) +GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { process_infos.Clear(); @@ -1261,10 +1275,10 @@ GDBRemoteCommunicationClient::FindProcesses (const ProcessInfoMatch &match_info, packet.Printf("pid:%u;",match_info.GetProcessInfo().GetProcessID()); if (match_info.GetProcessInfo().ParentProcessIDIsValid()) packet.Printf("parent_pid:%u;",match_info.GetProcessInfo().GetParentProcessID()); - if (match_info.GetProcessInfo().RealUserIDIsValid()) - packet.Printf("uid:%u;",match_info.GetProcessInfo().GetRealUserID()); - if (match_info.GetProcessInfo().RealGroupIDIsValid()) - packet.Printf("gid:%u;",match_info.GetProcessInfo().GetRealGroupID()); + if (match_info.GetProcessInfo().UserIDIsValid()) + packet.Printf("uid:%u;",match_info.GetProcessInfo().GetUserID()); + if (match_info.GetProcessInfo().GroupIDIsValid()) + packet.Printf("gid:%u;",match_info.GetProcessInfo().GetGroupID()); if (match_info.GetProcessInfo().EffectiveUserIDIsValid()) packet.Printf("euid:%u;",match_info.GetProcessInfo().GetEffectiveUserID()); if (match_info.GetProcessInfo().EffectiveGroupIDIsValid()) @@ -1291,7 +1305,7 @@ GDBRemoteCommunicationClient::FindProcesses (const ProcessInfoMatch &match_info, do { - ProcessInfo process_info; + ProcessInstanceInfo process_info; if (!DecodeProcessInfoResponse (response, process_info)) break; process_infos.Append(process_info); @@ -1447,3 +1461,154 @@ GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t } return false; } + +uint16_t +GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort () +{ + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qLaunchGDBServer", strlen("qLaunchGDBServer"), 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) + 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); + } + return port; + } + return 0; +} + +bool +GDBRemoteCommunicationClient::SetCurrentThread (int tid) +{ + if (m_curr_tid == tid) + return true; + + char packet[32]; + int packet_len; + if (tid <= 0) + packet_len = ::snprintf (packet, sizeof(packet), "Hg%i", tid); + else + packet_len = ::snprintf (packet, sizeof(packet), "Hg%x", tid); + assert (packet_len + 1 < sizeof(packet)); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.IsOKResponse()) + { + m_curr_tid = tid; + return true; + } + } + return false; +} + +bool +GDBRemoteCommunicationClient::SetCurrentThreadForRun (int tid) +{ + if (m_curr_tid_run == tid) + return true; + + char packet[32]; + int packet_len; + if (tid <= 0) + packet_len = ::snprintf (packet, sizeof(packet), "Hc%i", tid); + else + packet_len = ::snprintf (packet, sizeof(packet), "Hc%x", tid); + + assert (packet_len + 1 < sizeof(packet)); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.IsOKResponse()) + { + m_curr_tid_run = tid; + return true; + } + } + return false; +} + +bool +GDBRemoteCommunicationClient::GetStopReply (StringExtractorGDBRemote &response) +{ + if (SendPacketAndWaitForResponse("?", 1, response, false)) + return response.IsNormalResponse(); + return false; +} + +bool +GDBRemoteCommunicationClient::GetThreadStopInfo (uint32_t tid, StringExtractorGDBRemote &response) +{ + if (m_supports_qThreadStopInfo) + { + char packet[256]; + int packet_len = ::snprintf(packet, sizeof(packet), "qThreadStopInfo%x", tid); + assert (packet_len < sizeof(packet)); + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.IsUnsupportedResponse()) + m_supports_qThreadStopInfo = false; + else if (response.IsNormalResponse()) + return true; + else + return false; + } + } + if (SetCurrentThread (tid)) + return GetStopReply (response); + return false; +} + + +uint8_t +GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, bool insert, addr_t addr, uint32_t length) +{ + switch (type) + { + case eBreakpointSoftware: if (!m_supports_z0) return UINT8_MAX; break; + case eBreakpointHardware: if (!m_supports_z1) return UINT8_MAX; break; + case eWatchpointWrite: if (!m_supports_z2) return UINT8_MAX; break; + case eWatchpointRead: if (!m_supports_z3) return UINT8_MAX; break; + case eWatchpointReadWrite: if (!m_supports_z4) return UINT8_MAX; break; + default: return UINT8_MAX; + } + + char packet[64]; + const int packet_len = ::snprintf (packet, + sizeof(packet), + "%c%i,%llx,%x", + insert ? 'Z' : 'z', + type, + addr, + length); + + assert (packet_len + 1 < sizeof(packet)); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, true)) + { + if (response.IsOKResponse()) + return 0; + if (response.IsUnsupportedResponse()) + { + switch (type) + { + case eBreakpointSoftware: m_supports_z0 = false; break; + case eBreakpointHardware: m_supports_z1 = false; break; + case eWatchpointWrite: m_supports_z2 = false; break; + case eWatchpointRead: m_supports_z3 = false; break; + case eWatchpointReadWrite: m_supports_z4 = false; break; + default: break; + } + } + else if (response.IsErrorResponse()) + return response.GetError(); + } + return UINT8_MAX; +} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index ae1674a4d1f..5c24d642470 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -18,13 +18,22 @@ #include "GDBRemoteCommunication.h" +typedef enum +{ + eBreakpointSoftware = 0, + eBreakpointHardware, + eWatchpointWrite, + eWatchpointRead, + eWatchpointReadWrite +} GDBStoppointType; + class GDBRemoteCommunicationClient : public GDBRemoteCommunication { public: //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ - GDBRemoteCommunicationClient(); + GDBRemoteCommunicationClient(bool is_platform); virtual ~GDBRemoteCommunicationClient(); @@ -74,6 +83,9 @@ public: bool GetLaunchSuccess (std::string &error_str); + uint16_t + LaunchGDBserverAndGetPort (); + //------------------------------------------------------------------ /// Sends a GDB remote protocol 'A' packet that delivers program /// arguments to the remote server. @@ -214,11 +226,11 @@ public: bool GetProcessInfo (lldb::pid_t pid, - lldb_private::ProcessInfo &process_info); + lldb_private::ProcessInstanceInfo &process_info); uint32_t - FindProcesses (const lldb_private::ProcessInfoMatch &process_match_info, - lldb_private::ProcessInfoList &process_infos); + FindProcesses (const lldb_private::ProcessInstanceInfoMatch &process_match_info, + lldb_private::ProcessInstanceInfoList &process_infos); bool GetUserName (uint32_t uid, std::string &name); @@ -246,6 +258,33 @@ public: return old_packet_timeout; } + bool + GetStopReply (StringExtractorGDBRemote &response); + + bool + GetThreadStopInfo (uint32_t tid, + StringExtractorGDBRemote &response); + + bool + SupportsGDBStoppointPacket (GDBStoppointType type) + { + switch (type) + { + case eBreakpointSoftware: return m_supports_z0; + case eBreakpointHardware: return m_supports_z1; + case eWatchpointWrite: return m_supports_z2; + case eWatchpointRead: return m_supports_z3; + case eWatchpointReadWrite: return m_supports_z4; + default: break; + } + return false; + } + uint8_t + SendGDBStoppointTypePacket (GDBStoppointType type, // Type of breakpoint or watchpoint + bool insert, // Insert or remove? + lldb::addr_t addr, // Address of breakpoint or watchpoint + uint32_t length); // Byte Size of breakpoint or watchpoint + void TestPacketSpeed (const uint32_t num_packets); @@ -257,6 +296,13 @@ public: bool SendSpeedTestPacket (uint32_t send_size, uint32_t recv_size); + + bool + SetCurrentThread (int tid); + + bool + SetCurrentThreadForRun (int tid); + protected: //------------------------------------------------------------------ @@ -271,10 +317,21 @@ protected: lldb_private::LazyBool m_supports_vCont_s; lldb_private::LazyBool m_supports_vCont_S; lldb_private::LazyBool m_qHostInfo_is_valid; - bool m_supports_qProcessInfoPID; - bool m_supports_qfProcessInfo; - bool m_supports_qUserName; - bool m_supports_qGroupName; + bool + m_supports_qProcessInfoPID:1, + m_supports_qfProcessInfo:1, + m_supports_qUserName:1, + m_supports_qGroupName:1, + m_supports_qThreadStopInfo:1, + m_supports_z0:1, + m_supports_z1:1, + m_supports_z2:1, + m_supports_z3:1, + m_supports_z4:1; + + lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all other operations + lldb::tid_t m_curr_tid_run; // Current gdb remote protocol thread index for continue, step, etc + // If we need to send a packet while the target is running, the m_async_XXX // member variables take care of making this happen. @@ -294,7 +351,7 @@ protected: bool DecodeProcessInfoResponse (StringExtractorGDBRemote &response, - lldb_private::ProcessInfo &process_info); + lldb_private::ProcessInstanceInfo &process_info); private: //------------------------------------------------------------------ // For GDBRemoteCommunicationClient only diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index c2431380fd9..9379077335d 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -21,6 +21,7 @@ #include "lldb/Core/StreamString.h" #include "lldb/Host/Host.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Target/Process.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -33,9 +34,15 @@ using namespace lldb_private; //---------------------------------------------------------------------- // GDBRemoteCommunicationServer constructor //---------------------------------------------------------------------- -GDBRemoteCommunicationServer::GDBRemoteCommunicationServer() : - GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet"), - m_async_thread (LLDB_INVALID_HOST_THREAD) +GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) : + GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform), + m_async_thread (LLDB_INVALID_HOST_THREAD), + m_process_launch_info (), + m_process_launch_error (), + m_proc_infos (), + m_proc_infos_index (0), + m_lo_port_num (0), + m_hi_port_num (0) { } @@ -82,45 +89,76 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (const TimeValue* timeout const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType (); switch (packet_type) { - case StringExtractorGDBRemote::eServerPacketType_nack: - case StringExtractorGDBRemote::eServerPacketType_ack: - break; - - case StringExtractorGDBRemote::eServerPacketType_invalid: - error.SetErrorString("invalid packet"); - quit = true; - break; - - case StringExtractorGDBRemote::eServerPacketType_interrupt: - error.SetErrorString("interrupt received"); - interrupt = true; - break; - - case StringExtractorGDBRemote::eServerPacketType_unimplemented: - return SendUnimplementedResponse (packet.GetStringRef().c_str()) > 0; - - case StringExtractorGDBRemote::eServerPacketType_qHostInfo: - return Handle_qHostInfo (packet); - - case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID: - return Handle_qProcessInfoPID (packet); - - case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo: - return Handle_qfProcessInfo (packet); - - case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo: - return Handle_qsProcessInfo (packet); - - case StringExtractorGDBRemote::eServerPacketType_qUserName: - return Handle_qUserName (packet); - - case StringExtractorGDBRemote::eServerPacketType_qGroupName: - return Handle_qGroupName (packet); - - case StringExtractorGDBRemote::eServerPacketType_qSpeedTest: - return Handle_qSpeedTest (packet); - case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode: - return Handle_QStartNoAckMode (packet); + case StringExtractorGDBRemote::eServerPacketType_nack: + case StringExtractorGDBRemote::eServerPacketType_ack: + break; + + case StringExtractorGDBRemote::eServerPacketType_invalid: + error.SetErrorString("invalid packet"); + quit = true; + break; + + case StringExtractorGDBRemote::eServerPacketType_interrupt: + error.SetErrorString("interrupt received"); + interrupt = true; + break; + + case StringExtractorGDBRemote::eServerPacketType_unimplemented: + return SendUnimplementedResponse (packet.GetStringRef().c_str()) > 0; + + case StringExtractorGDBRemote::eServerPacketType_A: + return Handle_A (packet); + + case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo: + return Handle_qfProcessInfo (packet); + + case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo: + return Handle_qsProcessInfo (packet); + + case StringExtractorGDBRemote::eServerPacketType_qC: + return Handle_qC (packet); + + case StringExtractorGDBRemote::eServerPacketType_qHostInfo: + return Handle_qHostInfo (packet); + + case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer: + return Handle_qLaunchGDBServer (packet); + + case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess: + return Handle_qLaunchSuccess (packet); + + case StringExtractorGDBRemote::eServerPacketType_qGroupName: + return Handle_qGroupName (packet); + + case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID: + return Handle_qProcessInfoPID (packet); + + case StringExtractorGDBRemote::eServerPacketType_qSpeedTest: + return Handle_qSpeedTest (packet); + + case StringExtractorGDBRemote::eServerPacketType_qUserName: + return Handle_qUserName (packet); + + case StringExtractorGDBRemote::eServerPacketType_QEnvironment: + return Handle_QEnvironment (packet); + + case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR: + return Handle_QSetDisableASLR (packet); + + case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN: + return Handle_QSetSTDIN (packet); + + case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT: + return Handle_QSetSTDOUT (packet); + + case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR: + return Handle_QSetSTDERR (packet); + + case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir: + return Handle_QSetWorkingDir (packet); + + case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode: + return Handle_QStartNoAckMode (packet); } return true; } @@ -236,13 +274,13 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet } static void -CreateProcessInfoResponse (const ProcessInfo &proc_info, StreamString &response) +CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &response) { response.Printf ("pid:%i;ppid:%i;uid:%i;gid:%i;euid:%i;egid:%i;", proc_info.GetProcessID(), proc_info.GetParentProcessID(), - proc_info.GetRealUserID(), - proc_info.GetRealGroupID(), + proc_info.GetUserID(), + proc_info.GetGroupID(), proc_info.GetEffectiveUserID(), proc_info.GetEffectiveGroupID()); response.PutCString ("name:"); @@ -262,11 +300,11 @@ bool GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet) { // Packet format: "qProcessInfoPID:%i" where %i is the pid - packet.SetFilePos(strlen ("qProcessInfoPID:")); + packet.SetFilePos(::strlen ("qProcessInfoPID:")); lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID); if (pid != LLDB_INVALID_PROCESS_ID) { - ProcessInfo proc_info; + ProcessInstanceInfo proc_info; if (Host::GetProcessInfo(pid, proc_info)) { StreamString response; @@ -283,8 +321,8 @@ GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &pa m_proc_infos_index = 0; m_proc_infos.Clear(); - ProcessInfoMatch match_info; - packet.SetFilePos(strlen ("qfProcessInfo")); + ProcessInstanceInfoMatch match_info; + packet.SetFilePos(::strlen ("qfProcessInfo")); if (packet.GetChar() == ':') { @@ -337,11 +375,11 @@ GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &pa } else if (key.compare("uid") == 0) { - match_info.GetProcessInfo().SetRealUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success)); + match_info.GetProcessInfo().SetUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success)); } else if (key.compare("gid") == 0) { - match_info.GetProcessInfo().SetRealGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success)); + match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success)); } else if (key.compare("euid") == 0) { @@ -395,7 +433,7 @@ bool GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet) { // Packet format: "qUserName:%i" where %i is the uid - packet.SetFilePos(strlen ("qUserName:")); + packet.SetFilePos(::strlen ("qUserName:")); uint32_t uid = packet.GetU32 (UINT32_MAX); if (uid != UINT32_MAX) { @@ -415,7 +453,7 @@ bool GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet) { // Packet format: "qGroupName:%i" where %i is the gid - packet.SetFilePos(strlen ("qGroupName:")); + packet.SetFilePos(::strlen ("qGroupName:")); uint32_t gid = packet.GetU32 (UINT32_MAX); if (gid != UINT32_MAX) { @@ -433,7 +471,7 @@ GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packe bool GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet) { - packet.SetFilePos(strlen ("qSpeedTest:")); + packet.SetFilePos(::strlen ("qSpeedTest:")); std::string key; std::string value; @@ -466,6 +504,327 @@ GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packe } return SendErrorResponse (7); } + + +static void * +AcceptPortFromInferior (void *arg) +{ + const char *connect_url = (const char *)arg; + ConnectionFileDescriptor file_conn; + Error error; + if (file_conn.Connect (connect_url, &error) == eConnectionStatusSuccess) + { + char pid_str[256]; + ::memset (pid_str, 0, sizeof(pid_str)); + ConnectionStatus status; + const size_t pid_str_len = file_conn.Read (pid_str, sizeof(pid_str), status, NULL); + if (pid_str_len > 0) + { + int pid = atoi (pid_str); + return (void *)(intptr_t)pid; + } + } + return NULL; +} +// +//static bool +//WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds) +//{ +// const int time_delta_usecs = 100000; +// const int num_retries = timeout_in_seconds/time_delta_usecs; +// for (int i=0; i<num_retries; i++) +// { +// struct proc_bsdinfo bsd_info; +// int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO, +// (uint64_t) 0, +// &bsd_info, +// PROC_PIDTBSDINFO_SIZE); +// +// switch (error) +// { +// case EINVAL: +// case ENOTSUP: +// case ESRCH: +// case EPERM: +// return false; +// +// default: +// break; +// +// case 0: +// if (bsd_info.pbi_status == SSTOP) +// return true; +// } +// ::usleep (time_delta_usecs); +// } +// return false; +//} + +bool +GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) +{ + // The 'A' packet is the most over designed packet ever here with + // redundant argument indexes, redundant argument lengths and needed hex + // encoded argument string values. Really all that is needed is a comma + // separated hex encoded argument value list, but we will stay true to the + // documented version of the 'A' packet here... + + packet.SetFilePos(1); // Skip the 'A' + bool success = true; + while (success && packet.GetBytesLeft() > 0) + { + // Decode the decimal argument string length. This length is the + // number of hex nibbles in the argument string value. + const uint32_t arg_len = packet.GetU32(UINT32_MAX); + if (arg_len == UINT32_MAX) + success = false; + else + { + // Make sure the argument hex string length is followed by a comma + if (packet.GetChar() != ',') + success = false; + else + { + // Decode the argument index. We ignore this really becuase + // who would really send down the arguments in a random order??? + const uint32_t arg_idx = packet.GetU32(UINT32_MAX); + if (arg_idx == UINT32_MAX) + success = false; + else + { + // Make sure the argument index is followed by a comma + if (packet.GetChar() != ',') + success = false; + else + { + // Decode the argument string value from hex bytes + // back into a UTF8 string and make sure the length + // matches the one supplied in the packet + std::string arg; + if (packet.GetHexByteString(arg) != (arg_len / 2)) + success = false; + else + { + // If there are any bytes lft + if (packet.GetBytesLeft()) + { + if (packet.GetChar() != ',') + success = false; + } + + if (success) + { + if (arg_idx == 0) + m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false); + m_process_launch_info.GetArguments().AppendArgument(arg.c_str()); + } + } + } + } + } + } + } + + if (success) + { + m_process_launch_info.GetFlags().Set (eLaunchFlagDebug); + m_process_launch_error = Host::LaunchProcess (m_process_launch_info); + if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) + { + return SendOKResponse (); + } + } + return SendErrorResponse (8); +} + +bool +GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet) +{ + lldb::pid_t pid = m_process_launch_info.GetProcessID(); + StreamString response; + response.Printf("QC%x", pid); + if (m_is_platform) + { + // If we launch a process and this GDB server is acting as a platform, + // then we need to clear the process launch state so we can start + // launching another process. In order to launch a process a bunch or + // packets need to be sent: environment packets, working directory, + // disable ASLR, and many more settings. When we launch a process we + // then need to know when to clear this information. Currently we are + // selecting the 'qC' packet as that packet which seems to make the most + // sense. + if (pid != LLDB_INVALID_PROCESS_ID) + { + m_process_launch_info.Clear(); + } + } + return SendPacket (response); +} + +bool +GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) +{ + // Spawn a local debugserver as a platform so we can then attach or launch + // a process... + + if (m_is_platform) + { + // Sleep and wait a bit for debugserver to start to listen... + ConnectionFileDescriptor file_conn; + char connect_url[PATH_MAX]; + Error error; + 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 + { + ::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); + + if (IS_VALID_LLDB_HOST_THREAD(accept_thread)) + { + // Spawn a debugserver and try to get + ProcessLaunchInfo debugserver_launch_info; + error = StartDebugserverProcess ("localhost:0", + unix_socket_name, + debugserver_launch_info); + + lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); + 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_result) + { + uint16_t port = (intptr_t)accept_thread_result; + char response[256]; + const int response_len = ::snprintf (response, sizeof(response), "pid:%u;port:%u;", debugserver_pid, port); + assert (response_len < sizeof(response)); + //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); + success = SendPacket (response, response_len) > 0; + } + } + ::unlink (unix_socket_name); + + if (!success) + { + if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + ::kill (debugserver_pid, SIGINT); + } + return success; + } + } + } + } + return SendErrorResponse (13); +} + +bool +GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet) +{ + if (m_process_launch_error.Success()) + return SendOKResponse(); + StreamString response; + response.PutChar('E'); + response.PutCString(m_process_launch_error.AsCString("<unknown error>")); + return SendPacket (response); +} + +bool +GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen ("QEnvironment:")); + const uint32_t bytes_left = packet.GetBytesLeft(); + if (bytes_left > 0) + { + m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek()); + return SendOKResponse (); + } + return SendErrorResponse (9); +} + +bool +GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen ("QSetDisableASLR:")); + if (packet.GetU32(0)) + m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR); + else + m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR); + return SendOKResponse (); +} + +bool +GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen ("QSetWorkingDir:")); + std::string path; + packet.GetHexByteString(path); + m_process_launch_info.SwapWorkingDirectory (path); + return SendOKResponse (); +} + +bool +GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen ("QSetSTDIN:")); + ProcessLaunchInfo::FileAction file_action; + std::string path; + packet.GetHexByteString(path); + const bool read = false; + const bool write = true; + if (file_action.Open(STDIN_FILENO, path.c_str(), read, write)) + { + m_process_launch_info.AppendFileAction(file_action); + return SendOKResponse (); + } + return SendErrorResponse (10); +} + +bool +GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen ("QSetSTDOUT:")); + ProcessLaunchInfo::FileAction file_action; + std::string path; + packet.GetHexByteString(path); + const bool read = true; + const bool write = false; + if (file_action.Open(STDOUT_FILENO, path.c_str(), read, write)) + { + m_process_launch_info.AppendFileAction(file_action); + return SendOKResponse (); + } + return SendErrorResponse (11); +} + +bool +GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen ("QSetSTDERR:")); + ProcessLaunchInfo::FileAction file_action; + std::string path; + packet.GetHexByteString(path); + const bool read = true; + const bool write = true; + if (file_action.Open(STDERR_FILENO, path.c_str(), read, write)) + { + m_process_launch_info.AppendFileAction(file_action); + return SendOKResponse (); + } + return SendErrorResponse (12); +} + bool GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet) { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 02440a2db96..1fddaeb5fea 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -31,7 +31,7 @@ public: //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ - GDBRemoteCommunicationServer(); + GDBRemoteCommunicationServer(bool is_platform); virtual ~GDBRemoteCommunicationServer(); @@ -53,10 +53,26 @@ public: bool HandshakeWithClient (lldb_private::Error *error_ptr); + // Set both ports to zero to let the platform automatically bind to + // a port chosen by the OS. + void + SetPortRange (uint16_t lo_port_num, uint16_t hi_port_num) + { + m_lo_port_num = lo_port_num; + m_hi_port_num = hi_port_num; + } + protected: + //typedef std::map<uint16_t, lldb::pid_t> PortToPIDMap; + lldb::thread_t m_async_thread; - lldb_private::ProcessInfoList m_proc_infos; + lldb_private::ProcessLaunchInfo m_process_launch_info; + lldb_private::Error m_process_launch_error; + 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; size_t SendUnimplementedResponse (const char *packet); @@ -68,9 +84,18 @@ protected: SendOKResponse (); bool + Handle_A (StringExtractorGDBRemote &packet); + + bool + Handle_qLaunchSuccess (StringExtractorGDBRemote &packet); + + bool Handle_qHostInfo (StringExtractorGDBRemote &packet); bool + Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet); + + bool Handle_qProcessInfoPID (StringExtractorGDBRemote &packet); bool @@ -79,6 +104,9 @@ protected: bool Handle_qsProcessInfo (StringExtractorGDBRemote &packet); + bool + Handle_qC (StringExtractorGDBRemote &packet); + bool Handle_qUserName (StringExtractorGDBRemote &packet); @@ -89,8 +117,26 @@ protected: Handle_qSpeedTest (StringExtractorGDBRemote &packet); bool + Handle_QEnvironment (StringExtractorGDBRemote &packet); + + bool + Handle_QSetDisableASLR (StringExtractorGDBRemote &packet); + + bool + Handle_QSetWorkingDir (StringExtractorGDBRemote &packet); + + bool Handle_QStartNoAckMode (StringExtractorGDBRemote &packet); + bool + Handle_QSetSTDIN (StringExtractorGDBRemote &packet); + + bool + Handle_QSetSTDOUT (StringExtractorGDBRemote &packet); + + bool + Handle_QSetSTDERR (StringExtractorGDBRemote &packet); + private: //------------------------------------------------------------------ // For GDBRemoteCommunicationServer only diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index 0a1f87279f8..841efa207db 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -220,7 +220,7 @@ GDBRemoteRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data) if (gdb_comm.GetSequenceMutex (locker)) { const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); - if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID())) + if (thread_suffix_supported || GetGDBProcess().GetGDBRemote().SetCurrentThread(m_thread.GetID())) { char packet[64]; StringExtractorGDBRemote response; @@ -329,7 +329,7 @@ GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, if (gdb_comm.GetSequenceMutex (locker)) { const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); - if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID())) + if (thread_suffix_supported || GetGDBProcess().GetGDBRemote().SetCurrentThread(m_thread.GetID())) { uint32_t offset, end_offset; StreamString packet; @@ -407,7 +407,7 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) { char packet[32]; const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); - if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID())) + if (thread_suffix_supported || GetGDBProcess().GetGDBRemote().SetCurrentThread(m_thread.GetID())) { int packet_len = 0; if (thread_suffix_supported) @@ -449,7 +449,7 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data if (gdb_comm.GetSequenceMutex (locker)) { const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); - if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID())) + if (thread_suffix_supported || GetGDBProcess().GetGDBRemote().SetCurrentThread(m_thread.GetID())) { if (gdb_comm.SendPacketAndWaitForResponse((const char *)data_sp->GetBytes(), data_sp->GetByteSize(), @@ -474,91 +474,102 @@ GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, ui void GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters() { - static RegisterInfo - g_register_infos[] = - { - // NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE - // ====== ======= == ==== ============= ============ =============== =============== ========= ===== =========== - { "r0", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 0 }}, - { "r1", NULL, 4, 4, eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 1 }}, - { "r2", NULL, 4, 8, eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 2 }}, - { "r3", NULL, 4, 12, eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 3 }}, - { "r4", NULL, 4, 16, eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 4 }}, - { "r5", NULL, 4, 20, eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 5 }}, - { "r6", NULL, 4, 24, eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 6 }}, - { "r7", NULL, 4, 28, eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, 7 }}, - { "r8", NULL, 4, 32, eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 8 }}, - { "r9", NULL, 4, 36, eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 9 }}, - { "r10", NULL, 4, 40, eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 10 }}, - { "r11", NULL, 4, 44, eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 11 }}, - { "r12", NULL, 4, 48, eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 12 }}, - { "sp", "r13", 4, 52, eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, 13 }}, - { "lr", "r14", 4, 56, eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM, 14 }}, - { "pc", "r15", 4, 60, eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, 15 }}, -// { NULL, NULL, 12, 64, eEncodingIEEE754, eFormatFloat, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, 16 }}, -// { NULL, NULL, 12, 76, eEncodingIEEE754, eFormatFloat, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, 17 }}, -// { NULL, NULL, 12, 88, eEncodingIEEE754, eFormatFloat, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, 18 }}, -// { NULL, NULL, 12, 100, eEncodingIEEE754, eFormatFloat, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, 19 }}, -// { NULL, NULL, 12, 112, eEncodingIEEE754, eFormatFloat, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, 20 }}, -// { NULL, NULL, 12, 124, eEncodingIEEE754, eFormatFloat, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, 21 }}, -// { NULL, NULL, 12, 136, eEncodingIEEE754, eFormatFloat, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, 22 }}, -// { NULL, NULL, 12, 148, eEncodingIEEE754, eFormatFloat, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, 23 }}, -// { NULL, NULL, 12, 160, eEncodingIEEE754, eFormatFloat, { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, 24 }}, - { "cpsr", "psr", 4, 172, eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, 25 }}, - { "s0", NULL, 4, 176, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 26 }}, - { "s1", NULL, 4, 180, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 27 }}, - { "s2", NULL, 4, 184, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 28 }}, - { "s3", NULL, 4, 188, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 29 }}, - { "s4", NULL, 4, 192, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 30 }}, - { "s5", NULL, 4, 196, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 31 }}, - { "s6", NULL, 4, 200, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 32 }}, - { "s7", NULL, 4, 204, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 33 }}, - { "s8", NULL, 4, 208, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 34 }}, - { "s9", NULL, 4, 212, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 35 }}, - { "s10", NULL, 4, 216, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 36 }}, - { "s11", NULL, 4, 220, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 37 }}, - { "s12", NULL, 4, 224, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 38 }}, - { "s13", NULL, 4, 228, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 39 }}, - { "s14", NULL, 4, 232, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 40 }}, - { "s15", NULL, 4, 236, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 41 }}, - { "s16", NULL, 4, 240, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 42 }}, - { "s17", NULL, 4, 244, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 43 }}, - { "s18", NULL, 4, 248, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 44 }}, - { "s19", NULL, 4, 252, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 45 }}, - { "s20", NULL, 4, 256, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 46 }}, - { "s21", NULL, 4, 260, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 47 }}, - { "s22", NULL, 4, 264, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 48 }}, - { "s23", NULL, 4, 268, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 49 }}, - { "s24", NULL, 4, 272, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 50 }}, - { "s25", NULL, 4, 276, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 51 }}, - { "s26", NULL, 4, 280, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 52 }}, - { "s27", NULL, 4, 284, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 53 }}, - { "s28", NULL, 4, 288, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 54 }}, - { "s29", NULL, 4, 292, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 55 }}, - { "s30", NULL, 4, 296, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 56 }}, - { "s31", NULL, 4, 300, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 57 }}, - { "fpscr", NULL, 4, 304, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 58 }}, - { "d16", NULL, 8, 308, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 59 }}, - { "d17", NULL, 8, 316, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 60 }}, - { "d18", NULL, 8, 324, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 61 }}, - { "d19", NULL, 8, 332, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 62 }}, - { "d20", NULL, 8, 340, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 63 }}, - { "d21", NULL, 8, 348, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 64 }}, - { "d22", NULL, 8, 356, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 65 }}, - { "d23", NULL, 8, 364, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 66 }}, - { "d24", NULL, 8, 372, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 67 }}, - { "d25", NULL, 8, 380, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 68 }}, - { "d26", NULL, 8, 388, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 69 }}, - { "d27", NULL, 8, 396, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 70 }}, - { "d28", NULL, 8, 404, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 71 }}, - { "d29", NULL, 8, 412, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 72 }}, - { "d30", NULL, 8, 420, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 73 }}, - { "d31", NULL, 8, 428, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 74 }}, + static RegisterInfo g_register_infos[] = { +// NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB +// ====== ====== === === ============= ============ =================== =================== ====================== === ==== + { "r0", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_INVALID_REGNUM, 0, 0 }}, + { "r1", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_INVALID_REGNUM, 1, 1 }}, + { "r2", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_INVALID_REGNUM, 2, 2 }}, + { "r3", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_INVALID_REGNUM, 3, 3 }}, + { "r4", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, 4, 4 }}, + { "r5", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, 5, 5 }}, + { "r6", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, 6, 6 }}, + { "r7", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, 7, 7 }}, + { "r8", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, 8, 8 }}, + { "r9", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, 9, 9 }}, + { "r10", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, 10, 10 }}, + { "r11", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM, 11, 11 }}, + { "r12", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, 12, 12 }}, + { "sp", "r13", 4, 0, eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, 13, 13 }}, + { "lr", "r14", 4, 0, eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, 14, 14 }}, + { "pc", "r15", 4, 0, eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, 15, 15 }}, + { "f0", NULL, 12, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 16, 16 }}, + { "f1", NULL, 12, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 17, 17 }}, + { "f2", NULL, 12, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 18, 18 }}, + { "f3", NULL, 12, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 19, 19 }}, + { "f4", NULL, 12, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 20, 20 }}, + { "f5", NULL, 12, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 21, 21 }}, + { "f6", NULL, 12, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 22, 22 }}, + { "f7", NULL, 12, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 23, 23 }}, + { "fps", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 24, 24 }}, + { "cpsr", "psr", 4, 0, eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_INVALID_REGNUM, 25, 25 }}, + { "s0", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, 26, 26 }}, + { "s1", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, 27, 27 }}, + { "s2", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, 28, 28 }}, + { "s3", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, 29, 29 }}, + { "s4", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, 30, 30 }}, + { "s5", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, 31, 31 }}, + { "s6", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, 32, 32 }}, + { "s7", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, 33, 33 }}, + { "s8", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, 34, 34 }}, + { "s9", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, 35, 35 }}, + { "s10", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, 36, 36 }}, + { "s11", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, 37, 37 }}, + { "s12", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, 38, 38 }}, + { "s13", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, 39, 39 }}, + { "s14", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, 40, 40 }}, + { "s15", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, 41, 41 }}, + { "s16", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, 42, 42 }}, + { "s17", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, 43, 43 }}, + { "s18", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, 44, 44 }}, + { "s19", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, 45, 45 }}, + { "s20", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, 46, 46 }}, + { "s21", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, 47, 47 }}, + { "s22", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, 48, 48 }}, + { "s23", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, 49, 49 }}, + { "s24", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, 50, 50 }}, + { "s25", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, 51, 51 }}, + { "s26", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, 52, 52 }}, + { "s27", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, 53, 53 }}, + { "s28", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, 54, 54 }}, + { "s29", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, 55, 55 }}, + { "s30", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, 56, 56 }}, + { "s31", NULL, 4, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, 57, 57 }}, + { "fpscr",NULL, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 58, 58 }}, + { "d16", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, 59, 59 }}, + { "d17", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, 60, 60 }}, + { "d18", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, 61, 61 }}, + { "d19", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, 62, 62 }}, + { "d20", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, 63, 63 }}, + { "d21", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, 64, 64 }}, + { "d22", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, 65, 65 }}, + { "d23", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, 66, 66 }}, + { "d24", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, 67, 67 }}, + { "d25", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, 68, 68 }}, + { "d26", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, 69, 69 }}, + { "d27", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, 70, 70 }}, + { "d28", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, 71, 71 }}, + { "d29", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, 72, 72 }}, + { "d30", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, 73, 73 }}, + { "d31", NULL, 8, 0, eEncodingIEEE754, eFormatHex, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, 74, 74 }}, }; + static const uint32_t num_registers = sizeof (g_register_infos)/sizeof (RegisterInfo); static ConstString gpr_reg_set ("General Purpose Registers"); + static ConstString sfp_reg_set ("Software Floating Point Registers"); static ConstString vfp_reg_set ("Floating Point Registers"); - for (uint32_t i=0; i<num_registers; ++i) + uint32_t i; + // Calculate the offsets of the registers + if (g_register_infos[2].byte_offset == 0) + { + uint32_t byte_offset = 0; + for (i=0; i<num_registers; ++i) + { + g_register_infos[i].byte_offset = byte_offset; + byte_offset += g_register_infos[i].byte_size; + } + } + for (i=0; i<num_registers; ++i) { ConstString name; ConstString alt_name; @@ -566,8 +577,13 @@ GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters() name.SetCString(g_register_infos[i].name); if (g_register_infos[i].alt_name && g_register_infos[i].alt_name[0]) alt_name.SetCString(g_register_infos[i].alt_name); - - AddRegister (g_register_infos[i], name, alt_name, i < 26 ? gpr_reg_set : vfp_reg_set); + + if (i <= 15 || i == 25) + AddRegister (g_register_infos[i], name, alt_name, gpr_reg_set); + else if (i <= 24) + AddRegister (g_register_infos[i], name, alt_name, sfp_reg_set); + else + AddRegister (g_register_infos[i], name, alt_name, vfp_reg_set); } } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index ec07fbee072..79f77e219d1 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -114,16 +114,13 @@ ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) : Process (target, listener), m_flags (0), m_stdio_mutex (Mutex::eMutexTypeRecursive), - m_gdb_comm(), + m_gdb_comm(false), m_debugserver_pid (LLDB_INVALID_PROCESS_ID), m_debugserver_thread (LLDB_INVALID_HOST_THREAD), m_last_stop_packet (), m_register_info (), m_async_broadcaster ("lldb.process.gdb-remote.async-broadcaster"), m_async_thread (LLDB_INVALID_HOST_THREAD), - m_curr_tid (LLDB_INVALID_THREAD_ID), - m_curr_tid_run (LLDB_INVALID_THREAD_ID), - m_z0_supported (1), m_continue_c_tids (), m_continue_C_tids (), m_continue_s_tids (), @@ -430,7 +427,6 @@ ProcessGDBRemote::DoLaunch ObjectFile * object_file = module->GetObjectFile(); if (object_file) { - ArchSpec inferior_arch(module->GetArchitecture()); char host_port[128]; snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ()); char connect_url[128]; @@ -439,13 +435,7 @@ ProcessGDBRemote::DoLaunch // Make sure we aren't already connected? if (!m_gdb_comm.IsConnected()) { - error = StartDebugserverProcess (host_port, - NULL, - NULL, - LLDB_INVALID_PROCESS_ID, - NULL, - false, - inferior_arch); + error = StartDebugserverProcess (host_port); if (error.Fail()) return error; @@ -700,8 +690,6 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid) Error error; // Clear out and clean up from any current state Clear(); - const ArchSpec &arch_spec = GetTarget().GetArchitecture(); - if (attach_pid != LLDB_INVALID_PROCESS_ID) { // Make sure we aren't already connected? @@ -712,13 +700,7 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid) char connect_url[128]; snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port); - error = StartDebugserverProcess (host_port, // debugserver_url - NULL, // inferior_argv - NULL, // inferior_envp - LLDB_INVALID_PROCESS_ID, // Don't send any attach to pid options to debugserver - NULL, // Don't send any attach by process name option to debugserver - false, // Don't send any attach wait_for_launch flag as an option to debugserver - arch_spec); + error = StartDebugserverProcess (host_port); if (error.Fail()) { @@ -778,21 +760,12 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait // Make sure we aren't already connected? if (!m_gdb_comm.IsConnected()) { - - const ArchSpec &arch_spec = GetTarget().GetArchitecture(); - char host_port[128]; snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ()); char connect_url[128]; snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port); - error = StartDebugserverProcess (host_port, // debugserver_url - NULL, // inferior_argv - NULL, // inferior_envp - LLDB_INVALID_PROCESS_ID, // Don't send any attach to pid options to debugserver - NULL, // Don't send any attach by process name option to debugserver - false, // Don't send any attach wait_for_launch flag as an option to debugserver - arch_spec); + error = StartDebugserverProcess (host_port); if (error.Fail()) { const char *error_string = error.AsCString(); @@ -925,7 +898,7 @@ ProcessGDBRemote::DoResume () if (num_continue_c_tids == num_threads) { // All threads are resuming... - SetCurrentGDBRemoteThreadForRun (-1); + m_gdb_comm.SetCurrentThreadForRun (-1); continue_packet.PutChar ('c'); } else if (num_continue_c_tids == 1 && @@ -934,7 +907,7 @@ ProcessGDBRemote::DoResume () num_continue_S_tids == 0 ) { // Only one thread is continuing - SetCurrentGDBRemoteThreadForRun (m_continue_c_tids.front()); + m_gdb_comm.SetCurrentThreadForRun (m_continue_c_tids.front()); continue_packet.PutChar ('c'); } else @@ -960,7 +933,7 @@ ProcessGDBRemote::DoResume () if (!continue_packet_error) { // Add threads continuing with the same signo... - SetCurrentGDBRemoteThreadForRun (-1); + m_gdb_comm.SetCurrentThreadForRun (-1); continue_packet.Printf("C%2.2x", continue_signo); } } @@ -970,7 +943,7 @@ ProcessGDBRemote::DoResume () num_continue_S_tids == 0 ) { // Only one thread is continuing with signal - SetCurrentGDBRemoteThreadForRun (m_continue_C_tids.front().first); + m_gdb_comm.SetCurrentThreadForRun (m_continue_C_tids.front().first); continue_packet.Printf("C%2.2x", m_continue_C_tids.front().second); } else @@ -985,7 +958,7 @@ ProcessGDBRemote::DoResume () if (num_continue_s_tids == num_threads) { // All threads are resuming... - SetCurrentGDBRemoteThreadForRun (-1); + m_gdb_comm.SetCurrentThreadForRun (-1); continue_packet.PutChar ('s'); } else if (num_continue_c_tids == 0 && @@ -994,7 +967,7 @@ ProcessGDBRemote::DoResume () num_continue_S_tids == 0 ) { // Only one thread is stepping - SetCurrentGDBRemoteThreadForRun (m_continue_s_tids.front()); + m_gdb_comm.SetCurrentThreadForRun (m_continue_s_tids.front()); continue_packet.PutChar ('s'); } else @@ -1021,7 +994,7 @@ ProcessGDBRemote::DoResume () if (!continue_packet_error) { // Add threads stepping with the same signo... - SetCurrentGDBRemoteThreadForRun (-1); + m_gdb_comm.SetCurrentThreadForRun (-1); continue_packet.Printf("S%2.2x", step_signo); } } @@ -1031,7 +1004,7 @@ ProcessGDBRemote::DoResume () num_continue_S_tids == 1 ) { // Only one thread is stepping with signal - SetCurrentGDBRemoteThreadForRun (m_continue_S_tids.front().first); + m_gdb_comm.SetCurrentThreadForRun (m_continue_S_tids.front().first); continue_packet.Printf("S%2.2x", m_continue_S_tids.front().second); } else @@ -1667,40 +1640,28 @@ ProcessGDBRemote::EnableBreakpoint (BreakpointSite *bp_site) { // Try and set hardware breakpoint, and if that fails, fall through // and set a software breakpoint? - } - - if (m_z0_supported) - { - char packet[64]; - const int packet_len = ::snprintf (packet, sizeof(packet), "Z0,%llx,%zx", addr, bp_op_size); - assert (packet_len + 1 < sizeof(packet)); - StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true)) + if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointHardware)) { - if (response.IsUnsupportedResponse()) - { - // Disable z packet support and try again - m_z0_supported = 0; - return EnableBreakpoint (bp_site); - } - else if (response.IsOKResponse()) + if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, true, addr, bp_op_size) == 0) { bp_site->SetEnabled(true); - bp_site->SetType (BreakpointSite::eExternal); + bp_site->SetType (BreakpointSite::eHardware); return error; } - else - { - uint8_t error_byte = response.GetError(); - if (error_byte) - error.SetErrorStringWithFormat("%x packet failed with error: %i (0x%2.2x).\n", packet, error_byte, error_byte); - } } } - else + + if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointSoftware)) { - return EnableSoftwareBreakpoint (bp_site); + if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, true, addr, bp_op_size) == 0) + { + bp_site->SetEnabled(true); + bp_site->SetType (BreakpointSite::eExternal); + return error; + } } + + return EnableSoftwareBreakpoint (bp_site); } if (log) @@ -1731,44 +1692,25 @@ ProcessGDBRemote::DisableBreakpoint (BreakpointSite *bp_site) { const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site); - if (bp_site->IsHardware()) - { - // TODO: disable hardware breakpoint... - } - else + BreakpointSite::Type bp_type = bp_site->GetType(); + switch (bp_type) { - if (m_z0_supported) - { - char packet[64]; - const int packet_len = ::snprintf (packet, sizeof(packet), "z0,%llx,%zx", addr, bp_op_size); - assert (packet_len + 1 < sizeof(packet)); - StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true)) - { - if (response.IsUnsupportedResponse()) - { - error.SetErrorString("Breakpoint site was set with Z packet, yet remote debugserver states z packets are not supported."); - } - else if (response.IsOKResponse()) - { - if (log) - log->Printf ("ProcessGDBRemote::DisableBreakpoint (site_id = %d) addr = 0x%8.8llx -- SUCCESS", site_id, (uint64_t)addr); - bp_site->SetEnabled(false); - return error; - } - else - { - uint8_t error_byte = response.GetError(); - if (error_byte) - error.SetErrorStringWithFormat("%x packet failed with error: %i (0x%2.2x).\n", packet, error_byte, error_byte); - } - } - } - else - { - return DisableSoftwareBreakpoint (bp_site); - } + case BreakpointSite::eSoftware: + error = DisableSoftwareBreakpoint (bp_site); + break; + + case BreakpointSite::eHardware: + if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false, addr, bp_op_size)) + error.SetErrorToGenericError(); + break; + + case BreakpointSite::eExternal: + if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false, addr, bp_op_size)) + error.SetErrorToGenericError(); + break; } + if (error.Success()) + bp_site->SetEnabled(false); } else { @@ -1869,16 +1811,7 @@ ProcessGDBRemote::DoSignal (int signo) } Error -ProcessGDBRemote::StartDebugserverProcess -( - const char *debugserver_url, // The connection string to use in the spawned debugserver ("localhost:1234" or "/dev/tty...") - char const *inferior_argv[], // Arguments for the inferior program including the path to the inferior itself as the first argument - char const *inferior_envp[], // Environment to pass along to the inferior program - lldb::pid_t attach_pid, // If inferior inferior_argv == NULL, and attach_pid != LLDB_INVALID_PROCESS_ID send this pid as an argument to debugserver - const char *attach_name, // Wait for the next process to launch whose basename matches "attach_name" - bool wait_for_launch, // Wait for the process named "attach_name" to launch - const ArchSpec& inferior_arch // The arch of the inferior that we will launch -) +ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url) // The connection string to use in the spawned debugserver ("localhost:1234" or "/dev/tty...") { Error error; if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID) @@ -1886,8 +1819,9 @@ ProcessGDBRemote::StartDebugserverProcess // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; - FileSpec debugserver_file_spec; + ProcessLaunchInfo launch_info; char debugserver_path[PATH_MAX]; + FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); // Always check to see if we have an environment override for the path // to the debugserver to use and use it if we do. @@ -1922,25 +1856,10 @@ ProcessGDBRemote::StartDebugserverProcess debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); m_stdio_communication.Clear(); - posix_spawnattr_t attr; LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - Error local_err; // Errors that don't affect the spawning. - if (log) - log->Printf ("%s ( path='%s', argv=%p, envp=%p, arch=%s )", - __FUNCTION__, - debugserver_path, - inferior_argv, - inferior_envp, - inferior_arch.GetArchitectureName()); - error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX); - if (error.Fail() || log) - error.PutToLog(log.get(), "::posix_spawnattr_init ( &attr )"); - if (error.Fail()) - return error; - - Args debugserver_args; + Args &debugserver_args = launch_info.GetArguments(); char arg_cstr[PATH_MAX]; // Start args with "debugserver /file/path -r --" @@ -1968,6 +1887,12 @@ ProcessGDBRemote::StartDebugserverProcess // debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt"); // debugserver_args.AppendArgument("--log-flags=0x802e0e"); + // We currently send down all arguments, attach pids, or attach + // process names in dedicated GDB server packets, so we don't need + // to pass them as arguments. This is currently because of all the + // things we need to setup prior to launching: the environment, + // current working dir, file actions, etc. +#if 0 // Now append the program arguments if (inferior_argv) { @@ -1990,20 +1915,18 @@ ProcessGDBRemote::StartDebugserverProcess debugserver_args.AppendArgument ("--attach"); debugserver_args.AppendArgument (attach_name); } - - Error file_actions_err; - posix_spawn_file_actions_t file_actions; -#if DONT_CLOSE_DEBUGSERVER_STDIO - file_actions_err.SetErrorString ("Remove this after uncommenting the code block below."); -#else - file_actions_err.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX); - if (file_actions_err.Success()) - { - ::posix_spawn_file_actions_addclose (&file_actions, STDIN_FILENO); - ::posix_spawn_file_actions_addclose (&file_actions, STDOUT_FILENO); - ::posix_spawn_file_actions_addclose (&file_actions, STDERR_FILENO); - } #endif + + ProcessLaunchInfo::FileAction file_action; + + // Close STDIN, STDOUT and STDERR. We might need to redirect them + // to "/dev/null" if we run into any problems. + file_action.Close (STDIN_FILENO); + launch_info.AppendFileAction (file_action); + file_action.Close (STDOUT_FILENO); + launch_info.AppendFileAction (file_action); + file_action.Close (STDERR_FILENO); + launch_info.AppendFileAction (file_action); if (log) { @@ -2012,28 +1935,15 @@ ProcessGDBRemote::StartDebugserverProcess log->Printf("%s arguments:\n%s", debugserver_args.GetArgumentAtIndex(0), strm.GetData()); } - error.SetError (::posix_spawnp (&m_debugserver_pid, - debugserver_path, - file_actions_err.Success() ? &file_actions : NULL, - &attr, - debugserver_args.GetArgumentVector(), - (char * const*)inferior_envp), - eErrorTypePOSIX); - - - ::posix_spawnattr_destroy (&attr); - - if (file_actions_err.Success()) - ::posix_spawn_file_actions_destroy (&file_actions); + error = Host::LaunchProcess(launch_info); - // We have seen some cases where posix_spawnp was returning a valid - // looking pid even when an error was returned, so clear it out - if (error.Fail()) + if (error.Success ()) + m_debugserver_pid = launch_info.GetProcessID(); + else m_debugserver_pid = LLDB_INVALID_PROCESS_ID; if (error.Fail() || log) - error.PutToLog(log.get(), "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", m_debugserver_pid, debugserver_path, NULL, &attr, inferior_argv, inferior_envp); - + error.PutToLog(log.get(), "Host::LaunchProcess (launch_info) => pid=%i, path='%s'", m_debugserver_pid, debugserver_path); } else { @@ -2143,71 +2053,8 @@ ProcessGDBRemote::Initialize() } bool -ProcessGDBRemote::SetCurrentGDBRemoteThread (int tid) -{ - if (m_curr_tid == tid) - return true; - - char packet[32]; - int packet_len; - if (tid <= 0) - packet_len = ::snprintf (packet, sizeof(packet), "Hg%i", tid); - else - packet_len = ::snprintf (packet, sizeof(packet), "Hg%x", tid); - assert (packet_len + 1 < sizeof(packet)); - StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false)) - { - if (response.IsOKResponse()) - { - m_curr_tid = tid; - return true; - } - } - return false; -} - -bool -ProcessGDBRemote::SetCurrentGDBRemoteThreadForRun (int tid) -{ - if (m_curr_tid_run == tid) - return true; - - char packet[32]; - int packet_len; - if (tid <= 0) - packet_len = ::snprintf (packet, sizeof(packet), "Hc%i", tid); - else - packet_len = ::snprintf (packet, sizeof(packet), "Hc%x", tid); - - assert (packet_len + 1 < sizeof(packet)); - StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false)) - { - if (response.IsOKResponse()) - { - m_curr_tid_run = tid; - return true; - } - } - return false; -} - -void -ProcessGDBRemote::ResetGDBRemoteState () -{ - // Reset and GDB remote state - m_curr_tid = LLDB_INVALID_THREAD_ID; - m_curr_tid_run = LLDB_INVALID_THREAD_ID; - m_z0_supported = 1; -} - - -bool ProcessGDBRemote::StartAsyncThread () { - ResetGDBRemoteState (); - LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); if (log) diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index e9ab4df70f0..cf03604a182 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -215,12 +215,6 @@ protected: friend class GDBRemoteCommunicationClient; friend class GDBRemoteRegisterContext; - bool - SetCurrentGDBRemoteThread (int tid); - - bool - SetCurrentGDBRemoteThreadForRun (int tid); - //---------------------------------------------------------------------- // Accessors //---------------------------------------------------------------------- @@ -275,13 +269,7 @@ protected: UpdateThreadListIfNeeded (); lldb_private::Error - StartDebugserverProcess (const char *debugserver_url, // The connection string to use in the spawned debugserver ("localhost:1234" or "/dev/tty...") - char const *inferior_argv[], - char const *inferior_envp[], - lldb::pid_t attach_pid, // If inferior inferior_argv == NULL, then attach to this pid - const char *attach_pid_name, // Wait for the next process to launch whose basename matches "attach_wait_name" - bool wait_for_launch, // Wait for the process named "attach_wait_name" to launch - const lldb_private::ArchSpec& arch_spec); + StartDebugserverProcess (const char *debugserver_url); void KillDebugserverProcess (); @@ -313,11 +301,6 @@ protected: GDBRemoteDynamicRegisterInfo m_register_info; lldb_private::Broadcaster m_async_broadcaster; lldb::thread_t m_async_thread; - // Current GDB remote state. Any members added here need to be reset to - // proper default values in ResetGDBRemoteState (). - lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all other operations - lldb::tid_t m_curr_tid_run; // Current gdb remote protocol thread index for continue, step, etc - uint32_t m_z0_supported:1; // Set to non-zero if Z0 and z0 packets are supported typedef std::vector<lldb::tid_t> tid_collection; typedef std::vector< std::pair<lldb::tid_t,int> > tid_sig_collection; tid_collection m_continue_c_tids; // 'c' for continue @@ -330,9 +313,6 @@ protected: bool m_local_debugserver; // Is the debugserver process we are talking to local or on another machine. std::vector<lldb::user_id_t> m_thread_observation_bps; - void - ResetGDBRemoteState (); - bool StartAsyncThread (); diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index 9955409226a..351b6eb2bc9 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -261,13 +261,10 @@ ThreadGDBRemote::GetPrivateStopReason () m_thread_stop_reason_stop_id = process_stop_id; m_actual_stop_info_sp.reset(); - char packet[256]; - ::snprintf(packet, sizeof(packet), "qThreadStopInfo%x", GetID()); StringExtractorGDBRemote stop_packet; - if (GetGDBProcess().GetGDBRemote().SendPacketAndWaitForResponse(packet, stop_packet, false)) - { - GetGDBProcess().SetThreadStopInfo (stop_packet); - } + ProcessGDBRemote &gdb_process = GetGDBProcess(); + if (gdb_process.GetGDBRemote().GetThreadStopInfo(GetID(), stop_packet)) + gdb_process.SetThreadStopInfo (stop_packet); } return m_actual_stop_info_sp; } diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp index 458420893ae..a2568a3bbf4 100644 --- a/lldb/source/Symbol/ObjectFile.cpp +++ b/lldb/source/Symbol/ObjectFile.cpp @@ -61,8 +61,8 @@ ObjectFile::FindPlugin (Module* module, const FileSpec* file, lldb::addr_t file_ // No need to delegate further if (file_offset, file_size) exceeds the total file size. // This is the base case. - if (file_offset + file_size > file->GetByteSize()) - return NULL; +// if (file_offset + file_size > file->GetByteSize()) +// return NULL; DataBufferSP file_header_data_sp(file->ReadFileContents(file_offset, 512)); uint32_t idx; diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp index cddd37ff6be..34c7337979e 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -14,9 +14,11 @@ // Other libraries and framework includes // Project includes #include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" #include "lldb/Core/PluginManager.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/Host.h" +#include "lldb/Target/Process.h" #include "lldb/Target/Target.h" using namespace lldb; @@ -165,6 +167,9 @@ Platform::Platform (bool is_host) : m_max_uid_name_len (0), m_max_gid_name_len (0) { + LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf ("%p Platform::Platform()", this); } //------------------------------------------------------------------ @@ -175,6 +180,9 @@ Platform::Platform (bool is_host) : //------------------------------------------------------------------ Platform::~Platform() { + LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf ("%p Platform::~Platform()", this); } void @@ -300,6 +308,15 @@ Platform::GetOSKernelDescription (std::string &s) } const char * +Platform::GetName () +{ + const char *name = GetHostname(); + if (name == NULL || name[0] == '\0') + name = GetShortPluginName(); + return name; +} + +const char * Platform::GetHostname () { if (IsHost() && m_name.empty()) @@ -498,21 +515,66 @@ Platform::DisconnectRemote () } bool -Platform::GetProcessInfo (lldb::pid_t pid, ProcessInfo &process_info) +Platform::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) { // Take care of the host case so that each subclass can just - // call Platform::GetProcessInfo (pid, process_info) + // call this function to get the host functionality. if (IsHost()) return Host::GetProcessInfo (pid, process_info); return false; } uint32_t -Platform::FindProcesses (const ProcessInfoMatch &match_info, - ProcessInfoList &process_infos) +Platform::FindProcesses (const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { + // Take care of the host case so that each subclass can just + // call this function to get the host functionality. uint32_t match_count = 0; if (IsHost()) match_count = Host::FindProcesses (match_info, process_infos); return match_count; } + + +Error +Platform::LaunchProcess (ProcessLaunchInfo &launch_info) +{ + Error error; + // Take care of the host case so that each subclass can just + // call this function to get the host functionality. + if (IsHost()) + error = Host::LaunchProcess (launch_info); + else + error.SetErrorString ("base lldb_private::Platform class can't launch remote processes"); + return error; +} + +lldb::ProcessSP +Platform::DebugProcess (ProcessLaunchInfo &launch_info, + Debugger &debugger, + Target *target, // Can be NULL, if NULL create a new target, else use existing one + Listener &listener, + Error &error) +{ + ProcessSP process_sp; + // Make sure we stop at the entry point + launch_info.GetFlags ().Set (eLaunchFlagDebug); + error = LaunchProcess (launch_info); + if (error.Success()) + { + lldb::pid_t pid = launch_info.GetProcessID(); + if (pid != LLDB_INVALID_PROCESS_ID) + { + process_sp = Attach (pid, debugger, target, listener, error); + +// if (process_sp) +// { +// if (launch_info.GetFlags().IsClear (eLaunchFlagStopAtEntry)) +// process_sp->Resume(); +// } + } + } + return process_sp; +} + diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 940ff2bd949..c33dd183ec9 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -40,7 +40,7 @@ using namespace lldb; using namespace lldb_private; void -ProcessInfo::Dump (Stream &s, Platform *platform) const +ProcessInstanceInfo::Dump (Stream &s, Platform *platform) const { const char *cstr; if (m_pid != LLDB_INVALID_PROCESS_ID) @@ -56,59 +56,80 @@ ProcessInfo::Dump (Stream &s, Platform *platform) const m_executable.Dump(&s); s.EOL(); } - const uint32_t argc = m_args.GetSize(); + const uint32_t argc = m_arguments.GetArgumentCount(); if (argc > 0) { for (uint32_t i=0; i<argc; i++) { + const char *arg = m_arguments.GetArgumentAtIndex(i); if (i < 10) - s.Printf (" arg[%u] = %s\n", i, m_args.GetStringAtIndex(i)); + s.Printf (" arg[%u] = %s\n", i, arg); else - s.Printf ("arg[%u] = %s\n", i, m_args.GetStringAtIndex(i)); + s.Printf ("arg[%u] = %s\n", i, arg); } } + + const uint32_t envc = m_environment.GetArgumentCount(); + if (envc > 0) + { + for (uint32_t i=0; i<envc; i++) + { + const char *env = m_environment.GetArgumentAtIndex(i); + if (i < 10) + s.Printf (" env[%u] = %s\n", i, env); + else + s.Printf ("env[%u] = %s\n", i, env); + } + } + if (m_arch.IsValid()) s.Printf (" arch = %s\n", m_arch.GetTriple().str().c_str()); - if (m_real_uid != UINT32_MAX) + if (m_uid != UINT32_MAX) { - cstr = platform->GetUserName (m_real_uid); - s.Printf (" uid = %-5u (%s)\n", m_real_uid, cstr ? cstr : ""); + cstr = platform->GetUserName (m_uid); + s.Printf (" uid = %-5u (%s)\n", m_uid, cstr ? cstr : ""); } - if (m_real_gid != UINT32_MAX) + if (m_gid != UINT32_MAX) { - cstr = platform->GetGroupName (m_real_gid); - s.Printf (" gid = %-5u (%s)\n", m_real_gid, cstr ? cstr : ""); + cstr = platform->GetGroupName (m_gid); + s.Printf (" gid = %-5u (%s)\n", m_gid, cstr ? cstr : ""); } - if (m_effective_uid != UINT32_MAX) + if (m_euid != UINT32_MAX) { - cstr = platform->GetUserName (m_effective_uid); - s.Printf (" euid = %-5u (%s)\n", m_effective_uid, cstr ? cstr : ""); + cstr = platform->GetUserName (m_euid); + s.Printf (" euid = %-5u (%s)\n", m_euid, cstr ? cstr : ""); } - if (m_effective_gid != UINT32_MAX) + if (m_egid != UINT32_MAX) { - cstr = platform->GetGroupName (m_effective_gid); - s.Printf (" egid = %-5u (%s)\n", m_effective_gid, cstr ? cstr : ""); + cstr = platform->GetGroupName (m_egid); + s.Printf (" egid = %-5u (%s)\n", m_egid, cstr ? cstr : ""); } } void -ProcessInfo::DumpTableHeader (Stream &s, Platform *platform, bool verbose) +ProcessInstanceInfo::DumpTableHeader (Stream &s, Platform *platform, bool show_args, bool verbose) { + const char *label; + if (show_args || verbose) + label = "ARGUMENTS"; + else + label = "NAME"; + if (verbose) { - s.PutCString ("PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME\n"); + s.Printf ("PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE %s\n", label); s.PutCString ("====== ====== ========== ========== ========== ========== ======================== ============================\n"); } else { - s.PutCString ("PID PARENT USER ARCH NAME\n"); + s.Printf ("PID PARENT USER ARCH %s\n", label); s.PutCString ("====== ====== ========== ======= ============================\n"); } } void -ProcessInfo::DumpAsTableRow (Stream &s, Platform *platform, bool verbose) const +ProcessInstanceInfo::DumpAsTableRow (Stream &s, Platform *platform, bool show_args, bool verbose) const { if (m_pid != LLDB_INVALID_PROCESS_ID) { @@ -118,49 +139,49 @@ ProcessInfo::DumpAsTableRow (Stream &s, Platform *platform, bool verbose) const if (verbose) { - cstr = platform->GetUserName (m_real_uid); + cstr = platform->GetUserName (m_uid); if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed s.Printf ("%-10s ", cstr); else - s.Printf ("%-10u ", m_real_uid); + s.Printf ("%-10u ", m_uid); - cstr = platform->GetGroupName (m_real_gid); + cstr = platform->GetGroupName (m_gid); if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed s.Printf ("%-10s ", cstr); else - s.Printf ("%-10u ", m_real_gid); + s.Printf ("%-10u ", m_gid); - cstr = platform->GetUserName (m_effective_uid); + cstr = platform->GetUserName (m_euid); if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed s.Printf ("%-10s ", cstr); else - s.Printf ("%-10u ", m_effective_uid); + s.Printf ("%-10u ", m_euid); - cstr = platform->GetGroupName (m_effective_gid); + cstr = platform->GetGroupName (m_egid); if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed s.Printf ("%-10s ", cstr); else - s.Printf ("%-10u ", m_effective_gid); + s.Printf ("%-10u ", m_egid); s.Printf ("%-24s ", m_arch.IsValid() ? m_arch.GetTriple().str().c_str() : ""); } else { s.Printf ("%-10s %.*-7s ", - platform->GetUserName (m_effective_uid), + platform->GetUserName (m_euid), (int)m_arch.GetTriple().getArchName().size(), m_arch.GetTriple().getArchName().data()); } - if (verbose) + if (verbose || show_args) { - const uint32_t argc = m_args.GetSize(); + const uint32_t argc = m_arguments.GetArgumentCount(); if (argc > 0) { for (uint32_t i=0; i<argc; i++) { if (i > 0) s.PutChar (' '); - s.PutCString (m_args.GetStringAtIndex(i)); + s.PutCString (m_arguments.GetArgumentAtIndex(i)); } } } @@ -173,8 +194,263 @@ ProcessInfo::DumpAsTableRow (Stream &s, Platform *platform, bool verbose) const } } + +void +ProcessInfo::SetArgumentsFromArgs (const Args& args, + bool first_arg_is_executable, + bool first_arg_is_executable_and_argument) +{ + // Copy all arguments + m_arguments = args; + + // Is the first argument the executable? + if (first_arg_is_executable) + { + const char *first_arg = args.GetArgumentAtIndex (0); + if (first_arg) + { + // Yes the first argument is an executable, set it as the executable + // in the launch options. Don't resolve the file path as the path + // could be a remote platform path + const bool resolve = false; + m_executable.SetFile(first_arg, resolve); + + // If argument zero is an executable and shouldn't be included + // in the arguments, remove it from the front of the arguments + if (first_arg_is_executable_and_argument == false) + m_arguments.DeleteArgumentAtIndex (0); + } + } +} + +bool +ProcessLaunchInfo::FileAction::Open (int fd, const char *path, bool read, bool write) +{ + if ((read || write) && fd >= 0 && path && path[0]) + { + m_action = eFileActionOpen; + m_fd = fd; + if (read && write) + m_arg = O_RDWR; + else if (read) + m_arg = O_RDONLY; + else + m_arg = O_WRONLY; + m_path.assign (path); + return true; + } + else + { + Clear(); + } + return false; +} + bool -ProcessInfoMatch::NameMatches (const char *process_name) const +ProcessLaunchInfo::FileAction::Close (int fd) +{ + Clear(); + if (fd >= 0) + { + m_action = eFileActionClose; + m_fd = fd; + } + return m_fd >= 0; +} + + +bool +ProcessLaunchInfo::FileAction::Duplicate (int fd, int dup_fd) +{ + Clear(); + if (fd >= 0 && dup_fd >= 0) + { + m_action = eFileActionDuplicate; + m_fd = fd; + m_arg = dup_fd; + } + return m_fd >= 0; +} + + + +bool +ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (posix_spawn_file_actions_t *file_actions, + const FileAction *info, + Log *log, + Error& error) +{ + if (info == NULL) + return false; + + switch (info->m_action) + { + case eFileActionNone: + error.Clear(); + break; + + case eFileActionClose: + if (info->m_fd == -1) + error.SetErrorString ("invalid fd for posix_spawn_file_actions_addclose(...)"); + else + { + error.SetError (::posix_spawn_file_actions_addclose (file_actions, info->m_fd), + eErrorTypePOSIX); + if (log && (error.Fail() || log)) + error.PutToLog(log, "posix_spawn_file_actions_addclose (action=%p, fd=%i)", + file_actions, info->m_fd); + } + break; + + case eFileActionDuplicate: + if (info->m_fd == -1) + error.SetErrorString ("invalid fd for posix_spawn_file_actions_adddup2(...)"); + else if (info->m_arg == -1) + error.SetErrorString ("invalid duplicate fd for posix_spawn_file_actions_adddup2(...)"); + else + { + error.SetError (::posix_spawn_file_actions_adddup2 (file_actions, info->m_fd, info->m_arg), + eErrorTypePOSIX); + if (log && (error.Fail() || log)) + error.PutToLog(log, "posix_spawn_file_actions_adddup2 (action=%p, fd=%i, dup_fd=%i)", + file_actions, info->m_fd, info->m_arg); + } + break; + + case eFileActionOpen: + if (info->m_fd == -1) + error.SetErrorString ("invalid fd in posix_spawn_file_actions_addopen(...)"); + else + { + int oflag = info->m_arg; + mode_t mode = 0; + + error.SetError (::posix_spawn_file_actions_addopen (file_actions, + info->m_fd, + info->m_path.c_str(), + oflag, + mode), + eErrorTypePOSIX); + if (error.Fail() || log) + error.PutToLog(log, + "posix_spawn_file_actions_addopen (action=%p, fd=%i, path='%s', oflag=%i, mode=%i)", + file_actions, info->m_fd, info->m_path.c_str(), oflag, mode); + } + break; + + default: + error.SetErrorStringWithFormat ("invalid file action: %i", info->m_action); + break; + } + return error.Success(); +} + +Error +ProcessLaunchCommandOptions::SetOptionValue (int option_idx, const char *option_arg) +{ + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 's': // Stop at program entry point + launch_info.GetFlags().Set (eLaunchFlagStopAtEntry); + break; + + case 'e': // STDERR for read + write + { + ProcessLaunchInfo::FileAction action; + if (action.Open(STDERR_FILENO, option_arg, true, true)) + launch_info.AppendFileAction (action); + } + break; + + case 'i': // STDIN for read only + { + ProcessLaunchInfo::FileAction action; + if (action.Open(STDIN_FILENO, option_arg, true, false)) + launch_info.AppendFileAction (action); + } + break; + + case 'o': // Open STDOUT for write only + { + ProcessLaunchInfo::FileAction action; + if (action.Open(STDOUT_FILENO, option_arg, false, true)) + launch_info.AppendFileAction (action); + } + break; + + case 'p': // Process plug-in name + launch_info.SetProcessPluginName (option_arg); + break; + + case 'n': // Disable STDIO + { + ProcessLaunchInfo::FileAction action; + if (action.Open(STDERR_FILENO, "/dev/null", true, true)) + launch_info.AppendFileAction (action); + if (action.Open(STDOUT_FILENO, "/dev/null", false, true)) + launch_info.AppendFileAction (action); + if (action.Open(STDIN_FILENO, "/dev/null", true, false)) + launch_info.AppendFileAction (action); + } + break; + + case 'w': + launch_info.SetWorkingDirectory (option_arg); + break; + + case 't': // Open process in new terminal window + launch_info.GetFlags().Set (eLaunchFlagLaunchInTTY); + break; + + case 'a': + launch_info.GetArchitecture().SetTriple (option_arg, + m_interpreter.GetPlatform(true).get()); + break; + + case 'A': + launch_info.GetFlags().Set (eLaunchFlagDisableASLR); + break; + + case 'v': + launch_info.GetEnvironmentEntries().AppendArgument(option_arg); + break; + + default: + error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); + break; + + } + return error; +} + +OptionDefinition +ProcessLaunchCommandOptions::g_option_table[] = +{ +{ LLDB_OPT_SET_ALL, false, "stop-at-entry", 's', no_argument, NULL, 0, eArgTypeNone, "Stop at the entry point of the program when launching a process."}, +{ LLDB_OPT_SET_ALL, false, "disable-aslr", 'A', no_argument, NULL, 0, eArgTypeNone, "Disable address space layout randomization when launching a process."}, +{ LLDB_OPT_SET_ALL, false, "plugin", 'p', required_argument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."}, +{ LLDB_OPT_SET_ALL, false, "working-dir", 'w', required_argument, NULL, 0, eArgTypePath, "Set the current working directory to <path> when running the inferior."}, +{ LLDB_OPT_SET_ALL, false, "arch", 'a', required_argument, NULL, 0, eArgTypeArchitecture, "Set the architecture for the process to launch when ambiguous."}, +{ LLDB_OPT_SET_ALL, false, "environment", 'v', required_argument, NULL, 0, eArgTypeNone, "Specify an environment variable name/value stirng (--environement NAME=VALUE). Can be specified multiple times for subsequent environment entries."}, + +{ LLDB_OPT_SET_1 , false, "stdin", 'i', required_argument, NULL, 0, eArgTypePath, "Redirect stdin for the process to <path>."}, +{ LLDB_OPT_SET_1 , false, "stdout", 'o', required_argument, NULL, 0, eArgTypePath, "Redirect stdout for the process to <path>."}, +{ LLDB_OPT_SET_1 , false, "stderr", 'e', required_argument, NULL, 0, eArgTypePath, "Redirect stderr for the process to <path>."}, + +{ LLDB_OPT_SET_2 , false, "tty", 't', no_argument, NULL, 0, eArgTypeNone, "Start the process in a terminal (not supported on all platforms)."}, + +{ LLDB_OPT_SET_3 , false, "no-stdio", 'n', no_argument, NULL, 0, eArgTypeNone, "Do not set up for terminal I/O to go to running process."}, + +{ 0 , false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } +}; + + + +bool +ProcessInstanceInfoMatch::NameMatches (const char *process_name) const { if (m_name_match_type == eNameMatchIgnore || process_name == NULL) return true; @@ -186,7 +462,7 @@ ProcessInfoMatch::NameMatches (const char *process_name) const } bool -ProcessInfoMatch::Matches (const ProcessInfo &proc_info) const +ProcessInstanceInfoMatch::Matches (const ProcessInstanceInfo &proc_info) const { if (!NameMatches (proc_info.GetName())) return false; @@ -199,12 +475,12 @@ ProcessInfoMatch::Matches (const ProcessInfo &proc_info) const m_match_info.GetParentProcessID() != proc_info.GetParentProcessID()) return false; - if (m_match_info.RealUserIDIsValid () && - m_match_info.GetRealUserID() != proc_info.GetRealUserID()) + if (m_match_info.UserIDIsValid () && + m_match_info.GetUserID() != proc_info.GetUserID()) return false; - if (m_match_info.RealGroupIDIsValid () && - m_match_info.GetRealGroupID() != proc_info.GetRealGroupID()) + if (m_match_info.GroupIDIsValid () && + m_match_info.GetGroupID() != proc_info.GetGroupID()) return false; if (m_match_info.EffectiveUserIDIsValid () && @@ -222,7 +498,7 @@ ProcessInfoMatch::Matches (const ProcessInfo &proc_info) const } bool -ProcessInfoMatch::MatchAllProcesses () const +ProcessInstanceInfoMatch::MatchAllProcesses () const { if (m_name_match_type != eNameMatchIgnore) return false; @@ -233,10 +509,10 @@ ProcessInfoMatch::MatchAllProcesses () const if (m_match_info.ParentProcessIDIsValid()) return false; - if (m_match_info.RealUserIDIsValid ()) + if (m_match_info.UserIDIsValid ()) return false; - if (m_match_info.RealGroupIDIsValid ()) + if (m_match_info.GroupIDIsValid ()) return false; if (m_match_info.EffectiveUserIDIsValid ()) @@ -256,7 +532,7 @@ ProcessInfoMatch::MatchAllProcesses () const } void -ProcessInfoMatch::Clear() +ProcessInstanceInfoMatch::Clear() { m_match_info.Clear(); m_name_match_type = eNameMatchIgnore; @@ -1504,6 +1780,46 @@ Process::ReadMemory (addr_t addr, void *buf, size_t size, Error &error) size_t +Process::ReadCStringFromMemory (addr_t addr, char *dst, size_t dst_max_len) +{ + size_t total_cstr_len = 0; + if (dst && dst_max_len) + { + // NULL out everything just to be safe + memset (dst, 0, dst_max_len); + Error error; + addr_t curr_addr = addr; + const size_t cache_line_size = m_memory_cache.GetMemoryCacheLineSize(); + size_t bytes_left = dst_max_len - 1; + char *curr_dst = dst; + + while (bytes_left > 0) + { + addr_t cache_line_bytes_left = cache_line_size - (curr_addr % cache_line_size); + addr_t bytes_to_read = std::min<addr_t>(bytes_left, cache_line_bytes_left); + size_t bytes_read = ReadMemory (curr_addr, curr_dst, bytes_to_read, error); + + if (bytes_read == 0) + { + dst[total_cstr_len] = '\0'; + break; + } + const size_t len = strlen(curr_dst); + + total_cstr_len += len; + + if (len < bytes_to_read) + break; + + curr_dst += bytes_read; + curr_addr += bytes_read; + bytes_left -= bytes_read; + } + } + return total_cstr_len; +} + +size_t Process::ReadMemoryFromInferior (addr_t addr, void *buf, size_t size, Error &error) { if (buf == NULL || size == 0) @@ -1894,7 +2210,7 @@ Process::Attach (lldb::pid_t attach_pid) // Find the process and its architecture. Make sure it matches the architecture // of the current Target, and if not adjust it. - ProcessInfo process_info; + ProcessInstanceInfo process_info; PlatformSP platform_sp (m_target.GetDebugger().GetPlatformList().GetSelectedPlatform ()); if (platform_sp) { @@ -1947,11 +2263,11 @@ Process::Attach (const char *process_name, bool wait_for_launch) if (!wait_for_launch) { - ProcessInfoList process_infos; + ProcessInstanceInfoList process_infos; PlatformSP platform_sp (m_target.GetDebugger().GetPlatformList().GetSelectedPlatform ()); if (platform_sp) { - ProcessInfoMatch match_info; + ProcessInstanceInfoMatch match_info; match_info.GetProcessInfo().SetName(process_name); match_info.SetNameMatchType (eNameMatchEquals); platform_sp->FindProcesses (match_info, process_infos); @@ -1965,7 +2281,7 @@ Process::Attach (const char *process_name, bool wait_for_launch) } else { - ProcessInfo process_info; + ProcessInstanceInfo process_info; if (process_infos.GetInfoAtIndex (0, process_info)) { const ArchSpec &process_arch = process_info.GetArchitecture(); @@ -2034,7 +2350,7 @@ Process::CompleteAttach () for (int i = 0; i < num_modules; i++) { ModuleSP module_sp (modules.GetModuleAtIndex(i)); - if (module_sp->IsExecutable()) + if (module_sp && module_sp->IsExecutable()) { ModuleSP target_exe_module_sp (m_target.GetExecutableModule()); if (target_exe_module_sp != module_sp) @@ -2391,8 +2707,12 @@ Process::StartPrivateStateThread () { LogSP log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); + bool already_running = PrivateStateThreadIsValid (); if (log) - log->Printf ("Process::%s ( )", __FUNCTION__); + log->Printf ("Process::%s()%s ", __FUNCTION__, already_running ? " already running" : " starting private state thread"); + + if (already_running) + return true; // Create a thread that watches our internal state and controls which // events make it to clients (into the DCProcess event queue). @@ -2417,7 +2737,8 @@ Process::ResumePrivateStateThread () void Process::StopPrivateStateThread () { - ControlPrivateStateThread (eBroadcastInternalStateControlStop); + if (PrivateStateThreadIsValid ()) + ControlPrivateStateThread (eBroadcastInternalStateControlStop); } void @@ -2702,7 +3023,7 @@ Process::ProcessEventData::Dump (Stream *s) const if (m_process_sp) s->Printf(" process = %p (pid = %u), ", m_process_sp.get(), m_process_sp->GetID()); - s->Printf("state = %s", StateAsCString(GetState()));; + s->Printf("state = %s", StateAsCString(GetState())); } const Process::ProcessEventData * @@ -3005,7 +3326,7 @@ Process::UpdateInstanceName () sstr.Printf ("%s", module_sp->GetFileSpec().GetFilename().AsCString()); GetSettingsController()->RenameInstanceSettings (GetInstanceName().AsCString(), - sstr.GetData()); + sstr.GetData()); } } @@ -3661,7 +3982,11 @@ ProcessInstanceSettings::UpdateInstanceSettingsVariable (const ConstString &var_ UserSettingsController::UpdateStringArrayVariable (op, index_value, m_run_args, value, err); else if (var_name == EnvVarsVarName()) { - GetHostEnvironmentIfNeeded (); + // This is nice for local debugging, but it is isn't correct for + // remote debugging. We need to stop process.env-vars from being + // populated with the host environment and add this as a launch option + // and get the correct environment from the Target's platform. + // GetHostEnvironmentIfNeeded (); UserSettingsController::UpdateDictionaryVariable (op, index_value, m_env_vars, value, err); } else if (var_name == InputPathVarName()) diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp index 3c0a9cab86f..7e06a0f59bc 100644 --- a/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -53,48 +53,90 @@ StringExtractorGDBRemote::GetResponseType () const StringExtractorGDBRemote::ServerPacketType StringExtractorGDBRemote::GetServerPacketType () const { +#define PACKET_MATCHES(s) ((packet_size == (sizeof(s)-1)) && (strcmp((packet_cstr),(s)) == 0)) +#define PACKET_STARTS_WITH(s) ((packet_size >= (sizeof(s)-1)) && ::strncmp(packet_cstr, s, (sizeof(s)-1))==0) + // Empty is not a supported packet... if (m_packet.empty()) return eServerPacketType_invalid; + const size_t packet_size = m_packet.size(); const char *packet_cstr = m_packet.c_str(); switch (m_packet[0]) { case '\x03': - if (m_packet.size() == 1) - return eServerPacketType_interrupt; + if (packet_size == 1) return eServerPacketType_interrupt; break; case '-': - if (m_packet.size() == 1) - return eServerPacketType_nack; + if (packet_size == 1) return eServerPacketType_nack; break; case '+': - if (m_packet.size() == 1) - return eServerPacketType_ack; + if (packet_size == 1) return eServerPacketType_ack; break; + case 'A': + return eServerPacketType_A; + case 'Q': - if (strcmp (packet_cstr, "QStartNoAckMode") == 0) - return eServerPacketType_QStartNoAckMode; + switch (packet_cstr[1]) + { + case 'E': + if (PACKET_STARTS_WITH ("QEnvironment:")) return eServerPacketType_QEnvironment; + break; + + case 'S': + if (PACKET_MATCHES ("QStartNoAckMode")) return eServerPacketType_QStartNoAckMode; + else if (PACKET_STARTS_WITH ("QSetDisableASLR:")) return eServerPacketType_QSetDisableASLR; + else if (PACKET_STARTS_WITH ("QSetSTDIN:")) return eServerPacketType_QSetSTDIN; + else if (PACKET_STARTS_WITH ("QSetSTDOUT:")) return eServerPacketType_QSetSTDOUT; + else if (PACKET_STARTS_WITH ("QSetSTDERR:")) return eServerPacketType_QSetSTDERR; + else if (PACKET_STARTS_WITH ("QSetWorkingDir:")) return eServerPacketType_QSetWorkingDir; + break; + } break; case 'q': - if (packet_cstr[1] == 'S' && 0 == ::strncmp(packet_cstr, "qSpeedTest:", strlen("qSpeedTest:"))) - return eServerPacketType_qSpeedTest; - else if (packet_cstr[1] == 'H' && 0 == ::strcmp (packet_cstr, "qHostInfo")) - return eServerPacketType_qHostInfo; - else if (packet_cstr[1] == 'P' && 0 == ::strncmp(packet_cstr, "qProcessInfoPID:", strlen("qProcessInfoPID:"))) - return eServerPacketType_qProcessInfoPID; - else if (packet_cstr[1] == 'f' && 0 == ::strncmp(packet_cstr, "qfProcessInfo", strlen("qfProcessInfo"))) - return eServerPacketType_qfProcessInfo; - else if (packet_cstr[1] == 'U' && 0 == ::strncmp(packet_cstr, "qUserName:", strlen("qUserName:"))) - return eServerPacketType_qUserName; - else if (packet_cstr[1] == 'G' && 0 == ::strncmp(packet_cstr, "qGroupName:", strlen("qGroupName:"))) - return eServerPacketType_qGroupName; - else if (packet_cstr[1] == 's' && 0 == ::strcmp (packet_cstr, "qsProcessInfo")) - return eServerPacketType_qsProcessInfo; + switch (packet_cstr[1]) + { + case 's': + if (PACKET_MATCHES ("qsProcessInfo")) return eServerPacketType_qsProcessInfo; + break; + + case 'f': + if (PACKET_STARTS_WITH ("qfProcessInfo")) return eServerPacketType_qfProcessInfo; + break; + + case 'C': + if (packet_size == 2) return eServerPacketType_qC; + break; + + case 'G': + if (PACKET_STARTS_WITH ("qGroupName:")) return eServerPacketType_qGroupName; + break; + + case 'H': + if (PACKET_MATCHES ("qHostInfo")) return eServerPacketType_qHostInfo; + break; + + case 'L': + if (PACKET_MATCHES ("qLaunchGDBServer")) return eServerPacketType_qLaunchGDBServer; + if (PACKET_MATCHES ("qLaunchSuccess")) return eServerPacketType_qLaunchSuccess; + break; + + case 'P': + if (PACKET_STARTS_WITH ("qProcessInfoPID:")) return eServerPacketType_qProcessInfoPID; + break; + + case 'S': + if (PACKET_STARTS_WITH ("qSpeedTest:")) return eServerPacketType_qSpeedTest; + break; + + case 'U': + if (PACKET_STARTS_WITH ("qUserName:")) return eServerPacketType_qUserName; + break; + } break; } return eServerPacketType_unimplemented; diff --git a/lldb/source/Utility/StringExtractorGDBRemote.h b/lldb/source/Utility/StringExtractorGDBRemote.h index 36fd0344a09..5a24d894b10 100644 --- a/lldb/source/Utility/StringExtractorGDBRemote.h +++ b/lldb/source/Utility/StringExtractorGDBRemote.h @@ -46,13 +46,23 @@ public: eServerPacketType_invalid, eServerPacketType_unimplemented, eServerPacketType_interrupt, // CTRL+c packet or "\x03" - eServerPacketType_qHostInfo, - eServerPacketType_qProcessInfoPID, + eServerPacketType_A, // Program arguments packet eServerPacketType_qfProcessInfo, eServerPacketType_qsProcessInfo, - eServerPacketType_qUserName, + eServerPacketType_qC, eServerPacketType_qGroupName, + eServerPacketType_qHostInfo, + eServerPacketType_qLaunchGDBServer, + eServerPacketType_qLaunchSuccess, + eServerPacketType_qProcessInfoPID, eServerPacketType_qSpeedTest, + eServerPacketType_qUserName, + eServerPacketType_QEnvironment, + eServerPacketType_QSetDisableASLR, + eServerPacketType_QSetSTDIN, + eServerPacketType_QSetSTDOUT, + eServerPacketType_QSetSTDERR, + eServerPacketType_QSetWorkingDir, eServerPacketType_QStartNoAckMode }; diff --git a/lldb/test/abbreviation_tests/TestAbbreviations.py b/lldb/test/abbreviation_tests/TestAbbreviations.py index 9cbdae6ebe5..6f46346c54d 100644 --- a/lldb/test/abbreviation_tests/TestAbbreviations.py +++ b/lldb/test/abbreviation_tests/TestAbbreviations.py @@ -74,7 +74,7 @@ class AbbreviationsTestCase(TestBase): self.expect("fil " + exe, patterns = [ "Current executable set to .*a.out.*" ]) - self.expect("regexp-b product", + self.expect("_regexp-b product", substrs = [ "breakpoint set --name 'product'", "Breakpoint created: 1: name = 'product', locations = 1" ]) diff --git a/lldb/test/dotest.py b/lldb/test/dotest.py index 18b2e268b62..ecb4b722286 100755 --- a/lldb/test/dotest.py +++ b/lldb/test/dotest.py @@ -216,9 +216,9 @@ $ ./dotest.py -v -p ObjC Collected 4 tests test_break_with_dsym (TestObjCMethods.FoundationTestCase) -Test setting objc breakpoints using 'regexp-break' and 'breakpoint set'. ... ok +Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok test_break_with_dwarf (TestObjCMethods.FoundationTestCase) -Test setting objc breakpoints using 'regexp-break' and 'breakpoint set'. ... ok +Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase) Lookup objective-c data types and evaluate expressions. ... ok test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase) diff --git a/lldb/test/foundation/TestFoundationDisassembly.py b/lldb/test/foundation/TestFoundationDisassembly.py index 8722fab23a8..a51e2375b4c 100644 --- a/lldb/test/foundation/TestFoundationDisassembly.py +++ b/lldb/test/foundation/TestFoundationDisassembly.py @@ -70,7 +70,7 @@ class FoundationDisassembleTestCase(TestBase): self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) # Stop at +[NSString stringWithFormat:]. - self.expect("regexp-break +[NSString stringWithFormat:]", BREAKPOINT_CREATED, + self.expect("_regexp-break +[NSString stringWithFormat:]", BREAKPOINT_CREATED, substrs = ["Breakpoint created: 1: name = '+[NSString stringWithFormat:]', locations = 1"]) # Stop at -[MyString initWithNSString:]. @@ -82,7 +82,7 @@ class FoundationDisassembleTestCase(TestBase): startstr = "Breakpoint created: 3: name = 'description', locations = 1") # Stop at -[NSAutoreleasePool release]. - self.expect("regexp-break -[NSAutoreleasePool release]", BREAKPOINT_CREATED, + self.expect("_regexp-break -[NSAutoreleasePool release]", BREAKPOINT_CREATED, substrs = ["Breakpoint created: 4: name = '-[NSAutoreleasePool release]', locations = 1"]) self.runCmd("run", RUN_SUCCEEDED) diff --git a/lldb/test/foundation/TestObjCMethods.py b/lldb/test/foundation/TestObjCMethods.py index b8415fee209..9485cb57327 100644 --- a/lldb/test/foundation/TestObjCMethods.py +++ b/lldb/test/foundation/TestObjCMethods.py @@ -14,12 +14,12 @@ class FoundationTestCase(TestBase): mydir = "foundation" def test_break_with_dsym(self): - """Test setting objc breakpoints using 'regexp-break' and 'breakpoint set'.""" + """Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'.""" self.buildDsym() self.break_on_objc_methods() def test_break_with_dwarf(self): - """Test setting objc breakpoints using 'regexp-break' and 'breakpoint set'.""" + """Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'.""" self.buildDwarf() self.break_on_objc_methods() @@ -50,12 +50,12 @@ class FoundationTestCase(TestBase): self.print_ivars_correctly() def break_on_objc_methods(self): - """Test setting objc breakpoints using 'regexp-break' and 'breakpoint set'.""" + """Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'.""" exe = os.path.join(os.getcwd(), "a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) # Stop at +[NSString stringWithFormat:]. - self.expect("regexp-break +[NSString stringWithFormat:]", BREAKPOINT_CREATED, + self.expect("_regexp-break +[NSString stringWithFormat:]", BREAKPOINT_CREATED, substrs = ["Breakpoint created: 1: name = '+[NSString stringWithFormat:]', locations = 1"]) # Stop at -[MyString initWithNSString:]. @@ -67,7 +67,7 @@ class FoundationTestCase(TestBase): startstr = "Breakpoint created: 3: name = 'description', locations = 1") # Stop at -[NSAutoreleasePool release]. - self.expect("regexp-break -[NSAutoreleasePool release]", BREAKPOINT_CREATED, + self.expect("_regexp-break -[NSAutoreleasePool release]", BREAKPOINT_CREATED, substrs = ["Breakpoint created: 4: name = '-[NSAutoreleasePool release]', locations = 1"]) self.runCmd("run", RUN_SUCCEEDED) diff --git a/lldb/tools/darwin-debug/darwin-debug.cpp b/lldb/tools/darwin-debug/darwin-debug.cpp index 689c3864aff..9be32595246 100644 --- a/lldb/tools/darwin-debug/darwin-debug.cpp +++ b/lldb/tools/darwin-debug/darwin-debug.cpp @@ -246,7 +246,7 @@ int main (int argc, char *const *argv, char *const *envp, const char **apple) printf ("argv[%u] = '%s'\n", i, argv[i]); #endif - // Open the socket that was passed in as an argument + // Open the socket that was passed in as an option struct sockaddr_un saddr_un; int s = ::socket (AF_UNIX, SOCK_STREAM, 0); if (s < 0) diff --git a/lldb/tools/debugserver/source/MacOSX/CFString.h b/lldb/tools/debugserver/source/MacOSX/CFString.h index 2b96b8237fc..73945a28a65 100644 --- a/lldb/tools/debugserver/source/MacOSX/CFString.h +++ b/lldb/tools/debugserver/source/MacOSX/CFString.h @@ -24,7 +24,7 @@ public: // Constructors and Destructors //------------------------------------------------------------------ CFString (CFStringRef cf_str = NULL); - CFString (const char *s, CFStringEncoding encoding); + CFString (const char *s, CFStringEncoding encoding = kCFStringEncodingUTF8); CFString (const CFString& rhs); CFString& operator= (const CFString& rhs); virtual ~CFString (); diff --git a/lldb/tools/debugserver/source/RNBSocket.cpp b/lldb/tools/debugserver/source/RNBSocket.cpp index 139a4150adf..5af9810d0e4 100644 --- a/lldb/tools/debugserver/source/RNBSocket.cpp +++ b/lldb/tools/debugserver/source/RNBSocket.cpp @@ -31,78 +31,90 @@ This function blocks while waiting for that connection. */ rnb_err_t -RNBSocket::Listen (in_port_t listen_port_num) +RNBSocket::Listen (in_port_t port, PortBoundCallback callback, const void *callback_baton) { //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s called", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__); // Disconnect without saving errno Disconnect (false); DNBError err; - int listen_port = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (listen_port == -1) + int listen_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (listen_fd == -1) err.SetError(errno, DNBError::POSIX); if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::socket ( domain = AF_INET, type = SOCK_STREAM, protocol = IPPROTO_TCP ) => socket = %i", listen_port); + err.LogThreaded("::socket ( domain = AF_INET, type = SOCK_STREAM, protocol = IPPROTO_TCP ) => socket = %i", listen_fd); if (err.Fail()) return rnb_err; // enable local address reuse - SetSocketOption (listen_port, SOL_SOCKET, SO_REUSEADDR, 1); + SetSocketOption (listen_fd, SOL_SOCKET, SO_REUSEADDR, 1); struct sockaddr_in sa; ::memset (&sa, 0, sizeof sa); sa.sin_len = sizeof sa; sa.sin_family = AF_INET; - sa.sin_port = htons (listen_port_num); + sa.sin_port = htons (port); sa.sin_addr.s_addr = htonl (INADDR_ANY); - int error = ::bind (listen_port, (struct sockaddr *) &sa, sizeof(sa)); + int error = ::bind (listen_fd, (struct sockaddr *) &sa, sizeof(sa)); if (error == -1) err.SetError(errno, DNBError::POSIX); if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::bind ( socket = %i, (struct sockaddr *) &sa, sizeof(sa)) )", listen_port); + err.LogThreaded("::bind ( socket = %i, (struct sockaddr *) &sa, sizeof(sa)) )", listen_fd); if (err.Fail()) { - ClosePort (listen_port, false); + ClosePort (listen_fd, false); return rnb_err; } - error = ::listen (listen_port, 1); + if (callback && port == 0) + { + // We were asked to listen on port zero which means we + // must now read the actual port that was given to us + // as port zero is a special code for "find an open port + // for me". + socklen_t sa_len = sizeof (sa); + if (getsockname(listen_fd, (struct sockaddr *)&sa, &sa_len) == 0) + { + port = ntohs (sa.sin_port); + callback (callback_baton, port); + } + } + + error = ::listen (listen_fd, 1); if (error == -1) err.SetError(errno, DNBError::POSIX); if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::listen ( socket = %i, backlog = 1 )", listen_port); + err.LogThreaded("::listen ( socket = %i, backlog = 1 )", listen_fd); if (err.Fail()) { - ClosePort (listen_port, false); + ClosePort (listen_fd, false); return rnb_err; } - m_conn_port = ::accept (listen_port, NULL, 0); - if (m_conn_port == -1) + m_fd = ::accept (listen_fd, NULL, 0); + if (m_fd == -1) err.SetError(errno, DNBError::POSIX); if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::accept ( socket = %i, address = NULL, address_len = 0 )", listen_port); + err.LogThreaded("::accept ( socket = %i, address = NULL, address_len = 0 )", listen_fd); + + ClosePort (listen_fd, false); if (err.Fail()) { - ClosePort (listen_port, false); return rnb_err; } else { - // We are done with the listen port - ClosePort (listen_port, false); - // Keep our TCP packets coming without any delays. - SetSocketOption (m_conn_port, IPPROTO_TCP, TCP_NODELAY, 1); + SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1); } return rnb_success; @@ -114,12 +126,12 @@ RNBSocket::Connect (const char *host, uint16_t port) Disconnect (false); // Create the socket - m_conn_port = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (m_conn_port == -1) + m_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (m_fd == -1) return rnb_err; // Enable local address reuse - SetSocketOption (m_conn_port, SOL_SOCKET, SO_REUSEADDR, 1); + SetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, 1); struct sockaddr_in sa; ::memset (&sa, 0, sizeof (sa)); @@ -146,14 +158,14 @@ RNBSocket::Connect (const char *host, uint16_t port) } } - if (-1 == ::connect (m_conn_port, (const struct sockaddr *)&sa, sizeof(sa))) + if (-1 == ::connect (m_fd, (const struct sockaddr *)&sa, sizeof(sa))) { Disconnect (false); return rnb_err; } // Keep our TCP packets coming without any delays. - SetSocketOption (m_conn_port, IPPROTO_TCP, TCP_NODELAY, 1); + SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1); return rnb_success; } @@ -165,13 +177,13 @@ RNBSocket::ConnectToService() // Disconnect from any previous connections Disconnect(false); - m_conn_port = ::lockdown_checkin (NULL, NULL); - if (m_conn_port == -1) + m_fd = ::lockdown_checkin (NULL, NULL); + if (m_fd == -1) { DNBLogThreadedIf(LOG_RNB_COMM, "::lockdown_checkin(NULL, NULL) failed"); return rnb_not_connected; } - m_conn_port_from_lockdown = true; + m_fd_from_lockdown = true; return rnb_success; } #endif @@ -180,8 +192,8 @@ rnb_err_t RNBSocket::OpenFile (const char *path) { DNBError err; - m_conn_port = open (path, O_RDWR); - if (m_conn_port == -1) + m_fd = open (path, O_RDWR); + if (m_fd == -1) { err.SetError(errno, DNBError::POSIX); err.LogThreaded ("can't open file '%s'", path); @@ -191,11 +203,11 @@ RNBSocket::OpenFile (const char *path) { struct termios stdin_termios; - if (::tcgetattr (m_conn_port, &stdin_termios) == 0) + if (::tcgetattr (m_fd, &stdin_termios) == 0) { stdin_termios.c_lflag &= ~ECHO; // Turn off echoing stdin_termios.c_lflag &= ~ICANON; // Get one char at a time - ::tcsetattr (m_conn_port, TCSANOW, &stdin_termios); + ::tcsetattr (m_fd, TCSANOW, &stdin_termios); } } return rnb_success; @@ -210,9 +222,9 @@ RNBSocket::SetSocketOption(int fd, int level, int option_name, int option_value) rnb_err_t RNBSocket::Disconnect (bool save_errno) { - if (m_conn_port_from_lockdown) - m_conn_port_from_lockdown = false; - return ClosePort (m_conn_port, save_errno); + if (m_fd_from_lockdown) + m_fd_from_lockdown = false; + return ClosePort (m_fd, save_errno); } @@ -225,29 +237,29 @@ RNBSocket::Read (std::string &p) // Note that BUF is on the stack so we must be careful to keep any // writes to BUF from overflowing or we'll have security issues. - if (m_conn_port == -1) + if (m_fd == -1) return rnb_err; //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s calling read()", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__); DNBError err; - int bytesread = read (m_conn_port, buf, sizeof (buf)); + int bytesread = read (m_fd, buf, sizeof (buf)); if (bytesread <= 0) err.SetError(errno, DNBError::POSIX); else p.append(buf, bytesread); if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::read ( %i, %p, %zu ) => %i", m_conn_port, buf, sizeof (buf), bytesread); + err.LogThreaded("::read ( %i, %p, %zu ) => %i", m_fd, buf, sizeof (buf), bytesread); // Our port went away - we have to mark this so IsConnected will return the truth. if (bytesread == 0) { - m_conn_port = -1; + m_fd = -1; return rnb_not_connected; } else if (bytesread == -1) { - m_conn_port = -1; + m_fd = -1; return rnb_err; } // Strip spaces from the end of the buffer @@ -262,16 +274,16 @@ RNBSocket::Read (std::string &p) rnb_err_t RNBSocket::Write (const void *buffer, size_t length) { - if (m_conn_port == -1) + if (m_fd == -1) return rnb_err; DNBError err; - int bytessent = send (m_conn_port, buffer, length, 0); + int bytessent = send (m_fd, buffer, length, 0); if (bytessent < 0) err.SetError(errno, DNBError::POSIX); if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::send ( socket = %i, buffer = %p, length = %zu, flags = 0 ) => %i", m_conn_port, buffer, length, bytessent); + err.LogThreaded("::send ( socket = %i, buffer = %p, length = %zu, flags = 0 ) => %i", m_fd, buffer, length, bytessent); if (bytessent < 0) return rnb_err; diff --git a/lldb/tools/debugserver/source/RNBSocket.h b/lldb/tools/debugserver/source/RNBSocket.h index 56608bb17fc..5fd6ac2a570 100644 --- a/lldb/tools/debugserver/source/RNBSocket.h +++ b/lldb/tools/debugserver/source/RNBSocket.h @@ -23,10 +23,11 @@ class RNBSocket { public: + typedef void (*PortBoundCallback) (const void *baton, in_port_t port); RNBSocket () : - m_conn_port (-1), - m_conn_port_from_lockdown (false), + m_fd (-1), + m_fd_from_lockdown (false), m_timer (true) // Make a thread safe timer { } @@ -35,7 +36,7 @@ public: Disconnect (false); } - rnb_err_t Listen (in_port_t listen_port_num); + rnb_err_t Listen (in_port_t port, PortBoundCallback callback, const void *callback_baton); rnb_err_t Connect (const char *host, uint16_t port); #if defined (__arm__) @@ -46,7 +47,7 @@ public: rnb_err_t Read (std::string &p); rnb_err_t Write (const void *buffer, size_t length); - bool IsConnected () const { return m_conn_port != -1; } + bool IsConnected () const { return m_fd != -1; } void SaveErrno (int curr_errno); DNBTimer& Timer() { return m_timer; } @@ -58,8 +59,8 @@ private: protected: rnb_err_t ClosePort (int& fd, bool save_errno); - int m_conn_port; // Socket we use to communicate once conn established - bool m_conn_port_from_lockdown; + int m_fd; // Socket we use to communicate once conn established + bool m_fd_from_lockdown; DNBTimer m_timer; }; diff --git a/lldb/tools/debugserver/source/debugserver.cpp b/lldb/tools/debugserver/source/debugserver.cpp index 6e08d5dd8dc..12a873ef8e3 100644 --- a/lldb/tools/debugserver/source/debugserver.cpp +++ b/lldb/tools/debugserver/source/debugserver.cpp @@ -17,6 +17,12 @@ #include <string> #include <vector> #include <asl.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <sys/un.h> +#include <sys/types.h> #include "CFString.h" #include "DNB.h" @@ -608,13 +614,68 @@ RNBRunLoopPlatform (RNBRemote *remote) // Returns 1 for success 0 for failure. //---------------------------------------------------------------------- +static void +PortWasBoundCallback (const void *baton, in_port_t port) +{ + //::printf ("PortWasBoundCallback (baton = %p, port = %u)\n", baton, port); + + const char *unix_socket_name = (const char *)baton; + + if (unix_socket_name && unix_socket_name[0]) + { + // We were given a unix socket name to use to communicate the port + // that we ended up binding to back to our parent process + struct sockaddr_un saddr_un; + int s = ::socket (AF_UNIX, SOCK_STREAM, 0); + if (s < 0) + { + perror("error: socket (AF_UNIX, SOCK_STREAM, 0)"); + exit(1); + } + + saddr_un.sun_family = AF_UNIX; + ::strncpy(saddr_un.sun_path, unix_socket_name, sizeof(saddr_un.sun_path) - 1); + saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; + saddr_un.sun_len = SUN_LEN (&saddr_un); + + if (::connect (s, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0) + { + perror("error: connect (socket, &saddr_un, saddr_un_len)"); + exit(1); + } + + //::printf ("connect () sucess!!\n"); + + + // We were able to connect to the socket, now write our PID so whomever + // launched us will know this process's ID + RNBLogSTDOUT ("Listening to port %i...\n", port); + + char pid_str[64]; + const int pid_str_len = ::snprintf (pid_str, sizeof(pid_str), "%u", port); + const int bytes_sent = ::send (s, pid_str, pid_str_len, 0); + + if (pid_str_len != bytes_sent) + { + perror("error: send (s, pid_str, pid_str_len, 0)"); + exit (1); + } + + //::printf ("send () sucess!!\n"); + + // We are done with the socket + close (s); + } +} + static int -StartListening (RNBRemote *remote, int listen_port) +StartListening (RNBRemote *remote, int listen_port, const char *unix_socket_name) { if (!remote->Comm().IsConnected()) { - RNBLogSTDOUT ("Listening to port %i...\n", listen_port); - if (remote->Comm().Listen(listen_port) != rnb_success) + if (listen_port != 0) + RNBLogSTDOUT ("Listening to port %i...\n", listen_port); + if (remote->Comm().Listen(listen_port, PortWasBoundCallback, unix_socket_name) != rnb_success) { RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n"); return 0; @@ -709,6 +770,7 @@ static struct option g_long_options[] = { "disable-aslr", no_argument, NULL, 'D' }, // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization { "working-dir", required_argument, NULL, 'W' }, // The working directory that the inferior process should have (only if debugserver launches the process) { "platform", required_argument, NULL, 'p' }, // Put this executable into a remote platform mode + { "unix-socket", required_argument, NULL, 'u' }, // If we need to handshake with our parent process, an option will be passed down that specifies a unix socket name to use { NULL, 0, NULL, 0 } }; @@ -757,7 +819,8 @@ main (int argc, char *argv[]) std::string waitfor_pid_name; // Wait for a process that starts with this name std::string attach_pid_name; std::string arch_name; - std::string working_dir; // The new working directory to use for the inferior + std::string working_dir; // The new working directory to use for the inferior + std::string unix_socket_name; // If we need to handshake with our parent process, an option will be passed down that specifies a unix socket name to use useconds_t waitfor_interval = 1000; // Time in usecs between process lists polls when waiting for a process by name, default 1 msec. useconds_t waitfor_duration = 0; // Time in seconds to wait for a process by name, 0 means wait forever. bool no_stdio = false; @@ -768,7 +831,7 @@ main (int argc, char *argv[]) RNBRunLoopMode start_mode = eRNBRunLoopModeExit; - while ((ch = getopt_long(argc, argv, "a:A:d:gi:vktl:f:w:x:rs:n", g_long_options, &long_option_index)) != -1) + while ((ch = getopt_long(argc, argv, "a:A:d:gi:vktl:f:w:x:rs:nu:", g_long_options, &long_option_index)) != -1) { DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n", ch, (uint8_t)ch, @@ -967,6 +1030,11 @@ main (int argc, char *argv[]) case 'p': start_mode = eRNBRunLoopModePlatformMode; break; + + case 'u': + unix_socket_name.assign (optarg); + break; + } } @@ -1171,7 +1239,7 @@ main (int argc, char *argv[]) #endif if (listen_port != INT32_MAX) { - if (!StartListening (remote, listen_port)) + if (!StartListening (remote, listen_port, unix_socket_name.c_str())) mode = eRNBRunLoopModeExit; } else if (str[0] == '/') @@ -1282,7 +1350,7 @@ main (int argc, char *argv[]) { if (listen_port != INT32_MAX) { - if (!StartListening (remote, listen_port)) + if (!StartListening (remote, listen_port, unix_socket_name.c_str())) mode = eRNBRunLoopModeExit; } else if (str[0] == '/') @@ -1307,7 +1375,7 @@ main (int argc, char *argv[]) { if (listen_port != INT32_MAX) { - if (!StartListening (remote, listen_port)) + if (!StartListening (remote, listen_port, unix_socket_name.c_str())) mode = eRNBRunLoopModeExit; } else if (str[0] == '/') @@ -1334,7 +1402,7 @@ main (int argc, char *argv[]) case eRNBRunLoopModePlatformMode: if (listen_port != INT32_MAX) { - if (!StartListening (remote, listen_port)) + if (!StartListening (remote, listen_port, unix_socket_name.c_str())) mode = eRNBRunLoopModeExit; } else if (str[0] == '/') diff --git a/lldb/tools/lldb-platform/lldb-platform.cpp b/lldb/tools/lldb-platform/lldb-platform.cpp index be8359717fa..2dc54af2f7b 100644 --- a/lldb/tools/lldb-platform/lldb-platform.cpp +++ b/lldb/tools/lldb-platform/lldb-platform.cpp @@ -180,7 +180,7 @@ main (int argc, char *argv[]) argv += optind; - GDBRemoteCommunicationServer gdb_server; + GDBRemoteCommunicationServer gdb_server (true); if (!listen_host_post.empty()) { std::auto_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); |