| 1 | # Copyright 2017-2020 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 | # Test reading/writing variables with non-trivial DWARF locations. In |
| 17 | # particular the test uses register- and memory locations as well as |
| 18 | # composite locations with register- and memory pieces. |
| 19 | |
| 20 | load_lib dwarf.exp |
| 21 | |
| 22 | # This test can only be run on targets which support DWARF-2 and use gas. |
| 23 | if {![dwarf2_support]} { |
| 24 | return 0 |
| 25 | } |
| 26 | |
| 27 | # Choose suitable integer registers for the test. |
| 28 | |
| 29 | set dwarf_regnum {0 1} |
| 30 | |
| 31 | if { [is_aarch64_target] } { |
| 32 | set regname {x0 x1} |
| 33 | } elseif { [is_aarch32_target] |
| 34 | || [istarget "s390*-*-*" ] |
| 35 | || [istarget "powerpc*-*-*"] |
| 36 | || [istarget "rs6000*-*-aix*"] } { |
| 37 | set regname {r0 r1} |
| 38 | } elseif { [is_x86_like_target] } { |
| 39 | set regname {eax ecx} |
| 40 | } elseif { [is_amd64_regs_target] } { |
| 41 | set regname {rax rdx} |
| 42 | } else { |
| 43 | verbose "Skipping $gdb_test_file_name." |
| 44 | return |
| 45 | } |
| 46 | |
| 47 | standard_testfile .c -dw.S |
| 48 | |
| 49 | # Make some DWARF for the test. |
| 50 | |
| 51 | set asm_file [standard_output_file $srcfile2] |
| 52 | Dwarf::assemble $asm_file { |
| 53 | global dwarf_regnum regname |
| 54 | |
| 55 | set buf_var [gdb_target_symbol buf] |
| 56 | |
| 57 | cu {} { |
| 58 | DW_TAG_compile_unit { |
| 59 | {DW_AT_name var-pieces-dw.c} |
| 60 | {DW_AT_comp_dir /tmp} |
| 61 | } { |
| 62 | declare_labels char_type_label |
| 63 | declare_labels int_type_label short_type_label |
| 64 | declare_labels array_a8_label struct_s_label struct_t_label |
| 65 | declare_labels struct_st_label |
| 66 | |
| 67 | # char |
| 68 | char_type_label: base_type { |
| 69 | {name "char"} |
| 70 | {encoding @DW_ATE_unsigned_char} |
| 71 | {byte_size 1 DW_FORM_sdata} |
| 72 | } |
| 73 | |
| 74 | # int |
| 75 | int_type_label: base_type { |
| 76 | {name "int"} |
| 77 | {encoding @DW_ATE_signed} |
| 78 | {byte_size 4 DW_FORM_sdata} |
| 79 | } |
| 80 | |
| 81 | # char [8] |
| 82 | array_a8_label: array_type { |
| 83 | {type :$char_type_label} |
| 84 | } { |
| 85 | subrange_type { |
| 86 | {type :$int_type_label} |
| 87 | {upper_bound 7 DW_FORM_udata} |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | # struct s { char a, b, c, d; }; |
| 92 | struct_s_label: structure_type { |
| 93 | {name "s"} |
| 94 | {byte_size 4 DW_FORM_sdata} |
| 95 | } { |
| 96 | member { |
| 97 | {name "a"} |
| 98 | {type :$char_type_label} |
| 99 | {data_member_location 0 DW_FORM_udata} |
| 100 | } |
| 101 | member { |
| 102 | {name "b"} |
| 103 | {type :$char_type_label} |
| 104 | {data_member_location 1 DW_FORM_udata} |
| 105 | } |
| 106 | member { |
| 107 | {name "c"} |
| 108 | {type :$char_type_label} |
| 109 | {data_member_location 2 DW_FORM_udata} |
| 110 | } |
| 111 | member { |
| 112 | {name "d"} |
| 113 | {type :$char_type_label} |
| 114 | {data_member_location 3 DW_FORM_udata} |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | # struct t { int u, x:9, y:13, z:10; }; |
| 119 | struct_t_label: structure_type { |
| 120 | {name "t"} |
| 121 | {byte_size 8 DW_FORM_sdata} |
| 122 | } { |
| 123 | member { |
| 124 | {name "u"} |
| 125 | {type :$int_type_label} |
| 126 | } |
| 127 | member { |
| 128 | {name "x"} |
| 129 | {type :$int_type_label} |
| 130 | {data_member_location 4 DW_FORM_udata} |
| 131 | {bit_size 9 DW_FORM_udata} |
| 132 | } |
| 133 | member { |
| 134 | {name "y"} |
| 135 | {type :$int_type_label} |
| 136 | {data_bit_offset 41 DW_FORM_udata} |
| 137 | {bit_size 13 DW_FORM_udata} |
| 138 | } |
| 139 | member { |
| 140 | {name "z"} |
| 141 | {type :$int_type_label} |
| 142 | {data_bit_offset 54 DW_FORM_udata} |
| 143 | {bit_size 10 DW_FORM_udata} |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | # struct st { struct s s; struct t t; }; |
| 148 | struct_st_label: structure_type { |
| 149 | {name "st"} |
| 150 | {byte_size 12 DW_FORM_udata} |
| 151 | } { |
| 152 | member { |
| 153 | {name "s"} |
| 154 | {type :$struct_s_label} |
| 155 | } |
| 156 | member { |
| 157 | {name "t"} |
| 158 | {type :$struct_t_label} |
| 159 | {data_member_location 4 DW_FORM_udata} |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | DW_TAG_subprogram { |
| 164 | {MACRO_AT_func { main }} |
| 165 | {DW_AT_external 1 flag} |
| 166 | } { |
| 167 | # Simple memory location. |
| 168 | DW_TAG_variable { |
| 169 | {name "a"} |
| 170 | {type :$array_a8_label} |
| 171 | {location { |
| 172 | addr $buf_var |
| 173 | } SPECIAL_expr} |
| 174 | } |
| 175 | # Memory pieces: two bytes from &buf[2], and two bytes |
| 176 | # from &buf[0]. |
| 177 | DW_TAG_variable { |
| 178 | {name "s1"} |
| 179 | {type :$struct_s_label} |
| 180 | {location { |
| 181 | addr $buf_var |
| 182 | plus_uconst 2 |
| 183 | piece 2 |
| 184 | addr $buf_var |
| 185 | piece 2 |
| 186 | } SPECIAL_expr} |
| 187 | } |
| 188 | # Register- and memory pieces: one byte each from r0, |
| 189 | # &buf[4], r1, and &buf[5]. |
| 190 | DW_TAG_variable { |
| 191 | {name "s2"} |
| 192 | {type :$struct_s_label} |
| 193 | {location { |
| 194 | regx [lindex $dwarf_regnum 0] |
| 195 | piece 1 |
| 196 | addr "$buf_var + 4" |
| 197 | piece 1 |
| 198 | regx [lindex $dwarf_regnum 1] |
| 199 | piece 1 |
| 200 | addr "$buf_var + 5" |
| 201 | piece 1 |
| 202 | } SPECIAL_expr} |
| 203 | } |
| 204 | # Memory pieces for bitfield access: 8 bytes optimized |
| 205 | # out, 3 bytes from &buf[3], and 1 byte from &buf[1]. |
| 206 | DW_TAG_variable { |
| 207 | {name "st1"} |
| 208 | {type :$struct_st_label} |
| 209 | {location { |
| 210 | piece 8 |
| 211 | addr "$buf_var + 3" |
| 212 | piece 3 |
| 213 | addr "$buf_var + 1" |
| 214 | piece 1 |
| 215 | } SPECIAL_expr} |
| 216 | } |
| 217 | # Register pieces for bitfield access: 4 bytes optimized |
| 218 | # out, 3 bytes from r0, and 1 byte from r1. |
| 219 | DW_TAG_variable { |
| 220 | {name "t2"} |
| 221 | {type :$struct_t_label} |
| 222 | {location { |
| 223 | piece 4 |
| 224 | regx [lindex $dwarf_regnum 0] |
| 225 | piece 3 |
| 226 | regx [lindex $dwarf_regnum 1] |
| 227 | piece 1 |
| 228 | } SPECIAL_expr} |
| 229 | } |
| 230 | # One piece per bitfield, using piece offsets: 32 bits of |
| 231 | # an implicit value, 9 bits of a stack value, 13 bits of |
| 232 | # r0, and 10 bits of buf. |
| 233 | DW_TAG_variable { |
| 234 | {name "t3"} |
| 235 | {type :$struct_t_label} |
| 236 | {location { |
| 237 | implicit_value 0x12 0x34 0x56 0x78 0x9a |
| 238 | bit_piece 32 4 |
| 239 | const2s -280 |
| 240 | stack_value |
| 241 | bit_piece 9 2 |
| 242 | regx [lindex $dwarf_regnum 0] |
| 243 | bit_piece 13 14 |
| 244 | addr $buf_var |
| 245 | bit_piece 10 42 |
| 246 | } SPECIAL_expr} |
| 247 | } |
| 248 | } |
| 249 | } |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | if { [prepare_for_testing ${testfile}.exp ${testfile} \ |
| 254 | [list $srcfile $asm_file] {nodebug}] } { |
| 255 | return -1 |
| 256 | } |
| 257 | |
| 258 | if ![runto_main] { |
| 259 | return -1 |
| 260 | } |
| 261 | |
| 262 | # Determine byte order. |
| 263 | set endian [get_endianness] |
| 264 | |
| 265 | # Byte-aligned memory pieces. |
| 266 | gdb_test "print/d s1" " = \\{a = 2, b = 3, c = 0, d = 1\\}" \ |
| 267 | "s1 == re-ordered buf" |
| 268 | gdb_test_no_output "set var s1.a = 63" |
| 269 | gdb_test "print/d s1" " = \\{a = 63, b = 3, c = 0, d = 1\\}" \ |
| 270 | "verify s1.a" |
| 271 | gdb_test "print/d a" " = \\{0, 1, 63, 3, 4, 5, 6, 7\\}" \ |
| 272 | "verify s1.a through a" |
| 273 | gdb_test_no_output "set var s1.b = 42" |
| 274 | gdb_test "print/d s1" " = \\{a = 63, b = 42, c = 0, d = 1\\}" \ |
| 275 | "verify s1.b" |
| 276 | gdb_test "print/d a" " = \\{0, 1, 63, 42, 4, 5, 6, 7\\}" \ |
| 277 | "verify s1.b through a" |
| 278 | |
| 279 | # Byte-aligned register- and memory pieces. |
| 280 | gdb_test_no_output "set var \$[lindex $regname 0] = 81" \ |
| 281 | "init reg for s2.a" |
| 282 | gdb_test_no_output "set var \$[lindex $regname 1] = 28" \ |
| 283 | "init reg for s2.c" |
| 284 | gdb_test "print/u s2" " = \\{a = 81, b = 4, c = 28, d = 5\\}" \ |
| 285 | "initialized s2 from mem and regs" |
| 286 | gdb_test_no_output "set var s2.c += s2.a + s2.b - s2.d" |
| 287 | gdb_test "print/u s2" " = \\{a = 81, b = 4, c = 108, d = 5\\}" \ |
| 288 | "verify s2.c" |
| 289 | gdb_test "print/u \$[lindex $regname 1]" " = 108" \ |
| 290 | "verify s2.c through reg" |
| 291 | gdb_test_no_output "set var s2 = {191, 73, 231, 123}" \ |
| 292 | "re-initialize s2" |
| 293 | gdb_test "print/u s2" " = \\{a = 191, b = 73, c = 231, d = 123\\}" \ |
| 294 | "verify re-initialized s2" |
| 295 | |
| 296 | # Unaligned bitfield access through byte-aligned pieces. |
| 297 | gdb_test_no_output "set var a = { 0 }" |
| 298 | gdb_test_no_output "set var st1.t.x = -7" |
| 299 | gdb_test_no_output "set var st1.t.z = 340" |
| 300 | gdb_test_no_output "set var st1.t.y = 1234" |
| 301 | gdb_test "print st1.t" " = \\{u = <optimized out>, x = -7, y = 1234, z = 340\\}" \ |
| 302 | "verify st1.t" |
| 303 | switch $endian { |
| 304 | little {set val "0x55, 0x0, 0xf9, 0xa5, 0x9"} |
| 305 | big {set val "0x54, 0x0, 0xfc, 0x93, 0x49"} |
| 306 | } |
| 307 | # | -- | z:2-9 | -- | x:0-7 | x:8 y:0-6 | y:7-12 z:0-1 | -- | -- | |
| 308 | # \_______________________________________________/ |
| 309 | # val |
| 310 | gdb_test "print/x a" " = \\{0x0, ${val}, 0x0, 0x0\\}" \ |
| 311 | "verify st1 through a" |
| 312 | |
| 313 | switch $endian { big {set val 0x7ffc} little {set val 0x3ffe00} } |
| 314 | gdb_test_no_output "set var \$[lindex $regname 0] = $val" \ |
| 315 | "init t2, first piece" |
| 316 | gdb_test_no_output "set var \$[lindex $regname 1] = 0" \ |
| 317 | "init t2, second piece" |
| 318 | gdb_test "print/d t2" " = \\{u = <optimized out>, x = 0, y = -1, z = 0\\}" \ |
| 319 | "initialized t2 from regs" |
| 320 | gdb_test_no_output "set var t2.y = 2641" |
| 321 | gdb_test_no_output "set var t2.z = -400" |
| 322 | gdb_test_no_output "set var t2.x = 200" |
| 323 | gdb_test "print t2.x + t2.y + t2.z" " = 2441" |
| 324 | |
| 325 | # Bitfield access through pieces with nonzero piece offsets. |
| 326 | gdb_test_no_output "set var \$[lindex $regname 0] = 0xa8000" \ |
| 327 | "init reg for t3.y" |
| 328 | gdb_test_no_output "set var *(char \[2\] *) (a + 5) = { 70, 82 }" \ |
| 329 | "init mem for t3.z" |
| 330 | switch $endian { |
| 331 | little {set val "u = -1484430527, x = -70, y = 42, z = 145"} |
| 332 | big {set val "u = 591751049, x = -70, y = 42, z = 101"} |
| 333 | } |
| 334 | gdb_test "print t3" " = \\{$val\\}" \ |
| 335 | "initialized t3 from reg and mem" |
| 336 | gdb_test_no_output "set var t3.y = -1" \ |
| 337 | "overwrite t3.y" |
| 338 | gdb_test "print/x \$[lindex $regname 0]" " = 0x7ffc000" \ |
| 339 | "verify t3.y through reg" |
| 340 | gdb_test_no_output "set var t3.z = -614" \ |
| 341 | "overwrite t3.z" |
| 342 | switch $endian {big {set val "0x59, 0xa2"} little {set val "0x6a, 0x56"}} |
| 343 | gdb_test "print/x *(char \[2\] *) (a + 5)" " = \\{$val\\}" \ |
| 344 | "verify t3.z through mem" |