25.3 Debugging Optimized Code
Since the compiler generates debugging tables for a compilation unit before
it performs optimizations, the optimizing transformations may invalidate some
of the debugging data. You therefore need to anticipate certain
anomalous situations that may arise while debugging optimized code. This
section describes the most common cases.
- The "hopping Program Counter": Repeated 'step' or 'next' commands show the PC
bouncing back and forth in the code. This may result from any of the following
optimizations:
- Common subexpression elimination: using a single instance of code for a
quantity that the source computes several times. As a result you
may not be able to stop on what looks like a statement.
- Invariant code motion: moving an expression that does not change within a
loop, to the beginning of the loop.
- Instruction scheduling: moving instructions so as to
overlap loads and stores (typically) with other code, or in
general to move computations of values closer to their uses. Often
this causes you to pass an assignment statement without the assignment
happening and then later bounce back to the statement when the
value is actually needed. Placing a breakpoint on a line of code
and then stepping over it may, therefore, not always cause all the
expected side-effects.
- The "big leap": More commonly known as cross-jumping, in which two
identical pieces of code are merged and the program counter suddenly
jumps to a statement that is not supposed to be executed, simply because
it (and the code following) translates to the same thing as the code
that was supposed to be executed. This effect is typically seen in
sequences that end in a jump, such as a
goto
, a return
, or
a break
in a C switch
statement.
- The "roving variable": The symptom is an unexpected value in a variable.
There are various reasons for this effect:
- In a subprogram prologue, a parameter may not yet have been moved to its
"home".
- A variable may be dead, and its register re-used. This is
probably the most common cause.
- As mentioned above, the assignment of a value to a variable may
have been moved.
- A variable may be eliminated entirely by value propagation or
other means. In this case, GCC may incorrectly generate debugging
information for the variable
In general, when an unexpected value appears for a local variable or parameter
you should first ascertain if that value was actually computed by
your program, as opposed to being incorrectly reported by the debugger.
Record fields or
array elements in an object designated by an access value
are generally less of a problem, once you have ascertained that the access value
is sensible.
Typically, this means checking variables in the preceding code and in the
calling subprogram to verify that the value observed is explainable from other
values (one must apply the procedure recursively to those
other values); or re-running the code and stopping a little earlier
(perhaps before the call) and stepping to better see how the variable obtained
the value in question; or continuing to step from the point of the
strange value to see if code motion had simply moved the variable's
assignments later.