old-cross-binutils/gdb/testsuite/gdb.ada/set_pckd_arr_elt.exp

44 lines
1.4 KiB
Text
Raw Normal View History

# Copyright 2012-2013 Free Software Foundation, Inc.
[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
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
load_lib "ada.exp"
if { [skip_ada_tests] } { return -1 }
* lib/ada.exp (standard_ada_testfile): New proc. * gdb.ada/aliased_array.exp: Use standard_ada_testfile. * gdb.ada/array_bounds.exp: Use standard_ada_testfile. * gdb.ada/array_return.exp: Use standard_ada_testfile. * gdb.ada/array_subscript_addr.exp: Use standard_ada_testfile. * gdb.ada/arrayidx.exp: Use standard_ada_testfile. * gdb.ada/arrayparam.exp: Use standard_ada_testfile. * gdb.ada/arrayptr.exp: Use standard_ada_testfile. * gdb.ada/atomic_enum.exp: Use standard_ada_testfile. * gdb.ada/bad-task-bp-keyword.exp: Use standard_ada_testfile. * gdb.ada/bp_enum_homonym.exp: Use standard_ada_testfile. * gdb.ada/bp_on_var.exp: Use standard_ada_testfile. * gdb.ada/bp_range_type.exp: Use standard_ada_testfile. * gdb.ada/call_pn.exp: Use standard_ada_testfile. * gdb.ada/catch_ex.exp: Use standard_ada_testfile. * gdb.ada/char_enum.exp: Use standard_ada_testfile. * gdb.ada/char_param.exp: Use standard_ada_testfile. * gdb.ada/complete.exp: Use standard_ada_testfile. * gdb.ada/cond_lang.exp: Use standard_ada_testfile, standard_output_file. * gdb.ada/dyn_loc.exp: Use standard_ada_testfile. * gdb.ada/enum_idx_packed.exp: Use standard_ada_testfile. * gdb.ada/exec_changed.exp: Use standard_ada_testfile, standard_output_file. * gdb.ada/exprs.exp: Use standard_ada_testfile. * gdb.ada/fixed_cmp.exp: Use standard_ada_testfile. * gdb.ada/fixed_points.exp: Use standard_ada_testfile. * gdb.ada/formatted_ref.exp: Use standard_ada_testfile. * gdb.ada/frame_args.exp: Use standard_ada_testfile. * gdb.ada/fullname_bp.exp: Use standard_ada_testfile. * gdb.ada/fun_addr.exp: Use standard_ada_testfile. * gdb.ada/fun_in_declare.exp: Use standard_ada_testfile. * gdb.ada/funcall_param.exp: Use standard_ada_testfile. * gdb.ada/homonym.exp: Use standard_ada_testfile. * gdb.ada/info_locals_renaming.exp: Use standard_ada_testfile. * gdb.ada/int_deref.exp: Use standard_ada_testfile. * gdb.ada/interface.exp: Use standard_ada_testfile. * gdb.ada/lang_switch.exp: Use standard_ada_testfile, standard_output_file * gdb.ada/mi_catch_ex.exp: Use standard_ada_testfile. * gdb.ada/mi_task_arg.exp: Use standard_ada_testfile. * gdb.ada/mi_task_info.exp: Use standard_ada_testfile. * gdb.ada/mod_from_name.exp: Use standard_ada_testfile. * gdb.ada/nested.exp: Use standard_ada_testfile. * gdb.ada/null_array.exp: Use standard_ada_testfile. * gdb.ada/null_record.exp: Use standard_ada_testfile. * gdb.ada/operator_bp.exp: Use standard_ada_testfile. * gdb.ada/packed_array.exp: Use standard_ada_testfile. * gdb.ada/packed_tagged.exp: Use standard_ada_testfile. * gdb.ada/print_chars.exp: Use standard_ada_testfile. * gdb.ada/print_pc.exp: Use standard_ada_testfile. * gdb.ada/ptr_typedef.exp: Use standard_ada_testfile. * gdb.ada/ptype_field.exp: Use standard_ada_testfile. * gdb.ada/ptype_tagged_param.exp: Use standard_ada_testfile. * gdb.ada/rec_return.exp: Use standard_ada_testfile. * gdb.ada/ref_param.exp: Use standard_ada_testfile. * gdb.ada/ref_tick_size.exp: Use standard_ada_testfile. * gdb.ada/same_enum.exp: Use standard_ada_testfile. * gdb.ada/set_pckd_arr_elt.exp: Use standard_ada_testfile. * gdb.ada/small_reg_param.exp: Use standard_ada_testfile. * gdb.ada/start.exp: Use standard_ada_testfile. * gdb.ada/str_ref_cmp.exp: Use standard_ada_testfile. * gdb.ada/sym_print_name.exp: Use standard_ada_testfile. * gdb.ada/taft_type.exp: Use standard_ada_testfile. * gdb.ada/tagged.exp: Use standard_ada_testfile. * gdb.ada/tagged_not_init.exp: Use standard_ada_testfile. * gdb.ada/task_bp.exp: Use standard_ada_testfile. * gdb.ada/tasks.exp: Use standard_ada_testfile. * gdb.ada/tick_last_segv.exp: Use standard_ada_testfile. * gdb.ada/type_coercion.exp: Use standard_ada_testfile. * gdb.ada/uninitialized_vars.exp: Use standard_ada_testfile. * gdb.ada/variant_record_packed_array.exp: Use standard_ada_testfile. * gdb.ada/watch_arg.exp: Use standard_ada_testfile. * gdb.ada/whatis_array_val.exp: Use standard_ada_testfile. * gdb.ada/widewide.exp: Use standard_ada_testfile.
2012-07-26 18:43:02 +00:00
standard_ada_testfile foo
[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
if {[gdb_compile_ada "${srcfile}" "${binfile}" executable {debug}] != ""} {
return -1
}
clean_restart ${testfile}
set bp_location [gdb_get_line_number "STOP" ${testdir}/foo.adb]
runto "foo.adb:$bp_location"
gdb_test "print sa(3) := 9" " = 9"
# To verify that the assignment was made correctly, we use the fact
# that the program passes this very same element as an argument to
# one of the functions. So we insert a breakpoint on that function,
# and verify that the argument value is correct.
gdb_breakpoint "update_small"
gdb_test "continue" \
"Breakpoint .*, pck\\.update_small \\(s=9\\) at .*pck.adb:.*" \
"continue to update_small"