Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 8 May 2019 23:32:11 -0400
From:      Mark Johnston <markj@freebsd.org>
To:        Larry Rosenman <ler@freebsd.org>
Cc:        freebsd-current@freebsd.org
Subject:   Re: Crash loading dtraceall
Message-ID:  <20190509033211.GE11774@raichu>
In-Reply-To: <460d563e2fe48bfd90b489015b4c0f9d@FreeBSD.org>
References:  <20190508205245.ulbo6fusk3b4py7t@ler-imac.local> <20190508222932.GB11774@raichu> <845dd186ef038d98c1a95a7454e432d2@FreeBSD.org> <20190508225553.GC11774@raichu> <460d563e2fe48bfd90b489015b4c0f9d@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Wed, May 08, 2019 at 05:57:18PM -0500, Larry Rosenman wrote:
> On 05/08/2019 5:55 pm, Mark Johnston wrote:
> > On Wed, May 08, 2019 at 05:47:08PM -0500, Larry Rosenman wrote:
> >> On 05/08/2019 5:29 pm, Mark Johnston wrote:
> >> > On Wed, May 08, 2019 at 03:52:45PM -0500, Larry Rosenman wrote:
> >> >> Greetings,
> >> >>
> >> >>     Somewhere between r346483 and r347241 loading dtraceall causes a
> >> >>     crash.  I have the cores and kernels.
> >> >>
> >> >>     It's hard for me to bisect more than this, as the box is remote.
> >> >>
> >> >>     What more do you need?  (this dump is fropm r347355).
> >> >
> >> > Please visit frame 8 and print *lf.
> >> >
> >> #9  fbt_provide_module_function (lf=0xfffff800020ff000, symindx=30763,
> >> symval=0xfffffe00d74d7e00, opaque=0xfffffe00d74d7e50) at
> >> /usr/src/sys/cddl/dev/fbt/x86/fbt_isa.c:191
> >> 191			if (*instr == FBT_PUSHL_EBP)
> >> (kgdb) print *lf
> >> $1 = {ops = 0xfffff800020f6000, refs = 202, userrefs = 1, flags = 1,
> >> link = {tqe_next = 0xfffff800020fec00, tqe_prev = 0xffffffff80c767d0
> >> <linker_files>}, filename = 0xfffff80002101030 "kernel",
> >>    pathname = 0xfffff80002104080 "/boot/kernel/kernel", id = 1, 
> >> address =
> >> 0xffffffff80200000 "\177ELF\002\001\001\t", size = 17612816, 
> >> ctors_addr
> >> = 0x0, ctors_size = 0, ndeps = 0, deps = 0x0, common = {stqh_first =
> >> 0x0,
> >>      stqh_last = 0xfffff800020ff070}, modules = {tqh_first =
> >> 0xfffff800020e5800, tqh_last = 0xfffff80002116790}, loaded = {tqe_next 
> >> =
> >> 0x0, tqe_prev = 0x0}, loadcnt = 1, nenabled = 0, fbt_nentries = 25062}
> >> (kgdb)
> > 
> > And could you show the output of:
> > 
> > $ readelf -s /boot/kernel/kernel | grep "30763:"
> > _______________________________________________
> > freebsd-current@freebsd.org mailing list
> > https://lists.freebsd.org/mailman/listinfo/freebsd-current
> > To unsubscribe, send any mail to 
> > "freebsd-current-unsubscribe@freebsd.org"
> 
> [root@oldtbh2 /var/crash]# readelf -s /boot/kernel/kernel | grep 
> "30763:"
>   30763: ffffffff80791310    75 IFUNC   GLOBAL DEFAULT    8 x86_rng_store
> [root@oldtbh2 /var/crash]#

The problem is with the kernel linker's handling of ifuncs.  When
enumerating symbols, it replaces ifunc symbol values with the return
value of the resolver but preserves the original symbol size, which is
that of the resolver.  I believe this patch will address the panic
you're seeing:

diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
index 6ceb34d66b74..8bd9a0219a1d 100644
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -1350,17 +1350,23 @@ static int
 link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym,
     linker_symval_t *symval)
 {
+	c_linker_sym_t target;
 	elf_file_t ef;
 	const Elf_Sym *es;
 	caddr_t val;
+	long diff;
 
 	ef = (elf_file_t)lf;
 	es = (const Elf_Sym *)sym;
 	if (es >= ef->symtab && es < (ef->symtab + ef->nchains)) {
 		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)
+		if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC) {
 			val = ((caddr_t (*)(void))val)();
+			(void)link_elf_search_symbol(lf, val, &target, &diff);
+			if (diff == 0)
+				es = (const Elf_Sym *)target;
+		}
 		symval->value = val;
 		symval->size = es->st_size;
 		return (0);
@@ -1370,8 +1376,12 @@ link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym,
 	if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) {
 		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)
+		if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC) {
 			val = ((caddr_t (*)(void))val)();
+			(void)link_elf_search_symbol(lf, val, &target, &diff);
+			if (diff == 0)
+				es = (const Elf_Sym *)target;
+		}
 		symval->value = val;
 		symval->size = es->st_size;
 		return (0);
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
index ac4cc8c085cb..5ce160a05699 100644
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.c
@@ -1240,9 +1240,11 @@ static int
 link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym,
     linker_symval_t *symval)
 {
+	c_linker_sym_t target;
 	elf_file_t ef;
 	const Elf_Sym *es;
 	caddr_t val;
+	long diff;
 
 	ef = (elf_file_t) lf;
 	es = (const Elf_Sym*) sym;
@@ -1250,8 +1252,12 @@ link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym,
 	if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) {
 		symval->name = ef->ddbstrtab + es->st_name;
 		val = (caddr_t)es->st_value;
-		if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC)
+		if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC) {
 			val = ((caddr_t (*)(void))val)();
+			(void)link_elf_search_symbol(lf, val, &target, &diff);
+			if (diff == 0)
+				es = (const Elf_Sym *)target;
+		}
 		symval->value = val;
 		symval->size = es->st_size;
 		return 0;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20190509033211.GE11774>