Stop assuming no-debug-info functions return int
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)
The fact that GDB defaults to assuming that functions return int, when
it has no debug info for the function has been a recurring source of
user confusion.  Recently this came up on the errno pretty printer
discussions.  Shortly after, it came up again on IRC, with someone
wondering why does getenv() in GDB return a negative int:

  (gdb) p getenv("PATH")
  $1 = -6185

This question (with s/getenv/random-other-C-runtime-function) is a FAQ
on IRC.

The reason for the above is:

 (gdb) p getenv
 $2 = {<text variable, no debug info>} 0x7ffff7751d80 <getenv>
 (gdb) ptype getenv
 type = int ()

... which means that GDB truncated the 64-bit pointer that is actually
returned from getent to 32-bit, and then sign-extended it:

 (gdb) p /x -6185
 $6 = 0xffffe7d7

The workaround is to cast the function to the right type, like:

 (gdb) p ((char *(*) (const char *)) getenv) ("PATH")
 $3 = 0x7fffffffe7d7 "/usr/local/bin:/"...

IMO, we should do better than this.

I see the "assume-int" issue the same way I see printing bogus values
for optimized-out variables instead of "<optimized out>" -- I'd much
rather that the debugger tells me "I don't know" and tells me how to
fix it than showing me bogus misleading results, making me go around
tilting at windmills.

If GDB prints a signed integer when you're expecting a pointer or
aggregate, you at least have some sense that something is off, but
consider the case of the function actually returning a 64-bit integer.
For example, compile this without debug info:

 unsigned long long
 function ()
 {
   return 0x7fffffffffffffff;
 }

Currently, with pristine GDB, you get:

 (gdb) p function ()
 $1 = -1                      # incorrect
 (gdb) p /x function ()
 $2 = 0xffffffff              # incorrect

maybe after spending a few hours debugging you suspect something is
wrong with that -1, and do:

 (gdb) ptype function
 type = int ()

and maybe, just maybe, you realize that the function actually returns
unsigned long long.  And you try to fix it with:

(gdb) p /x (unsigned long long) function ()
 $3 = 0xffffffffffffffff      # incorrect

... which still produces the wrong result, because GDB simply applied
int to unsigned long long conversion.  Meaning, it sign-extended the
integer that it extracted from the return of the function, to 64-bits.

and then maybe, after asking around on IRC, you realize you have to
cast the function to a pointer of the right type, and call that.  It
won't be easy, but after a few missteps, you'll get to it:

.....  (gdb) p /x ((unsigned long long(*) ()) function) ()
 $666 = 0x7fffffffffffffff             # finally! :-)

So to improve on the user experience, this patch does the following
(interrelated) things:

 - makes no-debug-info functions no longer default to "int" as return
   type.  Instead, they're left with NULL/"<unknown return type>"
   return type.

    (gdb) ptype getenv
    type = <unknown return type> ()

 - makes calling a function with unknown return type an error.

    (gdb) p getenv ("PATH")
    'getenv' has unknown return type; cast the call to its declared return type

 - and then to make it easier to call the function, makes it possible
   to _only_ cast the return of the function to the right type,
   instead of having to cast the function to a function pointer:

    (gdb) p (char *) getenv ("PATH")                      # now Just Works
    $3 = 0x7fffffffe7d7 "/usr/local/bin:/"...

    (gdb) p ((char *(*) (const char *)) getenv) ("PATH")  # continues working
    $4 = 0x7fffffffe7d7 "/usr/local/bin:/"...

   I.e., it makes GDB default the function's return type to the type
   of the cast, and the function's parameters to the type of the
   arguments passed down.

After this patch, here's what you'll get for the "unsigned long long"
example above:

 (gdb) p function ()
 'function' has unknown return type; cast the call to its declared return type
 (gdb) p /x (unsigned long long) function ()
 $4 = 0x7fffffffffffffff     # correct!

Note that while with "print" GDB shows the name of the function that
has the problem:

  (gdb) p getenv ("PATH")
  'getenv' has unknown return type; cast the call to its declared return type

which can by handy in more complicated expressions, "ptype" does not:

  (gdb) ptype getenv ("PATH")
  function has unknown return type; cast the call to its declared return type

This will be fixed in the next patch.

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

* ada-lang.c (ada_evaluate_subexp) <TYPE_CODE_FUNC>: Don't handle
TYPE_GNU_IFUNC specially here.  Throw error if return type is
unknown.
* ada-typeprint.c (print_func_type): Handle functions with unknown
return type.
* c-typeprint.c (c_type_print_base): Handle functions and methods
with unknown return type.
* compile/compile-c-symbols.c (convert_symbol_bmsym)
<mst_text_gnu_ifunc>: Use nodebug_text_gnu_ifunc_symbol.
* compile/compile-c-types.c: Include "objfiles.h".
(convert_func): For functions with unknown return type, warn and
default to int.
* compile/compile-object-run.c (compile_object_run): Adjust call
to call_function_by_hand_dummy.
* elfread.c (elf_gnu_ifunc_resolve_addr): Adjust call to
call_function_by_hand.
* eval.c (evaluate_subexp_standard): Adjust calls to
call_function_by_hand.  Handle functions and methods with unknown
return type.  Pass expect_type to call_function_by_hand.
* f-typeprint.c (f_type_print_base): Handle functions with unknown
return type.
* gcore.c (call_target_sbrk): Adjust call to
call_function_by_hand.
* gdbtypes.c (objfile_type): Leave nodebug text symbol with NULL
return type instead of int.  Make nodebug_text_gnu_ifunc_symbol be
an integer address type instead of nodebug.
* guile/scm-value.c (gdbscm_value_call): Adjust call to
call_function_by_hand.
* infcall.c (error_call_unknown_return_type): New function.
(call_function_by_hand): New "default_return_type" parameter.
Pass it down.
(call_function_by_hand_dummy): New "default_return_type"
parameter.  Use it instead of defaulting to int.  If there's no
default and the return type is unknown, throw an error.  If
there's a default return type, and the called function has no
debug info, then assume the function is prototyped.
* infcall.h (call_function_by_hand, call_function_by_hand_dummy):
New "default_return_type" parameter.
(error_call_unknown_return_type): New declaration.
* linux-fork.c (call_lseek): Cast return type of lseek.
(inferior_call_waitpid, checkpoint_command): Adjust calls to
call_function_by_hand.
* linux-tdep.c (linux_infcall_mmap, linux_infcall_munmap): Adjust
calls to call_function_by_hand.
* m2-typeprint.c (m2_procedure): Handle functions with unknown
return type.
* objc-lang.c (lookup_objc_class, lookup_child_selector)
(value_nsstring, print_object_command): Adjust calls to
call_function_by_hand.
* p-typeprint.c (pascal_type_print_varspec_prefix): Handle
functions with unknown return type.
(pascal_type_print_func_varspec_suffix): New function.
(pascal_type_print_varspec_suffix) <TYPE_CODE_FUNC,
TYPE_CODE_METHOD>: Use it.
* python/py-value.c (valpy_call): Adjust call to
call_function_by_hand.
* rust-lang.c (rust_evaluate_funcall): Adjust call to
call_function_by_hand.
* valarith.c (value_x_binop, value_x_unop): Adjust calls to
call_function_by_hand.
* valops.c (value_allocate_space_in_inferior): Adjust call to
call_function_by_hand.
* typeprint.c (type_print_unknown_return_type): New function.
* typeprint.h (type_print_unknown_return_type): New declaration.

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

* gdb.base/break-main-file-remove-fail.exp (test_remove_bp): Cast
return type of munmap in infcall.
* gdb.base/break-probes.exp: Cast return type of foo in infcall.
* gdb.base/checkpoint.exp: Simplify using for loop.  Cast return
type of ftell in infcall.
* gdb.base/dprintf-detach.exp (dprintf_detach_test): Cast return
type of getpid in infcall.
* gdb.base/infcall-exec.exp: Cast return type of execlp in
infcall.
* gdb.base/info-os.exp: Cast return type of getpid in infcall.
Bail on failure to extract the pid.
* gdb.base/nodebug.c: #include <stdint.h>.
(multf, multf_noproto, mult, mult_noproto, add8, add8_noproto):
New functions.
* gdb.base/nodebug.exp (test_call_promotion): New procedure.
Change expected output of print/whatis/ptype with functions with
no debug info.  Test all supported languages.  Call
test_call_promotion.
* gdb.compile/compile.exp: Adjust expected output to expect
warning.
* gdb.threads/siginfo-threads.exp: Likewise.

