foo.c: ----------------------------------- #include <stdio.h> int main() { int foo; printf("Enter foo: "); scanf("%d", &foo); bar: if(foo)goto bar; return 0; } ----------------------------------- 0:~# gcc -g foo.c 0:~# gdb a.out GNU gdb (GDB) 7.0.1-debian Copyright (C) 2009 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. Type "show copying" and "show warranty" for details. This GDB was configured as "i486-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /root/a.out...done. (gdb) start Temporary breakpoint 1 at 0x804842d: file foo.c, line 6. Starting program: /root/a.out Temporary breakpoint 1, main () at foo.c:6 6 printf("Enter foo: "); (gdb) n 7 scanf("%d", &foo); (gdb) Enter foo: 0 9 return 0; (gdb) q A debugging session is active. Inferior 1 [process 21382] will be killed. Quit anyway? (y or n) y ----------------------------------- But gdb must say: 6 printf("Enter foo: "); (gdb) n 7 scanf("%d", &foo); (gdb) Enter foo: 0 8 bar: if(foo)goto bar; (gdb) 9 return 0; ----------------------------------- 0:~# gdb a.out GNU gdb (GDB) 7.0.1-debian Copyright (C) 2009 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. Type "show copying" and "show warranty" for details. This GDB was configured as "i486-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /root/a.out...done. (gdb) start Temporary breakpoint 1 at 0x804842d: file foo.c, line 6. Starting program: /root/a.out Temporary breakpoint 1, main () at foo.c:6 6 printf("Enter foo: "); (gdb) n 7 scanf("%d", &foo); (gdb) Enter foo: 1 ^C Program received signal SIGINT, Interrupt. 0x08048458 in main () at foo.c:8 8 bar: if(foo)goto bar; (gdb) q A debugging session is active. Inferior 1 [process 21399] will be killed. Quit anyway? (y or n) y ----------------------------------- But gdb must say: 6 printf("Enter foo: "); (gdb) n 7 scanf("%d", &foo); (gdb) Enter foo: 1 8 bar: if(foo)goto bar; (gdb) ^C ----------------------------------- 0:~# uname -a Linux debian 2.6.32-5-686 #1 SMP Sat Oct 30 22:47:19 UTC 2010 i686 GNU/Linux 0:~# gcc -v Using built-in specs. Target: i486-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Debian 4.4.5-8' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.4 --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-targets=all --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu Thread model: posix gcc version 4.4.5 (Debian 4.4.5-8)
I think this is a gcc bug, not a gdb bug. On Fedora 15,with the system gcc, it fails for me if I compile with -g. But if I use -g -O1, it works With plain -g, the line number table looks like: CU: pr.c: File name Line number Starting address pr.c 4 0x400534 pr.c 6 0x40053c pr.c 7 0x40054e pr.c 8 0x400569 pr.c 8 0x40056a pr.c 9 0x400571 pr.c 10 0x400576 Note the address of the first occurrence of line 8. Then if I disassemble I see: scanf("%d", &foo); 40054e: b8 84 06 40 00 mov $0x400684,%eax 400553: 48 8d 55 fc lea -0x4(%rbp),%rdx 400557: 48 89 d6 mov %rdx,%rsi 40055a: 48 89 c7 mov %rax,%rdi 40055d: b8 00 00 00 00 mov $0x0,%eax 400562: e8 d1 fe ff ff callq 400438 <__isoc99_scanf@plt> 400567: eb 01 jmp 40056a <main+0x36> bar: if(foo)goto bar; 400569: 90 nop 40056a: 8b 45 fc mov -0x4(%rbp),%eax 40056d: 85 c0 test %eax,%eax 40056f: 75 f8 jne 400569 <main+0x35> return 0; That is, the first "line 8" is that nop, which is skipped after the call.
Thank you, Tom. I posted the bug to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52160
This is what GCC produces: Here is what GCC produces: .loc 1 7 0 leaq -4(%rbp), %rax movq %rax, %rsi movl $.LC1, %edi movl $0, %eax call __isoc99_scanf jmp .L2 .L5: .loc 1 8 0 nop .L2: .loc 1 8 0 is_stmt 0 discriminator 1 movl -4(%rbp), %eax testl %eax, %eax jne .L5 This looks fine to me.
(In reply to comment #3) > .loc 1 8 0 is_stmt 0 discriminator 1 > This looks fine to me. Yeah, my mistake.
This seems to be a side effect of this code in handle_inferior_event: if ((stop_pc == stop_pc_sal.pc) && (ecs->event_thread->current_line != stop_pc_sal.line || ecs->event_thread->current_symtab != stop_pc_sal.symtab)) { /* We are at the start of a different line. So stop. Note that we don't stop if we step into the middle of a different line. That is said to make things like for (;;) statements work better. */ if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: stepped to a different line\n"); ecs->event_thread->control.stop_step = 1; print_end_stepping_range_reason (); stop_stepping (ecs); return; } Here we have: (top-gdb) p /x stop_pc $26 = 0x40056a (top-gdb) p /x stop_pc_sal.pc $27 = 0x400569 So we skip this stop and instead keep going. I am not sure whether that comment still makes sense. It is present in the initial public checkin of gdb, so I somewhat suspect it is very out of date now.
I tried this bug using GCC 7.4.0 and 9.2.0 and using GDB 7.9.1, 8.0, and 9.0, and in all cases we now see the expected behaviour, that is: (gdb) start Temporary breakpoint 1 at 0x40054f: file test.c, line 6. Starting program: /home/andrew/tmp/test Temporary breakpoint 1, main () at test.c:6 6 printf("Enter foo: "); (gdb) n 7 scanf("%d", &foo); (gdb) n Enter foo: 0 8 bar: if(foo)goto bar; (gdb) n 9 return 0; (gdb) q Given that the last thoughts on this issue were that it was a GDB issue I intend to close this bug as resolved. If this is still important to anyone, or there's a known specific combination of tools that trigger this bug then please feel free to reopen with the additional tool versions specified.