Big-endian targets: Don't ignore offset into DW_OP_stack_value

Recently I fixed a bug that caused a DW_OP_implicit_pointer with non-zero
offset into a DW_OP_implicit_value to be handled incorrectly on big-endian
targets.  GDB ignored the offset and copied the wrong bytes:

  https://sourceware.org/ml/gdb-patches/2017-01/msg00251.html

But there is still a similar issue when a DW_OP_implicit_pointer points
into a DW_OP_stack_value instead; and again, the offset is ignored.  There
is an important difference, though: While implicit values are treated like
blocks of data and anchored at the lowest-addressed byte, stack values
traditionally contain integer numbers and are anchored at the *least
significant* byte.  Also, stack values do not come in varying sizes, but
are cut down appropriately when used.  Thus, on big-endian targets the
scenario looks like this (higher addresses shown right):

  |<- - - - - Stack value - - - - - - ->|
                  |                     |
                  |<- original object ->|
                  |
                  | offset ->|####|
			      ^^^^
                              de-referenced
			      implicit pointer

(Note how the original object's size influences the position of the
de-referenced implicit pointer within the stack value.  This is not the
case for little-endian targets, where the original object starts at offset
zero within the stack value.)

This patch implements the logic indicated in the above diagram and adds an
appropriate test case.  A new function dwarf2_fetch_die_type_sect_off is
added; it is used for retrieving the original object's type, so its size
can be determined.  That type is passed to dwarf2_evaluate_loc_desc_full
via a new parameter.

gdb/ChangeLog:

	* dwarf2loc.c (indirect_synthetic_pointer): Get data type of
	pointed-to DIE and pass it to dwarf2_evaluate_loc_desc_full.
	(dwarf2_evaluate_loc_desc_full): New parameter subobj_type; rename
	byte_offset to subobj_byte_offset.  Fix the handling of
	DWARF_VALUE_STACK on big-endian targets when coming via an
	implicit pointer.
	(dwarf2_evaluate_loc_desc): Adjust call to
	dwarf2_evaluate_loc_desc_full.
	* dwarf2loc.h (dwarf2_fetch_die_type_sect_off): New declaration.
	* dwarf2read.c (dwarf2_fetch_die_type_sect_off): New function.

gdb/testsuite/ChangeLog:

	* lib/dwarf.exp: Add support for DW_OP_implicit_pointer.
	* gdb.dwarf2/nonvar-access.exp: Add test for stack value location
	and implicit pointer into such a location.
This commit is contained in:
Andreas Arnez
2017-03-16 19:50:24 +01:00
parent 6ebac3fbac
commit 7942e96e43
7 changed files with 131 additions and 46 deletions

View File

