[PATCH] Fix problem on solaris with single stepping and signal handling

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

[PATCH] Fix problem on solaris with single stepping and signal handling

Fred Fish-2
There is a problem on Solaris with signals that are being caught by
gdb and not passed on to the inferior.  It can be reproduced as
follows:

(1) Set a breakpoint and run the program until gdb stops at the
breakpoint

(2) Send the stopped process a signal like SIGALRM

(3) Try to single step the stopped process

(4) The process either will remain at the breakpoint or run freely to
the next breakpoint and/or exit.  I've seen both behaviors.

The problem is that gdb is unnecessarily setting a step resume
breakpoint for signals that are not going to be passed to the
inferior.  Then in a later pass through handle_inferior_event, the
presence of this breakpoint, after the inferior has stepped off the
breakpoint, allows the inferior to free run instead of stopping (for
the free run case), which makes sense if you want it to run the signal
handler and then break when it returns to the location of the step
resume breakpoint.  What actually happens of course is that gdb simply
steps off the breakpoint and then free runs the code it would have
executed in the absence of the signal.

Below is an example of how to reproduce the problem, and a simple
patch.  "gdb-old" is the version before the patch and "gdb" is the
version after the patch.

============================================================================

$ cat sigtest.c
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>

int ppid;
int cpid;

void bar ()
{
}

main ()
{
  ppid = getpid ();
  cpid = fork ();
  if (cpid > 0)
    for (;;)
      {
        bar ();
        sleep (1);
      }
  else
    for (;;)
      {
        kill (ppid, SIGALRM);
        sleep (1);
      }
}


$ gcc -g -o sigtest sigtest.c


$ ./gdb-old sigtest
GNU gdb 6.5.50.20060923-cvs
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "sparc-sun-solaris2.8"...
Setting up the environment for debugging gdb.
Function "internal_error" not defined.
Function "info_command" not defined.
/home/fnf/sandbox/experimental/build/sparc-sun-solaris2.8/gdb/gdb/.gdbinit:8: Error in sourced command file:
No breakpoint number 0.
(gdb) handle SIGALRM nopass
Signal        Stop      Print   Pass to program Description
SIGALRM       No        No      No              Alarm clock
(gdb) br bar
Breakpoint 1 at 0x105a4: file sigtest.c, line 10.
(gdb) run
Starting program: /home/fnf/sandbox/experimental/build/sparc-sun-solaris2.8/gdb/gdb/sigtest

Breakpoint 1, bar () at sigtest.c:10
10      }
(gdb) display/i $pc
1: x/i $pc  0x105a4 <bar+4>:    rett  %i7 + 8
(gdb) stepi
^C   (fnf: inferior is stuck, interrupt it)
Program received signal SIGINT, Interrupt.
0xff31b784 in _sigsuspend () from /usr/lib/libc.so.1
1: x/i $pc  0xff31b784 <_sigsuspend+4>: ta  8
(gdb) quit
The program is running.  Exit anyway? (y or n) y


$ ./gdb sigtest
GNU gdb 6.5.50.20060923-cvs
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "sparc-sun-solaris2.8"...
Setting up the environment for debugging gdb.
Function "internal_error" not defined.
Function "info_command" not defined.
/home/fnf/sandbox/experimental/build/sparc-sun-solaris2.8/gdb/gdb/.gdbinit:8: Error in sourced command file:
No breakpoint number 0.
(gdb) handle SIGALRM nopass
Signal        Stop      Print   Pass to program Description
SIGALRM       No        No      No              Alarm clock
(gdb) br bar
Breakpoint 1 at 0x105a4: file sigtest.c, line 10.
(gdb) run
Starting program: /home/fnf/sandbox/experimental/build/sparc-sun-solaris2.8/gdb/gdb/sigtest

Breakpoint 1, bar () at sigtest.c:10
10      }
(gdb) display/i $pc
1: x/i $pc  0x105a4 <bar+4>:    rett  %i7 + 8
(gdb) stepi
0x000105a8 in bar () at sigtest.c:10
10      }
1: x/i $pc  0x105a8 <bar+8>:    nop
(gdb)
main () at sigtest.c:20
20              sleep (1);
1: x/i $pc  0x10604 <main+88>:  mov  1, %o0     ! 0x1
(gdb)
0x00010608      20              sleep (1);
1: x/i $pc  0x10608 <main+92>:  call  0x2081c <sleep@plt>
(gdb)
0x0001060c      20              sleep (1);
1: x/i $pc  0x1060c <main+96>:  nop
(gdb)
0x0002081c in sleep@plt ()
1: x/i $pc  0x2081c <sleep@plt>:        sethi  %hi(0x15000), %g1
(gdb) quit
The program is running.  Exit anyway? (y or n) y
$ exit
exit

============================================================================

2007-01-25  Fred Fish  <[hidden email]>

        * infrun.c (handle_inferior_event): Don't set a step resume
        breakpoint for signals that are not being passed on to the
        inferior.

Index: infrun.c
diff -u -p -r1.1.1.5.2.4 infrun.c
--- infrun.c 25 Sep 2006 02:04:52 -0000 1.1.1.5.2.4
+++ infrun.c 25 Jan 2007 17:20:13 -0000
@@ -1964,6 +1964,7 @@ process_event_stop_test:
  stop_signal = TARGET_SIGNAL_0;
 
       if (prev_pc == read_pc ()
+  && stop_signal != TARGET_SIGNAL_0
   && !breakpoints_inserted
   && breakpoint_here_p (read_pc ())
   && step_resume_breakpoint == NULL)

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Fix problem on solaris with single stepping and signal handling

Daniel Jacobowitz-2
On Thu, Jan 25, 2007 at 10:37:54AM -0700, Fred Fish wrote:

> There is a problem on Solaris with signals that are being caught by
> gdb and not passed on to the inferior.  It can be reproduced as
> follows:
>
> (1) Set a breakpoint and run the program until gdb stops at the
> breakpoint
>
> (2) Send the stopped process a signal like SIGALRM
>
> (3) Try to single step the stopped process
>
> (4) The process either will remain at the breakpoint or run freely to
> the next breakpoint and/or exit.  I've seen both behaviors.
>
> The problem is that gdb is unnecessarily setting a step resume
> breakpoint for signals that are not going to be passed to the
> inferior.  Then in a later pass through handle_inferior_event, the
> presence of this breakpoint, after the inferior has stepped off the
> breakpoint, allows the inferior to free run instead of stopping (for
> the free run case), which makes sense if you want it to run the signal
> handler and then break when it returns to the location of the step
> resume breakpoint.  What actually happens of course is that gdb simply
> steps off the breakpoint and then free runs the code it would have
> executed in the absence of the signal.

I'm worried that this is the wrong fix.  I might easily be wrong here
though, so take with a grain of salt.

You're avoiding inserting the step resume breakpoint in some case.
This is an optimization, and not a bad idea.  But suppose we were going
to pass the signal to the inferior, but it was going to ignore it
(signal (SIGALRM, SIG_IGN)).  Wouldn't exactly the same bug
manifest that you're trying to fix?

Seems to me that we're confused because we've forcibly stepped past the
single step breakpoint and ended up on the other side of it instead of
on the first instruction of a signal handler.  We'd need to detect that
we didn't step into a signal handler, and treat it like hitting the
step resume breakpoint, perhaps.

--
Daniel Jacobowitz
CodeSourcery