]>
Commit | Line | Data |
---|---|---|
1d506c26 | 1 | # Copyright 2022-2024 Free Software Foundation, Inc. |
6849c6a2 PA |
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 left and right bit shifting, in all languages that have such | |
17 | # operator. | |
18 | ||
19 | clean_restart | |
20 | ||
21 | # Test a print command that prints out RESULT_RE. If WARNING_OR_ERROR | |
22 | # is non-empty, it is expected that for languages other than Go, GDB | |
23 | # prints this warning before the print result. For Go, this is an | |
24 | # expected error. If WARNING_OR_ERROR is empty, it is expected that | |
25 | # GDB prints no text other than the print result. | |
26 | proc test_shift {lang cmd result_re {warning_or_error ""}} { | |
6849c6a2 PA |
27 | if {$lang == "go"} { |
28 | if {$warning_or_error != ""} { | |
29 | set error_re "[string_to_regexp $warning_or_error]" | |
30 | gdb_test_multiple $cmd "" { | |
a68f7e98 | 31 | -re -wrap "^$error_re" { |
6849c6a2 PA |
32 | pass $gdb_test_name |
33 | } | |
34 | } | |
35 | } else { | |
36 | gdb_test_multiple $cmd "" { | |
a68f7e98 | 37 | -re -wrap "^\\$$::decimal$result_re" { |
6849c6a2 PA |
38 | pass $gdb_test_name |
39 | } | |
40 | } | |
41 | } | |
42 | } else { | |
43 | if {$warning_or_error != ""} { | |
44 | set warning_re "warning: [string_to_regexp $warning_or_error]\r\n" | |
45 | } else { | |
46 | set warning_re "" | |
47 | } | |
48 | ||
49 | gdb_test_multiple $cmd "" { | |
a68f7e98 | 50 | -re -wrap "^$warning_re\\$$::decimal$result_re" { |
6849c6a2 PA |
51 | pass $gdb_test_name |
52 | } | |
53 | } | |
54 | } | |
55 | } | |
56 | ||
57 | # Some warnings/errors GDB outputs. | |
58 | set rs_negative_shift_count "right shift count is negative" | |
59 | set rs_too_large_shift_count "right shift count >= width of type" | |
60 | set ls_negative_shift_count "left shift count is negative" | |
61 | set ls_too_large_shift_count "left shift count >= width of type" | |
62 | ||
63 | # Test a left shift that results in a too-large shift count warning in | |
64 | # all languages except Go. | |
65 | proc test_lshift_tl {lang cmd result_re} { | |
66 | if {$lang != "go"} { | |
67 | test_shift $lang $cmd $result_re $::ls_too_large_shift_count | |
68 | } else { | |
69 | test_shift $lang $cmd $result_re | |
70 | } | |
71 | } | |
72 | ||
73 | # Test a right shift that results in a too-large shift count warning | |
74 | # in all languages except Go. | |
75 | proc test_rshift_tl {lang cmd result_re} { | |
76 | if {$lang != "go"} { | |
77 | test_shift $lang $cmd $result_re $::rs_too_large_shift_count | |
78 | } else { | |
79 | test_shift $lang $cmd $result_re | |
80 | } | |
81 | } | |
82 | ||
83 | # Return VAL, an integer value converted/cast to the right type for | |
84 | # LANG. SIGNED indicates whether the type should be signed or | |
85 | # unsigned. BITS indicates the bit width of the type. E.g., signed=0 | |
86 | # and bits=32 results in: | |
87 | # Go => "uint($VAL)" | |
88 | # D => "cast(uint) $VAL" | |
89 | # Rust => "$VAL as i32" | |
90 | # C/C++/others => "(unsigned int) $VAL" | |
91 | proc make_val_cast {lang signed bits val} { | |
92 | if {$lang == "go"} { | |
93 | if {$signed} { | |
94 | set sign_prefix "" | |
95 | } else { | |
96 | set sign_prefix "u" | |
97 | } | |
98 | return "${sign_prefix}int${bits}($val)" | |
99 | } elseif {$lang == "d"} { | |
100 | if {$signed} { | |
101 | set sign_prefix "" | |
102 | } else { | |
103 | set sign_prefix "u" | |
104 | } | |
105 | if {$bits == 8} { | |
106 | set type "byte" | |
107 | } elseif {$bits == 16} { | |
108 | set type "short" | |
109 | } elseif {$bits == 32} { | |
110 | set type "int" | |
111 | } elseif {$bits == 64} { | |
112 | set type "long" | |
113 | } else { | |
114 | error "$lang: unsupported bits" | |
115 | } | |
116 | return "cast(${sign_prefix}$type) $val" | |
117 | } elseif {$lang == "rust"} { | |
118 | if {$signed} { | |
119 | set sign_prefix "i" | |
120 | } else { | |
121 | set sign_prefix "u" | |
122 | } | |
123 | return "$val as ${sign_prefix}$bits" | |
124 | } else { | |
125 | # C-like cast. | |
126 | if {$signed} { | |
127 | set sign_prefix "" | |
128 | } else { | |
129 | set sign_prefix "un" | |
130 | } | |
131 | if {$bits == 8} { | |
132 | set type "char" | |
133 | } elseif {$bits == 16} { | |
134 | set type "short" | |
135 | } elseif {$bits == 32} { | |
136 | set type "int" | |
137 | } elseif {$bits == 64} { | |
138 | if {$lang == "opencl"} { | |
139 | set type "long" | |
140 | } else { | |
141 | set type "long long" | |
142 | } | |
143 | } else { | |
144 | error "$lang: unsupported bits" | |
145 | } | |
146 | return "(${sign_prefix}signed $type) $val" | |
147 | } | |
148 | } | |
149 | ||
150 | # Generate make_int8 ... make_uint64 convenience procs, wrappers | |
151 | # around make_val_cast. | |
152 | foreach signed {0 1} { | |
153 | if {$signed} { | |
154 | set sign_prefix "" | |
155 | } else { | |
156 | set sign_prefix "u" | |
157 | } | |
158 | foreach bits {8 16 32 64} { | |
159 | proc make_${sign_prefix}int${bits} {lang val} \ | |
160 | "make_val_cast \$lang $signed $bits \$val" | |
161 | } | |
162 | } | |
163 | ||
164 | # Test bitshifting, particularly with negative shift counts and | |
165 | # too-large-for-type shift counts. Exercises all C-like-ish | |
166 | # languages. | |
167 | proc test_shifts {} { | |
168 | global ls_negative_shift_count rs_negative_shift_count | |
169 | ||
170 | # Extract the set of all supported languages. We try all except | |
171 | # languages we know wouldn't work. We do this instead of | |
172 | # hardcoding the set of languages that we know work, so that if | |
173 | # GDB gains a new language, it is automatically exercised. | |
174 | set supported_langs [get_set_option_choices "set language"] | |
175 | ||
176 | foreach_with_prefix lang $supported_langs { | |
177 | set skip_langs { | |
178 | "unknown" "ada" "modula-2" "pascal" "fortran" | |
179 | } | |
180 | if {[lsearch -exact $skip_langs $lang] >= 0} { | |
cdd42066 | 181 | return |
6849c6a2 PA |
182 | } |
183 | ||
184 | gdb_test_no_output "set language $lang" | |
185 | ||
186 | # Make sure a signed left shift that overflows, i.e., whose | |
187 | # result isn't representable in the signed type of the lhs, | |
188 | # which is actually undefined, doesn't crash GDB when is it | |
189 | # built with UBSan. | |
190 | ||
191 | with_test_prefix "lsh overflow" { | |
192 | test_shift $lang "print /x 0x0fffffffffffffff << 8" \ | |
193 | " = 0xffffffffffffff00" | |
194 | test_shift $lang "print /x 0x0fffffff << 8" \ | |
195 | " = 0xffffff00" | |
196 | ||
197 | # Make sure the result is still signed when the lhs was | |
198 | # signed. | |
199 | test_shift $lang "print 0x0fffffffffffffff << 8" " = -256" | |
200 | test_shift $lang "print 0x0fffffff << 8" " = -256" | |
201 | } | |
202 | ||
203 | # 8-bit and 16-bit are promoted to int. | |
204 | with_test_prefix "8-bit, promoted" { | |
205 | foreach lhs \ | |
206 | [list \ | |
207 | [make_int8 $lang 0x0f] \ | |
208 | [make_uint8 $lang 0x0f]] \ | |
209 | { | |
210 | test_shift $lang "print /x $lhs << 8" " = 0xf00" | |
211 | test_shift $lang "print $lhs << 8" " = 3840" | |
212 | } | |
213 | } | |
214 | with_test_prefix "16-bit, promoted" { | |
215 | foreach lhs \ | |
216 | [list \ | |
217 | [make_int16 $lang 0x0fff] \ | |
218 | [make_uint16 $lang 0x0fff]] \ | |
219 | { | |
220 | test_shift $lang "print /x $lhs << 8" " = 0xfff00" | |
221 | test_shift $lang "print $lhs << 8" " = 1048320" | |
222 | } | |
223 | } | |
224 | ||
225 | # Similarly, test shifting with both negative and too-large | |
226 | # rhs. Both cases are undefined, but GDB lets them go through | |
227 | # anyhow, similarly to how compilers don't error out. Try | |
228 | # both signed and unsigned lhs. | |
229 | ||
230 | # 8-bit lhs, signed and unsigned. These get promoted to | |
231 | # 32-bit int. | |
232 | with_test_prefix "8-bit, invalid" { | |
233 | foreach lhs \ | |
234 | [list \ | |
235 | [make_int8 $lang 0x7f] \ | |
236 | [make_uint8 $lang 0xff]] \ | |
237 | { | |
238 | test_shift $lang "print $lhs << -1" " = 0" \ | |
239 | $ls_negative_shift_count | |
240 | test_shift $lang "print $lhs >> -1" " = 0" \ | |
241 | $rs_negative_shift_count | |
242 | ||
243 | test_shift $lang "print/x $lhs << 8" " = 0x(7|f)f00" | |
244 | test_shift $lang "print/x $lhs >> 8" " = 0x0" | |
245 | ||
246 | test_lshift_tl $lang "print $lhs << 32" " = 0" | |
247 | test_rshift_tl $lang "print $lhs >> 32" " = 0" | |
248 | test_lshift_tl $lang "print $lhs << 33" " = 0" | |
249 | test_rshift_tl $lang "print $lhs >> 33" " = 0" | |
250 | } | |
251 | } | |
252 | ||
253 | # 16-bit lhs, signed and unsigned. These get promoted to 32-bit int. | |
254 | with_test_prefix "16-bit, invalid" { | |
255 | foreach {lhs res} \ | |
256 | [list \ | |
257 | [make_int16 $lang 0x7fff] 0x7fff \ | |
258 | [make_uint16 $lang 0xffff] 0xffff] \ | |
259 | { | |
260 | test_shift $lang "print $lhs << -1" " = 0" \ | |
261 | $ls_negative_shift_count | |
262 | test_shift $lang "print $lhs >> -1" " = 0" \ | |
263 | $rs_negative_shift_count | |
264 | ||
265 | # Confirm shifting by 0 doesn't warn. | |
266 | test_shift $lang "print/x $lhs << 0" " = $res" | |
267 | test_shift $lang "print/x $lhs >> 0" " = $res" | |
268 | ||
269 | # These don't overflow due to promotion. | |
270 | test_shift $lang "print/x $lhs << 16" " = 0x(7|f)fff0000" | |
271 | test_shift $lang "print/x $lhs >> 16" " = 0x0" | |
272 | ||
273 | test_lshift_tl $lang "print $lhs << 32" " = 0" | |
274 | test_rshift_tl $lang "print $lhs >> 32" " = 0" | |
275 | test_lshift_tl $lang "print $lhs << 33" " = 0" | |
276 | test_rshift_tl $lang "print $lhs >> 33" " = 0" | |
277 | } | |
278 | } | |
279 | ||
280 | # 32-bit lhs, signed and unsigned. | |
281 | with_test_prefix "32-bit, invalid" { | |
282 | foreach {lhs res} \ | |
283 | [list \ | |
284 | [make_int32 $lang 0x7fffffff] 0x7fffffff \ | |
285 | [make_uint32 $lang 0xffffffff] 0xffffffff] \ | |
286 | { | |
287 | test_shift $lang "print $lhs << -1" " = 0" \ | |
288 | $ls_negative_shift_count | |
289 | test_shift $lang "print $lhs >> -1" " = 0" \ | |
290 | $rs_negative_shift_count | |
291 | ||
292 | # Confirm shifting by 0 doesn't warn. | |
293 | test_shift $lang "print/x $lhs << 0" " = $res" | |
294 | test_shift $lang "print/x $lhs >> 0" " = $res" | |
295 | ||
296 | test_lshift_tl $lang "print $lhs << 32" " = 0" | |
297 | test_rshift_tl $lang "print $lhs >> 32" " = 0" | |
298 | ||
299 | test_lshift_tl $lang "print $lhs << 33" " = 0" | |
300 | test_rshift_tl $lang "print $lhs >> 33" " = 0" | |
301 | } | |
302 | } | |
303 | ||
304 | # 64-bit lhs, signed and unsigned. | |
305 | with_test_prefix "64-bit, invalid" { | |
306 | foreach {lhs res} \ | |
307 | [list \ | |
308 | [make_int64 $lang 0x7fffffffffffffff] \ | |
309 | 0x7fffffffffffffff \ | |
310 | \ | |
311 | [make_uint64 $lang 0xffffffffffffffff] \ | |
312 | 0xffffffffffffffff] \ | |
313 | { | |
314 | test_shift $lang "print $lhs << -1" " = 0" \ | |
315 | $ls_negative_shift_count | |
316 | test_shift $lang "print $lhs >> -1" " = 0" \ | |
317 | $rs_negative_shift_count | |
318 | ||
319 | # Confirm shifting by 0 doesn't warn. | |
320 | test_shift $lang "print/x $lhs << 0" " = $res" | |
321 | test_shift $lang "print/x $lhs >> 0" " = $res" | |
322 | ||
323 | test_lshift_tl $lang "print $lhs << 64" " = 0" | |
324 | test_rshift_tl $lang "print $lhs >> 64" " = 0" | |
325 | ||
326 | test_lshift_tl $lang "print $lhs << 65" " = 0" | |
327 | test_rshift_tl $lang "print $lhs >> 65" " = 0" | |
328 | } | |
329 | } | |
330 | ||
331 | # Right shift a negative number by a negative amount. | |
332 | with_test_prefix "neg lhs/rhs" { | |
333 | test_shift $lang "print -1 >> -1" " = -1" $rs_negative_shift_count | |
334 | test_shift $lang "print -4 >> -2" " = -1" $rs_negative_shift_count | |
335 | } | |
336 | ||
337 | # Check right shifting a negative value. For C++, this is | |
338 | # implementation-defined, up until C++20. In most | |
339 | # implementations, this performs an arithmetic right shift, so | |
340 | # that the result remains negative. Currently, GDB does | |
341 | # whatever the host's compiler does. If that turns out wrong | |
342 | # for some host/target, then GDB should be taught to ask the | |
343 | # target gdbarch what to do. | |
344 | with_test_prefix "rsh neg lhs" { | |
345 | test_shift $lang "print -1 >> 0" " = -1" | |
346 | test_shift $lang "print -1 >> 1" " = -1" | |
347 | test_shift $lang "print -8 >> 1" " = -4" | |
348 | test_shift $lang "print [make_int64 $lang -8] >> 1" " = -4" | |
349 | } | |
350 | ||
351 | # Make sure an unsigned 64-bit value with high bit set isn't | |
352 | # confused for a negative shift count in the warning messages. | |
353 | with_test_prefix "max-uint64" { | |
354 | test_lshift_tl $lang \ | |
355 | "print 1 << [make_uint64 $lang 0xffffffffffffffff]" " = 0" | |
356 | test_rshift_tl $lang \ | |
357 | "print 1 >> [make_uint64 $lang 0xffffffffffffffff]" " = 0" | |
358 | test_lshift_tl $lang \ | |
359 | "print -1 << [make_uint64 $lang 0xffffffffffffffff]" " = 0" | |
360 | test_rshift_tl $lang \ | |
361 | "print -1 >> [make_uint64 $lang 0xffffffffffffffff]" " = -1" | |
362 | } | |
363 | } | |
364 | } | |
365 | ||
366 | test_shifts |