commit 680f66b8216418f83f6e2b7fd2e8f8cec3cfd639 Author: Joe Lawrence Date: Tue Feb 1 21:26:12 2022 -0500 review changes diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 053a0c3ccd34..c19c091c36de 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -60,8 +60,6 @@ error(EXIT_STATUS_DIFF_FATAL, 0, "unreconcilable difference"); \ }) -unsigned int ABSOLUTE_RELA_TYPE; - char *childobj; enum subsection { @@ -72,13 +70,6 @@ enum subsection { enum loglevel loglevel = NORMAL; -enum architecture { - X86_64 = 0x1 << 0, - PPC64 = 0x1 << 1, -}; - -enum architecture target_arch; - bool KLP_ARCH; /******************* @@ -164,9 +155,10 @@ static int is_bundleable(struct symbol *sym) * the object file. The local entry point is 8 bytes after the global entry * point. */ -static int is_gcc6_localentry_bundled_sym(struct symbol *sym) +static bool is_gcc6_localentry_bundled_sym(struct kpatch_elf *kelf, + struct symbol *sym) { - if (target_arch == PPC64) { + if (kelf->target_arch == PPC64) { return ((PPC64_LOCAL_ENTRY_OFFSET(sym->sym.st_other) != 0) && sym->sym.st_value == 8); } @@ -227,7 +219,7 @@ static void kpatch_bundle_symbols(struct kpatch_elf *kelf) list_for_each_entry(sym, &kelf->symbols, list) { if (is_bundleable(sym)) { if (sym->sym.st_value != 0 && - !is_gcc6_localentry_bundled_sym(sym)) { + !is_gcc6_localentry_bundled_sym(kelf, sym)) { ERROR("symbol %s at offset %lu within section %s, expected 0", sym->name, sym->sym.st_value, sym->sec->name); @@ -759,12 +751,17 @@ static bool kpatch_line_macro_change_only_ppc64le(struct section *sec) return true; } -static bool kpatch_line_macro_change_only(struct section *sec) +static bool kpatch_line_macro_change_only(struct kpatch_elf *kelf, + struct section *sec) { - if (target_arch == X86_64) - return kpatch_line_macro_change_only_x86_64(sec); - else if (target_arch == PPC64) - return kpatch_line_macro_change_only_ppc64le(sec); + switch(kelf->target_arch) { + case PPC64: + return kpatch_line_macro_change_only_ppc64le(sec); + case X86_64: + return kpatch_line_macro_change_only_x86_64(sec); + default: + ERROR("unsupported arch"); + } return 0; } @@ -788,9 +785,10 @@ static bool kpatch_changed_child_needs_parent_profiling(struct symbol *sym) return false; } -static void kpatch_compare_sections(struct list_head *seclist) +static void kpatch_compare_sections(struct kpatch_elf *kelf) { struct section *sec; + struct list_head *seclist = &kelf->sections; /* compare all sections */ list_for_each_entry(sec, seclist, list) { @@ -802,7 +800,7 @@ static void kpatch_compare_sections(struct list_head *seclist) /* exclude WARN-only, might_sleep changes */ list_for_each_entry(sec, seclist, list) { - if (kpatch_line_macro_change_only(sec)) { + if (kpatch_line_macro_change_only(kelf, sec)) { log_debug("reverting macro / line number section %s status to SAME\n", sec->name); sec->status = SAME; @@ -1445,7 +1443,7 @@ static void kpatch_correlate_elfs(struct kpatch_elf *kelf_orig, static void kpatch_compare_correlated_elements(struct kpatch_elf *kelf) { /* lists are already correlated at this point */ - kpatch_compare_sections(&kelf->sections); + kpatch_compare_sections(kelf); kpatch_compare_symbols(&kelf->symbols); } @@ -1507,6 +1505,7 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) struct section *sec; struct rela *rela; struct symbol *sym; + unsigned int add_off; log_debug("\n"); @@ -1516,7 +1515,6 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) continue; list_for_each_entry(rela, &sec->relas, list) { - unsigned int add_off = 0; if (rela->sym->type != STT_SECTION || !rela->sym->sec) continue; @@ -1542,24 +1540,28 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) continue; } - if (target_arch == PPC64) - add_off = 0; - else if (target_arch == 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) + switch(kelf->target_arch) { + case PPC64: add_off = 0; - else - continue; + 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"); } - /* * Attempt to replace references to unbundled sections * with their symbols. @@ -1924,6 +1926,7 @@ static void kpatch_migrate_included_elements(struct kpatch_elf *kelf, struct kpa if (!out) ERROR("malloc"); memset(out, 0, sizeof(*out)); + out->target_arch = kelf->target_arch; INIT_LIST_HEAD(&out->sections); INIT_LIST_HEAD(&out->symbols); INIT_LIST_HEAD(&out->strings); @@ -2214,7 +2217,6 @@ static struct special_section special_sections[] = { { .name = ".retpoline_sites", .arch = X86_64, - .arch = X86_64, .group_size = retpoline_sites_group_size, }, { @@ -2782,7 +2784,7 @@ static void kpatch_create_kpatch_arch_section(struct kpatch_elf *kelf, char *obj ERROR("can't find .kpatch.strings symbol"); for (special = special_sections; special->name; special++) { - if ((special->arch & target_arch) == 0) + if ((special->arch & kelf->target_arch) == 0) continue; if (strcmp(special->name, ".parainstructions") && @@ -2796,7 +2798,6 @@ static void kpatch_create_kpatch_arch_section(struct kpatch_elf *kelf, char *obj /* entries[index].sec */ ALLOC_LINK(rela, &karch_sec->rela->relas); rela->sym = sec->secsym; - rela->type = ABSOLUTE_RELA_TYPE; rela->addend = 0; rela->offset = (unsigned int)(index * sizeof(struct kpatch_arch) + \ offsetof(struct kpatch_arch, sec)); @@ -2804,7 +2805,7 @@ static void kpatch_create_kpatch_arch_section(struct kpatch_elf *kelf, char *obj /* entries[index].objname */ ALLOC_LINK(rela, &karch_sec->rela->relas); rela->sym = strsym; - rela->type = ABSOLUTE_RELA_TYPE; + rela->type = absolute_rela_type(kelf); rela->addend = offset_of_string(&kelf->strings, objname); rela->offset = (unsigned int)(index * sizeof(struct kpatch_arch) + \ offsetof(struct kpatch_arch, objname)); @@ -2826,7 +2827,7 @@ static void kpatch_process_special_sections(struct kpatch_elf *kelf, int altinstr = 0; for (special = special_sections; special->name; special++) { - if ((special->arch & target_arch) == 0) + if ((special->arch & kelf->target_arch) == 0) continue; sec = find_section_by_name(&kelf->sections, special->name); @@ -2970,7 +2971,7 @@ static void kpatch_create_patches_sections(struct kpatch_elf *kelf, */ ALLOC_LINK(rela, &relasec->relas); rela->sym = sym; - rela->type = ABSOLUTE_RELA_TYPE; + rela->type = absolute_rela_type(kelf); rela->addend = 0; rela->offset = (unsigned int)(index * sizeof(*funcs)); @@ -2980,7 +2981,7 @@ static void kpatch_create_patches_sections(struct kpatch_elf *kelf, */ ALLOC_LINK(rela, &relasec->relas); rela->sym = strsym; - rela->type = ABSOLUTE_RELA_TYPE; + rela->type = absolute_rela_type(kelf); rela->addend = offset_of_string(&kelf->strings, sym->name); rela->offset = (unsigned int)(index * sizeof(*funcs) + offsetof(struct kpatch_patch_func, name)); @@ -2991,7 +2992,7 @@ static void kpatch_create_patches_sections(struct kpatch_elf *kelf, */ ALLOC_LINK(rela, &relasec->relas); rela->sym = strsym; - rela->type = ABSOLUTE_RELA_TYPE; + rela->type = absolute_rela_type(kelf); rela->addend = objname_offset; rela->offset = (unsigned int)(index * sizeof(*funcs) + offsetof(struct kpatch_patch_func,objname)); @@ -3024,7 +3025,8 @@ static int function_ptr_rela(const struct rela *rela) rela->type == R_PPC64_TOC16_LO_DS)); } -static bool need_dynrela(struct lookup_table *table, struct section *sec, const struct rela *rela) +static bool need_dynrela(struct kpatch_elf *kelf, struct lookup_table *table, + struct section *sec, const struct rela *rela) { struct lookup_result symbol; @@ -3126,7 +3128,7 @@ static bool need_dynrela(struct lookup_table *table, struct section *sec, const if (symbol.exported) { - if (is_gcc6_localentry_bundled_sym(rela->sym)) { + if (is_gcc6_localentry_bundled_sym(kelf, rela->sym)) { /* * On powerpc, the symbol is global and exported, but * it was also in the changed object file. In this @@ -3227,7 +3229,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(table, sec, rela)) + if (need_dynrela(kelf, table, sec, rela)) toc_rela(rela)->need_dynrela = 1; } } @@ -3265,7 +3267,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, special = false; for (s = special_sections; s->name; s++) { - if ((s->arch & target_arch) == 0) + if ((s->arch & kelf->target_arch) == 0) continue; if (!strcmp(sec->base->name, s->name)) @@ -3316,7 +3318,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, /* add rela to fill in ksyms[index].name field */ ALLOC_LINK(rela2, &ksym_sec->rela->relas); rela2->sym = strsym; - rela2->type = ABSOLUTE_RELA_TYPE; + rela2->type = absolute_rela_type(kelf); rela2->addend = offset_of_string(&kelf->strings, rela->sym->name); rela2->offset = (unsigned int)(index * sizeof(*ksyms) + \ offsetof(struct kpatch_symbol, name)); @@ -3324,13 +3326,13 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, /* add rela to fill in ksyms[index].objname field */ ALLOC_LINK(rela2, &ksym_sec->rela->relas); rela2->sym = strsym; - rela2->type = ABSOLUTE_RELA_TYPE; + rela2->type = absolute_rela_type(kelf); rela2->addend = offset_of_string(&kelf->strings, symbol.objname); rela2->offset = (unsigned int)(index * sizeof(*ksyms) + \ offsetof(struct kpatch_symbol, objname)); /* Fill in krelas[index] */ - if (is_gcc6_localentry_bundled_sym(rela->sym) && + if (is_gcc6_localentry_bundled_sym(kelf, rela->sym) && rela->addend == (int)rela->sym->sym.st_value) rela->addend -= rela->sym->sym.st_value; krelas[index].addend = rela->addend; @@ -3345,7 +3347,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, ERROR("can't create dynrela for section %s (symbol %s): no bundled or section symbol", sec->name, rela->sym->name); - rela2->type = ABSOLUTE_RELA_TYPE; + rela2->type = absolute_rela_type(kelf); rela2->addend = rela->offset; rela2->offset = (unsigned int)(index * sizeof(*krelas) + \ offsetof(struct kpatch_relocation, dest)); @@ -3353,7 +3355,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, /* add rela to fill in krelas[index].objname field */ ALLOC_LINK(rela2, &krela_sec->rela->relas); rela2->sym = strsym; - rela2->type = ABSOLUTE_RELA_TYPE; + rela2->type = absolute_rela_type(kelf); rela2->addend = offset_of_string(&kelf->strings, objname); rela2->offset = (unsigned int)(index * sizeof(*krelas) + \ offsetof(struct kpatch_relocation, objname)); @@ -3361,7 +3363,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, /* add rela to fill in krelas[index].ksym field */ ALLOC_LINK(rela2, &krela_sec->rela->relas); rela2->sym = ksym_sec_sym; - rela2->type = ABSOLUTE_RELA_TYPE; + rela2->type = absolute_rela_type(kelf); rela2->addend = (unsigned int)(index * sizeof(*ksyms)); rela2->offset = (unsigned int)(index * sizeof(*krelas) + \ offsetof(struct kpatch_relocation, ksym)); @@ -3424,7 +3426,7 @@ static void kpatch_create_callbacks_objname_rela(struct kpatch_elf *kelf, char * if (!strcmp(callbackp->name, sec->name)) { ALLOC_LINK(rela, &sec->relas); rela->sym = strsym; - rela->type = ABSOLUTE_RELA_TYPE; + rela->type = absolute_rela_type(kelf); rela->addend = objname_offset; rela->offset = callbackp->offset; break; @@ -3462,6 +3464,7 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) /* populate sections */ index = 0; list_for_each_entry(sym, &kelf->symbols, list) { + if (sym->type != STT_FUNC || sym->status == SAME) continue; @@ -3471,24 +3474,41 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) continue; } - if (target_arch == X86_64) { - rela = list_first_entry(&sym->sec->rela->relas, struct rela, list); + switch(kelf->target_arch) { + case PPC64: { + bool found = false; - /* - * For "call fentry", the relocation points to 1 byte past the - * beginning of the instruction. - */ - insn_offset = rela->offset - 1; + list_for_each_entry(rela, &sym->sec->rela->relas, list) + if (!strcmp(rela->sym->name, "_mcount")) { + found = true; + break; + } - if (rela->type == R_X86_64_NONE) { - void *newdata; + if (!found) + ERROR("%s: unexpected missing call to _mcount()", __func__); + + insn_offset = rela->offset; + break; + } + case X86_64: { unsigned char *insn; + void *newdata; + + rela = list_first_entry(&sym->sec->rela->relas, struct rela, list); + + /* + * For "call fentry", the relocation points to 1 byte past the + * beginning of the instruction. + */ + insn_offset = rela->offset - 1; /* * R_X86_64_NONE is only generated by older versions of * kernel/gcc which use the mcount script. There's a * NOP instead of a call to fentry. */ + if (rela->type != R_X86_64_NONE) + break; /* Make a writable copy of the text section data */ newdata = malloc(sym->sec->data->d_size); @@ -3513,20 +3533,10 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) insn[4] = 0; rela->type = R_X86_64_PC32; + break; } - } else if (target_arch == PPC64) { - bool found = false; - - list_for_each_entry(rela, &sym->sec->rela->relas, list) - if (!strcmp(rela->sym->name, "_mcount")) { - found = true; - break; - } - - if (!found) - ERROR("%s: unexpected missing call to _mcount()", __func__); - - insn_offset = rela->offset; + default: + ERROR("unsupported arch"); } /* @@ -3536,7 +3546,7 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) */ ALLOC_LINK(mcount_rela, &relasec->relas); mcount_rela->sym = sym; - mcount_rela->type = ABSOLUTE_RELA_TYPE; + mcount_rela->type = absolute_rela_type(kelf); mcount_rela->addend = insn_offset - sym->sym.st_value; mcount_rela->offset = (unsigned int) (index * sizeof(*funcs)); @@ -3647,7 +3657,7 @@ static void kpatch_no_sibling_calls_ppc64le(struct kpatch_elf *kelf) unsigned int insn; unsigned int offset; - if (target_arch != PPC64) + if (kelf->target_arch != PPC64) return; list_for_each_entry(sym, &kelf->symbols, list) { @@ -3693,47 +3703,32 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf) if (sym->type != STT_FUNC || !sym->sec || !sym->sec->rela) continue; - if (target_arch == PPC64) { - list_for_each_entry(rela, &sym->sec->rela->relas, list) { - if (!strcmp(rela->sym->name, "_mcount")) { - sym->has_func_profiling = 1; - break; + switch(kelf->target_arch) { + case PPC64: + list_for_each_entry(rela, &sym->sec->rela->relas, list) { + if (!strcmp(rela->sym->name, "_mcount")) { + sym->has_func_profiling = 1; + break; + } } - } - } else if (target_arch == X86_64) { - rela = list_first_entry(&sym->sec->rela->relas, struct rela, - list); - if ((rela->type != R_X86_64_NONE && - rela->type != R_X86_64_PC32 && - rela->type != R_X86_64_PLT32) || - strcmp(rela->sym->name, "__fentry__")) - continue; + break; + case X86_64: + rela = list_first_entry(&sym->sec->rela->relas, struct rela, + list); + if ((rela->type != R_X86_64_NONE && + rela->type != R_X86_64_PC32 && + rela->type != R_X86_64_PLT32) || + strcmp(rela->sym->name, "__fentry__")) + continue; - sym->has_func_profiling = 1; + sym->has_func_profiling = 1; + break; + default: + ERROR("unsupported arch"); } } } -static void set_target_architecture(struct kpatch_elf *kelf) -{ - GElf_Ehdr ehdr; - - if (!gelf_getehdr(kelf->elf, &ehdr)) - ERROR("gelf_getehdr"); - - switch (ehdr.e_machine) { - case (EM_X86_64) : - target_arch = X86_64; - ABSOLUTE_RELA_TYPE = R_X86_64_64; - break; - case (EM_PPC64) : - target_arch = PPC64; - ABSOLUTE_RELA_TYPE = R_PPC64_ADDR64; - break; - default: ERROR("Unsupported target architecture"); - } -} - struct arguments { char *args[7]; bool debug, klp_arch; @@ -3810,9 +3805,8 @@ int main(int argc, char *argv[]) childobj = basename(orig_obj); kelf_orig = kpatch_elf_open(orig_obj); - set_target_architecture(kelf_orig); - kpatch_find_func_profiling_calls(kelf_orig); kelf_patched = kpatch_elf_open(patched_obj); + kpatch_find_func_profiling_calls(kelf_orig); kpatch_find_func_profiling_calls(kelf_patched); kpatch_compare_elf_headers(kelf_orig->elf, kelf_patched->elf); diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c index bbeec6a2cec2..596d1a58a14d 100644 --- a/kpatch-build/kpatch-elf.c +++ b/kpatch-build/kpatch-elf.c @@ -132,6 +132,19 @@ struct rela *find_rela_by_offset(struct section *relasec, unsigned int offset) return NULL; } +unsigned int absolute_rela_type(struct kpatch_elf *kelf) +{ + switch(kelf->target_arch) { + case PPC64: + return R_PPC64_ADDR64; + case X86_64: + return R_X86_64_64; + default: + ERROR("unsupported arch"); + } + return 0; +} + /* returns the offset of the string in the string table */ int offset_of_string(struct list_head *list, char *name) { @@ -323,6 +336,7 @@ struct kpatch_elf *kpatch_elf_open(const char *name) int fd; struct kpatch_elf *kelf; struct section *sec; + GElf_Ehdr ehdr; fd = open(name, O_RDONLY); if (fd == -1) @@ -354,6 +368,18 @@ struct kpatch_elf *kpatch_elf_open(const char *name) kpatch_create_rela_list(kelf, sec); } + if (!gelf_getehdr(kelf->elf, &ehdr)) + ERROR("gelf_getehdr"); + switch (ehdr.e_machine) { + case EM_PPC64: + kelf->target_arch = PPC64; + break; + case EM_X86_64: + kelf->target_arch = X86_64; + break; + default: + ERROR("Unsupported target architecture"); + } return kelf; } diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h index 2045f42774d5..cfd256a1241b 100644 --- a/kpatch-build/kpatch-elf.h +++ b/kpatch-build/kpatch-elf.h @@ -109,8 +109,14 @@ struct string { char *name; }; +enum architecture { + PPC64 = 0x1 << 0, + X86_64 = 0x1 << 1, +}; + struct kpatch_elf { Elf *elf; + enum architecture target_arch; struct list_head sections; struct list_head symbols; struct list_head strings; @@ -142,6 +148,7 @@ struct rela *find_rela_by_offset(struct section *relasec, unsigned int offset); list_add_tail(&(_new)->list, (_list)); \ } +unsigned int absolute_rela_type(struct kpatch_elf *kelf); int offset_of_string(struct list_head *list, char *name); #ifndef R_PPC64_ENTRY