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

@ -1,3 +1,16 @@
2017-03-16 Andreas Arnez <arnez@linux.vnet.ibm.com>
* 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.
2017-03-16 Yao Qi <yao.qi@linaro.org> 2017-03-16 Yao Qi <yao.qi@linaro.org>
* arm-tdep.c (thumb_record_misc): Decode CBNZ, CBZ, REV16, * arm-tdep.c (thumb_record_misc): Decode CBNZ, CBZ, REV16,

View File

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

View File

@ -79,6 +79,9 @@ extern const gdb_byte *dwarf2_fetch_constant_bytes (sect_offset,
struct obstack *, struct obstack *,
LONGEST *); LONGEST *);
struct type *dwarf2_fetch_die_type_sect_off (sect_offset,
struct dwarf2_per_cu_data *);
struct type *dwarf2_get_die_type (cu_offset die_offset, struct type *dwarf2_get_die_type (cu_offset die_offset,
struct dwarf2_per_cu_data *per_cu); struct dwarf2_per_cu_data *per_cu);

View File

@ -20775,6 +20775,31 @@ dwarf2_fetch_constant_bytes (sect_offset offset,
return result; return result;
} }
/* Return the type of the die at OFFSET in PER_CU. Return NULL if no
valid type for this die is found. */
struct type *
dwarf2_fetch_die_type_sect_off (sect_offset offset,
struct dwarf2_per_cu_data *per_cu)
{
struct dwarf2_cu *cu;
struct die_info *die;
dw2_setup (per_cu->objfile);
if (per_cu->cu == NULL)
load_cu (per_cu);
cu = per_cu->cu;
if (!cu)
return NULL;
die = follow_die_offset (offset, per_cu->is_dwz, &cu);
if (!die)
return NULL;
return die_type (die, cu);
}
/* Return the type of the DIE at DIE_OFFSET in the CU named by /* Return the type of the DIE at DIE_OFFSET in the CU named by
PER_CU. */ PER_CU. */

View File

@ -1,3 +1,9 @@
2017-03-16 Andreas Arnez <arnez@linux.vnet.ibm.com>
* 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.
2017-03-16 Doug Evans <dje@google.com> 2017-03-16 Doug Evans <dje@google.com>
* gdb.python/py-lazy-string (pointer): Really add new typedef. * gdb.python/py-lazy-string (pointer): Really add new typedef.

View File

@ -33,7 +33,7 @@ Dwarf::assemble $asm_file {
} { } {
declare_labels int_type_label char_type_label \ declare_labels int_type_label char_type_label \
struct_s_label struct_t_label array_a9_label \ struct_s_label struct_t_label array_a9_label \
char_ptr_label implicit_a_label char_ptr_label implicit_a_label stack_b_label
int_type_label: base_type { int_type_label: base_type {
{name "int"} {name "int"}
@ -159,7 +159,24 @@ Dwarf::assemble $asm_file {
{name implicit_a_ptr} {name implicit_a_ptr}
{type :$char_ptr_label} {type :$char_ptr_label}
{location { {location {
GNU_implicit_pointer $implicit_a_label 5 implicit_pointer $implicit_a_label 5
} SPECIAL_expr}
}
# Stack-value location.
stack_b_label: DW_TAG_variable {
{name def_stack_b}
{type :$struct_t_label}
{location {
const4u 0x1a2b3c4d
stack_value
} SPECIAL_expr}
}
# Implicit pointer into stack value.
DW_TAG_variable {
{name implicit_b_ptr}
{type :$char_ptr_label}
{location {
implicit_pointer $stack_b_label 1
} SPECIAL_expr} } SPECIAL_expr}
} }
} }
@ -194,6 +211,13 @@ gdb_test "print/x def_implicit_a" \
gdb_test "print/x def_implicit_a\[5\]" " = 0x56" gdb_test "print/x def_implicit_a\[5\]" " = 0x56"
gdb_test "print/x *(char (*)\[5\]) implicit_a_ptr" \ gdb_test "print/x *(char (*)\[5\]) implicit_a_ptr" \
" = \\{0x56, 0x67, 0x78, 0x89, 0x9a\\}" " = \\{0x56, 0x67, 0x78, 0x89, 0x9a\\}"
switch $endian {
big {set val "a = 52, b = 2833485"}
little {set val "a = 77, b = 857502"}
}
gdb_test "print def_stack_b" " = \\{$val\\}"
switch $endian {big {set val 0x2b} little {set val 0x3c}}
gdb_test "print/x *implicit_b_ptr" " = $val"
# Byte-aligned fields, pieced together from DWARF stack values. # Byte-aligned fields, pieced together from DWARF stack values.
gdb_test "print def_s" " = \\{a = 0, b = -1\\}" gdb_test "print def_s" " = \\{a = 0, b = -1\\}"

View File

@ -946,9 +946,10 @@ namespace eval Dwarf {
define_label $l2 define_label $l2
} }
DW_OP_implicit_pointer -
DW_OP_GNU_implicit_pointer { DW_OP_GNU_implicit_pointer {
if {[llength $line] != 3} { if {[llength $line] != 3} {
error "usage: DW_OP_GNU_implicit_pointer LABEL OFFSET" error "usage: $opcode LABEL OFFSET"
} }
# Here label is a section offset. # Here label is a section offset.