* [patch 11/12] entryval#2: @entry values even for references
@ 2011-09-13 19:52 Jan Kratochvil
2011-09-16 12:29 ` Pedro Alves
0 siblings, 1 reply; 11+ messages in thread
From: Jan Kratochvil @ 2011-09-13 19:52 UTC (permalink / raw)
To: gdb-patches
Hi,
[patch 10/12] entryval: @entry values even for references
http://sourceware.org/ml/gdb-patches/2011-07/msg00440.html
various implementation changes, also the patch parts moved a bit.
Thanks,
Jan
gdb/
2011-09-13 Jan Kratochvil <jan.kratochvil@redhat.com>
Display @entry parameter values even for references.
* ada-valprint.c (ada_val_print_1) <TYPE_CODE_REF>: Try also
coerce_ref_if_computed.
* c-valprint.c (c_val_print) <TYPE_CODE_REF>: Likewise.
* dwarf2expr.c (dwarf_block_to_dwarf_reg_deref): New function.
(execute_stack_op) <DW_OP_GNU_entry_value>: Add -1 deref_size to the
existing push_dwarf_reg_entry_value call. Add new detection calling
dwarf_block_to_dwarf_reg_deref. Update the error message.
(ctx_no_push_dwarf_reg_entry_value): New parameter deref_size.
* dwarf2expr.h
(struct dwarf_expr_context_funcs) <push_dwarf_reg_entry_value>: Add new
parameter deref_size, describe it in the comment.
(ctx_no_push_dwarf_reg_entry_value): Add new parameter deref_size.
(dwarf_block_to_dwarf_reg_deref): New declaration.
* dwarf2loc.c (dwarf_entry_parameter_to_value): Add new parameter
deref_size, describe it in the function comment. New variables
data_src and size, fetch the alternative block accoring to DEREF_SIZE.
(dwarf_expr_push_dwarf_reg_entry_value): Add new parameter deref_size,
describe it in the function comment. Fetch the alternative block
accoring to DEREF_SIZE.
(entry_data_value_coerce_ref, entry_data_value_copy_closure)
(entry_data_value_free_closure, entry_data_value_funcs): New.
(value_of_dwarf_reg_entry): New variables checked_type, target_type,
outer_val, target_val, val and addr. Try to fetch and create also
referenced value content.
(pieced_value_funcs): NULL value for coerce_ref.
(needs_dwarf_reg_entry_value): Add new parameter deref_size.
* f-valprint.c (f_val_print) <TYPE_CODE_REF>: Try also
coerce_ref_if_computed.
* opencl-lang.c (opencl_value_funcs): NULL value for coerce_ref.
* p-valprint.c (pascal_val_print) <TYPE_CODE_REF>: Likewise.
* stack.c (read_frame_arg): Compare also dereferenced values.
* value.c (value_computed_funcs): Make the parameter v const, use
value_lval_const for it.
(value_lval_const, coerce_ref_if_computed): New function.
(coerce_ref): New variable retval. Call also coerce_ref_if_computed.
* value.h (struct lval_funcs): New field coerce_ref.
(value_computed_funcs): Make the parameter v const.
(value_lval_const, coerce_ref_if_computed): New declarations.
gdb/testsuite/
2011-09-13 Jan Kratochvil <jan.kratochvil@redhat.com>
Display @entry parameter values even for references.
* gdb.arch/amd64-entry-value.cc (reference, datap, datap_input): New
functions.
(main): New variables regvar, nodatavarp, stackvar1, stackvar2. Call
reference and datap_input.
* gdb.arch/amd64-entry-value.exp (reference, breakhere_reference): New
breakpoints.
(continue to breakpoint: entry_reference: reference)
(entry_reference: bt at entry)
(continue to breakpoint: entry_reference: breakhere_reference)
(entry_reference: bt, entry_reference: ptype regparam)
(entry_reference: p regparam, entry_reference: ptype regparam@entry)
(entry_reference: p regparam@entry, entry_reference: p ®param@entry)
(entry_reference: p regcopy, entry_reference: p nodataparam)
(entry_reference: p nodataparam@entry): New tests.
--- a/gdb/ada-valprint.c
+++ b/gdb/ada-valprint.c
@@ -898,9 +898,18 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr,
if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF)
{
- CORE_ADDR deref_val_int
- = unpack_pointer (type, valaddr + offset_aligned);
+ CORE_ADDR deref_val_int;
+ struct value *deref_val;
+ deref_val = coerce_ref_if_computed (original_value);
+ if (deref_val)
+ {
+ common_val_print (deref_val, stream, recurse + 1, options,
+ current_language);
+ return 0;
+ }
+
+ deref_val_int = unpack_pointer (type, valaddr + offset_aligned);
if (deref_val_int != 0)
{
struct value *deref_val =
--- a/gdb/c-valprint.c
+++ b/gdb/c-valprint.c
@@ -380,10 +380,19 @@ c_val_print (struct type *type, const gdb_byte *valaddr,
{
if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF)
{
- struct value *deref_val =
- value_at
- (TYPE_TARGET_TYPE (type),
- unpack_pointer (type, valaddr + embedded_offset));
+ struct value *deref_val;
+
+ deref_val = coerce_ref_if_computed (original_value);
+ if (deref_val)
+ {
+ common_val_print (deref_val, stream, recurse, options,
+ current_language);
+ return 0;
+ }
+
+ deref_val = value_at (TYPE_TARGET_TYPE (type),
+ unpack_pointer (type,
+ valaddr + embedded_offset));
common_val_print (deref_val, stream, recurse, options,
current_language);
--- a/gdb/dwarf2expr.c
+++ b/gdb/dwarf2expr.c
@@ -518,6 +518,63 @@ 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 just DW_OP_breg*(0) and
+ DW_OP_deref* return the DWARF register number. Otherwise return -1.
+ DEREF_SIZE_RETURN contains -1 for DW_OP_deref; otherwise it contains the
+ size from DW_OP_deref_size. */
+
+int
+dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf, const gdb_byte *buf_end,
+ CORE_ADDR *deref_size_return)
+{
+ ULONGEST dwarf_reg;
+ LONGEST offset;
+
+ if (buf_end <= buf)
+ return -1;
+ if (*buf >= DW_OP_breg0 && *buf <= DW_OP_breg31)
+ {
+ dwarf_reg = *buf - DW_OP_breg0;
+ buf++;
+ }
+ else if (*buf == DW_OP_bregx)
+ {
+ buf++;
+ buf = read_uleb128 (buf, buf_end, &dwarf_reg);
+ if ((int) dwarf_reg != dwarf_reg)
+ return -1;
+ }
+ else
+ return -1;
+
+ buf = read_sleb128 (buf, buf_end, &offset);
+ if (offset != 0)
+ return -1;
+
+ if (buf >= buf_end)
+ return -1;
+
+ if (*buf == DW_OP_deref)
+ {
+ buf++;
+ *deref_size_return = -1;
+ }
+ else if (*buf == DW_OP_deref_size)
+ {
+ buf++;
+ if (buf >= buf_end)
+ return -1;
+ *deref_size_return = *buf++;
+ }
+ else
+ return -1;
+
+ if (buf != buf_end)
+ return -1;
+
+ 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. */
@@ -1300,12 +1357,27 @@ execute_stack_op (struct dwarf_expr_context *ctx,
{
op_ptr += len;
ctx->funcs->push_dwarf_reg_entry_value (ctx, dwarf_reg,
- 0 /* unused */);
+ 0 /* unused */,
+ -1 /* deref_size */);
+ goto no_push;
+ }
+
+ dwarf_reg = dwarf_block_to_dwarf_reg_deref (op_ptr, op_ptr + len,
+ &deref_size);
+ if (dwarf_reg != -1)
+ {
+ if (deref_size == -1)
+ deref_size = ctx->addr_size;
+ op_ptr += len;
+ ctx->funcs->push_dwarf_reg_entry_value (ctx, dwarf_reg,
+ 0 /* unused */,
+ deref_size);
goto no_push;
}
error (_("DWARF-2 expression error: DW_OP_GNU_entry_value is "
- "supported only for single DW_OP_reg*"));
+ "supported only for single DW_OP_reg* "
+ "or for DW_OP_breg*(0)+DW_OP_deref*"));
}
case DW_OP_GNU_const_type:
@@ -1456,7 +1528,8 @@ ctx_no_get_base_type (struct dwarf_expr_context *ctx, size_t die)
void
ctx_no_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
- int dwarf_reg, CORE_ADDR fb_offset)
+ int dwarf_reg, CORE_ADDR fb_offset,
+ int deref_size)
{
internal_error (__FILE__, __LINE__,
_("Support for DW_OP_GNU_entry_value is unimplemented"));
--- a/gdb/dwarf2expr.h
+++ b/gdb/dwarf2expr.h
@@ -67,9 +67,11 @@ struct dwarf_expr_context_funcs
number DWARF_REG specifying the push_dwarf_reg_entry_value parameter is
not -1 FB_OFFSET is ignored. Otherwise FB_OFFSET specifies stack
parameter offset against caller's stack pointer (which equals the callee's
- frame base). */
+ frame base). If DEREF_SIZE is not -1 then use
+ DW_AT_GNU_call_site_data_value instead of DW_AT_GNU_call_site_value. */
void (*push_dwarf_reg_entry_value) (struct dwarf_expr_context *ctx,
- int dwarf_reg, CORE_ADDR fb_offset);
+ int dwarf_reg, CORE_ADDR fb_offset,
+ int deref_size);
#if 0
/* Not yet implemented. */
@@ -273,10 +275,15 @@ CORE_ADDR ctx_no_get_tls_address (void *baton, CORE_ADDR offset);
void ctx_no_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset);
struct type *ctx_no_get_base_type (struct dwarf_expr_context *ctx, size_t die);
void ctx_no_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
- int dwarf_reg, CORE_ADDR fb_offset);
+ int dwarf_reg, CORE_ADDR fb_offset,
+ int deref_size);
int dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end);
+int dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf,
+ const gdb_byte *buf_end,
+ CORE_ADDR *deref_size_return);
+
int dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
CORE_ADDR *fb_offset_return);
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -897,7 +897,9 @@ 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.
+/* Return value for PARAMETER matching DEREF_SIZE. If DEREF_SIZE is -1, return
+ the normal DW_AT_GNU_call_site_value block. Otherwise return the
+ DW_AT_GNU_call_site_data_value (dereferenced) block.
TYPE and CALLER_FRAME specify how to evaluate the DWARF block into returned
struct value.
@@ -907,33 +909,44 @@ dwarf_expr_reg_to_entry_parameter (struct frame_info *frame, int dwarf_reg,
static struct value *
dwarf_entry_parameter_to_value (struct call_site_parameter *parameter,
- struct type *type,
+ CORE_ADDR deref_size, struct type *type,
struct frame_info *caller_frame,
struct dwarf2_per_cu_data *per_cu)
{
+ const gdb_byte *data_src;
gdb_byte *data;
+ size_t size;
+
+ data_src = deref_size == -1 ? parameter->value : parameter->data_value;
+ size = deref_size == -1 ? parameter->value_size : parameter->data_value_size;
+
+ /* DEREF_SIZE size is not verified here. */
+ if (data_src == NULL)
+ throw_error (NO_ENTRY_VALUE_ERROR,
+ _("Cannot resolve DW_AT_GNU_call_site_data_value"));
/* DW_AT_GNU_call_site_value is a DWARF expression, not a DWARF
location. 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;
+ data = alloca (size + 1);
+ memcpy (data, data_src, size);
+ data[size] = DW_OP_stack_value;
- return dwarf2_evaluate_loc_desc (type, caller_frame, data,
- parameter->value_size + 1, per_cu);
+ return dwarf2_evaluate_loc_desc (type, caller_frame, data, 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.
+/* Execute call_site_parameter's DWARF block matching DEREF_SIZE for caller of
+ the CTX's frame. CTX must be of dwarf_expr_ctx_funcs kind. See DWARF_REG
+ and FB_OFFSET description at struct
+ dwarf_expr_context_funcs->push_dwarf_reg_entry_value.
The CTX caller can be from a different CU - per_cu_dwarf_call implementation
can be more simple as it does not support cross-CU DWARF executions. */
static void
dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
- int dwarf_reg, CORE_ADDR fb_offset)
+ int dwarf_reg, CORE_ADDR fb_offset,
+ int deref_size)
{
struct dwarf_expr_baton *debaton;
struct frame_info *frame, *caller_frame;
@@ -951,8 +964,13 @@ dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
parameter = dwarf_expr_reg_to_entry_parameter (frame, dwarf_reg, fb_offset,
&caller_per_cu);
- data_src = parameter->value;
- size = parameter->value_size;
+ data_src = deref_size == -1 ? parameter->value : parameter->data_value;
+ size = deref_size == -1 ? parameter->value_size : parameter->data_value_size;
+
+ /* DEREF_SIZE size is not verified here. */
+ if (data_src == NULL)
+ throw_error (NO_ENTRY_VALUE_ERROR,
+ _("Cannot resolve DW_AT_GNU_call_site_data_value"));
baton_local.frame = caller_frame;
baton_local.per_cu = caller_per_cu;
@@ -974,6 +992,62 @@ dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
ctx->baton = saved_ctx.baton;
}
+/* VALUE must be of type lval_computed with entry_data_value_funcs. Perform
+ the indirect method on it, that is use its stored target value, the sole
+ purpose of entry_data_value_funcs.. */
+
+static struct value *
+entry_data_value_coerce_ref (const struct value *value)
+{
+ struct type *checked_type = check_typedef (value_type (value));
+ struct value *target_val;
+
+ if (TYPE_CODE (checked_type) != TYPE_CODE_REF)
+ return NULL;
+
+ target_val = value_computed_closure (value);
+ value_incref (target_val);
+ return target_val;
+}
+
+/* Implement copy_closure. */
+
+static void *
+entry_data_value_copy_closure (const struct value *v)
+{
+ struct value *target_val = value_computed_closure (v);
+
+ value_incref (target_val);
+ return target_val;
+}
+
+/* Implement free_closure. */
+
+static void
+entry_data_value_free_closure (struct value *v)
+{
+ struct value *target_val = value_computed_closure (v);
+
+ value_free (target_val);
+}
+
+/* Vector for methods for an entry value reference where the referenced value
+ is stored in the caller. On the first dereference use
+ DW_AT_GNU_call_site_data_value in the caller. */
+
+static const struct lval_funcs entry_data_value_funcs =
+{
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* check_validity */
+ NULL, /* check_any_valid */
+ NULL, /* indirect */
+ entry_data_value_coerce_ref,
+ NULL, /* check_synthetic_pointer */
+ entry_data_value_copy_closure,
+ entry_data_value_free_closure
+};
+
/* Read parameter of TYPE at (callee) FRAME's function entry. DWARF_REG and
FB_OFFSET are used to match DW_AT_location at the caller's
DW_TAG_GNU_call_site_parameter. See DWARF_REG and FB_OFFSET description at
@@ -986,15 +1060,52 @@ static struct value *
value_of_dwarf_reg_entry (struct type *type, struct frame_info *frame,
int dwarf_reg, CORE_ADDR fb_offset)
{
+ struct type *checked_type = check_typedef (type);
+ struct type *target_type = TYPE_TARGET_TYPE (checked_type);
struct frame_info *caller_frame = get_prev_frame (frame);
+ struct value *outer_val, *target_val, *val;
struct call_site_parameter *parameter;
struct dwarf2_per_cu_data *caller_per_cu;
+ CORE_ADDR addr;
parameter = dwarf_expr_reg_to_entry_parameter (frame, dwarf_reg, fb_offset,
&caller_per_cu);
- return dwarf_entry_parameter_to_value (parameter, type, caller_frame,
- caller_per_cu);
+ outer_val = dwarf_entry_parameter_to_value (parameter, -1 /* deref_size */,
+ type, caller_frame,
+ caller_per_cu);
+
+ /* Check if DW_AT_GNU_call_site_data_value cannot be used. If it should be
+ used and it is not available do not fall back to OUTER_VAL - dereferencing
+ TYPE_CODE_REF with non-entry data value would give current value - not the
+ entry value. */
+
+ if (TYPE_CODE (checked_type) != TYPE_CODE_REF
+ || TYPE_TARGET_TYPE (checked_type) == NULL)
+ return outer_val;
+
+ target_val = dwarf_entry_parameter_to_value (parameter,
+ TYPE_LENGTH (target_type),
+ target_type, caller_frame,
+ caller_per_cu);
+
+ /* value_as_address dereferences TYPE_CODE_REF. */
+ addr = extract_typed_address (value_contents (outer_val), checked_type);
+
+ /* The target entry value has artificial address of the entry value
+ reference. */
+ VALUE_LVAL (target_val) = lval_memory;
+ set_value_address (target_val, addr);
+
+ release_value (target_val);
+ val = allocate_computed_value (type, &entry_data_value_funcs,
+ target_val /* closure */);
+
+ /* Copy the referencing pointer to the new computed value. */
+ memcpy (value_contents_raw (val), value_contents_raw (outer_val), TYPE_LENGTH (checked_type));
+ set_value_lazy (val, 0);
+
+ return val;
}
/* Read parameter of TYPE at (callee) FRAME's function entry. DATA and
@@ -1794,6 +1905,7 @@ static const struct lval_funcs pieced_value_funcs = {
check_pieced_value_validity,
check_pieced_value_invalid,
indirect_pieced_value,
+ NULL, /* coerce_ref */
check_pieced_synthetic_pointer,
copy_pieced_value_closure,
free_pieced_value_closure
@@ -2112,7 +2224,7 @@ needs_frame_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset)
static void
needs_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
- int dwarf_reg, CORE_ADDR fb_offset)
+ int dwarf_reg, CORE_ADDR fb_offset, int deref_size)
{
struct needs_frame_baton *nf_baton = ctx->baton;
--- a/gdb/f-valprint.c
+++ b/gdb/f-valprint.c
@@ -346,10 +346,19 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
{
if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF)
{
- struct value *deref_val =
- value_at
- (TYPE_TARGET_TYPE (type),
- unpack_pointer (type, valaddr + embedded_offset));
+ struct value *deref_val;
+
+ deref_val = coerce_ref_if_computed (original_value);
+ if (deref_val)
+ {
+ common_val_print (deref_val, stream, recurse, options,
+ current_language);
+ return 0;
+ }
+
+ deref_val = value_at (TYPE_TARGET_TYPE (type),
+ unpack_pointer (type,
+ valaddr + embedded_offset));
common_val_print (deref_val, stream, recurse,
options, current_language);
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -360,7 +360,8 @@ static const struct lval_funcs opencl_value_funcs =
lval_func_write,
lval_func_check_validity,
lval_func_check_any_valid,
- NULL,
+ NULL, /* indirect */
+ NULL, /* coerce_ref */
lval_func_check_synthetic_pointer,
lval_func_copy_closure,
lval_func_free_closure
--- a/gdb/p-valprint.c
+++ b/gdb/p-valprint.c
@@ -272,10 +272,19 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr,
{
if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF)
{
- struct value *deref_val =
- value_at
- (TYPE_TARGET_TYPE (type),
- unpack_pointer (type, valaddr + embedded_offset));
+ struct value *deref_val;
+
+ deref_val = coerce_ref_if_computed (original_value);
+ if (deref_val)
+ {
+ common_val_print (deref_val, stream, recurse + 1, options,
+ current_language);
+ return 0;
+ }
+
+ deref_val = value_at (TYPE_TARGET_TYPE (type),
+ unpack_pointer (type,
+ valaddr + embedded_offset));
common_val_print (deref_val, stream, recurse + 1, options,
current_language);
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -350,8 +350,50 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
if (!value_optimized_out (val)
&& value_available_contents_eq (val, 0, entryval, 0, len))
{
- entryval = NULL;
- val_equal = 1;
+ struct value *val_deref, *entryval_deref;
+
+ /* DW_AT_GNU_call_site_value does match with the current
+ value. If it is a reference still try to verify if
+ dereferenced DW_AT_GNU_call_site_data_value does not
+ differ. */
+
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ unsigned len_deref;
+
+ val_deref = coerce_ref (val);
+ if (value_lazy (val_deref))
+ value_fetch_lazy (val_deref);
+ len_deref = TYPE_LENGTH (value_type (val_deref));
+
+ entryval_deref = coerce_ref (entryval);
+ if (value_lazy (entryval_deref))
+ value_fetch_lazy (entryval_deref);
+
+ /* If the reference addresses match but dereferenced
+ content does not match print them. */
+ if (val != val_deref
+ && value_available_contents_eq (val_deref, 0,
+ entryval_deref, 0,
+ len_deref))
+ val_equal = 1;
+ }
+
+ /* Value was not a reference; and its content matches. */
+ if (val == val_deref)
+ val_equal = 1;
+ /* If the dereferenced content could not be fetched do not
+ display anything. */
+ else if (except.error == NO_ENTRY_VALUE_ERROR)
+ val_equal = 1;
+ else if (except.message)
+ {
+ entryval_error = alloca (strlen (except.message) + 1);
+ strcpy (entryval_error, except.message);
+ }
+
+ if (val_equal)
+ entryval = NULL;
}
}
--- a/gdb/testsuite/gdb.arch/amd64-entry-value.cc
+++ b/gdb/testsuite/gdb.arch/amd64-entry-value.cc
@@ -135,6 +135,40 @@ asm ("breakhere_stacktest:");
e (v, v);
}
+/* nodataparam has DW_AT_GNU_call_site_value but it does not have
+ DW_AT_GNU_call_site_data_value. GDB should not display dereferenced @entry
+ value for it. */
+
+static void __attribute__((noinline, noclone))
+reference (int ®param, int &nodataparam, int r3, int r4, int r5, int r6,
+ int &stackparam1, int &stackparam2)
+{
+ int regcopy = regparam, nodatacopy = nodataparam;
+ int stackcopy1 = stackparam1, stackcopy2 = stackparam2;
+
+ regparam = 21;
+ nodataparam = 22;
+ stackparam1 = 31;
+ stackparam2 = 32;
+ e (v, v);
+asm ("breakhere_reference:");
+ e (v, v);
+}
+
+static int *__attribute__((noinline, noclone))
+datap ()
+{
+ static int two = 2;
+
+ return &two;
+}
+
+static void __attribute__((noinline, noclone))
+datap_input (int *datap)
+{
+ (*datap)++;
+}
+
static int __attribute__((noinline, noclone))
data (void)
{
@@ -183,6 +217,12 @@ main ()
validity (5, data ());
invalid (data2 ());
+ {
+ int regvar = 1, *nodatavarp = datap (), stackvar1 = 11, stackvar2 = 12;
+ reference (regvar, *nodatavarp, 3, 4, 5, 6, stackvar1, stackvar2);
+ datap_input (nodatavarp);
+ }
+
if (v)
a (1, 1.25);
else
--- a/gdb/testsuite/gdb.arch/amd64-entry-value.exp
+++ b/gdb/testsuite/gdb.arch/amd64-entry-value.exp
@@ -42,6 +42,8 @@ gdb_breakpoint "different"
gdb_breakpoint "breakhere_different"
gdb_breakpoint "breakhere_validity"
gdb_breakpoint "breakhere_invalid"
+gdb_breakpoint "reference"
+gdb_breakpoint "breakhere_reference"
# Test @entry values for register passed parameters.
@@ -158,6 +160,38 @@ gdb_test_no_output "set print entry-values default" "entry_invalid: set print en
gdb_test "frame" {\(inv=<optimized out>\).*} "entry_invalid: frame: default"
+# Test @entry values for DW_AT_GNU_call_site_data_value parameters.
+
+gdb_continue_to_breakpoint "entry_reference: reference"
+
+# GCC PR debug/49980: Missing stackparam1@entry and stackparam2@entry.
+gdb_test "bt" "#0 +reference \\(regparam=regparam@entry=@0x\[0-9a-f\]+: 1, nodataparam=@0x\[0-9a-f\]+: 2, \[^\r\n\]+, stackparam1=@0x\[0-9a-f\]+: 11, stackparam2=@0x\[0-9a-f\]+: 12\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in main \\(\\) \[^\r\n\]*" \
+ "entry_reference: bt at entry"
+
+gdb_continue_to_breakpoint "entry_reference: breakhere_reference"
+
+# GCC PR debug/49980: Missing stackparam1@entry and stackparam2@entry.
+gdb_test "bt" "#0 +reference \\(regparam=@0x\[0-9a-f\]+: 21, regparam@entry=@0x\[0-9a-f\]+: 1, nodataparam=@0x\[0-9a-f\]+: 22, \[^\r\n\]+, stackparam1=@0x\[0-9a-f\]+: 31, stackparam2=@0x\[0-9a-f\]+: 32\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in main \\(\\) \[^\r\n\]*" \
+ "entry_reference: bt"
+gdb_test "ptype regparam" " = int &" "entry_reference: ptype regparam"
+
+set test "entry_reference: p regparam"
+set addr ""
+gdb_test_multiple "p regparam" $test {
+ -re " = \\(int &\\) @(0x\[0-9a-f\]+): 21\r\n$gdb_prompt $" {
+ set addr $expect_out(1,string)
+ pass $test
+ }
+}
+
+gdb_test "ptype regparam@entry" " = int &" "entry_reference: ptype regparam@entry"
+gdb_test "p regparam@entry" " = \\(int &\\) @$addr: 1" "entry_reference: p regparam@entry"
+gdb_test "p ®param@entry" " = \\(int \\*\\) $addr" "entry_reference: p ®param@entry"
+gdb_test "p regcopy" " = 1" "entry_reference: p regcopy"
+gdb_test "p nodataparam" " = \\(int &\\) @0x\[0-9a-f\]+: 22" "entry_reference: p nodataparam"
+gdb_test "p nodataparam@entry" "Cannot resolve DW_AT_GNU_call_site_data_value" "entry_reference: p nodataparam@entry"
+
+
# Test virtual tail call frames.
gdb_continue_to_breakpoint "tailcall: breakhere"
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1063,9 +1063,9 @@ set_value_pointed_to_offset (struct value *value, int val)
}
const struct lval_funcs *
-value_computed_funcs (struct value *v)
+value_computed_funcs (const struct value *v)
{
- gdb_assert (VALUE_LVAL (v) == lval_computed);
+ gdb_assert (value_lval_const (v) == lval_computed);
return v->location.computed.funcs;
}
@@ -1084,6 +1084,12 @@ deprecated_value_lval_hack (struct value *value)
return &value->lval;
}
+enum lval_type
+value_lval_const (const struct value *value)
+{
+ return value->lval;
+}
+
CORE_ADDR
value_address (const struct value *value)
{
@@ -3083,15 +3089,39 @@ value_from_history_ref (char *h, char **endp)
}
struct value *
+coerce_ref_if_computed (const struct value *arg)
+{
+ const struct lval_funcs *funcs;
+
+ if (TYPE_CODE (check_typedef (value_type (arg))) != TYPE_CODE_REF)
+ return NULL;
+
+ if (value_lval_const (arg) != lval_computed)
+ return NULL;
+
+ funcs = value_computed_funcs (arg);
+ if (funcs->coerce_ref == NULL)
+ return NULL;
+
+ return funcs->coerce_ref (arg);
+}
+
+struct value *
coerce_ref (struct value *arg)
{
struct type *value_type_arg_tmp = check_typedef (value_type (arg));
+ struct value *retval;
- if (TYPE_CODE (value_type_arg_tmp) == TYPE_CODE_REF)
- arg = value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
- unpack_pointer (value_type (arg),
- value_contents (arg)));
- return arg;
+ retval = coerce_ref_if_computed (arg);
+ if (retval)
+ return retval;
+
+ if (TYPE_CODE (value_type_arg_tmp) != TYPE_CODE_REF)
+ return arg;
+
+ return value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
+ unpack_pointer (value_type (arg),
+ value_contents (arg)));
}
struct value *
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -180,6 +180,11 @@ struct lval_funcs
will fall back to ordinary indirection. */
struct value *(*indirect) (struct value *value);
+ /* If non-NULL, this is used to implement reference resolving for
+ this value. This method may return NULL, in which case coerce_ref
+ will fall back to ordinary references resolving. */
+ struct value *(*coerce_ref) (const struct value *value);
+
/* If non-NULL, this is used to determine whether the indicated bits
of VALUE are a synthetic pointer. */
int (*check_synthetic_pointer) (const struct value *value,
@@ -213,7 +218,7 @@ extern struct value *allocate_optimized_out_value (struct type *type);
/* If VALUE is lval_computed, return its lval_funcs structure. */
-extern const struct lval_funcs *value_computed_funcs (struct value *value);
+extern const struct lval_funcs *value_computed_funcs (const struct value *);
/* If VALUE is lval_computed, return its closure. The meaning of the
returned value depends on the functions VALUE uses. */
@@ -314,6 +319,9 @@ extern void set_value_component_location (struct value *component,
extern enum lval_type *deprecated_value_lval_hack (struct value *);
#define VALUE_LVAL(val) (*deprecated_value_lval_hack (val))
+/* Like VALUE_LVAL, except the parameter can be const. */
+extern enum lval_type value_lval_const (const struct value *value);
+
/* If lval == lval_memory, return the address in the inferior. If
lval == lval_register, return the byte offset into the registers
structure. Otherwise, return 0. The returned address
@@ -340,6 +348,11 @@ extern struct frame_id *deprecated_value_frame_id_hack (struct value *);
extern short *deprecated_value_regnum_hack (struct value *);
#define VALUE_REGNUM(val) (*deprecated_value_regnum_hack (val))
+/* Return value after lval_funcs->coerce_ref (after check_typedef). Return
+ NULL if lval_funcs->coerce_ref is not applicable for whatever reason. */
+
+extern struct value *coerce_ref_if_computed (const struct value *arg);
+
/* Convert a REF to the object referenced. */
extern struct value *coerce_ref (struct value *value);
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [patch 11/12] entryval#2: @entry values even for references
2011-09-13 19:52 [patch 11/12] entryval#2: @entry values even for references Jan Kratochvil
@ 2011-09-16 12:29 ` Pedro Alves
2011-09-16 19:15 ` Jan Kratochvil
0 siblings, 1 reply; 11+ messages in thread
From: Pedro Alves @ 2011-09-16 12:29 UTC (permalink / raw)
To: gdb-patches; +Cc: Jan Kratochvil
On Tuesday 13 September 2011 20:50:47, Jan Kratochvil wrote:
> + struct value *deref_val;
> +
> + deref_val = coerce_ref_if_computed (original_value);
Hmm, this doesn't look right. It ignores embedded_offset. What if the reference
we're currently printing is a field of a struct at offset != 0?
E.g., `struct { long l; long &r } foo;', and we're `p foo', which descends
into printing R at FOO + offset of R ?
> + if (deref_val)
> + {
> + common_val_print (deref_val, stream, recurse, options,
> + current_language);
> + return 0;
> + }
> +
> + deref_val = value_at (TYPE_TARGET_TYPE (type),
> + unpack_pointer (type,
> + valaddr + embedded_offset));
--
Pedro Alves
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [patch 11/12] entryval#2: @entry values even for references
2011-09-16 12:29 ` Pedro Alves
@ 2011-09-16 19:15 ` Jan Kratochvil
2011-09-21 15:54 ` Pedro Alves
0 siblings, 1 reply; 11+ messages in thread
From: Jan Kratochvil @ 2011-09-16 19:15 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
On Fri, 16 Sep 2011 14:26:09 +0200, Pedro Alves wrote:
> On Tuesday 13 September 2011 20:50:47, Jan Kratochvil wrote:
> > + struct value *deref_val;
> > +
> > + deref_val = coerce_ref_if_computed (original_value);
>
> Hmm, this doesn't look right. It ignores embedded_offset. What if the reference
> we're currently printing is a field of a struct at offset != 0?
> E.g., `struct { long l; long &r } foo;', and we're `p foo', which descends
> into printing R at FOO + offset of R ?
It is not perfect but I do not know about some short way out.
coerce_ref_if_computed currently can have effect only for @entry values
(only entry_data_value_funcs has coerce_ref != NULL) and in such case the
first printing code will have embedded_offset == 0 and further printing gets
resolved via common_val_print passed the dereferenced value with
original_value no longer present anywhere.
If it should work really correctly there are more cases to catch such as
f77_print_array (*) being passed original_value etc. The correct way would be
the rework to full struct value * printing
http://sourceware.org/ml/gdb-patches/2010-10/msg00127.html
but I did not want to get deeper in the patchset dependencies.
(*) Fortran support is planned for entry_values, it was even AFAIK one of the
reasons for DW_AT_GNU_call_site_data_value at all, it waits now on
gcc PR debug/49981 but that can be incremental GDB update later.
Is it OK this way?
+ deref_val = coerce_ref_if_computed (original_value);
+ if (deref_val != NULL)
+ {
+ /* More complicated computed references are not supported. */
+ gdb_assert (embedded_offset == 0);
+ }
+ else
Thanks,
Jan
gdb/
2011-09-13 Jan Kratochvil <jan.kratochvil@redhat.com>
Display @entry parameter values even for references.
* ada-valprint.c (ada_val_print_1) <TYPE_CODE_REF>: Try also
coerce_ref_if_computed.
* c-valprint.c (c_val_print) <TYPE_CODE_REF>: Likewise.
* dwarf2expr.c (dwarf_block_to_dwarf_reg_deref): New function.
(execute_stack_op) <DW_OP_GNU_entry_value>: Add -1 deref_size to the
existing push_dwarf_reg_entry_value call. Add new detection calling
dwarf_block_to_dwarf_reg_deref. Update the error message.
(ctx_no_push_dwarf_reg_entry_value): New parameter deref_size.
* dwarf2expr.h
(struct dwarf_expr_context_funcs) <push_dwarf_reg_entry_value>: Add new
parameter deref_size, describe it in the comment.
(ctx_no_push_dwarf_reg_entry_value): Add new parameter deref_size.
(dwarf_block_to_dwarf_reg_deref): New declaration.
* dwarf2loc.c (dwarf_entry_parameter_to_value): Add new parameter
deref_size, describe it in the function comment. New variables
data_src and size, fetch the alternative block accoring to DEREF_SIZE.
(dwarf_expr_push_dwarf_reg_entry_value): Add new parameter deref_size,
describe it in the function comment. Fetch the alternative block
accoring to DEREF_SIZE.
(entry_data_value_coerce_ref, entry_data_value_copy_closure)
(entry_data_value_free_closure, entry_data_value_funcs): New.
(value_of_dwarf_reg_entry): New variables checked_type, target_type,
outer_val, target_val, val and addr. Try to fetch and create also
referenced value content.
(pieced_value_funcs): NULL value for coerce_ref.
(needs_dwarf_reg_entry_value): Add new parameter deref_size.
* f-valprint.c (f_val_print) <TYPE_CODE_REF>: Try also
coerce_ref_if_computed.
* opencl-lang.c (opencl_value_funcs): NULL value for coerce_ref.
* p-valprint.c (pascal_val_print) <TYPE_CODE_REF>: Likewise.
* stack.c (read_frame_arg): Compare also dereferenced values.
* value.c (value_computed_funcs): Make the parameter v const, use
value_lval_const for it.
(value_lval_const, coerce_ref_if_computed): New function.
(coerce_ref): New variable retval. Call also coerce_ref_if_computed.
* value.h (struct lval_funcs): New field coerce_ref.
(value_computed_funcs): Make the parameter v const.
(value_lval_const, coerce_ref_if_computed): New declarations.
gdb/testsuite/
2011-09-13 Jan Kratochvil <jan.kratochvil@redhat.com>
Display @entry parameter values even for references.
* gdb.arch/amd64-entry-value.cc (reference, datap, datap_input): New
functions.
(main): New variables regvar, nodatavarp, stackvar1, stackvar2. Call
reference and datap_input.
* gdb.arch/amd64-entry-value.exp (reference, breakhere_reference): New
breakpoints.
(continue to breakpoint: entry_reference: reference)
(entry_reference: bt at entry)
(continue to breakpoint: entry_reference: breakhere_reference)
(entry_reference: bt, entry_reference: ptype regparam)
(entry_reference: p regparam, entry_reference: ptype regparam@entry)
(entry_reference: p regparam@entry, entry_reference: p ®param@entry)
(entry_reference: p regcopy, entry_reference: p nodataparam)
(entry_reference: p nodataparam@entry): New tests.
--- a/gdb/ada-valprint.c
+++ b/gdb/ada-valprint.c
@@ -898,9 +898,18 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr,
if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF)
{
- CORE_ADDR deref_val_int
- = unpack_pointer (type, valaddr + offset_aligned);
+ CORE_ADDR deref_val_int;
+ struct value *deref_val;
+ deref_val = coerce_ref_if_computed (original_value);
+ if (deref_val)
+ {
+ common_val_print (deref_val, stream, recurse + 1, options,
+ current_language);
+ break;
+ }
+
+ deref_val_int = unpack_pointer (type, valaddr + offset_aligned);
if (deref_val_int != 0)
{
struct value *deref_val =
--- a/gdb/c-valprint.c
+++ b/gdb/c-valprint.c
@@ -380,10 +380,19 @@ c_val_print (struct type *type, const gdb_byte *valaddr,
{
if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF)
{
- struct value *deref_val =
- value_at
- (TYPE_TARGET_TYPE (type),
- unpack_pointer (type, valaddr + embedded_offset));
+ struct value *deref_val;
+
+ deref_val = coerce_ref_if_computed (original_value);
+ if (deref_val != NULL)
+ {
+ /* More complicated computed references are not supported. */
+ gdb_assert (embedded_offset == 0);
+ }
+ else
+ deref_val = value_at (TYPE_TARGET_TYPE (type),
+ unpack_pointer (type,
+ (valaddr
+ + embedded_offset)));
common_val_print (deref_val, stream, recurse, options,
current_language);
--- a/gdb/dwarf2expr.c
+++ b/gdb/dwarf2expr.c
@@ -518,6 +518,63 @@ 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 just DW_OP_breg*(0) and
+ DW_OP_deref* return the DWARF register number. Otherwise return -1.
+ DEREF_SIZE_RETURN contains -1 for DW_OP_deref; otherwise it contains the
+ size from DW_OP_deref_size. */
+
+int
+dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf, const gdb_byte *buf_end,
+ CORE_ADDR *deref_size_return)
+{
+ ULONGEST dwarf_reg;
+ LONGEST offset;
+
+ if (buf_end <= buf)
+ return -1;
+ if (*buf >= DW_OP_breg0 && *buf <= DW_OP_breg31)
+ {
+ dwarf_reg = *buf - DW_OP_breg0;
+ buf++;
+ }
+ else if (*buf == DW_OP_bregx)
+ {
+ buf++;
+ buf = read_uleb128 (buf, buf_end, &dwarf_reg);
+ if ((int) dwarf_reg != dwarf_reg)
+ return -1;
+ }
+ else
+ return -1;
+
+ buf = read_sleb128 (buf, buf_end, &offset);
+ if (offset != 0)
+ return -1;
+
+ if (buf >= buf_end)
+ return -1;
+
+ if (*buf == DW_OP_deref)
+ {
+ buf++;
+ *deref_size_return = -1;
+ }
+ else if (*buf == DW_OP_deref_size)
+ {
+ buf++;
+ if (buf >= buf_end)
+ return -1;
+ *deref_size_return = *buf++;
+ }
+ else
+ return -1;
+
+ if (buf != buf_end)
+ return -1;
+
+ 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. */
@@ -1300,12 +1357,27 @@ execute_stack_op (struct dwarf_expr_context *ctx,
{
op_ptr += len;
ctx->funcs->push_dwarf_reg_entry_value (ctx, dwarf_reg,
- 0 /* unused */);
+ 0 /* unused */,
+ -1 /* deref_size */);
+ goto no_push;
+ }
+
+ dwarf_reg = dwarf_block_to_dwarf_reg_deref (op_ptr, op_ptr + len,
+ &deref_size);
+ if (dwarf_reg != -1)
+ {
+ if (deref_size == -1)
+ deref_size = ctx->addr_size;
+ op_ptr += len;
+ ctx->funcs->push_dwarf_reg_entry_value (ctx, dwarf_reg,
+ 0 /* unused */,
+ deref_size);
goto no_push;
}
error (_("DWARF-2 expression error: DW_OP_GNU_entry_value is "
- "supported only for single DW_OP_reg*"));
+ "supported only for single DW_OP_reg* "
+ "or for DW_OP_breg*(0)+DW_OP_deref*"));
}
case DW_OP_GNU_const_type:
@@ -1456,7 +1528,8 @@ ctx_no_get_base_type (struct dwarf_expr_context *ctx, size_t die)
void
ctx_no_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
- int dwarf_reg, CORE_ADDR fb_offset)
+ int dwarf_reg, CORE_ADDR fb_offset,
+ int deref_size)
{
internal_error (__FILE__, __LINE__,
_("Support for DW_OP_GNU_entry_value is unimplemented"));
--- a/gdb/dwarf2expr.h
+++ b/gdb/dwarf2expr.h
@@ -67,9 +67,11 @@ struct dwarf_expr_context_funcs
number DWARF_REG specifying the push_dwarf_reg_entry_value parameter is
not -1 FB_OFFSET is ignored. Otherwise FB_OFFSET specifies stack
parameter offset against caller's stack pointer (which equals the callee's
- frame base). */
+ frame base). If DEREF_SIZE is not -1 then use
+ DW_AT_GNU_call_site_data_value instead of DW_AT_GNU_call_site_value. */
void (*push_dwarf_reg_entry_value) (struct dwarf_expr_context *ctx,
- int dwarf_reg, CORE_ADDR fb_offset);
+ int dwarf_reg, CORE_ADDR fb_offset,
+ int deref_size);
#if 0
/* Not yet implemented. */
@@ -273,10 +275,15 @@ CORE_ADDR ctx_no_get_tls_address (void *baton, CORE_ADDR offset);
void ctx_no_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset);
struct type *ctx_no_get_base_type (struct dwarf_expr_context *ctx, size_t die);
void ctx_no_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
- int dwarf_reg, CORE_ADDR fb_offset);
+ int dwarf_reg, CORE_ADDR fb_offset,
+ int deref_size);
int dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end);
+int dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf,
+ const gdb_byte *buf_end,
+ CORE_ADDR *deref_size_return);
+
int dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
CORE_ADDR *fb_offset_return);
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -892,7 +892,9 @@ 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.
+/* Return value for PARAMETER matching DEREF_SIZE. If DEREF_SIZE is -1, return
+ the normal DW_AT_GNU_call_site_value block. Otherwise return the
+ DW_AT_GNU_call_site_data_value (dereferenced) block.
TYPE and CALLER_FRAME specify how to evaluate the DWARF block into returned
struct value.
@@ -902,33 +904,44 @@ dwarf_expr_reg_to_entry_parameter (struct frame_info *frame, int dwarf_reg,
static struct value *
dwarf_entry_parameter_to_value (struct call_site_parameter *parameter,
- struct type *type,
+ CORE_ADDR deref_size, struct type *type,
struct frame_info *caller_frame,
struct dwarf2_per_cu_data *per_cu)
{
+ const gdb_byte *data_src;
gdb_byte *data;
+ size_t size;
+
+ data_src = deref_size == -1 ? parameter->value : parameter->data_value;
+ size = deref_size == -1 ? parameter->value_size : parameter->data_value_size;
+
+ /* DEREF_SIZE size is not verified here. */
+ if (data_src == NULL)
+ throw_error (NO_ENTRY_VALUE_ERROR,
+ _("Cannot resolve DW_AT_GNU_call_site_data_value"));
/* DW_AT_GNU_call_site_value is a DWARF expression, not a DWARF
location. 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;
+ data = alloca (size + 1);
+ memcpy (data, data_src, size);
+ data[size] = DW_OP_stack_value;
- return dwarf2_evaluate_loc_desc (type, caller_frame, data,
- parameter->value_size + 1, per_cu);
+ return dwarf2_evaluate_loc_desc (type, caller_frame, data, 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.
+/* Execute call_site_parameter's DWARF block matching DEREF_SIZE for caller of
+ the CTX's frame. CTX must be of dwarf_expr_ctx_funcs kind. See DWARF_REG
+ and FB_OFFSET description at struct
+ dwarf_expr_context_funcs->push_dwarf_reg_entry_value.
The CTX caller can be from a different CU - per_cu_dwarf_call implementation
can be more simple as it does not support cross-CU DWARF executions. */
static void
dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
- int dwarf_reg, CORE_ADDR fb_offset)
+ int dwarf_reg, CORE_ADDR fb_offset,
+ int deref_size)
{
struct dwarf_expr_baton *debaton;
struct frame_info *frame, *caller_frame;
@@ -946,8 +959,13 @@ dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
parameter = dwarf_expr_reg_to_entry_parameter (frame, dwarf_reg, fb_offset,
&caller_per_cu);
- data_src = parameter->value;
- size = parameter->value_size;
+ data_src = deref_size == -1 ? parameter->value : parameter->data_value;
+ size = deref_size == -1 ? parameter->value_size : parameter->data_value_size;
+
+ /* DEREF_SIZE size is not verified here. */
+ if (data_src == NULL)
+ throw_error (NO_ENTRY_VALUE_ERROR,
+ _("Cannot resolve DW_AT_GNU_call_site_data_value"));
baton_local.frame = caller_frame;
baton_local.per_cu = caller_per_cu;
@@ -969,6 +987,62 @@ dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
ctx->baton = saved_ctx.baton;
}
+/* VALUE must be of type lval_computed with entry_data_value_funcs. Perform
+ the indirect method on it, that is use its stored target value, the sole
+ purpose of entry_data_value_funcs.. */
+
+static struct value *
+entry_data_value_coerce_ref (const struct value *value)
+{
+ struct type *checked_type = check_typedef (value_type (value));
+ struct value *target_val;
+
+ if (TYPE_CODE (checked_type) != TYPE_CODE_REF)
+ return NULL;
+
+ target_val = value_computed_closure (value);
+ value_incref (target_val);
+ return target_val;
+}
+
+/* Implement copy_closure. */
+
+static void *
+entry_data_value_copy_closure (const struct value *v)
+{
+ struct value *target_val = value_computed_closure (v);
+
+ value_incref (target_val);
+ return target_val;
+}
+
+/* Implement free_closure. */
+
+static void
+entry_data_value_free_closure (struct value *v)
+{
+ struct value *target_val = value_computed_closure (v);
+
+ value_free (target_val);
+}
+
+/* Vector for methods for an entry value reference where the referenced value
+ is stored in the caller. On the first dereference use
+ DW_AT_GNU_call_site_data_value in the caller. */
+
+static const struct lval_funcs entry_data_value_funcs =
+{
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* check_validity */
+ NULL, /* check_any_valid */
+ NULL, /* indirect */
+ entry_data_value_coerce_ref,
+ NULL, /* check_synthetic_pointer */
+ entry_data_value_copy_closure,
+ entry_data_value_free_closure
+};
+
/* Read parameter of TYPE at (callee) FRAME's function entry. DWARF_REG and
FB_OFFSET are used to match DW_AT_location at the caller's
DW_TAG_GNU_call_site_parameter. See DWARF_REG and FB_OFFSET description at
@@ -981,15 +1055,52 @@ static struct value *
value_of_dwarf_reg_entry (struct type *type, struct frame_info *frame,
int dwarf_reg, CORE_ADDR fb_offset)
{
+ struct type *checked_type = check_typedef (type);
+ struct type *target_type = TYPE_TARGET_TYPE (checked_type);
struct frame_info *caller_frame = get_prev_frame (frame);
+ struct value *outer_val, *target_val, *val;
struct call_site_parameter *parameter;
struct dwarf2_per_cu_data *caller_per_cu;
+ CORE_ADDR addr;
parameter = dwarf_expr_reg_to_entry_parameter (frame, dwarf_reg, fb_offset,
&caller_per_cu);
- return dwarf_entry_parameter_to_value (parameter, type, caller_frame,
- caller_per_cu);
+ outer_val = dwarf_entry_parameter_to_value (parameter, -1 /* deref_size */,
+ type, caller_frame,
+ caller_per_cu);
+
+ /* Check if DW_AT_GNU_call_site_data_value cannot be used. If it should be
+ used and it is not available do not fall back to OUTER_VAL - dereferencing
+ TYPE_CODE_REF with non-entry data value would give current value - not the
+ entry value. */
+
+ if (TYPE_CODE (checked_type) != TYPE_CODE_REF
+ || TYPE_TARGET_TYPE (checked_type) == NULL)
+ return outer_val;
+
+ target_val = dwarf_entry_parameter_to_value (parameter,
+ TYPE_LENGTH (target_type),
+ target_type, caller_frame,
+ caller_per_cu);
+
+ /* value_as_address dereferences TYPE_CODE_REF. */
+ addr = extract_typed_address (value_contents (outer_val), checked_type);
+
+ /* The target entry value has artificial address of the entry value
+ reference. */
+ VALUE_LVAL (target_val) = lval_memory;
+ set_value_address (target_val, addr);
+
+ release_value (target_val);
+ val = allocate_computed_value (type, &entry_data_value_funcs,
+ target_val /* closure */);
+
+ /* Copy the referencing pointer to the new computed value. */
+ memcpy (value_contents_raw (val), value_contents_raw (outer_val), TYPE_LENGTH (checked_type));
+ set_value_lazy (val, 0);
+
+ return val;
}
/* Read parameter of TYPE at (callee) FRAME's function entry. DATA and
@@ -1781,6 +1892,7 @@ static const struct lval_funcs pieced_value_funcs = {
check_pieced_value_validity,
check_pieced_value_invalid,
indirect_pieced_value,
+ NULL, /* coerce_ref */
check_pieced_synthetic_pointer,
copy_pieced_value_closure,
free_pieced_value_closure
@@ -2099,7 +2211,7 @@ needs_frame_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset)
static void
needs_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
- int dwarf_reg, CORE_ADDR fb_offset)
+ int dwarf_reg, CORE_ADDR fb_offset, int deref_size)
{
struct needs_frame_baton *nf_baton = ctx->baton;
--- a/gdb/f-valprint.c
+++ b/gdb/f-valprint.c
@@ -346,10 +346,19 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
{
if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF)
{
- struct value *deref_val =
- value_at
- (TYPE_TARGET_TYPE (type),
- unpack_pointer (type, valaddr + embedded_offset));
+ struct value *deref_val;
+
+ deref_val = coerce_ref_if_computed (original_value);
+ if (deref_val != NULL)
+ {
+ /* More complicated computed references are not supported. */
+ gdb_assert (embedded_offset == 0);
+ }
+ else
+ deref_val = value_at (TYPE_TARGET_TYPE (type),
+ unpack_pointer (type,
+ (valaddr
+ + embedded_offset)));
common_val_print (deref_val, stream, recurse,
options, current_language);
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -360,7 +360,8 @@ static const struct lval_funcs opencl_value_funcs =
lval_func_write,
lval_func_check_validity,
lval_func_check_any_valid,
- NULL,
+ NULL, /* indirect */
+ NULL, /* coerce_ref */
lval_func_check_synthetic_pointer,
lval_func_copy_closure,
lval_func_free_closure
--- a/gdb/p-valprint.c
+++ b/gdb/p-valprint.c
@@ -272,10 +272,19 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr,
{
if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF)
{
- struct value *deref_val =
- value_at
- (TYPE_TARGET_TYPE (type),
- unpack_pointer (type, valaddr + embedded_offset));
+ struct value *deref_val;
+
+ deref_val = coerce_ref_if_computed (original_value);
+ if (deref_val != NULL)
+ {
+ /* More complicated computed references are not supported. */
+ gdb_assert (embedded_offset == 0);
+ }
+ else
+ deref_val = value_at (TYPE_TARGET_TYPE (type),
+ unpack_pointer (type,
+ (valaddr
+ + embedded_offset)));
common_val_print (deref_val, stream, recurse + 1, options,
current_language);
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -350,8 +350,50 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
if (!value_optimized_out (val)
&& value_available_contents_eq (val, 0, entryval, 0, len))
{
- entryval = NULL;
- val_equal = 1;
+ struct value *val_deref, *entryval_deref;
+
+ /* DW_AT_GNU_call_site_value does match with the current
+ value. If it is a reference still try to verify if
+ dereferenced DW_AT_GNU_call_site_data_value does not
+ differ. */
+
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ unsigned len_deref;
+
+ val_deref = coerce_ref (val);
+ if (value_lazy (val_deref))
+ value_fetch_lazy (val_deref);
+ len_deref = TYPE_LENGTH (value_type (val_deref));
+
+ entryval_deref = coerce_ref (entryval);
+ if (value_lazy (entryval_deref))
+ value_fetch_lazy (entryval_deref);
+
+ /* If the reference addresses match but dereferenced
+ content does not match print them. */
+ if (val != val_deref
+ && value_available_contents_eq (val_deref, 0,
+ entryval_deref, 0,
+ len_deref))
+ val_equal = 1;
+ }
+
+ /* Value was not a reference; and its content matches. */
+ if (val == val_deref)
+ val_equal = 1;
+ /* If the dereferenced content could not be fetched do not
+ display anything. */
+ else if (except.error == NO_ENTRY_VALUE_ERROR)
+ val_equal = 1;
+ else if (except.message)
+ {
+ entryval_error = alloca (strlen (except.message) + 1);
+ strcpy (entryval_error, except.message);
+ }
+
+ if (val_equal)
+ entryval = NULL;
}
}
--- a/gdb/testsuite/gdb.arch/amd64-entry-value.cc
+++ b/gdb/testsuite/gdb.arch/amd64-entry-value.cc
@@ -135,6 +135,40 @@ asm ("breakhere_stacktest:");
e (v, v);
}
+/* nodataparam has DW_AT_GNU_call_site_value but it does not have
+ DW_AT_GNU_call_site_data_value. GDB should not display dereferenced @entry
+ value for it. */
+
+static void __attribute__((noinline, noclone))
+reference (int ®param, int &nodataparam, int r3, int r4, int r5, int r6,
+ int &stackparam1, int &stackparam2)
+{
+ int regcopy = regparam, nodatacopy = nodataparam;
+ int stackcopy1 = stackparam1, stackcopy2 = stackparam2;
+
+ regparam = 21;
+ nodataparam = 22;
+ stackparam1 = 31;
+ stackparam2 = 32;
+ e (v, v);
+asm ("breakhere_reference:");
+ e (v, v);
+}
+
+static int *__attribute__((noinline, noclone))
+datap ()
+{
+ static int two = 2;
+
+ return &two;
+}
+
+static void __attribute__((noinline, noclone))
+datap_input (int *datap)
+{
+ (*datap)++;
+}
+
static int __attribute__((noinline, noclone))
data (void)
{
@@ -183,6 +217,12 @@ main ()
validity (5, data ());
invalid (data2 ());
+ {
+ int regvar = 1, *nodatavarp = datap (), stackvar1 = 11, stackvar2 = 12;
+ reference (regvar, *nodatavarp, 3, 4, 5, 6, stackvar1, stackvar2);
+ datap_input (nodatavarp);
+ }
+
if (v)
a (1, 1.25);
else
--- a/gdb/testsuite/gdb.arch/amd64-entry-value.exp
+++ b/gdb/testsuite/gdb.arch/amd64-entry-value.exp
@@ -42,6 +42,8 @@ gdb_breakpoint "different"
gdb_breakpoint "breakhere_different"
gdb_breakpoint "breakhere_validity"
gdb_breakpoint "breakhere_invalid"
+gdb_breakpoint "reference"
+gdb_breakpoint "breakhere_reference"
# Test @entry values for register passed parameters.
@@ -158,6 +160,38 @@ gdb_test_no_output "set print entry-values default" "entry_invalid: set print en
gdb_test "frame" {\(inv=<optimized out>\).*} "entry_invalid: frame: default"
+# Test @entry values for DW_AT_GNU_call_site_data_value parameters.
+
+gdb_continue_to_breakpoint "entry_reference: reference"
+
+# GCC PR debug/49980: Missing stackparam1@entry and stackparam2@entry.
+gdb_test "bt" "#0 +reference \\(regparam=regparam@entry=@0x\[0-9a-f\]+: 1, nodataparam=@0x\[0-9a-f\]+: 2, \[^\r\n\]+, stackparam1=@0x\[0-9a-f\]+: 11, stackparam2=@0x\[0-9a-f\]+: 12\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in main \\(\\) \[^\r\n\]*" \
+ "entry_reference: bt at entry"
+
+gdb_continue_to_breakpoint "entry_reference: breakhere_reference"
+
+# GCC PR debug/49980: Missing stackparam1@entry and stackparam2@entry.
+gdb_test "bt" "#0 +reference \\(regparam=@0x\[0-9a-f\]+: 21, regparam@entry=@0x\[0-9a-f\]+: 1, nodataparam=@0x\[0-9a-f\]+: 22, \[^\r\n\]+, stackparam1=@0x\[0-9a-f\]+: 31, stackparam2=@0x\[0-9a-f\]+: 32\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in main \\(\\) \[^\r\n\]*" \
+ "entry_reference: bt"
+gdb_test "ptype regparam" " = int &" "entry_reference: ptype regparam"
+
+set test "entry_reference: p regparam"
+set addr ""
+gdb_test_multiple "p regparam" $test {
+ -re " = \\(int &\\) @(0x\[0-9a-f\]+): 21\r\n$gdb_prompt $" {
+ set addr $expect_out(1,string)
+ pass $test
+ }
+}
+
+gdb_test "ptype regparam@entry" " = int &" "entry_reference: ptype regparam@entry"
+gdb_test "p regparam@entry" " = \\(int &\\) @$addr: 1" "entry_reference: p regparam@entry"
+gdb_test "p ®param@entry" " = \\(int \\*\\) $addr" "entry_reference: p ®param@entry"
+gdb_test "p regcopy" " = 1" "entry_reference: p regcopy"
+gdb_test "p nodataparam" " = \\(int &\\) @0x\[0-9a-f\]+: 22" "entry_reference: p nodataparam"
+gdb_test "p nodataparam@entry" "Cannot resolve DW_AT_GNU_call_site_data_value" "entry_reference: p nodataparam@entry"
+
+
# Test virtual tail call frames.
gdb_continue_to_breakpoint "tailcall: breakhere"
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1063,9 +1063,9 @@ set_value_pointed_to_offset (struct value *value, int val)
}
const struct lval_funcs *
-value_computed_funcs (struct value *v)
+value_computed_funcs (const struct value *v)
{
- gdb_assert (VALUE_LVAL (v) == lval_computed);
+ gdb_assert (value_lval_const (v) == lval_computed);
return v->location.computed.funcs;
}
@@ -1084,6 +1084,12 @@ deprecated_value_lval_hack (struct value *value)
return &value->lval;
}
+enum lval_type
+value_lval_const (const struct value *value)
+{
+ return value->lval;
+}
+
CORE_ADDR
value_address (const struct value *value)
{
@@ -3083,15 +3089,39 @@ value_from_history_ref (char *h, char **endp)
}
struct value *
+coerce_ref_if_computed (const struct value *arg)
+{
+ const struct lval_funcs *funcs;
+
+ if (TYPE_CODE (check_typedef (value_type (arg))) != TYPE_CODE_REF)
+ return NULL;
+
+ if (value_lval_const (arg) != lval_computed)
+ return NULL;
+
+ funcs = value_computed_funcs (arg);
+ if (funcs->coerce_ref == NULL)
+ return NULL;
+
+ return funcs->coerce_ref (arg);
+}
+
+struct value *
coerce_ref (struct value *arg)
{
struct type *value_type_arg_tmp = check_typedef (value_type (arg));
+ struct value *retval;
- if (TYPE_CODE (value_type_arg_tmp) == TYPE_CODE_REF)
- arg = value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
- unpack_pointer (value_type (arg),
- value_contents (arg)));
- return arg;
+ retval = coerce_ref_if_computed (arg);
+ if (retval)
+ return retval;
+
+ if (TYPE_CODE (value_type_arg_tmp) != TYPE_CODE_REF)
+ return arg;
+
+ return value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
+ unpack_pointer (value_type (arg),
+ value_contents (arg)));
}
struct value *
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -180,6 +180,11 @@ struct lval_funcs
will fall back to ordinary indirection. */
struct value *(*indirect) (struct value *value);
+ /* If non-NULL, this is used to implement reference resolving for
+ this value. This method may return NULL, in which case coerce_ref
+ will fall back to ordinary references resolving. */
+ struct value *(*coerce_ref) (const struct value *value);
+
/* If non-NULL, this is used to determine whether the indicated bits
of VALUE are a synthetic pointer. */
int (*check_synthetic_pointer) (const struct value *value,
@@ -213,7 +218,7 @@ extern struct value *allocate_optimized_out_value (struct type *type);
/* If VALUE is lval_computed, return its lval_funcs structure. */
-extern const struct lval_funcs *value_computed_funcs (struct value *value);
+extern const struct lval_funcs *value_computed_funcs (const struct value *);
/* If VALUE is lval_computed, return its closure. The meaning of the
returned value depends on the functions VALUE uses. */
@@ -314,6 +319,9 @@ extern void set_value_component_location (struct value *component,
extern enum lval_type *deprecated_value_lval_hack (struct value *);
#define VALUE_LVAL(val) (*deprecated_value_lval_hack (val))
+/* Like VALUE_LVAL, except the parameter can be const. */
+extern enum lval_type value_lval_const (const struct value *value);
+
/* If lval == lval_memory, return the address in the inferior. If
lval == lval_register, return the byte offset into the registers
structure. Otherwise, return 0. The returned address
@@ -340,6 +348,11 @@ extern struct frame_id *deprecated_value_frame_id_hack (struct value *);
extern short *deprecated_value_regnum_hack (struct value *);
#define VALUE_REGNUM(val) (*deprecated_value_regnum_hack (val))
+/* Return value after lval_funcs->coerce_ref (after check_typedef). Return
+ NULL if lval_funcs->coerce_ref is not applicable for whatever reason. */
+
+extern struct value *coerce_ref_if_computed (const struct value *arg);
+
/* Convert a REF to the object referenced. */
extern struct value *coerce_ref (struct value *value);
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [patch 11/12] entryval#2: @entry values even for references
2011-09-16 19:15 ` Jan Kratochvil
@ 2011-09-21 15:54 ` Pedro Alves
2011-09-22 22:49 ` Jan Kratochvil
0 siblings, 1 reply; 11+ messages in thread
From: Pedro Alves @ 2011-09-21 15:54 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On Friday 16 September 2011 19:24:34, Jan Kratochvil wrote:
> On Fri, 16 Sep 2011 14:26:09 +0200, Pedro Alves wrote:
> > On Tuesday 13 September 2011 20:50:47, Jan Kratochvil wrote:
> > > + struct value *deref_val;
> > > +
> > > + deref_val = coerce_ref_if_computed (original_value);
> >
> > Hmm, this doesn't look right. It ignores embedded_offset. What if the reference
> > we're currently printing is a field of a struct at offset != 0?
> > E.g., `struct { long l; long &r } foo;', and we're `p foo', which descends
> > into printing R at FOO + offset of R ?
>
> It is not perfect but I do not know about some short way out.
>
> coerce_ref_if_computed currently can have effect only for @entry values
> (only entry_data_value_funcs has coerce_ref != NULL) and in such case the
> first printing code will have embedded_offset == 0 and further printing gets
But not in the example I gave? Or are you saying that there can't be
an entryval whose type is a struct? If that's the case, I'm okay with
the assert for now.
> resolved via common_val_print passed the dereferenced value with
> original_value no longer present anywhere.
>
> If it should work really correctly there are more cases to catch such as
> f77_print_array (*) being passed original_value etc. The correct way would be
> the rework to full struct value * printing
> http://sourceware.org/ml/gdb-patches/2010-10/msg00127.html
> but I did not want to get deeper in the patchset dependencies.
I'm not sure that'd be necessary. (the first 2 steps are
complete, btw). That would change the running-offset scheme,
allowing value contents to be even more lazy, but that does not
mean the current scheme doesn't work.
E.g, if entryval's lval_funcs->coerce_ref took an embedded_offset,
and returned the target value with value_offset adjusted you'd be
almost there? The problem is that you share/refcount the target
value, so we'd either need to unshare it so we could have copies with
different offsets set, or we'd add a new lval_computed type that serves
as view with offset into a current value, as I proposed in that URL,
but without changing everything else in valprint.
> (*) Fortran support is planned for entry_values, it was even AFAIK one of the
> reasons for DW_AT_GNU_call_site_data_value at all, it waits now on
> gcc PR debug/49981 but that can be incremental GDB update later.
>
> Is it OK this way?
>
> + deref_val = coerce_ref_if_computed (original_value);
> + if (deref_val != NULL)
> + {
> + /* More complicated computed references are not supported. */
> + gdb_assert (embedded_offset == 0);
> + }
> + else
--
Pedro Alves
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [patch 11/12] entryval#2: @entry values even for references
2011-09-21 15:54 ` Pedro Alves
@ 2011-09-22 22:49 ` Jan Kratochvil
2011-09-23 6:02 ` Pedro Alves
0 siblings, 1 reply; 11+ messages in thread
From: Jan Kratochvil @ 2011-09-22 22:49 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
On Wed, 21 Sep 2011 17:32:44 +0200, Pedro Alves wrote:
> But not in the example I gave? Or are you saying that there can't be
> an entryval whose type is a struct?
Theoretically there can be, just:
(a) GCC currently cannot produce DW_AT_GNU_call_site_data_value (for the
struct content) in such case (it produces only DW_AT_GNU_call_site_value
- for the struct referencing pointer).
(b) Even if I create such DWARF attribute by hand the expression `s@entry.b'
for parameter `S &s' of type `class S { char a, b; };' never reaches this
point of code because:
#0 coerce_ref_if_computed (arg=0x202c8c0) at value.c:3096
#1 in coerce_ref (arg=0x202c8c0) at value.c:3115
#2 in coerce_array (arg=0x202c8c0) at value.c:3132
#3 in value_struct_elt (argp=0x7fffffffd258, args=0x0, name=0x26fccd0 "b", static_memfuncp=0x0, err=0xea593f "structure") at valops.c:2306
#4 in evaluate_subexp_standard (expect_type=0x0, exp=0x26fcc90, pos=0x7fffffffd68c, noside=EVAL_NORMAL) at eval.c:1966
#5 in evaluate_subexp_c (expect_type=0x0, exp=0x26fcc90, pos=0x7fffffffd68c, noside=EVAL_NORMAL) at c-lang.c:720
#6 in evaluate_subexp (expect_type=0x0, exp=0x26fcc90, pos=0x7fffffffd68c, noside=EVAL_NORMAL) at eval.c:76
#7 in evaluate_expression (exp=0x26fcc90) at eval.c:151
#8 in print_command_1 (exp=0x7fffffffde6f "s@entry.b", inspect=0, voidprint=1) at ./printcmd.c:973
So in all the cases like this one c_val_print already gets original_value
which is no longer "magic" in any way, it is already coerce-ref-ed.
(c) Your:
On Fri, 16 Sep 2011 14:26:09 +0200, Pedro Alves wrote:
> E.g., `struct { long l; long &r } foo;', and we're `p foo', which descends
> into printing R at FOO + offset of R ?
also cannot lead much to anything as if the parameter is of
struct s { long l; long &r; };
void f (struct s p) {}
then `print p@entry' just does not get `entry_data_value_funcs' at all
because `p' is not TYPE_CODE_REF. And anyway after any operation with `p'
it gets coerce-ref-ed, it is no longer "magic" and that new code is nop.
> If that's the case, I'm okay with the assert for now.
I think so.
> > If it should work really correctly there are more cases to catch such as
> > f77_print_array (*) being passed original_value etc. The correct way would be
> > the rework to full struct value * printing
> > http://sourceware.org/ml/gdb-patches/2010-10/msg00127.html
> > but I did not want to get deeper in the patchset dependencies.
>
> I'm not sure that'd be necessary.
As I do not see possible how to exploit the current gdb_assert()s I do not see
which parts to fix.
> (the first 2 steps are complete, btw).
I see, great, (2) thanks to val_print_scalar_formatted.
> That would change the running-offset scheme,
> allowing value contents to be even more lazy, but that does not
> mean the current scheme doesn't work.
From the larger picture the current API does not work as `struct value' should
reference all the memory it needs, not just the single contiguous block
value->contents. It breaks archer-jankratochvil-vla where single value uses
discontiguous memory areas. With FSF GDB one can see it on untracked virtual
method table:
class C {
virtual void m();
} c;
void C::m() {}
(gdb) file 8.o
Reading symbols from 8.o...done.
(gdb) set $a=c
(gdb) p $a.m
$1 = {void (C * const)} 0
(gdb) file
No executable file now.
Discard symbol table from `8.o'? (y or n) y
No symbol file now.
(gdb) p $a.m
There is no member named m.
> E.g, if entryval's lval_funcs->coerce_ref took an embedded_offset,
The problem is that if embedded_offset != 0 for entry_data_value_funcs value
it means one cannot derefence it.
It is like a request to coerce_ref `struct { long &r; } foo;' with embedded
offset != 0. It is error, its dereference exceeds its ->contents length.
entry_data_value_funcs value is created with embedded_offset == 0 and any
futher operation has to coerce_ref it first.
> and returned the target value with value_offset adjusted
The target value is at a new/different memory location, I do not see why
embedded_offset should map to value_offset there. The existing
value_at+unpack_pointer code also does not set value_offset.
You are rather suggesting handling pointed_to_offset != 0 remapping during the
coerce_ref but that seems very out of topic here, it is also always 0 for
entry_data_value_funcs.
> you'd be almost there?
Thanks for thinking more about it but I see entry_data_value_funcs as
a special kind of value. Sure it is not perfect as for example entry-value
`int *' will dereference to actual-value (not entry-value) `int'.
> The problem is that you share/refcount the target
> value, so we'd either need to unshare it so we could have copies with
> different offsets set, or we'd add a new lval_computed type that serves
> as view with offset into a current value, as I proposed in that URL,
> but without changing everything else in valprint.
I do not think this comment is relevant presuming offset really should
be == 0.
Thanks for the review,
Jan
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [patch 11/12] entryval#2: @entry values even for references
2011-09-22 22:49 ` Jan Kratochvil
@ 2011-09-23 6:02 ` Pedro Alves
2011-09-23 8:37 ` Jan Kratochvil
0 siblings, 1 reply; 11+ messages in thread
From: Pedro Alves @ 2011-09-23 6:02 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
Just a quick reply, can't reply in full now:
On Thursday 22 September 2011 22:47:53, Jan Kratochvil wrote:
> (b) Even if I create such DWARF attribute by hand the expression `s@entry.b'
> for parameter `S &s' of type `class S { char a, b; };' never reaches this
> point of code because:
That's not the case that descends into subfields of an object with
embedded_offset != 0. It's when printing the _whole struct_, and
gdb goes and prints a at embedded_offset 0 of s, and then b at
embedded_offset==offsetof(typeof(s), b) of s.
Try "p s@entry" ?
--
Pedro Alves
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [patch 11/12] entryval#2: @entry values even for references
2011-09-23 6:02 ` Pedro Alves
@ 2011-09-23 8:37 ` Jan Kratochvil
2011-09-23 10:27 ` Pedro Alves
0 siblings, 1 reply; 11+ messages in thread
From: Jan Kratochvil @ 2011-09-23 8:37 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
On Fri, 23 Sep 2011 01:42:02 +0200, Pedro Alves wrote:
> Just a quick reply, can't reply in full now:
>
> On Thursday 22 September 2011 22:47:53, Jan Kratochvil wrote:
> > (b) Even if I create such DWARF attribute by hand the expression `s@entry.b'
> > for parameter `S &s' of type `class S { char a, b; };' never reaches this
> > point of code because:
>
> That's not the case that descends into subfields of an object with
> embedded_offset != 0. It's when printing the _whole struct_, and
> gdb goes and prints a at embedded_offset 0 of s, and then b at
> embedded_offset==offsetof(typeof(s), b) of s.
>
> Try "p s@entry" ?
First c_val_print enters with TYPE_CODE_REF, embedded_offset==0 being
lval_computed with entry_data_value_funcs.
coerce_ref_if_computed succeeds, returning deref_val with TYPE_CODE_STRUCT,
embedded_offset==0 being lval_memory at some inferior address.
In this moment common_val_print is called with this new lval_memory value, the
former original_value with lval_computed is forgotten, there is no longer
anything non-standard (anything related to entry_data_value_funcs).
c_val_print cannot use for TYPE_CODE_REF coerce_ref as it has to respect
embedded_offset and the current sub-type etc. This is needed for the case of
foo.r in `struct { long l; long &r } foo;'. But the difference with
entry_data_value_funcs is that such value can never be a part of anything
else, it is always a toplevel value. embedded_offset != 0 for
entry_data_value_funcs would try to take the reference-pointer from some
shifted (and invalid) location. embedded_offset != 0 for
entry_data_value_funcs does not express the offset in the target structure
(pointed_to_offset would express that).
Entry values are not self-contained, they can reference other data which are
no longer in the entry-time state. This is a defect of the design but fixing
that would mean probably excessive and unbound debug info sizes.
Thanks,
Jan
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [patch 11/12] entryval#2: @entry values even for references
2011-09-23 8:37 ` Jan Kratochvil
@ 2011-09-23 10:27 ` Pedro Alves
2011-09-23 12:02 ` Jan Kratochvil
0 siblings, 1 reply; 11+ messages in thread
From: Pedro Alves @ 2011-09-23 10:27 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On Friday 23 September 2011 09:30:32, Jan Kratochvil wrote:
> On Fri, 23 Sep 2011 01:42:02 +0200, Pedro Alves wrote:
> > Just a quick reply, can't reply in full now:
> >
> > On Thursday 22 September 2011 22:47:53, Jan Kratochvil wrote:
> > > (b) Even if I create such DWARF attribute by hand the expression `s@entry.b'
> > > for parameter `S &s' of type `class S { char a, b; };' never reaches this
> > > point of code because:
> >
> > That's not the case that descends into subfields of an object with
> > embedded_offset != 0. It's when printing the _whole struct_, and
> > gdb goes and prints a at embedded_offset 0 of s, and then b at
> > embedded_offset==offsetof(typeof(s), b) of s.
> >
> > Try "p s@entry" ?
>
> First c_val_print enters with TYPE_CODE_REF, embedded_offset==0 being
> lval_computed with entry_data_value_funcs.
Sorry, in the hurry, I hadn't noticed you had used `S &s; class S { char a, b; };'.
That's not the case I raised originally. The case is an entry val of
type `struct { int a; long &b; }'. Calling an entry object of that
type `s', if we "print s@entry", I think we'll:
print A (TYPE_CODE_INT) at embedded_offset 0 of S, and then B
at embedded_offset==offsetof(typeof(s), b) of S (e.g., 8). B will
be TYPE_CODE_REF here, and coerce_ref_if_computed on S will wrongly
operate on the contents of the whole S (because it loses embedded_offset),
instead of working with the B contents of S.
> First c_val_print enters with TYPE_CODE_REF, embedded_offset==0 being
> lval_computed with entry_data_value_funcs.
> coerce_ref_if_computed succeeds, returning deref_val with TYPE_CODE_STRUCT,
> embedded_offset==0 being lval_memory at some inferior address.
--
Pedro Alves
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [patch 11/12] entryval#2: @entry values even for references
2011-09-23 10:27 ` Pedro Alves
@ 2011-09-23 12:02 ` Jan Kratochvil
2011-09-23 12:08 ` Pedro Alves
0 siblings, 1 reply; 11+ messages in thread
From: Jan Kratochvil @ 2011-09-23 12:02 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
On Fri, 23 Sep 2011 11:50:22 +0200, Pedro Alves wrote:
> Sorry, in the hurry, I hadn't noticed you had used `S &s; class S { char a, b; };'.
> That's not the case I raised originally. The case is an entry val of
> type `struct { int a; long &b; }'. Calling an entry object of that
> type `s', if we "print s@entry", I think we'll:
In such case the parameter `s' is not TYPE_CODE_REF and therefore
entry_data_value_funcs do not get ever used and therefore
coerce_ref_if_computed will always return NULL.
coerce_ref_if_computed is there only as a hack for TYPE_CODE_REF which
dereferences into something else than what a native normal such
TYPE_CODE_REF-pointer would derefefence into.
I had a former version of the patch which did not use coerce_ref_if_computed
and if it has seen TYPE_CODE_REF with both DW_AT_GNU_call_site_value (=the
pointer) and DW_AT_GNU_call_site_data_value (=the dereferenced data) then it
created non-lazy lval_memory object of TYPE_TARGET_TYPE type with
value_address set to that reference-pointer. But such case was (a) confusing
because `ptype param' and `ptype param@entry' could be different and (b)
dangerous as param@entry was modifiable due to its lval_memory (it is not_lval
now).
> print A (TYPE_CODE_INT) at embedded_offset 0 of S, and then B
> at embedded_offset==offsetof(typeof(s), b) of S (e.g., 8). B will
> be TYPE_CODE_REF here, and coerce_ref_if_computed on S will wrongly
coerce_ref_if_computed will be NULL as there is no coerce_ref_if_computed
anywhere present.
> operate on the contents of the whole S (because it loses embedded_offset),
> instead of working with the B contents of S.
Thanks,
Jan
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [patch 11/12] entryval#2: @entry values even for references
2011-09-23 12:02 ` Jan Kratochvil
@ 2011-09-23 12:08 ` Pedro Alves
2011-09-23 15:04 ` Jan Kratochvil
0 siblings, 1 reply; 11+ messages in thread
From: Pedro Alves @ 2011-09-23 12:08 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On Friday 23 September 2011 12:39:41, Jan Kratochvil wrote:
> On Fri, 23 Sep 2011 11:50:22 +0200, Pedro Alves wrote:
> > Sorry, in the hurry, I hadn't noticed you had used `S &s; class S { char a, b; };'.
> > That's not the case I raised originally. The case is an entry val of
> > type `struct { int a; long &b; }'. Calling an entry object of that
> > type `s', if we "print s@entry", I think we'll:
>
> In such case the parameter `s' is not TYPE_CODE_REF and therefore
> entry_data_value_funcs do not get ever used and therefore
> coerce_ref_if_computed will always return NULL.
>
> coerce_ref_if_computed is there only as a hack for TYPE_CODE_REF which
> dereferences into something else than what a native normal such
> TYPE_CODE_REF-pointer would derefefence into.
I see, thanks. Okay, let's go with this, with the
embedded_offset == 0 assertion in place.
I really dislike lval_computed special casing. We should be
aiming at making it generic enough to be able to reimplement the
regular lval_memory/lval_register, etc. lval types as lval_computed,
hence my insistence.
--
Pedro Alves
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [patch 11/12] entryval#2: @entry values even for references
2011-09-23 12:08 ` Pedro Alves
@ 2011-09-23 15:04 ` Jan Kratochvil
0 siblings, 0 replies; 11+ messages in thread
From: Jan Kratochvil @ 2011-09-23 15:04 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
On Fri, 23 Sep 2011 14:02:33 +0200, Pedro Alves wrote:
> I see, thanks. Okay, let's go with this, with the
> embedded_offset == 0 assertion in place.
OK, thanks.
> I really dislike lval_computed special casing. We should be
> aiming at making it generic enough to be able to reimplement the
> regular lval_memory/lval_register, etc. lval types as lval_computed,
> hence my insistence.
I agree, I just found this hack acceptable enough instead of making it
dependent on another cleanup patch(set).
Jan
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2011-09-23 12:08 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-13 19:52 [patch 11/12] entryval#2: @entry values even for references Jan Kratochvil
2011-09-16 12:29 ` Pedro Alves
2011-09-16 19:15 ` Jan Kratochvil
2011-09-21 15:54 ` Pedro Alves
2011-09-22 22:49 ` Jan Kratochvil
2011-09-23 6:02 ` Pedro Alves
2011-09-23 8:37 ` Jan Kratochvil
2011-09-23 10:27 ` Pedro Alves
2011-09-23 12:02 ` Jan Kratochvil
2011-09-23 12:08 ` Pedro Alves
2011-09-23 15:04 ` Jan Kratochvil
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox