Re: [patch 00/12] entryval#2: Fix x86_64 parameters, virtual tail call frames

Jan Kratochvil
2011-09-19T17:52:18Z

On Sat, 17 Sep 2011 10:56:46 +0200, Eli Zaretskii wrote:
> > maybe:
> > Control display of debugging info for determining virtual tail call frames.
> > The tail call frames GDB determines from similar inferior debug info content
> > like the @entry parameter values.
>
> Would it be good enough to lose the second sentence entirely? This is
> just a NEWS entry, so it doesn't need to go into all the details.

done.

> > Added:
> > Entry values are normally also printed at the function parameter list
> > according to @xref{set print entry-values}.
>
> @ref, nor @xref. The latter produces a capitalized "See", which is
> inappropriate in the middle of a sentence.

Changed, it produced (in .info)
function parameter list according to *Note set print entry-values::.
and now it produces:
function parameter list according to *note set print entry-values::.

> > the whole sentence is now:
> > In some cases @value{GDBN} can determine the value of function argument which
> > was passed by the function caller, even if the value was modified inside the
> > called function and therefore are different.
>
> "is different" ("argument" is single).

done.

> > > > +this feature will behave in the default @code{default} setting the same way as
> > > ^^^^^^^
> > > Lose this "default", it's redundant.
> >
> > done although I disagree a bit. The setting is called "default". That it is
> > the default choice is a coincidence.
>
> That's true, but consider how it will look in the manual:
>
> this feature will behave in the `default' setting the same way as ...
>
> Do you see any problems with reading and understanding this?

Unless we change the `default' name in fact I find both ways confusing but the
`default' name looks natural for the setting to me. OK, kept it that way.

> > During execution of function @code{C}, there will be no indication in
> > the stack frames that it was tail-called from @code{B}.
>
> How about "in the function call stack frames"?

done.

> > > However, in some cases @value{GDBN} can determine that @code{C} was
> > > tail-called from @code{B}, and will then create fictitious call
> > > frame for that, with the return address set up as if @code{B} called
> > > @code{C} normally.
> >
> > Used as you wrote it.
> >
> > Really no nominative? ", and will then" -> ", and it will then"?
>
> I don't mind adding "it", if you think it will make the sentence more
> clear.

OK, put it there.

> > Put there - isn't it too long?
>
> Wrap it at or before column 72 and you are good.

I meant more if there aren't too many lines (not columns). Anyway OK,
shortened to 66 columns now.

@smallexample
(gdb) x/i $pc - 2
0x40066b <b(int, double)+11>: jmp 0x400640 <c(int, double)>
(gdb) info frame
Stack level 1, frame at 0x7fffffffda30:
rip = 0x40066d in b (amd64-entry-value.cc:59); saved rip 0x4004c5
tail call frame, caller of frame at 0x7fffffffda30
source language c++.
Arglist at unknown address.
Locals at unknown address, Previous frame's sp is 0x7fffffffda30
@end smallexample

> > > > +The detection of all the possible code path executions can find them ambiguous.
> > > > +There is no execution history stored (possible @ref{Reverse Execution} is never
> > > > +used for this purpose) and the last known caller could have reached the known
> > > > +callee by multiple different jump sequences. In such case @value{GDBN} still
> > > > +tries to show at least all the unambiguous top tail callers and all the
> > > > +unambiguous bottom tail calees, if any.
> > >
> > > I don't understand what this means in practice. If you show an
> > > example of this, I could suggest some rewording.
> >
> > This is discussed above:
> >
> > tailcall: initial: 0x400735(amb_a(int)) 0x400725(amb_b(int)) 0x40071e(amb(int)) 0x400705(amb_x(int)) 0x4006f5(amb_y(int)) 0x4006e4(amb_z(int))
> > tailcall: compare: 0x400735(amb_a(int)) 0x400725(amb_b(int)) 0x400719(amb(int)) 0x400705(amb_x(int)) 0x4006f5(amb_y(int)) 0x4006e4(amb_z(int))
> > tailcall: reduced: 0x400735(amb_a(int)) 0x400725(amb_b(int)) | 0x400705(amb_x(int)) 0x4006f5(amb_y(int)) 0x4006e4(amb_z(int))
>
> But this is output only with "debug tailcall" set, isn't it?

Yes.

> The text
> I commented on is describing the functionality in general, not the
> effect of the "debug tailcall" setting. I was asking what does
> "@value{GDBN} still tries to show at least all the unambiguous top
> tail callers and all the unambiguous bottom tail calees, if any" mean
> when "debug tailcall" is _not_ set? Are you talking about output of
> some other command, like "bt"? if so, can you show me its output in
> such an ambiguous case?

The real frames (with legacy GDB, no virtual tail call frames, the amb_* frames
below are all virtual):

#0 d (i=<optimized out>, j=<optimized out>) at ./gdb.arch/amd64-entry-value.cc:34
#1 0x000000000040040c in main () at ./gdb.arch/amd64-entry-value.cc:125

Normal output of this patchset (with ambiguous frames suppression):

#0 d (i=<optimized out>, j=<optimized out>) at ./gdb.arch/amd64-entry-value.cc:34^M
#1 0x00000000004005b4 in amb_z (i=<optimized out>) at ./gdb.arch/amd64-entry-value.cc:58^M
#2 0x00000000004005c5 in amb_y (i=<optimized out>) at ./gdb.arch/amd64-entry-value.cc:64^M
#3 0x00000000004005d5 in amb_x (i=<optimized out>) at ./gdb.arch/amd64-entry-value.cc:70^M
#4 0x00000000004005f5 in amb_b (i=101) at ./gdb.arch/amd64-entry-value.cc:85^M
#5 0x0000000000400605 in amb_a (i=100) at ./gdb.arch/amd64-entry-value.cc:91^M
#6 0x000000000040040c in main () at ./gdb.arch/amd64-entry-value.cc:125^M

Output with the ambiguious-frames-suppresion algorithm disabled:

#0 d (i=125, j=125.5) at ./gdb.arch/amd64-entry-value.cc:34^M
#1 0x00000000004005b4 in amb_z (i=117) at ./gdb.arch/amd64-entry-value.cc:58^M
#2 0x00000000004005c5 in amb_y (i=111) at ./gdb.arch/amd64-entry-value.cc:64^M
#3 0x00000000004005d5 in amb_x (i=106) at ./gdb.arch/amd64-entry-value.cc:70^M
#4 0x00000000004005ee in amb (i=103) at ./gdb.arch/amd64-entry-value.cc:77^M
#5 0x00000000004005f5 in amb_b (i=101) at ./gdb.arch/amd64-entry-value.cc:85^M
#6 0x0000000000400605 in amb_a (i=100) at ./gdb.arch/amd64-entry-value.cc:91^M
#7 0x000000000040040c in main () at ./gdb.arch/amd64-entry-value.cc:125^M

That frame #4 could be also different (0x4005e9, not 0x4005ee), it is unsure
what to print there, therefore GDB normally omits printing the frame #4.
In this case there is only one ambiguous frame but GDB omits printing all the
frames between first ambiguous one and last ambiguous one.

> > It is the testcase "self: bt verbose", without `set verbose' there is:
> >
> > #0 d (i=<optimized out>, j=<optimized out>) at ./gdb.arch/amd64-entry-value.cc:34
> > #1 0x0000000000400715 in self (i=<optimized out>) at ./gdb.arch/amd64-entry-value.cc:120
> > #2 0x00000000004004d9 in main () at ./gdb.arch/amd64-entry-value.cc:191
> >
> > and one can be curious why those <optimized out> were not recovered by the
> > `entry values' feature. With `set verbose' it will print the reason:
> >
> > #0 d (DW_OP_GNU_entry_value resolving has found function "self(int)" at 0x4006e0 can call itself via tail calls
>
> I would suggest adding this example, both without and with "verbose"
> setting, to the text. It makes the description much more clear and
> understandable.

(a) I have removed `set verbose' to have effect on this patchset.
(b) I have renamed `set debug tailcall' to `set debug entry-values'.

It is difficult to describe which part of debug messages belongs to which of
those former two settings, if they should be really official.

Added a similar example.

> > Again the example given for NEWS `set debug tailcall' entry above.
>
> That example, together with some explanation of the "initial",
> "compare", and "reduced" lines, would go a long way towards making the
> docs clear.

Added.

Besides the archer-jankratochvil-entryval branch attaching diff against FSF
GDB HEAD only for gdb/doc/ . I will submit the patch part updates when the
doc gets final.

Thanks,
Jan

--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -7277,6 +7277,23 @@ If you ask to print an object whose contents are unknown to
by the debug information, @value{GDBN} will say @samp{<incomplete
type>}. @xref{Symbols, incomplete type}, for more about this.

+If you append @kbd{@@entry} string to a function parameter name you get its
+value at the time the function got called. If the value is not available an
+error message is printed. Entry values are available only with some compilers.
+Entry values are normally also printed at the function parameter list according
+to @ref{set print entry-values}.
+
+@smallexample
+Breakpoint 1, d (i=30) at gdb.base/entry-value.c:29
+29 i++;
+(gdb) next
+30 e (i);
+(gdb) print i
+$1 = 31
+(gdb) print i@@entry
+$2 = 30
+@end smallexample
+
Strings are identified as arrays of @code{char} values without specified
signedness. Arrays of either @code{signed char} or @code{unsigned char} get
printed as arrays of 1 byte sized integers. @code{-fsigned-char} or
@@ -7941,6 +7958,121 @@ thus speeding up the display of each Ada frame.
@item show print frame-arguments
Show how the value of arguments should be displayed when printing a frame.

+@anchor{set print entry-values}
+@item set print entry-values @var{value}
+@kindex set print entry-values
+Set printing of frame argument values at function entry. In some cases
+@value{GDBN} can determine the value of function argument which was passed by
+the function caller, even if the value was modified inside the called function
+and therefore is different. With optimized code, the current value could be
+unavailable, but the entry value may still be known.
+
+The default value is @code{default} (see below for its description). Older
+@value{GDBN} behaved as with the setting @code{no}. Compilers not supporting
+this feature will behave in the @code{default} setting the same way as with the
+@code{no} setting.
+
+This functionality is currently supported only by DWARF 2 debugging format and
+the compiler has to produce @samp{DW_TAG_GNU_call_site} tags. With
+@value{NGCC}, you need to specify @option{-O -g} during compilation, to get
+this information.
+
+The @var{value} parameter can be one of the following:
+
+@table @code
+@item no
+Print only actual parameter values, never print values from function entry
+point.
+@smallexample
+#0 equal (val=5)
+#0 different (val=6)
+#0 lost (val=<optimized out>)
+#0 born (val=10)
+#0 invalid (val=<optimized out>)
+@end smallexample
+
+@item only
+Print only parameter values from function entry point. The actual parameter
+values are never printed.
+@smallexample
+#0 equal (val@@entry=5)
+#0 different (val@@entry=5)
+#0 lost (val@@entry=5)
+#0 born (val@@entry=<optimized out>)
+#0 invalid (val@@entry=<optimized out>)
+@end smallexample
+
+@item preferred
+Print only parameter values from function entry point. If value from function
+entry point is not known while the actual value is known, print the actual
+value for such parameter.
+@smallexample
+#0 equal (val@@entry=5)
+#0 different (val@@entry=5)
+#0 lost (val@@entry=5)
+#0 born (val=10)
+#0 invalid (val@@entry=<optimized out>)
+@end smallexample
+
+@item if-needed
+Print actual parameter values. If actual parameter value is not known while
+value from function entry point is known, print the entry point value for such
+parameter.
+@smallexample
+#0 equal (val=5)
+#0 different (val=6)
+#0 lost (val@@entry=5)
+#0 born (val=10)
+#0 invalid (val=<optimized out>)
+@end smallexample
+
+@item both
+Always print both the actual parameter value and its value from function entry
+point, even if values of one or both are not available due to compiler
+optimizations.
+@smallexample
+#0 equal (val=5, val@@entry=5)
+#0 different (val=6, val@@entry=5)
+#0 lost (val=<optimized out>, val@@entry=5)
+#0 born (val=10, val@@entry=<optimized out>)
+#0 invalid (val=<optimized out>, val@@entry=<optimized out>)
+@end smallexample
+
+@item compact
+Print the actual parameter value if it is known and also its value from
+function entry point if it is known. If neither is known, print for the actual
+value @code{<optimized out>}. If not in MI mode (@pxref{GDB/MI}) and if both
+values are known and identical, print the shortened
+@code{param=param@@entry=VALUE} notation.
+@smallexample
+#0 equal (val=val@@entry=5)
+#0 different (val=6, val@@entry=5)
+#0 lost (val@@entry=5)
+#0 born (val=10)
+#0 invalid (val=<optimized out>)
+@end smallexample
+
+@item default
+Always print the actual parameter value. Print also its value from function
+entry point, but only if it is known. If not in MI mode (@pxref{GDB/MI}) and
+if both values are known and identical, print the shortened
+@code{param=param@@entry=VALUE} notation.
+@smallexample
+#0 equal (val=val@@entry=5)
+#0 different (val=6, val@@entry=5)
+#0 lost (val=<optimized out>, val@@entry=5)
+#0 born (val=10)
+#0 invalid (val=<optimized out>)
+@end smallexample
+@end table
+
+For analysis messages on possible failures of frame argument values at function
+entry resolution see @ref{set debug entry-values}.
+
+@item show print entry-values
+Show the method being used for printing of frame argument values at function
+entry.
+
@item set print repeats
@cindex repeated array elements
Set the threshold for suppressing display of repeated array
@@ -9486,6 +9618,7 @@ please report it to us as a bug (including a test case!).

@menu
* Inline Functions:: How @value{GDBN} presents inlining
+* Tail Call Frames:: @value{GDBN} analysis of jumps to functions
@end menu

@node Inline Functions
@@ -9553,6 +9686,153 @@ and print a variable where your program stored the return value.

@end itemize

+@node Tail Call Frames
+@section Tail Call Frames
+@cindex tail call frames, debugging
+
+Function @code{B} can call function @code{C} in its very last statement. In
+unoptimized compilation the call of @code{C} is immediately followed by return
+instruction at the end of @code{B} code. Optimizing compiler may replace the
+call and return in function @code{B} into one jump to function @code{C}
+instead. Such use of a jump instruction is called @dfn{tail call}.
+
+During execution of function @code{C}, there will be no indication in the
+function call stack frames that it was tail-called from @code{B}. If function
+@code{A} regularly calls function @code{B} which tail-calls function @code{C},
+then @value{GDBN} will see @code{A} as the caller of @code{C}. However, in
+some cases @value{GDBN} can determine that @code{C} was tail-called from
+@code{B}, and it will then create fictitious call frame for that, with the
+return address set up as if @code{B} called @code{C} normally.
+
+This functionality is currently supported only by DWARF 2 debugging format and
+the compiler has to produce @samp{DW_TAG_GNU_call_site} tags. With
+@value{NGCC}, you need to specify @option{-O -g} during compilation, to get
+this information.
+
+@kbd{info frame} command (@pxref{Frame Info}) will indicate the tail call frame
+kind by text @code{tail call frame} such as in this sample @value{GDBN} output:
+
+@smallexample
+(gdb) x/i $pc - 2
+ 0x40066b <b(int, double)+11>: jmp 0x400640 <c(int, double)>
+(gdb) info frame
+Stack level 1, frame at 0x7fffffffda30:
+ rip = 0x40066d in b (amd64-entry-value.cc:59); saved rip 0x4004c5
+ tail call frame, caller of frame at 0x7fffffffda30
+ source language c++.
+ Arglist at unknown address.
+ Locals at unknown address, Previous frame's sp is 0x7fffffffda30
+@end smallexample
+
+The detection of all the possible code path executions can find them ambiguous.
+There is no execution history stored (possible @ref{Reverse Execution} is never
+used for this purpose) and the last known caller could have reached the known
+callee by multiple different jump sequences. In such case @value{GDBN} still
+tries to show at least all the unambiguous top tail callers and all the
+unambiguous bottom tail calees, if any.
+
+@table @code
+@anchor{set debug entry-values}
+@item set debug entry-values
+@kindex set debug entry-values
+When set to on, enables printing of analysis messages for both frame argument
+values at function entry and tail calls. It will show all the possible valid
+tail calls code paths it has considered. It will also print the intersection
+of them with the final unambiguous (possibly partial or even empty) code path
+result.
+
+@item show debug entry-values
+@kindex show debug entry-values
+Show the current state of analysis messages printing for both frame argument
+values at function entry and tail calls.
+@end table
+
+The analysis messages for tail calls can for example show why the virtual tail
+call frame for function @code{c} has not been recognized (due to the indirect
+reference by variable @code{x}):
+
+@smallexample
+static void __attribute__((noinline, noclone)) c (void);
+void (*x) (void) = c;
+static void __attribute__((noinline, noclone)) a (void) @{ x++; @}
+static void __attribute__((noinline, noclone)) c (void) @{ a (); @}
+int main (void) @{ x (); return 0; @}
+
+Breakpoint 1, DW_OP_GNU_entry_value resolving cannot find
+DW_TAG_GNU_call_site 0x40039a in main
+a () at t.c:3
+3 static void __attribute__((noinline, noclone)) a (void) @{ x++; @}
+(gdb) bt
+#0 a () at t.c:3
+#1 0x000000000040039a in main () at t.c:5
+@end smallexample
+
+Another possibility is an ambiguous virtual tail call frames resolution:
+
+@smallexample
+int i;
+static void __attribute__((noinline, noclone)) f (void) @{ i++; @}
+static void __attribute__((noinline, noclone)) e (void) @{ f (); @}
+static void __attribute__((noinline, noclone)) d (void) @{ f (); @}
+static void __attribute__((noinline, noclone)) c (void) @{ d (); @}
+static void __attribute__((noinline, noclone)) b (void)
+@{ if (i) c (); else e (); @}
+static void __attribute__((noinline, noclone)) a (void) @{ b (); @}
+int main (void) @{ a (); return 0; @}
+
+tailcall: initial: 0x4004d2(a) 0x4004ce(b) 0x4004b2(c) 0x4004a2(d)
+tailcall: compare: 0x4004d2(a) 0x4004cc(b) 0x400492(e)
+tailcall: reduced: 0x4004d2(a) |
+(gdb) bt
+#0 f () at t.c:2
+#1 0x00000000004004d2 in a () at t.c:8
+#2 0x0000000000400395 in main () at t.c:9
+@end smallexample
+
+Frames #0 and #2 are real, #1 is a virtual tail call frame. The code can have
+possible execution paths
+@code{main@arrow{}a@arrow{}b@arrow{}c@arrow{}d@arrow{}f} or
+@code{main@arrow{}a@arrow{}b@arrow{}e@arrow{}f}, @value{GDBN} cannot find which
+one from the inferior state.
+
+@code{initial:} state shows some random possible calling sequence @value{GDBN}
+has found. It then finds another possible calling sequcen - that one is
+prefixed by @code{compare:}. The non-ambiguous intersection of these two is
+printed as the @code{reduced:} calling sequence. That one could have many
+futher @code{compare:} and @code{reduced:} statements as long as there remain
+any non-ambiguous sequence entries.
+
+For the frame of function @code{b} in both cases there are different possible
+@code{$pc} values (@code{0x4004cc} or @code{0x4004ce}), therefore this frame is
+also ambigous. The only non-ambiguous frame is the one for function @code{a},
+therefore this one is displayed to the user while the ambiguous frames are
+omitted.
+
+There can be also reasons why printing of frame argument values at function
+entry may fail:
+
+@smallexample
+int v;
+static void __attribute__((noinline, noclone)) c (int i) @{ v++; @}
+static void __attribute__((noinline, noclone)) a (int i);
+static void __attribute__((noinline, noclone)) b (int i) @{ a (i); @}
+static void __attribute__((noinline, noclone)) a (int i)
+@{ if (i) b (i - 1); else c (0); @}
+int main (void) @{ a (5); return 0; @}
+
+(gdb) bt
+#0 c (i=i@@entry=0) at t.c:2
+#1 0x0000000000400428 in a (DW_OP_GNU_entry_value resolving has found
+function "a" at 0x400420 can call itself via tail calls
+i=<optimized out>) at t.c:6
+#2 0x000000000040036e in main () at t.c:7
+@end smallexample
+
+@value{GDBN} cannot find out from the inferior state if and how many times did
+function @code{a} call itself (via function @code{b}) as these calls would be
+tail calls. Such tail calls would modify thue @code{i} variable, therefore
+@value{GDBN} cannot be sure the value it knows would be right - @value{GDBN}
+prints @code{<optimized out>} instead.

@node Macros
@chapter C Preprocessor Macros
@@ -23063,6 +23343,9 @@ inferior function call.
A frame representing an inlined function. The function was inlined
into a @code{gdb.NORMAL_FRAME} that is older than this one.

+@item gdb.TAILCALL_FRAME
+A frame representing a tail call. @xref{Tail Call Frames}.
+
@item gdb.SIGTRAMP_FRAME
A signal trampoline frame. This is the frame created by the OS when
it calls into a signal handler.