diff options
author | Zachary Turner <zturner@google.com> | 2015-05-20 18:31:17 +0000 |
---|---|---|
committer | Zachary Turner <zturner@google.com> | 2015-05-20 18:31:17 +0000 |
commit | c62733b0debd510b7926baf2090bd9e2ff9f3dad (patch) | |
tree | d881f88f780cdc8448bc137e99b9f3056aa41e0a /lldb/source/Plugins/Process | |
parent | fd28abcf15b433a4e36cee68a2f4bf7db6ce52a9 (diff) | |
download | bcm5719-llvm-c62733b0debd510b7926baf2090bd9e2ff9f3dad.tar.gz bcm5719-llvm-c62733b0debd510b7926baf2090bd9e2ff9f3dad.zip |
Implement attach to process on Windows.
Differential Revision: http://reviews.llvm.org/D9801
Reviewed by: Adrian McCarthy
llvm-svn: 237817
Diffstat (limited to 'lldb/source/Plugins/Process')
5 files changed, 190 insertions, 46 deletions
diff --git a/lldb/source/Plugins/Process/Windows/DebuggerThread.cpp b/lldb/source/Plugins/Process/Windows/DebuggerThread.cpp index 0959fc28489..d4659a5faf2 100644 --- a/lldb/source/Plugins/Process/Windows/DebuggerThread.cpp +++ b/lldb/source/Plugins/Process/Windows/DebuggerThread.cpp @@ -22,6 +22,7 @@ #include "lldb/Host/windows/HostThreadWindows.h" #include "lldb/Host/windows/ProcessLauncherWindows.h" #include "lldb/Target/ProcessLaunchInfo.h" +#include "lldb/Target/Process.h" #include "Plugins/Process/Windows/ProcessWindowsLog.h" @@ -43,6 +44,19 @@ struct DebugLaunchContext DebuggerThread *m_thread; ProcessLaunchInfo m_launch_info; }; + +struct DebugAttachContext +{ + DebugAttachContext(DebuggerThread *thread, lldb::pid_t pid, const ProcessAttachInfo &attach_info) + : m_thread(thread) + , m_pid(pid) + , m_attach_info(attach_info) + { + } + DebuggerThread *m_thread; + lldb::pid_t m_pid; + ProcessAttachInfo m_attach_info; +}; } DebuggerThread::DebuggerThread(DebugDelegateSP debug_delegate) @@ -64,7 +78,7 @@ DebuggerThread::DebugLaunch(const ProcessLaunchInfo &launch_info) Error error; DebugLaunchContext *context = new DebugLaunchContext(this, launch_info); HostThread slave_thread(ThreadLauncher::LaunchThread("lldb.plugin.process-windows.slave[?]", - DebuggerThreadRoutine, context, &error)); + DebuggerThreadLaunchRoutine, context, &error)); if (!error.Success()) { @@ -75,25 +89,53 @@ DebuggerThread::DebugLaunch(const ProcessLaunchInfo &launch_info) return error; } +Error +DebuggerThread::DebugAttach(lldb::pid_t pid, const ProcessAttachInfo &attach_info) +{ + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DebuggerThread::DebugAttach attaching to '%u'", (DWORD)pid); + + Error error; + DebugAttachContext *context = new DebugAttachContext(this, pid, attach_info); + HostThread slave_thread(ThreadLauncher::LaunchThread("lldb.plugin.process-windows.slave[?]", + DebuggerThreadAttachRoutine, context, &error)); + + if (!error.Success()) + { + WINERR_IFALL(WINDOWS_LOG_PROCESS, "DebugAttach couldn't attach to process '%u'. %s", (DWORD)pid, + error.AsCString()); + } + + return error; +} + lldb::thread_result_t -DebuggerThread::DebuggerThreadRoutine(void *data) +DebuggerThread::DebuggerThreadLaunchRoutine(void *data) { DebugLaunchContext *context = static_cast<DebugLaunchContext *>(data); - lldb::thread_result_t result = context->m_thread->DebuggerThreadRoutine(context->m_launch_info); + lldb::thread_result_t result = context->m_thread->DebuggerThreadLaunchRoutine(context->m_launch_info); + delete context; + return result; +} + +lldb::thread_result_t +DebuggerThread::DebuggerThreadAttachRoutine(void *data) +{ + DebugAttachContext *context = static_cast<DebugAttachContext *>(data); + lldb::thread_result_t result = + context->m_thread->DebuggerThreadAttachRoutine(context->m_pid, context->m_attach_info); delete context; return result; } lldb::thread_result_t -DebuggerThread::DebuggerThreadRoutine(const ProcessLaunchInfo &launch_info) +DebuggerThread::DebuggerThreadLaunchRoutine(const ProcessLaunchInfo &launch_info) { // Grab a shared_ptr reference to this so that we know it won't get deleted until after the // thread routine has exited. std::shared_ptr<DebuggerThread> this_ref(shared_from_this()); - WINLOG_IFALL(WINDOWS_LOG_PROCESS, - "DebuggerThread preparing to launch '%s'.", - launch_info.GetExecutableFile().GetPath().c_str()); + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DebuggerThread preparing to launch '%s' on background thread.", + launch_info.GetExecutableFile().GetPath().c_str()); Error error; ProcessLauncherWindows launcher; @@ -111,6 +153,31 @@ DebuggerThread::DebuggerThreadRoutine(const ProcessLaunchInfo &launch_info) return 0; } +lldb::thread_result_t +DebuggerThread::DebuggerThreadAttachRoutine(lldb::pid_t pid, const ProcessAttachInfo &attach_info) +{ + // Grab a shared_ptr reference to this so that we know it won't get deleted until after the + // thread routine has exited. + std::shared_ptr<DebuggerThread> this_ref(shared_from_this()); + + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DebuggerThread preparing to attach to process '%u' on background thread.", + (DWORD)pid); + + if (!DebugActiveProcess((DWORD)pid)) + { + Error error(::GetLastError(), eErrorTypeWin32); + m_debug_delegate->OnDebuggerError(error, 0); + return 0; + } + + // The attach was successful, enter the debug loop. From here on out, this is no different than + // a create process operation, so all the same comments in DebugLaunch should apply from this + // point out. + DebugLoop(); + + return 0; +} + Error DebuggerThread::StopDebugging(bool terminate) { diff --git a/lldb/source/Plugins/Process/Windows/DebuggerThread.h b/lldb/source/Plugins/Process/Windows/DebuggerThread.h index a11aede2020..0bfb6486208 100644 --- a/lldb/source/Plugins/Process/Windows/DebuggerThread.h +++ b/lldb/source/Plugins/Process/Windows/DebuggerThread.h @@ -34,6 +34,7 @@ class DebuggerThread : public std::enable_shared_from_this<DebuggerThread> virtual ~DebuggerThread(); Error DebugLaunch(const ProcessLaunchInfo &launch_info); + Error DebugAttach(lldb::pid_t pid, const ProcessAttachInfo &attach_info); HostProcess GetProcess() const @@ -80,8 +81,10 @@ class DebuggerThread : public std::enable_shared_from_this<DebuggerThread> // is finished processing and the debug loop can be // continued. - static lldb::thread_result_t DebuggerThreadRoutine(void *data); - lldb::thread_result_t DebuggerThreadRoutine(const ProcessLaunchInfo &launch_info); + static lldb::thread_result_t DebuggerThreadLaunchRoutine(void *data); + lldb::thread_result_t DebuggerThreadLaunchRoutine(const ProcessLaunchInfo &launch_info); + static lldb::thread_result_t DebuggerThreadAttachRoutine(void *data); + lldb::thread_result_t DebuggerThreadAttachRoutine(lldb::pid_t pid, const ProcessAttachInfo &launch_info); }; } diff --git a/lldb/source/Plugins/Process/Windows/DynamicLoaderWindows.cpp b/lldb/source/Plugins/Process/Windows/DynamicLoaderWindows.cpp index bc59069701f..552f75841cb 100644 --- a/lldb/source/Plugins/Process/Windows/DynamicLoaderWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/DynamicLoaderWindows.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "DynamicLoaderWindows.h" +#include "ProcessWindowsLog.h" #include "lldb/Core/PluginManager.h" #include "lldb/Target/Process.h" @@ -65,6 +66,7 @@ DynamicLoader *DynamicLoaderWindows::CreateInstance(Process *process, bool force if (should_create) return new DynamicLoaderWindows (process); + return nullptr; } diff --git a/lldb/source/Plugins/Process/Windows/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/ProcessWindows.cpp index c44dd82cd9f..716dabbf128 100644 --- a/lldb/source/Plugins/Process/Windows/ProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/ProcessWindows.cpp @@ -62,8 +62,8 @@ namespace lldb_private class ProcessWindowsData { public: - ProcessWindowsData(const ProcessLaunchInfo &launch_info) - : m_launch_info(launch_info) + ProcessWindowsData(bool stop_at_entry) + : m_stop_at_entry(stop_at_entry) , m_initial_stop_event(nullptr) , m_initial_stop_received(false) { @@ -72,11 +72,11 @@ class ProcessWindowsData ~ProcessWindowsData() { ::CloseHandle(m_initial_stop_event); } - ProcessLaunchInfo m_launch_info; lldb_private::Error m_launch_error; lldb_private::DebuggerThreadSP m_debugger; StopInfoSP m_pending_stop_info; HANDLE m_initial_stop_event; + bool m_stop_at_entry; bool m_initial_stop_received; std::map<lldb::tid_t, HostThread> m_new_threads; std::set<lldb::tid_t> m_exited_threads; @@ -257,7 +257,8 @@ ProcessWindows::DoLaunch(Module *exe_module, return result; } - m_session_data.reset(new ProcessWindowsData(launch_info)); + bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry); + m_session_data.reset(new ProcessWindowsData(stop_at_entry)); SetPrivateState(eStateLaunching); DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); @@ -266,42 +267,92 @@ ProcessWindows::DoLaunch(Module *exe_module, // Kick off the DebugLaunch asynchronously and wait for it to complete. result = debugger->DebugLaunch(launch_info); + if (result.Fail()) + { + WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s", + launch_info.GetExecutableFile().GetPath().c_str(), result.AsCString()); + return result; + } HostProcess process; - if (result.Success()) + Error error = WaitForDebuggerConnection(debugger, process); + if (error.Fail()) { - WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch started asynchronous launch of '%s'. Waiting for initial stop.", - launch_info.GetExecutableFile().GetPath().c_str()); - - // Block this function until we receive the initial stop from the process. - if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) == WAIT_OBJECT_0) - { - process = debugger->GetProcess(); - if (m_session_data->m_launch_error.Fail()) - result = m_session_data->m_launch_error; - } - else - result.SetError(::GetLastError(), eErrorTypeWin32); + WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s", + launch_info.GetExecutableFile().GetPath().c_str(), error.AsCString()); + return error; } - if (result.Success()) + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch successfully launched '%s'", + launch_info.GetExecutableFile().GetPath().c_str()); + + // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the private state + // should already be set to eStateStopped as a result of hitting the initial breakpoint. If + // it was not set, the breakpoint should have already been resumed from and the private state + // should already be eStateRunning. + launch_info.SetProcessID(process.GetProcessId()); + SetID(process.GetProcessId()); + + return result; +} + +Error +ProcessWindows::DoAttachToProcessWithID(lldb::pid_t pid, const ProcessAttachInfo &attach_info) +{ + m_session_data.reset(new ProcessWindowsData(!attach_info.GetContinueOnceAttached())); + + DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); + DebuggerThreadSP debugger(new DebuggerThread(delegate)); + + m_session_data->m_debugger = debugger; + + DWORD process_id = static_cast<DWORD>(pid); + Error error = debugger->DebugAttach(process_id, attach_info); + if (error.Fail()) { - WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch successfully launched '%s'", - launch_info.GetExecutableFile().GetPath().c_str()); + WINLOG_IFALL(WINDOWS_LOG_PROCESS, + "DoAttachToProcessWithID encountered an error occurred initiating the asynchronous attach. %s", + error.AsCString()); + return error; } - else + + HostProcess process; + error = WaitForDebuggerConnection(debugger, process); + if (error.Fail()) { - WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s", - launch_info.GetExecutableFile().GetPath().c_str(), result.AsCString()); - return result; + WINLOG_IFALL(WINDOWS_LOG_PROCESS, + "DoAttachToProcessWithID encountered an error waiting for the debugger to connect. %s", + error.AsCString()); + return error; } - // We've hit the initial stop. The private state should already be set to stopped as a result - // of encountering the breakpoint exception in ProcessWindows::OnDebugException. - launch_info.SetProcessID(process.GetProcessId()); + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoAttachToProcessWithID successfully attached to process with pid=%u", + process_id); + + // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the private state + // should already be set to eStateStopped as a result of hitting the initial breakpoint. If + // it was not set, the breakpoint should have already been resumed from and the private state + // should already be eStateRunning. SetID(process.GetProcessId()); + return error; +} - return result; +Error +ProcessWindows::WaitForDebuggerConnection(DebuggerThreadSP debugger, HostProcess &process) +{ + Error result; + WINLOG_IFANY(WINDOWS_LOG_PROCESS|WINDOWS_LOG_BREAKPOINTS, "WaitForDebuggerConnection Waiting for loader breakpoint."); + + // Block this function until we receive the initial stop from the process. + if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) == WAIT_OBJECT_0) + { + WINLOG_IFANY(WINDOWS_LOG_PROCESS|WINDOWS_LOG_BREAKPOINTS, "WaitForDebuggerConnection hit loader breakpoint, returning."); + + process = debugger->GetProcess(); + return m_session_data->m_launch_error; + } + else + return Error(::GetLastError(), eErrorTypeWin32); } Error @@ -521,11 +572,16 @@ ProcessWindows::DoHalt(bool &caused_stop) void ProcessWindows::DidLaunch() { + DidAttach(ArchSpec()); +} + +void +ProcessWindows::DidAttach(ArchSpec &arch_spec) +{ llvm::sys::ScopedLock lock(m_mutex); // The initial stop won't broadcast the state change event, so account for that here. - if (m_session_data && GetPrivateState() == eStateStopped && - m_session_data->m_launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) + if (m_session_data && GetPrivateState() == eStateStopped && m_session_data->m_stop_at_entry) RefreshStateAfterStop(); } @@ -557,11 +613,13 @@ size_t ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, Error &error) { llvm::sys::ScopedLock lock(m_mutex); + WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoWriteMemory attempting to write %u bytes into address 0x%I64x", size, vm_addr); if (!m_session_data) + { + WINERR_IFANY(WINDOWS_LOG_MEMORY, "DoWriteMemory cannot write, there is no active debugger connection."); return 0; - - WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoWriteMemory attempting to write %u bytes into address 0x%I64x", size, vm_addr); + } HostProcess process = m_session_data->m_debugger->GetProcess(); void *addr = reinterpret_cast<void *>(vm_addr); @@ -672,20 +730,18 @@ ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) WINLOG_IFALL(WINDOWS_LOG_PROCESS, "Debugger established connected to process %I64u. Image base = 0x%I64x", debugger->GetProcess().GetProcessId(), image_base); - // Either we successfully attached to an existing process, or we successfully launched a new - // process under the debugger. ModuleSP module = GetTarget().GetExecutableModule(); bool load_addr_changed; module->SetLoadAddress(GetTarget(), image_base, false, load_addr_changed); - // Notify the target that the executable module has loaded. This will cause any pending - // breakpoints to be resolved to explicit brekapoint sites. ModuleList loaded_modules; loaded_modules.Append(module); GetTarget().ModulesDidLoad(loaded_modules); + // Add the main executable module to the list of pending module loads. We can't call + // GetTarget().ModulesDidLoad() here because we still haven't returned from DoLaunch() / DoAttach() yet + // so the target may not have set the process instance to `this` yet. llvm::sys::ScopedLock lock(m_mutex); - const HostThreadWindows &wmain_thread = debugger->GetMainThread().GetNativeThread(); m_session_data->m_new_threads[wmain_thread.GetThreadId()] = debugger->GetMainThread(); } @@ -723,9 +779,18 @@ ProcessWindows::OnDebugException(bool first_chance, const ExceptionRecord &recor if (!m_session_data->m_initial_stop_received) { + WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS, + "Hit loader breakpoint at address 0x%I64x, setting initial stop event.", + record.GetExceptionAddress()); m_session_data->m_initial_stop_received = true; ::SetEvent(m_session_data->m_initial_stop_event); } + else + { + WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS, + "Hit non-loader breakpoint at address 0x%I64x.", + record.GetExceptionAddress()); + } SetPrivateState(eStateStopped); break; case EXCEPTION_SINGLE_STEP: diff --git a/lldb/source/Plugins/Process/Windows/ProcessWindows.h b/lldb/source/Plugins/Process/Windows/ProcessWindows.h index b370a4007a2..986bab39c11 100644 --- a/lldb/source/Plugins/Process/Windows/ProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/ProcessWindows.h @@ -30,6 +30,7 @@ class ProcessMonitor; namespace lldb_private { +class HostProcess; class ProcessWindowsData; } @@ -77,11 +78,14 @@ public: lldb_private::Error DoDetach(bool keep_stopped) override; lldb_private::Error DoLaunch(lldb_private::Module *exe_module, lldb_private::ProcessLaunchInfo &launch_info) override; + lldb_private::Error DoAttachToProcessWithID(lldb::pid_t pid, + const lldb_private::ProcessAttachInfo &attach_info) override; lldb_private::Error DoResume() override; lldb_private::Error DoDestroy() override; lldb_private::Error DoHalt(bool &caused_stop) override; void DidLaunch() override; + void DidAttach(lldb_private::ArchSpec &arch_spec) override; void RefreshStateAfterStop() override; lldb::addr_t GetImageInfoAddress() override; @@ -116,6 +120,9 @@ public: void OnDebuggerError(const lldb_private::Error &error, uint32_t type) override; private: + lldb_private::Error WaitForDebuggerConnection(lldb_private::DebuggerThreadSP debugger, + lldb_private::HostProcess &process); + llvm::sys::Mutex m_mutex; // Data for the active debugging session. |