Add test that exercises all bfd architecture, osabi, endian, etc. combinations
authorPedro Alves <palves@redhat.com>
Fri, 9 Dec 2016 14:59:09 +0000 (14:59 +0000)
committerPedro Alves <palves@redhat.com>
Fri, 9 Dec 2016 14:59:09 +0000 (14:59 +0000)
This adds a test that exposes several problems fixed by earlier
patches:

#1 - Buffer overrun when host/target formats match, but sizes don't.
     https://sourceware.org/ml/gdb-patches/2016-03/msg00125.html

#2 - Missing handling for FR-V FR300.
     https://sourceware.org/ml/gdb-patches/2016-03/msg00117.html

#3 - BFD architectures with spaces in their names (v850).
     https://sourceware.org/ml/binutils/2016-03/msg00108.html

#4 - The OS ABI names with spaces issue.
     https://sourceware.org/ml/gdb-patches/2016-03/msg00116.html

#5 - Bogus HP/PA long double format.
     https://sourceware.org/ml/gdb-patches/2016-03/msg00122.html

#6 - Cris big endian internal error.
     https://sourceware.org/ml/gdb-patches/2016-03/msg00126.html

#7 - Several PowerPC bfd archs/machines not handled by gdb.
     https://sourceware.org/bugzilla/show_bug.cgi?id=19797

And hopefully helps catch others in the future.

This started out as a test that simply did,

 gdb -ex "print 1.0L"

to exercise #1 above.

Then to cover both 32-bit target / 64-bit host and the converse, I
thought of having the testcase print the floats twice, once with the
architecture set to "i386" and then to "i386:x86-64".  This way it
wouldn't matter whether gdb was built as 32-bit or a 64-bit program.

Then I thought that other archs might have similar host/target
floatformat conversion issues as well.  Instead of hardcoding some
architectures in the test file, I thought we could just iterate over
all bfd architectures and OS ABIs supported by the gdb build being
tested.  This is what then exposed all the other problems listed
above...

With an --enable-targets=all, this exercises over 14 thousand
combinations.  If left in a single test file, it all consistenly runs
in under a minute on my machine (An Intel i7-4810MQ @ 2.8 MHZ running
Fedora 23).  Split in 8 chunks, as in this commit, it runs in around
25 seconds, with make -j8.

To avoid flooding the gdb.sum file, it avoids calling "pass" on each
tested combination/iteration.  I'm explicitly not implementing that by
passing an empty message to gdb_test / gdb_test_multiple, because I
still want a FAIL to be logged in gdb.sum.  So instead this puts the
internal passes in the gdb.log file, only, prefixed "IPASS:", for
internal pass.  TBC, if some iteration fails, it'll still show up as
FAIL in gdb.sum.  If this is an approach that takes on, I can see us
extending the common bits to support it for all testcases.

gdb/testsuite/ChangeLog:
2016-12-09  Pedro Alves  <palves@redhat.com>

* gdb.base/all-architectures-0.exp: New file.
* gdb.base/all-architectures-1.exp: New file.
* gdb.base/all-architectures-2.exp: New file.
* gdb.base/all-architectures-3.exp: New file.
* gdb.base/all-architectures-4.exp: New file.
* gdb.base/all-architectures-5.exp: New file.
* gdb.base/all-architectures-6.exp: New file.
* gdb.base/all-architectures-7.exp: New file.
* gdb.base/all-architectures.exp.in: New file.

gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/all-architectures-0.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/all-architectures-1.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/all-architectures-2.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/all-architectures-3.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/all-architectures-4.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/all-architectures-5.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/all-architectures-6.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/all-architectures-7.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/all-architectures.exp.in [new file with mode: 0644]

