Fix gdb.threads/process-dies-while-detaching.exp
I noticed [1] a test bug in gdb.threads/process-dies-while-detaching.exp. Simplified, the test code in question looks somewhat like this: ~~~ # Detach from a process, and ensure that it exits after detaching. # This relies on inferior I/O. proc detach_and_expect_exit {test} { gdb_test_multiple "detach" $test .... set saw_prompt 0 set saw_inf_exit 0 while { !$saw_prompt && !$saw_inf_exit } { gdb_test_multiple "" $test { -re "exited, status=0" { set saw_inf_exit 1 } -re "$gdb_prompt " { set saw_prompt 1 } } } pass $test } ~~~ The bug is in the while loop's condition. We want to make sure we see both the inferior output and the prompt, so the loop's test should be: - while { !$saw_prompt && !$saw_inf_exit } { + while { !$saw_prompt || !$saw_inf_exit } { If we just fix that, the test starts failing though, because it exposes a couple latent problems: - When called from test_detach_killed_outside, the parent doesn't print "exited, status=0", because in that case the child dies with a signal, and so detach_and_expect_exit times out. Fix it by making the parent print "signaled, sig=9" in that case, and have the .exp expect it. - When testing against --target_board=native-gdbserver, sometimes we'd get this: ERROR: Process no longer exists ERROR: : spawn id exp9 not open while executing "expect { -i exp8 -timeout 220 -i $server_spawn_id eof { pass $test wait -i $server_spawn_id unset server_spawn_id } timeout { ..." ("uplevel" body line 1) invoked from within "uplevel $body" NONE : spawn id exp9 not open The problem is that: - inferior_spawn_id and server_spawn_id are the same when testing with gdbserver. - gdbserver exits after "detach", so we get an eof for $inferior_spawn_id in the loop in detach_and_expect_exit. That's the first "ERROR: Process no longer exists". - and then when we reach test_server_exit, server_spawn_id is already closed (because server_spawn_id==inferior_spawn_id). To handle this, make the loop in detach_and_expect_exit use an indirect spawn id list and remove $inferior_spawn_id from the list as soon as we got the inferior output we're expecting, so that the "eof" is left unprocessed until we reach test_server_exit. [1] I changed GDB in a way that should have made the test fail, but it didn't. gdb/testsuite/ChangeLog: 2017-12-03 Pedro Alves <palves@redhat.com> * gdb.threads/process-dies-while-detaching.c: Include <errno.h> and <string.h>. (parent_function): Print distinct messages when waitpid fails, or the child exits with a signal, or the child exits for an unhandled reason. * gdb.threads/process-dies-while-detaching.exp (detach_and_expect_exit): New 'inf_output_re' parameter and use it. Wait for both inferior output and GDB's prompt. Use an indirect spawn id list. (do_detach): New parameter 'child_exit'. Use it to compute expected inferior output. (test_detach, test_detach_watch, test_detach_killed_outside): Adjust to pass down the expected child exit kind.
This commit is contained in:
parent
f143cb5fc6
commit
f0fb2488c9
|
@ -1,3 +1,19 @@
|
|||
2017-12-03 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* gdb.threads/process-dies-while-detaching.c: Include <errno.h>
|
||||
and <string.h>.
|
||||
(parent_function): Print distinct messages when waitpid fails, or
|
||||
the child exits with a signal, or the child exits for an unhandled
|
||||
reason.
|
||||
* gdb.threads/process-dies-while-detaching.exp
|
||||
(detach_and_expect_exit): New 'inf_output_re' parameter and use
|
||||
it. Wait for both inferior output and GDB's prompt. Use an
|
||||
indirect spawn id list.
|
||||
(do_detach): New parameter 'child_exit'. Use it to compute
|
||||
expected inferior output.
|
||||
(test_detach, test_detach_watch, test_detach_killed_outside):
|
||||
Adjust to pass down the expected child exit kind.
|
||||
|
||||
2017-12-01 Joel Brobecker <brobecker@adacore.com>
|
||||
Sergio Durigan Junior <sergiodj@redhat.com>
|
||||
Pedro Alves <palves@redhat.com>
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
/* This barrier ensures we only reach the initial breakpoint after all
|
||||
threads have started. */
|
||||
|
@ -78,15 +80,27 @@ parent_function (pid_t child)
|
|||
alarm (300);
|
||||
|
||||
ret = waitpid (child, &status, 0);
|
||||
|
||||
if (ret == -1)
|
||||
exit (1);
|
||||
else if (!WIFEXITED (status))
|
||||
exit (2);
|
||||
else
|
||||
{
|
||||
printf ("waitpid, errno=%d (%s)\n", errno, strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
else if (WIFEXITED (status))
|
||||
{
|
||||
printf ("exited, status=%d\n", WEXITSTATUS (status));
|
||||
exit (0);
|
||||
}
|
||||
else if (WIFSIGNALED (status))
|
||||
{
|
||||
printf ("signaled, sig=%d\n", WTERMSIG (status));
|
||||
exit (2);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("unexpected, status=%x\n", status);
|
||||
exit (3);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -72,9 +72,10 @@ proc return_if_fail { result } {
|
|||
}
|
||||
|
||||
# Detach from a process, and ensure that it exits after detaching.
|
||||
# This relies on inferior I/O.
|
||||
# This relies on inferior I/O. INF_OUTPUT_RE is the pattern that
|
||||
# matches the expected inferior output.
|
||||
|
||||
proc detach_and_expect_exit {test} {
|
||||
proc detach_and_expect_exit {inf_output_re test} {
|
||||
global decimal
|
||||
global gdb_spawn_id
|
||||
global inferior_spawn_id
|
||||
|
@ -85,9 +86,17 @@ proc detach_and_expect_exit {test} {
|
|||
}
|
||||
}]
|
||||
|
||||
# Use an indirect spawn id list, and remove inferior spawn id from
|
||||
# the expected output as soon as it matches, so that if
|
||||
# $inf_inferior_spawn_id is $server_spawn_id and we're testing in
|
||||
# "target remote" mode, the eof caused by gdbserver exiting is
|
||||
# left for the caller to handle.
|
||||
global daee_spawn_id_list
|
||||
set daee_spawn_id_list "$inferior_spawn_id $gdb_spawn_id"
|
||||
|
||||
set saw_prompt 0
|
||||
set saw_inf_exit 0
|
||||
while { !$saw_prompt && ! $saw_inf_exit } {
|
||||
while { !$saw_prompt || ! $saw_inf_exit } {
|
||||
# We don't know what order the interesting things will arrive in.
|
||||
# Using a pattern of the form 'x|y|z' instead of -re x ... -re y
|
||||
# ... -re z ensures that expect always chooses the match that
|
||||
|
@ -95,14 +104,16 @@ proc detach_and_expect_exit {test} {
|
|||
# first in the script that occurs anywhere in the input, so that
|
||||
# we don't skip anything.
|
||||
return_if_fail [gdb_test_multiple "" $test {
|
||||
-i "$inferior_spawn_id $gdb_spawn_id"
|
||||
-re "(exited, status=0)|($gdb_prompt )" {
|
||||
-i daee_spawn_id_list
|
||||
-re "($inf_output_re)|($gdb_prompt )" {
|
||||
if {[info exists expect_out(1,string)]} {
|
||||
verbose -log "saw inferior exit"
|
||||
set saw_inf_exit 1
|
||||
set daee_spawn_id_list "$gdb_spawn_id"
|
||||
} elseif {[info exists expect_out(2,string)]} {
|
||||
verbose -log "saw prompt"
|
||||
set saw_prompt 1
|
||||
set daee_spawn_id_list "$inferior_spawn_id"
|
||||
}
|
||||
array unset expect_out
|
||||
}
|
||||
|
@ -130,15 +141,28 @@ proc continue_to_exit_bp {} {
|
|||
#
|
||||
# CMD indicates what to do with the parent after detaching the child.
|
||||
# Can be either "detach" to detach, or "continue", to continue to
|
||||
# exit. If "continue", then CONTINUE_RE is the regexp to expect.
|
||||
# Defaults to normal exit output.
|
||||
# exit.
|
||||
#
|
||||
proc do_detach {multi_process cmd {continue_re ""}} {
|
||||
# CHILD_EXIT indicates how is the child expected to exit. Can be
|
||||
# either "normal" for normal exit, or "signal" for killed with signal
|
||||
# SIGKILL.
|
||||
#
|
||||
proc do_detach {multi_process cmd child_exit} {
|
||||
global decimal
|
||||
global server_spawn_id
|
||||
|
||||
if {$continue_re == ""} {
|
||||
if {$child_exit == "normal"} {
|
||||
set continue_re "exited normally.*"
|
||||
set inf_output_re "exited, status=0"
|
||||
} elseif {$child_exit == "signal"} {
|
||||
if {$multi_process} {
|
||||
set continue_re "exited with code 02.*"
|
||||
} else {
|
||||
set continue_re "terminated with signal SIGKILL.*"
|
||||
}
|
||||
set inf_output_re "signaled, sig=9"
|
||||
} else {
|
||||
error "unhandled \$child_exit: $child_exit"
|
||||
}
|
||||
|
||||
set is_remote [expr {[target_info exists gdb_protocol]
|
||||
|
@ -154,7 +178,7 @@ proc do_detach {multi_process cmd {continue_re ""}} {
|
|||
if {$cmd == "detach"} {
|
||||
# Make sure that detach works and that the parent process
|
||||
# exits cleanly.
|
||||
detach_and_expect_exit "detach parent"
|
||||
detach_and_expect_exit $inf_output_re "detach parent"
|
||||
} elseif {$cmd == "continue"} {
|
||||
# Make sure that continuing works and that the parent process
|
||||
# exits cleanly.
|
||||
|
@ -205,7 +229,7 @@ proc test_detach {multi_process cmd} {
|
|||
# Run to _exit in the child.
|
||||
continue_to_exit_bp
|
||||
|
||||
do_detach $multi_process $cmd
|
||||
do_detach $multi_process $cmd "normal"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,7 +264,7 @@ proc test_detach_watch {multi_process cmd} {
|
|||
# thread individually).
|
||||
continue_to_exit_bp
|
||||
|
||||
do_detach $multi_process $cmd
|
||||
do_detach $multi_process $cmd "normal"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,12 +303,7 @@ proc test_detach_killed_outside {multi_process cmd} {
|
|||
# Give it some time to die.
|
||||
sleep 2
|
||||
|
||||
if {$multi_process} {
|
||||
set continue_re "exited with code 02.*"
|
||||
} else {
|
||||
set continue_re "terminated with signal SIGKILL.*"
|
||||
}
|
||||
do_detach $multi_process $cmd $continue_re
|
||||
do_detach $multi_process $cmd "signal"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue