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>