@ -50,7 +50,8 @@ static struct value *dwarf2_evaluate_loc_desc_full (struct type *type,
const gdb_byte *data,
size_t size,
struct dwarf2_per_cu_data *per_cu,
LONGEST byte_offset);
struct type *subobj_type,
LONGEST subobj_byte_offset);
static struct call_site_parameter *dwarf_expr_reg_to_entry_parameter
(struct frame_info *frame,
@ -2163,12 +2164,18 @@ indirect_synthetic_pointer (sect_offset die, LONGEST byte_offset,
= dwarf2_fetch_die_loc_sect_off (die, per_cu,
get_frame_address_in_block_wrapper, frame);
/* Get type of pointed-to DIE. */
struct type *orig_type = dwarf2_fetch_die_type_sect_off (die, per_cu);
if (orig_type == NULL)
invalid_synthetic_pointer ();
/* If pointed-to DIE has a DW_AT_location, evaluate it and return the
resulting value. Otherwise, it may have a DW_AT_const_value instead,
or it may've been optimized out. */
if (baton.data != NULL)
return dwarf2_evaluate_loc_desc_full (TYPE_TARGET_TYPE (type), frame,
baton.data, baton.size, baton.per_cu,
return dwarf2_evaluate_loc_desc_full (orig_type, frame, baton.data,
baton.size, baton.per_cu,
TYPE_TARGET_TYPE (type),
byte_offset);
else
return fetch_const_value_from_synthetic_pointer (die, byte_offset, per_cu,
@ -2327,23 +2334,30 @@ static const struct lval_funcs pieced_value_funcs = {
/* Evaluate a location description, starting at DATA and with length
SIZE, to find the current location of variable of TYPE in the
context of FRAME. BYTE_OFFSET is applied after the contents are
computed. */
context of FRAME. If SUBOBJ_TYPE is non-NULL, return instead the
location of the subobject of type SUBOBJ_TYPE at byte offset
SUBOBJ_BYTE_OFFSET within the variable of type TYPE. */
static struct value *
dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
const gdb_byte *data, size_t size,
struct dwarf2_per_cu_data *per_cu,
LONGEST byte_offset)
struct type *subobj_type,
LONGEST subobj_byte_offset)
{
struct value *retval;
struct objfile *objfile = dwarf2_per_cu_objfile (per_cu);
if (byte_offset < 0)
if (subobj_type == NULL)
{
subobj_type = type;
subobj_byte_offset = 0;
}
else if (subobj_byte_offset < 0)
invalid_synthetic_pointer ();
if (size == 0)
return allocate_optimized_out_value (type);
return allocate_optimized_out_value (subobj_type);
dwarf_evaluate_loc_desc ctx;
ctx.frame = frame;
@ -2366,8 +2380,9 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
if (ex.error == NOT_AVAILABLE_ERROR)
{
free_values.free_to_mark ();
retval = allocate_value (type);
mark_value_bytes_unavailable (retval, 0, TYPE_LENGTH (type));
retval = allocate_value (subobj_type);
mark_value_bytes_unavailable (retval, 0,
TYPE_LENGTH (subobj_type));
return retval;
}
else if (ex.error == NO_ENTRY_VALUE_ERROR)
@ -2375,7 +2390,7 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
if (entry_values_debug)
exception_print (gdb_stdout, ex);
free_values.free_to_mark ();
return allocate_optimized_out_value (type);
return allocate_optimized_out_value (subobj_type);
}
else
throw_exception (ex);
@ -2390,7 +2405,7 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
for (i = 0; i < ctx.num_pieces; ++i)
bit_size += ctx.pieces[i].size;
if (8 * (byte_offset + TYPE_LENGTH (type)) > bit_size)
if (8 * (subobj_byte_offset + TYPE_LENGTH (subobj_type)) > bit_size)
invalid_synthetic_pointer ();
c = allocate_piece_closure (per_cu, ctx.num_pieces, ctx.pieces,
@ -2398,8 +2413,9 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
/* We must clean up the value chain after creating the piece
closure but before allocating the result. */
free_values.free_to_mark ();
retval = allocate_computed_value (type, &pieced_value_funcs, c);
set_value_offset (retval, byte_offset);
retval = allocate_computed_value (subobj_type,
&pieced_value_funcs, c);
set_value_offset (retval, subobj_byte_offset);
}
else
{
@ -2412,10 +2428,10 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
= longest_to_int (value_as_long (ctx.fetch (0)));
int gdb_regnum = dwarf_reg_to_regnum_or_error (arch, dwarf_regnum);
if (byte_offset != 0)
if (subobj_byte_offset != 0)
error (_("cannot use offset on synthetic pointer to register"));
free_values.free_to_mark ();
retval = value_from_register (type, gdb_regnum, frame);
retval = value_from_register (subobj_type, gdb_regnum, frame);
if (value_optimized_out (retval))
{
struct value *tmp;
@ -2426,8 +2442,9 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
inspecting a register ($pc, $sp, etc.), return a
generic optimized out value instead, so that we show
<optimized out> instead of <not saved>. */
tmp = allocate_value (type);
value_contents_copy (tmp, 0, retval, 0, TYPE_LENGTH (type));
tmp = allocate_value (subobj_type);
value_contents_copy (tmp, 0, retval, 0,
TYPE_LENGTH (subobj_type));
retval = tmp;
}
}
@ -2447,7 +2464,7 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
the operation. Therefore, we do the conversion here
since the type is readily available. */
switch (TYPE_CODE (type))
switch (TYPE_CODE (subobj_type))
{
case TYPE_CODE_FUNC:
case TYPE_CODE_METHOD:
@ -2460,7 +2477,8 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
address = value_as_address (value_from_pointer (ptr_type, address));
free_values.free_to_mark ();
retval = value_at_lazy (type, address + byte_offset);
retval = value_at_lazy (subobj_type,
address + subobj_byte_offset);
if (in_stack_memory)
set_value_stack (retval, 1);
}
@ -2469,18 +2487,15 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
case DWARF_VALUE_STACK:
{
struct value *value = ctx.fetch (0);
gdb_byte *contents;
const gdb_byte *val_bytes;
size_t n = TYPE_LENGTH (value_type (value));
size_t len = TYPE_LENGTH (subobj_type);
size_t max = TYPE_LENGTH (type);
struct gdbarch *objfile_gdbarch = get_objfile_arch (objfile);
struct cleanup *cleanup;
if (byte_offset + TYPE_LENGTH (type) > n)
if (subobj_byte_offset + len > max)
invalid_synthetic_pointer ();
val_bytes = value_contents_all (value);
val_bytes += byte_offset;
n -= byte_offset;
/* Preserve VALUE because we are going to free values back
to the mark, but we still need the value contents
below. */
@ -2488,17 +2503,14 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
free_values.free_to_mark ();
cleanup = make_cleanup_value_free (value);
retval = allocate_value (type);
contents = value_contents_raw (retval);
if (n > TYPE_LENGTH (type))
{
struct gdbarch *objfile_gdbarch = get_objfile_arch (objfile);
retval = allocate_value (subobj_type);
if (gdbarch_byte_order (objfile_gdbarch) == BFD_ENDIAN_BIG)
val_bytes += n - TYPE_LENGTH (type);
n = TYPE_LENGTH (type);
}
memcpy (contents, val_bytes, n);
/* The given offset is relative to the actual object. */
if (gdbarch_byte_order (objfile_gdbarch) == BFD_ENDIAN_BIG)
subobj_byte_offset += n - max;
memcpy (value_contents_raw (retval),
value_contents_all (value) + subobj_byte_offset, len);
do_cleanups (cleanup);
}
@ -2507,21 +2519,21 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
case DWARF_VALUE_LITERAL:
{
bfd_byte *contents;
size_t n = TYPE_LENGTH (type);
size_t n = TYPE_LENGTH (subobj_type);
if (byte_offset + n > ctx.len)
if (subobj_byte_offset + n > ctx.len)
invalid_synthetic_pointer ();
free_values.free_to_mark ();
retval = allocate_value (type);
retval = allocate_value (subobj_type);
contents = value_contents_raw (retval);
memcpy (contents, ctx.data + byte_offset, n);
memcpy (contents, ctx.data + subobj_byte_offset, n);
}
break;
case DWARF_VALUE_OPTIMIZED_OUT:
free_values.free_to_mark ();
retval = allocate_optimized_out_value (type);
retval = allocate_optimized_out_value (subobj_type);
break;
/* DWARF_VALUE_IMPLICIT_POINTER was converted to a pieced
@ -2547,7 +2559,8 @@ dwarf2_evaluate_loc_desc (struct type *type, struct frame_info *frame,
const gdb_byte *data, size_t size,
struct dwarf2_per_cu_data *per_cu)
{
return dwarf2_evaluate_loc_desc_full (type, frame, data, size, per_cu, 0);
return dwarf2_evaluate_loc_desc_full (type, frame, data, size, per_cu,
NULL, 0);
}
/* Evaluates a dwarf expression and stores the result in VAL, expecting