This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[patch 00/12] entryval#2: Fix x86_64 <optimized out> parameters, virtual tail call frames
- From: Jan Kratochvil <jan dot kratochvil at redhat dot com>
- To: gdb-patches at sourceware dot org
- Date: Tue, 13 Sep 2011 21:43:06 +0200
- Subject: [patch 00/12] entryval#2: Fix x86_64 <optimized out> parameters, virtual tail call frames
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 *);
@@ -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"));
}
-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;
}
@@ -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;
}
@@ -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 *);