public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Simon Marchi <simon.marchi@polymtl.ca>
To: Andrew Burgess <aburgess@redhat.com>, gdb-patches@sourceware.org
Cc: pedro@palves.net
Subject: Re: [PATCH 2/2] gdb: MI stopped events when unwindonsignal is on
Date: Tue, 29 Aug 2023 12:37:06 -0400	[thread overview]
Message-ID: <73807dfe-139f-431f-928c-ba7695cfc1cf@polymtl.ca> (raw)
In-Reply-To: <dd2debeecb1522b6b15c51bcaa367316228709dd.1691505844.git.aburgess@redhat.com>

On 8/8/23 10:45, Andrew Burgess via Gdb-patches wrote:
> This recent commit:
> 
>   commit b1c0ab20809a502b2d2224fecb0dca3ada2e9b22
>   Date:   Wed Jul 12 21:56:50 2023 +0100
> 
>       gdb: avoid double stop after failed breakpoint condition check
> 
> Addressed a problem where two MI stopped events would be reported if a
> breakpoint condition failed due to a signal, this commit was a
> replacement for this commit:
> 
>   commit 2e411b8c68eb2b035b31d5b00d940d4be1a0928b
>   Date:   Fri Oct 14 14:53:15 2022 +0100
> 
>       gdb: don't always print breakpoint location after failed condition check
> 
> which solved the two stop problem, but only for the CLI.  Before both
> of these commits, if a b/p condition failed due to a signal then the
> user would see two stops reported, the first at the location where the
> signal occurred, and the second at the location of the breakpoint.
> 
> By default GDB remains at the location where the signal occurred, so
> the second reported stop can be confusing, this is the problem that
> commit 2e411b8c68eb tried to solve (for the CLI) and b1c0ab20809a
> extended also address the issue for MI too.
> 
> However, while working on another patch I realised that there was a
> problem with GDB after the above commits.  Neither of the above
> commits considered 'set unwindonsignal on'.  With this setting on,
> when an inferior function call fails with a signal GDB will unwind the
> stack back to the location where the inferior function call started.
> In the b/p case we're looking at, the stop should be reported at the
> location of the breakpoint, not at the location where the signal
> occurred, and this isn't what happens.
> 
> This commit fixes this by ensuring that when unwindonsignal is 'on',
> GDB reports a single stop event at the location of the breakpoint,
> this fixes things for both CLI and MI.
> 
> The function call_thread_fsm::should_notify_stop is called when the
> inferior function call completes and GDB is figuring out if the user
> should be notified about this stop event by calling normal_stop from
> fetch_inferior_event in infrun.c.  If normal_stop is called, then this
> notification will be for the location where the inferior call stopped,
> which will be the location at which the signal occurred.
> 
> Prior to this commit, the only time that normal_stop was not called,
> was if the inferior function call completed successfully, this was
> controlled by ::should_notify_stop, which only turns false when the
> inferior function call has completed successfully.
> 
> In this commit I have extended the logic in ::should_notify_stop.  Now
> there are three cases in which ::should_notify_stop will return false,
> and we will not announce the first stop (by calling normal_stop).
> These three reasons are:
> 
>   1. If the inferior function call completes successfully, this is
>   unchanged behaviour,
> 
>   2. If the inferior function call stopped due to a signal and 'set
>   unwindonsignal on' is in effect, and
> 
>   3. If the inferior function call stopped due to an uncaught C++
>   exception, and 'set unwind-on-terminating-exception on' is in
>   effect.
> 
> However, if we don't call normal_stop then we need to call
> async_enable_stdin in call_thread_fsm::should_stop.  Prior to this
> commit this was only done for the case where the inferior function
> call completed successfully.
> 
> In this commit I now call ::should_notify_stop and use this to
> determine if we need to call async_enable_stdin.  With this done we
> now call async_enable_stdin for each of the three cases listed above,
> which means that GDB will exit wait_sync_command_done correctly (see
> run_inferior_call in infcall.c).
> 
> With these two changes the problem is mostly resolved.  However, the
> solution isn't ideal, we've still lost some information.
> 
> Here is how GDB 13.1 behaves, this is before commits b1c0ab20809a and
> 2e411b8c68eb:
> 
>   $ gdb -q /tmp/mi-condbreak-fail \
>         -ex 'set unwindonsignal on' \
>         -ex 'break 30 if (cond_fail())' \
>         -ex 'run'
>   Reading symbols from /tmp/mi-condbreak-fail...
>   Breakpoint 1 at 0x40111e: file /tmp/mi-condbreak-fail.c, line 30.
>   Starting program: /tmp/mi-condbreak-fail
> 
>   Program received signal SIGSEGV, Segmentation fault.
>   0x0000000000401116 in cond_fail () at /tmp/mi-condbreak-fail.c:24
>   24	  return *p;			/* Crash here.  */
>   Error in testing breakpoint condition:
>   The program being debugged was signaled while in a function called from GDB.
>   GDB has restored the context to what it was before the call.
>   To change this behavior use "set unwindonsignal off".
>   Evaluation of the expression containing the function
>   (cond_fail) will be abandoned.
> 
>   Breakpoint 1, foo () at /tmp/mi-condbreak-fail.c:30
>   30	  global_counter += 1;		/* Set breakpoint here.  */
>   (gdb)
> 
> In this state we see two stop notifications, the first is where the
> signal occurred, while the second is where the breakpoint is located.
> As GDB has unwound the stack (thanks to unwindonsignal) the second
> stop notification reflects where the inferior is actually located.
> 
> Then after commits b1c0ab20809a and 2e411b8c68eb the behaviour changed
> to this:
> 
>   $ gdb -q /tmp/mi-condbreak-fail \
>         -ex 'set unwindonsignal on' \
> 	-ex 'break 30 if (cond_fail())' \
> 	-ex 'run'
>   Reading symbols from /tmp/mi-condbreak-fail...
>   Breakpoint 1 at 0x40111e: file /tmp/mi-condbreak-fail.c, line 30.
>   Starting program: /tmp/mi-condbreak-fail
> 
>   Program received signal SIGSEGV, Segmentation fault.
>   0x0000000000401116 in cond_fail () at /tmp/mi-condbreak-fail.c:24
>   24	  return *p;			/* Crash here.  */
>   Error in testing condition for breakpoint 1:
>   The program being debugged was signaled while in a function called from GDB.
>   GDB has restored the context to what it was before the call.
>   To change this behavior use "set unwindonsignal off".
>   Evaluation of the expression containing the function
>   (cond_fail) will be abandoned.
>   (gdb) bt 1
>   #0  foo () at /tmp/mi-condbreak-fail.c:30
>   (More stack frames follow...)
>   (gdb)
> 
> This is the broken state.  GDB is reports the SIGSEGV location, but
> not the unwound breakpoint location.  The final 'bt 1' shows that the
> inferior is not located in cond_fail, which is the only location GDB
> reported, so this is clearly wrong.
> 
> After implementing the fixes described above we now get this
> behaviour:
> 
>   $ gdb -q /tmp/mi-condbreak-fail \
>         -ex 'set unwindonsignal on' \
>         -ex 'break 30 if (cond_fail())' \
>         -ex 'run'
>   Reading symbols from /tmp/mi-condbreak-fail...
>   Breakpoint 1 at 0x40111e: file /tmp/mi-condbreak-fail.c, line 30.
>   Starting program: /tmp/mi-condbreak-fail
>   Error in testing breakpoint condition for breakpoint 1:
>   The program being debugged was signaled while in a function called from GDB.
>   GDB has restored the context to what it was before the call.
>   To change this behavior use "set unwindonsignal off".
>   Evaluation of the expression containing the function
>   (cond_fail) will be abandoned.
> 
>   Breakpoint 1, foo () at /tmp/mi-condbreak-fail.c:30
>   30	  global_counter += 1;		/* Set breakpoint here.  */
>   (gdb)
> 
> This is better.  GDB now reports a single stop at the location of the
> breakpoint, which is where the inferior is actually located.  However,
> by removing the first stop notification we have lost some potentially
> useful information about which signal caused the inferior to stop.
> 
> To address this I've reworked the message that is printed to include
> the signal information.  GDB now reports this:
> 
>   $ gdb -q /tmp/mi-condbreak-fail \
>         -ex 'set unwindonsignal on' \
>         -ex 'break 30 if (cond_fail())' \
>         -ex 'run'
>   Reading symbols from /tmp/mi-condbreak-fail...
>   Breakpoint 1 at 0x40111e: file /tmp/mi-condbreak-fail.c, line 30.
>   Starting program: /tmp/mi-condbreak-fail
>   Error in testing condition for breakpoint 1:
>   The program being debugged received signal SIGSEGV, Segmentation fault
>   while in a function called from GDB.  GDB has restored the context
>   to what it was before the call.  To change this behavior use
>   "set unwindonsignal off".  Evaluation of the expression containing
>   the function (cond_fail) will be abandoned.
> 
>   Breakpoint 1, foo () at /tmp/mi-condbreak-fail.c:30
>   30	  global_counter += 1;		/* Set breakpoint here.  */
>   (gdb)
> 
> This is better, the user now sees a single stop notification at the
> correct location, and the error message describes which signal caused
> the inferior function call to stop.
> 
> However, we have lost the information about where the signal
> occurred.  I did consider trying to include this information in the
> error message, but, in the end, I opted not too.  I wasn't sure it was
> worth the effort.  If the user has selected to unwind on signal, then
> surely this implies they maybe aren't interested in debugging failed
> inferior calls, so, hopefully, just knowing the signal name will be
> enough.  I figure we can always add this information in later if
> there's a demand for it.

