Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 27 Dec 2001 15:54:41 -0800 (PST)
From:      Kip Macy <kip_macy@yahoo.com>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   gnu/33262: gdb does not handle pending signals correctly when single stepping
Message-ID:  <200112272354.fBRNsf696158@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         33262
>Category:       gnu
>Synopsis:       gdb does not handle pending signals correctly when single stepping
>Confidential:   no
>Severity:       critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Dec 27 16:00:10 PST 2001
>Closed-Date:
>Last-Modified:
>Originator:     Kip Macy
>Release:        4.4
>Organization:
Extended Solutions
>Environment:
FreeBSD raidclient1.lab.netapp.com 4.4-STABLE FreeBSD 4.4-STABLE #1: Tue Oct 23 22:43:28 PDT 2001     kmacy@raidclient1.lab.netapp.com:/usr/src/sys/compile/DEVELOPMENT  i386

>Description:
when a signal is pending (e.g. SIGALRM) at a breakpoint and the user
tries to single step - gdb will break at the signal handler in 
non-thread-code and at _sys_thread_sigprocmask in threaded code.
This makes it impossible to step through code that makes heavy use of
signals.

This is an example of the behaviour:
> gdb alr^Gmtest^M
GNU gdb 4.18
Copyright 1998 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 "i386-unknown-freebsd"...
(gdb) b main
Breakpoint 1 at 0x8048666: file alrmtest.c, line 44.
(gdb) r
Starting program: /amd/ayr/vol/users2/home/kmacy/alrmtest 

