mirror of https://github.com/dynup/kpatch
Switch to per-file lookup table pointers.
So far create-diff-object worked only with objectfiles built from a single source file. To support object-files built from multiple sources such as linked vmlinux.o, we call locals_match() for each of STT_FILE symbols and store the pointer to the beginning of appropriate symbol block in lookup table in each symbol. Signed-off-by: Artem Savkov <asavkov@redhat.com>
This commit is contained in:
parent
db442d1405
commit
720768767d
|
@ -926,6 +926,10 @@ static void __kpatch_correlate_section(struct section *sec1, struct section *sec
|
|||
static void kpatch_correlate_symbol(struct symbol *sym1, struct symbol *sym2)
|
||||
{
|
||||
CORRELATE_ELEMENT(sym1, sym2, "symbol");
|
||||
if (sym1->lookup_table_file_sym && !sym2->lookup_table_file_sym)
|
||||
sym2->lookup_table_file_sym = sym1->lookup_table_file_sym;
|
||||
else if (!sym1->lookup_table_file_sym && sym2->lookup_table_file_sym)
|
||||
sym1->lookup_table_file_sym = sym2->lookup_table_file_sym;
|
||||
}
|
||||
|
||||
static void kpatch_correlate_static_local(struct symbol *sym1, struct symbol *sym2)
|
||||
|
@ -2858,43 +2862,6 @@ static void kpatch_process_special_sections(struct kpatch_elf *kelf,
|
|||
kpatch_regenerate_orc_sections(kelf);
|
||||
}
|
||||
|
||||
static struct sym_compare_type *kpatch_elf_locals(struct kpatch_elf *kelf)
|
||||
{
|
||||
struct symbol *sym;
|
||||
int i = 0, sym_num = 0;
|
||||
struct sym_compare_type *sym_array;
|
||||
|
||||
list_for_each_entry(sym, &kelf->symbols, list) {
|
||||
if (sym->bind != STB_LOCAL)
|
||||
continue;
|
||||
if (sym->type != STT_FUNC && sym->type != STT_OBJECT)
|
||||
continue;
|
||||
|
||||
sym_num++;
|
||||
}
|
||||
|
||||
if (!sym_num)
|
||||
return NULL;
|
||||
|
||||
sym_array = malloc((sym_num + 1) * sizeof(struct sym_compare_type));
|
||||
if (!sym_array)
|
||||
ERROR("malloc");
|
||||
|
||||
list_for_each_entry(sym, &kelf->symbols, list) {
|
||||
if (sym->bind != STB_LOCAL)
|
||||
continue;
|
||||
if (sym->type != STT_FUNC && sym->type != STT_OBJECT)
|
||||
continue;
|
||||
|
||||
sym_array[i].type = sym->type;
|
||||
sym_array[i++].name = strdup(sym->name);
|
||||
}
|
||||
sym_array[i].type = 0;
|
||||
sym_array[i].name = NULL;
|
||||
|
||||
return sym_array;
|
||||
}
|
||||
|
||||
static void kpatch_create_patches_sections(struct kpatch_elf *kelf,
|
||||
struct lookup_table *table,
|
||||
char *objname)
|
||||
|
@ -3724,10 +3691,8 @@ int main(int argc, char *argv[])
|
|||
int num_changed, callbacks_exist, new_globals_exist;
|
||||
struct lookup_table *lookup;
|
||||
struct section *sec, *symtab;
|
||||
struct symbol *sym;
|
||||
char *hint = NULL, *orig_obj, *patched_obj, *parent_name;
|
||||
char *orig_obj, *patched_obj, *parent_name;
|
||||
char *parent_symtab, *mod_symvers, *patch_name, *output_obj;
|
||||
struct sym_compare_type *base_locals, *sym_comp;
|
||||
|
||||
memset(&arguments, 0, sizeof(arguments));
|
||||
argp_parse (&argp, argc, argv, 0, NULL, &arguments);
|
||||
|
@ -3761,21 +3726,7 @@ int main(int argc, char *argv[])
|
|||
kpatch_detect_child_functions(kelf_base);
|
||||
kpatch_detect_child_functions(kelf_patched);
|
||||
|
||||
list_for_each_entry(sym, &kelf_base->symbols, list) {
|
||||
if (sym->type == STT_FILE) {
|
||||
hint = strdup(sym->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hint) {
|
||||
log_normal("WARNING: FILE symbol not found in base. Stripped object file or assembly source?\n");
|
||||
return EXIT_STATUS_NO_CHANGE;
|
||||
}
|
||||
|
||||
base_locals = kpatch_elf_locals(kelf_base);
|
||||
|
||||
lookup = lookup_open(parent_symtab, parent_name, mod_symvers, hint,
|
||||
base_locals);
|
||||
lookup = lookup_open(parent_symtab, parent_name, mod_symvers, kelf_base);
|
||||
|
||||
kpatch_mark_grouped_sections(kelf_patched);
|
||||
kpatch_replace_sections_syms(kelf_base);
|
||||
|
@ -3816,7 +3767,6 @@ int main(int argc, char *argv[])
|
|||
log_debug("no changed functions were found, but callbacks exist\n");
|
||||
else {
|
||||
log_debug("no changed functions were found\n");
|
||||
free(hint);
|
||||
return EXIT_STATUS_NO_CHANGE;
|
||||
}
|
||||
}
|
||||
|
@ -3832,11 +3782,6 @@ int main(int argc, char *argv[])
|
|||
*/
|
||||
kpatch_elf_teardown(kelf_patched);
|
||||
|
||||
for (sym_comp = base_locals; sym_comp && sym_comp->name; sym_comp++)
|
||||
free(sym_comp->name);
|
||||
free(base_locals);
|
||||
free(hint);
|
||||
|
||||
kpatch_no_sibling_calls_ppc64le(kelf_out);
|
||||
|
||||
/* create strings, patches, and dynrelas sections */
|
||||
|
|
|
@ -76,6 +76,7 @@ struct symbol {
|
|||
struct section *sec;
|
||||
GElf_Sym sym;
|
||||
char *name;
|
||||
struct object_symbol *lookup_table_file_sym;
|
||||
unsigned int index;
|
||||
unsigned char bind, type;
|
||||
enum status status;
|
||||
|
|
|
@ -56,7 +56,6 @@ struct lookup_table {
|
|||
int obj_nr, exp_nr;
|
||||
struct object_symbol *obj_syms;
|
||||
struct export_symbol *exp_syms;
|
||||
struct object_symbol *local_syms;
|
||||
char *objname;
|
||||
};
|
||||
|
||||
|
@ -92,25 +91,31 @@ static int maybe_discarded_sym(const char *name)
|
|||
}
|
||||
|
||||
static int locals_match(struct lookup_table *table, int idx,
|
||||
struct sym_compare_type *child_locals)
|
||||
struct symbol *file_sym, struct list_head *sym_list)
|
||||
{
|
||||
struct sym_compare_type *child;
|
||||
struct object_symbol *sym;
|
||||
struct symbol *sym;
|
||||
struct object_symbol *table_sym;
|
||||
int i, found;
|
||||
|
||||
i = idx + 1;
|
||||
for_each_obj_symbol_continue(i, sym, table) {
|
||||
if (sym->type == STT_FILE)
|
||||
for_each_obj_symbol_continue(i, table_sym, table) {
|
||||
if (table_sym->type == STT_FILE)
|
||||
break;
|
||||
if (sym->bind != STB_LOCAL)
|
||||
if (table_sym->bind != STB_LOCAL)
|
||||
continue;
|
||||
if (sym->type != STT_FUNC && sym->type != STT_OBJECT)
|
||||
if (table_sym->type != STT_FUNC && table_sym->type != STT_OBJECT)
|
||||
continue;
|
||||
|
||||
found = 0;
|
||||
for (child = child_locals; child->name; child++) {
|
||||
if (child->type == sym->type &&
|
||||
!strcmp(child->name, sym->name)) {
|
||||
sym = file_sym;
|
||||
list_for_each_entry_continue(sym, sym_list, list) {
|
||||
if (sym->type == STT_FILE)
|
||||
break;
|
||||
if (sym->bind != STB_LOCAL)
|
||||
continue;
|
||||
|
||||
if (sym->type == table_sym->type &&
|
||||
!strcmp(sym->name, table_sym->name)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -120,27 +125,33 @@ static int locals_match(struct lookup_table *table, int idx,
|
|||
return 0;
|
||||
}
|
||||
|
||||
for (child = child_locals; child->name; child++) {
|
||||
sym = file_sym;
|
||||
list_for_each_entry_continue(sym, sym_list, list) {
|
||||
if (sym->type == STT_FILE)
|
||||
break;
|
||||
if (sym->bind != STB_LOCAL)
|
||||
continue;
|
||||
if (sym->type != STT_FUNC && table_sym->type != STT_OBJECT)
|
||||
continue;
|
||||
/*
|
||||
* Symbols which get discarded at link time are missing from
|
||||
* the lookup table, so skip them.
|
||||
*/
|
||||
if (maybe_discarded_sym(child->name))
|
||||
if (maybe_discarded_sym(sym->name))
|
||||
continue;
|
||||
|
||||
found = 0;
|
||||
i = idx + 1;
|
||||
for_each_obj_symbol_continue(i, sym, table) {
|
||||
if (sym->type == STT_FILE)
|
||||
for_each_obj_symbol_continue(i, table_sym, table) {
|
||||
if (table_sym->type == STT_FILE)
|
||||
break;
|
||||
if (sym->bind != STB_LOCAL)
|
||||
if (table_sym->bind != STB_LOCAL)
|
||||
continue;
|
||||
if (sym->type != STT_FUNC && sym->type != STT_OBJECT)
|
||||
continue;
|
||||
if (maybe_discarded_sym(sym->name))
|
||||
if (maybe_discarded_sym(table_sym->name))
|
||||
continue;
|
||||
|
||||
if (!strcmp(child->name, sym->name)) {
|
||||
if (sym->type == table_sym->type &&
|
||||
!strcmp(sym->name, table_sym->name)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -153,32 +164,56 @@ static int locals_match(struct lookup_table *table, int idx,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void find_local_syms(struct lookup_table *table, char *hint,
|
||||
struct sym_compare_type *child_locals)
|
||||
static void find_local_syms(struct lookup_table *table, struct symbol *file_sym,
|
||||
struct list_head *sym_list)
|
||||
{
|
||||
struct object_symbol *sym;
|
||||
struct object_symbol *lookup_table_file_sym = NULL;
|
||||
int i;
|
||||
|
||||
if (!child_locals)
|
||||
return;
|
||||
|
||||
for_each_obj_symbol(i, sym, table) {
|
||||
if (sym->type != STT_FILE)
|
||||
continue;
|
||||
if (strcmp(hint, sym->name))
|
||||
if (strcmp(file_sym->name, sym->name))
|
||||
continue;
|
||||
if (!locals_match(table, i, child_locals))
|
||||
if (!locals_match(table, i, file_sym, sym_list))
|
||||
continue;
|
||||
if (table->local_syms)
|
||||
if (lookup_table_file_sym)
|
||||
ERROR("found duplicate matches for %s local symbols in %s symbol table",
|
||||
hint, table->objname);
|
||||
file_sym->name, table->objname);
|
||||
|
||||
table->local_syms = sym;
|
||||
lookup_table_file_sym = sym;
|
||||
}
|
||||
|
||||
if (!table->local_syms)
|
||||
if (!lookup_table_file_sym)
|
||||
ERROR("couldn't find matching %s local symbols in %s symbol table",
|
||||
hint, table->objname);
|
||||
file_sym->name, table->objname);
|
||||
|
||||
list_for_each_entry_continue(file_sym, sym_list, list) {
|
||||
if (file_sym->type == STT_FILE)
|
||||
break;
|
||||
file_sym->lookup_table_file_sym = lookup_table_file_sym;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Because there can be duplicate symbols and duplicate filenames we need to
|
||||
* correlate each symbol from the elf file to it's corresponding symbol in
|
||||
* lookup table. Both the elf file and the lookup table can be split on
|
||||
* STT_FILE symbols into blocks of symbols originating from a single source
|
||||
* file. We then compare local symbol lists from both blocks and store the
|
||||
* pointer to STT_FILE symbol in lookup table for later use in
|
||||
* lookup_local_symbol().
|
||||
*/
|
||||
static void find_local_syms_multiple(struct lookup_table *table,
|
||||
struct kpatch_elf *kelf)
|
||||
{
|
||||
struct symbol *sym;
|
||||
|
||||
list_for_each_entry(sym, &kelf->symbols, list) {
|
||||
if (sym->type == STT_FILE)
|
||||
find_local_syms(table, sym, &kelf->symbols);
|
||||
}
|
||||
}
|
||||
|
||||
/* Strip the path and replace '-' with '_' */
|
||||
|
@ -371,8 +406,7 @@ static void symvers_read(struct lookup_table *table, char *path)
|
|||
}
|
||||
|
||||
struct lookup_table *lookup_open(char *symtab_path, char *objname,
|
||||
char *symvers_path, char *hint,
|
||||
struct sym_compare_type *locals)
|
||||
char *symvers_path, struct kpatch_elf *kelf)
|
||||
{
|
||||
struct lookup_table *table;
|
||||
|
||||
|
@ -384,7 +418,8 @@ struct lookup_table *lookup_open(char *symtab_path, char *objname,
|
|||
table->objname = objname;
|
||||
symtab_read(table, symtab_path);
|
||||
symvers_read(table, symvers_path);
|
||||
find_local_syms(table, hint, locals);
|
||||
|
||||
find_local_syms_multiple(table, kelf);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
@ -415,16 +450,13 @@ static bool lookup_local_symbol(struct lookup_table *table,
|
|||
unsigned long sympos = 0;
|
||||
int i, in_file = 0;
|
||||
|
||||
if (!table->local_syms)
|
||||
return false;
|
||||
|
||||
memset(result, 0, sizeof(*result));
|
||||
for_each_obj_symbol(i, sym, table) {
|
||||
if (sym->bind == STB_LOCAL && !strcmp(sym->name,
|
||||
lookup_sym->name))
|
||||
sympos++;
|
||||
|
||||
if (table->local_syms == sym) {
|
||||
if (lookup_sym->lookup_table_file_sym == sym) {
|
||||
in_file = 1;
|
||||
continue;
|
||||
}
|
||||
|
@ -437,7 +469,6 @@ static bool lookup_local_symbol(struct lookup_table *table,
|
|||
|
||||
if (sym->bind == STB_LOCAL && !strcmp(sym->name,
|
||||
lookup_sym->name)) {
|
||||
|
||||
if (result->objname)
|
||||
ERROR("duplicate local symbol found for %s",
|
||||
lookup_sym->name);
|
||||
|
|
|
@ -14,14 +14,8 @@ struct lookup_result {
|
|||
bool global, exported;
|
||||
};
|
||||
|
||||
struct sym_compare_type {
|
||||
char *name;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct lookup_table *lookup_open(char *symtab_path, char *objname,
|
||||
char *symvers_path, char *hint,
|
||||
struct sym_compare_type *locals);
|
||||
char *symvers_path, struct kpatch_elf *kelf);
|
||||
void lookup_close(struct lookup_table *table);
|
||||
bool lookup_symbol(struct lookup_table *table, struct symbol *sym,
|
||||
struct lookup_result *result);
|
||||
|
|
Loading…
Reference in New Issue