gdb/gdb-bz539590-gnu-ifunc.patch
Jan Kratochvil 79563d6f81 - Upgrade to the FSF GDB snapshot: 7.0.50.20100121
- archer-jankratochvil-fedora13 commit:
    ccde1530479cc966374351038057b9dda90aa251
- [expr-cumulative] Archer branch is now included.
2010-01-21 16:09:11 +00:00

1046 lines
37 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

http://sourceware.org/gdb/wiki/ProjectArcher
http://sourceware.org/gdb/wiki/ArcherBranchManagement
GIT snapshot:
commit 791165df07fd22d381def1318954c389a606f81a
archer-jankratochvil-ifunc
Index: gdb-7.0.50.20100121/gdb/alpha-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/alpha-linux-tdep.c 2010-01-01 08:31:29.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/alpha-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -26,6 +26,7 @@
#include "symtab.h"
#include "regset.h"
#include "regcache.h"
+#include "linux-tdep.h"
#include "alpha-tdep.h"
@@ -236,6 +237,9 @@ alpha_linux_init_abi (struct gdbarch_inf
set_gdbarch_regset_from_core_section
(gdbarch, alpha_linux_regset_from_core_section);
+
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ linux_convert_from_func_ptr_addr);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
Index: gdb-7.0.50.20100121/gdb/amd64-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/amd64-linux-tdep.c 2010-01-21 15:13:26.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/amd64-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -1557,6 +1557,9 @@ amd64_linux_init_abi (struct gdbarch_inf
amd64_linux_record_tdep.arg6 = AMD64_R9_REGNUM;
tdep->i386_syscall_record = amd64_linux_syscall_record;
+
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ linux_convert_from_func_ptr_addr);
}
Index: gdb-7.0.50.20100121/gdb/arm-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/arm-linux-tdep.c 2010-01-01 08:31:29.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/arm-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -907,6 +907,9 @@ arm_linux_init_abi (struct gdbarch_info
set_gdbarch_displaced_step_free_closure (gdbarch,
simple_displaced_step_free_closure);
set_gdbarch_displaced_step_location (gdbarch, displaced_step_at_entry_point);
+
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ linux_convert_from_func_ptr_addr);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
Index: gdb-7.0.50.20100121/gdb/elfread.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/elfread.c 2010-01-21 15:13:27.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/elfread.c 2010-01-21 15:15:41.000000000 +0100
@@ -184,7 +184,8 @@ record_minimal_symbol (const char *name,
{
struct gdbarch *gdbarch = get_objfile_arch (objfile);
- if (ms_type == mst_text || ms_type == mst_file_text)
+ if (ms_type == mst_text || ms_type == mst_file_text
+ || ms_type == mst_text_gnu_ifunc)
address = gdbarch_smash_text_address (gdbarch, address);
return prim_record_minimal_symbol_full (name, name_len, copy_name, address,
@@ -393,7 +394,10 @@ elf_symtab_read (struct objfile *objfile
{
if (sym->flags & (BSF_GLOBAL | BSF_WEAK))
{
- ms_type = mst_text;
+ if (sym->flags & BSF_GNU_INDIRECT_FUNCTION)
+ ms_type = mst_text_gnu_ifunc;
+ else
+ ms_type = mst_text;
}
else if ((sym->name[0] == '.' && sym->name[1] == 'L')
|| ((sym->flags & BSF_LOCAL)
Index: gdb-7.0.50.20100121/gdb/frv-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/frv-linux-tdep.c 2010-01-01 08:31:32.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/frv-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -32,6 +32,7 @@
#include "frame-unwind.h"
#include "regset.h"
#include "gdb_string.h"
+#include "linux-tdep.h"
/* Define the size (in bytes) of an FR-V instruction. */
static const int frv_instr_size = 4;
@@ -486,7 +487,21 @@ frv_linux_regset_from_core_section (stru
return NULL;
}
-
+static CORE_ADDR
+frv_linux_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
+ CORE_ADDR addr,
+ struct target_ops *targ)
+{
+ CORE_ADDR pc = frv_convert_from_func_ptr_addr (gdbarch, addr, targ);
+ CORE_ADDR resolved;
+
+ resolved = linux_convert_from_func_and_ptr (gdbarch, addr, pc);
+ if (resolved != pc)
+ pc = frv_convert_from_func_ptr_addr (gdbarch, resolved, targ);
+
+ return pc;
+}
+
static void
frv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
@@ -494,6 +509,10 @@ frv_linux_init_abi (struct gdbarch_info
frame_unwind_append_unwinder (gdbarch, &frv_linux_sigtramp_frame_unwind);
set_gdbarch_regset_from_core_section (gdbarch,
frv_linux_regset_from_core_section);
+
+ if (frv_abi (gdbarch) == FRV_ABI_FDPIC)
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ frv_linux_convert_from_func_ptr_addr);
}
static enum gdb_osabi
Index: gdb-7.0.50.20100121/gdb/frv-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/frv-tdep.c 2010-01-01 08:31:32.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/frv-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -1169,7 +1169,7 @@ find_func_descr (struct gdbarch *gdbarch
return descr;
}
-static CORE_ADDR
+CORE_ADDR
frv_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr,
struct target_ops *targ)
{
Index: gdb-7.0.50.20100121/gdb/frv-tdep.h
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/frv-tdep.h 2010-01-01 08:31:32.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/frv-tdep.h 2010-01-21 15:15:41.000000000 +0100
@@ -118,3 +118,6 @@ CORE_ADDR frv_fetch_objfile_link_map (st
struct target_so_ops;
extern struct target_so_ops frv_so_ops;
+CORE_ADDR frv_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
+ CORE_ADDR addr,
+ struct target_ops *targ);
Index: gdb-7.0.50.20100121/gdb/gdbtypes.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/gdbtypes.c 2010-01-21 15:13:26.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/gdbtypes.c 2010-01-21 15:15:41.000000000 +0100
@@ -1946,6 +1946,8 @@ init_type (enum type_code code, int leng
TYPE_NOTTEXT (type) = 1;
if (flags & TYPE_FLAG_FIXED_INSTANCE)
TYPE_FIXED_INSTANCE (type) = 1;
+ if (flags & TYPE_FLAG_GNU_IFUNC)
+ TYPE_GNU_IFUNC (type) = 1;
if (name)
TYPE_NAME (type) = obsavestring (name, strlen (name),
@@ -3955,6 +3957,8 @@ gdbtypes_post_init (struct gdbarch *gdba
= lookup_pointer_type (builtin_type->builtin_void);
builtin_type->builtin_func_ptr
= lookup_pointer_type (lookup_function_type (builtin_type->builtin_void));
+ builtin_type->builtin_func_func
+ = lookup_function_type (builtin_type->builtin_func_ptr);
/* This type represents a GDB internal function. */
builtin_type->internal_fn
@@ -4071,6 +4075,11 @@ objfile_type (struct objfile *objfile)
"<text variable, no debug info>", objfile);
TYPE_TARGET_TYPE (objfile_type->nodebug_text_symbol)
= objfile_type->builtin_int;
+ objfile_type->nodebug_text_gnu_ifunc_symbol
+ = init_type (TYPE_CODE_FUNC, 1, TYPE_FLAG_GNU_IFUNC,
+ "<text gnu-ifunc variable, no debug info>", objfile);
+ TYPE_TARGET_TYPE (objfile_type->nodebug_text_gnu_ifunc_symbol)
+ = objfile_type->nodebug_text_symbol;
objfile_type->nodebug_data_symbol
= init_type (TYPE_CODE_INT,
gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT, 0,
Index: gdb-7.0.50.20100121/gdb/gdbtypes.h
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/gdbtypes.h 2010-01-21 15:14:41.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/gdbtypes.h 2010-01-21 15:16:39.000000000 +0100
@@ -188,6 +188,7 @@ enum type_flag_value
TYPE_FLAG_FIXED_INSTANCE = (1 << 15),
TYPE_FLAG_STUB_SUPPORTED = (1 << 16),
TYPE_FLAG_NOTTEXT = (1 << 17),
+ TYPE_FLAG_GNU_IFUNC = (1 << 18),
/* Used for error-checking. */
TYPE_FLAG_MIN = TYPE_FLAG_UNSIGNED
@@ -293,6 +294,12 @@ enum type_instance_flag_value
#define TYPE_NOTTEXT(t) (TYPE_MAIN_TYPE (t)->flag_nottext)
+/* Currently used only for TYPE_CODE_FUNC where specifies the real function
+ address is returned by this function call. TYPE_TARGET_TYPE determines the
+ final returned function type to be presented to user. */
+
+#define TYPE_GNU_IFUNC(t) (TYPE_MAIN_TYPE (t)->flag_gnu_ifunc)
+
/* Type owner. If TYPE_OBJFILE_OWNED is true, the type is owned by
the objfile retrieved as TYPE_OBJFILE. Otherweise, the type is
owned by an architecture; TYPE_OBJFILE is NULL in this case. */
@@ -447,6 +454,7 @@ struct main_type
unsigned int flag_vector : 1;
unsigned int flag_stub_supported : 1;
unsigned int flag_nottext : 1;
+ unsigned int flag_gnu_ifunc : 1;
unsigned int flag_fixed_instance : 1;
unsigned int flag_objfile_owned : 1;
unsigned int flag_discardable : 1;
@@ -1243,6 +1251,10 @@ struct builtin_type
(*) () can server as a generic function pointer. */
struct type *builtin_func_ptr;
+ /* `function returning pointer to function (returning void)' type.
+ The final void return type is not significant for it. */
+ struct type *builtin_func_func;
+
/* Special-purpose types. */
@@ -1285,6 +1297,7 @@ struct objfile_type
/* Types used for symbols with no debug information. */
struct type *nodebug_text_symbol;
+ struct type *nodebug_text_gnu_ifunc_symbol;
struct type *nodebug_data_symbol;
struct type *nodebug_unknown_symbol;
struct type *nodebug_tls_symbol;
Index: gdb-7.0.50.20100121/gdb/hppa-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/hppa-linux-tdep.c 2010-01-01 08:31:33.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/hppa-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -32,6 +32,7 @@
#include "regset.h"
#include "regcache.h"
#include "hppa-tdep.h"
+#include "linux-tdep.h"
#include "elf/common.h"
@@ -513,7 +514,21 @@ hppa_linux_regset_from_core_section (str
return NULL;
}
-
+
+static CORE_ADDR
+hppa32_linux_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
+ CORE_ADDR addr,
+ struct target_ops *targ)
+{
+ CORE_ADDR pc = hppa32_convert_from_func_ptr_addr (gdbarch, addr, targ);
+ CORE_ADDR resolved;
+
+ resolved = linux_convert_from_func_and_ptr (gdbarch, addr, pc);
+ if (resolved != pc)
+ pc = hppa32_convert_from_func_ptr_addr (gdbarch, resolved, targ);
+
+ return pc;
+}
/* Forward declarations. */
extern initialize_file_ftype _initialize_hppa_linux_tdep;
@@ -555,6 +570,10 @@ hppa_linux_init_abi (struct gdbarch_info
/* Enable TLS support. */
set_gdbarch_fetch_tls_load_module_address (gdbarch,
svr4_fetch_objfile_link_map);
+
+ if (tdep->bytes_per_address == 4)
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ hppa32_linux_convert_from_func_ptr_addr);
}
void
Index: gdb-7.0.50.20100121/gdb/hppa-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/hppa-tdep.c 2010-01-19 10:39:12.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/hppa-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -1247,7 +1247,7 @@ hppa64_return_value (struct gdbarch *gdb
}
-static CORE_ADDR
+CORE_ADDR
hppa32_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr,
struct target_ops *targ)
{
Index: gdb-7.0.50.20100121/gdb/hppa-tdep.h
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/hppa-tdep.h 2010-01-01 08:31:33.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/hppa-tdep.h 2010-01-21 15:15:41.000000000 +0100
@@ -246,4 +246,8 @@ extern int hppa_in_solib_call_trampoline
CORE_ADDR pc, char *name);
extern CORE_ADDR hppa_skip_trampoline_code (struct frame_info *, CORE_ADDR pc);
+extern CORE_ADDR hppa32_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
+ CORE_ADDR addr,
+ struct target_ops *targ);
+
#endif /* hppa-tdep.h */
Index: gdb-7.0.50.20100121/gdb/i386-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/i386-linux-tdep.c 2010-01-04 15:57:43.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/i386-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -798,6 +798,9 @@ i386_linux_init_abi (struct gdbarch_info
i386_linux_get_syscall_number);
set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
+
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ linux_convert_from_func_ptr_addr);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
Index: gdb-7.0.50.20100121/gdb/ia64-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/ia64-linux-tdep.c 2010-01-01 08:31:36.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/ia64-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -26,6 +26,7 @@
#include "osabi.h"
#include "solib-svr4.h"
#include "symtab.h"
+#include "linux-tdep.h"
/* The sigtramp code is in a non-readable (executable-only) region
of memory called the ``gate page''. The addresses in question
@@ -139,6 +140,9 @@ ia64_linux_init_abi (struct gdbarch_info
/* Enable TLS support. */
set_gdbarch_fetch_tls_load_module_address (gdbarch,
svr4_fetch_objfile_link_map);
+
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ linux_convert_from_func_ptr_addr);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
Index: gdb-7.0.50.20100121/gdb/infcall.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/infcall.c 2010-01-01 08:31:36.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/infcall.c 2010-01-21 15:15:41.000000000 +0100
@@ -252,9 +252,17 @@ find_function_addr (struct value *functi
if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
|| TYPE_CODE (ftype) == TYPE_CODE_METHOD)
{
- funaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr,
- &current_target);
- value_type = TYPE_TARGET_TYPE (ftype);
+ CORE_ADDR funaddr2;
+
+ funaddr2 = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr,
+ &current_target);
+
+ /* If TYPE_GNU_IFUNC is currently not resolvable keep its type. */
+ if (funaddr2 != funaddr || !TYPE_GNU_IFUNC (ftype))
+ {
+ funaddr = funaddr2;
+ value_type = TYPE_TARGET_TYPE (ftype);
+ }
}
}
else if (code == TYPE_CODE_INT)
Index: gdb-7.0.50.20100121/gdb/linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/linux-tdep.c 2010-01-14 22:20:11.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -23,6 +23,8 @@
#include "auxv.h"
#include "target.h"
#include "elf/common.h"
+#include "value.h"
+#include "infcall.h"
/* This function is suitable for architectures that don't
extend/override the standard siginfo structure. */
@@ -152,3 +154,43 @@ linux_has_shared_address_space (void)
return target_is_uclinux;
}
+
+/* Call gnu-ifunc to resolve breakpoint at its returned function. */
+
+CORE_ADDR
+linux_convert_from_func_and_ptr (struct gdbarch *gdbarch, CORE_ADDR func_ptr,
+ CORE_ADDR pc)
+{
+ struct type *func_func_type = builtin_type (gdbarch)->builtin_func_func;
+ struct minimal_symbol *msymbol;
+ struct value *function, *address;
+
+ if (!target_has_execution)
+ return pc;
+
+ msymbol = lookup_minimal_symbol_by_pc (func_ptr);
+ if (msymbol == NULL)
+ return pc;
+ if (MSYMBOL_TYPE (msymbol) != mst_text_gnu_ifunc)
+ return pc;
+
+ /* Not at the gnu-ifunc entry point? */
+ if (SYMBOL_VALUE_ADDRESS (msymbol) != func_ptr)
+ return pc;
+
+ function = allocate_value (func_func_type);
+ set_value_address (function, pc);
+
+ /* gnu-ifuncs have no arguments. FUNCTION is the code instruction address
+ while ADDRESS is a function descriptor. */
+ address = call_function_by_hand (function, 0, NULL);
+
+ return value_as_address (address);
+}
+
+CORE_ADDR
+linux_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr,
+ struct target_ops *targ)
+{
+ return linux_convert_from_func_and_ptr (gdbarch, addr, addr);
+}
Index: gdb-7.0.50.20100121/gdb/linux-tdep.h
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/linux-tdep.h 2010-01-01 08:31:37.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/linux-tdep.h 2010-01-21 15:15:41.000000000 +0100
@@ -22,4 +22,11 @@
struct type *linux_get_siginfo_type (struct gdbarch *);
+CORE_ADDR linux_convert_from_func_and_ptr (struct gdbarch *gdbarch,
+ CORE_ADDR func_ptr, CORE_ADDR pc);
+
+CORE_ADDR linux_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
+ CORE_ADDR addr,
+ struct target_ops *targ);
+
#endif /* linux-tdep.h */
Index: gdb-7.0.50.20100121/gdb/m32r-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/m32r-linux-tdep.c 2010-01-01 08:31:37.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/m32r-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -30,6 +30,7 @@
#include "gdb_string.h"
#include "glibc-tdep.h"
+#include "linux-tdep.h"
#include "solib-svr4.h"
#include "symtab.h"
@@ -422,6 +423,9 @@ m32r_linux_init_abi (struct gdbarch_info
/* Enable TLS support. */
set_gdbarch_fetch_tls_load_module_address (gdbarch,
svr4_fetch_objfile_link_map);
+
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ linux_convert_from_func_ptr_addr);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
Index: gdb-7.0.50.20100121/gdb/microblaze-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/microblaze-linux-tdep.c 2010-01-01 08:31:37.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/microblaze-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -35,6 +35,7 @@
#include "trad-frame.h"
#include "frame-unwind.h"
#include "tramp-frame.h"
+#include "linux-tdep.h"
static int
@@ -133,6 +134,9 @@ microblaze_linux_init_abi (struct gdbarc
/* Trampolines. */
tramp_frame_prepend_unwinder (gdbarch,
&microblaze_linux_sighandler_tramp_frame);
+
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ linux_convert_from_func_ptr_addr);
}
void
Index: gdb-7.0.50.20100121/gdb/minsyms.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/minsyms.c 2010-01-21 15:13:26.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/minsyms.c 2010-01-21 15:15:41.000000000 +0100
@@ -331,8 +331,9 @@ lookup_minimal_symbol_text (const char *
msymbol = msymbol->hash_next)
{
if (strcmp (SYMBOL_LINKAGE_NAME (msymbol), name) == 0 &&
- (MSYMBOL_TYPE (msymbol) == mst_text ||
- MSYMBOL_TYPE (msymbol) == mst_file_text))
+ (MSYMBOL_TYPE (msymbol) == mst_text
+ || MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc
+ || MSYMBOL_TYPE (msymbol) == mst_file_text))
{
switch (MSYMBOL_TYPE (msymbol))
{
@@ -698,6 +699,16 @@ lookup_minimal_symbol_by_pc (CORE_ADDR p
{
return lookup_minimal_symbol_by_pc_section (pc, NULL);
}
+
+/* Return non-zero iff PC is in function implementing gnu-ifunc selection. */
+
+int
+in_gnu_ifunc_stub (CORE_ADDR pc)
+{
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc);
+
+ return msymbol && MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc;
+}
/* Return leading symbol character for a BFD. If BFD is NULL,
@@ -737,6 +748,7 @@ prim_record_minimal_symbol (const char *
switch (ms_type)
{
case mst_text:
+ case mst_text_gnu_ifunc:
case mst_file_text:
case mst_solib_trampoline:
section = SECT_OFF_TEXT (objfile);
@@ -1202,7 +1214,8 @@ find_solib_trampoline_target (struct fra
{
ALL_MSYMBOLS (objfile, msymbol)
{
- if (MSYMBOL_TYPE (msymbol) == mst_text
+ if ((MSYMBOL_TYPE (msymbol) == mst_text
+ || MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc)
&& strcmp (SYMBOL_LINKAGE_NAME (msymbol),
SYMBOL_LINKAGE_NAME (tsymbol)) == 0)
return SYMBOL_VALUE_ADDRESS (msymbol);
Index: gdb-7.0.50.20100121/gdb/mips-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/mips-linux-tdep.c 2010-01-01 08:31:37.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/mips-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -38,6 +38,7 @@
#include "target-descriptions.h"
#include "mips-linux-tdep.h"
#include "glibc-tdep.h"
+#include "linux-tdep.h"
static struct target_so_ops mips_svr4_so_ops;
@@ -1225,6 +1226,9 @@ mips_linux_init_abi (struct gdbarch_info
tdesc_numbered_register (feature, tdesc_data, MIPS_RESTART_REGNUM,
"restart");
}
+
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ linux_convert_from_func_ptr_addr);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
Index: gdb-7.0.50.20100121/gdb/mn10300-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/mn10300-linux-tdep.c 2010-01-01 08:31:37.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/mn10300-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -32,6 +32,7 @@
#include "frame.h"
#include "trad-frame.h"
#include "tramp-frame.h"
+#include "linux-tdep.h"
#include <stdlib.h>
@@ -718,6 +719,9 @@ am33_linux_init_osabi (struct gdbarch_in
tramp_frame_prepend_unwinder (gdbarch, &am33_linux_sigframe);
tramp_frame_prepend_unwinder (gdbarch, &am33_linux_rt_sigframe);
+
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ linux_convert_from_func_ptr_addr);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
Index: gdb-7.0.50.20100121/gdb/objc-lang.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/objc-lang.c 2010-01-14 09:03:36.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/objc-lang.c 2010-01-21 15:15:41.000000000 +0100
@@ -1178,16 +1178,6 @@ find_methods (struct symtab *symtab, cha
QUIT;
- /* The minimal symbol might point to a function descriptor;
- resolve it to the actual code address instead. */
- pc = gdbarch_convert_from_func_ptr_addr (gdbarch, pc,
- &current_target);
-
- if (symtab)
- if (pc < BLOCK_START (block) || pc >= BLOCK_END (block))
- /* Not in the specified symtab. */
- continue;
-
symname = SYMBOL_NATURAL_NAME (msymbol);
if (symname == NULL)
continue;
@@ -1223,6 +1213,17 @@ find_methods (struct symtab *symtab, cha
((nselector == NULL) || (strcmp (selector, nselector) != 0)))
continue;
+ /* The minimal symbol might point to a function descriptor;
+ resolve it to the actual code address instead. Delay the call as
+ its resolution may be expensive. */
+ pc = gdbarch_convert_from_func_ptr_addr (gdbarch, pc,
+ &current_target);
+
+ if (symtab)
+ if (pc < BLOCK_START (block) || pc >= BLOCK_END (block))
+ /* Not in the specified symtab. */
+ continue;
+
sym = find_pc_function (pc);
if (sym != NULL)
{
Index: gdb-7.0.50.20100121/gdb/parse.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/parse.c 2010-01-21 15:13:26.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/parse.c 2010-01-21 15:16:15.000000000 +0100
@@ -516,6 +516,11 @@ write_exp_msymbol (struct minimal_symbol
write_exp_elt_type (objfile_type (objfile)->nodebug_text_symbol);
break;
+ case mst_text_gnu_ifunc:
+ write_exp_elt_type (objfile_type (objfile)
+ ->nodebug_text_gnu_ifunc_symbol);
+ break;
+
case mst_data:
case mst_file_data:
case mst_bss:
Index: gdb-7.0.50.20100121/gdb/ppc-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/ppc-linux-tdep.c 2010-01-04 15:57:44.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/ppc-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -48,6 +48,7 @@
#include "arch-utils.h"
#include "spu-tdep.h"
#include "xml-syscall.h"
+#include "linux-tdep.h"
#include "features/rs6000/powerpc-32l.c"
#include "features/rs6000/powerpc-altivec32l.c"
@@ -672,8 +673,19 @@ ppc64_linux_convert_from_func_ptr_addr (
res = bfd_get_section_contents (s->bfd, s->the_bfd_section,
&buf, addr - s->addr, 8);
if (res != 0)
- return extract_unsigned_integer (buf, 8, byte_order)
- - bfd_section_vma (s->bfd, s->the_bfd_section) + s->addr;
+ {
+ CORE_ADDR pc, resolved;
+
+ pc = extract_unsigned_integer (buf, 8, byte_order)
+ - bfd_section_vma (s->bfd, s->the_bfd_section) + s->addr;
+
+ resolved = linux_convert_from_func_and_ptr (gdbarch, addr, pc);
+ if (resolved != pc)
+ pc = ppc64_linux_convert_from_func_ptr_addr (gdbarch, resolved,
+ targ);
+
+ return pc;
+ }
}
return addr;
Index: gdb-7.0.50.20100121/gdb/sh-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/sh-linux-tdep.c 2010-01-01 08:31:41.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/sh-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -25,6 +25,7 @@
#include "glibc-tdep.h"
#include "sh-tdep.h"
+#include "linux-tdep.h"
#define REGSx16(base) \
{(base), 0}, \
@@ -89,6 +90,9 @@ sh_linux_init_abi (struct gdbarch_info i
tdep->core_gregmap = (struct sh_corefile_regmap *)gregs_table;
tdep->core_fpregmap = (struct sh_corefile_regmap *)fpregs_table;
}
+
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ linux_convert_from_func_ptr_addr);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
Index: gdb-7.0.50.20100121/gdb/solib-svr4.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/solib-svr4.c 2010-01-21 15:15:22.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/solib-svr4.c 2010-01-21 15:15:41.000000000 +0100
@@ -1257,7 +1257,8 @@ svr4_in_dynsym_resolve_code (CORE_ADDR p
&& pc < info->interp_text_sect_high)
|| (pc >= info->interp_plt_sect_low
&& pc < info->interp_plt_sect_high)
- || in_plt_section (pc, NULL));
+ || in_plt_section (pc, NULL)
+ || in_gnu_ifunc_stub (pc));
}
/* Given an executable's ABFD and target, compute the entry-point
Index: gdb-7.0.50.20100121/gdb/sparc-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/sparc-linux-tdep.c 2010-01-01 08:31:42.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/sparc-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -32,6 +32,7 @@
#include "symtab.h"
#include "trad-frame.h"
#include "tramp-frame.h"
+#include "linux-tdep.h"
#include "sparc-tdep.h"
@@ -279,6 +280,9 @@ sparc32_linux_init_abi (struct gdbarch_i
dwarf2_append_unwinders (gdbarch);
set_gdbarch_write_pc (gdbarch, sparc_linux_write_pc);
+
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ linux_convert_from_func_ptr_addr);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
Index: gdb-7.0.50.20100121/gdb/sparc64-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/sparc64-linux-tdep.c 2010-01-01 08:31:42.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/sparc64-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -31,6 +31,7 @@
#include "symtab.h"
#include "trad-frame.h"
#include "tramp-frame.h"
+#include "linux-tdep.h"
#include "sparc64-tdep.h"
@@ -244,6 +245,9 @@ sparc64_linux_init_abi (struct gdbarch_i
tdep->step_trap = sparc64_linux_step_trap;
set_gdbarch_write_pc (gdbarch, sparc64_linux_write_pc);
+
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ linux_convert_from_func_ptr_addr);
}
Index: gdb-7.0.50.20100121/gdb/symmisc.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/symmisc.c 2010-01-21 15:13:27.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/symmisc.c 2010-01-21 15:15:41.000000000 +0100
@@ -294,6 +294,9 @@ dump_msymbols (struct objfile *objfile,
case mst_text:
ms_type = 'T';
break;
+ case mst_text_gnu_ifunc:
+ ms_type = 'i';
+ break;
case mst_solib_trampoline:
ms_type = 'S';
break;
Index: gdb-7.0.50.20100121/gdb/symtab.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/symtab.c 2010-01-21 15:13:27.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/symtab.c 2010-01-21 15:15:41.000000000 +0100
@@ -3244,7 +3244,7 @@ search_symbols (char *regexp, domain_enu
{mst_file_data, mst_solib_trampoline, mst_abs, mst_unknown};
static enum minimal_symbol_type types4[]
=
- {mst_file_bss, mst_text, mst_abs, mst_unknown};
+ {mst_file_bss, mst_text_gnu_ifunc, mst_abs, mst_unknown};
enum minimal_symbol_type ourtype;
enum minimal_symbol_type ourtype2;
enum minimal_symbol_type ourtype3;
Index: gdb-7.0.50.20100121/gdb/symtab.h
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/symtab.h 2010-01-21 15:11:09.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/symtab.h 2010-01-21 15:15:41.000000000 +0100
@@ -280,6 +280,8 @@ enum minimal_symbol_type
{
mst_unknown = 0, /* Unknown type, the default */
mst_text, /* Generally executable instructions */
+ mst_text_gnu_ifunc, /* Executable code returning address
+ of executable code */
mst_data, /* Generally initialized data */
mst_bss, /* Generally uninitialized data */
mst_abs, /* Generally absolute (nonrelocatable) */
@@ -1157,6 +1159,8 @@ extern struct minimal_symbol *lookup_min
extern struct minimal_symbol *lookup_minimal_symbol_by_pc (CORE_ADDR);
+extern int in_gnu_ifunc_stub (CORE_ADDR pc);
+
extern struct minimal_symbol
*lookup_minimal_symbol_by_pc_section (CORE_ADDR, struct obj_section *);
Index: gdb-7.0.50.20100121/gdb/testsuite/gdb.base/gnu-ifunc-lib.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb-7.0.50.20100121/gdb/testsuite/gdb.base/gnu-ifunc-lib.c 2010-01-21 15:15:41.000000000 +0100
@@ -0,0 +1,54 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+
+typedef int (*final_t) (int arg);
+
+static int
+init_stub (int arg)
+{
+ return 0;
+}
+
+static int
+final (int arg)
+{
+ return arg + 1;
+}
+
+static volatile int gnu_ifunc_initialized;
+
+void
+gnu_ifunc_pre (void)
+{
+ assert (!gnu_ifunc_initialized);
+
+ gnu_ifunc_initialized = 1;
+}
+
+final_t gnu_ifuncX (void) asm ("gnu_ifunc");
+asm (".type gnu_ifunc, @gnu_indirect_function");
+
+final_t
+gnu_ifuncX (void)
+{
+ if (!gnu_ifunc_initialized)
+ return init_stub;
+ else
+ return final;
+}
Index: gdb-7.0.50.20100121/gdb/testsuite/gdb.base/gnu-ifunc.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb-7.0.50.20100121/gdb/testsuite/gdb.base/gnu-ifunc.c 2010-01-21 15:15:41.000000000 +0100
@@ -0,0 +1,36 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+
+extern int gnu_ifunc (int arg);
+extern void gnu_ifunc_pre (void);
+
+int
+main (void)
+{
+ int i;
+
+ gnu_ifunc_pre ();
+
+ i = gnu_ifunc (1); /* break-at-call */
+ assert (i == 2);
+
+ gnu_ifunc (2); /* break-at-nextcall */
+
+ return 0; /* break-at-exit */
+}
Index: gdb-7.0.50.20100121/gdb/testsuite/gdb.base/gnu-ifunc.exp
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb-7.0.50.20100121/gdb/testsuite/gdb.base/gnu-ifunc.exp 2010-01-21 15:15:41.000000000 +0100
@@ -0,0 +1,115 @@
+# Copyright (C) 2009 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+if {[skip_shlib_tests]} {
+ return 0
+}
+
+set testfile "gnu-ifunc"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+set libfile "${testfile}-lib"
+set libsrc ${libfile}.c
+set lib_so ${objdir}/${subdir}/${libfile}.so
+
+set lib_nodebug_so_base ${libfile}-nodebug.so
+set lib_nodebug_so ${objdir}/${subdir}/${lib_nodebug_so_base}
+
+# {debug} provides DWARF symbol gnu_ifuncX confusing the ELF symbol
+# gnu_ifunc during address->symbol resolution for printing the symbol.
+# Still we need it here for "step"ping into the function.
+set lib_opts [list debug]
+set lib_nodebug_opts [list]
+set exec_opts [list debug shlib=$lib_so]
+
+if [get_compiler_info ${binfile}] {
+ return -1
+}
+
+if { [gdb_compile_shlib ${srcdir}/${subdir}/$libsrc $lib_so $lib_opts] != ""
+ || [gdb_compile ${srcdir}/${subdir}/$srcfile $binfile executable $exec_opts] != ""} {
+ untested "Could not compile either $libsrc or $srcfile."
+ return -1
+}
+
+# Start with a fresh gdb.
+
+clean_restart $testfile
+gdb_load_shlibs ${lib_so}
+
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 1;
+}
+
+# The "if" condition is artifical to test regression of a format patch.
+gdb_breakpoint "[gdb_get_line_number "break-at-nextcall"] if i && gnu_ifunc (i) != 42"
+
+gdb_breakpoint [gdb_get_line_number "break-at-call"]
+gdb_continue_to_breakpoint "break-at-call" ".*break-at-call.*"
+
+# Test GDB will automatically indirect the call.
+
+gdb_test "p gnu_ifunc (3)" " = 4"
+
+# Test GDB will skip the gnu_ifunc resolver on first call.
+
+gdb_test "step" "\r\nfinal .*"
+
+# Test GDB will not break before the final chosen implementation.
+
+# Also test a format patch regression:
+# Continuing.
+# Error in testing breakpoint condition:
+# Attempt to take address of value not located in memory.
+#
+# Breakpoint 2, main () at ./gdb.base/gnu-ifunc.c:33
+
+gdb_test "continue" "Continuing.\r\n\r\nBreakpoint .* (at|in) .*break-at-nextcall.*" \
+ "continue to break-at-nextcall"
+
+gdb_breakpoint "gnu_ifunc"
+
+gdb_continue_to_breakpoint "nextcall gnu_ifunc"
+
+gdb_test "frame" "#0 +(0x\[0-9a-f\]+ in +)?final \\(.*" "nextcall gnu_ifunc skipped"
+
+
+# Compare the two different addresses:
+
+gdb_test "p gnu_ifunc" " = {<text variable, no debug info>} 0x\[0-9a-f\]+ <final>" "p gnu_ifunc executing"
+gdb_test "info sym gnu_ifunc" "final in section .*" "info sym gnu_ifunc executing"
+
+set test "info addr gnu_ifunc"
+gdb_test_multiple $test $test {
+ -re "Symbol \"gnu_ifunc\" is at (0x\[0-9a-f\]+) in .*$gdb_prompt $" {
+ pass $test
+ }
+}
+gdb_test "info sym $expect_out(1,string)" "gnu_ifunc in section .*" "info sym <gnu_ifunc-address>"
+
+# <*gnu_ifunc> would be an incorrect resolution from DW_AT_MIPS_linkage_name.
+# We do not use {debug} build option for this purpose.
+
+if { [gdb_compile_shlib ${srcdir}/${subdir}/$libsrc $lib_nodebug_so $lib_nodebug_opts] != ""} {
+ untested "Could not compile either $libsrc."
+ return -1
+}
+
+clean_restart $lib_nodebug_so_base
+
+gdb_test "p gnu_ifunc" " = {<text gnu-ifunc variable, no debug info>} 0x\[0-9a-f\]+ <gnu_ifunc>" "p gnu_ifunc not executing without debug"
+gdb_test "info sym gnu_ifunc" "gnu_ifunc in section .*" "info sym gnu_ifunc not executing without debug"
Index: gdb-7.0.50.20100121/gdb/xtensa-linux-tdep.c
===================================================================
--- gdb-7.0.50.20100121.orig/gdb/xtensa-linux-tdep.c 2010-01-01 08:31:46.000000000 +0100
+++ gdb-7.0.50.20100121/gdb/xtensa-linux-tdep.c 2010-01-21 15:15:41.000000000 +0100
@@ -22,6 +22,7 @@
#include "solib-svr4.h"
#include "symtab.h"
+#include "linux-tdep.h"
/* OS specific initialization of gdbarch. */
@@ -30,6 +31,9 @@ xtensa_linux_init_abi (struct gdbarch_in
{
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
+
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ linux_convert_from_func_ptr_addr);
}
/* Provide a prototype to silence -Wmissing-prototypes. */