Breakpoint 1, main () at alrmtest.c:44
44              sk_init_timer();
(gdb) n
45              while (1) {
(gdb) n

Program received signal SIGTRAP, Trace/breakpoint trap.
0x80485c0 in sk_millisecond_clock () at alrmtest.c:10
10      sk_millisecond_clock()
(gdb) n

Program received signal SIGTRAP, Trace/breakpoint trap.
main () at alrmtest.c:45
45              while (1) {
(gdb) n

Program received signal SIGTRAP, Trace/breakpoint trap.
0x80485c0 in sk_millisecond_clock () at alrmtest.c:10
10      sk_millisecond_clock()
(gdb) n

Program received signal SIGTRAP, Trace/breakpoint trap.
main () at alrmtest.c:45
45              while (1) {
(gdb) n

Program received signal SIGTRAP, Trace/breakpoint trap.
0x80485c0 in sk_millisecond_clock () at alrmtest.c:10
10      sk_millisecond_clock()
(gdb) n

Program received signal SIGTRAP, Trace/breakpoint trap.
main () at alrmtest.c:45
45              while (1) {

This is the correct behavior (same program on Linux or Solaris):

[kmacy@pris ~]$ gdb linux_alrmtest/alrmtest
GNU gdb 5.0
Copyright 2000 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 "i686-pc-linux-gnu"...
(gdb) bt
No stack.
(gdb) b main
Breakpoint 1 at 0x804857e: file alrmtest.c, line 44.
(gdb) r
Starting program: /n/ayr/users2/kmacy/linux_alrmtest/alrmtest 

Breakpoint 1, main () at alrmtest.c:44
44              sk_init_timer();
(gdb) n
45              while (1) {
(gdb) n
50                      i = 0;
(gdb) n
54                      j = 0;
(gdb) n
55                      printf("milliseconds elapsed is %d\n", sk_msecs4);
(gdb) n
milliseconds elapsed is 40
56                      tmp_sleep(2);
(gdb) n
57              }
(gdb) n
45              while (1) {
(gdb) n
50                      i = 0;
(gdb) n
54                      j = 0;
(gdb) n
55                      printf("milliseconds elapsed is %d\n", sk_msecs4);
(gdb) n
milliseconds elapsed is 110
56                      tmp_sleep(2);
(gdb) n
57              }
(gdb) q

>How-To-Repeat:
single step through the while loop in alrmtest, the code follows:

#include <sys/types.h>
#include <sys/time.h>   /* for implementing system tic */
#include <signal.h>
#include <stdio.h>
#include <setjmp.h>

int sk_msecs4;
#define SK_MSEC_PER_TIC 10
void 
sk_millisecond_clock()
{
        extern int sk_msecs4;
        sk_msecs4 += SK_MSEC_PER_TIC; 
}

/*
 */
void 
sk_init_timer()
{
        struct itimerval tic;
        struct sigaction action;
        action.sa_handler = (void*) sk_millisecond_clock;
        action.sa_flags = SA_RESTART;
        sigemptyset(&action.sa_mask);
        sigaction(SIGALRM, &action, NULL);
        tic.it_interval.tv_sec = 0;
        tic.it_interval.tv_usec = SK_MSEC_PER_TIC * 1000;
        tic.it_value = tic.it_interval;
        setitimer(ITIMER_REAL, &tic, NULL);
}

unsigned int
tmp_sleep(unsigned int seconds) {
        struct timeval t;
        t.tv_sec = seconds;
        t.tv_usec = 0;
        select(0, NULL, NULL, NULL, &t);
}

int 
main() {
        int i, j;
        sk_init_timer();
        while (1) {
                
                /*  useless assignment to demonstrate lack of 
                 *  progress 
                 */
                i = 0;
                /*  useless assignment to demonstrate lack of 
                 *  progress 
                 */
                j = 0;
                printf("milliseconds elapsed is %d\n", sk_msecs4);
                tmp_sleep(2);
        }

}

>Fix:
Not sure yet, but the following indicates to me that 
freebsd_uthread_wait is not correct:
Breakpoint 6, wait_for_inferior () at /usr/src/gnu/usr.bin/binutils/gdb/../../../../contrib/gdb/gdb/infrun.c:1064
1064          registers_changed ();
(gdb) p w
$19 = {
  kind = TARGET_WAITKIND_STOPPED, 
  value = {
    integer = 0xe, 
    sig = TARGET_SIGNAL_ALRM, 
    related_pid = 0xe, 
    execd_pathname = 0xe <Error reading address 0xe: Bad address>, 
    syscall_id = 0xe
  }
}
(gdb) n
1066          if (target_wait_hook)
(gdb) p w
$20 = {
  kind = TARGET_WAITKIND_STOPPED, 
  value = {
    integer = 0xe, 
    sig = TARGET_SIGNAL_ALRM, 
    related_pid = 0xe, 
    execd_pathname = 0xe <Error reading address 0xe: Bad address>, 
    syscall_id = 0xe
  }
}
(gdb) n
1069            pid = target_wait (-1, &w);
(gdb) p w
$21 = {
  kind = TARGET_WAITKIND_STOPPED, 
  value = {
    integer = 0xe, 
    sig = TARGET_SIGNAL_ALRM, 
    related_pid = 0xe, 
    execd_pathname = 0xe <Error reading address 0xe: Bad address>, 
    syscall_id = 0xe
  }
}
(gdb) n
1074          thread_step_needed = 0;
(gdb) p w
$22 = {
  kind = TARGET_WAITKIND_STOPPED, 
  value = {
    integer = 0x5, 
    sig = TARGET_SIGNAL_TRAP, 
    related_pid = 0x5, 
    execd_pathname = 0x5 <Error reading address 0x5: Bad address>, 
    syscall_id = 0x5
  }
}

(gdb) p hoststatus
$50 = 0x57f
(gdb) p *ourstatus
$51 = {
  kind = TARGET_WAITKIND_STOPPED, 
  value = {
    integer = 0xe, 
    sig = TARGET_SIGNAL_ALRM, 
    related_pid = 0xe, 
    execd_pathname = 0xe <Error reading address 0xe: Bad address>, 
    syscall_id = 0xe
  }
}
(gdb) s
target_signal_from_host (hostsig=0x5) at /usr/src/gnu/usr.bin/binutils/gdb/../../../../contrib/gdb/gdb/target.c:1307
1307    {
(gdb) list
1302
1303    /* Convert host signal to our signals.  */
1304    enum target_signal
1305    target_signal_from_host (hostsig)
1306         int hostsig;
1307    {
1308      /* A switch statement would make sense but would require special kludges
1309         to deal with the cases where more than one signal has the same number.  */
1310
1311      if (hostsig == 0) return TARGET_SIGNAL_0;
(gdb) p hostsig
$52 = 0x5
(gdb) bt
#0  target_signal_from_host (hostsig=0x5) at /usr/src/gnu/usr.bin/binutils/gdb/../../../../contrib/gdb/gdb/target.c:1307
#1  0x80b9abb in store_waitstatus (ourstatus=0xbfbff538, hoststatus=0x57f) at /usr/src/gnu/usr.bin/binutils/gdb/../../../../contrib/gdb/gdb/target.c:1690
#2  0x808a268 in child_wait (pid=0xffffffff, ourstatus=0xbfbff538) at /usr/src/gnu/usr.bin/binutils/gdb/../../../../contrib/gdb/gdb/inftarg.c:247
#3  0x8080d60 in freebsd_uthread_wait (pid=0xffffffff, ourstatus=0xbfbff538) at /usr/src/gnu/usr.bin/binutils/gdb/freebsd-uthread.c:511
#4  0x8087bb4 in wait_for_inferior () at /usr/src/gnu/usr.bin/binutils/gdb/../../../../contrib/gdb/gdb/infrun.c:1069
#5  0x8087a09 in proceed (addr=0xffffffff, siggnal=TARGET_SIGNAL_DEFAULT, step=0x1) at /usr/src/gnu/usr.bin/binutils/gdb/../../../../contrib/gdb/gdb/infrun.c:922
#6  0x8085446 in step_1 (skip_subroutines=0x1, single_inst=0x0, count_string=0x0) at /usr/src/gnu/usr.bin/binutils/gdb/../../../../contrib/gdb/gdb/infcmd.c:416
#7  0x80852b1 in next_command (count_string=0x0, from_tty=0x1) at /usr/src/gnu/usr.bin/binutils/gdb/../../../../contrib/gdb/gdb/infcmd.c:332
#8  0x80bc317 in execute_command (p=0x8186001 "", from_tty=0x1) at /usr/src/gnu/usr.bin/binutils/gdb/../../../../contrib/gdb/gdb/top.c:1268
#9  0x80bc4a9 in command_loop () at /usr/src/gnu/usr.bin/binutils/gdb/../../../../contrib/gdb/gdb/top.c:1365
#10 0x8093665 in main (argc=0x1, argv=0xbfbff7ec) at /usr/src/gnu/usr.bin/binutils/gdb/../../../../contrib/gdb/gdb/main.c:636
#11 0x804a52d in _start (arguments=0xbfbff8f4 "/usr/libexec/elf/gdb") at /usr/src/lib/csu/i386-elf/crt1.c:96
(gdb) up
#1  0x80b9abb in store_waitstatus (ourstatus=0xbfbff538, hoststatus=0x57f) at /usr/src/gnu/usr.bin/binutils/gdb/../../../../contrib/gdb/gdb/target.c:1690
1690          ourstatus->value.sig = target_signal_from_host (WSTOPSIG (hoststatus));
(gdb) finish
Run till exit from #1  0x80b9abb in store_waitstatus (ourstatus=0xbfbff538, hoststatus=0x57f) at /usr/src/gnu/usr.bin/binutils/gdb/../../../../contrib/gdb/gdb/target.c:1690
child_wait (pid=0xffffffff, ourstatus=0xbfbff538) at /usr/src/gnu/usr.bin/binutils/gdb/../../../../contrib/gdb/gdb/inftarg.c:248
248       return pid;
(gdb) list
243     /* hack for thread testing */
244           } while( (pid != inferior_pid) && not_same_real_pid );
245     /*##*/
246
247       store_waitstatus (ourstatus, status);
248       return pid;
249     }
250     #endif /* CHILD_WAIT */
251
252     #if !defined(CHILD_POST_WAIT)
(gdb) p *ourstatus
$53 = {
  kind = TARGET_WAITKIND_STOPPED, 
  value = {
    integer = 0x5, 
    sig = TARGET_SIGNAL_TRAP, 
    related_pid = 0x5, 
    execd_pathname = 0x5 <Error reading address 0x5: Bad address>, 
    syscall_id = 0x5
  }
}
(gdb) 


>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200112272354.fBRNsf696158>