+2018-04-26 Pedro Alves <palves@redhat.com>
+
+ * blockframe.c (find_gnu_ifunc_target_type): New function.
+ (find_function_type): New.
+ * eval.c (evaluate_var_msym_value): For GNU ifunc types, always
+ return a value with a memory address.
+ (eval_call): For calls to GNU ifunc functions, try to find the
+ type of the target function from the type that the resolver
+ returns.
+ * gdbtypes.c (objfile_type): Don't install a return type for ifunc
+ symbols.
+ * infcall.c (find_function_return_type): Delete.
+ (find_function_addr): Add 'function_type' parameter. For calls to
+ GNU ifunc functions, try to find the type of the target function
+ from the type that the resolver returns, and return it via
+ FUNCTION_TYPE.
+ (call_function_by_hand_dummy): Adjust to use the function type
+ returned by find_function_addr.
+ (find_function_addr): Add 'function_type' parameter and move
+ description here.
+ * symtab.h (find_function_type, find_gnu_ifunc_target_type): New
+ declarations.
+
2018-04-26 Pedro Alves <palves@redhat.com>
* c-exp.y (variable production): Skip finding an alias for ifunc
return find_pc_partial_function_gnu_ifunc (pc, name, address, endaddr, NULL);
}
+/* See symtab.h. */
+
+struct type *
+find_function_type (CORE_ADDR pc)
+{
+ struct symbol *sym = find_pc_function (pc);
+
+ if (sym != NULL && BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) == pc)
+ return SYMBOL_TYPE (sym);
+
+ return NULL;
+}
+
+/* See symtab.h. */
+
+struct type *
+find_gnu_ifunc_target_type (CORE_ADDR resolver_funaddr)
+{
+ struct type *resolver_type = find_function_type (resolver_funaddr);
+ if (resolver_type != NULL)
+ {
+ /* Get the return type of the resolver. */
+ struct type *resolver_ret_type
+ = check_typedef (TYPE_TARGET_TYPE (resolver_type));
+
+ /* If we found a pointer to function, then the resolved type
+ is the type of the pointed-to function. */
+ if (TYPE_CODE (resolver_ret_type) == TYPE_CODE_PTR)
+ {
+ struct type *resolved_type
+ = TYPE_TARGET_TYPE (resolver_ret_type);
+ if (TYPE_CODE (check_typedef (resolved_type)) == TYPE_CODE_FUNC)
+ return resolved_type;
+ }
+ }
+
+ return NULL;
+}
+
/* Return the innermost stack frame that is executing inside of BLOCK and is
at least as old as the selected frame. Return NULL if there is no
such frame. If BLOCK is NULL, just return NULL. */
evaluate_var_msym_value (enum noside noside,
struct objfile *objfile, minimal_symbol *msymbol)
{
- if (noside == EVAL_AVOID_SIDE_EFFECTS)
- {
- type *the_type = find_minsym_type_and_address (msymbol, objfile, NULL);
- return value_zero (the_type, not_lval);
- }
+ CORE_ADDR address;
+ type *the_type = find_minsym_type_and_address (msymbol, objfile, &address);
+
+ if (noside == EVAL_AVOID_SIDE_EFFECTS && !TYPE_GNU_IFUNC (the_type))
+ return value_zero (the_type, not_lval);
else
- {
- CORE_ADDR address;
- type *the_type = find_minsym_type_and_address (msymbol, objfile, &address);
- return value_at_lazy (the_type, address);
- }
+ return value_at_lazy (the_type, address);
}
/* Helper for returning a value when handling EVAL_SKIP. */
else if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
|| TYPE_CODE (ftype) == TYPE_CODE_METHOD)
{
+ if (TYPE_GNU_IFUNC (ftype))
+ {
+ CORE_ADDR address = value_address (argvec[0]);
+ type *resolved_type = find_gnu_ifunc_target_type (address);
+
+ if (resolved_type != NULL)
+ ftype = resolved_type;
+ }
+
type *return_type = TYPE_TARGET_TYPE (ftype);
if (return_type == NULL)
objfile_type->nodebug_text_gnu_ifunc_symbol
= init_type (objfile, TYPE_CODE_FUNC, TARGET_CHAR_BIT,
"<text gnu-indirect-function variable, no debug info>");
- /* Ifunc resolvers return a function address. */
- TYPE_TARGET_TYPE (objfile_type->nodebug_text_gnu_ifunc_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),
return value_cast (type, arg);
}
-/* Return the return type of a function with its first instruction exactly at
- the PC address. Return NULL otherwise. */
-
-static struct type *
-find_function_return_type (CORE_ADDR pc)
-{
- struct symbol *sym = find_pc_function (pc);
-
- if (sym != NULL && BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) == pc
- && SYMBOL_TYPE (sym) != NULL)
- return TYPE_TARGET_TYPE (SYMBOL_TYPE (sym));
-
- return NULL;
-}
-
-/* Determine a function's address and its return type from its value.
- Calls error() if the function is not valid for calling. */
+/* See infcall.h. */
CORE_ADDR
-find_function_addr (struct value *function, struct type **retval_type)
+find_function_addr (struct value *function,
+ struct type **retval_type,
+ struct type **function_type)
{
struct type *ftype = check_typedef (value_type (function));
struct gdbarch *gdbarch = get_type_arch (ftype);
if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
|| TYPE_CODE (ftype) == TYPE_CODE_METHOD)
{
- value_type = TYPE_TARGET_TYPE (ftype);
-
if (TYPE_GNU_IFUNC (ftype))
{
- funaddr = gnu_ifunc_resolve_addr (gdbarch, funaddr);
+ CORE_ADDR resolver_addr = funaddr;
- /* Skip querying the function symbol if no RETVAL_TYPE has been
- asked for. */
- if (retval_type)
- value_type = find_function_return_type (funaddr);
+ /* Resolve the ifunc. Note this may call the resolver
+ function in the inferior. */
+ funaddr = gnu_ifunc_resolve_addr (gdbarch, resolver_addr);
+
+ /* Skip querying the function symbol if no RETVAL_TYPE or
+ FUNCTION_TYPE have been asked for. */
+ if (retval_type != NULL || function_type != NULL)
+ {
+ type *target_ftype = find_function_type (funaddr);
+ /* If we don't have debug info for the target function,
+ see if we can instead extract the target function's
+ type from the type that the resolver returns. */
+ if (target_ftype == NULL)
+ target_ftype = find_gnu_ifunc_target_type (resolver_addr);
+ if (target_ftype != NULL)
+ {
+ value_type = TYPE_TARGET_TYPE (check_typedef (target_ftype));
+ ftype = target_ftype;
+ }
+ }
}
+ else
+ value_type = TYPE_TARGET_TYPE (ftype);
}
else if (TYPE_CODE (ftype) == TYPE_CODE_INT)
{
if (retval_type != NULL)
*retval_type = value_type;
+ if (function_type != NULL)
+ *function_type = ftype;
return funaddr + gdbarch_deprecated_function_start_offset (gdbarch);
}
void *dummy_dtor_data)
{
CORE_ADDR sp;
- struct type *values_type, *target_values_type;
+ struct type *target_values_type;
unsigned char struct_return = 0, hidden_first_param_p = 0;
CORE_ADDR struct_addr = 0;
struct infcall_control_state *inf_status;
struct cleanup *inf_status_cleanup;
struct infcall_suspend_state *caller_state;
- CORE_ADDR funaddr;
CORE_ADDR real_pc;
- struct type *ftype = check_typedef (value_type (function));
CORE_ADDR bp_addr;
struct frame_id dummy_id;
struct frame_info *frame;
char name_buf[RAW_FUNCTION_ADDRESS_SIZE];
bool stack_temporaries = thread_stack_temporaries_enabled_p (inferior_ptid);
- if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
- ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
-
if (!target_has_execution)
noprocess ();
}
}
- funaddr = find_function_addr (function, &values_type);
+ type *ftype;
+ type *values_type;
+ CORE_ADDR funaddr = find_function_addr (function, &values_type, &ftype);
+
if (values_type == NULL)
values_type = default_return_type;
if (values_type == NULL)
struct value;
struct type;
+/* Determine a function's address and its return type from its value.
+ If the function is a GNU ifunc, then return the address of the
+ target function, and set *FUNCTION_TYPE to the target function's
+ type, and *RETVAL_TYPE to the target function's return type.
+ Calls error() if the function is not valid for calling. */
+
extern CORE_ADDR find_function_addr (struct value *function,
- struct type **retval_type);
+ struct type **retval_type,
+ struct type **function_type = NULL);
/* Perform a function call in the inferior.
extern int find_pc_partial_function (CORE_ADDR, const char **, CORE_ADDR *,
CORE_ADDR *);
+/* Return the type of a function with its first instruction exactly at
+ the PC address. Return NULL otherwise. */
+
+extern struct type *find_function_type (CORE_ADDR pc);
+
+/* See if we can figure out the function's actual type from the type
+ that the resolver returns. RESOLVER_FUNADDR is the address of the
+ ifunc resolver. */
+
+extern struct type *find_gnu_ifunc_target_type (CORE_ADDR resolver_funaddr);
+
extern void clear_pc_function_cache (void);
/* Expand symtab containing PC, SECTION if not already expanded. */
+2018-04-26 Pedro Alves <palves@redhat.com>
+
+ * gdb.compile/compile-ifunc.exp: Also expect "function has unknown
+ return type" warnings.
+
2018-04-25 Pedro Alves <palves@redhat.com>
* gdb.base/hook-stop.exp: Expect "killed" instead of "has been
}
gdb_test "compile code resultvar = gnu_ifunc (10);" \
- "warning: variable has unknown type; assuming int"
+ [multi_line \
+ "warning: variable has unknown type; assuming int" \
+ "warning: function has unknown return type; assuming int"]
gdb_test "p (int) resultvar" " = 11"
if ![runto_main] {
return -1
}
-
# gnu_ifunc (10): error: too many arguments to function 'gnu_ifunc'
- gdb_test_no_output "compile code resultvar = gnu_ifunc_alias (10);"
-
+ gdb_test "compile code resultvar = gnu_ifunc_alias (10);" \
+ "warning: function has unknown return type; assuming int"
gdb_test "p resultvar" " = 11"
}