Date: Sat, 5 Jan 2002 00:00:08 -0800 (PST) From: Bruce Evans <bde@zeta.org.au> To: freebsd-bugs@FreeBSD.org Subject: Re: ptrace bug was Re: gnu/33262: gdb does not handle pending signals correctly when single stepping Message-ID: <200201050800.g05808m62326@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
The following reply was made to PR gnu/33262; it has been noted by GNATS. From: Bruce Evans <bde@zeta.org.au> To: k Macy <kip_macy@yahoo.com> Cc: <freebsd-gnats-submit@FreeBSD.ORG> Subject: Re: ptrace bug was Re: gnu/33262: gdb does not handle pending signals correctly when single stepping Date: Sat, 5 Jan 2002 18:59:00 +1100 (EST) On Thu, 3 Jan 2002, k Macy wrote: > Not to mention that SIGVTALRM is already used by > the thread library (although I would hope that > _thread_sys_sigaction is smart enough to handle > that case). I've stepped through the GDB > code on both 4.18 and 5.1. On 5.1 I found the > following in i386fbsd-nat.c: > > void > child_resume (ptid_t ptid, int step, enum > target_signal signal) > { > pid_t pid = ptid_get_pid (ptid); > int request = PT_STEP; > > if (pid == -1) > /* Resume all threads. This only gets used in the > non-threaded > case, where "resume all threads" and "resume > inferior_ptid" are > the same. */ > pid = ptid_get_pid (inferior_ptid); > > if (!step) > { > unsigned int eflags; > > /* Workaround for a bug in FreeBSD. Make sure > that the trace > flag is off when doing a continue. There is > a code path > through the kernel which leaves the flag set > when it should > have been cleared. If a process has a signal > pending (such > as SIGALRM) and we do a PT_STEP, the process > never really has > a chance to run because the kernel needs to > notify the > debugger that a signal is being sent. > Therefore, the process > never goes through the kernel's trap() > function which would > normally clear it. */ > > eflags = read_register (PS_REGNUM); > if (eflags & 0x0100) > write_register (PS_REGNUM, eflags & ~0x0100); > > request = PT_CONTINUE; > } > > It is pretty clear that: > a) this does not deal with the case of step or next > b) this does not work in the case of continue often > times because step will be set to 1 > and hence, this code does _not_ work around the bug. > > This appears to be less of a GDB bug and more of a > kernel bug in ptrace. There are at least 3 bugs, and the enclosed patches fix 2 of them. (1) sendsig() didn't clear the trace flag. This was the primary cause of the misbehaviour reported in the PR. When gdb restarts the process, there is a SIGALRM pending unless you type _very_ fast. gdb sets the trace flag before restarting the process, and the bug causes the signal handler to inherit the trace flag, so the signal handler stops after its first instruction. (2) syscall() sometimes generates a SIGTRAP, and got it wrong. When the trace flag is set for an instruction that traps to the kernel for a syscall, syscall() wants to generate a SIGTRAP for the first instruction after the syscall returns instead of 1 later. It got this wrong by checking the new trace flag instead of the old one. This bites when the sigreturn() is from a signal handler and the signal handler interrupted an instruction that is being traced. With the fix for (1), the trace flag will be off until the signal handler calls sigreturn(). Bug (2) causes generation of a SIGTRAP for the instruction that is being traced before that instruction can be started, and this trap repeats unless you type faster than the signals arrive (or type ahead). (3) "stepi" seems to work perfectly with these fixes for (1) and (2), but "next" rarely works. gdb apparently gets confused about the temporary breakpoints that it sets for "next". It gets SIGTRAPs for them and should remove them and continue with single steps, but it leaves them in and spins getting SIGTRAPs (and SIGALRMs in the test program). This is with gdb-4.18. %%% Index: machdep.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/machdep.c,v retrieving revision 1.486 diff -u -2 -r1.486 machdep.c --- machdep.c 20 Dec 2001 23:48:29 -0000 1.486 +++ machdep.c 5 Jan 2002 07:18:13 -0000 @@ -402,5 +402,5 @@ /* See sendsig() for comments. */ - tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP); + tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP); } @@ -418,4 +418,5 @@ regs->tf_esp = (int)fp; regs->tf_eip = PS_STRINGS - szosigcode; + regs->tf_eflags &= ~PSL_T; regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; @@ -546,8 +547,4 @@ /* - * We should never have PSL_T set when returning from vm86 - * mode. It may be set here if we deliver a signal before - * getting to vm86 mode, so turn it off. - * * Clear PSL_NT to inhibit T_TSSFLT faults on return from * syscalls made by the signal handler. This just avoids @@ -556,5 +553,5 @@ * almost legitimately in probes for old cpu types. */ - tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP); + tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP); } @@ -572,4 +569,5 @@ regs->tf_esp = (int)sfp; regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); + regs->tf_eflags &= ~PSL_T; regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; Index: trap.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/trap.c,v retrieving revision 1.210 diff -u -2 -r1.210 trap.c --- trap.c 30 Dec 2001 19:43:59 -0000 1.210 +++ trap.c 5 Jan 2002 06:19:12 -0000 @@ -934,4 +934,5 @@ struct thread *td = curthread; struct proc *p = td->td_proc; + register_t orig_tf_eflags; u_int sticks; int error; @@ -951,4 +952,5 @@ #endif + orig_tf_eflags = frame.tf_eflags; sticks = td->td_kse->ke_sticks; td->td_frame = &frame; @@ -1066,5 +1068,5 @@ * Traced syscall. */ - if ((frame.tf_eflags & PSL_T) && !(frame.tf_eflags & PSL_VM)) { + if ((orig_tf_eflags & PSL_T) && !(orig_tf_eflags & PSL_VM)) { frame.tf_eflags &= ~PSL_T; trapsignal(p, SIGTRAP, 0); %%% Bruce 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?200201050800.g05808m62326>