Re: git: aefae931820f - main - linker: Improve handling of ifuncs when fetching symbol metadata
Date: Wed, 02 Jul 2025 18:25:53 UTC
Cy Schubert writes:
> In message <202507021341.562DfuEh023668@gitrepo.freebsd.org>, Mark Johnston
> wri
> tes:
> > The branch main has been updated by markj:
> >
> > URL: https://cgit.FreeBSD.org/src/commit/?id=aefae931820fe1e93a318552968510
> 29
> > 8c7941a0
> >
> > commit aefae931820fe1e93a318552968510298c7941a0
> > Author: Mark Johnston <markj@FreeBSD.org>
> > AuthorDate: 2025-07-02 13:34:47 +0000
> > Commit: Mark Johnston <markj@FreeBSD.org>
> > CommitDate: 2025-07-02 13:34:47 +0000
> >
> > linker: Improve handling of ifuncs when fetching symbol metadata
> >
> > When looking up symbol values, we map ifunc symbols to the value
> > returned by the resolver. However, the returned symbol size is still
> > that of the resolver. Be consistent and provide the size of the
> > implementation symbol as well.
> >
> > This fixes an inconsistency in dtrace's FBT provider, which enumerates
> > all function symbols and disassembles their values, using the symbol
> > size as the bound for the disassembly loop. In particular, for ifuncs,
> > we were not creating return probes.
> >
> > Reviewed by: kib
> > MFC after: 2 weeks
> > Sponsored by: Innovate UK
> > Differential Revision: https://reviews.freebsd.org/D50683
> > ---
> > sys/kern/link_elf.c | 38 ++++++++++++++++++++++++++++++++++----
> > sys/kern/link_elf_obj.c | 31 +++++++++++++++++++++++++++++--
> > 2 files changed, 63 insertions(+), 6 deletions(-)
> >
> > diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
> > index 53af1e164980..bbebadc4c395 100644
> > --- a/sys/kern/link_elf.c
> > +++ b/sys/kern/link_elf.c
> > @@ -1628,6 +1628,30 @@ link_elf_lookup_debug_symbol_ctf(linker_file_t lf, c
> on
> > st char *name,
> > return (i < ef->ddbsymcnt ? link_elf_ctf_get_ddb(lf, lc) : ENOENT);
> > }
> >
> > +static void
> > +link_elf_ifunc_symbol_value(linker_file_t lf, caddr_t *valp, size_t *sizep
> )
> > +{
> > + c_linker_sym_t sym;
> > + elf_file_t ef;
> > + const Elf_Sym *es;
> > + caddr_t val;
> > + long off;
> > +
> > + val = *valp;
> > + ef = (elf_file_t)lf;
> > +
> > + /* Provide the value and size of the target symbol, if available. */
> > + val = ((caddr_t (*)(void))val)();
> > + if (link_elf_search_symbol(lf, val, &sym, &off) == 0 && off == 0) {
> > + es = (const Elf_Sym *)sym;
> > + *valp = (caddr_t)ef->address + es->st_value;
> > + *sizep = es->st_size;
> > + } else {
> > + *valp = val;
> > + *sizep = 0;
> > + }
> > +}
> > +
> > static int
> > link_elf_symbol_values1(linker_file_t lf, c_linker_sym_t sym,
> > linker_symval_t *symval, bool see_local)
> > @@ -1635,6 +1659,7 @@ link_elf_symbol_values1(linker_file_t lf, c_linker_sy
> m_
> > t sym,
> > elf_file_t ef;
> > const Elf_Sym *es;
> > caddr_t val;
> > + size_t size;
> >
> > ef = (elf_file_t)lf;
> > es = (const Elf_Sym *)sym;
> > @@ -1644,9 +1669,11 @@ link_elf_symbol_values1(linker_file_t lf, c_linker_s
> ym
> > _t sym,
> > symval->name = ef->strtab + es->st_name;
> > val = (caddr_t)ef->address + es->st_value;
> > if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC)
> > - val = ((caddr_t (*)(void))val)();
> > + link_elf_ifunc_symbol_value(lf, &val, &size);
> > + else
> > + size = es->st_size;
> > symval->value = val;
> > - symval->size = es->st_size;
> > + symval->size = size;
> > return (0);
> > }
> > return (ENOENT);
> > @@ -1668,6 +1695,7 @@ link_elf_debug_symbol_values(linker_file_t lf, c_link
> er
> > _sym_t sym,
> > elf_file_t ef = (elf_file_t)lf;
> > const Elf_Sym *es = (const Elf_Sym *)sym;
> > caddr_t val;
> > + size_t size;
> >
> > if (link_elf_symbol_values1(lf, sym, symval, true) == 0)
> > return (0);
> > @@ -1678,9 +1706,11 @@ link_elf_debug_symbol_values(linker_file_t lf, c_lin
> ke
> > r_sym_t sym,
> > symval->name = ef->ddbstrtab + es->st_name;
> > val = (caddr_t)ef->address + es->st_value;
> > if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC)
> > - val = ((caddr_t (*)(void))val)();
> > + link_elf_ifunc_symbol_value(lf, &val, &size);
> > + else
> > + size = es->st_size;
> > symval->value = val;
> > - symval->size = es->st_size;
> > + symval->size = size;
> > return (0);
> > }
> > return (ENOENT);
> > diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
> > index 02fd4caffcd9..3d18aed2b1c0 100644
> > --- a/sys/kern/link_elf_obj.c
> > +++ b/sys/kern/link_elf_obj.c
> > @@ -1510,6 +1510,30 @@ link_elf_lookup_debug_symbol_ctf(linker_file_t lf, c
> on
> > st char *name,
> > return (link_elf_ctf_get_ddb(lf, lc));
> > }
> >
> > +static void
> > +link_elf_ifunc_symbol_value(linker_file_t lf, caddr_t *valp, size_t *sizep
> )
> > +{
> > + c_linker_sym_t sym;
> > + elf_file_t ef;
> > + const Elf_Sym *es;
> > + caddr_t val;
> > + long off;
> > +
> > + val = *valp;
> > + ef = (elf_file_t)lf;
> > +
> > + /* Provide the value and size of the target symbol, if available. */
> > + val = ((caddr_t (*)(void))val)();
> > + if (link_elf_search_symbol(lf, val, &sym, &off) == 0 && off == 0) {
> > + es = (const Elf_Sym *)sym;
> > + *valp = (caddr_t)ef->address + es->st_value;
> > + *sizep = es->st_size;
> > + } else {
> > + *valp = val;
> > + *sizep = 0;
> > + }
> > +}
> > +
> > static int
> > link_elf_symbol_values1(linker_file_t lf, c_linker_sym_t sym,
> > linker_symval_t *symval, bool see_local)
> > @@ -1517,6 +1541,7 @@ link_elf_symbol_values1(linker_file_t lf, c_linker_sy
> m_
> > t sym,
> > elf_file_t ef;
> > const Elf_Sym *es;
> > caddr_t val;
> > + size_t size;
> >
> > ef = (elf_file_t) lf;
> > es = (const Elf_Sym*) sym;
> > @@ -1527,9 +1552,11 @@ link_elf_symbol_values1(linker_file_t lf, c_linker_s
> ym
> > _t sym,
> > symval->name = ef->ddbstrtab + es->st_name;
> > val = (caddr_t)es->st_value;
> > if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC)
> > - val = ((caddr_t (*)(void))val)();
> > + link_elf_ifunc_symbol_value(lf, &val, &size);
> > + else
> > + size = es->st_size;
> > symval->value = val;
> > - symval->size = es->st_size;
> > + symval->size = size;
> > return (0);
> > }
> > return (ENOENT);
> >
>
> This commit may have caused a panic loading linux.ko.
>
> #0 __curthread () at /opt/src/git-src/sys/amd64/include/pcpu_aux.h:57
> #1 doadump (textdump=textdump@entry=1)
> at /opt/src/git-src/sys/kern/kern_shutdown.c:399
> #2 0xffffffff806fad1e in kern_reboot (howto=260)
> at /opt/src/git-src/sys/kern/kern_shutdown.c:519
> #3 0xffffffff806fb247 in vpanic (fmt=0xffffffff80b2e000 "%s",
> ap=ap@entry=0xfffffe008c8e2450)
> at /opt/src/git-src/sys/kern/kern_shutdown.c:974
> #4 0xffffffff806fb073 in panic (fmt=<unavailable>)
> at /opt/src/git-src/sys/kern/kern_shutdown.c:887
> #5 0xffffffff80aa8e7a in trap_fatal (frame=<optimized out>,
> eva=<optimized out>) at /opt/src/git-src/sys/amd64/amd64/trap.c:974
> #6 0xffffffff80aa8e7a in trap_pfault (frame=0xfffffe008c8e24d0,
> usermode=false, signo=<optimized out>, ucode=<optimized out>)
> #7 <signal handler called>
> #8 fbt_provide_module_function (lf=lf@entry=0xfffff80126035900,
> symindx=symindx@entry=753, symval=symval@entry=0xfffffe008c8e25f0,
> opaque=opaque@entry=0xfffffe008c8e2640)
> at /opt/src/git-src/sys/cddl/dev/fbt/x86/fbt_isa.c:205
> #9 0xffffffff80ac870d in link_elf_each_function_nameval (
> file=0xfffff80126035900,
> callback=0xffffffff81d916a0 <fbt_provide_module_function>,
> opaque=0xfffffe008c8e2640) at /opt/src/git-src/sys/kern/link_elf_obj.c:1
> 685
> --Type <RET> for more, q to quit, c to continue without paging--c
> #10 0xffffffff81d9035f in fbt_provide_module (arg=<optimized out>,
> lf=0xfffff80126035900) at /opt/src/git-src/sys/cddl/dev/fbt/fbt.c:221
> #11 0xffffffff81cc87fb in dtrace_module_loaded (ctl=0xfffff80126035900)
> at /opt/src/git-src/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrac
> e.c:16709
> #12 dtrace_kld_load (arg=<optimized out>, lf=0xfffff80126035900)
> at /opt/src/git-src/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrac
> e.c:16894
> #13 0xffffffff806c4ecb in linker_load_file (
> filename=0xfffff80054e6d500 "/boot/kernel/linux.ko",
> result=<optimized out>) at /opt/src/git-src/sys/kern/kern_linker.c:518
> #14 linker_load_module (kldname=kldname@entry=0x0,
> modname=0xfffff8005437c800 "linux", parent=parent@entry=0x0,
> verinfo=verinfo@entry=0x0, lfpp=lfpp@entry=0xfffffe008c8e2da0)
> at /opt/src/git-src/sys/kern/kern_linker.c:2292
> #15 0xffffffff806c69f5 in kern_kldload (td=td@entry=0xfffff8005ce3c780,
> file=file@entry=0xfffff8005437c800 "linux",
> fileid=fileid@entry=0xfffffe008c8e2de4)
> at /opt/src/git-src/sys/kern/kern_linker.c:1236
> #16 0xffffffff806c6b09 in sys_kldload (td=0xfffff8005ce3c780,
> uap=0xfffff8005ce3cba8) at /opt/src/git-src/sys/kern/kern_linker.c:1259
> #17 0xffffffff80aa97d6 in syscallenter (td=0xfffff8005ce3c780)
> at /opt/src/git-src/sys/amd64/amd64/../../kern/subr_syscall.c:193
> #18 amd64_syscall (td=0xfffff8005ce3c780, traced=0)
> at /opt/src/git-src/sys/amd64/amd64/trap.c:1215
> #19 <signal handler called>
> #20 0x00000ce63ecf8c3a in ?? ()
Confirmed. kldload linux causes the panic.
--
Cheers,
Cy Schubert <Cy.Schubert@cschubert.com>
FreeBSD UNIX: <cy@FreeBSD.org> Web: https://FreeBSD.org
NTP: <cy@nwtime.org> Web: https://nwtime.org
e**(i*pi)+1=0