Bug 9425 - When using "sigwait" GDB doesn't trap SIGINT. Ctrl+C terminates program when should break gdb.
Summary: When using "sigwait" GDB doesn't trap SIGINT. Ctrl+C terminates program when ...
Status: NEW
Alias: None
Product: gdb
Classification: Unclassified
Component: threads (show other bugs)
Version: 6.5
: P1 minor
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 9468 (view as bug list)
Depends on:
Blocks: 14559
  Show dependency treegraph
 
Reported: 2007-09-20 08:58 UTC by Jordi Blasi
Modified: 2018-01-30 15:38 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
test_gdb.cpp (632 bytes, application/octet-stream)
, Jordi Blasi
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jordi Blasi 2007-09-20 08:58:01 UTC
[Converted from Gnats 2320]

I'm having problems getting GDB to not pass SIGINT to my program. In my main thread I do a sigwait for SIGINT. When I'm debugging, while gdb is running I may want to break gdb to set breakpoints or so, then I hit Ctrl-C (send SIGINT) but gdb does not break, instead SIGINT is passed to my program that gracefully terminates and gdb prints "Program exited normally". Of course "info handle" shows that SIGINT should not be being passed to my program:

(gdb) info handle SIGINT
Signal        Stop      Print   Pass to program Description
SIGINT        Yes       Yes     No              Interrupt

GDB does not even print SIGINT signal delivery when I think it should.

Please check:

http://sourceware.org/ml/gdb/2006-04/msg00010.html 
http://bugzilla.kernel.org/show_bug.cgi?id=9039

Release:
GNU gdb 6.5

Environment:
GNU/Linux 2.6.20.1 #3 PREEMPT i686
gcc (GCC) 4.1.1 20060724 (prerelease) (4.1.1-3mdk)

How-To-Repeat:
Compile attached "test_gdb.cpp" file and run it under gdb. While running hit Ctrl+C to interrupt GDB. Program will terminate so no chance to debug it any more.
Comment 1 drow@false.org 2007-09-29 20:32:44 UTC
From: Daniel Jacobowitz <drow@false.org>
To: jordiblasi@gmail.com
Cc: gdb-gnats@sources.redhat.com
Subject: Re: threads/2320: When using "sigwait" GDB doesn't trap SIGINT.
	Ctrl+C terminates program when should break gdb.
Date: Sat, 29 Sep 2007 16:32:44 -0400

 On Thu, Sep 20, 2007 at 08:53:13AM -0000, jordiblasi@gmail.com wrote:
 > I'm having problems getting GDB to not pass SIGINT to my program. In
 > my main thread I do a sigwait for SIGINT. When I'm debugging, while
 > gdb is running I may want to break gdb to set breakpoints or so,
 > then I hit Ctrl-C (send SIGINT) but gdb does not break, instead
 > SIGINT is passed to my program that gracefully terminates and gdb
 > prints "Program exited normally".
 
 Thanks for the clear report and test case.  I discussed this with
 Roland McGrath in the bugzilla.kernel.org entry you linked to; our
 conclusion was that the kernel is correct to not report the SIGINT
 in this case.  Of course that's not the useful behavior for GDB.
 
 I'm not planning to work on this right now, but here's some notes
 on a possible solution if anyone else wants to.
 
   - Define a new PTRACE_SETOPTIONS bit to enable the extra reporting.
 
   - Report the signal as a special event, using a new PTRACE_EVENT_FOO
     code in the high half-word of the wait status.
 
   - Adjust GDB to set the new options bit when it sets other options.
 
 -- 
 Daniel Jacobowitz
 CodeSourcery
Comment 2 Jordi Blasi 2010-06-03 07:09:53 UTC
Is this bug likely to be revisited or resolved in the short-term? Is it really
ASSIGNED to someone.
Comment 3 Tom Tromey 2010-06-03 16:04:47 UTC
No, it is not really assigned.  That seems to be some sort of bug in
our bugzilla installation.  AFAIK nobody is actively working on this.
Comment 4 Frédéric Buclin 2010-09-26 13:04:33 UTC
*** Bug 9468 has been marked as a duplicate of this bug. ***
Comment 5 Tom Tromey 2013-11-26 20:41:58 UTC
See also bug #15250.  However it seems options may be limited
if gdb and the inferior are sharing a terminal.
Comment 6 cvs-commit@gcc.gnu.org 2018-01-30 15:38:18 UTC
The master branch has been updated by Pedro Alves <palves@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=e671cd59d74cec9f53e110ce887128d1eeadb7f2

