[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:
Zachary Turner 2014-11-11 00:00:14 +00:00
parent 6cc5f73e38
commit dcd80377f3
10 changed files with 173 additions and 11 deletions

View File

@ -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

View File

@ -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);
};

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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:

View File

@ -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

View File

@ -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;