* [patch 00/12] entryval#2: Fix x86_64 <optimized out> parameters, virtual tail call frames
@ 2011-09-13 19:44 Jan Kratochvil
2011-09-14 10:26 ` Eli Zaretskii
2011-09-30 0:02 ` obsolete: " Jan Kratochvil
0 siblings, 2 replies; 7+ messages in thread
From: Jan Kratochvil @ 2011-09-13 19:44 UTC (permalink / raw)
To: gdb-patches
Hi,
re-post of the series:
[patch 00/12] entryval: Fix x86_64 <optimized out> parameters, virtual tail call frames
http://sourceware.org/ml/gdb-patches/2011-07/msg00430.html
particular excerpt:
The patches are available (merged only) in GIT for more convenience at:
http://sourceware.org/gdb/wiki/ArcherBranchManagement
archer-jankratochvil-entryval
Here is attached a diff against the previous patch series. The changes are:
New `set print entry-values' setting.
Printed now for any frame arguments printing (not just during `bt full').
$sp shift is simulated in the tail call frames.
There is new NO_ENTRY_VALUE_ERROR (NOT_FOUND_ERROR is no longer reused).
[patch 07/12] const/non-const dropped thanks to new lval_funcs->coerce_ref.
Entry values are attempted even for non-loclist DWARF expressions.
MI is supported now, no specific MI protocol changes were needed.
Reviews were replied before. I will check it in if no new issues appear.
Thanks,
Jan
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -772,7 +772,7 @@ cli/cli-decode.h cli/cli-cmds.h cli/cli-dump.h cli/cli-utils.h \
cli/cli-script.h macrotab.h symtab.h version.h gnulib/wchar.in.h \
gnulib/string.in.h gnulib/str-two-way.h \
gnulib/stdint.in.h remote.h gdb.h sparc-nat.h \
-gdbthread.h dwarf2-frame.h nbsd-nat.h dcache.h \
+gdbthread.h dwarf2-frame.h dwarf2-frame-tailcall.h nbsd-nat.h dcache.h \
amd64-nat.h s390-tdep.h arm-linux-tdep.h exceptions.h macroscope.h \
gdbarch.h bsd-uthread.h gdb_stat.h memory-map.h memrange.h \
mdebugread.h m88k-tdep.h stabsread.h hppa-linux-offsets.h linux-fork.h \
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -93,6 +93,19 @@ info auto-load-scripts [REGEXP]
begin, assuming that tracepoints will be enabled as needed while the trace
is running.
+* New options
+
+set print entry-values (both|compact|default|if-needed|no|only|preferred)
+show print entry-values
+ Set printing of frame arguments values at function entry. In some cases
+ GDB can determine the value of function argument which was passed by the
+ function caller, despite the argument value may be already modified.
+
+set debug tailcall
+show debug tailcall
+ Control display of debugging info for determining virtual tail call frames,
+ present in inferior debug info together with the @entry values.
+
* New remote packets
QTEnable
--- a/gdb/ada-lang.h
+++ b/gdb/ada-lang.h
@@ -164,7 +164,8 @@ extern void ada_print_typedef (struct type *type, struct symbol *new_symbol,
struct ui_file *stream);
extern int ada_val_print (struct type *, const gdb_byte *, int, CORE_ADDR,
- struct ui_file *, int, struct value *,
+ struct ui_file *, int,
+ const struct value *,
const struct value_print_options *);
extern int ada_value_print (struct value *, struct ui_file *,
--- a/gdb/ada-valprint.c
+++ b/gdb/ada-valprint.c
@@ -37,18 +37,23 @@
#include "objfiles.h"
static void print_record (struct type *, const gdb_byte *, int,
- struct ui_file *, int, struct value *,
+ struct ui_file *,
+ int,
+ const struct value *,
const struct value_print_options *);
static int print_field_values (struct type *, const gdb_byte *,
- int, struct ui_file *, int, struct value *,
+ int,
+ struct ui_file *, int,
+ const struct value *,
const struct value_print_options *,
int, struct type *, int);
static void adjust_type_signedness (struct type *);
static int ada_val_print_1 (struct type *, const gdb_byte *, int, CORE_ADDR,
- struct ui_file *, int, struct value *,
+ struct ui_file *, int,
+ const struct value *,
const struct value_print_options *);
\f
@@ -568,7 +573,8 @@ ada_printstr (struct ui_file *stream, struct type *type,
int
ada_val_print (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
- struct ui_file *stream, int recurse, struct value *val,
+ struct ui_file *stream, int recurse,
+ const struct value *val,
const struct value_print_options *options)
{
volatile struct gdb_exception except;
@@ -595,7 +601,8 @@ ada_val_print (struct type *type, const gdb_byte *valaddr,
static int
ada_val_print_array (struct type *type, const gdb_byte *valaddr,
int offset, CORE_ADDR address,
- struct ui_file *stream, int recurse, struct value *val,
+ struct ui_file *stream, int recurse,
+ const struct value *val,
const struct value_print_options *options)
{
int result = 0;
@@ -663,7 +670,7 @@ static int
ada_val_print_1 (struct type *type, const gdb_byte *valaddr,
int offset, CORE_ADDR address,
struct ui_file *stream, int recurse,
- struct value *original_value,
+ const struct value *original_value,
const struct value_print_options *options)
{
unsigned int len;
@@ -892,23 +899,14 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr,
if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF)
{
CORE_ADDR deref_val_int;
+ struct value *deref_val;
- if (VALUE_LVAL (original_value) == lval_computed)
+ deref_val = coerce_ref_if_computed (original_value);
+ if (deref_val)
{
- const struct lval_funcs *funcs;
-
- funcs = value_computed_funcs (original_value);
- if (funcs->indirect)
- {
- struct value *result = funcs->indirect (original_value);
-
- if (result)
- {
- common_val_print (result, stream, recurse,
- options, current_language);
- return 0;
- }
- }
+ common_val_print (deref_val, stream, recurse + 1, options,
+ current_language);
+ return 0;
}
deref_val_int = unpack_pointer (type, valaddr + offset_aligned);
@@ -940,7 +938,8 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr,
static int
print_variant_part (struct type *type, int field_num,
const gdb_byte *valaddr, int offset,
- struct ui_file *stream, int recurse, struct value *val,
+ struct ui_file *stream, int recurse,
+ const struct value *val,
const struct value_print_options *options,
int comma_needed,
struct type *outer_type, int outer_offset)
@@ -1014,7 +1013,8 @@ ada_value_print (struct value *val0, struct ui_file *stream,
static void
print_record (struct type *type, const gdb_byte *valaddr,
int offset,
- struct ui_file *stream, int recurse, struct value *val,
+ struct ui_file *stream, int recurse,
+ const struct value *val,
const struct value_print_options *options)
{
type = ada_check_typedef (type);
@@ -1050,7 +1050,7 @@ print_record (struct type *type, const gdb_byte *valaddr,
static int
print_field_values (struct type *type, const gdb_byte *valaddr,
int offset, struct ui_file *stream, int recurse,
- struct value *val,
+ const struct value *val,
const struct value_print_options *options,
int comma_needed,
struct type *outer_type, int outer_offset)
--- a/gdb/c-lang.h
+++ b/gdb/c-lang.h
@@ -73,7 +73,8 @@ extern void c_print_typedef (struct type *,
extern int c_val_print (struct type *, const gdb_byte *,
int, CORE_ADDR,
- struct ui_file *, int, struct value *,
+ struct ui_file *, int,
+ const struct value *,
const struct value_print_options *);
extern int c_value_print (struct value *, struct ui_file *,
@@ -118,13 +119,15 @@ extern void cp_print_class_member (const gdb_byte *, struct type *,
extern void cp_print_value_fields (struct type *, struct type *,
const gdb_byte *, int, CORE_ADDR,
- struct ui_file *, int, struct value *,
+ struct ui_file *, int,
+ const struct value *,
const struct value_print_options *,
struct type **, int);
extern void cp_print_value_fields_rtti (struct type *,
const gdb_byte *, int, CORE_ADDR,
- struct ui_file *, int, struct value *,
+ struct ui_file *, int,
+ const struct value *,
const struct value_print_options *,
struct type **, int);
--- a/gdb/c-valprint.c
+++ b/gdb/c-valprint.c
@@ -149,7 +149,8 @@ c_textual_element_type (struct type *type, char format)
int
c_val_print (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
- struct ui_file *stream, int recurse, struct value *original_value,
+ struct ui_file *stream, int recurse,
+ const struct value *original_value,
const struct value_print_options *options)
{
struct gdbarch *gdbarch = get_type_arch (type);
@@ -381,22 +382,12 @@ c_val_print (struct type *type, const gdb_byte *valaddr,
{
struct value *deref_val;
- if (VALUE_LVAL (original_value) == lval_computed)
+ deref_val = coerce_ref_if_computed (original_value);
+ if (deref_val)
{
- const struct lval_funcs *funcs;
-
- funcs = value_computed_funcs (original_value);
- if (funcs->indirect)
- {
- struct value *result = funcs->indirect (original_value);
-
- if (result)
- {
- common_val_print (result, stream, recurse,
- options, current_language);
- return 0;
- }
- }
+ common_val_print (deref_val, stream, recurse, options,
+ current_language);
+ return 0;
}
deref_val = value_at (TYPE_TARGET_TYPE (type),
--- a/gdb/cp-valprint.c
+++ b/gdb/cp-valprint.c
@@ -85,7 +85,7 @@ static void cp_print_static_field (struct type *, struct value *,
static void cp_print_value (struct type *, struct type *,
const gdb_byte *, int,
CORE_ADDR, struct ui_file *,
- int, struct value *,
+ int, const struct value *,
const struct value_print_options *,
struct type **);
@@ -159,7 +159,7 @@ void
cp_print_value_fields (struct type *type, struct type *real_type,
const gdb_byte *valaddr, int offset,
CORE_ADDR address, struct ui_file *stream,
- int recurse, struct value *val,
+ int recurse, const struct value *val,
const struct value_print_options *options,
struct type **dont_print_vb,
int dont_print_statmem)
@@ -432,7 +432,7 @@ cp_print_value_fields_rtti (struct type *type,
const gdb_byte *valaddr, int offset,
CORE_ADDR address,
struct ui_file *stream, int recurse,
- struct value *val,
+ const struct value *val,
const struct value_print_options *options,
struct type **dont_print_vb,
int dont_print_statmem)
@@ -471,7 +471,7 @@ static void
cp_print_value (struct type *type, struct type *real_type,
const gdb_byte *valaddr, int offset,
CORE_ADDR address, struct ui_file *stream,
- int recurse, struct value *val,
+ int recurse, const struct value *val,
const struct value_print_options *options,
struct type **dont_print_vb)
{
@@ -498,7 +498,7 @@ cp_print_value (struct type *type, struct type *real_type,
struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i));
char *basename = TYPE_NAME (baseclass);
const gdb_byte *base_valaddr = NULL;
- struct value *base_val = NULL;
+ const struct value *base_val = NULL;
volatile struct gdb_exception ex;
if (BASETYPE_VIA_VIRTUAL (type, i))
--- a/gdb/d-lang.h
+++ b/gdb/d-lang.h
@@ -27,7 +27,8 @@ extern char *d_demangle (const char *mangled, int options);
extern int d_val_print (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
- struct ui_file *stream, int recurse, struct value *val,
+ struct ui_file *stream, int recurse,
+ const struct value *val,
const struct value_print_options *options);
#endif /* !defined (D_LANG_H) */
--- a/gdb/d-valprint.c
+++ b/gdb/d-valprint.c
@@ -72,7 +72,8 @@ dynamic_array_type (struct type *type, const gdb_byte *valaddr,
int
d_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
CORE_ADDR address, struct ui_file *stream, int recurse,
- struct value *val, const struct value_print_options *options)
+ const struct value *val,
+ const struct value_print_options *options)
{
int ret;
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -5947,13 +5947,8 @@ Similar, but print only the outermost @var{n} frames.
@itemx bt full
@itemx bt full @var{n}
@itemx bt full -@var{n}
-Print the values of the local variables also.
-
-Names with appended @code{@@entry} show values of function parameters at the
-time the function got called. The @code{@@entry} parameter line is not shown
-when the entry value is not available.
-
-@var{n} specifies the number of frames to print, as described above.
+Print the values of the local variables also. @var{n} specifies the
+number of frames to print, as described above.
@end table
@kindex where
@@ -6228,10 +6223,6 @@ architectures) that you specify in the @code{frame} command.
@item info args
Print the arguments of the selected frame, each on a separate line.
-Names with appended @code{@@entry} show values of function parameters at the
-time the function got called. The @code{@@entry} parameter line is not shown
-when the entry value is not available.
-
@item info locals
@kindex info locals
Print the local variables of the selected frame, each on a separate
@@ -7286,10 +7277,9 @@ 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 @code{@@entry} string to a function parameter name you get its
+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 since @value{NGCC}
-version 4.7.
+error message is printed. Entry values are available only with some compilers.
@smallexample
Breakpoint 1, d (i=30) at gdb.base/entry-value.c:29
@@ -7966,6 +7956,118 @@ 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.
+@item set print entry-values @var{value}
+@kindex set print entry-values
+Set printing of frame arguments values at function entry. In some cases
+@value{GDBN} can determine the value of function argument which was passed by
+the function caller, despite the argument value may be already modified by the
+current function and therefore different. For optimized code also the current
+value may be possibly not available and the entry value may be still known,
+which aids the debugging of production code.
+
+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 default @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. For example for
+@value{NGCC} additionally optimization and debugging compilation options must
+be enabled (@option{-O -g}). Still even with the required debug info there
+exist many reasons why the code path analysis by @value{GDBN} may fail in
+specific cases.
+
+@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
+set print entry-values 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 at least 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@@entry=<optimized out>)
+#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 at least the entry point 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 both
+set print entry-values both
+Always print both the actual parameter value and its value from function entry
+point. Still print both even if one of them or both are @code{<optimized out>}.
+@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 know 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 they are equal 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 they are equal 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
+
+@item show print entry-values
+Show printing of frame arguments values at function entry.
+
@item set print repeats
@cindex repeated array elements
Set the threshold for suppressing display of repeated array
@@ -9511,6 +9613,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
@@ -9578,6 +9681,60 @@ 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} by 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 tail call.
+
+During execution of function @code{C} there will remain no indication it has
+been tail called from function @code{B}. If function @code{A} regularly calls
+function @code{B} which tail calls function @code{C} then @value{GDBN} sees as
+the caller of function @code{C} the function @code{A}. @value{GDBN} can in
+some cases search all the possible code paths and if it determintes there
+exists an unambiguous code path it will create call frames for it (in this case
+a frame with @code{$pc} in function @code{B}). The virtual return address into
+such tail call frame will be pointing pointing right after the jump instruction
+(as if it would be a call instructions).
+
+This functionality is currently supported only by DWARF 2 debugging format and
+the compiler has to produce @samp{DW_TAG_GNU_call_site} tags. For example for
+@value{NGCC} additionally optimization and debugging compilation options must
+be enabled (@option{-O -g}). Still even with the required debug info there
+exist many reasons why the code path analysis by @value{GDBN} may fail in
+specific cases.
+
+@kbd{info frame} command (@pxref{Frame Info}) will indicate the tail call frame
+kind by text @code{tail call frame}.
+
+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.
+
+@kbd{set verbose} command (@pxref{Messages/Warnings, ,Optional Warnings and
+Messages}.) can show some reasons why the complete code path analysis did not
+succeed in a specific case.
+
+@table @code
+@item set debug tailcall
+@kindex set debug tailcall
+When set to on, enables tail calls analysis messages printing. 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 tailcall
+@kindex show debug tailcall
+Show the current state of tail calls analysis messages.
+@end table
+
@node Macros
@chapter C Preprocessor Macros
@@ -23078,6 +23235,13 @@ 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. Tail calls are used if the last statement of
+an inferior function is a call of a (usually different) function. Such call
+immediately followed by return instruction is in optimized code converted to
+just one jump instruction. @value{GDBN} can in some cases guess such jump has
+been executed and it creates a @code{gdb.TAILCALL_FRAME} for it.
+
@item gdb.SIGTRAMP_FRAME
A signal trampoline frame. This is the frame created by the OS when
it calls into a signal handler.
--- a/gdb/dwarf2-frame-tailcall.c
+++ b/gdb/dwarf2-frame-tailcall.c
@@ -27,13 +27,15 @@
#include "hashtab.h"
#include "exceptions.h"
#include "gdbtypes.h"
-
+#include "regcache.h"
+#include "value.h"
/* Contains struct tailcall_cache indexed by next_bottom_frame. */
static htab_t cache_htab;
-/* Associated structure of the unwinder for call_site_chain. */
-
+/* Associate structure of the unwinder to call_site_chain. Lifetime of this
+ structure is maintained by REFC decremented by dealloc_cache, all of them
+ get deleted during reinit_frame_cache. */
struct tailcall_cache
{
/* It must be the first one of this struct. It is the furthest callee. */
@@ -51,8 +53,15 @@ struct tailcall_cache
/* Unwound PC from the top (caller) frame, as it is not contained
in CHAIN. */
-
CORE_ADDR prev_pc;
+
+ /* Compensate SP in caller frames appropriately. prev_sp and
+ entry_cfa_sp_offset are valid only if PREV_SP_P. PREV_SP is SP at the top
+ (caller) frame. ENTRY_CFA_SP_OFFSET is shift of SP in tail call frames
+ against next_bottom_frame SP. */
+ unsigned prev_sp_p : 1;
+ CORE_ADDR prev_sp;
+ LONGEST entry_cfa_sp_offset;
};
/* hash_f for htab_create_alloc of cache_htab. */
@@ -86,7 +95,7 @@ cache_new_ref1 (struct frame_info *next_bottom_frame)
struct tailcall_cache *cache;
void **slot;
- cache = xmalloc (sizeof (*cache));
+ cache = xzalloc (sizeof (*cache));
cache->next_bottom_frame = next_bottom_frame;
cache->refc = 1;
@@ -205,16 +214,14 @@ tailcall_frame_this_id (struct frame_info *this_frame, void **this_cache,
{
struct tailcall_cache *cache = *this_cache;
struct frame_info *next_frame;
- CORE_ADDR this_frame_base;
/* Tail call does not make sense for a sentinel frame. */
next_frame = get_next_frame (this_frame);
gdb_assert (next_frame != NULL);
- /* SP does not change during tail calls. */
- this_frame_base = get_frame_base (next_frame);
-
- (*this_id) = frame_id_build (this_frame_base, get_frame_pc (this_frame));
+ *this_id = get_frame_id (next_frame);
+ (*this_id).code_addr = get_frame_pc (this_frame);
+ (*this_id).code_addr_p = 1;
(*this_id).inline_depth = (cache->chain_levels
- existing_next_levels (this_frame, cache));
gdb_assert ((*this_id).inline_depth > 0);
@@ -251,20 +258,53 @@ pretend_pc (struct frame_info *this_frame, struct tailcall_cache *cache)
return cache->prev_pc;
}
-/* Implementation of frame_prev_register_ftype. Register set of virtual tail
- call frames is assumed to be the one of the top (caller) frame. Only PC
- value can be different for virtual tail call frames. */
+/* Implementation of frame_prev_register_ftype. If no specific register
+ override is supplied NULL is returned (this is incompatible with
+ frame_prev_register_ftype semantics). next_bottom_frame and tail call
+ frames unwind the NULL case differently. */
+
+struct value *
+dwarf2_tailcall_prev_register_first (struct frame_info *this_frame,
+ void **tailcall_cachep, int regnum)
+{
+ struct gdbarch *this_gdbarch = get_frame_arch (this_frame);
+ struct tailcall_cache *cache = *tailcall_cachep;
+ CORE_ADDR addr;
+
+ if (regnum == gdbarch_pc_regnum (this_gdbarch))
+ addr = pretend_pc (this_frame, cache);
+ else if (cache->prev_sp_p && regnum == gdbarch_sp_regnum (this_gdbarch))
+ {
+ int next_levels = existing_next_levels (this_frame, cache);
+
+ if (next_levels == cache->chain_levels - 1)
+ addr = cache->prev_sp;
+ else
+ addr = get_frame_base (this_frame) - cache->entry_cfa_sp_offset;
+ }
+ else
+ return NULL;
+
+ return frame_unwind_got_address (this_frame, regnum, addr);
+}
+
+/* Implementation of frame_prev_register_ftype for tail call frames. Register
+ set of virtual tail call frames is assumed to be the one of the top (caller)
+ frame - assume unchanged register value for NULL from
+ dwarf2_tailcall_prev_register_first. */
static struct value *
tailcall_frame_prev_register (struct frame_info *this_frame,
void **this_cache, int regnum)
{
- struct gdbarch *this_gdbarch = get_frame_arch (this_frame);
struct tailcall_cache *cache = *this_cache;
+ struct value *val;
- if (regnum == gdbarch_pc_regnum (this_gdbarch))
- return frame_unwind_got_constant (this_frame, regnum,
- pretend_pc (this_frame, cache));
+ gdb_assert (this_frame != cache->next_bottom_frame);
+
+ val = dwarf2_tailcall_prev_register_first (this_frame, this_cache, regnum);
+ if (val)
+ return val;
return frame_unwind_got_register (this_frame, regnum, regnum);
}
@@ -312,19 +352,25 @@ tailcall_frame_sniffer (const struct frame_unwind *self,
/* The initial "sniffer" whether THIS_FRAME is a bottom (callee) frame of a new
chain to create. Keep TAILCALL_CACHEP NULL if it did not find any chain,
initialize it otherwise. No tail call chain is created if there are no
- unambiguous virtual tail call frames to report. */
+ unambiguous virtual tail call frames to report.
+
+ ENTRY_CFA_SP_OFFSETP is NULL if no special SP handling is possible,
+ otherwise *ENTRY_CFA_SP_OFFSETP is the number of bytes to subtract from tail
+ call frames frame base to get the SP value there - to simulate return
+ address pushed on the stack. */
void
dwarf2_tailcall_sniffer_first (struct frame_info *this_frame,
- void **tailcall_cachep)
+ void **tailcall_cachep,
+ const LONGEST *entry_cfa_sp_offsetp)
{
- CORE_ADDR prev_pc = 0; /* GCC warning. */
+ CORE_ADDR prev_pc = 0, prev_sp = 0; /* GCC warning. */
+ int prev_sp_p = 0;
CORE_ADDR this_pc, pc;
struct gdbarch *prev_gdbarch;
struct call_site_chain *chain = NULL;
struct frame_info *fi;
struct tailcall_cache *cache;
- int pc_regnum;
volatile struct gdb_exception except;
gdb_assert (*tailcall_cachep == NULL);
@@ -334,6 +380,8 @@ dwarf2_tailcall_sniffer_first (struct frame_info *this_frame,
/* Catch any unwinding errors. */
TRY_CATCH (except, RETURN_MASK_ERROR)
{
+ int pc_regnum, sp_regnum;
+
prev_gdbarch = frame_unwind_arch (this_frame);
pc_regnum = gdbarch_pc_regnum (prev_gdbarch);
if (pc_regnum == -1)
@@ -346,6 +394,14 @@ dwarf2_tailcall_sniffer_first (struct frame_info *this_frame,
/* call_site_find_chain can throw an exception. */
chain = call_site_find_chain (prev_gdbarch, prev_pc, this_pc);
+
+ if (entry_cfa_sp_offsetp == NULL)
+ break;
+ sp_regnum = gdbarch_sp_regnum (prev_gdbarch);
+ if (sp_regnum == -1)
+ break;
+ prev_sp = frame_unwind_register_unsigned (this_frame, sp_regnum);
+ prev_sp_p = 1;
}
if (except.reason < 0)
return;
@@ -362,6 +418,12 @@ dwarf2_tailcall_sniffer_first (struct frame_info *this_frame,
cache->chain = chain;
cache->prev_pc = prev_pc;
cache->chain_levels = pretended_chain_levels (chain);
+ cache->prev_sp_p = prev_sp_p;
+ if (cache->prev_sp_p)
+ {
+ cache->prev_sp = prev_sp;
+ cache->entry_cfa_sp_offset = *entry_cfa_sp_offsetp;
+ }
gdb_assert (cache->chain_levels > 0);
}
--- a/gdb/dwarf2-frame-tailcall.h
+++ b/gdb/dwarf2-frame-tailcall.h
@@ -25,8 +25,14 @@ struct frame_unwind;
/* The tail call frame unwinder. */
-extern void dwarf2_tailcall_sniffer_first (struct frame_info *this_frame,
- void **tailcall_cachep);
+extern void
+ dwarf2_tailcall_sniffer_first (struct frame_info *this_frame,
+ void **tailcall_cachep,
+ const LONGEST *entry_cfa_sp_offsetp);
+
+extern struct value *
+ dwarf2_tailcall_prev_register_first (struct frame_info *this_frame,
+ void **tailcall_cachep, int regnum);
extern const struct frame_unwind dwarf2_tailcall_frame_unwind;
--- a/gdb/dwarf2-frame.c
+++ b/gdb/dwarf2-frame.c
@@ -313,16 +313,6 @@ read_mem (void *baton, gdb_byte *buf, CORE_ADDR addr, size_t len)
read_memory (addr, buf, len);
}
-/* Helper function for execute_stack_op. */
-
-static void
-no_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx, int dwarf_reg,
- CORE_ADDR fb_offset, CORE_ADDR deref_size)
-{
- internal_error (__FILE__, __LINE__,
- _("Support for DW_OP_GNU_entry_value is unimplemented"));
-}
-
/* Execute the required actions for both the DW_CFA_restore and
DW_CFA_restore_extended instructions. */
static void
@@ -365,7 +355,7 @@ static const struct dwarf_expr_context_funcs dwarf2_frame_ctx_funcs =
ctx_no_get_tls_address,
ctx_no_dwarf_call,
ctx_no_get_base_type,
- no_push_dwarf_reg_entry_value
+ ctx_no_push_dwarf_reg_entry_value
};
static CORE_ADDR
@@ -409,7 +399,11 @@ Not implemented: computing unwound register using explicit value operator"));
}
\f
-static void
+/* Execute FDE program from INSN_PTR possibly up to INSN_END or up to inferior
+ PC. Modify FS state accordingly. Return current INSN_PTR where the
+ execution has stopped, one can resume it on the next call. */
+
+static const gdb_byte *
execute_cfa_program (struct dwarf2_fde *fde, const gdb_byte *insn_ptr,
const gdb_byte *insn_end, struct gdbarch *gdbarch,
CORE_ADDR pc, struct dwarf2_frame_state *fs)
@@ -692,9 +686,14 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"),
}
}
- /* Don't allow remember/restore between CIE and FDE programs. */
- dwarf2_frame_state_free_regs (fs->regs.prev);
- fs->regs.prev = NULL;
+ if (fs->initial.reg == NULL)
+ {
+ /* Don't allow remember/restore between CIE and FDE programs. */
+ dwarf2_frame_state_free_regs (fs->regs.prev);
+ fs->regs.prev = NULL;
+ }
+
+ return insn_ptr;
}
\f
@@ -1006,6 +1005,10 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache)
struct dwarf2_frame_state *fs;
struct dwarf2_fde *fde;
volatile struct gdb_exception ex;
+ CORE_ADDR entry_pc;
+ LONGEST entry_cfa_sp_offset;
+ int entry_cfa_sp_offset_p = 0;
+ const gdb_byte *instr;
if (*this_cache)
return *this_cache;
@@ -1057,8 +1060,25 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache)
fs->initial = fs->regs;
fs->initial.reg = dwarf2_frame_state_copy_regs (&fs->regs);
+ if (get_frame_func_if_available (this_frame, &entry_pc))
+ {
+ /* Decode the insns in the FDE up to the entry PC. */
+ instr = execute_cfa_program (fde, fde->instructions, fde->end, gdbarch,
+ entry_pc, fs);
+
+ if (fs->regs.cfa_how == CFA_REG_OFFSET
+ && (gdbarch_dwarf2_reg_to_regnum (gdbarch, fs->regs.cfa_reg)
+ == gdbarch_sp_regnum (gdbarch)))
+ {
+ entry_cfa_sp_offset = fs->regs.cfa_offset;
+ entry_cfa_sp_offset_p = 1;
+ }
+ }
+ else
+ instr = fde->instructions;
+
/* Then decode the insns in the FDE up to our target PC. */
- execute_cfa_program (fde, fde->instructions, fde->end, gdbarch,
+ execute_cfa_program (fde, instr, fde->end, gdbarch,
get_frame_pc (this_frame), fs);
TRY_CATCH (ex, RETURN_MASK_ERROR)
@@ -1201,7 +1221,9 @@ incomplete CFI data; unspecified registers (e.g., %s) at %s"),
/* Try to find a virtual tail call frames chain with bottom (callee) frame
starting at THIS_FRAME. */
- dwarf2_tailcall_sniffer_first (this_frame, &cache->tailcall_cache);
+ dwarf2_tailcall_sniffer_first (this_frame, &cache->tailcall_cache,
+ (entry_cfa_sp_offset_p
+ ? &entry_cfa_sp_offset : NULL));
return cache;
}
@@ -1248,14 +1270,21 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache,
CORE_ADDR addr;
int realnum;
- /* Virtual tail call frames report different values only for PC. Non-bottom
- frames of a virtual tail call frames chain use
+ /* Non-bottom frames of a virtual tail call frames chain use
dwarf2_tailcall_frame_unwind unwinder so this code does not apply for
- them. */
- if (cache->tailcall_cache && regnum == gdbarch_pc_regnum (gdbarch))
- return dwarf2_tailcall_frame_unwind.prev_register (this_frame,
- &cache->tailcall_cache,
- regnum);
+ them. If dwarf2_tailcall_prev_register_first does not have specific value
+ unwind the register, tail call frames are assumed to have the register set
+ of the top caller. */
+ if (cache->tailcall_cache)
+ {
+ struct value *val;
+
+ val = dwarf2_tailcall_prev_register_first (this_frame,
+ &cache->tailcall_cache,
+ regnum);
+ if (val)
+ return val;
+ }
switch (cache->reg[regnum].how)
{
--- a/gdb/dwarf2expr.c
+++ b/gdb/dwarf2expr.c
@@ -371,7 +371,7 @@ dwarf_expr_eval (struct dwarf_expr_context *ctx, const gdb_byte *addr,
/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
by R, and return the new value of BUF. Verify that it doesn't extend
- past BUF_END. */
+ past BUF_END. R can be NULL, the constant is then only skipped. */
const gdb_byte *
read_uleb128 (const gdb_byte *buf, const gdb_byte *buf_end, ULONGEST * r)
@@ -391,13 +391,14 @@ read_uleb128 (const gdb_byte *buf, const gdb_byte *buf_end, ULONGEST * r)
break;
shift += 7;
}
- *r = result;
+ if (r)
+ *r = result;
return buf;
}
/* Decode the signed LEB128 constant at BUF into the variable pointed to
by R, and return the new value of BUF. Verify that it doesn't extend
- past BUF_END. */
+ past BUF_END. R can be NULL, the constant is then only skipped. */
const gdb_byte *
read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end, LONGEST * r)
@@ -420,7 +421,8 @@ read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end, LONGEST * r)
if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
result |= -(((LONGEST) 1) << shift);
- *r = result;
+ if (r)
+ *r = result;
return buf;
}
\f
@@ -498,10 +500,19 @@ dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end)
return *buf - DW_OP_reg0;
}
- if (*buf != DW_OP_regx)
+ if (*buf == DW_OP_GNU_regval_type)
+ {
+ buf++;
+ buf = read_uleb128 (buf, buf_end, &dwarf_reg);
+ buf = read_uleb128 (buf, buf_end, NULL);
+ }
+ else if (*buf == DW_OP_regx)
+ {
+ buf++;
+ buf = read_uleb128 (buf, buf_end, &dwarf_reg);
+ }
+ else
return -1;
- buf++;
- buf = read_uleb128 (buf, buf_end, &dwarf_reg);
if (buf != buf_end || (int) dwarf_reg != dwarf_reg)
return -1;
return dwarf_reg;
@@ -531,7 +542,7 @@ dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf, const gdb_byte *buf_end,
buf++;
buf = read_uleb128 (buf, buf_end, &dwarf_reg);
if ((int) dwarf_reg != dwarf_reg)
- return -1;
+ return -1;
}
else
return -1;
@@ -552,7 +563,7 @@ dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf, const gdb_byte *buf_end,
{
buf++;
if (buf >= buf_end)
- return -1;
+ return -1;
*deref_size_return = *buf++;
}
else
@@ -564,6 +575,30 @@ dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf, const gdb_byte *buf_end,
return dwarf_reg;
}
+/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_fbreg(X) fill
+ in FB_OFFSET_RETURN with the X offset and return 1. Otherwise return 0. */
+
+int
+dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
+ CORE_ADDR *fb_offset_return)
+{
+ LONGEST fb_offset;
+
+ if (buf_end <= buf)
+ return 0;
+
+ if (*buf != DW_OP_fbreg)
+ return 0;
+ buf++;
+
+ buf = read_sleb128 (buf, buf_end, &fb_offset);
+ *fb_offset_return = fb_offset;
+ if (buf != buf_end || fb_offset != (LONGEST) *fb_offset_return)
+ return 0;
+
+ return 1;
+}
+
/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_bregSP(X) fill
in SP_OFFSET_RETURN with the X offset and return 1. Otherwise return 0.
The matched SP register number depends on GDBARCH. */
@@ -585,7 +620,7 @@ dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf,
else
{
if (*buf != DW_OP_bregx)
- return 0;
+ return 0;
buf++;
buf = read_uleb128 (buf, buf_end, &dwarf_reg);
}
@@ -602,30 +637,6 @@ dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf,
return 1;
}
-/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_fbreg(X) fill
- in FB_OFFSET_RETURN with the X offset and return 1. Otherwise return 0. */
-
-int
-dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
- CORE_ADDR *fb_offset_return)
-{
- LONGEST fb_offset;
-
- if (buf_end <= buf)
- return 0;
-
- if (*buf != DW_OP_fbreg)
- return 0;
- buf++;
-
- buf = read_sleb128 (buf, buf_end, &fb_offset);
- *fb_offset_return = fb_offset;
- if (buf != buf_end || fb_offset != (LONGEST) *fb_offset_return)
- return 0;
-
- return 1;
-}
-
/* The engine for the expression evaluator. Using the context in CTX,
evaluate the expression between OP_PTR and OP_END. */
@@ -1346,7 +1357,8 @@ execute_stack_op (struct dwarf_expr_context *ctx,
{
op_ptr += len;
ctx->funcs->push_dwarf_reg_entry_value (ctx, dwarf_reg,
- 0 /* unused */, -1);
+ 0 /* unused */,
+ -1 /* deref_size */);
goto no_push;
}
@@ -1511,6 +1523,18 @@ ctx_no_get_base_type (struct dwarf_expr_context *ctx, size_t die)
error (_("Support for typed DWARF is not supported in this context"));
}
+/* Stub dwarf_expr_context_funcs.push_dwarf_block_entry_value
+ implementation. */
+
+void
+ctx_no_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
+ int dwarf_reg, CORE_ADDR fb_offset,
+ int deref_size)
+{
+ internal_error (__FILE__, __LINE__,
+ _("Support for DW_OP_GNU_entry_value is unimplemented"));
+}
+
void
_initialize_dwarf2expr (void)
{
--- a/gdb/dwarf2expr.h
+++ b/gdb/dwarf2expr.h
@@ -71,7 +71,7 @@ struct dwarf_expr_context_funcs
DW_AT_GNU_call_site_data_value instead of DW_AT_GNU_call_site_value. */
void (*push_dwarf_reg_entry_value) (struct dwarf_expr_context *ctx,
int dwarf_reg, CORE_ADDR fb_offset,
- CORE_ADDR deref_size);
+ int deref_size);
#if 0
/* Not yet implemented. */
@@ -274,18 +274,21 @@ CORE_ADDR ctx_no_get_frame_pc (void *baton);
CORE_ADDR ctx_no_get_tls_address (void *baton, CORE_ADDR offset);
void ctx_no_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset);
struct type *ctx_no_get_base_type (struct dwarf_expr_context *ctx, size_t die);
+void ctx_no_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
+ int dwarf_reg, CORE_ADDR fb_offset,
+ int deref_size);
int dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end);
-int dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf,
- const gdb_byte *buf_end,
- CORE_ADDR *sp_offset_return);
+int dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf,
+ const gdb_byte *buf_end,
+ CORE_ADDR *deref_size_return);
int dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
CORE_ADDR *fb_offset_return);
-int dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf,
- const gdb_byte *buf_end,
- CORE_ADDR *deref_size_return);
+int dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf,
+ const gdb_byte *buf_end,
+ CORE_ADDR *sp_offset_return);
#endif /* dwarf2expr.h */
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -332,7 +332,7 @@ show_tailcall_debug (struct ui_file *file, int from_tty,
/* Find DW_TAG_GNU_call_site's DW_AT_GNU_call_site_target address.
CALLER_FRAME (for registers) can be NULL if it is not known. This function
- always returns valid address or it throws NOT_FOUND_ERROR. */
+ always returns valid address or it throws NO_ENTRY_VALUE_ERROR. */
static CORE_ADDR
call_site_to_target_addr (struct call_site *call_site,
@@ -349,10 +349,10 @@ call_site_to_target_addr (struct call_site *call_site,
dwarf_block = FIELD_DWARF_BLOCK (call_site->target);
if (dwarf_block == NULL)
- throw_error (NOT_FOUND_ERROR,
+ throw_error (NO_ENTRY_VALUE_ERROR,
_("DW_AT_GNU_call_site_target is not specified"));
if (caller_frame == NULL)
- throw_error (NOT_FOUND_ERROR,
+ throw_error (NO_ENTRY_VALUE_ERROR,
_("DW_AT_GNU_call_site_target DWARF block resolving "
"requires known frame which is currently not "
"available"));
@@ -377,7 +377,7 @@ call_site_to_target_addr (struct call_site *call_site,
physname = FIELD_STATIC_PHYSNAME (call_site->target);
msym = lookup_minimal_symbol_text (physname, NULL);
if (msym == NULL)
- throw_error (NOT_FOUND_ERROR,
+ throw_error (NO_ENTRY_VALUE_ERROR,
_("Cannot find function \"%s\" for a call site target"),
physname);
return SYMBOL_VALUE_ADDRESS (msym);
@@ -392,8 +392,8 @@ call_site_to_target_addr (struct call_site *call_site,
}
/* Convert function entry point exact address ADDR to the function which is
- compliant with TAIL_CALL_LIST_COMPLETE condition. Throw NOT_FOUND_ERROR
- otherwise. */
+ compliant with TAIL_CALL_LIST_COMPLETE condition. Throw
+ NO_ENTRY_VALUE_ERROR otherwise. */
static struct symbol *
func_addr_to_tail_call_list (struct gdbarch *gdbarch, CORE_ADDR addr)
@@ -402,7 +402,7 @@ func_addr_to_tail_call_list (struct gdbarch *gdbarch, CORE_ADDR addr)
struct type *type;
if (sym == NULL || BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) != addr)
- throw_error (NOT_FOUND_ERROR,
+ throw_error (NO_ENTRY_VALUE_ERROR,
_("DW_TAG_GNU_call_site resolving failed to find function "
"name for address %s"),
paddress (gdbarch, addr));
@@ -417,23 +417,9 @@ func_addr_to_tail_call_list (struct gdbarch *gdbarch, CORE_ADDR addr)
/* Define VEC (CORE_ADDR) functions. */
DEF_VEC_I (CORE_ADDR);
-/* Cleanup helper to free VEC (CORE_ADDR) **. */
-
-static void
-free_addr_vecp (void *arg)
-{
- VEC (CORE_ADDR) **vecp = arg;
-
- if (*vecp)
- {
- VEC_free (CORE_ADDR, *vecp);
- *vecp = NULL;
- }
-}
-
/* Verify function with entry point exact address ADDR can never call itself
- via its tail calls (incl. transitively). Throw NOT_FOUND_ERROR if it can
- call itself via tail calls.
+ via its tail calls (incl. transitively). Throw NO_ENTRY_VALUE_ERROR if it
+ can call itself via tail calls.
If a funtion can tail call itself its entry value based parameters are
unreliable. There is no verification whether the value of some/all
@@ -461,7 +447,7 @@ func_verify_no_selftailcall (struct gdbarch *gdbarch, CORE_ADDR verify_addr)
NULL);
make_cleanup_htab_delete (addr_hash);
- make_cleanup (free_addr_vecp, &todo);
+ make_cleanup (VEC_cleanup (CORE_ADDR), &todo);
VEC_safe_push (CORE_ADDR, todo, verify_addr);
while (!VEC_empty (CORE_ADDR, todo))
@@ -488,9 +474,10 @@ func_verify_no_selftailcall (struct gdbarch *gdbarch, CORE_ADDR verify_addr)
struct minimal_symbol *msym;
msym = lookup_minimal_symbol_by_pc (verify_addr);
- throw_error (NOT_FOUND_ERROR, _("DW_OP_GNU_entry_value resolving "
- "has found function \"%s\" at %s "
- "can call itself via tail calls"),
+ throw_error (NO_ENTRY_VALUE_ERROR,
+ _("DW_OP_GNU_entry_value resolving has found "
+ "function \"%s\" at %s can call itself via tail "
+ "calls"),
msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym),
paddress (gdbarch, verify_addr));
}
@@ -625,26 +612,12 @@ chain_candidate (struct gdbarch *gdbarch, struct call_site_chain **resultp,
gdb_assert (result->callers + result->callees < result->length);
}
-/* Cleanup helper to free VEC (call_sitep) **. */
-
-static void
-free_call_sitep_vecp (void *arg)
-{
- VEC (call_sitep) **vecp = arg;
-
- if (*vecp)
- {
- VEC_free (call_sitep, *vecp);
- *vecp = NULL;
- }
-}
-
/* Create and return call_site_chain for CALLER_PC and CALLEE_PC. All the
assumed frames between them use GDBARCH. Use depth first search so we can
keep single CHAIN of call_site's back to CALLER_PC. Function recursion
would have needless GDB stack overhead. Caller is responsible for xfree of
the returned result. Any unreliability results in thrown
- NOT_FOUND_ERROR. */
+ NO_ENTRY_VALUE_ERROR. */
static struct call_site_chain *
call_site_find_chain_1 (struct gdbarch *gdbarch, CORE_ADDR caller_pc,
@@ -668,7 +641,7 @@ call_site_find_chain_1 (struct gdbarch *gdbarch, CORE_ADDR caller_pc,
/* We are not interested in the specific PC inside the callee function. */
callee_pc = get_pc_function_start (callee_pc);
if (callee_pc == 0)
- throw_error (NOT_FOUND_ERROR, _("Unable to find function for PC %s"),
+ throw_error (NO_ENTRY_VALUE_ERROR, _("Unable to find function for PC %s"),
paddress (gdbarch, callee_pc));
back_to_retval = make_cleanup (free_current_contents, &retval);
@@ -680,7 +653,7 @@ call_site_find_chain_1 (struct gdbarch *gdbarch, CORE_ADDR caller_pc,
NULL);
make_cleanup_htab_delete (addr_hash);
- make_cleanup (free_call_sitep_vecp, &chain);
+ make_cleanup (VEC_cleanup (call_sitep), &chain);
/* Do not push CALL_SITE to CHAIN. Push there only the first tail call site at
the target's function. All the possible tail call sites in the target's
@@ -766,7 +739,7 @@ call_site_find_chain_1 (struct gdbarch *gdbarch, CORE_ADDR caller_pc,
msym_caller = lookup_minimal_symbol_by_pc (caller_pc);
msym_callee = lookup_minimal_symbol_by_pc (callee_pc);
- throw_error (NOT_FOUND_ERROR,
+ throw_error (NO_ENTRY_VALUE_ERROR,
_("There are no unambiguously determinable intermediate "
"callers or callees between caller function \"%s\" at %s "
"and callee function \"%s\" at %s"),
@@ -801,7 +774,7 @@ call_site_find_chain (struct gdbarch *gdbarch, CORE_ADDR caller_pc,
}
if (e.reason < 0)
{
- if (e.error == NOT_FOUND_ERROR)
+ if (e.error == NO_ENTRY_VALUE_ERROR)
{
if (info_verbose)
exception_print (gdb_stdout, e);
@@ -818,15 +791,17 @@ call_site_find_chain (struct gdbarch *gdbarch, CORE_ADDR caller_pc,
callee. See DWARF_REG and FB_OFFSET description at struct
dwarf_expr_context_funcs->push_dwarf_reg_entry_value.
- Function always returns non-NULL, it throws NOT_FOUND_ERROR otherwise. */
+ Function always returns non-NULL, it throws NO_ENTRY_VALUE_ERROR
+ otherwise. */
static struct call_site_parameter *
-dwarf_expr_dwarf_reg_entry_value (struct frame_info *frame, int dwarf_reg,
- CORE_ADDR fb_offset)
+dwarf_expr_reg_to_entry_parameter (struct frame_info *frame, int dwarf_reg,
+ CORE_ADDR fb_offset,
+ struct dwarf2_per_cu_data **per_cu_return)
{
CORE_ADDR func_addr = get_frame_func (frame);
CORE_ADDR caller_pc;
- struct gdbarch *caller_gdbarch = frame_unwind_arch (frame);
+ struct gdbarch *gdbarch = get_frame_arch (frame);
struct frame_info *caller_frame = get_prev_frame (frame);
struct call_site *call_site;
int iparams;
@@ -835,13 +810,27 @@ dwarf_expr_dwarf_reg_entry_value (struct frame_info *frame, int dwarf_reg,
struct call_site_parameter *parameter;
CORE_ADDR target_addr;
+ if (gdbarch != frame_unwind_arch (frame))
+ {
+ struct minimal_symbol *msym = lookup_minimal_symbol_by_pc (func_addr);
+ struct gdbarch *caller_gdbarch = frame_unwind_arch (frame);
+
+ throw_error (NO_ENTRY_VALUE_ERROR,
+ _("DW_OP_GNU_entry_value resolving callee gdbarch %s "
+ "(of %s (%s)) does not match caller gdbarch %s"),
+ gdbarch_bfd_arch_info (gdbarch)->printable_name,
+ paddress (gdbarch, func_addr),
+ msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym),
+ gdbarch_bfd_arch_info (caller_gdbarch)->printable_name);
+ }
+
if (caller_frame == NULL)
{
struct minimal_symbol *msym = lookup_minimal_symbol_by_pc (func_addr);
- throw_error (NOT_FOUND_ERROR, _("DW_OP_GNU_entry_value resolving "
- "requires caller of %s (%s)"),
- paddress (get_frame_arch (frame), func_addr),
+ throw_error (NO_ENTRY_VALUE_ERROR, _("DW_OP_GNU_entry_value resolving "
+ "requires caller of %s (%s)"),
+ paddress (gdbarch, func_addr),
msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym));
}
caller_pc = get_frame_pc (caller_frame);
@@ -852,11 +841,11 @@ dwarf_expr_dwarf_reg_entry_value (struct frame_info *frame, int dwarf_reg,
struct minimal_symbol *msym = lookup_minimal_symbol_by_pc (caller_pc);
/* DW_TAG_gnu_call_site will be missing just if GCC could not determine
- the call target. So do not complain more than NOT_FOUND_ERROR. */
- throw_error (NOT_FOUND_ERROR,
+ the call target. */
+ throw_error (NO_ENTRY_VALUE_ERROR,
_("DW_OP_GNU_entry_value resolving cannot find "
"DW_TAG_GNU_call_site %s in %s"),
- paddress (caller_gdbarch, caller_pc),
+ paddress (gdbarch, caller_pc),
msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym));
}
@@ -867,19 +856,19 @@ dwarf_expr_dwarf_reg_entry_value (struct frame_info *frame, int dwarf_reg,
target_msym = lookup_minimal_symbol_by_pc (target_addr);
func_msym = lookup_minimal_symbol_by_pc (func_addr);
- throw_error (NOT_FOUND_ERROR,
+ throw_error (NO_ENTRY_VALUE_ERROR,
_("DW_OP_GNU_entry_value resolving expects callee %s at %s "
"but the called frame is for %s at %s"),
(target_msym == NULL ? "???"
: SYMBOL_PRINT_NAME (target_msym)),
- paddress (caller_gdbarch, target_addr),
+ paddress (gdbarch, target_addr),
func_msym == NULL ? "???" : SYMBOL_PRINT_NAME (func_msym),
- paddress (caller_gdbarch, func_addr));
+ paddress (gdbarch, func_addr));
}
/* No entry value based parameters would be reliable if this function can
call itself via tail calls. */
- func_verify_no_selftailcall (caller_gdbarch, func_addr);
+ func_verify_no_selftailcall (gdbarch, func_addr);
for (iparams = 0; iparams < call_site->parameter_count; iparams++)
{
@@ -897,103 +886,94 @@ dwarf_expr_dwarf_reg_entry_value (struct frame_info *frame, int dwarf_reg,
struct minimal_symbol *msym = lookup_minimal_symbol_by_pc (caller_pc);
/* DW_TAG_GNU_call_site_parameter will be missing just if GCC could not
- determine its value. So do not complain more than NOT_FOUND_ERROR. */
- throw_error (NOT_FOUND_ERROR, _("Cannot find DWARF reg%d/fbreg(%s) at "
- "DW_TAG_GNU_call_site %s at %s"),
- dwarf_reg, paddress (caller_gdbarch, fb_offset),
- paddress (caller_gdbarch, caller_pc),
+ determine its value. */
+ throw_error (NO_ENTRY_VALUE_ERROR, _("Cannot find matching parameter "
+ "at DW_TAG_GNU_call_site %s at %s"),
+ paddress (gdbarch, caller_pc),
msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym));
}
+ *per_cu_return = call_site->per_cu;
return parameter;
}
-/* Return dwarf2_locexpr_baton for PARAMETER matching DEREF_SIZE. If
- DEREF_SIZE is -1, return the normal DW_AT_GNU_call_site_value block.
- Otherwise return the DW_AT_GNU_call_site_data_value (dereferenced) block.
-
- Function always returns non-NULL, it throws NOT_FOUND_ERROR if DEREF_SIZE
- was not -1 and the DW_AT_GNU_call_site_data_value block is not defined by
- PARAMETER. */
-
-static struct dwarf2_locexpr_baton *
-dwarf_entry_parameter_to_block (struct call_site_parameter *parameter,
- CORE_ADDR deref_size)
-{
-
- if (deref_size == -1)
- {
- gdb_assert (parameter->call_site_value != NULL);
- return parameter->call_site_value;
- }
-
- /* DEREF_SIZE size is not verified here. */
-
- if (parameter->call_site_data_value == NULL)
- throw_error (NOT_FOUND_ERROR,
- _("Cannot resolve DW_AT_GNU_call_site_data_value"));
-
- return parameter->call_site_data_value;
-}
-
-/* Return value for PARAMETER matching DEREF_SIZE, see
- dwarf_entry_parameter_to_block for the description of these parameters.
+/* Return value for PARAMETER matching DEREF_SIZE. If DEREF_SIZE is -1, return
+ the normal DW_AT_GNU_call_site_value block. Otherwise return the
+ DW_AT_GNU_call_site_data_value (dereferenced) block.
TYPE and CALLER_FRAME specify how to evaluate the DWARF block into returned
struct value.
Function always returns non-NULL, non-optimized out value. It throws
- NOT_FOUND_ERROR if it cannot resolve the value for any reason. */
+ NO_ENTRY_VALUE_ERROR if it cannot resolve the value for any reason. */
static struct value *
dwarf_entry_parameter_to_value (struct call_site_parameter *parameter,
CORE_ADDR deref_size, struct type *type,
- struct frame_info *caller_frame)
+ struct frame_info *caller_frame,
+ struct dwarf2_per_cu_data *per_cu)
{
- struct dwarf2_locexpr_baton *dwarf_block;
+ const gdb_byte *data_src;
gdb_byte *data;
+ size_t size;
- dwarf_block = dwarf_entry_parameter_to_block (parameter, deref_size);
+ data_src = deref_size == -1 ? parameter->value : parameter->data_value;
+ size = deref_size == -1 ? parameter->value_size : parameter->data_value_size;
+
+ /* DEREF_SIZE size is not verified here. */
+ if (data_src == NULL)
+ throw_error (NO_ENTRY_VALUE_ERROR,
+ _("Cannot resolve DW_AT_GNU_call_site_data_value"));
/* DW_AT_GNU_call_site_value is a DWARF expression, not a DWARF
- location. */
- data = alloca (dwarf_block->size + 1);
- memcpy (data, dwarf_block->data, dwarf_block->size);
- data[dwarf_block->size] = DW_OP_stack_value;
+ location. Postprocessing of DWARF_VALUE_MEMORY would lose the type from
+ DWARF block. */
+ data = alloca (size + 1);
+ memcpy (data, data_src, size);
+ data[size] = DW_OP_stack_value;
- return dwarf2_evaluate_loc_desc (type, caller_frame, data,
- dwarf_block->size + 1, dwarf_block->per_cu);
+ return dwarf2_evaluate_loc_desc (type, caller_frame, data, size + 1, per_cu);
}
-/* Execute DWARF_BLOCK for caller of the CTX's frame. CTX must be of
- dwarf_expr_ctx_funcs kind. See DWARF_REG, FB_OFFSET and DEREF_SIZE
- description at struct dwarf_expr_context_funcs->push_dwarf_reg_entry_value.
+/* Execute call_site_parameter's DWARF block matching DEREF_SIZE for caller of
+ the CTX's frame. CTX must be of dwarf_expr_ctx_funcs kind. See DWARF_REG
+ and FB_OFFSET description at struct
+ dwarf_expr_context_funcs->push_dwarf_reg_entry_value.
- The CTX caller can be from a different CU - per_cu_dwarf_call is simpler as
- it does not support cross-CU DWARF executions. */
+ The CTX caller can be from a different CU - per_cu_dwarf_call implementation
+ can be more simple as it does not support cross-CU DWARF executions. */
static void
dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
int dwarf_reg, CORE_ADDR fb_offset,
- CORE_ADDR deref_size)
+ int deref_size)
{
struct dwarf_expr_baton *debaton;
struct frame_info *frame, *caller_frame;
- struct dwarf2_locexpr_baton *dwarf_block;
+ struct dwarf2_per_cu_data *caller_per_cu;
struct dwarf_expr_baton baton_local;
struct dwarf_expr_context saved_ctx;
struct call_site_parameter *parameter;
+ const gdb_byte *data_src;
+ size_t size;
gdb_assert (ctx->funcs == &dwarf_expr_ctx_funcs);
debaton = ctx->baton;
frame = debaton->frame;
caller_frame = get_prev_frame (frame);
- parameter = dwarf_expr_dwarf_reg_entry_value (frame, dwarf_reg, fb_offset);
- dwarf_block = dwarf_entry_parameter_to_block (parameter, deref_size);
+ parameter = dwarf_expr_reg_to_entry_parameter (frame, dwarf_reg, fb_offset,
+ &caller_per_cu);
+ data_src = deref_size == -1 ? parameter->value : parameter->data_value;
+ size = deref_size == -1 ? parameter->value_size : parameter->data_value_size;
+
+ /* DEREF_SIZE size is not verified here. */
+ if (data_src == NULL)
+ throw_error (NO_ENTRY_VALUE_ERROR,
+ _("Cannot resolve DW_AT_GNU_call_site_data_value"));
baton_local.frame = caller_frame;
- baton_local.per_cu = dwarf_block->per_cu;
+ baton_local.per_cu = caller_per_cu;
saved_ctx.gdbarch = ctx->gdbarch;
saved_ctx.addr_size = ctx->addr_size;
@@ -1004,7 +984,7 @@ dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
ctx->offset = dwarf2_per_cu_text_offset (baton_local.per_cu);
ctx->baton = &baton_local;
- dwarf_expr_eval (ctx, dwarf_block->data, dwarf_block->size);
+ dwarf_expr_eval (ctx, data_src, size);
ctx->gdbarch = saved_ctx.gdbarch;
ctx->addr_size = saved_ctx.addr_size;
@@ -1012,6 +992,151 @@ dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
ctx->baton = saved_ctx.baton;
}
+/* VALUE must be of type lval_computed with entry_data_value_funcs. Perform
+ the indirect method on it, that is use its stored target value, the sole
+ purpose of entry_data_value_funcs.. */
+
+static struct value *
+entry_data_value_coerce_ref (const struct value *value)
+{
+ struct type *checked_type = check_typedef (value_type (value));
+ struct value *target_val;
+
+ if (TYPE_CODE (checked_type) != TYPE_CODE_REF)
+ return NULL;
+
+ target_val = value_computed_closure (value);
+ value_incref (target_val);
+ return target_val;
+}
+
+/* Implement copy_closure. */
+
+static void *
+entry_data_value_copy_closure (const struct value *v)
+{
+ struct value *target_val = value_computed_closure (v);
+
+ value_incref (target_val);
+ return target_val;
+}
+
+/* Implement free_closure. */
+
+static void
+entry_data_value_free_closure (struct value *v)
+{
+ struct value *target_val = value_computed_closure (v);
+
+ value_free (target_val);
+}
+
+/* Vector for methods for an entry value reference where the referenced value
+ is stored in the caller. On the first dereference use
+ DW_AT_GNU_call_site_data_value in the caller. */
+
+static const struct lval_funcs entry_data_value_funcs =
+{
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* check_validity */
+ NULL, /* check_any_valid */
+ NULL, /* indirect */
+ entry_data_value_coerce_ref,
+ NULL, /* check_synthetic_pointer */
+ entry_data_value_copy_closure,
+ entry_data_value_free_closure
+};
+
+/* Read parameter of TYPE at (callee) FRAME's function entry. DWARF_REG and
+ FB_OFFSET are used to match DW_AT_location at the caller's
+ DW_TAG_GNU_call_site_parameter. See DWARF_REG and FB_OFFSET description at
+ struct dwarf_expr_context_funcs->push_dwarf_reg_entry_value.
+
+ Function always returns non-NULL value. It throws NO_ENTRY_VALUE_ERROR if it
+ cannot resolve the parameter for any reason. */
+
+static struct value *
+value_of_dwarf_reg_entry (struct type *type, struct frame_info *frame,
+ int dwarf_reg, CORE_ADDR fb_offset)
+{
+ struct type *checked_type = check_typedef (type);
+ struct type *target_type = TYPE_TARGET_TYPE (checked_type);
+ struct frame_info *caller_frame = get_prev_frame (frame);
+ struct value *outer_val, *target_val, *val;
+ struct call_site_parameter *parameter;
+ struct dwarf2_per_cu_data *caller_per_cu;
+ CORE_ADDR addr;
+
+ parameter = dwarf_expr_reg_to_entry_parameter (frame, dwarf_reg, fb_offset,
+ &caller_per_cu);
+
+ outer_val = dwarf_entry_parameter_to_value (parameter, -1 /* deref_size */,
+ type, caller_frame,
+ caller_per_cu);
+
+ /* Check if DW_AT_GNU_call_site_data_value cannot be used. If it should be
+ used and it is not available do not fall back to OUTER_VAL - dereferencing
+ TYPE_CODE_REF with non-entry data value would give current value - not the
+ entry value. */
+
+ if (TYPE_CODE (checked_type) != TYPE_CODE_REF
+ || TYPE_TARGET_TYPE (checked_type) == NULL)
+ return outer_val;
+
+ target_val = dwarf_entry_parameter_to_value (parameter,
+ TYPE_LENGTH (target_type),
+ target_type, caller_frame,
+ caller_per_cu);
+
+ /* value_as_address dereferences TYPE_CODE_REF. */
+ addr = extract_typed_address (value_contents (outer_val), checked_type);
+
+ /* The target entry value has artificial address of the entry value
+ reference. */
+ VALUE_LVAL (target_val) = lval_memory;
+ set_value_address (target_val, addr);
+
+ release_value (target_val);
+ val = allocate_computed_value (type, &entry_data_value_funcs,
+ target_val /* closure */);
+
+ /* Copy the referencing pointer to the new computed value. */
+ memcpy (value_contents_raw (val), value_contents_raw (outer_val), TYPE_LENGTH (checked_type));
+ set_value_lazy (val, 0);
+
+ return val;
+}
+
+/* Read parameter of TYPE at (callee) FRAME's function entry. DATA and
+ SIZE are DWARF block used to match DW_AT_location at the caller's
+ DW_TAG_GNU_call_site_parameter.
+
+ Function always returns non-NULL value. It throws NO_ENTRY_VALUE_ERROR if it
+ cannot resolve the parameter for any reason. */
+
+static struct value *
+value_of_dwarf_block_entry (struct type *type, struct frame_info *frame,
+ const gdb_byte *block, size_t block_len)
+{
+ int dwarf_reg;
+ CORE_ADDR fb_offset;
+
+ dwarf_reg = dwarf_block_to_dwarf_reg (block, block + block_len);
+ if (dwarf_reg != -1)
+ return value_of_dwarf_reg_entry (type, frame, dwarf_reg, 0 /* unused */);
+
+ if (dwarf_block_to_fb_offset (block, block + block_len, &fb_offset))
+ return value_of_dwarf_reg_entry (type, frame, -1, fb_offset);
+
+ /* This can normally happen - throw NO_ENTRY_VALUE_ERROR to get the message
+ suppressed during normal operation. The expression can be arbitrary if
+ there is no caller-callee entry value binding expected. */
+ throw_error (NO_ENTRY_VALUE_ERROR,
+ _("DWARF-2 expression error: DW_OP_GNU_entry_value is supported "
+ "only for single DW_OP_reg* or for DW_OP_fbreg(*)"));
+}
+
struct piece_closure
{
/* Reference count. */
@@ -1780,6 +1905,7 @@ static const struct lval_funcs pieced_value_funcs = {
check_pieced_value_validity,
check_pieced_value_invalid,
indirect_pieced_value,
+ NULL, /* coerce_ref */
check_pieced_synthetic_pointer,
copy_pieced_value_closure,
free_pieced_value_closure
@@ -1853,19 +1979,18 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
}
if (ex.reason < 0)
{
- do_cleanups (old_chain);
-
if (ex.error == NOT_AVAILABLE_ERROR)
{
+ do_cleanups (old_chain);
retval = allocate_value (type);
mark_value_bytes_unavailable (retval, 0, TYPE_LENGTH (type));
return retval;
}
- else if (ex.error == NOT_FOUND_ERROR)
+ else if (ex.error == NO_ENTRY_VALUE_ERROR)
{
if (info_verbose)
exception_print (gdb_stdout, ex);
-
+ do_cleanups (old_chain);
return allocate_optimized_out_value (type);
}
else
@@ -2098,8 +2223,8 @@ needs_frame_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset)
/* DW_OP_GNU_entry_value accesses require a caller, therefore a frame. */
static void
-needs_dwarf_reg_entry_value (struct dwarf_expr_context *ctx, int dwarf_reg,
- CORE_ADDR fb_offset, CORE_ADDR deref_size)
+needs_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
+ int dwarf_reg, CORE_ADDR fb_offset, int deref_size)
{
struct needs_frame_baton *nf_baton = ctx->baton;
@@ -2934,6 +3059,19 @@ locexpr_read_variable (struct symbol *symbol, struct frame_info *frame)
return val;
}
+/* Return the value of SYMBOL in FRAME at (callee) FRAME's function
+ entry. SYMBOL should be a function parameter, otherwise NO_ENTRY_VALUE_ERROR
+ will be thrown. */
+
+static struct value *
+locexpr_read_variable_at_entry (struct symbol *symbol, struct frame_info *frame)
+{
+ struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+
+ return value_of_dwarf_block_entry (SYMBOL_TYPE (symbol), frame, dlbaton->data,
+ dlbaton->size);
+}
+
/* Return non-zero iff we need a frame to evaluate SYMBOL. */
static int
locexpr_read_needs_frame (struct symbol *symbol)
@@ -3585,7 +3723,7 @@ locexpr_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
evaluator. */
const struct symbol_computed_ops dwarf2_locexpr_funcs = {
locexpr_read_variable,
- NULL, /* read_variable_at_entry */
+ locexpr_read_variable_at_entry,
locexpr_read_needs_frame,
locexpr_describe_location,
locexpr_tracepoint_var_ref
@@ -3616,156 +3754,21 @@ loclist_read_variable (struct symbol *symbol, struct frame_info *frame)
return val;
}
-/* VALUE must be of type lval_computed with entry_data_value_funcs. Perform
- the indirect method on it, that is use its stored target value, the sole
- purpose of entry_data_value_funcs.. */
-
-struct value *
-entry_data_value_indirect (struct value *value)
-{
- struct type *checked_type = check_typedef (value_type (value));
- struct value *target_val = value_computed_closure (value);
-
- gdb_assert (TYPE_CODE (checked_type) == TYPE_CODE_PTR
- || TYPE_CODE (checked_type) == TYPE_CODE_REF);
-
- value_incref (target_val);
- return target_val;
-}
-
-/* Implement copy_closure. */
-
-static void *
-entry_data_value_copy_closure (const struct value *v)
-{
- struct value *target_val = value_computed_closure (v);
-
- value_incref (target_val);
- return target_val;
-}
-
-/* Implement free_closure. */
-
-static void
-entry_data_value_free_closure (struct value *v)
-{
- struct value *target_val = value_computed_closure (v);
-
- value_free (target_val);
-}
-
-/* Vector for methods for an entry value reference where the referenced value
- is stored in the caller. On the first dereference use
- DW_AT_GNU_call_site_data_value in the caller. */
-
-static struct lval_funcs entry_data_value_funcs =
-{
- NULL, /* read */
- NULL, /* write */
- NULL, /* check_validity */
- NULL, /* check_any_valid */
- entry_data_value_indirect,
- NULL, /* check_synthetic_pointer */
- entry_data_value_copy_closure,
- entry_data_value_free_closure
-};
-
-/* Return value of parameter of TYPE at (callee) FRAME which at function entry
- point. Parameter has been passed in DWARF_REG or FB_OFFSET, see their
- description at struct dwarf_expr_context_funcs->push_dwarf_reg_entry_value.
-
- Function always returns non-NULL, non-optimized out value. It throws
- NOT_FOUND_ERROR if it cannot resolve the value for any reason. */
-
-static struct value *
-value_of_dwarf_reg_entry (struct type *type, struct frame_info *frame,
- int dwarf_reg, CORE_ADDR fb_offset)
-{
- struct type *checked_type = check_typedef (type);
- struct frame_info *caller_frame = get_prev_frame (frame);
- struct value *outer_val;
- struct call_site_parameter *parameter;
-
- parameter = dwarf_expr_dwarf_reg_entry_value (frame, dwarf_reg, fb_offset);
-
- outer_val = dwarf_entry_parameter_to_value (parameter, -1 /* deref_size */,
- type, caller_frame);
-
- /* Check if DW_AT_GNU_call_site_data_value cannot be used. */
-
- if ((TYPE_CODE (checked_type) == TYPE_CODE_PTR
- || TYPE_CODE (checked_type) == TYPE_CODE_REF)
- && TYPE_TARGET_TYPE (checked_type) != NULL)
- {
- struct type *target_type = TYPE_TARGET_TYPE (checked_type);
- volatile struct gdb_exception e;
- struct value *target_val;
-
- TRY_CATCH (e, RETURN_MASK_ERROR)
- {
- int target_length = TYPE_LENGTH (target_type);
-
- target_val = dwarf_entry_parameter_to_value (parameter, target_length,
- target_type,
- caller_frame);
- }
- if (e.reason < 0)
- {
- if (e.error == NOT_FOUND_ERROR)
- {
- if (info_verbose)
- exception_print (gdb_stdout, e);
- }
- else
- throw_exception (e);
- }
- else
- {
- CORE_ADDR addr;
- struct value *val;
-
- /* value_as_address dereferences TYPE_CODE_REF. */
- addr = extract_typed_address (value_contents (outer_val),
- checked_type);
-
- /* The target entry value has artificial address of the entry value
- reference. */
- VALUE_LVAL (target_val) = lval_memory;
- set_value_address (target_val, addr);
-
- release_value (target_val);
- val = allocate_computed_value (type, &entry_data_value_funcs,
- target_val /* closure */);
-
- /* Copy the referencing pointer to the new computed value. */
- memcpy (value_contents_raw (val), value_contents_raw (outer_val),
- TYPE_LENGTH (checked_type));
- set_value_lazy (val, 0);
-
- return val;
- }
- }
-
- return outer_val;
-}
-
/* Read variable SYMBOL like loclist_read_variable at (callee) FRAME's function
- entry. SYMBOL should be a function parameter, otherwise NOT_FOUND_ERROR
+ entry. SYMBOL should be a function parameter, otherwise NO_ENTRY_VALUE_ERROR
will be thrown.
Function always returns non-NULL value, it may be marked optimized out if
- inferior frame information is not available. It throws NOT_FOUND_ERROR if
- it cannot resolve the parameter for any reason. */
+ inferior frame information is not available. It throws NO_ENTRY_VALUE_ERROR
+ if it cannot resolve the parameter for any reason. */
static struct value *
loclist_read_variable_at_entry (struct symbol *symbol, struct frame_info *frame)
{
struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
- struct value *val;
const gdb_byte *data;
size_t size;
- int dwarf_reg;
- CORE_ADDR deref_size, pc, fb_offset;
+ CORE_ADDR pc;
if (frame == NULL || !get_frame_func_if_available (frame, &pc))
return allocate_optimized_out_value (SYMBOL_TYPE (symbol));
@@ -3774,17 +3777,7 @@ loclist_read_variable_at_entry (struct symbol *symbol, struct frame_info *frame)
if (data == NULL)
return allocate_optimized_out_value (SYMBOL_TYPE (symbol));
- dwarf_reg = dwarf_block_to_dwarf_reg (data, data + size);
- if (dwarf_reg != -1)
- return value_of_dwarf_reg_entry (SYMBOL_TYPE (symbol), frame, dwarf_reg,
- 0 /* unused */);
-
- if (dwarf_block_to_fb_offset (data, data + size, &fb_offset))
- return value_of_dwarf_reg_entry (SYMBOL_TYPE (symbol), frame, -1,
- fb_offset);
-
- error (_("DWARF-2 expression error: DW_OP_GNU_entry_value is supported only "
- "for single DW_OP_reg* or for DW_OP_fbreg(*)"));
+ return value_of_dwarf_block_entry (SYMBOL_TYPE (symbol), frame, data, size);
}
/* Return non-zero iff we need a frame to evaluate SYMBOL. */
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -6127,24 +6127,6 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu)
using_directives = new->using_directives;
}
-/* Allocate a copy of BLK on CU's objfile_obstack (not comp_unit_obstack),
- including a copy of the BLK DWARF code. */
-
-static struct dwarf2_locexpr_baton *
-dlbaton_obstack_copy (const struct dwarf_block *blk, struct dwarf2_cu *cu)
-{
- struct objfile *objfile = cu->objfile;
- struct dwarf2_locexpr_baton *dlbaton;
-
- dlbaton = obstack_alloc (&objfile->objfile_obstack, sizeof (*dlbaton));
- dlbaton->data = obstack_copy (&objfile->objfile_obstack, blk->data,
- blk->size);
- dlbaton->size = blk->size;
- dlbaton->per_cu = cu->per_cu;
-
- return dlbaton;
-}
-
/* Read in DW_TAG_GNU_call_site and insert it to CU->call_site_htab. */
static void
@@ -6267,8 +6249,16 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
if (!attr || (attr_form_is_block (attr) && DW_BLOCK (attr)->size == 0))
/* Keep NULL DWARF_BLOCK. */;
else if (attr_form_is_block (attr))
- SET_FIELD_DWARF_BLOCK (call_site->target,
- dlbaton_obstack_copy (DW_BLOCK (attr), cu));
+ {
+ struct dwarf2_locexpr_baton *dlbaton;
+
+ dlbaton = obstack_alloc (&objfile->objfile_obstack, sizeof (*dlbaton));
+ dlbaton->data = DW_BLOCK (attr)->data;
+ dlbaton->size = DW_BLOCK (attr)->size;
+ dlbaton->per_cu = cu->per_cu;
+
+ SET_FIELD_DWARF_BLOCK (call_site->target, dlbaton);
+ }
else if (is_ref_attr (attr))
{
struct objfile *objfile = cu->objfile;
@@ -6310,6 +6300,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
"block nor reference, for DIE 0x%x [in module %s]"),
die->offset, cu->objfile->name);
+ call_site->per_cu = cu->per_cu;
+
for (child_die = die->child;
child_die && child_die->tag;
child_die = sibling_die (child_die))
@@ -6346,9 +6338,9 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
¶meter->fb_offset))
{
complaint (&symfile_complaints,
- _("Only single DW_OP_reg is supported for DW_FORM_block* "
- "DW_AT_location for DW_TAG_GNU_call_site "
- "child DIE 0x%x [in module %s]"),
+ _("Only single DW_OP_reg or DW_OP_fbreg is supported "
+ "for DW_FORM_block* DW_AT_location for "
+ "DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"),
child_die->offset, cu->objfile->name);
continue;
}
@@ -6362,10 +6354,12 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
child_die->offset, cu->objfile->name);
continue;
}
- parameter->call_site_value = dlbaton_obstack_copy (DW_BLOCK (attr), cu);
+ parameter->value = DW_BLOCK (attr)->data;
+ parameter->value_size = DW_BLOCK (attr)->size;
/* Parameters are not pre-cleared by memset above. */
- parameter->call_site_data_value = NULL;
+ parameter->data_value = NULL;
+ parameter->data_value_size = 0;
call_site->parameter_count++;
attr = dwarf2_attr (child_die, DW_AT_GNU_call_site_data_value, cu);
@@ -6377,8 +6371,10 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
"DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"),
child_die->offset, cu->objfile->name);
else
- parameter->call_site_data_value
- = dlbaton_obstack_copy (DW_BLOCK (attr), cu);
+ {
+ parameter->data_value = DW_BLOCK (attr)->data;
+ parameter->data_value_size = DW_BLOCK (attr)->size;
+ }
}
}
}
@@ -16599,14 +16595,6 @@ write_one_signatured_type (void **slot, void *d)
return 1;
}
-/* A cleanup function for an htab_t. */
-
-static void
-cleanup_htab (void *arg)
-{
- htab_delete (arg);
-}
-
/* Create an index file for OBJFILE in the directory DIR. */
static void
@@ -16663,7 +16651,7 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
psyms_seen = htab_create_alloc (100, htab_hash_pointer, htab_eq_pointer,
NULL, xcalloc, xfree);
- make_cleanup (cleanup_htab, psyms_seen);
+ make_cleanup_htab_delete (psyms_seen);
/* While we're scanning CU's create a table that maps a psymtab pointer
(which is what addrmap records) to its index (which is what is recorded
@@ -16673,7 +16661,7 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
hash_psymtab_cu_index,
eq_psymtab_cu_index,
NULL, xcalloc, xfree);
- make_cleanup (cleanup_htab, cu_index_htab);
+ make_cleanup_htab_delete (cu_index_htab);
psymtab_cu_index_map = (struct psymtab_cu_index_map *)
xmalloc (sizeof (struct psymtab_cu_index_map)
* dwarf2_per_objfile->n_comp_units);
--- a/gdb/exceptions.h
+++ b/gdb/exceptions.h
@@ -85,6 +85,9 @@ enum errors {
traceframe. */
NOT_AVAILABLE_ERROR,
+ /* DW_OP_GNU_entry_value resolving failed. */
+ NO_ENTRY_VALUE_ERROR,
+
/* Add more errors here. */
NR_ERRORS
};
--- a/gdb/f-lang.h
+++ b/gdb/f-lang.h
@@ -29,7 +29,8 @@ extern void f_print_type (struct type *, const char *, struct ui_file *, int,
int);
extern int f_val_print (struct type *, const gdb_byte *, int, CORE_ADDR,
- struct ui_file *, int, struct value *,
+ struct ui_file *, int,
+ const struct value *,
const struct value_print_options *);
/* Language-specific data structures */
--- a/gdb/f-valprint.c
+++ b/gdb/f-valprint.c
@@ -165,7 +165,8 @@ static void
f77_print_array_1 (int nss, int ndimensions, struct type *type,
const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
- struct ui_file *stream, int recurse, struct value *val,
+ struct ui_file *stream, int recurse,
+ const struct value *val,
const struct value_print_options *options,
int *elts)
{
@@ -216,7 +217,8 @@ static void
f77_print_array (struct type *type, const gdb_byte *valaddr,
int embedded_offset,
CORE_ADDR address, struct ui_file *stream,
- int recurse, struct value *val,
+ int recurse,
+ const struct value *val,
const struct value_print_options *options)
{
int ndimensions;
@@ -247,7 +249,7 @@ Type node corrupt! F77 arrays cannot have %d subscripts (%d Max)"),
int
f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
CORE_ADDR address, struct ui_file *stream, int recurse,
- struct value *original_value,
+ const struct value *original_value,
const struct value_print_options *options)
{
struct gdbarch *gdbarch = get_type_arch (type);
@@ -346,22 +348,12 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
{
struct value *deref_val;
- if (VALUE_LVAL (original_value) == lval_computed)
+ deref_val = coerce_ref_if_computed (original_value);
+ if (deref_val)
{
- const struct lval_funcs *funcs;
-
- funcs = value_computed_funcs (original_value);
- if (funcs->indirect)
- {
- struct value *result = funcs->indirect (original_value);
-
- if (result)
- {
- common_val_print (result, stream, recurse,
- options, current_language);
- return 0;
- }
- }
+ common_val_print (deref_val, stream, recurse, options,
+ current_language);
+ return 0;
}
deref_val = value_at (TYPE_TARGET_TYPE (type),
@@ -627,8 +619,7 @@ info_common_command (char *comname, int from_tty)
while (entry != NULL)
{
- print_variable_and_value (NULL, entry->symbol, fi, gdb_stdout, 0,
- PVAVD_IS_NOT_ARGUMENT);
+ print_variable_and_value (NULL, entry->symbol, fi, gdb_stdout, 0);
entry = entry->next;
}
}
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -711,6 +711,47 @@ extern int frame_register_read (struct frame_info *frame, int regnum,
gdb_byte *buf);
/* From stack.c. */
+
+extern const char print_entry_values_no[];
+extern const char print_entry_values_only[];
+extern const char print_entry_values_preferred[];
+extern const char print_entry_values_if_needed[];
+extern const char print_entry_values_both[];
+extern const char print_entry_values_compact[];
+extern const char print_entry_values_default[];
+extern const char *print_entry_values;
+
+/* Inferior function parameter value read in from a frame. */
+
+struct frame_arg
+{
+ /* Symbol for this parameter used for example for its name. */
+ struct symbol *sym;
+
+ /* Value of the parameter. It is NULL if ERROR is not NULL; if both VAL and
+ ERROR are NULL this parameter's value should not be printed. */
+ struct value *val;
+
+ /* String containing the error message, it is more usually NULL indicating no
+ error occured reading this parameter. */
+ char *error;
+
+ /* One of the print_entry_values_* entries as appropriate specifically for
+ this frame_arg. It will be different from print_entry_values. With
+ print_entry_values_no this frame_arg should be printed as a normal
+ parameter. print_entry_values_only says it should be printed as entry
+ value parameter. print_entry_values_compact says it should be printed as
+ both as a normal parameter and entry values parameter having the same
+ value - print_entry_values_compact is not permitted fi ui_out_is_mi_like_p
+ (in such case print_entry_values_no and print_entry_values_only is used
+ for each parameter kind specifically. */
+ const char *entry_kind;
+};
+
+extern void read_frame_arg (struct symbol *sym, struct frame_info *frame,
+ struct frame_arg *argp,
+ struct frame_arg *entryargp);
+
extern void args_info (char *, int);
extern void locals_info (char *, int);
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -911,7 +911,7 @@ struct func_type
struct call_site *tail_call_list;
};
-/* A place where some function gets called from, represented by
+/* A place where a function gets called from, represented by
DW_TAG_GNU_call_site. It can be looked up from symtab->call_site_htab. */
struct call_site
@@ -937,6 +937,10 @@ struct call_site
/* Size of the PARAMETER array. */
unsigned parameter_count;
+ /* CU of the function where the call is located. It gets used for DWARF
+ blocks execution in the parameter array below. */
+ struct dwarf2_per_cu_data *per_cu;
+
/* Describe DW_TAG_GNU_call_site's DW_TAG_formal_parameter. */
struct call_site_parameter
{
@@ -952,11 +956,13 @@ struct call_site
/* DW_TAG_formal_parameter's DW_AT_GNU_call_site_value. It is never
NULL. */
- struct dwarf2_locexpr_baton *call_site_value;
+ const gdb_byte *value;
+ size_t value_size;
/* DW_TAG_formal_parameter's DW_AT_GNU_call_site_data_value. It may be
NULL if not provided by DWARF. */
- struct dwarf2_locexpr_baton *call_site_data_value;
+ const gdb_byte *data_value;
+ size_t data_value_size;
}
parameter[1];
};
--- a/gdb/jv-lang.h
+++ b/gdb/jv-lang.h
@@ -43,7 +43,8 @@ struct builtin_java_type
extern const struct builtin_java_type *builtin_java_type (struct gdbarch *);
extern int java_val_print (struct type *, const gdb_byte *, int, CORE_ADDR,
- struct ui_file *, int, struct value *,
+ struct ui_file *, int,
+ const struct value *,
const struct value_print_options *);
extern int java_value_print (struct value *, struct ui_file *,
--- a/gdb/jv-valprint.c
+++ b/gdb/jv-valprint.c
@@ -264,7 +264,8 @@ static void
java_print_value_fields (struct type *type, const gdb_byte *valaddr,
int offset,
CORE_ADDR address, struct ui_file *stream,
- int recurse, struct value *val,
+ int recurse,
+ const struct value *val,
const struct value_print_options *options)
{
int i, len, n_baseclasses;
@@ -481,7 +482,8 @@ java_print_value_fields (struct type *type, const gdb_byte *valaddr,
int
java_val_print (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
- struct ui_file *stream, int recurse, struct value *val,
+ struct ui_file *stream, int recurse,
+ const struct value *val,
const struct value_print_options *options)
{
struct gdbarch *gdbarch = get_type_arch (type);
--- a/gdb/language.c
+++ b/gdb/language.c
@@ -1118,7 +1118,7 @@ static int
unk_lang_val_print (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
struct ui_file *stream, int recurse,
- struct value *val,
+ const struct value *val,
const struct value_print_options *options)
{
error (_("internal error - unimplemented "
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -234,7 +234,7 @@ struct language_defn
const gdb_byte *contents,
int embedded_offset, CORE_ADDR address,
struct ui_file *stream, int recurse,
- struct value *val,
+ const struct value *val,
const struct value_print_options *options);
/* Print a top-level value using syntax appropriate for this language. */
--- a/gdb/m2-lang.h
+++ b/gdb/m2-lang.h
@@ -33,7 +33,8 @@ extern int m2_is_long_set (struct type *type);
extern int m2_is_unbounded_array (struct type *type);
extern int m2_val_print (struct type *, const gdb_byte *, int, CORE_ADDR,
- struct ui_file *, int, struct value *,
+ struct ui_file *, int,
+ const struct value *,
const struct value_print_options *);
extern int get_long_set_bounds (struct type *type, LONGEST *low,
--- a/gdb/m2-valprint.c
+++ b/gdb/m2-valprint.c
@@ -38,7 +38,7 @@ static void
m2_print_array_contents (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
struct ui_file *stream, int recurse,
- struct value *val,
+ const struct value *val,
const struct value_print_options *options,
int len);
@@ -279,7 +279,7 @@ static void
m2_print_array_contents (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
struct ui_file *stream, int recurse,
- struct value *val,
+ const struct value *val,
const struct value_print_options *options,
int len)
{
@@ -317,7 +317,7 @@ m2_print_array_contents (struct type *type, const gdb_byte *valaddr,
int
m2_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
CORE_ADDR address, struct ui_file *stream, int recurse,
- struct value *original_value,
+ const struct value *original_value,
const struct value_print_options *options)
{
struct gdbarch *gdbarch = get_type_arch (type);
--- a/gdb/mi/mi-cmd-stack.c
+++ b/gdb/mi/mi-cmd-stack.c
@@ -236,6 +236,78 @@ mi_cmd_stack_list_variables (char *command, char **argv, int argc)
list_args_or_locals (all, parse_print_values (argv[0]), frame);
}
+/* Print single local or argument. ARG must be already read in. For WHAT and
+ VALUES see list_args_or_locals.
+
+ Errors are printed as if they would be the parameter value. Use zeroed ARG
+ iff it should not be printed accoring to VALUES. */
+
+static void
+list_arg_or_local (const struct frame_arg *arg, enum what_to_list what,
+ enum print_values values)
+{
+ struct cleanup *cleanup_tuple = NULL;
+ struct ui_out *uiout = current_uiout;
+ struct ui_stream *stb = ui_out_stream_new (uiout);
+
+ gdb_assert (!arg->val || !arg->error);
+ gdb_assert ((values == PRINT_NO_VALUES && arg->val == NULL
+ && arg->error == NULL)
+ || values == PRINT_SIMPLE_VALUES
+ || (values == PRINT_ALL_VALUES
+ && (arg->val != NULL || arg->error != NULL)));
+ gdb_assert (arg->entry_kind == print_entry_values_no
+ || (arg->entry_kind == print_entry_values_only
+ && (arg->val || arg->error)));
+
+ if (values != PRINT_NO_VALUES || what == all)
+ cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+
+ fputs_filtered (SYMBOL_PRINT_NAME (arg->sym), stb->stream);
+ if (arg->entry_kind == print_entry_values_only)
+ fputs_filtered ("@entry", stb->stream);
+ ui_out_field_stream (uiout, "name", stb);
+
+ if (what == all && SYMBOL_IS_ARGUMENT (arg->sym))
+ ui_out_field_int (uiout, "arg", 1);
+
+ if (values == PRINT_SIMPLE_VALUES)
+ {
+ check_typedef (arg->sym->type);
+ type_print (arg->sym->type, "", stb->stream, -1);
+ ui_out_field_stream (uiout, "type", stb);
+ }
+
+ if (arg->val || arg->error)
+ {
+ volatile struct gdb_exception except;
+
+ if (arg->error)
+ except.message = arg->error;
+ else
+ {
+ /* TRY_CATCH has two statements, wrap it in a block. */
+
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ struct value_print_options opts;
+
+ get_raw_print_options (&opts);
+ opts.deref_ref = 1;
+ common_val_print (arg->val, stb->stream, 0, &opts,
+ language_def (SYMBOL_LANGUAGE (arg->sym)));
+ }
+ }
+ if (except.message)
+ fprintf_filtered (stb->stream, _("<error reading variable: %s>"),
+ except.message);
+ ui_out_field_stream (uiout, "value", stb);
+ }
+
+ ui_out_stream_delete (stb);
+ if (values != PRINT_NO_VALUES || what == all)
+ do_cleanups (cleanup_tuple);
+}
/* Print a list of the locals or the arguments for the currently
selected frame. If the argument passed is 0, printonly the names
@@ -313,16 +385,8 @@ list_args_or_locals (enum what_to_list what, enum print_values values,
}
if (print_me)
{
- struct cleanup *cleanup_tuple = NULL;
struct symbol *sym2;
- struct value *val;
-
- if (values != PRINT_NO_VALUES || what == all)
- cleanup_tuple =
- make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
- ui_out_field_string (uiout, "name", SYMBOL_PRINT_NAME (sym));
- if (what == all && SYMBOL_IS_ARGUMENT (sym))
- ui_out_field_int (uiout, "arg", 1);
+ struct frame_arg arg, entryarg;
if (SYMBOL_IS_ARGUMENT (sym))
sym2 = lookup_symbol (SYMBOL_NATURAL_NAME (sym),
@@ -330,64 +394,34 @@ list_args_or_locals (enum what_to_list what, enum print_values values,
(int *) NULL);
else
sym2 = sym;
+
+ memset (&arg, 0, sizeof (arg));
+ arg.sym = sym2;
+ arg.entry_kind = print_entry_values_no;
+ memset (&entryarg, 0, sizeof (entryarg));
+ entryarg.sym = sym2;
+ entryarg.entry_kind = print_entry_values_no;
+
switch (values)
{
case PRINT_SIMPLE_VALUES:
type = check_typedef (sym2->type);
- type_print (sym2->type, "", stb->stream, -1);
- ui_out_field_stream (uiout, "type", stb);
if (TYPE_CODE (type) != TYPE_CODE_ARRAY
&& TYPE_CODE (type) != TYPE_CODE_STRUCT
&& TYPE_CODE (type) != TYPE_CODE_UNION)
{
- volatile struct gdb_exception except;
-
- TRY_CATCH (except, RETURN_MASK_ERROR)
- {
- struct value_print_options opts;
-
- val = read_var_value (sym2, fi);
- get_raw_print_options (&opts);
- opts.deref_ref = 1;
- common_val_print
- (val, stb->stream, 0, &opts,
- language_def (SYMBOL_LANGUAGE (sym2)));
- }
- if (except.reason < 0)
- fprintf_filtered (stb->stream,
- _("<error reading variable: %s>"),
- except.message);
-
- ui_out_field_stream (uiout, "value", stb);
- }
- break;
case PRINT_ALL_VALUES:
- {
- volatile struct gdb_exception except;
-
- TRY_CATCH (except, RETURN_MASK_ERROR)
- {
- struct value_print_options opts;
-
- val = read_var_value (sym2, fi);
- get_raw_print_options (&opts);
- opts.deref_ref = 1;
- common_val_print
- (val, stb->stream, 0, &opts,
- language_def (SYMBOL_LANGUAGE (sym2)));
- }
- if (except.reason < 0)
- fprintf_filtered (stb->stream,
- _("<error reading variable: %s>"),
- except.message);
-
- ui_out_field_stream (uiout, "value", stb);
- }
+ read_frame_arg (sym2, fi, &arg, &entryarg);
+ }
break;
}
- if (values != PRINT_NO_VALUES || what == all)
- do_cleanups (cleanup_tuple);
+ if (arg.entry_kind != print_entry_values_only)
+ list_arg_or_local (&arg, what, values);
+ if (entryarg.entry_kind != print_entry_values_no)
+ list_arg_or_local (&entryarg, what, values);
+ xfree (arg.error);
+ xfree (entryarg.error);
}
}
if (BLOCK_FUNCTION (block))
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -360,7 +360,8 @@ static const struct lval_funcs opencl_value_funcs =
lval_func_write,
lval_func_check_validity,
lval_func_check_any_valid,
- NULL,
+ NULL, /* indirect */
+ NULL, /* coerce_ref */
lval_func_check_synthetic_pointer,
lval_func_copy_closure,
lval_func_free_closure
--- a/gdb/p-lang.h
+++ b/gdb/p-lang.h
@@ -38,7 +38,7 @@ extern void pascal_print_typedef (struct type *, struct symbol *,
extern int pascal_val_print (struct type *, const gdb_byte *, int,
CORE_ADDR, struct ui_file *, int,
- struct value *,
+ const struct value *,
const struct value_print_options *);
extern int pascal_value_print (struct value *, struct ui_file *,
@@ -72,7 +72,8 @@ extern void
extern void pascal_object_print_value_fields (struct type *, const gdb_byte *,
int,
CORE_ADDR, struct ui_file *,
- int, struct value *,
+ int,
+ const struct value *,
const struct value_print_options *,
struct type **, int);
--- a/gdb/p-valprint.c
+++ b/gdb/p-valprint.c
@@ -49,7 +49,7 @@ int
pascal_val_print (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
struct ui_file *stream, int recurse,
- struct value *original_value,
+ const struct value *original_value,
const struct value_print_options *options)
{
struct gdbarch *gdbarch = get_type_arch (type);
@@ -274,22 +274,12 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr,
{
struct value *deref_val;
- if (VALUE_LVAL (original_value) == lval_computed)
+ deref_val = coerce_ref_if_computed (original_value);
+ if (deref_val)
{
- const struct lval_funcs *funcs;
-
- funcs = value_computed_funcs (original_value);
- if (funcs->indirect)
- {
- struct value *result = funcs->indirect (original_value);
-
- if (result)
- {
- common_val_print (result, stream, recurse,
- options, current_language);
- return 0;
- }
- }
+ common_val_print (deref_val, stream, recurse + 1, options,
+ current_language);
+ return 0;
}
deref_val = value_at (TYPE_TARGET_TYPE (type),
@@ -645,7 +635,7 @@ static void pascal_object_print_static_field (struct value *,
static void pascal_object_print_value (struct type *, const gdb_byte *,
int,
CORE_ADDR, struct ui_file *, int,
- struct value *,
+ const struct value *,
const struct value_print_options *,
struct type **);
@@ -704,7 +694,8 @@ void
pascal_object_print_value_fields (struct type *type, const gdb_byte *valaddr,
int offset,
CORE_ADDR address, struct ui_file *stream,
- int recurse, struct value *val,
+ int recurse,
+ const struct value *val,
const struct value_print_options *options,
struct type **dont_print_vb,
int dont_print_statmem)
@@ -898,7 +889,8 @@ static void
pascal_object_print_value (struct type *type, const gdb_byte *valaddr,
int offset,
CORE_ADDR address, struct ui_file *stream,
- int recurse, struct value *val,
+ int recurse,
+ const struct value *val,
const struct value_print_options *options,
struct type **dont_print_vb)
{
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -1956,114 +1956,33 @@ clear_dangling_display_expressions (struct so_list *solib)
struct symbol. NAME is the name to print; if NULL then VAR's print
name will be used. STREAM is the ui_file on which to print the
value. INDENT specifies the number of indent levels to print
- before printing the variable name. PRINT_ARGUMENT specifies whether @entry
- kind of function parameters should be printed. */
+ before printing the variable name. */
void
print_variable_and_value (const char *name, struct symbol *var,
struct frame_info *frame,
- struct ui_file *stream, int indent,
- enum print_argument print_argument)
+ struct ui_file *stream, int indent)
{
volatile struct gdb_exception except;
if (!name)
name = SYMBOL_PRINT_NAME (var);
+ fprintf_filtered (stream, "%s%s = ", n_spaces (2 * indent), name);
TRY_CATCH (except, RETURN_MASK_ERROR)
{
- struct value *val, *entryval = NULL;
+ struct value *val;
struct value_print_options opts;
val = read_var_value (var, frame);
get_user_print_options (&opts);
opts.deref_ref = 1;
-
- if (print_argument != PVAVD_IS_NOT_ARGUMENT
- && SYMBOL_CLASS (var) == LOC_COMPUTED
- && SYMBOL_COMPUTED_OPS (var)->read_variable_at_entry != NULL)
- {
- const struct symbol_computed_ops *ops;
- unsigned len = TYPE_LENGTH (value_type (val));
- volatile struct gdb_exception entryval_ex;
-
- ops = SYMBOL_COMPUTED_OPS (var);
-
- TRY_CATCH (entryval_ex, RETURN_MASK_ERROR)
- {
- entryval = ops->read_variable_at_entry (var, frame);
- }
-
- if (entryval_ex.reason < 0 || value_optimized_out (entryval))
- entryval = NULL;
- else
- {
- if (!value_optimized_out (val) && value_lazy (val))
- value_fetch_lazy (val);
- if (!value_optimized_out (val) && value_lazy (entryval))
- value_fetch_lazy (entryval);
- if (!value_optimized_out (val)
- && value_available_contents_eq (val, 0, entryval, 0, len))
- {
- volatile struct gdb_exception deref_ex;
- struct value *val_deref, *entryval_deref;
-
- /* DW_AT_GNU_call_site_value does match with the current
- value. If it is a reference still try to verify if
- dereferenced DW_AT_GNU_call_site_data_value does not
- differ. */
-
- TRY_CATCH (deref_ex, RETURN_MASK_ERROR)
- {
- unsigned len_deref;
-
- val_deref = coerce_ref (val);
- if (value_lazy (val_deref))
- value_fetch_lazy (val_deref);
- len_deref = TYPE_LENGTH (value_type (val_deref));
-
- entryval_deref = coerce_ref (entryval);
- if (value_lazy (entryval_deref))
- value_fetch_lazy (entryval_deref);
-
- /* If the reference addresses match but dereferenced
- content does not match print them. */
- if (val != val_deref
- && value_available_contents_eq (val_deref, 0,
- entryval_deref, 0,
- len_deref))
- entryval = NULL;
- }
-
- /* If the dereferenced content could not be fetch do not
- display anything. */
- if (deref_ex.reason < 0)
- entryval = NULL;
-
- /* Value was not a reference; and its content matches. */
- if (val == val_deref)
- entryval = NULL;
- }
- }
- }
-
- if (print_argument != PVAVD_ARGUMENT_PRINT_ENTRYVAL_ONLY)
- {
- fprintf_filtered (stream, "%s%s = ", n_spaces (2 * indent), name);
- common_val_print (val, stream, indent, &opts, current_language);
- fputc_filtered ('\n', stream);
- }
- if (entryval)
- {
- fprintf_filtered (stream, "%s%s@entry = ", n_spaces (2 * indent),
- name);
- common_val_print (entryval, stream, indent, &opts, current_language);
- fputc_filtered ('\n', stream);
- }
+ common_val_print (val, stream, indent, &opts, current_language);
}
if (except.reason < 0)
- fprintf_filtered (stream, "%s%s = <error reading variable %s (%s)>\n",
- n_spaces (2 * indent), name, name, except.message);
+ fprintf_filtered(stream, "<error reading variable %s (%s)>", name,
+ except.message);
+ fprintf_filtered (stream, "\n");
}
/* printf "printf format string" ARG to STREAM. */
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -595,6 +595,7 @@ gdbpy_initialize_frames (void)
PyModule_AddIntConstant (gdb_module, "NORMAL_FRAME", NORMAL_FRAME);
PyModule_AddIntConstant (gdb_module, "DUMMY_FRAME", DUMMY_FRAME);
PyModule_AddIntConstant (gdb_module, "INLINE_FRAME", INLINE_FRAME);
+ PyModule_AddIntConstant (gdb_module, "TAILCALL_FRAME", TAILCALL_FRAME);
PyModule_AddIntConstant (gdb_module, "SIGTRAMP_FRAME", SIGTRAMP_FRAME);
PyModule_AddIntConstant (gdb_module, "ARCH_FRAME", ARCH_FRAME);
PyModule_AddIntConstant (gdb_module, "SENTINEL_FRAME", SENTINEL_FRAME);
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -29,6 +29,7 @@
#include "language.h"
#include "vec.h"
#include "bcache.h"
+#include "dwarf2loc.h"
typedef struct pyty_type_object
{
@@ -822,6 +823,22 @@ check_types_equal (struct type *type1, struct type *type2,
FIELD_STATIC_PHYSNAME (*field2)))
return Py_NE;
break;
+ case FIELD_LOC_KIND_DWARF_BLOCK:
+ {
+ struct dwarf2_locexpr_baton *block1, *block2;
+
+ block1 = FIELD_DWARF_BLOCK (*field1);
+ block2 = FIELD_DWARF_BLOCK (*field2);
+ if (block1->per_cu != block2->per_cu
+ || block1->size != block2->size
+ || memcmp (block1->data, block2->data, block1->size) != 0)
+ return Py_NE;
+ }
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, _("Unsupported field kind "
+ "%d by check_types_equal"),
+ FIELD_LOC_KIND (*field1));
}
entry.type1 = FIELD_TYPE (*field1);
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -64,6 +64,29 @@ static const char *print_frame_arguments_choices[] =
{"all", "scalars", "none", NULL};
static const char *print_frame_arguments = "scalars";
+/* The possible choices of "set print entry-values", and the value
+ of this setting. */
+
+const char print_entry_values_no[] = "no";
+const char print_entry_values_only[] = "only";
+const char print_entry_values_preferred[] = "preferred";
+const char print_entry_values_if_needed[] = "if-needed";
+const char print_entry_values_both[] = "both";
+const char print_entry_values_compact[] = "compact";
+const char print_entry_values_default[] = "default";
+static const char *print_entry_values_choices[] =
+{
+ print_entry_values_no,
+ print_entry_values_only,
+ print_entry_values_preferred,
+ print_entry_values_if_needed,
+ print_entry_values_both,
+ print_entry_values_compact,
+ print_entry_values_default,
+ NULL
+};
+const char *print_entry_values = print_entry_values_default;
+
/* Prototypes for local functions. */
static void print_frame_local_vars (struct frame_info *, int,
@@ -162,6 +185,285 @@ print_frame_nameless_args (struct frame_info *frame, long start, int num,
}
}
+/* Print single argument of inferior function. ARG must be already
+ read in.
+
+ Errors are printed as if they would be the parameter value. Use zeroed ARG
+ iff it should not be printed accoring to user settings. */
+
+static void
+print_frame_arg (const struct frame_arg *arg)
+{
+ struct ui_out *uiout = current_uiout;
+ volatile struct gdb_exception except;
+ struct cleanup *old_chain;
+ struct ui_stream *stb;
+
+ stb = ui_out_stream_new (uiout);
+ old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+ gdb_assert (!arg->val || !arg->error);
+ gdb_assert (arg->entry_kind == print_entry_values_no
+ || arg->entry_kind == print_entry_values_only
+ || (!ui_out_is_mi_like_p (uiout)
+ && arg->entry_kind == print_entry_values_compact));
+
+ annotate_arg_begin ();
+
+ make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+ fprintf_symbol_filtered (stb->stream, SYMBOL_PRINT_NAME (arg->sym),
+ SYMBOL_LANGUAGE (arg->sym), DMGL_PARAMS | DMGL_ANSI);
+ if (arg->entry_kind == print_entry_values_compact)
+ {
+ /* It is OK to provide invalid MI-like stream as with
+ PRINT_ENTRY_VALUE_COMPACT we never use MI. */
+ fputs_filtered ("=", stb->stream);
+
+ fprintf_symbol_filtered (stb->stream, SYMBOL_PRINT_NAME (arg->sym),
+ SYMBOL_LANGUAGE (arg->sym),
+ DMGL_PARAMS | DMGL_ANSI);
+ }
+ if (arg->entry_kind == print_entry_values_only
+ || arg->entry_kind == print_entry_values_compact)
+ fputs_filtered ("@entry", stb->stream);
+ ui_out_field_stream (uiout, "name", stb);
+ annotate_arg_name_end ();
+ ui_out_text (uiout, "=");
+
+ if (!arg->val && !arg->error)
+ ui_out_text (uiout, "...");
+ else
+ {
+ if (arg->error)
+ except.message = arg->error;
+ else
+ {
+ /* TRY_CATCH has two statements, wrap it in a block. */
+
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ const struct language_defn *language;
+ struct value_print_options opts;
+
+ /* Avoid value_print because it will deref ref parameters. We
+ just want to print their addresses. Print ??? for args whose
+ address we do not know. We pass 2 as "recurse" to val_print
+ because our standard indentation here is 4 spaces, and
+ val_print indents 2 for each recurse. */
+
+ annotate_arg_value (value_type (arg->val));
+
+ /* Use the appropriate language to display our symbol, unless the
+ user forced the language to a specific language. */
+ if (language_mode == language_mode_auto)
+ language = language_def (SYMBOL_LANGUAGE (arg->sym));
+ else
+ language = current_language;
+
+ get_raw_print_options (&opts);
+ opts.deref_ref = 1;
+
+ /* True in "summary" mode, false otherwise. */
+ opts.summary = !strcmp (print_frame_arguments, "scalars");
+
+ common_val_print (arg->val, stb->stream, 2, &opts, language);
+ }
+ }
+ if (except.message)
+ fprintf_filtered (stb->stream, _("<error reading variable: %s>"),
+ except.message);
+ }
+
+ ui_out_field_stream (uiout, "value", stb);
+
+ /* Aleo invoke ui_out_tuple_end. */
+ do_cleanups (old_chain);
+
+ annotate_arg_end ();
+}
+
+/* Read in inferior function parameter SYM at FRAME into ARGP. Caller is
+ responsible for xfree of ARGP->ERROR. This function never throws an
+ exception. */
+
+void
+read_frame_arg (struct symbol *sym, struct frame_info *frame,
+ struct frame_arg *argp, struct frame_arg *entryargp)
+{
+ struct value *val = NULL, *entryval = NULL;
+ char *val_error = NULL, *entryval_error = NULL;
+ int val_equal = 0;
+ volatile struct gdb_exception except;
+
+ if (print_entry_values != print_entry_values_only
+ && print_entry_values != print_entry_values_preferred)
+ {
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ val = read_var_value (sym, frame);
+ }
+ if (!val)
+ {
+ val_error = alloca (strlen (except.message) + 1);
+ strcpy (val_error, except.message);
+ }
+ }
+
+ if (SYMBOL_CLASS (sym) == LOC_COMPUTED
+ && print_entry_values != print_entry_values_no
+ && (print_entry_values != print_entry_values_if_needed
+ || !val || value_optimized_out (val)))
+ {
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ const struct symbol_computed_ops *ops;
+
+ ops = SYMBOL_COMPUTED_OPS (sym);
+ entryval = ops->read_variable_at_entry (sym, frame);
+ }
+ if (!entryval)
+ {
+ entryval_error = alloca (strlen (except.message) + 1);
+ strcpy (entryval_error, except.message);
+ }
+
+ if (except.error == NO_ENTRY_VALUE_ERROR
+ || (entryval && value_optimized_out (entryval)))
+ {
+ entryval = NULL;
+ entryval_error = NULL;
+ }
+
+ if (print_entry_values == print_entry_values_compact
+ || print_entry_values == print_entry_values_default)
+ {
+ /* For MI do not try to use print_entry_values_compact for ARGP. */
+
+ if (val && entryval && !ui_out_is_mi_like_p (current_uiout))
+ {
+ unsigned len = TYPE_LENGTH (value_type (val));
+
+ if (!value_optimized_out (val) && value_lazy (val))
+ value_fetch_lazy (val);
+ if (!value_optimized_out (val) && value_lazy (entryval))
+ value_fetch_lazy (entryval);
+ if (!value_optimized_out (val)
+ && value_available_contents_eq (val, 0, entryval, 0, len))
+ {
+ struct value *val_deref, *entryval_deref;
+
+ /* DW_AT_GNU_call_site_value does match with the current
+ value. If it is a reference still try to verify if
+ dereferenced DW_AT_GNU_call_site_data_value does not
+ differ. */
+
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ unsigned len_deref;
+
+ val_deref = coerce_ref (val);
+ if (value_lazy (val_deref))
+ value_fetch_lazy (val_deref);
+ len_deref = TYPE_LENGTH (value_type (val_deref));
+
+ entryval_deref = coerce_ref (entryval);
+ if (value_lazy (entryval_deref))
+ value_fetch_lazy (entryval_deref);
+
+ /* If the reference addresses match but dereferenced
+ content does not match print them. */
+ if (val != val_deref
+ && value_available_contents_eq (val_deref, 0,
+ entryval_deref, 0,
+ len_deref))
+ val_equal = 1;
+ }
+
+ /* Value was not a reference; and its content matches. */
+ if (val == val_deref)
+ val_equal = 1;
+ /* If the dereferenced content could not be fetched do not
+ display anything. */
+ else if (except.error == NO_ENTRY_VALUE_ERROR)
+ val_equal = 1;
+ else if (except.message)
+ {
+ entryval_error = alloca (strlen (except.message) + 1);
+ strcpy (entryval_error, except.message);
+ }
+
+ if (val_equal)
+ entryval = NULL;
+ }
+ }
+
+ /* Try to remove possibly duplicate error message for ENTRYARGP even
+ in MI mode. */
+
+ if (val_error && entryval_error
+ && strcmp (val_error, entryval_error) == 0)
+ {
+ entryval_error = NULL;
+
+ /* Do not se VAL_EQUAL as the same error message may be shown for
+ the entry value even if no entry values are present in the
+ inferior. */
+ }
+ }
+ }
+
+ if (entryval == NULL)
+ {
+ if (print_entry_values == print_entry_values_preferred)
+ {
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ val = read_var_value (sym, frame);
+ }
+ if (!val)
+ {
+ val_error = alloca (strlen (except.message) + 1);
+ strcpy (val_error, except.message);
+ }
+ }
+ if (print_entry_values == print_entry_values_only
+ || print_entry_values == print_entry_values_both
+ || (print_entry_values == print_entry_values_preferred
+ && (!val || value_optimized_out (val))))
+ entryval = allocate_optimized_out_value (SYMBOL_TYPE (sym));
+ }
+ if ((print_entry_values == print_entry_values_compact
+ || print_entry_values == print_entry_values_if_needed
+ || print_entry_values == print_entry_values_preferred)
+ && (!val || value_optimized_out (val)) && entryval != NULL)
+ {
+ val = NULL;
+ val_error = NULL;
+ }
+
+ argp->sym = sym;
+ argp->val = val;
+ argp->error = val_error ? xstrdup (val_error) : NULL;
+ if (!val && !val_error)
+ argp->entry_kind = print_entry_values_only;
+ else if ((print_entry_values == print_entry_values_compact
+ || print_entry_values == print_entry_values_default) && val_equal)
+ {
+ argp->entry_kind = print_entry_values_compact;
+ gdb_assert (!ui_out_is_mi_like_p (current_uiout));
+ }
+ else
+ argp->entry_kind = print_entry_values_no;
+
+ entryargp->sym = sym;
+ entryargp->val = entryval;
+ entryargp->error = entryval_error ? xstrdup (entryval_error) : NULL;
+ if (!entryval && !entryval_error)
+ entryargp->entry_kind = print_entry_values_no;
+ else
+ entryargp->entry_kind = print_entry_values_only;
+}
+
/* Print the arguments of frame FRAME on STREAM, given the function
FUNC running in that frame (as a symbol), where NUM is the number
of arguments according to the stack frame (or -1 if the number of
@@ -198,10 +500,11 @@ print_frame_args (struct symbol *func, struct frame_info *frame,
struct block *b = SYMBOL_BLOCK_VALUE (func);
struct dict_iterator iter;
struct symbol *sym;
- struct value *val;
ALL_BLOCK_SYMBOLS (b, iter, sym)
{
+ struct frame_arg arg, entryarg;
+
QUIT;
/* Keep track of the highest stack argument offset seen, and
@@ -314,65 +617,34 @@ print_frame_args (struct symbol *func, struct frame_info *frame,
ui_out_text (uiout, ", ");
ui_out_wrap_hint (uiout, " ");
- annotate_arg_begin ();
-
- list_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
- fprintf_symbol_filtered (stb->stream, SYMBOL_PRINT_NAME (sym),
- SYMBOL_LANGUAGE (sym),
- DMGL_PARAMS | DMGL_ANSI);
- ui_out_field_stream (uiout, "name", stb);
- annotate_arg_name_end ();
- ui_out_text (uiout, "=");
+ if (!print_args)
+ {
+ memset (&arg, 0, sizeof (arg));
+ arg.sym = sym;
+ arg.entry_kind = print_entry_values_no;
+ memset (&entryarg, 0, sizeof (entryarg));
+ entryarg.sym = sym;
+ entryarg.entry_kind = print_entry_values_no;
+ }
+ else
+ read_frame_arg (sym, frame, &arg, &entryarg);
- if (print_args)
- {
- volatile struct gdb_exception except;
+ if (arg.entry_kind != print_entry_values_only)
+ print_frame_arg (&arg);
- TRY_CATCH (except, RETURN_MASK_ERROR)
- {
- const struct language_defn *language;
- struct value_print_options opts;
-
- /* Avoid value_print because it will deref ref parameters.
- We just want to print their addresses. Print ??? for
- args whose address we do not know. We pass 2 as
- "recurse" to val_print because our standard indentation
- here is 4 spaces, and val_print indents 2 for each
- recurse. */
- val = read_var_value (sym, frame);
-
- annotate_arg_value (value_type (val));
-
- /* Use the appropriate language to display our symbol,
- unless the user forced the language to a specific
- language. */
- if (language_mode == language_mode_auto)
- language = language_def (SYMBOL_LANGUAGE (sym));
- else
- language = current_language;
-
- get_raw_print_options (&opts);
- opts.deref_ref = 1;
- opts.summary = summary;
- common_val_print (val, stb->stream, 2, &opts, language);
- ui_out_field_stream (uiout, "value", stb);
- }
- if (except.reason < 0)
+ if (entryarg.entry_kind != print_entry_values_no)
+ {
+ if (arg.entry_kind != print_entry_values_only)
{
- fprintf_filtered (stb->stream,
- _("<error reading variable: %s>"),
- except.message);
- ui_out_field_stream (uiout, "value", stb);
+ ui_out_text (uiout, ", ");
+ ui_out_wrap_hint (uiout, " ");
}
- }
- else
- ui_out_text (uiout, "...");
-
- /* Invoke ui_out_tuple_end. */
- do_cleanups (list_chain);
+ print_frame_arg (&entryarg);
+ }
- annotate_arg_end ();
+ xfree (arg.error);
+ xfree (entryarg.error);
first = 0;
}
@@ -1087,8 +1359,7 @@ frame_info (char *addr_exp, int from_tty)
frame_stop_reason_string (reason));
}
else if (get_frame_type (fi) == TAILCALL_FRAME)
- printf_filtered (" tail call frame %d",
- frame_relative_level (get_prev_frame (fi)));
+ puts_filtered (" tail call frame");
else if (get_frame_type (fi) == INLINE_FRAME)
printf_filtered (" inlined into frame %d",
frame_relative_level (get_prev_frame (fi)));
@@ -1532,7 +1803,6 @@ struct print_variable_and_value_data
int num_tabs;
struct ui_file *stream;
int values_printed;
- enum print_argument print_argument;
};
/* The callback for the locals and args iterators. */
@@ -1544,17 +1814,13 @@ do_print_variable_and_value (const char *print_name,
{
struct print_variable_and_value_data *p = cb_data;
- print_variable_and_value (print_name, sym, p->frame, p->stream, p->num_tabs,
- p->print_argument);
+ print_variable_and_value (print_name, sym,
+ p->frame, p->stream, p->num_tabs);
p->values_printed = 1;
}
-/* Show function local variables at FRAME. FROM_FRAME is 1 if the local
- variables are printed after the function frame (parameter values) have been
- printed, it is 0 otherwise. Print them to STREAM. */
-
static void
-print_frame_local_vars (struct frame_info *frame, int from_frame,
+print_frame_local_vars (struct frame_info *frame, int num_tabs,
struct ui_file *stream)
{
struct print_variable_and_value_data cb_data;
@@ -1576,24 +1842,10 @@ print_frame_local_vars (struct frame_info *frame, int from_frame,
}
cb_data.frame = frame;
- cb_data.num_tabs = from_frame ? 4 : 0;
+ cb_data.num_tabs = 4 * num_tabs;
cb_data.stream = stream;
cb_data.values_printed = 0;
- if (from_frame)
- {
- /* For the variables we display them from the innermost block. But for
- parameters we need to fetch the outermost block still in the same
- function. Stop at the first inlined function boundary, if any. */
- struct symbol *func = get_frame_function (frame);
-
- cb_data.print_argument = PVAVD_ARGUMENT_PRINT_ENTRYVAL_ONLY;
- if (func)
- iterate_over_block_arg_vars (SYMBOL_BLOCK_VALUE (func),
- do_print_variable_and_value, &cb_data);
- }
-
- cb_data.print_argument = PVAVD_IS_NOT_ARGUMENT;
iterate_over_block_local_vars (block,
do_print_variable_and_value,
&cb_data);
@@ -1753,7 +2005,6 @@ print_frame_arg_vars (struct frame_info *frame, struct ui_file *stream)
cb_data.stream = gdb_stdout;
cb_data.values_printed = 0;
- cb_data.print_argument = PVAVD_ARGUMENT_PRINT_BOTH;
iterate_over_block_arg_vars (SYMBOL_BLOCK_VALUE (func),
do_print_variable_and_value, &cb_data);
@@ -2274,4 +2525,17 @@ source line."),
show_disassemble_next_line,
&setlist, &showlist);
disassemble_next_line = AUTO_BOOLEAN_FALSE;
+
+ add_setshow_enum_cmd ("entry-values", class_stack,
+ print_entry_values_choices, &print_entry_values,
+ _("Set printing of frame arguments values at function "
+ "entry"),
+ _("Show printing of frame arguments values at function "
+ "entry"),
+ _("\
+GDB can print in some cases besides frame arguments values also the values\n\
+they had at function entry (marked as `NAME@entry'). The value itself and/or\n\
+the entry value may be <optimized out>. Which of this current or entry\n\
+values get printed in which case can be set by this option."),
+ NULL, NULL, &setprintlist, &showprintlist);
}
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -534,8 +534,8 @@ struct symbol_computed_ops
struct frame_info * frame);
/* Read variable SYMBOL like read_variable at (callee) FRAME's function
- entry. SYMBOL should be a function parameter, otherwise NOT_FOUND_ERROR
- will be thrown. */
+ entry. SYMBOL should be a function parameter, otherwise
+ NO_ENTRY_VALUE_ERROR will be thrown. */
struct value *(*read_variable_at_entry) (struct symbol *symbol,
struct frame_info *frame);
--- a/gdb/testsuite/gdb.arch/amd64-entry-value.cc
+++ b/gdb/testsuite/gdb.arch/amd64-entry-value.cc
@@ -18,43 +18,51 @@
static volatile int v;
static void __attribute__((noinline, noclone))
-e (int i)
+e (int i, double j)
{
v = 0;
}
static void __attribute__((noinline, noclone))
-d (int i)
+d (int i, double j)
{
i++;
- e (i);
- e (v);
+ j++;
+ e (i, j);
+ e (v, v);
asm ("breakhere:");
- e (v);
+ e (v, v);
}
static void __attribute__((noinline, noclone))
-c (int i)
+locexpr (int i)
{
- d (i * 10);
+ i = i;
+asm ("breakhere_locexpr:");
}
static void __attribute__((noinline, noclone))
-a (int i)
+c (int i, double j)
{
- c (i + 1);
+ d (i * 10, j * 10);
}
static void __attribute__((noinline, noclone))
-b (int i)
+a (int i, double j)
{
- c (i + 2);
+ c (i + 1, j + 1);
+}
+
+static void __attribute__((noinline, noclone))
+b (int i, double j)
+{
+ c (i + 2, j + 2);
}
static void __attribute__((noinline, noclone))
amb_z (int i)
{
- d (i + 7);
+ d (i + 7, i + 7.5);
}
static void __attribute__((noinline, noclone))
@@ -108,46 +116,117 @@ self (int i)
}
else
{
- e (v);
- d (i + 2);
+ e (v, v);
+ d (i + 2, i + 2.5);
}
}
static void __attribute__((noinline, noclone))
-stacktest (int r1, int r2, int r3, int r4, int r5, int r6, int s1, int s2)
+stacktest (int r1, int r2, int r3, int r4, int r5, int r6, int s1, int s2,
+ double d1, double d2, double d3, double d4, double d5, double d6,
+ double d7, double d8, double d9, double da)
{
s1 = 3;
s2 = 4;
- e (v);
+ d9 = 3.5;
+ da = 4.5;
+ e (v, v);
asm ("breakhere_stacktest:");
- e (v);
+ e (v, v);
}
+/* nodataparam has DW_AT_GNU_call_site_value but it does not have
+ DW_AT_GNU_call_site_data_value. GDB should not display dereferenced @entry
+ value for it. */
+
static void __attribute__((noinline, noclone))
-reference (int &refparam)
+reference (int ®param, int &nodataparam, int r3, int r4, int r5, int r6,
+ int &stackparam1, int &stackparam2)
{
- int refcopy = refparam;
+ int regcopy = regparam, nodatacopy = nodataparam;
+ int stackcopy1 = stackparam1, stackcopy2 = stackparam2;
- refparam = 10;
+ regparam = 21;
+ nodataparam = 22;
+ stackparam1 = 31;
+ stackparam2 = 32;
+ e (v, v);
asm ("breakhere_reference:");
- e (v);
+ e (v, v);
+}
+
+static int *__attribute__((noinline, noclone))
+datap ()
+{
+ static int two = 2;
+
+ return &two;
+}
+
+static void __attribute__((noinline, noclone))
+datap_input (int *datap)
+{
+ (*datap)++;
+}
+
+static int __attribute__((noinline, noclone))
+data (void)
+{
+ return 10;
+}
+
+static int __attribute__((noinline, noclone))
+data2 (void)
+{
+ return 20;
+}
+
+static int __attribute__((noinline, noclone))
+different (int val)
+{
+ val++;
+ e (val, val);
+asm ("breakhere_different:");
+ return val;
+}
+
+static int __attribute__((noinline, noclone))
+validity (int lost, int born)
+{
+ lost = data ();
+ e (0, 0.0);
+asm ("breakhere_validity:");
+ return born;
+}
+
+static void __attribute__((noinline, noclone))
+invalid (int inv)
+{
+ e (0, 0.0);
+asm ("breakhere_invalid:");
}
int
main ()
{
- int refvar;
-
- d (30);
- stacktest (1, 2, 3, 4, 5, 6, 11, 12);
+ d (30, 30.5);
+ locexpr (30);
+ stacktest (1, 2, 3, 4, 5, 6, 11, 12,
+ 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 11.5, 12.5);
+ different (5);
+ validity (5, data ());
+ invalid (data2 ());
- refvar = 5;
- reference (refvar);
+ {
+ int regvar = 1, *nodatavarp = datap (), stackvar1 = 11, stackvar2 = 12;
+ reference (regvar, *nodatavarp, 3, 4, 5, 6, stackvar1, stackvar2);
+ datap_input (nodatavarp);
+ }
if (v)
- a (1);
+ a (1, 1.25);
else
- b (5);
+ b (5, 5.25);
amb_a (100);
self (200);
return 0;
--- a/gdb/testsuite/gdb.arch/amd64-entry-value.exp
+++ b/gdb/testsuite/gdb.arch/amd64-entry-value.exp
@@ -35,8 +35,13 @@ if ![runto_main] {
}
gdb_breakpoint "breakhere"
+gdb_breakpoint "breakhere_locexpr"
gdb_breakpoint "stacktest"
gdb_breakpoint "breakhere_stacktest"
+gdb_breakpoint "different"
+gdb_breakpoint "breakhere_different"
+gdb_breakpoint "breakhere_validity"
+gdb_breakpoint "breakhere_invalid"
gdb_breakpoint "reference"
gdb_breakpoint "breakhere_reference"
@@ -45,112 +50,175 @@ gdb_breakpoint "breakhere_reference"
gdb_continue_to_breakpoint "entry: breakhere"
-# (gdb) bt full
-# #0 d (i=31) at gdb.arch/amd64-entry-value.cc:33
-# i@entry = 30
-# #1 0x00000000004003da in main () at gdb.arch/amd64-entry-value.cc:56
-gdb_test "bt full" "^bt full\r\n#0 +d *\\(i=31\\) \[^\r\n\]*\r\n\[ \t\]*i@entry = 30\r\n#1 +0x\[0-9a-f\]+ in main .*" \
- "entry: bt full"
+gdb_test "bt" "^bt\r\n#0 +d *\\(i=31, i@entry=30, j=31\\.5, j@entry=30\\.5\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in main .*" \
+ "entry: bt"
gdb_test "p i" " = 31" "entry: p i"
gdb_test "p i@entry" " = 30" "entry: p i@entry"
+gdb_test "p j" { = 31\.5} "entry: p j"
+gdb_test "p j@entry" { = 30\.5} "entry: p j@entry"
+
+
+# Test @entry values when parameter in function is locexpr (and not loclist).
+
+gdb_continue_to_breakpoint "entry_locexpr: breakhere_locexpr"
+gdb_test "p i" " = 30" "entry_locexpr: p i"
+gdb_test_no_output "set variable i = 0" "entry_locexpr: set variable i = 0"
+gdb_test "bt" "^bt\r\n#0 +locexpr *\\(i=0, i@entry=30\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in main .*" \
+ "entry_locexpr: bt"
# Test @entry values for stack passed parameters.
gdb_continue_to_breakpoint "entry_stack: stacktest"
-# (gdb) bt full
-# #0 stacktest (r1=1, r2=2, r3=3, r4=4, r5=5, r6=6, s1=11, s2=12) at gdb.arch/amd64-entry-value.cc:121
-# #1 0x0000000000400412 in main () at gdb.arch/amd64-entry-value.cc:142
-# Check s1 and s2 are suppressed:
-gdb_test "bt full" "^bt full\r\n#0 +stacktest *\\(r1=1, r2=2, r3=3, r4=4, r5=5, r6=6, s1=11, s2=12\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in main .*" \
- "entry_stack: bt full at entry"
+gdb_test "bt" "^bt\r\n#0 +stacktest *\\(r1=r1@entry=1, r2=r2@entry=2, \[^\r\n\]+, s1=s1@entry=11, s2=s2@entry=12, \[^\r\n\]+, d9=d9@entry=11\\.5, da=da@entry=12\\.5\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in main .*" \
+ "entry_stack: bt at entry"
gdb_continue_to_breakpoint "entry_stack: breakhere_stacktest"
-# (gdb) bt full
-# #0 stacktest (r1=1, r2=2, r3=3, r4=4, r5=5, r6=6, s1=3, s2=4) at gdb.arch/amd64-entry-value.cc:123
-# s1@entry = 11
-# s2@entry = 12
-# #1 0x0000000000400412 in main () at gdb.arch/amd64-entry-value.cc:130
-# Check s1 and s2 are present:
-gdb_test "bt full" "^bt full\r\n#0 +stacktest *\\(r1=1, r2=2, r3=3, r4=4, r5=5, r6=6, s1=3, s2=4\\) \[^\r\n\]*\r\n\[ \t\]*s1@entry = 11\r\n\[ \t\]*s2@entry = 12\r\n#1 +0x\[0-9a-f\]+ in main .*" \
- "entry_stack: bt full"
+gdb_test "bt" "^bt\r\n#0 +stacktest *\\(r1=r1@entry=1, r2=r2@entry=2, \[^\r\n\]+, s1=3, s1@entry=11, s2=4, s2@entry=12, \[^\r\n\]+, d9=3\\.5, d9@entry=11\\.5, da=4\\.5, da@entry=12\\.5\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in main .*" \
+ "entry_stack: bt"
gdb_test "p s1" " = 3" "entry_stack: p s1"
gdb_test "p s1@entry" " = 11" "entry_stack: p s1@entry"
gdb_test "p s2" " = 4" "entry_stack: p s2"
gdb_test "p s2@entry" " = 12" "entry_stack: p s2@entry"
+gdb_test "p d9" " = 3\\.5" "entry_stack: p d9"
+gdb_test "p d9@entry" " = 11\\.5" "entry_stack: p d9@entry"
+gdb_test "p da" " = 4\\.5" "entry_stack: p da"
+gdb_test "p da@entry" " = 12\\.5" "entry_stack: p da@entry"
+
+
+# Test various kinds of `set print entry-values'.
+
+gdb_continue_to_breakpoint "entry_equal: breakhere"
+
+gdb_test_no_output "set print entry-values no" "entry_equal: set print entry-values no"
+gdb_test "frame" {\(val=5\).*} "entry_equal: frame: no"
+gdb_test_no_output "set print entry-values only" "entry_equal: set print entry-values only"
+gdb_test "frame" {\(val@entry=5\).*} "entry_equal: frame: only"
+gdb_test_no_output "set print entry-values preferred" "entry_equal: set print entry-values preferred"
+gdb_test "frame" {\(val@entry=5\).*} "entry_equal: frame: preferred"
+gdb_test_no_output "set print entry-values if-needed" "entry_equal: set print entry-values if-needed"
+gdb_test "frame" {\(val=5\).*} "entry_equal: frame: if-needed"
+gdb_test_no_output "set print entry-values both" "entry_equal: set print entry-values both"
+gdb_test "frame" {\(val=5, val@entry=5\).*} "entry_equal: frame: both"
+gdb_test_no_output "set print entry-values compact" "entry_equal: set print entry-values compact"
+gdb_test "frame" {\(val=val@entry=5\).*} "entry_equal: frame: compact"
+gdb_test_no_output "set print entry-values default" "entry_equal: set print entry-values default"
+gdb_test "frame" {\(val=val@entry=5\).*} "entry_equal: frame: default"
+
+gdb_continue_to_breakpoint "entry_different: breakhere"
+
+gdb_test_no_output "set print entry-values no" "entry_different: set print entry-values no"
+gdb_test "frame" {\(val=6\).*} "entry_different: frame: no"
+gdb_test_no_output "set print entry-values only" "entry_different: set print entry-values only"
+gdb_test "frame" {\(val@entry=5\).*} "entry_different: frame: only"
+gdb_test_no_output "set print entry-values preferred" "entry_different: set print entry-values preferred"
+gdb_test "frame" {\(val@entry=5\).*} "entry_different: frame: preferred"
+gdb_test_no_output "set print entry-values if-needed" "entry_different: set print entry-values if-needed"
+gdb_test "frame" {\(val=6\).*} "entry_different: frame: if-needed"
+gdb_test_no_output "set print entry-values both" "entry_different: set print entry-values both"
+gdb_test "frame" {\(val=6, val@entry=5\).*} "entry_different: frame: both"
+gdb_test_no_output "set print entry-values compact" "entry_different: set print entry-values compact"
+gdb_test "frame" {\(val=6, val@entry=5\).*} "entry_different: frame: compact"
+gdb_test_no_output "set print entry-values default" "entry_different: set print entry-values default"
+gdb_test "frame" {\(val=6, val@entry=5\).*} "entry_different: frame: default"
+
+gdb_continue_to_breakpoint "entry_validity: breakhere"
+
+gdb_test_no_output "set print entry-values no" "entry_validity: set print entry-values no"
+gdb_test "frame" {\(lost=<optimized out>, born=10\).*} "entry_validity: frame: no"
+gdb_test_no_output "set print entry-values only" "entry_validity: set print entry-values only"
+gdb_test "frame" {\(lost@entry=5, born@entry=<optimized out>\).*} "entry_validity: frame: only"
+gdb_test_no_output "set print entry-values preferred" "entry_validity: set print entry-values preferred"
+gdb_test "frame" {\(lost@entry=5, born=10\).*} "entry_validity: frame: preferred"
+gdb_test_no_output "set print entry-values if-needed" "entry_validity: set print entry-values if-needed"
+gdb_test "frame" {\(lost@entry=5, born=10\).*} "entry_validity: frame: if-needed"
+gdb_test_no_output "set print entry-values both" "entry_validity: set print entry-values both"
+gdb_test "frame" {\(lost=<optimized out>, lost@entry=5, born=10, born@entry=<optimized out>\).*} "entry_validity: frame: both"
+gdb_test_no_output "set print entry-values compact" "entry_validity: set print entry-values compact"
+gdb_test "frame" {\(lost@entry=5, born=10\).*} "entry_validity: frame: compact"
+gdb_test_no_output "set print entry-values default" "entry_validity: set print entry-values default"
+gdb_test "frame" {\(lost=<optimized out>, lost@entry=5, born=10\).*} "entry_validity: frame: default"
+
+gdb_continue_to_breakpoint "entry_invalid: breakhere"
+
+gdb_test_no_output "set print entry-values no" "entry_invalid: set print entry-values no"
+gdb_test "frame" {\(inv=<optimized out>\).*} "entry_invalid: frame: no"
+gdb_test_no_output "set print entry-values only" "entry_invalid: set print entry-values only"
+gdb_test "frame" {\(inv@entry=<optimized out>\).*} "entry_invalid: frame: only"
+gdb_test_no_output "set print entry-values preferred" "entry_invalid: set print entry-values preferred"
+gdb_test "frame" {\(inv@entry=<optimized out>\).*} "entry_invalid: frame: preferred"
+gdb_test_no_output "set print entry-values if-needed" "entry_invalid: set print entry-values if-needed"
+gdb_test "frame" {\(inv=<optimized out>\).*} "entry_invalid: frame: if-needed"
+gdb_test_no_output "set print entry-values both" "entry_invalid: set print entry-values both"
+gdb_test "frame" {\(inv=<optimized out>, inv@entry=<optimized out>\).*} "entry_invalid: frame: both"
+gdb_test_no_output "set print entry-values compact" "entry_invalid: set print entry-values compact"
+gdb_test "frame" {\(inv=<optimized out>\).*} "entry_invalid: frame: compact"
+gdb_test_no_output "set print entry-values default" "entry_invalid: set print entry-values default"
+gdb_test "frame" {\(inv=<optimized out>\).*} "entry_invalid: frame: default"
# Test @entry values for DW_AT_GNU_call_site_data_value parameters.
gdb_continue_to_breakpoint "entry_reference: reference"
-# (gdb) bt full
-# #0 reference (refparam=@0x7fffffffdc3c: 5) at gdb.arch/amd64-entry-value.cc:131
-# refcopy = 5
-# #1 0x0000000000400424 in main () at gdb.arch/amd64-entry-value.cc:145
-# refvar = 5
-# Check refparam@entry is suppressed:
-gdb_test "bt full" "#0 +reference \\(refparam=@0x\[0-9a-f\]+: 5\\) \[^\r\n\]*\r\n\[ \t\]*refcopy = 5\r\n#1 +0x\[0-9a-f\]+ in main \\(\\) \[^\r\n\]*\r\n\[ \t\]*refvar = 5" \
- "entry_reference: bt full at entry"
+# GCC PR debug/49980: Missing stackparam1@entry and stackparam2@entry.
+gdb_test "bt" "#0 +reference \\(regparam=regparam@entry=@0x\[0-9a-f\]+: 1, nodataparam=@0x\[0-9a-f\]+: 2, \[^\r\n\]+, stackparam1=@0x\[0-9a-f\]+: 11, stackparam2=@0x\[0-9a-f\]+: 12\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in main \\(\\) \[^\r\n\]*" \
+ "entry_reference: bt at entry"
gdb_continue_to_breakpoint "entry_reference: breakhere_reference"
-# (gdb) bt full
-# #0 reference (refparam=@0x7fffffffdc3c: 10) at gdb.arch/amd64-entry-value.cc:133
-# refparam@entry = @0x7fffffffdc3c: 5
-# refcopy = 5
-# #1 0x0000000000400424 in main () at gdb.arch/amd64-entry-value.cc:145
-# refvar = 10
-# Check refparam@entry is present:
-gdb_test "bt full" "#0 +reference \\(refparam=@0x\[0-9a-f\]+: 10\\) \[^\r\n\]*\r\n\[ \t\]*refparam@entry = @0x\[0-9a-f\]+: 5\r\n\[ \t\]*refcopy = 5\r\n#1 +0x\[0-9a-f\]+ in main \\(\\) \[^\r\n\]*\r\n\[ \t\]*refvar = 10" \
- "entry_reference: bt full"
-gdb_test "ptype refparam" " = int &" "entry_reference: ptype refparam"
-
-set test "entry_reference: p refparam"
+# GCC PR debug/49980: Missing stackparam1@entry and stackparam2@entry.
+gdb_test "bt" "#0 +reference \\(regparam=@0x\[0-9a-f\]+: 21, regparam@entry=@0x\[0-9a-f\]+: 1, nodataparam=@0x\[0-9a-f\]+: 22, \[^\r\n\]+, stackparam1=@0x\[0-9a-f\]+: 31, stackparam2=@0x\[0-9a-f\]+: 32\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in main \\(\\) \[^\r\n\]*" \
+ "entry_reference: bt"
+gdb_test "ptype regparam" " = int &" "entry_reference: ptype regparam"
+
+set test "entry_reference: p regparam"
set addr ""
-gdb_test_multiple "p refparam" $test {
- -re " = \\(int &\\) @(0x\[0-9a-f\]+): 10\r\n$gdb_prompt $" {
+gdb_test_multiple "p regparam" $test {
+ -re " = \\(int &\\) @(0x\[0-9a-f\]+): 21\r\n$gdb_prompt $" {
set addr $expect_out(1,string)
pass $test
}
}
-gdb_test "ptype refparam@entry" " = int &" "entry_reference: ptype refparam@entry"
-gdb_test "p refparam@entry" " = \\(int &\\) @$addr: 5" "entry_reference: p refparam@entry"
-gdb_test "p &refparam@entry" " = \\(int \\*\\) $addr" "entry_reference: p &refparam@entry"
-gdb_test "p refcopy" " = 5" "entry_reference: p refcopy"
+gdb_test "ptype regparam@entry" " = int &" "entry_reference: ptype regparam@entry"
+gdb_test "p regparam@entry" " = \\(int &\\) @$addr: 1" "entry_reference: p regparam@entry"
+gdb_test "p ®param@entry" " = \\(int \\*\\) $addr" "entry_reference: p ®param@entry"
+gdb_test "p regcopy" " = 1" "entry_reference: p regcopy"
+gdb_test "p nodataparam" " = \\(int &\\) @0x\[0-9a-f\]+: 22" "entry_reference: p nodataparam"
+gdb_test "p nodataparam@entry" "Cannot resolve DW_AT_GNU_call_site_data_value" "entry_reference: p nodataparam@entry"
# Test virtual tail call frames.
gdb_continue_to_breakpoint "tailcall: breakhere"
-# #0 d (i=71) at gdb.arch/amd64-entry-value.cc:33
-# #1 0x0000000000400527 in c (i=7) at gdb.arch/amd64-entry-value.cc:38
-# #2 0x0000000000400545 in b (i=5) at gdb.arch/amd64-entry-value.cc:50
-# #3 0x00000000004003ee in main () at gdb.arch/amd64-entry-value.cc:60
-gdb_test "bt" "^bt\r\n#0 +d *\\(i=71\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in c \\(i=7\\) \[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in b \\(i=5\\) \[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in main \[^\r\n\]*" \
+gdb_test "bt" "^bt\r\n#0 +d *\\(i=71, i@entry=70, j=73\\.5, j@entry=72\\.5\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in c \\(i=i@entry=7, j=j@entry=7\\.25\\) \[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in b \\(i=i@entry=5, j=j@entry=5\\.25\\) \[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in main \[^\r\n\]*" \
"tailcall: bt"
gdb_test "p i" " = 71" "tailcall: p i"
gdb_test "p i@entry" " = 70" "tailcall: p i@entry"
+gdb_test "p j" " = 73\\.5" "tailcall: p j"
+gdb_test "p j@entry" " = 72\\.5" "tailcall: p j@entry"
+
+# Test $sp simulation for tail call frames.
+#gdb_test {p/x $sp} " = 0x.*"
+#gdb_test {p/x $pc} " = 0x.*"
+gdb_test_no_output {set $sp0=$sp}
+gdb_test "up" "\r\n#1 .*"
+#gdb_test {p/x $sp} " = 0x.*"
+gdb_test {p $sp0 == $sp} " = true"
+gdb_test "frame 3" "\r\n#3 .*"
+gdb_test {p $sp0 + sizeof (void *) == $sp} " = true"
# Test partial-ambiguous virtual tail call frames chain.
gdb_continue_to_breakpoint "ambiguous: breakhere"
-# #0 d (i=<optimized out>) at gdb.arch/amd64-entry-value.cc:33
-# #1 0x0000000000400555 in amb_z (i=<optimized out>) at gdb.arch/amd64-entry-value.cc:56
-# #2 0x0000000000400565 in amb_y (i=<optimized out>) at gdb.arch/amd64-entry-value.cc:62
-# #3 0x0000000000400575 in amb_x (i=<optimized out>) at gdb.arch/amd64-entry-value.cc:68
-# --- here is missing a frame for ambiguous PC in amb ().
-# #4 0x0000000000400595 in amb_b (i=101) at gdb.arch/amd64-entry-value.cc:83
-# #5 0x00000000004005a5 in amb_a (i=100) at gdb.arch/amd64-entry-value.cc:89
-# #6 0x00000000004003f8 in main () at gdb.arch/amd64-entry-value.cc:100
-gdb_test "bt" "^bt\r\n#0 +d \\(i=<optimized out>\\)\[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in amb_z \\(i=<optimized out>\\)\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in amb_y \\(i=<optimized out>\\)\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in amb_x \\(i=<optimized out>\\)\[^\r\n\]*\r\n#4 +0x\[0-9a-f\]+ in amb_b \\(i=101\\)\[^\r\n\]*\r\n#5 +0x\[0-9a-f\]+ in amb_a \\(i=100\\)\[^\r\n\]*\r\n#6 +0x\[0-9a-f\]+ in main \\(\\)\[^\r\n\]*" \
+gdb_test "bt" "^bt\r\n#0 +d \\(i=<optimized out>, j=<optimized out>\\)\[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in amb_z \\(i=<optimized out>\\)\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in amb_y \\(i=<optimized out>\\)\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in amb_x \\(i=<optimized out>\\)\[^\r\n\]*\r\n#4 +0x\[0-9a-f\]+ in amb_b \\(i=i@entry=101\\)\[^\r\n\]*\r\n#5 +0x\[0-9a-f\]+ in amb_a \\(i=i@entry=100\\)\[^\r\n\]*\r\n#6 +0x\[0-9a-f\]+ in main \\(\\)\[^\r\n\]*" \
"ambiguous: bt"
@@ -159,10 +227,7 @@ gdb_test "bt" "^bt\r\n#0 +d \\(i=<optimized out>\\)\[^\r\n\]*\r\n#1 +0x\[0-9a-f\
gdb_continue_to_breakpoint "self: breakhere"
-# #0 d (i=<optimized out>) at gdb.arch/amd64-entry-value.cc:33
-# #1 0x00000000004005df in self (i=<optimized out>) at gdb.arch/amd64-entry-value.cc:111
-# #2 0x0000000000400406 in main () at gdb.arch/amd64-entry-value.cc:124
-gdb_test "bt" "^bt\r\n#0 +d \\(i=<optimized out>\\)\[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in self \\(i=<optimized out>\\)\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in main \\(\\)\[^\r\n\]*" \
+gdb_test "bt" "^bt\r\n#0 +d \\(i=<optimized out>, j=<optimized out>\\)\[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in self \\(i=<optimized out>\\)\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in main \\(\\)\[^\r\n\]*" \
"self: bt"
gdb_test_no_output "set verbose on"
--- a/gdb/testsuite/gdb.base/break.exp
+++ b/gdb/testsuite/gdb.base/break.exp
@@ -916,13 +916,13 @@ set bp_location14 [gdb_get_line_number "set breakpoint 14 here" $srcfile1]
gdb_test_multiple "continue" \
"run until breakpoint set at small function, optimized file" {
- -re "Breakpoint $decimal, marker4 \\(d=177601976\\) at .*$srcfile1:$bp_location13\[\r\n\]+$bp_location13\[\t \]+void marker4.*" {
+ -re "Breakpoint $decimal, marker4 \\(d=(d@entry=)?177601976\\) at .*$srcfile1:$bp_location13\[\r\n\]+$bp_location13\[\t \]+void marker4.*" {
pass "run until breakpoint set at small function, optimized file"
}
- -re "Breakpoint $decimal, $hex in marker4 \\(d=177601976\\) at .*$srcfile1:$bp_location13\[\r\n\]+$bp_location13\[\t \]+void marker4.*" {
+ -re "Breakpoint $decimal, $hex in marker4 \\(d=(d@entry=)?177601976\\) at .*$srcfile1:$bp_location13\[\r\n\]+$bp_location13\[\t \]+void marker4.*" {
pass "run until breakpoint set at small function, optimized file"
}
- -re "Breakpoint $decimal, marker4 \\(d=177601976\\) at .*$srcfile1:$bp_location14\[\r\n\]+$bp_location14\[\t \]+void marker4.*" {
+ -re "Breakpoint $decimal, marker4 \\(d=(d@entry=)?177601976\\) at .*$srcfile1:$bp_location14\[\r\n\]+$bp_location14\[\t \]+void marker4.*" {
# marker4() is defined at line 46 when compiled with -DPROTOTYPES
pass "run until breakpoint set at small function, optimized file (line bp_location14)"
}
--- a/gdb/testsuite/gdb.mi/Makefile.in
+++ b/gdb/testsuite/gdb.mi/Makefile.in
@@ -9,7 +9,8 @@ PROGS = basics c_variable cpp_variable var-cmd dw2-ref-missing-frame \
mi-pending mi-pthreads mi-read-memory mi-regs mi-return \
mi-reverse mi-simplerun mi-stack mi-stepi mi-syn-frame \
mi-var-block mi-var-child mi-var-cmd mi-var-cp mi-var-display \
- mi-var-invalidate mi-var-invalidate_bis mi-watch mi2-basics \
+ mi-var-invalidate mi-var-invalidate_bis mi-watch \
+ mi2-amd64-entry-value mi2-basics \
mi2-break mi2-cli mi2-disassemble mi2-eval mi2-file \
mi2-pthreads mi2-regs mi2-return mi2-simplerun mi2-stepi \
mi2-var-block mi2-var-child mi2-var-cmd mi2-var-display \
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi2-amd64-entry-value.c
@@ -0,0 +1,70 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+static volatile int v;
+
+static void __attribute__((noinline, noclone))
+e (int i, double j)
+{
+ v = 0;
+}
+
+static int __attribute__((noinline, noclone))
+data (void)
+{
+ return 10;
+}
+
+static int __attribute__((noinline, noclone))
+data2 (void)
+{
+ return 20;
+}
+
+static int __attribute__((noinline, noclone))
+different (int val)
+{
+ val++;
+ e (val, val);
+asm ("breakhere_different:");
+ return val;
+}
+
+static int __attribute__((noinline, noclone))
+validity (int lost, int born)
+{
+ lost = data ();
+ e (0, 0.0);
+asm ("breakhere_validity:");
+ return born;
+}
+
+static void __attribute__((noinline, noclone))
+invalid (int inv)
+{
+ e (0, 0.0);
+asm ("breakhere_invalid:");
+}
+
+int
+main ()
+{
+ different (5);
+ validity (5, data ());
+ invalid (data2 ());
+ return 0;
+}
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi2-amd64-entry-value.exp
@@ -0,0 +1,171 @@
+# Copyright (C) 2011 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi2"
+
+gdb_exit
+if [mi_gdb_start] {
+ continue
+}
+
+set testfile mi2-amd64-entry-value
+set srcfile ${testfile}.s
+set opts {}
+
+if [info exists COMPILE] {
+ # make check RUNTESTFLAGS="gdb.mi/mi2-amd64-entry-value.exp COMPILE=1"
+ set srcfile ${testfile}.c
+ lappend opts debug optimize=-O2
+} elseif { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
+ verbose "Skipping amd64-entry-value."
+ return
+}
+
+set executable ${testfile}
+set binfile ${objdir}/${subdir}/${executable}
+
+if [build_executable ${testfile}.exp ${executable} ${srcfile} $opts] {
+ return -1
+}
+
+mi_gdb_reinitialize_dir $srcdir/$subdir
+mi_gdb_load ${binfile}
+
+foreach name {different breakhere_different breakhere_validity breakhere_invalid} {
+ mi_create_breakpoint $name .* .* .* .* .* .* "break $name"
+}
+
+
+# Test various kinds of `set print entry-values'.
+
+if {[mi_runto main] == -1} {
+ return -1
+}
+mi_gdb_test "-gdb-set print entry-values no" {\^done} "no: set print entry-values"
+mi_send_resuming_command "exec-continue" "no: entry_equal: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="val",value="5"}} .* .* {.* disp="keep"} "no: entry_equal: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="5"}\]} "no: entry_equal: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "no: entry_different: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="val",value="6"}} .* .* {.* disp="keep"} "no: entry_different: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="6"}\]} "no: entry_different: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "no: validity: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="lost",value="<optimized out>"},{name="born",value="10"}} .* .* {.* disp="keep"} "no: validity: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="lost",arg="1",value="<optimized out>"},{name="born",arg="1",value="10"}\]} "no: validity: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "no: invalid: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="inv",value="<optimized out>"}} .* .* {.* disp="keep"} "no: invalid: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="inv",arg="1",value="<optimized out>"}\]} "no: invalid: -stack-list-variables"
+
+if {[mi_runto main] == -1} {
+ return -1
+}
+mi_gdb_test "-gdb-set print entry-values only" {\^done} "only: set print entry-values"
+mi_send_resuming_command "exec-continue" "only: entry_equal: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="val@entry",value="5"}} .* .* {.* disp="keep"} "only: entry_equal: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val@entry",arg="1",value="5"}\]} "only: entry_equal: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "only: entry_different: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="val@entry",value="5"}} .* .* {.* disp="keep"} "only: entry_different: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val@entry",arg="1",value="5"}\]} "only: entry_different: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "only: validity: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="lost@entry",value="5"},{name="born@entry",value="<optimized out>"}} .* .* {.* disp="keep"} "only: validity: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="lost@entry",arg="1",value="5"},{name="born@entry",arg="1",value="<optimized out>"}\]} "only: validity: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "only: invalid: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="inv@entry",value="<optimized out>"}} .* .* {.* disp="keep"} "only: invalid: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="inv@entry",arg="1",value="<optimized out>"}\]} "only: invalid: -stack-list-variables"
+
+if {[mi_runto main] == -1} {
+ return -1
+}
+mi_gdb_test "-gdb-set print entry-values preferred" {\^done} "preferred: set print entry-values"
+mi_send_resuming_command "exec-continue" "preferred: entry_equal: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="val@entry",value="5"}} .* .* {.* disp="keep"} "preferred: entry_equal: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val@entry",arg="1",value="5"}\]} "preferred: entry_equal: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "preferred: entry_different: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="val@entry",value="5"}} .* .* {.* disp="keep"} "preferred: entry_different: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val@entry",arg="1",value="5"}\]} "preferred: entry_different: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "preferred: validity: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="lost@entry",value="5"},{name="born",value="10"}} .* .* {.* disp="keep"} "preferred: validity: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="lost@entry",arg="1",value="5"},{name="born",arg="1",value="10"}\]} "preferred: validity: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "preferred: invalid: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="inv@entry",value="<optimized out>"}} .* .* {.* disp="keep"} "preferred: invalid: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="inv@entry",arg="1",value="<optimized out>"}\]} "preferred: invalid: -stack-list-variables"
+
+if {[mi_runto main] == -1} {
+ return -1
+}
+mi_gdb_test "-gdb-set print entry-values if-needed" {\^done} "if-needed: set print entry-values"
+mi_send_resuming_command "exec-continue" "if-needed: entry_equal: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="val",value="5"}} .* .* {.* disp="keep"} "if-needed: entry_equal: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="5"}\]} "if-needed: entry_equal: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "if-needed: entry_different: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="val",value="6"}} .* .* {.* disp="keep"} "if-needed: entry_different: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="6"}\]} "if-needed: entry_different: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "if-needed: validity: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="lost@entry",value="5"},{name="born",value="10"}} .* .* {.* disp="keep"} "if-needed: validity: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="lost@entry",arg="1",value="5"},{name="born",arg="1",value="10"}\]} "if-needed: validity: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "if-needed: invalid: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="inv",value="<optimized out>"}} .* .* {.* disp="keep"} "if-needed: invalid: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="inv",arg="1",value="<optimized out>"}\]} "if-needed: invalid: -stack-list-variables"
+
+if {[mi_runto main] == -1} {
+ return -1
+}
+mi_gdb_test "-gdb-set print entry-values both" {\^done} "both: set print entry-values"
+mi_send_resuming_command "exec-continue" "both: entry_equal: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="val",value="5"},{name="val@entry",value="5"}} .* .* {.* disp="keep"} "both: entry_equal: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="5"},{name="val@entry",arg="1",value="5"}\]} "both: entry_equal: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "both: entry_different: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="val",value="6"},{name="val@entry",value="5"}} .* .* {.* disp="keep"} "both: entry_different: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="6"},{name="val@entry",arg="1",value="5"}\]} "both: entry_different: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "both: validity: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="lost",value="<optimized out>"},{name="lost@entry",value="5"},{name="born",value="10"},{name="born@entry",value="<optimized out>"}} .* .* {.* disp="keep"} "both: validity: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="lost",arg="1",value="<optimized out>"},{name="lost@entry",arg="1",value="5"},{name="born",arg="1",value="10"},{name="born@entry",arg="1",value="<optimized out>"}\]} "both: validity: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "both: invalid: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="inv",value="<optimized out>"},{name="inv@entry",value="<optimized out>"}} .* .* {.* disp="keep"} "both: invalid: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="inv",arg="1",value="<optimized out>"},{name="inv@entry",arg="1",value="<optimized out>"}\]} "both: invalid: -stack-list-variables"
+
+if {[mi_runto main] == -1} {
+ return -1
+}
+mi_gdb_test "-gdb-set print entry-values compact" {\^done} "compact: set print entry-values"
+mi_send_resuming_command "exec-continue" "compact: entry_equal: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="val",value="5"},{name="val@entry",value="5"}} .* .* {.* disp="keep"} "compact: entry_equal: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="5"},{name="val@entry",arg="1",value="5"}\]} "compact: entry_equal: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "compact: entry_different: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="val",value="6"},{name="val@entry",value="5"}} .* .* {.* disp="keep"} "compact: entry_different: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="6"},{name="val@entry",arg="1",value="5"}\]} "compact: entry_different: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "compact: validity: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="lost@entry",value="5"},{name="born",value="10"}} .* .* {.* disp="keep"} "compact: validity: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="lost@entry",arg="1",value="5"},{name="born",arg="1",value="10"}\]} "compact: validity: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "compact: invalid: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="inv",value="<optimized out>"}} .* .* {.* disp="keep"} "compact: invalid: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="inv",arg="1",value="<optimized out>"}\]} "compact: invalid: -stack-list-variables"
+
+if {[mi_runto main] == -1} {
+ return -1
+}
+mi_gdb_test "-gdb-set print entry-values default" {\^done} "default: set print entry-values"
+mi_send_resuming_command "exec-continue" "default: entry_equal: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="val",value="5"},{name="val@entry",value="5"}} .* .* {.* disp="keep"} "default: entry_equal: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="5"},{name="val@entry",arg="1",value="5"}\]} "default: entry_equal: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "default: entry_different: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="val",value="6"},{name="val@entry",value="5"}} .* .* {.* disp="keep"} "default: entry_different: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="val",arg="1",value="6"},{name="val@entry",arg="1",value="5"}\]} "default: entry_different: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "default: validity: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="lost",value="<optimized out>"},{name="lost@entry",value="5"},{name="born",value="10"}} .* .* {.* disp="keep"} "default: validity: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="lost",arg="1",value="<optimized out>"},{name="lost@entry",arg="1",value="5"},{name="born",arg="1",value="10"}\]} "default: validity: -stack-list-variables"
+mi_send_resuming_command "exec-continue" "default: invalid: continue"
+mi_expect_stop "breakpoint-hit" .* {{name="inv",value="<optimized out>"}} .* .* {.* disp="keep"} "default: invalid: stop"
+mi_gdb_test "-stack-list-variables --all-values" {\^done,variables=\[{name="inv",arg="1",value="<optimized out>"}\]} "default: invalid: -stack-list-variables"
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1740,22 +1740,22 @@ value_ind (struct value *arg1)
base_type = check_typedef (value_type (arg1));
- if (TYPE_CODE (base_type) == TYPE_CODE_PTR)
+ if (VALUE_LVAL (arg1) == lval_computed)
{
- struct type *enc_type;
+ const struct lval_funcs *funcs = value_computed_funcs (arg1);
- if (VALUE_LVAL (arg1) == lval_computed)
+ if (funcs->indirect)
{
- const struct lval_funcs *funcs = value_computed_funcs (arg1);
+ struct value *result = funcs->indirect (arg1);
- if (funcs->indirect)
- {
- struct value *result = funcs->indirect (arg1);
-
- if (result)
- return result;
- }
+ if (result)
+ return result;
}
+ }
+
+ if (TYPE_CODE (base_type) == TYPE_CODE_PTR)
+ {
+ struct type *enc_type;
/* We may be pointing to something embedded in a larger object.
Get the real type of the enclosing object. */
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -340,7 +340,7 @@ val_print_invalid_address (struct ui_file *stream)
int
val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
CORE_ADDR address, struct ui_file *stream, int recurse,
- struct value *val,
+ const struct value *val,
const struct value_print_options *options,
const struct language_defn *language)
{
@@ -555,7 +555,7 @@ val_print_type_code_flags (struct type *type, const gdb_byte *valaddr,
void
val_print_scalar_formatted (struct type *type,
const gdb_byte *valaddr, int embedded_offset,
- struct value *val,
+ const struct value *val,
const struct value_print_options *options,
int size,
struct ui_file *stream)
@@ -1189,7 +1189,8 @@ void
val_print_array_elements (struct type *type,
const gdb_byte *valaddr, int embedded_offset,
CORE_ADDR address, struct ui_file *stream,
- int recurse, struct value *val,
+ int recurse,
+ const struct value *val,
const struct value_print_options *options,
unsigned int i)
{
--- a/gdb/valprint.h
+++ b/gdb/valprint.h
@@ -115,7 +115,7 @@ extern void maybe_print_array_index (struct type *index_type, LONGEST index,
extern void val_print_array_elements (struct type *, const gdb_byte *, int,
CORE_ADDR, struct ui_file *, int,
- struct value *,
+ const struct value *,
const struct value_print_options *,
unsigned int);
@@ -127,7 +127,8 @@ extern void val_print_type_code_flags (struct type *type,
struct ui_file *stream);
extern void val_print_scalar_formatted (struct type *,
- const gdb_byte *, int, struct value *,
+ const gdb_byte *, int,
+ const struct value *,
const struct value_print_options *,
int,
struct ui_file *);
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1063,9 +1063,9 @@ set_value_pointed_to_offset (struct value *value, int val)
}
const struct lval_funcs *
-value_computed_funcs (struct value *v)
+value_computed_funcs (const struct value *v)
{
- gdb_assert (VALUE_LVAL (v) == lval_computed);
+ gdb_assert (value_lval_const (v) == lval_computed);
return v->location.computed.funcs;
}
@@ -1084,6 +1084,12 @@ deprecated_value_lval_hack (struct value *value)
return &value->lval;
}
+enum lval_type
+value_lval_const (const struct value *value)
+{
+ return value->lval;
+}
+
CORE_ADDR
value_address (const struct value *value)
{
@@ -3083,26 +3089,36 @@ value_from_history_ref (char *h, char **endp)
}
struct value *
+coerce_ref_if_computed (const struct value *arg)
+{
+ const struct lval_funcs *funcs;
+
+ if (TYPE_CODE (check_typedef (value_type (arg))) != TYPE_CODE_REF)
+ return NULL;
+
+ if (value_lval_const (arg) != lval_computed)
+ return NULL;
+
+ funcs = value_computed_funcs (arg);
+ if (funcs->coerce_ref == NULL)
+ return NULL;
+
+ return funcs->coerce_ref (arg);
+}
+
+struct value *
coerce_ref (struct value *arg)
{
struct type *value_type_arg_tmp = check_typedef (value_type (arg));
+ struct value *retval;
+
+ retval = coerce_ref_if_computed (arg);
+ if (retval)
+ return retval;
if (TYPE_CODE (value_type_arg_tmp) != TYPE_CODE_REF)
return arg;
- if (VALUE_LVAL (arg) == lval_computed)
- {
- const struct lval_funcs *funcs = value_computed_funcs (arg);
-
- if (funcs->indirect)
- {
- struct value *result = funcs->indirect (arg);
-
- if (result)
- return result;
- }
- }
-
return value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
unpack_pointer (value_type (arg),
value_contents (arg)));
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -175,14 +175,16 @@ struct lval_funcs
/* Return 1 if any bit in VALUE is valid, 0 if they are all invalid. */
int (*check_any_valid) (const struct value *value);
- /* If non-NULL, this is used to implement pointer and/or reference
- indirection for this value. This method may return NULL, in which case
- value_ind will fall back to ordinary indirection.
-
- TYPE_CODE (check_typedef (value)) specifies which operation should be
- done. It is always either TYPE_CODE_PTR or TYPE_CODE_REF. */
+ /* If non-NULL, this is used to implement pointer indirection for
+ this value. This method may return NULL, in which case value_ind
+ will fall back to ordinary indirection. */
struct value *(*indirect) (struct value *value);
+ /* If non-NULL, this is used to implement reference resolving for
+ this value. This method may return NULL, in which case coerce_ref
+ will fall back to ordinary references resolving. */
+ struct value *(*coerce_ref) (const struct value *value);
+
/* If non-NULL, this is used to determine whether the indicated bits
of VALUE are a synthetic pointer. */
int (*check_synthetic_pointer) (const struct value *value,
@@ -216,7 +218,7 @@ extern struct value *allocate_optimized_out_value (struct type *type);
/* If VALUE is lval_computed, return its lval_funcs structure. */
-extern const struct lval_funcs *value_computed_funcs (struct value *value);
+extern const struct lval_funcs *value_computed_funcs (const struct value *);
/* If VALUE is lval_computed, return its closure. The meaning of the
returned value depends on the functions VALUE uses. */
@@ -317,6 +319,9 @@ extern void set_value_component_location (struct value *component,
extern enum lval_type *deprecated_value_lval_hack (struct value *);
#define VALUE_LVAL(val) (*deprecated_value_lval_hack (val))
+/* Like VALUE_LVAL, except the parameter can be const. */
+extern enum lval_type value_lval_const (const struct value *value);
+
/* If lval == lval_memory, return the address in the inferior. If
lval == lval_register, return the byte offset into the registers
structure. Otherwise, return 0. The returned address
@@ -343,6 +348,11 @@ extern struct frame_id *deprecated_value_frame_id_hack (struct value *);
extern short *deprecated_value_regnum_hack (struct value *);
#define VALUE_REGNUM(val) (*deprecated_value_regnum_hack (val))
+/* Return value after lval_funcs->coerce_ref (after check_typedef). Return
+ NULL if lval_funcs->coerce_ref is not applicable for whatever reason. */
+
+extern struct value *coerce_ref_if_computed (const struct value *arg);
+
/* Convert a REF to the object referenced. */
extern struct value *coerce_ref (struct value *value);
@@ -793,7 +803,7 @@ extern struct value *value_release_to_mark (struct value *mark);
extern int val_print (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
struct ui_file *stream, int recurse,
- struct value *val,
+ const struct value *val,
const struct value_print_options *options,
const struct language_defn *language);
@@ -807,28 +817,11 @@ extern int val_print_string (struct type *elttype, const char *encoding,
struct ui_file *stream,
const struct value_print_options *options);
-/* Specify how the @entry kind of function parameters should be printed. */
-enum print_argument
-{
- /* Symbol is not a function parameter - it is a variable. */
- PVAVD_IS_NOT_ARGUMENT,
-
- /* Symbol is a function parameter, print only its @entry value if it is not
- redundant together with the normal symbol printed value. */
- PVAVD_ARGUMENT_PRINT_ENTRYVAL_ONLY,
-
- /* Symbol is a function parameter, print its normal value. Print also its
- @entry value if it is not redundant together with its normal printed
- value. */
- PVAVD_ARGUMENT_PRINT_BOTH
-};
-
extern void print_variable_and_value (const char *name,
struct symbol *var,
struct frame_info *frame,
struct ui_file *stream,
- int indent,
- enum print_argument print_argument);
+ int indent);
extern int check_field (struct type *, const char *);
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [patch 00/12] entryval#2: Fix x86_64 <optimized out> parameters, virtual tail call frames
2011-09-13 19:44 [patch 00/12] entryval#2: Fix x86_64 <optimized out> parameters, virtual tail call frames Jan Kratochvil
@ 2011-09-14 10:26 ` Eli Zaretskii
2011-09-14 10:50 ` Jan Kratochvil
2011-09-16 9:44 ` Jan Kratochvil
2011-09-30 0:02 ` obsolete: " Jan Kratochvil
1 sibling, 2 replies; 7+ messages in thread
From: Eli Zaretskii @ 2011-09-14 10:26 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
> Date: Tue, 13 Sep 2011 21:43:06 +0200
> From: Jan Kratochvil <jan.kratochvil@redhat.com>
>
> re-post of the series:
> [patch 00/12] entryval: Fix x86_64 <optimized out> parameters, virtual tail call frames
> http://sourceware.org/ml/gdb-patches/2011-07/msg00430.html
>
> particular excerpt:
> The patches are available (merged only) in GIT for more convenience at:
> http://sourceware.org/gdb/wiki/ArcherBranchManagement
> archer-jankratochvil-entryval
>
>
> Here is attached a diff against the previous patch series. The changes are:
Sorry, I'm confused: am I supposed to review only the diffs in this
message and forget about the rest of the series? If no, which parts
should I review?
For now, here are the comments about this part alone:
> +set print entry-values (both|compact|default|if-needed|no|only|preferred)
> +show print entry-values
> + Set printing of frame arguments values at function entry. In some cases
^^^^^^^^^^^^^^^^^^^^^^
"frame arguments' values" (with the apostrophe), or "frame argument
values" (in single).
> + GDB can determine the value of function argument which was passed by the
> + function caller, despite the argument value may be already modified.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
"even if the value was modified inside the called function", I think.
> +set debug tailcall
> +show debug tailcall
> + Control display of debugging info for determining virtual tail call frames,
> + present in inferior debug info together with the @entry values.
Is it possible to rephrase this in a less mysterious way? (I cannot
suggest a new wording because I don't understand what you meant ;-)
> -If you append @code{@@entry} string to a function parameter name you get its
> +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 since @value{NGCC}
> -version 4.7.
> +error message is printed. Entry values are available only with some compilers.
I think it would be good to have a cross-reference here to where you
describe "set print entry-values".
> +the function caller, despite the argument value may be already modified by the
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Same correction as above.
> +current function and therefore different.
^^^^^^^^^
"are different"
> For optimized code also the current
> +value may be possibly not available and the entry value may be still known,
> +which aids the debugging of production code.
With optimized code, the current value could be unavailable, but the
entry value may still be known.
> +this feature will behave in the default @code{default} setting the same way as
^^^^^^^
Lose this "default", it's redundant.
> +the compiler has to produce @samp{DW_TAG_GNU_call_site} tags. For example for
> +@value{NGCC} additionally optimization and debugging compilation options must
> +be enabled (@option{-O -g}).
With @value{NGCC}, you need to specify @option{-O -g} during
compilation, to get this information.
> Still even with the required debug info there
> +exist many reasons why the code path analysis by @value{GDBN} may fail in
> +specific cases.
I would omit this sentence, it isn't useful.
> +@table @code
> +@item no
This table needs to be preceded by a sentence saying something like
The @{value} parameter can be one of the following:
> +@item only
> +set print entry-values only
I think this second line should be deleted.
> +Print only parameter values from function entry point. If value from function
> +entry point is not known while the actual value is known print at least the
^
Comma here.
> +@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
This example is identical to the previous one and does not show the
effect of the `preferred' setting.
> +@item if-needed
> +Print actual parameter values. If actual parameter value is not known while
> +value from function entry point is known print at least the entry point value
^
A comma is missing. Also, what do you mean by "at least"?
> +@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
I think this example should show almost all values NOT @entry.
> +Always print both the actual parameter value and its value from function entry
> +point. Still print both even if one of them or both are @code{<optimized out>}.
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.
> +@item compact
I cannot say I like the "compact" name. How about "both-if-known"
(and "both-always" for the previous one)?
> +Print the actual parameter value if it is know 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 they are equal print the shortened
^^^^^^^^^^^^^^^^^^^^^^^^
"known and identical". And a comma after that.
> +@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
^
Comma.
> +both values are known and they are equal print the shortened
> +@code{param=param@@entry=VALUE} notation.
Not quite clear how this differs from the previous one. Maybe it
would be better to say "like compact, but...".
> +@item show print entry-values
> +Show printing of frame arguments values at function entry.
"Show the method being used for printing of..."
> +Function @code{B} can call function @code{C} by its very last statement. In
^^
"in"
> +instead. Such use of a jump instruction is called tail call.
"@dfn{tail call}" -- you are introducing new terminology.
> +During execution of function @code{C} there will remain no indication it has
> +been tail called from function @code{B}.
During execution of function @code{C}, there will be no indication
in the generated code that it was tail-called from @code{B}.
> +function @code{B} which tail calls function @code{C} then @value{GDBN} sees as
^^^^^^^^^^
"tail-calls", and a comma before "then".
> +the caller of function @code{C} the function @code{A}.
then @value{GDBN} will see @code{A} as the caller of @{C}.
> @value{GDBN} can in
> +some cases search all the possible code paths and if it determintes there
> +exists an unambiguous code path it will create call frames for it (in this case
> +a frame with @code{$pc} in function @code{B}). The virtual return address into
> +such tail call frame will be pointing pointing right after the jump instruction
> +(as if it would be a call instructions).
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.
> +the compiler has to produce @samp{DW_TAG_GNU_call_site} tags. For example for
> +@value{NGCC} additionally optimization and debugging compilation options must
> +be enabled (@option{-O -g}). Still even with the required debug info there
> +exist many reasons why the code path analysis by @value{GDBN} may fail in
> +specific cases.
Please modify this as I did with a similar text above.
> +@kbd{info frame} command (@pxref{Frame Info}) will indicate the tail call frame
> +kind by text @code{tail call frame}.
An example would be good.
> +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.
> +@kbd{set verbose} command (@pxref{Messages/Warnings, ,Optional Warnings and
> +Messages}.) can show some reasons why the complete code path analysis did not
> +succeed in a specific case.
Ditto. Also, @pxref should not have a period at its end, before the
closing parenthesis, it generates such punctuation automatically (so
the above will have 2 periods in the manual).
> +@table @code
> +@item set debug tailcall
> +@kindex set debug tailcall
> +When set to on, enables tail calls analysis messages printing. 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.
Example, please! Some rewording is in order, but I need an example to
suggest it.
> +@item gdb.TAILCALL_FRAME
> +A frame representing a tail call. Tail calls are used if the last statement of
> +an inferior function is a call of a (usually different) function. Such call
> +immediately followed by return instruction is in optimized code converted to
> +just one jump instruction. @value{GDBN} can in some cases guess such jump has
> +been executed and it creates a @code{gdb.TAILCALL_FRAME} for it.
Instead of all this description, just add a cross-reference to where
tail-calls are described.
> + add_setshow_enum_cmd ("entry-values", class_stack,
> + print_entry_values_choices, &print_entry_values,
> + _("Set printing of frame arguments values at function "
I suggest
Set printing of function arguments at function entry.
> +GDB can print in some cases besides frame arguments values also the values\n\
> +they had at function entry (marked as `NAME@entry'). The value itself and/or\n\
> +the entry value may be <optimized out>. Which of this current or entry\n\
> +values get printed in which case can be set by this option."),
GDB can sometimes determine the values of function arguments at entry,
in addition to their current values. This option tells GDB whether
to print the current value, the value at entry (marked as val@entry),
or both. Note that one or both of these values may be <optimized out>.
Thanks.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [patch 00/12] entryval#2: Fix x86_64 <optimized out> parameters, virtual tail call frames
2011-09-14 10:26 ` Eli Zaretskii
@ 2011-09-14 10:50 ` Jan Kratochvil
2011-09-16 9:44 ` Jan Kratochvil
1 sibling, 0 replies; 7+ messages in thread
From: Jan Kratochvil @ 2011-09-14 10:50 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
On Wed, 14 Sep 2011 11:28:10 +0200, Eli Zaretskii wrote:
> > Here is attached a diff against the previous patch series. The changes are:
>
> Sorry, I'm confused: am I supposed to review only the diffs in this
> message and forget about the rest of the series? If no, which parts
> should I review?
I have marked the parts to review with `+doc' in the subject.
> For now, here are the comments about this part alone:
I did not expect you would review this part but as the original patchset docs
were reviewed it is also a possible way, so everything is OK this way.
I will incorporate the suggestions and I will reply the specific patch parts
with them.
Thanks,
Jan
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [patch 00/12] entryval#2: Fix x86_64 <optimized out> parameters, virtual tail call frames
2011-09-14 10:26 ` Eli Zaretskii
2011-09-14 10:50 ` Jan Kratochvil
@ 2011-09-16 9:44 ` Jan Kratochvil
2011-09-17 13:42 ` Eli Zaretskii
1 sibling, 1 reply; 7+ messages in thread
From: Jan Kratochvil @ 2011-09-16 9:44 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
Hi Eli,
not yet re-posting, just updated the branch:
archer-jankratochvil-entryval
(IIRC GIT not being friendly to you but I guess you do not need it for the
review follow-up.)
On Wed, 14 Sep 2011 11:28:10 +0200, Eli Zaretskii wrote:
> > +set print entry-values (both|compact|default|if-needed|no|only|preferred)
> > +show print entry-values
> > + Set printing of frame arguments values at function entry. In some cases
> ^^^^^^^^^^^^^^^^^^^^^^
> "frame arguments' values" (with the apostrophe), or "frame argument
> values" (in single).
done, the latter.
> > + GDB can determine the value of function argument which was passed by the
> > + function caller, despite the argument value may be already modified.
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> "even if the value was modified inside the called function", I think.
done.
> > +set debug tailcall
> > +show debug tailcall
> > + Control display of debugging info for determining virtual tail call frames,
> > + present in inferior debug info together with the @entry values.
>
> Is it possible to rephrase this in a less mysterious way? (I cannot
> suggest a new wording because I don't understand what you meant ;-)
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.
Some samples of `Virtual tail call frames' were shown in:
[patch 04/12] entryval: Virtual tail call frames
http://sourceware.org/ml/gdb-patches/2011-07/msg00434.html
Sometimes it is not clear why GDB did not find some virtual tail call frame
while one thinks it could. With `set debug tailcall 1' GDB will print also:
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))
which clearly shows why the `amb' frame is not listed:
#0 d (i=125, j=125.5) at gdb.arch/amd64-entry-value.cc:30
#1 0x00000000004006e4 in amb_z (i=<optimized out>) at gdb.arch/amd64-entry-value.cc:65
#2 0x00000000004006f5 in amb_y (i=<optimized out>) at gdb.arch/amd64-entry-value.cc:71
#3 0x0000000000400705 in amb_x (i=<optimized out>) at gdb.arch/amd64-entry-value.cc:77
#4 0x0000000000400725 in amb_b (i=i@entry=101) at gdb.arch/amd64-entry-value.cc:92
#5 0x0000000000400735 in amb_a (i=i@entry=100) at gdb.arch/amd64-entry-value.cc:98
#6 0x000000000040052e in main () at gdb.arch/amd64-entry-value.cc:230
The `tailcall: *' lines are normally (`set debug tailcall 0') not shown to the
user.
> > -If you append @code{@@entry} string to a function parameter name you get its
> > +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 since @value{NGCC}
> > -version 4.7.
> > +error message is printed. Entry values are available only with some compilers.
>
> I think it would be good to have a cross-reference here to where you
> describe "set print entry-values".
Added:
Entry values are normally also printed at the function parameter list
according to @xref{set print entry-values}.
> > +the function caller, despite the argument value may be already modified by the
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> Same correction as above.
done.
> > +current function and therefore different.
> ^^^^^^^^^
> "are different"
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.
> > For optimized code also the current
> > +value may be possibly not available and the entry value may be still known,
> > +which aids the debugging of production code.
>
> With optimized code, the current value could be unavailable, but the
> entry value may still be known.
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. There can be:
set foo (bar|baz|default)
but still the GDB factory setting can be:
set foo baz
In this case the factory setting of GDB is:
set print entry-values default
from the choices:
set print entry-values (both|compact|default|if-needed|no|only|preferred)
We could for example chooce since gdb-8.0 the default one is "compact";
although in such case the setting name "default" would be confusing then.
> > +the compiler has to produce @samp{DW_TAG_GNU_call_site} tags. For example for
> > +@value{NGCC} additionally optimization and debugging compilation options must
> > +be enabled (@option{-O -g}).
>
> With @value{NGCC}, you need to specify @option{-O -g} during
> compilation, to get this information.
done.
> > Still even with the required debug info there
> > +exist many reasons why the code path analysis by @value{GDBN} may fail in
> > +specific cases.
>
> I would omit this sentence, it isn't useful.
done.
> > +@table @code
> > +@item no
>
> This table needs to be preceded by a sentence saying something like
>
> The @{value} parameter can be one of the following:
done:
[...] this information.
The @{value} parameter can be one of the following:
@table @code
@item no
> > +@item only
> > +set print entry-values only
>
> I think this second line should be deleted.
Yes; and the same for "both".
> > +Print only parameter values from function entry point. If value from function
> > +entry point is not known while the actual value is known print at least the
> ^
> Comma here.
done, 3 times.
> This example is identical to the previous one and does not show the
> effect of the `preferred' setting.
There were some errors in the doc, I have synced it with the GDB output and
I agree with the differences/fixes, the changes were:
preferred:
-#0 born (val@@entry=<optimized out>)
+#0 born (val=10)
if-needed:
-#0 equal (val@@entry=5)
+#0 equal (val=5)
-#0 different (val@@entry=5)
+#0 different (val=6)
-#0 invalid (val@@entry=<optimized out>)
+#0 invalid (val=<optimized out>)
> > +@item if-needed
> > +Print actual parameter values. If actual parameter value is not known while
> > +value from function entry point is known print at least the entry point value
> ^
> A comma is missing. Also, what do you mean by "at least"?
It was only a language construct without technical meaning, like that 'if we
do not know what we were primarily asked for (actual parameter value), provide
at least least the inferior substitution (the entry value).'.
I have removed "at least" from both `preferred' and `if-needed'.
> > +@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
>
> I think this example should show almost all values NOT @entry.
I agree, fixed above, thanks for reading what I wrote.
> > +Always print both the actual parameter value and its value from function entry
> > +point. Still print both even if one of them or both are @code{<optimized out>}.
>
> 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.
done.
> > +@item compact
>
> I cannot say I like the "compact" name. How about "both-if-known"
> (and "both-always" for the previous one)?
I do not find it close to "both", it is more a variant of "default". Just
I could not make "default" the optimal (shortest) output as I think replacing
former:
f (val=<optimized out>)
by the `default' variant:
f (val=<optimized out>, val@entry=5)
is more backward compatible than the radical change of `compact' variant:
f (val@entry=5)
If there were no users of existing/previous GDB I would propose `compact' as
the default/only output kind.
> > +Print the actual parameter value if it is know 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 they are equal print the shortened
> ^^^^^^^^^^^^^^^^^^^^^^^^
> "known and identical". And a comma after that.
done.
> > +@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
> ^
> Comma.
done.
> > +both values are known and they are equal print the shortened
> > +@code{param=param@@entry=VALUE} notation.
>
> Not quite clear how this differs from the previous one.
The difference is small, described above
"default":
f (val=<optimized out>, val@entry=5)
"compact":
f (val@entry=5)
> Maybe it would be better to say "like compact, but...".
I find it easy to find out from the sample output if there are concerns about
the text. Important is there "Always print the actual parameter value." which
is not true for the "compact" mode and this IMO breaks backward compatibility
of the "compact" mode.
> > +@item show print entry-values
> > +Show printing of frame arguments values at function entry.
>
> "Show the method being used for printing of..."
done.
> > +Function @code{B} can call function @code{C} by its very last statement. In
> ^^
> "in"
done.
> > +instead. Such use of a jump instruction is called tail call.
>
> "@dfn{tail call}" -- you are introducing new terminology.
done.
> > +During execution of function @code{C} there will remain no indication it has
> > +been tail called from function @code{B}.
>
> During execution of function @code{C}, there will be no indication
> in the generated code that it was tail-called from @code{B}.
I was trying to express the opposite. There remains no indication in the
stack frames. The generated code contains the only indication but it is a bit
difficult to decode out - this is the whole new tail call frames logic in GDB.
used:
During execution of function @code{C}, there will be no indication in
the stack frames that it was tail-called from @code{B}.
> > +function @code{B} which tail calls function @code{C} then @value{GDBN} sees as
> ^^^^^^^^^^
> "tail-calls", and a comma before "then".
done.
> > +the caller of function @code{C} the function @code{A}.
>
> then @value{GDBN} will see @code{A} as the caller of @{C}.
done.
> > @value{GDBN} can in
> > +some cases search all the possible code paths and if it determintes there
> > +exists an unambiguous code path it will create call frames for it (in this case
> > +a frame with @code{$pc} in function @code{B}). The virtual return address into
> > +such tail call frame will be pointing pointing right after the jump instruction
> > +(as if it would be a call instructions).
>
> 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"?
> > +the compiler has to produce @samp{DW_TAG_GNU_call_site} tags. For example for
> > +@value{NGCC} additionally optimization and debugging compilation options must
> > +be enabled (@option{-O -g}). Still even with the required debug info there
> > +exist many reasons why the code path analysis by @value{GDBN} may fail in
> > +specific cases.
>
> Please modify this as I did with a similar text above.
done.
> > +@kbd{info frame} command (@pxref{Frame Info}) will indicate the tail call frame
> > +kind by text @code{tail call frame}.
>
> An example would be good.
Put there - isn't it too long?
@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 (./gdb.arch/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))
In this case both address 0x40071e or 0x400719 could be in the backtrace so
GDB will rather omit `amb(int)' completely. In this case both addresses
belong to the same function `amb(int)' but in more complicated examples they
could be also from different functions (and have different number of virtual
frames etc.).
> > +@kbd{set verbose} command (@pxref{Messages/Warnings, ,Optional Warnings and
> > +Messages}.) can show some reasons why the complete code path analysis did not
> > +succeed in a specific case.
>
> Ditto.
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
[...]
> Also, @pxref should not have a period at its end, before the
> closing parenthesis, it generates such punctuation automatically (so
> the above will have 2 periods in the manual).
In fact I know, fixed, thanks.
> > +@table @code
> > +@item set debug tailcall
> > +@kindex set debug tailcall
> > +When set to on, enables tail calls analysis messages printing. 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.
>
> Example, please! Some rewording is in order, but I need an example to
> suggest it.
Again the example given for NEWS `set debug tailcall' entry above.
> > +@item gdb.TAILCALL_FRAME
> > +A frame representing a tail call. Tail calls are used if the last statement of
> > +an inferior function is a call of a (usually different) function. Such call
> > +immediately followed by return instruction is in optimized code converted to
> > +just one jump instruction. @value{GDBN} can in some cases guess such jump has
> > +been executed and it creates a @code{gdb.TAILCALL_FRAME} for it.
>
> Instead of all this description, just add a cross-reference to where
> tail-calls are described.
done:
@item gdb.TAILCALL_FRAME
A frame representing a tail call. @xref{Tail Call Frames}.
> > + add_setshow_enum_cmd ("entry-values", class_stack,
> > + print_entry_values_choices, &print_entry_values,
> > + _("Set printing of frame arguments values at function "
>
> I suggest
>
> Set printing of function arguments at function entry.
done:
_("Set printing of function arguments at function "
"entry"),
_("Show printing of function arguments at function "
"entry"),
> > +GDB can print in some cases besides frame arguments values also the values\n\
> > +they had at function entry (marked as `NAME@entry'). The value itself and/or\n\
> > +the entry value may be <optimized out>. Which of this current or entry\n\
> > +values get printed in which case can be set by this option."),
>
> GDB can sometimes determine the values of function arguments at entry,
> in addition to their current values. This option tells GDB whether
> to print the current value, the value at entry (marked as val@entry),
> or both. Note that one or both of these values may be <optimized out>.
done.
Thanks,
Jan
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [patch 00/12] entryval#2: Fix x86_64 <optimized out> parameters, virtual tail call frames
2011-09-16 9:44 ` Jan Kratochvil
@ 2011-09-17 13:42 ` Eli Zaretskii
2011-09-19 18:30 ` Jan Kratochvil
0 siblings, 1 reply; 7+ messages in thread
From: Eli Zaretskii @ 2011-09-17 13:42 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
> Date: Fri, 16 Sep 2011 11:35:55 +0200
> From: Jan Kratochvil <jan.kratochvil@redhat.com>
> Cc: gdb-patches@sourceware.org
>
> not yet re-posting, just updated the branch:
> archer-jankratochvil-entryval
> (IIRC GIT not being friendly to you but I guess you do not need it for the
> review follow-up.)
I can use git repositories through Bazaar with the bzr-git plugin (but
committing into git repositories is not yet supported by that plugin).
> > > +set debug tailcall
> > > +show debug tailcall
> > > + Control display of debugging info for determining virtual tail call frames,
> > > + present in inferior debug info together with the @entry values.
> >
> > Is it possible to rephrase this in a less mysterious way? (I cannot
> > suggest a new wording because I don't understand what you meant ;-)
>
> 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.
> 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.
> 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).
> > > +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?
> We could for example chooce since gdb-8.0 the default one is "compact";
The result above will be still correct English and clearly
understandable even after such a change, won't it? And having a
`default' setting that is not the default sounds wrong anyway...
> 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"?
> > 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.
> > > +@kbd{info frame} command (@pxref{Frame Info}) will indicate the tail call frame
> > > +kind by text @code{tail call frame}.
> >
> > An example would be good.
>
> Put there - isn't it too long?
Wrap it at or before column 72 and you are good.
> > > +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? 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?
> 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.
> > > +@table @code
> > > +@item set debug tailcall
> > > +@kindex set debug tailcall
> > > +When set to on, enables tail calls analysis messages printing. 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.
> >
> > Example, please! Some rewording is in order, but I need an example to
> > suggest it.
>
> 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.
Thanks.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [patch 00/12] entryval#2: Fix x86_64 <optimized out> parameters, virtual tail call frames
2011-09-17 13:42 ` Eli Zaretskii
@ 2011-09-19 18:30 ` Jan Kratochvil
0 siblings, 0 replies; 7+ messages in thread
From: Jan Kratochvil @ 2011-09-19 18:30 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
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.
^ permalink raw reply [flat|nested] 7+ messages in thread
* obsolete: [patch 00/12] entryval#2: Fix x86_64 <optimized out> parameters, virtual tail call frames
2011-09-13 19:44 [patch 00/12] entryval#2: Fix x86_64 <optimized out> parameters, virtual tail call frames Jan Kratochvil
2011-09-14 10:26 ` Eli Zaretskii
@ 2011-09-30 0:02 ` Jan Kratochvil
1 sibling, 0 replies; 7+ messages in thread
From: Jan Kratochvil @ 2011-09-30 0:02 UTC (permalink / raw)
To: gdb-patches
obsoleted by:
[patch 00/12] entryval#3: Fix x86_64 <optimized out> parameters, virtual tail call frames
http://sourceware.org/ml/gdb-patches/2011-09/msg00552.html
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2011-09-29 19:57 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-13 19:44 [patch 00/12] entryval#2: Fix x86_64 <optimized out> parameters, virtual tail call frames Jan Kratochvil
2011-09-14 10:26 ` Eli Zaretskii
2011-09-14 10:50 ` Jan Kratochvil
2011-09-16 9:44 ` Jan Kratochvil
2011-09-17 13:42 ` Eli Zaretskii
2011-09-19 18:30 ` Jan Kratochvil
2011-09-30 0:02 ` obsolete: " Jan Kratochvil
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox