add file hint to add-patches-section

Currently, add-patches-section just blindly looks in vmlinux
for a function symbol matching the name of the patched function
in the input object file.  However, for local symbols, they may
appear multiple times in the vmlinux symbol table since the symbol
name may be reused locally in different files.

This commit add support for "file hinting".  It tracks what
file the symbol is in and searches for local symbols within
that file in vmlinux first.  If it doesn't find one, it then
searches globally like it always has.

Fixes issue #53

Signed-off-by: Seth Jennings <sjenning@redhat.com>
This commit is contained in:
Seth Jennings 2014-03-12 11:18:44 -05:00
parent c09ed67945
commit 75ceca4f33

View File

@ -70,7 +70,7 @@ struct sym {
}; };
struct symlist { struct symlist {
struct sym *head; struct sym *head, *tail;
size_t len; size_t len;
}; };
@ -131,8 +131,11 @@ static void insert_sym(struct symlist *list, GElf_Sym *sym, char *name,
newsym->name = name; newsym->name = name;
newsym->index = index; newsym->index = index;
newsym->next = list->head; if (list->tail)
list->tail->next = newsym;
if (!list->head)
list->head = newsym; list->head = newsym;
list->tail = newsym;
} }
static void find_section_by_name(struct elf *elf, char *name, struct section *sec) static void find_section_by_name(struct elf *elf, char *name, struct section *sec)
@ -192,13 +195,36 @@ static void create_symlist(struct elf *elf, struct symlist *symlist)
} }
} }
static struct sym *find_symbol_by_name(struct symlist *list, char *name) static struct sym *find_symbol_by_name(struct symlist *list, struct sym *sym,
char *hint)
{ {
struct sym *cur; struct sym *cur, *ret = NULL;
char *name = sym->name, *curfile = NULL;
/* try to find a local symbol in the hint file first */
if (hint && GELF_ST_BIND(sym->sym.st_info) == STB_LOCAL) {
for_each_sym(list, cur) {
if (GELF_ST_TYPE(cur->sym.st_info) == STT_FILE)
curfile = cur->name;
if (!curfile || strcmp(curfile, hint))
continue;
if (!strcmp(cur->name, name)) {
if (ret)
ERROR("unresolvable symbol ambiguity for symbol '%s' in file '%s'", name, hint);
ret = cur;
}
}
}
if (ret)
return ret;
/* search globally for the symbol */
for_each_sym(list, cur) for_each_sym(list, cur)
if (!strcmp(cur->name, name)) if (GELF_ST_BIND(sym->sym.st_info) == STB_GLOBAL &&
!strcmp(cur->name, name))
return cur; return cur;
return NULL; return NULL;
} }
@ -218,6 +244,7 @@ int main(int argc, char **argv)
GElf_Shdr sh, *shp; GElf_Shdr sh, *shp;
GElf_Ehdr eh; GElf_Ehdr eh;
GElf_Sym sym; GElf_Sym sym;
char *hint = NULL;
/* set elf version (required by libelf) */ /* set elf version (required by libelf) */
if (elf_version(EV_CURRENT) == EV_NONE) if (elf_version(EV_CURRENT) == EV_NONE)
@ -240,12 +267,15 @@ int main(int argc, char **argv)
/* lookup patched functions in vmlinux */ /* lookup patched functions in vmlinux */
for_each_sym(&symlist, cur) { for_each_sym(&symlist, cur) {
if (GELF_ST_TYPE(cur->sym.st_info) == STT_FILE)
hint = cur->name;
if (GELF_ST_TYPE(cur->sym.st_info) != STT_FUNC) if (GELF_ST_TYPE(cur->sym.st_info) != STT_FUNC)
continue; continue;
printf("found patched function %s\n", cur->name); printf("found patched function %s\n", cur->name);
vsym = find_symbol_by_name(&symlistv, cur->name); vsym = find_symbol_by_name(&symlistv, cur, hint);
if (!vsym) if (!vsym)
ERROR("couldn't find patched function in vmlinux"); ERROR("couldn't find patched function in vmlinux");
cur->vm_addr = vsym->sym.st_value; cur->vm_addr = vsym->sym.st_value;