mirror of
https://github.com/dynup/kpatch
synced 2025-04-25 04:27:56 +00:00
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:
parent
c09ed67945
commit
75ceca4f33
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user