[patch 2/7] internal types for STT_GNU_IFUNC

Jan Kratochvil jan.kratochvil@redhat.com
Sat Mar 19 21:16:00 GMT 2011


Hi,

see [patch 5/7] why GDB now needs to track also the GOT entries (.got.plt) for
.plt sections.  Currently minimal symbols for the GOT entries are
user-visible, therefore they also have their specific type.

When GDB already has to track them I find useful to also display them.
5	  puts ("hello");
(gdb) p 'puts@got.plt'
$1 = (<text from jump slot in .got.plt, no debug info>) 0x4003be <puts@plt+6>
(gdb) next
hello
6	  return 0;
(gdb) p 'puts@got.plt'
$2 = (<text from jump slot in .got.plt, no debug info>) 0x7ffff7aa98e0 <_IO_puts>


Thanks,
Jan


gdb/
2011-03-19  Jan Kratochvil  <jan.kratochvil@redhat.com>

	GDB internal type support for STT_GNU_IFUNC.
	* elfread.c (record_minimal_symbol): Support mst_text_gnu_ifunc.
	(elf_symtab_read): Set mst_text_gnu_ifunc for
	BSF_GNU_INDIRECT_FUNCTION.
	* eval.c (evaluate_subexp_standard): Support TYPE_GNU_IFUNC.
	* gdbtypes.c (init_type): Support TYPE_FLAG_GNU_IFUNC,
	builtin_func_func, nodebug_text_gnu_ifunc_symbol and
	nodebug_got_plt_symbol.
	* gdbtypes.h (enum type_flag_value): New entry TYPE_FLAG_GNU_IFUNC.
	(TYPE_GNU_IFUNC): New.
	(struct main_type): New field flag_gnu_ifunc.
	(struct builtin_type): New field builtin_func_func.
	(struct objfile_type): New fields nodebug_text_gnu_ifunc_symbol and
	nodebug_got_plt_symbol.
	* minsyms.c (lookup_minimal_symbol_text): Support mst_text_gnu_ifunc.
	(in_gnu_ifunc_stub): New.
	(prim_record_minimal_symbol, find_solib_trampoline_target): Support
	mst_text_gnu_ifunc.
	* parse.c (write_exp_msymbol): New variable ifunc_msym.  Detect and
	support mst_text_gnu_ifunc.  Support mst_slot_got_plt.
	* solib-svr4.c (svr4_in_dynsym_resolve_code): Return true also for
	in_gnu_ifunc_stub.
	* symmisc.c (dump_msymbols): Support mst_text_gnu_ifunc.
	* symtab.c (search_symbols): Likewise.
	* symtab.h (enum minimal_symbol_type): New fields mst_text_gnu_ifunc
	and mst_slot_got_plt.
	(in_gnu_ifunc_stub): New declaration.

