From: Guinevere Larsen <blarsen@redhat.com>
To: Carl Love <cel@us.ibm.com>, Simon Marchi <simark@simark.ca>,
gdb-patches@sourceware.org,
UlrichWeigand <Ulrich.Weigand@de.ibm.com>,
pedro@palves.net
Cc: luis.machado@arm.com
Subject: Re: [PATCH 2/2 ver 7] Fix reverse stepping multiple contiguous PC ranges over the line table.
Date: Tue, 8 Aug 2023 16:14:30 +0200 [thread overview]
Message-ID: <4771b172-902b-5995-d32d-494e6d6f5341@redhat.com> (raw)
In-Reply-To: <a930296aedf13b9eb79748e785b3e76d6cc0ac17.camel@us.ibm.com>
On 07/08/2023 21:03, Carl Love wrote:
>
> Bruno, Simon, GDB maintainers:
Heads up, I go by Guinevere now, no longer Bruno :)
Other than that, I have a very minor nit inlined, but you can take or
leave that one, honestly.
Reviewed-By: Guinevere Larsen <blarsen@redhat.com>
>
> Version 7, addressed behavior of GDB when stepping backward thru a
> function call as mentioned by Bruno. GDB would stop at the function
> call and then a reverse step/next would cause GDB to stop at the first
> instruction of the same line as the function call instead of stopping
> in the previous line. The behavior was fixed and the various test
> programs were updated to remove one of the two reverse step or next
> instructions required to reach the previous line.
>
> Version 6, fixed various code style issues in the GDB source. The
> testcases were updated to use with_test_prefix for each gdb test in the
> step and next test cases, switch using the standard_testfile, use
> foreach_with_prefix to combine otherwise identical tests. Retested on
> Power 10.
>
> Version 5, changed comments in test case func-map-to-same-line.c.
> Patch 1/2 implemented the new options for gdb_compile. Updated the
> call to proc run_tests to use the new gdb_compile options in a
> foreach_with_prefix loop.
>
> Version 4, additional fixes for gcc version check, wrap function calls
> using "with_test_prefix", move load_lib dwarf.exe. Fixed typo noted by
> Luis.
>
> Version 3, added the gcc version check as discussed further from
> version 2 of the patch. Also updated the tests to check for supporting
> reverse execution rather than requiring recording. I also noticed
> there were a couple more instances of a requirement check, i.e. if []
> which I changed to "require" per the current style for checking on the
> test requirements.
>
>
> The following patch fixes issues on PowerPC with the reverse-step and
> reverse-next instructions when there are multiple assignment statements
> on the same line and when there are multiple function calls on the same
> line. The commit log below discusses these issues in further depth.
> The discussion included what the correct operation should be for these
> commands based on the GDB documentation. The proposed patch at that
> time changed how the commands worked on other platforms such as X86 in
> a way they no longer matched the documentation.
>
> The issue is the line table contains multiple entries for the same
> source line. The patch adds a function to search the line table to
> find the address of the first instruction of a line. When setup up the
> reverse stepping range, the function is called to make sure the start
> of the range corresponds to the address of the first instruction for
> the line. This approach was used. When Luis initially developed the
> patch, he considered merging the contiguous ranges in the line table
> when reading the line tables. He decided it was better to work with the
> data directly in the line table rather than creating and using a
> modified version of the line table.
>
> The following patch fixes the execution of the reveres-step and
> reverse-next commands for both senarios of multiple statements on the
> same line for PowerPC and aarch64-linux. Unlike the previous patch, it
> does not change the operation of the commands on other platforms, i.e.
> X86. The patch adds new test cases for both scenarios to verify they
> work correctly.
>
> The patch has been tested on PowerPC, Intel X86 and aarch64-linux with
> no new regression failures.
>
> Please let me know if the patch is acceptable for mainline. Thanks.
>
> Carl
>
>
>
> --------------------------------
> Fix reverse stepping multiple contiguous PC ranges over the line table.
>
> There are a couple of scenarios where the GDB reverse-step and reverse-next
> commands do not work correctly.
>
> Scenario 1 issue description by Luis Machado:
>
> When running GDB's testsuite on aarch64-linux/Ubuntu 20.04 (also spotted on
> the ppc backend), I noticed some failures in gdb.reverse/solib-precsave.exp
> and gdb.reverse/solib-reverse.exp.
>
> The failure happens around the following code:
>
> 38 b[1] = shr2(17); /* middle part two */
> 40 b[0] = 6; b[1] = 9; /* generic statement, end part two */
> 42 shr1 ("message 1\n"); /* shr1 one */
>
> Normal execution:
>
> - step from line 38 will land on line 40.
> - step from line 40 will land on line 42.
>
> Reverse execution:
> - step from line 42 will land on line 40.
> - step from line 40 will land on line 40.
> - step from line 40 will land on line 38.
>
> V
> The problem here is that line 40 contains two contiguous but distinct
> PC ranges in the line table, like so:
>
> Line 40 - [0x7ec ~ 0x7f4]
> Line 40 - [0x7f4 ~ 0x7fc]
>
> The two distinct ranges are generated because GCC started outputting source
> column information, which GDB doesn't take into account at the moment.
>
> When stepping forward from line 40, we skip both of these ranges and land on
> line 42. When stepping backward from line 42, we stop at the start PC of the
> second (or first, going backwards) range of line 40.
>
> Since we've reached ecs->event_thread->control.step_range_start, we stop
> stepping backwards.
>
> ---------------------------------------------------------
>
> Scenario 2 issue described by Pedro Alves:
>
> The following explanation of the issue was taken from the gdb mailing list
> discussion of the withdrawn patch to change the behavior of the reverse-step
> and reverse-next commands. Specifically, message from Pedro Alves
> <pedro@palves.net> where he demonstrates the issue where you have multiple
> function calls on the same source code line:
>
> https://sourceware.org/pipermail/gdb-patches/2023-January/196110.html
>
> The source line looks like:
>
> func1 (); func2 ();
>
> so stepping backwards over that line should always stop at the first
> instruction of the line, not in the middle. Let's simplify this.
>
> Here's the full source code of my example:
>
> (gdb) list 1
> 1 void func1 ()
> 2 {
> 3 }
> 4
> 5 void func2 ()
> 6 {
> 7 }
> 8
> 9 int main ()
> 10 {
> 11 func1 (); func2 ();
> 12 }
>
> Compiled with:
>
> $ gcc reverse.c -o reverse -g3 -O0
> $ gcc -v
> ...
> gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)
>
> Now let's debug it with target record, using current gdb git master (f3d8ae90b236),
> without your patch:
>
> $ gdb ~/reverse
> GNU gdb (GDB) 14.0.50.20230124-git
> ...
> Reading symbols from /home/pedro/reverse...
> (gdb) start
> Temporary breakpoint 1 at 0x1147: file reverse.c, line 11.
> Starting program: /home/pedro/reverse
> [Thread debugging using libthread_db enabled]
> Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
>
> Temporary breakpoint 1, main () at reverse.c:11
> 11 func1 (); func2 ();
> (gdb) record
>
> (gdb) disassemble /s
> Dump of assembler code for function main:
> reverse.c:
> 10 {
> 0x000055555555513f <+0>: endbr64
> 0x0000555555555143 <+4>: push %rbp
> 0x0000555555555144 <+5>: mov %rsp,%rbp
>
> 11 func1 (); func2 ();
> => 0x0000555555555147 <+8>: mov $0x0,%eax
> 0x000055555555514c <+13>: call 0x555555555129 <func1>
> 0x0000555555555151 <+18>: mov $0x0,%eax
> 0x0000555555555156 <+23>: call 0x555555555134 <func2>
> 0x000055555555515b <+28>: mov $0x0,%eax
>
> 12 }
> 0x0000555555555160 <+33>: pop %rbp
> 0x0000555555555161 <+34>: ret
> End of assembler dump.
>
> (gdb) n
> 12 }
>
> So far so good, a "next" stepped over the whole of line 11 and stopped at line 12.
>
> Let's confirm where we are now:
>
> (gdb) disassemble /s
> Dump of assembler code for function main:
> reverse.c:
> 10 {
> 0x000055555555513f <+0>: endbr64
> 0x0000555555555143 <+4>: push %rbp
> 0x0000555555555144 <+5>: mov %rsp,%rbp
>
> 11 func1 (); func2 ();
> 0x0000555555555147 <+8>: mov $0x0,%eax
> 0x000055555555514c <+13>: call 0x555555555129 <func1>
> 0x0000555555555151 <+18>: mov $0x0,%eax
> 0x0000555555555156 <+23>: call 0x555555555134 <func2>
> 0x000055555555515b <+28>: mov $0x0,%eax
>
> 12 }
> => 0x0000555555555160 <+33>: pop %rbp
> 0x0000555555555161 <+34>: ret
> End of assembler dump.
>
> Good, we're at the first instruction of line 12.
>
> Now let's undo the "next", with "reverse-next":
>
> (gdb) reverse-next
> 11 func1 (); func2 ();
>
> Seemingly stopped at line 11. Let's see exactly where:
>
> (gdb) disassemble /s
> Dump of assembler code for function main:
> reverse.c:
> 10 {
> 0x000055555555513f <+0>: endbr64
> 0x0000555555555143 <+4>: push %rbp
> 0x0000555555555144 <+5>: mov %rsp,%rbp
>
> 11 func1 (); func2 ();
> 0x0000555555555147 <+8>: mov $0x0,%eax
> 0x000055555555514c <+13>: call 0x555555555129 <func1>
> => 0x0000555555555151 <+18>: mov $0x0,%eax
> 0x0000555555555156 <+23>: call 0x555555555134 <func2>
> 0x000055555555515b <+28>: mov $0x0,%eax
>
> 12 }
> 0x0000555555555160 <+33>: pop %rbp
> 0x0000555555555161 <+34>: ret
> End of assembler dump.
> (gdb)
>
> And lo, we stopped in the middle of line 11! That is a bug, we should have
> stepped back all the way to the beginning of the line. The "reverse-next"
> should have fully undone the prior "next" command.
>
> The above issues were fixed by introducing a new function that looks for
> adjacent PC ranges for the same line, until we notice a line change. Then
> we take that as the start PC of the range. The new start PC for the range
> is used for the control.step_range_start when setting up a step range.
>
> The test case gdb.reverse/map-to-same-line.exp is added to test the fix
> for the issues in scenario 1.
>
> The test case gdb.reverse/func-map-to-same-line.exp was added to test the
> fix for scenario 2 when the binary was compiled with and without line
> table information.
>
> bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28426
>
> Co-authored-by: Luis Machado <luis.machado@arm.com>
> Co-authored-by: Carl Love <cel@us.ibm.com>
> ---
> gdb/infcmd.c | 13 ++
> gdb/infrun.c | 59 +++++++
> gdb/symtab.c | 49 ++++++
> gdb/symtab.h | 16 ++
> gdb/testsuite/gdb.mi/mi-reverse.exp | 5 +-
> .../gdb.reverse/finish-reverse-next.exp | 42 ++---
> .../gdb.reverse/func-map-to-same-line.c | 37 +++++
> .../gdb.reverse/func-map-to-same-line.exp | 139 ++++++++++++++++
> gdb/testsuite/gdb.reverse/map-to-same-line.c | 58 +++++++
> .../gdb.reverse/map-to-same-line.exp | 153 ++++++++++++++++++
> 10 files changed, 537 insertions(+), 34 deletions(-)
> create mode 100644 gdb/testsuite/gdb.reverse/func-map-to-same-line.c
> create mode 100644 gdb/testsuite/gdb.reverse/func-map-to-same-line.exp
> create mode 100644 gdb/testsuite/gdb.reverse/map-to-same-line.c
> create mode 100644 gdb/testsuite/gdb.reverse/map-to-same-line.exp
>
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 15702f84894..add0eadd8c1 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -982,6 +982,19 @@ prepare_one_step (thread_info *tp, struct step_command_fsm *sm)
> &tp->control.step_range_start,
> &tp->control.step_range_end);
>
> + if (execution_direction == EXEC_REVERSE)
> + {
> + symtab_and_line sal = find_pc_line (pc, 0);
> + symtab_and_line sal_start
> + = find_pc_line (tp->control.step_range_start, 0);
> +
> + if (sal.line == sal_start.line)
> + /* Executing in reverse, the step_range_start address is in
> + the same line. We want to stop in the previous line so
> + move step_range_start before the current line. */
> + tp->control.step_range_start--;
> + }
> +
> /* There's a problem in gcc (PR gcc/98780) that causes missing line
> table entries, which results in a too large stepping range.
> Use inlined_subroutine info to make the range more narrow. */
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 8286026e6c6..32ba852f227 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -115,6 +115,9 @@ static struct async_event_handler *infrun_async_inferior_event_token;
> Starts off as -1, indicating "never enabled/disabled". */
> static int infrun_is_async = -1;
>
> +static CORE_ADDR update_line_range_start (CORE_ADDR pc,
> + struct execution_control_state *ecs);
> +
> /* See infrun.h. */
>
> void
> @@ -6884,6 +6887,27 @@ handle_signal_stop (struct execution_control_state *ecs)
> process_event_stop_test (ecs);
> }
>
> +/* Return the address for the beginning of the line. */
> +
> +CORE_ADDR
> +update_line_range_start (CORE_ADDR pc, struct execution_control_state *ecs)
> +{
> + /* The line table may have multiple entries for the same source code line.
> + Given the PC, check the line table and return the PC that corresponds
> + to the line table entry for the source line that PC is in. */
> + CORE_ADDR start_line_pc = ecs->event_thread->control.step_range_start;
> + gdb::optional<CORE_ADDR> real_range_start;
> +
> + /* Call find_line_range_start to get the smallest address in the
> + linetable for multiple Line X entries in the line table. */
> + real_range_start = find_line_range_start (pc);
> +
> + if (real_range_start.has_value ())
> + start_line_pc = *real_range_start;
> +
> + return start_line_pc;
> +}
> +
> /* Come here when we've got some debug event / signal we can explain
> (IOW, not a random signal), and test whether it should cause a
> stop, or whether we should resume the inferior (transparently).
> @@ -7685,6 +7709,28 @@ process_event_stop_test (struct execution_control_state *ecs)
>
> if (stop_pc_sal.is_stmt)
> {
> + if (execution_direction == EXEC_REVERSE)
> + {
> + /* We are stepping backwards make sure we have reached the
> + beginning of the line. */
> + CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
> + CORE_ADDR start_line_pc
> + = update_line_range_start (stop_pc, ecs);
> +
> + if (stop_pc != start_line_pc)
> + {
> + /* Have not reached the beginning of the source code line.
> + Set a step range. Execution should stop in any function
> + calls we execute back into before reaching the beginning
> + of the line. */
> + ecs->event_thread->control.step_range_start = start_line_pc;
> + ecs->event_thread->control.step_range_end = stop_pc;
> + set_step_info (ecs->event_thread, frame, stop_pc_sal);
> + keep_going (ecs);
> + return;
> + }
> + }
> +
> /* We are at the start of a statement.
>
> So stop. Note that we don't stop if we step into the middle of a
> @@ -7747,6 +7793,19 @@ process_event_stop_test (struct execution_control_state *ecs)
> set_step_info (ecs->event_thread, frame, stop_pc_sal);
>
> infrun_debug_printf ("keep going");
> +
> + if (execution_direction == EXEC_REVERSE)
> + {
> + CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
> +
> + /* Make sure the stop_pc is set to the beginning of the line. */
> + if (stop_pc != ecs->event_thread->control.step_range_start)
> + {
> + stop_pc = update_line_range_start (stop_pc, ecs);
> + ecs->event_thread->control.step_range_start = stop_pc;
pretty small nit, but I think it is better to just use
ecs->event_thread->control.step_range_start
= update_line_range_start (stop_pc, ecs);
Just because it is kind of weird, to see the step_range_start being set
to stop pc, and made me do a double take :)
--
Cheers,
Guinevere Larsen
She/Her/Hers
next prev parent reply other threads:[~2023-08-08 14:14 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-07 18:54 [PATCH 0/2] " Carl Love
2023-08-07 19:03 ` [PATCH 1/2 ver 2] " Carl Love
2023-08-08 10:04 ` Guinevere Larsen
2023-08-08 15:38 ` Carl Love
2023-08-08 15:45 ` Guinevere Larsen
2023-08-07 19:03 ` [PATCH 2/2 ver 7] " Carl Love
2023-08-08 14:14 ` Guinevere Larsen [this message]
2023-08-08 15:52 ` Carl Love
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=4771b172-902b-5995-d32d-494e6d6f5341@redhat.com \
--to=blarsen@redhat.com \
--cc=Ulrich.Weigand@de.ibm.com \
--cc=cel@us.ibm.com \
--cc=gdb-patches@sourceware.org \
--cc=luis.machado@arm.com \
--cc=pedro@palves.net \
--cc=simark@simark.ca \
/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).