Index: lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.cpp +++ lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.cpp @@ -13,6 +13,8 @@ #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Host/FileSpec.h" #include "lldb/Host/Predicate.h" #include "lldb/Host/ThisThread.h" #include "lldb/Host/ThreadLauncher.h" @@ -21,6 +23,7 @@ #include "lldb/Host/windows/ProcessLauncherWindows.h" #include "lldb/Target/ProcessLaunchInfo.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/raw_ostream.h" using namespace lldb; @@ -185,7 +188,8 @@ ((HostThreadWindows &)m_main_thread.GetNativeThread()).SetOwnsHandle(false); m_image_file = info.hFile; - m_debug_delegate->OnDebuggerConnected(); + lldb::addr_t load_addr = reinterpret_cast(info.lpBaseOfImage); + m_debug_delegate->OnDebuggerConnected(load_addr); return DBG_CONTINUE; } @@ -211,7 +215,33 @@ DWORD DebuggerThread::HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, DWORD thread_id) { - // Windows does not automatically close info.hFile when the DLL is unloaded. + if (info.hFile == nullptr) + { + // Not sure what this is, so just ignore it. + return DBG_CONTINUE; + } + + std::vector buffer(1); + DWORD required_size = GetFinalPathNameByHandle(info.hFile, &buffer[0], 0, VOLUME_NAME_DOS); + if (required_size > 0) + { + buffer.resize(required_size + 1); + required_size = GetFinalPathNameByHandle(info.hFile, &buffer[0], required_size + 1, VOLUME_NAME_DOS); + llvm::StringRef path_str(&buffer[0]); + const char *path = path_str.data(); + if (path_str.startswith("\\\\?\\")) + path += 4; + + FileSpec file_spec(path, false); + ModuleSpec module_spec(file_spec); + lldb::addr_t load_addr = reinterpret_cast(info.lpBaseOfDll); + m_debug_delegate->OnLoadDll(module_spec, load_addr); + } + else + { + // An unknown error occurred getting the path name. + } + // Windows does not automatically close info.hFile, so we need to do it. ::CloseHandle(info.hFile); return DBG_CONTINUE; } @@ -219,6 +249,7 @@ DWORD DebuggerThread::HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info, DWORD thread_id) { + m_debug_delegate->OnUnloadDll(reinterpret_cast(info.lpBaseOfDll)); return DBG_CONTINUE; } Index: lldb/trunk/source/Plugins/Process/Windows/IDebugDelegate.h =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/IDebugDelegate.h +++ lldb/trunk/source/Plugins/Process/Windows/IDebugDelegate.h @@ -11,6 +11,8 @@ #define liblldb_Plugins_Process_Windows_IDebugDelegate_H_ #include "ForwardDecl.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-types.h" #include namespace lldb_private @@ -30,12 +32,12 @@ virtual ~IDebugDelegate() {} virtual void OnExitProcess(uint32_t exit_code) = 0; - virtual void OnDebuggerConnected() = 0; + virtual void OnDebuggerConnected(lldb::addr_t image_base) = 0; virtual ExceptionResult OnDebugException(bool first_chance, const ExceptionRecord &record) = 0; virtual void OnCreateThread(const HostThread &thread) = 0; virtual void OnExitThread(const HostThread &thread) = 0; - virtual void OnLoadDll() = 0; - virtual void OnUnloadDll() = 0; + virtual void OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr) = 0; + virtual void OnUnloadDll(lldb::addr_t module_addr) = 0; virtual void OnDebugString(const std::string &string) = 0; virtual void OnDebuggerError(const Error &error, uint32_t type) = 0; }; Index: lldb/trunk/source/Plugins/Process/Windows/LocalDebugDelegate.h =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/LocalDebugDelegate.h +++ lldb/trunk/source/Plugins/Process/Windows/LocalDebugDelegate.h @@ -43,12 +43,12 @@ explicit LocalDebugDelegate::LocalDebugDelegate(lldb::ProcessSP process); virtual void OnExitProcess(uint32_t exit_code) override; - virtual void OnDebuggerConnected() override; + virtual void OnDebuggerConnected(lldb::addr_t image_base) override; virtual ExceptionResult OnDebugException(bool first_chance, const ExceptionRecord &record) override; virtual void OnCreateThread(const HostThread &thread) override; virtual void OnExitThread(const HostThread &thread) override; - virtual void OnLoadDll() override; - virtual void OnUnloadDll() override; + virtual void OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr) override; + virtual void OnUnloadDll(lldb::addr_t module_addr) override; virtual void OnDebugString(const std::string &message) override; virtual void OnDebuggerError(const Error &error, uint32_t type) override; Index: lldb/trunk/source/Plugins/Process/Windows/LocalDebugDelegate.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/LocalDebugDelegate.cpp +++ lldb/trunk/source/Plugins/Process/Windows/LocalDebugDelegate.cpp @@ -25,9 +25,9 @@ } void -LocalDebugDelegate::OnDebuggerConnected() +LocalDebugDelegate::OnDebuggerConnected(lldb::addr_t image_base) { - ((ProcessWindows &)*m_process).OnDebuggerConnected(); + ((ProcessWindows &)*m_process).OnDebuggerConnected(image_base); } ExceptionResult @@ -49,15 +49,15 @@ } void -LocalDebugDelegate::OnLoadDll() +LocalDebugDelegate::OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr) { - ((ProcessWindows &)*m_process).OnLoadDll(); + ((ProcessWindows &)*m_process).OnLoadDll(module_spec, module_addr); } void -LocalDebugDelegate::OnUnloadDll() +LocalDebugDelegate::OnUnloadDll(lldb::addr_t module_addr) { - ((ProcessWindows &)*m_process).OnUnloadDll(); + ((ProcessWindows &)*m_process).OnUnloadDll(module_addr); } void Index: lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.h =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.h +++ lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.h @@ -20,6 +20,7 @@ // Other libraries and framework includes #include "ForwardDecl.h" #include "IDebugDelegate.h" +#include "lldb/lldb-forward.h" #include "lldb/Core/Error.h" #include "lldb/Host/HostThread.h" #include "lldb/Target/Process.h" @@ -28,7 +29,6 @@ namespace lldb_private { -class HostProcess; class ProcessWindowsData; } @@ -116,20 +116,18 @@ // IDebugDelegate overrides. virtual void OnExitProcess(uint32_t exit_code) override; - virtual void OnDebuggerConnected() override; + virtual void OnDebuggerConnected(lldb::addr_t image_base) override; virtual ExceptionResult OnDebugException(bool first_chance, const lldb_private::ExceptionRecord &record) override; virtual void OnCreateThread(const lldb_private::HostThread &thread) override; virtual void OnExitThread(const lldb_private::HostThread &thread) override; - virtual void OnLoadDll() override; - virtual void OnUnloadDll() override; + virtual void OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr) override; + virtual void OnUnloadDll(lldb::addr_t module_addr) override; virtual void OnDebugString(const std::string &string) override; virtual void OnDebuggerError(const lldb_private::Error &error, uint32_t type) override; private: - std::shared_ptr m_active_exception; - std::unique_ptr m_data_up; - lldb_private::Error m_launch_error; - lldb_private::DebuggerThreadSP m_debugger; + // Data for the active debugging session. + std::unique_ptr m_session_data; }; #endif // liblldb_Plugins_Process_Windows_ProcessWindows_H_ Index: lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp +++ lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp @@ -42,15 +42,22 @@ class ProcessWindowsData { public: - ProcessWindowsData() - : m_launched_event(nullptr) + ProcessWindowsData(const ProcessLaunchInfo &launch_info) + : m_initial_stop_event(nullptr) + , m_launch_info(launch_info) + , m_initial_stop_received(false) { - m_launched_event = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); + m_initial_stop_event = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); } - ~ProcessWindowsData() { ::CloseHandle(m_launched_event); } + ~ProcessWindowsData() { ::CloseHandle(m_initial_stop_event); } - HANDLE m_launched_event; + ProcessLaunchInfo m_launch_info; + std::shared_ptr m_active_exception; + lldb_private::Error m_launch_error; + lldb_private::DebuggerThreadSP m_debugger; + HANDLE m_initial_stop_event; + bool m_initial_stop_received; }; } //------------------------------------------------------------------------------ @@ -81,7 +88,6 @@ ProcessWindows::ProcessWindows(Target &target, Listener &listener) : lldb_private::Process(target, listener) - , m_data_up(new ProcessWindowsData()) { } @@ -120,28 +126,36 @@ ProcessLaunchInfo &launch_info) { Error result; - HostProcess process; + if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) + { + result.SetErrorString("ProcessWindows can only be used to launch processes for debugging."); + return result; + } + + m_session_data.reset(new ProcessWindowsData(launch_info)); + SetPrivateState(eStateLaunching); - if (launch_info.GetFlags().Test(eLaunchFlagDebug)) + DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); + m_session_data->m_debugger.reset(new DebuggerThread(delegate)); + DebuggerThreadSP debugger = m_session_data->m_debugger; + + // Kick off the DebugLaunch asynchronously and wait for it to complete. + result = debugger->DebugLaunch(launch_info); + + HostProcess process; + if (result.Success()) { - DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); - m_debugger.reset(new DebuggerThread(delegate)); - // Kick off the DebugLaunch asynchronously and wait for it to complete. - result = m_debugger->DebugLaunch(launch_info); - if (result.Success()) - { - if (::WaitForSingleObject(m_data_up->m_launched_event, INFINITE) == WAIT_OBJECT_0) - process = m_debugger->GetProcess(); - else - result.SetError(::GetLastError(), eErrorTypeWin32); - } + if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) == WAIT_OBJECT_0) + process = debugger->GetProcess(); + else + result.SetError(::GetLastError(), eErrorTypeWin32); } - else - return Host::LaunchProcess(launch_info); if (!result.Success()) 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. launch_info.SetProcessID(process.GetProcessId()); SetID(process.GetProcessId()); @@ -152,11 +166,17 @@ ProcessWindows::DoResume() { Error error; - if (!m_active_exception) - return error; + if (GetPrivateState() == eStateStopped) + { + if (m_session_data->m_active_exception) + { + // Resume the process and continue processing debug events. + m_session_data->m_active_exception.reset(); + m_session_data->m_debugger->ContinueAsyncException(ExceptionResult::Handled); + } - m_debugger->ContinueAsyncException(ExceptionResult::Handled); - SetPrivateState(eStateRunning); + SetPrivateState(eStateRunning); + } return error; } @@ -197,7 +217,6 @@ ProcessWindows::DoDetach(bool keep_stopped) { Error error; - error.SetErrorString("Detaching from processes is not currently supported on Windows."); return error; } @@ -205,7 +224,11 @@ ProcessWindows::DoDestroy() { Error error; - error.SetErrorString("Destroying processes is not currently supported on Windows."); + if (GetPrivateState() != eStateExited && GetPrivateState() != eStateDetached) + { + DebugActiveProcessStop(m_session_data->m_debugger->GetProcess().GetProcessId()); + SetPrivateState(eStateExited); + } return error; } @@ -217,7 +240,18 @@ bool ProcessWindows::IsAlive() { - return false; + StateType state = GetPrivateState(); + switch (state) + { + case eStateCrashed: + case eStateDetached: + case eStateUnloaded: + case eStateExited: + case eStateInvalid: + return false; + default: + return true; + } } size_t @@ -250,23 +284,55 @@ } void -ProcessWindows::OnDebuggerConnected() +ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) { - ::SetEvent(m_data_up->m_launched_event); + ModuleSP module = GetTarget().GetExecutableModule(); + bool load_addr_changed; + module->SetLoadAddress(GetTarget(), image_base, false, load_addr_changed); } ExceptionResult ProcessWindows::OnDebugException(bool first_chance, const ExceptionRecord &record) { - ExceptionResult result = ExceptionResult::Handled; - m_active_exception.reset(new ExceptionRecord(record)); + ExceptionResult result = ExceptionResult::NotHandled; + m_session_data->m_active_exception.reset(new ExceptionRecord(record)); switch (record.GetExceptionCode()) { case EXCEPTION_BREAKPOINT: - SetPrivateState(eStateStopped); + // Handle breakpoints at the first chance. result = ExceptionResult::WillHandle; + + if (!m_session_data->m_initial_stop_received) + { + m_session_data->m_initial_stop_received = true; + ::SetEvent(m_session_data->m_initial_stop_event); + } break; + default: + // For non-breakpoints, give the application a chance to handle the exception first. + if (first_chance) + result = ExceptionResult::NotHandled; + else + result = ExceptionResult::WillHandle; } + + if (!first_chance) + { + // Any second chance exception is an application crash by definition. + SetPrivateState(eStateCrashed); + } + else if (result == ExceptionResult::WillHandle) + { + // For first chance exceptions that we can handle, the process is stopped so the user + // can inspect / manipulate the state of the process in the debugger. + SetPrivateState(eStateStopped); + } + else + { + // For first chance exceptions that we either eat or send back to the application, don't + // modify the state of the application. + } + return result; } @@ -281,13 +347,21 @@ } void -ProcessWindows::OnLoadDll() +ProcessWindows::OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr) { + // Confusingly, there is no Target::AddSharedModule. Instead, calling GetSharedModule() with + // a new module will add it to the module list and return a corresponding ModuleSP. + Error error; + ModuleSP module = GetTarget().GetSharedModule(module_spec, &error); + bool load_addr_changed = false; + module->SetLoadAddress(GetTarget(), module_addr, false, load_addr_changed); } void -ProcessWindows::OnUnloadDll() +ProcessWindows::OnUnloadDll(lldb::addr_t module_addr) { + // TODO: Figure out how to get the ModuleSP loaded at the specified address and remove + // it from the target's module list. } void @@ -298,16 +372,15 @@ void ProcessWindows::OnDebuggerError(const Error &error, uint32_t type) { - DWORD result = ::WaitForSingleObject(m_data_up->m_launched_event, 0); - if (result == WAIT_TIMEOUT) + if (!m_session_data->m_initial_stop_received) { // If we haven't actually launched the process yet, this was an error // launching the process. Set the internal error and signal. - m_launch_error = error; - ::SetEvent(m_data_up->m_launched_event); + m_session_data->m_launch_error = error; + ::SetEvent(m_session_data->m_initial_stop_event); return; } - // This happened while debugging. - // TODO: Implement this. + // This happened while debugging. Do we shutdown the debugging session, try to continue, + // or do something else? }