37 files changed:
gdb/ChangeLog
gdb/ada-lang.c
gdb/ada-typeprint.c
gdb/c-typeprint.c
gdb/compile/compile-c-symbols.c
gdb/compile/compile-c-types.c
gdb/compile/compile-object-run.c
gdb/elfread.c
gdb/eval.c
gdb/f-typeprint.c
gdb/gcore.c
gdb/gdbtypes.c
gdb/guile/scm-value.c
gdb/infcall.c
gdb/infcall.h
gdb/linux-fork.c
gdb/linux-tdep.c
gdb/m2-typeprint.c
gdb/objc-lang.c
gdb/p-typeprint.c
gdb/python/py-value.c
gdb/rust-lang.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/break-main-file-remove-fail.exp
gdb/testsuite/gdb.base/break-probes.exp
gdb/testsuite/gdb.base/checkpoint.exp
gdb/testsuite/gdb.base/dprintf-detach.exp
gdb/testsuite/gdb.base/infcall-exec.exp
gdb/testsuite/gdb.base/info-os.exp
gdb/testsuite/gdb.base/nodebug.c
gdb/testsuite/gdb.base/nodebug.exp
gdb/testsuite/gdb.compile/compile.exp
gdb/testsuite/gdb.threads/siginfo-threads.exp
gdb/typeprint.c
gdb/typeprint.h
gdb/valarith.c
gdb/valops.c

index d1fe7ca875891155e745581a56486162e49f14a1..85cd3f9039966358e0815176a0070098a7243597 100644 (file)
@@ -1,3 +1,70 @@
+2017-09-04  Pedro Alves  <palves@redhat.com>
+
+       * ada-lang.c (ada_evaluate_subexp) <TYPE_CODE_FUNC>: Don't handle
+       TYPE_GNU_IFUNC specially here.  Throw error if return type is
+       unknown.
+       * ada-typeprint.c (print_func_type): Handle functions with unknown
+       return type.
+       * c-typeprint.c (c_type_print_base): Handle functions and methods
+       with unknown return type.
+       * compile/compile-c-symbols.c (convert_symbol_bmsym)
+       <mst_text_gnu_ifunc>: Use nodebug_text_gnu_ifunc_symbol.
+       * compile/compile-c-types.c: Include "objfiles.h".
+       (convert_func): For functions with unknown return type, warn and
+       default to int.
+       * compile/compile-object-run.c (compile_object_run): Adjust call
+       to call_function_by_hand_dummy.
+       * elfread.c (elf_gnu_ifunc_resolve_addr): Adjust call to
+       call_function_by_hand.
+       * eval.c (evaluate_subexp_standard): Adjust calls to
+       call_function_by_hand.  Handle functions and methods with unknown
+       return type.  Pass expect_type to call_function_by_hand.
+       * f-typeprint.c (f_type_print_base): Handle functions with unknown
+       return type.
+       * gcore.c (call_target_sbrk): Adjust call to
+       call_function_by_hand.
+       * gdbtypes.c (objfile_type): Leave nodebug text symbol with NULL
+       return type instead of int.  Make nodebug_text_gnu_ifunc_symbol be
+       an integer address type instead of nodebug.
+       * guile/scm-value.c (gdbscm_value_call): Adjust call to
+       call_function_by_hand.
+       * infcall.c (error_call_unknown_return_type): New function.
+       (call_function_by_hand): New "default_return_type" parameter.
+       Pass it down.
+       (call_function_by_hand_dummy): New "default_return_type"
+       parameter.  Use it instead of defaulting to int.  If there's no
+       default and the return type is unknown, throw an error.  If
+       there's a default return type, and the called function has no
+       debug info, then assume the function is prototyped.
+       * infcall.h (call_function_by_hand, call_function_by_hand_dummy):
+       New "default_return_type" parameter.
+       (error_call_unknown_return_type): New declaration.
+       * linux-fork.c (call_lseek): Cast return type of lseek.
+       (inferior_call_waitpid, checkpoint_command): Adjust calls to
+       call_function_by_hand.
+       * linux-tdep.c (linux_infcall_mmap, linux_infcall_munmap): Adjust
+       calls to call_function_by_hand.
+       * m2-typeprint.c (m2_procedure): Handle functions with unknown
+       return type.
+       * objc-lang.c (lookup_objc_class, lookup_child_selector)
+       (value_nsstring, print_object_command): Adjust calls to
+       call_function_by_hand.
+       * p-typeprint.c (pascal_type_print_varspec_prefix): Handle
+       functions with unknown return type.
+       (pascal_type_print_func_varspec_suffix): New function.
+       (pascal_type_print_varspec_suffix) <TYPE_CODE_FUNC,
+       TYPE_CODE_METHOD>: Use it.
+       * python/py-value.c (valpy_call): Adjust call to
+       call_function_by_hand.
+       * rust-lang.c (rust_evaluate_funcall): Adjust call to
+       call_function_by_hand.
+       * valarith.c (value_x_binop, value_x_unop): Adjust calls to
+       call_function_by_hand.
+       * valops.c (value_allocate_space_in_inferior): Adjust call to
+       call_function_by_hand.
+       * typeprint.c (type_print_unknown_return_type): New function.
+       * typeprint.h (type_print_unknown_return_type): New declaration.
+
 2017-09-04  Pedro Alves  <palves@redhat.com>
 
        * gdbtypes.c (lookup_function_type_with_arguments): Mark function
index b4e193ca80214927237f7aeca8711e0abcba5eca..519dfb12924d12a25b3d2411ee04fa3f0ed17b62 100644 (file)
@@ -10789,13 +10789,11 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
         case TYPE_CODE_FUNC:
           if (noside == EVAL_AVOID_SIDE_EFFECTS)
            {
-             struct type *rtype = TYPE_TARGET_TYPE (type);
-
-             if (TYPE_GNU_IFUNC (type))
-               return allocate_value (TYPE_TARGET_TYPE (rtype));
-             return allocate_value (rtype);
+             if (TYPE_TARGET_TYPE (type) == NULL)
+               error_call_unknown_return_type (NULL);
+             return allocate_value (TYPE_TARGET_TYPE (type));
            }
-          return call_function_by_hand (argvec[0], nargs, argvec + 1);
+         return call_function_by_hand (argvec[0], NULL, nargs, argvec + 1);
        case TYPE_CODE_INTERNAL_FUNCTION:
          if (noside == EVAL_AVOID_SIDE_EFFECTS)
            /* We don't know anything about what the internal
index 8392513426041ff10bbb99975339736146eae5d6..2224bb3d79f86970cf7a7ea494a8a24b11105174 100644 (file)
@@ -773,7 +773,8 @@ print_func_type (struct type *type, struct ui_file *stream, const char *name,
 {
   int i, len = TYPE_NFIELDS (type);
 
-  if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_VOID)
+  if (TYPE_TARGET_TYPE (type) != NULL
+      && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_VOID)
     fprintf_filtered (stream, "procedure");
   else
     fprintf_filtered (stream, "function");
@@ -798,7 +799,9 @@ print_func_type (struct type *type, struct ui_file *stream, const char *name,
       fprintf_filtered (stream, ")");
     }
 
-  if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
+  if (TYPE_TARGET_TYPE (type) == NULL)
+    fprintf_filtered (stream, " return <unknown return type>");
+  else if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
     {
       fprintf_filtered (stream, " return ");
       ada_print_type (TYPE_TARGET_TYPE (type), "", stream, 0, 0, flags);
index 890888bd4f9da17720932344061016db43b70aca..f752300403ee66090315128d8df1b0a05b039049 100644 (file)
@@ -893,13 +893,19 @@ c_type_print_base (struct type *type, struct ui_file *stream,
       fprintf_filtered (stream, _("<unnamed typedef>"));
       break;
 
+    case TYPE_CODE_FUNC:
+    case TYPE_CODE_METHOD:
+      if (TYPE_TARGET_TYPE (type) == NULL)
+       type_print_unknown_return_type (stream);
+      else
+       c_type_print_base (TYPE_TARGET_TYPE (type),
+                          stream, show, level, flags);
+      break;
     case TYPE_CODE_ARRAY:
     case TYPE_CODE_PTR:
     case TYPE_CODE_MEMBERPTR:
     case TYPE_CODE_REF:
     case TYPE_CODE_RVALUE_REF:
-    case TYPE_CODE_FUNC:
-    case TYPE_CODE_METHOD:
     case TYPE_CODE_METHODPTR:
       c_type_print_base (TYPE_TARGET_TYPE (type),
                         stream, show, level, flags);
index 1cdea852ea37555efb1e95fbb1d678867c826a94..ee21cf1515af1fbb9326015c63ad0b29bcbb3748 100644 (file)
@@ -376,9 +376,7 @@ convert_symbol_bmsym (struct compile_c_instance *context,
       break;
 
     case mst_text_gnu_ifunc:
-      /* nodebug_text_gnu_ifunc_symbol would cause:
-        function return type cannot be function  */
-      type = objfile_type (objfile)->nodebug_text_symbol;
+      type = objfile_type (objfile)->nodebug_text_gnu_ifunc_symbol;
       kind = GCC_C_SYMBOL_FUNCTION;
       addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
       break;
