mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-25 19:14:52 +08:00
PPC64: always make synthetic .text symbols for GNU ifunc symbols
If you create an ifunc using GCC's __attribute__ ifunc, like: extern int gnu_ifunc (int arg); static int gnu_ifunc_target (int arg) { return 0; } __typeof (gnu_ifunc) *gnu_ifunc_resolver (unsigned long hwcap) { return gnu_ifunc_target; } __typeof (gnu_ifunc) gnu_ifunc __attribute__ ((ifunc ("gnu_ifunc_resolver"))); then you end up with two (function descriptor) symbols, one for the ifunc itself, and another for the resolver: (...) 12: 0000000000020060 104 FUNC GLOBAL DEFAULT 18 gnu_ifunc_resolver (...) 16: 0000000000020060 104 GNU_IFUNC GLOBAL DEFAULT 18 gnu_ifunc (...) Both ifunc and resolver symbols have the same address/value, so ppc64_elf_get_synthetic_symtab only creates a synthetic text symbol for one of them. In the case above, it ends up being created for the resolver, only: (gdb) maint print msymbols (...) [ 7] t 0x980 .frame_dummy section .text [ 8] T 0x9e4 .gnu_ifunc_resolver section .text [ 9] T 0xa58 __glink_PLTresolve section .text (...) GDB needs to know when a program stepped into an ifunc resolver, so that it can know whether to step past the resolver into the target function without the user noticing. The way GDB does it is my checking whether the current PC points to an ifunc symbol (since resolver and ifunc have the same address by design). The problem is then that ppc64_elf_get_synthetic_symtab never creates the synchetic symbol for the ifunc, so GDB stops stepping at the resolver (in a test added by the following patch): (gdb) step gnu_ifunc_resolver (hwcap=21) at gdb/testsuite/gdb.base/gnu-ifunc-lib.c:33 33 { (gdb) FAIL: gdb.base/gnu-ifunc.exp: resolver_attr=1: resolver_debug=1: final_debug=0: step After this commit, we get: [ 8] i 0x9e4 .gnu_ifunc section .text [ 9] T 0x9e4 .gnu_ifunc_resolver section .text And stepping an ifunc call takes to the final function: (gdb) step 0x00000000100009e8 in .final () (gdb) PASS: gdb.base/gnu-ifunc.exp: resolver_attr=1: resolver_debug=1: final_debug=0: step An alternative to touching bfd I considered was for GDB to check whether there's an ifunc data symbol / function descriptor that points to the current PC, whenever the program stops, but discarded it because we'd have to do a linear scan over .opd over an over to find a matching function descriptor for the current PC. At that point I considered caching that info, but quickly dismissed it as then that has no advantage (memory or performance) over just creating the synthetic ifunc text symbol in the first place. I ran the binutils and ld testsuites on PPC64 ELFv1 (machine gcc110 on the GCC compile farm), and saw no regressions. This commit is part of a GDB patch series that includes GDB tests that fail without this fix. bfd/ChangeLog: 2018-04-26 Pedro Alves <palves@redhat.com> * elf64-ppc.c (ppc64_elf_get_synthetic_symtab): Don't consider ifunc and non-ifunc symbols duplicates.
This commit is contained in:
parent
f50776aad5
commit
bfa5bd2ab3
@ -1,3 +1,8 @@
|
||||
2018-04-26 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* elf64-ppc.c (ppc64_elf_get_synthetic_symtab): Don't consider
|
||||
ifunc and non-ifunc symbols duplicates.
|
||||
|
||||
2018-04-25 Christophe Lyon <christophe.lyon@st.com>
|
||||
Mickaël Guêné <mickael.guene@st.com>
|
||||
|
||||
|
@ -3366,13 +3366,23 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
|
||||
|
||||
if (!relocatable && symcount > 1)
|
||||
{
|
||||
/* Trim duplicate syms, since we may have merged the normal and
|
||||
dynamic symbols. Actually, we only care about syms that have
|
||||
different values, so trim any with the same value. */
|
||||
/* Trim duplicate syms, since we may have merged the normal
|
||||
and dynamic symbols. Actually, we only care about syms
|
||||
that have different values, so trim any with the same
|
||||
value. Don't consider ifunc and ifunc resolver symbols
|
||||
duplicates however, because GDB wants to know whether a
|
||||
text symbol is an ifunc resolver. */
|
||||
for (i = 1, j = 1; i < symcount; ++i)
|
||||
if (syms[i - 1]->value + syms[i - 1]->section->vma
|
||||
!= syms[i]->value + syms[i]->section->vma)
|
||||
syms[j++] = syms[i];
|
||||
{
|
||||
const asymbol *s0 = syms[i - 1];
|
||||
const asymbol *s1 = syms[i];
|
||||
|
||||
if ((s0->value + s0->section->vma
|
||||
!= s1->value + s1->section->vma)
|
||||
|| ((s0->flags & BSF_GNU_INDIRECT_FUNCTION)
|
||||
!= (s1->flags & BSF_GNU_INDIRECT_FUNCTION)))
|
||||
syms[j++] = syms[i];
|
||||
}
|
||||
symcount = j;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user