From: Pedro Alves Date: Fri, 2 Jun 2023 22:08:49 +0000 (+0100) Subject: Windows gdb: Avoid hang second attach/run X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7a15a5f571da8772765bfb17d1049a097205035e;p=thirdparty%2Fbinutils-gdb.git Windows gdb: Avoid hang second attach/run gdb.base/attach.exp starts a second inferior and tries to attach the second inferior to the same process that inferior 1 is already debugging. The point is to make sure that the backend errors out when it tries to attach to a process that is already being debugged. windows_nat_target::attach and windows_nat_target::create_inferior both hang in this situation, because they call into do_synchronously, which hangs because the 'process_thread' thread is blocked in WaitForDebugEvent. E.g.: attach 4420 FAIL: gdb.base/attach.exp: do_attach_failure_tests: fail to attach again (timeout) Until the Windows backend is taught to debug multiple processes, which will probably require having one process_thread thread per inferior, detect the situation and error out before GDB hangs. This results in the following progression in gdb.base/attach.exp: -FAIL: gdb.base/attach.exp: do_attach_failure_tests: fail to attach again (timeout) -FAIL: gdb.base/attach.exp: do_attach_failure_tests: set confirm off (timeout) -FAIL: gdb.base/attach.exp: do_attach_failure_tests: switch to inferior 1 (timeout) -FAIL: gdb.base/attach.exp: do_attach_failure_tests: exit after attach failures (timeout) -FAIL: gdb.base/attach.exp: do_attach_failure_tests: gdb_breakpoint: set breakpoint at main (timeout) -FAIL: gdb.base/attach.exp: do_attach_failure_tests: stop at main (timeout) +PASS: gdb.base/attach.exp: do_attach_failure_tests: fail to attach again +PASS: gdb.base/attach.exp: do_attach_failure_tests: set confirm off +PASS: gdb.base/attach.exp: do_attach_failure_tests: switch to inferior 1 +PASS: gdb.base/attach.exp: do_attach_failure_tests: exit after attach failures +PASS: gdb.base/attach.exp: do_attach_failure_tests: stop at main There are still other failures not addressed by this patch. Tests that launch a second program with "run" exist, but are normally gated by allow_multi_inferior_tests. Approved-By: Tom Tromey Change-Id: I55b4438795439673c49fa55f55ddf0191f4f0ea8 commit-id: 1caa5be0 --- diff --git a/gdb/testsuite/gdb.base/attach.exp b/gdb/testsuite/gdb.base/attach.exp index bffdfd9b1aa..a4e7d72ef94 100644 --- a/gdb/testsuite/gdb.base/attach.exp +++ b/gdb/testsuite/gdb.base/attach.exp @@ -175,6 +175,10 @@ proc_with_prefix do_attach_failure_tests {} { # Response expected when using gdbserver. pass "$test" } + -re -wrap "Can only debug one process at a time\\." { + # Response expected on Windows. + pass "$test" + } } # To ensure the target is still alive and working after this, try to run diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index b9d32b6c0c4..d506b42fbda 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -2056,14 +2056,24 @@ out: return ret; } +/* Throw an error if we're already debugging a Windows process. We + can only debug one at a time currently. */ + +static void +ensure_only_one_process () +{ + if (windows_process->process_id != 0) + error (_("Can only debug one process at a time.")); +} + /* Attach to process PID, then initialize for debugging it. */ void windows_nat_target::attach (const char *args, int from_tty) { - DWORD pid; + ensure_only_one_process (); - pid = parse_pid_to_attach (args); + DWORD pid = parse_pid_to_attach (args); if (set_process_privilege (SE_DEBUG_NAME, TRUE) < 0) warning ("Failed to get SE_DEBUG_NAME privilege\n" @@ -2415,6 +2425,8 @@ windows_nat_target::detach (inferior *inf, int from_tty) switch_to_no_thread (); detach_inferior (inf); + windows_process->process_id = 0; + maybe_unpush_target (); } @@ -2857,6 +2869,8 @@ windows_nat_target::create_inferior (const char *exec_file, DWORD flags = 0; const std::string &inferior_tty = current_inferior ()->tty (); + ensure_only_one_process (); + if (!exec_file) error (_("No executable specified, use `target exec'.")); @@ -3166,6 +3180,7 @@ windows_nat_target::mourn_inferior () CHECK (CloseHandle (windows_process->handle)); windows_process->open_process_used = 0; } + windows_process->process_id = 0; inf_child_target::mourn_inferior (); }