commit e671cd59d74cec9f53e110ce887128d1eeadb7f2
Author: Pedro Alves <palves@redhat.com>
Date:   Tue Jan 30 14:23:51 2018 +0000

    Per-inferior target_terminal state, fix PR gdb/13211, more
    
    In my multi-target branch I ran into problems with GDB's terminal
    handling that exist in master as well, with multi-inferior debugging.
    
    This patch adds a testcase for said problems
    (gdb.multi/multi-term-settings.exp), fixes the problems, fixes PR
    gdb/13211 as well (and adds a testcase for that too,
    gdb.base/interrupt-daemon.exp).
    
    The basis of the problem I ran into is the following.  Consider a
    scenario where you have:
    
     - inferior 1 - started with "attach", process is running on some
       other terminal.
    
     - inferior 2 - started with "run", process is sharing gdb's terminal.
    
    In this scenario, when you stop/resume both inferiors, you want GDB to
    save/restore the terminal settings of inferior 2, the one that is
    sharing GDB's terminal.  I.e., you want inferior 2 to "own" the
    terminal (in target_terminal::is_ours/target_terminal::is_inferior
    sense).
    
    Unfortunately, that's not what you get currently.  Because GDB doesn't
    know whether an attached inferior is actually sharing GDB's terminal,
    it tries to save/restore its settings anyway, ignoring errors.  In
    this case, this is pointless, because inferior 1 is running on a
    different terminal, but GDB doesn't know better.
    
    And then, because it is only possible to have the terminal settings of
    a single inferior be in effect at a time, or make one inferior/pgrp be
    the terminal's foreground pgrp (aka, only one inferior can "own" the
    terminal, ignoring fork children here), if GDB happens to try to
    restore the terminal settings of inferior 1 first, then GDB never
    restores the terminal settings of inferior 2.
    
    This patch fixes that and a few things more along the way:
    
     - Moves enum target_terminal::terminal_state out of the
       target_terminal class (it's currently private) and makes it a
       scoped enum so that it can be easily used elsewhere.
    
     - Replaces the inflow.c:terminal_is_ours boolean with a
       target_terminal_state variable.  This allows distinguishing is_ours
       and is_ours_for_output states.  This allows finally making
       child_terminal_ours_1 do something with its "output_only"
       parameter.
    
     - Makes each inferior have its own copy of the
       is_ours/is_ours_for_output/is_inferior state.
    
     - Adds a way for GDB to tell whether the inferior is sharing GDB's
       terminal.  Works best on Linux and Solaris; the fallback works just
       as well as currently.
    
     - With that, we can remove the inf->attach_flag tests from
       child_terminal_inferior/child_terminal_ours.
    
     - Currently target_ops.to_ours is responsible for both saving the
       current inferior's terminal state, and restoring gdb's state.
       Because each inferior has its own terminal state (possibly handled
       by different targets in a multi-target world, even), we need to
       split the inferior-saving part from the gdb-restoring part.  The
       patch adds a new target_ops.to_save_inferior target method for
       that.
    
     - Adds a new target_terminal::save_inferior() function, so that
       sequences like:
    
         scoped_restore_terminal_state save_state;
         target_terminal::ours_for_output ();
    
       ... restore back inferiors that were
       target_terminal_state::is_inferior before back to is_inferior, and
       leaves inferiors that were is_ours alone.
    
     - Along the way, this adds a default implementation of
       target_pass_ctrlc to inflow.c (for inf-child.c), that handles
       passing the Ctrl-C to a process running on GDB's terminal or to
       some other process otherwise.
    
     - Similarly, adds a new target default implementation of
       target_interrupt, for the "interrupt" command.  The current
       implementation of this hook in inf-ptrace.c kills the whole process
       group, but that's incorrect/undesirable because we may not be
       attached to all processes in the process group.  And also, it's
       incorrect because inferior_process_group() doesn't really return
       the inferior's real process group id if the inferior is not a
       process group leader...  This is the cause of PR gdb/13211 [1],
       which this patch fixes.  While at it, that target method's "ptid"
       parameter is eliminated, because it's not really used.
    
     - A new test is included that exercises and fixes PR gdb/13211, and
       also fixes a GDB issue reported on stackoverflow that I ran into
       while working on this [2].  The problem is similar to PR gdb/13211,
       except that it also triggers with Ctrl-C.  When debugging a daemon
       (i.e., a process that disconnects from the controlling terminal and
       is not a process group leader, then Ctrl-C doesn't work, you just
       can't interrupt the inferior at all, resulting in a hung debug
       session.  The problem is that since the inferior is no longer
       associated with gdb's session / controlling terminal, then trying
       to put the inferior in the foreground fails.  And so Ctrl-C never
       reaches the inferior directly.  pass_signal is only used when the
       inferior is attached, but that is not the case here.  This is fixed
       by the new child_pass_ctrlc.  Without the fix, the new
       interrupt-daemon.exp testcase fails with timeout waiting for a
       SIGINT that never arrives.
    
    [1] PR gdb/13211 - Async / Process group and interrupt not working
    https://sourceware.org/bugzilla/show_bug.cgi?id=13211
    
    [2] GDB not reacting Ctrl-C when after fork() and setsid()
    https://stackoverflow.com/questions/46101292/gdb-not-reacting-ctrl-c-when-after-fork-and-setsid
    
    Note this patch does _not_ fix:
    
     - PR gdb/14559 - The 'interrupt' command does not work if sigwait is in use
       https://sourceware.org/bugzilla/show_bug.cgi?id=14559
    
     - PR gdb/9425 - When using "sigwait" GDB doesn't trap SIGINT. Ctrl+C terminates program when should break gdb.
       https://sourceware.org/bugzilla/show_bug.cgi?id=9425
    
    The only way to fix that that I know of (without changing the kernel)
    is to make GDB put inferiors in a separate session (create a
    pseudo-tty master/slave pair, make the inferior run with the slave as
    its terminal, and have gdb pump output/input on the master end).
    
    gdb/ChangeLog:
    2018-01-30  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/13211
    	* config.in, configure: Regenerate.
    	* configure.ac: Check for getpgid.
    	* go32-nat.c (go32_pass_ctrlc): New.
    	(go32_target): Install it.
    	* inf-child.c (inf_child_target): Install
    	child_terminal_save_inferior, child_pass_ctrlc and
    	child_interrupt.
    	* inf-ptrace.c (inf_ptrace_interrupt): Delete.
    	(inf_ptrace_target): No longer install it.
    	* infcmd.c (interrupt_target_1): Adjust.
    	* inferior.h (child_terminal_save_inferior, child_pass_ctrlc)
    	(child_interrupt): Declare.
    	(inferior::terminal_state): New.
    	* inflow.c (struct terminal_info): Update comments.
    	(inferior_process_group): Delete.
    	(terminal_is_ours): Delete.
    	(gdb_tty_state): New.
    	(child_terminal_init): Adjust.
    	(is_gdb_terminal, sharing_input_terminal_1)
    	(sharing_input_terminal): New functions.
    	(child_terminal_inferior): Adjust.  Use sharing_input_terminal.
    	Set the process's actual process group in the foreground if
    	possible.  Handle is_ours_for_output/is_ours distinction.  Don't
    	mark terminal as the inferior's if not sharing GDB's terminal.
    	Don't check attach_flag.
    	(child_terminal_ours_for_output, child_terminal_ours): Adjust to
    	pass down a target_terminal_state.
    	(child_terminal_save_inferior): New, factored out from ...
    	(child_terminal_ours_1): ... this.  Handle
    	target_terminal_state::is_ours_for_output.
    	(child_interrupt, child_pass_ctrlc): New.
    	(inflow_inferior_exit): Clear the inferior's terminal_state.
    	(copy_terminal_info): Copy the inferior's terminal state.
    	(_initialize_inflow): Remove reference to terminal_is_ours.
    	* inflow.h (inferior_process_group): Delete.
    	* nto-procfs.c (nto_handle_sigint, procfs_interrupt): Adjust.
    	* procfs.c (procfs_target): Don't install procfs_interrupt.
    	(procfs_interrupt): Delete.
    	* remote.c (remote_serial_quit_handler): Adjust.
    	(remote_interrupt): Remove ptid parameter.  Adjust.
    	* target-delegates.c: Regenerate.
    	* target.c: Include "terminal.h".
    	(target_terminal::terminal_state): Rename to ...
    	(target_terminal::m_terminal_state): ... this.
    	(target_terminal::init): Adjust.
    	(target_terminal::inferior): Adjust to per-inferior
    	terminal_state.
    	(target_terminal::restore_inferior, target_terminal_is_ours_kind): New.
    	(target_terminal::ours, target_terminal::ours_for_output): Use
    	target_terminal_is_ours_kind.
    	(target_interrupt): Remove ptid parameter.  Adjust.
    	(default_target_pass_ctrlc): Adjust.
    	* target.h (target_ops::to_terminal_save_inferior): New field.
    	(target_ops::to_interrupt): Remove ptid_t parameter.
    	(target_interrupt): Remove ptid_t parameter.  Update comment.
    	(target_pass_ctrlc): Update comment.
    	* target/target.h (target_terminal_state): New scoped enum,
    	factored out of ...
    	(target_terminal::terminal_state): ... here.
    	(target_terminal::inferior): Update comments.
    	(target_terminal::restore_inferior): New.
    	(target_terminal::is_inferior, target_terminal::is_ours)
    	(target_terminal::is_ours_for_output): Adjust.
    	(target_terminal::scoped_restore_terminal_state): Adjust to
    	rename, and call restore_inferior() instead of inferior().
    	(target_terminal::scoped_restore_terminal_state::m_state): Change
    	type.
    	(target_terminal::terminal_state): Rename to ...
    	(target_terminal::m_terminal_state): ... this and change type.
    
    gdb/gdbserver/ChangeLog:
    2018-01-30  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/13211
    	* target.c (target_terminal::terminal_state): Rename to ...
    	(target_terminal::m_terminal_state): ... this.
    
    gdb/testsuite/ChangeLog:
    2018-01-30  Pedro Alves  <palves@redhat.com>
    
    	PR gdb/13211
    	* gdb.base/interrupt-daemon.c: New.
    	* gdb.base/interrupt-daemon.exp: New.
    	* gdb.multi/multi-term-settings.c: New.
    	* gdb.multi/multi-term-settings.exp: New.