index dc6391c8b5bf006fa7c58712d5b0542c2bb4d057..2bfa72d2b8cdb1a742b6f2b84bc60799c18eb24c 100644 (file)
@@ -21,6 +21,8 @@
 #include "defs.h"
 #include "gdbtypes.h"
 #include "compile-internal.h"
+#include "objfiles.h"
+
 /* An object that maps a gdb type to a gcc type.  */
 
 struct type_map_instance
@@ -233,9 +235,25 @@ convert_func (struct compile_c_instance *context, struct type *type)
   struct gcc_type_array array;
   int is_varargs = TYPE_VARARGS (type) || !TYPE_PROTOTYPED (type);
 
+  struct type *target_type = TYPE_TARGET_TYPE (type);
+
+  /* Functions with no debug info have no return type.  Ideally we'd
+     want to fallback to the type of the cast just before the
+     function, like GDB's built-in expression parser, but we don't
+     have access to that type here.  For now, fallback to int, like
+     GDB's parser used to do.  */
+  if (target_type == NULL)
+    {
+      if (TYPE_OBJFILE_OWNED (type))
+       target_type = objfile_type (TYPE_OWNER (type).objfile)->builtin_int;
+      else
+       target_type = builtin_type (TYPE_OWNER (type).gdbarch)->builtin_int;
+      warning (_("function has unknown return type; assuming int"));
+    }
+
   /* This approach means we can't make self-referential function
      types.  Those are impossible in C, though.  */
-  return_type = convert_type (context, TYPE_TARGET_TYPE (type));
+  return_type = convert_type (context, target_type);
 
   array.n_elements = TYPE_NFIELDS (type);
   array.elements = XNEWVEC (gcc_type, TYPE_NFIELDS (type));
index de5fa163020100c613af5b122b30610b55bb2c48..43da59fc791b4f17bf7412e7b4c3002ad7a512e4 100644 (file)
@@ -172,7 +172,8 @@ compile_object_run (struct compile_module *module)
          ++current_arg;
        }
       gdb_assert (current_arg == TYPE_NFIELDS (func_type));
-      call_function_by_hand_dummy (func_val, TYPE_NFIELDS (func_type), vargs,
+      call_function_by_hand_dummy (func_val,
+                                  NULL, TYPE_NFIELDS (func_type), vargs,
                                   do_module_cleanup, data);
     }
   CATCH (ex, RETURN_MASK_ERROR)
index cad7aa8647fff3a481ef22308eb8586a71326fbc..ae84e43837c865ddace5ab281515c578ef51abb2 100644 (file)
@@ -877,7 +877,7 @@ elf_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc)
   target_auxv_search (&current_target, AT_HWCAP, &hwcap);
   hwcap_val = value_from_longest (builtin_type (gdbarch)
                                  ->builtin_unsigned_long, hwcap);
-  address_val = call_function_by_hand (function, 1, &hwcap_val);
+  address_val = call_function_by_hand (function, NULL, 1, &hwcap_val);
   address = value_as_address (address_val);
   address = gdbarch_convert_from_func_ptr_addr (gdbarch, address,
                                                &current_target);
