forked from OSchip/llvm-project
[ProcessWindows] Implement breakpoint stop / resume on Windows.
This patch implements basic support for stopping at breakpoints and resuming later. While a breakpoint is stopped at, LLDB will cease to process events in the debug loop, effectively suspending the process, and then resume later when ProcessWindows::DoResume is called. As a side effect, this also correctly handles the loader breakpoint (i.e. the initial stop) so that LLDB goes through the correct state sequence during the initial process launch. llvm-svn: 221642
This commit is contained in:
parent
6cc5f73e38
commit
dcd80377f3
|
@ -8,6 +8,7 @@
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "DebuggerThread.h"
|
#include "DebuggerThread.h"
|
||||||
|
#include "ExceptionRecord.h"
|
||||||
#include "IDebugDelegate.h"
|
#include "IDebugDelegate.h"
|
||||||
#include "ProcessMessages.h"
|
#include "ProcessMessages.h"
|
||||||
|
|
||||||
|
@ -97,6 +98,12 @@ DebuggerThread::DebuggerThreadRoutine(const ProcessLaunchInfo &launch_info)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DebuggerThread::ContinueAsyncException(ExceptionResult result)
|
||||||
|
{
|
||||||
|
m_exception.SetValue(result, eBroadcastAlways);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DebuggerThread::DebugLoop()
|
DebuggerThread::DebugLoop()
|
||||||
{
|
{
|
||||||
|
@ -108,8 +115,17 @@ DebuggerThread::DebugLoop()
|
||||||
switch (dbe.dwDebugEventCode)
|
switch (dbe.dwDebugEventCode)
|
||||||
{
|
{
|
||||||
case EXCEPTION_DEBUG_EVENT:
|
case EXCEPTION_DEBUG_EVENT:
|
||||||
continue_status = HandleExceptionEvent(dbe.u.Exception, dbe.dwThreadId);
|
{
|
||||||
|
ExceptionResult status = HandleExceptionEvent(dbe.u.Exception, dbe.dwThreadId);
|
||||||
|
m_exception.SetValue(status, eBroadcastNever);
|
||||||
|
m_exception.WaitForValueNotEqualTo(ExceptionResult::WillHandle, status);
|
||||||
|
|
||||||
|
if (status == ExceptionResult::Handled)
|
||||||
|
continue_status = DBG_CONTINUE;
|
||||||
|
else if (status == ExceptionResult::NotHandled)
|
||||||
|
continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case CREATE_THREAD_DEBUG_EVENT:
|
case CREATE_THREAD_DEBUG_EVENT:
|
||||||
continue_status = HandleCreateThreadEvent(dbe.u.CreateThread, dbe.dwThreadId);
|
continue_status = HandleCreateThreadEvent(dbe.u.CreateThread, dbe.dwThreadId);
|
||||||
break;
|
break;
|
||||||
|
@ -143,10 +159,12 @@ DebuggerThread::DebugLoop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD
|
ExceptionResult
|
||||||
DebuggerThread::HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, DWORD thread_id)
|
DebuggerThread::HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, DWORD thread_id)
|
||||||
{
|
{
|
||||||
return DBG_CONTINUE;
|
bool first_chance = (info.dwFirstChance != 0);
|
||||||
|
ProcessMessageException message(m_process, ExceptionRecord(info.ExceptionRecord), first_chance);
|
||||||
|
return m_debug_delegate->OnDebugException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD
|
DWORD
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "ForwardDecl.h"
|
#include "ForwardDecl.h"
|
||||||
#include "lldb/Host/HostProcess.h"
|
#include "lldb/Host/HostProcess.h"
|
||||||
#include "lldb/Host/HostThread.h"
|
#include "lldb/Host/HostThread.h"
|
||||||
|
#include "lldb/Host/Predicate.h"
|
||||||
#include "lldb/Host/windows/windows.h"
|
#include "lldb/Host/windows/windows.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -45,9 +46,11 @@ class DebuggerThread : public std::enable_shared_from_this<DebuggerThread>
|
||||||
return m_main_thread;
|
return m_main_thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ContinueAsyncException(ExceptionResult result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DebugLoop();
|
void DebugLoop();
|
||||||
DWORD HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, DWORD thread_id);
|
ExceptionResult HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, DWORD thread_id);
|
||||||
DWORD HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, DWORD thread_id);
|
DWORD HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, DWORD thread_id);
|
||||||
DWORD HandleCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO &info, DWORD thread_id);
|
DWORD HandleCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO &info, DWORD thread_id);
|
||||||
DWORD HandleExitThreadEvent(const EXIT_THREAD_DEBUG_INFO &info, DWORD thread_id);
|
DWORD HandleExitThreadEvent(const EXIT_THREAD_DEBUG_INFO &info, DWORD thread_id);
|
||||||
|
@ -63,6 +66,10 @@ class DebuggerThread : public std::enable_shared_from_this<DebuggerThread>
|
||||||
HostThread m_main_thread; // The main thread of the inferior.
|
HostThread m_main_thread; // The main thread of the inferior.
|
||||||
HANDLE m_image_file; // The image file of the process being debugged.
|
HANDLE m_image_file; // The image file of the process being debugged.
|
||||||
|
|
||||||
|
Predicate<ExceptionResult> m_exception; // A predicate which gets signalled when an exception
|
||||||
|
// is finished processing and the debug loop can be
|
||||||
|
// continued.
|
||||||
|
|
||||||
static lldb::thread_result_t DebuggerThreadRoutine(void *data);
|
static lldb::thread_result_t DebuggerThreadRoutine(void *data);
|
||||||
lldb::thread_result_t DebuggerThreadRoutine(const ProcessLaunchInfo &launch_info);
|
lldb::thread_result_t DebuggerThreadRoutine(const ProcessLaunchInfo &launch_info);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
//===-- ExceptionRecord.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_Plugins_Process_Windows_ExceptionRecord_H_
|
||||||
|
#define liblldb_Plugins_Process_Windows_ExceptionRecord_H_
|
||||||
|
|
||||||
|
#include "ForwardDecl.h"
|
||||||
|
|
||||||
|
#include "lldb/lldb-forward.h"
|
||||||
|
#include "lldb/Host/windows/windows.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace lldb_private
|
||||||
|
{
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// ExceptionRecord
|
||||||
|
//
|
||||||
|
// ExceptionRecord defines an interface which allows implementors to receive
|
||||||
|
// notification of events that happen in a debugged process.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
class ExceptionRecord
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ExceptionRecord(const EXCEPTION_RECORD &record)
|
||||||
|
{
|
||||||
|
m_code = record.ExceptionCode;
|
||||||
|
m_continuable = (record.ExceptionFlags == 0);
|
||||||
|
if (record.ExceptionRecord)
|
||||||
|
m_next_exception.reset(new ExceptionRecord(*record.ExceptionRecord));
|
||||||
|
m_exception_addr = reinterpret_cast<lldb::addr_t>(record.ExceptionAddress);
|
||||||
|
m_arguments.assign(record.ExceptionInformation, record.ExceptionInformation + record.NumberParameters);
|
||||||
|
}
|
||||||
|
virtual ~ExceptionRecord() {}
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
GetExceptionCode() const
|
||||||
|
{
|
||||||
|
return m_code;
|
||||||
|
}
|
||||||
|
bool
|
||||||
|
IsContinuable() const
|
||||||
|
{
|
||||||
|
return m_continuable;
|
||||||
|
}
|
||||||
|
const ExceptionRecord *
|
||||||
|
GetNextException() const
|
||||||
|
{
|
||||||
|
return m_next_exception.get();
|
||||||
|
}
|
||||||
|
lldb::addr_t
|
||||||
|
GetExceptionAddress() const
|
||||||
|
{
|
||||||
|
return m_exception_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
DWORD m_code;
|
||||||
|
bool m_continuable;
|
||||||
|
std::shared_ptr<ExceptionRecord> m_next_exception;
|
||||||
|
lldb::addr_t m_exception_addr;
|
||||||
|
std::vector<ULONG_PTR> m_arguments;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -14,12 +14,25 @@ class ProcessWindows;
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
// ExceptionResult is returned by the debug delegate to specify how it processed
|
||||||
|
// the exception.
|
||||||
|
enum class ExceptionResult
|
||||||
|
{
|
||||||
|
Handled, // The delegate handled the exception. Continue.
|
||||||
|
NotHandled, // The delegate did not handle the exception. Keep
|
||||||
|
// searching.
|
||||||
|
WillHandle // The delegate will handle the exception. Do not
|
||||||
|
// process further debug events until it finishes.
|
||||||
|
};
|
||||||
|
|
||||||
namespace lldb_private
|
namespace lldb_private
|
||||||
{
|
{
|
||||||
class IDebugDelegate;
|
|
||||||
|
|
||||||
|
class IDebugDelegate;
|
||||||
class DebuggerThread;
|
class DebuggerThread;
|
||||||
|
|
||||||
|
class ExceptionRecord;
|
||||||
|
|
||||||
// Process message forward declarations.
|
// Process message forward declarations.
|
||||||
class ProcessMessageBase;
|
class ProcessMessageBase;
|
||||||
class ProcessMessageExitProcess;
|
class ProcessMessageExitProcess;
|
||||||
|
|
|
@ -28,7 +28,7 @@ class IDebugDelegate
|
||||||
|
|
||||||
virtual void OnExitProcess(const ProcessMessageExitProcess &message) = 0;
|
virtual void OnExitProcess(const ProcessMessageExitProcess &message) = 0;
|
||||||
virtual void OnDebuggerConnected(const ProcessMessageDebuggerConnected &message) = 0;
|
virtual void OnDebuggerConnected(const ProcessMessageDebuggerConnected &message) = 0;
|
||||||
virtual void OnDebugException(const ProcessMessageException &message) = 0;
|
virtual ExceptionResult OnDebugException(const ProcessMessageException &message) = 0;
|
||||||
virtual void OnCreateThread(const ProcessMessageCreateThread &message) = 0;
|
virtual void OnCreateThread(const ProcessMessageCreateThread &message) = 0;
|
||||||
virtual void OnExitThread(const ProcessMessageExitThread &message) = 0;
|
virtual void OnExitThread(const ProcessMessageExitThread &message) = 0;
|
||||||
virtual void OnLoadDll(const ProcessMessageLoadDll &message) = 0;
|
virtual void OnLoadDll(const ProcessMessageLoadDll &message) = 0;
|
||||||
|
|
|
@ -30,10 +30,10 @@ LocalDebugDelegate::OnDebuggerConnected(const ProcessMessageDebuggerConnected &m
|
||||||
((ProcessWindows &)*m_process).OnDebuggerConnected(message);
|
((ProcessWindows &)*m_process).OnDebuggerConnected(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
ExceptionResult
|
||||||
LocalDebugDelegate::OnDebugException(const ProcessMessageException &message)
|
LocalDebugDelegate::OnDebugException(const ProcessMessageException &message)
|
||||||
{
|
{
|
||||||
((ProcessWindows &)*m_process).OnDebugException(message);
|
return ((ProcessWindows &)*m_process).OnDebugException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -44,7 +44,7 @@ class LocalDebugDelegate : public IDebugDelegate
|
||||||
|
|
||||||
void OnExitProcess(const ProcessMessageExitProcess &message) override;
|
void OnExitProcess(const ProcessMessageExitProcess &message) override;
|
||||||
void OnDebuggerConnected(const ProcessMessageDebuggerConnected &message) override;
|
void OnDebuggerConnected(const ProcessMessageDebuggerConnected &message) override;
|
||||||
void OnDebugException(const ProcessMessageException &message) override;
|
ExceptionResult OnDebugException(const ProcessMessageException &message) override;
|
||||||
void OnCreateThread(const ProcessMessageCreateThread &message) override;
|
void OnCreateThread(const ProcessMessageCreateThread &message) override;
|
||||||
void OnExitThread(const ProcessMessageExitThread &message) override;
|
void OnExitThread(const ProcessMessageExitThread &message) override;
|
||||||
void OnLoadDll(const ProcessMessageLoadDll &message) override;
|
void OnLoadDll(const ProcessMessageLoadDll &message) override;
|
||||||
|
|
|
@ -10,9 +10,13 @@
|
||||||
#ifndef liblldb_Plugins_Process_Windows_ProcessMessages_H_
|
#ifndef liblldb_Plugins_Process_Windows_ProcessMessages_H_
|
||||||
#define liblldb_Plugins_Process_Windows_ProcessMessages_H_
|
#define liblldb_Plugins_Process_Windows_ProcessMessages_H_
|
||||||
|
|
||||||
|
#include "ExceptionRecord.h"
|
||||||
|
|
||||||
#include "lldb/Core/Error.h"
|
#include "lldb/Core/Error.h"
|
||||||
#include "lldb/Host/HostProcess.h"
|
#include "lldb/Host/HostProcess.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace lldb_private
|
namespace lldb_private
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -51,6 +55,32 @@ class ProcessMessageDebuggerConnected : public ProcessMessageBase
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ProcessMessageException : public ProcessMessageBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProcessMessageException(const HostProcess &process, const ExceptionRecord &exception, bool first_chance)
|
||||||
|
: ProcessMessageBase(process)
|
||||||
|
, m_exception(exception)
|
||||||
|
, m_first_chance(first_chance)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IsFirstChance() const
|
||||||
|
{
|
||||||
|
return m_first_chance;
|
||||||
|
}
|
||||||
|
const ExceptionRecord &
|
||||||
|
GetExceptionRecord() const
|
||||||
|
{
|
||||||
|
return m_exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_first_chance;
|
||||||
|
ExceptionRecord m_exception;
|
||||||
|
};
|
||||||
|
|
||||||
class ProcessMessageExitProcess : public ProcessMessageBase
|
class ProcessMessageExitProcess : public ProcessMessageBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "lldb/Target/Target.h"
|
#include "lldb/Target/Target.h"
|
||||||
|
|
||||||
#include "DebuggerThread.h"
|
#include "DebuggerThread.h"
|
||||||
|
#include "ExceptionRecord.h"
|
||||||
#include "LocalDebugDelegate.h"
|
#include "LocalDebugDelegate.h"
|
||||||
#include "ProcessMessages.h"
|
#include "ProcessMessages.h"
|
||||||
#include "ProcessWindows.h"
|
#include "ProcessWindows.h"
|
||||||
|
@ -144,6 +145,7 @@ ProcessWindows::DoLaunch(Module *exe_module,
|
||||||
|
|
||||||
launch_info.SetProcessID(process.GetProcessId());
|
launch_info.SetProcessID(process.GetProcessId());
|
||||||
SetID(process.GetProcessId());
|
SetID(process.GetProcessId());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,6 +153,11 @@ Error
|
||||||
ProcessWindows::DoResume()
|
ProcessWindows::DoResume()
|
||||||
{
|
{
|
||||||
Error error;
|
Error error;
|
||||||
|
if (!m_active_exception)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
m_debugger->ContinueAsyncException(ExceptionResult::Handled);
|
||||||
|
SetPrivateState(eStateRunning);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,6 +247,7 @@ void
|
||||||
ProcessWindows::OnExitProcess(const ProcessMessageExitProcess &message)
|
ProcessWindows::OnExitProcess(const ProcessMessageExitProcess &message)
|
||||||
{
|
{
|
||||||
SetProcessExitStatus(nullptr, GetID(), true, 0, message.GetExitCode());
|
SetProcessExitStatus(nullptr, GetID(), true, 0, message.GetExitCode());
|
||||||
|
SetPrivateState(eStateExited);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -248,9 +256,20 @@ ProcessWindows::OnDebuggerConnected(const ProcessMessageDebuggerConnected &messa
|
||||||
::SetEvent(m_data_up->m_launched_event);
|
::SetEvent(m_data_up->m_launched_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
ExceptionResult
|
||||||
ProcessWindows::OnDebugException(const ProcessMessageException &message)
|
ProcessWindows::OnDebugException(const ProcessMessageException &message)
|
||||||
{
|
{
|
||||||
|
ExceptionResult result = ExceptionResult::Handled;
|
||||||
|
const ExceptionRecord &record = message.GetExceptionRecord();
|
||||||
|
m_active_exception.reset(new ExceptionRecord(record));
|
||||||
|
switch (record.GetExceptionCode())
|
||||||
|
{
|
||||||
|
case EXCEPTION_BREAKPOINT:
|
||||||
|
SetPrivateState(eStateStopped);
|
||||||
|
result = ExceptionResult::WillHandle;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -117,7 +117,7 @@ public:
|
||||||
// IDebugDelegate overrides.
|
// IDebugDelegate overrides.
|
||||||
virtual void OnExitProcess(const lldb_private::ProcessMessageExitProcess &message) override;
|
virtual void OnExitProcess(const lldb_private::ProcessMessageExitProcess &message) override;
|
||||||
virtual void OnDebuggerConnected(const lldb_private::ProcessMessageDebuggerConnected &message) override;
|
virtual void OnDebuggerConnected(const lldb_private::ProcessMessageDebuggerConnected &message) override;
|
||||||
virtual void OnDebugException(const lldb_private::ProcessMessageException &message) override;
|
virtual ExceptionResult OnDebugException(const lldb_private::ProcessMessageException &message) override;
|
||||||
virtual void OnCreateThread(const lldb_private::ProcessMessageCreateThread &message) override;
|
virtual void OnCreateThread(const lldb_private::ProcessMessageCreateThread &message) override;
|
||||||
virtual void OnExitThread(const lldb_private::ProcessMessageExitThread &message) override;
|
virtual void OnExitThread(const lldb_private::ProcessMessageExitThread &message) override;
|
||||||
virtual void OnLoadDll(const lldb_private::ProcessMessageLoadDll &message) override;
|
virtual void OnLoadDll(const lldb_private::ProcessMessageLoadDll &message) override;
|
||||||
|
@ -126,6 +126,7 @@ public:
|
||||||
virtual void OnDebuggerError(const lldb_private::ProcessMessageDebuggerError &message) override;
|
virtual void OnDebuggerError(const lldb_private::ProcessMessageDebuggerError &message) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::shared_ptr<lldb_private::ExceptionRecord> m_active_exception;
|
||||||
std::unique_ptr<lldb_private::ProcessWindowsData> m_data_up;
|
std::unique_ptr<lldb_private::ProcessWindowsData> m_data_up;
|
||||||
lldb_private::Error m_launch_error;
|
lldb_private::Error m_launch_error;
|
||||||
lldb_private::DebuggerThreadSP m_debugger;
|
lldb_private::DebuggerThreadSP m_debugger;
|
||||||
|
|
Loading…
Reference in New Issue