From 61ce2b5a5324233febdd15ce815bab0f19f7aef1 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 5 May 2021 22:37:46 -0700 Subject: [PATCH 1/5] create-diff-object: Add --arch option We could be generating patches for architectures that are different from the current one. Use "--arch" to specify the architecture. Signed-off-by: Bill Wendling --- kpatch-build/create-diff-object.c | 262 +++++++++++++++++------------- kpatch-build/kpatch-build | 12 +- 2 files changed, 161 insertions(+), 113 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 14eb1f587..82c5b6ddf 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -60,11 +60,15 @@ error(EXIT_STATUS_DIFF_FATAL, 0, "unreconcilable difference"); \ }) -#ifdef __powerpc64__ -#define ABSOLUTE_RELA_TYPE R_PPC64_ADDR64 -#else -#define ABSOLUTE_RELA_TYPE R_X86_64_64 -#endif +#define ABSOLUTE_RELA_TYPE \ +({ \ + unsigned int __ret; \ + if (arch == X86_64) \ + __ret = R_X86_64_64; \ + else if (arch == PPC64) \ + __ret = R_PPC64_ADDR64; \ + __ret; \ +}) char *childobj; @@ -76,6 +80,15 @@ enum subsection { enum loglevel loglevel = NORMAL; +enum architecture { + X86_64 = 0x1 << 0, + PPC64 = 0x1 << 1, + DEFAULT_ARCH = X86_64, +}; + +/* Default to the x86 architecture. */ +enum architecture arch = DEFAULT_ARCH; + bool KLP_ARCH; /******************* @@ -83,6 +96,7 @@ bool KLP_ARCH; * ****************/ struct special_section { char *name; + enum architecture arch; int (*group_size)(struct kpatch_elf *kelf, int offset); }; @@ -137,41 +151,37 @@ static int is_bundleable(struct symbol *sym) return 0; } -#ifdef __powerpc64__ /* Symbol st_others value for powerpc */ #define STO_PPC64_LOCAL_BIT 5 #define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT) #define PPC64_LOCAL_ENTRY_OFFSET(other) \ (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2) -/* - * On ppc64le, the function prologue generated by GCC 6+ has the sequence: - * - * .globl my_func - * .type my_func, @function - * .quad .TOC.-my_func - * my_func: - * .reloc ., R_PPC64_ENTRY ; optional - * ld r2,-8(r12) - * add r2,r2,r12 - * .localentry my_func, .-my_func - * - * my_func is the global entry point, which, when called, sets up the TOC. - * .localentry is the local entry point, for calls to the function from within - * 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) -{ - return ((PPC64_LOCAL_ENTRY_OFFSET(sym->sym.st_other) != 0) && - sym->sym.st_value == 8); -} -#else static int is_gcc6_localentry_bundled_sym(struct symbol *sym) { + if (arch == PPC64) + /* + * On ppc64le, the function prologue generated by GCC 6+ has + * the sequence: + * + * .globl my_func + * .type my_func, @function + * .quad .TOC.-my_func + * my_func: + * .reloc ., R_PPC64_ENTRY ; optional + * ld r2,-8(r12) + * add r2,r2,r12 + * .localentry my_func, .-my_func + * + * my_func is the global entry point, which, when called, sets + * up the TOC. .localentry is the local entry point, for calls + * to the function from within the object file. The local + * entry point is 8 bytes after the global entry point. + */ + return ((PPC64_LOCAL_ENTRY_OFFSET(sym->sym.st_other) != 0) && + sym->sym.st_value == 8); return 0; } -#endif /* * On ppc64le, when a function references data, it does so indirectly, via the @@ -577,7 +587,6 @@ static void kpatch_compare_correlated_section(struct section *sec) log_debug("section %s has changed\n", sec->name); } -#ifdef __x86_64__ /* * Determine if a section has changed only due to a WARN* or might_sleep * macro call's embedding of the line number into an instruction operand. @@ -609,7 +618,7 @@ static void kpatch_compare_correlated_section(struct section *sec) * 3) (optional) __warned.xxxxx static local rela * 4) warn_slowpath_* or __might_sleep or some other similar rela */ -static int kpatch_line_macro_change_only(struct section *sec) +static int kpatch_line_macro_change_only_x86_64(struct section *sec) { struct insn insn1, insn2; unsigned long start1, start2, size, offset, length; @@ -688,11 +697,11 @@ static int kpatch_line_macro_change_only(struct section *sec) return 1; } -#elif __powerpc64__ + #define PPC_INSTR_LEN 4 #define PPC_RA_OFFSET 16 -static int kpatch_line_macro_change_only(struct section *sec) +static int kpatch_line_macro_change_only_ppc64le(struct section *sec) { unsigned long start1, start2, size, offset; unsigned int instr1, instr2; @@ -754,12 +763,15 @@ static int kpatch_line_macro_change_only(struct section *sec) return 1; } -#else + static int kpatch_line_macro_change_only(struct section *sec) { + if (arch == X86_64) + return kpatch_line_macro_change_only_x86_64(sec); + else if (arch == PPC64) + return kpatch_line_macro_change_only_ppc64le(sec); return 0; } -#endif /* * Child functions with "*.cold" names don't have _fentry_ calls, but "*.part", @@ -1430,7 +1442,6 @@ static void kpatch_compare_correlated_elements(struct kpatch_elf *kelf) kpatch_compare_symbols(&kelf->symbols); } -#ifdef __x86_64__ static void rela_insn(const struct section *sec, const struct rela *rela, struct insn *insn) { @@ -1454,7 +1465,6 @@ static void rela_insn(const struct section *sec, const struct rela *rela, return; } } -#endif static bool is_callback_section(struct section *sec) { @@ -1525,22 +1535,23 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) continue; } -#ifdef __powerpc64__ - add_off = 0; -#else - 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) + if (arch == PPC64) add_off = 0; - else - continue; -#endif + else if (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) + add_off = 0; + else + continue; + } + /* * Attempt to replace references to unbundled sections @@ -2001,7 +2012,6 @@ static int jump_table_group_size(struct kpatch_elf *kelf, int offset) return size; } -#ifdef __x86_64__ static int parainstructions_group_size(struct kpatch_elf *kelf, int offset) { static int size = 0; @@ -2051,8 +2061,7 @@ static int static_call_sites_group_size(struct kpatch_elf *kelf, int offset) return size; } -#endif -#ifdef __powerpc64__ + static int fixup_entry_group_size(struct kpatch_elf *kelf, int offset) { static int size = 0; @@ -2077,7 +2086,6 @@ static int fixup_barrier_nospec_group_size(struct kpatch_elf *kelf, int offset) { return 8; } -#endif /* * The rela groups in the .fixup section vary in size. The beginning of each @@ -2132,60 +2140,69 @@ static int fixup_group_size(struct kpatch_elf *kelf, int offset) static struct special_section special_sections[] = { { .name = "__bug_table", + .arch = X86_64 | PPC64, .group_size = bug_table_group_size, }, { .name = ".fixup", + .arch = X86_64 | PPC64, .group_size = fixup_group_size, }, { .name = "__ex_table", /* must come after .fixup */ + .arch = X86_64 | PPC64, .group_size = ex_table_group_size, }, { .name = "__jump_table", + .arch = X86_64 | PPC64, .group_size = jump_table_group_size, }, -#ifdef __x86_64__ { .name = ".smp_locks", + .arch = X86_64, .group_size = smp_locks_group_size, }, { .name = ".parainstructions", + .arch = X86_64, .group_size = parainstructions_group_size, }, { .name = ".altinstructions", + .arch = X86_64, .group_size = altinstructions_group_size, }, { .name = ".static_call_sites", + .arch = X86_64, .group_size = static_call_sites_group_size, }, -#endif -#ifdef __powerpc64__ { .name = "__ftr_fixup", + .arch = PPC64, .group_size = fixup_entry_group_size, }, { .name = "__mmu_ftr_fixup", + .arch = PPC64, .group_size = fixup_entry_group_size, }, { .name = "__fw_ftr_fixup", + .arch = PPC64, .group_size = fixup_entry_group_size, }, { .name = "__lwsync_fixup", + .arch = PPC64, .group_size = fixup_lwsync_group_size, }, { .name = "__barrier_nospec_fixup", + .arch = PPC64, .group_size = fixup_barrier_nospec_group_size, }, -#endif {}, }; @@ -2723,6 +2740,9 @@ 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 & arch) == 0) + continue; + if (strcmp(special->name, ".parainstructions") && strcmp(special->name, ".altinstructions")) continue; @@ -2764,6 +2784,9 @@ static void kpatch_process_special_sections(struct kpatch_elf *kelf, int altinstr = 0; for (special = special_sections; special->name; special++) { + if ((special->arch & arch) == 0) + continue; + sec = find_section_by_name(&kelf->sections, special->name); if (!sec || !sec->rela) continue; @@ -3232,9 +3255,13 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, continue; special = false; - for (s = special_sections; s->name; s++) + for (s = special_sections; s->name; s++) { + if ((s->arch & arch) == 0) + continue; + if (!strcmp(sec->base->name, s->name)) special = true; + } list_for_each_entry_safe(rela, safe, &sec->relas, list) { if (!rela->need_dynrela) @@ -3433,65 +3460,63 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) continue; } -#ifdef __x86_64__ - - 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; - if (rela->type == R_X86_64_NONE) { - void *newdata; - unsigned char *insn; + if (arch == X86_64) { + rela = list_first_entry(&sym->sec->rela->relas, struct rela, list); /* - * 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. + * For "call fentry", the relocation points to 1 byte past the + * beginning of the instruction. */ + insn_offset = rela->offset - 1; - /* Make a writable copy of the text section data */ - newdata = malloc(sym->sec->data->d_size); - memcpy(newdata, sym->sec->data->d_buf, sym->sec->data->d_size); - sym->sec->data->d_buf = newdata; - insn = newdata; + if (rela->type == R_X86_64_NONE) { + void *newdata; + unsigned char *insn; - /* - * Replace the NOP with a call to fentry. The fentry - * rela symbol is already there, just need to change - * the relocation type accordingly. - */ - insn = sym->sec->data->d_buf; - if (insn[0] != 0xf) - ERROR("%s: unexpected instruction at the start of the function", sym->name); - insn[0] = 0xe8; - insn[1] = 0; - insn[2] = 0; - insn[3] = 0; - insn[4] = 0; - - rela->type = R_X86_64_PC32; - } + /* + * 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. + */ -#else /* __powerpc64__ */ -{ - bool found = false; + /* Make a writable copy of the text section data */ + newdata = malloc(sym->sec->data->d_size); + memcpy(newdata, sym->sec->data->d_buf, sym->sec->data->d_size); + sym->sec->data->d_buf = newdata; + insn = newdata; - list_for_each_entry(rela, &sym->sec->rela->relas, list) - if (!strcmp(rela->sym->name, "_mcount")) { - found = true; - break; + /* + * Replace the NOP with a call to fentry. The fentry + * rela symbol is already there, just need to change + * the relocation type accordingly. + */ + insn = sym->sec->data->d_buf; + if (insn[0] != 0xf) + ERROR("%s: unexpected instruction at the start of the function", sym->name); + insn[0] = 0xe8; + insn[1] = 0; + insn[2] = 0; + insn[3] = 0; + insn[4] = 0; + + rela->type = R_X86_64_PC32; } + } else if (arch == PPC64) { + bool found = false; - if (!found) - ERROR("%s: unexpected missing call to _mcount()", __func__); + 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; + } - insn_offset = rela->offset; -} -#endif /* * 'rela' points to the mcount/fentry call. * @@ -3606,11 +3631,13 @@ static void kpatch_build_strings_section_data(struct kpatch_elf *kelf) */ static void kpatch_no_sibling_calls_ppc64le(struct kpatch_elf *kelf) { -#ifdef __powerpc64__ struct symbol *sym; unsigned int insn; unsigned int offset; + if (arch != PPC64) + return; + list_for_each_entry(sym, &kelf->symbols, list) { if (sym->type != STT_FUNC || sym->status != CHANGED) continue; @@ -3643,17 +3670,18 @@ static void kpatch_no_sibling_calls_ppc64le(struct kpatch_elf *kelf) sym->name, sym->sym.st_value + offset, sym->name); } } -#endif } struct arguments { char *args[7]; + enum architecture arch; bool debug, klp_arch; }; static char args_doc[] = "original.o patched.o parent-name parent-symtab Module.symvers patch-module-name output.o"; static struct argp_option options[] = { + {"arch", 777, "ARCH", 0, "Architecture: x86_64, powerpc [default: x86_64]"}, {"debug", 'd', NULL, 0, "Show debug output" }, {"klp-arch", 'a', NULL, 0, "Kernel supports .klp.arch section" }, { NULL } @@ -3673,6 +3701,14 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) case 'a': arguments->klp_arch = 1; break; + case 777: /* --arch */ + if (!strcmp(arg, "x86_64")) + arguments->arch = X86_64; + else if (!strcmp(arg, "powerpc")) + arguments->arch = PPC64; + else + argp_failure (state, 1, 0, "invalid value for --arch: %s", arg); + break; case ARGP_KEY_ARG: if (state->arg_num >= 7) /* Too many arguments. */ @@ -3710,6 +3746,8 @@ int main(int argc, char *argv[]) loglevel = DEBUG; if (arguments.klp_arch) KLP_ARCH = true; + if (arguments.arch != DEFAULT_ARCH) + arch = arguments.arch; elf_version(EV_CURRENT); diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index 617f85780..4825fecc8 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -1057,7 +1057,17 @@ for i in $FILES; do # create-diff-object orig.o patched.o parent-name parent-symtab # Module.symvers patch-mod-name output.o - "$TOOLSDIR"/create-diff-object $CDO_FLAGS "orig/$i" "patched/$i" "$KOBJFILE_NAME" \ + arch=$(readelf --file-header "orig/$i" | grep "Machine:" | sed -e 's,.*Machine:\s*,,') + case "${arch}" in + PowerPC*) + ARCH_FLAG="--arch powerpc" + ;; + *) + ARCH_FLAG="--arch x86_64" + ;; + esac + "$TOOLSDIR"/create-diff-object ${ARCH_FLAG} $CDO_FLAGS \ + "orig/$i" "patched/$i" "$KOBJFILE_NAME" \ "$SYMTAB" "$SYMVERS_FILE" "${MODNAME//-/_}" \ "output/$i" 2>&1 | logger 1 check_pipe_status create-diff-object From e0902068e4f37c7915c536642036cedb8654e275 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 5 May 2021 22:49:42 -0700 Subject: [PATCH 2/5] Properly quote the ARCH_FLAG variable --- kpatch-build/kpatch-build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index 4825fecc8..e5a891292 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -1066,7 +1066,7 @@ for i in $FILES; do ARCH_FLAG="--arch x86_64" ;; esac - "$TOOLSDIR"/create-diff-object ${ARCH_FLAG} $CDO_FLAGS \ + "$TOOLSDIR"/create-diff-object "$ARCH_FLAG" $CDO_FLAGS \ "orig/$i" "patched/$i" "$KOBJFILE_NAME" \ "$SYMTAB" "$SYMVERS_FILE" "${MODNAME//-/_}" \ "output/$i" 2>&1 | logger 1 From a01387cac973cdc34ffab63b69ee68efbced73a0 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 7 Jun 2021 11:11:23 -0700 Subject: [PATCH 3/5] kpatch-build: add "--arch" flag to other create-* binaries --- kpatch-build/create-diff-object.c | 112 ++++++++++++++-------------- kpatch-build/create-klp-module.c | 17 +++++ kpatch-build/create-kpatch-module.c | 17 +++++ kpatch-build/kpatch-elf.c | 32 ++++---- kpatch-build/kpatch-elf.h | 8 ++ test/unit/Makefile.include | 5 +- 6 files changed, 117 insertions(+), 74 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 82c5b6ddf..34d611a86 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -60,13 +60,14 @@ error(EXIT_STATUS_DIFF_FATAL, 0, "unreconcilable difference"); \ }) -#define ABSOLUTE_RELA_TYPE \ +#define ABSOLUTE_RELA_TYPE \ ({ \ - unsigned int __ret; \ - if (arch == X86_64) \ - __ret = R_X86_64_64; \ - else if (arch == PPC64) \ - __ret = R_PPC64_ADDR64; \ + typeof(R_X86_64_64) __ret = 0; \ + switch (current_arch) { \ + case ARM64: __ret = R_AARCH64_ABS64; \ + case PPC64: __ret = R_PPC64_ADDR64; \ + case X86_64: __ret = R_X86_64_64; \ + } \ __ret; \ }) @@ -80,17 +81,10 @@ enum subsection { enum loglevel loglevel = NORMAL; -enum architecture { - X86_64 = 0x1 << 0, - PPC64 = 0x1 << 1, - DEFAULT_ARCH = X86_64, -}; - -/* Default to the x86 architecture. */ -enum architecture arch = DEFAULT_ARCH; - bool KLP_ARCH; +enum architecture current_arch; + /******************* * Data structures * ****************/ @@ -157,30 +151,29 @@ static int is_bundleable(struct symbol *sym) #define PPC64_LOCAL_ENTRY_OFFSET(other) \ (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2) +/* + * On ppc64le, the function prologue generated by GCC 6+ has the sequence: + * + * .globl my_func + * .type my_func, @function + * .quad .TOC.-my_func + * my_func: + * .reloc ., R_PPC64_ENTRY ; optional + * ld r2,-8(r12) + * add r2,r2,r12 + * .localentry my_func, .-my_func + * + * my_func is the global entry point, which, when called, sets up the TOC. + * .localentry is the local entry point, for calls to the function from within + * 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) { - if (arch == PPC64) - /* - * On ppc64le, the function prologue generated by GCC 6+ has - * the sequence: - * - * .globl my_func - * .type my_func, @function - * .quad .TOC.-my_func - * my_func: - * .reloc ., R_PPC64_ENTRY ; optional - * ld r2,-8(r12) - * add r2,r2,r12 - * .localentry my_func, .-my_func - * - * my_func is the global entry point, which, when called, sets - * up the TOC. .localentry is the local entry point, for calls - * to the function from within the object file. The local - * entry point is 8 bytes after the global entry point. - */ - return ((PPC64_LOCAL_ENTRY_OFFSET(sym->sym.st_other) != 0) && - sym->sym.st_value == 8); - return 0; + if (current_arch != PPC64) + return 0; + return ((PPC64_LOCAL_ENTRY_OFFSET(sym->sym.st_other) != 0) && + sym->sym.st_value == 8); } /* @@ -701,7 +694,7 @@ static int kpatch_line_macro_change_only_x86_64(struct section *sec) #define PPC_INSTR_LEN 4 #define PPC_RA_OFFSET 16 -static int kpatch_line_macro_change_only_ppc64le(struct section *sec) +static int kpatch_line_macro_change_only_ppc64(struct section *sec) { unsigned long start1, start2, size, offset; unsigned int instr1, instr2; @@ -764,12 +757,19 @@ static int kpatch_line_macro_change_only_ppc64le(struct section *sec) return 1; } +static int kpatch_line_macro_change_only_arm64(struct section *sec) +{ + /* TODO */ + return 0; +} + static int kpatch_line_macro_change_only(struct section *sec) { - if (arch == X86_64) - return kpatch_line_macro_change_only_x86_64(sec); - else if (arch == PPC64) - return kpatch_line_macro_change_only_ppc64le(sec); + switch (current_arch) { + case ARM64: return kpatch_line_macro_change_only_arm64(sec); + case PPC64: return kpatch_line_macro_change_only_ppc64(sec); + case X86_64: return kpatch_line_macro_change_only_x86_64(sec); + } return 0; } @@ -1535,9 +1535,9 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) continue; } - if (arch == PPC64) + if (current_arch == PPC64) { add_off = 0; - else if (arch == X86_64) { + } else if (current_arch == X86_64) { if (rela->type == R_X86_64_PC32 || rela->type == R_X86_64_PLT32) { struct insn insn; @@ -1552,7 +1552,6 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) continue; } - /* * Attempt to replace references to unbundled sections * with their symbols. @@ -3460,8 +3459,7 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) continue; } - - if (arch == X86_64) { + if (current_arch == X86_64) { rela = list_first_entry(&sym->sec->rela->relas, struct rela, list); /* @@ -3502,7 +3500,7 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) rela->type = R_X86_64_PC32; } - } else if (arch == PPC64) { + } else if (current_arch == PPC64) { bool found = false; list_for_each_entry(rela, &sym->sec->rela->relas, list) @@ -3635,7 +3633,7 @@ static void kpatch_no_sibling_calls_ppc64le(struct kpatch_elf *kelf) unsigned int insn; unsigned int offset; - if (arch != PPC64) + if (current_arch != PPC64) return; list_for_each_entry(sym, &kelf->symbols, list) { @@ -3681,9 +3679,9 @@ struct arguments { static char args_doc[] = "original.o patched.o parent-name parent-symtab Module.symvers patch-module-name output.o"; static struct argp_option options[] = { - {"arch", 777, "ARCH", 0, "Architecture: x86_64, powerpc [default: x86_64]"}, - {"debug", 'd', NULL, 0, "Show debug output" }, - {"klp-arch", 'a', NULL, 0, "Kernel supports .klp.arch section" }, + {"arch", 777, "ARCH", 0, "Architecture [x86_64, ppc64, arm64]" }, + {"debug", 'd', NULL, 0, "Show debug output" }, + {"klp-arch", 'a', NULL, 0, "Kernel supports .klp.arch section" }, { NULL } }; @@ -3704,10 +3702,13 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) case 777: /* --arch */ if (!strcmp(arg, "x86_64")) arguments->arch = X86_64; - else if (!strcmp(arg, "powerpc")) + else if (!strcmp(arg, "ppc64")) arguments->arch = PPC64; + else if (!strcmp(arg, "arm64")) + arguments->arch = ARM64; else - argp_failure (state, 1, 0, "invalid value for --arch: %s", arg); + /* Unsupported architecture */ + argp_failure (state, 1, 0, "unsupported architecture: %s", arg); break; case ARGP_KEY_ARG: if (state->arg_num >= 7) @@ -3746,8 +3747,7 @@ int main(int argc, char *argv[]) loglevel = DEBUG; if (arguments.klp_arch) KLP_ARCH = true; - if (arguments.arch != DEFAULT_ARCH) - arch = arguments.arch; + current_arch = arguments.arch; elf_version(EV_CURRENT); diff --git a/kpatch-build/create-klp-module.c b/kpatch-build/create-klp-module.c index d1b03fe7e..58ba0e16e 100644 --- a/kpatch-build/create-klp-module.c +++ b/kpatch-build/create-klp-module.c @@ -30,6 +30,9 @@ char *childobj; enum loglevel loglevel = NORMAL; +/* For kpatch-elf.c */ +enum architecture current_arch; + /* * Add a symbol from .kpatch.symbols to the symbol table * @@ -379,6 +382,7 @@ static void remove_intermediate_sections(struct kpatch_elf *kelf) struct arguments { char *args[2]; + enum architecture arch; int debug; int no_klp_arch; }; @@ -386,6 +390,7 @@ struct arguments { static char args_doc[] = "input.ko output.ko"; static struct argp_option options[] = { + {"arch", 777, "ARCH", 0, "Architecture of objects [x86_64, ppc64, arm64]" }, {"debug", 'd', 0, 0, "Show debug output" }, {"no-klp-arch-sections", 'n', 0, 0, "Do not output .klp.arch.* sections" }, { 0 } @@ -405,6 +410,17 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) case 'n': arguments->no_klp_arch = 1; break; + case 777: + if (!strcmp(arg, "x86_64")) + arguments->arch = X86_64; + else if (!strcmp(arg, "ppc64")) + arguments->arch = PPC64; + else if (!strcmp(arg, "arm64")) + arguments->arch = ARM64; + else + /* Unsupported architecture */ + argp_usage (state); + break; case ARGP_KEY_ARG: if (state->arg_num >= 2) /* Too many arguments. */ @@ -437,6 +453,7 @@ int main(int argc, char *argv[]) argp_parse (&argp, argc, argv, 0, 0, &arguments); if (arguments.debug) loglevel = DEBUG; + current_arch = arguments.arch; elf_version(EV_CURRENT); diff --git a/kpatch-build/create-kpatch-module.c b/kpatch-build/create-kpatch-module.c index 2884f93d9..bbbeaaee5 100644 --- a/kpatch-build/create-kpatch-module.c +++ b/kpatch-build/create-kpatch-module.c @@ -31,6 +31,9 @@ char *childobj; enum loglevel loglevel = NORMAL; +/* For kpatch-elf.c */ +enum architecture current_arch = X86_64; + /* * Create .kpatch.dynrelas from .kpatch.relocations and .kpatch.symbols sections * @@ -153,12 +156,14 @@ static void remove_intermediate_sections(struct kpatch_elf *kelf) struct arguments { char *args[2]; + enum architecture arch; int debug; }; static char args_doc[] = "input.o output.o"; static struct argp_option options[] = { + {"arch", 777, "ARCH", 0, "Architecture of objects [x86_64, ppc64, arm64]" }, {"debug", 'd', 0, 0, "Show debug output" }, { 0 } }; @@ -174,6 +179,17 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) case 'd': arguments->debug = 1; break; + case 777: + if (!strcmp(arg, "x86_64")) + arguments->arch = X86_64; + else if (!strcmp(arg, "ppc64")) + arguments->arch = PPC64; + else if (!strcmp(arg, "arm64")) + arguments->arch = ARM64; + else + /* Unsupported architecture */ + argp_usage (state); + break; case ARGP_KEY_ARG: if (state->arg_num >= 2) /* Too many arguments. */ @@ -205,6 +221,7 @@ int main(int argc, char *argv[]) argp_parse (&argp, argc, argv, 0, 0, &arguments); if (arguments.debug) loglevel = DEBUG; + current_arch = arguments.arch; elf_version(EV_CURRENT); diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c index 7e272e2c8..a72467091 100644 --- a/kpatch-build/kpatch-elf.c +++ b/kpatch-build/kpatch-elf.c @@ -325,24 +325,24 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf) list_for_each_entry(sym, &kelf->symbols, list) { if (sym->type != STT_FUNC || !sym->sec || !sym->sec->rela) continue; -#ifdef __powerpc64__ - list_for_each_entry(rela, &sym->sec->rela->relas, list) { - if (!strcmp(rela->sym->name, "_mcount")) { - sym->has_func_profiling = 1; - break; + if (current_arch == PPC64) { + list_for_each_entry(rela, &sym->sec->rela->relas, list) { + if (!strcmp(rela->sym->name, "_mcount")) { + sym->has_func_profiling = 1; + break; + } } + } else { + 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; } -#else - 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; -#endif } } diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h index 36f500aab..4a717679f 100644 --- a/kpatch-build/kpatch-elf.h +++ b/kpatch-build/kpatch-elf.h @@ -110,6 +110,14 @@ struct kpatch_elf { int fd; }; +enum architecture { + ARM64, + PPC64, + X86_64, +}; + +extern enum architecture current_arch; + /******************* * Helper functions ******************/ diff --git a/test/unit/Makefile.include b/test/unit/Makefile.include index 21e6be8d4..21bda7383 100644 --- a/test/unit/Makefile.include +++ b/test/unit/Makefile.include @@ -8,6 +8,7 @@ EXT_SYMTAB ?= symtab EXT_SYMVERS ?= symvers EXT_ENV ?= env TNAME = $(@:.$(EXT_OUTPUT)=) +ARCH = --arch=x86_64 ifndef VERBOSE MUTE_PASS := >/dev/null @@ -57,7 +58,7 @@ clean: @echo "BUILD $(TNAME)" $(call check_all,$(TNAME).$(EXT_ORIG)) $(call check_all,$(TNAME).$(EXT_PATCHED)) - $(CDO_ENV) $(shell cat $(TNAME).$(EXT_ENV) 2>/dev/null) $(CDO) $(TNAME).$(EXT_ORIG) $(TNAME).$(EXT_PATCHED) \ + $(CDO_ENV) $(shell cat $(TNAME).$(EXT_ENV) 2>/dev/null) $(CDO) $(ARCH) $(TNAME).$(EXT_ORIG) $(TNAME).$(EXT_PATCHED) \ vmlinux $(TNAME).$(EXT_SYMTAB) $(SYMVERS_FILE) \ test_$(TNAME) $@ $(MUTE_PASS) @@ -65,7 +66,7 @@ clean: @echo "BUILD $(TNAME)-FAIL" $(call check_all,$(TNAME).$(EXT_ORIG)) $(call check_all,$(TNAME).$(EXT_FAIL)) - ! $(CDO_ENV) $(shell cat $(TNAME).$(EXT_ENV) 2>/dev/null) $(CDO) $(TNAME).$(EXT_ORIG) $(TNAME).$(EXT_FAIL) \ + ! $(CDO_ENV) $(shell cat $(TNAME).$(EXT_ENV) 2>/dev/null) $(CDO) $(ARCH) $(TNAME).$(EXT_ORIG) $(TNAME).$(EXT_FAIL) \ vmlinux $(TNAME).$(EXT_SYMTAB) $(SYMVERS_FILE) \ test_$(TNAME) $@ $(MUTE_FAIL) # Expecting to fail, thus create output file manually so we won't rerun the From a17bc0f95eb5957492175af4052730cef0be8786 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 7 Jun 2021 11:17:09 -0700 Subject: [PATCH 4/5] kpatch-build: make architecture masks so we can easily check them --- kpatch-build/create-diff-object.c | 6 +++--- kpatch-build/kpatch-elf.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 34d611a86..d53401951 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -2739,7 +2739,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 & arch) == 0) + if ((special->arch & current_arch) == 0) continue; if (strcmp(special->name, ".parainstructions") && @@ -2783,7 +2783,7 @@ static void kpatch_process_special_sections(struct kpatch_elf *kelf, int altinstr = 0; for (special = special_sections; special->name; special++) { - if ((special->arch & arch) == 0) + if ((special->arch & current_arch) == 0) continue; sec = find_section_by_name(&kelf->sections, special->name); @@ -3255,7 +3255,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, special = false; for (s = special_sections; s->name; s++) { - if ((s->arch & arch) == 0) + if ((s->arch & current_arch) == 0) continue; if (!strcmp(sec->base->name, s->name)) diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h index 4a717679f..d69ade9d8 100644 --- a/kpatch-build/kpatch-elf.h +++ b/kpatch-build/kpatch-elf.h @@ -111,9 +111,9 @@ struct kpatch_elf { }; enum architecture { - ARM64, - PPC64, - X86_64, + ARM64 = 0x1 << 0, + PPC64 = 0x1 << 1, + X86_64 = 0x1 << 2, }; extern enum architecture current_arch; From 0c814c3e3d21cd43dbd409859e9c0a14ecda449f Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 7 Jun 2021 11:22:03 -0700 Subject: [PATCH 5/5] kpatch-build: initialize variable to prevent spurious warning --- kpatch-build/create-diff-object.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index d53401951..4ab566fc0 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -1500,7 +1500,7 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) struct section *sec; struct rela *rela; struct symbol *sym; - unsigned int add_off; + unsigned int add_off = 0; log_debug("\n"); @@ -3500,7 +3500,7 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) rela->type = R_X86_64_PC32; } - } else if (current_arch == PPC64) { + } else { /* current_arch == PPC64 */ bool found = false; list_for_each_entry(rela, &sym->sec->rela->relas, list)