Sources Bugzilla – Bug 12940
RFE: Step into the last function call on a line
Last modified: 2013-02-22 16:10:25 UTC
int a (void) { return 1; } int b (void) { return 2; } void f (int x) {} int main (void) { f (a () + b ()); return 0; } ------------------------------------------------------------------------------- Expected: 6 f (a () + b ()); (gdb) stepfunc f (x=3) at lastfunc.c:3 3 void f (int x) {} Actual: 6 f (a () + b ()); (gdb) step a () at lastfunc.c:1 1 int a (void) { return 1; } Now one has to (according to the number of called functions): (gdb) step (gdb) finish (gdb) step (gdb) finish (gdb) step or: (gdb) record (gdb) next (gdb) reverse-step (gdb) reverse-finish (gdb) step or to use: (gdb) ignorefunc a (gdb) ignorefunc b (gdb) step with: define ignorefunc break $arg0 commands up tbreak commands step end continue end end This feature should be doable the right way (to find the last call instruction during instruction stepping in a line) with the recent DW_TAG_GNU_call_site markers.
This feature is highly valuable when debugging modern C++ code. It is common to have lines looking like: a = b->f( c->g(), d->h()->x() ); It is often the case that g, h, and x are accessors of some form, and are usually not the source of bugs. The bug would typically be in f. As outlined above, the current commands needed to step into f are tedious. So, one wants to use one command to step from the start of that statement directly into function f. Siva Chandra <sivachandra@google.com> has written a Python script that implements the core part of this feature. It uses a recent patch to expose find_pc_line to the Python API, http://sourceware.org/ml/gdb-patches/2012-05/msg00257.html. The simplest implementation of the features is to look at all functions calls for a statement and break on the textually last one in the assembly code. I have used a debugger with this implementation, and it alone is valuable. There are situations, however, where the simple implementation of the feature might yield unintended results. (1) The compiler uses branching internal to a statement that results in the textually last function in the assembly not being the last function called in time. This situation is mostly ignorable. If not though, the user's solution is to compile at a lower optimization level. Otherwise, the compiler and debugger would need to conspire to present the order correctly. That implementation can wait until demonstrated need. (2) Two functions whose results are combined by non-function code. i = f() + g(); b = f() && g(); In the first case, the compiler could generate the function calls in either order. In the second case, f might return false, in which case g is never executed to step into. This situation is hard to resolve, as the user's intent is hard to discern. Any solution can wait until demonstrated need. (3) The statement might include implicit conversion functions that happen as the last call. In this case, the statement i = f(g()); is implemented as i = f(g()).operator int(); and the textually last call is to operator int. The user might not recognize the implicit conversion as being there, and the step would go too far. This situation can be resolved by providing a variant of the function-step command that ignores implicit function calls when choosing the last function. (4) The statement might include a user-defined operator function that the user does not recognize as a function. The most common case here is operator =. In this case, the statement t = f(g()); is implemented as t.operator=(f(g()); and the textually last call is ot operator =. The user might not recognize the assignment operator as being a function call, and the step would go too far. This situation is by far the most common one that I encounted in actual use. It can be resolved by providing a variant of the function-step command that ignores assignment operator function calls when choosing the last function. Alternately, it could ignore all operator function calls. However, even without addressing the situations above, the feature saves significant debugging time.
Just if not clear there is DW_TAG_GNU_call_site now to find the function calls.