mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2025-02-22 02:21:19 +00:00
gdb/
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/ 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.
This commit is contained in:
parent
36b11add17
commit
a471c5941e
@ -1,3 +1,45 @@
|
||||
2011-10-09 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.
|
||||
|
||||
2011-10-09 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
Support @entry in input expressions.
|
||||
|
@ -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 =
|
||||
|
@ -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);
|
||||
|
@ -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. */
|
||||
|
||||
@ -1304,12 +1361,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:
|
||||
@ -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"));
|
||||
|
@ -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);
|
||||
|
||||
|
145
gdb/dwarf2loc.c
145
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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
46
gdb/stack.c
46
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,21 @@
|
||||
2011-10-09 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.
|
||||
|
||||
2011-10-09 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
Support @entry in input expressions.
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
44
gdb/value.c
44
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 *
|
||||
|
15
gdb/value.h
15
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user