From 0875794a962c041bde76423e980875a467bb0bbe Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Mon, 28 Mar 2011 20:21:04 +0000 Subject: [PATCH] gdb/ 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. --- gdb/ChangeLog | 30 ++++++++++++++++++++++++++++++ gdb/elfread.c | 8 ++++++-- gdb/eval.c | 2 ++ gdb/gdbtypes.c | 16 ++++++++++++++++ gdb/gdbtypes.h | 14 ++++++++++++++ gdb/minsyms.c | 19 ++++++++++++++++--- gdb/parse.c | 24 +++++++++++++++++++++++- gdb/solib-svr4.c | 3 ++- gdb/symmisc.c | 3 +++ gdb/symtab.c | 2 +- gdb/symtab.h | 5 +++++ 11 files changed, 118 insertions(+), 8 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 9547bc4f5b3..3dd893818d0 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,33 @@ +2011-03-28 Jan Kratochvil + + 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. + 2011-03-28 Jan Kratochvil Support a ring of related breakpoints. diff --git a/gdb/elfread.c b/gdb/elfread.c index dacc6f05483..200b82fac1c 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -185,7 +185,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, @@ -394,7 +395,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) diff --git a/gdb/eval.c b/gdb/eval.c index 09b41a0fbc2..bbc7b8a71f8 100644 --- 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 diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 91fafa21524..3b459312d28 100644 --- 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) "", 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, + "", + 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, + "", + 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, diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 5f89feccd93..39ca1b465ce 100644 --- 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; diff --git a/gdb/minsyms.c b/gdb/minsyms.c index 4551b078adf..534a8b20cbf 100644 --- a/gdb/minsyms.c +++ b/gdb/minsyms.c @@ -334,8 +334,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)) { @@ -697,6 +698,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 @@ -766,6 +777,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); @@ -1231,7 +1243,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); diff --git a/gdb/parse.c b/gdb/parse.c index 02a7d894f72..4815854c831 100644 --- 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, ¤t_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; diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index 432da9963eb..78c6b1c3ee1 100644 --- 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 diff --git a/gdb/symmisc.c b/gdb/symmisc.c index 74e49414cbe..66c2f05adb8 100644 --- a/gdb/symmisc.c +++ b/gdb/symmisc.c @@ -265,6 +265,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; diff --git a/gdb/symtab.c b/gdb/symtab.c index 3061f3cb427..8aa692d6c3b 100644 --- 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; diff --git a/gdb/symtab.h b/gdb/symtab.h index e946c65fea3..9e248280948 100644 --- 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 **); -- 2.30.2