[PATCHv5 05/11] gdb: don't always print breakpoint location after failed condition check
Andrew Burgess
aburgess@redhat.com
Mon Apr 3 13:51:04 GMT 2023
Andrew Burgess <aburgess@redhat.com> writes:
> Consider the following session:
>
> (gdb) list some_func
> 1 int
> 2 some_func ()
> 3 {
> 4 int *p = 0;
> 5 return *p;
> 6 }
> 7
> 8 void
> 9 foo ()
> 10 {
> (gdb) break foo if (some_func ())
> Breakpoint 1 at 0x40111e: file bpcond.c, line 11.
> (gdb) r
> Starting program: /tmp/bpcond
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0000000000401116 in some_func () at bpcond.c:5
> 5 return *p;
> Error in testing condition for breakpoint 1:
> The program being debugged stopped while in a function called from GDB.
> Evaluation of the expression containing the function
> (some_func) will be abandoned.
> When the function is done executing, GDB will silently stop.
>
> Breakpoint 1, 0x0000000000401116 in some_func () at bpcond.c:5
> 5 return *p;
> (gdb)
>
> What happens here is the breakpoint condition includes a call to an
> inferior function, and the inferior function segfaults. We can see
> that GDB reports the segfault, and then gives an error message that
> indicates that an inferior function call was interrupted.
>
> After this GDB appears to report that it is stopped at Breakpoint 1,
> inside some_func.
>
> I find this second stop report a little confusing. While it is true
> that GDB stopped as a result of hitting breakpoint 1, I think the
> message GDB currently prints might give the impression that GDB is
> actually stopped at a location of breakpoint 1, which is not the case.
>
> Also, I find the second stop message draws attention away from
> the "Program received signal SIGSEGV, Segmentation fault" stop
> message, and this second stop might be thought of as replacing in
> someway the earlier message.
>
> In short, I think things would be clearer if the second stop message
> were not reported at all, so the output should, I think, look like
> this:
>
> (gdb) list some_func
> 1 int
> 2 some_func ()
> 3 {
> 4 int *p = 0;
> 5 return *p;
> 6 }
> 7
> 8 void
> 9 foo ()
> 10 {
> (gdb) break foo if (some_func ())
> Breakpoint 1 at 0x40111e: file bpcond.c, line 11.
> (gdb) r
> Starting program: /tmp/bpcond
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0000000000401116 in some_func () at bpcond.c:5
> 5 return *p;
> Error in testing condition for breakpoint 1:
> The program being debugged stopped while in a function called from GDB.
> Evaluation of the expression containing the function
> (some_func) will be abandoned.
> When the function is done executing, GDB will silently stop.
> (gdb)
>
> The user can still find the number of the breakpoint that triggered
> the initial stop in this line:
>
> Error in testing condition for breakpoint 1:
>
> But there's now only one stop reason reported, the SIGSEGV, which I
> think is much clearer.
>
> To achieve this change I set the bpstat::print field when:
>
> (a) a breakpoint condition evaluation failed, and
>
> (b) the $pc of the thread changed during condition evaluation.
>
> I've updated the existing tests that checked the error message printed
> when a breakpoint condition evaluation failed.
I went ahead and pushed this commit.
If there are any problems, please let me know, I'm happy to address any
issues.
Thanks,
Andrew
> ---
> gdb/breakpoint.c | 12 ++++++++++++
> gdb/testsuite/gdb.base/infcall-failure.exp | 18 ++++++++----------
> 2 files changed, 20 insertions(+), 10 deletions(-)
>
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index dcd42e6b2e2..445b46a706a 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -5534,6 +5534,7 @@ bpstat_check_breakpoint_conditions (bpstat *bs, thread_info *thread)
> else
> within_current_scope = false;
> }
> + CORE_ADDR pc_before_check = get_frame_pc (get_selected_frame (nullptr));
> if (within_current_scope)
> {
> try
> @@ -5545,6 +5546,17 @@ bpstat_check_breakpoint_conditions (bpstat *bs, thread_info *thread)
> exception_fprintf (gdb_stderr, ex,
> "Error in testing condition for breakpoint %d:\n",
> b->number);
> +
> + /* If the pc value changed as a result of evaluating the
> + condition then we probably stopped within an inferior
> + function call due to some unexpected stop, e.g. the thread
> + hit another breakpoint, or the thread received an
> + unexpected signal. In this case we don't want to also
> + print the information about this breakpoint. */
> + CORE_ADDR pc_after_check
> + = get_frame_pc (get_selected_frame (nullptr));
> + if (pc_before_check != pc_after_check)
> + bs->print = 0;
> }
> }
> else
> diff --git a/gdb/testsuite/gdb.base/infcall-failure.exp b/gdb/testsuite/gdb.base/infcall-failure.exp
> index 214a64f8de3..5ad179a089d 100644
> --- a/gdb/testsuite/gdb.base/infcall-failure.exp
> +++ b/gdb/testsuite/gdb.base/infcall-failure.exp
> @@ -78,10 +78,7 @@ proc_with_prefix run_cond_hits_breakpoint_test { async_p non_stop_p } {
> "The program being debugged stopped while in a function called from GDB\\." \
> "Evaluation of the expression containing the function" \
> "\\(func_bp\\) will be abandoned\\." \
> - "When the function is done executing, GDB will silently stop\\." \
> - "" \
> - "Breakpoint ${bp_1_num}, \[^\r\n\]+" \
> - "${::decimal}\\s+\[^\r\n\]+Second breakpoint\[^\r\n\]+"]
> + "When the function is done executing, GDB will silently stop\\."]
> }
>
> # Start GDB according to ASYNC_P and NON_STOP_P, then call an inferior
> @@ -138,13 +135,12 @@ proc_with_prefix run_cond_hits_segfault_test { async_p non_stop_p } {
> "${::hex} in func_segfault \\(\\) at \[^\r\n\]+:${::segv_line}" \
> "${::decimal}\\s+\[^\r\n\]+Segfault here\[^\r\n\]+" \
> "Error in testing condition for breakpoint ${bp_1_num}:" \
> - "The program being debugged stopped while in a function called from GDB\\." \
> + "The program being debugged was signaled while in a function called from GDB\\." \
> + "GDB remains in the frame where the signal was received\\." \
> + "To change this behavior use \"set unwindonsignal on\"\\." \
> "Evaluation of the expression containing the function" \
> "\\(func_segfault\\) will be abandoned\\." \
> - "When the function is done executing, GDB will silently stop\\." \
> - "" \
> - "Breakpoint ${bp_1_num}, \[^\r\n\]+" \
> - "${::decimal}\\s+\[^\r\n\]+Segfault here\[^\r\n\]+"]
> + "When the function is done executing, GDB will silently stop\\."]
> }
>
> # Start GDB according to ASYNC_P and NON_STOP_P, then call an inferior
> @@ -168,7 +164,9 @@ proc_with_prefix run_call_hits_segfault_test { async_p non_stop_p } {
> "Program received signal SIGSEGV, Segmentation fault\\." \
> "${::hex} in func_segfault \\(\\) at \[^\r\n\]+:${::segv_line}" \
> "${::decimal}\\s+\[^\r\n\]+Segfault here\[^\r\n\]+" \
> - "The program being debugged stopped while in a function called from GDB\\." \
> + "The program being debugged was signaled while in a function called from GDB\\." \
> + "GDB remains in the frame where the signal was received\\." \
> + "To change this behavior use \"set unwindonsignal on\"\\." \
> "Evaluation of the expression containing the function" \
> "\\(func_segfault\\) will be abandoned\\." \
> "When the function is done executing, GDB will silently stop\\."]
> --
> 2.25.4
More information about the Gdb-patches
mailing list