[Lldb-commits] [PATCH] Primitive attach support for linux
Greg Clayton
gclayton at apple.com
Tue Jun 14 08:38:33 PDT 2011
This patch is in linux files only, so feel free to commit as long as no one else has any objections!
Greg Clayton
On Jun 14, 2011, at 5:48 AM, Marco Minutoli wrote:
> This patch is a starting point for the attach functionality.
> ---
> source/Plugins/Process/Linux/ProcessLinux.cpp | 11 ++-
> source/Plugins/Process/Linux/ProcessMonitor.cpp | 178 +++++++++++++++++++++--
> source/Plugins/Process/Linux/ProcessMonitor.h | 49 ++++++-
> 3 files changed, 214 insertions(+), 24 deletions(-)
>
> diff --git a/source/Plugins/Process/Linux/ProcessLinux.cpp b/source/Plugins/Process/Linux/ProcessLinux.cpp
> index c4ce8ee..e6940fe 100644
> --- a/source/Plugins/Process/Linux/ProcessLinux.cpp
> +++ b/source/Plugins/Process/Linux/ProcessLinux.cpp
> @@ -105,7 +105,16 @@ ProcessLinux::CanDebug(Target &target)
> Error
> ProcessLinux::DoAttachToProcessWithID(lldb::pid_t pid)
> {
> - return Error(1, eErrorTypeGeneric);
> + Error error;
> + assert(m_monitor == NULL);
> +
> + m_monitor = new ProcessMonitor(this, pid, error);
> +
> + if (!error.Success())
> + return error;
> +
> + SetID(pid);
> + return error;
> }
>
> Error
> diff --git a/source/Plugins/Process/Linux/ProcessMonitor.cpp b/source/Plugins/Process/Linux/ProcessMonitor.cpp
> index ce16159..ebe5959 100644
> --- a/source/Plugins/Process/Linux/ProcessMonitor.cpp
> +++ b/source/Plugins/Process/Linux/ProcessMonitor.cpp
> @@ -524,6 +524,17 @@ KillOperation::Execute(ProcessMonitor *monitor)
> m_result = true;
> }
>
> +ProcessMonitor::OperationArgs::OperationArgs(ProcessMonitor *monitor)
> + : m_monitor(monitor)
> +{
> + sem_init(&m_semaphore, 0, 0);
> +}
> +
> +ProcessMonitor::OperationArgs::~OperationArgs()
> +{
> + sem_destroy(&m_semaphore);
> +}
> +
> ProcessMonitor::LaunchArgs::LaunchArgs(ProcessMonitor *monitor,
> lldb_private::Module *module,
> char const **argv,
> @@ -531,21 +542,23 @@ ProcessMonitor::LaunchArgs::LaunchArgs(ProcessMonitor *monitor,
> const char *stdin_path,
> const char *stdout_path,
> const char *stderr_path)
> - : m_monitor(monitor),
> + : OperationArgs(monitor),
> m_module(module),
> m_argv(argv),
> m_envp(envp),
> m_stdin_path(stdin_path),
> m_stdout_path(stdout_path),
> - m_stderr_path(stderr_path)
> -{
> - sem_init(&m_semaphore, 0, 0);
> -}
> + m_stderr_path(stderr_path) { }
>
> ProcessMonitor::LaunchArgs::~LaunchArgs()
> -{
> - sem_destroy(&m_semaphore);
> -}
> +{ }
> +
> +ProcessMonitor::AttachArgs::AttachArgs(ProcessMonitor *monitor,
> + lldb::pid_t pid)
> + : OperationArgs(monitor), m_pid(pid) { }
> +
> +ProcessMonitor::AttachArgs::~AttachArgs()
> +{ }
>
> //------------------------------------------------------------------------------
> /// The basic design of the ProcessMonitor is built around two threads.
> @@ -587,7 +600,7 @@ ProcessMonitor::ProcessMonitor(ProcessLinux *process,
> error.SetErrorString("Monitor failed to initialize.");
> }
>
> - StartOperationThread(args.get(), error);
> + StartLaunchOpThread(args.get(), error);
> if (!error.Success())
> return;
>
> @@ -607,7 +620,7 @@ WAIT_AGAIN:
> // Check that the launch was a success.
> if (!args->m_error.Success())
> {
> - StopOperationThread();
> + StopLaunchOpThread();
> error = args->m_error;
> return;
> }
> @@ -623,6 +636,64 @@ WAIT_AGAIN:
> }
> }
>
> +ProcessMonitor::ProcessMonitor(ProcessLinux *process,
> + lldb::pid_t pid,
> + lldb_private::Error &error)
> + : m_process(process),
> + m_operation_thread(LLDB_INVALID_HOST_THREAD),
> + m_pid(LLDB_INVALID_PROCESS_ID),
> + m_terminal_fd(-1),
> + m_monitor_thread(LLDB_INVALID_HOST_THREAD),
> + m_client_fd(-1),
> + m_server_fd(-1)
> +{
> + std::auto_ptr<AttachArgs> args;
> +
> + args.reset(new AttachArgs(this, pid));
> +
> + // Server/client descriptors.
> + if (!EnableIPC())
> + {
> + error.SetErrorToGenericError();
> + error.SetErrorString("Monitor failed to initialize.");
> + }
> +
> + StartAttachOpThread(args.get(), error);
> + if (!error.Success())
> + return;
> +
> +WAIT_AGAIN:
> + // Wait for the operation thread to initialize.
> + if (sem_wait(&args->m_semaphore))
> + {
> + if (errno == EINTR)
> + goto WAIT_AGAIN;
> + else
> + {
> + error.SetErrorToErrno();
> + return;
> + }
> + }
> +
> + // Check that the launch was a success.
> + if (!args->m_error.Success())
> + {
> + StopAttachOpThread();
> + error = args->m_error;
> + return;
> + }
> +
> + // Finally, start monitoring the child process for change in state.
> + m_monitor_thread = Host::StartMonitoringChildProcess(
> + ProcessMonitor::MonitorCallback, this, GetPID(), true);
> + if (!IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
> + {
> + error.SetErrorToGenericError();
> + error.SetErrorString("Process attach failed.");
> + return;
> + }
> +}
> +
> ProcessMonitor::~ProcessMonitor()
> {
> StopMonitor();
> @@ -631,7 +702,7 @@ ProcessMonitor::~ProcessMonitor()
> //------------------------------------------------------------------------------
> // Thread setup and tear down.
> void
> -ProcessMonitor::StartOperationThread(LaunchArgs *args, Error &error)
> +ProcessMonitor::StartLaunchOpThread(LaunchArgs *args, Error &error)
> {
> static const char *g_thread_name = "lldb.process.linux.operation";
>
> @@ -639,11 +710,11 @@ ProcessMonitor::StartOperationThread(LaunchArgs *args, Error &error)
> return;
>
> m_operation_thread =
> - Host::ThreadCreate(g_thread_name, OperationThread, args, &error);
> + Host::ThreadCreate(g_thread_name, LaunchOpThread, args, &error);
> }
>
> void
> -ProcessMonitor::StopOperationThread()
> +ProcessMonitor::StopLaunchOpThread()
> {
> lldb::thread_result_t result;
>
> @@ -655,7 +726,7 @@ ProcessMonitor::StopOperationThread()
> }
>
> void *
> -ProcessMonitor::OperationThread(void *arg)
> +ProcessMonitor::LaunchOpThread(void *arg)
> {
> LaunchArgs *args = static_cast<LaunchArgs*>(arg);
>
> @@ -833,6 +904,80 @@ ProcessMonitor::EnableIPC()
> return true;
> }
>
> +void
> +ProcessMonitor::StartAttachOpThread(AttachArgs *args, lldb_private::Error &error)
> +{
> + static const char *g_thread_name = "lldb.process.linux.operation";
> +
> + if (IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
> + return;
> +
> + m_operation_thread =
> + Host::ThreadCreate(g_thread_name, AttachOpThread, args, &error);
> +}
> +
> +void
> +ProcessMonitor::StopAttachOpThread()
> +{
> + assert(!"Not implemented yet!!!");
> +}
> +
> +void *
> +ProcessMonitor::AttachOpThread(void *arg)
> +{
> + AttachArgs *args = static_cast<AttachArgs*>(arg);
> +
> + if (!Attach(args))
> + return NULL;
> +
> + ServeOperation(args);
> + return NULL;
> +}
> +
> +bool
> +ProcessMonitor::Attach(AttachArgs *args)
> +{
> + lldb::pid_t pid = args->m_pid;
> +
> + ProcessMonitor *monitor = args->m_monitor;
> + ProcessLinux &process = monitor->GetProcess();
> +
> + lldb::ThreadSP inferior;
> +
> + if (pid <= 1)
> + {
> + args->m_error.SetErrorToGenericError();
> + args->m_error.SetErrorString("Attaching to process 1 is not allowed.");
> + goto FINISH;
> + }
> +
> + // Attach to the requested process.
> + if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0)
> + {
> + args->m_error.SetErrorToErrno();
> + goto FINISH;
> + }
> +
> + int status;
> + if ((status = waitpid(pid, NULL, 0)) < 0)
> + {
> + args->m_error.SetErrorToErrno();
> + goto FINISH;
> + }
> +
> + // Update the process thread list with the attached thread and
> + // mark it as current.
> + inferior.reset(new LinuxThread(process, pid));
> + process.GetThreadList().AddThread(inferior);
> + process.GetThreadList().SetSelectedThreadByID(pid);
> +
> + // Let our process instance know the thread has stopped.
> + process.SendMessage(ProcessMessage::Trace(pid));
> +
> + FINISH:
> + return args->m_error.Success();
> +}
> +
> bool
> ProcessMonitor::MonitorCallback(void *callback_baton,
> lldb::pid_t pid,
> @@ -1094,10 +1239,11 @@ ProcessMonitor::GetCrashReasonForSIGBUS(const struct siginfo *info)
> }
>
> void
> -ProcessMonitor::ServeOperation(LaunchArgs *args)
> +ProcessMonitor::ServeOperation(OperationArgs *args)
> {
> int status;
> pollfd fdset;
> +
> ProcessMonitor *monitor = args->m_monitor;
>
> fdset.fd = monitor->m_server_fd;
> @@ -1326,7 +1472,7 @@ void
> ProcessMonitor::StopMonitor()
> {
> StopMonitoringChildProcess();
> - StopOperationThread();
> + StopLaunchOpThread();
> CloseFD(m_terminal_fd);
> CloseFD(m_client_fd);
> CloseFD(m_server_fd);
> diff --git a/source/Plugins/Process/Linux/ProcessMonitor.h b/source/Plugins/Process/Linux/ProcessMonitor.h
> index 9b8051b..ef9a179 100644
> --- a/source/Plugins/Process/Linux/ProcessMonitor.h
> +++ b/source/Plugins/Process/Linux/ProcessMonitor.h
> @@ -56,6 +56,10 @@ public:
> const char *stderr_path,
> lldb_private::Error &error);
>
> + ProcessMonitor(ProcessLinux *process,
> + lldb::pid_t pid,
> + lldb_private::Error &error);
> +
> ~ProcessMonitor();
>
> /// Provides the process number of debugee.
> @@ -169,11 +173,22 @@ private:
> int m_client_fd;
> int m_server_fd;
>
> + struct OperationArgs
> + {
> + OperationArgs(ProcessMonitor *monitor);
> +
> + ~OperationArgs();
> +
> + ProcessMonitor *m_monitor; // The monitor performing the attach.
> + sem_t m_semaphore; // Posted to once operation complete.
> + lldb_private::Error m_error; // Set if process operation failed.
> + };
> +
> /// @class LauchArgs
> ///
> /// @brief Simple structure to pass data to the thread responsible for
> /// launching a child process.
> - struct LaunchArgs
> + struct LaunchArgs : OperationArgs
> {
> LaunchArgs(ProcessMonitor *monitor,
> lldb_private::Module *module,
> @@ -192,18 +207,16 @@ private:
> const char *m_stdin_path; // Redirect stdin or NULL.
> const char *m_stdout_path; // Redirect stdout or NULL.
> const char *m_stderr_path; // Redirect stderr or NULL.
> - sem_t m_semaphore; // Posted to once launch complete.
> - lldb_private::Error m_error; // Set if process launch failed.
> };
>
> void
> - StartOperationThread(LaunchArgs *args, lldb_private::Error &error);
> + StartLaunchOpThread(LaunchArgs *args, lldb_private::Error &error);
>
> void
> - StopOperationThread();
> + StopLaunchOpThread();
>
> static void *
> - OperationThread(void *arg);
> + LaunchOpThread(void *arg);
>
> static bool
> Launch(LaunchArgs *args);
> @@ -211,8 +224,30 @@ private:
> bool
> EnableIPC();
>
> + struct AttachArgs : OperationArgs
> + {
> + AttachArgs(ProcessMonitor *monitor,
> + lldb::pid_t pid);
> +
> + ~AttachArgs();
> +
> + lldb::pid_t m_pid; // pid of the process to be attached.
> + };
> +
> + void
> + StartAttachOpThread(AttachArgs *args, lldb_private::Error &error);
> +
> + void
> + StopAttachOpThread();
> +
> + static void *
> + AttachOpThread(void *args);
> +
> + static bool
> + Attach(AttachArgs *args);
> +
> static void
> - ServeOperation(LaunchArgs *args);
> + ServeOperation(OperationArgs *args);
>
> static bool
> DupDescriptor(const char *path, int fd, int flags);
> --
> 1.7.3.4
>
> _______________________________________________
> lldb-commits mailing list
> lldb-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits
More information about the lldb-commits
mailing list