diff options
Diffstat (limited to 'include/lldb/Target/Process.h')
-rw-r--r-- | include/lldb/Target/Process.h | 3786 |
1 files changed, 3786 insertions, 0 deletions
diff --git a/include/lldb/Target/Process.h b/include/lldb/Target/Process.h new file mode 100644 index 000000000000..ef89a1eb1418 --- /dev/null +++ b/include/lldb/Target/Process.h @@ -0,0 +1,3786 @@ +//===-- Process.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Process_h_ +#define liblldb_Process_h_ + +// C Includes +#include <limits.h> +#include <spawn.h> + +// C++ Includes +#include <list> +#include <iosfwd> +#include <vector> + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Broadcaster.h" +#include "lldb/Core/Communication.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Event.h" +#include "lldb/Core/RangeMap.h" +#include "lldb/Core/StringList.h" +#include "lldb/Core/ThreadSafeValue.h" +#include "lldb/Core/PluginInterface.h" +#include "lldb/Core/UserSettingsController.h" +#include "lldb/Breakpoint/BreakpointSiteList.h" +#include "lldb/Expression/ClangPersistentVariables.h" +#include "lldb/Expression/IRDynamicChecks.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/ProcessRunLock.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Interpreter/Options.h" +#include "lldb/Target/ExecutionContextScope.h" +#include "lldb/Target/Memory.h" +#include "lldb/Target/ThreadList.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/PseudoTerminal.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +// ProcessProperties +//---------------------------------------------------------------------- +class ProcessProperties : public Properties +{ +public: + ProcessProperties(bool is_global); + + virtual + ~ProcessProperties(); + + bool + GetDisableMemoryCache() const; + + Args + GetExtraStartupCommands () const; + + void + SetExtraStartupCommands (const Args &args); + + FileSpec + GetPythonOSPluginPath () const; + + void + SetPythonOSPluginPath (const FileSpec &file); + + bool + GetIgnoreBreakpointsInExpressions () const; + + void + SetIgnoreBreakpointsInExpressions (bool ignore); + + bool + GetUnwindOnErrorInExpressions () const; + + void + SetUnwindOnErrorInExpressions (bool ignore); + + bool + GetStopOnSharedLibraryEvents () const; + + void + SetStopOnSharedLibraryEvents (bool stop); + + bool + GetDetachKeepsStopped () const; + + void + SetDetachKeepsStopped (bool keep_stopped); +}; + +typedef std::shared_ptr<ProcessProperties> ProcessPropertiesSP; + +//---------------------------------------------------------------------- +// 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_arguments (), + m_environment (), + m_uid (UINT32_MAX), + m_gid (UINT32_MAX), + m_arch(), + m_pid (LLDB_INVALID_PROCESS_ID) + { + } + + ProcessInfo (const char *name, + const ArchSpec &arch, + lldb::pid_t pid) : + m_executable (name, false), + m_arguments (), + m_environment(), + m_uid (UINT32_MAX), + m_gid (UINT32_MAX), + m_arch (arch), + m_pid (pid) + { + } + + void + Clear () + { + m_executable.Clear(); + m_arguments.Clear(); + m_environment.Clear(); + m_uid = UINT32_MAX; + m_gid = UINT32_MAX; + m_arch.Clear(); + m_pid = LLDB_INVALID_PROCESS_ID; + } + + const char * + GetName() const + { + return m_executable.GetFilename().GetCString(); + } + + size_t + GetNameLength() const + { + return m_executable.GetFilename().GetLength(); + } + + FileSpec & + GetExecutableFile () + { + return m_executable; + } + + void + SetExecutableFile (const FileSpec &exe_file, bool add_exe_file_as_first_arg) + { + if (exe_file) + { + m_executable = exe_file; + if (add_exe_file_as_first_arg) + { + char filename[PATH_MAX]; + if (exe_file.GetPath(filename, sizeof(filename))) + m_arguments.InsertArgumentAtIndex (0, filename); + } + } + else + { + m_executable.Clear(); + } + } + + const FileSpec & + GetExecutableFile () const + { + return m_executable; + } + + uint32_t + GetUserID() const + { + return m_uid; + } + + uint32_t + GetGroupID() const + { + return m_gid; + } + + bool + UserIDIsValid () const + { + return m_uid != UINT32_MAX; + } + + bool + GroupIDIsValid () const + { + return m_gid != UINT32_MAX; + } + + void + SetUserID (uint32_t uid) + { + m_uid = uid; + } + + void + SetGroupID (uint32_t gid) + { + m_gid = gid; + } + + ArchSpec & + GetArchitecture () + { + return m_arch; + } + + const ArchSpec & + GetArchitecture () const + { + return m_arch; + } + + lldb::pid_t + GetProcessID () const + { + return m_pid; + } + + void + SetProcessID (lldb::pid_t pid) + { + m_pid = pid; + } + + bool + ProcessIDIsValid() const + { + 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; + } + + const char * + GetArg0 () const + { + if (m_arg0.empty()) + return NULL; + return m_arg0.c_str(); + } + + void + SetArg0 (const char *arg) + { + if (arg && arg[0]) + m_arg0 = arg; + else + m_arg0.clear(); + } + + void + SetArguments (const Args& args, bool first_arg_is_executable); + + void + SetArguments (char const **argv, bool first_arg_is_executable); + + Args & + GetEnvironmentEntries () + { + return m_environment; + } + + const Args & + GetEnvironmentEntries () const + { + return m_environment; + } + +protected: + FileSpec m_executable; + std::string m_arg0; // argv[0] if supported. If empty, then use m_executable. + // Not all process plug-ins support specifying an argv[0] + // that differs from the resolved platform executable + // (which is in m_executable) + Args m_arguments; // All program arguments except argv[0] + 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 + { + return m_parent_pid; + } + + void + SetParentProcessID (lldb::pid_t pid) + { + m_parent_pid = pid; + } + + bool + ParentProcessIDIsValid() const + { + return m_parent_pid != LLDB_INVALID_PROCESS_ID; + } + + void + Dump (Stream &s, Platform *platform) const; + + static void + 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: + enum Action + { + eFileActionNone, + eFileActionClose, + eFileActionDuplicate, + eFileActionOpen + }; + + + 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); + + int + GetFD () const + { + return m_fd; + } + + Action + GetAction () const + { + return m_action; + } + + int + GetActionArgument () const + { + return m_arg; + } + + const char * + GetPath () const + { + if (m_path.empty()) + return NULL; + return m_path.c_str(); + } + + protected: + 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_working_dir (), + m_plugin_name (), + m_shell (), + m_flags (0), + m_file_actions (), + m_pty (), + m_resume_count (0), + m_monitor_callback (NULL), + m_monitor_callback_baton (NULL), + m_monitor_signals (false) + { + } + + ProcessLaunchInfo (const char *stdin_path, + const char *stdout_path, + const char *stderr_path, + const char *working_directory, + uint32_t launch_flags) : + ProcessInfo(), + m_working_dir (), + m_plugin_name (), + m_shell (), + m_flags (launch_flags), + m_file_actions (), + m_pty (), + m_resume_count (0), + m_monitor_callback (NULL), + m_monitor_callback_baton (NULL), + m_monitor_signals (false) + { + if (stdin_path) + { + ProcessLaunchInfo::FileAction file_action; + const bool read = true; + const bool write = false; + if (file_action.Open(STDIN_FILENO, stdin_path, read, write)) + AppendFileAction (file_action); + } + if (stdout_path) + { + ProcessLaunchInfo::FileAction file_action; + const bool read = false; + const bool write = true; + if (file_action.Open(STDOUT_FILENO, stdout_path, read, write)) + AppendFileAction (file_action); + } + if (stderr_path) + { + ProcessLaunchInfo::FileAction file_action; + const bool read = false; + const bool write = true; + if (file_action.Open(STDERR_FILENO, stderr_path, read, write)) + AppendFileAction (file_action); + } + if (working_directory) + SetWorkingDirectory(working_directory); + } + + void + AppendFileAction (const FileAction &info) + { + m_file_actions.push_back(info); + } + + bool + AppendCloseFileAction (int fd) + { + FileAction file_action; + if (file_action.Close (fd)) + { + AppendFileAction (file_action); + return true; + } + return false; + } + + bool + AppendDuplicateFileAction (int fd, int dup_fd) + { + FileAction file_action; + if (file_action.Duplicate (fd, dup_fd)) + { + AppendFileAction (file_action); + return true; + } + return false; + } + + bool + AppendOpenFileAction (int fd, const char *path, bool read, bool write) + { + FileAction file_action; + if (file_action.Open (fd, path, read, write)) + { + AppendFileAction (file_action); + return true; + } + return false; + } + + bool + AppendSuppressFileAction (int fd, bool read, bool write) + { + FileAction file_action; + if (file_action.Open (fd, "/dev/null", read, write)) + { + AppendFileAction (file_action); + return true; + } + return false; + } + + void + FinalizeFileActions (Target *target, + bool default_to_use_pty); + + 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; + } + + const FileAction * + GetFileActionForFD (int fd) const + { + for (size_t idx=0, count=m_file_actions.size(); idx < count; ++idx) + { + if (m_file_actions[idx].GetFD () == fd) + 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 + SetWorkingDirectory (const char *working_dir) + { + if (working_dir && working_dir[0]) + m_working_dir.assign (working_dir); + else + m_working_dir.clear(); + } + + void + SwapWorkingDirectory (std::string &working_dir) + { + 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 char * + GetShell () const + { + if (m_shell.empty()) + return NULL; + return m_shell.c_str(); + } + + void + SetShell (const char * path) + { + if (path && path[0]) + { + m_shell.assign (path); + m_flags.Set (lldb::eLaunchFlagLaunchInShell); + } + else + { + m_shell.clear(); + m_flags.Clear (lldb::eLaunchFlagLaunchInShell); + } + } + + uint32_t + GetResumeCount () const + { + return m_resume_count; + } + + void + SetResumeCount (uint32_t c) + { + m_resume_count = c; + } + + bool + GetLaunchInSeparateProcessGroup () + { + return m_flags.Test(lldb::eLaunchFlagLaunchInSeparateProcessGroup); + } + + void + SetLaunchInSeparateProcessGroup (bool separate) + { + if (separate) + m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup); + else + m_flags.Clear (lldb::eLaunchFlagLaunchInSeparateProcessGroup); + + } + + void + Clear () + { + ProcessInfo::Clear(); + m_working_dir.clear(); + m_plugin_name.clear(); + m_shell.clear(); + m_flags.Clear(); + m_file_actions.clear(); + m_resume_count = 0; + } + + bool + ConvertArgumentsForLaunchingInShell (Error &error, + bool localhost, + bool will_debug, + bool first_arg_is_full_shell_command); + + void + SetMonitorProcessCallback (Host::MonitorChildProcessCallback callback, + void *baton, + bool monitor_signals) + { + m_monitor_callback = callback; + m_monitor_callback_baton = baton; + m_monitor_signals = monitor_signals; + } + + bool + MonitorProcess () const + { + if (m_monitor_callback && ProcessIDIsValid()) + { + Host::StartMonitoringChildProcess (m_monitor_callback, + m_monitor_callback_baton, + GetProcessID(), + m_monitor_signals); + return true; + } + return false; + } + + lldb_utility::PseudoTerminal & + GetPTY () + { + return m_pty; + } + +protected: + std::string m_working_dir; + std::string m_plugin_name; + std::string m_shell; + Flags m_flags; // Bitwise OR of bits from lldb::LaunchFlags + std::vector<FileAction> m_file_actions; // File actions for any other files + lldb_utility::PseudoTerminal m_pty; + uint32_t m_resume_count; // How many times do we resume after launching + Host::MonitorChildProcessCallback m_monitor_callback; + void *m_monitor_callback_baton; + bool m_monitor_signals; + +}; + +//---------------------------------------------------------------------- +// ProcessLaunchInfo +// +// Describes any information that is required to launch a process. +//---------------------------------------------------------------------- + +class ProcessAttachInfo : public ProcessInstanceInfo +{ +public: + ProcessAttachInfo() : + ProcessInstanceInfo(), + m_plugin_name (), + m_resume_count (0), + m_wait_for_launch (false), + m_ignore_existing (true), + m_continue_once_attached (false) + { + } + + ProcessAttachInfo (const ProcessLaunchInfo &launch_info) : + ProcessInstanceInfo(), + m_plugin_name (), + m_resume_count (0), + m_wait_for_launch (false), + m_ignore_existing (true), + m_continue_once_attached (false) + { + ProcessInfo::operator= (launch_info); + SetProcessPluginName (launch_info.GetProcessPluginName()); + SetResumeCount (launch_info.GetResumeCount()); + } + + bool + GetWaitForLaunch () const + { + return m_wait_for_launch; + } + + void + SetWaitForLaunch (bool b) + { + m_wait_for_launch = b; + } + + bool + GetIgnoreExisting () const + { + return m_ignore_existing; + } + + void + SetIgnoreExisting (bool b) + { + m_ignore_existing = b; + } + + bool + GetContinueOnceAttached () const + { + return m_continue_once_attached; + } + + void + SetContinueOnceAttached (bool b) + { + m_continue_once_attached = b; + } + + uint32_t + GetResumeCount () const + { + return m_resume_count; + } + + void + SetResumeCount (uint32_t c) + { + m_resume_count = c; + } + + 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(); + } + + void + Clear () + { + ProcessInstanceInfo::Clear(); + m_plugin_name.clear(); + m_resume_count = 0; + m_wait_for_launch = false; + m_ignore_existing = true; + m_continue_once_attached = false; + } + + bool + ProcessInfoSpecified () const + { + if (GetExecutableFile()) + return true; + if (GetProcessID() != LLDB_INVALID_PROCESS_ID) + return true; + if (GetParentProcessID() != LLDB_INVALID_PROCESS_ID) + return true; + return false; + } +protected: + std::string m_plugin_name; + uint32_t m_resume_count; // How many times do we resume after launching + bool m_wait_for_launch; + bool m_ignore_existing; + bool m_continue_once_attached; // Supports the use-case scenario of immediately continuing the process once attached. +}; + +class ProcessLaunchCommandOptions : public Options +{ +public: + + ProcessLaunchCommandOptions (CommandInterpreter &interpreter) : + Options(interpreter) + { + // Keep default values of all options in one place: OptionParsingStarting () + OptionParsingStarting (); + } + + ~ProcessLaunchCommandOptions () + { + } + + Error + SetOptionValue (uint32_t option_idx, const char *option_arg); + + void + OptionParsingStarting () + { + 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 (eNameMatchIgnore), + m_match_all_users (false) + { + } + + ProcessInstanceInfoMatch (const char *process_name, + NameMatchType process_name_match_type) : + m_match_info (), + m_name_match_type (process_name_match_type), + m_match_all_users (false) + { + m_match_info.GetExecutableFile().SetFile(process_name, false); + } + + ProcessInstanceInfo & + GetProcessInfo () + { + return m_match_info; + } + + const ProcessInstanceInfo & + GetProcessInfo () const + { + return m_match_info; + } + + bool + GetMatchAllUsers () const + { + return m_match_all_users; + } + + void + SetMatchAllUsers (bool b) + { + m_match_all_users = b; + } + + NameMatchType + GetNameMatchType () const + { + return m_name_match_type; + } + + void + SetNameMatchType (NameMatchType name_match_type) + { + m_name_match_type = name_match_type; + } + + bool + NameMatches (const char *process_name) const; + + bool + Matches (const ProcessInstanceInfo &proc_info) const; + + bool + MatchAllProcesses () const; + void + Clear (); + +protected: + ProcessInstanceInfo m_match_info; + NameMatchType m_name_match_type; + bool m_match_all_users; +}; + +class ProcessInstanceInfoList +{ +public: + ProcessInstanceInfoList () : + m_infos() + { + } + + void + Clear() + { + m_infos.clear(); + } + + size_t + GetSize() + { + return m_infos.size(); + } + + void + Append (const ProcessInstanceInfo &info) + { + m_infos.push_back (info); + } + + const char * + GetProcessNameAtIndex (size_t idx) + { + if (idx < m_infos.size()) + return m_infos[idx].GetName(); + return NULL; + } + + size_t + GetProcessNameLengthAtIndex (size_t idx) + { + if (idx < m_infos.size()) + return m_infos[idx].GetNameLength(); + return 0; + } + + lldb::pid_t + GetProcessIDAtIndex (size_t idx) + { + if (idx < m_infos.size()) + return m_infos[idx].GetProcessID(); + return 0; + } + + bool + GetInfoAtIndex (size_t idx, ProcessInstanceInfo &info) + { + if (idx < m_infos.size()) + { + info = m_infos[idx]; + return true; + } + return false; + } + + // You must ensure "idx" is valid before calling this function + const ProcessInstanceInfo & + GetProcessInfoAtIndex (size_t idx) const + { + assert (idx < m_infos.size()); + return m_infos[idx]; + } + +protected: + typedef std::vector<ProcessInstanceInfo> collection; + collection m_infos; +}; + + +// This class tracks the Modification state of the process. Things that can currently modify +// the program are running the program (which will up the StopID) and writing memory (which +// will up the MemoryID.) +// FIXME: Should we also include modification of register states? + +class ProcessModID +{ +friend bool operator== (const ProcessModID &lhs, const ProcessModID &rhs); +public: + ProcessModID () : + m_stop_id (0), + m_last_natural_stop_id(0), + m_resume_id (0), + m_memory_id (0), + m_last_user_expression_resume (0), + m_running_user_expression (false) + {} + + ProcessModID (const ProcessModID &rhs) : + m_stop_id (rhs.m_stop_id), + m_memory_id (rhs.m_memory_id) + {} + + const ProcessModID & operator= (const ProcessModID &rhs) + { + if (this != &rhs) + { + m_stop_id = rhs.m_stop_id; + m_memory_id = rhs.m_memory_id; + } + return *this; + } + + ~ProcessModID () {} + + void BumpStopID () { + m_stop_id++; + if (!IsLastResumeForUserExpression()) + m_last_natural_stop_id++; + } + + void BumpMemoryID () { m_memory_id++; } + + void BumpResumeID () { + m_resume_id++; + if (m_running_user_expression > 0) + m_last_user_expression_resume = m_resume_id; + } + + uint32_t GetStopID() const { return m_stop_id; } + uint32_t GetLastNaturalStopID() const { return m_last_natural_stop_id; } + uint32_t GetMemoryID () const { return m_memory_id; } + uint32_t GetResumeID () const { return m_resume_id; } + uint32_t GetLastUserExpressionResumeID () const { return m_last_user_expression_resume; } + + bool MemoryIDEqual (const ProcessModID &compare) const + { + return m_memory_id == compare.m_memory_id; + } + + bool StopIDEqual (const ProcessModID &compare) const + { + return m_stop_id == compare.m_stop_id; + } + + void SetInvalid () + { + m_stop_id = UINT32_MAX; + } + + bool IsValid () const + { + return m_stop_id != UINT32_MAX; + } + + bool + IsLastResumeForUserExpression () const + { + return m_resume_id == m_last_user_expression_resume; + } + + void + SetRunningUserExpression (bool on) + { + // REMOVEME printf ("Setting running user expression %s at resume id %d - value: %d.\n", on ? "on" : "off", m_resume_id, m_running_user_expression); + if (on) + m_running_user_expression++; + else + m_running_user_expression--; + } + +private: + uint32_t m_stop_id; + uint32_t m_last_natural_stop_id; + uint32_t m_resume_id; + uint32_t m_memory_id; + uint32_t m_last_user_expression_resume; + uint32_t m_running_user_expression; +}; +inline bool operator== (const ProcessModID &lhs, const ProcessModID &rhs) +{ + if (lhs.StopIDEqual (rhs) + && lhs.MemoryIDEqual (rhs)) + return true; + else + return false; +} + +inline bool operator!= (const ProcessModID &lhs, const ProcessModID &rhs) +{ + if (!lhs.StopIDEqual (rhs) + || !lhs.MemoryIDEqual (rhs)) + return true; + else + return false; +} + +class MemoryRegionInfo +{ +public: + typedef Range<lldb::addr_t, lldb::addr_t> RangeType; + + enum OptionalBool { + eDontKnow = -1, + eNo = 0, + eYes = 1 + }; + + MemoryRegionInfo () : + m_range (), + m_read (eDontKnow), + m_write (eDontKnow), + m_execute (eDontKnow) + { + } + + ~MemoryRegionInfo () + { + } + + RangeType & + GetRange() + { + return m_range; + } + + void + Clear() + { + m_range.Clear(); + m_read = m_write = m_execute = eDontKnow; + } + + const RangeType & + GetRange() const + { + return m_range; + } + + OptionalBool + GetReadable () const + { + return m_read; + } + + OptionalBool + GetWritable () const + { + return m_write; + } + + OptionalBool + GetExecutable () const + { + return m_execute; + } + + void + SetReadable (OptionalBool val) + { + m_read = val; + } + + void + SetWritable (OptionalBool val) + { + m_write = val; + } + + void + SetExecutable (OptionalBool val) + { + m_execute = val; + } + +protected: + RangeType m_range; + OptionalBool m_read; + OptionalBool m_write; + OptionalBool m_execute; +}; + +//---------------------------------------------------------------------- +/// @class Process Process.h "lldb/Target/Process.h" +/// @brief A plug-in interface definition class for debugging a process. +//---------------------------------------------------------------------- +class Process : + public std::enable_shared_from_this<Process>, + public ProcessProperties, + public UserID, + public Broadcaster, + public ExecutionContextScope, + public PluginInterface +{ +friend class ThreadList; +friend class ClangFunction; // For WaitForStateChangeEventsPrivate +friend class CommandObjectProcessLaunch; +friend class ProcessEventData; +friend class CommandObjectBreakpointCommand; +friend class StopInfo; + +public: + + //------------------------------------------------------------------ + /// Broadcaster event bits definitions. + //------------------------------------------------------------------ + enum + { + eBroadcastBitStateChanged = (1 << 0), + eBroadcastBitInterrupt = (1 << 1), + eBroadcastBitSTDOUT = (1 << 2), + eBroadcastBitSTDERR = (1 << 3), + eBroadcastBitProfileData = (1 << 4) + }; + + enum + { + eBroadcastInternalStateControlStop = (1<<0), + eBroadcastInternalStateControlPause = (1<<1), + eBroadcastInternalStateControlResume = (1<<2) + }; + + typedef Range<lldb::addr_t, lldb::addr_t> LoadRange; + // We use a read/write lock to allow on or more clients to + // access the process state while the process is stopped (reader). + // We lock the write lock to control access to the process + // while it is running (readers, or clients that want the process + // stopped can block waiting for the process to stop, or just + // try to lock it to see if they can immediately access the stopped + // process. If the try read lock fails, then the process is running. + typedef ProcessRunLock::ProcessRunLocker StopLocker; + + // These two functions fill out the Broadcaster interface: + + static ConstString &GetStaticBroadcasterClass (); + + virtual ConstString &GetBroadcasterClass() const + { + return GetStaticBroadcasterClass(); + } + + + //------------------------------------------------------------------ + /// A notification structure that can be used by clients to listen + /// for changes in a process's lifetime. + /// + /// @see RegisterNotificationCallbacks (const Notifications&) + /// @see UnregisterNotificationCallbacks (const Notifications&) + //------------------------------------------------------------------ +#ifndef SWIG + typedef struct + { + void *baton; + void (*initialize)(void *baton, Process *process); + void (*process_state_changed) (void *baton, Process *process, lldb::StateType state); + } Notifications; + + class ProcessEventData : + public EventData + { + friend class Process; + + public: + ProcessEventData (); + ProcessEventData (const lldb::ProcessSP &process, lldb::StateType state); + + virtual ~ProcessEventData(); + + static const ConstString & + GetFlavorString (); + + virtual const ConstString & + GetFlavor () const; + + const lldb::ProcessSP & + GetProcessSP() const + { + return m_process_sp; + } + lldb::StateType + GetState() const + { + return m_state; + } + bool + GetRestarted () const + { + return m_restarted; + } + + size_t + GetNumRestartedReasons () + { + return m_restarted_reasons.size(); + } + + const char * + GetRestartedReasonAtIndex(size_t idx) + { + if (idx > m_restarted_reasons.size()) + return NULL; + else + return m_restarted_reasons[idx].c_str(); + } + + bool + GetInterrupted () const + { + return m_interrupted; + } + + virtual void + Dump (Stream *s) const; + + virtual void + DoOnRemoval (Event *event_ptr); + + static const Process::ProcessEventData * + GetEventDataFromEvent (const Event *event_ptr); + + static lldb::ProcessSP + GetProcessFromEvent (const Event *event_ptr); + + static lldb::StateType + GetStateFromEvent (const Event *event_ptr); + + static bool + GetRestartedFromEvent (const Event *event_ptr); + + static size_t + GetNumRestartedReasons(const Event *event_ptr); + + static const char * + GetRestartedReasonAtIndex(const Event *event_ptr, size_t idx); + + static void + AddRestartedReason (Event *event_ptr, const char *reason); + + static void + SetRestartedInEvent (Event *event_ptr, bool new_value); + + static bool + GetInterruptedFromEvent (const Event *event_ptr); + + static void + SetInterruptedInEvent (Event *event_ptr, bool new_value); + + static bool + SetUpdateStateOnRemoval (Event *event_ptr); + + private: + + void + SetUpdateStateOnRemoval() + { + m_update_state++; + } + void + SetRestarted (bool new_value) + { + m_restarted = new_value; + } + void + SetInterrupted (bool new_value) + { + m_interrupted = new_value; + } + void + AddRestartedReason (const char *reason) + { + m_restarted_reasons.push_back(reason); + } + + lldb::ProcessSP m_process_sp; + lldb::StateType m_state; + std::vector<std::string> m_restarted_reasons; + bool m_restarted; // For "eStateStopped" events, this is true if the target was automatically restarted. + int m_update_state; + bool m_interrupted; + DISALLOW_COPY_AND_ASSIGN (ProcessEventData); + + }; + +#endif + + static void + SettingsInitialize (); + + static void + SettingsTerminate (); + + static const ProcessPropertiesSP & + GetGlobalProperties(); + + //------------------------------------------------------------------ + /// Construct with a shared pointer to a target, and the Process listener. + //------------------------------------------------------------------ + Process(Target &target, Listener &listener); + + //------------------------------------------------------------------ + /// Destructor. + /// + /// The destructor is virtual since this class is designed to be + /// inherited from by the plug-in instance. + //------------------------------------------------------------------ + virtual + ~Process(); + + //------------------------------------------------------------------ + /// Find a Process plug-in that can debug \a module using the + /// currently selected architecture. + /// + /// Scans all loaded plug-in interfaces that implement versions of + /// the Process plug-in interface and returns the first instance + /// that can debug the file. + /// + /// @param[in] module_sp + /// The module shared pointer that this process will debug. + /// + /// @param[in] plugin_name + /// If NULL, select the best plug-in for the binary. If non-NULL + /// then look for a plugin whose PluginInfo's name matches + /// this string. + /// + /// @see Process::CanDebug () + //------------------------------------------------------------------ + static lldb::ProcessSP + FindPlugin (Target &target, + const char *plugin_name, + Listener &listener, + const FileSpec *crash_file_path); + + + + //------------------------------------------------------------------ + /// Static function that can be used with the \b host function + /// Host::StartMonitoringChildProcess (). + /// + /// This function can be used by lldb_private::Process subclasses + /// when they want to watch for a local process and have its exit + /// status automatically set when the host child process exits. + /// Subclasses should call Host::StartMonitoringChildProcess () + /// with: + /// callback = Process::SetHostProcessExitStatus + /// callback_baton = NULL + /// pid = Process::GetID() + /// monitor_signals = false + //------------------------------------------------------------------ + static bool + SetProcessExitStatus (void *callback_baton, // The callback baton which should be set to NULL + lldb::pid_t pid, // The process ID we want to monitor + bool exited, + int signo, // Zero for no signal + int status); // Exit value of process if signal is zero + + lldb::ByteOrder + GetByteOrder () const; + + uint32_t + GetAddressByteSize () const; + + uint32_t + GetUniqueID() const + { + return m_process_unique_id; + } + //------------------------------------------------------------------ + /// Check if a plug-in instance can debug the file in \a module. + /// + /// Each plug-in is given a chance to say whether it can debug + /// the file in \a module. If the Process plug-in instance can + /// debug a file on the current system, it should return \b true. + /// + /// @return + /// Returns \b true if this Process plug-in instance can + /// debug the executable, \b false otherwise. + //------------------------------------------------------------------ + virtual bool + CanDebug (Target &target, + bool plugin_specified_by_name) = 0; + + + //------------------------------------------------------------------ + /// This object is about to be destroyed, do any necessary cleanup. + /// + /// Subclasses that override this method should always call this + /// superclass method. + //------------------------------------------------------------------ + virtual void + Finalize(); + + + //------------------------------------------------------------------ + /// Return whether this object is valid (i.e. has not been finalized.) + /// + /// @return + /// Returns \b true if this Process has not been finalized + /// and \b false otherwise. + //------------------------------------------------------------------ + bool + IsValid() const + { + return !m_finalize_called; + } + + //------------------------------------------------------------------ + /// Return a multi-word command object that can be used to expose + /// plug-in specific commands. + /// + /// This object will be used to resolve plug-in commands and can be + /// triggered by a call to: + /// + /// (lldb) process commmand <args> + /// + /// @return + /// A CommandObject which can be one of the concrete subclasses + /// of CommandObject like CommandObjectRaw, CommandObjectParsed, + /// or CommandObjectMultiword. + //------------------------------------------------------------------ + virtual CommandObject * + GetPluginCommandObject() + { + return NULL; + } + + //------------------------------------------------------------------ + /// 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. + //------------------------------------------------------------------ + virtual Error + Launch (const ProcessLaunchInfo &launch_info); + + virtual Error + LoadCore (); + + virtual Error + DoLoadCore () + { + Error error; + error.SetErrorStringWithFormat("error: %s does not support loading core files.", GetPluginName().GetCString()); + return error; + } + + //------------------------------------------------------------------ + /// Get the dynamic loader plug-in for this process. + /// + /// The default action is to let the DynamicLoader plug-ins check + /// the main executable and the DynamicLoader will select itself + /// automatically. Subclasses can override this if inspecting the + /// executable is not desired, or if Process subclasses can only + /// use a specific DynamicLoader plug-in. + //------------------------------------------------------------------ + virtual DynamicLoader * + GetDynamicLoader (); + + //------------------------------------------------------------------ + /// Attach to an existing process using the process attach info. + /// + /// This function is not meant to be overridden by Process + /// subclasses. It will first call WillAttach (lldb::pid_t) + /// or WillAttach (const char *), and if that returns \b + /// true, DoAttach (lldb::pid_t) or DoAttach (const char *) will + /// be called to actually do the attach. If DoAttach returns \b + /// true, then Process::DidAttach() will be called. + /// + /// @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. + //------------------------------------------------------------------ + virtual Error + Attach (ProcessAttachInfo &attach_info); + + //------------------------------------------------------------------ + /// Attach to a remote system via a URL + /// + /// @param[in] strm + /// A stream where output intended for the user + /// (if the driver has a way to display that) generated during + /// the connection. This may be NULL if no output is needed.A + /// + /// @param[in] remote_url + /// The URL format that we are connecting to. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error + ConnectRemote (Stream *strm, const char *remote_url); + + bool + GetShouldDetach () const + { + return m_should_detach; + } + + void + SetShouldDetach (bool b) + { + m_should_detach = b; + } + + //------------------------------------------------------------------ + /// Get the image information address for the current process. + /// + /// Some runtimes have system functions that can help dynamic + /// loaders locate the dynamic loader information needed to observe + /// shared libraries being loaded or unloaded. This function is + /// in the Process interface (as opposed to the DynamicLoader + /// interface) to ensure that remote debugging can take advantage of + /// this functionality. + /// + /// @return + /// The address of the dynamic loader information, or + /// LLDB_INVALID_ADDRESS if this is not supported by this + /// interface. + //------------------------------------------------------------------ + virtual lldb::addr_t + GetImageInfoAddress (); + + //------------------------------------------------------------------ + /// Load a shared library into this process. + /// + /// Try and load a shared library into the current process. This + /// call might fail in the dynamic loader plug-in says it isn't safe + /// to try and load shared libraries at the moment. + /// + /// @param[in] image_spec + /// The image file spec that points to the shared library that + /// you want to load. + /// + /// @param[out] error + /// An error object that gets filled in with any errors that + /// might occur when trying to load the shared library. + /// + /// @return + /// A token that represents the shared library that can be + /// later used to unload the shared library. A value of + /// LLDB_INVALID_IMAGE_TOKEN will be returned if the shared + /// library can't be opened. + //------------------------------------------------------------------ + virtual uint32_t + LoadImage (const FileSpec &image_spec, Error &error); + + virtual Error + UnloadImage (uint32_t image_token); + + //------------------------------------------------------------------ + /// Register for process and thread notifications. + /// + /// Clients can register nofication callbacks by filling out a + /// Process::Notifications structure and calling this function. + /// + /// @param[in] callbacks + /// A structure that contains the notification baton and + /// callback functions. + /// + /// @see Process::Notifications + //------------------------------------------------------------------ +#ifndef SWIG + void + RegisterNotificationCallbacks (const Process::Notifications& callbacks); +#endif + //------------------------------------------------------------------ + /// Unregister for process and thread notifications. + /// + /// Clients can unregister nofication callbacks by passing a copy of + /// the original baton and callbacks in \a callbacks. + /// + /// @param[in] callbacks + /// A structure that contains the notification baton and + /// callback functions. + /// + /// @return + /// Returns \b true if the notification callbacks were + /// successfully removed from the process, \b false otherwise. + /// + /// @see Process::Notifications + //------------------------------------------------------------------ +#ifndef SWIG + bool + UnregisterNotificationCallbacks (const Process::Notifications& callbacks); +#endif + //================================================================== + // Built in Process Control functions + //================================================================== + //------------------------------------------------------------------ + /// Resumes all of a process's threads as configured using the + /// Thread run control functions. + /// + /// Threads for a process should be updated with one of the run + /// control actions (resume, step, or suspend) that they should take + /// when the process is resumed. If no run control action is given + /// to a thread it will be resumed by default. + /// + /// This function is not meant to be overridden by Process + /// subclasses. This function will take care of disabling any + /// breakpoints that threads may be stopped at, single stepping, and + /// re-enabling breakpoints, and enabling the basic flow control + /// that the plug-in instances need not worry about. + /// + /// N.B. This function also sets the Write side of the Run Lock, + /// which is unset when the corresponding stop event is pulled off + /// the Public Event Queue. If you need to resume the process without + /// setting the Run Lock, use PrivateResume (though you should only do + /// that from inside the Process class. + /// + /// @return + /// Returns an error object. + /// + /// @see Thread:Resume() + /// @see Thread:Step() + /// @see Thread:Suspend() + //------------------------------------------------------------------ + Error + Resume(); + + //------------------------------------------------------------------ + /// Halts a running process. + /// + /// This function is not meant to be overridden by Process + /// subclasses. + /// If the process is successfully halted, a eStateStopped + /// process event with GetInterrupted will be broadcast. If false, we will + /// halt the process with no events generated by the halt. + /// + /// @param[in] clear_thread_plans + /// If true, when the process stops, clear all thread plans. + /// + /// @return + /// Returns an error object. If the error is empty, the process is halted. + /// otherwise the halt has failed. + //------------------------------------------------------------------ + Error + Halt (bool clear_thread_plans = false); + + //------------------------------------------------------------------ + /// Detaches from a running or stopped process. + /// + /// This function is not meant to be overridden by Process + /// subclasses. + /// + /// @param[in] keep_stopped + /// If true, don't resume the process on detach. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + Error + Detach (bool keep_stopped); + + //------------------------------------------------------------------ + /// Kills the process and shuts down all threads that were spawned + /// to track and monitor the process. + /// + /// This function is not meant to be overridden by Process + /// subclasses. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + Error + Destroy(); + + //------------------------------------------------------------------ + /// Sends a process a UNIX signal \a signal. + /// + /// This function is not meant to be overridden by Process + /// subclasses. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + Error + Signal (int signal); + + virtual UnixSignals & + GetUnixSignals () + { + return m_unix_signals; + } + + //================================================================== + // Plug-in Process Control Overrides + //================================================================== + + //------------------------------------------------------------------ + /// Called before attaching to a process. + /// + /// Allow Process plug-ins to execute some code before attaching a + /// process. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error + WillAttachToProcessWithID (lldb::pid_t pid) + { + return Error(); + } + + //------------------------------------------------------------------ + /// Called before attaching to a process. + /// + /// Allow Process plug-ins to execute some code before attaching a + /// process. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error + WillAttachToProcessWithName (const char *process_name, bool wait_for_launch) + { + return Error(); + } + + //------------------------------------------------------------------ + /// Attach to a remote system via a URL + /// + /// @param[in] strm + /// A stream where output intended for the user + /// (if the driver has a way to display that) generated during + /// the connection. This may be NULL if no output is needed.A + /// + /// @param[in] remote_url + /// The URL format that we are connecting to. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error + DoConnectRemote (Stream *strm, const char *remote_url) + { + Error error; + error.SetErrorString ("remote connections are not supported"); + return error; + } + + //------------------------------------------------------------------ + /// Attach to an existing process using a process ID. + /// + /// @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. + //------------------------------------------------------------------ + virtual Error + DoAttachToProcessWithID (lldb::pid_t pid) + { + Error error; + error.SetErrorStringWithFormat("error: %s does not support attaching to a process by pid", GetPluginName().GetCString()); + return error; + } + + //------------------------------------------------------------------ + /// Attach to an existing process using a process ID. + /// + /// @param[in] pid + /// The process ID that we should attempt to attach to. + /// + /// @param[in] attach_info + /// Information on how to do the attach. For example, GetUserID() + /// will return the uid to attach as. + /// + /// @return + /// Returns \a pid if attaching was successful, or + /// LLDB_INVALID_PROCESS_ID if attaching fails. + /// hanming : need flag + //------------------------------------------------------------------ + virtual Error + DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info) + { + Error error; + error.SetErrorStringWithFormat("error: %s does not support attaching to a process by pid", GetPluginName().GetCString()); + return error; + } + + //------------------------------------------------------------------ + /// Attach to an existing process using a partial process name. + /// + /// @param[in] process_name + /// The name of the process to attach to. + /// + /// @param[in] wait_for_launch + /// If \b true, wait for the process to be launched and attach + /// as soon as possible after it does launch. If \b false, then + /// search for a matching process the currently exists. + /// + /// @param[in] attach_info + /// Information on how to do the attach. For example, GetUserID() + /// will return the uid to attach as. + /// + /// @return + /// Returns \a pid if attaching was successful, or + /// LLDB_INVALID_PROCESS_ID if attaching fails. + //------------------------------------------------------------------ + virtual Error + DoAttachToProcessWithName (const char *process_name, bool wait_for_launch, const ProcessAttachInfo &attach_info) + { + Error error; + error.SetErrorString("attach by name is not supported"); + return error; + } + + //------------------------------------------------------------------ + /// Called after attaching a process. + /// + /// Allow Process plug-ins to execute some code after attaching to + /// a process. + //------------------------------------------------------------------ + virtual void + DidAttach () {} + + + //------------------------------------------------------------------ + /// Called after a process re-execs itself. + /// + /// Allow Process plug-ins to execute some code after a process has + /// exec'ed itself. Subclasses typically should override DoDidExec() + /// as the lldb_private::Process class needs to remove its dynamic + /// loader, runtime, ABI and other plug-ins, as well as unload all + /// shared libraries. + //------------------------------------------------------------------ + virtual void + DidExec (); + + //------------------------------------------------------------------ + /// Subclasses of Process should implement this function if they + /// need to do anything after a process exec's itself. + //------------------------------------------------------------------ + virtual void + DoDidExec () + { + } + + //------------------------------------------------------------------ + /// Called before launching to a process. + /// + /// Allow Process plug-ins to execute some code before launching a + /// process. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error + WillLaunch (Module* module) + { + return Error(); + } + + //------------------------------------------------------------------ + /// Launch a new process. + /// + /// Launch a new process by spawning a new process using \a 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. + /// + /// @param[in] module + /// The module from which to extract the file specification and + /// launch. + /// + /// @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 + /// A new valid process ID, or LLDB_INVALID_PROCESS_ID if + /// launching fails. + //------------------------------------------------------------------ + virtual Error + DoLaunch (Module *exe_module, + const ProcessLaunchInfo &launch_info) + { + Error error; + error.SetErrorStringWithFormat("error: %s does not support launching processes", GetPluginName().GetCString()); + return error; + } + + + //------------------------------------------------------------------ + /// Called after launching a process. + /// + /// Allow Process plug-ins to execute some code after launching + /// a process. + //------------------------------------------------------------------ + virtual void + DidLaunch () {} + + + + //------------------------------------------------------------------ + /// Called before resuming to a process. + /// + /// Allow Process plug-ins to execute some code before resuming a + /// process. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error + WillResume () { return Error(); } + + //------------------------------------------------------------------ + /// Resumes all of a process's threads as configured using the + /// Thread run control functions. + /// + /// Threads for a process should be updated with one of the run + /// control actions (resume, step, or suspend) that they should take + /// when the process is resumed. If no run control action is given + /// to a thread it will be resumed by default. + /// + /// @return + /// Returns \b true if the process successfully resumes using + /// the thread run control actions, \b false otherwise. + /// + /// @see Thread:Resume() + /// @see Thread:Step() + /// @see Thread:Suspend() + //------------------------------------------------------------------ + virtual Error + DoResume () + { + Error error; + error.SetErrorStringWithFormat("error: %s does not support resuming processes", GetPluginName().GetCString()); + return error; + } + + + //------------------------------------------------------------------ + /// Called after resuming a process. + /// + /// Allow Process plug-ins to execute some code after resuming + /// a process. + //------------------------------------------------------------------ + virtual void + DidResume () {} + + + //------------------------------------------------------------------ + /// Called before halting to a process. + /// + /// Allow Process plug-ins to execute some code before halting a + /// process. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error + WillHalt () { return Error(); } + + //------------------------------------------------------------------ + /// Halts a running process. + /// + /// DoHalt must produce one and only one stop StateChanged event if it actually + /// stops the process. If the stop happens through some natural event (for + /// instance a SIGSTOP), then forwarding that event will do. Otherwise, you must + /// generate the event manually. Note also, the private event thread is stopped when + /// DoHalt is run to prevent the events generated while halting to trigger + /// other state changes before the halt is complete. + /// + /// @param[out] caused_stop + /// If true, then this Halt caused the stop, otherwise, the + /// process was already stopped. + /// + /// @return + /// Returns \b true if the process successfully halts, \b false + /// otherwise. + //------------------------------------------------------------------ + virtual Error + DoHalt (bool &caused_stop) + { + Error error; + error.SetErrorStringWithFormat("error: %s does not support halting processes", GetPluginName().GetCString()); + return error; + } + + + //------------------------------------------------------------------ + /// Called after halting a process. + /// + /// Allow Process plug-ins to execute some code after halting + /// a process. + //------------------------------------------------------------------ + virtual void + DidHalt () {} + + //------------------------------------------------------------------ + /// Called before detaching from a process. + /// + /// Allow Process plug-ins to execute some code before detaching + /// from a process. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error + WillDetach () + { + return Error(); + } + + //------------------------------------------------------------------ + /// Detaches from a running or stopped process. + /// + /// @return + /// Returns \b true if the process successfully detaches, \b + /// false otherwise. + //------------------------------------------------------------------ + virtual Error + DoDetach (bool keep_stopped) + { + Error error; + error.SetErrorStringWithFormat("error: %s does not support detaching from processes", GetPluginName().GetCString()); + return error; + } + + + //------------------------------------------------------------------ + /// Called after detaching from a process. + /// + /// Allow Process plug-ins to execute some code after detaching + /// from a process. + //------------------------------------------------------------------ + virtual void + DidDetach () {} + + virtual bool + DetachRequiresHalt() { return false; } + + //------------------------------------------------------------------ + /// Called before sending a signal to a process. + /// + /// Allow Process plug-ins to execute some code before sending a + /// signal to a process. + /// + /// @return + /// Returns no error if it is safe to proceed with a call to + /// Process::DoSignal(int), otherwise an error describing what + /// prevents the signal from being sent. + //------------------------------------------------------------------ + virtual Error + WillSignal () { return Error(); } + + //------------------------------------------------------------------ + /// Sends a process a UNIX signal \a signal. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error + DoSignal (int signal) + { + Error error; + error.SetErrorStringWithFormat("error: %s does not support senging signals to processes", GetPluginName().GetCString()); + return error; + } + + virtual Error + WillDestroy () { return Error(); } + + virtual Error + DoDestroy () = 0; + + virtual void + DidDestroy () { } + + virtual bool + DestroyRequiresHalt() { return true; } + + + //------------------------------------------------------------------ + /// Called after sending a signal to a process. + /// + /// Allow Process plug-ins to execute some code after sending a + /// signal to a process. + //------------------------------------------------------------------ + virtual void + DidSignal () {} + + //------------------------------------------------------------------ + /// Currently called as part of ShouldStop. + /// FIXME: Should really happen when the target stops before the + /// event is taken from the queue... + /// + /// This callback is called as the event + /// is about to be queued up to allow Process plug-ins to execute + /// some code prior to clients being notified that a process was + /// stopped. Common operations include updating the thread list, + /// invalidating any thread state (registers, stack, etc) prior to + /// letting the notification go out. + /// + //------------------------------------------------------------------ + virtual void + RefreshStateAfterStop () = 0; + + //------------------------------------------------------------------ + /// Get the target object pointer for this module. + /// + /// @return + /// A Target object pointer to the target that owns this + /// module. + //------------------------------------------------------------------ + Target & + GetTarget () + { + return m_target; + } + + //------------------------------------------------------------------ + /// Get the const target object pointer for this module. + /// + /// @return + /// A const Target object pointer to the target that owns this + /// module. + //------------------------------------------------------------------ + const Target & + GetTarget () const + { + return m_target; + } + + //------------------------------------------------------------------ + /// Flush all data in the process. + /// + /// Flush the memory caches, all threads, and any other cached data + /// in the process. + /// + /// This function can be called after a world changing event like + /// adding a new symbol file, or after the process makes a large + /// context switch (from boot ROM to booted into an OS). + //------------------------------------------------------------------ + void + Flush (); + + //------------------------------------------------------------------ + /// Get accessor for the current process state. + /// + /// @return + /// The current state of the process. + /// + /// @see lldb::StateType + //------------------------------------------------------------------ + lldb::StateType + GetState (); + + ExecutionResults + RunThreadPlan (ExecutionContext &exe_ctx, + lldb::ThreadPlanSP &thread_plan_sp, + bool stop_others, + bool run_others, + bool unwind_on_error, + bool ignore_breakpoints, + uint32_t timeout_usec, + Stream &errors); + + static const char * + ExecutionResultAsCString (ExecutionResults result); + + void + GetStatus (Stream &ostrm); + + size_t + GetThreadStatus (Stream &ostrm, + bool only_threads_with_stop_reason, + uint32_t start_frame, + uint32_t num_frames, + uint32_t num_frames_with_source); + + void + SendAsyncInterrupt (); + +protected: + + void + SetState (lldb::EventSP &event_sp); + + lldb::StateType + GetPrivateState (); + + //------------------------------------------------------------------ + /// The "private" side of resuming a process. This doesn't alter the + /// state of m_run_lock, but just causes the process to resume. + /// + /// @return + /// An Error object describing the success or failure of the resume. + //------------------------------------------------------------------ + Error + PrivateResume (); + + //------------------------------------------------------------------ + // Called internally + //------------------------------------------------------------------ + void + CompleteAttach (); + +public: + //------------------------------------------------------------------ + /// Get the exit status for a process. + /// + /// @return + /// The process's return code, or -1 if the current process + /// state is not eStateExited. + //------------------------------------------------------------------ + int + GetExitStatus (); + + //------------------------------------------------------------------ + /// Get a textual description of what the process exited. + /// + /// @return + /// The textual description of why the process exited, or NULL + /// if there is no description available. + //------------------------------------------------------------------ + const char * + GetExitDescription (); + + + virtual void + DidExit () + { + } + + //------------------------------------------------------------------ + /// Get the Modification ID of the process. + /// + /// @return + /// The modification ID of the process. + //------------------------------------------------------------------ + ProcessModID + GetModID () const + { + return m_mod_id; + } + + const ProcessModID & + GetModIDRef () const + { + return m_mod_id; + } + + uint32_t + GetStopID () const + { + return m_mod_id.GetStopID(); + } + + uint32_t + GetResumeID () const + { + return m_mod_id.GetResumeID(); + } + + uint32_t + GetLastUserExpressionResumeID () const + { + return m_mod_id.GetLastUserExpressionResumeID(); + } + + uint32_t + GetLastNaturalStopID() + { + return m_mod_id.GetLastNaturalStopID(); + } + + //------------------------------------------------------------------ + /// Set accessor for the process exit status (return code). + /// + /// Sometimes a child exits and the exit can be detected by global + /// functions (signal handler for SIGCHLD for example). This + /// accessor allows the exit status to be set from an external + /// source. + /// + /// Setting this will cause a eStateExited event to be posted to + /// the process event queue. + /// + /// @param[in] exit_status + /// The value for the process's return code. + /// + /// @see lldb::StateType + //------------------------------------------------------------------ + virtual bool + SetExitStatus (int exit_status, const char *cstr); + + //------------------------------------------------------------------ + /// Check if a process is still alive. + /// + /// @return + /// Returns \b true if the process is still valid, \b false + /// otherwise. + //------------------------------------------------------------------ + virtual bool + IsAlive () = 0; + + //------------------------------------------------------------------ + /// Before lldb detaches from a process, it warns the user that they are about to lose their debug session. + /// In some cases, this warning doesn't need to be emitted -- for instance, with core file debugging where + /// the user can reconstruct the "state" by simply re-running the debugger on the core file. + /// + /// @return + // true if the user should be warned about detaching from this process. + //------------------------------------------------------------------ + virtual bool + WarnBeforeDetach () const + { + return true; + } + + //------------------------------------------------------------------ + /// Actually do the reading of memory from a process. + /// + /// Subclasses must override this function and can return fewer + /// bytes than requested when memory requests are too large. This + /// class will break up the memory requests and keep advancing the + /// arguments along as needed. + /// + /// @param[in] vm_addr + /// A virtual load address that indicates where to start reading + /// memory from. + /// + /// @param[in] size + /// The number of bytes to read. + /// + /// @param[out] buf + /// A byte buffer that is at least \a size bytes long that + /// will receive the memory bytes. + /// + /// @return + /// The number of bytes that were actually read into \a buf. + //------------------------------------------------------------------ + virtual size_t + DoReadMemory (lldb::addr_t vm_addr, + void *buf, + size_t size, + Error &error) = 0; + + //------------------------------------------------------------------ + /// Read of memory from a process. + /// + /// This function will read memory from the current process's + /// address space and remove any traps that may have been inserted + /// into the memory. + /// + /// This function is not meant to be overridden by Process + /// subclasses, the subclasses should implement + /// Process::DoReadMemory (lldb::addr_t, size_t, void *). + /// + /// @param[in] vm_addr + /// A virtual load address that indicates where to start reading + /// memory from. + /// + /// @param[out] buf + /// A byte buffer that is at least \a size bytes long that + /// will receive the memory bytes. + /// + /// @param[in] size + /// The number of bytes to read. + /// + /// @return + /// The number of bytes that were actually read into \a buf. If + /// the returned number is greater than zero, yet less than \a + /// size, then this function will get called again with \a + /// vm_addr, \a buf, and \a size updated appropriately. Zero is + /// returned to indicate an error. + //------------------------------------------------------------------ + virtual size_t + ReadMemory (lldb::addr_t vm_addr, + void *buf, + size_t size, + Error &error); + + //------------------------------------------------------------------ + /// Read a NULL terminated string from memory + /// + /// This function will read a cache page at a time until a NULL + /// string terminator is found. It will stop reading if an aligned + /// sequence of NULL termination \a type_width bytes is not found + /// before reading \a cstr_max_len bytes. The results are always + /// guaranteed to be NULL terminated, and that no more than + /// (max_bytes - type_width) bytes will be read. + /// + /// @param[in] vm_addr + /// The virtual load address to start the memory read. + /// + /// @param[in] str + /// A character buffer containing at least max_bytes. + /// + /// @param[in] max_bytes + /// The maximum number of bytes to read. + /// + /// @param[in] error + /// The error status of the read operation. + /// + /// @param[in] type_width + /// The size of the null terminator (1 to 4 bytes per + /// character). Defaults to 1. + /// + /// @return + /// The error status or the number of bytes prior to the null terminator. + //------------------------------------------------------------------ + size_t + ReadStringFromMemory (lldb::addr_t vm_addr, + char *str, + size_t max_bytes, + Error &error, + size_t type_width = 1); + + //------------------------------------------------------------------ + /// Read a NULL terminated C string from memory + /// + /// This function will read a cache page at a time until the NULL + /// C string 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, + Error &error); + + size_t + ReadCStringFromMemory (lldb::addr_t vm_addr, + std::string &out_str, + Error &error); + + size_t + ReadMemoryFromInferior (lldb::addr_t vm_addr, + void *buf, + size_t size, + Error &error); + + //------------------------------------------------------------------ + /// Reads an unsigned integer of the specified byte size from + /// process memory. + /// + /// @param[in] load_addr + /// A load address of the integer to read. + /// + /// @param[in] byte_size + /// The size in byte of the integer to read. + /// + /// @param[in] fail_value + /// The value to return if we fail to read an integer. + /// + /// @param[out] error + /// An error that indicates the success or failure of this + /// operation. If error indicates success (error.Success()), + /// then the value returned can be trusted, otherwise zero + /// will be returned. + /// + /// @return + /// The unsigned integer that was read from the process memory + /// space. If the integer was smaller than a uint64_t, any + /// unused upper bytes will be zero filled. If the process + /// byte order differs from the host byte order, the integer + /// value will be appropriately byte swapped into host byte + /// order. + //------------------------------------------------------------------ + uint64_t + ReadUnsignedIntegerFromMemory (lldb::addr_t load_addr, + size_t byte_size, + uint64_t fail_value, + Error &error); + + lldb::addr_t + ReadPointerFromMemory (lldb::addr_t vm_addr, + Error &error); + + bool + WritePointerToMemory (lldb::addr_t vm_addr, + lldb::addr_t ptr_value, + Error &error); + + //------------------------------------------------------------------ + /// Actually do the writing of memory to a process. + /// + /// @param[in] vm_addr + /// A virtual load address that indicates where to start writing + /// memory to. + /// + /// @param[in] buf + /// A byte buffer that is at least \a size bytes long that + /// contains the data to write. + /// + /// @param[in] size + /// The number of bytes to write. + /// + /// @param[out] error + /// An error value in case the memory write fails. + /// + /// @return + /// The number of bytes that were actually written. + //------------------------------------------------------------------ + virtual size_t + DoWriteMemory (lldb::addr_t vm_addr, const void *buf, size_t size, Error &error) + { + error.SetErrorStringWithFormat("error: %s does not support writing to processes", GetPluginName().GetCString()); + return 0; + } + + + //------------------------------------------------------------------ + /// Write all or part of a scalar value to memory. + /// + /// The value contained in \a scalar will be swapped to match the + /// byte order of the process that is being debugged. If \a size is + /// less than the size of scalar, the least significate \a size bytes + /// from scalar will be written. If \a size is larger than the byte + /// size of scalar, then the extra space will be padded with zeros + /// and the scalar value will be placed in the least significant + /// bytes in memory. + /// + /// @param[in] vm_addr + /// A virtual load address that indicates where to start writing + /// memory to. + /// + /// @param[in] scalar + /// The scalar to write to the debugged process. + /// + /// @param[in] size + /// This value can be smaller or larger than the scalar value + /// itself. If \a size is smaller than the size of \a scalar, + /// the least significant bytes in \a scalar will be used. If + /// \a size is larger than the byte size of \a scalar, then + /// the extra space will be padded with zeros. If \a size is + /// set to UINT32_MAX, then the size of \a scalar will be used. + /// + /// @param[out] error + /// An error value in case the memory write fails. + /// + /// @return + /// The number of bytes that were actually written. + //------------------------------------------------------------------ + size_t + WriteScalarToMemory (lldb::addr_t vm_addr, + const Scalar &scalar, + size_t size, + Error &error); + + size_t + ReadScalarIntegerFromMemory (lldb::addr_t addr, + uint32_t byte_size, + bool is_signed, + Scalar &scalar, + Error &error); + + //------------------------------------------------------------------ + /// Write memory to a process. + /// + /// This function will write memory to the current process's + /// address space and maintain any traps that might be present due + /// to software breakpoints. + /// + /// This function is not meant to be overridden by Process + /// subclasses, the subclasses should implement + /// Process::DoWriteMemory (lldb::addr_t, size_t, void *). + /// + /// @param[in] vm_addr + /// A virtual load address that indicates where to start writing + /// memory to. + /// + /// @param[in] buf + /// A byte buffer that is at least \a size bytes long that + /// contains the data to write. + /// + /// @param[in] size + /// The number of bytes to write. + /// + /// @return + /// The number of bytes that were actually written. + //------------------------------------------------------------------ + size_t + WriteMemory (lldb::addr_t vm_addr, const void *buf, size_t size, Error &error); + + + //------------------------------------------------------------------ + /// Actually allocate memory in the process. + /// + /// This function will allocate memory in the process's address + /// space. This can't rely on the generic function calling mechanism, + /// since that requires this function. + /// + /// @param[in] size + /// The size of the allocation requested. + /// + /// @return + /// The address of the allocated buffer in the process, or + /// LLDB_INVALID_ADDRESS if the allocation failed. + //------------------------------------------------------------------ + + virtual lldb::addr_t + DoAllocateMemory (size_t size, uint32_t permissions, Error &error) + { + error.SetErrorStringWithFormat("error: %s does not support allocating in the debug process", GetPluginName().GetCString()); + return LLDB_INVALID_ADDRESS; + } + + + //------------------------------------------------------------------ + /// The public interface to allocating memory in the process. + /// + /// This function will allocate memory in the process's address + /// space. This can't rely on the generic function calling mechanism, + /// since that requires this function. + /// + /// @param[in] size + /// The size of the allocation requested. + /// + /// @param[in] permissions + /// Or together any of the lldb::Permissions bits. The permissions on + /// a given memory allocation can't be changed after allocation. Note + /// that a block that isn't set writable can still be written on from lldb, + /// just not by the process itself. + /// + /// @param[in/out] error + /// An error object to fill in if things go wrong. + /// @return + /// The address of the allocated buffer in the process, or + /// LLDB_INVALID_ADDRESS if the allocation failed. + //------------------------------------------------------------------ + + lldb::addr_t + AllocateMemory (size_t size, uint32_t permissions, Error &error); + + + //------------------------------------------------------------------ + /// Resolve dynamically loaded indirect functions. + /// + /// @param[in] address + /// The load address of the indirect function to resolve. + /// + /// @param[out] error + /// An error value in case the resolve fails. + /// + /// @return + /// The address of the resolved function. + /// LLDB_INVALID_ADDRESS if the resolution failed. + //------------------------------------------------------------------ + + virtual lldb::addr_t + ResolveIndirectFunction(const Address *address, Error &error) + { + error.SetErrorStringWithFormat("error: %s does not support indirect functions in the debug process", GetPluginName().GetCString()); + return LLDB_INVALID_ADDRESS; + } + + virtual Error + GetMemoryRegionInfo (lldb::addr_t load_addr, + MemoryRegionInfo &range_info) + { + Error error; + error.SetErrorString ("Process::GetMemoryRegionInfo() not supported"); + return error; + } + + virtual Error + GetWatchpointSupportInfo (uint32_t &num) + { + Error error; + num = 0; + error.SetErrorString ("Process::GetWatchpointSupportInfo() not supported"); + return error; + } + + virtual Error + GetWatchpointSupportInfo (uint32_t &num, bool& after) + { + Error error; + num = 0; + after = true; + error.SetErrorString ("Process::GetWatchpointSupportInfo() not supported"); + return error; + } + + lldb::ModuleSP + ReadModuleFromMemory (const FileSpec& file_spec, + lldb::addr_t header_addr); + + //------------------------------------------------------------------ + /// Attempt to get the attributes for a region of memory in the process. + /// + /// It may be possible for the remote debug server to inspect attributes + /// for a region of memory in the process, such as whether there is a + /// valid page of memory at a given address or whether that page is + /// readable/writable/executable by the process. + /// + /// @param[in] load_addr + /// The address of interest in the process. + /// + /// @param[out] permissions + /// If this call returns successfully, this bitmask will have + /// its Permissions bits set to indicate whether the region is + /// readable/writable/executable. If this call fails, the + /// bitmask values are undefined. + /// + /// @return + /// Returns true if it was able to determine the attributes of the + /// memory region. False if not. + //------------------------------------------------------------------ + + virtual bool + GetLoadAddressPermissions (lldb::addr_t load_addr, uint32_t &permissions) + { + MemoryRegionInfo range_info; + permissions = 0; + Error error (GetMemoryRegionInfo (load_addr, range_info)); + if (!error.Success()) + return false; + if (range_info.GetReadable() == MemoryRegionInfo::eDontKnow + || range_info.GetWritable() == MemoryRegionInfo::eDontKnow + || range_info.GetExecutable() == MemoryRegionInfo::eDontKnow) + { + return false; + } + + if (range_info.GetReadable() == MemoryRegionInfo::eYes) + permissions |= lldb::ePermissionsReadable; + + if (range_info.GetWritable() == MemoryRegionInfo::eYes) + permissions |= lldb::ePermissionsWritable; + + if (range_info.GetExecutable() == MemoryRegionInfo::eYes) + permissions |= lldb::ePermissionsExecutable; + + return true; + } + + //------------------------------------------------------------------ + /// Determines whether executing JIT-compiled code in this process + /// is possible. + /// + /// @return + /// True if execution of JIT code is possible; false otherwise. + //------------------------------------------------------------------ + bool CanJIT (); + + //------------------------------------------------------------------ + /// Sets whether executing JIT-compiled code in this process + /// is possible. + /// + /// @param[in] can_jit + /// True if execution of JIT code is possible; false otherwise. + //------------------------------------------------------------------ + void SetCanJIT (bool can_jit); + + //------------------------------------------------------------------ + /// Actually deallocate memory in the process. + /// + /// This function will deallocate memory in the process's address + /// space that was allocated with AllocateMemory. + /// + /// @param[in] ptr + /// A return value from AllocateMemory, pointing to the memory you + /// want to deallocate. + /// + /// @return + /// \btrue if the memory was deallocated, \bfalse otherwise. + //------------------------------------------------------------------ + + virtual Error + DoDeallocateMemory (lldb::addr_t ptr) + { + Error error; + error.SetErrorStringWithFormat("error: %s does not support deallocating in the debug process", GetPluginName().GetCString()); + return error; + } + + + //------------------------------------------------------------------ + /// The public interface to deallocating memory in the process. + /// + /// This function will deallocate memory in the process's address + /// space that was allocated with AllocateMemory. + /// + /// @param[in] ptr + /// A return value from AllocateMemory, pointing to the memory you + /// want to deallocate. + /// + /// @return + /// \btrue if the memory was deallocated, \bfalse otherwise. + //------------------------------------------------------------------ + + Error + DeallocateMemory (lldb::addr_t ptr); + + //------------------------------------------------------------------ + /// Get any available STDOUT. + /// + /// If the process was launched without supplying valid file paths + /// for stdin, stdout, and stderr, then the Process class might + /// try to cache the STDOUT for the process if it is able. Events + /// will be queued indicating that there is STDOUT available that + /// can be retrieved using this function. + /// + /// @param[out] buf + /// A buffer that will receive any STDOUT bytes that are + /// currently available. + /// + /// @param[out] buf_size + /// The size in bytes for the buffer \a buf. + /// + /// @return + /// The number of bytes written into \a buf. If this value is + /// equal to \a buf_size, another call to this function should + /// be made to retrieve more STDOUT data. + //------------------------------------------------------------------ + virtual size_t + GetSTDOUT (char *buf, size_t buf_size, Error &error); + + //------------------------------------------------------------------ + /// Get any available STDERR. + /// + /// If the process was launched without supplying valid file paths + /// for stdin, stdout, and stderr, then the Process class might + /// try to cache the STDERR for the process if it is able. Events + /// will be queued indicating that there is STDERR available that + /// can be retrieved using this function. + /// + /// @param[out] buf + /// A buffer that will receive any STDERR bytes that are + /// currently available. + /// + /// @param[out] buf_size + /// The size in bytes for the buffer \a buf. + /// + /// @return + /// The number of bytes written into \a buf. If this value is + /// equal to \a buf_size, another call to this function should + /// be made to retrieve more STDERR data. + //------------------------------------------------------------------ + virtual size_t + GetSTDERR (char *buf, size_t buf_size, Error &error); + + virtual size_t + PutSTDIN (const char *buf, size_t buf_size, Error &error) + { + error.SetErrorString("stdin unsupported"); + return 0; + } + + //------------------------------------------------------------------ + /// Get any available profile data. + /// + /// @param[out] buf + /// A buffer that will receive any profile data bytes that are + /// currently available. + /// + /// @param[out] buf_size + /// The size in bytes for the buffer \a buf. + /// + /// @return + /// The number of bytes written into \a buf. If this value is + /// equal to \a buf_size, another call to this function should + /// be made to retrieve more profile data. + //------------------------------------------------------------------ + virtual size_t + GetAsyncProfileData (char *buf, size_t buf_size, Error &error); + + //---------------------------------------------------------------------- + // Process Breakpoints + //---------------------------------------------------------------------- + size_t + GetSoftwareBreakpointTrapOpcode (BreakpointSite* bp_site); + + virtual Error + EnableBreakpointSite (BreakpointSite *bp_site) + { + Error error; + error.SetErrorStringWithFormat("error: %s does not support enabling breakpoints", GetPluginName().GetCString()); + return error; + } + + + virtual Error + DisableBreakpointSite (BreakpointSite *bp_site) + { + Error error; + error.SetErrorStringWithFormat("error: %s does not support disabling breakpoints", GetPluginName().GetCString()); + return error; + } + + + // This is implemented completely using the lldb::Process API. Subclasses + // don't need to implement this function unless the standard flow of + // read existing opcode, write breakpoint opcode, verify breakpoint opcode + // doesn't work for a specific process plug-in. + virtual Error + EnableSoftwareBreakpoint (BreakpointSite *bp_site); + + // This is implemented completely using the lldb::Process API. Subclasses + // don't need to implement this function unless the standard flow of + // restoring original opcode in memory and verifying the restored opcode + // doesn't work for a specific process plug-in. + virtual Error + DisableSoftwareBreakpoint (BreakpointSite *bp_site); + + BreakpointSiteList & + GetBreakpointSiteList(); + + const BreakpointSiteList & + GetBreakpointSiteList() const; + + void + DisableAllBreakpointSites (); + + Error + ClearBreakpointSiteByID (lldb::user_id_t break_id); + + lldb::break_id_t + CreateBreakpointSite (const lldb::BreakpointLocationSP &owner, + bool use_hardware); + + Error + DisableBreakpointSiteByID (lldb::user_id_t break_id); + + Error + EnableBreakpointSiteByID (lldb::user_id_t break_id); + + + // BreakpointLocations use RemoveOwnerFromBreakpointSite to remove + // themselves from the owner's list of this breakpoint sites. + void + RemoveOwnerFromBreakpointSite (lldb::user_id_t owner_id, + lldb::user_id_t owner_loc_id, + lldb::BreakpointSiteSP &bp_site_sp); + + //---------------------------------------------------------------------- + // Process Watchpoints (optional) + //---------------------------------------------------------------------- + virtual Error + EnableWatchpoint (Watchpoint *wp, bool notify = true); + + virtual Error + DisableWatchpoint (Watchpoint *wp, bool notify = true); + + //------------------------------------------------------------------ + // Thread Queries + //------------------------------------------------------------------ + virtual bool + UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list) = 0; + + void + UpdateThreadListIfNeeded (); + + ThreadList & + GetThreadList () + { + return m_thread_list; + } + + uint32_t + GetNextThreadIndexID (uint64_t thread_id); + + lldb::ThreadSP + CreateOSPluginThread (lldb::tid_t tid, lldb::addr_t context); + + // Returns true if an index id has been assigned to a thread. + bool + HasAssignedIndexIDToThread(uint64_t sb_thread_id); + + // Given a thread_id, it will assign a more reasonable index id for display to the user. + // If the thread_id has previously been assigned, the same index id will be used. + uint32_t + AssignIndexIDToThread(uint64_t thread_id); + + //------------------------------------------------------------------ + // Event Handling + //------------------------------------------------------------------ + lldb::StateType + GetNextEvent (lldb::EventSP &event_sp); + + lldb::StateType + WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp_ptr = NULL); + + lldb::StateType + WaitForStateChangedEvents (const TimeValue *timeout, lldb::EventSP &event_sp); + + Event * + PeekAtStateChangedEvents (); + + + class + ProcessEventHijacker + { + public: + ProcessEventHijacker (Process &process, Listener *listener) : + m_process (process) + { + m_process.HijackProcessEvents (listener); + } + ~ProcessEventHijacker () + { + m_process.RestoreProcessEvents(); + } + + private: + Process &m_process; + }; + friend class ProcessEventHijacker; + //------------------------------------------------------------------ + /// If you need to ensure that you and only you will hear about some public + /// event, then make a new listener, set to listen to process events, and + /// then call this with that listener. Then you will have to wait on that + /// listener explicitly for events (rather than using the GetNextEvent & WaitFor* + /// calls above. Be sure to call RestoreProcessEvents when you are done. + /// + /// @param[in] listener + /// This is the new listener to whom all process events will be delivered. + /// + /// @return + /// Returns \b true if the new listener could be installed, + /// \b false otherwise. + //------------------------------------------------------------------ + bool + HijackProcessEvents (Listener *listener); + + //------------------------------------------------------------------ + /// Restores the process event broadcasting to its normal state. + /// + //------------------------------------------------------------------ + void + RestoreProcessEvents (); + +private: + //------------------------------------------------------------------ + /// This is the part of the event handling that for a process event. + /// It decides what to do with the event and returns true if the + /// event needs to be propagated to the user, and false otherwise. + /// If the event is not propagated, this call will most likely set + /// the target to executing again. + /// There is only one place where this call should be called, HandlePrivateEvent. + /// Don't call it from anywhere else... + /// + /// @param[in] event_ptr + /// This is the event we are handling. + /// + /// @return + /// Returns \b true if the event should be reported to the + /// user, \b false otherwise. + //------------------------------------------------------------------ + bool + ShouldBroadcastEvent (Event *event_ptr); + +public: + const lldb::ABISP & + GetABI (); + + OperatingSystem * + GetOperatingSystem () + { + return m_os_ap.get(); + } + + + virtual LanguageRuntime * + GetLanguageRuntime (lldb::LanguageType language, bool retry_if_null = true); + + virtual CPPLanguageRuntime * + GetCPPLanguageRuntime (bool retry_if_null = true); + + virtual ObjCLanguageRuntime * + GetObjCLanguageRuntime (bool retry_if_null = true); + + bool + IsPossibleDynamicValue (ValueObject& in_value); + + bool + IsRunning () const; + + DynamicCheckerFunctions *GetDynamicCheckers() + { + return m_dynamic_checkers_ap.get(); + } + + void SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers) + { + m_dynamic_checkers_ap.reset(dynamic_checkers); + } + + //------------------------------------------------------------------ + /// Call this to set the lldb in the mode where it breaks on new thread + /// creations, and then auto-restarts. This is useful when you are trying + /// to run only one thread, but either that thread or the kernel is creating + /// new threads in the process. If you stop when the thread is created, you + /// can immediately suspend it, and keep executing only the one thread you intend. + /// + /// @return + /// Returns \b true if we were able to start up the notification + /// \b false otherwise. + //------------------------------------------------------------------ + virtual bool + StartNoticingNewThreads() + { + return true; + } + + //------------------------------------------------------------------ + /// Call this to turn off the stop & notice new threads mode. + /// + /// @return + /// Returns \b true if we were able to start up the notification + /// \b false otherwise. + //------------------------------------------------------------------ + virtual bool + StopNoticingNewThreads() + { + return true; + } + + void + SetRunningUserExpression (bool on); + + //------------------------------------------------------------------ + // lldb::ExecutionContextScope pure virtual functions + //------------------------------------------------------------------ + virtual lldb::TargetSP + CalculateTarget (); + + virtual lldb::ProcessSP + CalculateProcess () + { + return shared_from_this(); + } + + virtual lldb::ThreadSP + CalculateThread () + { + return lldb::ThreadSP(); + } + + virtual lldb::StackFrameSP + CalculateStackFrame () + { + return lldb::StackFrameSP(); + } + + virtual void + CalculateExecutionContext (ExecutionContext &exe_ctx); + + void + SetSTDIOFileDescriptor (int file_descriptor); + + //------------------------------------------------------------------ + // Add a permanent region of memory that should never be read or + // written to. This can be used to ensure that memory reads or writes + // to certain areas of memory never end up being sent to the + // DoReadMemory or DoWriteMemory functions which can improve + // performance. + //------------------------------------------------------------------ + void + AddInvalidMemoryRegion (const LoadRange ®ion); + + //------------------------------------------------------------------ + // Remove a permanent region of memory that should never be read or + // written to that was previously added with AddInvalidMemoryRegion. + //------------------------------------------------------------------ + bool + RemoveInvalidMemoryRange (const LoadRange ®ion); + + //------------------------------------------------------------------ + // If the setup code of a thread plan needs to do work that might involve + // calling a function in the target, it should not do that work directly + // in one of the thread plan functions (DidPush/WillResume) because + // such work needs to be handled carefully. Instead, put that work in + // a PreResumeAction callback, and register it with the process. It will + // get done before the actual "DoResume" gets called. + //------------------------------------------------------------------ + + typedef bool (PreResumeActionCallback)(void *); + + void + AddPreResumeAction (PreResumeActionCallback callback, void *baton); + + bool + RunPreResumeActions (); + + void + ClearPreResumeActions (); + + ProcessRunLock & + GetRunLock () + { + if (Host::GetCurrentThread() == m_private_state_thread) + return m_private_run_lock; + else + return m_public_run_lock; + } + +protected: + //------------------------------------------------------------------ + // NextEventAction provides a way to register an action on the next + // event that is delivered to this process. There is currently only + // one next event action allowed in the process at one time. If a + // new "NextEventAction" is added while one is already present, the + // old action will be discarded (with HandleBeingUnshipped called + // after it is discarded.) + // + // If you want to resume the process as a result of a resume action, + // call RequestResume, don't call Resume directly. + //------------------------------------------------------------------ + class NextEventAction + { + public: + typedef enum EventActionResult + { + eEventActionSuccess, + eEventActionRetry, + eEventActionExit + } EventActionResult; + + NextEventAction (Process *process) : + m_process(process) + { + } + + virtual + ~NextEventAction() + { + } + + virtual EventActionResult PerformAction (lldb::EventSP &event_sp) = 0; + virtual void HandleBeingUnshipped () {} + virtual EventActionResult HandleBeingInterrupted () = 0; + virtual const char *GetExitString() = 0; + void RequestResume() + { + m_process->m_resume_requested = true; + } + protected: + Process *m_process; + }; + + void SetNextEventAction (Process::NextEventAction *next_event_action) + { + if (m_next_event_action_ap.get()) + m_next_event_action_ap->HandleBeingUnshipped(); + + m_next_event_action_ap.reset(next_event_action); + } + + // This is the completer for Attaching: + class AttachCompletionHandler : public NextEventAction + { + public: + AttachCompletionHandler (Process *process, uint32_t exec_count) : + NextEventAction (process), + m_exec_count (exec_count) + { + } + + virtual + ~AttachCompletionHandler() + { + } + + virtual EventActionResult PerformAction (lldb::EventSP &event_sp); + virtual EventActionResult HandleBeingInterrupted (); + virtual const char *GetExitString(); + private: + uint32_t m_exec_count; + std::string m_exit_string; + }; + + bool + HijackPrivateProcessEvents (Listener *listener); + + void + RestorePrivateProcessEvents (); + + bool + PrivateStateThreadIsValid () const + { + return IS_VALID_LLDB_HOST_THREAD(m_private_state_thread); + } + + //------------------------------------------------------------------ + // Type definitions + //------------------------------------------------------------------ + typedef std::map<lldb::LanguageType, lldb::LanguageRuntimeSP> LanguageRuntimeCollection; + + struct PreResumeCallbackAndBaton + { + bool (*callback) (void *); + void *baton; + PreResumeCallbackAndBaton (PreResumeActionCallback in_callback, void *in_baton) : + callback (in_callback), + baton (in_baton) + { + } + }; + + //------------------------------------------------------------------ + // Member variables + //------------------------------------------------------------------ + Target & m_target; ///< The target that owns this process. + ThreadSafeValue<lldb::StateType> m_public_state; + ThreadSafeValue<lldb::StateType> m_private_state; // The actual state of our process + Broadcaster m_private_state_broadcaster; // This broadcaster feeds state changed events into the private state thread's listener. + Broadcaster m_private_state_control_broadcaster; // This is the control broadcaster, used to pause, resume & stop the private state thread. + Listener m_private_state_listener; // This is the listener for the private state thread. + Predicate<bool> m_private_state_control_wait; /// This Predicate is used to signal that a control operation is complete. + lldb::thread_t m_private_state_thread; // Thread ID for the thread that watches interal state events + ProcessModID m_mod_id; ///< Tracks the state of the process over stops and other alterations. + uint32_t m_process_unique_id; ///< Each lldb_private::Process class that is created gets a unique integer ID that increments with each new instance + uint32_t m_thread_index_id; ///< Each thread is created with a 1 based index that won't get re-used. + std::map<uint64_t, uint32_t> m_thread_id_to_index_id_map; + int m_exit_status; ///< The exit status of the process, or -1 if not set. + std::string m_exit_string; ///< A textual description of why a process exited. + Mutex m_thread_mutex; + ThreadList m_thread_list_real; ///< The threads for this process as are known to the protocol we are debugging with + ThreadList m_thread_list; ///< The threads for this process as the user will see them. This is usually the same as + ///< m_thread_list_real, but might be different if there is an OS plug-in creating memory threads + std::vector<Notifications> m_notifications; ///< The list of notifications that this process can deliver. + std::vector<lldb::addr_t> m_image_tokens; + Listener &m_listener; + BreakpointSiteList m_breakpoint_site_list; ///< This is the list of breakpoint locations we intend to insert in the target. + std::unique_ptr<DynamicLoader> m_dyld_ap; + std::unique_ptr<DynamicCheckerFunctions> m_dynamic_checkers_ap; ///< The functions used by the expression parser to validate data that expressions use. + std::unique_ptr<OperatingSystem> m_os_ap; + UnixSignals m_unix_signals; /// This is the current signal set for this process. + lldb::ABISP m_abi_sp; + lldb::InputReaderSP m_process_input_reader; + Communication m_stdio_communication; + Mutex m_stdio_communication_mutex; + std::string m_stdout_data; + std::string m_stderr_data; + Mutex m_profile_data_comm_mutex; + std::vector<std::string> m_profile_data; + MemoryCache m_memory_cache; + AllocatedMemoryCache m_allocated_memory_cache; + bool m_should_detach; /// Should we detach if the process object goes away with an explicit call to Kill or Detach? + LanguageRuntimeCollection m_language_runtimes; + std::unique_ptr<NextEventAction> m_next_event_action_ap; + std::vector<PreResumeCallbackAndBaton> m_pre_resume_actions; + ProcessRunLock m_public_run_lock; + ProcessRunLock m_private_run_lock; + Predicate<bool> m_currently_handling_event; // This predicate is set in HandlePrivateEvent while all its business is being done. + bool m_currently_handling_do_on_removals; + bool m_resume_requested; // If m_currently_handling_event or m_currently_handling_do_on_removals are true, Resume will only request a resume, using this flag to check. + bool m_finalize_called; + bool m_clear_thread_plans_on_stop; + lldb::StateType m_last_broadcast_state; /// This helps with the Public event coalescing in ShouldBroadcastEvent. + bool m_destroy_in_process; + + enum { + eCanJITDontKnow= 0, + eCanJITYes, + eCanJITNo + } m_can_jit; + + size_t + RemoveBreakpointOpcodesFromBuffer (lldb::addr_t addr, size_t size, uint8_t *buf) const; + + void + SynchronouslyNotifyStateChanged (lldb::StateType state); + + void + SetPublicState (lldb::StateType new_state, bool restarted); + + void + SetPrivateState (lldb::StateType state); + + bool + StartPrivateStateThread (bool force = false); + + void + StopPrivateStateThread (); + + void + PausePrivateStateThread (); + + void + ResumePrivateStateThread (); + + static void * + PrivateStateThread (void *arg); + + void * + RunPrivateStateThread (); + + void + HandlePrivateEvent (lldb::EventSP &event_sp); + + lldb::StateType + WaitForProcessStopPrivate (const TimeValue *timeout, lldb::EventSP &event_sp); + + // This waits for both the state change broadcaster, and the control broadcaster. + // If control_only, it only waits for the control broadcaster. + + bool + WaitForEventsPrivate (const TimeValue *timeout, lldb::EventSP &event_sp, bool control_only); + + lldb::StateType + WaitForStateChangedEventsPrivate (const TimeValue *timeout, lldb::EventSP &event_sp); + + lldb::StateType + WaitForState (const TimeValue *timeout, + const lldb::StateType *match_states, + const uint32_t num_match_states); + + size_t + WriteMemoryPrivate (lldb::addr_t addr, const void *buf, size_t size, Error &error); + + void + AppendSTDOUT (const char *s, size_t len); + + void + AppendSTDERR (const char *s, size_t len); + + void + BroadcastAsyncProfileData(const std::string &one_profile_data); + + static void + STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len); + + void + PushProcessInputReader (); + + void + PopProcessInputReader (); + + void + ResetProcessInputReader (); + + static size_t + ProcessInputReaderCallback (void *baton, + InputReader &reader, + lldb::InputReaderAction notification, + const char *bytes, + size_t bytes_len); + + Error + HaltForDestroyOrDetach(lldb::EventSP &exit_event_sp); + +private: + //------------------------------------------------------------------ + // For Process only + //------------------------------------------------------------------ + void ControlPrivateStateThread (uint32_t signal); + + DISALLOW_COPY_AND_ASSIGN (Process); + +}; + +} // namespace lldb_private + +#endif // liblldb_Process_h_ |