Fix calling prototyped functions via function pointers
authorPedro Alves <palves@redhat.com>
Mon, 4 Sep 2017 19:21:13 +0000 (20:21 +0100)
committerPedro Alves <palves@redhat.com>
Mon, 4 Sep 2017 19:21:13 +0000 (20:21 +0100)
Calling a prototyped function via a function pointer with the right
prototype doesn't work correctly, if the called function requires
argument coercion...  Like, e.g., with:

  float mult (float f1, float f2) { return f1 * f2; }

  (gdb) p mult (2, 3.5)
  $1 = 7
  (gdb) p ((float (*) (float, float)) mult) (2, 3.5)
  $2 = 0

both calls should have returned the same, of course.  The problem is
that GDB misses marking the type of the function pointer target as
prototyped...

Without the fix, the new test fails like this:

 (gdb) p ((int (*) (float, float)) t_float_values2)(3.14159,float_val2)
 $30 = 0
 (gdb) FAIL: gdb.base/callfuncs.exp: p ((int (*) (float, float)) t_float_values2)(3.14159,float_val2)

gdb/ChangeLog:
2017-09-04  Pedro Alves  <palves@redhat.com>

* gdbtypes.c (lookup_function_type_with_arguments): Mark function
types with more than one parameter as prototyped.

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

* gdb.base/callfuncs.exp (do_function_calls): New parameter
"prototypes".  Test calling float functions via prototyped and
unprototyped function pointers.
(perform_all_tests): New parameter "prototypes".  Pass it down.
(top level): Pass down "prototypes" parameter to
perform_all_tests.

gdb/ChangeLog
gdb/gdbtypes.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/callfuncs.exp

index 9c9c6b1f921002ceb4da79b55a09741cea0ad600..d1fe7ca875891155e745581a56486162e49f14a1 100644 (file)
@@ -1,3 +1,8 @@
+2017-09-04  Pedro Alves  <palves@redhat.com>
+
+       * gdbtypes.c (lookup_function_type_with_arguments): Mark function
+       types with more than one parameter as prototyped.
+
 2017-09-04  Pedro Alves  <palves@redhat.com>
 
        * cli/cli-cmds.c (print_disassembly, disassemble_current_function)
index a68692341eacd40c6b3f61e0832b9f512e954c9d..ceb4f0ca2aa1fe4b2433681c1a4d921fb23724ba 100644 (file)
@@ -547,6 +547,8 @@ lookup_function_type_with_arguments (struct type *type,
          gdb_assert (nparams == 0);
          TYPE_PROTOTYPED (fn) = 1;
        }
+      else
+       TYPE_PROTOTYPED (fn) = 1;
     }
 
   TYPE_NFIELDS (fn) = nparams;
index 24ad99b0eb38f601444e186f64f3e061cada4a9b..35c5928def49f748034cc6b55c6855bebb47e6b4 100644 (file)
@@ -1,3 +1,12 @@
+2017-09-04  Pedro Alves  <palves@redhat.com>
+
+       * gdb.base/callfuncs.exp (do_function_calls): New parameter
+       "prototypes".  Test calling float functions via prototyped and
+       unprototyped function pointers.
+       (perform_all_tests): New parameter "prototypes".  Pass it down.
+       (top level): Pass down "prototypes" parameter to
+       perform_all_tests.
+
 2017-09-04  Simon Marchi  <simon.marchi@ericsson.com>
 
        * gdb.base/commands.exp (loop_break_test, loop_continue_test):
index 36519638d551f22a884ee2408f36729ec987c9b4..a537ebdd686373233fe36785283bac318aa14272 100644 (file)
@@ -39,7 +39,7 @@ set skip_float_test [gdb_skip_float_test]
 # specifies that the numeric value of a relational or logical expression
 # (computed in the inferior) is 1 for true and 0 for false.
 
-proc do_function_calls {} {
+proc do_function_calls {prototypes} {
     global gdb_prompt skip_float_test
 
     # We need to up this because this can be really slow on some boards.
@@ -95,11 +95,25 @@ proc do_function_calls {} {
        setup_xfail "mn10300-*-*"
        if { [test_compiler_info "armcc-*"] } { setup_xfail "*-*-*" }
        gdb_test "p t_float_values(float_val1,-2.3765)" " = 1"
+       # Same, via unprototyped function pointer (t_float_values is
+       # always unprototyped).
+       gdb_test "p ((int (*) ()) t_float_values)(float_val1,-2.3765)" " = 1"
 
        # Test passing of arguments which might not be widened.
        gdb_test "p t_float_values2(0.0,0.0)" " = 0"
+       # Same, via function pointer.
+       if {$prototypes} {
+           gdb_test "p ((int (*) (float, float)) t_float_values2)(0.0,0.0)" " = 0"
+       } else {
+           gdb_test "p ((int (*) ()) t_float_values2)(0.0,0.0)" " = 0"
+       }
 
        gdb_test "p t_float_values2(3.14159,float_val2)" " = 1"
+       if {$prototypes} {
+           gdb_test "p ((int (*) (float, float)) t_float_values2)(3.14159,float_val2)" " = 1"
+       } else {
+           gdb_test "p ((int (*) ()) t_float_values2)(3.14159,float_val2)" " = 1"
+       }
 
        gdb_test "p t_float_many_args (float_val1, float_val2, float_val3, float_val4, float_val5, float_val6, float_val7, float_val8, float_val9, float_val10, float_val11, float_val12, float_val13, float_val14, float_val15)" " = 1" "call function with many float arguments."
 
@@ -315,7 +329,7 @@ proc rerun_and_prepare {} {
        "next to t_structs_c"
 }
 
-proc perform_all_tests {} {
+proc perform_all_tests {prototypes} {
     gdb_test_no_output "set print sevenbit-strings"
     gdb_test_no_output "set print address off"
     gdb_test_no_output "set width 0"
@@ -326,7 +340,7 @@ proc perform_all_tests {} {
     set old_reg_content [fetch_all_registers "retrieve original register contents"]
 
     # Perform function calls.
-    do_function_calls
+    do_function_calls $prototypes
 
     # Check if all registers still have the same value.
     set new_reg_content [fetch_all_registers \
@@ -500,9 +514,11 @@ proc perform_all_tests {} {
 # Perform all tests with and without function prototypes.
 
 if { ![prepare_for_testing "failed to prepare" $testfile $srcfile "$compile_flags additional_flags=-DPROTOTYPES"] } {
-    perform_all_tests
+    perform_all_tests 1
 }
 
 if { ![prepare_for_testing "failed to prepare" $testfile $srcfile "$compile_flags additional_flags=-DNO_PROTOTYPES"] } {
-    with_test_prefix "noproto" perform_all_tests
+    with_test_prefix "noproto" {
+       perform_all_tests 0
+    }
 }