From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 57979 invoked by alias); 17 Mar 2016 12:12:57 -0000 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 Received: (qmail 57962 invoked by uid 89); 17 Mar 2016 12:12:57 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.9 required=5.0 tests=BAYES_00,KAM_LAZY_DOMAIN_SECURITY,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=no version=3.3.2 spammy=lean, cancelled, traps, remembering X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Thu, 17 Mar 2016 12:12:55 +0000 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (Postfix) with ESMTPS id 818C6C0AEE4D; Thu, 17 Mar 2016 12:12:54 +0000 (UTC) Received: from [127.0.0.1] (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u2HCCrN3031809; Thu, 17 Mar 2016 08:12:53 -0400 Subject: Re: [PATCH 3/8] Deliver signal in hardware single step To: Yao Qi References: <1457088276-1170-1-git-send-email-yao.qi@linaro.org> <1457088276-1170-4-git-send-email-yao.qi@linaro.org> <56E2A685.2080602@redhat.com> <56E2A753.9060805@redhat.com> <56E2AE04.7030306@redhat.com> <86io0mya1n.fsf@gmail.com> Cc: gdb-patches@sourceware.org From: Pedro Alves Message-ID: <56EA9F45.7050409@redhat.com> Date: Thu, 17 Mar 2016 12:12:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.6.0 MIME-Version: 1.0 In-Reply-To: <86io0mya1n.fsf@gmail.com> Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-SW-Source: 2016-03/txt/msg00308.txt.bz2 On 03/16/2016 10:47 AM, Yao Qi wrote: > Pedro Alves writes: > > Hi Pedro, > >> - If there's a signal handler installed, we'll stop at its entry, >> but we haven't stepped over the original breakpoint yet. If we >> were already stopped at the entry of the signal handler, and it >> nested, we'll find the program stopped at the same PC it had >> started at. But we won't know whether the step-over finished >> successfully (could be a "jmp $pc" instruction), or if instead we're >> in a new handler invocation, and thus this is a new, >> separate breakpoint hit. > > GDBserver doesn't have to tell the program stopped at the same PC > it had started at when step over is finished. When step over, GDBserver > uninsert breakpoint, resumes the lwp, and wait the next event from the > lwp. Once the event from the lwp arrives, GDBserver reinsert breakpoint > and thinks step over is finished. That is all ... > >> >> A signal handler that segfaults in the first instruction >> would be the easiest way to reproduce this that I can think of. >> (If it's crashing, you'd expect the user might try putting a >> breakpoint there.) > > I write a case like this, set the conditional breakpoint on the first > instruction of handler, and looks breakpoint condition in target side > still works properly. > > (gdb) disassemble handler > Dump of assembler code for function handler: > 0x0000000000400586 <+0>: movb $0x0,0x0 > 0x000000000040058e <+8>: retq > > (gdb) p/x $rsp > $1 = 0x7fffffffde00 > (gdb) b *handler if $rsp < 0x7fffffffde00 - 3300 > > the condition like this can guarantee that the condition will be true > after several recursions. > >> >> Now, if after stepping into the handler, we immediately reinsert the >> breakpoint and continue, we'll retrap it, it ends up OK. > > breakpoint is reinserted after stepping into the handler, because > GDBserver thinks step over is finished, as I said above. > >> But if we immediately instead start a new step-over for the same >> breakpoint address, we will miss the new hit, and nest a new handler, >> on and on. > > This won't happen. After hardware single step with signal delivered, > the program stops at the entry of handler, and GDBserver gets an event. > Then, GDBserver thinks step over is finished, and then proceed all lwps. > However, the thread still stopped at the breakpoint (of different > stack frames), so it needs step over again. > The loop like this will go > on until the breakpoint condition is true, need_step_over_p decides to > resume rather than step over. The program will hit the breakpoint, and > GDBserver reports the event back to GDB. > > Note in my experiment with the test case above, I don't let GDBserver > treat SIGSEGV as SIGTRAP, otherwise SIGSEGV will be reported back to GDB. > OK. We need to think of unconditional tracepoints as well, not just conditional breakpoints, however. Here's a likely scenario, that I think will happen: #1 - tracepoint set at 0xf00. #2 - Program stops at 0xf00, tracepoint is collected. #3 - gdbserver starts a step-over #4 - instead, a signal arrives, step-over cancelled. #5 - signal should be passed, not reported to gdb. #6 - gdbserver starts a new step-over, passing signal as well. #7 - step lands in handler. step over finished. #8 - gdbserver proceeds/continues #9 - signal handler returns, again to 0xf00, tracepoint traps again and is thus collected again. This is a spurious collection. gdb avoids the spurious double-hit in #9 by remembering that it was stepping over a breakpoint when a signal arrived, in order to continue the step over once the handler returns (tp->step_after_step_resume_breakpoint). This only works if the handler doesn't cause some other unrelated user-visible stop -- in that case, then the next time the user continues the program, and the handler returns to the original breakpoint address, we'll still report a new breakpoint hit. I think. Maybe we can just not bother and live with the spurious double tracepoint hit/collect in gdbserver. (Likewise dprintf.) Dunno, but I'm now starting to lean toward that. Thanks, Pedro Alves