From a471c5941e127823b95893176c7c9301c4b4cb32 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Sun, 9 Oct 2011 19:43:41 +0000 Subject: [PATCH] gdb/ Display @entry parameter values even for references. * ada-valprint.c (ada_val_print_1) : Try also coerce_ref_if_computed. * c-valprint.c (c_val_print) : Likewise. * dwarf2expr.c (dwarf_block_to_dwarf_reg_deref): New function. (execute_stack_op) : 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) : 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) : Try also coerce_ref_if_computed. * opencl-lang.c (opencl_value_funcs): NULL value for coerce_ref. * p-valprint.c (pascal_val_print) : 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/ 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. --- gdb/ChangeLog | 42 ++++++ gdb/ada-valprint.c | 13 +- gdb/c-valprint.c | 17 ++- gdb/dwarf2expr.c | 79 +++++++++- gdb/dwarf2expr.h | 13 +- gdb/dwarf2loc.c | 145 +++++++++++++++++-- gdb/f-valprint.c | 17 ++- gdb/opencl-lang.c | 3 +- gdb/p-valprint.c | 17 ++- gdb/stack.c | 46 +++++- gdb/testsuite/ChangeLog | 18 +++ gdb/testsuite/gdb.arch/amd64-entry-value.cc | 40 +++++ gdb/testsuite/gdb.arch/amd64-entry-value.exp | 34 +++++ gdb/value.c | 44 +++++- gdb/value.h | 15 +- 15 files changed, 496 insertions(+), 47 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 5d1339e3d8..e7cb9982a0 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,45 @@ +2011-10-09 Jan Kratochvil + + Display @entry parameter values even for references. + * ada-valprint.c (ada_val_print_1) : Try also + coerce_ref_if_computed. + * c-valprint.c (c_val_print) : Likewise. + * dwarf2expr.c (dwarf_block_to_dwarf_reg_deref): New function. + (execute_stack_op) : 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) : 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) : Try also + coerce_ref_if_computed. + * opencl-lang.c (opencl_value_funcs): NULL value for coerce_ref. + * p-valprint.c (pascal_val_print) : 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. + 2011-10-09 Jan Kratochvil Support @entry in input expressions. diff --git a/gdb/ada-valprint.c b/gdb/ada-valprint.c index 7b9e3ee870..8a72b9e35c 100644 --- 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 = diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c index 76579d2116..3461b08b92 100644 --- 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); diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c index 4fccc262ec..71aff6ad33 100644 --- 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 = 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 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: @@ -1460,7 +1532,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")); diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h index c014ce20ab..a319ca3281 100644 --- 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. */ @@ -277,10 +279,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); diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index a44d3d2788..0e1179c00f 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -910,7 +910,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. @@ -920,33 +922,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; @@ -964,8 +977,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; @@ -987,6 +1005,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 @@ -999,15 +1073,53 @@ 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 @@ -1799,6 +1911,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 @@ -2118,7 +2231,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; diff --git a/gdb/f-valprint.c b/gdb/f-valprint.c index 66b425d78c..b800d89d4b 100644 --- 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); diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c index 79ad5f6590..05955b4136 100644 --- 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 diff --git a/gdb/p-valprint.c b/gdb/p-valprint.c index d2efa5b3d2..e55b12269a 100644 --- 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); diff --git a/gdb/stack.c b/gdb/stack.c index 397b345dd2..b01dc1c9fa 100644 --- 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; } } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index e3df529a84..1a7b5da892 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,21 @@ +2011-10-09 Jan Kratochvil + + 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. + 2011-10-09 Jan Kratochvil Support @entry in input expressions. diff --git a/gdb/testsuite/gdb.arch/amd64-entry-value.cc b/gdb/testsuite/gdb.arch/amd64-entry-value.cc index 7b7d050e00..2202e28b25 100644 --- 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 diff --git a/gdb/testsuite/gdb.arch/amd64-entry-value.exp b/gdb/testsuite/gdb.arch/amd64-entry-value.exp index 10a82ab682..185249c448 100644 --- 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=\).*} "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" diff --git a/gdb/value.c b/gdb/value.c index 087cdfd5c2..e72670b6a2 100644 --- 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) { @@ -3082,16 +3088,40 @@ value_from_history_ref (char *h, char **endp) return access_value_history (index); } +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 * diff --git a/gdb/value.h b/gdb/value.h index 83c94fcab7..dc2ac13ab1 100644 --- 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); -- 2.34.1