This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch 07/12] entryval#3: Display @entry parameters


Hi,

[patch 07/12+doc] entryval#2: Display @entry parameters
http://sourceware.org/ml/gdb-patches/2011-09/msg00229.html

doc updates by Eli.


Thanks,
Jan


gdb/
2011-09-13  Jan Kratochvil  <jan.kratochvil@redhat.com>

	Display @entry parameter values (without references).
	* dwarf2expr.c (dwarf_block_to_fb_offset, dwarf_block_to_sp_offset):
	New functions.
	* dwarf2expr.h (dwarf_block_to_fb_offset, dwarf_block_to_sp_offset):
	New declarations.
	* dwarf2loc.c (dwarf2_find_location_expression): Support location list
	entry record.
	(dwarf_entry_parameter_to_value, value_of_dwarf_reg_entry)
	(value_of_dwarf_block_entry, locexpr_read_variable_at_entry): New
	functions.
	(dwarf2_locexpr_funcs): Install locexpr_read_variable_at_entry.
	(loclist_read_variable_at_entry): New function.
	(dwarf2_loclist_funcs): Install loclist_read_variable_at_entry.
	* dwarf2read.c (read_call_site_scope): Support also DW_OP_fbreg in
	DW_AT_location, call dwarf_block_to_sp_offset for it.
	* frame.h (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, print_entry_values): New declarations.
	(struct frame_arg): New field entry_kind.
	(read_frame_arg): New parameter entryargp.
	* mi/mi-cmd-stack.c (list_arg_or_local): New gdb_assert for
	arg->entry_kind.  Optionally print the `@entry' suffix.
	(list_args_or_locals): New variable entryarg, initialize it.
	Initialize also entry_kind of arg and entryarg.  Conditionalize
	list_arg_or_local for arg, add list_arg_or_local for entryarg.  Call
	xfree for entryarg.error.
	* stack.c (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, print_entry_values_choices)
	(print_entry_values): New variables.
	(print_frame_arg): New gdb_assert for arg->entry_kind.  Optionally
	print the `@entry' suffix, possibly in combination for
	print_entry_values_compact.
	(read_frame_arg): New parameter entryargp, new variables entryval,
	entryval_error and val_equal.  Read in also entryargp, respect
	print_entry_values, compare the values using val_equal, fill in also
	argp->entry_kind (together with entryargp->entry_kind).
	(print_frame_args): New variable entryarg, initialize it.
	Conditionalize print_frame_arg for arg, add print_frame_arg for
	entryarg.  Call xfree for entryarg.error.
	(_initialize_stack): Call add_setshow_enum_cmd for `entry-values'.
	* symtab.h (struct symbol_computed_ops): New field
	read_variable_at_entry.

gdb/doc/
2011-09-19  Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Eli Zaretskii  <eliz@gnu.org>

	* gdb.texinfo (Tail Call Frames): Add anchor.  Add self tail call
	example.
	(Print Settings): New description of set print entry-values and show
	print entry-values.

gdb/testsuite/
2011-09-13  Jan Kratochvil  <jan.kratochvil@redhat.com>

	Display @entry parameter values (without references).
	* gdb.arch/amd64-entry-value.cc (locexpr, stacktest, data, data2)
	(different, validity, invalid): New functions.
	(main): Call them.
	* gdb.arch/amd64-entry-value.exp: New breakpoints breakhere_locexpr,
	stacktest, breakhere_stacktest, different, breakhere_different,
	breakhere_validity and breakhere_invalid.
	(entry: bt): Update for @entry.
	(entry_locexpr: *, entry_stack: *, entry_equal: *, entry_different: *)
	(entry_validity: *, entry_invalid: *): Many new tests.
	* gdb.base/break.exp
	(run until breakpoint set at small function, optimized file): Accept
	also the @entry suffix.
	* gdb.mi/Makefile.in (PROGS): Add mi2-amd64-entry-value.
	* gdb.mi/mi2-amd64-entry-value.c: New files.
	* gdb.mi/mi2-amd64-entry-value.exp: New files.

--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -7941,6 +7941,120 @@ 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 argument values at function entry.  In some cases
+@value{GDBN} can determine the value of function argument which was passed by
+the function caller, even if the value was modified inside the called function
+and therefore is different.  With optimized code, the current value could be
+unavailable, but the entry value may still be known.
+
+The default value is @code{default} (see below for its description).  Older
+@value{GDBN} behaved as with the setting @code{no}.  Compilers not supporting
+this feature will behave in the @code{default} setting the same way as with the
+@code{no} setting.
+
+This functionality is currently supported only by DWARF 2 debugging format and
+the compiler has to produce @samp{DW_TAG_GNU_call_site} tags.  With
+@value{NGCC}, you need to specify @option{-O -g} during compilation, to get
+this information.
+
+The @var{value} parameter can be one of the following:
+
+@table @code
+@item no
+Print only actual parameter values, never print values from function entry
+point.
+@smallexample
+#0  equal (val=5)
+#0  different (val=6)
+#0  lost (val=<optimized out>)
+#0  born (val=10)
+#0  invalid (val=<optimized out>)
+@end smallexample
+
+@item only
+Print only parameter values from function entry point.  The actual parameter
+values are never printed.
+@smallexample
+#0  equal (val@@entry=5)
+#0  different (val@@entry=5)
+#0  lost (val@@entry=5)
+#0  born (val@@entry=<optimized out>)
+#0  invalid (val@@entry=<optimized out>)
+@end smallexample
+
+@item preferred
+Print only parameter values from function entry point.  If value from function
+entry point is not known while the actual value is known, print the actual
+value for such parameter.
+@smallexample
+#0  equal (val@@entry=5)
+#0  different (val@@entry=5)
+#0  lost (val@@entry=5)
+#0  born (val=10)
+#0  invalid (val@@entry=<optimized out>)
+@end smallexample
+
+@item if-needed
+Print actual parameter values.  If actual parameter value is not known while
+value from function entry point is known, print the entry point value for such
+parameter.
+@smallexample
+#0  equal (val=5)
+#0  different (val=6)
+#0  lost (val@@entry=5)
+#0  born (val=10)
+#0  invalid (val=<optimized out>)
+@end smallexample
+
+@item both
+Always print both the actual parameter value and its value from function entry
+point, even if values of one or both are not available due to compiler
+optimizations.
+@smallexample
+#0  equal (val=5, val@@entry=5)
+#0  different (val=6, val@@entry=5)
+#0  lost (val=<optimized out>, val@@entry=5)
+#0  born (val=10, val@@entry=<optimized out>)
+#0  invalid (val=<optimized out>, val@@entry=<optimized out>)
+@end smallexample
+
+@item compact
+Print the actual parameter value if it is known and also its value from
+function entry point if it is known.  If neither is known, print for the actual
+value @code{<optimized out>}.  If not in MI mode (@pxref{GDB/MI}) and if both
+values are known and identical, print the shortened
+@code{param=param@@entry=VALUE} notation.
+@smallexample
+#0  equal (val=val@@entry=5)
+#0  different (val=6, val@@entry=5)
+#0  lost (val@@entry=5)
+#0  born (val=10)
+#0  invalid (val=<optimized out>)
+@end smallexample
+
+@item default
+Always print the actual parameter value.  Print also its value from function
+entry point, but only if it is known.  If not in MI mode (@pxref{GDB/MI}) and
+if both values are known and identical, print the shortened
+@code{param=param@@entry=VALUE} notation.
+@smallexample
+#0  equal (val=val@@entry=5)
+#0  different (val=6, val@@entry=5)
+#0  lost (val=<optimized out>, val@@entry=5)
+#0  born (val=10)
+#0  invalid (val=<optimized out>)
+@end smallexample
+@end table
+
+For analysis messages on possible failures of frame argument values at function
+entry resolution see @ref{set debug entry-values}.
+
+@item show print entry-values
+Show the method being used for printing of frame argument values at function
+entry.
+
 @item set print repeats
 @cindex repeated array elements
 Set the threshold for suppressing display of repeated array
@@ -9600,6 +9714,7 @@ tries to show at least all the unambiguous top tail callers and all the
 unambiguous bottom tail calees, if any.
 
 @table @code
+@anchor{set debug entry-values}
 @item set debug entry-values
 @kindex set debug entry-values
 When set to on, enables printing of analysis messages for both frame argument
@@ -9675,6 +9790,32 @@ also ambigous.  The only non-ambiguous frame is the one for function @code{a},
 therefore this one is displayed to the user while the ambiguous frames are
 omitted.
 
+There can be also reasons why printing of frame argument values at function
+entry may fail:
+
+@smallexample
+int v;
+static void __attribute__((noinline, noclone)) c (int i) @{ v++; @}
+static void __attribute__((noinline, noclone)) a (int i);
+static void __attribute__((noinline, noclone)) b (int i) @{ a (i); @}
+static void __attribute__((noinline, noclone)) a (int i)
+@{ if (i) b (i - 1); else c (0); @}
+int main (void) @{ a (5); return 0; @}
+
+(gdb) bt
+#0  c (i=i@@entry=0) at t.c:2
+#1  0x0000000000400428 in a (DW_OP_GNU_entry_value resolving has found
+function "a" at 0x400420 can call itself via tail calls
+i=<optimized out>) at t.c:6
+#2  0x000000000040036e in main () at t.c:7
+@end smallexample
+
+@value{GDBN} cannot find out from the inferior state if and how many times did
+function @code{a} call itself (via function @code{b}) as these calls would be
+tail calls.  Such tail calls would modify thue @code{i} variable, therefore
+@value{GDBN} cannot be sure the value it knows would be right - @value{GDBN}
+prints @code{<optimized out>} instead.
+
 @node Macros
 @chapter C Preprocessor Macros
 
--- a/gdb/dwarf2expr.c
+++ b/gdb/dwarf2expr.c
@@ -518,6 +518,68 @@ dwarf_block_to_dwarf_reg (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.  */
+
+int
+dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf,
+			  const gdb_byte *buf_end, CORE_ADDR *sp_offset_return)
+{
+  ULONGEST dwarf_reg;
+  LONGEST sp_offset;
+
+  if (buf_end <= buf)
+    return 0;
+  if (*buf >= DW_OP_breg0 && *buf <= DW_OP_breg31)
+    {
+      dwarf_reg = *buf - DW_OP_breg0;
+      buf++;
+    }
+  else
+    {
+      if (*buf != DW_OP_bregx)
+       return 0;
+      buf++;
+      buf = read_uleb128 (buf, buf_end, &dwarf_reg);
+    }
+
+  if (gdbarch_dwarf2_reg_to_regnum (gdbarch, dwarf_reg)
+      != gdbarch_sp_regnum (gdbarch))
+    return 0;
+
+  buf = read_sleb128 (buf, buf_end, &sp_offset);
+  *sp_offset_return = sp_offset;
+  if (buf != buf_end || sp_offset != (LONGEST) *sp_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.  */
 
--- a/gdb/dwarf2expr.h
+++ b/gdb/dwarf2expr.h
@@ -277,4 +277,11 @@ void ctx_no_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
 
 int dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end);
 
+int dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
+			      CORE_ADDR *fb_offset_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
@@ -121,6 +121,24 @@ dwarf2_find_location_expression (struct dwarf2_loclist_baton *baton,
       length = extract_unsigned_integer (loc_ptr, 2, byte_order);
       loc_ptr += 2;
 
+      if (low == high && pc == low)
+	{
+	  /* This is entry PC record present only at entry point
+	     of a function.  Verify it is really the function entry point.  */
+
+	  struct block *pc_block = block_for_pc (pc);
+	  struct symbol *pc_func = NULL;
+
+	  if (pc_block)
+	    pc_func = block_linkage_function (pc_block);
+
+	  if (pc_func && pc == BLOCK_START (SYMBOL_BLOCK_VALUE (pc_func)))
+	    {
+	      *locexpr_length = length;
+	      return loc_ptr;
+	    }
+	}
+
       if (pc >= low && pc < high)
 	{
 	  *locexpr_length = length;
@@ -892,6 +910,33 @@ dwarf_expr_reg_to_entry_parameter (struct frame_info *frame, int dwarf_reg,
   return parameter;
 }
 
+/* Return value for PARAMETER for DW_AT_GNU_call_site_value.
+
+   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
+   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,
+				struct type *type,
+				struct frame_info *caller_frame,
+				struct dwarf2_per_cu_data *per_cu)
+{
+  gdb_byte *data;
+
+  /* DW_AT_GNU_call_site_value is a DWARF expression, not a DWARF
+     location.  Postprocessing of DWARF_VALUE_MEMORY would lose the type from
+     DWARF block.  */
+  data = alloca (parameter->value_size + 1);
+  memcpy (data, parameter->value, parameter->value_size);
+  data[parameter->value_size] = DW_OP_stack_value;
+
+  return dwarf2_evaluate_loc_desc (type, caller_frame, data,
+				   parameter->value_size + 1, per_cu);
+}
+
 /* Execute call_site_parameter's DWARF block 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.
@@ -942,6 +987,58 @@ dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
   ctx->baton = saved_ctx.baton;
 }
 
+/* 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 frame_info *caller_frame = get_prev_frame (frame);
+  struct call_site_parameter *parameter;
+  struct dwarf2_per_cu_data *caller_per_cu;
+
+  parameter = dwarf_expr_reg_to_entry_parameter (frame, dwarf_reg, fb_offset,
+						 &caller_per_cu);
+
+  return dwarf_entry_parameter_to_value (parameter, type, caller_frame,
+					 caller_per_cu);
+}
+
+/* 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.  */
@@ -2851,6 +2948,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)
@@ -3492,6 +3602,7 @@ locexpr_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
    evaluator.  */
 const struct symbol_computed_ops dwarf2_locexpr_funcs = {
   locexpr_read_variable,
+  locexpr_read_variable_at_entry,
   locexpr_read_needs_frame,
   locexpr_describe_location,
   locexpr_tracepoint_var_ref
@@ -3522,6 +3633,32 @@ loclist_read_variable (struct symbol *symbol, struct frame_info *frame)
   return val;
 }
 
+/* Read variable SYMBOL like loclist_read_variable at (callee) FRAME's function
+   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 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);
+  const gdb_byte *data;
+  size_t size;
+  CORE_ADDR pc;
+
+  if (frame == NULL || !get_frame_func_if_available (frame, &pc))
+    return allocate_optimized_out_value (SYMBOL_TYPE (symbol));
+
+  data = dwarf2_find_location_expression (dlbaton, &size, pc);
+  if (data == NULL)
+    return allocate_optimized_out_value (SYMBOL_TYPE (symbol));
+
+  return value_of_dwarf_block_entry (SYMBOL_TYPE (symbol), frame, data, size);
+}
+
 /* Return non-zero iff we need a frame to evaluate SYMBOL.  */
 static int
 loclist_read_needs_frame (struct symbol *symbol)
@@ -3641,6 +3778,7 @@ loclist_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
    evaluator and location lists.  */
 const struct symbol_computed_ops dwarf2_loclist_funcs = {
   loclist_read_variable,
+  loclist_read_variable_at_entry,
   loclist_read_needs_frame,
   loclist_describe_location,
   loclist_tracepoint_var_ref
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -6332,10 +6332,13 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
 	}
       parameter->dwarf_reg = dwarf_block_to_dwarf_reg (DW_BLOCK (attr)->data,
 				 &DW_BLOCK (attr)->data[DW_BLOCK (attr)->size]);
-      if (parameter->dwarf_reg == -1)
+      if (parameter->dwarf_reg == -1
+	  && !dwarf_block_to_sp_offset (gdbarch, DW_BLOCK (attr)->data,
+				  &DW_BLOCK (attr)->data[DW_BLOCK (attr)->size],
+					&parameter->fb_offset))
 	{
 	  complaint (&symfile_complaints,
-		     _("Only single DW_OP_reg is supported "
+		     _("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);
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -712,6 +712,15 @@ extern int frame_register_read (struct frame_info *frame, int regnum,
 
 /* 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
@@ -726,10 +735,22 @@ struct frame_arg
   /* 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 *argp,
+			    struct frame_arg *entryargp);
 
 extern void args_info (char *, int);
 
--- a/gdb/mi/mi-cmd-stack.c
+++ b/gdb/mi/mi-cmd-stack.c
@@ -256,11 +256,17 @@ list_arg_or_local (const struct frame_arg *arg, enum what_to_list what,
 	      || 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);
 
-  ui_out_field_string (uiout, "name", SYMBOL_PRINT_NAME (arg->sym));
+  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);
@@ -380,7 +386,7 @@ list_args_or_locals (enum what_to_list what, enum print_values values,
 	  if (print_me)
 	    {
 	      struct symbol *sym2;
-	      struct frame_arg arg;
+	      struct frame_arg arg, entryarg;
 
 	      if (SYMBOL_IS_ARGUMENT (sym))
 		sym2 = lookup_symbol (SYMBOL_NATURAL_NAME (sym),
@@ -391,6 +397,10 @@ list_args_or_locals (enum what_to_list what, enum print_values values,
 
 	      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)
 		{
@@ -401,13 +411,17 @@ list_args_or_locals (enum what_to_list what, enum print_values values,
 		      && TYPE_CODE (type) != TYPE_CODE_UNION)
 		    {
 		case PRINT_ALL_VALUES:
-		      read_frame_arg (sym2, fi, &arg);
+		      read_frame_arg (sym2, fi, &arg, &entryarg);
 		    }
 		  break;
 		}
 
-	      list_arg_or_local (&arg, what, values);
+	      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/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,
@@ -180,12 +203,29 @@ print_frame_arg (const struct frame_arg *arg)
   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, "=");
@@ -248,25 +288,138 @@ print_frame_arg (const struct frame_arg *arg)
 
 void
 read_frame_arg (struct symbol *sym, struct frame_info *frame,
-	        struct frame_arg *argp)
+	        struct frame_arg *argp, struct frame_arg *entryargp)
 {
-  struct value *val = NULL;
-  char *val_error = NULL;
+  struct value *val = NULL, *entryval = NULL;
+  char *val_error = NULL, *entryval_error = NULL;
+  int val_equal = 0;
   volatile struct gdb_exception except;
 
-  TRY_CATCH (except, RETURN_MASK_ERROR)
+  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))
+		{
+		  entryval = NULL;
+		  val_equal = 1;
+		}
+	    }
+
+	  /* 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)
     {
-      val = read_var_value (sym, frame);
+      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 (!val)
+  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_error = alloca (strlen (except.message) + 1);
-      strcpy (val_error, except.message);
+      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
@@ -308,7 +461,7 @@ print_frame_args (struct symbol *func, struct frame_info *frame,
 
       ALL_BLOCK_SYMBOLS (b, iter, sym)
         {
-	  struct frame_arg arg;
+	  struct frame_arg arg, entryarg;
 
 	  QUIT;
 
@@ -426,13 +579,30 @@ print_frame_args (struct symbol *func, struct frame_info *frame,
 	    {
 	      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);
+	    read_frame_arg (sym, frame, &arg, &entryarg);
 
-	  print_frame_arg (&arg);
+	  if (arg.entry_kind != print_entry_values_only)
+	    print_frame_arg (&arg);
+
+	  if (entryarg.entry_kind != print_entry_values_no)
+	    {
+	      if (arg.entry_kind != print_entry_values_only)
+		{
+		  ui_out_text (uiout, ", ");
+		  ui_out_wrap_hint (uiout, "    ");
+		}
+
+	      print_frame_arg (&entryarg);
+	    }
 
 	  xfree (arg.error);
+	  xfree (entryarg.error);
 
 	  first = 0;
 	}
@@ -2313,4 +2483,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 function arguments at function "
+			  "entry"),
+			_("Show printing of function arguments at function "
+			  "entry"),
+			_("\
+GDB can sometimes determine the values of function arguments at entry,\n\
+in addition to their current values.  This option tells GDB whether\n\
+to print the current value, the value at entry (marked as val@entry),\n\
+or both.  Note that one or both of these values may be <optimized out>."),
+			NULL, NULL, &setprintlist, &showprintlist);
 }
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -533,6 +533,12 @@ struct symbol_computed_ops
   struct value *(*read_variable) (struct symbol * symbol,
 				  struct frame_info * frame);
 
+  /* Read variable SYMBOL like read_variable at (callee) FRAME's function
+     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);
+
   /* Return non-zero if we need a frame to find the value of the SYMBOL.  */
   int (*read_needs_frame) (struct symbol * symbol);
 
--- a/gdb/testsuite/gdb.arch/amd64-entry-value.cc
+++ b/gdb/testsuite/gdb.arch/amd64-entry-value.cc
@@ -35,6 +35,13 @@ asm ("breakhere:");
 }
 
 static void __attribute__((noinline, noclone))
+locexpr (int i)
+{
+  i = i;
+asm ("breakhere_locexpr:");
+}
+
+static void __attribute__((noinline, noclone))
 c (int i, double j)
 {
   d (i * 10, j * 10);
@@ -114,10 +121,68 @@ self (int i)
     }
 }
 
+static void __attribute__((noinline, noclone))
+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;
+  d9 = 3.5;
+  da = 4.5;
+  e (v, v);
+asm ("breakhere_stacktest:");
+  e (v, v);
+}
+
+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 ()
 {
   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 ());
+
   if (v)
     a (1, 1.25);
   else
--- a/gdb/testsuite/gdb.arch/amd64-entry-value.exp
+++ b/gdb/testsuite/gdb.arch/amd64-entry-value.exp
@@ -35,23 +35,128 @@ 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"
 
 
 # Test @entry values for register passed parameters.
 
 gdb_continue_to_breakpoint "entry: breakhere"
 
-gdb_test "bt" "^bt\r\n#0 +d *\\(i=31, j=31\\.5\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in main .*" \
+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 j" { = 31\.5} "entry: p j"
 
 
+# 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_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_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 s2" " = 4" "entry_stack: p s2"
+gdb_test "p d9" " = 3\\.5" "entry_stack: p d9"
+gdb_test "p da" " = 4\\.5" "entry_stack: p da"
+
+
+# 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 virtual tail call frames.
 
 gdb_continue_to_breakpoint "tailcall: breakhere"
 
-gdb_test "bt" "^bt\r\n#0 +d *\\(i=71, j=73\\.5\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in c \\(i=7, j=7\\.25\\) \[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in b \\(i=5, j=5\\.25\\) \[^\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 j" " = 73\\.5" "tailcall: p j"
@@ -71,7 +176,7 @@ gdb_test {p $sp0 + sizeof (void *) == $sp} " = true"
 
 gdb_continue_to_breakpoint "ambiguous: breakhere"
 
-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=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"
 
 
--- 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 mi2-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"


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]