gdb/17347 - Regression: GDB stopped on run with attached process

Doing:

  gdb --pid=PID -ex run

Results in GDB getting a SIGTTIN, and thus ending stopped.  That's
usually indicative of a missing target_terminal_ours call.

E.g., from the PR:

 $ sleep 1h & p=$!; sleep 0.1; gdb -batch sleep $p -ex run
 [1] 28263
 [1]   Killed                  sleep 1h

 [2]+  Stopped                 gdb -batch sleep $p -ex run

The workaround is doing:

 gdb -ex "attach $PID" -ex "run"

instead of

 gdb [-p] $PID -ex "run"

With the former, gdb waits for the attach command to complete before
moving on to the "run" command, because the interpreter is in sync
mode at this point, within execute_command.  But for the latter,
attach_command is called directly from captured_main, and thus misses
that waiting.  IOW, "run" is running before the attach continuation
has run, before the program stops and attach completes.  The broken
terminal settings are just one symptom of that.  Any command that
queries or requires input results in the same.

The fix is to wait in catch_command_errors (which is specific to
main.c nowadays), just like we wait in execute_command.

gdb/ChangeLog:
2014-09-11  Pedro Alves  <palves@redhat.com>

	PR gdb/17347
	* main.c: Include "infrun.h".
	(catch_command_errors, catch_command_errors_const): Wait for the
	foreground command to complete.
	* top.c (maybe_wait_sync_command_done): New function, factored out
	from ...
	(maybe_wait_sync_command_done): ... here.
	* top.h (maybe_wait_sync_command_done): New declaration.

gdb/testsuite/ChangeLog:
2014-09-11  Pedro Alves  <palves@redhat.com>

	PR gdb/17347
	* lib/gdb.exp (gdb_spawn_with_cmdline_opts): New procedure.
	* gdb.base/attach.exp (test_command_line_attach_run): New
	procedure.
	(top level): Call it.
This commit is contained in:
Pedro Alves 2014-09-11 13:04:15 +01:00
parent 4c92ff2c35
commit 98880d46bd
7 changed files with 115 additions and 10 deletions

View File

@ -1,3 +1,14 @@
2014-09-11 Pedro Alves <palves@redhat.com>
PR gdb/17347
* main.c: Include "infrun.h".
(catch_command_errors, catch_command_errors_const): Wait for the
foreground command to complete.
* top.c (maybe_wait_sync_command_done): New function, factored out
from ...
(maybe_wait_sync_command_done): ... here.
* top.h (maybe_wait_sync_command_done): New declaration.
2014-09-11 Tom Tromey <tromey@redhat.com>
Gary Benson <gbenson@redhat.com>

View File

@ -45,6 +45,7 @@
#include "filestuff.h"
#include <signal.h>
#include "event-top.h"
#include "infrun.h"
/* The selected interpreter. This will be used as a set command
variable, so it should always be malloc'ed - since
@ -369,7 +370,11 @@ catch_command_errors (catch_command_errors_ftype *command,
TRY_CATCH (e, mask)
{
int was_sync = sync_execution;
command (arg, from_tty);
maybe_wait_sync_command_done (was_sync);
}
return handle_command_errors (e);
}
@ -388,7 +393,11 @@ catch_command_errors_const (catch_command_errors_const_ftype *command,
TRY_CATCH (e, mask)
{
int was_sync = sync_execution;
command (arg, from_tty);
maybe_wait_sync_command_done (was_sync);
}
return handle_command_errors (e);
}

View File

@ -1,3 +1,11 @@
2014-09-11 Pedro Alves <palves@redhat.com>
PR gdb/17347
* lib/gdb.exp (gdb_spawn_with_cmdline_opts): New procedure.
* gdb.base/attach.exp (test_command_line_attach_run): New
procedure.
(top level): Call it.
2014-09-11 Pedro Alves <palves@redhat.com>
* lib/gdb.exp (spawn_wait_for_attach): New procedure.

View File

@ -396,6 +396,49 @@ proc do_command_attach_tests {} {
remote_exec build "kill -9 ${testpid}"
}
# Test ' gdb --pid PID -ex "run" '. GDB used to have a bug where
# "run" would run before the attach finished - PR17347.
proc test_command_line_attach_run {} {
global gdb_prompt
global binfile
if ![isnative] then {
unsupported "commandline attach run test"
return 0
}
with_test_prefix "cmdline attach run" {
set testpid [spawn_wait_for_attach $binfile]
set test "run to prompt"
gdb_exit
set res [gdb_spawn_with_cmdline_opts \
"-iex \"set height 0\" -iex \"set width 0\" --pid=$testpid -ex \"start\""]
if { $res != 0} {
fail $test
return $res
}
gdb_test_multiple "" $test {
-re {Attaching to.*Start it from the beginning\? \(y or n\) } {
pass $test
}
}
send_gdb "y\n"
set test "run to main"
gdb_test_multiple "" $test {
-re "Temporary breakpoint .* main .*$gdb_prompt $" {
pass $test
}
}
# Get rid of the process
remote_exec build "kill -9 ${testpid}"
}
}
# Start with a fresh gdb
@ -420,4 +463,6 @@ do_call_attach_tests
do_command_attach_tests
test_command_line_attach_run
return 0

View File

@ -3311,6 +3311,22 @@ proc gdb_spawn { } {
default_gdb_spawn
}
# Spawn GDB with CMDLINE_FLAGS appended to the GDBFLAGS global.
proc gdb_spawn_with_cmdline_opts { cmdline_flags } {
global GDBFLAGS
set saved_gdbflags $GDBFLAGS
append GDBFLAGS $cmdline_flags
set res [gdb_spawn]
set GDBFLAGS $saved_gdbflags
return $res
}
# Start gdb running, wait for prompt, and disable the pagers.
# Overridable function -- you can override this function in your

View File

@ -373,6 +373,23 @@ check_frame_language_change (void)
}
}
/* See top.h. */
void
maybe_wait_sync_command_done (int was_sync)
{
/* If the interpreter is in sync mode (we're running a user
command's list, running command hooks or similars), and we
just ran a synchronous command that started the target, wait
for that command to end. */
if (!interpreter_async && !was_sync && sync_execution)
{
while (gdb_do_one_event () >= 0)
if (!sync_execution)
break;
}
}
/* Execute the line P as a command, in the current user context.
Pass FROM_TTY as second argument to the defining function. */
@ -459,16 +476,7 @@ execute_command (char *p, int from_tty)
else
cmd_func (c, arg, from_tty);
/* If the interpreter is in sync mode (we're running a user
command's list, running command hooks or similars), and we
just ran a synchronous command that started the target, wait
for that command to end. */
if (!interpreter_async && !was_sync && sync_execution)
{
while (gdb_do_one_event () >= 0)
if (!sync_execution)
break;
}
maybe_wait_sync_command_done (was_sync);
/* If this command has been post-hooked, run the hook last. */
execute_cmd_post_hook (c);

View File

@ -42,6 +42,14 @@ extern void quit_command (char *, int);
extern void quit_cover (void);
extern void execute_command (char *, int);
/* If the interpreter is in sync mode (we're running a user command's
list, running command hooks or similars), and we just ran a
synchronous command that started the target, wait for that command
to end. WAS_SYNC indicates whether sync_execution was set before
the command was run. */
extern void maybe_wait_sync_command_done (int was_sync);
extern void check_frame_language_change (void);
/* Prepare for execution of a command.