--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -184,7 +184,8 @@ record_minimal_symbol (const char *name, int name_len, int copy_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, int type,
 	    {
 	      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)
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1832,6 +1832,8 @@ evaluate_subexp_standard (struct type *expect_type,
 	      return value_zero (builtin_type (exp->gdbarch)->builtin_int,
 				 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
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -1902,6 +1902,8 @@ init_type (enum type_code code, int length, int flags,
     TYPE_STUB_SUPPORTED (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),
@@ -3772,6 +3774,8 @@ gdbtypes_post_init (struct gdbarch *gdbarch)
     = 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
@@ -3885,6 +3889,18 @@ 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-indirect-function variable, no debug info>",
+		 objfile);
+  TYPE_TARGET_TYPE (objfile_type->nodebug_text_gnu_ifunc_symbol)
+    = objfile_type->nodebug_text_symbol;
+  objfile_type->nodebug_got_plt_symbol
+    = init_type (TYPE_CODE_PTR, gdbarch_addr_bit (gdbarch) / 8, 0,
+		 "<text from jump slot in .got.plt, no debug info>",
+		 objfile);
+  TYPE_TARGET_TYPE (objfile_type->nodebug_got_plt_symbol)
+    = objfile_type->nodebug_text_symbol;
   objfile_type->nodebug_data_symbol
     = init_type (TYPE_CODE_INT,
 		 gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT, 0,
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -170,6 +170,7 @@ enum type_flag_value
   TYPE_FLAG_VECTOR = (1 << 15),
   TYPE_FLAG_FIXED_INSTANCE = (1 << 16),
   TYPE_FLAG_STUB_SUPPORTED = (1 << 17),
+  TYPE_FLAG_GNU_IFUNC = (1 << 18),
 
   /* Used for error-checking.  */
   TYPE_FLAG_MIN = TYPE_FLAG_UNSIGNED
@@ -271,6 +272,12 @@ enum type_instance_flag_value
 
 #define TYPE_NOTTEXT(t)	(TYPE_INSTANCE_FLAGS (t) & TYPE_INSTANCE_FLAG_NOTTEXT)
 
+/* Used only for TYPE_CODE_FUNC where it 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.  */
@@ -387,6 +394,7 @@ struct main_type
   unsigned int flag_varargs : 1;
   unsigned int flag_vector : 1;
   unsigned int flag_stub_supported : 1;
+  unsigned int flag_gnu_ifunc : 1;
   unsigned int flag_fixed_instance : 1;
   unsigned int flag_objfile_owned : 1;
   /* True if this type was declared with "class" rather than
@@ -1178,6 +1186,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.  */
 
@@ -1218,6 +1230,8 @@ 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_got_plt_symbol;
   struct type *nodebug_data_symbol;
   struct type *nodebug_unknown_symbol;
   struct type *nodebug_tls_symbol;
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -333,8 +333,9 @@ lookup_minimal_symbol_text (const char *name, struct objfile *objf)
 	       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))
 		    {
@@ -696,6 +697,16 @@ lookup_minimal_symbol_by_pc (CORE_ADDR pc)
   return lookup_minimal_symbol_by_pc_section (pc, NULL);
 }
 
+/* Return non-zero iff PC is in an STT_GNU_IFUNC function resolver.  */
+
+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;
+}
+
 /* Find the minimal symbol named NAME, and return both the minsym
    struct and its objfile.  This only checks the linkage name.  Sets
    *OBJFILE_P and returns the minimal symbol, if it is found.  If it
@@ -765,6 +776,7 @@ prim_record_minimal_symbol (const char *name, CORE_ADDR address,
   switch (ms_type)
     {
     case mst_text:
+    case mst_text_gnu_ifunc:
     case mst_file_text:
     case mst_solib_trampoline:
       section = SECT_OFF_TEXT (objfile);
@@ -1230,7 +1242,8 @@ find_solib_trampoline_target (struct frame_info *frame, CORE_ADDR pc)
     {
       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);
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -487,9 +487,22 @@ write_exp_msymbol (struct minimal_symbol *msymbol)
   pc = gdbarch_convert_from_func_ptr_addr (gdbarch, addr, &current_target);
   if (pc != addr)
     {
+      struct minimal_symbol *ifunc_msym = lookup_minimal_symbol_by_pc (pc);
+
       /* In this case, assume we have a code symbol instead of
 	 a data symbol.  */
-      type = mst_text;
+
+      if (ifunc_msym != NULL && MSYMBOL_TYPE (ifunc_msym) == mst_text_gnu_ifunc
+	  && SYMBOL_VALUE_ADDRESS (ifunc_msym) == pc)
+	{
+	  /* A function descriptor has been resolved but PC is still in the
+	     STT_GNU_IFUNC resolver body (such as because inferior does not
+	     run to be able to call it).  */
+
+	  type = mst_text_gnu_ifunc;
+	}
+      else
+	type = mst_text;
       section = NULL;
       addr = pc;
     }
@@ -521,6 +534,11 @@ write_exp_msymbol (struct minimal_symbol *msymbol)
       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:
@@ -528,6 +546,10 @@ write_exp_msymbol (struct minimal_symbol *msymbol)
       write_exp_elt_type (objfile_type (objfile)->nodebug_data_symbol);
       break;
 
+    case mst_slot_got_plt:
+      write_exp_elt_type (objfile_type (objfile)->nodebug_got_plt_symbol);
+      break;
+
     default:
       write_exp_elt_type (objfile_type (objfile)->nodebug_unknown_symbol);
       break;
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -1276,7 +1276,8 @@ svr4_in_dynsym_resolve_code (CORE_ADDR pc)
 	   && 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
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -264,6 +264,9 @@ dump_msymbols (struct objfile *objfile, struct ui_file *outfile)
 	case mst_text:
 	  ms_type = 'T';
 	  break;
+	case mst_text_gnu_ifunc:
+	  ms_type = 'i';
+	  break;
 	case mst_solib_trampoline:
 	  ms_type = 'S';
 	  break;
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3006,7 +3006,7 @@ search_symbols (char *regexp, domain_enum kind, int nfiles, char *files[],
   static const enum minimal_symbol_type types3[]
     = {mst_file_data, mst_solib_trampoline, mst_abs, mst_unknown};
   static const 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;
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -290,6 +290,9 @@ 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_slot_got_plt,		/* GOT entries for .plt sections */
   mst_data,			/* Generally initialized data */
   mst_bss,			/* Generally uninitialized data */
   mst_abs,			/* Generally absolute (nonrelocatable) */
@@ -1034,6 +1037,8 @@ extern struct minimal_symbol *lookup_minimal_symbol_by_pc_name
 
 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_and_objfile (const char *,
 				       struct objfile **);



More information about the Gdb-patches mailing list