2 2009-11-24 Jan Kratochvil <jan.kratochvil@redhat.com>
4 Transparent GNU-IFUNCs support.
5 * elfread.c (record_minimal_symbol): Apply also for mst_text_gnu_ifunc.
6 (elf_symtab_read): Set also mst_text_gnu_ifunc.
7 * gdbtypes.c (init_type): Support TYPE_FLAG_GNU_IFUNC.
8 (gdbtypes_post_init): Initialize builtin_func_func_ptr.
9 (objfile_type): Initialize nodebug_text_gnu_ifunc_symbol.
10 * gdbtypes.h (enum type_flag_value <TYPE_FLAG_GNU_IFUNC>)
11 (TYPE_GNU_IFUNC, struct main_type <flag_gnu_ifunc>)
12 (struct builtin_type <builtin_func_func_ptr>)
13 (struct objfile_type <nodebug_text_gnu_ifunc_symbol>): New.
14 * infcall.c (find_function_addr <TYPE_GNU_IFUNC (ftype)>): New.
15 * minsyms.c (lookup_minimal_symbol_text, prim_record_minimal_symbol)
16 (find_solib_trampoline_target): Support also mst_text_gnu_ifunc.
17 (in_gnu_ifunc_stub): New.
18 * parse.c (write_exp_msymbol <mst_text_gnu_ifunc>): New.
19 * solib-svr4.c (svr4_in_dynsym_resolve_code): Call also
21 * symmisc.c (dump_msymbols <mst_text_gnu_ifunc>): New.
22 * symtab.c (search_symbols): Support also mst_text_gnu_ifunc.
23 * symtab.h (enum minimal_symbol_type <mst_text_gnu_ifunc>)
24 (in_gnu_ifunc_stub): New.
25 * linespec.c: Include infcall.h.
26 (minsym_found <MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc>): New.
29 2009-11-24 Jan Kratochvil <jan.kratochvil@redhat.com>
31 Transparent GNU-IFUNCs support.
32 * gdb.base/gnu-ifunc-lib.c, gdb.base/gnu-ifunc.c,
33 gdb.base/gnu-ifunc.exp: New.
35 Index: gdb-7.0/gdb/elfread.c
36 ===================================================================
37 --- gdb-7.0.orig/gdb/elfread.c 2009-11-25 10:24:45.000000000 +0100
38 +++ gdb-7.0/gdb/elfread.c 2009-11-25 10:25:50.000000000 +0100
39 @@ -168,7 +168,8 @@ record_minimal_symbol (char *name, CORE_
41 struct gdbarch *gdbarch = get_objfile_arch (objfile);
43 - if (ms_type == mst_text || ms_type == mst_file_text)
44 + if (ms_type == mst_text || ms_type == mst_file_text
45 + || ms_type == mst_text_gnu_ifunc)
46 address = gdbarch_smash_text_address (gdbarch, address);
48 return prim_record_minimal_symbol_and_info
49 @@ -373,7 +374,10 @@ elf_symtab_read (struct objfile *objfile
51 if (sym->flags & (BSF_GLOBAL | BSF_WEAK))
54 + if (sym->flags & BSF_GNU_INDIRECT_FUNCTION)
55 + ms_type = mst_text_gnu_ifunc;
59 else if ((sym->name[0] == '.' && sym->name[1] == 'L')
60 || ((sym->flags & BSF_LOCAL)
61 Index: gdb-7.0/gdb/gdbtypes.c
62 ===================================================================
63 --- gdb-7.0.orig/gdb/gdbtypes.c 2009-11-25 10:24:47.000000000 +0100
64 +++ gdb-7.0/gdb/gdbtypes.c 2009-11-25 10:24:56.000000000 +0100
65 @@ -1904,6 +1904,8 @@ init_type (enum type_code code, int leng
66 TYPE_NOTTEXT (type) = 1;
67 if (flags & TYPE_FLAG_FIXED_INSTANCE)
68 TYPE_FIXED_INSTANCE (type) = 1;
69 + if (flags & TYPE_FLAG_GNU_IFUNC)
70 + TYPE_GNU_IFUNC (type) = 1;
73 TYPE_NAME (type) = obsavestring (name, strlen (name),
74 @@ -3762,6 +3764,8 @@ gdbtypes_post_init (struct gdbarch *gdba
75 = lookup_pointer_type (builtin_type->builtin_void);
76 builtin_type->builtin_func_ptr
77 = lookup_pointer_type (lookup_function_type (builtin_type->builtin_void));
78 + builtin_type->builtin_func_func_ptr
79 + = lookup_pointer_type (lookup_function_type (builtin_type->builtin_func_ptr));
81 /* This type represents a GDB internal function. */
82 builtin_type->internal_fn
83 @@ -3878,6 +3882,11 @@ objfile_type (struct objfile *objfile)
84 "<text variable, no debug info>", objfile);
85 TYPE_TARGET_TYPE (objfile_type->nodebug_text_symbol)
86 = objfile_type->builtin_int;
87 + objfile_type->nodebug_text_gnu_ifunc_symbol
88 + = init_type (TYPE_CODE_FUNC, 1, TYPE_FLAG_GNU_IFUNC,
89 + "<text gnu-ifunc variable, no debug info>", objfile);
90 + TYPE_TARGET_TYPE (objfile_type->nodebug_text_gnu_ifunc_symbol)
91 + = objfile_type->nodebug_text_symbol;
92 objfile_type->nodebug_data_symbol
93 = init_type (TYPE_CODE_INT,
94 gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT, 0,
95 Index: gdb-7.0/gdb/gdbtypes.h
96 ===================================================================
97 --- gdb-7.0.orig/gdb/gdbtypes.h 2009-11-25 10:24:48.000000000 +0100
98 +++ gdb-7.0/gdb/gdbtypes.h 2009-11-25 10:25:17.000000000 +0100
99 @@ -187,6 +187,7 @@ enum type_flag_value
100 TYPE_FLAG_FIXED_INSTANCE = (1 << 15),
101 TYPE_FLAG_STUB_SUPPORTED = (1 << 16),
102 TYPE_FLAG_NOTTEXT = (1 << 17),
103 + TYPE_FLAG_GNU_IFUNC = (1 << 18),
105 /* Used for error-checking. */
106 TYPE_FLAG_MIN = TYPE_FLAG_UNSIGNED
107 @@ -292,6 +293,12 @@ enum type_instance_flag_value
109 #define TYPE_NOTTEXT(t) (TYPE_MAIN_TYPE (t)->flag_nottext)
111 +/* Currently used only for TYPE_CODE_FUNC where specifies the real function
112 + address is returned by this function call. TYPE_TARGET_TYPE determines the
113 + final returned function type to be presented to user. */
115 +#define TYPE_GNU_IFUNC(t) (TYPE_MAIN_TYPE (t)->flag_gnu_ifunc)
117 /* Type owner. If TYPE_OBJFILE_OWNED is true, the type is owned by
118 the objfile retrieved as TYPE_OBJFILE. Otherweise, the type is
119 owned by an architecture; TYPE_OBJFILE is NULL in this case. */
120 @@ -427,6 +434,7 @@ struct main_type
121 unsigned int flag_vector : 1;
122 unsigned int flag_stub_supported : 1;
123 unsigned int flag_nottext : 1;
124 + unsigned int flag_gnu_ifunc : 1;
125 unsigned int flag_fixed_instance : 1;
126 unsigned int flag_objfile_owned : 1;
127 unsigned int flag_discardable : 1;
128 @@ -1144,6 +1152,10 @@ struct builtin_type
129 (*) () can server as a generic function pointer. */
130 struct type *builtin_func_ptr;
132 + /* `pointer to function returning pointer to function (returning void)' type.
133 + The final void return type is not significant for it. */
134 + struct type *builtin_func_func_ptr;
137 /* Special-purpose types. */
139 @@ -1186,6 +1198,7 @@ struct objfile_type
141 /* Types used for symbols with no debug information. */
142 struct type *nodebug_text_symbol;
143 + struct type *nodebug_text_gnu_ifunc_symbol;
144 struct type *nodebug_data_symbol;
145 struct type *nodebug_unknown_symbol;
146 struct type *nodebug_tls_symbol;
147 Index: gdb-7.0/gdb/infcall.c
148 ===================================================================
149 --- gdb-7.0.orig/gdb/infcall.c 2009-11-25 10:24:45.000000000 +0100
150 +++ gdb-7.0/gdb/infcall.c 2009-11-25 10:24:56.000000000 +0100
151 @@ -286,6 +286,27 @@ find_function_addr (struct value *functi
153 error (_("Invalid data type for function to be called."));
155 + if (TYPE_GNU_IFUNC (ftype))
157 + struct type *func_func_ptr;
159 + funaddr += gdbarch_deprecated_function_start_offset (gdbarch);
161 + /* Cast FUNADDR to drop TYPE_GNU_IFUNC and being able to call gnu-ifunc
162 + FUNADDR without causing deadlock by this block of code. */
164 + func_func_ptr = builtin_type (gdbarch)->builtin_func_func_ptr;
165 + function = value_from_pointer (func_func_ptr, funaddr);
167 + /* gnu-ifuncs have no arguments. */
168 + function = call_function_by_hand (function, 0, NULL);
170 + funaddr = value_as_address (function);
172 + /* This is `int' as the return type of the final function. */
173 + value_type = TYPE_TARGET_TYPE (value_type);
176 if (retval_type != NULL)
177 *retval_type = value_type;
178 return funaddr + gdbarch_deprecated_function_start_offset (gdbarch);
179 Index: gdb-7.0/gdb/linespec.c
180 ===================================================================
181 --- gdb-7.0.orig/gdb/linespec.c 2009-11-25 10:24:45.000000000 +0100
182 +++ gdb-7.0/gdb/linespec.c 2009-11-25 10:24:56.000000000 +0100
185 #include "mi/mi-cmds.h"
187 +#include "infcall.h"
189 /* We share this one with symtab.c, but it is not exported widely. */
191 @@ -1875,6 +1876,22 @@ minsym_found (int funfirstline, struct m
192 pc = gdbarch_convert_from_func_ptr_addr (gdbarch,
196 + /* Call gnu-ifunc to resolve breakpoint at its returned function. */
197 + if (MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc)
199 + struct type *func_func_ptr;
200 + struct value *function;
202 + func_func_ptr = builtin_type (gdbarch)->builtin_func_func_ptr;
203 + function = value_from_pointer (func_func_ptr, pc);
205 + /* gnu-ifuncs have no arguments. */
206 + function = call_function_by_hand (function, 0, NULL);
208 + pc = value_as_address (function);
211 if (pc != values.sals[0].pc)
212 values.sals[0] = find_pc_sect_line (pc, NULL, 0);
214 Index: gdb-7.0/gdb/minsyms.c
215 ===================================================================
216 --- gdb-7.0.orig/gdb/minsyms.c 2009-11-25 10:24:47.000000000 +0100
217 +++ gdb-7.0/gdb/minsyms.c 2009-11-25 10:24:56.000000000 +0100
218 @@ -331,8 +331,9 @@ lookup_minimal_symbol_text (const char *
219 msymbol = msymbol->hash_next)
221 if (strcmp (SYMBOL_LINKAGE_NAME (msymbol), name) == 0 &&
222 - (MSYMBOL_TYPE (msymbol) == mst_text ||
223 - MSYMBOL_TYPE (msymbol) == mst_file_text))
224 + (MSYMBOL_TYPE (msymbol) == mst_text
225 + || MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc
226 + || MSYMBOL_TYPE (msymbol) == mst_file_text))
228 switch (MSYMBOL_TYPE (msymbol))
230 @@ -699,6 +700,16 @@ lookup_minimal_symbol_by_pc (CORE_ADDR p
232 return lookup_minimal_symbol_by_pc_section (pc, NULL);
235 +/* Return non-zero iff PC is in function implementing gnu-ifunc selection. */
238 +in_gnu_ifunc_stub (CORE_ADDR pc)
240 + struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc);
242 + return msymbol && MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc;
246 /* Return leading symbol character for a BFD. If BFD is NULL,
247 @@ -738,6 +749,7 @@ prim_record_minimal_symbol (const char *
251 + case mst_text_gnu_ifunc:
253 case mst_solib_trampoline:
254 section = SECT_OFF_TEXT (objfile);
255 @@ -1184,7 +1196,8 @@ find_solib_trampoline_target (struct fra
257 ALL_MSYMBOLS (objfile, msymbol)
259 - if (MSYMBOL_TYPE (msymbol) == mst_text
260 + if ((MSYMBOL_TYPE (msymbol) == mst_text
261 + || MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc)
262 && strcmp (SYMBOL_LINKAGE_NAME (msymbol),
263 SYMBOL_LINKAGE_NAME (tsymbol)) == 0)
264 return SYMBOL_VALUE_ADDRESS (msymbol);
265 Index: gdb-7.0/gdb/parse.c
266 ===================================================================
267 --- gdb-7.0.orig/gdb/parse.c 2009-11-25 10:24:47.000000000 +0100
268 +++ gdb-7.0/gdb/parse.c 2009-11-25 10:26:16.000000000 +0100
269 @@ -517,6 +517,11 @@ write_exp_msymbol (struct minimal_symbol
270 write_exp_elt_type (objfile_type (objfile)->nodebug_text_symbol);
273 + case mst_text_gnu_ifunc:
274 + write_exp_elt_type (objfile_type (objfile)
275 + ->nodebug_text_gnu_ifunc_symbol);
281 Index: gdb-7.0/gdb/solib-svr4.c
282 ===================================================================
283 --- gdb-7.0.orig/gdb/solib-svr4.c 2009-11-25 10:24:49.000000000 +0100
284 +++ gdb-7.0/gdb/solib-svr4.c 2009-11-25 10:26:41.000000000 +0100
285 @@ -1242,7 +1242,8 @@ svr4_in_dynsym_resolve_code (CORE_ADDR p
287 return ((pc >= interp_text_sect_low && pc < interp_text_sect_high)
288 || (pc >= interp_plt_sect_low && pc < interp_plt_sect_high)
289 - || in_plt_section (pc, NULL));
290 + || in_plt_section (pc, NULL)
291 + || in_gnu_ifunc_stub (pc));
294 /* Given an executable's ABFD and target, compute the entry-point
295 Index: gdb-7.0/gdb/symmisc.c
296 ===================================================================
297 --- gdb-7.0.orig/gdb/symmisc.c 2009-11-25 10:24:47.000000000 +0100
298 +++ gdb-7.0/gdb/symmisc.c 2009-11-25 10:24:56.000000000 +0100
299 @@ -287,6 +287,9 @@ dump_msymbols (struct objfile *objfile,
303 + case mst_text_gnu_ifunc:
306 case mst_solib_trampoline:
309 Index: gdb-7.0/gdb/symtab.c
310 ===================================================================
311 --- gdb-7.0.orig/gdb/symtab.c 2009-11-25 10:24:47.000000000 +0100
312 +++ gdb-7.0/gdb/symtab.c 2009-11-25 10:24:56.000000000 +0100
313 @@ -3155,7 +3155,7 @@ search_symbols (char *regexp, domain_enu
314 {mst_file_data, mst_solib_trampoline, mst_abs, mst_unknown};
315 static enum minimal_symbol_type types4[]
317 - {mst_file_bss, mst_text, mst_abs, mst_unknown};
318 + {mst_file_bss, mst_text_gnu_ifunc, mst_abs, mst_unknown};
319 enum minimal_symbol_type ourtype;
320 enum minimal_symbol_type ourtype2;
321 enum minimal_symbol_type ourtype3;
322 Index: gdb-7.0/gdb/symtab.h
323 ===================================================================
324 --- gdb-7.0.orig/gdb/symtab.h 2009-11-25 10:24:45.000000000 +0100
325 +++ gdb-7.0/gdb/symtab.h 2009-11-25 10:24:56.000000000 +0100
326 @@ -275,6 +275,8 @@ enum minimal_symbol_type
328 mst_unknown = 0, /* Unknown type, the default */
329 mst_text, /* Generally executable instructions */
330 + mst_text_gnu_ifunc, /* Executable code returning address
331 + of executable code */
332 mst_data, /* Generally initialized data */
333 mst_bss, /* Generally uninitialized data */
334 mst_abs, /* Generally absolute (nonrelocatable) */
335 @@ -1149,6 +1151,8 @@ extern struct minimal_symbol *lookup_min
337 extern struct minimal_symbol *lookup_minimal_symbol_by_pc (CORE_ADDR);
339 +extern int in_gnu_ifunc_stub (CORE_ADDR pc);
341 extern struct minimal_symbol
342 *lookup_minimal_symbol_by_pc_section (CORE_ADDR, struct obj_section *);
344 Index: gdb-7.0/gdb/testsuite/gdb.base/gnu-ifunc-lib.c
345 ===================================================================
346 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
347 +++ gdb-7.0/gdb/testsuite/gdb.base/gnu-ifunc-lib.c 2009-11-25 10:24:56.000000000 +0100
349 +/* This testcase is part of GDB, the GNU debugger.
351 + Copyright 2009 Free Software Foundation, Inc.
353 + This program is free software; you can redistribute it and/or modify
354 + it under the terms of the GNU General Public License as published by
355 + the Free Software Foundation; either version 3 of the License, or
356 + (at your option) any later version.
358 + This program is distributed in the hope that it will be useful,
359 + but WITHOUT ANY WARRANTY; without even the implied warranty of
360 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
361 + GNU General Public License for more details.
363 + You should have received a copy of the GNU General Public License
364 + along with this program. If not, see <http://www.gnu.org/licenses/>. */
368 +typedef int (*final_t) (int arg);
376 +static volatile int gnu_ifunc_initialized;
379 +gnu_ifunc_pre (void)
381 + assert (!gnu_ifunc_initialized);
384 +final_t gnu_ifuncX (void) asm ("gnu_ifunc");
385 +asm (".type gnu_ifunc, @gnu_indirect_function");
390 + gnu_ifunc_initialized = 1;
394 Index: gdb-7.0/gdb/testsuite/gdb.base/gnu-ifunc.c
395 ===================================================================
396 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
397 +++ gdb-7.0/gdb/testsuite/gdb.base/gnu-ifunc.c 2009-11-25 10:24:56.000000000 +0100
399 +/* This testcase is part of GDB, the GNU debugger.
401 + Copyright 2009 Free Software Foundation, Inc.
403 + This program is free software; you can redistribute it and/or modify
404 + it under the terms of the GNU General Public License as published by
405 + the Free Software Foundation; either version 3 of the License, or
406 + (at your option) any later version.
408 + This program is distributed in the hope that it will be useful,
409 + but WITHOUT ANY WARRANTY; without even the implied warranty of
410 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
411 + GNU General Public License for more details.
413 + You should have received a copy of the GNU General Public License
414 + along with this program. If not, see <http://www.gnu.org/licenses/>. */
418 +extern int gnu_ifunc (int arg);
419 +extern void gnu_ifunc_pre (void);
428 + i = gnu_ifunc (1); /* break-at-call */
431 + gnu_ifunc (2); /* break-at-nextcall */
433 + return 0; /* break-at-exit */
435 Index: gdb-7.0/gdb/testsuite/gdb.base/gnu-ifunc.exp
436 ===================================================================
437 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
438 +++ gdb-7.0/gdb/testsuite/gdb.base/gnu-ifunc.exp 2009-11-25 10:24:56.000000000 +0100
440 +# Copyright (C) 2009 Free Software Foundation, Inc.
442 +# This program is free software; you can redistribute it and/or modify
443 +# it under the terms of the GNU General Public License as published by
444 +# the Free Software Foundation; either version 3 of the License, or
445 +# (at your option) any later version.
447 +# This program is distributed in the hope that it will be useful,
448 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
449 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
450 +# GNU General Public License for more details.
452 +# You should have received a copy of the GNU General Public License
453 +# along with this program. If not, see <http://www.gnu.org/licenses/>.
455 +if {[skip_shlib_tests]} {
459 +set testfile "gnu-ifunc"
460 +set srcfile ${testfile}.c
461 +set binfile ${objdir}/${subdir}/${testfile}
463 +set libfile "${testfile}-lib"
464 +set libsrc ${libfile}.c
465 +set lib_so ${objdir}/${subdir}/${libfile}.so
467 +set lib_opts [list debug]
468 +set exec_opts [list debug shlib=$lib_so]
470 +if [get_compiler_info ${binfile}] {
474 +if { [gdb_compile_shlib ${srcdir}/${subdir}/$libsrc $lib_so $lib_opts] != ""
475 + || [gdb_compile ${srcdir}/${subdir}/$srcfile $binfile executable $exec_opts] != ""} {
476 + untested "Could not compile either $libsrc or $srcfile."
480 +# Start with a fresh gdb.
482 +clean_restart $testfile
483 +gdb_load_shlibs ${lib_so}
485 +if ![runto_main] then {
486 + fail "Can't run to main"
490 +gdb_breakpoint [gdb_get_line_number "break-at-nextcall"]
492 +gdb_breakpoint [gdb_get_line_number "break-at-call"]
493 +gdb_continue_to_breakpoint "break-at-call" ".*break-at-call.*"
495 +# Test GDB will automatically indirect the call.
497 +gdb_test "p gnu_ifunc (3)" " = 4"
499 +# Test GDB will skip the gnu_ifunc resolver on first call.
501 +gdb_test "step" "\r\nfinal .*"
503 +# Test GDB will not break before the final chosen implementation.
505 +gdb_continue_to_breakpoint "break-at-nextcall" ".*break-at-nextcall.*"
507 +gdb_breakpoint "gnu_ifunc"
509 +gdb_continue_to_breakpoint "nextcall gnu_ifunc"
511 +gdb_test "frame" "#0 +final \\(.*" "nextcall gnu_ifunc skipped"