old-cross-binutils/gdb/testsuite/gdb.ada
Joel Brobecker 53ba833325 [Ada] Crash when trying to set value of packed array element
Consider the following declaration:

   type Small is new Integer range 0 .. 2 ** 4 - 1;
   type Simple_Array is array (1 .. 4) of Small;
   pragma Pack (Simple_Array);

   SA : Simple_Array := (1, 2, 3, 4);

Trying to change the value of one of the elements in the packed array
causes the debugger to crash:

    (gdb) set sa(3) := 9
    [1]    4880 segmentation fault  gdb -q foo

The circumstances leading to the crash are as follow:

   . ada_evaluate_subexp creates a value corresponding to "sa(3)".

   . ada_evaluate_subexp then tries to assign 9 to this value, and
     for this calls value_assign (via ada_value_assign).

   . Because the array is packed, the destination value is 3 bits long,
     and as a result, value_assign uses the parent to determine that
     element byte address and offset:

      | if (value_bitsize (toval))
      |   {
      |     struct value *parent = value_parent (toval);
      |
      |     changed_addr = value_address (parent) + value_offset (toval);

The destination value (corresponding to "sa(3)") was incorrectly created
by ada-lang.c:ada_value_primitive_packed_val, because the "parent" was
left as NULL. So, when we try to dereference it to get the parent address,
GDB crashed.

The first part of the fix therefore consists in setting that field.
This required the addition of a new "setter" in value.[hc].  It fixes
the crash, but is still not sufficient for the assignment to actually
work.

The second part of the problem came from the fact that value_assign
seems to expect the "child"'s address to be equal to the parent's address,
with the difference being the offset. Unfortunately, this requirement was
not followed by ada_value_primitive_packed_val, so the second part of
the fix consisted in fixing that.

Still, this was not sufficient, because it caused a regression when
trying to perform an aggregate assignment of a packed array of packed
record.  The key element here is the nesting of packed entities.
Looking at the way ada_value_primitive_packed_val creates the value
of each sub-component, one can see that the value's offset is set
to the offset compared to the start of the parent. This was meant to
match what value_primitive_field does as well.

So, with our array of records, if the record offset was 2, and if
the field we're interested in that record is at offset 1, the record
value's offset would be set to 2, and the field value's offset would
be set to 1. But the address for both values would be left to the
array's address. This is where things start breaking down, because
the value_address function for our field value would return the
address of the array + 1, instead of + 3.

This is what causes the final issue, here, because ada-lang.c's
value_assign_to_component needs to compute the offset of the
subcomponent compared to the top-level aggregate's start address
(the array in our case). And it does so by subtracting the array's
address from the sub-component's address.  When you have two levels
of packed components, and the mid-level component is at an offset of
the top-level component, things didn't work, because the component's
address was miscomputed (the parent's offset is missing).

The fix consists is fixing value_address to match the work done by
value_primitive_field (where we ignore the parent's offset).

gdb/ChangeLog:

        * value.h (set_value_parent): Add declaration.
        * value.c (set_value_parent): New function.
        (value_address): If VALUE->PARENT is not NULL, then use it as
        the base address instead of VALUE->LOCATION.address.
        * ada-lang.c (ada_value_primitive_packed_val): Keep V's address
        the same as OBJ's address.  Adjust V's offset accordingly.
        Set V's parent.

gdb/testsuite/ChangeLog:

        * gdb.ada/set_pckd_arr_elt: New testcase.
2012-03-16 17:55:45 +00:00
..
aliased_array
array_bounds
array_return
array_subscript_addr
arrayidx
arrayparam
arrayptr
atomic_enum
bp_enum_homonym
bp_on_var
bp_range_type
call_pn
catch_ex
char_enum
char_param
complete
cond_lang
dyn_loc
enum_idx_packed
exec_changed
exprs
fixed_cmp
fixed_points
formatted_ref
frame_args
fullname_bp
fun_addr
fun_in_declare
funcall_param
homonym
info_locals_renaming
int_deref
interface
lang_switch
mi_catch_ex
mi_task_arg
mi_task_info
mod_from_name
nested
null_array
null_record
operator_bp
packed_array
packed_tagged
print_chars
ptr_typedef
ptype_field
ptype_tagged_param
rec_return
ref_param
ref_tick_size
same_enum
set_pckd_arr_elt [Ada] Crash when trying to set value of packed array element 2012-03-16 17:55:45 +00:00
small_reg_param
start
str_ref_cmp
sym_print_name
taft_type
tagged
tagged_not_init
task_bp
tasks
tick_last_segv
type_coercion
uninitialized_vars
variant_record_packed_array
watch_arg
whatis_array_val
widewide
aliased_array.exp
array_bounds.exp
array_return.exp
array_subscript_addr.exp
arrayidx.exp
arrayparam.exp
arrayptr.exp
assign_1.exp
atomic_enum.exp
boolean_expr.exp
bp_enum_homonym.exp
bp_on_var.exp
bp_range_type.exp
call_pn.exp
catch_ex.exp
char_enum.exp
char_param.exp
complete.exp
cond_lang.exp
dyn_loc.exp
enum_idx_packed.exp
exec_changed.exp
exprs.exp
fixed_cmp.exp
fixed_points.exp
formatted_ref.exp
frame_args.exp
fullname_bp.exp
fun_addr.exp
fun_in_declare.exp
funcall_param.exp
gnat_ada.gpr
homonym.exp
info_locals_renaming.exp
info_types.c
info_types.exp
int_deref.exp
interface.exp
lang_switch.exp
Makefile.in
mi_catch_ex.exp
mi_task_arg.exp
mi_task_info.exp
mod_from_name.exp
nested.exp
null_array.exp
null_record.exp
operator_bp.exp
packed_array.exp
packed_tagged.exp
print_chars.exp
print_pc.exp
ptr_typedef.exp
ptype_arith_binop.exp
ptype_field.exp
ptype_tagged_param.exp
rec_return.exp
ref_param.exp
ref_tick_size.exp
same_enum.exp
set_pckd_arr_elt.exp [Ada] Crash when trying to set value of packed array element 2012-03-16 17:55:45 +00:00
small_reg_param.exp
start.exp
str_ref_cmp.exp
sym_print_name.exp
taft_type.exp
tagged.exp
tagged_not_init.exp
task_bp.exp
tasks.exp
tick_last_segv.exp
type_coercion.exp
uninitialized_vars.exp
variant_record_packed_array.exp
watch_arg.exp
whatis_array_val.exp
widewide.exp