| 1 | # Copyright 2016-2019 Free Software Foundation, Inc. |
| 2 | |
| 3 | # This program is free software; you can redistribute it and/or modify |
| 4 | # it under the terms of the GNU General Public License as published by |
| 5 | # the Free Software Foundation; either version 3 of the License, or |
| 6 | # (at your option) any later version. |
| 7 | # |
| 8 | # This program is distributed in the hope that it will be useful, |
| 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | # GNU General Public License for more details. |
| 12 | # |
| 13 | # You should have received a copy of the GNU General Public License |
| 14 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 15 | |
| 16 | # This test ensures that with "set print object on", -var-create will |
| 17 | # return "<optimized out>" for an optimized out pointer to structure, |
| 18 | # rather than attempting to dereference the pointer to determine its |
| 19 | # actual type (instead of its declared type). We want to test that GDB |
| 20 | # can display such a pointer without throwing an error, while also |
| 21 | # ensuring that any attempt to dereference the pointer *will* throw an |
| 22 | # error. |
| 23 | |
| 24 | load_lib dwarf.exp |
| 25 | |
| 26 | # This test can only be run on targets which support DWARF-2 and use gas. |
| 27 | if {![dwarf2_support]} { |
| 28 | return 0 |
| 29 | } |
| 30 | |
| 31 | standard_testfile dw2-opt-structptr.c dw2-opt-structptr-dw.S |
| 32 | |
| 33 | # Generate a test program with dwarf information showing the variable |
| 34 | # 'ptr', a pointer-to-struct, as optimized out. The dwarf will also |
| 35 | # describe the structure as have a scalar, array, and pointer-to-struct |
| 36 | # members. |
| 37 | |
| 38 | proc build_test_program {} { |
| 39 | global testfile srcfile srcfile2 |
| 40 | |
| 41 | # Make some DWARF for the test. |
| 42 | set asm_file [standard_output_file $srcfile2] |
| 43 | Dwarf::assemble $asm_file { |
| 44 | global srcdir subdir srcfile |
| 45 | |
| 46 | # Creating a CU with 4-byte addresses lets this test link on |
| 47 | # both 32- and 64-bit machines. |
| 48 | cu { addr_size 4 } { |
| 49 | |
| 50 | DW_TAG_compile_unit { |
| 51 | {DW_AT_language @DW_LANG_C99} |
| 52 | {DW_AT_name dw2-opt-structptr.c} |
| 53 | {DW_AT_comp_dir /tmp} |
| 54 | } { |
| 55 | declare_labels int_label struct_label pointer_label \ |
| 56 | array_label |
| 57 | |
| 58 | int_label: DW_TAG_base_type { |
| 59 | {DW_AT_byte_size 4 DW_FORM_sdata} |
| 60 | {DW_AT_encoding @DW_ATE_signed} |
| 61 | {DW_AT_name integer} |
| 62 | } |
| 63 | |
| 64 | array_label: DW_TAG_array_type { |
| 65 | {DW_AT_name foo__array_type} |
| 66 | {DW_AT_type :$int_label} |
| 67 | } { |
| 68 | DW_TAG_subrange_type { |
| 69 | {DW_AT_type :$int_label} |
| 70 | {DW_AT_lower_bound 0 DW_FORM_data1} |
| 71 | {DW_AT_upper_bound 127 DW_FORM_data1} |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | struct_label: DW_TAG_structure_type { |
| 76 | {DW_AT_name "foo"} |
| 77 | {DW_AT_byte_size 12 DW_FORM_sdata} |
| 78 | } { |
| 79 | member { |
| 80 | {name a} |
| 81 | {type :$int_label} |
| 82 | {data_member_location 0 data1} |
| 83 | } |
| 84 | member { |
| 85 | {name x} |
| 86 | {type :$array_label} |
| 87 | {data_member_location 4 data1} |
| 88 | } |
| 89 | member { |
| 90 | {name y} |
| 91 | {type :$pointer_label} |
| 92 | {data_member_location 8 data1} |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | pointer_label: DW_TAG_pointer_type { |
| 97 | {DW_AT_byte_size 4 DW_FORM_sdata} |
| 98 | {DW_AT_type :$struct_label} |
| 99 | } |
| 100 | |
| 101 | DW_TAG_subprogram { |
| 102 | {DW_AT_name func01} |
| 103 | {DW_AT_type :$int_label} |
| 104 | {external 1 flag} |
| 105 | {MACRO_AT_func {func01 ${srcdir}/${subdir}/${srcfile}}} |
| 106 | } { |
| 107 | DW_TAG_variable { |
| 108 | {DW_AT_name ptr} |
| 109 | {DW_AT_type :$pointer_label} |
| 110 | {DW_AT_location {} DW_FORM_block1} |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | DW_TAG_subprogram { |
| 115 | {DW_AT_name main} |
| 116 | {DW_AT_type :$int_label} |
| 117 | {external 1 flag} |
| 118 | {MACRO_AT_func {main ${srcdir}/${subdir}/${srcfile}}} |
| 119 | } { |
| 120 | } |
| 121 | } |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | set sources "$srcfile $asm_file" |
| 126 | if {[build_executable $testfile.exp $testfile $sources {nodebug}]} { |
| 127 | untested "failed to compile" |
| 128 | return -1 |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | # Test access to an optimized-out pointer-to-struct using the |
| 133 | # console interpreter. |
| 134 | |
| 135 | proc do_console_test {} { |
| 136 | global binfile |
| 137 | |
| 138 | clean_restart $binfile |
| 139 | |
| 140 | with_test_prefix "console" { |
| 141 | gdb_test_no_output "set print object on" |
| 142 | |
| 143 | if {![runto_main]} { |
| 144 | return -1 |
| 145 | } |
| 146 | |
| 147 | if {![runto func01]} { |
| 148 | return -1 |
| 149 | } |
| 150 | |
| 151 | gdb_test "info addr ptr" "Symbol \"ptr\" is optimized out." |
| 152 | |
| 153 | gdb_test "print ptr" "<optimized out>" |
| 154 | |
| 155 | gdb_test "print *ptr" "value has been optimized out" |
| 156 | |
| 157 | gdb_test "print ptr->a" "value has been optimized out" |
| 158 | |
| 159 | gdb_test "print ptr->x" "value has been optimized out" |
| 160 | |
| 161 | gdb_test "print ptr->y" "value has been optimized out" |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | # Test access to an optimized-out pointer-to-struct using the |
| 166 | # MI interpreter. |
| 167 | |
| 168 | proc do_mi_test {} { |
| 169 | |
| 170 | load_lib mi-support.exp |
| 171 | set MIFLAGS "-i=mi" |
| 172 | |
| 173 | global mi_gdb_prompt |
| 174 | global srcdir |
| 175 | global subdir |
| 176 | global binfile |
| 177 | |
| 178 | with_test_prefix "mi" { |
| 179 | gdb_exit |
| 180 | if {[mi_gdb_start]} { |
| 181 | return -1 |
| 182 | } |
| 183 | |
| 184 | mi_delete_breakpoints |
| 185 | mi_gdb_reinitialize_dir $srcdir/$subdir |
| 186 | mi_gdb_load $binfile |
| 187 | |
| 188 | # This causes GDB to dereference a pointer-to-structure when doing |
| 189 | # -var-create. |
| 190 | mi_gdb_test "-gdb-set print object on" ".*" "set print object on" |
| 191 | |
| 192 | mi_gdb_test "-break-insert main" ".*" "insert breakpoint main" |
| 193 | mi_gdb_test "-break-insert func01" ".*" "insert breakpoint func01" |
| 194 | |
| 195 | # Run to main. Use an explicit expect here since the limited |
| 196 | # debug info will result in output that isn't handled by the |
| 197 | # MI test utilities. |
| 198 | set test "run to main" |
| 199 | mi_run_cmd |
| 200 | gdb_expect { |
| 201 | -re "\\*stopped,reason=\"breakpoint-hit\".*func=\"main\".*$mi_gdb_prompt$" { |
| 202 | pass "$test" |
| 203 | } |
| 204 | timeout { |
| 205 | fail "$test (timeout)" |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | # Run to func01. Use an explicit expect here as above. |
| 210 | set test "continue to func01" |
| 211 | mi_send_resuming_command "exec-continue" "$test" |
| 212 | gdb_expect { |
| 213 | -re "\\*stopped,reason=\"breakpoint-hit\".*func=\"func01\".*$mi_gdb_prompt$" { |
| 214 | pass "$test" |
| 215 | } |
| 216 | timeout { |
| 217 | fail "$test (timeout)" |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | # Test that -var-create for 'ptr' is successful. |
| 222 | mi_create_varobj "var1" "ptr" "create varobj for ptr" |
| 223 | |
| 224 | # Test that -var-list-children of 'ptr' is successful. |
| 225 | mi_list_varobj_children "var1" { \ |
| 226 | {var1.a a 0 integer} \ |
| 227 | {var1.x x 128 foo__array_type} \ |
| 228 | {var1.y y 3 "struct foo \\*"} \ |
| 229 | } "get children of var1 (ptr)" |
| 230 | |
| 231 | # Test that dereferencing 'ptr' will throw an error. |
| 232 | mi_gdb_test "-var-create var2 * &((ptr)->a)" \ |
| 233 | "\\^error,msg=\"value has been optimized out\"" \ |
| 234 | "throw error, dereference ptr to access integer member " |
| 235 | |
| 236 | # Test that dereferencing 'ptr' will throw an error. |
| 237 | mi_gdb_test "-var-create var3 * &((ptr)->x)" \ |
| 238 | "\\^error,msg=\"value has been optimized out\"" \ |
| 239 | "throw error, dereference ptr to access array member " |
| 240 | |
| 241 | # Test that dereferencing 'ptr' will throw an error. |
| 242 | mi_gdb_test "-var-create var4 * &((ptr)->y)" \ |
| 243 | "\\^error,msg=\"value has been optimized out\"" \ |
| 244 | "throw error, dereference ptr to access pointer member " |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | build_test_program |
| 249 | do_console_test |
| 250 | do_mi_test |