+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
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
{
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");
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);
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);
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;
#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
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));
++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)
target_auxv_search (¤t_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,
¤t_target);
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."));
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. */
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;
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]);
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"));
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. */
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 -> ( ");
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;
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),
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);
}
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
/* 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
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)
}
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);
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
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
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
{
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]);
}
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;
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. */
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."),
/* 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, "
{
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);
}
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);
}
}
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));
}
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 *
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)
{
(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"));
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)
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 ");
}
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 ");
}
}
}
+/* 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. */
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:
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:
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)
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;
}
+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
# 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"
}
# Call something to ensure that relocation occurred
- gdb_test "call foo(23)" "\\\$.* = 31.*\\\M.*"
+ gdb_test "call (int) foo(23)" "\\\$.* = 31.*\\\M.*"
}
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.
# 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
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"
}
# 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"
#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 */
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;
+}
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.
# 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"
# 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 {
# 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"
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"
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. */
{
fprintf_filtered (stream, _("<not associated>"));
}
-
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);
= 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,
= 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);
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)