diff --git a/kpatch-build/Makefile b/kpatch-build/Makefile index a874dd3..da96edf 100644 --- a/kpatch-build/Makefile +++ b/kpatch-build/Makefile @@ -31,8 +31,8 @@ all: $(TARGETS) -include $(SOURCES:.c=.d) create-diff-object: create-diff-object.o kpatch-elf.o lookup.o $(INSN) -create-klp-module: create-klp-module.o kpatch-elf.o -create-kpatch-module: create-kpatch-module.o kpatch-elf.o +create-klp-module: create-klp-module.o kpatch-elf.o $(INSN) +create-kpatch-module: create-kpatch-module.o kpatch-elf.o $(INSN) $(PLUGIN): gcc-plugins/ppc64le-plugin.c g++ $(PLUGIN_CFLAGS) $< -o $@ diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 826741d..bebe3bd 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -48,7 +48,6 @@ #include "list.h" #include "lookup.h" -#include "asm/insn.h" #include "kpatch-patch.h" #include "kpatch-elf.h" #include "kpatch-intermediate.h" @@ -85,51 +84,51 @@ struct special_section { * Functions * **********/ -static int is_bundleable(struct symbol *sym) +static bool is_bundleable(struct symbol *sym) { if (sym->type == STT_FUNC && !strncmp(sym->sec->name, ".text.",6) && !strcmp(sym->sec->name + 6, sym->name)) - return 1; + return true; if (sym->type == STT_FUNC && !strncmp(sym->sec->name, ".text.unlikely.",15) && (!strcmp(sym->sec->name + 15, sym->name) || (strstr(sym->name, ".cold") && !strncmp(sym->sec->name + 15, sym->name, strlen(sym->sec->name) - 15)))) - return 1; + return true; if (sym->type == STT_FUNC && !strncmp(sym->sec->name, ".text.hot.",10) && !strcmp(sym->sec->name + 10, sym->name)) - return 1; + return true; if (sym->type == STT_OBJECT && !strncmp(sym->sec->name, ".data.",6) && !strcmp(sym->sec->name + 6, sym->name)) - return 1; + return true; if (sym->type == STT_OBJECT && !strncmp(sym->sec->name, ".data.rel.", 10) && !strcmp(sym->sec->name + 10, sym->name)) - return 1; + return true; if (sym->type == STT_OBJECT && !strncmp(sym->sec->name, ".data.rel.ro.", 13) && !strcmp(sym->sec->name + 13, sym->name)) - return 1; + return true; if (sym->type == STT_OBJECT && !strncmp(sym->sec->name, ".rodata.",8) && !strcmp(sym->sec->name + 8, sym->name)) - return 1; + return true; if (sym->type == STT_OBJECT && !strncmp(sym->sec->name, ".bss.",5) && !strcmp(sym->sec->name + 5, sym->name)) - return 1; + return true; - return 0; + return false; } /* Symbol st_others value for powerpc */ @@ -303,6 +302,12 @@ static bool is_dynamic_debug_symbol(struct symbol *sym) return false; } +static bool is_string_literal_section(struct section *sec) +{ + return !strncmp(sec->name, ".rodata.", 8) && + strstr(sec->name, ".str1."); +} + /* * This function detects whether the given symbol is a "special" static local * variable (for lack of a better term). @@ -506,7 +511,7 @@ static bool rela_equal(struct rela *rela1, struct rela *rela2) return !kpatch_mangled_strcmp(rela_toc1->sym->name, rela_toc2->sym->name); } -static void kpatch_compare_correlated_rela_section(struct section *sec) +static void kpatch_compare_correlated_rela_section(struct section *relasec) { struct rela *rela1, *rela2 = NULL; @@ -514,22 +519,22 @@ static void kpatch_compare_correlated_rela_section(struct section *sec) * On ppc64le, don't compare the .rela.toc section. The .toc and * .rela.toc sections are included as standard elements. */ - if (!strcmp(sec->name, ".rela.toc")) { - sec->status = SAME; + if (!strcmp(relasec->name, ".rela.toc")) { + relasec->status = SAME; return; } - rela2 = list_entry(sec->twin->relas.next, struct rela, list); - list_for_each_entry(rela1, &sec->relas, list) { + rela2 = list_entry(relasec->twin->relas.next, struct rela, list); + list_for_each_entry(rela1, &relasec->relas, list) { if (rela_equal(rela1, rela2)) { rela2 = list_entry(rela2->list.next, struct rela, list); continue; } - sec->status = CHANGED; + relasec->status = CHANGED; return; } - sec->status = SAME; + relasec->status = SAME; } static void kpatch_compare_correlated_nonrela_section(struct section *sec) @@ -577,39 +582,6 @@ out: log_debug("section %s has changed\n", sec->name); } -static unsigned int insn_length(struct kpatch_elf *kelf, void *addr) -{ - struct insn decoded_insn; - char *insn = addr; - - switch(kelf->arch) { - - case X86_64: - insn_init(&decoded_insn, addr, 1); - insn_get_length(&decoded_insn); - return decoded_insn.length; - - case PPC64: - return 4; - - case S390: - switch(insn[0] >> 6) { - case 0: - return 2; - case 1: - case 2: - return 4; - case 3: - return 6; - } - - default: - ERROR("unsupported arch"); - } - - return 0; -} - /* * This function is not comprehensive, i.e. it doesn't detect immediate loads * to *all* registers. It only detects those which have been found in the wild @@ -874,7 +846,7 @@ static enum subsection kpatch_subsection_type(struct section *sec) return SUBSECTION_NORMAL; } -static int kpatch_subsection_changed(struct section *sec1, struct section *sec2) +static bool kpatch_subsection_changed(struct section *sec1, struct section *sec2) { return kpatch_subsection_type(sec1) != kpatch_subsection_type(sec2); } @@ -1138,13 +1110,13 @@ static char *kpatch_section_function_name(struct section *sec) return sec->sym ? sec->sym->name : sec->name; } -static struct symbol *kpatch_find_uncorrelated_rela(struct section *rela_sec, +static struct symbol *kpatch_find_uncorrelated_rela(struct section *relasec, struct symbol *sym) { struct rela *rela, *rela_toc; /* find the patched object's corresponding variable */ - list_for_each_entry(rela, &rela_sec->relas, list) { + list_for_each_entry(rela, &relasec->relas, list) { struct symbol *patched_sym; rela_toc = toc_rela(rela); @@ -1198,34 +1170,34 @@ static struct symbol *kpatch_find_static_twin_in_children(struct symbol *parent, * in the base object, find a corresponding usage of a similarly named symbol * in the patched object. */ -static struct symbol *kpatch_find_static_twin(struct section *sec, +static struct symbol *kpatch_find_static_twin(struct section *relasec, struct symbol *sym) { struct symbol *res; - if (!sec->twin && sec->base->sym) { + if (!relasec->twin && relasec->base->sym) { struct symbol *parent = NULL; /* * The static twin might have been in a .part. symbol in the * original object that got removed in the patched object. */ - parent = kpatch_get_correlated_parent(sec->base->sym); + parent = kpatch_get_correlated_parent(relasec->base->sym); if (parent) - sec = parent->sec->rela; + relasec = parent->sec->rela; } - if (!sec->twin) + if (!relasec->twin) return NULL; - res = kpatch_find_uncorrelated_rela(sec->twin, sym); + res = kpatch_find_uncorrelated_rela(relasec->twin, sym); if (res != NULL) return res; /* Look if reference might have moved to child functions' sections */ - if (sec->twin->base->sym) - return kpatch_find_static_twin_in_children(sec->twin->base->sym, + if (relasec->twin->base->sym) + return kpatch_find_static_twin_in_children(relasec->twin->base->sym, sym); return NULL; @@ -1248,18 +1220,19 @@ static bool kpatch_is_normal_static_local(struct symbol *sym) return true; } -static struct rela *kpatch_find_static_twin_ref(struct section *rela_sec, struct symbol *sym) +static struct rela *kpatch_find_static_twin_ref(struct section *relasec, + struct symbol *sym) { struct rela *rela; - list_for_each_entry(rela, &rela_sec->relas, list) { + list_for_each_entry(rela, &relasec->relas, list) { if (rela->sym == sym->twin) return rela; } /* Reference to static variable might have moved to child function section */ - if (rela_sec->base->sym) { - struct symbol *parent = rela_sec->base->sym; + if (relasec->base->sym) { + struct symbol *parent = relasec->base->sym; struct symbol *child; list_for_each_entry(child, &parent->children, subfunction_node) { @@ -1305,7 +1278,7 @@ static void kpatch_correlate_static_local_variables(struct kpatch_elf *orig, struct kpatch_elf *patched) { struct symbol *sym, *patched_sym; - struct section *sec; + struct section *relasec; struct rela *rela; int bundled, patched_bundled; @@ -1338,14 +1311,14 @@ static void kpatch_correlate_static_local_variables(struct kpatch_elf *orig, * Do the correlations: for each section reference to a static local, * look for a corresponding reference in the section's twin. */ - list_for_each_entry(sec, &orig->sections, list) { + list_for_each_entry(relasec, &orig->sections, list) { - if (!is_rela_section(sec) || - is_debug_section(sec) || - !strcmp(sec->name, ".rela.toc")) + if (!is_rela_section(relasec) || + is_debug_section(relasec) || + !strcmp(relasec->name, ".rela.toc")) continue; - list_for_each_entry(rela, &sec->relas, list) { + list_for_each_entry(rela, &relasec->relas, list) { if (!toc_rela(rela)) continue; /* skip toc constants */ @@ -1358,7 +1331,7 @@ static void kpatch_correlate_static_local_variables(struct kpatch_elf *orig, continue; bundled = sym == sym->sec->sym; - if (bundled && sym->sec == sec->base) { + if (bundled && sym->sec == relasec->base) { /* * A rare case where a static local data * structure references itself. There's no @@ -1371,11 +1344,11 @@ static void kpatch_correlate_static_local_variables(struct kpatch_elf *orig, continue; } - patched_sym = kpatch_find_static_twin(sec, sym); + patched_sym = kpatch_find_static_twin(relasec, sym); if (!patched_sym) DIFF_FATAL("reference to static local variable %s in %s was removed", sym->name, - kpatch_section_function_name(sec)); + kpatch_section_function_name(relasec)); patched_bundled = patched_sym == patched_sym->sec->sym; if (bundled != patched_bundled) @@ -1401,23 +1374,23 @@ static void kpatch_correlate_static_local_variables(struct kpatch_elf *orig, * corresponding reference in the patched object (because a static * local can be referenced by more than one section). */ - list_for_each_entry(sec, &orig->sections, list) { + list_for_each_entry(relasec, &orig->sections, list) { - if (!is_rela_section(sec) || - is_debug_section(sec)) + if (!is_rela_section(relasec) || + is_debug_section(relasec)) continue; - list_for_each_entry(rela, &sec->relas, list) { - struct section *target_sec = sec; + list_for_each_entry(rela, &relasec->relas, list) { + struct section *target_sec = relasec; sym = rela->sym; if (!kpatch_is_normal_static_local(sym)) continue; - if (!sec->twin && sec->base->sym) { + if (!relasec->twin && relasec->base->sym) { struct symbol *parent = NULL; - parent = kpatch_get_correlated_parent(sec->base->sym); + parent = kpatch_get_correlated_parent(relasec->base->sym); if (parent) target_sec = parent->sec->rela; } @@ -1439,13 +1412,13 @@ static void kpatch_correlate_static_local_variables(struct kpatch_elf *orig, * static locals to see if we need to print any warnings about new * variables. */ - list_for_each_entry(sec, &patched->sections, list) { + list_for_each_entry(relasec, &patched->sections, list) { - if (!is_rela_section(sec) || - is_debug_section(sec)) + if (!is_rela_section(relasec) || + is_debug_section(relasec)) continue; - list_for_each_entry(rela, &sec->relas, list) { + list_for_each_entry(rela, &relasec->relas, list) { sym = rela->sym; if (!kpatch_is_normal_static_local(sym)) @@ -1456,7 +1429,7 @@ static void kpatch_correlate_static_local_variables(struct kpatch_elf *orig, log_normal("WARNING: unable to correlate static local variable %s used by %s, assuming variable is new\n", sym->name, - kpatch_section_function_name(sec)); + kpatch_section_function_name(relasec)); return; } } @@ -1476,30 +1449,6 @@ static void kpatch_compare_correlated_elements(struct kpatch_elf *kelf) kpatch_compare_symbols(&kelf->symbols); } -static void rela_insn(const struct section *sec, const struct rela *rela, - struct insn *insn) -{ - unsigned long insn_addr, start, end, rela_addr; - - start = (unsigned long)sec->base->data->d_buf; - end = start + sec->base->sh.sh_size; - - if (end <= start) - ERROR("bad section size"); - - rela_addr = start + rela->offset; - for (insn_addr = start; insn_addr < end; insn_addr += insn->length) { - insn_init(insn, (void *)insn_addr, 1); - insn_get_length(insn); - if (!insn->length) - ERROR("can't decode instruction in section %s at offset 0x%lx", - sec->base->name, insn_addr); - if (rela_addr >= insn_addr && - rela_addr < insn_addr + insn->length) - return; - } -} - static bool is_callback_section(struct section *sec) { static char *callback_sections[] = { @@ -1531,23 +1480,34 @@ static bool is_callback_section(struct section *sec) { */ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) { - struct section *sec; + struct section *relasec; struct rela *rela; struct symbol *sym; - unsigned int add_off; + long target_off; + bool found = false; log_debug("\n"); - list_for_each_entry(sec, &kelf->sections, list) { - if (!is_rela_section(sec) || - is_debug_section(sec)) + list_for_each_entry(relasec, &kelf->sections, list) { + if (!is_rela_section(relasec) || is_debug_section(relasec)) continue; - list_for_each_entry(rela, &sec->relas, list) { + list_for_each_entry(rela, &relasec->relas, list) { if (rela->sym->type != STT_SECTION || !rela->sym->sec) continue; + /* + * These sections don't have symbols associated with + * them: + */ + if (!strcmp(rela->sym->name, ".toc") || + !strcmp(rela->sym->name, ".fixup") || + !strcmp(rela->sym->name, ".altinstr_replacement") || + !strcmp(rela->sym->name, ".altinstr_aux") || + !strcmp(rela->sym->name, ".text..refcount")) + continue; + /* * Replace references to bundled sections with their * symbols. @@ -1569,27 +1529,7 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) continue; } - switch(kelf->arch) { - case PPC64: - add_off = 0; - break; - case X86_64: - if (rela->type == R_X86_64_PC32 || - rela->type == R_X86_64_PLT32) { - struct insn insn; - rela_insn(sec, rela, &insn); - add_off = (unsigned int)((long)insn.next_byte - - (long)sec->base->data->d_buf - - rela->offset); - } else if (rela->type == R_X86_64_64 || - rela->type == R_X86_64_32S) - add_off = 0; - else - continue; - break; - default: - ERROR("unsupported arch"); - } + target_off = rela_target_offset(kelf, relasec, rela); /* * Attempt to replace references to unbundled sections @@ -1605,7 +1545,8 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) start = sym->sym.st_value; end = sym->sym.st_value + sym->sym.st_size; - if (!is_text_section(sym->sec) && + if (is_text_section(relasec->base) && + !is_text_section(sym->sec) && rela->type == R_X86_64_32S && rela->addend == (long)sym->sec->sh.sh_size && end == (long)sym->sec->sh.sh_size) { @@ -1641,20 +1582,32 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) * &(var1+sizeof(var1)) will always * be the same as &var2. */ + } else if (target_off == start && target_off == end) { - } else if (rela->addend + add_off < start || - rela->addend + add_off >= end) + /* + * Allow replacement for references to + * empty symbols. + */ + + } else if (target_off < start || target_off >= end) continue; log_debug("%s: replacing %s+%ld reference with %s+%ld\n", - sec->name, + relasec->name, rela->sym->name, rela->addend, sym->name, rela->addend - start); + found = true; rela->sym = sym; rela->addend -= start; break; } + + if (!found && !is_string_literal_section(rela->sym->sec) && + strncmp(rela->sym->name, ".rodata", 7)) { + ERROR("%s+0x%x: can't find replacement symbol for %s+%ld reference", + relasec->base->name, rela->offset, rela->sym->name, rela->addend); + } } } log_debug("\n"); @@ -1772,12 +1725,6 @@ static void kpatch_include_symbol(struct symbol *sym) kpatch_include_section(sym->sec); } -static bool is_string_literal_section(struct section *sec) -{ - return !strncmp(sec->name, ".rodata.", 8) && - strstr(sec->name, ".str1."); -} - static void kpatch_include_standard_elements(struct kpatch_elf *kelf) { struct section *sec; @@ -1824,12 +1771,12 @@ static void kpatch_include_standard_elements(struct kpatch_elf *kelf) list_entry(kelf->symbols.next, struct symbol, list)->include = 1; } -static int kpatch_include_callback_elements(struct kpatch_elf *kelf) +static bool kpatch_include_callback_elements(struct kpatch_elf *kelf) { struct section *sec; struct symbol *sym; struct rela *rela; - int found = 0; + bool found = false; /* include load/unload sections */ list_for_each_entry(sec, &kelf->sections, list) { @@ -1837,7 +1784,7 @@ static int kpatch_include_callback_elements(struct kpatch_elf *kelf) continue; sec->include = 1; - found = 1; + found = true; if (is_rela_section(sec)) { /* include callback dependencies */ rela = list_entry(sec->relas.next, struct rela, list); @@ -1941,7 +1888,7 @@ static void kpatch_print_changes(struct kpatch_elf *kelf) static void kpatch_migrate_symbols(struct list_head *src, struct list_head *dst, - int (*select)(struct symbol *)) + bool (*select)(struct symbol *)) { struct symbol *sym, *safe; @@ -2164,17 +2111,17 @@ static int fixup_barrier_nospec_group_size(struct kpatch_elf *kelf, int offset) */ static int fixup_group_size(struct kpatch_elf *kelf, int offset) { - struct section *sec; + struct section *relasec; struct rela *rela; int found; - sec = find_section_by_name(&kelf->sections, ".rela__ex_table"); - if (!sec) + relasec = find_section_by_name(&kelf->sections, ".rela__ex_table"); + if (!relasec) ERROR("missing .rela__ex_table section"); /* find beginning of this group */ found = 0; - list_for_each_entry(rela, &sec->relas, list) { + list_for_each_entry(rela, &relasec->relas, list) { if (!strcmp(rela->sym->name, ".fixup") && rela->addend == offset) { found = 1; @@ -2187,7 +2134,7 @@ static int fixup_group_size(struct kpatch_elf *kelf, int offset) /* find beginning of next group */ found = 0; - list_for_each_entry_continue(rela, &sec->relas, list) { + list_for_each_entry_continue(rela, &relasec->relas, list) { if (!strcmp(rela->sym->name, ".fixup") && rela->addend > offset) { found = 1; @@ -2287,7 +2234,7 @@ static struct special_section special_sections[] = { }; static bool should_keep_jump_label(struct lookup_table *lookup, - struct section *sec, + struct section *relasec, unsigned int group_offset, unsigned int group_size, int *jump_labels_found) @@ -2302,7 +2249,7 @@ static bool should_keep_jump_label(struct lookup_table *lookup, * struct. It has three fields: code, target, and key. Each field has * a relocation associated with it. */ - list_for_each_entry(rela, &sec->relas, list) { + list_for_each_entry(rela, &relasec->relas, list) { if (rela->offset >= group_offset && rela->offset < group_offset + group_size) { if (i == 0) @@ -2389,29 +2336,29 @@ static bool should_keep_jump_label(struct lookup_table *lookup, } static bool should_keep_rela_group(struct lookup_table *lookup, - struct section *sec, unsigned int offset, + struct section *relasec, unsigned int offset, unsigned int size, int *jump_labels_found) { struct rela *rela; bool found = false; /* check if any relas in the group reference any changed functions */ - list_for_each_entry(rela, &sec->relas, list) { + list_for_each_entry(rela, &relasec->relas, list) { if (rela->offset >= offset && rela->offset < offset + size && rela->sym->type == STT_FUNC && rela->sym->sec->include) { found = true; log_debug("new/changed symbol %s found in special section %s\n", - rela->sym->name, sec->name); + rela->sym->name, relasec->name); } } if (!found) return false; - if (!strcmp(sec->name, ".rela__jump_table")) - return should_keep_jump_label(lookup, sec, offset, size, + if (!strcmp(relasec->name, ".rela__jump_table")) + return should_keep_jump_label(lookup, relasec, offset, size, jump_labels_found); return true; @@ -2428,13 +2375,13 @@ static void kpatch_update_ex_table_addend(struct kpatch_elf *kelf, int group_size) { struct rela *rela; - struct section *sec; + struct section *relasec; - sec = find_section_by_name(&kelf->sections, ".rela__ex_table"); - if (!sec) + relasec = find_section_by_name(&kelf->sections, ".rela__ex_table"); + if (!relasec) ERROR("missing .rela__ex_table section"); - list_for_each_entry(rela, &sec->relas, list) { + list_for_each_entry(rela, &relasec->relas, list) { if (!strcmp(rela->sym->name, ".fixup") && rela->addend >= src_offset && rela->addend < src_offset + group_size) @@ -2445,7 +2392,7 @@ static void kpatch_update_ex_table_addend(struct kpatch_elf *kelf, static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, struct lookup_table *lookup, struct special_section *special, - struct section *sec) + struct section *relasec) { struct rela *rela, *safe; char *src, *dest; @@ -2454,15 +2401,15 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, LIST_HEAD(newrelas); - src = sec->base->data->d_buf; + src = relasec->base->data->d_buf; /* alloc buffer for new base section */ - dest = malloc(sec->base->sh.sh_size); + dest = malloc(relasec->base->sh.sh_size); if (!dest) ERROR("malloc"); /* Restore the stashed r_addend from kpatch_update_ex_table_addend. */ if (!strcmp(special->name, "__ex_table")) { - list_for_each_entry(rela, &sec->relas, list) { + list_for_each_entry(rela, &relasec->relas, list) { if (!strcmp(rela->sym->name, ".fixup")) rela->addend = rela->rela.r_addend; } @@ -2470,7 +2417,7 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, src_offset = 0; dest_offset = 0; - for ( ; src_offset < sec->base->sh.sh_size; src_offset += group_size) { + for ( ; src_offset < relasec->base->sh.sh_size; src_offset += group_size) { group_size = special->group_size(kelf, src_offset); @@ -2482,10 +2429,10 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, * contains the data but doesn't go past the end of the * section. */ - if (src_offset + group_size > sec->base->sh.sh_size) - group_size = (unsigned int)(sec->base->sh.sh_size - src_offset); + if (src_offset + group_size > relasec->base->sh.sh_size) + group_size = (unsigned int)(relasec->base->sh.sh_size - src_offset); - if (!should_keep_rela_group(lookup, sec, src_offset, group_size, + if (!should_keep_rela_group(lookup, relasec, src_offset, group_size, &jump_labels_found)) continue; @@ -2494,7 +2441,7 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, * aren't sorted (e.g. .rela.fixup), so go through the entire * rela list each time. */ - list_for_each_entry_safe(rela, safe, &sec->relas, list) { + list_for_each_entry_safe(rela, safe, &relasec->relas, list) { if (rela->offset >= src_offset && rela->offset < src_offset + group_size) { /* copy rela entry */ @@ -2525,21 +2472,21 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, if (!dest_offset) { /* no changed or global functions referenced */ - sec->status = sec->base->status = SAME; - sec->include = sec->base->include = 0; + relasec->status = relasec->base->status = SAME; + relasec->include = relasec->base->include = 0; free(dest); return; } /* overwrite with new relas list */ - list_replace(&newrelas, &sec->relas); + list_replace(&newrelas, &relasec->relas); /* include both rela and base sections */ - sec->include = 1; - sec->base->include = 1; + relasec->include = 1; + relasec->base->include = 1; /* include secsym so .kpatch.arch relas can point to section symbols */ - if (sec->base->secsym) - sec->base->secsym->include = 1; + if (relasec->base->secsym) + relasec->base->secsym->include = 1; /* * Update text section data buf and size. @@ -2547,8 +2494,8 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, * The rela section's data buf and size will be regenerated in * kpatch_rebuild_rela_section_data(). */ - sec->base->data->d_buf = dest; - sec->base->data->d_size = dest_offset; + relasec->base->data->d_buf = dest; + relasec->base->data->d_size = dest_offset; } #define ORC_IP_PTR_SIZE 4 @@ -2645,19 +2592,33 @@ next: static void kpatch_check_relocations(struct kpatch_elf *kelf) { struct rela *rela; - struct section *sec; - Elf_Data *sdata; + struct section *relasec; + long sec_size; + long sec_off; - list_for_each_entry(sec, &kelf->sections, list) { - if (!is_rela_section(sec)) + list_for_each_entry(relasec, &kelf->sections, list) { + if (!is_rela_section(relasec)) continue; - list_for_each_entry(rela, &sec->relas, list) { - if (rela->sym->sec) { - sdata = rela->sym->sec->data; - if ((long)rela->sym->sym.st_value + rela->addend > (long)sdata->d_size) { - ERROR("out-of-range relocation %s+%lx in %s", rela->sym->name, - rela->addend, sec->name); - } + list_for_each_entry(rela, &relasec->relas, list) { + if (!rela->sym->sec) + continue; + + sec_size = rela->sym->sec->data->d_size; + sec_off = (long)rela->sym->sym.st_value + + rela_target_offset(kelf, relasec, rela); + + /* + * This check isn't perfect: we still allow relocations + * to the end of a section. There are real instances + * of that, including ORC entries, LOCKDEP=n + * zero-length '__key' passing, and the loop edge case + * described in kpatch_replace_sections_syms(). For + * now, just allow all such cases. + */ + if (sec_off < 0 || sec_off > sec_size) { + ERROR("%s+0x%x: out-of-range relocation %s+%lx", + relasec->base->name, rela->offset, + rela->sym->name, rela->addend); } } } @@ -3056,7 +3017,7 @@ static void kpatch_create_patches_sections(struct kpatch_elf *kelf, } -static int kpatch_is_core_module_symbol(char *name) +static bool kpatch_is_core_module_symbol(char *name) { return (!strcmp(name, "kpatch_shadow_alloc") || !strcmp(name, "kpatch_shadow_free") || @@ -3076,11 +3037,11 @@ static int function_ptr_rela(const struct rela *rela) } static bool need_dynrela(struct kpatch_elf *kelf, struct lookup_table *table, - struct section *sec, const struct rela *rela) + struct section *relasec, const struct rela *rela) { struct lookup_result symbol; - if (is_debug_section(sec)) + if (is_debug_section(relasec)) return false; /* @@ -3092,7 +3053,7 @@ static bool need_dynrela(struct kpatch_elf *kelf, struct lookup_table *table, return false; /* v5.13+ kernels use relative jump labels */ - if (rela->type == R_PPC64_REL64 && strcmp(sec->name, ".rela__jump_table")) + if (rela->type == R_PPC64_REL64 && strcmp(relasec->name, ".rela__jump_table")) return false; /* @@ -3249,7 +3210,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, char *pmod_name) { int nr, index; - struct section *sec, *ksym_sec, *krela_sec; + struct section *relasec, *ksym_sec, *krela_sec; struct rela *rela, *rela2, *safe; struct symbol *strsym, *ksym_sec_sym; struct kpatch_symbol *ksyms; @@ -3261,12 +3222,12 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, /* count rela entries that need to be dynamic */ nr = 0; - list_for_each_entry(sec, &kelf->sections, list) { - if (!is_rela_section(sec)) + list_for_each_entry(relasec, &kelf->sections, list) { + if (!is_rela_section(relasec)) continue; - if (!strcmp(sec->name, ".rela.kpatch.funcs")) + if (!strcmp(relasec->name, ".rela.kpatch.funcs")) continue; - list_for_each_entry(rela, &sec->relas, list) { + list_for_each_entry(rela, &relasec->relas, list) { /* upper bound on number of kpatch relas and symbols */ nr++; @@ -3282,7 +3243,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, * internal symbol function pointer check which is done * via .toc indirection in need_dynrela(). */ - if (need_dynrela(kelf, table, sec, rela)) + if (need_dynrela(kelf, table, relasec, rela)) toc_rela(rela)->need_dynrela = 1; } } @@ -3310,12 +3271,12 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, /* populate sections */ index = 0; - list_for_each_entry(sec, &kelf->sections, list) { - if (!is_rela_section(sec)) + list_for_each_entry(relasec, &kelf->sections, list) { + if (!is_rela_section(relasec)) continue; - if (!strcmp(sec->name, ".rela.kpatch.funcs") || - !strcmp(sec->name, ".rela.kpatch.relocations") || - !strcmp(sec->name, ".rela.kpatch.symbols")) + if (!strcmp(relasec->name, ".rela.kpatch.funcs") || + !strcmp(relasec->name, ".rela.kpatch.relocations") || + !strcmp(relasec->name, ".rela.kpatch.symbols")) continue; special = false; @@ -3323,11 +3284,11 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, if ((s->arch & kelf->arch) == 0) continue; - if (!strcmp(sec->base->name, s->name)) + if (!strcmp(relasec->base->name, s->name)) special = true; } - list_for_each_entry_safe(rela, safe, &sec->relas, list) { + list_for_each_entry_safe(rela, safe, &relasec->relas, list) { if (!rela->need_dynrela) { rela->sym->strip = SYMBOL_USED; continue; @@ -3348,7 +3309,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, */ if (!KLP_ARCH && !vmlinux && special) ERROR("unsupported dynrela reference to symbol '%s' in module-specific special section '%s'", - rela->sym->name, sec->base->name); + rela->sym->name, relasec->base->name); if (!lookup_symbol(table, rela->sym, &symbol)) ERROR("can't find symbol '%s' in symbol table", @@ -3394,11 +3355,11 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, /* add rela to fill in krelas[index].dest field */ ALLOC_LINK(rela2, &krela_sec->rela->relas); - if (sec->base->secsym) - rela2->sym = sec->base->secsym; + if (relasec->base->secsym) + rela2->sym = relasec->base->secsym; else ERROR("can't create dynrela for section %s (symbol %s): no bundled or section symbol", - sec->name, rela->sym->name); + relasec->name, rela->sym->name); rela2->type = absolute_rela_type(kelf); rela2->addend = rela->offset; @@ -3706,7 +3667,7 @@ static void kpatch_build_strings_section_data(struct kpatch_elf *kelf) static void kpatch_no_sibling_calls_ppc64le(struct kpatch_elf *kelf) { struct symbol *sym; - unsigned int insn; + unsigned char *insn; unsigned int offset; if (kelf->arch != PPC64) @@ -3718,7 +3679,7 @@ static void kpatch_no_sibling_calls_ppc64le(struct kpatch_elf *kelf) for (offset = 0; offset < sym->sec->data->d_size; offset += 4) { - insn = *(unsigned int *)(sym->sec->data->d_buf + offset); + insn = sym->sec->data->d_buf + offset; /* * The instruction 0x48000000 can be assumed to be a @@ -3733,7 +3694,8 @@ static void kpatch_no_sibling_calls_ppc64le(struct kpatch_elf *kelf) * there's a REL24 relocation for the address which * will be written by the linker or the kernel. */ - if (insn != 0x48000000) + if (insn[3] != 0x48 || insn[2] != 0x00 || + insn[1] != 0x00 || insn[0] != 0x00) continue; /* Make sure it's not a branch-to-self: */ @@ -3833,7 +3795,7 @@ int main(int argc, char *argv[]) struct arguments arguments; int num_changed, callbacks_exist, new_globals_exist; struct lookup_table *lookup; - struct section *sec, *symtab; + struct section *relasec, *symtab; char *orig_obj, *patched_obj, *parent_name; char *parent_symtab, *mod_symvers, *patch_name, *output_obj; @@ -3958,12 +3920,12 @@ int main(int argc, char *argv[]) if (!symtab) ERROR("missing .symtab section"); - list_for_each_entry(sec, &kelf_out->sections, list) { - if (!is_rela_section(sec)) + list_for_each_entry(relasec, &kelf_out->sections, list) { + if (!is_rela_section(relasec)) continue; - sec->sh.sh_link = symtab->index; - sec->sh.sh_info = sec->base->index; - kpatch_rebuild_rela_section_data(sec); + relasec->sh.sh_link = symtab->index; + relasec->sh.sh_info = relasec->base->index; + kpatch_rebuild_rela_section_data(relasec); } kpatch_check_relocations(kelf_out); diff --git a/kpatch-build/create-klp-module.c b/kpatch-build/create-klp-module.c index c036b94..e942b9e 100644 --- a/kpatch-build/create-klp-module.c +++ b/kpatch-build/create-klp-module.c @@ -122,37 +122,37 @@ static struct section *find_or_add_klp_relasec(struct kpatch_elf *kelf, struct section *base, char *objname) { - struct section *sec; + struct section *relasec; char buf[256]; /* .klp.rela.objname.secname */ snprintf(buf, 256, KLP_RELASEC_PREFIX "%s.%s", objname, base->name); - list_for_each_entry(sec, &kelf->sections, list) { - if (!strcmp(sec->name, buf)) - return sec; + list_for_each_entry(relasec, &kelf->sections, list) { + if (!strcmp(relasec->name, buf)) + return relasec; } - ALLOC_LINK(sec, &kelf->sections); - sec->name = strdup(buf); - if (!sec->name) + ALLOC_LINK(relasec, &kelf->sections); + relasec->name = strdup(buf); + if (!relasec->name) ERROR("strdup"); - sec->base = base; + relasec->base = base; - INIT_LIST_HEAD(&sec->relas); + INIT_LIST_HEAD(&relasec->relas); - sec->data = malloc(sizeof(*sec->data)); - if (!sec->data) + relasec->data = malloc(sizeof(*relasec->data)); + if (!relasec->data) ERROR("malloc"); - sec->data->d_type = ELF_T_RELA; + relasec->data->d_type = ELF_T_RELA; /* sh_info and sh_link are set when rebuilding rela sections */ - sec->sh.sh_type = SHT_RELA; - sec->sh.sh_entsize = sizeof(GElf_Rela); - sec->sh.sh_addralign = 8; - sec->sh.sh_flags = SHF_RELA_LIVEPATCH | SHF_INFO_LINK | SHF_ALLOC; + relasec->sh.sh_type = SHT_RELA; + relasec->sh.sh_entsize = sizeof(GElf_Rela); + relasec->sh.sh_addralign = 8; + relasec->sh.sh_flags = SHF_RELA_LIVEPATCH | SHF_INFO_LINK | SHF_ALLOC; - return sec; + return relasec; } /* @@ -429,7 +429,7 @@ static struct argp argp = { options, parse_opt, args_doc, 0 }; int main(int argc, char *argv[]) { struct kpatch_elf *kelf; - struct section *symtab, *sec; + struct section *symtab, *relasec; struct section *ksymsec, *krelasec, *strsec; struct arguments arguments; char *strings; @@ -493,12 +493,12 @@ int main(int argc, char *argv[]) if (!symtab) ERROR("missing .symtab section"); - list_for_each_entry(sec, &kelf->sections, list) { - if (!is_rela_section(sec)) + list_for_each_entry(relasec, &kelf->sections, list) { + if (!is_rela_section(relasec)) continue; - sec->sh.sh_link = symtab->index; - sec->sh.sh_info = sec->base->index; - kpatch_rebuild_rela_section_data(sec); + relasec->sh.sh_link = symtab->index; + relasec->sh.sh_info = relasec->base->index; + kpatch_rebuild_rela_section_data(relasec); } kpatch_create_shstrtab(kelf); diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index 41a9a30..9f0fc6d 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -97,6 +97,18 @@ logger() { fi } +trace_on() { + if [[ $DEBUG -eq 1 ]] || [[ $DEBUG -ge 3 ]]; then + set -o xtrace + fi +} + +trace_off() { + if [[ $DEBUG -eq 1 ]] || [[ $DEBUG -ge 3 ]]; then + set +o xtrace + fi +} + save_env() { export -p | grep -wv -e 'OLDPWD=' -e 'PWD=' > "$ENVFILE" } @@ -619,9 +631,7 @@ if [[ ${#PATCH_LIST[@]} -eq 0 ]]; then exit 1 fi -if [[ $DEBUG -eq 1 ]] || [[ $DEBUG -ge 3 ]]; then - set -o xtrace -fi +trace_on if [[ -n "$SRCRPM" ]]; then if [[ -n "$ARCHVERSION" ]]; then @@ -836,9 +846,11 @@ fi # kernel option checking +trace_off "reading .config" # Don't check external file. # shellcheck disable=SC1090 source "$CONFIGFILE" +trace_on [[ "$DISTRO" = openEuler ]] && [[ -z "$CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY" ]] && \ die "openEuler kernel doesn't have 'CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY' enabled" @@ -988,26 +1000,28 @@ fi grep -q vmlinux "$KERNEL_SRCDIR/Module.symvers" || die "truncated $KERNEL_SRCDIR/Module.symvers file" if [[ -n "$CONFIG_MODVERSIONS" ]]; then - while read -ra sym_line; do - if [[ ${#sym_line[@]} -lt 4 ]]; then - die "Malformed ${TEMPDIR}/Module.symvers file" - fi + trace_off "reading Module.symvers" + while read -ra sym_line; do + if [[ ${#sym_line[@]} -lt 4 ]]; then + die "Malformed ${TEMPDIR}/Module.symvers file" + fi - sym=${sym_line[1]} + sym=${sym_line[1]} - read -ra patched_sym_line <<< "$(grep "\s$sym\s" "$BUILDDIR/Module.symvers")" - if [[ ${#patched_sym_line[@]} -lt 4 ]]; then - die "Malformed symbol entry for ${sym} in ${BUILDDIR}/Module.symvers file" - fi + read -ra patched_sym_line <<< "$(grep "\s$sym\s" "$BUILDDIR/Module.symvers")" + if [[ ${#patched_sym_line[@]} -lt 4 ]]; then + die "Malformed symbol entry for ${sym} in ${BUILDDIR}/Module.symvers file" + fi - # Assume that both original and patched symvers have the same format. - # In both cases, the symbol should have the same CRC, belong to the same - # Module/Namespace and have the same export type. - if [[ ${#sym_line[@]} -ne ${#patched_sym_line[@]} || \ - "${sym_line[*]}" != "${patched_sym_line[*]}" ]]; then - warn "Version disagreement for symbol ${sym}" - fi - done < "${TEMPDIR}/Module.symvers" + # Assume that both original and patched symvers have the same format. + # In both cases, the symbol should have the same CRC, belong to the same + # Module/Namespace and have the same export type. + if [[ ${#sym_line[@]} -ne ${#patched_sym_line[@]} || \ + "${sym_line[*]}" != "${patched_sym_line[*]}" ]]; then + warn "Version disagreement for symbol ${sym}" + fi + done < "${TEMPDIR}/Module.symvers" + trace_on fi # Read as words, no quotes. diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c index c6ef6f1..6a43ef5 100644 --- a/kpatch-build/kpatch-elf.c +++ b/kpatch-build/kpatch-elf.c @@ -31,6 +31,7 @@ #include #include +#include "asm/insn.h" #include "kpatch-elf.h" /******************* @@ -53,18 +54,18 @@ char *status_str(enum status status) return NULL; } -int is_rela_section(struct section *sec) +bool is_rela_section(struct section *sec) { return (sec->sh.sh_type == SHT_RELA); } -int is_text_section(struct section *sec) +bool is_text_section(struct section *sec) { return (sec->sh.sh_type == SHT_PROGBITS && (sec->sh.sh_flags & SHF_EXECINSTR)); } -int is_debug_section(struct section *sec) +bool is_debug_section(struct section *sec) { char *name; if (is_rela_section(sec)) @@ -164,7 +165,105 @@ int offset_of_string(struct list_head *list, char *name) return index; } -void kpatch_create_rela_list(struct kpatch_elf *kelf, struct section *sec) +static void rela_insn(const struct section *sec, const struct rela *rela, + struct insn *insn) +{ + unsigned long insn_addr, start, end, rela_addr; + + start = (unsigned long)sec->data->d_buf; + end = start + sec->sh.sh_size; + + if (end <= start) + ERROR("bad section size"); + + rela_addr = start + rela->offset; + for (insn_addr = start; insn_addr < end; insn_addr += insn->length) { + insn_init(insn, (void *)insn_addr, 1); + insn_get_length(insn); + if (!insn->length) + ERROR("can't decode instruction in section %s at offset 0x%lx", + sec->name, insn_addr); + if (rela_addr >= insn_addr && + rela_addr < insn_addr + insn->length) + return; + } + + ERROR("can't find instruction for rela at %s+0x%x", + sec->name, rela->offset); +} + +/* + * Return the addend, adjusted for any PC-relative relocation trickery, to + * point to the relevant symbol offset. + */ +long rela_target_offset(struct kpatch_elf *kelf, struct section *relasec, + struct rela *rela) +{ + long add_off; + struct section *sec = relasec->base; + + switch(kelf->arch) { + case PPC64: + add_off = 0; + break; + case X86_64: + if (!is_text_section(sec) || + rela->type == R_X86_64_64 || + rela->type == R_X86_64_32S) + add_off = 0; + else if (rela->type == R_X86_64_PC32 || + rela->type == R_X86_64_PLT32 || + rela->type == R_X86_64_NONE) { + struct insn insn; + rela_insn(sec, rela, &insn); + add_off = (long)insn.next_byte - + (long)sec->data->d_buf - + rela->offset; + } else + ERROR("unhandled rela type %d", rela->type); + break; + default: + ERROR("unsupported arch\n"); + } + + return rela->addend + add_off; +} + +unsigned int insn_length(struct kpatch_elf *kelf, void *addr) +{ + struct insn decoded_insn; + char *insn = addr; + + switch(kelf->arch) { + + case X86_64: + insn_init(&decoded_insn, addr, 1); + insn_get_length(&decoded_insn); + return decoded_insn.length; + + case PPC64: + return 4; + + case S390: + switch(insn[0] >> 6) { + case 0: + return 2; + case 1: + case 2: + return 4; + case 3: + return 6; + } + + default: + ERROR("unsupported arch"); + } + + return 0; +} + +static void kpatch_create_rela_list(struct kpatch_elf *kelf, + struct section *relasec) { int index = 0, skip = 0; struct rela *rela; @@ -172,28 +271,28 @@ void kpatch_create_rela_list(struct kpatch_elf *kelf, struct section *sec) unsigned long rela_nr; /* find matching base (text/data) section */ - sec->base = find_section_by_index(&kelf->sections, sec->sh.sh_info); - if (!sec->base) - ERROR("can't find base section for rela section %s", sec->name); + relasec->base = find_section_by_index(&kelf->sections, relasec->sh.sh_info); + if (!relasec->base) + ERROR("can't find base section for rela section %s", relasec->name); /* create reverse link from base section to this rela section */ - sec->base->rela = sec; + relasec->base->rela = relasec; - rela_nr = sec->sh.sh_size / sec->sh.sh_entsize; + rela_nr = relasec->sh.sh_size / relasec->sh.sh_entsize; log_debug("\n=== rela list for %s (%ld entries) ===\n", - sec->base->name, rela_nr); + relasec->base->name, rela_nr); - if (is_debug_section(sec)) { + if (is_debug_section(relasec)) { log_debug("skipping rela listing for .debug_* section\n"); skip = 1; } /* read and store the rela entries */ while (rela_nr--) { - ALLOC_LINK(rela, &sec->relas); + ALLOC_LINK(rela, &relasec->relas); - if (!gelf_getrela(sec->data, index, &rela->rela)) + if (!gelf_getrela(relasec->data, index, &rela->rela)) ERROR("gelf_getrela"); index++; @@ -206,7 +305,9 @@ void kpatch_create_rela_list(struct kpatch_elf *kelf, struct section *sec) ERROR("could not find rela entry symbol\n"); if (rela->sym->sec && (rela->sym->sec->sh.sh_flags & SHF_STRINGS)) { - rela->string = rela->sym->sec->data->d_buf + rela->addend; + rela->string = rela->sym->sec->data->d_buf + + rela->sym->sym.st_value + + rela_target_offset(kelf, relasec, rela); if (!rela->string) ERROR("could not lookup rela string for %s+%ld", rela->sym->name, rela->addend); @@ -223,7 +324,7 @@ void kpatch_create_rela_list(struct kpatch_elf *kelf, struct section *sec) } } -void kpatch_create_section_list(struct kpatch_elf *kelf) +static void kpatch_create_section_list(struct kpatch_elf *kelf) { Elf_Scn *scn = NULL; struct section *sec; @@ -277,7 +378,7 @@ void kpatch_create_section_list(struct kpatch_elf *kelf) ERROR("expected NULL"); } -void kpatch_create_symbol_list(struct kpatch_elf *kelf) +static void kpatch_create_symbol_list(struct kpatch_elf *kelf) { struct section *symtab; struct symbol *sym; @@ -346,7 +447,7 @@ struct kpatch_elf *kpatch_elf_open(const char *name) Elf *elf; int fd; struct kpatch_elf *kelf; - struct section *sec; + struct section *relasec; GElf_Ehdr ehdr; fd = open(name, O_RDONLY); @@ -368,16 +469,6 @@ struct kpatch_elf *kpatch_elf_open(const char *name) /* read and store section, symbol entries from file */ kelf->elf = elf; kelf->fd = fd; - kpatch_create_section_list(kelf); - kpatch_create_symbol_list(kelf); - - /* for each rela section, read and store the rela entries */ - list_for_each_entry(sec, &kelf->sections, list) { - if (!is_rela_section(sec)) - continue; - INIT_LIST_HEAD(&sec->relas); - kpatch_create_rela_list(kelf, sec); - } if (!gelf_getehdr(kelf->elf, &ehdr)) ERROR("gelf_getehdr"); @@ -391,6 +482,18 @@ struct kpatch_elf *kpatch_elf_open(const char *name) default: ERROR("Unsupported target architecture"); } + + kpatch_create_section_list(kelf); + kpatch_create_symbol_list(kelf); + + /* for each rela section, read and store the rela entries */ + list_for_each_entry(relasec, &kelf->sections, list) { + if (!is_rela_section(relasec)) + continue; + INIT_LIST_HEAD(&relasec->relas); + kpatch_create_rela_list(kelf, relasec); + } + return kelf; } @@ -442,22 +545,22 @@ next: } } -int is_null_sym(struct symbol *sym) +bool is_null_sym(struct symbol *sym) { return !strlen(sym->name); } -int is_file_sym(struct symbol *sym) +bool is_file_sym(struct symbol *sym) { return sym->type == STT_FILE; } -int is_local_func_sym(struct symbol *sym) +bool is_local_func_sym(struct symbol *sym) { return sym->bind == STB_LOCAL && sym->type == STT_FUNC; } -int is_local_sym(struct symbol *sym) +bool is_local_sym(struct symbol *sym) { return sym->bind == STB_LOCAL; } diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h index abc6efd..3bc6e76 100644 --- a/kpatch-build/kpatch-elf.h +++ b/kpatch-build/kpatch-elf.h @@ -129,9 +129,9 @@ struct kpatch_elf { * Helper functions ******************/ char *status_str(enum status status); -int is_rela_section(struct section *sec); -int is_text_section(struct section *sec); -int is_debug_section(struct section *sec); +bool is_rela_section(struct section *sec); +bool is_text_section(struct section *sec); +bool is_debug_section(struct section *sec); struct section *find_section_by_index(struct list_head *list, unsigned int index); struct section *find_section_by_name(struct list_head *list, const char *name); @@ -152,6 +152,9 @@ struct rela *find_rela_by_offset(struct section *relasec, unsigned int offset); unsigned int absolute_rela_type(struct kpatch_elf *kelf); int offset_of_string(struct list_head *list, char *name); +long rela_target_offset(struct kpatch_elf *kelf, struct section *relasec, + struct rela *rela); +unsigned int insn_length(struct kpatch_elf *kelf, void *addr); #ifndef R_PPC64_ENTRY #define R_PPC64_ENTRY 118 @@ -160,16 +163,13 @@ int offset_of_string(struct list_head *list, char *name); /************* * Functions * **********/ -void kpatch_create_rela_list(struct kpatch_elf *kelf, struct section *sec); -void kpatch_create_section_list(struct kpatch_elf *kelf); -void kpatch_create_symbol_list(struct kpatch_elf *kelf); struct kpatch_elf *kpatch_elf_open(const char *name); void kpatch_dump_kelf(struct kpatch_elf *kelf); -int is_null_sym(struct symbol *sym); -int is_file_sym(struct symbol *sym); -int is_local_func_sym(struct symbol *sym); -int is_local_sym(struct symbol *sym); +bool is_null_sym(struct symbol *sym); +bool is_file_sym(struct symbol *sym); +bool is_local_func_sym(struct symbol *sym); +bool is_local_sym(struct symbol *sym); void print_strtab(char *buf, size_t size); void kpatch_create_shstrtab(struct kpatch_elf *kelf);