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 "ExceptionRecord.h"
|
||||
#include "IDebugDelegate.h"
|
||||
#include "ProcessMessages.h"
|
||||
|
||||
|
@ -97,6 +98,12 @@ DebuggerThread::DebuggerThreadRoutine(const ProcessLaunchInfo &launch_info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
DebuggerThread::ContinueAsyncException(ExceptionResult result)
|
||||
{
|
||||
m_exception.SetValue(result, eBroadcastAlways);
|
||||
}
|
||||
|
||||
void
|
||||
DebuggerThread::DebugLoop()
|
||||
{
|
||||
|
@ -108,8 +115,17 @@ DebuggerThread::DebugLoop()
|
|||
switch (dbe.dwDebugEventCode)
|
||||
{
|
||||
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;
|
||||
}
|
||||
case CREATE_THREAD_DEBUG_EVENT:
|
||||
continue_status = HandleCreateThreadEvent(dbe.u.CreateThread, dbe.dwThreadId);
|
||||
break;
|
||||
|
@ -143,10 +159,12 @@ DebuggerThread::DebugLoop()
|
|||
}
|
||||
}
|
||||
|
||||
DWORD
|
||||
ExceptionResult
|
||||
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
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "ForwardDecl.h"
|
||||
#include "lldb/Host/HostProcess.h"
|
||||
#include "lldb/Host/HostThread.h"
|
||||
#include "lldb/Host/Predicate.h"
|
||||
#include "lldb/Host/windows/windows.h"
|
||||
|
||||
#include <memory>
|
||||
|
@ -45,9 +46,11 @@ class DebuggerThread : public std::enable_shared_from_this<DebuggerThread>
|
|||
return m_main_thread;
|
||||
}
|
||||
|
||||
void ContinueAsyncException(ExceptionResult result);
|
||||
|
||||
private:
|
||||
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 HandleCreateProcessEvent(const CREATE_PROCESS_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.
|
||||
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);
|
||||
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>
|
||||
|
||||
// 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
|
||||
{
|
||||
class IDebugDelegate;
|
||||
|
||||
class IDebugDelegate;
|
||||
class DebuggerThread;
|
||||
|
||||
class ExceptionRecord;
|
||||
|
||||
// Process message forward declarations.
|
||||
class ProcessMessageBase;
|
||||
class ProcessMessageExitProcess;
|
||||
|
|
|
@ -28,7 +28,7 @@ class IDebugDelegate
|
|||
|
||||
virtual void OnExitProcess(const ProcessMessageExitProcess &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 OnExitThread(const ProcessMessageExitThread &message) = 0;
|
||||
virtual void OnLoadDll(const ProcessMessageLoadDll &message) = 0;
|
||||
|
|
|
@ -30,10 +30,10 @@ LocalDebugDelegate::OnDebuggerConnected(const ProcessMessageDebuggerConnected &m
|
|||
((ProcessWindows &)*m_process).OnDebuggerConnected(message);
|
||||
}
|
||||
|
||||
void
|
||||
ExceptionResult
|
||||
LocalDebugDelegate::OnDebugException(const ProcessMessageException &message)
|
||||
{
|
||||
((ProcessWindows &)*m_process).OnDebugException(message);
|
||||
return ((ProcessWindows &)*m_process).OnDebugException(message);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -44,7 +44,7 @@ class LocalDebugDelegate : public IDebugDelegate
|
|||
|
||||
void OnExitProcess(const ProcessMessageExitProcess &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 OnExitThread(const ProcessMessageExitThread &message) override;
|
||||
void OnLoadDll(const ProcessMessageLoadDll &message) override;
|
||||
|
|
|
@ -10,9 +10,13 @@
|
|||
#ifndef liblldb_Plugins_Process_Windows_ProcessMessages_H_
|
||||
#define liblldb_Plugins_Process_Windows_ProcessMessages_H_
|
||||
|
||||
#include "ExceptionRecord.h"
|
||||
|
||||
#include "lldb/Core/Error.h"
|
||||
#include "lldb/Host/HostProcess.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
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
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "lldb/Target/Target.h"
|
||||
|
||||
#include "DebuggerThread.h"
|
||||
#include "ExceptionRecord.h"
|
||||
#include "LocalDebugDelegate.h"
|
||||
#include "ProcessMessages.h"
|
||||
#include "ProcessWindows.h"
|
||||
|
@ -144,6 +145,7 @@ ProcessWindows::DoLaunch(Module *exe_module,
|
|||
|
||||
launch_info.SetProcessID(process.GetProcessId());
|
||||
SetID(process.GetProcessId());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -151,6 +153,11 @@ Error
|
|||
ProcessWindows::DoResume()
|
||||
{
|
||||
Error error;
|
||||
if (!m_active_exception)
|
||||
return error;
|
||||
|
||||
m_debugger->ContinueAsyncException(ExceptionResult::Handled);
|
||||
SetPrivateState(eStateRunning);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -240,6 +247,7 @@ void
|
|||
ProcessWindows::OnExitProcess(const ProcessMessageExitProcess &message)
|
||||
{
|
||||
SetProcessExitStatus(nullptr, GetID(), true, 0, message.GetExitCode());
|
||||
SetPrivateState(eStateExited);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -248,9 +256,20 @@ ProcessWindows::OnDebuggerConnected(const ProcessMessageDebuggerConnected &messa
|
|||
::SetEvent(m_data_up->m_launched_event);
|
||||
}
|
||||
|
||||
void
|
||||
ExceptionResult
|
||||
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
|
||||
|
|
|
@ -117,7 +117,7 @@ public:
|
|||
// IDebugDelegate overrides.
|
||||
virtual void OnExitProcess(const lldb_private::ProcessMessageExitProcess &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 OnExitThread(const lldb_private::ProcessMessageExitThread &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;
|
||||
|
||||
private:
|
||||
std::shared_ptr<lldb_private::ExceptionRecord> m_active_exception;
|
||||
std::unique_ptr<lldb_private::ProcessWindowsData> m_data_up;
|
||||
lldb_private::Error m_launch_error;
|
||||
lldb_private::DebuggerThreadSP m_debugger;
|
||||
|
|
Loading…
Reference in New Issue