Fix breakpoints in ifunc after inferior resolved it (@got.plt symbol creation)
Setting a breakpoint on an ifunc symbol after the ifunc has already
been resolved by the inferior should result in creating a breakpoint
location at the ifunc target. However, that's not what happens on
current Fedora:
(gdb) n
53 i = gnu_ifunc (1); /* break-at-call */
(gdb)
54 assert (i == 2);
(gdb) b gnu_ifunc
Breakpoint 2 at gnu-indirect-function resolver at 0x7ffff7bd36ee
(gdb) info breakpoints
Num Type Disp Enb Address What
2 STT_GNU_IFUNC resolver keep y 0x00007ffff7bd36ee <gnu_ifunc+4>
The problem is that elf_gnu_ifunc_resolve_by_got never manages to
resolve an ifunc target. The reason is that GDB never actually
creates the internal got.plt symbols:
(gdb) p 'gnu_ifunc@got.plt'
No symbol "gnu_ifunc@got.plt" in current context.
and this is because GDB expects that rela.plt has relocations for
.plt, while it actually has relocations for .got.plt:
Relocation section [10] '.rela.plt' for section [22] '.got.plt' at offset 0x570 contains 2 entries:
Offset Type Value Addend Name
0x0000000000601018 X86_64_JUMP_SLOT
000000000000000000 +0 __assert_fail
0x0000000000601020 X86_64_JUMP_SLOT
000000000000000000 +0 gnu_ifunc
Using an older system on the GCC compile farm (machine gcc15, an
x86-64 running Debian 6.0.8, with GNU ld 2.20.1), we see that it used
to be that we'd get a .rela.plt section for .plt:
Relocation section [ 9] '.rela.plt' for section [11] '.plt' at offset 0x578 contains 3 entries:
Offset Type Value Addend Name
0x0000000000600cc0 X86_64_JUMP_SLOT
000000000000000000 +0 __assert_fail
0x0000000000600cc8 X86_64_JUMP_SLOT
000000000000000000 +0 __libc_start_main
0x0000000000600cd0 X86_64_JUMP_SLOT
000000000000000000 +0 gnu_ifunc
Those offsets did point into .got.plt, as seen with objdump -h:
20 .got.plt
00000030 0000000000600ca8 0000000000600ca8 00000ca8 2**3
CONTENTS, ALLOC, LOAD, DATA
I also tested on gcc110 on the compile farm (PPC64 running CentOS
7.4.1708, with GNU ld 2.25.1), and there we see instead:
Relocation section [ 9] '.rela.plt' for section [23] '.plt' at offset 0x5d0 contains 4 entries:
Offset Type Value Addend Name
0x0000000010020148 PPC64_JMP_SLOT
000000000000000000 +0 __libc_start_main
0x0000000010020160 PPC64_JMP_SLOT
000000000000000000 +0 __gmon_start__
0x0000000010020178 PPC64_JMP_SLOT
000000000000000000 +0 __assert_fail
0x0000000010020190 PPC64_JMP_SLOT
000000000000000000 +0 gnu_ifunc
But note that those offsets point into .plt, not .got.plt, as seen
with objdump -h:
22 .plt
00000078 0000000010020130 0000000010020130 00010130 2**3
ALLOC
This commit makes us support all the different combinations above.
With that addressed, we now get:
(gdb) p 'gnu_ifunc@got.plt'
$1 = (<text from jump slot in .got.plt, no debug info>) 0x400753 <final>
And setting a breakpoint on the ifunc finds the ifunc target:
(gdb) b gnu_ifunc
Breakpoint 2 at 0x400753
(gdb) info breakpoints
Num Type Disp Enb Address What
2 breakpoint keep y 0x0000000000400753 <final>
gdb/ChangeLog:
2018-04-26 Pedro Alves <palves@redhat.com>
* elfread.c (elf_rel_plt_read): Look for relocations for .got.plt too.