Bug 25528

Summary: step will stopped at any "asm volatile" statement
Product: gdb Reporter: Anonymous <iamanonymous.cs>
Component: gdbAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED NOTABUG    
Severity: critical CC: iamanonymous.cs, vries
Priority: P2    
Version: HEAD   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:

Description Anonymous 2020-02-10 16:18:40 UTC
$ gdb -v
GNU gdb (GDB) 9.0.50.20191210-git
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++,d --enable-shared --enable-threads=posix --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-multilib --disable-werror --enable-checking=release --enable-default-pie --enable-default-ssp --enable-cet=auto gdc_include_dir=/usr/include/dlang/gdc
Thread model: posix
gcc version 9.2.0 (GCC) 

$ cat small.c
const signed char NM[] = {-1, 0, 1};

__attribute__((noinline)) void f(short delta)
{
  short p = 2, s;
  for (s = 0; s < 2; s++)
  {
    p += delta;
    if (NM[p] == 0)
      asm volatile("");
  }
}

void main(void) { f(-1); }


$ gcc -g small.c

$ gdb -q ./a.out
Reading symbols from ./a.out...
(gdb) break small.c:9
Breakpoint 1 at 0x113f: file small.c, line 9.
(gdb) run
Starting program: /home/yibiao/cv-gcov/a.out 

Breakpoint 1, f (delta=-1) at small.c:9
9	    if (NM[p] == 0)
(gdb) step
10	      asm volatile("");
(gdb) c
Continuing.

Breakpoint 1, f (delta=-1) at small.c:9
9	    if (NM[p] == 0)
(gdb) step
10	      asm volatile("");
(gdb) q
A debugging session is active.

	Inferior 1 [process 4947] will be killed.

Quit anyway? (y or n) y



###############################################################################
### We can find that Line #10 @asm volatile("");@ is executed twice. 
### However, it is obvious that Line #9 "if (NM[p] == 0)" is True in the second for loop. 
###############################################################################
Comment 1 Anonymous 2020-12-29 03:33:51 UTC
In current version of GDB, statement with asm volatile will be skipped.

I was wondering that this is the default behavior of GDB.

Therefore, I think this bug in previous version is a bug of GDB.
Comment 2 Tom de Vries 2020-12-30 17:02:58 UTC
(In reply to Yibiao Yang from comment #1)
> In current version of GDB, statement with asm volatile will be skipped.
> 
> I was wondering that this is the default behavior of GDB.
> 

Compiling with gcc 9.3.1, and looking at the line info using readline -wL, I get:
...
CU: small.c:

Line number    Starting address    View    Stmt
4            0x400492               x
5            0x40049c               x
6            0x4004a2               x
6            0x4004a8               x
8            0x4004aa               x
9            0x4004b8               x
9            0x4004c5               x
10           0x4004c9               x
6            0x4004c9       1       x
6            0x4004d4               x
12           0x4004db               x
14           0x4004df               x
14           0x4004e3               x
14           0x4004ed               x
14           0x4004f0               x
...

while we have:
...
$ cat -n small.c
     1  const signed char NM[] = {-1, 0, 1};
     2
     3  __attribute__((noinline)) void f(short delta)
     4  {
     5    short p = 2, s;
     6    for (s = 0; s < 2; s++)
     7    {
     8      p += delta;
     9      if (NM[p] == 0)
    10        asm volatile("");
    11    }
    12  }
    13
    14  void main(void) { f(-1); }
    15
...

So, the line with the asm stmt does have line info, but shares the address with another entry with another line number.

Using this debugging session, we can see that we do visit the address, but show line 6 instead of line 10:
...
(gdb) 
9           if (NM[p] == 0)
(gdb) p /x $pc
$1 = 0x4004b8
(gdb) s
6         for (s = 0; s < 2; s++)
(gdb) p /x $pc
$2 = 0x4004c9
(gdb) 
...
which I'd say is a valid interpretation of the line number info.
Comment 3 Tom de Vries 2020-12-30 17:16:13 UTC
(In reply to Yibiao Yang from comment #0)
> $ gdb -q ./a.out
> Reading symbols from ./a.out...
> (gdb) break small.c:9
> Breakpoint 1 at 0x113f: file small.c, line 9.
> (gdb) run
> Starting program: /home/yibiao/cv-gcov/a.out 
> 
> Breakpoint 1, f (delta=-1) at small.c:9
> 9	    if (NM[p] == 0)
> (gdb) step
> 10	      asm volatile("");
> (gdb) c
> Continuing.
> 
> Breakpoint 1, f (delta=-1) at small.c:9
> 9	    if (NM[p] == 0)
> (gdb) step
> 10	      asm volatile("");
> (gdb) q
> A debugging session is active.
> 
> 	Inferior 1 [process 4947] will be killed.
> 
> Quit anyway? (y or n) y
> 
> 
> 
> #############################################################################
> ##
> ### We can find that Line #10 @asm volatile("");@ is executed twice. 
> ### However, it is obvious that Line #9 "if (NM[p] == 0)" is True in the
> second for loop. 
> #############################################################################
> ##

I think this is a different variant of the same problem: the target of the true _and_ false path end up at the same insn, which has two entries in the line table.  So either we show the "true" line twice, or the "false" line twice.

Confusing, but not a gdb bug.

On the gcc side, it could be argued that this is exactly what you asked for by providing an _empty_ asm stmt.