Skip to content

Commit

Permalink
libmcount: support no-plt binary
Browse files Browse the repository at this point in the history
Issue reported that no-plt binary is handled as plt-enable
binary because some functions are still left in plt section.
The patch fixes this bug by comparing the name of self with
a list of known functions.

Fixed: #TBU

Signed-off-by: ChoKyuWon <[email protected]>
  • Loading branch information
ChoKyuWon committed Sep 2, 2023
1 parent 5897da8 commit 4b712b5
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 25 deletions.
4 changes: 2 additions & 2 deletions arch/x86_64/mcount-noplt.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ struct plthook_data *mcount_arch_hook_no_plt(struct uftrace_elf_data *elf, const
pd->module_id = (unsigned long)pd;
pd->base_addr = offset;

if (load_elf_dynsymtab(&pd->dsymtab, elf, offset, 0) < 0 || pd->dsymtab.nr_sym == 0) {
if (arch_load_dynsymtab_noplt(&pd->dsymtab, elf, offset, 0) < 0 ||
pd->dsymtab.nr_sym == 0) {
free(pd);
return NULL;
}
Expand Down Expand Up @@ -97,7 +98,6 @@ struct plthook_data *mcount_arch_hook_no_plt(struct uftrace_elf_data *elf, const
}
if (skip)
continue;

/* copy trampoline instructions */
memcpy(tramp, tramp_insns, TRAMP_ENT_SIZE);

Expand Down
5 changes: 3 additions & 2 deletions arch/x86_64/symbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ int arch_load_dynsymtab_noplt(struct uftrace_symtab *dsymtab, struct uftrace_elf

/* assumes there's only one RELA section (rela.dyn) for no-plt binary */
elf_for_each_shdr(elf, &sec_iter) {
if (sec_iter.shdr.sh_type == SHT_RELA) {
if (strcmp(elf_get_name(elf, &sec_iter, sec_iter.shdr.sh_name), ".rela.dyn") == 0) {
memcpy(&rel_iter, &sec_iter, sizeof(sec_iter));
pr_dbg2("found RELA section: %s\n",
pr_dbg2("found rela.dyn section: %s\n",
elf_get_name(elf, &sec_iter, sec_iter.shdr.sh_name));

reloc_start = rel_iter.shdr.sh_addr + offset;
Expand Down Expand Up @@ -93,6 +93,7 @@ int arch_load_dynsymtab_noplt(struct uftrace_symtab *dsymtab, struct uftrace_elf
pr_dbg3("[%zd] %c %lx + %-5u %s\n", dsymtab->nr_sym, sym->type, sym->addr,
sym->size, sym->name);
}
sort_dynsymtab(dsymtab);

return dsymtab->nr_sym;
}
Expand Down
53 changes: 51 additions & 2 deletions libmcount/plthook.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ const struct plthook_skip_symbol plt_skip_syms[] = {
};
size_t plt_skip_nr = ARRAY_SIZE(plt_skip_syms);

const char *const additional_plt_skip_syms[] = {
"__stack_chk_fail",
"__monstartup",
"__cxa_atexit",
};
size_t additional_plt_skip_nr = ARRAY_SIZE(additional_plt_skip_syms);

#undef SKIP_SYM
#undef ALIAS_DECL

Expand Down Expand Up @@ -191,7 +198,12 @@ static int find_got(struct uftrace_elf_data *elf, struct uftrace_elf_iter *iter,
bool plt_found = false;
unsigned long pltgot_addr = 0;
unsigned long plt_addr = 0;
unsigned long jmprel_addr = 0;
struct uftrace_elf_iter sec_iter;
size_t jmprel_nr = 0;
struct plthook_data *pd;
bool is_rela = true;
const char *fname;

elf_for_each_shdr(elf, iter) {
if (iter->shdr.sh_type == SHT_DYNAMIC)
Expand All @@ -204,13 +216,47 @@ static int find_got(struct uftrace_elf_data *elf, struct uftrace_elf_iter *iter,
pltgot_addr = (unsigned long)iter->dyn.d_un.d_val + offset;
break;
case DT_JMPREL:
plt_found = true;
jmprel_addr = (unsigned long)iter->dyn.d_un.d_ptr + offset;
break;
case DT_PLTRELSZ:
jmprel_nr = (unsigned long)iter->dyn.d_un.d_val;
break;
case DT_PLTREL:
if (iter->dyn.d_un.d_val == DT_REL)
is_rela = false;
break;
default:
break;
}
}

elf_for_each_shdr(elf, &sec_iter) {
if (sec_iter.shdr.sh_type == SHT_DYNSYM) {
elf_get_strtab(elf, &sec_iter, sec_iter.shdr.sh_link);
elf_get_secdata(elf, &sec_iter);
break;
}
}

for (size_t i = 0; i < jmprel_nr; i += (is_rela ? sizeof(Elf64_Rela) : sizeof(Elf64_Rel))) {
bool found = false;
Elf64_Rela *rel = (void *)jmprel_addr + i;
elf_get_symbol(elf, &sec_iter, elf_rel_symbol(rel));
fname = elf_get_name(elf, &sec_iter, sec_iter.sym.st_name);
for (size_t k = 0; k < additional_plt_skip_nr; k++) {
if (!strcmp(fname, additional_plt_skip_syms[k]))
found = true;
}
for (size_t k = 0; k < plt_skip_nr; k++) {
if (!strcmp(fname, plt_skip_syms[k].name))
found = true;
}
if (!found) {
plt_found = true;
break;
}
}

if (!plt_found) {
pd = mcount_arch_hook_no_plt(elf, modname, offset);
if (pd == NULL)
Expand Down Expand Up @@ -246,7 +292,10 @@ static int find_got(struct uftrace_elf_data *elf, struct uftrace_elf_iter *iter,

memset(&pd->dsymtab, 0, sizeof(pd->dsymtab));
/* do not demangle symbol names since it might call dlsym() */
load_elf_dynsymtab(&pd->dsymtab, elf, pd->base_addr, 0);
if (!plt_found)
arch_load_dynsymtab_noplt(&pd->dsymtab, elf, pd->base_addr, 0);
else
load_elf_dynsymtab(&pd->dsymtab, elf, pd->base_addr, 0);

pd->resolved_addr = xcalloc(pd->dsymtab.nr_sym, sizeof(long));
pd->special_funcs = NULL;
Expand Down
42 changes: 23 additions & 19 deletions utils/symbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,10 +472,12 @@ static int load_dyn_symbol(struct uftrace_symtab *dsymtab, int sym_idx, unsigned
return 1;
}

static void sort_dynsymtab(struct uftrace_symtab *dsymtab)
void sort_dynsymtab(struct uftrace_symtab *dsymtab)
{
unsigned i, k;

if (dsymtab->nr_sym == 0)
return;
dsymtab->nr_alloc = dsymtab->nr_sym;
dsymtab->sym = xrealloc(dsymtab->sym, dsymtab->nr_sym * sizeof(*dsymtab->sym));

Expand Down Expand Up @@ -643,24 +645,6 @@ int load_elf_dynsymtab(struct uftrace_symtab *dsymtab, struct uftrace_elf_data *
return ret;
}

static int load_dynsymtab(struct uftrace_symtab *dsymtab, const char *filename,
unsigned long offset, unsigned long flags)
{
int ret;
struct uftrace_elf_data elf;

if (elf_init(filename, &elf) < 0) {
pr_dbg("error during open symbol file: %s: %m\n", filename);
return -1;
}

pr_dbg3("loading dynamic symbols from %s (offset: %#lx)\n", filename, offset);
ret = load_elf_dynsymtab(dsymtab, &elf, offset, flags);

elf_finish(&elf);
return ret;
}

static void merge_symtabs(struct uftrace_symtab *left, struct uftrace_symtab *right)
{
size_t nr_sym = left->nr_sym + right->nr_sym;
Expand Down Expand Up @@ -714,6 +698,26 @@ static void merge_symtabs(struct uftrace_symtab *left, struct uftrace_symtab *ri
left->name_sorted = true;
}

static int load_dynsymtab(struct uftrace_symtab *dsymtab, const char *filename,
unsigned long offset, unsigned long flags)
{
struct uftrace_symtab dsymtab_noplt = {};
struct uftrace_elf_data elf;

if (elf_init(filename, &elf) < 0) {
pr_dbg("error during open symbol file: %s: %m\n", filename);
return -1;
}

pr_dbg3("loading dynamic symbols from %s (offset: %#lx)\n", filename, offset);
load_elf_dynsymtab(dsymtab, &elf, offset, flags);
arch_load_dynsymtab_noplt(&dsymtab_noplt, &elf, offset, flags);
merge_symtabs(dsymtab, &dsymtab_noplt);

elf_finish(&elf);
return dsymtab->nr_sym;
}

static int update_symtab_using_dynsym(struct uftrace_symtab *symtab, const char *filename,
unsigned long offset, unsigned long flags)
{
Expand Down
1 change: 1 addition & 0 deletions utils/symbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ struct uftrace_module *load_module_symtab(struct uftrace_sym_info *sinfo, const
char *build_id);
void save_module_symtabs(const char *dirname);
void unload_module_symtabs(void);
void sort_dynsymtab(struct uftrace_symtab *dsymtab);

enum uftrace_trace_type {
TRACE_ERROR = -1,
Expand Down

0 comments on commit 4b712b5

Please sign in to comment.