forked from OSchip/llvm-project
Implement attach to process on Windows.
Differential Revision: http://reviews.llvm.org/D9801 Reviewed by: Adrian McCarthy llvm-svn: 237817
This commit is contained in:
parent
fd28abcf15
commit
c62733b0de
|
@ -526,51 +526,88 @@ PlatformWindows::LaunchProcess (ProcessLaunchInfo &launch_info)
|
|||
return error;
|
||||
}
|
||||
|
||||
ProcessSP
|
||||
PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, Target *target, Error &error)
|
||||
{
|
||||
// Windows has special considerations that must be followed when launching or attaching to a process. The
|
||||
// key requirement is that when launching or attaching to a process, you must do it from the same the thread
|
||||
// that will go into a permanent loop which will then receive debug events from the process. In particular,
|
||||
// this means we can't use any of LLDB's generic mechanisms to do it for us, because it doesn't have the
|
||||
// special knowledge required for setting up the background thread or passing the right flags.
|
||||
//
|
||||
// Another problem is that that LLDB's standard model for debugging a process is to first launch it, have
|
||||
// it stop at the entry point, and then attach to it. In Windows this doesn't quite work, you have to
|
||||
// specify as an argument to CreateProcess() that you're going to debug the process. So we override DebugProcess
|
||||
// here to handle this. Launch operations go directly to the process plugin, and attach operations almost go
|
||||
// directly to the process plugin (but we hijack the events first). In essence, we encapsulate all the logic
|
||||
// of Launching and Attaching in the process plugin, and PlatformWindows::DebugProcess is just a pass-through
|
||||
// to get to the process plugin.
|
||||
|
||||
if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
|
||||
{
|
||||
// This is a process attach. Don't need to launch anything.
|
||||
ProcessAttachInfo attach_info(launch_info);
|
||||
return Attach(attach_info, debugger, target, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessSP process_sp = target->CreateProcess(launch_info.GetListenerForProcess(debugger),
|
||||
launch_info.GetProcessPluginName(),
|
||||
nullptr);
|
||||
|
||||
// We need to launch and attach to the process.
|
||||
launch_info.GetFlags().Set(eLaunchFlagDebug);
|
||||
if (process_sp)
|
||||
error = process_sp->Launch(launch_info);
|
||||
|
||||
return process_sp;
|
||||
}
|
||||
}
|
||||
|
||||
lldb::ProcessSP
|
||||
PlatformWindows::Attach(ProcessAttachInfo &attach_info,
|
||||
Debugger &debugger,
|
||||
Target *target,
|
||||
Error &error)
|
||||
{
|
||||
error.Clear();
|
||||
lldb::ProcessSP process_sp;
|
||||
if (IsHost())
|
||||
{
|
||||
if (target == NULL)
|
||||
{
|
||||
TargetSP new_target_sp;
|
||||
FileSpec emptyFileSpec;
|
||||
ArchSpec emptyArchSpec;
|
||||
|
||||
error = debugger.GetTargetList().CreateTarget (debugger,
|
||||
NULL,
|
||||
NULL,
|
||||
false,
|
||||
NULL,
|
||||
new_target_sp);
|
||||
target = new_target_sp.get();
|
||||
}
|
||||
else
|
||||
error.Clear();
|
||||
|
||||
if (target && error.Success())
|
||||
{
|
||||
debugger.GetTargetList().SetSelectedTarget(target);
|
||||
// The Windows platform always currently uses the GDB remote debugger plug-in
|
||||
// so even when debugging locally we are debugging remotely!
|
||||
// Just like the darwin plugin.
|
||||
process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL);
|
||||
|
||||
if (process_sp)
|
||||
error = process_sp->Attach (attach_info);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!IsHost())
|
||||
{
|
||||
if (m_remote_platform_sp)
|
||||
process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error);
|
||||
else
|
||||
error.SetErrorString ("the platform is not currently connected");
|
||||
return process_sp;
|
||||
}
|
||||
|
||||
if (target == NULL)
|
||||
{
|
||||
TargetSP new_target_sp;
|
||||
FileSpec emptyFileSpec;
|
||||
ArchSpec emptyArchSpec;
|
||||
|
||||
error = debugger.GetTargetList().CreateTarget (debugger,
|
||||
NULL,
|
||||
NULL,
|
||||
false,
|
||||
NULL,
|
||||
new_target_sp);
|
||||
target = new_target_sp.get();
|
||||
}
|
||||
|
||||
if (!target || error.Fail())
|
||||
return process_sp;
|
||||
|
||||
debugger.GetTargetList().SetSelectedTarget(target);
|
||||
|
||||
const char *plugin_name = attach_info.GetProcessPluginName();
|
||||
process_sp = target->CreateProcess(attach_info.GetListenerForProcess(debugger), plugin_name, NULL);
|
||||
|
||||
process_sp->HijackProcessEvents(attach_info.GetHijackListener().get());
|
||||
if (process_sp)
|
||||
error = process_sp->Attach (attach_info);
|
||||
|
||||
return process_sp;
|
||||
}
|
||||
|
||||
|
@ -687,3 +724,9 @@ PlatformWindows::GetStatus (Stream &strm)
|
|||
<< " Build: " << update << '\n';
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
PlatformWindows::CanDebugProcess()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -122,10 +122,12 @@ public:
|
|||
LaunchProcess(lldb_private::ProcessLaunchInfo &launch_info) override;
|
||||
|
||||
lldb::ProcessSP
|
||||
Attach(lldb_private::ProcessAttachInfo &attach_info,
|
||||
lldb_private::Debugger &debugger,
|
||||
lldb_private::Target *target,
|
||||
lldb_private::Error &error) override;
|
||||
DebugProcess(lldb_private::ProcessLaunchInfo &launch_info, lldb_private::Debugger &debugger,
|
||||
lldb_private::Target *target, lldb_private::Error &error) override;
|
||||
|
||||
lldb::ProcessSP
|
||||
Attach(lldb_private::ProcessAttachInfo &attach_info, lldb_private::Debugger &debugger,
|
||||
lldb_private::Target *target, lldb_private::Error &error) override;
|
||||
|
||||
lldb_private::Error
|
||||
GetFileWithUUID(const lldb_private::FileSpec &platform_file,
|
||||
|
@ -145,12 +147,7 @@ public:
|
|||
void
|
||||
GetStatus(lldb_private::Stream &strm) override;
|
||||
|
||||
// Local debugging not yet supported
|
||||
bool
|
||||
CanDebugProcess(void) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool CanDebugProcess() override;
|
||||
|
||||
// FIXME not sure what the _sigtramp equivalent would be on this platform
|
||||
void
|
||||
|
|
|
@ -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::DebuggerThreadRoutine(const ProcessLaunchInfo &launch_info)
|
||||
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::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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,44 +267,94 @@ ProcessWindows::DoLaunch(Module *exe_module,
|
|||
|
||||
// Kick off the DebugLaunch asynchronously and wait for it to complete.
|
||||
result = debugger->DebugLaunch(launch_info);
|
||||
|
||||
HostProcess process;
|
||||
if (result.Success())
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if (result.Success())
|
||||
{
|
||||
WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch successfully launched '%s'",
|
||||
launch_info.GetExecutableFile().GetPath().c_str());
|
||||
}
|
||||
else
|
||||
if (result.Fail())
|
||||
{
|
||||
WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s",
|
||||
launch_info.GetExecutableFile().GetPath().c_str(), result.AsCString());
|
||||
return result;
|
||||
}
|
||||
|
||||
// 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.
|
||||
HostProcess process;
|
||||
Error error = WaitForDebuggerConnection(debugger, process);
|
||||
if (error.Fail())
|
||||
{
|
||||
WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s",
|
||||
launch_info.GetExecutableFile().GetPath().c_str(), error.AsCString());
|
||||
return error;
|
||||
}
|
||||
|
||||
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,
|
||||
"DoAttachToProcessWithID encountered an error occurred initiating the asynchronous attach. %s",
|
||||
error.AsCString());
|
||||
return error;
|
||||
}
|
||||
|
||||
HostProcess process;
|
||||
error = WaitForDebuggerConnection(debugger, process);
|
||||
if (error.Fail())
|
||||
{
|
||||
WINLOG_IFALL(WINDOWS_LOG_PROCESS,
|
||||
"DoAttachToProcessWithID encountered an error waiting for the debugger to connect. %s",
|
||||
error.AsCString());
|
||||
return error;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
ProcessWindows::DoResume()
|
||||
{
|
||||
|
@ -520,12 +571,17 @@ 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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -3336,6 +3336,9 @@ Process::AttachCompletionHandler::PerformAction (lldb::EventSP &event_sp)
|
|||
|
||||
switch (state)
|
||||
{
|
||||
case eStateAttaching:
|
||||
return eEventActionSuccess;
|
||||
|
||||
case eStateRunning:
|
||||
case eStateConnected:
|
||||
return eEventActionRetry;
|
||||
|
@ -4457,7 +4460,8 @@ Process::HandlePrivateEvent (EventSP &event_sp)
|
|||
// Only push the input handler if we aren't fowarding events,
|
||||
// as this means the curses GUI is in use...
|
||||
// Or don't push it if we are launching since it will come up stopped.
|
||||
if (!GetTarget().GetDebugger().IsForwardingEvents() && new_state != eStateLaunching)
|
||||
if (!GetTarget().GetDebugger().IsForwardingEvents() && new_state != eStateLaunching &&
|
||||
new_state != eStateAttaching)
|
||||
PushProcessIOHandler ();
|
||||
m_iohandler_sync.SetValue(true, eBroadcastAlways);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue