binutils-gdb/gdb/testsuite/gdb.base/all-architectures.exp.tcl
Pedro Alves 01772c548b Fix undefined behavior in the Fortran, Go and Pascal number parsers
This commit ports these two fixes to the C parser:

  commit ebf13736b4
  CommitDate: Thu Sep 4 21:46:28 2014 +0100

      parse_number("0") reads uninitialized memory

  commit 20562150d8
  CommitDate: Wed Oct 3 15:19:06 2018 -0600

      Avoid undefined behavior in parse_number

... to the Fortran, Go, and Fortran number parsers, fixing the same
problems there.

Also add a new testcase that exercises printing 0xffffffffffffffff
(max 64-bit) in all languages, which crashes a GDB built with UBsan
without the fix.

I moved get_set_option_choices out of all-architectures.exp.tcl to
common code to be able to extract all the supported languages.  I did
a tweak to it to generalize it a bit -- you now have to pass down the
"set" part of the command as well.  This is so that the proc can be
used with "maintenance set" commands as well in future.

Change-Id: I8e8f2fdc1e8407f63d923c26fd55d98148b9e16a
2022-04-08 16:19:15 +01:00

336 lines
11 KiB
Tcl

# Copyright (C) 2016-2022 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"
set supported_archs [get_set_option_choices "set 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 "set 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 "set mipsfpu"]
set supported_mips_abi [get_set_option_choices "set 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 "set arm fpu"]
set supported_arm_abi [get_set_option_choices "set 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"
}
set default_architecture "i386"
# 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 ARCH.
proc do_arch_tests {arch} {
print_floats
# When we disassemble using the default architecture then we
# expect that the only error we should get from the disassembler
# is a memory error.
#
# When we force the architecture to something other than the
# default then we might get the message about unknown errors, this
# happens if the libopcodes disassembler returns -1 without first
# registering a memory error.
set pattern "Cannot access memory at address 0x100"
if { $arch != $::default_architecture } {
set pattern "(($pattern)|(unknown disassembler error \\(error = -1\\)))"
}
# GDB can't access memory because there is no loaded executable
# nor live inferior.
gdb_test_internal "disassemble 0x100,+4" "${pattern}"
}
# 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 set to $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 set to \"$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 arch} {
if {$cur_axis == [llength $all_axes]} {
do_arch_tests $arch
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] $arch
}
}
}
run_axis $all_axes 0 $arch
}
}
}
}
# 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"