[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 "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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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