RE: breaking at for-loop test line

Atul Talesara
2004-07-29T05:10:18Z

First of all, my apologies for the length of the reply,
but I thought of taking a inter-mixeded code to assist
the explanation.
One-liner explanation:
When breakpoint is placed at line 7, it corresponds
to the first instruction before beginning of the
for(...)loop, which happens to be the initialization,
hence breakpoint there is hit only once.

For those who are eager for detailed explanation,
can go ahead:

Though the gdb/gcc versions are not relevant for this
discussion, I'm producing them for completeness:

gcc version 3.2
GNU gdb 5.2.1-4 for "i386-redhat-linux"

>
> 1 #include <iostream.h>
> 2
> 3 int main(int argc, char* argv[])
> 4 {
> 5 int i = 0;
> 6
> 7 for (i = 0; i < 3; i++) {
> 8 cout << i << endl;
> 9 }
> 10
> 11 while (i < 6) {
> 12 cout << i++ << endl;
> 13 }
> 14
> 15 exit(0);
> 16 }
>
> If I set a breakpoint at line 7, and another at line 11,
> and "run" and "continue" until exit, it will only break once
> on the for-loop, but it will break on each iteration of the
> while-loop. How does this make sense? Is there any way to
> get a breakpoint at the top of the for-loop to act like the
> while-loop?
Well, when you set the breakpoint at the line of for (...) loop
the break is placed on the instruction which initializes
your loop variable, 'i' in this case.
Here's the edited inter-mixed code:

------------
# objdump -S s.out

int main(int argc, char* argv[])
{
8048608: push %ebp

...

for (i = 0; i < 3; i++) {
804861f: movl $0x0,0xfffffffc(%ebp)
8048626: cmpl $0x2,0xfffffffc(%ebp)

cout << i << endl;
804862e: sub $0x8,%esp
...
8048657: jmp 8048626 <main+0x1e>

while (i < 6) {
804865a: cmpl $0x5,0xfffffffc(%ebp)
...
cout << i++ << endl;
8048662: sub $0x8,%esp
...
8048689: add $0x10,%esp
804868c: jmp 804865a <main+0x52>

------------
And here's the GDB session:

------------
(gdb) b 7
Breakpoint 1 at 0x804861f: file test.cpp, line 7.
(gdb) b 11
Breakpoint 2 at 0x804865a: file test.cpp, line 11.
------------
So if you see carefully, the breakpoint is placed at the
address "0x804861f" which corresponds to
"movl $0x0,0xfffffffc(%ebp)" which is nothing but the
initialization of for() loop "i=0" which is bound to
execute only *once* for the life of the program.
(See the jump at the end of for (..) loop: 0x8048657,
this jumps to "0x8048626" and your break was address
above that!)

On other hand if you see for while() loop, break is placed
at "0x804865a" which corresponds to the comparison instruction:
"cmpl $0x5,0xfffffffc(%ebp)" which is bound to execute
*every time* we loop to the beginning of while().
(See the jump at end of while loop: 0x804868c,
this jumps to "0x804865a" where your break is placed!)

Yes, you guessed it right ...
If you skip the initialization part in the for(...) loop,
you will get the breakpoint behaviour exactly like your
while(...) loop! Here's the mixed-disassembly snippet:

--------
# objdump -S s.out

int main(int argc, char* argv[])
{
8048608: push %ebp

...

for (; i < 3; i++) {
804861f: cmpl $0x2,0xfffffffc(%ebp)
...
cout << i << endl;
8048627: sub $0x8,%esp
...

8048650: jmp 804861f <main+0x17>

GDB Session:
(gdb) b 7
Breakpoint 1 at 0x804861f: file s.cpp, line 7.
--------

In this case the jump at the end of for() loop
(0x8048650) corresponds to the condition of the
for() loop (0x804861f) and the breakpoint at line
7 indeed behaves like break on while().

Hope the breakpoint behaviour now makes sense :-)
Allen, you can check the same with your platform,
I don't have access to Sol box.

Regards,
Atul P Talesara
----------------------------------------------------------
Begin with an End in mind.
----------------------------------------------------------