Hind Forsum
Hind Forsum

Reputation: 10527

Why doesn't gdb "u" command exit the loop?

I've got a very simple main function, with a for loop inside it, like below:

#include<stdio.h> 
int main() 
{ 
   for(int i=0;i<30;++i) 
     printf("%d\n",i); 
   return 0; 
} 

I tried to compile it like:

gcc 4.c -g 

Then I debug it with gdb:

$ gdb a.out 
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04)... 
Reading symbols from a.out...done. 
(gdb) list 
1    #include<stdio.h> 
2    int main() 
3    { 
4      for(int i=0;i<30;++i) 
5        printf("%d\n",i); 
6      return 0; 
7    } 
(gdb) b 5 
Breakpoint 1 at 0x400537: file 4.c, line 5. 
(gdb) b 6 
Breakpoint 2 at 0x400555: file 4.c, line 6. 
(gdb) r 
Starting program: /home/a/cpp/a.out  

Breakpoint 1, main () at 4.c:5 
5        printf("%d\n",i); 
(gdb) p i 
$1 = 0 
(gdb) u 
0 
4      for(int i=0;i<30;++i) 
(gdb) u //not exiting for loop?

Breakpoint 1, main () at 4.c:5 
5        printf("%d\n",i); 
(gdb)  
1 
4      for(int i=0;i<30;++i) 
(gdb) u 

Seems the "u" command doesn't help to execute the whole for loop and come to next break point, but something like a "n" command.

Why? Any misunderstanding from my description? Thanks.

Upvotes: 2

Views: 396

Answers (1)

Matthew Fisher
Matthew Fisher

Reputation: 2336

It appears that gdb has to go through the loop once in order understand the loop structure.

(gdb) list
1   #include<stdio.h> 
2   int main() 
3   { 
4      for(int i=0;i<5;++i) 
5      {
6        printf("%d\n",i); 
7      }
8      return 0; 
9   } 
10  
(gdb) b main
Breakpoint 1 at 0x400535: file junk.cpp, line 4.
(gdb) b 8
Breakpoint 2 at 0x40055c: file junk.cpp, line 8.
(gdb) r
Starting program: /tmp/local/matcher_server/bin/a.out 

Breakpoint 1, main () at junk.cpp:4
4      for(int i=0;i<30;++i) 
(gdb) n
6        printf("%d\n",i); 
(gdb) n
0
4      for(int i=0;i<30;++i) 
(gdb) u
1
2
3
4

Breakpoint 2, main () at junk.cpp:8
8      return 0; 

To understand why, we need to look at the assembler for main

(gdb) disass
Dump of assembler code for function main():
   0x000000000040052d <+0>: push   %rbp
   0x000000000040052e <+1>: mov    %rsp,%rbp
   0x0000000000400531 <+4>: sub    $0x10,%rsp
   0x0000000000400535 <+8>: movl   $0x0,-0x4(%rbp)
   0x000000000040053c <+15>:    jmp    0x400556 <main()+41>
   0x000000000040053e <+17>:    mov    -0x4(%rbp),%eax
   0x0000000000400541 <+20>:    mov    %eax,%esi
   0x0000000000400543 <+22>:    mov    $0x4005f4,%edi
   0x0000000000400548 <+27>:    mov    $0x0,%eax
   0x000000000040054d <+32>:    callq  0x400410 <printf@plt>
=> 0x0000000000400552 <+37>:    addl   $0x1,-0x4(%rbp)
   0x0000000000400556 <+41>:    cmpl   $0x1d,-0x4(%rbp)
   0x000000000040055a <+45>:    jle    0x40053e <main()+17>
   0x000000000040055c <+47>:    mov    $0x0,%eax
   0x0000000000400561 <+52>:    leaveq 
   0x0000000000400562 <+53>:    retq   
End of assembler dump.

and the line details from dwarfdump

.debug_line: line number info for a single cu
Source lines (from CU-DIE at .debug_info offset 0x0000000b):
<pc>        [row,col] NS BB ET PE EB IS= DI= uri: "filepath"
NS new statement, BB new basic block, ET end of text sequence
PE prologue end, EB epilogue begin
IA=val ISA number, DI=val discriminator value
0x0040052d  [   3, 0] NS uri: "/tmp/local/matcher_server/bin/junk.cpp"
0x00400535  [   4, 0] NS
0x0040053e  [   6, 0] NS DI=0x2
0x00400552  [   4, 0] NS DI=0x2
0x00400556  [   4, 0] DI=0x1
0x0040055c  [   8, 0] NS
0x00400561  [   9, 0] NS
0x00400563  [   9, 0] NS ET

The [ 3,0] column is the line and column number. As we can see the loop causes the line numbers to be non-sequential, 3,4,6,4.

I suspect that first time the program hits line 6 and the 'u' command is given gdb is confused about the loop in the DWARF symbols. On the second loop, it gets it right however. Perhaps a small bug or an artifact of how the 'u' command is implemented.

Note that gdb will still hit breakpoints during the 'u' command. In your example, you will need to remove the breakpoint on the printf.

Upvotes: 3

Related Questions