From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 32410 invoked by alias); 28 Apr 2011 12:01:24 -0000 Received: (qmail 32402 invoked by uid 22791); 28 Apr 2011 12:01:23 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL,BAYES_00,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 28 Apr 2011 12:01:07 +0000 Received: (qmail 7838 invoked from network); 28 Apr 2011 12:01:06 -0000 Received: from unknown (HELO scottsdale.localnet) (pedro@127.0.0.2) by mail.codesourcery.com with ESMTPA; 28 Apr 2011 12:01:06 -0000 From: Pedro Alves To: "Ulrich Weigand" Subject: Re: [patch] Re: [commit] Re: [rfc][1/2] Signal delivery + software single-step is broken Date: Thu, 28 Apr 2011 12:01:00 -0000 User-Agent: KMail/1.13.5 (Linux/2.6.35-28-generic; KDE/4.6.2; x86_64; ; ) Cc: gdb-patches@sourceware.org References: <201104280854.p3S8sddT022602@d06av02.portsmouth.uk.ibm.com> In-Reply-To: <201104280854.p3S8sddT022602@d06av02.portsmouth.uk.ibm.com> MIME-Version: 1.0 Content-Type: Text/Plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Message-Id: <201104281301.04426.pedro@codesourcery.com> X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-04/txt/msg00539.txt.bz2 On Thursday 28 April 2011 09:54:39, Ulrich Weigand wrote: > Index: gdb/infrun.c > =================================================================== > RCS file: /cvs/src/src/gdb/infrun.c,v > retrieving revision 1.476 > diff -u -p -r1.476 infrun.c > --- gdb/infrun.c 27 Apr 2011 17:08:41 -0000 1.476 > +++ gdb/infrun.c 28 Apr 2011 08:29:36 -0000 > @@ -1703,6 +1703,42 @@ a command like `return' or `jump' to con > else if (step) > step = maybe_software_singlestep (gdbarch, pc); > > + /* Currently, our software single-step implementation leads to different > + results than hardware single-stepping in one situation: when stepping > + into delivering a signal which has an associated signal handler, > + hardware single-step will stop at the first instruction of the handler, > + while software single-step will simply skip execution of the handler. > + > + For now, this difference in behavior is accepted since there is no > + easy way to actually implement single-stepping into a signal handler > + without kernel support. > + > + However, there is one scenario where this difference leads to follow-on > + problems: if we're stepping off a breakpoint by removing all breakpoints > + and then single-stepping. In this case, the software single-step > + behavior means that even if there is a breakpoint in the signal > + handler, GDB still would not stop. > + > + Fortunately, we can at least fix this particular issue. We detect > + here the case where we are about to deliver a signal while software > + single-stepping with breakpoints removed. In this situation, we > + revert the decisions to remove all breakpoints and insert single- > + step breakpoints, and instead we install a step-resume breakpoint > + at the current address, deliver the signal without stepping, and > + once we arrive back at the step-resume breakpoint, actually step > + over the breakpoint we originally wanted to step over. */ > + if (singlestep_breakpoints_inserted_p > + && tp->control.trap_expected && sig != TARGET_SIGNAL_0) > + { > + remove_single_step_breakpoints (); > + singlestep_breakpoints_inserted_p = 0; > + tp->control.trap_expected = 0; > + > + insert_step_resume_breakpoint_at_frame (get_current_frame ()); > + insert_breakpoints (); > + tp->step_after_step_resume_breakpoint = 1; > + } > + (I wish there was no need to undo stuff, and do the decision before actually inserting sss breakpoints, but I see why you did it. We need to call gdbarch_software_single_step to know whether sss breakpoints will be inserted, which, actually inserts them.) I'm trying to think whether this works okay with nested signals. Consider that you had a signal to deliver while stepping over a breakpoint, and you hit that new code. Now, the signal handler runs with breakpoint inserted, and happens to hit a breakpoint that shouldn't cause a stop and so needs stepping over immediately (e.g., "b foo if 0"). This sets stepping_over_breakpoint=1, and keeps going. Say an asynchronous pass/nostop signal happens while trying to step over that breakpoint, and we see it before the "step" finishes. While handling it, we end up in keep_going, here, because we already had a step-resume breakpoint set, I think: /* Note: step_resume_breakpoint may be non-NULL. This occures when either there's a nested signal, or when there's a pending signal enabled just as the signal handler returns (leaving the inferior at the step-resume-breakpoint without actually executing it). Either way continue until the breakpoint is really hit. */ keep_going (ecs); return; } eventually re-reaching resume with trap_expected set, sss breakpoints inserted, and with a signal to deliver. Since you'll already have one step-resume breakpoint set (back in the main code), and you can't set another -- you'd hit the assert in insert_step_resume_breakpoint_at_sal trying to insert a second one. But I'm not certain I'm guessing the flow correctly on software-step archs. Here's a small test that nests SIGSEGV handlers. Setting a breakpoint at the *(int *)p lines like I mentioned above should do the trick. #include #include #include static void *p; static void handler (int sig, siginfo_t *info, void *context) { /* Trigger a nested SIGSEGV. */ *(int *)p = 0; _exit (0); } int main (void) { /* Set up the signal handler. */ struct sigaction action; memset (&action, 0, sizeof (action)); action.sa_sigaction = handler; action.sa_flags |= SA_SIGINFO | SA_NODEFER; if (sigaction (SIGSEGV, &action, NULL)) { perror ("sigaction"); return 1; } /* Trigger SIGSEGV. */ *(int *)p = 0; return 0; } -- Pedro Alves