index d905df3b268cc1ad78d89157c479136122697442..967ed280c4edc8d016e913414f053f5ce7cb179e 100644 (file)
@@ -1,3 +1,15 @@
+2016-12-09  Pedro Alves  <palves@redhat.com>
+
+       * gdb.base/all-architectures-0.exp: New file.
+       * gdb.base/all-architectures-1.exp: New file.
+       * gdb.base/all-architectures-2.exp: New file.
+       * gdb.base/all-architectures-3.exp: New file.
+       * gdb.base/all-architectures-4.exp: New file.
+       * gdb.base/all-architectures-5.exp: New file.
+       * gdb.base/all-architectures-6.exp: New file.
+       * gdb.base/all-architectures-7.exp: New file.
+       * gdb.base/all-architectures.exp.in: New file.
+
 2016-12-09  Yao Qi  <yao.qi@linaro.org>
 
        * gdb.perf/skip-prologue.exp: Add parameter COMPILE.
diff --git a/gdb/testsuite/gdb.base/all-architectures-0.exp b/gdb/testsuite/gdb.base/all-architectures-0.exp
new file mode 100644 (file)
index 0000000..cd28390
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright 2016 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/>.  */
+
+set test_slice 0
+source $srcdir/$subdir/all-architectures.exp.in
diff --git a/gdb/testsuite/gdb.base/all-architectures-1.exp b/gdb/testsuite/gdb.base/all-architectures-1.exp
new file mode 100644 (file)
index 0000000..034fbc4
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright 2016 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/>.  */
+
+set test_slice 1
+source $srcdir/$subdir/all-architectures.exp.in
diff --git a/gdb/testsuite/gdb.base/all-architectures-2.exp b/gdb/testsuite/gdb.base/all-architectures-2.exp
new file mode 100644 (file)
index 0000000..142bc74
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright 2016 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/>.  */
+
+set test_slice 2
+source $srcdir/$subdir/all-architectures.exp.in
diff --git a/gdb/testsuite/gdb.base/all-architectures-3.exp b/gdb/testsuite/gdb.base/all-architectures-3.exp
new file mode 100644 (file)
index 0000000..02ebf14
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright 2016 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/>.  */
+
+set test_slice 3
+source $srcdir/$subdir/all-architectures.exp.in
diff --git a/gdb/testsuite/gdb.base/all-architectures-4.exp b/gdb/testsuite/gdb.base/all-architectures-4.exp
new file mode 100644 (file)
index 0000000..1041869
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright 2016 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/>.  */
+
+set test_slice 4
+source $srcdir/$subdir/all-architectures.exp.in
diff --git a/gdb/testsuite/gdb.base/all-architectures-5.exp b/gdb/testsuite/gdb.base/all-architectures-5.exp
new file mode 100644 (file)
index 0000000..9a524d4
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright 2016 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/>.  */
+
+set test_slice 5
+source $srcdir/$subdir/all-architectures.exp.in
diff --git a/gdb/testsuite/gdb.base/all-architectures-6.exp b/gdb/testsuite/gdb.base/all-architectures-6.exp
new file mode 100644 (file)
index 0000000..35092e9
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright 2016 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/>.  */
+
+set test_slice 6
+source $srcdir/$subdir/all-architectures.exp.in
diff --git a/gdb/testsuite/gdb.base/all-architectures-7.exp b/gdb/testsuite/gdb.base/all-architectures-7.exp
new file mode 100644 (file)
index 0000000..a1702bf
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright 2016 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/>.  */
+
+set test_slice 7
+source $srcdir/$subdir/all-architectures.exp.in
diff --git a/gdb/testsuite/gdb.base/all-architectures.exp.in b/gdb/testsuite/gdb.base/all-architectures.exp.in
new file mode 100644 (file)
index 0000000..4a8099c
--- /dev/null
@@ -0,0 +1,349 @@
+# Copyright (C) 2016 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 == "rl78"} {
+               if {$want_tests_messages} {
+                   kfail "set architecture rl78" "gdb/20953"
+               }
+               continue
+           }
+           if {$arch == "rx"} {
+               if {$want_tests_messages} {
+                   kfail "set architecture rx" "gdb/20954"
+               }
+               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"