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/
	Display @entry parameter values (without references).
	* 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/
	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.
This commit is contained in:
Jan Kratochvil 2011-10-09 19:34:19 +00:00
parent 93d86cefdf
commit e18b27534c
18 changed files with 1088 additions and 25 deletions

View File

@ -1,3 +1,51 @@
2011-10-09 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.
2011-10-09 Jan Kratochvil <jan.kratochvil@redhat.com>
Code reshuffle.

View File

@ -1,3 +1,12 @@
2011-10-09 Jan Kratochvil <jan.kratochvil@redhat.com>
Eli Zaretskii <eliz@gnu.org>
Display @entry parameter values (without references).
* 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.
2011-10-09 Jan Kratochvil <jan.kratochvil@redhat.com>
Eli Zaretskii <eliz@gnu.org>

View File

@ -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

View File

@ -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. */

View File

@ -281,4 +281,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 */

View File

@ -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. */
@ -2853,6 +2950,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)
@ -3494,6 +3604,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
@ -3524,6 +3635,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)
@ -3643,6 +3780,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

View File

@ -6346,10 +6346,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);

View File

@ -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);

View File

@ -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))

View File

@ -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)
{
val = read_var_value (sym, frame);
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 (!val)
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)))
{
val_error = alloca (strlen (except.message) + 1);
strcpy (val_error, except.message);
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)
{
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
@ -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);
}

View File

@ -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);

View File

@ -1,3 +1,22 @@
2011-10-09 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.
2011-10-09 Jan Kratochvil <jan.kratochvil@redhat.com>
Protect entry values against self tail calls.

View File

@ -34,6 +34,13 @@ asm ("breakhere:");
e (v, v);
}
static void __attribute__((noinline, noclone))
locexpr (int i)
{
i = i;
asm ("breakhere_locexpr:");
}
static void __attribute__((noinline, noclone))
c (int i, double j)
{
@ -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

View File

@ -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"

View File

@ -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)"
}

View File

@ -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 \

View File

@ -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;
}

View File

@ -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"