[gdb/breakpoint] Fix stepping past non-stmt line-table entries
authorTom de Vries <tdevries@suse.de>
Fri, 29 Jan 2021 12:36:52 +0000 (13:36 +0100)
committerTom de Vries <tdevries@suse.de>
Fri, 29 Jan 2021 12:36:52 +0000 (13:36 +0100)
commitebde6f2ddc987e7e2d5a218ee8cf0126ec189424
tree0139faae85bca87713ab18a3a6fa2fff412961c0
parent620ec3caae78dd969fc4bdad7fad4248f52386d5
[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.
gdb/ChangeLog
gdb/infrun.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.dwarf2/dw2-step-out-of-function-no-stmt.c [new file with mode: 0644]
gdb/testsuite/gdb.dwarf2/dw2-step-out-of-function-no-stmt.exp [new file with mode: 0644]