summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/Windows/ProcessWindows.cpp
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2015-05-20 18:31:17 +0000
committerZachary Turner <zturner@google.com>2015-05-20 18:31:17 +0000
commitc62733b0debd510b7926baf2090bd9e2ff9f3dad (patch)
treed881f88f780cdc8448bc137e99b9f3056aa41e0a /lldb/source/Plugins/Process/Windows/ProcessWindows.cpp
parentfd28abcf15b433a4e36cee68a2f4bf7db6ce52a9 (diff)
downloadbcm5719-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/Windows/ProcessWindows.cpp')
-rw-r--r--lldb/source/Plugins/Process/Windows/ProcessWindows.cpp139
1 files changed, 102 insertions, 37 deletions
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:
OpenPOWER on IntegriCloud