mirror of
https://github.com/opnsense/src.git
synced 2026-06-17 04:29:12 -04:00
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
This commit is contained in:
parent
c9fcffff6c
commit
aefae93182
2 changed files with 63 additions and 6 deletions
|
|
@ -1628,6 +1628,30 @@ link_elf_lookup_debug_symbol_ctf(linker_file_t lf, const 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_sym_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_sym_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_linker_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_linker_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);
|
||||
|
|
|
|||
|
|
@ -1510,6 +1510,30 @@ link_elf_lookup_debug_symbol_ctf(linker_file_t lf, const 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_sym_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_sym_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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue