Index: source/Plugins/Process/Windows/DebuggerThread.cpp =================================================================== --- source/Plugins/Process/Windows/DebuggerThread.cpp +++ source/Plugins/Process/Windows/DebuggerThread.cpp @@ -283,9 +283,9 @@ { bool first_chance = (info.dwFirstChance != 0); - m_active_exception.reset(new ExceptionRecord(info.ExceptionRecord)); + m_active_exception.reset(new ExceptionRecord(info.ExceptionRecord, thread_id)); WINLOG_IFANY(WINDOWS_LOG_EVENT | WINDOWS_LOG_EXCEPTION, - "HandleExceptionEvent encountered %s chance exception 0x%x on thread %u", + "HandleExceptionEvent encountered %s chance exception 0x%x on thread 0x%x", first_chance ? "first" : "second", info.ExceptionRecord.ExceptionCode, thread_id); ExceptionResult result = m_debug_delegate->OnDebugException(first_chance, @@ -308,9 +308,11 @@ DebuggerThread::HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, DWORD thread_id) { WINLOG_IFANY(WINDOWS_LOG_EVENT|WINDOWS_LOG_THREAD, - "HandleCreateThreadEvent Thread %u spawned in process %I64u", - m_process.GetProcessId(), thread_id); - + "HandleCreateThreadEvent Thread 0x%x spawned in process %I64u", + thread_id, m_process.GetProcessId()); + HostThread thread(info.hThread); + thread.GetNativeThread().SetOwnsHandle(false); + m_debug_delegate->OnCreateThread(thread); return DBG_CONTINUE; } @@ -347,7 +349,7 @@ WINLOG_IFANY(WINDOWS_LOG_EVENT|WINDOWS_LOG_THREAD, "HandleExitThreadEvent Thread %u exited with code %u in process %I64u", thread_id, info.dwExitCode, m_process.GetProcessId()); - + m_debug_delegate->OnExitThread(thread_id, info.dwExitCode); return DBG_CONTINUE; } @@ -358,9 +360,9 @@ "HandleExitProcessEvent process %I64u exited with code %u", m_process.GetProcessId(), info.dwExitCode); - FreeProcessHandles(); - m_debug_delegate->OnExitProcess(info.dwExitCode); + + FreeProcessHandles(); return DBG_CONTINUE; } Index: source/Plugins/Process/Windows/ExceptionRecord.h =================================================================== --- source/Plugins/Process/Windows/ExceptionRecord.h +++ source/Plugins/Process/Windows/ExceptionRecord.h @@ -30,13 +30,14 @@ class ExceptionRecord { public: - explicit ExceptionRecord(const EXCEPTION_RECORD &record) + ExceptionRecord(const EXCEPTION_RECORD &record, lldb::tid_t thread_id) { m_code = record.ExceptionCode; m_continuable = (record.ExceptionFlags == 0); if (record.ExceptionRecord) - m_next_exception.reset(new ExceptionRecord(*record.ExceptionRecord)); + m_next_exception.reset(new ExceptionRecord(*record.ExceptionRecord, thread_id)); m_exception_addr = reinterpret_cast(record.ExceptionAddress); + m_thread_id = thread_id; m_arguments.assign(record.ExceptionInformation, record.ExceptionInformation + record.NumberParameters); } virtual ~ExceptionRecord() {} @@ -62,11 +63,18 @@ return m_exception_addr; } + lldb::tid_t + GetThreadID() const + { + return m_thread_id; + } + private: DWORD m_code; bool m_continuable; std::shared_ptr m_next_exception; lldb::addr_t m_exception_addr; + lldb::tid_t m_thread_id; std::vector m_arguments; }; } Index: source/Plugins/Process/Windows/IDebugDelegate.h =================================================================== --- source/Plugins/Process/Windows/IDebugDelegate.h +++ source/Plugins/Process/Windows/IDebugDelegate.h @@ -35,7 +35,7 @@ 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 OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) = 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; Index: source/Plugins/Process/Windows/LocalDebugDelegate.h =================================================================== --- source/Plugins/Process/Windows/LocalDebugDelegate.h +++ source/Plugins/Process/Windows/LocalDebugDelegate.h @@ -46,7 +46,7 @@ void OnDebuggerConnected(lldb::addr_t image_base) override; ExceptionResult OnDebugException(bool first_chance, const ExceptionRecord &record) override; void OnCreateThread(const HostThread &thread) override; - void OnExitThread(const HostThread &thread) override; + void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; void OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr) override; void OnUnloadDll(lldb::addr_t module_addr) override; void OnDebugString(const std::string &message) override; Index: source/Plugins/Process/Windows/LocalDebugDelegate.cpp =================================================================== --- source/Plugins/Process/Windows/LocalDebugDelegate.cpp +++ source/Plugins/Process/Windows/LocalDebugDelegate.cpp @@ -43,9 +43,9 @@ } void -LocalDebugDelegate::OnExitThread(const HostThread &thread) +LocalDebugDelegate::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) { - ((ProcessWindows &)*m_process).OnExitThread(thread); + ((ProcessWindows &)*m_process).OnExitThread(thread_id, exit_code); } void Index: source/Plugins/Process/Windows/ProcessWindows.h =================================================================== --- source/Plugins/Process/Windows/ProcessWindows.h +++ source/Plugins/Process/Windows/ProcessWindows.h @@ -109,7 +109,7 @@ void OnDebuggerConnected(lldb::addr_t image_base) override; ExceptionResult OnDebugException(bool first_chance, const lldb_private::ExceptionRecord &record) override; void OnCreateThread(const lldb_private::HostThread &thread) override; - void OnExitThread(const lldb_private::HostThread &thread) override; + void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; void OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr) override; void OnUnloadDll(lldb::addr_t module_addr) override; void OnDebugString(const std::string &string) override; Index: source/Plugins/Process/Windows/ProcessWindows.cpp =================================================================== --- source/Plugins/Process/Windows/ProcessWindows.cpp +++ source/Plugins/Process/Windows/ProcessWindows.cpp @@ -13,6 +13,7 @@ // C++ Includes #include #include +#include #include // Other libraries and framework includes @@ -78,7 +79,7 @@ HANDLE m_initial_stop_event; bool m_initial_stop_received; std::map m_new_threads; - std::map m_exited_threads; + std::set m_exited_threads; }; } //------------------------------------------------------------------------------ @@ -425,11 +426,11 @@ } StopInfoSP stop_info; + m_thread_list.SetSelectedThreadByID(active_exception->GetThreadID()); ThreadSP stop_thread = m_thread_list.GetSelectedThread(); RegisterContextSP register_context = stop_thread->GetRegisterContext(); // The current EIP is AFTER the BP opcode, which is one byte. - // TODO(zturner): Can't we just use active_exception->GetExceptionAddress()? uint64_t pc = register_context->GetPC() - 1; if (active_exception->GetExceptionCode() == EXCEPTION_BREAKPOINT) { @@ -445,7 +446,8 @@ if (site->ValidForThisThread(stop_thread.get())) { WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, - "Breakpoint site %d is valid for this thread, creating stop info.", site->GetID()); + "Breakpoint site %d is valid for this thread (0x%I64x), creating stop info.", + site->GetID(), stop_thread->GetID()); stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID( *stop_thread, site->GetID()); @@ -471,8 +473,8 @@ { std::string desc; llvm::raw_string_ostream desc_stream(desc); - desc_stream << "Exception 0x" << llvm::format_hex(active_exception->GetExceptionCode(), 8) - << " encountered at address 0x" << llvm::format_hex(pc, 8); + desc_stream << "Exception " << llvm::format_hex(active_exception->GetExceptionCode(), 8) + << " encountered at address " << llvm::format_hex(pc, 8); stop_info = StopInfo::CreateStopReasonWithException(*stop_thread, desc_stream.str().c_str()); stop_thread->SetStopInfo(stop_info); WINLOG_IFALL(WINDOWS_LOG_EXCEPTION, desc_stream.str().c_str()); @@ -701,7 +703,7 @@ if (!m_session_data) { WINERR_IFANY(WINDOWS_LOG_EXCEPTION, - "Debugger thread reported exception 0x%u at address 0x%I64x, but there is no session.", + "Debugger thread reported exception 0x%x at address 0x%I64x, but there is no session.", record.GetExceptionCode(), record.GetExceptionAddress()); return ExceptionResult::SendToApplication; } @@ -732,7 +734,7 @@ break; default: WINLOG_IFANY(WINDOWS_LOG_EXCEPTION, - "Debugger thread reported exception 0x%u at address 0x%I64x (first_chance=%s)", + "Debugger thread reported exception 0x%x at address 0x%I64x (first_chance=%s)", record.GetExceptionCode(), record.GetExceptionAddress(), BOOL_STR(first_chance)); // For non-breakpoints, give the application a chance to handle the exception first. if (first_chance) @@ -753,18 +755,22 @@ } void -ProcessWindows::OnExitThread(const HostThread &exited_thread) +ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) { llvm::sys::ScopedLock lock(m_mutex); + // On a forced termination, we may get exit thread events after the session + // data has been cleaned up. + if (!m_session_data) + return; + // A thread may have started and exited before the debugger stopped allowing a refresh. // Just remove it from the new threads list in that case. - const HostThreadWindows &wexited_thread = exited_thread.GetNativeThread(); - auto iter = m_session_data->m_new_threads.find(wexited_thread.GetThreadId()); + auto iter = m_session_data->m_new_threads.find(thread_id); if (iter != m_session_data->m_new_threads.end()) m_session_data->m_new_threads.erase(iter); else - m_session_data->m_exited_threads[wexited_thread.GetThreadId()] = exited_thread; + m_session_data->m_exited_threads.insert(thread_id); } void Index: source/Target/ThreadList.cpp =================================================================== --- source/Target/ThreadList.cpp +++ source/Target/ThreadList.cpp @@ -247,8 +247,8 @@ // figuring out whether the thread plan conditions are met. So we don't want // to keep the ThreadList locked the whole time we are doing this. // FIXME: It is possible that running code could cause new threads - // to be created. If that happens we will miss asking them whether - // then should stop. This is not a big deal, since we haven't had + // to be created. If that happens, we will miss asking them whether + // they should stop. This is not a big deal since we haven't had // a chance to hang any interesting operations on those threads yet. collection threads_copy;