Detect broken ptrace in gdb_skip_float_test
authorYao Qi <yao.qi@linaro.org>
Fri, 2 Sep 2016 08:22:13 +0000 (09:22 +0100)
committerYao Qi <yao.qi@linaro.org>
Fri, 2 Sep 2016 08:22:13 +0000 (09:22 +0100)
We recently found a ARM kernel ptrace bug
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-May/431962.html
Details can be found in the comment in gdb_skip_float_test.  We can
skip floating point tests if the kernel bug is detected.

This patch adds more code in gdb_skip_float_test to detect the broken
ptrace on arm-linux.  Such detection should be done at the beginning
of the test, because it starts a fresh GDB, so change the test cases
to invoke gdb_skip_float_test at the beginning of test, and use its
return value afterwards.

Since gdb_skip_float_test becomes a gdb_caching_proc, so it can't
have an argument, this patch also removes argument "msg", which isn't
useful.

gdb/testsuite:

2016-09-02  Yao Qi  <yao.qi@linaro.org>

* gdb.arch/arm-neon.exp: Skip it if gdb_skip_float_test returns
true.
* gdb.base/call-ar-st.exp: Invoke gdb_skip_float_test.
* gdb.base/call-rt-st.exp: Likewise.
* gdb.base/call-sc.exp: Invoke gdb_skip_float_test and use its
return value instead of gdb,skip_float_test.
* gdb.base/callfuncs.exp: Invoke gdb_skip_float_test.
(do_function_calls): Use its return value instead of
gdb,skip_float_test.
* gdb.base/finish.exp: Likewise.
* gdb.base/funcargs.exp: Likewise.
* gdb.base/return.exp: Likewise.
* gdb.base/return2.exp: Likewise.
* gdb.base/varargs.exp: Likewise.
* lib/gdb.exp (gdb_skip_float_test): Change it to
gdb_caching_proc.  Detect the broken ptrace on arm-linux.

12 files changed:
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.arch/arm-neon.exp
gdb/testsuite/gdb.base/call-ar-st.exp
gdb/testsuite/gdb.base/call-rt-st.exp
gdb/testsuite/gdb.base/call-sc.exp
gdb/testsuite/gdb.base/callfuncs.exp
gdb/testsuite/gdb.base/finish.exp
gdb/testsuite/gdb.base/funcargs.exp
gdb/testsuite/gdb.base/return.exp
gdb/testsuite/gdb.base/return2.exp
gdb/testsuite/gdb.base/varargs.exp
gdb/testsuite/lib/gdb.exp

index 8b4cdd5d79067bcf2d03e94b495b0797c5d66f6a..76b5e9c9c7b578d1e859dc2e32b80bd125547ea2 100644 (file)
@@ -1,3 +1,22 @@
+2016-09-02  Yao Qi  <yao.qi@linaro.org>
+
+       * gdb.arch/arm-neon.exp: Skip it if gdb_skip_float_test returns
+       true.
+       * gdb.base/call-ar-st.exp: Invoke gdb_skip_float_test.
+       * gdb.base/call-rt-st.exp: Likewise.
+       * gdb.base/call-sc.exp: Invoke gdb_skip_float_test and use its
+       return value instead of gdb,skip_float_test.
+       * gdb.base/callfuncs.exp: Invoke gdb_skip_float_test.
+       (do_function_calls): Use its return value instead of
+       gdb,skip_float_test.
+       * gdb.base/finish.exp: Likewise.
+       * gdb.base/funcargs.exp: Likewise.
+       * gdb.base/return.exp: Likewise.
+       * gdb.base/return2.exp: Likewise.
+       * gdb.base/varargs.exp: Likewise.
+       * lib/gdb.exp (gdb_skip_float_test): Change it to
+       gdb_caching_proc.  Detect the broken ptrace on arm-linux.
+
 2016-08-30  Andreas Arnez  <arnez@linux.vnet.ibm.com>
 
        * gdb.multi/tids.exp: Test "thread apply all".
