Re: Single stepping a simple C-program, but...

Pedro Alves
2008-05-19T22:39:48Z

A Monday 19 May 2008 21:48:18, Pedro Alves wrote:
> A Monday 19 May 2008 21:18:36, Peter Toft wrote:
> > Hi guys
> >
> > I was a bit surprised today with GDB, and I hope one of you can explain
> > it to me. Take a look at http://pastebin.org/37117
>
> 01. #include <stdio.h>
> 02.
> 03. int main(void)
> 04. {
> 05. int ii=4;
> 06.
> 07. if ((ii>3) || (ii<1))
> 08. printf("hej A\n");
> 09. else
> 10. printf("hej B\n");
> 11.
> 12. return 0;
> 13. }
>
> > Press download and save as my_program.c
> > $ gcc -g my_program.c
> > $ gdb ./a.out
> > (gdb) br 7
> > Breakpoint 1 at 0x804838c: file my_program.c, line 7.
> > (gdb) r
> > Starting program: /home/pto/c/a.out
> >
> > Breakpoint 1, main () at my_program.c:7
> > 7 if ((ii>3) || (ii<1))
> > (gdb) s
> > 8 printf("hej A\n");
> > (gdb) s
> > hej A
> > 7 if ((ii>3) || (ii<1)) <----------- WHY!!!!??
> > (gdb) s
> > 12 return 0;
> >
> > -------
> >
> > Why does the second "step" i.e. "s" take me BACK to line 7 after I
> > have been in line 8????
>
> Presumably, because there's a branch instruction after the printf
> call to skip the else clause, GDB hits it (step-resume breakpoint),
> and the debug info gcc is producing is marking that address as belonging
> to line 7?

I got curious.
gcc version 4.2.3 (Ubuntu 4.2.3-2ubuntu7) (x86_64-linux-gnu)
GNU gdb 6.8.50.20080515-cvs

Built with gcc my_program.c -g3 -O0 -o my_program

5 int ii=4;
(gdb) n
7 if ((ii>3) || (ii<1))
(gdb)
8 printf("hej A\n");
(gdb)
hej A
7 if ((ii>3) || (ii<1))
(gdb) p $pc
$1 = (void (*)()) 0x4004bd <main+37>

(gdb) disassemble /m
6
7 if ((ii>3) || (ii<1))
0x00000000004004a7 <main+15>: cmpl $0x3,-0x4(%rbp)
0x00000000004004ab <main+19>: jg 0x4004b3 <main+27>
0x00000000004004ad <main+21>: cmpl $0x0,-0x4(%rbp)
0x00000000004004b1 <main+25>: jg 0x4004bf <main+39>
0x00000000004004bd <main+37>: jmp 0x4004c9 <main+49>

8 printf("hej A\n");
0x00000000004004b3 <main+27>: mov $0x4005b8,%edi
0x00000000004004b8 <main+32>: callq 0x4003c0 <puts@plt>

9 else
10 printf("hej B\n");
0x00000000004004bf <main+39>: mov $0x4005be,%edi
0x00000000004004c4 <main+44>: callq 0x4003c0 <puts@plt>

11
12 return 0;
0x00000000004004c9 <main+49>: mov $0x0,%eax

Humm, this output isn't clear, as GDB is grouping insns by
line number first then sorting by address.

objdump -dS:

int main(void)
{
400498: 55 push %rbp
400499: 48 89 e5 mov %rsp,%rbp
40049c: 48 83 ec 10 sub $0x10,%rsp
int ii=4;
4004a0: c7 45 fc 04 00 00 00 movl $0x4,-0x4(%rbp)

if ((ii>3) || (ii<1))
4004a7: 83 7d fc 03 cmpl $0x3,-0x4(%rbp)
4004ab: 7f 06 jg 4004b3 <main+0x1b>
4004ad: 83 7d fc 00 cmpl $0x0,-0x4(%rbp)
4004b1: 7f 0c jg 4004bf <main+0x27>
printf("hej A\n");
4004b3: bf b8 05 40 00 mov $0x4005b8,%edi
4004b8: e8 03 ff ff ff callq 4003c0 <puts@plt>

int main(void)
{
int ii=4;

if ((ii>3) || (ii<1))
4004a7: 83 7d fc 03 cmpl $0x3,-0x4(%rbp)
4004ab: 7f 06 jg 4004b3 <main+0x1b>
4004ad: 83 7d fc 00 cmpl $0x0,-0x4(%rbp)
4004b1: 7f 0c jg 4004bf <main+0x27>
printf("hej A\n");
4004b3: bf b8 05 40 00 mov $0x4005b8,%edi
4004b8: e8 03 ff ff ff callq 4003c0 <puts@plt>

int main(void)
{
int ii=4;

if ((ii>3) || (ii<1))
4004bd: eb 0a jmp 4004c9 <main+0x31>

^^^ jmp over else
printf("hej A\n");
else
printf("hej B\n");
4004bf: bf be 05 40 00 mov $0x4005be,%edi
4004c4: e8 f7 fe ff ff callq 4003c0 <puts@plt>

return 0;
4004c9: b8 00 00 00 00 mov $0x0,%eax
}

Ah, that's better. Notice how line info is making objdump print
the same sources more than once:

readelf -wl ./my_program

Line Number Statements:
Extended opcode 2: set Address to 0x400498
Special opcode 8: advance Address by 0 to 0x400498 and Line by 3 to 4
Special opcode 118: advance Address by 8 to 0x4004a0 and Line by 1 to 5
Special opcode 105: advance Address by 7 to 0x4004a7 and Line by 2 to 7
Special opcode 174: advance Address by 12 to 0x4004b3 and Line by 1 to 8
Special opcode 144: advance Address by 10 to 0x4004bd and Line by -1 to 7
^^^^^^ ^
Special opcode 36: advance Address by 2 to 0x4004bf and Line by 3 to 10
Special opcode 147: advance Address by 10 to 0x4004c9 and Line by 2 to 12
Special opcode 76: advance Address by 5 to 0x4004ce and Line by 1 to 13
Advance PC by 2 to 0x4004d0
Extended opcode 1: End of Sequence

There you go. Not much for GDB to do.

--
Pedro Alves