aboutsummaryrefslogtreecommitdiff
blob: c7615acfdb6a06d30fc9e2a395b4c8c7425da4ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# Copyright (C) 2016-2017 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 part of the gdb testsuite.

# Test manually setting _all_ combinations of all supported bfd
# architectures and OS ABIs.  This ensures that gdbarch initialization
# routines handle unusual combinations gracefully, at least without
# crashing.

# While at it, because the number of possible combinations is quite
# large, embed other checks that might be useful to do with all
# supported archs.

# One such test is ensuring that printing float, double and long
# double types works in cross/bi-arch scenarios.  Some of GDB's float
# format conversion routines used to fail to consider that even if
# host and target floating formats match, their sizes may still
# differ.  E.g., on x86, long double is 80-bit extended precision on
# both 32-bit vs 64-bit, but it's stored as 96 bit on 32-bit, and 128
# bit on 64-bit.  This resulted in GDB accessing memory out of bounds.
# This test catches the issue when run against gdb linked with
# libmcheck, or run under Valgrind.

# Note: this test is actually split in several driver .exp files, in
# order to be able to parallelize the work.  Each driver .exp file
# exercises a different slice of the supported architectures.  See
# all-architectures-*.exp and the TEST_SLICE variable.

clean_restart

# By default, preparation steps don't output a PASS message.  This is
# because the testcase has several thousand such steps.
set want_tests_messages 0

# Call this when an "internal" preparation-like step test passed.
# Logs the pass in gdb.log, but not in gdb.sum.

proc internal_pass {message} {
    global want_tests_messages

    if {$want_tests_messages} {
	pass $message
    } else {
	# Skip the sum file, but still log an internal pass in the log
	# file.
	global pf_prefix

	verbose -log "IPASS: $pf_prefix $message"
    }
}

# The number of times gdb_test_internal was called, and the number of
# time that resulted in an internal pass.  If these don't match, then
# some test failed.
set test_count 0
set internal_pass_count 0

# Like gdb_test, but calls internal_pass instead of pass, on success.

proc gdb_test_internal {cmd pattern {message ""}} {
    global test_count internal_pass_count
    global gdb_prompt

    incr test_count

    if {$message == ""} {
	set message $cmd
    }

    gdb_test_multiple $cmd $message {
	-re "$pattern\r\n$gdb_prompt $" {
	    internal_pass $message
	    incr internal_pass_count
	}
    }
}

gdb_test_internal "set max-completions unlimited" \
    "^set max-completions unlimited"

# Return a list of all the accepted values of "set WHAT".

proc get_set_option_choices {what} {
    global gdb_prompt

    set values {}

    set test "complete set $what"
    gdb_test_multiple "complete set $what " "$test" {
	-re "set $what (\[^\r\n\]+)\r\n" {
	    lappend values $expect_out(1,string)
	    exp_continue
	}
	-re "$gdb_prompt " {
	    internal_pass $test
	}
    }
    return $values
}

set supported_archs [get_set_option_choices "architecture"]
# There should be at least one more than "auto".
gdb_assert {[llength $supported_archs] > 1} "at least one architecture"

set supported_osabis [get_set_option_choices "osabi"]
# There should be at least one more than "auto" and "default".
gdb_assert {[llength $supported_osabis] > 2} "at least one osabi"

if {[lsearch $supported_archs "mips"] >= 0} {
    set supported_mipsfpu [get_set_option_choices "mipsfpu"]
    set supported_mips_abi [get_set_option_choices "mips abi"]

    gdb_assert {[llength $supported_mipsfpu] != 0} "at least one mipsfpu"
    gdb_assert {[llength $supported_mips_abi] != 0} "at least one mips abi"
}

if {[lsearch $supported_archs "arm"] >= 0} {
    set supported_arm_fpu [get_set_option_choices "arm fpu"]
    set supported_arm_abi [get_set_option_choices "arm abi"]

    gdb_assert {[llength $supported_arm_fpu] != 0} "at least one arm fpu"
    gdb_assert {[llength $supported_arm_abi] != 0} "at least one arm abi"
}

# Exercise printing float, double and long double.

proc print_floats {} {
    gdb_test_internal "ptype 1.0L" "type = long double" "ptype, long double"
    gdb_test_internal "print 1.0L" " = 1" "print, long double"

    gdb_test_internal "ptype 1.0" "type = double" "ptype, double"
    gdb_test_internal "print 1.0" " = 1" "print, double"

    gdb_test_internal "ptype 1.0f" "type = float" "ptype, float"
    gdb_test_internal "print 1.0f" " = 1" "print, float"
}

# Run tests on the current architecture.

proc do_arch_tests {} {
    print_floats
}

# Given we can't change arch, osabi, endianness, etc. atomically, we
# need to silently ignore the case of the current OS ABI (not the one
# we'll switch to) not having a handler for the arch.
set osabi_warning \
    [multi_line \
	 "warning: A handler for the OS ABI .* is not built into this configuration" \
	 "of GDB.  Attempting to continue with the default .* settings." \
	 "" \
	 "" \
	]

set endian_warning "(Little|Big) endian target not supported by GDB\r\n"

# Like gdb_test_no_output, but use internal_pass instead of pass, and
# ignore "no handler for OS ABI" warnings.

