aboutsummaryrefslogtreecommitdiff
path: root/gdb/elfread.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2018-04-26 13:01:27 +0100
committerPedro Alves <palves@redhat.com>2018-04-26 13:09:16 +0100
commitf50776aad58a1df6b8f7f2a7d25a3b10aa074f7b (patch)
tree12fa9bfb091d97cad5718f9ed886d362e5444952 /gdb/elfread.c
parent20944a6e20324cd897bf6c4c5fd20ef7224dacaa (diff)
downloadgdb-f50776aad58a1df6b8f7f2a7d25a3b10aa074f7b.zip
gdb-f50776aad58a1df6b8f7f2a7d25a3b10aa074f7b.tar.gz
gdb-f50776aad58a1df6b8f7f2a7d25a3b10aa074f7b.tar.bz2
For PPC64/ELFv1: Introduce mst_data_gnu_ifunc
Running the new tests added later in the series on PPC64 (ELFv1) revealed that the current ifunc support needs a bit of a design rework to work properly on PPC64/ELFv1, as most of the new tests fail. The ifunc support only kind of works today if the ifunc symbol and the resolver have the same name, as is currently tested by the gdb.base/gnu-ifunc.exp testcase, which is unlike how ifuncs are written nowadays. The crux of the problem is that ifunc symbols are really function descriptors, not text symbols: 44: 0000000000020060 104 FUNC GLOBAL DEFAULT 18 gnu_ifunc_resolver 54: 0000000000020060 104 GNU_IFUNC GLOBAL DEFAULT 18 gnu_ifunc But, currently GDB only knows about ifunc symbols that are text symbols. GDB's support happens to work in practice for PPC64 when the ifunc and resolver are one and only, like in the current gdb.base/gnu-ifunc.exp testcase: 15: 0000000000020060 104 GNU_IFUNC GLOBAL DEFAULT 18 gnu_ifunc because in that case, the synthetic ".gnu_ifunc" entry point text symbol that bfd creates from the actual GNU ifunc "gnu_ifunc" function (descriptor) symbol ends up with the the "is a gnu ifunc" flag set / copied over: (gdb) maint print msymbols ... [ 8] i 0x9c4 .gnu_ifunc section .text <<< mst_text_gnu_ifunc ... [29] D 0x20060 gnu_ifunc section .opd crtstuff.c <<< mst_data But, if the resolver gets a distinct symbol/name from the ifunc symbol, then we end up with this: (gdb) maint print msymbols [ 8] T 0x9e4 .gnu_ifunc_resolver section .text <<< mst_text ... [29] D 0x20060 gnu_ifunc section .opd crtstuff.c <<< mst_data [30] D 0x20060 gnu_ifunc_resolver section .opd crtstuff.c <<< mst_data I have a follow up bfd patch that turns that into: (gdb) maint print msymbols + [ 8] i 0x9e4 .gnu_ifunc section .text <<< mst_text_gnu_ifunc [ 8] T 0x9e4 .gnu_ifunc_resolver section .text <<< mst_text ... [29] D 0x20060 gnu_ifunc section .opd crtstuff.c [30] D 0x20060 gnu_ifunc_resolver section .opd crtstuff.c but that won't help everything. We still need this patch. Specifically, when we do a symbol lookup by name, like e.g., to call a function (see c-exp.y hunk), e.g., "p gnu_ifunc()", then we need to know that the found "gnu_ifunc" minimal symbol is an ifunc in order to do some special processing. But, on PPC, that lookup by name finds the function descriptor symbol, which presently is just a mst_data symbol, while at present, we look for mst_text_gnu_ifunc symbols to decide whether to do special GNU ifunc processing. In most of those places, we could try to resolve the function descriptor with gdbarch_convert_from_func_ptr_addr, and then lookup the minimal symbol at the resolved PC, see if that finds a minimal symbol of type mst_text_gnu_ifunc. If so, then we could assume that the original mst_dadta / function descriptor "gnu_ifunc" symbol was an ifunc. I tried it, and it mostly works, even if it's not the most efficient. However, there's one case that can't work with such a design -- it's that of the user calling the ifunc resolver directly to debug it, like "p gnu_ifunc_resolver(0)", expecting that to return the function pointer of the final function (which is exercised by the new tests added later). In this case, with the not-fully-working solution, we'd resolve the function descriptor, find that there's an mst_text_gnu_ifunc symbol for the resolved address, and proceed calling the function as if we tried to call "gnu_ifunc", the user-visible GNU ifunc symbol, instead of the resolver. I.e., it'd be impossible to call the resolver directly as a normal function. Introducing mst_data_gnu_ifunc eliminates the need for several gdbarch_convert_from_func_ptr_addr calls, and, fixes the "call resolver directly" use case mentioned above too. It's the cleanest approach I could think of. In sum, we make GNU ifunc function descriptor symbols get a new "mst_data_gnu_ifunc" minimal symbol type instead of the bare mst_data type. So when symbol lookup by name finds such a minimal symbol, we know we found an ifunc symbol, without resolving the entry/text symbol. If the user calls the the resolver symbol instead, like "p gnu_ifunc_resolver(0)", then we'll find the regular mst_data symbol for "gnu_ifunc_resolver", and we'll call the resolver function as just another regular function. With this, most of the GNU ifunc tests added by a later patch pass on PPC64 too. The following bfd patch fixes the remaining issues. gdb/ChangeLog: 2018-04-26 Pedro Alves <palves@redhat.com> * breakpoint.c (set_breakpoint_location_function): Handle mst_data_gnu_ifunc. * c-exp.y (variable production): Handle mst_data_gnu_ifunc. * elfread.c (elf_symtab_read): Give data symbols with BSF_GNU_INDIRECT_FUNCTION set mst_data_gnu_ifunc type. (elf_rel_plt_read): Update comment. * linespec.c (convert_linespec_to_sals): Handle mst_data_gnu_ifunc. (minsym_found): Handle mst_data_gnu_ifunc. * minsyms.c (msymbol_is_function, minimal_symbol_reader::record) (find_solib_trampoline_target): Handle mst_data_gnu_ifunc. * parse.c (find_minsym_type_and_address): Handle mst_data_gnu_ifunc. * symmisc.c (dump_msymbols): Handle mst_data_gnu_ifunc. * symtab.c (find_gnu_ifunc): Handle mst_data_gnu_ifunc. * symtab.h (minimal_symbol_type) <mst_text_gnu_ifunc>: Update comment. <mst_data_gnu_ifunc>: New enumerator.
Diffstat (limited to 'gdb/elfread.c')
-rw-r--r--gdb/elfread.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 82437f8..e724f34 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -422,7 +422,11 @@ elf_symtab_read (minimal_symbol_reader &reader,
{
if (sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE))
{
- if (sym->section->flags & SEC_LOAD)
+ if (sym->flags & BSF_GNU_INDIRECT_FUNCTION)
+ {
+ ms_type = mst_data_gnu_ifunc;
+ }
+ else if (sym->section->flags & SEC_LOAD)
{
ms_type = mst_data;
}
@@ -614,9 +618,10 @@ elf_rel_plt_read (minimal_symbol_reader &reader,
else
continue;
- /* We cannot check if NAME is a reference to mst_text_gnu_ifunc as in
- OBJFILE the symbol is undefined and the objfile having NAME defined
- may not yet have been loaded. */
+ /* We cannot check if NAME is a reference to
+ mst_text_gnu_ifunc/mst_data_gnu_ifunc as in OBJFILE the
+ symbol is undefined and the objfile having NAME defined may
+ not yet have been loaded. */
string_buffer.assign (name);
string_buffer.append (got_suffix, got_suffix + got_suffix_len);