index 80dfb2e38d8b2bcd7f345ed18880aa81bcc97199..1ec67513af262d77383bc73bd9fe2c95c31b79d1 100644 (file)
@@ -1147,12 +1147,12 @@ evaluate_subexp_standard (struct type *expect_type,
        argvec[3] = value_from_longest (long_type, selector);
        argvec[4] = 0;
 
-       ret = call_function_by_hand (argvec[0], 3, argvec + 1);
+       ret = call_function_by_hand (argvec[0], NULL, 3, argvec + 1);
        if (gnu_runtime)
          {
            /* Function objc_msg_lookup returns a pointer.  */
            argvec[0] = ret;
-           ret = call_function_by_hand (argvec[0], 3, argvec + 1);
+           ret = call_function_by_hand (argvec[0], NULL, 3, argvec + 1);
          }
        if (value_as_long (ret) == 0)
          error (_("Target does not respond to this message selector."));
@@ -1169,11 +1169,11 @@ evaluate_subexp_standard (struct type *expect_type,
        argvec[3] = value_from_longest (long_type, selector);
        argvec[4] = 0;
 
-       ret = call_function_by_hand (argvec[0], 3, argvec + 1);
+       ret = call_function_by_hand (argvec[0], NULL, 3, argvec + 1);
        if (gnu_runtime)
          {
            argvec[0] = ret;
-           ret = call_function_by_hand (argvec[0], 3, argvec + 1);
+           ret = call_function_by_hand (argvec[0], NULL, 3, argvec + 1);
          }
 
        /* ret should now be the selector.  */
@@ -1315,10 +1315,10 @@ evaluate_subexp_standard (struct type *expect_type,
            deprecated_set_value_type (argvec[0],
                                       lookup_pointer_type (lookup_function_type (value_type (argvec[0]))));
            argvec[0]
-             = call_function_by_hand (argvec[0], nargs + 2, argvec + 1);
+             = call_function_by_hand (argvec[0], NULL, nargs + 2, argvec + 1);
          }
 
-       ret = call_function_by_hand (argvec[0], nargs + 2, argvec + 1);
+       ret = call_function_by_hand (argvec[0], NULL, nargs + 2, argvec + 1);
        return ret;
       }
       break;
@@ -1705,12 +1705,9 @@ evaluate_subexp_standard (struct type *expect_type,
        error (_("Cannot evaluate function -- may be inlined"));
       if (noside == EVAL_AVOID_SIDE_EFFECTS)
        {
-         /* If the return type doesn't look like a function type, call an
-            error.  This can happen if somebody tries to turn a variable into
-            a function call.  This is here because people often want to
-            call, eg, strcmp, which gdb doesn't know is a function.  If
-            gdb isn't asked for it's opinion (ie. through "whatis"),
-            it won't offer it.  */
+         /* If the return type doesn't look like a function type,
+            call an error.  This can happen if somebody tries to turn
+            a variable into a function call.  */
 
          struct type *ftype = value_type (argvec[0]);
 
@@ -1731,10 +1728,19 @@ evaluate_subexp_standard (struct type *expect_type,
                error (_("Xmethod is missing return type."));
              return value_zero (return_type, not_lval);
            }
-         else if (TYPE_GNU_IFUNC (ftype))
-           return allocate_value (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (ftype)));
-         else if (TYPE_TARGET_TYPE (ftype))
-           return allocate_value (TYPE_TARGET_TYPE (ftype));
+         else if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
+                  || TYPE_CODE (ftype) == TYPE_CODE_METHOD)
+           {
+             struct type *return_type = TYPE_TARGET_TYPE (ftype);
+
+             if (return_type == NULL)
+               return_type = expect_type;
+
+             if (return_type == NULL)
+               error_call_unknown_return_type (NULL);
+
+             return allocate_value (return_type);
+           }
          else
            error (_("Expression of type other than "
                     "\"Function returning ...\" used as function"));
@@ -1747,7 +1753,8 @@ evaluate_subexp_standard (struct type *expect_type,
        case TYPE_CODE_XMETHOD:
          return call_xmethod (argvec[0], nargs, argvec + 1);
        default:
-         return call_function_by_hand (argvec[0], nargs, argvec + 1);
+         return call_function_by_hand (argvec[0],
+                                       expect_type, nargs, argvec + 1);
        }
       /* pai: FIXME save value from call_function_by_hand, then adjust
         pc by adjust_fn_pc if +ve.  */
index 7dbe093a7fcafd12353189207f1ded02f20989ff..2a858aab171da5c65c5cbd3dbe15da337a3a64ae 100644 (file)
@@ -304,9 +304,14 @@ f_type_print_base (struct type *type, struct ui_file *stream, int show,
       break;
 
     case TYPE_CODE_ARRAY:
-    case TYPE_CODE_FUNC:
       f_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
       break;
+    case TYPE_CODE_FUNC:
+      if (TYPE_TARGET_TYPE (type) == NULL)
+       type_print_unknown_return_type (stream);
+      else
+       f_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+      break;
 
     case TYPE_CODE_PTR:
       fprintf_filtered (stream, "PTR TO -> ( ");
index 50aff2ce520ab692e0e9a5cba13e51b356727b3f..07c1997bfdff4479666f509bf3b76ef5ceeaf9ff 100644 (file)
@@ -303,7 +303,7 @@ call_target_sbrk (int sbrk_arg)
   target_sbrk_arg = value_from_longest (builtin_type (gdbarch)->builtin_int, 
                                        sbrk_arg);
   gdb_assert (target_sbrk_arg);
-  ret = call_function_by_hand (sbrk_fn, 1, &target_sbrk_arg);
+  ret = call_function_by_hand (sbrk_fn, NULL, 1, &target_sbrk_arg);
   if (ret == NULL)
     return (bfd_vma) 0;
 
index ceb4f0ca2aa1fe4b2433681c1a4d921fb23724ba..a22f0ca21e8e2f4e8e4c3c3794c5e09ca7d540f7 100644 (file)
@@ -5312,13 +5312,13 @@ objfile_type (struct objfile *objfile)
   objfile_type->nodebug_text_symbol
     = init_type (objfile, TYPE_CODE_FUNC, 1,
                 "<text variable, no debug info>");
-  TYPE_TARGET_TYPE (objfile_type->nodebug_text_symbol)
-    = objfile_type->builtin_int;
   objfile_type->nodebug_text_gnu_ifunc_symbol
     = init_type (objfile, TYPE_CODE_FUNC, 1,
                 "<text gnu-indirect-function variable, no debug info>");
+  /* Ifunc resolvers return a function address.  */
   TYPE_TARGET_TYPE (objfile_type->nodebug_text_gnu_ifunc_symbol)
-    = objfile_type->nodebug_text_symbol;
+    = init_integer_type (objfile, gdbarch_addr_bit (gdbarch), 1,
+                        "__IFUNC_RESOLVER_RET");
   TYPE_GNU_IFUNC (objfile_type->nodebug_text_gnu_ifunc_symbol) = 1;
   objfile_type->nodebug_got_plt_symbol
     = init_pointer_type (objfile, gdbarch_addr_bit (gdbarch),
index f63103227cef7b35d1c9813708925f945b59d2fd..0dc66302ed3f6fa3bda237d46b0e4fe0e51b8826 100644 (file)
@@ -864,7 +864,7 @@ gdbscm_value_call (SCM self, SCM args)
       struct cleanup *cleanup = make_cleanup_value_free_to_mark (mark);
       struct value *return_value;
 
-      return_value = call_function_by_hand (function, args_count, vargs);
+      return_value = call_function_by_hand (function, NULL, args_count, vargs);
       result = vlscm_scm_from_value (return_value);
       do_cleanups (cleanup);
     }
index 9e434a9df41e6b299456000a601097d835731cdf..cd3eedfeeb712b27234a68cf8af394558ce4f57d 100644 (file)
@@ -340,6 +340,20 @@ push_dummy_code (struct gdbarch *gdbarch,
                                  regcache);
 }
 
+/* See infcall.h.  */
+
+void
+error_call_unknown_return_type (const char *func_name)
+{
+  if (func_name != NULL)
+    error (_("'%s' has unknown return type; "
+            "cast the call to its declared return type"),
+          func_name);
+  else
+    error (_("function has unknown return type; "
+            "cast the call to its declared return type"));
+}
+
 /* Fetch the name of the function at FUNADDR.
    This is used in printing an error message for call_function_by_hand.
    BUF is used to print FUNADDR in hex if the function name cannot be
@@ -673,9 +687,12 @@ cleanup_delete_std_terminate_breakpoint (void *ignore)
 /* See infcall.h.  */
 
 struct value *
-call_function_by_hand (struct value *function, int nargs, struct value **args)
+call_function_by_hand (struct value *function,
+                      type *default_return_type,
+                      int nargs, struct value **args)
 {
-  return call_function_by_hand_dummy (function, nargs, args, NULL, NULL);
+  return call_function_by_hand_dummy (function, default_return_type,
+                                     nargs, args, NULL, NULL);
 }
 
 /* All this stuff with a dummy frame may seem unnecessarily complicated
@@ -698,6 +715,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
 
 struct value *
 call_function_by_hand_dummy (struct value *function,
+                            type *default_return_type,
                             int nargs, struct value **args,
                             dummy_frame_dtor_ftype *dummy_dtor,
                             void *dummy_dtor_data)
@@ -850,8 +868,16 @@ call_function_by_hand_dummy (struct value *function,
   }
 
   funaddr = find_function_addr (function, &values_type);
-  if (!values_type)
-    values_type = builtin_type (gdbarch)->builtin_int;
+  if (values_type == NULL)
+    values_type = default_return_type;
+  if (values_type == NULL)
+    {
+      const char *name = get_function_name (funaddr,
+                                           name_buf, sizeof (name_buf));
+      error (_("'%s' has unknown return type; "
+              "cast the call to its declared return type"),
+            name);
+    }
 
   values_type = check_typedef (values_type);
 
@@ -955,6 +981,21 @@ call_function_by_hand_dummy (struct value *function,
           prototyped.  Can we respect TYPE_VARARGS?  Probably not.  */
        if (TYPE_CODE (ftype) == TYPE_CODE_METHOD)
          prototyped = 1;
+       if (TYPE_TARGET_TYPE (ftype) == NULL && TYPE_NFIELDS (ftype) == 0
+           && default_return_type != NULL)
+         {
+           /* Calling a no-debug function with the return type
+              explicitly cast.  Assume the function is prototyped,
+              with a prototype matching the types of the arguments.
+              E.g., with:
+                float mult (float v1, float v2) { return v1 * v2; }
+              This:
+                (gdb) p (float) mult (2.0f, 3.0f)
+              Is a simpler alternative to:
+                (gdb) p ((float (*) (float, float)) mult) (2.0f, 3.0f)
+            */
+           prototyped = 1;
+         }
        else if (i < TYPE_NFIELDS (ftype))
          prototyped = TYPE_PROTOTYPED (ftype);
        else
index cbaa943b241c2b0103baffcf579b5bb20377e130..a456d92e044865eaec4539a5187b54e3f4233349 100644 (file)
@@ -35,9 +35,15 @@ extern CORE_ADDR find_function_addr (struct value *function,
    representing what the function returned.  May fail to return, if a
    breakpoint or signal is hit during the execution of the function.
 
+   DFEAULT_RETURN_TYPE is used as function return type if the return
+   type is unknown.  This is used when calling functions with no debug
+   info.
+
    ARGS is modified to contain coerced values.  */
 
-extern struct value *call_function_by_hand (struct value *function, int nargs,
+extern struct value *call_function_by_hand (struct value *function,
+                                           type *default_return_type,
+                                           int nargs,
                                            struct value **args);
 
 /* Similar to call_function_by_hand and additional call
@@ -45,9 +51,18 @@ extern struct value *call_function_by_hand (struct value *function, int nargs,
    created inferior call dummy frame.  */
 
 extern struct value *
-  call_function_by_hand_dummy (struct value *function, int nargs,
+  call_function_by_hand_dummy (struct value *function,
+                              type *default_return_type,
+                              int nargs,
                               struct value **args,
                               dummy_frame_dtor_ftype *dummy_dtor,
                               void *dummy_dtor_data);
 
+/* Throw an error indicating that the user tried to call a function
+   that has unknown return type.  FUNC_NAME is the name of the
+   function to be included in the error message; may be NULL, in which
+   case the error message doesn't include a function name.  */
+
+extern void error_call_unknown_return_type (const char *func_name);
+
 #endif
index 573a3e9ecf040bb77b3f116e60289ba60266ffd0..16403c96016690371dd59156b7f2feb234ea3b2c 100644 (file)
@@ -248,7 +248,7 @@ call_lseek (int fd, off_t offset, int whence)
 {
   char exp[80];
 
-  snprintf (&exp[0], sizeof (exp), "lseek (%d, %ld, %d)",
+  snprintf (&exp[0], sizeof (exp), "(long) lseek (%d, %ld, %d)",
            fd, (long) offset, whence);
   return (off_t) parse_and_eval_long (&exp[0]);
 }
@@ -492,7 +492,7 @@ inferior_call_waitpid (ptid_t pptid, int pid)
   argv[2] = value_from_longest (builtin_type (gdbarch)->builtin_int, 0);
   argv[3] = 0;
 
-  retv = call_function_by_hand (waitpid_fn, 3, argv);
+  retv = call_function_by_hand (waitpid_fn, NULL, 3, argv);
   if (value_as_long (retv) < 0)
     goto out;
 
@@ -707,7 +707,7 @@ checkpoint_command (char *args, int from_tty)
     scoped_restore save_pid
       = make_scoped_restore (&checkpointing_pid, ptid_get_pid (inferior_ptid));
 
-    ret = call_function_by_hand (fork_fn, 0, &ret);
+    ret = call_function_by_hand (fork_fn, NULL, 0, &ret);
   }
 
   if (!ret)    /* Probably can't happen.  */
index f5389a07f9f3bdbeee5ac486acb7c3872805110b..eb446599528ee13143cac584b1abcaed8a6eefb9 100644 (file)
@@ -2448,7 +2448,7 @@ linux_infcall_mmap (CORE_ADDR size, unsigned prot)
   arg[ARG_FD] = value_from_longest (builtin_type (gdbarch)->builtin_int, -1);
   arg[ARG_OFFSET] = value_from_longest (builtin_type (gdbarch)->builtin_int64,
                                        0);
-  addr_val = call_function_by_hand (mmap_val, ARG_LAST, arg);
+  addr_val = call_function_by_hand (mmap_val, NULL, ARG_LAST, arg);
   retval = value_as_address (addr_val);
   if (retval == (CORE_ADDR) -1)
     error (_("Failed inferior mmap call for %s bytes, errno is changed."),
@@ -2477,7 +2477,7 @@ linux_infcall_munmap (CORE_ADDR addr, CORE_ADDR size)
   /* Assuming sizeof (unsigned long) == sizeof (size_t).  */
   arg[ARG_LENGTH] = value_from_ulongest
                    (builtin_type (gdbarch)->builtin_unsigned_long, size);
-  retval_val = call_function_by_hand (munmap_val, ARG_LAST, arg);
+  retval_val = call_function_by_hand (munmap_val, NULL, ARG_LAST, arg);
   retval = value_as_long (retval_val);
   if (retval != 0)
     warning (_("Failed inferior munmap call at %s for %s bytes, "
index 4cf15698fe3dff4ed224b9c40b6dbbf6f8b83acd..0dd6f19fc7a1b00cd31adae16c732d7768bc3f49 100644 (file)
@@ -280,7 +280,8 @@ m2_procedure (struct type *type, struct ui_file *stream,
 {
   fprintf_filtered (stream, "PROCEDURE ");
   m2_type_name (type, stream);
-  if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
+  if (TYPE_TARGET_TYPE (type) == NULL
+      || TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
     {
       int i, len = TYPE_NFIELDS (type);
 
@@ -294,11 +295,11 @@ m2_procedure (struct type *type, struct ui_file *stream,
            }
          m2_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0, flags);
        }
+      fprintf_filtered (stream, ") : ");
       if (TYPE_TARGET_TYPE (type) != NULL)
-       {
-         fprintf_filtered (stream, " : ");
-         m2_print_type (TYPE_TARGET_TYPE (type), "", stream, 0, 0, flags);
-       }
+       m2_print_type (TYPE_TARGET_TYPE (type), "", stream, 0, 0, flags);
+      else
+       type_print_unknown_return_type (stream);
     }
 }
 
index bd085142416e42ad0e2ecfdae18eb2bd90989609..624310e3b0119b530a7a60e63e1453b997b802fd 100644 (file)
@@ -130,7 +130,8 @@ lookup_objc_class (struct gdbarch *gdbarch, const char *classname)
 
   classval = value_string (classname, strlen (classname) + 1, char_type);
   classval = value_coerce_array (classval);
-  return (CORE_ADDR) value_as_long (call_function_by_hand (function, 
+  return (CORE_ADDR) value_as_long (call_function_by_hand (function,
+                                                          NULL,
                                                           1, &classval));
 }
 
@@ -160,7 +161,7 @@ lookup_child_selector (struct gdbarch *gdbarch, const char *selname)
   selstring = value_coerce_array (value_string (selname, 
                                                strlen (selname) + 1,
                                                char_type));
-  return value_as_long (call_function_by_hand (function, 1, &selstring));
+  return value_as_long (call_function_by_hand (function, NULL, 1, &selstring));
 }
 
 struct value * 
@@ -181,12 +182,13 @@ value_nsstring (struct gdbarch *gdbarch, char *ptr, int len)
   if (lookup_minimal_symbol("_NSNewStringFromCString", 0, 0).minsym)
     {
       function = find_function_in_inferior("_NSNewStringFromCString", NULL);
-      nsstringValue = call_function_by_hand(function, 1, &stringValue[2]);
+      nsstringValue = call_function_by_hand(function,
+                                           NULL, 1, &stringValue[2]);
     }
   else if (lookup_minimal_symbol("istr", 0, 0).minsym)
     {
       function = find_function_in_inferior("istr", NULL);
-      nsstringValue = call_function_by_hand(function, 1, &stringValue[2]);
+      nsstringValue = call_function_by_hand(function, NULL, 1, &stringValue[2]);
     }
   else if (lookup_minimal_symbol("+[NSString stringWithCString:]", 0, 0).minsym)
     {
@@ -198,7 +200,7 @@ value_nsstring (struct gdbarch *gdbarch, char *ptr, int len)
        (type, lookup_objc_class (gdbarch, "NSString"));
       stringValue[1] = value_from_longest 
        (type, lookup_child_selector (gdbarch, "stringWithCString:"));
-      nsstringValue = call_function_by_hand(function, 3, &stringValue[0]);
+      nsstringValue = call_function_by_hand(function, NULL, 3, &stringValue[0]);
     }
   else
     error (_("NSString: internal error -- no way to create new NSString"));
@@ -1209,7 +1211,7 @@ print_object_command (char *args, int from_tty)
   if (function == NULL)
     error (_("Unable to locate _NSPrintForDebugger in child process"));
 
-  description = call_function_by_hand (function, 1, &object);
+  description = call_function_by_hand (function, NULL, 1, &object);
 
   string_addr = value_as_long (description);
   if (string_addr == 0)
index d08f6f792f64039d830ab71a440350834c1430c9..33b4992c335d583b369d9167b9eb074851e8185f 100644 (file)
@@ -227,7 +227,8 @@ pascal_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
     case TYPE_CODE_METHOD:
       if (passed_a_ptr)
        fprintf_filtered (stream, "(");
-      if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
+      if (TYPE_TARGET_TYPE (type) != NULL
+         && TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
        {
          fprintf_filtered (stream, "function  ");
        }
@@ -255,7 +256,8 @@ pascal_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
       if (passed_a_ptr)
        fprintf_filtered (stream, "(");
 
-      if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
+      if (TYPE_TARGET_TYPE (type) != NULL
+         && TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
        {
          fprintf_filtered (stream, "function  ");
        }
@@ -334,6 +336,33 @@ pascal_print_func_args (struct type *type, struct ui_file *stream,
     }
 }
 
+/* Helper for pascal_type_print_varspec_suffix to print the suffix of
+   a function or method.  */
+
+static void
+pascal_type_print_func_varspec_suffix  (struct type *type, struct ui_file *stream,
+                                       int show, int passed_a_ptr,
+                                       int demangled_args,
+                                       const struct type_print_options *flags)
+{
+  if (TYPE_TARGET_TYPE (type) == NULL
+      || TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
+    {
+      fprintf_filtered (stream, " : ");
+      pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
+                                       stream, 0, 0, flags);
+
+      if (TYPE_TARGET_TYPE (type) == NULL)
+       type_print_unknown_return_type (stream);
+      else
+       pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, 0,
+                               flags);
+
+      pascal_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
+                                       passed_a_ptr, 0, flags);
+    }
+}
+
 /* Print any array sizes, function arguments or close parentheses
    needed after the variable name (to describe its type).
    Args work like pascal_type_print_varspec_prefix.  */
@@ -365,16 +394,8 @@ pascal_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
       pascal_type_print_method_args ("",
                                     "",
                                     stream);
-      if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
-       {
-         fprintf_filtered (stream, " : ");
-         pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-                                           stream, 0, 0, flags);
-         pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, 0,
-                                 flags);
-         pascal_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
-                                           passed_a_ptr, 0, flags);
-       }
+      pascal_type_print_func_varspec_suffix (type, stream, show,
+                                            passed_a_ptr, 0, flags);
       break;
 
     case TYPE_CODE_PTR:
@@ -388,16 +409,8 @@ pascal_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
        fprintf_filtered (stream, ")");
       if (!demangled_args)
        pascal_print_func_args (type, stream, flags);
-      if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
-       {
-         fprintf_filtered (stream, " : ");
-         pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-                                           stream, 0, 0, flags);
-         pascal_type_print_base (TYPE_TARGET_TYPE (type), stream, show, 0,
-                                 flags);
-         pascal_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
-                                           passed_a_ptr, 0, flags);
-       }
+      pascal_type_print_func_varspec_suffix (type, stream, show,
+                                            passed_a_ptr, 0, flags);
       break;
 
     case TYPE_CODE_UNDEF:
index b5a0ef86d24aa0625dc4c5829057abbc2c2a4288..cbbb9362ec9afcdcafd5f25a79442aac1f9ca1a5 100644 (file)
@@ -925,7 +925,8 @@ valpy_call (PyObject *self, PyObject *args, PyObject *keywords)
       scoped_value_mark free_values;
       struct value *return_value;
 
-      return_value = call_function_by_hand (function, args_count, vargs);
+      return_value = call_function_by_hand (function, NULL,
+                                           args_count, vargs);
       result = value_to_value_object (return_value);
     }
   CATCH (except, RETURN_MASK_ALL)
