Files
binutils-gdb/gdb/testsuite/gdb.dwarf2/dw2-step-out-of-function-no-stmt.c
Tom de Vries ebde6f2ddc [gdb/breakpoint] Fix stepping past non-stmt line-table entries
Consider the test-case small.c:
...
$ cat -n small.c
     1  __attribute__ ((noinline, noclone))
     2  int foo (char *c)
     3  {
     4    asm volatile ("" : : "r" (c) : "memory");
     5    return 1;
     6  }
     7
     8  int main ()
     9  {
    10    char tpl1[20] = "/tmp/test.XXX";
    11    char tpl2[20] = "/tmp/test.XXX";
    12    int fd1 = foo (tpl1);
    13    int fd2 = foo (tpl2);
    14    if (fd1 == -1) {
    15      return 1;
    16    }
    17
    18    return 0;
    19  }
...

Compiled with gcc-8 and optimization:
...
$ gcc-8 -O2 -g small.c
...

We step through the calls to foo, but fail to visit line 13:
...
12	  int fd1 = foo (tpl1);
(gdb) step
foo (c=c@entry=0x7fffffffdea0 "/tmp/test.XXX") at small.c:5
5	  return 1;
(gdb) step
foo (c=c@entry=0x7fffffffdec0 "/tmp/test.XXX") at small.c:5
5	  return 1;
(gdb) step
main () at small.c:14
14	  if (fd1 == -1) {
(gdb)
...

This is caused by the following.  The calls to foo are implemented by these
insns:
....
  4003df:       0f 29 04 24             movaps %xmm0,(%rsp)
  4003e3:       0f 29 44 24 20          movaps %xmm0,0x20(%rsp)
  4003e8:       e8 03 01 00 00          callq  4004f0 <foo>
  4003ed:       48 8d 7c 24 20          lea    0x20(%rsp),%rdi
  4003f2:       89 c2                   mov    %eax,%edx
  4003f4:       e8 f7 00 00 00          callq  4004f0 <foo>
  4003f9:       31 c0                   xor    %eax,%eax
...
with corresponding line table entries:
...
INDEX  LINE   ADDRESS            IS-STMT
8      12     0x00000000004003df Y
9      10     0x00000000004003df
10     11     0x00000000004003e3
11     12     0x00000000004003e8
12     13     0x00000000004003ed
13     12     0x00000000004003f2
14     13     0x00000000004003f4 Y
15     13     0x00000000004003f4
16     14     0x00000000004003f9 Y
17     14     0x00000000004003f9
...

Once we step out of the call to foo at 4003e8, we land at 4003ed, and gdb
enters process_event_stop_test to figure out what to do.

That entry has is-stmt=n, so it's not the start of a line, so we don't stop
there.  However, we do update ecs->event_thread->current_line to line 13,
because the frame has changed (because we stepped out of the function).

Next we land at 4003f2.  Again the entry has is-stmt=n, so it's not the start
of a line, so we don't stop there.  However, because the frame hasn't changed,
we don't update update ecs->event_thread->current_line, so it stays 13.

Next we land at 4003f4.  Now is-stmt=y, so it's the start of a line, and we'd
like to stop here.

But we don't stop because this test fails:
...
  if ((ecs->event_thread->suspend.stop_pc == stop_pc_sal.pc)
      && (ecs->event_thread->current_line != stop_pc_sal.line
          || ecs->event_thread->current_symtab != stop_pc_sal.symtab))
    {
...
because ecs->event_thread->current_line == 13 and stop_pc_sal.line == 13.

Fix this by resetting ecs->event_thread->current_line to 0 if is-stmt=n and
the frame has changed, such that we have:
...
12        int fd1 = foo (tpl1);
(gdb) step
foo (c=c@entry=0x7fffffffdbc0 "/tmp/test.XXX") at small.c:5
5         return 1;
(gdb) step
main () at small.c:13
13        int fd2 = foo (tpl2);
(gdb)
...

Tested on x86_64-linux, with gcc-7 and gcc-8.

gdb/ChangeLog:

2021-01-29  Tom de Vries  <tdevries@suse.de>

	PR breakpoints/26063
	* infrun.c (process_event_stop_test): Reset
	ecs->event_thread->current_line to 0 if is-stmt=n and frame has
	changed.

gdb/testsuite/ChangeLog:

2021-01-29  Tom de Vries  <tdevries@suse.de>

	PR breakpoints/26063
	* gdb.dwarf2/dw2-step-out-of-function-no-stmt.c: New test.
	* gdb.dwarf2/dw2-step-out-of-function-no-stmt.exp: New file.
2021-01-29 13:36:52 +01:00

45 lines
974 B
C

/*
Copyright 2021 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
void
foo (int x)
{
}
void
bar (void)
{
asm ("bar_label: .globl bar_label");
}
int
main (void)
{
asm ("main_label: .globl main_label");
bar ();
asm ("main_label_2: .globl main_label_2");
foo (10);
asm ("main_label_3: .globl main_label_3");
return 0;
}