proc gdb_test_no_output_osabi {cmd test} {
    global osabi_warning
    global gdb_prompt

    gdb_test_multiple "$cmd" $test {
	-re "^${cmd}\r\n(${osabi_warning})?$gdb_prompt $" {
	    internal_pass $test
	}
    }
}

# It'd be nicer/safer to restart GDB on each iteration, but, that
# increases the testcase's run time several times fold.  At the time
# of writting, it'd jump from 20s to 4min on x86-64 GNU/Linux with
# --enable-targets=all.

set num_slices 8
set num_archs [llength $supported_archs]
set archs_per_slice [expr (($num_archs + $num_slices - 1) / $num_slices)]

with_test_prefix "tests" {
    foreach_with_prefix osabi $supported_osabis {

	gdb_test_no_output_osabi "set osabi $osabi" \
	    "set osabi"

	set arch_count 0
	foreach_with_prefix arch $supported_archs {

	    incr arch_count

	    # Skip architectures outside our slice.
	    if {$arch_count < [expr $test_slice * $archs_per_slice]} {
		continue
	    }
	    if {$arch_count >= [expr ($test_slice + 1) * $archs_per_slice]} {
		continue
	    }

	    if {$arch == "auto"} {
		continue
	    }
	    set default_endian ""
	    foreach_with_prefix endian {"auto" "big" "little"} {

		set test "set endian"
		if {$endian == $default_endian} {
		    continue
		} elseif {$endian == "auto"} {
		    gdb_test_multiple "set endian $endian" $test {
			-re "^set endian $endian\r\n(${osabi_warning})?The target endianness is set automatically \\(currently .* endian\\)\r\n$gdb_prompt $" {
			    internal_pass $test
			}
		    }
		} else {
		    gdb_test_multiple "set endian $endian" $test {
			-re "^set endian $endian\r\n${endian_warning}.*\r\n$gdb_prompt $" {
			    internal_pass $test
			    continue
			}
			-re "^set endian $endian\r\n(${osabi_warning})?The target is assumed to be $endian endian\r\n$gdb_prompt $" {
			    internal_pass $test
			}
		    }
		}

		# Skip setting the same architecture again.
		if {$endian == "auto"} {
		    set arch_re [string_to_regexp $arch]
		    set test "set architecture $arch"
		    gdb_test_multiple $test $test {
			-re "^set architecture $arch_re\r\n(${osabi_warning})?The target architecture is assumed to be $arch_re\r\n$gdb_prompt $" {
			    internal_pass $test
			}
			-re "Architecture .* not recognized.*$gdb_prompt $" {
			    # GDB is missing support for a few
			    # machines that bfd supports.
			    if  {$arch == "powerpc:EC603e"
				 || $arch == "powerpc:e500mc"
				 || $arch == "powerpc:e500mc64"
				 || $arch == "powerpc:vle"
				 || $arch == "powerpc:titan"
				 || $arch == "powerpc:e5500"
				 || $arch == "powerpc:e6500"} {
				if {$want_tests_messages} {
				    kfail $test "gdb/19797"
				}
			    } else {
				fail "$test (arch not recognized)"
			    }
			    continue
			}
		    }

		    # Record what is the default endianess.  As an
		    # optimization, we'll skip testing the manual "set
		    # endian DEFAULT" case.
		    set test "show endian"
		    gdb_test_multiple "show endian" $test {
			-re "currently little endian.*$gdb_prompt $" {
			    set default_endian "little"
			    internal_pass $test
			}
			-re "currently big endian.*$gdb_prompt $" {
			    set default_endian "big"
			    internal_pass $test
			}
		    }
		}

		# Some architectures have extra settings that affect
		# the ABI.  Specify the extra testing axes in a
		# declarative form.
		#
		# A list of {COMMAND, VAR, OPTIONS-LIST} elements.
		set all_axes {}

		if {$arch == "mips"} {
		    lappend all_axes [list "set mips abi" mips_abi $supported_mips_abi]
		    lappend all_axes [list "set mipsfpu" mipsfpu $supported_mipsfpu]
		} elseif {$arch == "arm"} {
		    lappend all_axes [list "set arm abi" arm_abi $supported_arm_abi]
		    lappend all_axes [list "set arm fpu" arm_fpu $supported_arm_fpu]
		}

		# Run testing axis CUR_AXIS.  This is a recursive
		# procedure that tries all combinations of options of
		# all the testing axes.
		proc run_axis {all_axes cur_axis} {
		    if {$cur_axis == [llength $all_axes]} {
			do_arch_tests
			return
		    }

		    # Unpack the axis.
		    set axis [lindex $all_axes $cur_axis]
		    set cmd [lindex $axis 0]
		    set var [lindex $axis 1]
		    set options [lindex $axis 2]

		    foreach v $options {
			with_test_prefix "$var=$v" {
			    gdb_test_no_output_osabi "$cmd $v" "$cmd"
			    run_axis $all_axes [expr $cur_axis + 1]
			}
		    }
		}

		run_axis $all_axes 0
	    }
	}
    }
}

# A test that:
#
#  - ensures there's a PASS if all internal tests actually passed
#
#  - ensures there's at least one test that is interpreted as a
#    regression (a matching PASS->FAIL) if some of the internal tests
#    failed, instead of looking like it could be a new FAIL that could
#    be ignored.
#
gdb_assert {$internal_pass_count == $test_count} "all passed"