index 817976ab33a7a40dd445bef24a26b105de8f637b..c5764bf8d124d2bf0175a92eaca939b6103a4cde 100644 (file)
@@ -1290,7 +1290,7 @@ rust_evaluate_funcall (struct expression *exp, int *pos, enum noside noside)
   if (noside == EVAL_AVOID_SIDE_EFFECTS)
     result = value_zero (TYPE_TARGET_TYPE (fn_type), not_lval);
   else
-    result = call_function_by_hand (function, num_args + 1, args.data ());
+    result = call_function_by_hand (function, NULL, num_args + 1, args.data ());
   return result;
 }
 
index 35c5928def49f748034cc6b55c6855bebb47e6b4..c00c30038c510baddefc63758568746217570fa0 100644 (file)
@@ -1,3 +1,27 @@
+2017-09-04  Pedro Alves  <palves@redhat.com>
+
+       * gdb.base/break-main-file-remove-fail.exp (test_remove_bp): Cast
+       return type of munmap in infcall.
+       * gdb.base/break-probes.exp: Cast return type of foo in infcall.
+       * gdb.base/checkpoint.exp: Simplify using for loop.  Cast return
+       type of ftell in infcall.
+       * gdb.base/dprintf-detach.exp (dprintf_detach_test): Cast return
+       type of getpid in infcall.
+       * gdb.base/infcall-exec.exp: Cast return type of execlp in
+       infcall.
+       * gdb.base/info-os.exp: Cast return type of getpid in infcall.
+       Bail on failure to extract the pid.
+       * gdb.base/nodebug.c: #include <stdint.h>.
+       (multf, multf_noproto, mult, mult_noproto, add8, add8_noproto):
+       New functions.
+       * gdb.base/nodebug.exp (test_call_promotion): New procedure.
+       Change expected output of print/whatis/ptype with functions with
+       no debug info.  Test all supported languages.  Call
+       test_call_promotion.
+       * gdb.compile/compile.exp: Adjust expected output to expect
+       warning.
+       * gdb.threads/siginfo-threads.exp: Likewise.
+
 2017-09-04  Pedro Alves  <palves@redhat.com>
 
        * gdb.base/callfuncs.exp (do_function_calls): New parameter
