diff options
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 101 | ||||
-rw-r--r-- | gdb/ada-lang.c | 4 | ||||
-rw-r--r-- | gdb/ada-valprint.c | 6 | ||||
-rw-r--r-- | gdb/c-valprint.c | 6 | ||||
-rw-r--r-- | gdb/cp-valprint.c | 11 | ||||
-rw-r--r-- | gdb/d-valprint.c | 5 | ||||
-rw-r--r-- | gdb/dwarf2loc.c | 81 | ||||
-rw-r--r-- | gdb/findvar.c | 8 | ||||
-rw-r--r-- | gdb/frame-unwind.c | 2 | ||||
-rw-r--r-- | gdb/jv-valprint.c | 13 | ||||
-rw-r--r-- | gdb/mips-tdep.c | 6 | ||||
-rw-r--r-- | gdb/opencl-lang.c | 54 | ||||
-rw-r--r-- | gdb/p-valprint.c | 5 | ||||
-rw-r--r-- | gdb/stack.c | 17 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp | 30 | ||||
-rw-r--r-- | gdb/valprint.c | 22 | ||||
-rw-r--r-- | gdb/value.c | 467 | ||||
-rw-r--r-- | gdb/value.h | 158 |
19 files changed, 554 insertions, 450 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 6704916..cc71db5 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,104 @@ +2014-08-19 Andrew Burgess <aburgess@broadcom.com> + Pedro Alves <palves@redhat.com> + + PR symtab/14604 + PR symtab/14605 + * ada-lang.c (coerce_unspec_val_to_type): Use + value_contents_copy_raw. + * ada-valprint.c (val_print_packed_array_elements): Adjust. + * c-valprint.c (c_val_print): Use value_bits_any_optimized_out. + * cp-valprint.c (cp_print_value_fields): Let the common printing + code handle optimized out values. + (cp_print_value_fields_rtti): Use value_bits_any_optimized_out. + * d-valprint.c (dynamic_array_type): Use + value_bits_any_optimized_out. + * dwarf2loc.c (entry_data_value_funcs): Remove check_validity and + check_any_valid fields. + (check_pieced_value_bits): Delete and inline ... + (check_pieced_synthetic_pointer): ... here. + (check_pieced_value_validity): Delete. + (check_pieced_value_invalid): Delete. + (pieced_value_funcs): Remove check_validity and check_any_valid + fields. + (read_pieced_value): Use mark_value_bits_optimized_out. + (write_pieced_value): Switch to use + mark_value_bytes_optimized_out. + (dwarf2_evaluate_loc_desc_full): Copy the value contents instead + of assuming the whole value is optimized out. + * findvar.c (read_frame_register_value): Remove special handling + of optimized out registers. + (value_from_register): Use mark_value_bytes_optimized_out. + * frame-unwind.c (frame_unwind_got_optimized): Use + mark_value_bytes_optimized_out. + * jv-valprint.c (java_value_print): Adjust. + (java_print_value_fields): Let the common printing code handle + optimized out values. + * mips-tdep.c (mips_print_register): Remove special handling of + optimized out registers. + * opencl-lang.c (lval_func_check_validity): Delete. + (lval_func_check_any_valid): Delete. + (opencl_value_funcs): Remove check_validity and check_any_valid + fields. + * p-valprint.c (pascal_object_print_value_fields): Let the common + printing code handle optimized out values. + * stack.c (read_frame_arg): Remove special handling of optimized + out values. Fetch both VAL and ENTRYVAL before comparing + contents. Adjust to value_available_contents_eq rename. + * valprint.c (valprint_check_validity) + (val_print_scalar_formatted): Use value_bits_any_optimized_out. + (val_print_array_elements): Adjust. + * value.c (struct value) <optimized_out>: Now a VEC(range_s). + (value_bits_any_optimized_out): New function. + (value_entirely_covered_by_range_vector): New function, factored + out from value_entirely_unavailable. + (value_entirely_unavailable): Reimplement. + (value_entirely_optimized_out): New function. + (insert_into_bit_range_vector): New function, factored out from + mark_value_bits_unavailable. + (mark_value_bits_unavailable): Reimplement. + (struct ranges_and_idx): New struct. + (find_first_range_overlap_and_match): New function, factored out + from value_available_contents_bits_eq. + (value_available_contents_bits_eq): Rename to ... + (value_contents_bits_eq): ... this. Check both unavailable + contents and optimized out contents. + (value_available_contents_eq): Rename to ... + (value_contents_eq): ... this. + (allocate_value_lazy): Remove reference to the old optimized_out + boolean. + (allocate_optimized_out_value): Use + mark_value_bytes_optimized_out. + (require_not_optimized_out): Adjust to check whether the + optimized_out vec is empty. + (ranges_copy_adjusted): New function, factored out from + value_contents_copy_raw. + (value_contents_copy_raw): Also copy the optimized out ranges. + Assert the destination ranges aren't optimized out. + (value_contents_copy): Update comment, remove call to + require_not_optimized_out. + (value_contents_equal): Adjust to check whether the optimized_out + vec is empty. + (set_value_optimized_out, value_optimized_out_const): Delete. + (mark_value_bytes_optimized_out, mark_value_bits_optimized_out): + New functions. + (value_entirely_optimized_out, value_bits_valid): Delete. + (value_copy): Take a VEC copy of the 'optimized_out' field. + (value_primitive_field): Remove special handling of optimized out. + (value_fetch_lazy): Assert that lazy values have no unavailable + regions. Use value_bits_any_optimized_out. Remove some special + handling for optimized out values. + * value.h: Add intro comment about <optimized out> and + <unavailable>. + (struct lval_funcs): Remove check_validity and check_any_valid + fields. + (set_value_optimized_out, value_optimized_out_const): Remove. + (mark_value_bytes_optimized_out, mark_value_bits_optimized_out): + New declarations. + (value_bits_any_optimized_out): New declaration. + (value_bits_valid): Delete declaration. + (value_available_contents_eq): Rename to ... + (value_contents_eq): ... this, and extend comments. + 2014-08-19 Jan Kratochvil <jan.kratochvil@redhat.com> Fix -fsanitize=address on unreadable inferior strings. diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index c4e85d2..28999c7 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -679,14 +679,12 @@ coerce_unspec_val_to_type (struct value *val, struct type *type) else { result = allocate_value (type); - memcpy (value_contents_raw (result), value_contents (val), - TYPE_LENGTH (type)); + value_contents_copy_raw (result, 0, val, 0, TYPE_LENGTH (type)); } set_value_component_location (result, val); set_value_bitsize (result, value_bitsize (val)); set_value_bitpos (result, value_bitpos (val)); set_value_address (result, value_address (val)); - set_value_optimized_out (result, value_optimized_out_const (val)); return result; } } diff --git a/gdb/ada-valprint.c b/gdb/ada-valprint.c index ed1eac4..ae07cc21 100644 --- a/gdb/ada-valprint.c +++ b/gdb/ada-valprint.c @@ -185,9 +185,9 @@ val_print_packed_array_elements (struct type *type, const gdb_byte *valaddr, (i * bitsize) / HOST_CHAR_BIT, (i * bitsize) % HOST_CHAR_BIT, bitsize, elttype); - if (!value_available_contents_eq (v0, value_embedded_offset (v0), - v1, value_embedded_offset (v1), - eltlen)) + if (!value_contents_eq (v0, value_embedded_offset (v0), + v1, value_embedded_offset (v1), + eltlen)) break; } diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c index 19c1cb1..17963f0 100644 --- a/gdb/c-valprint.c +++ b/gdb/c-valprint.c @@ -172,9 +172,9 @@ c_val_print (struct type *type, const gdb_byte *valaddr, options->format) && value_bytes_available (original_value, embedded_offset, TYPE_LENGTH (type)) - && value_bits_valid (original_value, - TARGET_CHAR_BIT * embedded_offset, - TARGET_CHAR_BIT * TYPE_LENGTH (type))) + && !value_bits_any_optimized_out (original_value, + TARGET_CHAR_BIT * embedded_offset, + TARGET_CHAR_BIT * TYPE_LENGTH (type))) { int force_ellipses = 0; diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c index e38a2be..62de777 100644 --- a/gdb/cp-valprint.c +++ b/gdb/cp-valprint.c @@ -293,12 +293,6 @@ cp_print_value_fields (struct type *type, struct type *real_type, { fputs_filtered (_("<synthetic pointer>"), stream); } - else if (!value_bits_valid (val, - TYPE_FIELD_BITPOS (type, i), - TYPE_FIELD_BITSIZE (type, i))) - { - val_print_optimized_out (val, stream); - } else { struct value_print_options opts = *options; @@ -433,8 +427,9 @@ cp_print_value_fields_rtti (struct type *type, /* We require all bits to be valid in order to attempt a conversion. */ - if (value_bits_valid (val, TARGET_CHAR_BIT * offset, - TARGET_CHAR_BIT * TYPE_LENGTH (type))) + if (!value_bits_any_optimized_out (val, + TARGET_CHAR_BIT * offset, + TARGET_CHAR_BIT * TYPE_LENGTH (type))) { struct value *value; int full, top, using_enc; diff --git a/gdb/d-valprint.c b/gdb/d-valprint.c index 755f180..788b3d5 100644 --- a/gdb/d-valprint.c +++ b/gdb/d-valprint.c @@ -38,8 +38,9 @@ dynamic_array_type (struct type *type, const gdb_byte *valaddr, && TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_INT && strcmp (TYPE_FIELD_NAME (type, 0), "length") == 0 && strcmp (TYPE_FIELD_NAME (type, 1), "ptr") == 0 - && value_bits_valid (val, TARGET_CHAR_BIT * embedded_offset, - TARGET_CHAR_BIT * TYPE_LENGTH (type))) + && !value_bits_any_optimized_out (val, + TARGET_CHAR_BIT * embedded_offset, + TARGET_CHAR_BIT * TYPE_LENGTH (type))) { CORE_ADDR addr; struct type *elttype; diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index fd78f6f..e347e59 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -1300,8 +1300,6 @@ 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 */ @@ -1710,7 +1708,7 @@ read_pieced_value (struct value *v) memset (buffer, 0, this_size); if (optim) - set_value_optimized_out (v, 1); + mark_value_bits_optimized_out (v, offset, this_size_bits); if (unavail) mark_value_bits_unavailable (v, offset, this_size_bits); } @@ -1770,7 +1768,7 @@ read_pieced_value (struct value *v) break; case DWARF_VALUE_OPTIMIZED_OUT: - set_value_optimized_out (v, 1); + mark_value_bits_optimized_out (v, offset, this_size_bits); break; default: @@ -1808,7 +1806,7 @@ write_pieced_value (struct value *to, struct value *from) if (frame == NULL) { - set_value_optimized_out (to, 1); + mark_value_bytes_optimized_out (to, 0, TYPE_LENGTH (value_type (to))); return; } @@ -1940,7 +1938,7 @@ write_pieced_value (struct value *to, struct value *from) source_buffer, this_size); break; default: - set_value_optimized_out (to, 1); + mark_value_bytes_optimized_out (to, 0, TYPE_LENGTH (value_type (to))); break; } offset += this_size_bits; @@ -1949,24 +1947,16 @@ write_pieced_value (struct value *to, struct value *from) do_cleanups (cleanup); } -/* A helper function that checks bit validity in a pieced value. - CHECK_FOR indicates the kind of validity checking. - DWARF_VALUE_MEMORY means to check whether any bit is valid. - DWARF_VALUE_OPTIMIZED_OUT means to check whether any bit is - optimized out. - DWARF_VALUE_IMPLICIT_POINTER means to check whether the bits are an - implicit pointer. */ +/* An implementation of an lval_funcs method to see whether a value is + a synthetic pointer. */ static int -check_pieced_value_bits (const struct value *value, int bit_offset, - int bit_length, - enum dwarf_value_location check_for) +check_pieced_synthetic_pointer (const struct value *value, int bit_offset, + int bit_length) { struct piece_closure *c = (struct piece_closure *) value_computed_closure (value); int i; - int validity = (check_for == DWARF_VALUE_MEMORY - || check_for == DWARF_VALUE_IMPLICIT_POINTER); bit_offset += 8 * value_offset (value); if (value_bitsize (value)) @@ -1991,52 +1981,11 @@ check_pieced_value_bits (const struct value *value, int bit_offset, else bit_length -= this_size_bits; - if (check_for == DWARF_VALUE_IMPLICIT_POINTER) - { - if (p->location != DWARF_VALUE_IMPLICIT_POINTER) - return 0; - } - else if (p->location == DWARF_VALUE_OPTIMIZED_OUT - || p->location == DWARF_VALUE_IMPLICIT_POINTER) - { - if (validity) - return 0; - } - else - { - if (!validity) - return 1; - } + if (p->location != DWARF_VALUE_IMPLICIT_POINTER) + return 0; } - return validity; -} - -static int -check_pieced_value_validity (const struct value *value, int bit_offset, - int bit_length) -{ - return check_pieced_value_bits (value, bit_offset, bit_length, - DWARF_VALUE_MEMORY); -} - -static int -check_pieced_value_invalid (const struct value *value) -{ - return check_pieced_value_bits (value, 0, - 8 * TYPE_LENGTH (value_type (value)), - DWARF_VALUE_OPTIMIZED_OUT); -} - -/* An implementation of an lval_funcs method to see whether a value is - a synthetic pointer. */ - -static int -check_pieced_synthetic_pointer (const struct value *value, int bit_offset, - int bit_length) -{ - return check_pieced_value_bits (value, bit_offset, bit_length, - DWARF_VALUE_IMPLICIT_POINTER); + return 1; } /* A wrapper function for get_frame_address_in_block. */ @@ -2185,8 +2134,6 @@ free_pieced_value_closure (struct value *v) static const struct lval_funcs pieced_value_funcs = { read_pieced_value, write_pieced_value, - check_pieced_value_validity, - check_pieced_value_invalid, indirect_pieced_value, NULL, /* coerce_ref */ check_pieced_synthetic_pointer, @@ -2316,6 +2263,8 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame, retval = value_from_register (type, gdb_regnum, frame); if (value_optimized_out (retval)) { + struct value *tmp; + /* This means the register has undefined value / was not saved. As we're computing the location of some variable etc. in the program, not a value for @@ -2323,7 +2272,9 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame, generic optimized out value instead, so that we show <optimized out> instead of <not saved>. */ do_cleanups (value_chain); - retval = allocate_optimized_out_value (type); + tmp = allocate_value (type); + value_contents_copy (tmp, 0, retval, 0, TYPE_LENGTH (type)); + retval = tmp; } } break; diff --git a/gdb/findvar.c b/gdb/findvar.c index 41887de..f69a8e0 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -679,12 +679,6 @@ read_frame_register_value (struct value *value, struct frame_info *frame) struct value *regval = get_frame_register_value (frame, regnum); int reg_len = TYPE_LENGTH (value_type (regval)) - reg_offset; - if (value_optimized_out (regval)) - { - set_value_optimized_out (value, 1); - break; - } - /* If the register length is larger than the number of bytes remaining to copy, then only copy the appropriate bytes. */ if (reg_len > len) @@ -730,7 +724,7 @@ value_from_register (struct type *type, int regnum, struct frame_info *frame) if (!ok) { if (optim) - set_value_optimized_out (v, 1); + mark_value_bytes_optimized_out (v, 0, TYPE_LENGTH (type)); if (unavail) mark_value_bytes_unavailable (v, 0, TYPE_LENGTH (type)); } diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c index ebc01ff..1068b02 100644 --- a/gdb/frame-unwind.c +++ b/gdb/frame-unwind.c @@ -202,7 +202,7 @@ frame_unwind_got_optimized (struct frame_info *frame, int regnum) "<not saved>". */ val = allocate_value_lazy (type); set_value_lazy (val, 0); - set_value_optimized_out (val, 1); + mark_value_bytes_optimized_out (val, 0, TYPE_LENGTH (type)); VALUE_LVAL (val) = lval_register; VALUE_REGNUM (val) = regnum; VALUE_FRAME_ID (val) = get_frame_id (frame); diff --git a/gdb/jv-valprint.c b/gdb/jv-valprint.c index fd5904b..91b45e2 100644 --- a/gdb/jv-valprint.c +++ b/gdb/jv-valprint.c @@ -181,10 +181,10 @@ java_value_print (struct value *val, struct ui_file *stream, set_value_offset (next_v, value_offset (next_v) + TYPE_LENGTH (el_type)); value_fetch_lazy (next_v); - if (!(value_available_contents_eq - (v, value_embedded_offset (v), - next_v, value_embedded_offset (next_v), - TYPE_LENGTH (el_type)))) + if (!value_contents_eq (v, value_embedded_offset (v), + next_v, + value_embedded_offset (next_v), + TYPE_LENGTH (el_type))) break; } @@ -391,11 +391,6 @@ java_print_value_fields (struct type *type, const gdb_byte *valaddr, { fputs_filtered (_("<synthetic pointer>"), stream); } - else if (!value_bits_valid (val, TYPE_FIELD_BITPOS (type, i), - TYPE_FIELD_BITSIZE (type, i))) - { - val_print_optimized_out (val, stream); - } else { struct value_print_options opts; diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 8165f94..188580f 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -6194,12 +6194,6 @@ mips_print_register (struct ui_file *file, struct frame_info *frame, } val = get_frame_register_value (frame, regnum); - if (value_optimized_out (val)) - { - fprintf_filtered (file, "%s: [Invalid]", - gdbarch_register_name (gdbarch, regnum)); - return; - } fputs_filtered (gdbarch_register_name (gdbarch, regnum), file); diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c index c9f0476..2006cd8 100644 --- a/gdb/opencl-lang.c +++ b/gdb/opencl-lang.c @@ -238,58 +238,6 @@ lval_func_write (struct value *v, struct value *fromval) value_free_to_mark (mark); } -/* Return nonzero if all bits in V within OFFSET and LENGTH are valid. */ - -static int -lval_func_check_validity (const struct value *v, int offset, int length) -{ - struct lval_closure *c = (struct lval_closure *) value_computed_closure (v); - /* Size of the target type in bits. */ - int elsize = - TYPE_LENGTH (TYPE_TARGET_TYPE (check_typedef (value_type (c->val)))) * 8; - int startrest = offset % elsize; - int start = offset / elsize; - int endrest = (offset + length) % elsize; - int end = (offset + length) / elsize; - int i; - - if (endrest) - end++; - - if (end > c->n) - return 0; - - for (i = start; i < end; i++) - { - int comp_offset = (i == start) ? startrest : 0; - int comp_length = (i == end) ? endrest : elsize; - - if (!value_bits_valid (c->val, c->indices[i] * elsize + comp_offset, - comp_length)) - return 0; - } - - return 1; -} - -/* Return nonzero if any bit in V is valid. */ - -static int -lval_func_check_any_valid (const struct value *v) -{ - struct lval_closure *c = (struct lval_closure *) value_computed_closure (v); - /* Size of the target type in bits. */ - int elsize = - TYPE_LENGTH (TYPE_TARGET_TYPE (check_typedef (value_type (c->val)))) * 8; - int i; - - for (i = 0; i < c->n; i++) - if (value_bits_valid (c->val, c->indices[i] * elsize, elsize)) - return 1; - - return 0; -} - /* Return nonzero if bits in V from OFFSET and LENGTH represent a synthetic pointer. */ @@ -356,8 +304,6 @@ static const struct lval_funcs opencl_value_funcs = { lval_func_read, lval_func_write, - lval_func_check_validity, - lval_func_check_any_valid, NULL, /* indirect */ NULL, /* coerce_ref */ lval_func_check_synthetic_pointer, diff --git a/gdb/p-valprint.c b/gdb/p-valprint.c index 70eb3a8..c796218 100644 --- a/gdb/p-valprint.c +++ b/gdb/p-valprint.c @@ -627,11 +627,6 @@ pascal_object_print_value_fields (struct type *type, const gdb_byte *valaddr, { fputs_filtered (_("<synthetic pointer>"), stream); } - else if (!value_bits_valid (val, TYPE_FIELD_BITPOS (type, i), - TYPE_FIELD_BITSIZE (type, i))) - { - val_print_optimized_out (val, stream); - } else { struct value_print_options opts = *options; diff --git a/gdb/stack.c b/gdb/stack.c index 3fa50b4..c9a85ca 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -382,9 +382,12 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame, { struct type *type = value_type (val); - if (!value_optimized_out (val) - && value_available_contents_eq (val, 0, entryval, 0, - TYPE_LENGTH (type))) + if (value_lazy (val)) + value_fetch_lazy (val); + if (value_lazy (entryval)) + value_fetch_lazy (entryval); + + if (value_contents_eq (val, 0, entryval, 0, TYPE_LENGTH (type))) { /* Initialize it just to avoid a GCC false warning. */ struct value *val_deref = NULL, *entryval_deref; @@ -410,11 +413,9 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame, /* If the reference addresses match but dereferenced content does not match print them. */ if (val != val_deref - && !value_optimized_out (val_deref) - && !value_optimized_out (entryval_deref) - && value_available_contents_eq (val_deref, 0, - entryval_deref, 0, - TYPE_LENGTH (type_deref))) + && value_contents_eq (val_deref, 0, + entryval_deref, 0, + TYPE_LENGTH (type_deref))) val_equal = 1; } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index d30f7a3..e7a4644 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2014-08-19 Andrew Burgess <aburgess@broadcom.com> + Pedro Alves <palves@redhat.com> + + PR symtab/14604 + PR symtab/14605 + * gdb.dwarf2/dw2-op-out-param.exp: Remove kfail branches and use + gdb_test. + 2014-08-19 Pedro Alves <palves@redhat.com> * gdb.base/watchpoint-hw-hit-once.c (main): Update comment. diff --git a/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp b/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp index 5ab5817..d245951 100644 --- a/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp +++ b/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp @@ -50,36 +50,12 @@ gdb_test "bt" "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?int_param_single_ # (2) struct_param_single_reg_loc gdb_continue_to_breakpoint "Stop in breakpt for struct_param_single_reg_loc" -set test "Backtrace for test struct_param_single_reg_loc" -gdb_test_multiple "bt" "$test" { - -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_single_reg_loc \\(operand0={a = 0xdeadbe00deadbe01, b = <optimized out>}, operand1={a = <optimized out>, b = 0xdeadbe04deadbe05}, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { - xpass $test - } - -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_single_reg_loc \\(operand0=<optimized out>, operand1=<optimized out>, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { - kfail "symtab/14604" $test - } -} +gdb_test "bt" "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_single_reg_loc \\(operand0={a = 0xdeadbe00deadbe01, b = <optimized out>}, operand1={a = <optimized out>, b = 0xdeadbe04deadbe05}, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)" "Backtrace for test struct_param_single_reg_loc" # (3) struct_param_two_reg_pieces gdb_continue_to_breakpoint "Stop in breakpt for struct_param_two_reg_pieces" -set test "Backtrace for test struct_param_two_reg_pieces" -gdb_test_multiple "bt" "$test" { - -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_two_reg_pieces \\(operand0={a = 0xdeadbe04deadbe05, b = <optimized out>}, operand1={a = <optimized out>, b = 0xdeadbe00deadbe01}, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { - xpass $test - } - -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_two_reg_pieces \\(operand0=.*, operand1=.*, operand2=.*\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { - kfail "symtab/14605" $test - } -} +gdb_test "bt" "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_two_reg_pieces \\(operand0={a = 0xdeadbe04deadbe05, b = <optimized out>}, operand1={a = <optimized out>, b = 0xdeadbe00deadbe01}, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)" "Backtrace for test struct_param_two_reg_pieces" # (4) int_param_two_reg_pieces gdb_continue_to_breakpoint "Stop in breakpt for int_param_two_reg_pieces" -set test "Backtrace for test int_param_two_reg_pieces" -gdb_test_multiple "bt" "$test" { - -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?int_param_two_reg_pieces \\(operand0=<optimized out>, operand1=<optimized out>, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { - xpass $test - } - -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?int_param_two_reg_pieces \\(operand0=.*, operand1=.*, operand2=.*\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { - kfail "symtab/14605" $test - } -} +gdb_test "bt" "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?int_param_two_reg_pieces \\(operand0=<optimized out>, operand1=<optimized out>, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)" "Backtrace for test int_param_two_reg_pieces" diff --git a/gdb/valprint.c b/gdb/valprint.c index a87d67c..8cb5c74 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -308,8 +308,9 @@ valprint_check_validity (struct ui_file *stream, && TYPE_CODE (type) != TYPE_CODE_STRUCT && TYPE_CODE (type) != TYPE_CODE_ARRAY) { - if (!value_bits_valid (val, TARGET_CHAR_BIT * embedded_offset, - TARGET_CHAR_BIT * TYPE_LENGTH (type))) + if (value_bits_any_optimized_out (val, + TARGET_CHAR_BIT * embedded_offset, + TARGET_CHAR_BIT * TYPE_LENGTH (type))) { val_print_optimized_out (val, stream); return 0; @@ -980,8 +981,9 @@ val_print_scalar_formatted (struct type *type, /* A scalar object that does not have all bits available can't be printed, because all bits contribute to its representation. */ - if (!value_bits_valid (val, TARGET_CHAR_BIT * embedded_offset, - TARGET_CHAR_BIT * TYPE_LENGTH (type))) + if (value_bits_any_optimized_out (val, + TARGET_CHAR_BIT * embedded_offset, + TARGET_CHAR_BIT * TYPE_LENGTH (type))) val_print_optimized_out (val, stream); else if (!value_bytes_available (val, embedded_offset, TYPE_LENGTH (type))) val_print_unavailable (stream); @@ -1682,12 +1684,12 @@ val_print_array_elements (struct type *type, if (options->repeat_count_threshold < UINT_MAX) { while (rep1 < len - && value_available_contents_eq (val, - embedded_offset + i * eltlen, - val, - (embedded_offset - + rep1 * eltlen), - eltlen)) + && value_contents_eq (val, + embedded_offset + i * eltlen, + val, + (embedded_offset + + rep1 * eltlen), + eltlen)) { ++reps; ++rep1; diff --git a/gdb/value.c b/gdb/value.c index cec1d4a..b74f23a 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -195,15 +195,6 @@ struct value reset, be sure to consider this use as well! */ unsigned int lazy : 1; - /* If nonzero, this is the value of a variable that does not - actually exist in the program. If nonzero, and LVAL is - lval_register, this is a register ($pc, $sp, etc., never a - program variable) that has not been saved in the frame. All - optimized-out values are treated pretty much the same, except - registers have a different string representation and related - error strings. */ - unsigned int optimized_out : 1; - /* If value is a variable, is it initialized or not. */ unsigned int initialized : 1; @@ -334,9 +325,20 @@ struct value /* Unavailable ranges in CONTENTS. We mark unavailable ranges, rather than available, since the common and default case is for a - value to be available. This is filled in at value read time. The - unavailable ranges are tracked in bits. */ + value to be available. This is filled in at value read time. + The unavailable ranges are tracked in bits. Note that a contents + bit that has been optimized out doesn't really exist in the + program, so it can't be marked unavailable either. */ VEC(range_s) *unavailable; + + /* Likewise, but for optimized out contents (a chunk of the value of + a variable that does not actually exist in the program). If LVAL + is lval_register, this is a register ($pc, $sp, etc., never a + program variable) that has not been saved in the frame. Not + saved registers and optimized-out program variables values are + treated pretty much the same, except not-saved registers have a + different string representation and related error strings. */ + VEC(range_s) *optimized_out; }; int @@ -356,6 +358,14 @@ value_bytes_available (const struct value *value, int offset, int length) } int +value_bits_any_optimized_out (const struct value *value, int bit_offset, int bit_length) +{ + gdb_assert (!value->lazy); + + return ranges_contain (value->optimized_out, bit_offset, bit_length); +} + +int value_entirely_available (struct value *value) { /* We can only tell whether the whole value is available when we try @@ -368,17 +378,22 @@ value_entirely_available (struct value *value) return 0; } -int -value_entirely_unavailable (struct value *value) +/* Returns true if VALUE is entirely covered by RANGES. If the value + is lazy, it'll be read now. Note that RANGE is a pointer to + pointer because reading the value might change *RANGE. */ + +static int +value_entirely_covered_by_range_vector (struct value *value, + VEC(range_s) **ranges) { - /* We can only tell whether the whole value is available when we try - to read it. */ + /* We can only tell whether the whole value is optimized out / + unavailable when we try to read it. */ if (value->lazy) value_fetch_lazy (value); - if (VEC_length (range_s, value->unavailable) == 1) + if (VEC_length (range_s, *ranges) == 1) { - struct range *t = VEC_index (range_s, value->unavailable, 0); + struct range *t = VEC_index (range_s, *ranges, 0); if (t->offset == 0 && t->length == (TARGET_CHAR_BIT @@ -389,8 +404,23 @@ value_entirely_unavailable (struct value *value) return 0; } -void -mark_value_bits_unavailable (struct value *value, int offset, int length) +int +value_entirely_unavailable (struct value *value) +{ + return value_entirely_covered_by_range_vector (value, &value->unavailable); +} + +int +value_entirely_optimized_out (struct value *value) +{ + return value_entirely_covered_by_range_vector (value, &value->optimized_out); +} + +/* Insert into the vector pointed to by VECTORP the bit range starting of + OFFSET bits, and extending for the next LENGTH bits. */ + +static void +insert_into_bit_range_vector (VEC(range_s) **vectorp, int offset, int length) { range_s newr; int i; @@ -481,10 +511,10 @@ mark_value_bits_unavailable (struct value *value, int offset, int length) */ - i = VEC_lower_bound (range_s, value->unavailable, &newr, range_lessthan); + i = VEC_lower_bound (range_s, *vectorp, &newr, range_lessthan); if (i > 0) { - struct range *bef = VEC_index (range_s, value->unavailable, i - 1); + struct range *bef = VEC_index (range_s, *vectorp, i - 1); if (ranges_overlap (bef->offset, bef->length, offset, length)) { @@ -505,18 +535,18 @@ mark_value_bits_unavailable (struct value *value, int offset, int length) else { /* #3 */ - VEC_safe_insert (range_s, value->unavailable, i, &newr); + VEC_safe_insert (range_s, *vectorp, i, &newr); } } else { /* #4 */ - VEC_safe_insert (range_s, value->unavailable, i, &newr); + VEC_safe_insert (range_s, *vectorp, i, &newr); } /* Check whether the ranges following the one we've just added or touched can be folded in (#5 above). */ - if (i + 1 < VEC_length (range_s, value->unavailable)) + if (i + 1 < VEC_length (range_s, *vectorp)) { struct range *t; struct range *r; @@ -524,11 +554,11 @@ mark_value_bits_unavailable (struct value *value, int offset, int length) int next = i + 1; /* Get the range we just touched. */ - t = VEC_index (range_s, value->unavailable, i); + t = VEC_index (range_s, *vectorp, i); removed = 0; i = next; - for (; VEC_iterate (range_s, value->unavailable, i, r); i++) + for (; VEC_iterate (range_s, *vectorp, i, r); i++) if (r->offset <= t->offset + t->length) { ULONGEST l, h; @@ -550,11 +580,17 @@ mark_value_bits_unavailable (struct value *value, int offset, int length) } if (removed != 0) - VEC_block_remove (range_s, value->unavailable, next, removed); + VEC_block_remove (range_s, *vectorp, next, removed); } } void +mark_value_bits_unavailable (struct value *value, int offset, int length) +{ + insert_into_bit_range_vector (&value->unavailable, offset, length); +} + +void mark_value_bytes_unavailable (struct value *value, int offset, int length) { mark_value_bits_unavailable (value, @@ -682,48 +718,53 @@ memcmp_with_bit_offsets (const gdb_byte *ptr1, size_t offset1_bits, return 0; } -/* Helper function for value_available_contents_eq. The only difference is - that this function is bit rather than byte based. +/* Helper struct for find_first_range_overlap_and_match and + value_contents_bits_eq. Keep track of which slot of a given ranges + vector have we last looked at. */ - Compare LENGTH bits of VAL1's contents starting at OFFSET1 bits with - LENGTH bits of VAL2's contents starting at OFFSET2 bits. Return true - if the available bits match. */ +struct ranges_and_idx +{ + /* The ranges. */ + VEC(range_s) *ranges; + + /* The range we've last found in RANGES. Given ranges are sorted, + we can start the next lookup here. */ + int idx; +}; + +/* Helper function for value_contents_bits_eq. Compare LENGTH bits of + RP1's ranges starting at OFFSET1 bits with LENGTH bits of RP2's + ranges starting at OFFSET2 bits. Return true if the ranges match + and fill in *L and *H with the overlapping window relative to + (both) OFFSET1 or OFFSET2. */ static int -value_available_contents_bits_eq (const struct value *val1, int offset1, - const struct value *val2, int offset2, - int length) +find_first_range_overlap_and_match (struct ranges_and_idx *rp1, + struct ranges_and_idx *rp2, + int offset1, int offset2, + int length, ULONGEST *l, ULONGEST *h) { - int idx1 = 0, idx2 = 0; - - /* See function description in value.h. */ - gdb_assert (!val1->lazy && !val2->lazy); + rp1->idx = find_first_range_overlap (rp1->ranges, rp1->idx, + offset1, length); + rp2->idx = find_first_range_overlap (rp2->ranges, rp2->idx, + offset2, length); - while (length > 0) + if (rp1->idx == -1 && rp2->idx == -1) + { + *l = length; + *h = length; + return 1; + } + else if (rp1->idx == -1 || rp2->idx == -1) + return 0; + else { range_s *r1, *r2; ULONGEST l1, h1; ULONGEST l2, h2; - idx1 = find_first_range_overlap (val1->unavailable, idx1, - offset1, length); - idx2 = find_first_range_overlap (val2->unavailable, idx2, - offset2, length); - - /* The usual case is for both values to be completely available. */ - if (idx1 == -1 && idx2 == -1) - return (memcmp_with_bit_offsets (val1->contents, offset1, - val2->contents, offset2, - length) == 0); - /* The contents only match equal if the available set matches as - well. */ - else if (idx1 == -1 || idx2 == -1) - return 0; - - gdb_assert (idx1 != -1 && idx2 != -1); - - r1 = VEC_index (range_s, val1->unavailable, idx1); - r2 = VEC_index (range_s, val2->unavailable, idx2); + r1 = VEC_index (range_s, rp1->ranges, rp1->idx); + r2 = VEC_index (range_s, rp2->ranges, rp2->idx); /* Get the unavailable windows intersected by the incoming ranges. The first and last ranges that overlap the argument @@ -732,7 +773,7 @@ value_available_contents_bits_eq (const struct value *val1, int offset1, h1 = min (offset1 + length, r1->offset + r1->length); l2 = max (offset2, r2->offset); - h2 = min (offset2 + length, r2->offset + r2->length); + h2 = min (offset2 + length, offset2 + r2->length); /* Make them relative to the respective start offsets, so we can compare them for equality. */ @@ -742,31 +783,93 @@ value_available_contents_bits_eq (const struct value *val1, int offset1, l2 -= offset2; h2 -= offset2; - /* Different availability, no match. */ + /* Different ranges, no match. */ if (l1 != l2 || h1 != h2) return 0; - /* Compare the _available_ contents. */ + *h = h1; + *l = l1; + return 1; + } +} + +/* Helper function for value_contents_eq. The only difference is that + this function is bit rather than byte based. + + Compare LENGTH bits of VAL1's contents starting at OFFSET1 bits + with LENGTH bits of VAL2's contents starting at OFFSET2 bits. + Return true if the available bits match. */ + +static int +value_contents_bits_eq (const struct value *val1, int offset1, + const struct value *val2, int offset2, + int length) +{ + /* Each array element corresponds to a ranges source (unavailable, + optimized out). '1' is for VAL1, '2' for VAL2. */ + struct ranges_and_idx rp1[2], rp2[2]; + + /* See function description in value.h. */ + gdb_assert (!val1->lazy && !val2->lazy); + + /* We shouldn't be trying to compare past the end of the values. */ + gdb_assert (offset1 + length + <= TYPE_LENGTH (val1->enclosing_type) * TARGET_CHAR_BIT); + gdb_assert (offset2 + length + <= TYPE_LENGTH (val2->enclosing_type) * TARGET_CHAR_BIT); + + memset (&rp1, 0, sizeof (rp1)); + memset (&rp2, 0, sizeof (rp2)); + rp1[0].ranges = val1->unavailable; + rp2[0].ranges = val2->unavailable; + rp1[1].ranges = val1->optimized_out; + rp2[1].ranges = val2->optimized_out; + + while (length > 0) + { + ULONGEST l, h; + int i; + + for (i = 0; i < 2; i++) + { + ULONGEST l_tmp, h_tmp; + + /* The contents only match equal if the invalid/unavailable + contents ranges match as well. */ + if (!find_first_range_overlap_and_match (&rp1[i], &rp2[i], + offset1, offset2, length, + &l_tmp, &h_tmp)) + return 0; + + /* We're interested in the lowest/first range found. */ + if (i == 0 || l_tmp < l) + { + l = l_tmp; + h = h_tmp; + } + } + + /* Compare the available/valid contents. */ if (memcmp_with_bit_offsets (val1->contents, offset1, - val2->contents, offset2, l1) != 0) + val2->contents, offset2, l) != 0) return 0; - length -= h1; - offset1 += h1; - offset2 += h1; + length -= h; + offset1 += h; + offset2 += h; } return 1; } int -value_available_contents_eq (const struct value *val1, int offset1, - const struct value *val2, int offset2, - int length) +value_contents_eq (const struct value *val1, int offset1, + const struct value *val2, int offset2, + int length) { - return value_available_contents_bits_eq (val1, offset1 * TARGET_CHAR_BIT, - val2, offset2 * TARGET_CHAR_BIT, - length * TARGET_CHAR_BIT); + return value_contents_bits_eq (val1, offset1 * TARGET_CHAR_BIT, + val2, offset2 * TARGET_CHAR_BIT, + length * TARGET_CHAR_BIT); } /* Prototypes for local functions. */ @@ -834,7 +937,6 @@ allocate_value_lazy (struct type *type) val->bitsize = 0; VALUE_REGNUM (val) = -1; val->lazy = 1; - val->optimized_out = 0; val->embedded_offset = 0; val->pointed_to_offset = 0; val->modifiable = 1; @@ -903,11 +1005,8 @@ allocate_optimized_out_value (struct type *type) { struct value *retval = allocate_value_lazy (type); - set_value_optimized_out (retval, 1); - /* FIXME: we should be able to avoid allocating the value's contents - buffer, but value_available_contents_bits_eq can't handle - that. */ - /* set_value_lazy (retval, 0); */ + mark_value_bytes_optimized_out (retval, 0, TYPE_LENGTH (type)); + set_value_lazy (retval, 0); return retval; } @@ -1055,7 +1154,7 @@ error_value_optimized_out (void) static void require_not_optimized_out (const struct value *value) { - if (value->optimized_out) + if (!VEC_empty (range_s, value->optimized_out)) { if (value->lval == lval_register) error (_("register has not been saved in frame")); @@ -1095,6 +1194,31 @@ value_contents_all (struct value *value) return result; } +/* Copy ranges in SRC_RANGE that overlap [SRC_BIT_OFFSET, + SRC_BIT_OFFSET+BIT_LENGTH) ranges into *DST_RANGE, adjusted. */ + +static void +ranges_copy_adjusted (VEC (range_s) **dst_range, int dst_bit_offset, + VEC (range_s) *src_range, int src_bit_offset, + int bit_length) +{ + range_s *r; + int i; + + for (i = 0; VEC_iterate (range_s, src_range, i, r); i++) + { + ULONGEST h, l; + + l = max (r->offset, src_bit_offset); + h = min (r->offset + r->length, src_bit_offset + bit_length); + + if (l < h) + insert_into_bit_range_vector (dst_range, + dst_bit_offset + (l - src_bit_offset), + h - l); + } +} + /* Copy LENGTH bytes of SRC value's (all) contents (value_contents_all) starting at SRC_OFFSET, into DST value's (all) contents, starting at DST_OFFSET. If unavailable contents are @@ -1123,6 +1247,9 @@ value_contents_copy_raw (struct value *dst, int dst_offset, replaced. Make sure to remember to implement replacing if it turns out actually necessary. */ gdb_assert (value_bytes_available (dst, dst_offset, length)); + gdb_assert (!value_bits_any_optimized_out (dst, + TARGET_CHAR_BIT * dst_offset, + TARGET_CHAR_BIT * length)); /* Copy the data. */ memcpy (value_contents_all_raw (dst) + dst_offset, @@ -1133,18 +1260,14 @@ value_contents_copy_raw (struct value *dst, int dst_offset, src_bit_offset = src_offset * TARGET_CHAR_BIT; dst_bit_offset = dst_offset * TARGET_CHAR_BIT; bit_length = length * TARGET_CHAR_BIT; - for (i = 0; VEC_iterate (range_s, src->unavailable, i, r); i++) - { - ULONGEST h, l; - l = max (r->offset, src_bit_offset); - h = min (r->offset + r->length, src_bit_offset + bit_length); + ranges_copy_adjusted (&dst->unavailable, dst_bit_offset, + src->unavailable, src_bit_offset, + bit_length); - if (l < h) - mark_value_bits_unavailable (dst, - dst_bit_offset + (l - src_bit_offset), - h - l); - } + ranges_copy_adjusted (&dst->optimized_out, dst_bit_offset, + src->optimized_out, src_bit_offset, + bit_length); } /* Copy LENGTH bytes of SRC value's (all) contents @@ -1152,8 +1275,7 @@ value_contents_copy_raw (struct value *dst, int dst_offset, (all) contents, starting at DST_OFFSET. If unavailable contents are being copied from SRC, the corresponding DST contents are marked unavailable accordingly. DST must not be lazy. If SRC is - lazy, it will be fetched now. If SRC is not valid (is optimized - out), an error is thrown. + lazy, it will be fetched now. It is assumed the contents of DST in the [DST_OFFSET, DST_OFFSET+LENGTH) range are wholly available. */ @@ -1162,8 +1284,6 @@ void value_contents_copy (struct value *dst, int dst_offset, struct value *src, int src_offset, int length) { - require_not_optimized_out (src); - if (src->lazy) value_fetch_lazy (src); @@ -1216,45 +1336,29 @@ value_optimized_out (struct value *value) { /* We can only know if a value is optimized out once we have tried to fetch it. */ - if (!value->optimized_out && value->lazy) + if (VEC_empty (range_s, value->optimized_out) && value->lazy) value_fetch_lazy (value); - return value->optimized_out; + return !VEC_empty (range_s, value->optimized_out); } -int -value_optimized_out_const (const struct value *value) -{ - return value->optimized_out; -} +/* Mark contents of VALUE as optimized out, starting at OFFSET bytes, and + the following LENGTH bytes. */ void -set_value_optimized_out (struct value *value, int val) +mark_value_bytes_optimized_out (struct value *value, int offset, int length) { - value->optimized_out = val; + mark_value_bits_optimized_out (value, + offset * TARGET_CHAR_BIT, + length * TARGET_CHAR_BIT); } -int -value_entirely_optimized_out (const struct value *value) -{ - if (!value->optimized_out) - return 0; - if (value->lval != lval_computed - || !value->location.computed.funcs->check_any_valid) - return 1; - return !value->location.computed.funcs->check_any_valid (value); -} +/* See value.h. */ -int -value_bits_valid (const struct value *value, int offset, int length) +void +mark_value_bits_optimized_out (struct value *value, int offset, int length) { - if (!value->optimized_out) - return 1; - if (value->lval != lval_computed - || !value->location.computed.funcs->check_validity) - return 0; - return value->location.computed.funcs->check_validity (value, offset, - length); + insert_into_bit_range_vector (&value->optimized_out, offset, length); } int @@ -1567,7 +1671,6 @@ value_copy (struct value *arg) VALUE_FRAME_ID (val) = VALUE_FRAME_ID (arg); VALUE_REGNUM (val) = VALUE_REGNUM (arg); val->lazy = arg->lazy; - val->optimized_out = arg->optimized_out; val->embedded_offset = value_embedded_offset (arg); val->pointed_to_offset = arg->pointed_to_offset; val->modifiable = arg->modifiable; @@ -1578,6 +1681,7 @@ value_copy (struct value *arg) } val->unavailable = VEC_copy (range_s, arg->unavailable); + val->optimized_out = VEC_copy (range_s, arg->optimized_out); set_value_parent (val, arg->parent); if (VALUE_LVAL (val) == lval_computed) { @@ -2852,24 +2956,19 @@ value_primitive_field (struct value *arg1, int offset, int bitpos = TYPE_FIELD_BITPOS (arg_type, fieldno); int container_bitsize = TYPE_LENGTH (type) * 8; - if (arg1->optimized_out) - v = allocate_optimized_out_value (type); + v = allocate_value_lazy (type); + v->bitsize = TYPE_FIELD_BITSIZE (arg_type, fieldno); + if ((bitpos % container_bitsize) + v->bitsize <= container_bitsize + && TYPE_LENGTH (type) <= (int) sizeof (LONGEST)) + v->bitpos = bitpos % container_bitsize; else - { - v = allocate_value_lazy (type); - v->bitsize = TYPE_FIELD_BITSIZE (arg_type, fieldno); - if ((bitpos % container_bitsize) + v->bitsize <= container_bitsize - && TYPE_LENGTH (type) <= (int) sizeof (LONGEST)) - v->bitpos = bitpos % container_bitsize; - else - v->bitpos = bitpos % 8; - v->offset = (value_embedded_offset (arg1) - + offset - + (bitpos - v->bitpos) / 8); - set_value_parent (v, arg1); - if (!value_lazy (arg1)) - value_fetch_lazy (v); - } + v->bitpos = bitpos % 8; + v->offset = (value_embedded_offset (arg1) + + offset + + (bitpos - v->bitpos) / 8); + set_value_parent (v, arg1); + if (!value_lazy (arg1)) + value_fetch_lazy (v); } else if (fieldno < TYPE_N_BASECLASSES (arg_type)) { @@ -2882,37 +2981,29 @@ value_primitive_field (struct value *arg1, int offset, if (VALUE_LVAL (arg1) == lval_register && value_lazy (arg1)) value_fetch_lazy (arg1); - /* The optimized_out flag is only set correctly once a lazy value is - loaded, having just loaded some lazy values we should check the - optimized out case now. */ - if (arg1->optimized_out) - v = allocate_optimized_out_value (type); + /* We special case virtual inheritance here because this + requires access to the contents, which we would rather avoid + for references to ordinary fields of unavailable values. */ + if (BASETYPE_VIA_VIRTUAL (arg_type, fieldno)) + boffset = baseclass_offset (arg_type, fieldno, + value_contents (arg1), + value_embedded_offset (arg1), + value_address (arg1), + arg1); else - { - /* We special case virtual inheritance here because this - requires access to the contents, which we would rather avoid - for references to ordinary fields of unavailable values. */ - if (BASETYPE_VIA_VIRTUAL (arg_type, fieldno)) - boffset = baseclass_offset (arg_type, fieldno, - value_contents (arg1), - value_embedded_offset (arg1), - value_address (arg1), - arg1); - else - boffset = TYPE_FIELD_BITPOS (arg_type, fieldno) / 8; + boffset = TYPE_FIELD_BITPOS (arg_type, fieldno) / 8; - if (value_lazy (arg1)) - v = allocate_value_lazy (value_enclosing_type (arg1)); - else - { - v = allocate_value (value_enclosing_type (arg1)); - value_contents_copy_raw (v, 0, arg1, 0, - TYPE_LENGTH (value_enclosing_type (arg1))); - } - v->type = type; - v->offset = value_offset (arg1); - v->embedded_offset = offset + value_embedded_offset (arg1) + boffset; + if (value_lazy (arg1)) + v = allocate_value_lazy (value_enclosing_type (arg1)); + else + { + v = allocate_value (value_enclosing_type (arg1)); + value_contents_copy_raw (v, 0, arg1, 0, + TYPE_LENGTH (value_enclosing_type (arg1))); } + v->type = type; + v->offset = value_offset (arg1); + v->embedded_offset = offset + value_embedded_offset (arg1) + boffset; } else { @@ -2923,12 +3014,7 @@ value_primitive_field (struct value *arg1, int offset, if (VALUE_LVAL (arg1) == lval_register && value_lazy (arg1)) value_fetch_lazy (arg1); - /* The optimized_out flag is only set correctly once a lazy value is - loaded, having just loaded some lazy values we should check for - the optimized out case now. */ - if (arg1->optimized_out) - v = allocate_optimized_out_value (type); - else if (value_lazy (arg1)) + if (value_lazy (arg1)) v = allocate_value_lazy (type); else { @@ -3657,6 +3743,11 @@ value_fetch_lazy (struct value *val) { gdb_assert (value_lazy (val)); allocate_value_contents (val); + /* A value is either lazy, or fully fetched. The + availability/validity is only established as we try to fetch a + value. */ + gdb_assert (VEC_empty (range_s, val->optimized_out)); + gdb_assert (VEC_empty (range_s, val->unavailable)); if (value_bitsize (val)) { /* To read a lazy bitfield, read the entire enclosing value. This @@ -3673,10 +3764,11 @@ value_fetch_lazy (struct value *val) if (value_lazy (parent)) value_fetch_lazy (parent); - if (!value_bits_valid (parent, - TARGET_CHAR_BIT * offset + value_bitpos (val), - value_bitsize (val))) - set_value_optimized_out (val, 1); + if (value_bits_any_optimized_out (parent, + TARGET_CHAR_BIT * offset + value_bitpos (val), + value_bitsize (val))) + mark_value_bytes_optimized_out (val, value_embedded_offset (val), + TYPE_LENGTH (type)); else if (!unpack_value_bits_as_long (value_type (val), value_contents_for_printing (parent), offset, @@ -3751,16 +3843,12 @@ value_fetch_lazy (struct value *val) if (value_lazy (new_val)) value_fetch_lazy (new_val); - /* If the register was not saved, mark it optimized out. */ - if (value_optimized_out (new_val)) - set_value_optimized_out (val, 1); - else - { - set_value_lazy (val, 0); - value_contents_copy (val, value_embedded_offset (val), - new_val, value_embedded_offset (new_val), - TYPE_LENGTH (type)); - } + /* Copy the contents and the unavailability/optimized-out + meta-data from NEW_VAL to VAL. */ + set_value_lazy (val, 0); + value_contents_copy (val, value_embedded_offset (val), + new_val, value_embedded_offset (new_val), + TYPE_LENGTH (type)); if (frame_debug) { @@ -3813,11 +3901,6 @@ value_fetch_lazy (struct value *val) else if (VALUE_LVAL (val) == lval_computed && value_computed_funcs (val)->read != NULL) value_computed_funcs (val)->read (val); - /* Don't call value_optimized_out on val, doing so would result in a - recursive call back to value_fetch_lazy, instead check the - optimized_out flag directly. */ - else if (val->optimized_out) - /* Keep it optimized out. */; else internal_error (__FILE__, __LINE__, _("Unexpected lazy value type.")); diff --git a/gdb/value.h b/gdb/value.h index 843478b..5d4949c 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -33,6 +33,54 @@ struct language_defn; struct value_print_options; struct xmethod_worker; +/* Values can be partially 'optimized out' and/or 'unavailable'. + These are distinct states and have different string representations + and related error strings. + + 'unavailable' has a specific meaning in this context. It means the + value exists in the program (at the machine level), but GDB has no + means to get to it. Such a value is normally printed as + <unavailable>. Examples of how to end up with an unavailable value + would be: + + - We're inspecting a traceframe, and the memory or registers the + debug information says the value lives on haven't been collected. + + - We're inspecting a core dump, the memory or registers the debug + information says the value lives aren't present in the dump + (that is, we have a partial/trimmed core dump, or we don't fully + understand/handle the core dump's format). + + - We're doing live debugging, but the debug API has no means to + get at where the value lives in the machine, like e.g., ptrace + not having access to some register or register set. + + - Any other similar scenario. + + OTOH, "optimized out" is about what the compiler decided to generate + (or not generate). A chunk of a value that was optimized out does + not actually exist in the program. There's no way to get at it + short of compiling the program differently. + + A register that has not been saved in a frame is likewise considered + optimized out, except not-saved registers have a different string + representation and related error strings. E.g., we'll print them as + <not-saved> instead of <optimized out>, as in: + + (gdb) p/x $rax + $1 = <not saved> + (gdb) info registers rax + rax <not saved> + + If the debug info describes a variable as being in such a register, + we'll still print the variable as <optimized out>. IOW, <not saved> + is reserved for inspecting registers at the machine level. + + When comparing value contents, optimized out chunks, unavailable + chunks, and valid contents data are all considered different. See + value_contents_eq for more info. +*/ + /* The structure which defines the type of a value. It should never be possible for a program lval value to survive over a call to the inferior (i.e. to be put into the history list or an internal @@ -181,14 +229,6 @@ struct lval_funcs TOVAL is not considered as an lvalue. */ void (*write) (struct value *toval, struct value *fromval); - /* Check the validity of some bits in VALUE. This should return 1 - if all the bits starting at OFFSET and extending for LENGTH bits - are valid, or 0 if any bit is invalid. */ - int (*check_validity) (const struct value *value, int offset, int length); - - /* Return 1 if any bit in VALUE is valid, 0 if they are all invalid. */ - int (*check_any_valid) (const struct value *value); - /* If non-NULL, this is used to implement pointer indirection for this value. This method may return NULL, in which case value_ind will fall back to ordinary indirection. */ @@ -327,16 +367,29 @@ extern int value_fetch_lazy (struct value *val); exist in the program, at least partially. If the value is lazy, this may fetch it now. */ extern int value_optimized_out (struct value *value); -extern void set_value_optimized_out (struct value *value, int val); -/* Like value_optimized_out, but don't fetch the value even if it is - lazy. Mainly useful for constructing other values using VALUE as - template. */ -extern int value_optimized_out_const (const struct value *value); +/* Given a value, return true if any of the contents bits starting at + OFFSET and extending for LENGTH bits is optimized out, false + otherwise. */ + +extern int value_bits_any_optimized_out (const struct value *value, + int bit_offset, int bit_length); + +/* Like value_optimized_out, but return true iff the whole value is + optimized out. */ +extern int value_entirely_optimized_out (struct value *value); + +/* Mark VALUE's content bytes starting at OFFSET and extending for + LENGTH bytes as optimized out. */ + +extern void mark_value_bytes_optimized_out (struct value *value, + int offset, int length); + +/* Mark VALUE's content bits starting at OFFSET and extending for + LENGTH bits as optimized out. */ -/* Like value_optimized_out, but return false if any bit in the object - is valid. */ -extern int value_entirely_optimized_out (const struct value *value); +extern void mark_value_bits_optimized_out (struct value *value, + int offset, int length); /* Set or return field indicating whether a variable is initialized or not, based on debugging information supplied by the compiler. @@ -416,13 +469,6 @@ extern struct value *coerce_ref (struct value *value); extern struct value *coerce_array (struct value *value); /* Given a value, determine whether the bits starting at OFFSET and - extending for LENGTH bits are valid. This returns nonzero if all - bits in the given range are valid, zero if any bit is invalid. */ - -extern int value_bits_valid (const struct value *value, - int offset, int length); - -/* Given a value, determine whether the bits starting at OFFSET and extending for LENGTH bits are a synthetic pointer. */ extern int value_bits_synthetic_pointer (const struct value *value, @@ -473,35 +519,53 @@ extern void mark_value_bits_unavailable (struct value *value, its enclosing type chunk, you'd do: int len = TYPE_LENGTH (check_typedef (value_enclosing_type (val))); - value_available_contents (val, 0, val, 0, len); + value_contents_eq (val, 0, val, 0, len); + + Returns true iff the set of available/valid contents match. + + Optimized-out contents are equal to optimized-out contents, and are + not equal to non-optimized-out contents. - Returns true iff the set of available contents match. Unavailable - contents compare equal with unavailable contents, and different - with any available byte. For example, if 'x's represent an - unavailable byte, and 'V' and 'Z' represent different available - bytes, in a value with length 16: + Unavailable contente are equal to unavailable contents, and are not + equal to non-unavailable contents. - offset: 0 4 8 12 16 - contents: xxxxVVVVxxxxVVZZ + For example, if 'x's represent an unavailable byte, and 'V' and 'Z' + represent different available/valid bytes, in a value with length + 16: + + offset: 0 4 8 12 16 + contents: xxxxVVVVxxxxVVZZ then: - value_available_contents_eq(val, 0, val, 8, 6) => 1 - value_available_contents_eq(val, 0, val, 4, 4) => 1 - value_available_contents_eq(val, 0, val, 8, 8) => 0 - value_available_contents_eq(val, 4, val, 12, 2) => 1 - value_available_contents_eq(val, 4, val, 12, 4) => 0 - value_available_contents_eq(val, 3, val, 4, 4) => 0 - - We only know whether a value chunk is available if we've tried to - read it. As this routine is used by printing routines, which may - be printing values in the value history, long after the inferior is - gone, it works with const values. Therefore, this routine must not - be called with lazy values. */ - -extern int value_available_contents_eq (const struct value *val1, int offset1, - const struct value *val2, int offset2, - int length); + value_contents_eq(val, 0, val, 8, 6) => 1 + value_contents_eq(val, 0, val, 4, 4) => 0 + value_contents_eq(val, 0, val, 8, 8) => 0 + value_contents_eq(val, 4, val, 12, 2) => 1 + value_contents_eq(val, 4, val, 12, 4) => 0 + value_contents_eq(val, 3, val, 4, 4) => 0 + + If 'x's represent an unavailable byte, 'o' represents an optimized + out byte, in a value with length 8: + + offset: 0 4 8 + contents: xxxxoooo + + then: + + value_contents_eq(val, 0, val, 2, 2) => 1 + value_contents_eq(val, 4, val, 6, 2) => 1 + value_contents_eq(val, 0, val, 4, 4) => 0 + + We only know whether a value chunk is unavailable or optimized out + if we've tried to read it. As this routine is used by printing + routines, which may be printing values in the value history, long + after the inferior is gone, it works with const values. Therefore, + this routine must not be called with lazy values. */ + +extern int value_contents_eq (const struct value *val1, int offset1, + const struct value *val2, int offset2, + int length); /* Read LENGTH bytes of memory starting at MEMADDR into BUFFER, which is (or will be copied to) VAL's contents buffer offset by |