@@ -239,12 +239,13 @@ void DebuggerThread::DebugLoop() {
239
239
BOOL wait_result = WaitForDebugEvent (&dbe, INFINITE);
240
240
if (wait_result) {
241
241
DWORD continue_status = DBG_CONTINUE;
242
+ bool shutting_down = m_is_shutting_down;
242
243
switch (dbe.dwDebugEventCode ) {
243
244
default :
244
245
llvm_unreachable (" Unhandle debug event code!" );
245
246
case EXCEPTION_DEBUG_EVENT: {
246
- ExceptionResult status =
247
- HandleExceptionEvent ( dbe.u .Exception , dbe.dwThreadId );
247
+ ExceptionResult status = HandleExceptionEvent (
248
+ dbe.u .Exception , dbe.dwThreadId , shutting_down );
248
249
249
250
if (status == ExceptionResult::MaskException)
250
251
continue_status = DBG_CONTINUE;
@@ -292,6 +293,45 @@ void DebuggerThread::DebugLoop() {
292
293
293
294
::ContinueDebugEvent (dbe.dwProcessId, dbe.dwThreadId, continue_status);
294
295
296
+ // We have to DebugActiveProcessStop after ContinueDebugEvent, otherwise
297
+ // the target process will crash
298
+ if (shutting_down) {
299
+ // A breakpoint that occurs while `m_pid_to_detach` is non-zero is a
300
+ // magic exception that we use simply to wake up the DebuggerThread so
301
+ // that we can close out the debug loop.
302
+ if (m_pid_to_detach != 0 &&
303
+ (dbe.u .Exception .ExceptionRecord .ExceptionCode ==
304
+ EXCEPTION_BREAKPOINT ||
305
+ dbe.u .Exception .ExceptionRecord .ExceptionCode ==
306
+ STATUS_WX86_BREAKPOINT)) {
307
+ LLDB_LOG (log,
308
+ " Breakpoint exception is cue to detach from process {0:x}" ,
309
+ m_pid_to_detach.load ());
310
+
311
+ // detaching with leaving breakpoint exception event on the queue may
312
+ // cause target process to crash so process events as possible since
313
+ // target threads are running at this time, there is possibility to
314
+ // have some breakpoint exception between last WaitForDebugEvent and
315
+ // DebugActiveProcessStop but ignore for now.
316
+ while (WaitForDebugEvent (&dbe, 0 )) {
317
+ continue_status = DBG_CONTINUE;
318
+ if (dbe.dwDebugEventCode == EXCEPTION_DEBUG_EVENT &&
319
+ !(dbe.u .Exception .ExceptionRecord .ExceptionCode ==
320
+ EXCEPTION_BREAKPOINT ||
321
+ dbe.u .Exception .ExceptionRecord .ExceptionCode ==
322
+ STATUS_WX86_BREAKPOINT ||
323
+ dbe.u .Exception .ExceptionRecord .ExceptionCode ==
324
+ EXCEPTION_SINGLE_STEP))
325
+ continue_status = DBG_EXCEPTION_NOT_HANDLED;
326
+ ::ContinueDebugEvent (dbe.dwProcessId, dbe.dwThreadId,
327
+ continue_status);
328
+ }
329
+
330
+ ::DebugActiveProcessStop (m_pid_to_detach);
331
+ m_detached = true ;
332
+ }
333
+ }
334
+
295
335
if (m_detached) {
296
336
should_debug = false ;
297
337
}
@@ -310,25 +350,18 @@ void DebuggerThread::DebugLoop() {
310
350
311
351
ExceptionResult
312
352
DebuggerThread::HandleExceptionEvent (const EXCEPTION_DEBUG_INFO &info,
313
- DWORD thread_id) {
353
+ DWORD thread_id, bool shutting_down ) {
314
354
Log *log = GetLog (WindowsLog::Event | WindowsLog::Exception);
315
- if (m_is_shutting_down) {
316
- // A breakpoint that occurs while `m_pid_to_detach` is non-zero is a magic
317
- // exception that
318
- // we use simply to wake up the DebuggerThread so that we can close out the
319
- // debug loop.
320
- if (m_pid_to_detach != 0 &&
355
+ if (shutting_down) {
356
+ bool is_breakpoint =
321
357
(info.ExceptionRecord .ExceptionCode == EXCEPTION_BREAKPOINT ||
322
- info.ExceptionRecord .ExceptionCode == STATUS_WX86_BREAKPOINT)) {
323
- LLDB_LOG (log, " Breakpoint exception is cue to detach from process {0:x}" ,
324
- m_pid_to_detach.load ());
325
- ::DebugActiveProcessStop (m_pid_to_detach);
326
- m_detached = true ;
327
- }
358
+ info.ExceptionRecord .ExceptionCode == STATUS_WX86_BREAKPOINT);
328
359
329
360
// Don't perform any blocking operations while we're shutting down. That
330
361
// will cause TerminateProcess -> WaitForSingleObject to time out.
331
- return ExceptionResult::SendToApplication;
362
+ // We should not send breakpoint exceptions to the application.
363
+ return is_breakpoint ? ExceptionResult::MaskException
364
+ : ExceptionResult::SendToApplication;
332
365
}
333
366
334
367
bool first_chance = (info.dwFirstChance != 0 );
0 commit comments