index eba72bc85d1aff14b9b535e2404f0a751054e082..080d193a347e88c2981b01c42422451fe1ed9e6d 100644 (file)
@@ -88,7 +88,7 @@ proc test_remove_bp { initial_load } {
        # should warn the user about it.
        set pagesize [get_integer_valueof "pg_size" 0]
        set align_addr [expr $bp_addr - $bp_addr % $pagesize]
-       set munmap [get_integer_valueof "munmap ($align_addr, $pagesize)" -1]
+       set munmap [get_integer_valueof "(int) munmap ($align_addr, $pagesize)" -1]
 
        if {$munmap != 0} {
            unsupported "can't munmap foo's page"
index 929509a015dca65946a6e08a4967860873867fbf..318a21993e0633fa4fe6e9a68435091edf553003 100644 (file)
@@ -86,5 +86,5 @@ if { $using_probes } {
     }
 
     # Call something to ensure that relocation occurred
-    gdb_test "call foo(23)" "\\\$.* = 31.*\\\M.*"
+    gdb_test "call (int) foo(23)" "\\\$.* = 31.*\\\M.*"
 }
index 12c1d8ae142abb4d4b000936b82db0fd0b2016aa..677c3892fd7009d65708b229ed0b7ea171173ccd 100644 (file)
@@ -224,45 +224,11 @@ gdb_test "shell diff $pi_txt $copy1_txt" \
 delete_breakpoints
 gdb_breakpoint $break2_loc
 
-gdb_test "restart 1" "if .c == EOF.*" "restart 1 three"
-gdb_test "continue" "breakpoint 2.*" "break2 1 one"
-gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 1"
-
-gdb_test "restart 2" "if .c == EOF.*" "restart 2 three"
-gdb_test "continue" "breakpoint 2.*" "break2 2 one"
-gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 2"
-
-gdb_test "restart 3" "if .c == EOF.*" "restart 3 three"
-gdb_test "continue" "breakpoint 2.*" "break2 3 one"
-gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 3"
-
-gdb_test "restart 4" "if .c == EOF.*" "restart 4 three"
-gdb_test "continue" "breakpoint 2.*" "break2 4 one"
-gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 4"
-
-gdb_test "restart 5" "if .c == EOF.*" "restart 5 three"
-gdb_test "continue" "breakpoint 2.*" "break2 5 one"
-gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 5"
-
-gdb_test "restart 6" "if .c == EOF.*" "restart 6 three"
-gdb_test "continue" "breakpoint 2.*" "break2 6 one"
-gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 6"
-
-gdb_test "restart 7" "if .c == EOF.*" "restart 7 three"
-gdb_test "continue" "breakpoint 2.*" "break2 7 one"
-gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 7"
-
-gdb_test "restart 8" "if .c == EOF.*" "restart 8 three"
-gdb_test "continue" "breakpoint 2.*" "break2 8 one"
-gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 8"
-
-gdb_test "restart 9" "if .c == EOF.*" "restart 9 three"
-gdb_test "continue" "breakpoint 2.*" "break2 9 one"
-gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 9"
-
-gdb_test "restart 10" "if .c == EOF.*" "restart 10 three"
-gdb_test "continue" "breakpoint 2.*" "break2 10 one"
-gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 10"
+for {set num 1} {$num <= 10} {incr num} {
+    gdb_test "restart $num" "if .c == EOF.*" "restart $num three"
+    gdb_test "continue" "breakpoint 2.*" "break2 $num one"
+    gdb_test "print (long) ftell (out) > 100000" " = 1.*" "outfile still open $num"
+}
 
 #
 # Now confirm that if one fork exits, we automatically switch to another one.
index 4c6ef1cf3c5d46e3b520cfaa0476050a57cd03cb..940a9ef537ef6421a61b89903aaf6f60e9902ae8 100644 (file)
@@ -53,7 +53,7 @@ proc dprintf_detach_test { breakpoint_always_inserted dprintf_style disconnected
        # Get PID of test program.
        set inferior_pid -1
        set test "get inferior process ID"
-       gdb_test_multiple "call getpid ()" $test {
+       gdb_test_multiple "call (int) getpid ()" $test {
            -re ".* = ($decimal).*$gdb_prompt $" {
                set inferior_pid $expect_out(1,string)
                pass $test
index 39840769cf3fe4feec0cb1ad716f12c25bf72786..8419905e9cbb29aed037b9b834cc4ce166e7fbbe 100644 (file)
@@ -44,5 +44,5 @@ append expected_result "\[\r\n\]+.*"
 append expected_result "Breakpoint 1, main .*at .*$srcfile2:$decimal"
 append expected_result ".*"
 
-gdb_test "call execlp \(\"$binfile2\", \"$binfile2\", \(char \*\)0\)" \
+gdb_test "call (int) execlp \(\"$binfile2\", \"$binfile2\", \(char \*\)0\)" \
     $expected_result "call execlp"
index 0168ccb3c18af3173233a2099c65e375f7fc3cf8..574da26c331ac1265be4eb7224f760b57185c638 100644 (file)
@@ -39,14 +39,18 @@ if ![runto_main] then {
 }
 
 # Get PID of test program.
-set inferior_pid -1
+set inferior_pid ""
 set test "get inferior process ID"
-gdb_test_multiple "call getpid()" $test {
+gdb_test_multiple "call (int) getpid()" $test {
     -re ".* = ($decimal).*$gdb_prompt $" {
        set inferior_pid $expect_out(1,string)
        pass $test
     }
 }
+if {$inferior_pid == ""} {
+    untested "failed to get pid"
+    return
+}
 
 gdb_breakpoint ${srcfile}:[gdb_get_line_number "Set breakpoint here"]
 gdb_continue_to_breakpoint "Set breakpoint here"
index eb5d661a095cebe2073e6afdd463ed9e6be7291c..99641e801217c990c5eefe9d8105c985a1f00a1e 100644 (file)
@@ -1,4 +1,6 @@
 #include <stdlib.h>
+#include <stdint.h>
+
 /* Test that things still (sort of) work when compiled without -g.  */
 
 int dataglobal = 3;                    /* Should go in global data */
@@ -43,3 +45,42 @@ int array_index (char *arr, int i)
   free (x);
   return retval;
 }
+
+float
+multf (float v1, float v2)
+{
+  return v1 * v2;
+}
+
+float
+multf_noproto (v1, v2)
+  float v1, v2;
+{
+  return v1 * v2;
+}
+
+double
+mult (double v1, double v2)
+{
+  return v1 * v2;
+}
+
+double
+mult_noproto (v1, v2)
+  double v1, v2;
+{
+  return v1 * v2;
+}
+
+uint8_t
+add8 (uint8_t v1, uint8_t v2)
+{
+  return v1 + v2;
+}
+
+uint8_t
+add8_noproto (v1, v2)
+  uint8_t v1, v2;
+{
+  return v1 + v2;
+}
index a54e5bb65edb0e844c28696252be7c13539ae7a9..7bdf9ad7662b16ea8f797e5967175eec1dbf5b25 100644 (file)
@@ -39,6 +39,40 @@ if  { [gdb_compile $srcdir/$subdir/$srcfile $binfile executable $exec_opts] != "
 
 clean_restart $binfile
 
+# Test calling no-debug functions involving argument types that may
+# require coercion/promotion, both prototyped and unprototyped, both
+# return-type-cast style, and function-pointer-cast styles.
+proc test_call_promotion {} {
+    if [target_info exists gdb,cannot_call_functions] {
+       return
+    }
+
+    # Call prototyped function with float parameters via both
+    # return-type cast and function-pointer cast.  This checks that
+    # GDB doesn't do float->double coercion.
+    gdb_test "p (float) multf(2.0f, 3.0f)" " = 6"
+    gdb_test "p ((float (*) (float, float)) multf)(2, 3)" " = 6"
+    gdb_test "p ((float (*) (float, float)) multf)(2.0f, 3.0f)" " = 6"
+
+    # Call unprototyped function with float parameters via
+    # function-pointer cast, only.  return-type cast assumes
+    # protototyped.  Check that GDB does float->double coercion.
+    gdb_test "p ((float (*) ()) multf_noproto)(2.0f, 3.0f)" " = 6"
+    gdb_test "p ((float (*) ()) multf_noproto)(2.0, 3.0)" " = 6"
+
+    # Same, but for double.
+    gdb_test "p (double) mult (2.0, 3.0)" " = 6"
+    gdb_test "p ((double (*) (double, double)) mult)(2.0f, 3.0f)" " = 6"
+    gdb_test "p ((double (*) (double, double)) mult)(2, 3)" " = 6"
+    gdb_test "p ((double (*) ()) mult_noproto)(2.0f, 3.0f)" " = 6"
+    gdb_test "p ((double (*) ()) mult_noproto)(2.0, 3.0)" " = 6"
+
+    # Check that GDB promotes char->int correctly.
+    gdb_test "p /d (uint8) add8((uint8) 2, (uint8) 3)" " = 5"
+    gdb_test "p /d ((uint8 (*) (uint8, uint8)) add8)((uint8) 2, (uint8) 3)" " = 5"
+    gdb_test "p /d ((uint8 (*) ()) add8_noproto)((uint8) 2, (uint8) 3)" " = 5"
+}
+
 if [runto inner] then {
     
     # Expect to find global/local symbols in each of text/data/bss.
@@ -59,18 +93,66 @@ if [runto inner] then {
     # out debugging info for non-aggregate return values of functions
     # even without -g, which should be accepted.
 
-    gdb_test "p top" \
-       "\{(<(text variable|function), no debug info>|short \\(int\\)|short \\(\\))\} \[0-9a-fx]* <\\.?top(\\(int\\)|)>"
-    gdb_test "whatis top" \
-       "(<(text variable|function), no debug info>|short \\(int\\)|short \\(\\))"
-    gdb_test "ptype top" "(short|int) \\((|void|int|<non-float parameter>|<non-float parameter>, <non-float parameter>)\\)"
-    
-    gdb_test "p middle" \
-       "\{(<(text variable|function), no debug info>|short \\(int\\)|short \\(\\))\} \[0-9a-fx]* <\\.?middle(\\(int\\)|)>"
-    gdb_test "whatis middle" \
-       "(<(text variable|function), no debug info>|short \\(int\\)|short \\(\\))"
-    gdb_test "ptype middle" "(short|int) \\((|void|int|<non-float parameter>|<non-float parameter>, <non-float parameter>)\\)"
-    
+    with_test_prefix "func" {
+       # Most languages default to printing like C.
+       set c_print_re " = \\{<text variable, no debug info>\\} $hex <top>"
+       set c_whatis_re " = <text variable, no debug info>"
+       set c_ptype_re "= <unknown return type> \\(\\)"
+
+       set cxx_ptype_re "= <unknown return type> \\(void\\)"
+
+       set ada_ptype_re " = function return <unknown return type>"
+
+       set m2_print_re " = \\{PROCEDURE <text variable, no debug info> \\(\\) : <unknown return type>\\} $hex <top>"
+       set m2_whatis_re "PROCEDURE <text variable, no debug info> \\(\\) : <unknown return type>"
+       set m2_ptype_re $m2_whatis_re
+
+       # Rust can't access minsyms?
+       set rust_nosym "No symbol 'top' in current context"
+
+       set pascal_ptype_re "type = procedure  : <unknown return type>"
+
+       #LANG           #PRINT          #WHATIS         #PTYPE
+       foreach lang_line {
+           {"ada"              $c_print_re     $c_whatis_re    $ada_ptype_re}
+           {"asm"              $c_print_re     $c_whatis_re    $c_ptype_re}
+           {"c"                $c_print_re     $c_whatis_re    $c_ptype_re}
+           {"c++"              $c_print_re     $c_whatis_re    $cxx_ptype_re}
+           {"d"                $c_print_re     $c_whatis_re    $c_ptype_re}
+           {"fortran"  $c_print_re     $c_whatis_re    $c_ptype_re}
+           {"go"               $c_print_re     $c_whatis_re    $c_ptype_re}
+           {"minimal"  $c_print_re     $c_whatis_re    $c_ptype_re}
+           {"modula-2" $m2_print_re    $m2_whatis_re   $m2_ptype_re}
+           {"objective-c"      $c_print_re     $c_whatis_re    $c_ptype_re}
+           {"opencl"   $c_print_re     $c_whatis_re    $c_ptype_re}
+           {"pascal"   $c_print_re     $c_whatis_re    $pascal_ptype_re}
+           {"rust"             $rust_nosym     $rust_nosym     $rust_nosym}
+       } {
+           set lang [lindex $lang_line 0]
+           set print_re [lindex $lang_line 1]
+           set whatis_re [lindex $lang_line 2]
+           set ptype_re [lindex $lang_line 3]
+
+           set print_re [subst "$print_re"]
+           set whatis_re [subst "$whatis_re"]
+           set ptype_re [subst "$ptype_re"]
+
+           with_test_prefix "$lang" {
+               gdb_test_no_output "set language $lang"
+               gdb_test "p top" $print_re
+               gdb_test "whatis top" $whatis_re
+               gdb_test "ptype top" $ptype_re
+           }
+       }
+    }
+
+    gdb_test_no_output "set language auto"
+
+    # We can't rely on uintXX_t being available/known to GDB because
+    # we may or may not have debug info for those (depending on
+    # whether we have debug info for the C runtime, for example).
+    gdb_test_no_output "macro define uint8 unsigned char"
+
     gdb_test "p dataglobal" "= 3"
     gdb_test "whatis dataglobal" \
        "<(data variable|variable), no debug info>|int"
@@ -122,17 +204,27 @@ if [runto inner] then {
     
     # This test is not as obscure as it might look.  `p getenv ("TERM")'
     # is a real-world example, at least on many systems.
+
+    gdb_test {p/c array_index("abcdef",2)} \
+       "'array_index' has unknown return type; cast the call to its declared return type"
+    gdb_test {ptype array_index("abcdef",2)} \
+       "function has unknown return type; cast the call to its declared return type"
+    gdb_test {whatis array_index("abcdef",2)} \
+       "function has unknown return type; cast the call to its declared return type"
+
     if [target_info exists gdb,cannot_call_functions] {
-       unsupported "p/c array_index(\"abcdef\",2)"
+       unsupported "p/c (int) array_index(\"abcdef\",2)"
     } else {
        # We need to up this because this can be really slow on some boards.
        # (malloc() is called as part of the test).
        set prev_timeout $timeout
        set timeout 60
-       gdb_test {p/c array_index("abcdef",2)} " = 99 'c'"
+       gdb_test {p/c (int) array_index("abcdef",2)} " = 99 'c'"
        set timeout $prev_timeout
     }
-    
+
+    test_call_promotion
+
     # Now, try that we can give names of file-local symbols which happen
     # to be unique, and have it still work
     if [runto middle] then {
index b2218704cb40fa599d76a68f88b769560d9c5c2d..c23ff6aabd507114ba1a86aeb07ee8632661d952 100644 (file)
@@ -296,12 +296,14 @@ gdb_test "p globalvar" " = 77" "expect 77"
 
 # Test reference to minimal_symbol, not (full) symbol.
 
-gdb_test_no_output "compile code globalvar = func_nodebug (75);" \
+gdb_test "compile code globalvar = func_nodebug (75);" \
+    "warning: function has unknown return type; assuming int" \
     "call func_nodebug"
 gdb_test "p globalvar" " = -75" "expect -75"
-gdb_test_no_output \
-  "compile code int (*funcp) (int) = func_nodebug; globalvar = funcp (76);" \
-  "call func_nodebug indirectly"
+gdb_test \
+    "compile code int (*funcp) (int) = func_nodebug; globalvar = funcp (76);" \
+    "warning: function has unknown return type; assuming int" \
+    "call func_nodebug indirectly"
 gdb_test "p globalvar" " = -76" "expect -76"
 
 
index 328168c8eb3970b7ca8d5cd95d95438cb9519154..8ee4c36644cf50badb214af6b1f3bdd45ca1f6fe 100644 (file)
@@ -40,12 +40,17 @@ gdb_test "handle SIGUSR2 stop print pass" \
 gdb_breakpoint [gdb_get_line_number "break-at-exit"]
 
 set test "get pid"
-gdb_test_multiple "p getpid ()" $test {
+set pid ""
+gdb_test_multiple "p (int) getpid ()" $test {
     -re " = (\[0-9\]+)\r\n$gdb_prompt $" {
        set pid $expect_out(1,string)
        pass $test
     }
 }
+if {$pid == ""} {
+    untested "failed to get pid"
+    return
+}
 
 for {set sigcount 0} {$sigcount < 4} {incr sigcount} {
     set test "catch signal $sigcount"
index 045271a8074883d00c86da26b135569b713c3d13..8e58bf9b5f80def8901ee8b2f9a1202708c90604 100644 (file)
@@ -386,6 +386,14 @@ type_to_string (struct type *type)
   return {};
 }
 
+/* See typeprint.h.  */
+
+void
+type_print_unknown_return_type (struct ui_file *stream)
+{
+  fprintf_filtered (stream, _("<unknown return type>"));
+}
+
 /* Print type of EXP, or last thing in value history if EXP == NULL.
    show is passed to type_print.  */
 
@@ -757,4 +765,3 @@ val_print_not_associated (struct ui_file *stream)
 {
   fprintf_filtered (stream, _("<not associated>"));
 }
-
index 72da7f485b9f1012da5f4227cabbf288a4e47fe0..d4e19e5b881dd0d37d6f69d5d66fb96e4560b78f 100644 (file)
@@ -74,6 +74,10 @@ void c_type_print_varspec_suffix (struct type *, struct ui_file *, int,
 void c_type_print_args (struct type *, struct ui_file *, int, enum language,
                        const struct type_print_options *);
 
+/* Print <unknown return type> to stream STREAM.  */
+
+void type_print_unknown_return_type (struct ui_file *stream);
+
 extern void val_print_not_allocated (struct ui_file *stream);
 
 extern void val_print_not_associated (struct ui_file *stream);
index 9724acace78b1f84e0f70c540893d190f7193c00..bcc5ff6c0a950c6cf3f0ee2b459dec5263efd07d 100644 (file)
@@ -505,7 +505,7 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
            = TYPE_TARGET_TYPE (check_typedef (value_type (argvec[0])));
          return value_zero (return_type, VALUE_LVAL (arg1));
        }
-      return call_function_by_hand (argvec[0], 2 - static_memfuncp,
+      return call_function_by_hand (argvec[0], NULL, 2 - static_memfuncp,
                                    argvec + 1);
     }
   throw_error (NOT_FOUND_ERROR,
@@ -624,7 +624,7 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
            = TYPE_TARGET_TYPE (check_typedef (value_type (argvec[0])));
          return value_zero (return_type, VALUE_LVAL (arg1));
        }
-      return call_function_by_hand (argvec[0], nargs, argvec + 1);
+      return call_function_by_hand (argvec[0], NULL, nargs, argvec + 1);
     }
   throw_error (NOT_FOUND_ERROR,
                _("member function %s not found"), tstr);
index c1bb93776ad645b2350e505d8354ce7a2c0d7cac..f5e3aabbf8f70f8c170efdf82ea1d443385abb99 100644 (file)
@@ -192,7 +192,7 @@ value_allocate_space_in_inferior (int len)
   struct value *blocklen;
 
   blocklen = value_from_longest (builtin_type (gdbarch)->builtin_int, len);
-  val = call_function_by_hand (val, 1, &blocklen);
+  val = call_function_by_hand (val, NULL, 1, &blocklen);
   if (value_logical_not (val))
     {
       if (!target_has_execution)