index 053170f7f5f3437c32ec1e678bb7b3e6c8a9f28b..e4612f9159d6ecf7842c6d85c4f1c9a470bd3cbe 100644 (file)
@@ -20,6 +20,11 @@ if {![istarget "aarch64*-*-*"] && ![istarget "arm*-*-*"]} {
     return
 }
 
+if { [gdb_skip_float_test] } {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
 standard_testfile
 if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug quiet}] } {
     unsupported "ARM NEON is not supported"
index 28436d50238ea84af045f92c027e130c5677f36b..c63935ad214a4661c258107c39e8a6282216b6a2 100644 (file)
@@ -33,6 +33,8 @@ if [get_compiler_info] {
     return -1
 }
 
+set skip_float_test [gdb_skip_float_test]
+
 if {[prepare_for_testing $testfile.exp $testfile $srcfile debug]} {
     untested $testfile.exp
     return -1
@@ -65,7 +67,7 @@ gdb_test continue \
 
 
 #call print_double_array(double_array)
-if {![gdb_skip_float_test "print print_double_array(double_array)"] && \
+if {!$skip_float_test && \
     ![gdb_skip_stdio_test "print print_double_array(double_array)"] } {
 
     gdb_test_stdio "print print_double_array(double_array)" \
@@ -126,7 +128,7 @@ gdb_test "tbreak $stop_line" \
        "Temporary breakpoint.* file .*$srcfile, line $stop_line.*" \
        "tbreakpoint at tbreak3"
 
-if {![gdb_skip_float_test "continuing to tbreak3"] && \
+if {!$skip_float_test && \
     ![gdb_skip_stdio_test "continuing to tbreak3"] } {
 
     gdb_test_stdio "continue" \
@@ -168,7 +170,7 @@ if ![gdb_skip_stdio_test "next over print_int_array in print_all_arrays"] {
 }
 
 #call print_double_array(array_d)
-if {![gdb_skip_float_test "print print_double_array(array_d)"] && \
+if {!$skip_float_test && \
     ![gdb_skip_stdio_test "print print_double_array(array_d)"] } {
 
     gdb_test_stdio "print print_double_array(array_d)" \
@@ -186,7 +188,7 @@ gdb_test "tbreak $stop_line" \
 "Temporary breakpoint.* file .*$srcfile, line $stop_line.*" \
 "tbreakpoint at tbreak4"
 
-if {![gdb_skip_float_test "continuing to tbreak4"] && \
+if {!$skip_float_test && \
     ![gdb_skip_stdio_test "continuing to tbreak4"] } {
 
     gdb_test_stdio "continue" \
@@ -305,7 +307,7 @@ if ![gdb_skip_stdio_test "continuing to tbreak6"] {
 #                         *flags, *flags_combo, *three_char, *five_char, 
 #                         *int_char_combo, *d1, *d2, *d3, *f1, *f2, *f3)
 
-if {![gdb_skip_float_test "print print_small_structs(...)"] && \
+if {!$skip_float_test && \
     ![gdb_skip_stdio_test "print print_small_structs(...)"] } {
     gdb_test_stdio "print print_small_structs(*struct1, *struct2, *struct3, *struct4, *flags, *flags_combo, *three_char, *five_char, *int_char_combo, *d1, *d2, *d3, *f1, *f2, *f3)" \
        [multi_line \
@@ -369,7 +371,7 @@ gdb_test "print compute_with_small_structs(20)" \
 #call print_ten_doubles(123.456, 123.456, -0.12, -1.23, 343434.8, 89.098, 
 #                       3.14, -5678.12345, -0.11111111, 216.97065)
 
-if {![gdb_skip_float_test "print print_ten_doubles(...)"] && \
+if {!$skip_float_test && \
     ![gdb_skip_stdio_test "print print_ten_doubles(...)"]} {
     gdb_test_stdio "print print_ten_doubles(123.456, 123.456, -0.12, -1.23, 343434.8, 89.098, 3.14, -5678.12345, -0.11111111, 216.97065)" \
        [multi_line \
@@ -397,7 +399,7 @@ gdb_test "tbreak print_long_arg_list" \
 # The short match case below handles cases where a buffer
 # overflows or something, and expect can't deal with the full
 # line.  Perhaps a more elegant solution exists... -sts 1999-08-17
-if {![gdb_skip_float_test "step into print_long_arg_list"]} {
+if {!$skip_float_test} {
     gdb_test_multiple "continue" "step into print_long_arg_list" {
        -re ".*print_long_arg_list \\(a=22.25, b=33.375, c=0, d=-25, e=100, f=2345, struct1=\{value = 6, head = 0\}, struct2=\{value = 10, head = 0\}, struct3=\{value = 12, head = 0\}, struct4=\{value = 14, head = 0\}, flags=\{alpha = 1, beta = 0, gamma = 1, delta = 0, epsilon = 1, omega = 0\}, flags_combo=\{alpha = 1, beta = 0, ch1 = 121 \'y\', gamma = 1, delta = 0, ch2 = 110 \'n\', epsilon = 1, omega = 0\}, three_char=\{ch1 = 97 \'a\', ch2 = 98 \'b\', ch3 = 99 \'c\'\}, five_char=\{ch1 = 108 \'l\', ch2 = 109 \'m\', ch3 = 110 \'n\', ch4 = 111 \'o\', ch5 = 112 \'p\'\}, int_char_combo=\{int1 = 123, ch1 = 122 \'z\'\}, d1=\{double1 = 10.5\}, d2=\{double1 = -3.375\}, d3=\{double1 = 675.09375\}, f1=\{float1 = 45.2340012, float2 = 43.5999985\}, f2=\{float1 = 78.0100021, float2 = 122.099998\}, f3=\{float1 = -1232.34497, float2 = -199.210007\}\\) at .*${srcfile}:$stop_line\[\r\n\]+$stop_line\[ \t\]+printf\\(\"double :.*\", a\\);.*$gdb_prompt $" {
            pass "step into print_long_arg_list"
@@ -419,7 +421,7 @@ set ws "\[\n\r\t \]+"
 #                         flags_combo, three_char, five_char, int_char_combo, 
 #                         d1, d2, d3, f1, f2, f3)
 
-if {![gdb_skip_float_test "print_small_structs from print_long_arg_list"] && \
+if {!$skip_float_test && \
     ![gdb_skip_stdio_test "print_small_structs from print_long_arg_list"] } {
 
     # On 32-bit SPARC, some of the args are passed by ref, others by
@@ -520,7 +522,7 @@ gdb_test continue "Continuing\\..*main \\(\\) at .*$srcfile:$stop_line\[\r\n\t \
 
 #call print_long_arg_list(a, b, c, d, e, f, *struct1, *struct2, *struct3, *struct4, *flags, *flags_combo, *three_char, *five_char, *int_char_combo, *d1, *d2, *d3, *f1, *f2, *f3)
 
-if {![gdb_skip_float_test "print print_long_arg_list"] && \
+if {!$skip_float_test && \
     ![gdb_skip_stdio_test "print print_long_arg_list"] } {
 
     gdb_test_stdio "print print_long_arg_list(a, b, c, d, e, f, *struct1, *struct2, *struct3, *struct4, *flags, *flags_combo, *three_char, *five_char, *int_char_combo, *d1, *d2, *d3, *f1, *f2, *f3)" \
index 0f9c5e8f7f048a8570821cb29350716c54cf8b76..a92ba9ee51b906780909d88451b8fda6c58c4eda 100644 (file)
@@ -44,6 +44,8 @@ if [target_info exists gdb,cannot_call_functions] {
     continue
 }
 
+set skip_float_test [gdb_skip_float_test]
+
 # Start with a fresh gdb.
 
 clean_restart ${binfile}
@@ -128,14 +130,14 @@ if ![gdb_skip_stdio_test "print print_one_large_struct(...)"] {
        ".\[0-9\]+ = \\{next_index = \\{1, 2, 3, 4, 5, 6, 7, 8, 9, 10\\}, values = \\{4, 6, 8, 10, 12, 14, 16, 18, 20, 22\\}, head = 0\\}"
 }
 
-if {![gdb_skip_float_test "print print_one_double(*d1)"] && \
+if {!$skip_float_test && \
         ![gdb_skip_stdio_test "print print_one_double(*d1)"] } {
     print_struct_call "print_one_double(*d1)" \
        ".*Contents of one_double_t:\[ \r\n\]+1\\.111110\[ \r\n\]+" \
        ".\[0-9\]+ = \\{double1 = 1\\.111\[0-9\]*\\}"
 }
 
-if {![gdb_skip_float_test "print print_two_floats(*f3)"] && \
+if {!$skip_float_test && \
         ![gdb_skip_stdio_test "print print_two_floats(*f3)"] } {
     print_struct_call "print_two_floats(*f3)" \
        ".*Contents of two_floats_t:\[ \r\n\]+-2\\.345000\[ \t]+1\\.000000\[ \r\n\]+" \
index 7592d65e6b7a976657a8a88ffbbe54fb06dd2c9c..89065e1ed4dee05afdb6e744f82d98a897421ab0 100644 (file)
@@ -35,6 +35,7 @@ standard_testfile .c
 if [get_compiler_info] {
     return -1
 }
+set skip_float_test [gdb_skip_float_test]
 
 # Compile a variant of scalars.c using TYPE to specify the type of the
 # parameter and return-type.  Run the compiled program up to "main".
@@ -427,7 +428,7 @@ start_scalars_test tll
 test_scalar_calls
 test_scalar_returns
 
-if ![target_info exists gdb,skip_float_tests] {
+if {!$skip_float_test} {
     # Approx size: 4, 8, ...
     start_scalars_test tf
     test_scalar_calls
index 1ec33d8958cf94f9eab4b3cd2faf771573957d9f..b1089527b899ffdb30fd6aa546d861d2ea11a609 100644 (file)
@@ -30,6 +30,8 @@ if [target_info exists gdb,cannot_call_functions] {
     continue
 }
 
+set skip_float_test [gdb_skip_float_test]
+
 # FIXME:  Before calling this proc, we should probably verify that
 # we can call inferior functions and get a valid integral value
 # returned.
@@ -38,7 +40,7 @@ if [target_info exists gdb,cannot_call_functions] {
 # (computed in the inferior) is 1 for true and 0 for false.
 
 proc do_function_calls {} {
-    global gdb_prompt
+    global gdb_prompt skip_float_test
 
     # We need to up this because this can be really slow on some boards.
     set timeout 60
@@ -71,7 +73,7 @@ proc do_function_calls {} {
     gdb_test "p t_long_values(789,long_val2)" " = 1"
     gdb_test "p t_long_values(long_val1,-321)" " = 1"
 
-    if ![target_info exists gdb,skip_float_tests] {
+    if {!$skip_float_test} {
        gdb_test "p t_float_values(0.0,0.0)" " = 0"
 
        # These next four tests fail on the mn10300.
@@ -199,7 +201,7 @@ proc do_function_calls {} {
     gdb_test "p t_structs_l(struct_val1)" "= 51" \
        "call inferior func with struct - returns long"
 
-    if ![target_info exists gdb,skip_float_tests] {
+    if {!$skip_float_test} {
        gdb_test "p t_structs_f(struct_val1)" "= 2.12.*" \
            "call inferior func with struct - returns float"
        gdb_test "p t_structs_d(struct_val1)" "= 9.87.*" \
index 47bf6f881df1953750533a5c56e0cf2b031973ad..c5387bb2d00d13cdb141e4ebf624e0118d68b5ae 100644 (file)
@@ -15,6 +15,7 @@
 
 # This file was written by Michael Snyder (msnyder@redhat.com)
 
+set skip_float_test [gdb_skip_float_test]
 
 # re-use the program from the "return2" test.
 if { [prepare_for_testing finish.exp finish return2.c] } {
@@ -86,7 +87,7 @@ proc finish_abbreviation { abbrev } {
 }
 
 proc finish_tests { } {
-    global gdb_prompt
+    global gdb_prompt skip_float_test
 
     if { ! [ runto_main ] } then {
        untested finish.exp
@@ -99,7 +100,7 @@ proc finish_tests { } {
     finish_1 "int"
     finish_1 "long"
     finish_1 "long_long"
-    if ![target_info exists gdb,skip_float_tests] {
+    if {!$skip_float_test} {
        finish_1 "float"
        finish_1 "double"
     }
index 792ca9efd211bf94d48d795ef163b88ad545d7a2..fe04b2f34a2a806373d484ddd6ab50444173b5f3 100644 (file)
@@ -29,6 +29,8 @@ if [get_compiler_info] {
     return -1
 }
 
+set skip_float_test [gdb_skip_float_test]
+
 if {[prepare_for_testing $testfile.exp $testfile $srcfile $compile_flags]} {
     untested $testfile.exp
     return -1
@@ -1155,7 +1157,7 @@ gdb_test_no_output "set print frame-arguments all"
 
 integral_args
 unsigned_integral_args
-if {![target_info exists gdb,skip_float_tests]} {
+if {!$skip_float_test} {
   float_and_integral_args
 }
 
@@ -1165,7 +1167,7 @@ if [support_complex_tests] {
 
     complex_integral_args
 
-    if {![target_info exists gdb,skip_float_tests]} {
+    if {!$skip_float_test} {
        complex_float_integral_args
     }
 }
index 95748eb25cf03bd3f38f1c3f487e3ed6519bdcec..63cccf2634e454a03129d41bbb3807346af13491 100644 (file)
@@ -19,8 +19,10 @@ if { [prepare_for_testing return.exp "return"] } {
     return -1
 }
 
+set skip_float_test [gdb_skip_float_test]
+
 proc return_tests { } {
-    global gdb_prompt
+    global gdb_prompt skip_float_test
 
 
     if { ! [ runto func1 ] } then { return 0 }
@@ -88,7 +90,7 @@ proc return_tests { } {
     # is not xfailed.
 
     setup_xfail "sparc-*-solaris2.3*" "sparc-*-solaris2.4*" "m6811-*-*"
-    if ![target_info exists gdb,skip_float_tests] {
+    if {!$skip_float_test} {
        gdb_test "p tmp3" ".* = 5.*" \
            "correct value returned double test (known problem with sparc solaris)"
     }
index d6ff2831c26f0a393594e74dc16041822dc0e79b..77be75eb7165a461c0566b08db7b33dd044cab65 100644 (file)
@@ -23,6 +23,8 @@ if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {deb
      return -1
 }
 
+set skip_float_test [gdb_skip_float_test]
+
 proc return_1 { type } {
     global gdb_prompt
 
@@ -77,7 +79,7 @@ proc return_void { } {
 }
 
 proc return2_tests { } {
-    global gdb_prompt
+    global gdb_prompt skip_float_test
 
     if { ! [ runto_main ] } then {
        untested return2.exp
@@ -92,7 +94,7 @@ proc return2_tests { } {
     if { ! [istarget "m6811-*-*"] && ![istarget "h8300*-*"] } then {
         return_1 "long_long"
     }
-    if ![target_info exists gdb,skip_float_tests] {
+    if {!$skip_float_test} {
        return_1 "float"
        if { ! [istarget "m6811-*-*"] } then {
            return_1 "double"
index f4005414f6f05493d6bf7fc57452566940fa7a97..36b01078bc7469e529a40e57a87320c1ad035da3 100644 (file)
@@ -37,6 +37,8 @@ if [get_compiler_info] {
     return -1
 }
 
+set skip_float_test [gdb_skip_float_test]
+
 set additional_flags {debug}
 if [support_complex_tests] {
     lappend additional_flags "additional_flags=-DTEST_COMPLEX"
@@ -87,7 +89,7 @@ gdb_test_stdio "print find_max2(3,1,2,3)" \
     ".\[0-9\]+ = 3" \
     "print find_max2(3,1,2,3)"
 
-if {![target_info exists gdb,skip_float_tests]} {
+if {!$skip_float_test} {
     gdb_test_stdio "print find_max_double(5,1.0,17.0,2.0,3.0,4.0)" \
        "find_max\\(.*\\) returns 17\\.000000\[ \r\n\]+" \
        ".\[0-9\]+ = 17" \
index b7b8fad75cda653161b61a65de11f95b0492aaa1..5cab774ba7be45f24ed08da7a9700c70b35766fb 100644 (file)
@@ -4882,14 +4882,102 @@ proc rerun_to_main {} {
   }
 }
 
-# Print a message and return true if a test should be skipped
-# due to lack of floating point suport.
+# Return true if a test should be skipped due to lack of floating
+# point support or GDB can't fetch the contents from floating point
+# registers.
 
-proc gdb_skip_float_test { msg } {
+gdb_caching_proc gdb_skip_float_test {
     if [target_info exists gdb,skip_float_tests] {
-       verbose "Skipping test '$msg': no float tests."
        return 1
     }
+
+    # There is an ARM kernel ptrace bug that hardware VFP registers
+    # are not updated after GDB ptrace set VFP registers.  The bug
+    # was introduced by kernel commit 8130b9d7b9d858aa04ce67805e8951e3cb6e9b2f
+    # in 2012 and is fixed in e2dfb4b880146bfd4b6aa8e138c0205407cebbaf
+    # in May 2016.  In other words, kernels older than 4.6.3, 4.4.14,
+    # 4.1.27, 3.18.36, and 3.14.73 have this bug.
+    # This kernel bug is detected by check how does GDB change the
+    # program result by changing one VFP register.
+    if { [istarget "arm*-*-linux*"] } {
+
+       set compile_flags {debug nowarnings }
+
+       # Set up, compile, and execute a test program having VFP
+       # operations.
+       set src [standard_temp_file arm_vfp[pid].c]
+       set exe [standard_temp_file arm_vfp[pid].x]
+
+       gdb_produce_source $src {
+           int main() {
+               double d = 4.0;
+               int ret;
+
+               asm ("vldr d0, [%0]" : : "r" (&d));
+               asm ("vldr d1, [%0]" : : "r" (&d));
+               asm (".global break_here\n"
+                    "break_here:");
+               asm ("vcmp.f64 d0, d1\n"
+                    "vmrs APSR_nzcv, fpscr\n"
+                    "bne L_value_different\n"
+                    "movs %0, #0\n"
+                    "b L_end\n"
+                    "L_value_different:\n"
+                    "movs %0, #1\n"
+                    "L_end:\n" : "=r" (ret) :);
+
+               /* Return $d0 != $d1.  */
+               return ret;
+           }
+       }
+
+       verbose "compiling testfile $src" 2
+       set lines [gdb_compile $src $exe executable $compile_flags]
+       file delete $src
+
+       if ![string match "" $lines] then {
+           verbose "testfile compilation failed, returning 1" 2
+           return 0
+       }
+
+       # No error message, compilation succeeded so now run it via gdb.
+       # Run the test up to 5 times to detect whether ptrace can
+       # correctly update VFP registers or not.
+       set skip_vfp_test 0
+       for {set i 0} {$i < 5} {incr i} {
+           global gdb_prompt srcdir subdir
+
+           gdb_exit
+           gdb_start
+           gdb_reinitialize_dir $srcdir/$subdir
+           gdb_load "$exe"
+
+           runto_main
+           gdb_test "break *break_here"
+           gdb_continue_to_breakpoint "break_here"
+
+           # Modify $d0 to a different value, so the exit code should
+           # be 1.
+           gdb_test "set \$d0 = 5.0"
+
+           set test "continue to exit"
+           gdb_test_multiple "continue" "$test" {
+               -re "exited with code 01.*$gdb_prompt $" {
+               }
+               -re "exited normally.*$gdb_prompt $" {
+                   # However, the exit code is 0.  That means something
+                   # wrong in setting VFP registers.
+                   set skip_vfp_test 1
+                   break
+               }
+           }
+       }
+
+       gdb_exit
+       remote_file build delete $exe
+
+       return $skip_vfp_test
+    }
     return 0
 }