* [patchv2] Fix crash on optimized-out entry data values @ 2014-07-09 10:33 Jan Kratochvil 2014-07-09 11:52 ` Pedro Alves 0 siblings, 1 reply; 28+ messages in thread From: Jan Kratochvil @ 2014-07-09 10:33 UTC (permalink / raw) To: gdb-patches [-- Attachment #1: Type: text/plain, Size: 813 bytes --] Hi, former post of this fix was for: [patch+7.8] Fix crash on optimized-out entry data values https://sourceware.org/ml/gdb-patches/2014-06/msg00797.html = https://bugzilla.redhat.com/show_bug.cgi?id=1111910 this can happen for real world -O2 -g executables: #9 0x0000003b6e0998b2 in wxEntry (argc=@0x7fffffffd86c: 1, argc@entry=@0x7fffffffd86c: <optimized out>, ^^^^^^^^^^^^^^^ argv=<optimized out>) at src/common/init.cpp:460 GDB did crash in such case. But the fix was wrong/regressing as shown here: https://bugzilla.redhat.com/show_bug.cgi?id=1117192 https://bugzilla.redhat.com/attachment.cgi?id=916298 (at the bottom) Here is a new fix, also with a new testcase reproducing crash of the wrong fix above. No regressions on {x86_64,x86_64-m32,i686}-fedorarawhide-linux-gnu. Jan [-- Attachment #2: optimfix2.patch --] [-- Type: text/plain, Size: 31989 bytes --] gdb/ 2014-07-09 Jan Kratochvil <jan.kratochvil@redhat.com> * value.c (struct value): Extend the comment for fields optimized_out and unavailable. (value_available_contents_bits_eq): Handle OPTIMIZED_OUT values with empty UNAVAILABLE as special cases. gdb/testsuite/ 2014-07-09 Jan Kratochvil <jan.kratochvil@redhat.com> * gdb.arch/amd64-entry-value-paramref.S: New file. * gdb.arch/amd64-entry-value-paramref.cc: New file. * gdb.arch/amd64-entry-value-paramref.exp: New file. * gdb.arch/amd64-optimout-repeat.S: New file. * gdb.arch/amd64-optimout-repeat.c: New file. * gdb.arch/amd64-optimout-repeat.exp: New file. diff --git a/gdb/value.c b/gdb/value.c index 557056f..4b7495e 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -198,12 +198,13 @@ struct value 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 + actually fully 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. */ + error strings. It is true also for only partially optimized + out variables - see the 'unavailable' field below. */ unsigned int optimized_out : 1; /* If value is a variable, is it initialized or not. */ @@ -334,7 +335,10 @@ struct value valid if lazy is nonzero. */ gdb_byte *contents; - /* Unavailable ranges in CONTENTS. We mark unavailable ranges, + /* If OPTIMIZED_OUT is false then UNAVAILABLE must be VEC_empty + (not necessarily NULL). If OPTIMIZED_OUT is true then VEC_empty + UNAVAILABLE means the whole value range. Otherwise it specifies + 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. */ @@ -701,6 +705,15 @@ value_available_contents_bits_eq (const struct value *val1, int offset1, /* See function description in value.h. */ gdb_assert (!val1->lazy && !val2->lazy); + gdb_assert (val1->optimized_out || VEC_empty (range_s, val1->unavailable)); + gdb_assert (val2->optimized_out || VEC_empty (range_s, val2->unavailable)); + if (val1->optimized_out != val2->optimized_out) + return 0; + if (val1->optimized_out && val2->optimized_out + && VEC_empty (range_s, val1->unavailable) + && VEC_empty (range_s, val2->unavailable)) + return 1; + while (length > 0) { range_s *r1, *r2; diff --git a/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.S b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.S new file mode 100644 index 0000000..a1e9d0a --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.S @@ -0,0 +1,459 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + 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/>. */ + +/* This file is compiled from gdb.arch/amd64-entry-value-paramref.cc + using -g -dA -S -O2. + Additionally it has been patched. */ + + .file "amd64-entry-value-paramref.cc" + .text +.Ltext0: + .p2align 4,,15 + .type _ZL3barRi.constprop.0, @function +_ZL3barRi.constprop.0: +.LFB2: + .file 1 "gdb.arch/amd64-entry-value-paramref.cc" + # gdb.arch/amd64-entry-value-paramref.cc:21 + .loc 1 21 0 + .cfi_startproc +.LVL0: +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + # gdb.arch/amd64-entry-value-paramref.cc:23 + .loc 1 23 0 + movl vv(%rip), %eax + # gdb.arch/amd64-entry-value-paramref.cc:24 + .loc 1 24 0 + movq %rdi, p(%rip) + # gdb.arch/amd64-entry-value-paramref.cc:23 + .loc 1 23 0 + addl $1, %eax + movl %eax, vv(%rip) + # gdb.arch/amd64-entry-value-paramref.cc:25 + .loc 1 25 0 + movl (%rdi), %eax +# SUCC: EXIT [100.0%] + # gdb.arch/amd64-entry-value-paramref.cc:26 + .loc 1 26 0 + ret + .cfi_endproc +.LFE2: + .size _ZL3barRi.constprop.0, .-_ZL3barRi.constprop.0 + .section .text.startup,"ax",@progbits + .p2align 4,,15 + .globl main + .type main, @function +main: +.LFB1: + # gdb.arch/amd64-entry-value-paramref.cc:30 + .loc 1 30 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + subq $16, %rsp + .cfi_def_cfa_offset 24 +.LBB2: + # gdb.arch/amd64-entry-value-paramref.cc:32 + .loc 1 32 0 + leaq 12(%rsp), %rdi + # gdb.arch/amd64-entry-value-paramref.cc:31 + .loc 1 31 0 + movl $10, 12(%rsp) + # gdb.arch/amd64-entry-value-paramref.cc:32 + .loc 1 32 0 + call _ZL3barRi.constprop.0 +.LVL1: +.LBE2: + # gdb.arch/amd64-entry-value-paramref.cc:33 + .loc 1 33 0 + addq $16, %rsp + .cfi_def_cfa_offset 8 +# SUCC: EXIT [100.0%] + ret + .cfi_endproc +.LFE1: + .size main, .-main + .globl p + .bss + .align 8 + .type p, @object + .size p, 8 +p: + .zero 8 + .globl vv + .align 4 + .type vv, @object + .size vv, 4 +vv: + .zero 4 + .text +.Letext0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .long .Linfo_end - .Linfo_start # Length of Compilation Unit Info +.Linfo_start: + .value 0x4 # DWARF version number + .long .Ldebug_abbrev0 # Offset Into Abbrev. Section + .byte 0x8 # Pointer Size (in bytes) + .uleb128 0x1 # (DIE (0xb) DW_TAG_compile_unit) + .long .LASF0 # DW_AT_producer: "GNU C++ 4.8.2 20131212 (Red Hat 4.8.2-7) -mtune=generic -march=x86-64 -g -O2" + .byte 0x4 # DW_AT_language + .long .LASF1 # DW_AT_name: "gdb.arch/amd64-entry-value-paramref.cc" + .long .LASF2 # DW_AT_comp_dir: "" + .long .Ldebug_ranges0+0 # DW_AT_ranges + .quad 0 # DW_AT_low_pc + .long .Ldebug_line0 # DW_AT_stmt_list +DIE29: .uleb128 0x2 # (DIE (0x29) DW_TAG_subprogram) + .ascii "bar\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x15 # DW_AT_decl_line + .long DIE45 # DW_AT_type + .byte 0x1 # DW_AT_inline +DIE39: .uleb128 0x3 # (DIE (0x39) DW_TAG_formal_parameter) + .ascii "ref\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x15 # DW_AT_decl_line + .long DIE4c # DW_AT_type + .byte 0 # end of children of DIE 0x29 +DIE45: .uleb128 0x4 # (DIE (0x45) DW_TAG_base_type) + .byte 0x4 # DW_AT_byte_size + .byte 0x5 # DW_AT_encoding + .ascii "int\0" # DW_AT_name +DIE4c: .uleb128 0x5 # (DIE (0x4c) DW_TAG_const_type) + .long DIE51 # DW_AT_type +DIE51: .uleb128 0x6 # (DIE (0x51) DW_TAG_reference_type) + .byte 0x8 # DW_AT_byte_size + .long DIE45 # DW_AT_type +DIE57: .uleb128 0x7 # (DIE (0x57) DW_TAG_subprogram) + .long DIE29 # DW_AT_abstract_origin + .quad .LFB2 # DW_AT_low_pc + .quad .LFE2-.LFB2 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites +DIE72: .uleb128 0x8 # (DIE (0x72) DW_TAG_formal_parameter) + .long DIE39 # DW_AT_abstract_origin + .uleb128 0x1 # DW_AT_location + .byte 0x55 # DW_OP_reg5 + .byte 0 # end of children of DIE 0x57 +DIE7a: .uleb128 0x9 # (DIE (0x7a) DW_TAG_subprogram) + # DW_AT_external + .long .LASF3 # DW_AT_name: "main" + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x1d # DW_AT_decl_line + .long DIE45 # DW_AT_type + .quad .LFB1 # DW_AT_low_pc + .quad .LFE1-.LFB1 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites +DIE9b: .uleb128 0xa # (DIE (0x9b) DW_TAG_lexical_block) + .quad .LBB2 # DW_AT_low_pc + .quad .LBE2-.LBB2 # DW_AT_high_pc +DIEac: .uleb128 0xb # (DIE (0xac) DW_TAG_variable) + .ascii "var\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x1f # DW_AT_decl_line + .long DIE45 # DW_AT_type + .uleb128 0x2 # DW_AT_location + .byte 0x91 # DW_OP_fbreg + .sleb128 -12 +DIEba: .uleb128 0xc # (DIE (0xba) DW_TAG_GNU_call_site) + .quad .LVL1 # DW_AT_low_pc + .long DIE57 # DW_AT_abstract_origin +DIEc7: .uleb128 0xd # (DIE (0xc7) DW_TAG_GNU_call_site_parameter) + .uleb128 0x1 # DW_AT_location + .byte 0x55 # DW_OP_reg5 + .uleb128 0x2 # DW_AT_GNU_call_site_value + .byte 0x91 # DW_OP_fbreg + .sleb128 -12 +#if 0 + .uleb128 0x1 # DW_AT_GNU_call_site_data_value + .byte 0x3a # DW_OP_lit10 +#else + .uleb128 1f - 2f # DW_AT_GNU_call_site_data_value +2: + .byte 0xf3 # DW_OP_GNU_entry_value + .uleb128 1f - 3f +3: + .byte 0x55 # DW_OP_reg5 +1: +#endif + .byte 0 # end of children of DIE 0xba + .byte 0 # end of children of DIE 0x9b + .byte 0 # end of children of DIE 0x7a +DIEd2: .uleb128 0xe # (DIE (0xd2) DW_TAG_variable) + .ascii "vv\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x12 # DW_AT_decl_line + .long DIEe6 # DW_AT_type + # DW_AT_external + .uleb128 0x9 # DW_AT_location + .byte 0x3 # DW_OP_addr + .quad vv +DIEe6: .uleb128 0xf # (DIE (0xe6) DW_TAG_volatile_type) + .long DIE45 # DW_AT_type +DIEeb: .uleb128 0xe # (DIE (0xeb) DW_TAG_variable) + .ascii "p\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x12 # DW_AT_decl_line + .long DIEfe # DW_AT_type + # DW_AT_external + .uleb128 0x9 # DW_AT_location + .byte 0x3 # DW_OP_addr + .quad p +DIEfe: .uleb128 0x10 # (DIE (0xfe) DW_TAG_pointer_type) + .byte 0x8 # DW_AT_byte_size + .long DIEe6 # DW_AT_type + .byte 0 # end of children of DIE 0xb +.Linfo_end: + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .uleb128 0x1 # (abbrev code) + .uleb128 0x11 # (TAG: DW_TAG_compile_unit) + .byte 0x1 # DW_children_yes + .uleb128 0x25 # (DW_AT_producer) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x13 # (DW_AT_language) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x1b # (DW_AT_comp_dir) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x55 # (DW_AT_ranges) + .uleb128 0x17 # (DW_FORM_sec_offset) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x10 # (DW_AT_stmt_list) + .uleb128 0x17 # (DW_FORM_sec_offset) + .byte 0 + .byte 0 + .uleb128 0x2 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x20 # (DW_AT_inline) + .uleb128 0xb # (DW_FORM_data1) + .byte 0 + .byte 0 + .uleb128 0x3 # (abbrev code) + .uleb128 0x5 # (TAG: DW_TAG_formal_parameter) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x4 # (abbrev code) + .uleb128 0x24 # (TAG: DW_TAG_base_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3e # (DW_AT_encoding) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .byte 0 + .byte 0 + .uleb128 0x5 # (abbrev code) + .uleb128 0x26 # (TAG: DW_TAG_const_type) + .byte 0 # DW_children_no + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x6 # (abbrev code) + .uleb128 0x10 # (TAG: DW_TAG_reference_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x7 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x31 # (DW_AT_abstract_origin) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .byte 0 + .byte 0 + .uleb128 0x8 # (abbrev code) + .uleb128 0x5 # (TAG: DW_TAG_formal_parameter) + .byte 0 # DW_children_no + .uleb128 0x31 # (DW_AT_abstract_origin) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x18 # (DW_FORM_exprloc) + .byte 0 + .byte 0 + .uleb128 0x9 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x3f # (DW_AT_external) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .byte 0 + .byte 0 + .uleb128 0xa # (abbrev code) + .uleb128 0xb # (TAG: DW_TAG_lexical_block) + .byte 0x1 # DW_children_yes + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .byte 0 + .byte 0 + .uleb128 0xb # (abbrev code) + .uleb128 0x34 # (TAG: DW_TAG_variable) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x18 # (DW_FORM_exprloc) + .byte 0 + .byte 0 + .uleb128 0xc # (abbrev code) + .uleb128 0x4109 # (TAG: DW_TAG_GNU_call_site) + .byte 0x1 # DW_children_yes + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x31 # (DW_AT_abstract_origin) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0xd # (abbrev code) + .uleb128 0x410a # (TAG: DW_TAG_GNU_call_site_parameter) + .byte 0 # DW_children_no + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2111 # (DW_AT_GNU_call_site_value) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2112 # (DW_AT_GNU_call_site_data_value) + .uleb128 0x18 # (DW_FORM_exprloc) + .byte 0 + .byte 0 + .uleb128 0xe # (abbrev code) + .uleb128 0x34 # (TAG: DW_TAG_variable) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x3f # (DW_AT_external) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x18 # (DW_FORM_exprloc) + .byte 0 + .byte 0 + .uleb128 0xf # (abbrev code) + .uleb128 0x35 # (TAG: DW_TAG_volatile_type) + .byte 0 # DW_children_no + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x10 # (abbrev code) + .uleb128 0xf # (TAG: DW_TAG_pointer_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .byte 0 + .section .debug_aranges,"",@progbits + .long 0x3c # Length of Address Ranges Info + .value 0x2 # DWARF Version + .long .Ldebug_info0 # Offset of Compilation Unit Info + .byte 0x8 # Size of Address + .byte 0 # Size of Segment Descriptor + .value 0 # Pad to 16 byte boundary + .value 0 + .quad .Ltext0 # Address + .quad .Letext0-.Ltext0 # Length + .quad .LFB1 # Address + .quad .LFE1-.LFB1 # Length + .quad 0 + .quad 0 + .section .debug_ranges,"",@progbits +.Ldebug_ranges0: + .quad .Ltext0 # Offset 0 + .quad .Letext0 + .quad .LFB1 # Offset 0x10 + .quad .LFE1 + .quad 0 + .quad 0 + .section .debug_line,"",@progbits +.Ldebug_line0: + .section .debug_str,"MS",@progbits,1 +.LASF1: + .string "gdb.arch/amd64-entry-value-paramref.cc" +.LASF2: + .string "" +.LASF0: + .string "GNU C++ 4.8.2 20131212 (Red Hat 4.8.2-7) -mtune=generic -march=x86-64 -g -O2" +.LASF3: + .string "main" + .ident "GCC: (GNU) 4.8.2 20131212 (Red Hat 4.8.2-7)" + .section .note.GNU-stack,"",@progbits diff --git a/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.cc b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.cc new file mode 100644 index 0000000..aa473a3 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.cc @@ -0,0 +1,33 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + 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/>. */ + +volatile int vv, *p; + +static __attribute__((noinline)) int +bar (int &ref) +{ + vv++; /* break-here */ + p = &ref; + return ref; +} + +int +main (void) +{ + int var = 10; + return bar (var); +} diff --git a/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.exp b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.exp new file mode 100644 index 0000000..f06247d --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.exp @@ -0,0 +1,35 @@ +# Copyright (C) 2014 Free Software Foundation, Inc. +# +# 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/>. + +standard_testfile .S .cc + +if { ![istarget x86_64-*-* ] || ![is_lp64_target] } { + verbose "Skipping amd64-entry-value-paramref." + return +} + +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} "c++"] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +set srcfile $srcfile2 +gdb_breakpoint [gdb_get_line_number "break-here"] + +gdb_continue_to_breakpoint "break-here" ".* break-here .*" +gdb_test "frame" {bar \(ref=@0x[0-9a-f]+: 10, ref@entry=@0x[0-9a-f]+: <optimized out>\) at .*} diff --git a/gdb/testsuite/gdb.arch/amd64-optimout-repeat.S b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.S new file mode 100755 index 0000000..2f8f4d2 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.S @@ -0,0 +1,297 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012-2014 Free Software Foundation, Inc. + + 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/>. */ + +/* This file is compiled from gdb.arch/amd64-entry-value-param.c + using -g -dA -S -O2. */ + + .file "amd64-optimout-repeat.c" + .text +.Ltext0: + .section .text.unlikely,"ax",@progbits +.LCOLDB0: + .section .text.startup,"ax",@progbits +.LHOTB0: + .p2align 4,,15 + .section .text.unlikely +.Ltext_cold0: + .section .text.startup + .globl main + .type main, @function +main: +.LFB0: + .file 1 "gdb.arch/amd64-optimout-repeat.c" + # gdb.arch/amd64-optimout-repeat.c:20 + .loc 1 20 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) +.LVL0: + # gdb.arch/amd64-optimout-repeat.c:29 + .loc 1 29 0 + xorl %eax, %eax +# SUCC: EXIT [100.0%] + ret + .cfi_endproc +.LFE0: + .size main, .-main + .section .text.unlikely +.LCOLDE0: + .section .text.startup +.LHOTE0: + .text +.Letext0: + .section .text.unlikely +.Letext_cold0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .long 0x97 # Length of Compilation Unit Info + .value 0x4 # DWARF version number + .long .Ldebug_abbrev0 # Offset Into Abbrev. Section + .byte 0x8 # Pointer Size (in bytes) + .uleb128 0x1 # (DIE (0xb) DW_TAG_compile_unit) + .long .LASF1 # DW_AT_producer: "GNU C 4.9.1 20140709 (prerelease) -mtune=generic -march=x86-64 -g -O2" + .byte 0x1 # DW_AT_language + .long .LASF2 # DW_AT_name: "gdb.arch/amd64-optimout-repeat.c" + .long .LASF3 # DW_AT_comp_dir: "" + .long .Ldebug_ranges0+0 # DW_AT_ranges + .quad 0 # DW_AT_low_pc + .long .Ldebug_line0 # DW_AT_stmt_list + .uleb128 0x2 # (DIE (0x29) DW_TAG_subprogram) + # DW_AT_external + .long .LASF4 # DW_AT_name: "main" + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-optimout-repeat.c) + .byte 0x13 # DW_AT_decl_line + # DW_AT_prototyped + .long 0x7c # DW_AT_type + .quad .LFB0 # DW_AT_low_pc + .quad .LFE0-.LFB0 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites + .long 0x7c # DW_AT_sibling + .uleb128 0x3 # (DIE (0x4a) DW_TAG_structure_type) + .value 0x404 # DW_AT_byte_size + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-optimout-repeat.c) + .byte 0x15 # DW_AT_decl_line + .long 0x6a # DW_AT_sibling + .uleb128 0x4 # (DIE (0x53) DW_TAG_member) + .ascii "i\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-optimout-repeat.c) + .byte 0x17 # DW_AT_decl_line + .long 0x7c # DW_AT_type + .byte 0 # DW_AT_data_member_location + .uleb128 0x4 # (DIE (0x5d) DW_TAG_member) + .ascii "xxx\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-optimout-repeat.c) + .byte 0x18 # DW_AT_decl_line + .long 0x83 # DW_AT_type + .byte 0x4 # DW_AT_data_member_location + .byte 0 # end of children of DIE 0x4a + .uleb128 0x5 # (DIE (0x6a) DW_TAG_variable) + .ascii "v\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-optimout-repeat.c) + .byte 0x1a # DW_AT_decl_line + .long 0x4a # DW_AT_type + .uleb128 0x7 # DW_AT_location + .byte 0x30 # DW_OP_lit0 + .byte 0x9f # DW_OP_stack_value + .byte 0x93 # DW_OP_piece + .uleb128 0x4 + .byte 0x93 # DW_OP_piece + .uleb128 0x400 + .byte 0 # end of children of DIE 0x29 + .uleb128 0x6 # (DIE (0x7c) DW_TAG_base_type) + .byte 0x4 # DW_AT_byte_size + .byte 0x5 # DW_AT_encoding + .ascii "int\0" # DW_AT_name + .uleb128 0x7 # (DIE (0x83) DW_TAG_array_type) + .long 0x7c # DW_AT_type + .long 0x93 # DW_AT_sibling + .uleb128 0x8 # (DIE (0x8c) DW_TAG_subrange_type) + .long 0x93 # DW_AT_type + .byte 0xff # DW_AT_upper_bound + .byte 0 # end of children of DIE 0x83 + .uleb128 0x9 # (DIE (0x93) DW_TAG_base_type) + .byte 0x8 # DW_AT_byte_size + .byte 0x7 # DW_AT_encoding + .long .LASF0 # DW_AT_name: "sizetype" + .byte 0 # end of children of DIE 0xb + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .uleb128 0x1 # (abbrev code) + .uleb128 0x11 # (TAG: DW_TAG_compile_unit) + .byte 0x1 # DW_children_yes + .uleb128 0x25 # (DW_AT_producer) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x13 # (DW_AT_language) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x1b # (DW_AT_comp_dir) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x55 # (DW_AT_ranges) + .uleb128 0x17 # (DW_FORM_sec_offset) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x10 # (DW_AT_stmt_list) + .uleb128 0x17 # (DW_FORM_sec_offset) + .byte 0 + .byte 0 + .uleb128 0x2 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x3f # (DW_AT_external) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x27 # (DW_AT_prototyped) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x1 # (DW_AT_sibling) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x3 # (abbrev code) + .uleb128 0x13 # (TAG: DW_TAG_structure_type) + .byte 0x1 # DW_children_yes + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0x5 # (DW_FORM_data2) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x1 # (DW_AT_sibling) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x4 # (abbrev code) + .uleb128 0xd # (TAG: DW_TAG_member) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x38 # (DW_AT_data_member_location) + .uleb128 0xb # (DW_FORM_data1) + .byte 0 + .byte 0 + .uleb128 0x5 # (abbrev code) + .uleb128 0x34 # (TAG: DW_TAG_variable) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x18 # (DW_FORM_exprloc) + .byte 0 + .byte 0 + .uleb128 0x6 # (abbrev code) + .uleb128 0x24 # (TAG: DW_TAG_base_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3e # (DW_AT_encoding) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .byte 0 + .byte 0 + .uleb128 0x7 # (abbrev code) + .uleb128 0x1 # (TAG: DW_TAG_array_type) + .byte 0x1 # DW_children_yes + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x1 # (DW_AT_sibling) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x8 # (abbrev code) + .uleb128 0x21 # (TAG: DW_TAG_subrange_type) + .byte 0 # DW_children_no + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x2f # (DW_AT_upper_bound) + .uleb128 0xb # (DW_FORM_data1) + .byte 0 + .byte 0 + .uleb128 0x9 # (abbrev code) + .uleb128 0x24 # (TAG: DW_TAG_base_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3e # (DW_AT_encoding) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .byte 0 + .byte 0 + .byte 0 + .section .debug_aranges,"",@progbits + .long 0x2c # Length of Address Ranges Info + .value 0x2 # DWARF Version + .long .Ldebug_info0 # Offset of Compilation Unit Info + .byte 0x8 # Size of Address + .byte 0 # Size of Segment Descriptor + .value 0 # Pad to 16 byte boundary + .value 0 + .quad .LFB0 # Address + .quad .LFE0-.LFB0 # Length + .quad 0 + .quad 0 + .section .debug_ranges,"",@progbits +.Ldebug_ranges0: + .quad .LFB0 # Offset 0 + .quad .LFE0 + .quad 0 + .quad 0 + .section .debug_line,"",@progbits +.Ldebug_line0: + .section .debug_str,"MS",@progbits,1 +.LASF0: + .string "sizetype" +.LASF2: + .string "gdb.arch/amd64-optimout-repeat.c" +.LASF1: + .string "GNU C 4.9.1 20140709 (prerelease) -mtune=generic -march=x86-64 -g -O2" +.LASF3: + .string "" +.LASF4: + .string "main" + .ident "GCC: (GNU) 4.9.1 20140709 (prerelease)" + .section .note.GNU-stack,"",@progbits diff --git a/gdb/testsuite/gdb.arch/amd64-optimout-repeat.c b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.c new file mode 100644 index 0000000..a32b6de --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.c @@ -0,0 +1,29 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + 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/>. */ + +int +main (void) +{ + struct + { + int i; + int xxx[0x100]; + } + v = { 0 }; + + return v.i; +} diff --git a/gdb/testsuite/gdb.arch/amd64-optimout-repeat.exp b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.exp new file mode 100644 index 0000000..f3c93a4 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.exp @@ -0,0 +1,36 @@ +# Copyright (C) 2014 Free Software Foundation, Inc. +# +# 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/>. + +standard_testfile .S .c +set opts {} + +if [info exists COMPILE] { + # make check RUNTESTFLAGS="gdb.arch/amd64-optimout-repeat.exp COMPILE=1" + set srcfile ${srcfile2} + lappend opts debug optimize=-O2 +} elseif { ![istarget x86_64-*-* ] || ![is_lp64_target] } { + verbose "Skipping amd64-optimout-repeat." + return +} + +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} $opts] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +gdb_test "print v" { = {i = 0, xxx = {<optimized out> <repeats 256 times>}}} ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [patchv2] Fix crash on optimized-out entry data values 2014-07-09 10:33 [patchv2] Fix crash on optimized-out entry data values Jan Kratochvil @ 2014-07-09 11:52 ` Pedro Alves 2014-07-09 15:31 ` Jan Kratochvil 0 siblings, 1 reply; 28+ messages in thread From: Pedro Alves @ 2014-07-09 11:52 UTC (permalink / raw) To: Jan Kratochvil, gdb-patches On 07/09/2014 11:33 AM, Jan Kratochvil wrote: > Hi, > > former post of this fix was for: > [patch+7.8] Fix crash on optimized-out entry data values > https://sourceware.org/ml/gdb-patches/2014-06/msg00797.html > = > https://bugzilla.redhat.com/show_bug.cgi?id=1111910 > this can happen for real world -O2 -g executables: > #9 0x0000003b6e0998b2 in wxEntry (argc=@0x7fffffffd86c: 1, > argc@entry=@0x7fffffffd86c: <optimized out>, > ^^^^^^^^^^^^^^^ > argv=<optimized out>) at src/common/init.cpp:460 > GDB did crash in such case. > > But the fix was wrong/regressing as shown here: > https://bugzilla.redhat.com/show_bug.cgi?id=1117192 > https://bugzilla.redhat.com/attachment.cgi?id=916298 (at the bottom) > > Here is a new fix, also with a new testcase reproducing crash of the wrong fix > above. > > No regressions on {x86_64,x86_64-m32,i686}-fedorarawhide-linux-gnu. > > > Jan > > > optimfix2.patch > > > gdb/ > 2014-07-09 Jan Kratochvil <jan.kratochvil@redhat.com> > > * value.c (struct value): Extend the comment for fields optimized_out > and unavailable. > (value_available_contents_bits_eq): Handle OPTIMIZED_OUT values with > empty UNAVAILABLE as special cases. > > gdb/testsuite/ > 2014-07-09 Jan Kratochvil <jan.kratochvil@redhat.com> > > * gdb.arch/amd64-entry-value-paramref.S: New file. > * gdb.arch/amd64-entry-value-paramref.cc: New file. > * gdb.arch/amd64-entry-value-paramref.exp: New file. > * gdb.arch/amd64-optimout-repeat.S: New file. > * gdb.arch/amd64-optimout-repeat.c: New file. > * gdb.arch/amd64-optimout-repeat.exp: New file. > > diff --git a/gdb/value.c b/gdb/value.c > index 557056f..4b7495e 100644 > --- a/gdb/value.c > +++ b/gdb/value.c > @@ -198,12 +198,13 @@ struct value > 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 > + actually fully 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. */ > + error strings. It is true also for only partially optimized > + out variables - see the 'unavailable' field below. */ > unsigned int optimized_out : 1; > > /* If value is a variable, is it initialized or not. */ > @@ -334,7 +335,10 @@ struct value > valid if lazy is nonzero. */ > gdb_byte *contents; > > - /* Unavailable ranges in CONTENTS. We mark unavailable ranges, > + /* If OPTIMIZED_OUT is false then UNAVAILABLE must be VEC_empty > + (not necessarily NULL). Hmm, why? We can collect only part of a non-optimized out value. What am I missing? Does this manage to somehow pass the tests under gdb.trace/ (against --target_board=native-gdbserver) ? > If OPTIMIZED_OUT is true then VEC_empty > + UNAVAILABLE means the whole value range. Otherwise it specifies > + 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. */ > @@ -701,6 +705,15 @@ value_available_contents_bits_eq (const struct value *val1, int offset1, > /* See function description in value.h. */ > gdb_assert (!val1->lazy && !val2->lazy); > > + gdb_assert (val1->optimized_out || VEC_empty (range_s, val1->unavailable)); > + gdb_assert (val2->optimized_out || VEC_empty (range_s, val2->unavailable)); -- Pedro Alves ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [patchv2] Fix crash on optimized-out entry data values 2014-07-09 11:52 ` Pedro Alves @ 2014-07-09 15:31 ` Jan Kratochvil 2014-07-11 16:07 ` [patchv3] " Jan Kratochvil 2014-07-14 18:47 ` [PATCH] Handle partially optimized out values similarly to unavailable values (Re: [patchv2] Fix crash on optimized-out entry data values) Pedro Alves 0 siblings, 2 replies; 28+ messages in thread From: Jan Kratochvil @ 2014-07-09 15:31 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches On Wed, 09 Jul 2014 13:52:00 +0200, Pedro Alves wrote: > On 07/09/2014 11:33 AM, Jan Kratochvil wrote: > > --- a/gdb/value.c > > +++ b/gdb/value.c > > @@ -198,12 +198,13 @@ struct value > > 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 > > + actually fully 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. */ > > + error strings. It is true also for only partially optimized > > + out variables - see the 'unavailable' field below. */ > > unsigned int optimized_out : 1; > > > > /* If value is a variable, is it initialized or not. */ > > @@ -334,7 +335,10 @@ struct value > > valid if lazy is nonzero. */ > > gdb_byte *contents; > > > > - /* Unavailable ranges in CONTENTS. We mark unavailable ranges, > > + /* If OPTIMIZED_OUT is false then UNAVAILABLE must be VEC_empty > > + (not necessarily NULL). > > Hmm, why? We can collect only part of a non-optimized out value. > What am I missing? I miss some documentation how these availability fields interact together. value_available_contents_bits_eq is written according to the struct value comments but they do not correspond to the real world struct value data. 'unavailable' suggests that optimized out variable should have it set to the full range of the variable. But struct value with OPTIMIZED_OUT field set still has UNAVAILABLE empty. As the variable is optimized out the CONTENTS is also NULL - this causes the crash reproduced by 'gdb.arch/amd64-entry-value-paramref.exp'. There are also check_validity and check_any_valid methods but how they are related to the 'unavailable' data field is also not documented. This patch was my second attempt to fix/document the availability stuff, it would be useful to suggest how it is designed. > Does this manage to somehow pass the tests > under gdb.trace/ (against --target_board=native-gdbserver) ? You are right, this patch regresses during gdbserver mode. > > If OPTIMIZED_OUT is true then VEC_empty > > + UNAVAILABLE means the whole value range. Otherwise it specifies > > + 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. */ > > @@ -701,6 +705,15 @@ value_available_contents_bits_eq (const struct value *val1, int offset1, > > /* See function description in value.h. */ > > gdb_assert (!val1->lazy && !val2->lazy); > > > > + gdb_assert (val1->optimized_out || VEC_empty (range_s, val1->unavailable)); > > + gdb_assert (val2->optimized_out || VEC_empty (range_s, val2->unavailable)); Thanks, Jan ^ permalink raw reply [flat|nested] 28+ messages in thread
* [patchv3] Fix crash on optimized-out entry data values 2014-07-09 15:31 ` Jan Kratochvil @ 2014-07-11 16:07 ` Jan Kratochvil 2014-07-14 7:02 ` Yao Qi 2014-07-14 18:12 ` Pedro Alves 2014-07-14 18:47 ` [PATCH] Handle partially optimized out values similarly to unavailable values (Re: [patchv2] Fix crash on optimized-out entry data values) Pedro Alves 1 sibling, 2 replies; 28+ messages in thread From: Jan Kratochvil @ 2014-07-11 16:07 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches [-- Attachment #1: Type: text/plain, Size: 2068 bytes --] On Wed, 09 Jul 2014 17:31:21 +0200, Jan Kratochvil wrote: > On Wed, 09 Jul 2014 13:52:00 +0200, Pedro Alves wrote: > > On 07/09/2014 11:33 AM, Jan Kratochvil wrote: > > > --- a/gdb/value.c > > > +++ b/gdb/value.c > > > @@ -198,12 +198,13 @@ struct value > > > 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 > > > + actually fully 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. */ > > > + error strings. It is true also for only partially optimized > > > + out variables - see the 'unavailable' field below. */ > > > unsigned int optimized_out : 1; > > > > > > /* If value is a variable, is it initialized or not. */ > > > @@ -334,7 +335,10 @@ struct value > > > valid if lazy is nonzero. */ > > > gdb_byte *contents; > > > > > > - /* Unavailable ranges in CONTENTS. We mark unavailable ranges, > > > + /* If OPTIMIZED_OUT is false then UNAVAILABLE must be VEC_empty > > > + (not necessarily NULL). > > > > Hmm, why? We can collect only part of a non-optimized out value. > > What am I missing? > > I miss some documentation how these availability fields interact together. From a comment in mail Message-Id: <201102071427.55970.pedro@codesourcery.com> We give preference to printing <optimized out> rather than <unavailable>, since if a value had been optimized out at compile time, it can never be collected at run-time. it seems it is just reversed, that 'unavailable' can exist only for !optimized_out and it cannot exist for for optimized_out values. > You are right, this patch regresses during gdbserver mode. It PASSes now even in gdbserver mode. Thanks, Jan [-- Attachment #2: optimfix3.patch --] [-- Type: text/plain, Size: 31821 bytes --] gdb/ 2014-07-09 Jan Kratochvil <jan.kratochvil@redhat.com> * value.c (struct value): Extend the comment for fields optimized_out and unavailable. (value_available_contents_bits_eq): Handle OPTIMIZED_OUT values as special cases. gdb/testsuite/ 2014-07-09 Jan Kratochvil <jan.kratochvil@redhat.com> * gdb.arch/amd64-entry-value-paramref.S: New file. * gdb.arch/amd64-entry-value-paramref.cc: New file. * gdb.arch/amd64-entry-value-paramref.exp: New file. * gdb.arch/amd64-optimout-repeat.S: New file. * gdb.arch/amd64-optimout-repeat.c: New file. * gdb.arch/amd64-optimout-repeat.exp: New file. diff --git a/gdb/value.c b/gdb/value.c index 557056f..c017c75 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -198,12 +198,14 @@ struct value 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 + actually exist in the program at all. 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. */ + error strings. When it is zero it still maybe only partially + available (equally partially optimized out) - see the + 'unavailable' field below. */ unsigned int optimized_out : 1; /* If value is a variable, is it initialized or not. */ @@ -334,7 +336,9 @@ struct value valid if lazy is nonzero. */ gdb_byte *contents; - /* Unavailable ranges in CONTENTS. We mark unavailable ranges, + /* If OPTIMIZED_OUT is nonzero then UNAVAILABLE must be VEC_empty + (not necessarily NULL). Otherwise it specifies + 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. */ @@ -701,6 +705,13 @@ value_available_contents_bits_eq (const struct value *val1, int offset1, /* See function description in value.h. */ gdb_assert (!val1->lazy && !val2->lazy); + gdb_assert (!val1->optimized_out || VEC_empty (range_s, val1->unavailable)); + gdb_assert (!val2->optimized_out || VEC_empty (range_s, val2->unavailable)); + if (val1->optimized_out != val2->optimized_out) + return 0; + if (val1->optimized_out && val2->optimized_out) + return 1; + while (length > 0) { range_s *r1, *r2; diff --git a/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.S b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.S new file mode 100644 index 0000000..a1e9d0a --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.S @@ -0,0 +1,459 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + 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/>. */ + +/* This file is compiled from gdb.arch/amd64-entry-value-paramref.cc + using -g -dA -S -O2. + Additionally it has been patched. */ + + .file "amd64-entry-value-paramref.cc" + .text +.Ltext0: + .p2align 4,,15 + .type _ZL3barRi.constprop.0, @function +_ZL3barRi.constprop.0: +.LFB2: + .file 1 "gdb.arch/amd64-entry-value-paramref.cc" + # gdb.arch/amd64-entry-value-paramref.cc:21 + .loc 1 21 0 + .cfi_startproc +.LVL0: +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + # gdb.arch/amd64-entry-value-paramref.cc:23 + .loc 1 23 0 + movl vv(%rip), %eax + # gdb.arch/amd64-entry-value-paramref.cc:24 + .loc 1 24 0 + movq %rdi, p(%rip) + # gdb.arch/amd64-entry-value-paramref.cc:23 + .loc 1 23 0 + addl $1, %eax + movl %eax, vv(%rip) + # gdb.arch/amd64-entry-value-paramref.cc:25 + .loc 1 25 0 + movl (%rdi), %eax +# SUCC: EXIT [100.0%] + # gdb.arch/amd64-entry-value-paramref.cc:26 + .loc 1 26 0 + ret + .cfi_endproc +.LFE2: + .size _ZL3barRi.constprop.0, .-_ZL3barRi.constprop.0 + .section .text.startup,"ax",@progbits + .p2align 4,,15 + .globl main + .type main, @function +main: +.LFB1: + # gdb.arch/amd64-entry-value-paramref.cc:30 + .loc 1 30 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + subq $16, %rsp + .cfi_def_cfa_offset 24 +.LBB2: + # gdb.arch/amd64-entry-value-paramref.cc:32 + .loc 1 32 0 + leaq 12(%rsp), %rdi + # gdb.arch/amd64-entry-value-paramref.cc:31 + .loc 1 31 0 + movl $10, 12(%rsp) + # gdb.arch/amd64-entry-value-paramref.cc:32 + .loc 1 32 0 + call _ZL3barRi.constprop.0 +.LVL1: +.LBE2: + # gdb.arch/amd64-entry-value-paramref.cc:33 + .loc 1 33 0 + addq $16, %rsp + .cfi_def_cfa_offset 8 +# SUCC: EXIT [100.0%] + ret + .cfi_endproc +.LFE1: + .size main, .-main + .globl p + .bss + .align 8 + .type p, @object + .size p, 8 +p: + .zero 8 + .globl vv + .align 4 + .type vv, @object + .size vv, 4 +vv: + .zero 4 + .text +.Letext0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .long .Linfo_end - .Linfo_start # Length of Compilation Unit Info +.Linfo_start: + .value 0x4 # DWARF version number + .long .Ldebug_abbrev0 # Offset Into Abbrev. Section + .byte 0x8 # Pointer Size (in bytes) + .uleb128 0x1 # (DIE (0xb) DW_TAG_compile_unit) + .long .LASF0 # DW_AT_producer: "GNU C++ 4.8.2 20131212 (Red Hat 4.8.2-7) -mtune=generic -march=x86-64 -g -O2" + .byte 0x4 # DW_AT_language + .long .LASF1 # DW_AT_name: "gdb.arch/amd64-entry-value-paramref.cc" + .long .LASF2 # DW_AT_comp_dir: "" + .long .Ldebug_ranges0+0 # DW_AT_ranges + .quad 0 # DW_AT_low_pc + .long .Ldebug_line0 # DW_AT_stmt_list +DIE29: .uleb128 0x2 # (DIE (0x29) DW_TAG_subprogram) + .ascii "bar\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x15 # DW_AT_decl_line + .long DIE45 # DW_AT_type + .byte 0x1 # DW_AT_inline +DIE39: .uleb128 0x3 # (DIE (0x39) DW_TAG_formal_parameter) + .ascii "ref\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x15 # DW_AT_decl_line + .long DIE4c # DW_AT_type + .byte 0 # end of children of DIE 0x29 +DIE45: .uleb128 0x4 # (DIE (0x45) DW_TAG_base_type) + .byte 0x4 # DW_AT_byte_size + .byte 0x5 # DW_AT_encoding + .ascii "int\0" # DW_AT_name +DIE4c: .uleb128 0x5 # (DIE (0x4c) DW_TAG_const_type) + .long DIE51 # DW_AT_type +DIE51: .uleb128 0x6 # (DIE (0x51) DW_TAG_reference_type) + .byte 0x8 # DW_AT_byte_size + .long DIE45 # DW_AT_type +DIE57: .uleb128 0x7 # (DIE (0x57) DW_TAG_subprogram) + .long DIE29 # DW_AT_abstract_origin + .quad .LFB2 # DW_AT_low_pc + .quad .LFE2-.LFB2 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites +DIE72: .uleb128 0x8 # (DIE (0x72) DW_TAG_formal_parameter) + .long DIE39 # DW_AT_abstract_origin + .uleb128 0x1 # DW_AT_location + .byte 0x55 # DW_OP_reg5 + .byte 0 # end of children of DIE 0x57 +DIE7a: .uleb128 0x9 # (DIE (0x7a) DW_TAG_subprogram) + # DW_AT_external + .long .LASF3 # DW_AT_name: "main" + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x1d # DW_AT_decl_line + .long DIE45 # DW_AT_type + .quad .LFB1 # DW_AT_low_pc + .quad .LFE1-.LFB1 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites +DIE9b: .uleb128 0xa # (DIE (0x9b) DW_TAG_lexical_block) + .quad .LBB2 # DW_AT_low_pc + .quad .LBE2-.LBB2 # DW_AT_high_pc +DIEac: .uleb128 0xb # (DIE (0xac) DW_TAG_variable) + .ascii "var\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x1f # DW_AT_decl_line + .long DIE45 # DW_AT_type + .uleb128 0x2 # DW_AT_location + .byte 0x91 # DW_OP_fbreg + .sleb128 -12 +DIEba: .uleb128 0xc # (DIE (0xba) DW_TAG_GNU_call_site) + .quad .LVL1 # DW_AT_low_pc + .long DIE57 # DW_AT_abstract_origin +DIEc7: .uleb128 0xd # (DIE (0xc7) DW_TAG_GNU_call_site_parameter) + .uleb128 0x1 # DW_AT_location + .byte 0x55 # DW_OP_reg5 + .uleb128 0x2 # DW_AT_GNU_call_site_value + .byte 0x91 # DW_OP_fbreg + .sleb128 -12 +#if 0 + .uleb128 0x1 # DW_AT_GNU_call_site_data_value + .byte 0x3a # DW_OP_lit10 +#else + .uleb128 1f - 2f # DW_AT_GNU_call_site_data_value +2: + .byte 0xf3 # DW_OP_GNU_entry_value + .uleb128 1f - 3f +3: + .byte 0x55 # DW_OP_reg5 +1: +#endif + .byte 0 # end of children of DIE 0xba + .byte 0 # end of children of DIE 0x9b + .byte 0 # end of children of DIE 0x7a +DIEd2: .uleb128 0xe # (DIE (0xd2) DW_TAG_variable) + .ascii "vv\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x12 # DW_AT_decl_line + .long DIEe6 # DW_AT_type + # DW_AT_external + .uleb128 0x9 # DW_AT_location + .byte 0x3 # DW_OP_addr + .quad vv +DIEe6: .uleb128 0xf # (DIE (0xe6) DW_TAG_volatile_type) + .long DIE45 # DW_AT_type +DIEeb: .uleb128 0xe # (DIE (0xeb) DW_TAG_variable) + .ascii "p\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x12 # DW_AT_decl_line + .long DIEfe # DW_AT_type + # DW_AT_external + .uleb128 0x9 # DW_AT_location + .byte 0x3 # DW_OP_addr + .quad p +DIEfe: .uleb128 0x10 # (DIE (0xfe) DW_TAG_pointer_type) + .byte 0x8 # DW_AT_byte_size + .long DIEe6 # DW_AT_type + .byte 0 # end of children of DIE 0xb +.Linfo_end: + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .uleb128 0x1 # (abbrev code) + .uleb128 0x11 # (TAG: DW_TAG_compile_unit) + .byte 0x1 # DW_children_yes + .uleb128 0x25 # (DW_AT_producer) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x13 # (DW_AT_language) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x1b # (DW_AT_comp_dir) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x55 # (DW_AT_ranges) + .uleb128 0x17 # (DW_FORM_sec_offset) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x10 # (DW_AT_stmt_list) + .uleb128 0x17 # (DW_FORM_sec_offset) + .byte 0 + .byte 0 + .uleb128 0x2 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x20 # (DW_AT_inline) + .uleb128 0xb # (DW_FORM_data1) + .byte 0 + .byte 0 + .uleb128 0x3 # (abbrev code) + .uleb128 0x5 # (TAG: DW_TAG_formal_parameter) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x4 # (abbrev code) + .uleb128 0x24 # (TAG: DW_TAG_base_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3e # (DW_AT_encoding) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .byte 0 + .byte 0 + .uleb128 0x5 # (abbrev code) + .uleb128 0x26 # (TAG: DW_TAG_const_type) + .byte 0 # DW_children_no + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x6 # (abbrev code) + .uleb128 0x10 # (TAG: DW_TAG_reference_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x7 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x31 # (DW_AT_abstract_origin) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .byte 0 + .byte 0 + .uleb128 0x8 # (abbrev code) + .uleb128 0x5 # (TAG: DW_TAG_formal_parameter) + .byte 0 # DW_children_no + .uleb128 0x31 # (DW_AT_abstract_origin) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x18 # (DW_FORM_exprloc) + .byte 0 + .byte 0 + .uleb128 0x9 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x3f # (DW_AT_external) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .byte 0 + .byte 0 + .uleb128 0xa # (abbrev code) + .uleb128 0xb # (TAG: DW_TAG_lexical_block) + .byte 0x1 # DW_children_yes + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .byte 0 + .byte 0 + .uleb128 0xb # (abbrev code) + .uleb128 0x34 # (TAG: DW_TAG_variable) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x18 # (DW_FORM_exprloc) + .byte 0 + .byte 0 + .uleb128 0xc # (abbrev code) + .uleb128 0x4109 # (TAG: DW_TAG_GNU_call_site) + .byte 0x1 # DW_children_yes + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x31 # (DW_AT_abstract_origin) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0xd # (abbrev code) + .uleb128 0x410a # (TAG: DW_TAG_GNU_call_site_parameter) + .byte 0 # DW_children_no + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2111 # (DW_AT_GNU_call_site_value) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2112 # (DW_AT_GNU_call_site_data_value) + .uleb128 0x18 # (DW_FORM_exprloc) + .byte 0 + .byte 0 + .uleb128 0xe # (abbrev code) + .uleb128 0x34 # (TAG: DW_TAG_variable) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x3f # (DW_AT_external) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x18 # (DW_FORM_exprloc) + .byte 0 + .byte 0 + .uleb128 0xf # (abbrev code) + .uleb128 0x35 # (TAG: DW_TAG_volatile_type) + .byte 0 # DW_children_no + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x10 # (abbrev code) + .uleb128 0xf # (TAG: DW_TAG_pointer_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .byte 0 + .section .debug_aranges,"",@progbits + .long 0x3c # Length of Address Ranges Info + .value 0x2 # DWARF Version + .long .Ldebug_info0 # Offset of Compilation Unit Info + .byte 0x8 # Size of Address + .byte 0 # Size of Segment Descriptor + .value 0 # Pad to 16 byte boundary + .value 0 + .quad .Ltext0 # Address + .quad .Letext0-.Ltext0 # Length + .quad .LFB1 # Address + .quad .LFE1-.LFB1 # Length + .quad 0 + .quad 0 + .section .debug_ranges,"",@progbits +.Ldebug_ranges0: + .quad .Ltext0 # Offset 0 + .quad .Letext0 + .quad .LFB1 # Offset 0x10 + .quad .LFE1 + .quad 0 + .quad 0 + .section .debug_line,"",@progbits +.Ldebug_line0: + .section .debug_str,"MS",@progbits,1 +.LASF1: + .string "gdb.arch/amd64-entry-value-paramref.cc" +.LASF2: + .string "" +.LASF0: + .string "GNU C++ 4.8.2 20131212 (Red Hat 4.8.2-7) -mtune=generic -march=x86-64 -g -O2" +.LASF3: + .string "main" + .ident "GCC: (GNU) 4.8.2 20131212 (Red Hat 4.8.2-7)" + .section .note.GNU-stack,"",@progbits diff --git a/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.cc b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.cc new file mode 100644 index 0000000..aa473a3 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.cc @@ -0,0 +1,33 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + 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/>. */ + +volatile int vv, *p; + +static __attribute__((noinline)) int +bar (int &ref) +{ + vv++; /* break-here */ + p = &ref; + return ref; +} + +int +main (void) +{ + int var = 10; + return bar (var); +} diff --git a/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.exp b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.exp new file mode 100644 index 0000000..f06247d --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.exp @@ -0,0 +1,35 @@ +# Copyright (C) 2014 Free Software Foundation, Inc. +# +# 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/>. + +standard_testfile .S .cc + +if { ![istarget x86_64-*-* ] || ![is_lp64_target] } { + verbose "Skipping amd64-entry-value-paramref." + return +} + +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} "c++"] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +set srcfile $srcfile2 +gdb_breakpoint [gdb_get_line_number "break-here"] + +gdb_continue_to_breakpoint "break-here" ".* break-here .*" +gdb_test "frame" {bar \(ref=@0x[0-9a-f]+: 10, ref@entry=@0x[0-9a-f]+: <optimized out>\) at .*} diff --git a/gdb/testsuite/gdb.arch/amd64-optimout-repeat.S b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.S new file mode 100644 index 0000000..2f8f4d2 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.S @@ -0,0 +1,297 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012-2014 Free Software Foundation, Inc. + + 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/>. */ + +/* This file is compiled from gdb.arch/amd64-entry-value-param.c + using -g -dA -S -O2. */ + + .file "amd64-optimout-repeat.c" + .text +.Ltext0: + .section .text.unlikely,"ax",@progbits +.LCOLDB0: + .section .text.startup,"ax",@progbits +.LHOTB0: + .p2align 4,,15 + .section .text.unlikely +.Ltext_cold0: + .section .text.startup + .globl main + .type main, @function +main: +.LFB0: + .file 1 "gdb.arch/amd64-optimout-repeat.c" + # gdb.arch/amd64-optimout-repeat.c:20 + .loc 1 20 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) +.LVL0: + # gdb.arch/amd64-optimout-repeat.c:29 + .loc 1 29 0 + xorl %eax, %eax +# SUCC: EXIT [100.0%] + ret + .cfi_endproc +.LFE0: + .size main, .-main + .section .text.unlikely +.LCOLDE0: + .section .text.startup +.LHOTE0: + .text +.Letext0: + .section .text.unlikely +.Letext_cold0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .long 0x97 # Length of Compilation Unit Info + .value 0x4 # DWARF version number + .long .Ldebug_abbrev0 # Offset Into Abbrev. Section + .byte 0x8 # Pointer Size (in bytes) + .uleb128 0x1 # (DIE (0xb) DW_TAG_compile_unit) + .long .LASF1 # DW_AT_producer: "GNU C 4.9.1 20140709 (prerelease) -mtune=generic -march=x86-64 -g -O2" + .byte 0x1 # DW_AT_language + .long .LASF2 # DW_AT_name: "gdb.arch/amd64-optimout-repeat.c" + .long .LASF3 # DW_AT_comp_dir: "" + .long .Ldebug_ranges0+0 # DW_AT_ranges + .quad 0 # DW_AT_low_pc + .long .Ldebug_line0 # DW_AT_stmt_list + .uleb128 0x2 # (DIE (0x29) DW_TAG_subprogram) + # DW_AT_external + .long .LASF4 # DW_AT_name: "main" + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-optimout-repeat.c) + .byte 0x13 # DW_AT_decl_line + # DW_AT_prototyped + .long 0x7c # DW_AT_type + .quad .LFB0 # DW_AT_low_pc + .quad .LFE0-.LFB0 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites + .long 0x7c # DW_AT_sibling + .uleb128 0x3 # (DIE (0x4a) DW_TAG_structure_type) + .value 0x404 # DW_AT_byte_size + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-optimout-repeat.c) + .byte 0x15 # DW_AT_decl_line + .long 0x6a # DW_AT_sibling + .uleb128 0x4 # (DIE (0x53) DW_TAG_member) + .ascii "i\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-optimout-repeat.c) + .byte 0x17 # DW_AT_decl_line + .long 0x7c # DW_AT_type + .byte 0 # DW_AT_data_member_location + .uleb128 0x4 # (DIE (0x5d) DW_TAG_member) + .ascii "xxx\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-optimout-repeat.c) + .byte 0x18 # DW_AT_decl_line + .long 0x83 # DW_AT_type + .byte 0x4 # DW_AT_data_member_location + .byte 0 # end of children of DIE 0x4a + .uleb128 0x5 # (DIE (0x6a) DW_TAG_variable) + .ascii "v\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-optimout-repeat.c) + .byte 0x1a # DW_AT_decl_line + .long 0x4a # DW_AT_type + .uleb128 0x7 # DW_AT_location + .byte 0x30 # DW_OP_lit0 + .byte 0x9f # DW_OP_stack_value + .byte 0x93 # DW_OP_piece + .uleb128 0x4 + .byte 0x93 # DW_OP_piece + .uleb128 0x400 + .byte 0 # end of children of DIE 0x29 + .uleb128 0x6 # (DIE (0x7c) DW_TAG_base_type) + .byte 0x4 # DW_AT_byte_size + .byte 0x5 # DW_AT_encoding + .ascii "int\0" # DW_AT_name + .uleb128 0x7 # (DIE (0x83) DW_TAG_array_type) + .long 0x7c # DW_AT_type + .long 0x93 # DW_AT_sibling + .uleb128 0x8 # (DIE (0x8c) DW_TAG_subrange_type) + .long 0x93 # DW_AT_type + .byte 0xff # DW_AT_upper_bound + .byte 0 # end of children of DIE 0x83 + .uleb128 0x9 # (DIE (0x93) DW_TAG_base_type) + .byte 0x8 # DW_AT_byte_size + .byte 0x7 # DW_AT_encoding + .long .LASF0 # DW_AT_name: "sizetype" + .byte 0 # end of children of DIE 0xb + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .uleb128 0x1 # (abbrev code) + .uleb128 0x11 # (TAG: DW_TAG_compile_unit) + .byte 0x1 # DW_children_yes + .uleb128 0x25 # (DW_AT_producer) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x13 # (DW_AT_language) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x1b # (DW_AT_comp_dir) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x55 # (DW_AT_ranges) + .uleb128 0x17 # (DW_FORM_sec_offset) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x10 # (DW_AT_stmt_list) + .uleb128 0x17 # (DW_FORM_sec_offset) + .byte 0 + .byte 0 + .uleb128 0x2 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x3f # (DW_AT_external) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x27 # (DW_AT_prototyped) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x1 # (DW_AT_sibling) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x3 # (abbrev code) + .uleb128 0x13 # (TAG: DW_TAG_structure_type) + .byte 0x1 # DW_children_yes + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0x5 # (DW_FORM_data2) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x1 # (DW_AT_sibling) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x4 # (abbrev code) + .uleb128 0xd # (TAG: DW_TAG_member) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x38 # (DW_AT_data_member_location) + .uleb128 0xb # (DW_FORM_data1) + .byte 0 + .byte 0 + .uleb128 0x5 # (abbrev code) + .uleb128 0x34 # (TAG: DW_TAG_variable) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x18 # (DW_FORM_exprloc) + .byte 0 + .byte 0 + .uleb128 0x6 # (abbrev code) + .uleb128 0x24 # (TAG: DW_TAG_base_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3e # (DW_AT_encoding) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .byte 0 + .byte 0 + .uleb128 0x7 # (abbrev code) + .uleb128 0x1 # (TAG: DW_TAG_array_type) + .byte 0x1 # DW_children_yes + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x1 # (DW_AT_sibling) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x8 # (abbrev code) + .uleb128 0x21 # (TAG: DW_TAG_subrange_type) + .byte 0 # DW_children_no + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x2f # (DW_AT_upper_bound) + .uleb128 0xb # (DW_FORM_data1) + .byte 0 + .byte 0 + .uleb128 0x9 # (abbrev code) + .uleb128 0x24 # (TAG: DW_TAG_base_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3e # (DW_AT_encoding) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .byte 0 + .byte 0 + .byte 0 + .section .debug_aranges,"",@progbits + .long 0x2c # Length of Address Ranges Info + .value 0x2 # DWARF Version + .long .Ldebug_info0 # Offset of Compilation Unit Info + .byte 0x8 # Size of Address + .byte 0 # Size of Segment Descriptor + .value 0 # Pad to 16 byte boundary + .value 0 + .quad .LFB0 # Address + .quad .LFE0-.LFB0 # Length + .quad 0 + .quad 0 + .section .debug_ranges,"",@progbits +.Ldebug_ranges0: + .quad .LFB0 # Offset 0 + .quad .LFE0 + .quad 0 + .quad 0 + .section .debug_line,"",@progbits +.Ldebug_line0: + .section .debug_str,"MS",@progbits,1 +.LASF0: + .string "sizetype" +.LASF2: + .string "gdb.arch/amd64-optimout-repeat.c" +.LASF1: + .string "GNU C 4.9.1 20140709 (prerelease) -mtune=generic -march=x86-64 -g -O2" +.LASF3: + .string "" +.LASF4: + .string "main" + .ident "GCC: (GNU) 4.9.1 20140709 (prerelease)" + .section .note.GNU-stack,"",@progbits diff --git a/gdb/testsuite/gdb.arch/amd64-optimout-repeat.c b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.c new file mode 100644 index 0000000..a32b6de --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.c @@ -0,0 +1,29 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + 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/>. */ + +int +main (void) +{ + struct + { + int i; + int xxx[0x100]; + } + v = { 0 }; + + return v.i; +} diff --git a/gdb/testsuite/gdb.arch/amd64-optimout-repeat.exp b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.exp new file mode 100644 index 0000000..f3c93a4 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.exp @@ -0,0 +1,36 @@ +# Copyright (C) 2014 Free Software Foundation, Inc. +# +# 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/>. + +standard_testfile .S .c +set opts {} + +if [info exists COMPILE] { + # make check RUNTESTFLAGS="gdb.arch/amd64-optimout-repeat.exp COMPILE=1" + set srcfile ${srcfile2} + lappend opts debug optimize=-O2 +} elseif { ![istarget x86_64-*-* ] || ![is_lp64_target] } { + verbose "Skipping amd64-optimout-repeat." + return +} + +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} $opts] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +gdb_test "print v" { = {i = 0, xxx = {<optimized out> <repeats 256 times>}}} ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [patchv3] Fix crash on optimized-out entry data values 2014-07-11 16:07 ` [patchv3] " Jan Kratochvil @ 2014-07-14 7:02 ` Yao Qi 2014-07-14 8:32 ` Jan Kratochvil 2014-07-14 18:12 ` Pedro Alves 1 sibling, 1 reply; 28+ messages in thread From: Yao Qi @ 2014-07-14 7:02 UTC (permalink / raw) To: Jan Kratochvil, Pedro Alves; +Cc: gdb-patches On 07/11/2014 11:37 PM, Jan Kratochvil wrote: > gdb/testsuite/ > 2014-07-09 Jan Kratochvil <jan.kratochvil@redhat.com> > > * gdb.arch/amd64-entry-value-paramref.S: New file. > * gdb.arch/amd64-entry-value-paramref.cc: New file. > * gdb.arch/amd64-entry-value-paramref.exp: New file. > * gdb.arch/amd64-optimout-repeat.S: New file. > * gdb.arch/amd64-optimout-repeat.c: New file. > * gdb.arch/amd64-optimout-repeat.exp: New file. IWBN to generate .S files by dwarf assembler (gdb.trace/entry-values.exp, for example). Although DW_OP_GNU_entry_value isn't supported in dwarf assembler, it shouldn't be hard to handle it. -- Yao (é½å°§) ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [patchv3] Fix crash on optimized-out entry data values 2014-07-14 7:02 ` Yao Qi @ 2014-07-14 8:32 ` Jan Kratochvil 0 siblings, 0 replies; 28+ messages in thread From: Jan Kratochvil @ 2014-07-14 8:32 UTC (permalink / raw) To: Yao Qi; +Cc: Pedro Alves, gdb-patches On Mon, 14 Jul 2014 02:28:05 +0200, Yao Qi wrote: > On 07/11/2014 11:37 PM, Jan Kratochvil wrote: > > gdb/testsuite/ > > 2014-07-09 Jan Kratochvil <jan.kratochvil@redhat.com> > > > > * gdb.arch/amd64-entry-value-paramref.S: New file. > > * gdb.arch/amd64-entry-value-paramref.cc: New file. > > * gdb.arch/amd64-entry-value-paramref.exp: New file. > > * gdb.arch/amd64-optimout-repeat.S: New file. > > * gdb.arch/amd64-optimout-repeat.c: New file. > > * gdb.arch/amd64-optimout-repeat.exp: New file. > > IWBN to generate .S files by dwarf assembler > (gdb.trace/entry-values.exp, for example). I am aware of it but I find it a lot of work while the gcc generated files are IMO good enough. So only if it is a patch acceptance requirement. Jan ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [patchv3] Fix crash on optimized-out entry data values 2014-07-11 16:07 ` [patchv3] " Jan Kratochvil 2014-07-14 7:02 ` Yao Qi @ 2014-07-14 18:12 ` Pedro Alves 1 sibling, 0 replies; 28+ messages in thread From: Pedro Alves @ 2014-07-14 18:12 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches On 07/11/2014 04:37 PM, Jan Kratochvil wrote: > On Wed, 09 Jul 2014 17:31:21 +0200, Jan Kratochvil wrote: >> On Wed, 09 Jul 2014 13:52:00 +0200, Pedro Alves wrote: >>> On 07/09/2014 11:33 AM, Jan Kratochvil wrote: >>>> --- a/gdb/value.c >>>> +++ b/gdb/value.c >>>> @@ -198,12 +198,13 @@ struct value >>>> 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 >>>> + actually fully 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. */ >>>> + error strings. It is true also for only partially optimized >>>> + out variables - see the 'unavailable' field below. */ >>>> unsigned int optimized_out : 1; >>>> >>>> /* If value is a variable, is it initialized or not. */ >>>> @@ -334,7 +335,10 @@ struct value >>>> valid if lazy is nonzero. */ >>>> gdb_byte *contents; >>>> >>>> - /* Unavailable ranges in CONTENTS. We mark unavailable ranges, >>>> + /* If OPTIMIZED_OUT is false then UNAVAILABLE must be VEC_empty >>>> + (not necessarily NULL). >>> >>> Hmm, why? We can collect only part of a non-optimized out value. >>> What am I missing? >> >> I miss some documentation how these availability fields interact together. > > From a comment in mail > Message-Id: <201102071427.55970.pedro@codesourcery.com> > We give preference to printing <optimized out> rather > than <unavailable>, since if a value had been optimized out > at compile time, it can never be collected at run-time. > > it seems it is just reversed, that 'unavailable' can exist only for > !optimized_out and it cannot exist for for optimized_out values. Not really true either. A value can be partially optimized out. And then when e.g., inspecting a traceframe or a partial core dump, the bits that are not optimized out may well not have been collected, so those will be unavailable. I'm sending you a different patch in a bit. -- Pedro Alves ^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH] Handle partially optimized out values similarly to unavailable values (Re: [patchv2] Fix crash on optimized-out entry data values) 2014-07-09 15:31 ` Jan Kratochvil 2014-07-11 16:07 ` [patchv3] " Jan Kratochvil @ 2014-07-14 18:47 ` Pedro Alves 2014-07-17 8:04 ` Jan Kratochvil 1 sibling, 1 reply; 28+ messages in thread From: Pedro Alves @ 2014-07-14 18:47 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches On 07/09/2014 04:31 PM, Jan Kratochvil wrote: > On Wed, 09 Jul 2014 13:52:00 +0200, Pedro Alves wrote: >> On 07/09/2014 11:33 AM, Jan Kratochvil wrote: >>> --- a/gdb/value.c >>> +++ b/gdb/value.c >>> @@ -198,12 +198,13 @@ struct value >>> 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 >>> + actually fully 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. */ >>> + error strings. It is true also for only partially optimized >>> + out variables - see the 'unavailable' field below. */ >>> unsigned int optimized_out : 1; >>> >>> /* If value is a variable, is it initialized or not. */ >>> @@ -334,7 +335,10 @@ struct value >>> valid if lazy is nonzero. */ >>> gdb_byte *contents; >>> >>> - /* Unavailable ranges in CONTENTS. We mark unavailable ranges, >>> + /* If OPTIMIZED_OUT is false then UNAVAILABLE must be VEC_empty >>> + (not necessarily NULL). >> >> Hmm, why? We can collect only part of a non-optimized out value. >> What am I missing? > > I miss some documentation how these availability fields interact together. > value_available_contents_bits_eq is written according to the struct value > comments but they do not correspond to the real world struct value data. value_available_contents_bits_eq isn't paying attention to the optimized out bits at all. But as you found it, that's not sufficient. Currently it either returns that a zeroed value equals an optimized out value, because allocate_value_contents zeros to buffer, which is bogus, or crashes, if the optimized out value hasn't had its contents buffer allocated. > > 'unavailable' suggests that optimized out variable should have it set to the > full range of the variable. 'unavailable' has a specific meaning here, and it doesn't include "optimized out" values. See comment added to value.h in the patch. > But struct value with OPTIMIZED_OUT field set > still has UNAVAILABLE empty. As the variable is optimized out the CONTENTS is > also NULL - this causes the crash reproduced by > 'gdb.arch/amd64-entry-value-paramref.exp'. > > There are also check_validity and check_any_valid methods but how they are > related to the 'unavailable' data field is also not documented. Yeah, confusing terminology. They are not related at all. "valid" == "!optimized out" in the current sources. A value can be both "valid" and "not available". > > This patch was my second attempt to fix/document the availability stuff, it > would be useful to suggest how it is designed. Time to pick up more pieces of https://sourceware.org/ml/gdb-patches/2013-08/msg00300.html ... I've picked that, and trimmed it to a bare minimal. I've done a few things differently, like not merging the range vectors, and dropped the generic availability API (several spots in that series look misconverted to me, best do this in smaller baby steps). No regressions for me on x86-64 F20, native and gdbserver, and also fixes your test's crash. Let me know what you think. 8<--------------------------- From c5d14e921f8ed79c861c74d41f05688aa2c8bf0e Mon Sep 17 00:00:00 2001 From: Pedro Alves <palves@redhat.com> Date: Mon, 14 Jul 2014 17:58:59 +0100 Subject: [PATCH] Handle partially optimized out values similarly to unavailable values This fixes PR symtab/14604, PR symtab/14605, and Jan's test at https://sourceware.org/ml/gdb-patches/2014-07/msg00158.html. The PRs are about variables described by the DWARF as being split over multiple registers using DWARF piece information, but some of those registers being marked as optimised out (not saved) by a later frame. GDB currently incorrectly mishandles these partially-optimized-out values. Even though we can usually tell from the debug info whether a local or global is optimized out, handling the case of a local living in a register that was not saved in a frame requires fetching the variable. GDB also needs to fetch a value to tell whether parts of it are "<unavailable>". Given this, it's not worth it to try to avoid fetching lazy optimized-out values based on debug info alone. So this patch makes GDB track which chunks of a value's contents are optimized out like it tracks <unavailable> contents. That is, it makes value->optimized_out be a bit range vector instead of a boolean, and removes the struct lval_funcs check_validity and check_any_valid hooks. Unlike Andrew's series which this is based on (at https://sourceware.org/ml/gdb-patches/2013-08/msg00300.html, note some pieces have gone in since), this doesn't merge optimized out and unavailable contents validity/availability behind a single interface, nor does it merge the bit range vectors themselves (at least yet). While it may be desirable to have a single entry point that returns existence of contents irrespective of what may make them invalid/unavailable, several places want to treat optimized out / unavailable / etc. differently, so each spot that potentially could use it will need to be careful considered on case-by-case basis, and best done as a separate change. This fixes Jan's test, because value_available_contents_eq wasn't considering optimized out value contents. It does now, and because of that it's been renamed to value_contents_eq. A new intro comment is added to value.h describing "<optimized out>" and "<unavailable>" values. gdb/ 2014-07-14 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): Remove use of optimized_out. (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. gdb/testsuite/ 2014-07-14 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. --- gdb/ada-lang.c | 4 +- gdb/ada-valprint.c | 6 +- gdb/c-valprint.c | 6 +- gdb/cp-valprint.c | 11 +- gdb/d-valprint.c | 5 +- gdb/dwarf2loc.c | 81 +---- gdb/findvar.c | 8 +- gdb/frame-unwind.c | 2 +- gdb/jv-valprint.c | 13 +- gdb/mips-tdep.c | 6 - gdb/opencl-lang.c | 54 --- gdb/p-valprint.c | 5 - gdb/stack.c | 15 +- gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp | 30 +- gdb/valprint.c | 22 +- gdb/value.c | 459 +++++++++++++++----------- gdb/value.h | 147 ++++++--- 17 files changed, 430 insertions(+), 444 deletions(-) diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 6956909..63f84ea 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -682,14 +682,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 b7b3a9c..b4f191f 100644 --- a/gdb/ada-valprint.c +++ b/gdb/ada-valprint.c @@ -186,9 +186,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 f4694b0..2f2789c 100644 --- a/gdb/c-valprint.c +++ b/gdb/c-valprint.c @@ -173,9 +173,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 3e1d6ed..0d6c3fc 100644 --- a/gdb/cp-valprint.c +++ b/gdb/cp-valprint.c @@ -294,12 +294,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; @@ -434,8 +428,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 fcab9b9..37689d8 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -1285,8 +1285,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 */ @@ -1704,7 +1702,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); } @@ -1764,7 +1762,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: @@ -1802,7 +1800,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; } @@ -1934,7 +1932,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; @@ -1943,24 +1941,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)) @@ -1985,52 +1975,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. */ @@ -2179,8 +2128,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, @@ -2308,6 +2255,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 @@ -2315,7 +2264,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 9390c8a..346a499 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -681,12 +681,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) @@ -732,7 +726,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 fdfea6e..1cc3303 100644 --- a/gdb/frame-unwind.c +++ b/gdb/frame-unwind.c @@ -203,7 +203,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 a7bb494..93a827e 100644 --- a/gdb/jv-valprint.c +++ b/gdb/jv-valprint.c @@ -183,10 +183,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; } @@ -393,11 +393,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 c3e8e77..34b75f7 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -6196,12 +6196,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 2dd76fa..6a3ba69 100644 --- a/gdb/opencl-lang.c +++ b/gdb/opencl-lang.c @@ -240,58 +240,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. */ @@ -358,8 +306,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 0d6d8e7..346ce29 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -385,9 +385,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; @@ -413,9 +416,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_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/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 8600b34..981ef9b 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -311,8 +311,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; @@ -983,8 +984,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); @@ -1685,12 +1687,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 29abe5f..b97e85b 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -197,15 +197,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; @@ -339,6 +330,15 @@ struct value value to be available. This is filled in at value read time. The unavailable ranges are tracked in bits. */ 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 @@ -358,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 @@ -370,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 @@ -391,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; @@ -483,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)) { @@ -507,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; @@ -526,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; @@ -552,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, @@ -684,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 cmp_ranges and value_contents_bits_eq. Keep + track of which slot in a given ranges VEC 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 @@ -734,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. */ @@ -744,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. */ @@ -836,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; @@ -905,7 +1005,7 @@ allocate_optimized_out_value (struct type *type) { struct value *retval = allocate_value_lazy (type); - set_value_optimized_out (retval, 1); + mark_value_bytes_optimized_out (retval, 0, TYPE_LENGTH (type)); set_value_lazy (retval, 0); return retval; } @@ -1054,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")); @@ -1094,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 @@ -1122,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, @@ -1132,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 @@ -1151,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. */ @@ -1161,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); @@ -1213,47 +1334,31 @@ value_contents_writeable (struct value *value) int 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) + /* We can only know if a value is optimized out once we have tried + to fetch it. */ + 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 @@ -1566,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; @@ -2851,24 +2955,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)) { @@ -2881,37 +2980,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 { @@ -2922,12 +3013,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 { @@ -3646,6 +3732,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 @@ -3662,10 +3753,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, @@ -3740,16 +3832,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) { @@ -3802,11 +3890,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 86ebd70..5380f76 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -33,6 +33,43 @@ 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. 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>. + + When comparing value contents, optimized out chunks, unavailable + chunks, and valid contents data are all 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 +218,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 +356,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 +458,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 +508,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 compare equal with optimized out contents, + and different with any non-optimized-out byte. - 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 contents compare equal with unavailable contents, and + different with any non-unavailable byte. - 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 -- 1.9.3 ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH] Handle partially optimized out values similarly to unavailable values (Re: [patchv2] Fix crash on optimized-out entry data values) 2014-07-14 18:47 ` [PATCH] Handle partially optimized out values similarly to unavailable values (Re: [patchv2] Fix crash on optimized-out entry data values) Pedro Alves @ 2014-07-17 8:04 ` Jan Kratochvil 2014-07-17 8:35 ` Jan Kratochvil ` (2 more replies) 0 siblings, 3 replies; 28+ messages in thread From: Jan Kratochvil @ 2014-07-17 8:04 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches On Mon, 14 Jul 2014 20:11:41 +0200, Pedro Alves wrote: [...] > --- a/gdb/value.c > +++ b/gdb/value.c [...] > @@ -339,6 +330,15 @@ struct value > value to be available. This is filled in at value read time. The > unavailable ranges are tracked in bits. */ > 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; I miss here explicit description if a bit of the range can appear on both 'unavailable' and 'optimized_out'. IMO it should not. > }; > > int [...] > +/* 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) Here should be: if (i == 0 || l_tmp < l || (l_tmp == l && h_tmp < h)) It could skip [0]'s part which is non-equal otherwise. > + { > + 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; > } [...] > @@ -1566,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; Why 'optimized_out' no longer needs to be copied? > val->embedded_offset = value_embedded_offset (arg); > val->pointed_to_offset = arg->pointed_to_offset; > val->modifiable = arg->modifiable; [...] > @@ -3662,10 +3753,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)); That was required before but it could handle partially optimized out bitfields; but maybe it is not useful much. > else if (!unpack_value_bits_as_long (value_type (val), > value_contents_for_printing (parent), > offset, [...] > --- a/gdb/value.h > +++ b/gdb/value.h > @@ -33,6 +33,43 @@ 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. Examples "printed as." - is the sentence finished? > + 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> s/<not-saved>/<unavailable>/? > + instead of <optimized out>. > + > + When comparing value contents, optimized out chunks, unavailable > + chunks, and valid contents data are all 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 [...] > @@ -473,35 +508,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 compare equal with optimized out contents, > + and different with any non-optimized-out byte. English: s/different/differ/ > > - 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 contents compare equal with unavailable contents, and > + different with any non-unavailable byte. English: s/different/differ/ > > - 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. */ [...] This patch is apparently not suitable for gdb-7.8 which is I guess often crashing on -O2 -g entry values so there could be some rather minimal crash avoiding patch instead. Thanks, Jan ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH] Handle partially optimized out values similarly to unavailable values (Re: [patchv2] Fix crash on optimized-out entry data values) 2014-07-17 8:04 ` Jan Kratochvil @ 2014-07-17 8:35 ` Jan Kratochvil 2014-07-17 13:38 ` Pedro Alves 2014-07-24 12:51 ` [PATCH v2] Handle partially optimized out values similarly to unavailable values Pedro Alves 2 siblings, 0 replies; 28+ messages in thread From: Jan Kratochvil @ 2014-07-17 8:35 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches On Wed, 16 Jul 2014 23:58:38 +0200, Jan Kratochvil wrote: > On Mon, 14 Jul 2014 20:11:41 +0200, Pedro Alves wrote: > > + /* 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) > > Here should be: > if (i == 0 || l_tmp < l || (l_tmp == l && h_tmp < h)) > > It could skip [0]'s part which is non-equal otherwise. No, the code was OK. This comes from the fact that 'unavailable' and 'optimized_out' ranges cannot overlap (probably, I ask for its clarification somewhere else in the mail). Maybe it would be all easier to have there single map and each range mapping into enum { VALID, OPTIMIZED_OUT, UNAVAILABLE }. Jan ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH] Handle partially optimized out values similarly to unavailable values (Re: [patchv2] Fix crash on optimized-out entry data values) 2014-07-17 8:04 ` Jan Kratochvil 2014-07-17 8:35 ` Jan Kratochvil @ 2014-07-17 13:38 ` Pedro Alves 2014-07-20 15:33 ` [read_frame_arg patch] " Jan Kratochvil 2014-07-24 12:51 ` [PATCH v2] Handle partially optimized out values similarly to unavailable values Pedro Alves 2 siblings, 1 reply; 28+ messages in thread From: Pedro Alves @ 2014-07-17 13:38 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches On 07/16/2014 10:58 PM, Jan Kratochvil wrote: > > > This patch is apparently not suitable for gdb-7.8 which is I guess often > crashing on -O2 -g entry values so there could be some rather minimal crash > avoiding patch instead. > Yeah. So this was originally "caused" (more exposed) by 4f14910f: gdb/ChangeLog 2013-11-26 Andrew Burgess <aburgess@broadcom.com> * value.c (allocate_optimized_out_value): Mark value as non-lazy. I tried a few approaches in value_available_contents_eq today, and ended up thinking that the simplest should be to just revert that patch until we have the fuller fix in place. While doing just that fixes the crash, it surprisingly causes one of your new tests to FAIL: (gdb) frame #0 bar (ref=ref@entry=@0x7fffffffd184: 10) at gdb.arch/amd64-entry-value-paramref.cc:23 23 vv++; /* break-here */ (gdb) FAIL: gdb.arch/amd64-entry-value-paramref.exp: frame If I instead make allocate_optimized_out_value not allocate a lazy value, like: struct value * allocate_optimized_out_value (struct type *type) { - struct value *retval = allocate_value_lazy (type); + struct value *retval = allocate_value (type); set_value_optimized_out (retval, 1); - set_value_lazy (retval, 0); return retval; } Then the test passes. (gdb) PASS: gdb.arch/amd64-entry-value-paramref.exp: continue to breakpoint: break-here frame #0 bar (ref=@0x7fffffffd184: 10, ref@entry=@0x7fffffffd184: <optimized out>) at gdb.arch/amd64-entry-value-paramref.cc:23 23 vv++; /* break-here */ (gdb) PASS: gdb.arch/amd64-entry-value-paramref.exp: frame The difference is that if we let the value be lazy, value_fetch_lazy fetches contents from memory, and then those contents compare equal with the non-entry value. Hmm. But that's odd, why would value_fetch_lazy fetch the value from memory at all, it it started out as an optimized-out / not_lval value? What made it be lval_memory ? Turns out it's the code disabled in value_of_dwarf_reg_entry: target_val = dwarf_entry_parameter_to_value (parameter, TYPE_LENGTH (target_type), target_type, caller_frame, caller_per_cu); /* value_as_address dereferences TYPE_CODE_REF. */ addr = extract_typed_address (value_contents (outer_val), checked_type); /* The target entry value has artificial address of the entry value reference. */ VALUE_LVAL (target_val) = lval_memory; set_value_address (target_val, addr); It looks quite wrong to me to just change a value's lval like that. I ran the testsuite with that code disabled (like in the patch below), and that caused no regressions. I can't say I really understand the intention here though. What would we be missing if we removed that code? ------------------ From 91d05d6af2b36a701429219f37712e7c6f944c4f Mon Sep 17 00:00:00 2001 From: Pedro Alves <palves@redhat.com> Date: Thu, 17 Jul 2014 11:06:18 +0100 Subject: [PATCH] Fix crash on optimized-out entry data values The tests at <https://sourceware.org/ml/gdb-patches/2014-07/msg00277.html> show that comparing a fully optimized out value's contents with a value that has not been optimized out, or is partially optimized out crashes GDB: (gdb) bt #0 __memcmp_sse4_1 () at ../sysdeps/x86_64/multiarch/memcmp-sse4.S:816 #1 0x00000000005a1914 in memcmp_with_bit_offsets (ptr1=0x202b2f0 "\n", offset1_bits=0, ptr2=0x0, offset2_bits=0, length_bits=32) at /home/pedro/gdb/mygit/build/../src/gdb/value.c:678 #2 0x00000000005a1a05 in value_available_contents_bits_eq (val1=0x2361ad0, offset1=0, val2=0x23683b0, offset2=0, length=32) at /home/pedro/gdb/mygit/build/../src/gdb/value.c:717 #3 0x00000000005a1c09 in value_available_contents_eq (val1=0x2361ad0, offset1=0, val2=0x23683b0, offset2=0, length=4) at /home/pedro/gdb/mygit/build/../src/gdb/value.c:769 #4 0x00000000006033ed in read_frame_arg (sym=0x1b78d20, frame=0x19bca50, argp=0x7fff4aba82b0, entryargp=0x7fff4aba82d0) at /home/pedro/gdb/mygit/build/../src/gdb/stack.c:416 #5 0x0000000000603abb in print_frame_args (func=0x1b78cb0, frame=0x19bca50, num=-1, stream=0x1aea450) at /home/pedro/gdb/mygit/build/../src/gdb/stack.c:671 #6 0x0000000000604ae8 in print_frame (frame=0x19bca50, print_level=0, print_what=SRC_AND_LOC, print_args=1, sal=...) at /home/pedro/gdb/mygit/build/../src/gdb/stack.c:1205 #7 0x0000000000604050 in print_frame_info (frame=0x19bca50, print_level=0, print_what=SRC_AND_LOC, print_args=1, set_current_sal=1) at /home/pedro/gdb/mygit/build/../src/gdb/stack.c:857 #8 0x00000000006029b3 in print_stack_frame (frame=0x19bca50, print_level=0, print_what=SRC_AND_LOC, set_current_sal=1) at /home/pedro/gdb/mygit/build/../src/gdb/stack.c:169 #9 0x00000000005fc4b8 in print_stop_event (ws=0x7fff4aba8790) at /home/pedro/gdb/mygit/build/../src/gdb/infrun.c:6068 #10 0x00000000005fc830 in normal_stop () at /home/pedro/gdb/mygit/build/../src/gdb/infrun.c:6214 The 'ptr2=0x0' in frame #1 is val2->contents, and since git 4f14910f: gdb/ChangeLog 2013-11-26 Andrew Burgess <aburgess@broadcom.com> * value.c (allocate_optimized_out_value): Mark value as non-lazy. ... a fully optimized-out value can have it's value contents buffer NULL. As a spotgap fix, revert 4f14910f, with a comment. A full fix would be too invasive for 7.8. gdb/ 2014-07-17 Pedro Alves <palves@redhat.com> * value.c (allocate_optimized_out_value): Don't mark value as non-lazy. --- gdb/dwarf2loc.c | 2 ++ gdb/value.c | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index fcab9b9..8ed3be0 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -1335,6 +1335,7 @@ value_of_dwarf_reg_entry (struct type *type, struct frame_info *frame, target_type, caller_frame, caller_per_cu); +#if 0 /* value_as_address dereferences TYPE_CODE_REF. */ addr = extract_typed_address (value_contents (outer_val), checked_type); @@ -1342,6 +1343,7 @@ value_of_dwarf_reg_entry (struct type *type, struct frame_info *frame, reference. */ VALUE_LVAL (target_val) = lval_memory; set_value_address (target_val, addr); +#endif release_value (target_val); val = allocate_computed_value (type, &entry_data_value_funcs, diff --git a/gdb/value.c b/gdb/value.c index 29abe5f..8b44a6d 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -906,7 +906,10 @@ allocate_optimized_out_value (struct type *type) struct value *retval = allocate_value_lazy (type); set_value_optimized_out (retval, 1); - set_value_lazy (retval, 0); + /* 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); */ return retval; } -- 1.9.3 ^ permalink raw reply [flat|nested] 28+ messages in thread
* [read_frame_arg patch] Handle partially optimized out values similarly to unavailable values (Re: [patchv2] Fix crash on optimized-out entry data values) 2014-07-17 13:38 ` Pedro Alves @ 2014-07-20 15:33 ` Jan Kratochvil 2014-07-22 19:33 ` Pedro Alves 0 siblings, 1 reply; 28+ messages in thread From: Jan Kratochvil @ 2014-07-20 15:33 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches [-- Attachment #1: Type: text/plain, Size: 6582 bytes --] On Thu, 17 Jul 2014 14:23:06 +0200, Pedro Alves wrote: > On 07/16/2014 10:58 PM, Jan Kratochvil wrote: > > This patch is apparently not suitable for gdb-7.8 which is I guess often > > crashing on -O2 -g entry values so there could be some rather minimal crash > > avoiding patch instead. > > Yeah. > > So this was originally "caused" (more exposed) by 4f14910f: > > gdb/ChangeLog > 2013-11-26 Andrew Burgess <aburgess@broadcom.com> > > * value.c (allocate_optimized_out_value): Mark value as non-lazy. > > I tried a few approaches in value_available_contents_eq > today, and ended up thinking that the simplest should be to > just revert that patch until we have the fuller fix in place. OK, that seems as the best solution for 7.8 to me. > While doing just that fixes the crash, it surprisingly causes > one of your new tests to FAIL: > > (gdb) frame > #0 bar (ref=ref@entry=@0x7fffffffd184: 10) at gdb.arch/amd64-entry-value-paramref.cc:23 > 23 vv++; /* break-here */ > (gdb) FAIL: gdb.arch/amd64-entry-value-paramref.exp: frame There is a bug in that entry value code of mine, fix attached. The testcase then PASSes with the reverted optimization by Andrew Burgess. For the attached fix - if you nitpick the missing conditional case: value_optimized_out (val_deref) && value_optimized_out (entryval_deref) It is not detected there but that IMO does not matter much as * It is for 7.8 only, for trunk it will get compared correctly thanks to the new implementation of value_available_contents_eq() called value_contents_eq(). * If the conditional 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))) val_equal = 1; fails it may just print bar (ref=@0x7fffffffd904: <optimized out>, ref@entry=@0x7fffffffd904: <optimized out>) (or some variant with some partially optimized-out/unavailable parts) instead of the more correct bar (ref=ref@entry=@0x7fffffffd904: <optimized out>) which is not much a bug. The attached fix no longe makes sense after the new implementation of value_available_contents_eq() called value_contents_eq() gets applied as it handles all the optimized-out/unavailable values on its own, therefore the attached patch is really only for 7.8. > Turns out it's the code disabled in value_of_dwarf_reg_entry: > > target_val = dwarf_entry_parameter_to_value (parameter, > TYPE_LENGTH (target_type), > target_type, caller_frame, > caller_per_cu); > > /* value_as_address dereferences TYPE_CODE_REF. */ > addr = extract_typed_address (value_contents (outer_val), checked_type); > > /* The target entry value has artificial address of the entry value > reference. */ > VALUE_LVAL (target_val) = lval_memory; > set_value_address (target_val, addr); > > It looks quite wrong to me to just change a value's lval like that. > > I ran the testsuite with that code disabled (like in the patch below), > and that caused no regressions. I can't say I really understand the > intention here though. What would we be missing if we removed that code? I cannot reproduce any wrong case having the code above #if 0-ed. I just do not find it correct to have it disabled. But at the same time I do like much / I do not find correct the code myself. It is a bit problematic to have struct value describing a memory content which is no longer present there. What happens there: ------------------------------------------------------------------------------ volatile int vv; static __attribute__((noinline)) int bar (int &ref) { ref = 20; vv++; /* break-here */ return ref; } int main (void) { int var = 10; return bar (var); } ------------------------------------------------------------------------------ <4><c7>: Abbrev Number: 13 (DW_TAG_GNU_call_site_parameter) <c8> DW_AT_location : 1 byte block: 55 (DW_OP_reg5 (rdi)) <ca> DW_AT_GNU_call_site_value: 2 byte block: 91 74 (DW_OP_fbreg: -12) <cd> DW_AT_GNU_call_site_data_value: 1 byte block: 3a (DW_OP_lit10) ------------------------------------------------------------------------------ gdb -ex 'b value_addr' -ex r --args ../gdb ./1 -ex 'watch vv' -ex r -ex 'p &ref@entry' -> 6 return ref; bar (ref=@0x7fffffffd944: 20, ref@entry=@0x7fffffffd944: 10) at 1.C:25 ------------------------------------------------------------------------------ At /* break-here */ struct value variable 'ref' is TYPE_CODE_REF. With FSF GDB HEAD: (gdb) x/gx arg1.contents 0x6004000a4ad0: 0x00007fffffffd944 (gdb) p ((struct value *)arg1.location.computed.closure).lval $1 = lval_memory (gdb) p/x ((struct value *)arg1.location.computed.closure).location.address $3 = 0x7fffffffd944 With your #if0-ed code: (gdb) x/gx arg1.contents 0x6004000a4ad0: 0x00007fffffffd944 (gdb) p ((struct value *)arg1.location.computed.closure).lval $8 = not_lval (gdb) p/x ((struct value *)arg1.location.computed.closure).location.address $9 = 0x0 I do not see how to access ((struct value *)arg1.location.computed.closure).location.address from GDB CLI. Trying (gdb) p &ref@entry will invoke value_addr()'s: if (TYPE_CODE (type) == TYPE_CODE_REF) /* Copy the value, but change the type from (T&) to (T*). We keep the same location information, which is efficient, and allows &(&X) to get the location containing the reference. */ and therefore the address gets fetched already from arg1.contents and not from ((struct value *)arg1.location.computed.closure).location.address . And for any other type than TYPE_CODE_REF this code you #if 0-ed does not get executed at all. This DW_AT_GNU_call_site_data_value DWARF was meant primarily for Fortran but with -O0 entry values do not get produced and with -Og and higher Fortran always optimizes out the passing by reference. If you do not like the #if 0 code there I am OK with removing it as I do not know how to make it's use reproducible for user anyway. In the worst case - if there really is some way how to exploit it - one should just get Attempt to take address of value not located in memory. instead of some wrong value and it may be easy to fix then. Thanks for the analysis, Jan [-- Attachment #2: 1 --] [-- Type: text/plain, Size: 711 bytes --] gdb/ 2014-07-20 Jan Kratochvil <jan.kratochvil@redhat.com> * stack.c (read_frame_arg): Verify value_optimized_out before calling value_available_contents_eq. diff --git a/gdb/stack.c b/gdb/stack.c index 0d6d8e7..4db5df5 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -413,6 +413,8 @@ 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))) ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [read_frame_arg patch] Handle partially optimized out values similarly to unavailable values (Re: [patchv2] Fix crash on optimized-out entry data values) 2014-07-20 15:33 ` [read_frame_arg patch] " Jan Kratochvil @ 2014-07-22 19:33 ` Pedro Alves 2014-07-22 20:21 ` [commit+7.8] [read_frame_arg patch] Handle partially optimized out values similarly to unavailable values Jan Kratochvil 2014-07-23 14:26 ` [commit] Remove setting value address for reference entry value target data value Jan Kratochvil 0 siblings, 2 replies; 28+ messages in thread From: Pedro Alves @ 2014-07-22 19:33 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches On 07/20/2014 04:07 PM, Jan Kratochvil wrote: > On Thu, 17 Jul 2014 14:23:06 +0200, Pedro Alves wrote: >> On 07/16/2014 10:58 PM, Jan Kratochvil wrote: >>> This patch is apparently not suitable for gdb-7.8 which is I guess often >>> crashing on -O2 -g entry values so there could be some rather minimal crash >>> avoiding patch instead. >> >> Yeah. >> >> So this was originally "caused" (more exposed) by 4f14910f: >> >> gdb/ChangeLog >> 2013-11-26 Andrew Burgess <aburgess@broadcom.com> >> >> * value.c (allocate_optimized_out_value): Mark value as non-lazy. >> >> I tried a few approaches in value_available_contents_eq >> today, and ended up thinking that the simplest should be to >> just revert that patch until we have the fuller fix in place. > > OK, that seems as the best solution for 7.8 to me. > > >> While doing just that fixes the crash, it surprisingly causes >> one of your new tests to FAIL: >> >> (gdb) frame >> #0 bar (ref=ref@entry=@0x7fffffffd184: 10) at gdb.arch/amd64-entry-value-paramref.cc:23 >> 23 vv++; /* break-here */ >> (gdb) FAIL: gdb.arch/amd64-entry-value-paramref.exp: frame > > There is a bug in that entry value code of mine, fix attached. > The testcase then PASSes with the reverted optimization by Andrew Burgess. > OK, I've pushed the reversion (without the #if 0 bit) to both master and 7.8. > For the attached fix - if you nitpick the missing conditional case: > value_optimized_out (val_deref) && value_optimized_out (entryval_deref) > It is not detected there but that IMO does not matter much as > * It is for 7.8 only, for trunk it will get compared correctly thanks to the > new implementation of value_available_contents_eq() > called value_contents_eq(). > * If the conditional > 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))) > val_equal = 1; > fails it may just print > bar (ref=@0x7fffffffd904: <optimized out>, ref@entry=@0x7fffffffd904: <optimized out>) > (or some variant with some partially optimized-out/unavailable parts) > instead of the more correct > bar (ref=ref@entry=@0x7fffffffd904: <optimized out>) > which is not much a bug. That's fine with me. > The attached fix no longe makes sense after the new implementation > of value_available_contents_eq() called value_contents_eq() gets applied as it > handles all the optimized-out/unavailable values on its own, therefore the > attached patch is really only for 7.8. As it's best not to get ourselves in a situation where we have a fix in the branch but not in mainline, and avoid putting pressure on the better fix, it's better to put your patch in mainline too. > I do not see how to access > ((struct value *)arg1.location.computed.closure).location.address > from GDB CLI. Trying > (gdb) p &ref@entry > will invoke value_addr()'s: > if (TYPE_CODE (type) == TYPE_CODE_REF) > /* Copy the value, but change the type from (T&) to (T*). We > keep the same location information, which is efficient, and > allows &(&X) to get the location containing the reference. */ > and therefore the address gets fetched already from > arg1.contents > and not from > ((struct value *)arg1.location.computed.closure).location.address > . > Yeah. > And for any other type than TYPE_CODE_REF this code you #if 0-ed does not get > executed at all. This DW_AT_GNU_call_site_data_value DWARF was meant > primarily for Fortran but with -O0 entry values do not get produced > and with -Og and higher Fortran always optimizes out the passing by reference. > > If you do not like the #if 0 code there I am OK with removing it as I do not > know how to make it's use reproducible for user anyway. In the worst case > - if there really is some way how to exploit it - one should just get > Attempt to take address of value not located in memory. > instead of some wrong value and it may be easy to fix then. Thanks Jan. Indeed I'd much prefer removing it. It's fine with me to still leave it in 7.8 in case we missed something. -- Pedro Alves ^ permalink raw reply [flat|nested] 28+ messages in thread
* [commit+7.8] [read_frame_arg patch] Handle partially optimized out values similarly to unavailable values 2014-07-22 19:33 ` Pedro Alves @ 2014-07-22 20:21 ` Jan Kratochvil 2014-08-05 17:16 ` Doug Evans 2014-07-23 14:26 ` [commit] Remove setting value address for reference entry value target data value Jan Kratochvil 1 sibling, 1 reply; 28+ messages in thread From: Jan Kratochvil @ 2014-07-22 20:21 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches [-- Attachment #1: Type: text/plain, Size: 320 bytes --] On Tue, 22 Jul 2014 21:19:22 +0200, Pedro Alves wrote: > OK, I've pushed the reversion (without the #if 0 bit) to both master > and 7.8. Therefore pushed in the fix of read_frame_arg together with the testcase. e214cf6c2e05bcfc85dc6f335d8ffdc3629cf0cf and also for 7.8: 0f9e1204f3de3cbe46a2b9e54049c1df9a5df305 Jan [-- Attachment #2: 1 --] [-- Type: text/plain, Size: 31708 bytes --] commit e214cf6c2e05bcfc85dc6f335d8ffdc3629cf0cf Author: Jan Kratochvil <jan.kratochvil@redhat.com> Date: Tue Jul 22 22:09:35 2014 +0200 Fix read_frame_arg for optimized-out entry values. gdb/ 2014-07-22 Jan Kratochvil <jan.kratochvil@redhat.com> * stack.c (read_frame_arg): Verify value_optimized_out before calling value_available_contents_eq. gdb/testsuite/ 2014-07-22 Jan Kratochvil <jan.kratochvil@redhat.com> * gdb.arch/amd64-entry-value-paramref.S: New file. * gdb.arch/amd64-entry-value-paramref.cc: New file. * gdb.arch/amd64-entry-value-paramref.exp: New file. * gdb.arch/amd64-optimout-repeat.S: New file. * gdb.arch/amd64-optimout-repeat.c: New file. * gdb.arch/amd64-optimout-repeat.exp: New file. Message-ID: <20140720150727.GA18488@host2.jankratochvil.net> Message-ID: <20140711153757.GA452@host2.jankratochvil.net> diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 6ce1e52..73a13d3 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,8 @@ +2014-07-22 Jan Kratochvil <jan.kratochvil@redhat.com> + + * stack.c (read_frame_arg): Verify value_optimized_out before calling + value_available_contents_eq. + 2014-07-22 Pedro Alves <palves@redhat.com> * value.c (allocate_optimized_out_value): Don't mark value as diff --git a/gdb/stack.c b/gdb/stack.c index 0d6d8e7..4db5df5 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -413,6 +413,8 @@ 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))) diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index d9c420e..f534f18 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2014-07-22 Jan Kratochvil <jan.kratochvil@redhat.com> + + * gdb.arch/amd64-entry-value-paramref.S: New file. + * gdb.arch/amd64-entry-value-paramref.cc: New file. + * gdb.arch/amd64-entry-value-paramref.exp: New file. + * gdb.arch/amd64-optimout-repeat.S: New file. + * gdb.arch/amd64-optimout-repeat.c: New file. + * gdb.arch/amd64-optimout-repeat.exp: New file. + 2014-07-17 Jan Kratochvil <jan.kratochvil@redhat.com> PR gdb/17170 diff --git a/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.S b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.S new file mode 100644 index 0000000..a1e9d0a --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.S @@ -0,0 +1,459 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + 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/>. */ + +/* This file is compiled from gdb.arch/amd64-entry-value-paramref.cc + using -g -dA -S -O2. + Additionally it has been patched. */ + + .file "amd64-entry-value-paramref.cc" + .text +.Ltext0: + .p2align 4,,15 + .type _ZL3barRi.constprop.0, @function +_ZL3barRi.constprop.0: +.LFB2: + .file 1 "gdb.arch/amd64-entry-value-paramref.cc" + # gdb.arch/amd64-entry-value-paramref.cc:21 + .loc 1 21 0 + .cfi_startproc +.LVL0: +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + # gdb.arch/amd64-entry-value-paramref.cc:23 + .loc 1 23 0 + movl vv(%rip), %eax + # gdb.arch/amd64-entry-value-paramref.cc:24 + .loc 1 24 0 + movq %rdi, p(%rip) + # gdb.arch/amd64-entry-value-paramref.cc:23 + .loc 1 23 0 + addl $1, %eax + movl %eax, vv(%rip) + # gdb.arch/amd64-entry-value-paramref.cc:25 + .loc 1 25 0 + movl (%rdi), %eax +# SUCC: EXIT [100.0%] + # gdb.arch/amd64-entry-value-paramref.cc:26 + .loc 1 26 0 + ret + .cfi_endproc +.LFE2: + .size _ZL3barRi.constprop.0, .-_ZL3barRi.constprop.0 + .section .text.startup,"ax",@progbits + .p2align 4,,15 + .globl main + .type main, @function +main: +.LFB1: + # gdb.arch/amd64-entry-value-paramref.cc:30 + .loc 1 30 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) + subq $16, %rsp + .cfi_def_cfa_offset 24 +.LBB2: + # gdb.arch/amd64-entry-value-paramref.cc:32 + .loc 1 32 0 + leaq 12(%rsp), %rdi + # gdb.arch/amd64-entry-value-paramref.cc:31 + .loc 1 31 0 + movl $10, 12(%rsp) + # gdb.arch/amd64-entry-value-paramref.cc:32 + .loc 1 32 0 + call _ZL3barRi.constprop.0 +.LVL1: +.LBE2: + # gdb.arch/amd64-entry-value-paramref.cc:33 + .loc 1 33 0 + addq $16, %rsp + .cfi_def_cfa_offset 8 +# SUCC: EXIT [100.0%] + ret + .cfi_endproc +.LFE1: + .size main, .-main + .globl p + .bss + .align 8 + .type p, @object + .size p, 8 +p: + .zero 8 + .globl vv + .align 4 + .type vv, @object + .size vv, 4 +vv: + .zero 4 + .text +.Letext0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .long .Linfo_end - .Linfo_start # Length of Compilation Unit Info +.Linfo_start: + .value 0x4 # DWARF version number + .long .Ldebug_abbrev0 # Offset Into Abbrev. Section + .byte 0x8 # Pointer Size (in bytes) + .uleb128 0x1 # (DIE (0xb) DW_TAG_compile_unit) + .long .LASF0 # DW_AT_producer: "GNU C++ 4.8.2 20131212 (Red Hat 4.8.2-7) -mtune=generic -march=x86-64 -g -O2" + .byte 0x4 # DW_AT_language + .long .LASF1 # DW_AT_name: "gdb.arch/amd64-entry-value-paramref.cc" + .long .LASF2 # DW_AT_comp_dir: "" + .long .Ldebug_ranges0+0 # DW_AT_ranges + .quad 0 # DW_AT_low_pc + .long .Ldebug_line0 # DW_AT_stmt_list +DIE29: .uleb128 0x2 # (DIE (0x29) DW_TAG_subprogram) + .ascii "bar\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x15 # DW_AT_decl_line + .long DIE45 # DW_AT_type + .byte 0x1 # DW_AT_inline +DIE39: .uleb128 0x3 # (DIE (0x39) DW_TAG_formal_parameter) + .ascii "ref\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x15 # DW_AT_decl_line + .long DIE4c # DW_AT_type + .byte 0 # end of children of DIE 0x29 +DIE45: .uleb128 0x4 # (DIE (0x45) DW_TAG_base_type) + .byte 0x4 # DW_AT_byte_size + .byte 0x5 # DW_AT_encoding + .ascii "int\0" # DW_AT_name +DIE4c: .uleb128 0x5 # (DIE (0x4c) DW_TAG_const_type) + .long DIE51 # DW_AT_type +DIE51: .uleb128 0x6 # (DIE (0x51) DW_TAG_reference_type) + .byte 0x8 # DW_AT_byte_size + .long DIE45 # DW_AT_type +DIE57: .uleb128 0x7 # (DIE (0x57) DW_TAG_subprogram) + .long DIE29 # DW_AT_abstract_origin + .quad .LFB2 # DW_AT_low_pc + .quad .LFE2-.LFB2 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites +DIE72: .uleb128 0x8 # (DIE (0x72) DW_TAG_formal_parameter) + .long DIE39 # DW_AT_abstract_origin + .uleb128 0x1 # DW_AT_location + .byte 0x55 # DW_OP_reg5 + .byte 0 # end of children of DIE 0x57 +DIE7a: .uleb128 0x9 # (DIE (0x7a) DW_TAG_subprogram) + # DW_AT_external + .long .LASF3 # DW_AT_name: "main" + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x1d # DW_AT_decl_line + .long DIE45 # DW_AT_type + .quad .LFB1 # DW_AT_low_pc + .quad .LFE1-.LFB1 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites +DIE9b: .uleb128 0xa # (DIE (0x9b) DW_TAG_lexical_block) + .quad .LBB2 # DW_AT_low_pc + .quad .LBE2-.LBB2 # DW_AT_high_pc +DIEac: .uleb128 0xb # (DIE (0xac) DW_TAG_variable) + .ascii "var\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x1f # DW_AT_decl_line + .long DIE45 # DW_AT_type + .uleb128 0x2 # DW_AT_location + .byte 0x91 # DW_OP_fbreg + .sleb128 -12 +DIEba: .uleb128 0xc # (DIE (0xba) DW_TAG_GNU_call_site) + .quad .LVL1 # DW_AT_low_pc + .long DIE57 # DW_AT_abstract_origin +DIEc7: .uleb128 0xd # (DIE (0xc7) DW_TAG_GNU_call_site_parameter) + .uleb128 0x1 # DW_AT_location + .byte 0x55 # DW_OP_reg5 + .uleb128 0x2 # DW_AT_GNU_call_site_value + .byte 0x91 # DW_OP_fbreg + .sleb128 -12 +#if 0 + .uleb128 0x1 # DW_AT_GNU_call_site_data_value + .byte 0x3a # DW_OP_lit10 +#else + .uleb128 1f - 2f # DW_AT_GNU_call_site_data_value +2: + .byte 0xf3 # DW_OP_GNU_entry_value + .uleb128 1f - 3f +3: + .byte 0x55 # DW_OP_reg5 +1: +#endif + .byte 0 # end of children of DIE 0xba + .byte 0 # end of children of DIE 0x9b + .byte 0 # end of children of DIE 0x7a +DIEd2: .uleb128 0xe # (DIE (0xd2) DW_TAG_variable) + .ascii "vv\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x12 # DW_AT_decl_line + .long DIEe6 # DW_AT_type + # DW_AT_external + .uleb128 0x9 # DW_AT_location + .byte 0x3 # DW_OP_addr + .quad vv +DIEe6: .uleb128 0xf # (DIE (0xe6) DW_TAG_volatile_type) + .long DIE45 # DW_AT_type +DIEeb: .uleb128 0xe # (DIE (0xeb) DW_TAG_variable) + .ascii "p\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-entry-value-paramref.cc) + .byte 0x12 # DW_AT_decl_line + .long DIEfe # DW_AT_type + # DW_AT_external + .uleb128 0x9 # DW_AT_location + .byte 0x3 # DW_OP_addr + .quad p +DIEfe: .uleb128 0x10 # (DIE (0xfe) DW_TAG_pointer_type) + .byte 0x8 # DW_AT_byte_size + .long DIEe6 # DW_AT_type + .byte 0 # end of children of DIE 0xb +.Linfo_end: + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .uleb128 0x1 # (abbrev code) + .uleb128 0x11 # (TAG: DW_TAG_compile_unit) + .byte 0x1 # DW_children_yes + .uleb128 0x25 # (DW_AT_producer) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x13 # (DW_AT_language) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x1b # (DW_AT_comp_dir) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x55 # (DW_AT_ranges) + .uleb128 0x17 # (DW_FORM_sec_offset) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x10 # (DW_AT_stmt_list) + .uleb128 0x17 # (DW_FORM_sec_offset) + .byte 0 + .byte 0 + .uleb128 0x2 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x20 # (DW_AT_inline) + .uleb128 0xb # (DW_FORM_data1) + .byte 0 + .byte 0 + .uleb128 0x3 # (abbrev code) + .uleb128 0x5 # (TAG: DW_TAG_formal_parameter) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x4 # (abbrev code) + .uleb128 0x24 # (TAG: DW_TAG_base_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3e # (DW_AT_encoding) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .byte 0 + .byte 0 + .uleb128 0x5 # (abbrev code) + .uleb128 0x26 # (TAG: DW_TAG_const_type) + .byte 0 # DW_children_no + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x6 # (abbrev code) + .uleb128 0x10 # (TAG: DW_TAG_reference_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x7 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x31 # (DW_AT_abstract_origin) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .byte 0 + .byte 0 + .uleb128 0x8 # (abbrev code) + .uleb128 0x5 # (TAG: DW_TAG_formal_parameter) + .byte 0 # DW_children_no + .uleb128 0x31 # (DW_AT_abstract_origin) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x18 # (DW_FORM_exprloc) + .byte 0 + .byte 0 + .uleb128 0x9 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x3f # (DW_AT_external) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .byte 0 + .byte 0 + .uleb128 0xa # (abbrev code) + .uleb128 0xb # (TAG: DW_TAG_lexical_block) + .byte 0x1 # DW_children_yes + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .byte 0 + .byte 0 + .uleb128 0xb # (abbrev code) + .uleb128 0x34 # (TAG: DW_TAG_variable) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x18 # (DW_FORM_exprloc) + .byte 0 + .byte 0 + .uleb128 0xc # (abbrev code) + .uleb128 0x4109 # (TAG: DW_TAG_GNU_call_site) + .byte 0x1 # DW_children_yes + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x31 # (DW_AT_abstract_origin) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0xd # (abbrev code) + .uleb128 0x410a # (TAG: DW_TAG_GNU_call_site_parameter) + .byte 0 # DW_children_no + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2111 # (DW_AT_GNU_call_site_value) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2112 # (DW_AT_GNU_call_site_data_value) + .uleb128 0x18 # (DW_FORM_exprloc) + .byte 0 + .byte 0 + .uleb128 0xe # (abbrev code) + .uleb128 0x34 # (TAG: DW_TAG_variable) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x3f # (DW_AT_external) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x18 # (DW_FORM_exprloc) + .byte 0 + .byte 0 + .uleb128 0xf # (abbrev code) + .uleb128 0x35 # (TAG: DW_TAG_volatile_type) + .byte 0 # DW_children_no + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x10 # (abbrev code) + .uleb128 0xf # (TAG: DW_TAG_pointer_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .byte 0 + .section .debug_aranges,"",@progbits + .long 0x3c # Length of Address Ranges Info + .value 0x2 # DWARF Version + .long .Ldebug_info0 # Offset of Compilation Unit Info + .byte 0x8 # Size of Address + .byte 0 # Size of Segment Descriptor + .value 0 # Pad to 16 byte boundary + .value 0 + .quad .Ltext0 # Address + .quad .Letext0-.Ltext0 # Length + .quad .LFB1 # Address + .quad .LFE1-.LFB1 # Length + .quad 0 + .quad 0 + .section .debug_ranges,"",@progbits +.Ldebug_ranges0: + .quad .Ltext0 # Offset 0 + .quad .Letext0 + .quad .LFB1 # Offset 0x10 + .quad .LFE1 + .quad 0 + .quad 0 + .section .debug_line,"",@progbits +.Ldebug_line0: + .section .debug_str,"MS",@progbits,1 +.LASF1: + .string "gdb.arch/amd64-entry-value-paramref.cc" +.LASF2: + .string "" +.LASF0: + .string "GNU C++ 4.8.2 20131212 (Red Hat 4.8.2-7) -mtune=generic -march=x86-64 -g -O2" +.LASF3: + .string "main" + .ident "GCC: (GNU) 4.8.2 20131212 (Red Hat 4.8.2-7)" + .section .note.GNU-stack,"",@progbits diff --git a/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.cc b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.cc new file mode 100644 index 0000000..aa473a3 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.cc @@ -0,0 +1,33 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + 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/>. */ + +volatile int vv, *p; + +static __attribute__((noinline)) int +bar (int &ref) +{ + vv++; /* break-here */ + p = &ref; + return ref; +} + +int +main (void) +{ + int var = 10; + return bar (var); +} diff --git a/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.exp b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.exp new file mode 100644 index 0000000..f06247d --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-entry-value-paramref.exp @@ -0,0 +1,35 @@ +# Copyright (C) 2014 Free Software Foundation, Inc. +# +# 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/>. + +standard_testfile .S .cc + +if { ![istarget x86_64-*-* ] || ![is_lp64_target] } { + verbose "Skipping amd64-entry-value-paramref." + return +} + +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} "c++"] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +set srcfile $srcfile2 +gdb_breakpoint [gdb_get_line_number "break-here"] + +gdb_continue_to_breakpoint "break-here" ".* break-here .*" +gdb_test "frame" {bar \(ref=@0x[0-9a-f]+: 10, ref@entry=@0x[0-9a-f]+: <optimized out>\) at .*} diff --git a/gdb/testsuite/gdb.arch/amd64-optimout-repeat.S b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.S new file mode 100644 index 0000000..2f8f4d2 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.S @@ -0,0 +1,297 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012-2014 Free Software Foundation, Inc. + + 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/>. */ + +/* This file is compiled from gdb.arch/amd64-entry-value-param.c + using -g -dA -S -O2. */ + + .file "amd64-optimout-repeat.c" + .text +.Ltext0: + .section .text.unlikely,"ax",@progbits +.LCOLDB0: + .section .text.startup,"ax",@progbits +.LHOTB0: + .p2align 4,,15 + .section .text.unlikely +.Ltext_cold0: + .section .text.startup + .globl main + .type main, @function +main: +.LFB0: + .file 1 "gdb.arch/amd64-optimout-repeat.c" + # gdb.arch/amd64-optimout-repeat.c:20 + .loc 1 20 0 + .cfi_startproc +# BLOCK 2 freq:10000 seq:0 +# PRED: ENTRY [100.0%] (FALLTHRU) +.LVL0: + # gdb.arch/amd64-optimout-repeat.c:29 + .loc 1 29 0 + xorl %eax, %eax +# SUCC: EXIT [100.0%] + ret + .cfi_endproc +.LFE0: + .size main, .-main + .section .text.unlikely +.LCOLDE0: + .section .text.startup +.LHOTE0: + .text +.Letext0: + .section .text.unlikely +.Letext_cold0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .long 0x97 # Length of Compilation Unit Info + .value 0x4 # DWARF version number + .long .Ldebug_abbrev0 # Offset Into Abbrev. Section + .byte 0x8 # Pointer Size (in bytes) + .uleb128 0x1 # (DIE (0xb) DW_TAG_compile_unit) + .long .LASF1 # DW_AT_producer: "GNU C 4.9.1 20140709 (prerelease) -mtune=generic -march=x86-64 -g -O2" + .byte 0x1 # DW_AT_language + .long .LASF2 # DW_AT_name: "gdb.arch/amd64-optimout-repeat.c" + .long .LASF3 # DW_AT_comp_dir: "" + .long .Ldebug_ranges0+0 # DW_AT_ranges + .quad 0 # DW_AT_low_pc + .long .Ldebug_line0 # DW_AT_stmt_list + .uleb128 0x2 # (DIE (0x29) DW_TAG_subprogram) + # DW_AT_external + .long .LASF4 # DW_AT_name: "main" + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-optimout-repeat.c) + .byte 0x13 # DW_AT_decl_line + # DW_AT_prototyped + .long 0x7c # DW_AT_type + .quad .LFB0 # DW_AT_low_pc + .quad .LFE0-.LFB0 # DW_AT_high_pc + .uleb128 0x1 # DW_AT_frame_base + .byte 0x9c # DW_OP_call_frame_cfa + # DW_AT_GNU_all_call_sites + .long 0x7c # DW_AT_sibling + .uleb128 0x3 # (DIE (0x4a) DW_TAG_structure_type) + .value 0x404 # DW_AT_byte_size + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-optimout-repeat.c) + .byte 0x15 # DW_AT_decl_line + .long 0x6a # DW_AT_sibling + .uleb128 0x4 # (DIE (0x53) DW_TAG_member) + .ascii "i\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-optimout-repeat.c) + .byte 0x17 # DW_AT_decl_line + .long 0x7c # DW_AT_type + .byte 0 # DW_AT_data_member_location + .uleb128 0x4 # (DIE (0x5d) DW_TAG_member) + .ascii "xxx\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-optimout-repeat.c) + .byte 0x18 # DW_AT_decl_line + .long 0x83 # DW_AT_type + .byte 0x4 # DW_AT_data_member_location + .byte 0 # end of children of DIE 0x4a + .uleb128 0x5 # (DIE (0x6a) DW_TAG_variable) + .ascii "v\0" # DW_AT_name + .byte 0x1 # DW_AT_decl_file (gdb.arch/amd64-optimout-repeat.c) + .byte 0x1a # DW_AT_decl_line + .long 0x4a # DW_AT_type + .uleb128 0x7 # DW_AT_location + .byte 0x30 # DW_OP_lit0 + .byte 0x9f # DW_OP_stack_value + .byte 0x93 # DW_OP_piece + .uleb128 0x4 + .byte 0x93 # DW_OP_piece + .uleb128 0x400 + .byte 0 # end of children of DIE 0x29 + .uleb128 0x6 # (DIE (0x7c) DW_TAG_base_type) + .byte 0x4 # DW_AT_byte_size + .byte 0x5 # DW_AT_encoding + .ascii "int\0" # DW_AT_name + .uleb128 0x7 # (DIE (0x83) DW_TAG_array_type) + .long 0x7c # DW_AT_type + .long 0x93 # DW_AT_sibling + .uleb128 0x8 # (DIE (0x8c) DW_TAG_subrange_type) + .long 0x93 # DW_AT_type + .byte 0xff # DW_AT_upper_bound + .byte 0 # end of children of DIE 0x83 + .uleb128 0x9 # (DIE (0x93) DW_TAG_base_type) + .byte 0x8 # DW_AT_byte_size + .byte 0x7 # DW_AT_encoding + .long .LASF0 # DW_AT_name: "sizetype" + .byte 0 # end of children of DIE 0xb + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .uleb128 0x1 # (abbrev code) + .uleb128 0x11 # (TAG: DW_TAG_compile_unit) + .byte 0x1 # DW_children_yes + .uleb128 0x25 # (DW_AT_producer) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x13 # (DW_AT_language) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x1b # (DW_AT_comp_dir) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x55 # (DW_AT_ranges) + .uleb128 0x17 # (DW_FORM_sec_offset) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x10 # (DW_AT_stmt_list) + .uleb128 0x17 # (DW_FORM_sec_offset) + .byte 0 + .byte 0 + .uleb128 0x2 # (abbrev code) + .uleb128 0x2e # (TAG: DW_TAG_subprogram) + .byte 0x1 # DW_children_yes + .uleb128 0x3f # (DW_AT_external) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x27 # (DW_AT_prototyped) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x11 # (DW_AT_low_pc) + .uleb128 0x1 # (DW_FORM_addr) + .uleb128 0x12 # (DW_AT_high_pc) + .uleb128 0x7 # (DW_FORM_data8) + .uleb128 0x40 # (DW_AT_frame_base) + .uleb128 0x18 # (DW_FORM_exprloc) + .uleb128 0x2117 # (DW_AT_GNU_all_call_sites) + .uleb128 0x19 # (DW_FORM_flag_present) + .uleb128 0x1 # (DW_AT_sibling) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x3 # (abbrev code) + .uleb128 0x13 # (TAG: DW_TAG_structure_type) + .byte 0x1 # DW_children_yes + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0x5 # (DW_FORM_data2) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x1 # (DW_AT_sibling) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x4 # (abbrev code) + .uleb128 0xd # (TAG: DW_TAG_member) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x38 # (DW_AT_data_member_location) + .uleb128 0xb # (DW_FORM_data1) + .byte 0 + .byte 0 + .uleb128 0x5 # (abbrev code) + .uleb128 0x34 # (TAG: DW_TAG_variable) + .byte 0 # DW_children_no + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .uleb128 0x3a # (DW_AT_decl_file) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3b # (DW_AT_decl_line) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x2 # (DW_AT_location) + .uleb128 0x18 # (DW_FORM_exprloc) + .byte 0 + .byte 0 + .uleb128 0x6 # (abbrev code) + .uleb128 0x24 # (TAG: DW_TAG_base_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3e # (DW_AT_encoding) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0x8 # (DW_FORM_string) + .byte 0 + .byte 0 + .uleb128 0x7 # (abbrev code) + .uleb128 0x1 # (TAG: DW_TAG_array_type) + .byte 0x1 # DW_children_yes + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x1 # (DW_AT_sibling) + .uleb128 0x13 # (DW_FORM_ref4) + .byte 0 + .byte 0 + .uleb128 0x8 # (abbrev code) + .uleb128 0x21 # (TAG: DW_TAG_subrange_type) + .byte 0 # DW_children_no + .uleb128 0x49 # (DW_AT_type) + .uleb128 0x13 # (DW_FORM_ref4) + .uleb128 0x2f # (DW_AT_upper_bound) + .uleb128 0xb # (DW_FORM_data1) + .byte 0 + .byte 0 + .uleb128 0x9 # (abbrev code) + .uleb128 0x24 # (TAG: DW_TAG_base_type) + .byte 0 # DW_children_no + .uleb128 0xb # (DW_AT_byte_size) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3e # (DW_AT_encoding) + .uleb128 0xb # (DW_FORM_data1) + .uleb128 0x3 # (DW_AT_name) + .uleb128 0xe # (DW_FORM_strp) + .byte 0 + .byte 0 + .byte 0 + .section .debug_aranges,"",@progbits + .long 0x2c # Length of Address Ranges Info + .value 0x2 # DWARF Version + .long .Ldebug_info0 # Offset of Compilation Unit Info + .byte 0x8 # Size of Address + .byte 0 # Size of Segment Descriptor + .value 0 # Pad to 16 byte boundary + .value 0 + .quad .LFB0 # Address + .quad .LFE0-.LFB0 # Length + .quad 0 + .quad 0 + .section .debug_ranges,"",@progbits +.Ldebug_ranges0: + .quad .LFB0 # Offset 0 + .quad .LFE0 + .quad 0 + .quad 0 + .section .debug_line,"",@progbits +.Ldebug_line0: + .section .debug_str,"MS",@progbits,1 +.LASF0: + .string "sizetype" +.LASF2: + .string "gdb.arch/amd64-optimout-repeat.c" +.LASF1: + .string "GNU C 4.9.1 20140709 (prerelease) -mtune=generic -march=x86-64 -g -O2" +.LASF3: + .string "" +.LASF4: + .string "main" + .ident "GCC: (GNU) 4.9.1 20140709 (prerelease)" + .section .note.GNU-stack,"",@progbits diff --git a/gdb/testsuite/gdb.arch/amd64-optimout-repeat.c b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.c new file mode 100644 index 0000000..a32b6de --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.c @@ -0,0 +1,29 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + 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/>. */ + +int +main (void) +{ + struct + { + int i; + int xxx[0x100]; + } + v = { 0 }; + + return v.i; +} diff --git a/gdb/testsuite/gdb.arch/amd64-optimout-repeat.exp b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.exp new file mode 100644 index 0000000..f3c93a4 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-optimout-repeat.exp @@ -0,0 +1,36 @@ +# Copyright (C) 2014 Free Software Foundation, Inc. +# +# 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/>. + +standard_testfile .S .c +set opts {} + +if [info exists COMPILE] { + # make check RUNTESTFLAGS="gdb.arch/amd64-optimout-repeat.exp COMPILE=1" + set srcfile ${srcfile2} + lappend opts debug optimize=-O2 +} elseif { ![istarget x86_64-*-* ] || ![is_lp64_target] } { + verbose "Skipping amd64-optimout-repeat." + return +} + +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} $opts] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +gdb_test "print v" { = {i = 0, xxx = {<optimized out> <repeats 256 times>}}} ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [commit+7.8] [read_frame_arg patch] Handle partially optimized out values similarly to unavailable values 2014-07-22 20:21 ` [commit+7.8] [read_frame_arg patch] Handle partially optimized out values similarly to unavailable values Jan Kratochvil @ 2014-08-05 17:16 ` Doug Evans 2014-08-14 18:25 ` Jan Kratochvil 0 siblings, 1 reply; 28+ messages in thread From: Doug Evans @ 2014-08-05 17:16 UTC (permalink / raw) To: Jan Kratochvil; +Cc: Pedro Alves, gdb-patches Jan Kratochvil writes: > On Tue, 22 Jul 2014 21:19:22 +0200, Pedro Alves wrote: > > OK, I've pushed the reversion (without the #if 0 bit) to both master > > and 7.8. > > Therefore pushed in the fix of read_frame_arg together with the testcase. > e214cf6c2e05bcfc85dc6f335d8ffdc3629cf0cf > and also for 7.8: > 0f9e1204f3de3cbe46a2b9e54049c1df9a5df305 > > > Jan > commit e214cf6c2e05bcfc85dc6f335d8ffdc3629cf0cf > Author: Jan Kratochvil <jan.kratochvil@redhat.com> > Date: Tue Jul 22 22:09:35 2014 +0200 > > Fix read_frame_arg for optimized-out entry values. > > gdb/ > 2014-07-22 Jan Kratochvil <jan.kratochvil@redhat.com> > > * stack.c (read_frame_arg): Verify value_optimized_out before calling > value_available_contents_eq. > > gdb/testsuite/ > 2014-07-22 Jan Kratochvil <jan.kratochvil@redhat.com> > > * gdb.arch/amd64-entry-value-paramref.S: New file. > * gdb.arch/amd64-entry-value-paramref.cc: New file. > * gdb.arch/amd64-entry-value-paramref.exp: New file. > * gdb.arch/amd64-optimout-repeat.S: New file. > * gdb.arch/amd64-optimout-repeat.c: New file. > * gdb.arch/amd64-optimout-repeat.exp: New file. > > Message-ID: <20140720150727.GA18488@host2.jankratochvil.net> > Message-ID: <20140711153757.GA452@host2.jankratochvil.net> Hi. In trunk I'm seeing amd64-entry-value-paramref.exp fail with a gdb internal error. I can debug this further if you need me to. (gdb) file testsuite/gdb.arch/amd64-entry-value-paramref [...] (top-gdb) bt #0 internal_error (file=0xa249e8 "../../entry-value/gdb/dwarf2read.c", line=15776, string=0xa28050 "could not find partial DIE 0x%x in cache [from module %s]\n") at ../../entry-value/gdb/utils.c:823 #1 0x00000000006a89cb in find_partial_die (offset=..., offset_in_dwz=0, cu=0x1029370) at ../../entry-value/gdb/dwarf2read.c:15776 #2 0x00000000006a8c9d in fixup_partial_die (part_die=0x103a6f0, cu=0x1029370) at ../../entry-value/gdb/dwarf2read.c:15855 #3 0x0000000000692b49 in scan_partial_symbols (first_die=0x103a690, lowpc=0x7fffffffdb78, highpc=0x7fffffffdb70, need_pc=0, cu=0x1029370) at ../../entry-value/gdb/dwarf2read.c:6567 #4 0x000000000069132a in process_psymtab_comp_unit_reader (reader=0x7fffffffdcc0, info_ptr=0xf6c78c "\002bar", comp_unit_die=0x103a480, has_children=1, data=0x7fffffffdd90) at ../../entry-value/gdb/dwarf2read.c:5913 #5 0x0000000000690662 in init_cutu_and_read_dies (this_cu=0xf5d770, abbrev_table=0x0, use_existing_cu=0, keep=0, die_reader_func=0x690fe2 <process_psymtab_comp_unit_reader>, data=0x7fffffffdd90) at ../../entry-value/gdb/dwarf2read.c:5529 #6 0x00000000006917d0 in process_psymtab_comp_unit (this_cu=0xf5d770, want_partial_unit=0, pretend_language=language_minimal) at ../../entry-value/gdb/dwarf2read.c:5998 #7 0x0000000000692456 in dwarf2_build_psymtabs_hard (objfile=0x101eab0) at ../../entry-value/gdb/dwarf2read.c:6397 #8 0x000000000068d225 in dwarf2_build_psymtabs (objfile=0x101eab0) at ../../entry-value/gdb/dwarf2read.c:4173 #9 0x0000000000554e9d in read_psyms (objfile=0x101eab0) at ../../entry-value/gdb/elfread.c:1363 [...] ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [commit+7.8] [read_frame_arg patch] Handle partially optimized out values similarly to unavailable values 2014-08-05 17:16 ` Doug Evans @ 2014-08-14 18:25 ` Jan Kratochvil 0 siblings, 0 replies; 28+ messages in thread From: Jan Kratochvil @ 2014-08-14 18:25 UTC (permalink / raw) To: Doug Evans; +Cc: Pedro Alves, gdb-patches On Tue, 05 Aug 2014 19:16:17 +0200, Doug Evans wrote: > In trunk I'm seeing amd64-entry-value-paramref.exp fail with a > gdb internal error. I can debug this further if you need me to. Yes, please. We probably agree it should be sufficient to send me binaries built by the testcase. Thanks, Jan ^ permalink raw reply [flat|nested] 28+ messages in thread
* [commit] Remove setting value address for reference entry value target data value 2014-07-22 19:33 ` Pedro Alves 2014-07-22 20:21 ` [commit+7.8] [read_frame_arg patch] Handle partially optimized out values similarly to unavailable values Jan Kratochvil @ 2014-07-23 14:26 ` Jan Kratochvil 1 sibling, 0 replies; 28+ messages in thread From: Jan Kratochvil @ 2014-07-23 14:26 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches [-- Attachment #1: Type: text/plain, Size: 207 bytes --] On Tue, 22 Jul 2014 21:19:22 +0200, Pedro Alves wrote: > Thanks Jan. Indeed I'd much prefer removing it. > It's fine with me to still leave it in 7.8 in case we missed > something. Removed on trunk. Jan [-- Attachment #2: 1 --] [-- Type: text/plain, Size: 5404 bytes --] commit 45326f6fbe28ef5bac22dac447a4181c44cb945a Author: Jan Kratochvil <jan.kratochvil@redhat.com> Date: Tue Jul 22 22:15:27 2014 +0200 Remove setting value address for reference entry value target data value. I cannot reproduce any wrong case having the code removed. I just do not find it correct to have it disabled. But at the same time I do like much / I do not find correct the code myself. It is a bit problematic to have struct value describing a memory content which is no longer present there. What happens there: ------------------------------------------------------------------------------ volatile int vv; static __attribute__((noinline)) int bar (int &ref) { ref = 20; vv++; /* break-here */ return ref; } int main (void) { int var = 10; return bar (var); } ------------------------------------------------------------------------------ <4><c7>: Abbrev Number: 13 (DW_TAG_GNU_call_site_parameter) <c8> DW_AT_location : 1 byte block: 55 (DW_OP_reg5 (rdi)) <ca> DW_AT_GNU_call_site_value: 2 byte block: 91 74 (DW_OP_fbreg: -12) <cd> DW_AT_GNU_call_site_data_value: 1 byte block: 3a (DW_OP_lit10) ------------------------------------------------------------------------------ gdb -ex 'b value_addr' -ex r --args ../gdb ./1 -ex 'watch vv' -ex r -ex 'p &ref@entry' -> 6 return ref; bar (ref=@0x7fffffffd944: 20, ref@entry=@0x7fffffffd944: 10) at 1.C:25 ------------------------------------------------------------------------------ At /* break-here */ struct value variable 'ref' is TYPE_CODE_REF. With FSF GDB HEAD: (gdb) x/gx arg1.contents 0x6004000a4ad0: 0x00007fffffffd944 (gdb) p ((struct value *)arg1.location.computed.closure).lval $1 = lval_memory (gdb) p/x ((struct value *)arg1.location.computed.closure).location.address $3 = 0x7fffffffd944 With your #if0-ed code: (gdb) x/gx arg1.contents 0x6004000a4ad0: 0x00007fffffffd944 (gdb) p ((struct value *)arg1.location.computed.closure).lval $8 = not_lval (gdb) p/x ((struct value *)arg1.location.computed.closure).location.address $9 = 0x0 I do not see how to access ((struct value *)arg1.location.computed.closure).location.address from GDB CLI. Trying (gdb) p &ref@entry will invoke value_addr()'s: if (TYPE_CODE (type) == TYPE_CODE_REF) /* Copy the value, but change the type from (T&) to (T*). We keep the same location information, which is efficient, and allows &(&X) to get the location containing the reference. */ and therefore the address gets fetched already from arg1.contents and not from ((struct value *)arg1.location.computed.closure).location.address . And for any other type than TYPE_CODE_REF this code you removed does not get executed at all. This DW_AT_GNU_call_site_data_value DWARF was meant primarily for Fortran but with -O0 entry values do not get produced and with -Og and higher Fortran always optimizes out the passing by reference. If you do not like the removed code there I am OK with removing it as I do not know how to make it's use reproducible for user anyway. In the worst case - if there really is some way how to exploit it - one should just get Attempt to take address of value not located in memory. instead of some wrong value and it may be easy to fix then. gdb/ 2014-07-22 Jan Kratochvil <jan.kratochvil@redhat.com> * dwarf2loc.c (value_of_dwarf_reg_entry): Remove setting value address for reference entry value target data value. Message-ID: <20140720150727.GA18488@host2.jankratochvil.net> diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 73a13d3..687e2fe 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,10 @@ 2014-07-22 Jan Kratochvil <jan.kratochvil@redhat.com> + * dwarf2loc.c (value_of_dwarf_reg_entry): Remove setting value address + for reference entry value target data value. + +2014-07-22 Jan Kratochvil <jan.kratochvil@redhat.com> + * stack.c (read_frame_arg): Verify value_optimized_out before calling value_available_contents_eq. diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index fcab9b9..b1c7ee1 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -1312,7 +1312,6 @@ value_of_dwarf_reg_entry (struct type *type, struct frame_info *frame, struct value *outer_val, *target_val, *val; struct call_site_parameter *parameter; struct dwarf2_per_cu_data *caller_per_cu; - CORE_ADDR addr; parameter = dwarf_expr_reg_to_entry_parameter (frame, kind, kind_u, &caller_per_cu); @@ -1335,14 +1334,6 @@ value_of_dwarf_reg_entry (struct type *type, struct frame_info *frame, target_type, caller_frame, caller_per_cu); - /* value_as_address dereferences TYPE_CODE_REF. */ - addr = extract_typed_address (value_contents (outer_val), checked_type); - - /* The target entry value has artificial address of the entry value - reference. */ - VALUE_LVAL (target_val) = lval_memory; - set_value_address (target_val, addr); - release_value (target_val); val = allocate_computed_value (type, &entry_data_value_funcs, target_val /* closure */); ^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v2] Handle partially optimized out values similarly to unavailable values 2014-07-17 8:04 ` Jan Kratochvil 2014-07-17 8:35 ` Jan Kratochvil 2014-07-17 13:38 ` Pedro Alves @ 2014-07-24 12:51 ` Pedro Alves 2014-08-15 20:13 ` Jan Kratochvil 2 siblings, 1 reply; 28+ messages in thread From: Pedro Alves @ 2014-07-24 12:51 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches On 07/16/2014 10:58 PM, Jan Kratochvil wrote: > On Mon, 14 Jul 2014 20:11:41 +0200, Pedro Alves wrote: > [...] >> --- a/gdb/value.c >> +++ b/gdb/value.c > [...] >> @@ -339,6 +330,15 @@ struct value >> value to be available. This is filled in at value read time. The >> unavailable ranges are tracked in bits. */ >> 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; > > I miss here explicit description if a bit of the range can appear on both > 'unavailable' and 'optimized_out'. IMO it should not. Yeah, it should not. Added: @@ -327,8 +327,10 @@ 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; >> @@ -1566,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; > > Why 'optimized_out' no longer needs to be copied? Hmm, I blindly assumed the function was using value_contents_copy. Copying that now. Thanks for spotting this. >> @@ -3662,10 +3753,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)); > > That was required before but it could handle partially optimized out > bitfields; but maybe it is not useful much. Yeah, though it doesn't look trivial. We should be able to copy the contents straight from the parent to VAL, but note we're copying only a few bits off the parent, into a wider VAL. So it seems like we'd need to: - have a value_contents_copy function that knows to copy bits, not bytes. - handle sign/zero extension - and handle big/little endian at that Best leave that out for now. >> >> +/* 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. Examples > > "printed as." - is the sentence finished? Whoops, it wasn't, thanks. I meant to write: "Such a value is normally printed as <unavailable>." > > >> + 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> > > s/<not-saved>/<unavailable>/? Nope, we really print them as <not-saved>. More here: https://sourceware.org/ml/gdb-patches/2013-09/msg00176.html I've extended the comment based on that email: @@ -60,11 +60,21 @@ struct xmethod_worker; 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>. + 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. >> + Returns true iff the set of available/valid contents match. >> + >> + Optimized out contents compare equal with optimized out contents, >> + and different with any non-optimized-out byte. > > English: s/different/differ/ The "different" is bound to the "compare" before, so it results in "contents compare ... different". I don't know how I'd use differ in a similar vein in the above. Sounds like I best rewrite this then. Here's what I came up with: @@ -513,11 +523,11 @@ extern void mark_value_bits_unavailable (struct value *value, Returns true iff the set of available/valid contents match. - Optimized out contents compare equal with optimized out contents, - and different with any non-optimized-out contents. + Optimized-out contents are equal to optimized-out contents, and are + not equal to non-optimized-out contents. - Unavailable contents compare equal with unavailable contents, and - different with non-unavailable contents. + Unavailable contents are equal to unavailable contents, and are not + equal to non-unavailable contents. > Maybe it would be all easier to have there single map and each range mapping > into enum { VALID, OPTIMIZED_OUT, UNAVAILABLE }. Yeah, as mentioned in the commit log, that was part of Andrew's original series, but I'd rather take baby steps and do that separately, as it required new code in the range merging code. New patch below. Let me know what you think. Thanks for the review. 8<------------ From d856ed9cb43ad48829c805a88dc6da55bfa149f0 Mon Sep 17 00:00:00 2001 From: Pedro Alves <palves@redhat.com> Date: Thu, 24 Jul 2014 12:48:35 +0100 Subject: [PATCH] Handle partially optimized out values similarly to unavailable values This fixes PR symtab/14604, PR symtab/14605, and Jan's test at https://sourceware.org/ml/gdb-patches/2014-07/msg00158.html, in a tree with bddbbed reverted: 2014-07-22 Pedro Alves <palves@redhat.com> * value.c (allocate_optimized_out_value): Don't mark value as non-lazy. The PRs are about variables described by the DWARF as being split over multiple registers using DWARF piece information, but some of those registers being marked as optimised out (not saved) by a later frame. GDB currently incorrectly mishandles these partially-optimized-out values. Even though we can usually tell from the debug info whether a local or global is optimized out, handling the case of a local living in a register that was not saved in a frame requires fetching the variable. GDB also needs to fetch a value to tell whether parts of it are "<unavailable>". Given this, it's not worth it to try to avoid fetching lazy optimized-out values based on debug info alone. So this patch makes GDB track which chunks of a value's contents are optimized out like it tracks <unavailable> contents. That is, it makes value->optimized_out be a bit range vector instead of a boolean, and removes the struct lval_funcs check_validity and check_any_valid hooks. Unlike Andrew's series which this is based on (at https://sourceware.org/ml/gdb-patches/2013-08/msg00300.html, note some pieces have gone in since), this doesn't merge optimized out and unavailable contents validity/availability behind a single interface, nor does it merge the bit range vectors themselves (at least yet). While it may be desirable to have a single entry point that returns existence of contents irrespective of what may make them invalid/unavailable, several places want to treat optimized out / unavailable / etc. differently, so each spot that potentially could use it will need to be careful considered on case-by-case basis, and best done as a separate change. This fixes Jan's test, because value_available_contents_eq wasn't considering optimized out value contents. It does now, and because of that it's been renamed to value_contents_eq. A new intro comment is added to value.h describing "<optimized out>", "<not saved>" and "<unavailable>" values. gdb/ 2014-07-24 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. gdb/testsuite/ 2014-07-24 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. --- gdb/ada-lang.c | 4 +- gdb/ada-valprint.c | 6 +- gdb/c-valprint.c | 6 +- gdb/cp-valprint.c | 11 +- gdb/d-valprint.c | 5 +- gdb/dwarf2loc.c | 81 +---- gdb/findvar.c | 8 +- gdb/frame-unwind.c | 2 +- gdb/jv-valprint.c | 13 +- gdb/mips-tdep.c | 6 - gdb/opencl-lang.c | 54 --- gdb/p-valprint.c | 5 - gdb/stack.c | 17 +- gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp | 30 +- gdb/valprint.c | 22 +- gdb/value.c | 467 +++++++++++++++----------- gdb/value.h | 158 ++++++--- 17 files changed, 445 insertions(+), 450 deletions(-) diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 6956909..63f84ea 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -682,14 +682,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 b7b3a9c..b4f191f 100644 --- a/gdb/ada-valprint.c +++ b/gdb/ada-valprint.c @@ -186,9 +186,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 f4694b0..2f2789c 100644 --- a/gdb/c-valprint.c +++ b/gdb/c-valprint.c @@ -173,9 +173,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 3e1d6ed..0d6c3fc 100644 --- a/gdb/cp-valprint.c +++ b/gdb/cp-valprint.c @@ -294,12 +294,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; @@ -434,8 +428,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 b1c7ee1..588abac 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -1285,8 +1285,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 */ @@ -1695,7 +1693,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); } @@ -1755,7 +1753,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: @@ -1793,7 +1791,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; } @@ -1925,7 +1923,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; @@ -1934,24 +1932,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)) @@ -1976,52 +1966,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. */ @@ -2170,8 +2119,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, @@ -2299,6 +2246,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 @@ -2306,7 +2255,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 9390c8a..346a499 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -681,12 +681,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) @@ -732,7 +726,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 fdfea6e..1cc3303 100644 --- a/gdb/frame-unwind.c +++ b/gdb/frame-unwind.c @@ -203,7 +203,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 a7bb494..93a827e 100644 --- a/gdb/jv-valprint.c +++ b/gdb/jv-valprint.c @@ -183,10 +183,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; } @@ -393,11 +393,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 c3e8e77..34b75f7 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -6196,12 +6196,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 2dd76fa..6a3ba69 100644 --- a/gdb/opencl-lang.c +++ b/gdb/opencl-lang.c @@ -240,58 +240,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. */ @@ -358,8 +306,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 4db5df5..346ce29 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -385,9 +385,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; @@ -413,11 +416,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/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 8600b34..981ef9b 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -311,8 +311,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; @@ -983,8 +984,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); @@ -1685,12 +1687,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 8b44a6d..01e9409 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -197,15 +197,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; @@ -336,9 +327,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 @@ -358,6 +360,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 @@ -370,17 +380,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 @@ -391,8 +406,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; @@ -483,10 +513,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)) { @@ -507,18 +537,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; @@ -526,11 +556,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; @@ -552,11 +582,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, @@ -684,48 +720,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 @@ -734,7 +775,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. */ @@ -744,31 +785,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. */ @@ -836,7 +939,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; @@ -905,11 +1007,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; } @@ -1057,7 +1156,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")); @@ -1097,6 +1196,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 @@ -1125,6 +1249,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, @@ -1135,18 +1262,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 @@ -1154,8 +1277,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. */ @@ -1164,8 +1286,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); @@ -1218,45 +1338,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 @@ -1569,7 +1673,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; @@ -1580,6 +1683,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) { @@ -2854,24 +2958,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)) { @@ -2884,37 +2983,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 { @@ -2925,12 +3016,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 { @@ -3649,6 +3735,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 @@ -3665,10 +3756,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, @@ -3743,16 +3835,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) { @@ -3805,11 +3893,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 86ebd70..bff5220 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 -- 1.9.3 ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values 2014-07-24 12:51 ` [PATCH v2] Handle partially optimized out values similarly to unavailable values Pedro Alves @ 2014-08-15 20:13 ` Jan Kratochvil 2014-08-19 23:36 ` Pedro Alves 0 siblings, 1 reply; 28+ messages in thread From: Jan Kratochvil @ 2014-08-15 20:13 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches On Thu, 24 Jul 2014 14:08:13 +0200, Pedro Alves wrote: > New patch below. Let me know what you think. My comments have been addressed, I find it OK. Thanks, Jan ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values 2014-08-15 20:13 ` Jan Kratochvil @ 2014-08-19 23:36 ` Pedro Alves 2014-08-20 0:55 ` Andrew Pinski 2014-08-21 19:57 ` Regression for i686 gdb.dwarf2/pieces-optimized-out.exp [Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values] Jan Kratochvil 0 siblings, 2 replies; 28+ messages in thread From: Pedro Alves @ 2014-08-19 23:36 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches On 08/15/2014 09:13 PM, Jan Kratochvil wrote: > On Thu, 24 Jul 2014 14:08:13 +0200, Pedro Alves wrote: >> New patch below. Let me know what you think. > > My comments have been addressed, I find it OK. Great, I pushed this in then. Thanks! Pedro Alves ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values 2014-08-19 23:36 ` Pedro Alves @ 2014-08-20 0:55 ` Andrew Pinski 2014-08-20 9:46 ` Pedro Alves 2014-08-21 19:57 ` Regression for i686 gdb.dwarf2/pieces-optimized-out.exp [Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values] Jan Kratochvil 1 sibling, 1 reply; 28+ messages in thread From: Andrew Pinski @ 2014-08-20 0:55 UTC (permalink / raw) To: Pedro Alves; +Cc: Jan Kratochvil, gdb-patches On Tue, Aug 19, 2014 at 4:36 PM, Pedro Alves <palves@redhat.com> wrote: > On 08/15/2014 09:13 PM, Jan Kratochvil wrote: >> On Thu, 24 Jul 2014 14:08:13 +0200, Pedro Alves wrote: >>> New patch below. Let me know what you think. >> >> My comments have been addressed, I find it OK. > > Great, I pushed this in then. This caused a build error for me: cc1: warnings being treated as errors ../../gdb/value.c: In function ‘value_contents_eq’: ../../gdb/value.c:830: error: ‘l’ may be used uninitialized in this function ../../gdb/value.c:830: note: ‘l’ was declared here ../../gdb/value.c:830: error: ‘h’ may be used uninitialized in this function ../../gdb/value.c:830: note: ‘h’ was declared here make[2]: *** [value.o] Error 1 Thanks, Andrew Pinski > > Thanks! > > Pedro Alves > ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values 2014-08-20 0:55 ` Andrew Pinski @ 2014-08-20 9:46 ` Pedro Alves 2014-08-20 10:32 ` [PUSHED] value.c (value_contents_bits_eq): Initialize l,h for gcc, -Wall. (was: Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values) Pedro Alves 0 siblings, 1 reply; 28+ messages in thread From: Pedro Alves @ 2014-08-20 9:46 UTC (permalink / raw) To: Andrew Pinski; +Cc: Jan Kratochvil, gdb-patches On 08/20/2014 01:54 AM, Andrew Pinski wrote: > On Tue, Aug 19, 2014 at 4:36 PM, Pedro Alves <palves@redhat.com> wrote: >> Great, I pushed this in then. > > This caused a build error for me: > > cc1: warnings being treated as errors > ../../gdb/value.c: In function âvalue_contents_eqâ: > ../../gdb/value.c:830: error: âlâ may be used uninitialized in this function > ../../gdb/value.c:830: note: âlâ was declared here > ../../gdb/value.c:830: error: âhâ may be used uninitialized in this function > ../../gdb/value.c:830: note: âhâ was declared here > make[2]: *** [value.o] Error 1 > > Thanks, > Andrew Pinski Thanks Andrew. I'm looking. -- Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 28+ messages in thread
* [PUSHED] value.c (value_contents_bits_eq): Initialize l,h for gcc, -Wall. (was: Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values) 2014-08-20 9:46 ` Pedro Alves @ 2014-08-20 10:32 ` Pedro Alves 2014-08-20 16:28 ` Andrew Pinski 0 siblings, 1 reply; 28+ messages in thread From: Pedro Alves @ 2014-08-20 10:32 UTC (permalink / raw) To: Andrew Pinski; +Cc: Jan Kratochvil, gdb-patches On 08/20/2014 10:46 AM, Pedro Alves wrote: > On 08/20/2014 01:54 AM, Andrew Pinski wrote: >> On Tue, Aug 19, 2014 at 4:36 PM, Pedro Alves <palves@redhat.com> wrote: > > >>> Great, I pushed this in then. >> >> This caused a build error for me: >> >> cc1: warnings being treated as errors >> ../../gdb/value.c: In function âvalue_contents_eqâ: >> ../../gdb/value.c:830: error: âlâ may be used uninitialized in this function >> ../../gdb/value.c:830: note: âlâ was declared here >> ../../gdb/value.c:830: error: âhâ may be used uninitialized in this function >> ../../gdb/value.c:830: note: âhâ was declared here >> make[2]: *** [value.o] Error 1 >> >> Thanks, >> Andrew Pinski > > Thanks Andrew. I'm looking. > I can't trigger that, but should be fixed now. Thanks. ------------ value.c (value_contents_bits_eq): Initialize l,h for gcc -Wall. gdb/ * value.c (value_contents_bits_eq): Initialize l,h for gcc -Wall. --- gdb/ChangeLog | 4 ++++ gdb/value.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 55cc92c..c0b4f82 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,7 @@ +2014-08-20 Pedro Alves <palves@redhat.com> + + * value.c (value_contents_bits_eq): Initialize l,h for gcc -Wall. + 2014-08-20 Yao Qi <yao@codesourcery.com> * amd64-tdep.c (amd64_classify): Add a blank line after the diff --git a/gdb/value.c b/gdb/value.c index b74f23a..09ee1ca 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -827,7 +827,7 @@ value_contents_bits_eq (const struct value *val1, int offset1, while (length > 0) { - ULONGEST l, h; + ULONGEST l = 0, h = 0; /* init for gcc -Wall */ int i; for (i = 0; i < 2; i++) -- 1.9.3 -- Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PUSHED] value.c (value_contents_bits_eq): Initialize l,h for gcc, -Wall. (was: Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values) 2014-08-20 10:32 ` [PUSHED] value.c (value_contents_bits_eq): Initialize l,h for gcc, -Wall. (was: Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values) Pedro Alves @ 2014-08-20 16:28 ` Andrew Pinski 0 siblings, 0 replies; 28+ messages in thread From: Andrew Pinski @ 2014-08-20 16:28 UTC (permalink / raw) To: Pedro Alves; +Cc: Jan Kratochvil, gdb-patches On Wed, Aug 20, 2014 at 3:32 AM, Pedro Alves <palves@redhat.com> wrote: > On 08/20/2014 10:46 AM, Pedro Alves wrote: >> On 08/20/2014 01:54 AM, Andrew Pinski wrote: >>> On Tue, Aug 19, 2014 at 4:36 PM, Pedro Alves <palves@redhat.com> wrote: >> >> >>>> Great, I pushed this in then. >>> >>> This caused a build error for me: >>> >>> cc1: warnings being treated as errors >>> ../../gdb/value.c: In function ‘value_contents_eq’: >>> ../../gdb/value.c:830: error: ‘l’ may be used uninitialized in this function >>> ../../gdb/value.c:830: note: ‘l’ was declared here >>> ../../gdb/value.c:830: error: ‘h’ may be used uninitialized in this function >>> ../../gdb/value.c:830: note: ‘h’ was declared here >>> make[2]: *** [value.o] Error 1 >>> >>> Thanks, >>> Andrew Pinski >> >> Thanks Andrew. I'm looking. >> > > I can't trigger that, but should be fixed now. Yes this fixes the issue for me. Thanks, Andrew > > Thanks. > > ------------ > value.c (value_contents_bits_eq): Initialize l,h for gcc -Wall. > > gdb/ > * value.c (value_contents_bits_eq): Initialize l,h for gcc -Wall. > --- > gdb/ChangeLog | 4 ++++ > gdb/value.c | 2 +- > 2 files changed, 5 insertions(+), 1 deletion(-) > > diff --git a/gdb/ChangeLog b/gdb/ChangeLog > index 55cc92c..c0b4f82 100644 > --- a/gdb/ChangeLog > +++ b/gdb/ChangeLog > @@ -1,3 +1,7 @@ > +2014-08-20 Pedro Alves <palves@redhat.com> > + > + * value.c (value_contents_bits_eq): Initialize l,h for gcc -Wall. > + > 2014-08-20 Yao Qi <yao@codesourcery.com> > > * amd64-tdep.c (amd64_classify): Add a blank line after the > diff --git a/gdb/value.c b/gdb/value.c > index b74f23a..09ee1ca 100644 > --- a/gdb/value.c > +++ b/gdb/value.c > @@ -827,7 +827,7 @@ value_contents_bits_eq (const struct value *val1, int offset1, > > while (length > 0) > { > - ULONGEST l, h; > + ULONGEST l = 0, h = 0; /* init for gcc -Wall */ > int i; > > for (i = 0; i < 2; i++) > -- > 1.9.3 > > > > -- > Thanks, > Pedro Alves ^ permalink raw reply [flat|nested] 28+ messages in thread
* Regression for i686 gdb.dwarf2/pieces-optimized-out.exp [Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values] 2014-08-19 23:36 ` Pedro Alves 2014-08-20 0:55 ` Andrew Pinski @ 2014-08-21 19:57 ` Jan Kratochvil 2014-08-22 16:20 ` Pedro Alves 1 sibling, 1 reply; 28+ messages in thread From: Jan Kratochvil @ 2014-08-21 19:57 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches On Wed, 20 Aug 2014 01:36:35 +0200, Pedro Alves wrote: > Great, I pushed this in then. -PASS: gdb.dwarf2/pieces-optimized-out.exp: print s +FAIL: gdb.dwarf2/pieces-optimized-out.exp: print s for i686 and x86_64-m32 configurations on all known platforms: 9a0dc9e3699018b15980bb6a39eb33dea8fefa34 is the first bad commit commit 9a0dc9e3699018b15980bb6a39eb33dea8fefa34 Author: Pedro Alves <palves@redhat.com> Date: Wed Aug 20 00:07:40 2014 +0100 Handle partially optimized out values similarly to unavailable values Jan ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Regression for i686 gdb.dwarf2/pieces-optimized-out.exp [Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values] 2014-08-21 19:57 ` Regression for i686 gdb.dwarf2/pieces-optimized-out.exp [Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values] Jan Kratochvil @ 2014-08-22 16:20 ` Pedro Alves 2014-08-24 19:56 ` Jan Kratochvil 2014-09-04 11:36 ` [pushed] " Pedro Alves 0 siblings, 2 replies; 28+ messages in thread From: Pedro Alves @ 2014-08-22 16:20 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches On 08/21/2014 08:57 PM, Jan Kratochvil wrote: > On Wed, 20 Aug 2014 01:36:35 +0200, Pedro Alves wrote: >> Great, I pushed this in then. > > -PASS: gdb.dwarf2/pieces-optimized-out.exp: print s > +FAIL: gdb.dwarf2/pieces-optimized-out.exp: print s > > for i686 and x86_64-m32 configurations on all known platforms: > > 9a0dc9e3699018b15980bb6a39eb33dea8fefa34 is the first bad commit > commit 9a0dc9e3699018b15980bb6a39eb33dea8fefa34 > Author: Pedro Alves <palves@redhat.com> > Date: Wed Aug 20 00:07:40 2014 +0100 > > Handle partially optimized out values similarly to unavailable values > Thanks Jan. So it didn't take that long to get back to handling partially optimized out bitfields after all... I think I found an easy way. We don't currently print partially optimized out scalars, though we could print the valid/invalid bits with p/t, for example, and I think the code ends up clearer anyway. ---------- Subject: [PATCH] Regression for i686 gdb.dwarf2/pieces-optimized-out.exp Git 9a0dc9e3 regressed gdb.dwarf2/pieces-optimized-out.exp, visible on i686 (the test doesn't run on x86_64): (gdb) p s -$1 = {a = 5, b = <optimized out>, c = <optimized out>, d = <optimized out>} +$1 = {a = 5, b = <optimized out>, c = 0, d = 0} -(gdb) PASS: gdb.dwarf2/pieces-optimized-out.exp: print s +(gdb) FAIL: gdb.dwarf2/pieces-optimized-out.exp: print s The regression was caused by this removal in 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; The idea was that we'd just fallback to calling value_field_bitfield, which handles unavailable values (in unpack_value_bits_as_long_1) so should be able to handle optimized out values too. Alas, it doesn't. This is currently a bit too messy. Instead of teaching unpack_value_bits_as_long_1 about optimized out bits, let's bite the bullet and teach the value code to handle partially optimized out bitfield, by having it unpack a bitfield and then propagate the range metadata. Turns out the resulting code looks simpler and clearer. Tested on x86_64 Fedora 20, -m64/-m32. gdb/ChangeLog: 2014-08-22 Pedro Alves <palves@redhat.com> * value.c (value_ranges_copy_adjusted): New function, factored out from ... (value_contents_copy_raw): ... here. (unpack_value_bits_as_long_1): Rename back to ... (unpack_bits_as_long): ... this. Remove 'original_value' and 'result' parameters. Change return type to LONGEST. (unpack_value_bits_as_long): Delete. (unpack_value_field_as_long_1): Delete. (unpack_value_field_as_long, unpack_field_as_long): Reimplement. (unpack_value_bitfield): New function. (value_field_bitfield): Reimplement using unpack_value_bitfield. (value_fetch_lazy): Use unpack_value_bitfield. * value.h (unpack_value_bits_as_long): Delete declaration. --- gdb/value.c | 227 +++++++++++++++++++++++++++++------------------------------- gdb/value.h | 7 -- 2 files changed, 109 insertions(+), 125 deletions(-) diff --git a/gdb/value.c b/gdb/value.c index 077d234..6620f96 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -1219,6 +1219,22 @@ ranges_copy_adjusted (VEC (range_s) **dst_range, int dst_bit_offset, } } +/* Copy the ranges metadata in SRC that overlaps [SRC_BIT_OFFSET, + SRC_BIT_OFFSET+BIT_LENGTH) into DST, adjusted. */ + +static void +value_ranges_copy_adjusted (struct value *dst, int dst_bit_offset, + const struct value *src, int src_bit_offset, + int bit_length) +{ + ranges_copy_adjusted (&dst->unavailable, dst_bit_offset, + src->unavailable, src_bit_offset, + bit_length); + 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 (value_contents_all) starting at SRC_OFFSET, into DST value's (all) contents, starting at DST_OFFSET. If unavailable contents are @@ -1261,13 +1277,9 @@ value_contents_copy_raw (struct value *dst, int dst_offset, dst_bit_offset = dst_offset * TARGET_CHAR_BIT; bit_length = length * TARGET_CHAR_BIT; - ranges_copy_adjusted (&dst->unavailable, dst_bit_offset, - src->unavailable, src_bit_offset, - bit_length); - - ranges_copy_adjusted (&dst->optimized_out, dst_bit_offset, - src->optimized_out, src_bit_offset, - bit_length); + value_ranges_copy_adjusted (dst, dst_bit_offset, + src, src_bit_offset, + bit_length); } /* Copy LENGTH bytes of SRC value's (all) contents @@ -3105,16 +3117,24 @@ value_fn_field (struct value **arg1p, struct fn_field *f, \f -/* Helper function for both unpack_value_bits_as_long and - unpack_bits_as_long. See those functions for more details on the - interface; the only difference is that this function accepts either - a NULL or a non-NULL ORIGINAL_VALUE. */ +/* Unpack a bitfield of the specified FIELD_TYPE, from the object at + VALADDR, and store the result in *RESULT. + The bitfield starts at BITPOS bits and contains BITSIZE bits. -static int -unpack_value_bits_as_long_1 (struct type *field_type, const gdb_byte *valaddr, - int embedded_offset, int bitpos, int bitsize, - const struct value *original_value, - LONGEST *result) + Extracting bits depends on endianness of the machine. Compute the + number of least significant bits to discard. For big endian machines, + we compute the total number of bits in the anonymous object, subtract + off the bit count from the MSB of the object to the MSB of the + bitfield, then the size of the bitfield, which leaves the LSB discard + count. For little endian machines, the discard count is simply the + number of bits from the LSB of the anonymous object to the LSB of the + bitfield. + + If the field is signed, we also do sign extension. */ + +static LONGEST +unpack_bits_as_long (struct type *field_type, const gdb_byte *valaddr, + int bitpos, int bitsize) { enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (field_type)); ULONGEST val; @@ -3133,12 +3153,7 @@ unpack_value_bits_as_long_1 (struct type *field_type, const gdb_byte *valaddr, read_offset = bitpos / 8; - if (original_value != NULL - && !value_bits_available (original_value, embedded_offset + bitpos, - bitsize)) - return 0; - - val = extract_unsigned_integer (valaddr + embedded_offset + read_offset, + val = extract_unsigned_integer (valaddr + read_offset, bytes_read, byte_order); /* Extract bits. See comment above. */ @@ -3165,60 +3180,7 @@ unpack_value_bits_as_long_1 (struct type *field_type, const gdb_byte *valaddr, } } - *result = val; - return 1; -} - -/* Unpack a bitfield of the specified FIELD_TYPE, from the object at - VALADDR + EMBEDDED_OFFSET, and store the result in *RESULT. - VALADDR points to the contents of ORIGINAL_VALUE, which must not be - NULL. The bitfield starts at BITPOS bits and contains BITSIZE - bits. - - Returns false if the value contents are unavailable, otherwise - returns true, indicating a valid value has been stored in *RESULT. - - Extracting bits depends on endianness of the machine. Compute the - number of least significant bits to discard. For big endian machines, - we compute the total number of bits in the anonymous object, subtract - off the bit count from the MSB of the object to the MSB of the - bitfield, then the size of the bitfield, which leaves the LSB discard - count. For little endian machines, the discard count is simply the - number of bits from the LSB of the anonymous object to the LSB of the - bitfield. - - If the field is signed, we also do sign extension. */ - -int -unpack_value_bits_as_long (struct type *field_type, const gdb_byte *valaddr, - int embedded_offset, int bitpos, int bitsize, - const struct value *original_value, - LONGEST *result) -{ - gdb_assert (original_value != NULL); - - return unpack_value_bits_as_long_1 (field_type, valaddr, embedded_offset, - bitpos, bitsize, original_value, result); - -} - -/* Unpack a field FIELDNO of the specified TYPE, from the object at - VALADDR + EMBEDDED_OFFSET. VALADDR points to the contents of - ORIGINAL_VALUE. See unpack_value_bits_as_long for more - details. */ - -static int -unpack_value_field_as_long_1 (struct type *type, const gdb_byte *valaddr, - int embedded_offset, int fieldno, - const struct value *val, LONGEST *result) -{ - int bitpos = TYPE_FIELD_BITPOS (type, fieldno); - int bitsize = TYPE_FIELD_BITSIZE (type, fieldno); - struct type *field_type = TYPE_FIELD_TYPE (type, fieldno); - - return unpack_value_bits_as_long_1 (field_type, valaddr, embedded_offset, - bitpos, bitsize, val, - result); + return val; } /* Unpack a field FIELDNO of the specified TYPE, from the object at @@ -3231,51 +3193,95 @@ unpack_value_field_as_long (struct type *type, const gdb_byte *valaddr, int embedded_offset, int fieldno, const struct value *val, LONGEST *result) { + int bitpos = TYPE_FIELD_BITPOS (type, fieldno); + int bitsize = TYPE_FIELD_BITSIZE (type, fieldno); + struct type *field_type = TYPE_FIELD_TYPE (type, fieldno); + int bit_offset; + gdb_assert (val != NULL); - return unpack_value_field_as_long_1 (type, valaddr, embedded_offset, - fieldno, val, result); + bit_offset = embedded_offset * TARGET_CHAR_BIT + bitpos; + if (value_bits_any_optimized_out (val, bit_offset, bitsize) + || !value_bits_available (val, bit_offset, bitsize)) + return 0; + + *result = unpack_bits_as_long (field_type, valaddr + embedded_offset, + bitpos, bitsize); + return 1; } /* Unpack a field FIELDNO of the specified TYPE, from the anonymous - object at VALADDR. See unpack_value_bits_as_long for more details. - This function differs from unpack_value_field_as_long in that it - operates without a struct value object. */ + object at VALADDR. See unpack_bits_as_long for more details. */ LONGEST unpack_field_as_long (struct type *type, const gdb_byte *valaddr, int fieldno) { - LONGEST result; + int bitpos = TYPE_FIELD_BITPOS (type, fieldno); + int bitsize = TYPE_FIELD_BITSIZE (type, fieldno); + struct type *field_type = TYPE_FIELD_TYPE (type, fieldno); - unpack_value_field_as_long_1 (type, valaddr, 0, fieldno, NULL, &result); - return result; + return unpack_bits_as_long (field_type, valaddr, bitpos, bitsize); +} + +/* Unpack a bitfield of BITSIZE bits found at BITPOS in the object at + VALADDR + EMBEDDEDOFFSET that has the type of DEST_VAL and store + the contents in DEST_VAL, zero or sign extending if the type of + DEST_VAL is wider than BITSIZE. VALADDR points to the contents of + VAL. If the VAL's contents required to extract the bitfield from + are unavailable/optimized out, DEST_VAL is correspondingly + marked unavailable/optimized out. */ + +static void +unpack_value_bitfield (struct value *dest_val, + int bitpos, int bitsize, + const gdb_byte *valaddr, int embedded_offset, + const struct value *val) +{ + enum bfd_endian byte_order; + int src_bit_offset; + int dst_bit_offset; + LONGEST num; + struct type *field_type = value_type (dest_val); + + /* First, unpack and sign extend the bitfield as if it was wholly + available. Invalid/unavailable bits are read as zero, but that's + OK, as they'll end up marked below. */ + byte_order = gdbarch_byte_order (get_type_arch (field_type)); + num = unpack_bits_as_long (field_type, valaddr + embedded_offset, + bitpos, bitsize); + store_signed_integer (value_contents_raw (dest_val), + TYPE_LENGTH (field_type), byte_order, num); + + /* Now copy the optimized out / unavailability ranges to the right + bits. */ + src_bit_offset = embedded_offset * TARGET_CHAR_BIT + bitpos; + if (byte_order == BFD_ENDIAN_BIG) + dst_bit_offset = TYPE_LENGTH (field_type) * TARGET_CHAR_BIT - bitsize; + else + dst_bit_offset = 0; + value_ranges_copy_adjusted (dest_val, dst_bit_offset, + val, src_bit_offset, bitsize); } /* Return a new value with type TYPE, which is FIELDNO field of the object at VALADDR + EMBEDDEDOFFSET. VALADDR points to the contents of VAL. If the VAL's contents required to extract the bitfield - from are unavailable, the new value is correspondingly marked as - unavailable. */ + from are unavailable/optimized out, the new value is + correspondingly marked unavailable/optimized out. */ struct value * value_field_bitfield (struct type *type, int fieldno, const gdb_byte *valaddr, int embedded_offset, const struct value *val) { - LONGEST l; + int bitpos = TYPE_FIELD_BITPOS (type, fieldno); + int bitsize = TYPE_FIELD_BITSIZE (type, fieldno); + struct value *res_val = allocate_value (TYPE_FIELD_TYPE (type, fieldno)); - if (!unpack_value_field_as_long (type, valaddr, embedded_offset, fieldno, - val, &l)) - { - struct type *field_type = TYPE_FIELD_TYPE (type, fieldno); - struct value *retval = allocate_value (field_type); - mark_value_bytes_unavailable (retval, 0, TYPE_LENGTH (field_type)); - return retval; - } - else - { - return value_from_longest (TYPE_FIELD_TYPE (type, fieldno), l); - } + unpack_value_bitfield (res_val, bitpos, bitsize, + valaddr, embedded_offset, val); + + return res_val; } /* Modify the value of a bitfield. ADDR points to a block of memory in @@ -3757,30 +3763,15 @@ value_fetch_lazy (struct value *val) word, but we have no way to record that just specific bits of a value have been fetched. */ struct type *type = check_typedef (value_type (val)); - enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type)); struct value *parent = value_parent (val); - LONGEST offset = value_offset (val); - LONGEST num; if (value_lazy (parent)) value_fetch_lazy (parent); - 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, - value_bitpos (val), - value_bitsize (val), parent, &num)) - mark_value_bytes_unavailable (val, - value_embedded_offset (val), - TYPE_LENGTH (type)); - else - store_signed_integer (value_contents_raw (val), TYPE_LENGTH (type), - byte_order, num); + unpack_value_bitfield (val, + value_bitpos (val), value_bitsize (val), + value_contents_for_printing (parent), + value_offset (val), parent); } else if (VALUE_LVAL (val) == lval_memory) { diff --git a/gdb/value.h b/gdb/value.h index 5d4949c..4cdbf21 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -606,13 +606,6 @@ extern DOUBLEST unpack_double (struct type *type, const gdb_byte *valaddr, int *invp); extern CORE_ADDR unpack_pointer (struct type *type, const gdb_byte *valaddr); -extern int unpack_value_bits_as_long (struct type *field_type, - const gdb_byte *valaddr, - int embedded_offset, int bitpos, - int bitsize, - const struct value *original_value, - LONGEST *result); - extern LONGEST unpack_field_as_long (struct type *type, const gdb_byte *valaddr, int fieldno); -- 1.9.3 ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Regression for i686 gdb.dwarf2/pieces-optimized-out.exp [Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values] 2014-08-22 16:20 ` Pedro Alves @ 2014-08-24 19:56 ` Jan Kratochvil 2014-09-04 11:36 ` [pushed] " Pedro Alves 1 sibling, 0 replies; 28+ messages in thread From: Jan Kratochvil @ 2014-08-24 19:56 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches On Fri, 22 Aug 2014 18:20:38 +0200, Pedro Alves wrote: > So it didn't take that long to get back to handling partially > optimized out bitfields after all... I think I found an easy way. > We don't currently print partially optimized out scalars, though > we could print the valid/invalid bits with p/t, for example, > and I think the code ends up clearer anyway. If you waited for my reply you can check it in as I do not think I can reliably review this code. Thanks, Jan ^ permalink raw reply [flat|nested] 28+ messages in thread
* [pushed] Re: Regression for i686 gdb.dwarf2/pieces-optimized-out.exp [Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values] 2014-08-22 16:20 ` Pedro Alves 2014-08-24 19:56 ` Jan Kratochvil @ 2014-09-04 11:36 ` Pedro Alves 1 sibling, 0 replies; 28+ messages in thread From: Pedro Alves @ 2014-09-04 11:36 UTC (permalink / raw) To: gdb-patches; +Cc: Jan Kratochvil I've pushed this in now. Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2014-09-04 11:36 UTC | newest] Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2014-07-09 10:33 [patchv2] Fix crash on optimized-out entry data values Jan Kratochvil 2014-07-09 11:52 ` Pedro Alves 2014-07-09 15:31 ` Jan Kratochvil 2014-07-11 16:07 ` [patchv3] " Jan Kratochvil 2014-07-14 7:02 ` Yao Qi 2014-07-14 8:32 ` Jan Kratochvil 2014-07-14 18:12 ` Pedro Alves 2014-07-14 18:47 ` [PATCH] Handle partially optimized out values similarly to unavailable values (Re: [patchv2] Fix crash on optimized-out entry data values) Pedro Alves 2014-07-17 8:04 ` Jan Kratochvil 2014-07-17 8:35 ` Jan Kratochvil 2014-07-17 13:38 ` Pedro Alves 2014-07-20 15:33 ` [read_frame_arg patch] " Jan Kratochvil 2014-07-22 19:33 ` Pedro Alves 2014-07-22 20:21 ` [commit+7.8] [read_frame_arg patch] Handle partially optimized out values similarly to unavailable values Jan Kratochvil 2014-08-05 17:16 ` Doug Evans 2014-08-14 18:25 ` Jan Kratochvil 2014-07-23 14:26 ` [commit] Remove setting value address for reference entry value target data value Jan Kratochvil 2014-07-24 12:51 ` [PATCH v2] Handle partially optimized out values similarly to unavailable values Pedro Alves 2014-08-15 20:13 ` Jan Kratochvil 2014-08-19 23:36 ` Pedro Alves 2014-08-20 0:55 ` Andrew Pinski 2014-08-20 9:46 ` Pedro Alves 2014-08-20 10:32 ` [PUSHED] value.c (value_contents_bits_eq): Initialize l,h for gcc, -Wall. (was: Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values) Pedro Alves 2014-08-20 16:28 ` Andrew Pinski 2014-08-21 19:57 ` Regression for i686 gdb.dwarf2/pieces-optimized-out.exp [Re: [PATCH v2] Handle partially optimized out values similarly to unavailable values] Jan Kratochvil 2014-08-22 16:20 ` Pedro Alves 2014-08-24 19:56 ` Jan Kratochvil 2014-09-04 11:36 ` [pushed] " Pedro Alves
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).