This is the mail archive of the gdb@sourceware.cygnus.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

On Digital UNIX, "continue" doesn't continue correctly if a signal isdelivered


On Digital UNIX/Alpha, we have a program that has an interval timer set
up to continuously deliver signals; with GDB 4.18, we find that if you
stop at a breakpoint, and then try to continue from that breakpoint, it
doesn't continue - instead, it stops again at the same breakpoint.

The same thing happens with the GDB that was in the CVS tree as of a
short while ago.

The problem appears to be that various tests in "wait_for_inferior()",
which test whether the current SP is for a frame closer to the top of
the stack than the frame for "step_sp" (or "step_sp - 16") fail, because
"step_sp" hasn't been set.  When continuing from the breakpoint (with
the PRSTEP flag set in the "pr_flags" field of the structure passed to
PIOCRUN, so that it executes only one instruction), it stops in
"__sigtramp", as a SIGALRM was delivered to the process in the interval
since the breakpoint trap; however, GDB doesn't realize that it's in the
signal trampoline, and doesn't properly continue, so that when it next
gets a breakpoint trap after returning from the signal, as it presumably
re-executes the breakpoint instruction, it doesn't realize that it
should drive on, and it just stops.

"step_sp" gets set by "step_1()", "step_once()", and
"until_next_command()", presumably because all those routines call
"proceed()" with "step" set; however, "step_sp" isn't set by
"continue_command()" or any routine between "continue_command()" and
"proceed()", presumably because "proceed()" isn't called with "step" set
in that code path.

However, "proceed()" will be single-stepping, because we're resuming
from a breakpoint, and we need to step over the instruction at which the
breakpoint was placed and then put the breakpoint back, as per:

  if (addr == (CORE_ADDR) -1)
    {
      /* If there is a breakpoint at the address we will resume at,
	 step one instruction before inserting breakpoints
	 so that we do not stop right away (and report a second
	 hit at this breakpoint).  */
 
      if (read_pc () == stop_pc && breakpoint_here_p (read_pc ()))
	oneproc = 1;

in "proceed()".

Making "proceed()" set "step_frame_address" and "step_sp" if "oneproc"
is set but "step" isn't set appears to fix the problem:

Index: gdb/infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.14
diff -c -r1.14 gdb/infrun.c
*** gdb/infrun.c	2000/05/22 09:02:23	1.14
--- gdb/infrun.c	2000/05/24 03:44:38
***************
*** 1040,1048 ****
  #endif /* HP_OS_BUG */
  
    if (oneproc)
!     /* We will get a trace trap after one instruction.
!        Continue it automatically and insert breakpoints then.  */
!     trap_expected = 1;
    else
      {
        int temp = insert_breakpoints ();
--- 1040,1058 ----
  #endif /* HP_OS_BUG */
  
    if (oneproc)
!     {
!       /* We will get a trace trap after one instruction.
! 	 Continue it automatically and insert breakpoints then.  */
!       trap_expected = 1;
! 
!       /* Oh, and if we weren't explicitly told to single-step, our
!          caller may not have updated "step_sp", so do it ourselves. */
!       if (!step)
! 	{
! 	  step_frame_address = FRAME_FP (get_current_frame ());
! 	  step_sp = read_sp ();
! 	}
!     }
    else
      {
        int temp = insert_breakpoints ();

Whether this is the right way to fix this is another matter.  (For
example, perhaps "proceed()" should always set "step_frame_address" and
"step_sp" if it will be passing a non-zero value as the first argument
to "resume()", and the routines in "gdb/infcmd.c" that set them should
leave it up to "proceed()" to do so.)

I've attached a small sample program which exhibits the problem; if run
with "clock" as an argument, it sets up a timer to repeatedly deliver
SIGALRM, and if you set a breakpoint on "procedure()", run the program,
and then type "continue", it will stop again in "procedure()" without
printing "Hello", indicating that it hasn't continued from the
breakpoint.

However, if run with "noclock" as an argument, so that it doesn't
repeatedly get SIGALRM, it *will* print "Hello" before stopping again at
"procedure()".

Applying the patch above makes "continue" behave correctly regardless of
whether the program was run with "clock" or "noclock".
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <sys/time.h>

char poop[17];

static void
clock_handler(int signo)
{
}

static void
subprocedure(void)
{
}

static void
procedure(void)
{
	subprocedure();
}

int
main(int argc, char **argv)
{
	struct sigaction new;
	struct itimerval timer;

	if (argc != 2) {
		fprintf(stderr, "Usage: sigcrap [clock|noclock]\n");
		return 1;
	}
	if (strcmp(argv[1], "clock") == 0) {
		new.sa_handler = clock_handler;
		sigemptyset(&new.sa_mask);
		new.sa_flags = 0;
		if (sigaction(SIGALRM, &new, NULL) < 0) {
			fprintf(stderr, "sigaction: %s\n", strerror(errno));
			return 2;
		}

		timer.it_value.tv_sec = 0;
		timer.it_value.tv_usec = 1000*10;
		timer.it_interval.tv_sec = 0;
		timer.it_interval.tv_usec = 1000*10;
		if (setitimer(ITIMER_REAL, &timer, NULL) < 0) {
			fprintf(stderr, "setitimer: %s\n", strerror(errno));
			return 2;
		}
	}

	for (;;) {
		procedure();
		fprintf(stderr, "Hello\n");
	}
	return 0;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]