Hi Andrew,

Starting with this commit, I see this failure with the native-gdbserver
board:

FAIL: gdb.mi/mi-condbreak-throw.exp: unwind_on_exception=off: wait for stop (unexpected output)

Do you see it?

Simon

  parent reply	other threads:[~2023-08-29 16:37 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-08 14:45 [PATCH 0/2] Stop notifications " Andrew Burgess
2023-08-08 14:45 ` [PATCH 1/2] gdb/testsuite: add mi_info_frame helper proc (and use it) Andrew Burgess
2023-08-08 14:45 ` [PATCH 2/2] gdb: MI stopped events when unwindonsignal is on Andrew Burgess
2023-08-10 15:06   ` Thiago Jung Bauermann
2023-08-14 14:50     ` Andrew Burgess
2023-08-15  0:32       ` Thiago Jung Bauermann
2023-08-16 14:28         ` Andrew Burgess
2023-08-18 21:56           ` Thiago Jung Bauermann
2023-08-23  9:33             ` Andrew Burgess
2023-08-29 16:37   ` Simon Marchi [this message]
2023-09-08  8:54     ` Andrew Burgess
2023-09-08 10:03     ` Andrew Burgess

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=73807dfe-139f-431f-928c-ba7695cfc1cf@polymtl.ca \
    --to=simon.marchi@polymtl.ca \
    --cc=aburgess@redhat.com \
    --cc=gdb-patches@sourceware.org \
    --cc=pedro@palves.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).