From 2bb3a8f543b478cd8c11f3982bc0db8412104d9f Mon Sep 17 00:00:00 2001 From: renoseven Date: Thu, 13 Mar 2025 09:50:55 +0800 Subject: [PATCH] update to 1.2.1-5 Signed-off-by: renoseven --- 0012-upatch-diff-format-code.patch | 8357 +++++++++++++++++ 0013-upatch-manage-format-code.patch | 8180 ++++++++++++++++ ...-upatch-manage-remove-build-id-check.patch | 88 + 0015-upatch-diff-print-detail-changes.patch | 96 + ...-upatch-diff-ignore-useless-sections.patch | 82 + 0017-upatch-manage-enrich-log-output.patch | 340 + 0018-project-change-build-options.patch | 58 + ...age-increase-jump-table-size-to-4096.patch | 26 + ...x-failed-to-attach-non-exist-process.patch | 67 + ...x-failed-to-alloc-patch-memory-issue.patch | 526 ++ ...ix-misresolve-.rela.plt-symbol-issue.patch | 29 + ...fix-misresolve-std-cout-symbol-issue.patch | 29 + ...x-access-global-variable-coredump-is.patch | 93 + 0025-project-update-CMakeLists.txt.patch | 36 + 0026-upatch-manage-fix-compile-issue.patch | 30 + ...-build-supress-rpm-signature-warning.patch | 33 + ...-support-custom-kernel-configuration.patch | 208 + 0029-common-add-unit-test-for-process.patch | 61 + ...-build-add-unit-test-for-spec-writer.patch | 50 + ...syscare-remove-root-permission-check.patch | 57 + ...ove-upatch-failure-process-blacklist.patch | 107 + ...e-syscare-info-syscare-target-output.patch | 53 + ...syscared-impl-syscare-rescan-command.patch | 44 + ...-syscare-impl-syscare-rescan-command.patch | 59 + 0036-syscared-impl-log-config.patch | 141 + 0037-syscared-impl-patch-blacklist.patch | 410 + 0038-metadata-viewer-add-component.patch | 284 + 0039-metadata-generator-add-component.patch | 533 ++ 0040-project-update-Cargo.lock.patch | 49 + ...ed-fix-patch-target-is-blocked-issue.patch | 26 + ...-riscv64-support-from-master-to-2503.patch | 1230 +++ ...x-detect-incorrect-kernel-source-dir.patch | 44 + 0044-upatch-manage-fix-compile-failure.patch | 26 + ...od-patch-conflicts-with-itself-issue.patch | 78 + ...on-fix-failed-to-acquire-flock-issue.patch | 177 + 0047-syscare-rewrite-syscare-cli.patch | 1352 +++ syscare.spec | 71 +- 37 files changed, 23122 insertions(+), 8 deletions(-) create mode 100644 0012-upatch-diff-format-code.patch create mode 100644 0013-upatch-manage-format-code.patch create mode 100644 0014-upatch-manage-remove-build-id-check.patch create mode 100644 0015-upatch-diff-print-detail-changes.patch create mode 100644 0016-upatch-diff-ignore-useless-sections.patch create mode 100644 0017-upatch-manage-enrich-log-output.patch create mode 100644 0018-project-change-build-options.patch create mode 100644 0019-upatch-manage-increase-jump-table-size-to-4096.patch create mode 100644 0020-upatch-manage-fix-failed-to-attach-non-exist-process.patch create mode 100644 0021-upatch-manage-fix-failed-to-alloc-patch-memory-issue.patch create mode 100644 0022-upatch-manage-fix-misresolve-.rela.plt-symbol-issue.patch create mode 100644 0023-upatch-manage-fix-misresolve-std-cout-symbol-issue.patch create mode 100644 0024-upatch-manage-fix-access-global-variable-coredump-is.patch create mode 100644 0025-project-update-CMakeLists.txt.patch create mode 100644 0026-upatch-manage-fix-compile-issue.patch create mode 100644 0027-syscare-build-supress-rpm-signature-warning.patch create mode 100644 0028-syscare-build-support-custom-kernel-configuration.patch create mode 100644 0029-common-add-unit-test-for-process.patch create mode 100644 0030-syscare-build-add-unit-test-for-spec-writer.patch create mode 100644 0031-syscare-remove-root-permission-check.patch create mode 100644 0032-syscared-remove-upatch-failure-process-blacklist.patch create mode 100644 0033-syscare-optimize-syscare-info-syscare-target-output.patch create mode 100644 0034-syscared-impl-syscare-rescan-command.patch create mode 100644 0035-syscare-impl-syscare-rescan-command.patch create mode 100644 0036-syscared-impl-log-config.patch create mode 100644 0037-syscared-impl-patch-blacklist.patch create mode 100644 0038-metadata-viewer-add-component.patch create mode 100644 0039-metadata-generator-add-component.patch create mode 100644 0040-project-update-Cargo.lock.patch create mode 100644 0041-syscared-fix-patch-target-is-blocked-issue.patch create mode 100644 0042-riscv64-sync-riscv64-support-from-master-to-2503.patch create mode 100644 0043-syscare-build-fix-detect-incorrect-kernel-source-dir.patch create mode 100644 0044-upatch-manage-fix-compile-failure.patch create mode 100644 0045-syscared-fix-kmod-patch-conflicts-with-itself-issue.patch create mode 100644 0046-common-fix-failed-to-acquire-flock-issue.patch create mode 100644 0047-syscare-rewrite-syscare-cli.patch diff --git a/0012-upatch-diff-format-code.patch b/0012-upatch-diff-format-code.patch new file mode 100644 index 0000000..5620e49 --- /dev/null +++ b/0012-upatch-diff-format-code.patch @@ -0,0 +1,8357 @@ +From 47ac3ae5e1e6cb790df0f24433e2d8071ef7541f Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Sat, 15 Feb 2025 17:05:06 +0800 +Subject: [PATCH] upatch-diff: format code + +Signed-off-by: renoseven +--- + upatch-diff/create-diff-object.c | 367 ++--- + upatch-diff/elf-common.c | 145 +- + upatch-diff/elf-common.h | 191 +-- + upatch-diff/elf-compare.c | 556 ++++---- + upatch-diff/elf-compare.h | 2 +- + upatch-diff/elf-correlate.c | 515 +++---- + upatch-diff/elf-correlate.h | 2 +- + upatch-diff/elf-create.c | 210 ++- + upatch-diff/elf-create.h | 2 +- + upatch-diff/elf-debug.c | 80 +- + upatch-diff/elf-insn.c | 118 +- + upatch-diff/elf-resolve.c | 5 +- + upatch-diff/elf-resolve.h | 2 +- + upatch-diff/insn/asm/inat-tables.h | 2024 ++++++++++++++-------------- + upatch-diff/insn/asm/inat.h | 162 ++- + upatch-diff/insn/asm/insn.h | 183 +-- + upatch-diff/insn/inat.c | 99 +- + upatch-diff/insn/insn.c | 861 ++++++------ + upatch-diff/list.h | 115 +- + upatch-diff/log.h | 50 +- + upatch-diff/running-elf.c | 42 +- + upatch-diff/running-elf.h | 6 +- + upatch-diff/upatch-dynrela.h | 2 +- + upatch-diff/upatch-elf.c | 170 ++- + upatch-diff/upatch-elf.h | 140 +- + upatch-diff/upatch-patch.h | 4 +- + 26 files changed, 3201 insertions(+), 2852 deletions(-) + +diff --git a/upatch-diff/create-diff-object.c b/upatch-diff/create-diff-object.c +index 0eea362..02d43c2 100644 +--- a/upatch-diff/create-diff-object.c ++++ b/upatch-diff/create-diff-object.c +@@ -62,7 +62,7 @@ + + #define PROG_VERSION "upatch-diff "BUILD_VERSION + +-enum LogLevel g_loglevel = NORMAL; ++enum log_level g_loglevel = NORMAL; + char *g_logprefix; + char *g_uelf_name; + char *g_relf_name; +@@ -87,7 +87,8 @@ static struct argp_option options[] = { + static char program_doc[] = + "upatch-build -- generate a patch object based on the source object"; + +-static char args_doc[] = "-s source_obj -p patched_obj -r elf_file -o output_obj"; ++static char args_doc[] = ++ "-s source_obj -p patched_obj -r elf_file -o output_obj"; + + const char *argp_program_version = PROG_VERSION; + +@@ -99,8 +100,8 @@ static error_t check_opt(struct argp_state *state) + arguments->patched_obj == NULL || + arguments->running_elf == NULL || + arguments->output_obj == NULL) { +- argp_usage(state); +- return ARGP_ERR_UNKNOWN; ++ argp_usage(state); ++ return ARGP_ERR_UNKNOWN; + } + return 0; + } +@@ -109,8 +110,7 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) + { + struct arguments *arguments = state->input; + +- switch (key) +- { ++ switch (key) { + case 'd': + arguments->debug = true; + break; +@@ -136,7 +136,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) + return 0; + } + +-static struct argp argp = {options, parse_opt, args_doc, program_doc, NULL, NULL, NULL}; ++static struct argp argp = { ++ options, parse_opt, args_doc, program_doc, NULL, NULL, NULL ++}; + + /* + * Key point for chreate-diff-object: +@@ -155,16 +157,17 @@ static void show_program_info(struct arguments *arguments) + log_debug("output object: %s\n", arguments->output_obj); + } + +-static void compare_elf_headers(struct upatch_elf *uelf_source, struct upatch_elf *uelf_patched) ++static void compare_elf_headers(struct upatch_elf *uelf_source, ++ struct upatch_elf *uelf_patched) + { + GElf_Ehdr ehdr_source, ehdr_patched; + +- if (!gelf_getehdr(uelf_source->elf, &ehdr_source)) ++ if (!gelf_getehdr(uelf_source->elf, &ehdr_source)) { + ERROR("gelf_getehdr source failed for %s.", elf_errmsg(0)); +- +- if (!gelf_getehdr(uelf_patched->elf, &ehdr_patched)) ++ } ++ if (!gelf_getehdr(uelf_patched->elf, &ehdr_patched)) { + ERROR("gelf_getehdr patched failed for %s.", elf_errmsg(0)); +- ++ } + if (memcmp(ehdr_source.e_ident, ehdr_patched.e_ident, EI_NIDENT) || + ehdr_source.e_type != ehdr_patched.e_type || + ehdr_source.e_machine != ehdr_patched.e_machine || +@@ -175,32 +178,35 @@ static void compare_elf_headers(struct upatch_elf *uelf_source, struct upatch_el + ehdr_source.e_ehsize != ehdr_patched.e_ehsize || + ehdr_source.e_phentsize != ehdr_patched.e_phentsize || + ehdr_source.e_shentsize != ehdr_patched.e_shentsize) { +- ERROR("compare_elf_headers failed."); +- } ++ ERROR("compare_elf_headers failed."); ++ } + } + + /* we can sure we only handle relocatable file, this is unnecessary */ + static void check_program_headers(struct upatch_elf *uelf) + { + size_t ph_nr; +- if (elf_getphdrnum(uelf->elf, &ph_nr)) +- ERROR("elf_getphdrnum with error %s.", elf_errmsg(0)); + +- if (ph_nr != 0) ++ if (elf_getphdrnum(uelf->elf, &ph_nr)) { ++ ERROR("elf_getphdrnum with error %s.", elf_errmsg(0)); ++ } ++ if (ph_nr != 0) { + ERROR("ELF contains program header."); ++ } + } + + static char *strarrcmp(char *name, char **prefix) + { + size_t len; + +- if (name == NULL) ++ if (name == NULL) { + return NULL; +- ++ } + while (*prefix != NULL) { + len = strlen(*prefix); +- if (!strncmp(name, *prefix, len)) ++ if (!strncmp(name, *prefix, len)) { + return name + len; ++ } + prefix++; + } + +@@ -229,27 +235,33 @@ static bool is_bundleable(struct symbol *sym) + NULL, + }; + +- if (sym == NULL || sym->sec == NULL) ++ if (sym == NULL || sym->sec == NULL) { + return false; ++ } + +- if (sym->type == STT_FUNC) ++ if (sym->type == STT_FUNC) { + name = strarrcmp(sym->sec->name, func_prefix); +- else if (sym->type == STT_OBJECT) ++ } else if (sym->type == STT_OBJECT) { + name = strarrcmp(sym->sec->name, obj_prefix); ++ } + + /* no prefix found or invalid type */ +- if (name == NULL) ++ if (name == NULL) { + return false; +- +- if (!strcmp(name, sym->name)) ++ } ++ if (!strcmp(name, sym->name)) { + return true; ++ } + + /* special case for cold func */ + text_name_len = strlen(".text.unlikely."); +- if (sym->type == STT_FUNC && !strncmp(sym->sec->name, ".text.unlikely.", text_name_len) && ++ if (sym->type == STT_FUNC && ++ !strncmp(sym->sec->name, ".text.unlikely.", text_name_len) && + strstr(sym->name, ".cold") && +- !strncmp(sym->sec->name + text_name_len, sym->name, strlen(sym->sec->name) - text_name_len)) ++ !strncmp(sym->sec->name + text_name_len, sym->name, ++ strlen(sym->sec->name) - text_name_len)) { + return true; ++ } + + return false; + } +@@ -267,7 +279,7 @@ static void bundle_symbols(struct upatch_elf *uelf) + if (is_bundleable(sym)) { + if (sym->sym.st_value != 0 && + is_gcc6_localentry_bundled_sym(uelf)) { +- ERROR("Symbol '%s' at offset %lu within section '%s', expected 0.", ++ ERROR("Symbol '%s' at offset %lu of section '%s', expected 0.", + sym->name, sym->sym.st_value, sym->sec->name); + } + sym->sec->sym = sym; +@@ -291,24 +303,27 @@ static void detect_child_functions(struct upatch_elf *uelf) + char *pname; + + list_for_each_entry(sym, &uelf->symbols, list) { +- if (sym->type != STT_FUNC) ++ if (sym->type != STT_FUNC) { + continue; +- ++ } + childstr = strstr(sym->name, ".cold"); +- if (!childstr) ++ if (!childstr) { + childstr = strstr(sym->name, ".part"); +- +- if (!childstr) ++ } ++ if (!childstr) { + continue; ++ } + + pname = strndup(sym->name, (size_t)(childstr - sym->name)); + log_debug("symbol '%s', pname: '%s'\n", sym->name, pname); +- if (!pname) ++ if (!pname) { + ERROR("detect_child_functions strndup failed."); ++ } + + sym->parent = find_symbol_by_name(&uelf->symbols, pname); +- if (sym->parent) ++ if (sym->parent) { + list_add_tail(&sym->subfunction_node, &sym->parent->children); ++ } + + free(pname); + } +@@ -316,32 +331,35 @@ static void detect_child_functions(struct upatch_elf *uelf) + + static bool discarded_sym(struct running_elf *relf, struct symbol *sym) + { +- if (!sym || !sym->sec || !sym->sec->name) +- return false; +- ++ if (!sym || !sym->sec || !sym->sec->name) { ++ return false; ++ } + /* +- * ".gnu.warning." section is to prevent some symbols in the dynamic library being used by external programs. +- * in the exec program, these sections are discarded in linker. so we discard these symbols. ++ * ".gnu.warning." section is to prevent some symbols ++ * in the dynamic library being used by external programs. ++ * In the exec program, these sections are discarded in linker. ++ * so we discard these symbols. + */ +- if (relf->is_exec && !strncmp(sym->sec->name, ".gnu.warning.", strlen(".gnu.warning."))) +- return true; ++ if (relf->is_exec && ++ !strncmp(sym->sec->name, ".gnu.warning.", strlen(".gnu.warning."))) { ++ return true; ++ } + +- return false; ++ return false; + } + +-enum LOCAL_MATCH { ++enum local_match { + FOUND, + NOT_FOUND, + EMPTY, + }; + +-static enum LOCAL_MATCH locals_match( +- struct upatch_elf *uelf, struct running_elf *relf, +- struct symbol *file_sym, int file_sym_idx) ++static enum local_match locals_match(struct upatch_elf *uelf, ++ struct running_elf *relf, struct symbol *file_sym, int file_sym_idx) + { + struct symbol *uelf_sym = NULL; + struct debug_symbol *relf_sym = NULL; +- enum LOCAL_MATCH found = EMPTY; ++ enum local_match found = EMPTY; + + for (int i = file_sym_idx + 1; i < relf->obj_nr; i++) { + relf_sym = &relf->obj_syms[i]; +@@ -363,7 +381,7 @@ static enum LOCAL_MATCH locals_match( + if (uelf_sym->type == STT_FILE) { + break; // find until next file + } +- if(uelf_sym->bind != STB_LOCAL) { ++ if (uelf_sym->bind != STB_LOCAL) { + continue; + } + if ((uelf_sym->type == relf_sym->type) && +@@ -385,7 +403,7 @@ static enum LOCAL_MATCH locals_match( + if (uelf_sym->type == STT_FILE) { + break; // find until next file + } +- if(uelf_sym->bind != STB_LOCAL) { ++ if (uelf_sym->bind != STB_LOCAL) { + continue; + } + if ((relf_sym->type != STT_FUNC) && +@@ -428,7 +446,7 @@ static void find_local_syms(struct upatch_elf *uelf, struct running_elf *relf, + { + struct debug_symbol *relf_sym = NULL; + struct debug_symbol *found_sym = NULL; +- enum LOCAL_MATCH found; ++ enum local_match found; + + for (int i = 0; i < relf->obj_nr; i++) { + relf_sym = &relf->obj_syms[i]; +@@ -443,12 +461,10 @@ static void find_local_syms(struct upatch_elf *uelf, struct running_elf *relf, + found = locals_match(uelf, relf, file_sym, i); + if (found == NOT_FOUND) { + continue; +- } +- else if (found == EMPTY) { ++ } else if (found == EMPTY) { + found_sym = relf_sym; + break; +- } +- else { ++ } else { + if (found_sym) { + ERROR("Found duplicate local symbols in '%s'", g_relf_name); + } +@@ -469,8 +485,8 @@ static void find_local_syms(struct upatch_elf *uelf, struct running_elf *relf, + } + + /* +- * Because there can be duplicate symbols in elf, we need correlate each symbol from +- * source elf to it's corresponding symbol in running elf. ++ * Because there can be duplicate symbols in elf, we need correlate each symbol ++ * from source elf to it's corresponding symbol in running elf. + * Both the source elf and the running elf can be split on STT_FILE + * symbols into blocks of symbols originating from a single source file. + * We then compare local symbol lists from both blocks and store the pointer +@@ -509,24 +525,28 @@ static void mark_file_symbols(struct upatch_elf *uelf) + + static void mark_grouped_sections(struct upatch_elf *uelf) + { +- struct section *groupsec, *sec; +- unsigned int *data, *end; ++ struct section *groupsec; ++ struct section *sec; ++ unsigned int *data; ++ unsigned int *end; + + list_for_each_entry(groupsec, &uelf->sections, list) { +- if (groupsec->sh.sh_type != SHT_GROUP) ++ if (groupsec->sh.sh_type != SHT_GROUP) { + continue; +- data = groupsec->data->d_buf; +- end = groupsec->data->d_buf + groupsec->data->d_size; +- data++; /* skip first flag word (e.g. GRP_COMDAT) */ +- while (data < end) { +- sec = find_section_by_index(&uelf->sections, *data); +- if (!sec) +- ERROR("Group section not found"); +- sec->grouped = 1; +- log_debug("Marking section '%s' (%d) as grouped\n", +- sec->name, sec->index); +- data++; +- } ++ } ++ data = groupsec->data->d_buf; ++ end = groupsec->data->d_buf + groupsec->data->d_size; ++ data++; /* skip first flag word (e.g. GRP_COMDAT) */ ++ while (data < end) { ++ sec = find_section_by_index(&uelf->sections, *data); ++ if (!sec) { ++ ERROR("Group section not found"); ++ } ++ sec->grouped = 1; ++ log_debug("Marking section '%s' (%d) as grouped\n", ++ sec->name, sec->index); ++ data++; ++ } + } + } + +@@ -545,26 +565,32 @@ static void replace_section_syms(struct upatch_elf *uelf) + bool found = false; + + list_for_each_entry(relasec, &uelf->sections, list) { +- if (!is_rela_section(relasec) || is_debug_section(relasec) || is_note_section(relasec)) ++ if (!is_rela_section(relasec) || ++ is_debug_section(relasec) || ++ is_note_section(relasec)) { + continue; ++ } + + list_for_each_entry(rela, &relasec->relas, list) { +- if (!rela->sym || !rela->sym->sec || rela->sym->type != STT_SECTION) ++ if (!rela->sym || !rela->sym->sec || ++ rela->sym->type != STT_SECTION) { + continue; +- +- log_debug("Found replace symbol for section '%s' \n", rela->sym->name); ++ } ++ log_debug("Found replace symbol for section '%s'\n", ++ rela->sym->name); + + /* + * for section symbol, rela->sym->sec is the section itself. +- * rela->sym->sec->sym is the bundleable symbol which is a function or object. ++ * rela->sym->sec->sym is the bundleable symbol which is ++ * a function or object. + */ + if (rela->sym->sec->sym) { +- log_debug("Act: Replace it with '%s' <- '%s' \n", rela->sym->sec->sym->name, rela->sym->sec->name); ++ log_debug("Act: Replace it with '%s' <- '%s'\n", ++ rela->sym->sec->sym->name, rela->sym->sec->name); + rela->sym = rela->sym->sec->sym; +- +- if (rela->sym->sym.st_value != 0) ++ if (rela->sym->sym.st_value != 0) { + ERROR("Symbol offset is not zero."); +- ++ } + continue; + } + +@@ -572,9 +598,13 @@ static void replace_section_syms(struct upatch_elf *uelf) + list_for_each_entry(sym, &uelf->symbols, list) { + long start, end; + +- /* find object which belongs to this section, it could be .data .rodata etc */ +- if (sym->type == STT_SECTION || sym->sec != rela->sym->sec) ++ /* ++ * find object which belongs to this section, ++ * it could be .data .rodata etc. ++ */ ++ if (sym->type == STT_SECTION || sym->sec != rela->sym->sec) { + continue; ++ } + + start = (long)sym->sym.st_value; + end = (long)(sym->sym.st_value + sym->sym.st_size); +@@ -582,17 +612,20 @@ static void replace_section_syms(struct upatch_elf *uelf) + /* text section refer other sections */ + if (is_text_section(relasec->base) && + !is_text_section(sym->sec) && +- (rela->type == R_X86_64_32S || rela->type == R_X86_64_32 || rela->type == R_AARCH64_ABS64) && ++ (rela->type == R_X86_64_32S || ++ rela->type == R_X86_64_32 || ++ rela->type == R_AARCH64_ABS64) && + rela->addend == (long)sym->sec->sh.sh_size && +- end == (long)sym->sec->sh.sh_size) ++ end == (long)sym->sec->sh.sh_size) { + ERROR("Relocation refer end of data sections."); +- else if (target_off == start && target_off == end){ +- if(is_mapping_symbol(uelf, sym)) ++ } else if (target_off == start && target_off == end) { ++ if (is_mapping_symbol(uelf, sym)) { + continue; ++ } + log_debug("Find relocation reference for empty symbol.\n"); +- } +- else if (target_off < start || target_off >= end) ++ } else if (target_off < start || target_off >= end) { + continue; ++ } + + log_debug("'%s': Replacing '%s+%ld' reference with '%s+%ld'\n", + relasec->name, rela->sym->name, rela->addend, +@@ -653,9 +686,9 @@ static void mark_ignored_sections(struct upatch_elf *uelf) + list_for_each_entry(sec, &uelf->sections, list) { + if (!strncmp(sec->name, ".discard", strlen(".discard")) || + !strncmp(sec->name, ".rela.discard", strlen(".rela.discard"))) { +- log_debug("Found discard section '%s'\n", sec->name); +- sec->ignore = 1; +- } ++ log_debug("Found discard section '%s'\n", sec->name); ++ sec->ignore = 1; ++ } + } + + /* TODO: handle ignore information from sections or settings */ +@@ -672,26 +705,30 @@ static void mark_ignored_sections_same(void) {} + * We use st_other to mark these symbols. + */ + static void include_special_local_section(struct upatch_elf *uelf) { +- struct symbol *sym, *sym_changed; ++ struct symbol *sym; ++ struct symbol *sym_changed; + struct rela *rela; + + list_for_each_entry(sym_changed, &uelf->symbols, list) { +- if (!(sym_changed->status == CHANGED && sym_changed->type == STT_FUNC)) ++ if (!(sym_changed->status == CHANGED && sym_changed->type == STT_FUNC)) { + continue; +- +- if (!sym_changed->sec || !sym_changed->sec->rela) ++ } ++ if (!sym_changed->sec || !sym_changed->sec->rela) { + continue; ++ } + + list_for_each_entry(rela, &sym_changed->sec->rela->relas, list) { + sym = rela->sym; +- if (sym->sec && sym->status == SAME && sym->bind == STB_LOCAL && !sym->sec->include) { ++ if (sym->sec && sym->bind == STB_LOCAL && ++ sym->status == SAME && !sym->sec->include) { + sym->sym.st_other |= SYM_OTHER; + sym->sec->include = 1; + sym->sec->data->d_buf = NULL; + sym->sec->data->d_size = 0; + // arm error: (.debug_info+0x...) undefined reference to `no symbol' +- if (sym->sec->secsym) ++ if (sym->sec->secsym) { + sym->sec->secsym->include = 1; ++ } + } + } + } +@@ -700,16 +737,15 @@ static void include_special_local_section(struct upatch_elf *uelf) { + static void include_section(struct section *sec); + static void include_symbol(struct symbol *sym) + { +- if (sym->include) ++ if (sym->include) { + return; +- ++ } + /* + * The symbol gets included even if its section isn't needed, as it + * might be needed: either permanently for a rela, or temporarily for + * the later creation of a dynrela. + */ + sym->include = 1; +- + /* + * For a function/object symbol, if it has a section, we only need to + * include the section if it has changed. Otherwise the symbol will be +@@ -718,27 +754,32 @@ static void include_symbol(struct symbol *sym) + * For section symbols, we always include the section because + * references to them can't otherwise be resolved externally. + */ +- if (sym->sec && (sym->type == STT_SECTION || sym->status != SAME)) ++ if (sym->sec && (sym->type == STT_SECTION || sym->status != SAME)) { + include_section(sym->sec); ++ } + } + + static void include_section(struct section *sec) + { + struct rela *rela; + +- if (sec->include) ++ if (sec->include) { + return; ++ } + + sec->include = 1; +- if (sec->secsym) ++ if (sec->secsym) { + sec->secsym->include = 1; ++ } + +- if (!sec->rela) ++ if (!sec->rela) { + return; ++ } + + sec->rela->include = 1; +- list_for_each_entry(rela, &sec->rela->relas, list) ++ list_for_each_entry(rela, &sec->rela->relas, list) { + include_symbol(rela->sym); ++ } + } + + static void include_standard_elements(struct upatch_elf *uelf) +@@ -751,14 +792,16 @@ static void include_standard_elements(struct upatch_elf *uelf) + !strcmp(sec->name, ".strtab") || + !strcmp(sec->name, ".symtab") || + !strcmp(sec->name, ".rodata") || +- is_string_literal_section(sec)) ++ is_string_literal_section(sec)) { + include_section(sec); ++ } + } + +- list_for_each_entry(sym, &uelf->symbols, list) +- if (sym->sec && is_string_literal_section(sym->sec)) ++ list_for_each_entry(sym, &uelf->symbols, list) { ++ if (sym->sec && is_string_literal_section(sym->sec)) { + sym->include = 1; +- ++ } ++ } + /* include the NULL symbol */ + list_entry(uelf->symbols.next, struct symbol, list)->include = 1; + } +@@ -774,7 +817,6 @@ static int include_changed_functions(struct upatch_elf *uelf) + changed_nr++; + include_symbol(sym); + } +- + /* exception handler is a special function */ + if (sym->status == CHANGED && + sym->type == STT_SECTION && +@@ -783,9 +825,9 @@ static int include_changed_functions(struct upatch_elf *uelf) + changed_nr++; + include_symbol(sym); + } +- +- if (sym->type == STT_FILE) ++ if (sym->type == STT_FILE) { + sym->include = 1; ++ } + } + + return changed_nr; +@@ -797,8 +839,7 @@ static int include_new_globals(struct upatch_elf *uelf) + int nr = 0; + + list_for_each_entry(sym, &uelf->symbols, list) { +- if (sym->bind == STB_GLOBAL && sym->sec && +- sym->status == NEW) { ++ if (sym->bind == STB_GLOBAL && sym->sec && sym->status == NEW) { + include_symbol(sym); + nr++; + } +@@ -809,19 +850,21 @@ static int include_new_globals(struct upatch_elf *uelf) + + static void include_debug_sections(struct upatch_elf *uelf) + { +- struct rela *rela, *saferela; +- struct section *sec = NULL, *eh_sec = NULL; ++ struct rela *rela; ++ struct rela *saferela; ++ struct section *sec = NULL; ++ struct section *eh_sec = NULL; + + /* include all .debug_* sections */ + list_for_each_entry(sec, &uelf->sections, list) { + if (is_debug_section(sec)) { + sec->include = 1; +- +- if (!is_rela_section(sec) && sec->secsym) ++ if (!is_rela_section(sec) && sec->secsym) { + sec->secsym->include = 1; +- +- if (!is_rela_section(sec) && is_eh_frame(sec)) ++ } ++ if (!is_rela_section(sec) && is_eh_frame(sec)) { + eh_sec = sec; ++ } + } + } + +@@ -831,19 +874,20 @@ static void include_debug_sections(struct upatch_elf *uelf) + * for eh_frame section, sync the FDE at the same time + */ + list_for_each_entry(sec, &uelf->sections, list) { +- if (!is_rela_section(sec) || !is_debug_section(sec)) ++ if (!is_rela_section(sec) || !is_debug_section(sec)) { + continue; +- +- list_for_each_entry_safe(rela, saferela, &sec->relas, list) ++ } ++ list_for_each_entry_safe(rela, saferela, &sec->relas, list) { + // The shndex of symbol is SHN_COMMON, there is no related section + if (rela->sym && !rela->sym->include) { + list_del(&rela->list); + free(rela); + } ++ } + } +- +- if (eh_sec) ++ if (eh_sec) { + upatch_rebuild_eh_frame(eh_sec); ++ } + } + + /* currently, there si no special section need to be handled */ +@@ -855,7 +899,7 @@ static bool has_tls_included(struct upatch_elf *uelf) + + list_for_each_entry(sym, &uelf->symbols, list) { + if (sym->include == 1 && sym->type == STT_TLS) { +- log_normal("TLS symbol '%s' included, but it's not supported", sym->name); ++ log_normal("TLS symbol '%s' is not supported", sym->name); + return true; + } + } +@@ -869,40 +913,47 @@ static void verify_patchability(struct upatch_elf *uelf) + + list_for_each_entry(sec, &uelf->sections, list) { + if (sec->status == CHANGED && !sec->include && !is_rela_section(sec)) { +- log_normal("Section '%s' is changed, but it is not selected for inclusion\n", sec->name); ++ log_normal("Section '%s' changed, but not included\n", sec->name); + errs++; + } + + if (sec->status != SAME && sec->grouped) { +- log_normal("Section '%s' is changed, but it is a part of a section group\n", sec->name); ++ log_normal("Section '%s' is changed, but it is in section group\n", ++ sec->name); + errs++; + } + + if (sec->sh.sh_type == SHT_GROUP && sec->status == NEW) { +- log_normal("Section '%s' is new, but type 'SHT_GROUP' is not supported\n", sec->name); ++ log_normal("Section '%s' is new, but it is not supported\n", ++ sec->name); + errs++; + } + +- if (sec->include && sec->status != NEW && +- (!strncmp(sec->name, ".data", 5) || !strncmp(sec->name, ".bss", 4)) && +- (strcmp(sec->name, ".data.unlikely") && strcmp(sec->name, ".data.once"))) { +- log_normal("Data section '%s' is selected for inclusion\n", sec->name); ++ if ((sec->include && sec->status != NEW) && ++ (!strncmp(sec->name, ".data", 5) || ++ !strncmp(sec->name, ".bss", 4)) && ++ (strcmp(sec->name, ".data.unlikely") && ++ strcmp(sec->name, ".data.once"))) { ++ log_normal("Data section '%s' is included", sec->name); + errs++; + } + } + +- if (errs) +- DIFF_FATAL("%d, Unsupported section changes", errs); +- ++ if (errs) { ++ ERROR("%d, Unsupported section changes", errs); ++ } + if (has_tls_included(uelf)) { +- DIFF_FATAL("Unsupported symbol included"); ++ ERROR("Unsupported symbol included"); + } + } + +-static void migrate_included_elements(struct upatch_elf *uelf_patched, struct upatch_elf *uelf_out) ++static void migrate_included_elements(struct upatch_elf *uelf_patched, ++ struct upatch_elf *uelf_out) + { +- struct section *sec, *safesec; +- struct symbol *sym, *safesym; ++ struct section *sec; ++ struct section *safesec; ++ struct symbol *sym; ++ struct symbol *safesym; + + memset(uelf_out, 0, sizeof(struct upatch_elf)); + uelf_out->arch = uelf_patched->arch; +@@ -913,48 +964,58 @@ static void migrate_included_elements(struct upatch_elf *uelf_patched, struct up + + /* migrate included sections from uelf_patched to uelf_out */ + list_for_each_entry_safe(sec, safesec, &uelf_patched->sections, list) { +- if (!sec->include) ++ if (!sec->include) { + continue; +- ++ } + list_del(&sec->list); + list_add_tail(&sec->list, &uelf_out->sections); + sec->index = 0; +- if (!is_rela_section(sec) && sec->secsym && !sec->secsym->include) ++ ++ if (!is_rela_section(sec) && sec->secsym && !sec->secsym->include) { + sec->secsym = NULL; // break link to non-included section symbol ++ } + } + + /* migrate included symbols from kelf to out */ + list_for_each_entry_safe(sym, safesym, &uelf_patched->symbols, list) { +- if (!sym->include) ++ if (!sym->include) { + continue; ++ } + + list_del(&sym->list); + list_add_tail(&sym->list, &uelf_out->symbols); + sym->index = 0; + sym->strip = SYMBOL_DEFAULT; +- if (sym->sec && !sym->sec->include) ++ ++ if (sym->sec && !sym->sec->include) { + sym->sec = NULL; // break link to non-included section ++ } + } + } + + int main(int argc, char*argv[]) + { + struct arguments arguments; +- struct upatch_elf uelf_source, uelf_patched, uelf_out; ++ struct upatch_elf uelf_source; ++ struct upatch_elf uelf_patched; ++ struct upatch_elf uelf_out; + struct running_elf relf; + +- int num_changed, new_globals_exist; ++ int num_changed; ++ int new_globals_exist; + + memset(&arguments, 0, sizeof(arguments)); + argp_parse(&argp, argc, argv, 0, NULL, &arguments); + +- if (arguments.debug) ++ if (arguments.debug) { + g_loglevel = DEBUG; ++ } + g_logprefix = basename(arguments.source_obj); + show_program_info(&arguments); + +- if (elf_version(EV_CURRENT) == EV_NONE) ++ if (elf_version(EV_CURRENT) == EV_NONE) { + ERROR("ELF library initialization failed"); ++ } + + /* TODO: with debug info, this may changed */ + g_uelf_name = arguments.source_obj; +@@ -1008,7 +1069,6 @@ int main(int argc, char*argv[]) + upatch_elf_close(&uelf_patched); + + relf_close(&relf); +- + return 0; + } + +@@ -1062,7 +1122,8 @@ int main(int argc, char*argv[]) + + upatch_dump_kelf(&uelf_out); + +- upatch_write_output_elf(&uelf_out, uelf_patched.elf, arguments.output_obj, 0664); ++ upatch_write_output_elf(&uelf_out, uelf_patched.elf, arguments.output_obj, ++ 0664); + + upatch_elf_destroy(&uelf_source); + upatch_elf_destroy(&uelf_patched); +diff --git a/upatch-diff/elf-common.c b/upatch-diff/elf-common.c +index a74da3a..5aa35f1 100644 +--- a/upatch-diff/elf-common.c ++++ b/upatch-diff/elf-common.c +@@ -31,95 +31,104 @@ int mangled_strcmp(char *str1, char *str2) + /* + * ELF string sections aren't mangled, though they look that way. + */ +- if (strstr(str1, ".str1.")) +- return strcmp(str1, str2); +- +- while (*str1 == *str2) { +- if (!*str2) +- return 0; ++ if (strstr(str1, ".str1.")) { ++ return strcmp(str1, str2); ++ } + ++ while (*str1 == *str2) { ++ if (!*str2) { ++ return 0; ++ } + // format like ".[0-9]" +- if (*str1 == '.' && isdigit(str1[1])) { +- if (!isdigit(str2[1])) +- return 1; +- while (isdigit(*++str1)) +- ; +- while (isdigit(*++str2)) +- ; +- } else { +- str1++; +- str2++; +- } +- } +- +- if ((!*str1 && has_digit_tail(str2)) || +- (!*str2 && has_digit_tail(str1))) +- return 0; +- +- return 1; ++ if (*str1 == '.' && isdigit(str1[1])) { ++ if (!isdigit(str2[1])) { ++ return 1; ++ } ++ while (isdigit(*++str1)) { ++ // empty loop body ++ } ++ while (isdigit(*++str2)) { ++ // empty loop body ++ } ++ } else { ++ str1++; ++ str2++; ++ } ++ } ++ ++ if ((!*str1 && has_digit_tail(str2)) || ++ (!*str2 && has_digit_tail(str1))) { ++ return 0; ++ } ++ ++ return 1; + } + + bool is_normal_static_local(struct symbol *sym) + { + // only handle local variable +- if (sym->type != STT_OBJECT || sym->bind != STB_LOCAL) +- return false; +- ++ if (sym->type != STT_OBJECT || sym->bind != STB_LOCAL) { ++ return false; ++ } + // TODO: .Local ? need a example here +- if (!strncmp(sym->name, ".L", 2)) { +- ERROR("find no-local variable \n"); +- return false; ++ if (!strncmp(sym->name, ".L", 2)) { ++ ERROR("find no-local variable\n"); ++ return false; ++ } ++ if (!strchr(sym->name, '.')) { ++ return false; + } + +- if (!strchr(sym->name, '.')) +- return false; +- +- /* +- * TODO: Special static local variables should never be correlated and should always +- * be included if they are referenced by an included function. +- */ +- +- return true; ++ /* ++ * TODO: Special static local variables should never be correlated and should always ++ * be included if they are referenced by an included function. ++ */ ++ return true; + } + + int offset_of_string(struct list_head *list, char *name) + { +- struct string *string; +- int index = 0; +- +- list_for_each_entry(string, list, list) { +- if (!strcmp(string->name, name)) +- return index; +- index += (int)strlen(string->name) + 1; +- } +- +- ALLOC_LINK(string, list); +- string->name = name; +- return index; ++ struct string *string; ++ int index = 0; ++ ++ list_for_each_entry(string, list, list) { ++ if (!strcmp(string->name, name)) { ++ return index; ++ } ++ index += (int)strlen(string->name) + 1; ++ } ++ ++ ALLOC_LINK(string, list); ++ string->name = name; ++ ++ return index; + } + + // no need for X86 + bool is_gcc6_localentry_bundled_sym(struct upatch_elf *uelf) + { +- switch(uelf->arch) { +- case AARCH64: +- return false; +- case X86_64: +- return false; +- default: +- ERROR("unsupported arch"); +- } +- return false; ++ switch (uelf->arch) { ++ case AARCH64: ++ return false; ++ case X86_64: ++ return false; ++ default: ++ ERROR("unsupported arch"); ++ } ++ ++ return false; + } + + bool is_mapping_symbol(struct upatch_elf *uelf, struct symbol *sym) + { +- if (uelf->arch != AARCH64) +- return false; +- +- if (sym->name && sym->name[0] == '$' +- && sym->type == STT_NOTYPE +- && sym->bind == STB_LOCAL) +- return true; +- return false; ++ if (uelf->arch != AARCH64) { ++ return false; ++ } ++ if (sym->name && sym->name[0] == '$' && ++ sym->type == STT_NOTYPE && ++ sym->bind == STB_LOCAL) { ++ return true; ++ } ++ ++ return false; + } +diff --git a/upatch-diff/elf-common.h b/upatch-diff/elf-common.h +index f3d4308..f5a48da 100644 +--- a/upatch-diff/elf-common.h ++++ b/upatch-diff/elf-common.h +@@ -36,14 +36,16 @@ + #include "log.h" + + #define ALLOC_LINK(_new, _list) \ +-{ \ +- (_new) = calloc(1, sizeof(*(_new))); \ +- if (!(_new)) \ +- ERROR("calloc"); \ +- INIT_LIST_HEAD(&(_new)->list); \ +- if (_list) \ +- list_add_tail(&(_new)->list, (_list)); \ +-} ++ do { \ ++ (_new) = calloc(1, sizeof(*(_new))); \ ++ if (!(_new)) { \ ++ ERROR("calloc"); \ ++ } \ ++ INIT_LIST_HEAD(&(_new)->list); \ ++ if (_list) { \ ++ list_add(&(_new)->list, (_list)); \ ++ } \ ++ } while (0) + + static inline bool is_rela_section(struct section *sec) + { +@@ -51,120 +53,132 @@ static inline bool is_rela_section(struct section *sec) + * An architecture usually only accepts one type. + * And, X86_64 only uses RELA + */ +- return (sec->sh.sh_type == SHT_RELA); ++ return (sec->sh.sh_type == SHT_RELA); + } + + + static inline bool is_text_section(struct section *sec) + { +- return (sec->sh.sh_type == SHT_PROGBITS && +- (sec->sh.sh_flags & SHF_EXECINSTR)); ++ return (sec->sh.sh_type == SHT_PROGBITS && ++ (sec->sh.sh_flags & SHF_EXECINSTR)); + } + + static inline bool is_string_section(struct section *sec) + { +- return sec->sh.sh_flags & SHF_STRINGS; ++ return sec->sh.sh_flags & SHF_STRINGS; + } + + /* used for c++ exception handle */ + static inline bool is_except_section(struct section *sec) + { +- return !strncmp(sec->name, ".gcc_except_table", 17); ++ return !strncmp(sec->name, ".gcc_except_table", 17); + } + + static inline bool is_note_section(struct section *sec) + { +- if (is_rela_section(sec)) +- sec = sec->base; +- return sec->sh.sh_type == SHT_NOTE; ++ if (is_rela_section(sec)) { ++ sec = sec->base; ++ } ++ return sec->sh.sh_type == SHT_NOTE; + } + + static inline bool is_eh_frame(struct section *sec) + { +- char *name; +- if (is_rela_section(sec)) +- name = sec->base->name; +- else +- name = sec->name; +- +- return !strncmp(name, ".eh_frame", 9); ++ char *name; ++ if (is_rela_section(sec)) { ++ name = sec->base->name; ++ } else { ++ name = sec->name; ++ } ++ return !strncmp(name, ".eh_frame", 9); + } + + static inline bool is_debug_section(struct section *sec) + { +- char *name; +- if (is_rela_section(sec)) +- name = sec->base->name; +- else +- name = sec->name; +- +- /* .eh_frame_hdr will be generated by the linker */ +- return !strncmp(name, ".debug_", 7) || +- !strncmp(name, ".eh_frame", 9); ++ char *name; ++ if (is_rela_section(sec)) { ++ name = sec->base->name; ++ } else { ++ name = sec->name; ++ } ++ /* .eh_frame_hdr will be generated by the linker */ ++ return !strncmp(name, ".debug_", 7) || ++ !strncmp(name, ".eh_frame", 9); + } + + static inline struct symbol *find_symbol_by_index(struct list_head *list, unsigned int index) + { +- struct symbol *sym; ++ struct symbol *sym; + +- list_for_each_entry(sym, list, list) +- if (sym->index == index) +- return sym; ++ list_for_each_entry(sym, list, list) { ++ if (sym->index == index) { ++ return sym; ++ } ++ } + +- return NULL; ++ return NULL; + } + + static inline struct symbol *find_symbol_by_name(struct list_head *list, const char *name) + { +- struct symbol *sym; ++ struct symbol *sym; + +- list_for_each_entry(sym, list, list) +- if (sym->name && !strcmp(sym->name, name)) +- return sym; ++ list_for_each_entry(sym, list, list) { ++ if (sym->name && !strcmp(sym->name, name)) { ++ return sym; ++ } ++ } + +- return NULL; ++ return NULL; + } + + static inline struct section *find_section_by_index(struct list_head *list, unsigned int index) + { +- struct section *sec; ++ struct section *sec; + +- list_for_each_entry(sec, list, list) +- if (sec->index == index) +- return sec; ++ list_for_each_entry(sec, list, list) { ++ if (sec->index == index) { ++ return sec; ++ } ++ } + +- return NULL; ++ return NULL; + } + + static inline struct section *find_section_by_name(struct list_head *list, const char *name) + { +- struct section *sec; ++ struct section *sec; + +- list_for_each_entry(sec, list, list) +- if (!strcmp(sec->name, name)) +- return sec; ++ list_for_each_entry(sec, list, list) { ++ if (!strcmp(sec->name, name)) { ++ return sec; ++ } ++ } + +- return NULL; ++ return NULL; + } + + // section like .rodata.str1. and .rodata.__func__. + static inline bool is_string_literal_section(struct section *sec) + { +- return !strncmp(sec->name, ".rodata.", 8) && (strstr(sec->name, ".str") || strstr(sec->name, "__func__")); ++ return !strncmp(sec->name, ".rodata.", 8) && (strstr(sec->name, ".str") || strstr(sec->name, "__func__")); + } + + static inline bool has_digit_tail(char *tail) + { +- if (*tail != '.') +- return false; ++ if (*tail != '.') { ++ return false; ++ } + +- while (isdigit(*++tail)) +- ; ++ while (isdigit(*++tail)) { ++ // empty loop body ++ } + +- if (!*tail) +- return true; ++ if (!*tail) { ++ return true; ++ } + +- return false; ++ return false; + } + + /* +@@ -178,59 +192,60 @@ bool is_normal_static_local(struct symbol *); + + static inline char *section_function_name(struct section *sec) + { +- if (is_rela_section(sec)) +- sec = sec->base; +- return sec->sym ? sec->sym->name : sec->name; ++ if (is_rela_section(sec)) { ++ sec = sec->base; ++ } ++ return sec->sym ? sec->sym->name : sec->name; + } + + static inline char *status_str(enum status status) + { +- switch(status) { +- case NEW: +- return "NEW"; +- case CHANGED: +- return "CHANGED"; +- case SAME: +- return "SAME"; +- default: +- ERROR("status_str"); +- } +- return NULL; ++ switch (status) { ++ case NEW: ++ return "NEW"; ++ case CHANGED: ++ return "CHANGED"; ++ case SAME: ++ return "SAME"; ++ default: ++ ERROR("status_str"); ++ } ++ return NULL; + } + + int offset_of_string(struct list_head *, char *); + + static inline unsigned int absolute_rela_type(struct upatch_elf *uelf) + { +- switch(uelf->arch) { +- case AARCH64: +- return R_AARCH64_ABS64; +- case X86_64: +- return R_X86_64_64; +- default: +- ERROR("unsupported arch"); +- } +- return 0; ++ switch (uelf->arch) { ++ case AARCH64: ++ return R_AARCH64_ABS64; ++ case X86_64: ++ return R_X86_64_64; ++ default: ++ ERROR("unsupported arch"); ++ } ++ return 0; + } + + static inline bool is_null_sym(struct symbol *sym) + { +- return !strlen(sym->name); ++ return !strlen(sym->name); + } + + static inline bool is_file_sym(struct symbol *sym) + { +- return sym->type == STT_FILE; ++ return sym->type == STT_FILE; + } + + static inline bool is_local_func_sym(struct symbol *sym) + { +- return sym->bind == STB_LOCAL && sym->type == STT_FUNC; ++ return sym->bind == STB_LOCAL && sym->type == STT_FUNC; + } + + static inline bool is_local_sym(struct symbol *sym) + { +- return sym->bind == STB_LOCAL; ++ return sym->bind == STB_LOCAL; + } + + bool is_gcc6_localentry_bundled_sym(struct upatch_elf *); +@@ -243,4 +258,4 @@ bool is_gcc6_localentry_bundled_sym(struct upatch_elf *); + */ + bool is_mapping_symbol(struct upatch_elf *, struct symbol *); + +-#endif +\ No newline at end of file ++#endif +diff --git a/upatch-diff/elf-compare.c b/upatch-diff/elf-compare.c +index 5d39825..7ca6845 100644 +--- a/upatch-diff/elf-compare.c ++++ b/upatch-diff/elf-compare.c +@@ -29,26 +29,26 @@ + #include "elf-compare.h" + #include "elf-insn.h" + +-static void compare_correlated_symbol(struct symbol *sym, struct symbol *symtwin) ++static void compare_correlated_symbol(struct symbol *sym, ++ struct symbol *symtwin) + { + // compare bind and type info + if (sym->sym.st_info != symtwin->sym.st_info || +- (sym->sec && !symtwin->sec) || +- (symtwin->sec && !sym->sec)) +- DIFF_FATAL("symbol info mismatch: %s", sym->name); +- ++ (sym->sec && !symtwin->sec) || ++ (symtwin->sec && !sym->sec)) { ++ ERROR("symbol info mismatch: %s", sym->name); ++ } + // check if correlated symbols have correlated sections +- if (sym->sec && symtwin->sec && sym->sec->twin != symtwin->sec) +- DIFF_FATAL("symbol changed sections: %s", sym->name); +- ++ if (sym->sec && symtwin->sec && sym->sec->twin != symtwin->sec) { ++ ERROR("symbol changed sections: %s", sym->name); ++ } + // data object can't change size +- if (sym->type == STT_OBJECT && sym->sym.st_size != symtwin->sym.st_size) +- DIFF_FATAL("object size mismatch: %s", sym->name); +- +- if (sym->sym.st_shndx == SHN_UNDEF || +- sym->sym.st_shndx == SHN_ABS) +- sym->status = SAME; +- ++ if (sym->type == STT_OBJECT && sym->sym.st_size != symtwin->sym.st_size) { ++ ERROR("object size mismatch: %s", sym->name); ++ } ++ if (sym->sym.st_shndx == SHN_UNDEF || sym->sym.st_shndx == SHN_ABS) { ++ sym->status = SAME; ++ } + /* + * For local symbols, we handle them based on their matching sections. + */ +@@ -56,323 +56,355 @@ static void compare_correlated_symbol(struct symbol *sym, struct symbol *symtwin + + void upatch_compare_symbols(struct upatch_elf *uelf) + { +- struct symbol *sym; +- +- list_for_each_entry(sym, &uelf->symbols, list) { +- if (sym->twin) +- compare_correlated_symbol(sym, sym->twin); +- else +- sym->status = NEW; ++ struct symbol *sym; + +- log_debug("symbol %s is %s\n", sym->name, status_str(sym->status)); +- } ++ list_for_each_entry(sym, &uelf->symbols, list) { ++ if (sym->twin) { ++ compare_correlated_symbol(sym, sym->twin); ++ } else { ++ sym->status = NEW; ++ } ++ log_debug("symbol %s is %s\n", sym->name, status_str(sym->status)); ++ } + } + + static bool rela_equal(struct rela *rela1, struct rela *rela2) + { +- if (rela1->type != rela2->type || +- rela1->offset != rela2->offset) ++ if (rela1->type != rela2->type || rela1->offset != rela2->offset) { + return false; +- ++ } + /* TODO: handle altinstr_aux */ +- + /* TODO: handle rela for toc section */ +- +- if (rela1->string) +- return rela2->string && !strcmp(rela1->string, rela2->string); +- +- if (rela1->addend != rela2->addend) { +- log_debug("relocation addend has changed from %ld to %ld", rela1->addend, rela2->addend); +- return false; ++ if (rela1->string) { ++ return rela2->string && !strcmp(rela1->string, rela2->string); ++ } ++ if (rela1->addend != rela2->addend) { ++ log_debug("relocation addend has changed from %ld to %ld", ++ rela1->addend, rela2->addend); ++ return false; + } + + return !mangled_strcmp(rela1->sym->name, rela2->sym->name); + } + +-static void compare_correlated_rela_section(struct section *relasec, struct section *relasec_twin) ++static void compare_correlated_rela_section(struct section *relasec, ++ struct section *relasec_twin) + { +- struct rela *rela1, *rela2 = NULL; ++ struct rela *rela1 = NULL; ++ struct rela *rela2 = NULL; + + /* check relocation item one by one, order matters */ +- 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; +- } +- relasec->status = CHANGED; +- return; +- } +- +- relasec->status = SAME; ++ 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; ++ } ++ relasec->status = CHANGED; ++ return; ++ } ++ relasec->status = SAME; + } + +-static void compare_correlated_nonrela_section(struct section *sec, struct section *sectwin) ++static void compare_correlated_nonrela_section(struct section *sec, ++ struct section *sectwin) + { +- if (sec->sh.sh_type != SHT_NOBITS && ++ if (sec->sh.sh_type != SHT_NOBITS && + (sec->data->d_size != sectwin->data->d_size || +- memcmp(sec->data->d_buf, sectwin->data->d_buf, sec->data->d_size))) +- sec->status = CHANGED; +- else +- sec->status = SAME; ++ memcmp(sec->data->d_buf, sectwin->data->d_buf, sec->data->d_size))) { ++ sec->status = CHANGED; ++ } else { ++ sec->status = SAME; ++ } + } + + // we may change status of sec, they are not same +-static int compare_correlated_section(struct section *sec, struct section *sectwin) ++static int compare_correlated_section(struct section *sec, ++ struct section *sectwin) + { + /* TODO: addr align of rodata has changed. after strlen(str) >= 30, align 8 exists */ + /* compare section headers */ +- if (sec->sh.sh_type != sectwin->sh.sh_type || +- sec->sh.sh_flags != sectwin->sh.sh_flags || +- sec->sh.sh_entsize != sectwin->sh.sh_entsize || +- (sec->sh.sh_addralign != sectwin->sh.sh_addralign && +- !is_text_section(sec) && !is_string_section(sec))) { +- DIFF_FATAL("%s section header details differ from %s", sec->name, sectwin->name); ++ if (sec->sh.sh_type != sectwin->sh.sh_type || ++ sec->sh.sh_flags != sectwin->sh.sh_flags || ++ sec->sh.sh_entsize != sectwin->sh.sh_entsize || ++ (sec->sh.sh_addralign != sectwin->sh.sh_addralign && ++ !is_text_section(sec) && !is_string_section(sec))) { ++ ERROR("%s section header details differ from %s", ++ sec->name, sectwin->name); + return -1; + } + +- if (is_note_section(sec)) { +- sec->status = SAME; +- goto out; +- } +- +- /* As above but for aarch64 */ +- if (!strcmp(sec->name, ".rela__patchable_function_entries") || +- !strcmp(sec->name, "__patchable_function_entries")) { +- sec->status = SAME; +- goto out; +- } +- ++ if (is_note_section(sec)) { ++ sec->status = SAME; ++ goto out; ++ } ++ /* As above but for aarch64 */ ++ if (!strcmp(sec->name, ".rela__patchable_function_entries") || ++ !strcmp(sec->name, "__patchable_function_entries")) { ++ sec->status = SAME; ++ goto out; ++ } + /* compare file size and data size(memory size) */ +- if (sec->sh.sh_size != sectwin->sh.sh_size || +- sec->data->d_size != sectwin->data->d_size || ++ if (sec->sh.sh_size != sectwin->sh.sh_size || ++ sec->data->d_size != sectwin->data->d_size || + (sec->rela && !sectwin->rela) || (!sec->rela && sectwin->rela)) { +- sec->status = CHANGED; +- goto out; +- } ++ sec->status = CHANGED; ++ goto out; ++ } + +- if (is_rela_section(sec)) ++ if (is_rela_section(sec)) { + compare_correlated_rela_section(sec, sectwin); +- else ++ } else { + compare_correlated_nonrela_section(sec, sectwin); ++ } + + out: +- if(sec->status == CHANGED) +- log_debug("section %s has changed\n", sec->name); ++ if (sec->status == CHANGED) { ++ log_debug("section %s has changed\n", sec->name); ++ } + + return 0; + } + + bool upatch_handle_redis_line(const char *symname) + { +- if (!strncmp(symname, "_serverPanic", 12) || +- !strncmp(symname, "_serverAssert", 13) || +- !strncmp(symname, "_serverAssertWithInfo", 21) || ++ if (!strncmp(symname, "_serverPanic", 12) || ++ !strncmp(symname, "_serverAssert", 13) || ++ !strncmp(symname, "_serverAssertWithInfo", 21) || + !strncmp(symname, "rdbReportError", 14) || +- !strncmp(symname, "RedisModule__Assert", 19)) +- return true; +- return false; ++ !strncmp(symname, "RedisModule__Assert", 19)) { ++ return true; ++ } ++ ++ return false; + } + + /* TODO: let user support this list or generate by the compiler ? */ + bool check_line_func(const char *symname) + { +- if (!strncmp(basename(g_relf_name), "redis-server", 12)) +- return upatch_handle_redis_line(symname); ++ if (!strncmp(basename(g_relf_name), "redis-server", 12)) { ++ return upatch_handle_redis_line(symname); ++ } + +- return false; ++ return false; + } + + /* Determine if a section has changed only due to a __LINE__ bumber change. + * For example, a WARN() or might_sleep() macro's embedding of the line number into an + * instruction operand. + */ +-static bool _line_macro_change_only(struct upatch_elf *uelf, struct section *sec) ++static bool line_macro_change_only_x86_64(struct upatch_elf *uelf, ++ struct section *sec) + { +- unsigned long offset, insn1_len, insn2_len; +- void *data1, *data2, *insn1, *insn2; +- struct rela *rela; +- bool found, found_any = false; +- +- if (sec->status != CHANGED || +- is_rela_section(sec) || +- !is_text_section(sec) || +- sec->sh.sh_size != sec->twin->sh.sh_size || +- !sec->rela || +- sec->rela->status != SAME) +- return false; +- +- data1 = sec->twin->data->d_buf; +- data2 = sec->data->d_buf; +- for (offset = 0; offset < sec->sh.sh_size; offset += insn1_len) { +- insn1 = data1 + offset; +- insn2 = data2 + offset; +- +- insn1_len = insn_length(uelf, insn1); +- insn2_len = insn_length(uelf, insn2); +- +- if (!insn1_len || !insn2_len) +- ERROR("decode instruction in section %s at offset 0x%lx failed", +- sec->name, offset); +- +- if (insn1_len != insn2_len) +- return false; +- +- /* if insn are same, continue*/ +- if (!memcmp(insn1, insn2, insn1_len)) +- continue; +- +- log_debug("check list for %s at 0x%lx \n", sec->name, offset); +- +- /* +- * Here we found a differece between two instructions of the +- * same length. Only ignore the change if: +- * +- * 1) the instruction match a known pattern of a '__LINE__' +- * macro immediate value which was embedded in the instruction. +- * +- * 2) the instructions are followed by certain expected relocations. +- * (white-list) +- */ +- if (!insn_is_load_immediate(uelf, insn1) || +- !insn_is_load_immediate(uelf, insn2)) +- return false; +- +- found = false; +- list_for_each_entry(rela, &sec->rela->relas, list) { +- if (rela->offset < offset + insn1_len) +- continue; +- +- if (rela->string) +- continue; +- +- /* TODO: we may need black list ? */ +- if (check_line_func(rela->sym->name)) { +- found = true; +- break; +- } +- +- return false; +- } +- if (!found) +- return false; +- +- found_any = true; +- } +- +- if (!found_any) +- ERROR("no instruction changes detected for changed section %s", +- sec->name); ++ unsigned long offset; ++ unsigned long insn1_len; ++ unsigned long insn2_len; ++ ++ void *data1; ++ void *data2; ++ void *insn1; ++ void *insn2; ++ ++ struct rela *rela = NULL; ++ bool found_any = false; ++ bool found = false; ++ ++ if (sec->status != CHANGED || ++ is_rela_section(sec) || ++ !is_text_section(sec) || ++ sec->sh.sh_size != sec->twin->sh.sh_size || ++ !sec->rela || ++ sec->rela->status != SAME) { ++ return false; ++ } ++ ++ data1 = sec->twin->data->d_buf; ++ data2 = sec->data->d_buf; ++ for (offset = 0; offset < sec->sh.sh_size; offset += insn1_len) { ++ insn1 = data1 + offset; ++ insn2 = data2 + offset; ++ ++ insn1_len = insn_length(uelf, insn1); ++ insn2_len = insn_length(uelf, insn2); ++ if (!insn1_len || !insn2_len) { ++ ERROR("decode instruction in section %s at offset 0x%lx failed", ++ sec->name, offset); ++ } ++ ++ if (insn1_len != insn2_len) { ++ return false; ++ } ++ ++ /* if insn are same, continue */ ++ if (!memcmp(insn1, insn2, insn1_len)) { ++ continue; ++ } ++ log_debug("check list for %s at 0x%lx\n", sec->name, offset); ++ ++ /* ++ * Here we found a differece between two instructions of the ++ * same length. Only ignore the change if: ++ * ++ * 1) the instruction match a known pattern of a '__LINE__' ++ * macro immediate value which was embedded in the instruction. ++ * ++ * 2) the instructions are followed by certain expected relocations. ++ * (white-list) ++ */ ++ if (!insn_is_load_immediate(uelf, insn1) || ++ !insn_is_load_immediate(uelf, insn2)) { ++ return false; ++ } ++ ++ found = false; ++ list_for_each_entry(rela, &sec->rela->relas, list) { ++ if (rela->offset < offset + insn1_len) { ++ continue; ++ } ++ if (rela->string) { ++ continue; ++ } ++ /* TODO: we may need black list ? */ ++ if (check_line_func(rela->sym->name)) { ++ found = true; ++ break; ++ } ++ return false; ++ } ++ if (!found) { ++ return false; ++ } ++ ++ found_any = true; ++ } ++ ++ if (!found_any) { ++ ERROR("no instruction changes detected for changed section %s", ++ sec->name); ++ } + + return true; + } + +-static bool _line_macro_change_only_aarch64(struct upatch_elf *uelf, struct section *sec) ++static bool line_macro_change_only_aarch64(struct upatch_elf *uelf, ++ struct section *sec) + { ++ unsigned long start1; ++ unsigned long start2; ++ unsigned long size; ++ unsigned long offset; ++ ++ struct rela *rela = NULL; ++ bool found_any = false; ++ bool found = false; ++ ++ unsigned int mov_imm_mask = ((1<<16) - 1)<<5; ++ unsigned long insn_len = insn_length(uelf, NULL); ++ ++ if (sec->status != CHANGED || ++ is_rela_section(sec) || ++ !is_text_section(sec) || ++ sec->sh.sh_size != sec->twin->sh.sh_size || ++ !sec->rela || ++ sec->rela->status != SAME) { ++ return false; ++ } ++ ++ start1 = (unsigned long)sec->twin->data->d_buf; ++ start2 = (unsigned long)sec->data->d_buf; ++ size = sec->sh.sh_size; ++ for (offset = 0; offset < size; offset += insn_len) { ++ if (!memcmp((void *)start1 + offset, (void *)start2 + offset, ++ insn_len)) { ++ continue; ++ } ++ ++ /* verify it's a mov immediate to w1 */ ++ if ((*(unsigned int *)(start1 + offset) & ~mov_imm_mask) != ++ (*(unsigned int *)(start2 + offset) & ~mov_imm_mask)) { ++ return false; ++ } ++ ++ found = false; ++ list_for_each_entry(rela, &sec->rela->relas, list) { ++ if (rela->offset < offset + insn_len) { ++ continue; ++ } ++ if (rela->string) { ++ continue; ++ } ++ /* TODO: we may need black list ? */ ++ if (check_line_func(rela->sym->name)) { ++ found = true; ++ break; ++ } ++ return false; ++ } ++ if (!found) { ++ return false; ++ } + +- unsigned long start1, start2, size, offset; +- struct rela *rela; +- bool found_any = false, found; +- unsigned int mov_imm_mask = ((1<<16) - 1)<<5; +- unsigned long insn_len = insn_length(uelf, NULL); +- +- if (sec->status != CHANGED || +- is_rela_section(sec) || +- !is_text_section(sec) || +- sec->sh.sh_size != sec->twin->sh.sh_size || +- !sec->rela || +- sec->rela->status != SAME) +- return false; +- +- start1 = (unsigned long)sec->twin->data->d_buf; +- start2 = (unsigned long)sec->data->d_buf; +- size = sec->sh.sh_size; +- for (offset = 0; offset < size; offset += insn_len) { +- if (!memcmp((void *)start1 + offset, (void *)start2 + offset, insn_len)) +- continue; +- +- /* verify it's a mov immediate to w1 */ +- if ((*(unsigned int *)(start1 + offset) & ~mov_imm_mask) != +- (*(unsigned int *)(start2 + offset) & ~mov_imm_mask)) +- return false; +- +- found = false; +- list_for_each_entry(rela, &sec->rela->relas, list) { +- if (rela->offset < offset + insn_len) +- continue; +- if (rela->string) +- continue; +- +- /* TODO: we may need black list ? */ +- if (check_line_func(rela->sym->name)) { +- found = true; +- break; +- } +- return false; +- } +- if (!found) +- return false; +- +- found_any = true; +- } +- +- if (!found_any) +- ERROR("no instruction changes detected for changed section %s", +- sec->name); +- +- return true; ++ found_any = true; ++ } ++ ++ if (!found_any) { ++ ERROR("no instruction changes detected for changed section %s", ++ sec->name); ++ } ++ ++ return true; + } + + static bool line_macro_change_only(struct upatch_elf *uelf, struct section *sec) + { +- switch(uelf->arch) { +- case AARCH64: +- return _line_macro_change_only_aarch64(uelf, sec); +- case X86_64: +- return _line_macro_change_only(uelf, sec); +- default: +- ERROR("unsupported arch"); +- } +- return false; ++ switch (uelf->arch) { ++ case AARCH64: ++ return line_macro_change_only_aarch64(uelf, sec); ++ case X86_64: ++ return line_macro_change_only_x86_64(uelf, sec); ++ default: ++ ERROR("unsupported arch"); ++ } ++ return false; + } + +-static inline void update_section_status(struct section *sec, enum status status) ++static void update_section_status(struct section *sec, enum status status) + { +- if (sec == NULL) { +- return; +- } +- if (sec->twin != NULL) { +- sec->twin->status = status; +- } +- if (is_rela_section(sec)) { +- if ((sec->base != NULL) && (sec->base->sym != NULL) && status != SAME) { +- sec->base->sym->status = status; +- } +- } else { +- if (sec->sym != NULL) { +- sec->sym->status = status; +- } +- } ++ if (sec == NULL) { ++ return; ++ } ++ if (sec->twin != NULL) { ++ sec->twin->status = status; ++ } ++ if (is_rela_section(sec)) { ++ if ((sec->base != NULL) && (sec->base->sym != NULL) && status != SAME) { ++ sec->base->sym->status = status; ++ } ++ } else { ++ if (sec->sym != NULL) { ++ sec->sym->status = status; ++ } ++ } + } + + void upatch_compare_sections(struct upatch_elf *uelf) + { +- struct section *sec = NULL; +- +- list_for_each_entry(sec, &uelf->sections, list) { +- if (sec->twin == NULL) { +- sec->status = NEW; +- } +- else { +- compare_correlated_section(sec, sec->twin); +- } +- /* exclude WARN-only, might_sleep changes */ +- if (line_macro_change_only(uelf, sec)) { +- log_debug("reverting macro / line number section %s status to SAME\n", sec->name); +- sec->status = SAME; +- } +- /* sync status */ +- update_section_status(sec, sec->status); +- update_section_status(sec->twin, sec->status); +- } +-} +\ No newline at end of file ++ struct section *sec = NULL; ++ ++ list_for_each_entry(sec, &uelf->sections, list) { ++ if (sec->twin == NULL) { ++ sec->status = NEW; ++ } else { ++ compare_correlated_section(sec, sec->twin); ++ } ++ /* exclude WARN-only, might_sleep changes */ ++ if (line_macro_change_only(uelf, sec)) { ++ log_debug("reverting line number section %s status to SAME\n", ++ sec->name); ++ sec->status = SAME; ++ } ++ /* sync status */ ++ update_section_status(sec, sec->status); ++ update_section_status(sec->twin, sec->status); ++ } ++} +diff --git a/upatch-diff/elf-compare.h b/upatch-diff/elf-compare.h +index 3fd46a9..8ec1655 100644 +--- a/upatch-diff/elf-compare.h ++++ b/upatch-diff/elf-compare.h +@@ -37,4 +37,4 @@ static inline void upatch_compare_correlated_elements(struct upatch_elf *uelf) + upatch_compare_symbols(uelf); + } + +-#endif +\ No newline at end of file ++#endif +diff --git a/upatch-diff/elf-correlate.c b/upatch-diff/elf-correlate.c +index cc3b925..979453b 100644 +--- a/upatch-diff/elf-correlate.c ++++ b/upatch-diff/elf-correlate.c +@@ -27,67 +27,80 @@ + #include "elf-common.h" + #include "elf-correlate.h" + +-static void correlate_symbol(struct symbol *sym_orig, struct symbol *sym_patched) ++static void correlate_symbol(struct symbol *sym_orig, ++ struct symbol *sym_patched) + { +- log_debug("correlate symbol %s <-> %s \n", sym_orig->name, sym_patched->name); ++ log_debug("correlate symbol %s <-> %s\n", ++ sym_orig->name, sym_patched->name); + + sym_orig->twin = sym_patched; + sym_patched->twin = sym_orig; + sym_orig->status = sym_patched->status = SAME; + if (strcmp(sym_orig->name, sym_patched->name)) { +- log_debug("renaming symbol %s to %s \n", sym_patched->name, sym_orig->name); ++ log_debug("renaming symbol %s to %s\n", ++ sym_patched->name, sym_orig->name); + sym_patched->name = sym_orig->name; + sym_patched->name_source = DATA_SOURCE_REF; + } +- if (sym_orig->relf_sym && !sym_patched->relf_sym) +- sym_patched->relf_sym = sym_orig->relf_sym; ++ if (sym_orig->relf_sym && !sym_patched->relf_sym) { ++ sym_patched->relf_sym = sym_orig->relf_sym; ++ } + } + +-void upatch_correlate_symbols(struct upatch_elf *uelf_source, struct upatch_elf *uelf_patched) ++void upatch_correlate_symbols(struct upatch_elf *uelf_source, ++ struct upatch_elf *uelf_patched) + { +- struct symbol *sym_orig, *sym_patched; +- +- list_for_each_entry(sym_orig, &uelf_source->symbols, list) { +- if (sym_orig->twin) +- continue; ++ struct symbol *sym_orig; ++ struct symbol *sym_patched; + ++ list_for_each_entry(sym_orig, &uelf_source->symbols, list) { ++ if (sym_orig->twin) { ++ continue; ++ } + /* find matched symbol */ +- list_for_each_entry(sym_patched, &uelf_patched->symbols, list) { +- if (mangled_strcmp(sym_orig->name, sym_patched->name) || +- sym_orig->type != sym_patched->type || sym_patched->twin) +- continue; +- +- /* +- * TODO: Special static local variables should never be correlated and should always +- * be included if they are referenced by an included function. +- */ +- /* +- * The .LCx symbols point to string literals in +- * '.rodata..str1.*' sections. They get included +- * in include_standard_elements(). +- * Clang creates similar .Ltmp%d symbols in .rodata.str +- */ +- if (sym_orig->type == STT_NOTYPE && +- (!strncmp(sym_orig->name, ".LC", 3) || !strncmp(sym_orig->name, ".Ltmp", 5))) +- continue; +- +- if (is_mapping_symbol(uelf_source, sym_orig)) +- continue; +- +- /* group section symbols must have correlated sections */ +- if (sym_orig->sec && sym_orig->sec->sh.sh_type == SHT_GROUP && +- sym_orig->sec->twin != sym_patched->sec) +- continue; +- +- correlate_symbol(sym_orig, sym_patched); +- break; +- } +- } ++ list_for_each_entry(sym_patched, &uelf_patched->symbols, list) { ++ if (mangled_strcmp(sym_orig->name, sym_patched->name) || ++ sym_orig->type != sym_patched->type || sym_patched->twin) { ++ continue; ++ } ++ /* ++ * TODO: Special static local variables should never be correlated ++ * and should always be included if they are referenced by ++ * an included function. ++ */ ++ /* ++ * The .LCx symbols point to string literals in ++ * '.rodata..str1.*' sections. They get included ++ * in include_standard_elements(). ++ * Clang creates similar .Ltmp%d symbols in .rodata.str ++ */ ++ if (sym_orig->type == STT_NOTYPE && ++ (!strncmp(sym_orig->name, ".LC", 3) || ++ !strncmp(sym_orig->name, ".Ltmp", 5))) { ++ continue; ++ } ++ ++ if (is_mapping_symbol(uelf_source, sym_orig)) { ++ continue; ++ } ++ ++ /* group section symbols must have correlated sections */ ++ if (sym_orig->sec && sym_orig->sec->sh.sh_type == SHT_GROUP && ++ sym_orig->sec->twin != sym_patched->sec) { ++ continue; ++ } ++ ++ correlate_symbol(sym_orig, sym_patched); ++ break; ++ } ++ } + } + +-static void __correlate_section(struct section *sec_orig, struct section *sec_patched) ++static void correlate_section_impl(struct section *sec_orig, ++ struct section *sec_patched) + { +- log_debug("correlate section %s <-> %s \n", sec_orig->name, sec_patched->name); ++ log_debug("correlate section %s <-> %s\n", ++ sec_orig->name, sec_patched->name); + + sec_orig->twin = sec_patched; + sec_patched->twin = sec_orig; +@@ -96,96 +109,104 @@ static void __correlate_section(struct section *sec_orig, struct section *sec_pa + + /* Make sure these two sections have the same name */ + if (strcmp(sec_orig->name, sec_patched->name)) { +- log_debug("renaming section %s to %s \n", sec_patched->name, sec_orig->name); ++ log_debug("renaming section %s to %s\n", ++ sec_patched->name, sec_orig->name); + sec_patched->name = sec_orig->name; + sec_patched->name_source = DATA_SOURCE_REF; + } + } + +-static void correlate_section(struct section *sec_orig, struct section *sec_patched) ++static void correlate_section(struct section *sec_orig, ++ struct section *sec_patched) + { +- __correlate_section(sec_orig, sec_patched); +- +- if (is_rela_section(sec_orig)) { +- __correlate_section(sec_orig->base, sec_patched->base); ++ correlate_section_impl(sec_orig, sec_patched); + ++ if (is_rela_section(sec_orig)) { ++ correlate_section_impl(sec_orig->base, sec_patched->base); + /* handle symbol for base section now */ +- sec_orig = sec_orig->base; +- sec_patched = sec_patched->base; +- } else if (sec_orig->rela && sec_patched->rela) { +- __correlate_section(sec_orig->rela, sec_patched->rela); +- } +- +- if (sec_orig->secsym && sec_patched->secsym) { +- correlate_symbol(sec_orig->secsym, sec_patched->secsym); +- } +- +- if (sec_orig->sym) { +- correlate_symbol(sec_orig->sym, sec_patched->sym); +- } ++ sec_orig = sec_orig->base; ++ sec_patched = sec_patched->base; ++ } else if (sec_orig->rela && sec_patched->rela) { ++ correlate_section_impl(sec_orig->rela, sec_patched->rela); ++ } ++ if (sec_orig->secsym && sec_patched->secsym) { ++ correlate_symbol(sec_orig->secsym, sec_patched->secsym); ++ } ++ if (sec_orig->sym) { ++ correlate_symbol(sec_orig->sym, sec_patched->sym); ++ } + } + +-void upatch_correlate_sections(struct upatch_elf *uelf_source, struct upatch_elf *uelf_patched) ++void upatch_correlate_sections(struct upatch_elf *uelf_source, ++ struct upatch_elf *uelf_patched) + { +- struct section *sec_orig, *sec_patched; ++ struct section *sec_orig; ++ struct section *sec_patched; + +- list_for_each_entry(sec_orig, &uelf_source->sections, list) { ++ list_for_each_entry(sec_orig, &uelf_source->sections, list) { + /* already found */ +- if (sec_orig->twin) +- continue; +- +- list_for_each_entry(sec_patched, &uelf_patched->sections, list) { +- if (mangled_strcmp(sec_orig->name, sec_patched->name) || +- sec_patched->twin) +- continue; +- +- /* +- * TODO: Special static local variables should never be correlated and should always +- * be included if they are referenced by an included function. +- */ +- /* +- * Group sections must match exactly to be correlated. +- */ +- if (sec_orig->sh.sh_type == SHT_GROUP) { +- if (sec_orig->data->d_size != sec_patched->data->d_size) +- continue; +- if (memcmp(sec_orig->data->d_buf, sec_patched->data->d_buf, +- sec_orig->data->d_size)) +- continue; +- } +- +- correlate_section(sec_orig, sec_patched); +- break; +- } +- } ++ if (sec_orig->twin) { ++ continue; ++ } ++ list_for_each_entry(sec_patched, &uelf_patched->sections, list) { ++ if (mangled_strcmp(sec_orig->name, sec_patched->name) || ++ sec_patched->twin) { ++ continue; ++ } ++ /* ++ * TODO: Special static local variables should never be correlated ++ * and should always be included if they are referenced by ++ * an included function. ++ */ ++ /* ++ * Group sections must match exactly to be correlated. ++ */ ++ if (sec_orig->sh.sh_type == SHT_GROUP) { ++ if (sec_orig->data->d_size != sec_patched->data->d_size) { ++ continue; ++ } ++ if (memcmp(sec_orig->data->d_buf, sec_patched->data->d_buf, ++ sec_orig->data->d_size)) { ++ continue; ++ } ++ } ++ ++ correlate_section(sec_orig, sec_patched); ++ break; ++ } ++ } + } + + /* TODO: need handle .toc section */ +-static struct symbol *find_uncorrelated_rela(struct section *relasec, struct symbol *sym) ++static struct symbol *find_uncorrelated_rela(struct section *relasec, ++ struct symbol *sym) + { +- struct rela *rela; +- +- /* find the patched object's corresponding variable */ +- list_for_each_entry(rela, &relasec->relas, list) { +- struct symbol *patched_sym = rela->sym; +- if (patched_sym->twin) +- continue; ++ struct rela *rela; + +- if (sym->type != patched_sym->type || +- (sym->type == STT_OBJECT && +- sym->sym.st_size != patched_sym->sym.st_size)) +- continue; ++ /* find the patched object's corresponding variable */ ++ list_for_each_entry(rela, &relasec->relas, list) { ++ struct symbol *patched_sym = rela->sym; + +- if (mangled_strcmp(patched_sym->name, sym->name)) +- continue; ++ if (patched_sym->twin) { ++ continue; ++ } ++ if (sym->type != patched_sym->type || ++ ( ++ sym->type == STT_OBJECT && ++ sym->sym.st_size != patched_sym->sym.st_size ++ )) { ++ continue; ++ } ++ if (mangled_strcmp(patched_sym->name, sym->name)) { ++ continue; ++ } + +- log_debug("find uncorrelated rela symbol successful %s [%s] \n", ++ log_debug("find uncorrelated rela symbol successful %s [%s]\n", + patched_sym->name, section_function_name(relasec)); ++ return patched_sym; ++ } + +- return patched_sym; +- } +- +- return NULL; ++ return NULL; + } + + /* +@@ -193,27 +214,30 @@ static struct symbol *find_uncorrelated_rela(struct section *relasec, struct sym + * in the base object, find a corresponding usage of a similarly named symbol + * in the patched object. + */ +-static struct symbol *find_static_twin(struct section *relasec, struct symbol *sym) ++static struct symbol *find_static_twin(struct section *relasec, ++ struct symbol *sym) + { + /* TODO: handle .part symbol is neccessry */ ++ if (!relasec->twin) { ++ return NULL; ++ } + +- if (!relasec->twin) +- return NULL; +- +- return find_uncorrelated_rela(relasec->twin, sym); ++ return find_uncorrelated_rela(relasec->twin, sym); + } + +-static struct rela *find_static_twin_ref(struct section *relasec, struct symbol *sym) ++static struct rela *find_static_twin_ref(struct section *relasec, ++ struct symbol *sym) + { +- struct rela *rela; ++ struct rela *rela; + +- list_for_each_entry(rela, &relasec->relas, list) { +- if (rela->sym == sym->twin) +- return rela; +- } ++ list_for_each_entry(rela, &relasec->relas, list) { ++ if (rela->sym == sym->twin) { ++ return rela; ++ } ++ } + +- /* TODO: handle child func here */ +- return NULL; ++ /* TODO: handle child func here */ ++ return NULL; + } + + /* Check two things: +@@ -222,58 +246,65 @@ static struct rela *find_static_twin_ref(struct section *relasec, struct symbol + * a corresponding reference in the patched object + * (because a staticlocal can be referenced by more than one section) + */ +-static void check_static_variable_correlate(struct upatch_elf *uelf_source, struct upatch_elf *uelf_patched) ++static void check_static_variable_correlate(struct upatch_elf *uelf_source, ++ struct upatch_elf *uelf_patched) + { +- struct section *relasec; +- struct rela *rela; ++ struct section *relasec; ++ struct rela *rela; + struct symbol *sym; + +- list_for_each_entry(relasec, &uelf_source->sections, list) { +- if (!is_rela_section(relasec) || +- is_debug_section(relasec) || +- is_note_section(relasec)) +- continue; ++ list_for_each_entry(relasec, &uelf_source->sections, list) { ++ if (!is_rela_section(relasec) || ++ is_debug_section(relasec) || ++ is_note_section(relasec)) { ++ continue; ++ } + +- list_for_each_entry(rela, &relasec->relas, list) { ++ list_for_each_entry(rela, &relasec->relas, list) { + sym = rela->sym; +- if (!is_normal_static_local(sym)) +- continue; +- +- if (!sym->twin || !relasec->twin) +- DIFF_FATAL("reference to static local variable %s in %s was removed", ++ if (!is_normal_static_local(sym)) { ++ continue; ++ } ++ if (!sym->twin || !relasec->twin) { ++ ERROR("reference to static local variable %s in %s was removed", + sym->name, section_function_name(relasec)); +- +- if(!find_static_twin_ref(relasec->twin, sym)) +- DIFF_FATAL("static local %s has been correlated with %s, but patched %s is missing a reference to it", +- sym->name, sym->twin->name, section_function_name(relasec->twin)); ++ } ++ if (!find_static_twin_ref(relasec->twin, sym)) { ++ ERROR("static local %s has been correlated with %s, " ++ "but patched %s is missing a reference to it", ++ sym->name, sym->twin->name, ++ section_function_name(relasec->twin)); ++ } + } + } + +- /* +- * Now go through the patched object and look for any uncorrelated +- * static locals to see if we need to print any warnings about new +- * variables. +- */ +- +- list_for_each_entry(relasec, &uelf_patched->sections, list) { +- +- if (!is_rela_section(relasec) || +- is_debug_section(relasec) || +- is_note_section(relasec)) +- continue; +- +- list_for_each_entry(rela, &relasec->relas, list) { +- sym = rela->sym; +- if (!is_normal_static_local(sym)) +- continue; ++ /* ++ * Now go through the patched object and look for any uncorrelated ++ * static locals to see if we need to print any warnings about new ++ * variables. ++ */ ++ ++ list_for_each_entry(relasec, &uelf_patched->sections, list) { ++ if (!is_rela_section(relasec) || ++ is_debug_section(relasec) || ++ is_note_section(relasec)) { ++ continue; ++ } + +- if (sym->twin) +- continue; ++ list_for_each_entry(rela, &relasec->relas, list) { ++ sym = rela->sym; + +- log_normal("unable to correlate static local variable %s used by %s, assuming variable is new \n", +- sym->name, section_function_name(relasec)); +- } +- } ++ if (!is_normal_static_local(sym)) { ++ continue; ++ } ++ if (sym->twin) { ++ continue; ++ } ++ log_normal("unable to correlate static local variable %s used by %s" ++ ", assuming variable is new\n", ++ sym->name, section_function_name(relasec)); ++ } ++ } + } + + static void uncorrelate_symbol(struct symbol *sym) +@@ -312,88 +343,104 @@ static void uncorrelate_section(struct section *sec) + * they can occasionally be referenced by data sections as + * well. + */ +-void upatch_correlate_static_local_variables(struct upatch_elf *uelf_source, struct upatch_elf *uelf_patched) ++void upatch_correlate_static_local_variables(struct upatch_elf *uelf_source, ++ struct upatch_elf *uelf_patched) + { +- struct symbol *sym, *patched_sym; +- struct section *relasec; +- struct rela *rela; +- int bundled, patched_bundled; +- +- /* +- * undo the correlations for all static locals. Two static locals can have the same numbered suffix in the orig +- * and patchedobjects by coincidence. +- */ +- list_for_each_entry(sym, &uelf_source->symbols, list) { +- if (!is_normal_static_local(sym)) +- continue; ++ struct symbol *sym; ++ struct symbol *patched_sym; + +- log_debug("find normal symbol %s \n", sym->name); +- if (sym->twin) +- uncorrelate_symbol(sym); ++ struct section *relasec; ++ struct rela *rela; + +- bundled = (sym == sym->sec->sym) ? 1 : 0; +- if (bundled && sym->sec->twin) { +- log_debug("find bundled static symbol %s \n", sym->name); ++ int bundled; ++ int patched_bundled; + +- uncorrelate_section(sym->sec); ++ /* ++ * undo the correlations for all static locals. ++ * Two static locals can have the same numbered suffix in the orig ++ * and patchedobjects by coincidence. ++ */ ++ list_for_each_entry(sym, &uelf_source->symbols, list) { ++ if (!is_normal_static_local(sym)) { ++ continue; ++ } + +- if (sym->sec->secsym) +- uncorrelate_symbol(sym->sec->secsym); ++ log_debug("find normal symbol %s\n", sym->name); ++ if (sym->twin) { ++ uncorrelate_symbol(sym); ++ } + +- if (sym->sec->rela) +- uncorrelate_section(sym->sec->rela); // uncorrelate relocation section which is not equal to reference +- } +- } ++ bundled = (sym == sym->sec->sym) ? 1 : 0; ++ if (bundled && sym->sec->twin) { ++ log_debug("find bundled static symbol %s\n", sym->name); ++ ++ uncorrelate_section(sym->sec); ++ if (sym->sec->secsym) { ++ uncorrelate_symbol(sym->sec->secsym); ++ } ++ if (sym->sec->rela) { ++ // uncorrelate relocation section which not equals to reference ++ uncorrelate_section(sym->sec->rela); ++ } ++ } ++ } + + /* +- * 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(relasec, &uelf_source->sections, list) { +- ++ * 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(relasec, &uelf_source->sections, list) { + /* handle .rela.toc sectoins */ +- if (!is_rela_section(relasec) || +- is_debug_section(relasec) || +- is_note_section(relasec)) +- continue; ++ if (!is_rela_section(relasec) || ++ is_debug_section(relasec) || ++ is_note_section(relasec)) { ++ continue; ++ } + + /* check all relocation symbols */ +- list_for_each_entry(rela, &relasec->relas, list) { ++ list_for_each_entry(rela, &relasec->relas, list) { + sym = rela->sym; + +- if (!is_normal_static_local(sym)) +- continue; +- +- if (sym->twin) +- continue; +- +- bundled = (sym == sym->sec->sym) ? 1 : 0; +- if (bundled && sym->sec == relasec->base) { +- /* +- * TODO: A rare case where a static local data structure references itself. +- * There's no reliable way to correlate this. Hopefully +- * to the symbol somewhere that can be used. +- */ +- log_debug("can't correlate static local %s's reference to itself\n", sym->name); +- continue; +- } +- +- patched_sym = find_static_twin(relasec, sym); +- if (!patched_sym) +- DIFF_FATAL("reference to static local variable %s in %s was removed", ++ if (!is_normal_static_local(sym)) { ++ continue; ++ } ++ if (sym->twin) { ++ continue; ++ } ++ ++ bundled = (sym == sym->sec->sym) ? 1 : 0; ++ if (bundled && sym->sec == relasec->base) { ++ /* ++ * TODO: ++ * A rare case where a static local data structure references ++ * itself. ++ * There's no reliable way to correlate this. ++ * Hopefully to the symbol somewhere that can be used. ++ */ ++ log_debug("can't correlate static local %s's ref to itself\n", ++ sym->name); ++ continue; ++ } ++ ++ patched_sym = find_static_twin(relasec, sym); ++ if (!patched_sym) { ++ ERROR("reference to static local variable %s in %s was removed", + sym->name, section_function_name(relasec)); +- +- patched_bundled = (patched_sym == patched_sym->sec->sym) ? 1 : 0; +- if (bundled != patched_bundled) +- ERROR("bundle mismatch for symbol %s", sym->name); +- if (!bundled && sym->sec->twin != patched_sym->sec) +- ERROR("sections %s and %s aren't correlated for symbol %s", +- sym->sec->name, patched_sym->sec->name, sym->name); +- +- correlate_symbol(sym, patched_sym); +- +- if (bundled) +- correlate_section(sym->sec, patched_sym->sec); ++ } ++ ++ patched_bundled = (patched_sym == patched_sym->sec->sym) ? 1 : 0; ++ if (bundled != patched_bundled) { ++ ERROR("bundle mismatch for symbol %s", sym->name); ++ } ++ if (!bundled && sym->sec->twin != patched_sym->sec) { ++ ERROR("sections %s and %s aren't correlated for symbol %s", ++ sym->sec->name, patched_sym->sec->name, sym->name); ++ } ++ ++ correlate_symbol(sym, patched_sym); ++ if (bundled) { ++ correlate_section(sym->sec, patched_sym->sec); ++ } + } + } + +diff --git a/upatch-diff/elf-correlate.h b/upatch-diff/elf-correlate.h +index 2122030..820d07a 100644 +--- a/upatch-diff/elf-correlate.h ++++ b/upatch-diff/elf-correlate.h +@@ -39,4 +39,4 @@ static inline void upatch_correlate_elf(struct upatch_elf *uelf_source, struct u + + void upatch_correlate_static_local_variables(struct upatch_elf *, struct upatch_elf *); + +-#endif +\ No newline at end of file ++#endif +diff --git a/upatch-diff/elf-create.c b/upatch-diff/elf-create.c +index bd7edf0..20d1994 100644 +--- a/upatch-diff/elf-create.c ++++ b/upatch-diff/elf-create.c +@@ -40,7 +40,8 @@ static struct section *create_section_pair(struct upatch_elf *uelf, char *name, + unsigned int entsize, unsigned int nr) + { + char *relaname; +- struct section *sec, *relasec; ++ struct section *sec; ++ struct section *relasec; + size_t size = strlen(name) + strlen(".rela") + 1; + + relaname = calloc(1, size); +@@ -136,14 +137,21 @@ void upatch_create_strings_elements(struct upatch_elf *uelf) + } + + /* create upatch func info section */ +-void upatch_create_patches_sections(struct upatch_elf *uelf, struct running_elf *relf) ++void upatch_create_patches_sections(struct upatch_elf *uelf, ++ struct running_elf *relf) + { +- struct symbol *sym, *strsym; +- struct section *sec, *relasec; ++ struct symbol *sym; ++ struct symbol *strsym; ++ ++ struct section *sec; ++ struct section *relasec; ++ + struct upatch_patch_func *funcs; + struct rela *rela; + struct lookup_result symbol; +- unsigned int nr = 0, index = 0; ++ ++ unsigned int nr = 0; ++ unsigned int index = 0; + + /* find changed func */ + list_for_each_entry(sym, &uelf->symbols, list) { +@@ -167,15 +175,12 @@ void upatch_create_patches_sections(struct upatch_elf *uelf, struct running_elf + if (sym->type != STT_FUNC || sym->status != CHANGED || sym->parent) { + continue; + } +- + if (!lookup_relf(relf, sym, &symbol)) { + ERROR("Cannot find symbol '%s' in %s", sym->name, g_relf_name); + } +- + if (sym->bind == STB_LOCAL && symbol.global) { + ERROR("Cannot find local symbol '%s' in symbol table.", sym->name); + } +- + log_debug("lookup for %s: symbol name %s sympos=%lu size=%lu.\n", + sym->name, symbol.symbol->name, symbol.sympos, symbol.symbol->size); + +@@ -185,7 +190,8 @@ void upatch_create_patches_sections(struct upatch_elf *uelf, struct running_elf + funcs[index].new_size = sym->sym.st_size; + funcs[index].sympos = symbol.sympos; + +- log_debug("change func %s from 0x%lx.\n", sym->name, funcs[index].old_addr); ++ log_debug("change func %s from 0x%lx.\n", ++ sym->name, funcs[index].old_addr); + + /* Add a rela than will handle funcs[index].new_addr */ + ALLOC_LINK(rela, &relasec->relas); +@@ -205,18 +211,20 @@ void upatch_create_patches_sections(struct upatch_elf *uelf, struct running_elf + index++; + } + +- if (index != nr) +- ERROR("sanity check failed in funcs sections. \n"); ++ if (index != nr) { ++ ERROR("sanity check failed in funcs sections.\n"); ++ } + } + +-static bool need_dynrela(struct running_elf *relf, +- struct section *relasec, struct rela *rela) ++static bool need_dynrela(struct running_elf *relf, struct section *relasec, ++ struct rela *rela) + { + struct lookup_result symbol; + + if (is_debug_section(relasec) || +- is_note_section(relasec)) ++ is_note_section(relasec)) { + return false; ++ } + + if (!lookup_relf(relf, rela->sym, &symbol)) { + /* relocation is based on new symbol. */ +@@ -224,8 +232,9 @@ static bool need_dynrela(struct running_elf *relf, + } + + if (rela->sym->bind == STB_LOCAL) { +- if (symbol.global) +- ERROR("No releated local symbol found. \n"); ++ if (symbol.global) { ++ ERROR("No releated local symbol found.\n"); ++ } + return true; + } + +@@ -239,7 +248,8 @@ static bool need_dynrela(struct running_elf *relf, + * 1. refer to old symbols + * + */ +-void upatch_create_intermediate_sections(struct upatch_elf *uelf, struct running_elf *relf) ++void upatch_create_intermediate_sections(struct upatch_elf *uelf, ++ struct running_elf *relf) + { + struct rela *rela, *rela_safe; + struct section *relasec, *usym_sec, *urela_sec; +@@ -249,24 +259,27 @@ void upatch_create_intermediate_sections(struct upatch_elf *uelf, struct running + unsigned int nr = 0, index = 0; + + list_for_each_entry(relasec, &uelf->sections, list) { +- if (!is_rela_section(relasec)) ++ if (!is_rela_section(relasec)) { + continue; ++ } + /* no need to handle upatch meta section. */ +- if (!strcmp(relasec->name, ".rela.upatch.funcs")) ++ if (!strcmp(relasec->name, ".rela.upatch.funcs")) { + continue; +- ++ } + list_for_each_entry(rela, &relasec->relas, list) { + nr++; +- if (need_dynrela(relf, relasec, rela)){ ++ if (need_dynrela(relf, relasec, rela)) { + rela->need_dynrela = 1; + } + } + } + +- urela_sec = create_section_pair(uelf, ".upatch.relocations", sizeof(*urelas), nr); ++ urela_sec = create_section_pair(uelf, ".upatch.relocations", ++ sizeof(*urelas), nr); + urelas = urela_sec->data->d_buf; + +- usym_sec = create_section_pair(uelf, ".upatch.symbols", sizeof(*usyms), nr); ++ usym_sec = create_section_pair(uelf, ".upatch.symbols", ++ sizeof(*usyms), nr); + usyms = usym_sec->data->d_buf; + + ALLOC_LINK(usym_sec_sym, &uelf->symbols); +@@ -277,17 +290,19 @@ void upatch_create_intermediate_sections(struct upatch_elf *uelf, struct running + usym_sec_sym->name = ".upatch.symbols"; + + strsym = find_symbol_by_name(&uelf->symbols, ".upatch.strings"); +- if (!strsym) +- ERROR("can't find .upatch.strings symbol. \n"); ++ if (!strsym) { ++ ERROR("can't find .upatch.strings symbol.\n"); ++ } + + list_for_each_entry(relasec, &uelf->sections, list) { +- if (!is_rela_section(relasec)) ++ if (!is_rela_section(relasec)) { + continue; ++ } + if (!strcmp(relasec->name, ".rela.upatch.funcs") || + !strcmp(relasec->name, ".rela.upatch.relocations") || +- !strcmp(relasec->name, ".rela.upatch.symbols")) ++ !strcmp(relasec->name, ".rela.upatch.symbols")) { + continue; +- ++ } + list_for_each_entry_safe(rela, rela_safe, &relasec->relas, list) { + if (!rela->need_dynrela) { + rela->sym->strip = SYMBOL_USED; +@@ -314,12 +329,14 @@ void upatch_build_strings_section_data(struct upatch_elf *uelf) + char *strtab; + + sec = find_section_by_name(&uelf->sections, ".upatch.strings"); +- if (!sec) ++ if (!sec) { + ERROR("can't find strings section."); ++ } + + size = 0; +- list_for_each_entry(string, &uelf->strings, list) ++ list_for_each_entry(string, &uelf->strings, list) { + size += strlen(string->name) + 1; ++ } + + /* allocate section resources */ + strtab = calloc(1, size); +@@ -345,9 +362,9 @@ static void migrate_symbols(struct list_head *src, + struct symbol *sym, *sym_safe; + + list_for_each_entry_safe(sym, sym_safe, src, list) { +- if (select && !select(sym)) ++ if (select && !select(sym)) { + continue; +- ++ } + list_del(&sym->list); + list_add_tail(&sym->list, dst); + } +@@ -402,9 +419,9 @@ void upatch_reindex_elements(struct upatch_elf *uelf) + list_for_each_entry(sym, &uelf->symbols, list) { + sym->index = index; + index++; +- if (sym->sec) ++ if (sym->sec) { + sym->sym.st_shndx = (unsigned short)sym->sec->index; +- else if (sym->sym.st_shndx != SHN_ABS) { ++ } else if (sym->sym.st_shndx != SHN_ABS) { + sym->sym.st_shndx = SHN_UNDEF; + } + } +@@ -415,10 +432,13 @@ static void rebuild_rela_section_data(struct section *sec) + struct rela *rela; + GElf_Rela *relas; + size_t size; +- unsigned int nr = 0, index = 0; + +- list_for_each_entry(rela, &sec->relas, list) ++ unsigned int nr = 0; ++ unsigned int index = 0; ++ ++ list_for_each_entry(rela, &sec->relas, list) { + nr++; ++ } + + size = nr * sizeof(*relas); + relas = calloc(1, size); +@@ -438,22 +458,26 @@ static void rebuild_rela_section_data(struct section *sec) + index++; + } + +- if (index != nr) ++ if (index != nr) { + ERROR("size mismatch in rebuild rela section."); ++ } + } + + /* update index for relocations */ + void upatch_rebuild_relocations(struct upatch_elf *uelf) + { +- struct section *relasec, *symtab; ++ struct section *relasec; ++ struct section *symtab; + + symtab = find_section_by_name(&uelf->sections, ".symtab"); +- if (!symtab) +- ERROR("missing .symtab section in rebuild relocations. \n"); ++ if (!symtab) { ++ ERROR("missing .symtab section in rebuild relocations.\n"); ++ } + + list_for_each_entry(relasec, &uelf->sections, list) { +- if (!is_rela_section(relasec)) ++ if (!is_rela_section(relasec)) { + continue; ++ } + relasec->sh.sh_link = (Elf64_Word)symtab->index; + relasec->sh.sh_info = (Elf64_Word)relasec->base->index; + rebuild_rela_section_data(relasec); +@@ -471,18 +495,23 @@ static void print_strtab(char *buf, size_t size) + size_t i; + + for (i = 0; i < size; i++) { +- if (buf[i] == 0) ++ if (buf[i] == 0) { + log_debug("\\0"); +- else ++ } else { + log_debug("%c", buf[i]); ++ } + } + } + + void upatch_create_shstrtab(struct upatch_elf *uelf) + { +- size_t size, offset, len; +- struct section *shstrtab, *sec; ++ struct section *shstrtab; ++ struct section *sec; ++ + char *buf; ++ size_t size; ++ size_t offset; ++ size_t len; + + shstrtab = find_section_by_name(&uelf->sections, ".shstrtab"); + if (!shstrtab) { +@@ -491,8 +520,9 @@ void upatch_create_shstrtab(struct upatch_elf *uelf) + + /* determine size of string table */ + size = 1; +- list_for_each_entry(sec, &uelf->sections, list) ++ list_for_each_entry(sec, &uelf->sections, list) { + size += strlen(sec->name) + 1; ++ } + + buf = calloc(1, size); + if (!buf) { +@@ -520,13 +550,16 @@ void upatch_create_shstrtab(struct upatch_elf *uelf) + print_strtab(buf, size); + log_debug("\n"); + +- list_for_each_entry(sec, &uelf->sections, list) ++ list_for_each_entry(sec, &uelf->sections, list) { + log_debug("%s @ shstrtab offset %d\n", sec->name, sec->sh.sh_name); ++ } + } + + void upatch_create_strtab(struct upatch_elf *uelf) + { +- size_t size = 0, offset = 0, len = 0; ++ size_t size = 0; ++ size_t offset = 0; ++ size_t len = 0; + + struct section *strtab = find_section_by_name(&uelf->sections, ".strtab"); + if (!strtab) { +@@ -535,8 +568,9 @@ void upatch_create_strtab(struct upatch_elf *uelf) + + struct symbol *sym = NULL; + list_for_each_entry(sym, &uelf->symbols, list) { +- if (sym->type == STT_SECTION) ++ if (sym->type == STT_SECTION) { + continue; ++ } + size += strlen(sym->name) + 1; + } + +@@ -569,8 +603,9 @@ void upatch_create_strtab(struct upatch_elf *uelf) + print_strtab(buf, size); + log_debug("\n"); + +- list_for_each_entry(sym, &uelf->symbols, list) ++ list_for_each_entry(sym, &uelf->symbols, list) { + log_debug("%s @ strtab offset %d\n", sym->name, sym->sym.st_name); ++ } + } + + void upatch_create_symtab(struct upatch_elf *uelf) +@@ -578,17 +613,22 @@ void upatch_create_symtab(struct upatch_elf *uelf) + struct section *symtab; + struct section *strtab; + struct symbol *sym; +- size_t size; ++ ++ unsigned int nr = 0; ++ unsigned int nr_local = 0; ++ + char *buf; +- unsigned int nr = 0, nr_local = 0; ++ size_t size; + unsigned long offset = 0; + + symtab = find_section_by_name(&uelf->sections, ".symtab"); +- if (!symtab) ++ if (!symtab) { + ERROR("find_section_by_name failed."); ++ } + +- list_for_each_entry(sym, &uelf->symbols, list) ++ list_for_each_entry(sym, &uelf->symbols, list) { + nr++; ++ } + + size = nr * symtab->sh.sh_entsize; + buf = calloc(1, size); +@@ -600,9 +640,9 @@ void upatch_create_symtab(struct upatch_elf *uelf) + list_for_each_entry(sym, &uelf->symbols, list) { + memcpy(buf + offset, &sym->sym, symtab->sh.sh_entsize); + offset += symtab->sh.sh_entsize; +- +- if (is_local_sym(sym)) ++ if (is_local_sym(sym)) { + nr_local++; ++ } + } + + symtab->data->d_buf = buf; +@@ -611,38 +651,52 @@ void upatch_create_symtab(struct upatch_elf *uelf) + + /* update symtab section header */ + strtab = find_section_by_name(&uelf->sections, ".strtab"); +- if (!strtab) ++ if (!strtab) { + ERROR("missing .strtab section in create symtab."); ++ } + + symtab->sh.sh_link = (Elf64_Word)strtab->index; + symtab->sh.sh_info = nr_local; + } + +-void upatch_write_output_elf(struct upatch_elf *uelf, Elf *elf, char *outfile, mode_t mode) ++void upatch_write_output_elf(struct upatch_elf *uelf, Elf *elf, ++ char *outfile, mode_t mode) + { + int fd; ++ + Elf *elfout; ++ + Elf_Scn *scn; + Elf_Data *data; +- GElf_Ehdr eh, ehout; ++ ++ GElf_Ehdr eh; ++ GElf_Ehdr ehout; ++ + GElf_Shdr sh; +- struct section *sec, *shstrtab; ++ ++ struct section *sec; ++ struct section *shstrtab; + + fd = creat(outfile, mode); +- if (fd == -1) ++ if (fd == -1) { + ERROR("creat failed."); ++ } + + elfout = elf_begin(fd, ELF_C_WRITE, NULL); +- if (!elfout) ++ if (!elfout) { + ERROR("elf_begin failed."); ++ } + + /* alloc ELF header */ +- if (!gelf_newehdr(elfout, gelf_getclass(elf))) ++ if (!gelf_newehdr(elfout, gelf_getclass(elf))) { + ERROR("gelf_newehdr failed."); +- if (!gelf_getehdr(elfout, &ehout)) ++ } ++ if (!gelf_getehdr(elfout, &ehout)) { + ERROR("gelf_getehdr elfout failed."); +- if (!gelf_getehdr(elf, &eh)) ++ } ++ if (!gelf_getehdr(elf, &eh)) { + ERROR("gelf_getehdr elf failed."); ++ } + + memset(&ehout, 0, sizeof(ehout)); + ehout.e_ident[EI_DATA] = eh.e_ident[EI_DATA]; +@@ -651,43 +705,51 @@ void upatch_write_output_elf(struct upatch_elf *uelf, Elf *elf, char *outfile, m + ehout.e_version = EV_CURRENT; + + shstrtab = find_section_by_name(&uelf->sections, ".shstrtab"); +- if (!shstrtab) ++ if (!shstrtab) { + ERROR("missing .shstrtab sections in write output elf"); ++ } + + ehout.e_shstrndx = (unsigned short)shstrtab->index; + + /* add changed sections */ + list_for_each_entry(sec, &uelf->sections, list) { + scn = elf_newscn(elfout); +- if (!scn) ++ if (!scn) { + ERROR("elf_newscn failed."); ++ } + + data = elf_newdata(scn); +- if (!data) ++ if (!data) { + ERROR("elf_newdata failed."); ++ } + +- if (!elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY)) ++ if (!elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY)) { + ERROR("elf_flagdata failed."); ++ } + + data->d_type = sec->data->d_type; + data->d_buf = sec->data->d_buf; + data->d_size = sec->data->d_size; + +- if (!gelf_getshdr(scn, &sh)) ++ if (!gelf_getshdr(scn, &sh)) { + ERROR("gelf_getshdr in adding changed sections"); ++ } + + sh = sec->sh; + +- if (!gelf_update_shdr(scn, &sh)) ++ if (!gelf_update_shdr(scn, &sh)) { + ERROR("gelf_update_shdr failed."); ++ } + } + +- if (!gelf_update_ehdr(elfout, &ehout)) ++ if (!gelf_update_ehdr(elfout, &ehout)) { + ERROR("gelf_update_ehdr failed."); ++ } + +- if (elf_update(elfout, ELF_C_WRITE) < 0) ++ if (elf_update(elfout, ELF_C_WRITE) < 0) { + ERROR("elf_update failed."); ++ } + + elf_end(elfout); + close(fd); +-} +\ No newline at end of file ++} +diff --git a/upatch-diff/elf-create.h b/upatch-diff/elf-create.h +index ce7f263..b9efbb3 100644 +--- a/upatch-diff/elf-create.h ++++ b/upatch-diff/elf-create.h +@@ -55,4 +55,4 @@ void upatch_create_symtab(struct upatch_elf *); + + void upatch_write_output_elf(struct upatch_elf *, Elf *, char *, mode_t); + +-#endif /* __UPATCH_CREATE_H_ */ +\ No newline at end of file ++#endif /* __UPATCH_CREATE_H_ */ +diff --git a/upatch-diff/elf-debug.c b/upatch-diff/elf-debug.c +index 0490f86..677b8bc 100644 +--- a/upatch-diff/elf-debug.c ++++ b/upatch-diff/elf-debug.c +@@ -36,12 +36,15 @@ void upatch_print_changes(struct upatch_elf *uelf) + struct symbol *sym; + + list_for_each_entry(sym, &uelf->symbols, list) { +- if (!sym->include || !sym->sec || sym->type != STT_FUNC || sym->parent) ++ if (!sym->include || !sym->sec || ++ sym->type != STT_FUNC || sym->parent) { + continue; +- if (sym->status == NEW) ++ } ++ if (sym->status == NEW) { + log_normal("New function: %s\n", sym->name); +- else if (sym->status == CHANGED) ++ } else if (sym->status == CHANGED) { + log_normal("Changed function: %s\n", sym->name); ++ } + } + } + +@@ -53,26 +56,31 @@ void upatch_dump_kelf(struct upatch_elf *uelf) + + log_debug("\n=== Sections ===\n"); + list_for_each_entry(sec, &uelf->sections, list) { +- log_debug("%02d %s (%s)", sec->index, sec->name, status_str(sec->status)); ++ log_debug("%02d %s (%s)", ++ sec->index, sec->name, status_str(sec->status)); + if (is_rela_section(sec)) { + log_debug(", base-> %s\n", sec->base->name); +- if (is_debug_section(sec) || is_note_section(sec)) ++ if (is_debug_section(sec) || is_note_section(sec)) { + goto next; ++ } + log_debug("rela section expansion\n"); + list_for_each_entry(rela, &sec->relas, list) { +- log_debug("sym %d, offset %ld, type %d, %s %s %ld \n", ++ log_debug("sym %d, offset %ld, type %d, %s %s %ld\n", + rela->sym->index, rela->offset, + rela->type, rela->sym->name, + (rela->addend < 0) ? "-" : "+", + labs(rela->addend)); + } + } else { +- if (sec->sym) ++ if (sec->sym) { + log_debug(", sym-> %s", sec->sym->name); +- if (sec->secsym) ++ } ++ if (sec->secsym) { + log_debug(", secsym-> %s", sec->secsym->name); +- if (sec->rela) ++ } ++ if (sec->rela) { + log_debug(", rela-> %s", sec->rela->name); ++ } + } + next: + log_debug("\n"); +@@ -83,14 +91,16 @@ next: + log_debug("sym %02d, type %d, bind %d, ndx %02d, name %s (%s)", + sym->index, sym->type, sym->bind, sym->sym.st_shndx, + sym->name, status_str(sym->status)); +- if (sym->sec && (sym->type == STT_FUNC || sym->type == STT_OBJECT)) ++ if (sym->sec && (sym->type == STT_FUNC || sym->type == STT_OBJECT)) { + log_debug(" -> %s", sym->sec->name); ++ } + log_debug("\n"); + } + } + + /* debuginfo releated */ +-static inline bool skip_bytes(unsigned char **iter, unsigned char *end, unsigned int len) ++static inline bool skip_bytes(unsigned char **iter, unsigned char *end, ++ unsigned int len) + { + if ((unsigned int)(end - *iter) < len) { + *iter = end; +@@ -104,26 +114,33 @@ void upatch_rebuild_eh_frame(struct section *sec) + { + void *eh_frame; + unsigned long long frame_size; ++ + struct rela *rela; +- unsigned char *data, *data_end; +- unsigned int hdr_length, hdr_id; ++ unsigned char *data; ++ unsigned char *data_end; ++ ++ unsigned int hdr_length; ++ unsigned int hdr_id; ++ + unsigned long current_offset; + unsigned int count = 0; + + /* sanity check */ +- if (!is_eh_frame(sec) || is_rela_section(sec) || !sec->rela) ++ if (!is_eh_frame(sec) || is_rela_section(sec) || !sec->rela) { + return; ++ } + +- list_for_each_entry(rela, &sec->rela->relas, list) +- count ++; ++ list_for_each_entry(rela, &sec->rela->relas, list) { ++ count++; ++ } + + /* currently, only delete is possible */ + if (sec->rela->sh.sh_entsize != 0 && +- count == sec->rela->sh.sh_size / sec->rela->sh.sh_entsize) ++ count == sec->rela->sh.sh_size / sec->rela->sh.sh_entsize) { + return; ++ } + +- log_debug("sync modification for eh_frame \n"); +- ++ log_debug("sync modification for eh_frame\n"); + data = sec->data->d_buf; + data_end = sec->data->d_buf + sec->data->d_size; + +@@ -131,7 +148,7 @@ void upatch_rebuild_eh_frame(struct section *sec) + frame_size = 0; + eh_frame = calloc(1, sec->data->d_size); + if (!eh_frame) { +- ERROR("malloc eh_frame failed \n"); ++ ERROR("malloc eh_frame failed\n"); + } + + /* 8 is the offset of PC begin */ +@@ -139,27 +156,30 @@ void upatch_rebuild_eh_frame(struct section *sec) + list_for_each_entry(rela, &sec->rela->relas, list) { + unsigned long offset = rela->offset; + bool found_rela = false; +- log_debug("handle relocaton offset at 0x%lx \n", offset); ++ log_debug("handle relocaton offset at 0x%lx\n", offset); + while (data != data_end) { + void *__src = data; + +- log_debug("current handle offset is 0x%lx \n", current_offset); ++ log_debug("current handle offset is 0x%lx\n", current_offset); + + REQUIRE(skip_bytes(&data, data_end, 4), "no length to be read"); + hdr_length = *(unsigned int *)(data - 4); + +- REQUIRE(hdr_length != 0xffffffff, "64 bit .eh_frame is not supported"); ++ REQUIRE(hdr_length != 0xffffffff, ++ "64 bit .eh_frame is not supported"); + /* if it is 0, we reach the end. */ +- if (hdr_length == 0) ++ if (hdr_length == 0) { + break; ++ } + + REQUIRE(skip_bytes(&data, data_end, 4), "no length to be read"); + hdr_id = *(unsigned int *)(data - 4); + +- REQUIRE(skip_bytes(&data, data_end, hdr_length - 4), "no length to be read"); +- +- if (current_offset == offset) ++ REQUIRE(skip_bytes(&data, data_end, hdr_length - 4), ++ "no length to be read"); ++ if (current_offset == offset) { + found_rela = true; ++ } + + /* CIE or relocation releated FDE */ + if (hdr_id == 0 || found_rela) { +@@ -173,14 +193,14 @@ void upatch_rebuild_eh_frame(struct section *sec) + + frame_size += (hdr_length + 4); + } else { +- log_debug("remove FDE at 0x%lx \n", current_offset); ++ log_debug("remove FDE at 0x%lx\n", current_offset); + } +- + /* hdr_length(value) + hdr_length(body) */ + current_offset += (4 + hdr_length); + +- if (found_rela) ++ if (found_rela) { + break; ++ } + } + } + +diff --git a/upatch-diff/elf-insn.c b/upatch-diff/elf-insn.c +index 11380d0..8fcfc39 100644 +--- a/upatch-diff/elf-insn.c ++++ b/upatch-diff/elf-insn.c +@@ -30,24 +30,30 @@ + + void rela_insn(const struct section *sec, const struct rela *rela, struct insn *insn) + { +- unsigned long insn_addr, start, end, rela_addr; ++ unsigned long start; ++ unsigned long end; ++ ++ unsigned long rela_addr; ++ unsigned long insn_addr; + + start = (unsigned long)sec->data->d_buf; + end = start + sec->sh.sh_size; + +- if (end <= start) ++ 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) ++ 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) ++ } ++ if (rela_addr >= insn_addr && rela_addr < insn_addr + insn->length) { + return; ++ } + } + + ERROR("can't find instruction for rela at %s+0x%lx", +@@ -56,33 +62,33 @@ void rela_insn(const struct section *sec, const struct rela *rela, struct insn * + + long rela_target_offset(struct upatch_elf *uelf, struct section *relasec, struct rela *rela) + { +- long add_off; + struct section *sec = relasec->base; ++ long add_off; + +- switch(uelf->arch) { +- case AARCH64: +- add_off = 0; +- break; +- case X86_64: +- if (!is_text_section(sec) || +- rela->type == R_X86_64_64 || +- rela->type == R_X86_64_32 || +- rela->type == R_X86_64_32S) ++ switch (uelf->arch) { ++ case AARCH64: + 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 = (long)insn.next_byte - +- (long)sec->data->d_buf - +- (long)rela->offset; +- } else { +- ERROR("unable to handle rela type %d \n", rela->type); +- } +- break; +- default: +- ERROR("unsupported arch \n"); +- break; ++ break; ++ case X86_64: ++ if (!is_text_section(sec) || ++ rela->type == R_X86_64_64 || ++ rela->type == R_X86_64_32 || ++ rela->type == R_X86_64_32S) { ++ 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 = (long)insn.next_byte - ++ (long)sec->data->d_buf - ++ (long)rela->offset; ++ } else { ++ ERROR("unable to handle rela type %d\n", rela->type); ++ } ++ break; ++ default: ++ ERROR("unsupported arch\n"); ++ break; + } + + return rela->addend + add_off; +@@ -92,15 +98,15 @@ unsigned int insn_length(struct upatch_elf *uelf, void *addr) + { + struct insn decoded_insn; + +- switch(uelf->arch) { +- case AARCH64: +- return ARM64_INSTR_LEN; +- case X86_64: +- insn_init(&decoded_insn, addr, 1); +- insn_get_length(&decoded_insn); +- return decoded_insn.length; +- default: +- ERROR("unsupported arch"); ++ switch (uelf->arch) { ++ case AARCH64: ++ return ARM64_INSTR_LEN; ++ case X86_64: ++ insn_init(&decoded_insn, addr, 1); ++ insn_get_length(&decoded_insn); ++ return decoded_insn.length; ++ default: ++ ERROR("unsupported arch"); + } + + return 0; +@@ -111,23 +117,23 @@ bool insn_is_load_immediate(struct upatch_elf *uelf, void *addr) + { + unsigned char *insn = addr; + +- switch(uelf->arch) { +- case X86_64: +- /* arg2: mov $imm, %esi */ +- if (insn[0] == 0xbe) +- return true; +- +- /* arg3: mov $imm, %edx */ +- if (insn[0] == 0xba) +- return true; +- +- /* 0x41 is the prefix extend - REX.B */ +- if (insn[0] == 0x41 && insn[1] == 0xb8) +- return true; +- +- break; +- default: +- ERROR("unsupported arch"); ++ switch (uelf->arch) { ++ case X86_64: ++ /* arg2: mov $imm, %esi */ ++ if (insn[0] == 0xbe) { ++ return true; ++ } ++ /* arg3: mov $imm, %edx */ ++ if (insn[0] == 0xba) { ++ return true; ++ } ++ /* 0x41 is the prefix extend - REX.B */ ++ if (insn[0] == 0x41 && insn[1] == 0xb8) { ++ return true; ++ } ++ break; ++ default: ++ ERROR("unsupported arch"); + } + return false; +-} +\ No newline at end of file ++} +diff --git a/upatch-diff/elf-resolve.c b/upatch-diff/elf-resolve.c +index 0eb55cc..67ab069 100755 +--- a/upatch-diff/elf-resolve.c ++++ b/upatch-diff/elf-resolve.c +@@ -34,11 +34,12 @@ void upatch_partly_resolve(struct upatch_elf *uelf, struct running_elf *relf) + + list_for_each_entry(sym, &uelf->symbols, list) { + if (sym->sym.st_other & SYM_OTHER) { +- if (!lookup_relf(relf, sym, &symbol)) ++ if (!lookup_relf(relf, sym, &symbol)) { + continue; ++ } + /* keep it undefined for link purpose */ + sym->sym.st_value = symbol.symbol->addr; + sym->sym.st_size = symbol.symbol->size; + } + } +-} +\ No newline at end of file ++} +diff --git a/upatch-diff/elf-resolve.h b/upatch-diff/elf-resolve.h +index 9eccdfd..05b4b35 100755 +--- a/upatch-diff/elf-resolve.h ++++ b/upatch-diff/elf-resolve.h +@@ -25,4 +25,4 @@ + + void upatch_partly_resolve(struct upatch_elf *, struct running_elf *); + +-#endif /* __UPATCH_RESOLVE_H_ */ +\ No newline at end of file ++#endif /* __UPATCH_RESOLVE_H_ */ +diff --git a/upatch-diff/insn/asm/inat-tables.h b/upatch-diff/insn/asm/inat-tables.h +index 8419e2e..331eb86 100644 +--- a/upatch-diff/insn/asm/inat-tables.h ++++ b/upatch-diff/insn/asm/inat-tables.h +@@ -11,922 +11,922 @@ + + /* Table: one byte opcode */ + const insn_attr_t inat_primary_table[INAT_OPCODE_TABLE_SIZE] = { +- [0x00] = INAT_MODRM, +- [0x01] = INAT_MODRM, +- [0x02] = INAT_MODRM, +- [0x03] = INAT_MODRM, +- [0x04] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x05] = INAT_MAKE_IMM(INAT_IMM_VWORD32), +- [0x08] = INAT_MODRM, +- [0x09] = INAT_MODRM, +- [0x0a] = INAT_MODRM, +- [0x0b] = INAT_MODRM, +- [0x0c] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x0d] = INAT_MAKE_IMM(INAT_IMM_VWORD32), +- [0x0f] = INAT_MAKE_ESCAPE(1), +- [0x10] = INAT_MODRM, +- [0x11] = INAT_MODRM, +- [0x12] = INAT_MODRM, +- [0x13] = INAT_MODRM, +- [0x14] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x15] = INAT_MAKE_IMM(INAT_IMM_VWORD32), +- [0x18] = INAT_MODRM, +- [0x19] = INAT_MODRM, +- [0x1a] = INAT_MODRM, +- [0x1b] = INAT_MODRM, +- [0x1c] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x1d] = INAT_MAKE_IMM(INAT_IMM_VWORD32), +- [0x20] = INAT_MODRM, +- [0x21] = INAT_MODRM, +- [0x22] = INAT_MODRM, +- [0x23] = INAT_MODRM, +- [0x24] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x25] = INAT_MAKE_IMM(INAT_IMM_VWORD32), +- [0x26] = INAT_MAKE_PREFIX(INAT_PFX_ES), +- [0x28] = INAT_MODRM, +- [0x29] = INAT_MODRM, +- [0x2a] = INAT_MODRM, +- [0x2b] = INAT_MODRM, +- [0x2c] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x2d] = INAT_MAKE_IMM(INAT_IMM_VWORD32), +- [0x2e] = INAT_MAKE_PREFIX(INAT_PFX_CS), +- [0x30] = INAT_MODRM, +- [0x31] = INAT_MODRM, +- [0x32] = INAT_MODRM, +- [0x33] = INAT_MODRM, +- [0x34] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x35] = INAT_MAKE_IMM(INAT_IMM_VWORD32), +- [0x36] = INAT_MAKE_PREFIX(INAT_PFX_SS), +- [0x38] = INAT_MODRM, +- [0x39] = INAT_MODRM, +- [0x3a] = INAT_MODRM, +- [0x3b] = INAT_MODRM, +- [0x3c] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x3d] = INAT_MAKE_IMM(INAT_IMM_VWORD32), +- [0x3e] = INAT_MAKE_PREFIX(INAT_PFX_DS), +- [0x40] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x41] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x42] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x43] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x44] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x45] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x46] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x47] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x48] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x49] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x4a] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x4b] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x4c] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x4d] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x4e] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x4f] = INAT_MAKE_PREFIX(INAT_PFX_REX), +- [0x50] = INAT_FORCE64, +- [0x51] = INAT_FORCE64, +- [0x52] = INAT_FORCE64, +- [0x53] = INAT_FORCE64, +- [0x54] = INAT_FORCE64, +- [0x55] = INAT_FORCE64, +- [0x56] = INAT_FORCE64, +- [0x57] = INAT_FORCE64, +- [0x58] = INAT_FORCE64, +- [0x59] = INAT_FORCE64, +- [0x5a] = INAT_FORCE64, +- [0x5b] = INAT_FORCE64, +- [0x5c] = INAT_FORCE64, +- [0x5d] = INAT_FORCE64, +- [0x5e] = INAT_FORCE64, +- [0x5f] = INAT_FORCE64, +- [0x62] = INAT_MODRM, +- [0x63] = INAT_MODRM | INAT_MODRM, +- [0x64] = INAT_MAKE_PREFIX(INAT_PFX_FS), +- [0x65] = INAT_MAKE_PREFIX(INAT_PFX_GS), +- [0x66] = INAT_MAKE_PREFIX(INAT_PFX_OPNDSZ), +- [0x67] = INAT_MAKE_PREFIX(INAT_PFX_ADDRSZ), +- [0x68] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x69] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_MODRM, +- [0x6a] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, +- [0x6b] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, +- [0x70] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x71] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x72] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x73] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x74] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x75] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x76] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x77] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x78] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x79] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x7a] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x7b] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x7c] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x7d] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x7e] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x7f] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0x80] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(1), +- [0x81] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_MODRM | INAT_MAKE_GROUP(1), +- [0x82] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(1), +- [0x83] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(1), +- [0x84] = INAT_MODRM, +- [0x85] = INAT_MODRM, +- [0x86] = INAT_MODRM, +- [0x87] = INAT_MODRM, +- [0x88] = INAT_MODRM, +- [0x89] = INAT_MODRM, +- [0x8a] = INAT_MODRM, +- [0x8b] = INAT_MODRM, +- [0x8c] = INAT_MODRM, +- [0x8d] = INAT_MODRM, +- [0x8e] = INAT_MODRM, +- [0x8f] = INAT_MAKE_GROUP(2) | INAT_MODRM | INAT_FORCE64, +- [0x9a] = INAT_MAKE_IMM(INAT_IMM_PTR), +- [0x9c] = INAT_FORCE64, +- [0x9d] = INAT_FORCE64, +- [0xa0] = INAT_MOFFSET, +- [0xa1] = INAT_MOFFSET, +- [0xa2] = INAT_MOFFSET, +- [0xa3] = INAT_MOFFSET, +- [0xa8] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xa9] = INAT_MAKE_IMM(INAT_IMM_VWORD32), +- [0xb0] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xb1] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xb2] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xb3] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xb4] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xb5] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xb6] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xb7] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xb8] = INAT_MAKE_IMM(INAT_IMM_VWORD), +- [0xb9] = INAT_MAKE_IMM(INAT_IMM_VWORD), +- [0xba] = INAT_MAKE_IMM(INAT_IMM_VWORD), +- [0xbb] = INAT_MAKE_IMM(INAT_IMM_VWORD), +- [0xbc] = INAT_MAKE_IMM(INAT_IMM_VWORD), +- [0xbd] = INAT_MAKE_IMM(INAT_IMM_VWORD), +- [0xbe] = INAT_MAKE_IMM(INAT_IMM_VWORD), +- [0xbf] = INAT_MAKE_IMM(INAT_IMM_VWORD), +- [0xc0] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(3), +- [0xc1] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(3), +- [0xc2] = INAT_MAKE_IMM(INAT_IMM_WORD) | INAT_FORCE64, +- [0xc4] = INAT_MODRM | INAT_MAKE_PREFIX(INAT_PFX_VEX3), +- [0xc5] = INAT_MODRM | INAT_MAKE_PREFIX(INAT_PFX_VEX2), +- [0xc6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(4), +- [0xc7] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_MODRM | INAT_MAKE_GROUP(5), +- [0xc8] = INAT_MAKE_IMM(INAT_IMM_WORD) | INAT_SCNDIMM, +- [0xc9] = INAT_FORCE64, +- [0xca] = INAT_MAKE_IMM(INAT_IMM_WORD), +- [0xcd] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xd0] = INAT_MODRM | INAT_MAKE_GROUP(3), +- [0xd1] = INAT_MODRM | INAT_MAKE_GROUP(3), +- [0xd2] = INAT_MODRM | INAT_MAKE_GROUP(3), +- [0xd3] = INAT_MODRM | INAT_MAKE_GROUP(3), +- [0xd4] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xd5] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xd8] = INAT_MODRM, +- [0xd9] = INAT_MODRM, +- [0xda] = INAT_MODRM, +- [0xdb] = INAT_MODRM, +- [0xdc] = INAT_MODRM, +- [0xdd] = INAT_MODRM, +- [0xde] = INAT_MODRM, +- [0xdf] = INAT_MODRM, +- [0xe0] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, +- [0xe1] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, +- [0xe2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, +- [0xe3] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, +- [0xe4] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xe5] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xe6] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xe7] = INAT_MAKE_IMM(INAT_IMM_BYTE), +- [0xe8] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0xe9] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0xea] = INAT_MAKE_IMM(INAT_IMM_PTR), +- [0xeb] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, +- [0xf0] = INAT_MAKE_PREFIX(INAT_PFX_LOCK), +- [0xf2] = INAT_MAKE_PREFIX(INAT_PFX_REPNE) | INAT_MAKE_PREFIX(INAT_PFX_REPNE), +- [0xf3] = INAT_MAKE_PREFIX(INAT_PFX_REPE) | INAT_MAKE_PREFIX(INAT_PFX_REPE), +- [0xf6] = INAT_MODRM | INAT_MAKE_GROUP(6), +- [0xf7] = INAT_MODRM | INAT_MAKE_GROUP(7), +- [0xfe] = INAT_MAKE_GROUP(8), +- [0xff] = INAT_MAKE_GROUP(9), ++ [0x00] = INAT_MODRM, ++ [0x01] = INAT_MODRM, ++ [0x02] = INAT_MODRM, ++ [0x03] = INAT_MODRM, ++ [0x04] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x05] = INAT_MAKE_IMM(INAT_IMM_VWORD32), ++ [0x08] = INAT_MODRM, ++ [0x09] = INAT_MODRM, ++ [0x0a] = INAT_MODRM, ++ [0x0b] = INAT_MODRM, ++ [0x0c] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x0d] = INAT_MAKE_IMM(INAT_IMM_VWORD32), ++ [0x0f] = INAT_MAKE_ESCAPE(1), ++ [0x10] = INAT_MODRM, ++ [0x11] = INAT_MODRM, ++ [0x12] = INAT_MODRM, ++ [0x13] = INAT_MODRM, ++ [0x14] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x15] = INAT_MAKE_IMM(INAT_IMM_VWORD32), ++ [0x18] = INAT_MODRM, ++ [0x19] = INAT_MODRM, ++ [0x1a] = INAT_MODRM, ++ [0x1b] = INAT_MODRM, ++ [0x1c] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x1d] = INAT_MAKE_IMM(INAT_IMM_VWORD32), ++ [0x20] = INAT_MODRM, ++ [0x21] = INAT_MODRM, ++ [0x22] = INAT_MODRM, ++ [0x23] = INAT_MODRM, ++ [0x24] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x25] = INAT_MAKE_IMM(INAT_IMM_VWORD32), ++ [0x26] = INAT_MAKE_PREFIX(INAT_PFX_ES), ++ [0x28] = INAT_MODRM, ++ [0x29] = INAT_MODRM, ++ [0x2a] = INAT_MODRM, ++ [0x2b] = INAT_MODRM, ++ [0x2c] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x2d] = INAT_MAKE_IMM(INAT_IMM_VWORD32), ++ [0x2e] = INAT_MAKE_PREFIX(INAT_PFX_CS), ++ [0x30] = INAT_MODRM, ++ [0x31] = INAT_MODRM, ++ [0x32] = INAT_MODRM, ++ [0x33] = INAT_MODRM, ++ [0x34] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x35] = INAT_MAKE_IMM(INAT_IMM_VWORD32), ++ [0x36] = INAT_MAKE_PREFIX(INAT_PFX_SS), ++ [0x38] = INAT_MODRM, ++ [0x39] = INAT_MODRM, ++ [0x3a] = INAT_MODRM, ++ [0x3b] = INAT_MODRM, ++ [0x3c] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x3d] = INAT_MAKE_IMM(INAT_IMM_VWORD32), ++ [0x3e] = INAT_MAKE_PREFIX(INAT_PFX_DS), ++ [0x40] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x41] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x42] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x43] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x44] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x45] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x46] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x47] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x48] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x49] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x4a] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x4b] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x4c] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x4d] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x4e] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x4f] = INAT_MAKE_PREFIX(INAT_PFX_REX), ++ [0x50] = INAT_FORCE64, ++ [0x51] = INAT_FORCE64, ++ [0x52] = INAT_FORCE64, ++ [0x53] = INAT_FORCE64, ++ [0x54] = INAT_FORCE64, ++ [0x55] = INAT_FORCE64, ++ [0x56] = INAT_FORCE64, ++ [0x57] = INAT_FORCE64, ++ [0x58] = INAT_FORCE64, ++ [0x59] = INAT_FORCE64, ++ [0x5a] = INAT_FORCE64, ++ [0x5b] = INAT_FORCE64, ++ [0x5c] = INAT_FORCE64, ++ [0x5d] = INAT_FORCE64, ++ [0x5e] = INAT_FORCE64, ++ [0x5f] = INAT_FORCE64, ++ [0x62] = INAT_MODRM, ++ [0x63] = INAT_MODRM | INAT_MODRM, ++ [0x64] = INAT_MAKE_PREFIX(INAT_PFX_FS), ++ [0x65] = INAT_MAKE_PREFIX(INAT_PFX_GS), ++ [0x66] = INAT_MAKE_PREFIX(INAT_PFX_OPNDSZ), ++ [0x67] = INAT_MAKE_PREFIX(INAT_PFX_ADDRSZ), ++ [0x68] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x69] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_MODRM, ++ [0x6a] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, ++ [0x6b] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, ++ [0x70] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x71] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x72] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x73] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x74] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x75] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x76] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x77] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x78] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x79] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x7a] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x7b] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x7c] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x7d] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x7e] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x7f] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x80] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(1), ++ [0x81] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_MODRM | INAT_MAKE_GROUP(1), ++ [0x82] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(1), ++ [0x83] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(1), ++ [0x84] = INAT_MODRM, ++ [0x85] = INAT_MODRM, ++ [0x86] = INAT_MODRM, ++ [0x87] = INAT_MODRM, ++ [0x88] = INAT_MODRM, ++ [0x89] = INAT_MODRM, ++ [0x8a] = INAT_MODRM, ++ [0x8b] = INAT_MODRM, ++ [0x8c] = INAT_MODRM, ++ [0x8d] = INAT_MODRM, ++ [0x8e] = INAT_MODRM, ++ [0x8f] = INAT_MAKE_GROUP(2) | INAT_MODRM | INAT_FORCE64, ++ [0x9a] = INAT_MAKE_IMM(INAT_IMM_PTR), ++ [0x9c] = INAT_FORCE64, ++ [0x9d] = INAT_FORCE64, ++ [0xa0] = INAT_MOFFSET, ++ [0xa1] = INAT_MOFFSET, ++ [0xa2] = INAT_MOFFSET, ++ [0xa3] = INAT_MOFFSET, ++ [0xa8] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xa9] = INAT_MAKE_IMM(INAT_IMM_VWORD32), ++ [0xb0] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xb1] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xb2] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xb3] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xb4] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xb5] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xb6] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xb7] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xb8] = INAT_MAKE_IMM(INAT_IMM_VWORD), ++ [0xb9] = INAT_MAKE_IMM(INAT_IMM_VWORD), ++ [0xba] = INAT_MAKE_IMM(INAT_IMM_VWORD), ++ [0xbb] = INAT_MAKE_IMM(INAT_IMM_VWORD), ++ [0xbc] = INAT_MAKE_IMM(INAT_IMM_VWORD), ++ [0xbd] = INAT_MAKE_IMM(INAT_IMM_VWORD), ++ [0xbe] = INAT_MAKE_IMM(INAT_IMM_VWORD), ++ [0xbf] = INAT_MAKE_IMM(INAT_IMM_VWORD), ++ [0xc0] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(3), ++ [0xc1] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(3), ++ [0xc2] = INAT_MAKE_IMM(INAT_IMM_WORD) | INAT_FORCE64, ++ [0xc4] = INAT_MODRM | INAT_MAKE_PREFIX(INAT_PFX_VEX3), ++ [0xc5] = INAT_MODRM | INAT_MAKE_PREFIX(INAT_PFX_VEX2), ++ [0xc6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(4), ++ [0xc7] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_MODRM | INAT_MAKE_GROUP(5), ++ [0xc8] = INAT_MAKE_IMM(INAT_IMM_WORD) | INAT_SCNDIMM, ++ [0xc9] = INAT_FORCE64, ++ [0xca] = INAT_MAKE_IMM(INAT_IMM_WORD), ++ [0xcd] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xd0] = INAT_MODRM | INAT_MAKE_GROUP(3), ++ [0xd1] = INAT_MODRM | INAT_MAKE_GROUP(3), ++ [0xd2] = INAT_MODRM | INAT_MAKE_GROUP(3), ++ [0xd3] = INAT_MODRM | INAT_MAKE_GROUP(3), ++ [0xd4] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xd5] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xd8] = INAT_MODRM, ++ [0xd9] = INAT_MODRM, ++ [0xda] = INAT_MODRM, ++ [0xdb] = INAT_MODRM, ++ [0xdc] = INAT_MODRM, ++ [0xdd] = INAT_MODRM, ++ [0xde] = INAT_MODRM, ++ [0xdf] = INAT_MODRM, ++ [0xe0] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, ++ [0xe1] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, ++ [0xe2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, ++ [0xe3] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, ++ [0xe4] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xe5] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xe6] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xe7] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0xe8] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0xe9] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0xea] = INAT_MAKE_IMM(INAT_IMM_PTR), ++ [0xeb] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, ++ [0xf0] = INAT_MAKE_PREFIX(INAT_PFX_LOCK), ++ [0xf2] = INAT_MAKE_PREFIX(INAT_PFX_REPNE) | INAT_MAKE_PREFIX(INAT_PFX_REPNE), ++ [0xf3] = INAT_MAKE_PREFIX(INAT_PFX_REPE) | INAT_MAKE_PREFIX(INAT_PFX_REPE), ++ [0xf6] = INAT_MODRM | INAT_MAKE_GROUP(6), ++ [0xf7] = INAT_MODRM | INAT_MAKE_GROUP(7), ++ [0xfe] = INAT_MAKE_GROUP(8), ++ [0xff] = INAT_MAKE_GROUP(9), + }; + + /* Table: 2-byte opcode (0x0f) */ + const insn_attr_t inat_escape_table_1[INAT_OPCODE_TABLE_SIZE] = { +- [0x00] = INAT_MAKE_GROUP(10), +- [0x01] = INAT_MAKE_GROUP(11), +- [0x02] = INAT_MODRM, +- [0x03] = INAT_MODRM, +- [0x0d] = INAT_MAKE_GROUP(12), +- [0x0f] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, +- [0x10] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x11] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x12] = INAT_MODRM | INAT_VEXOK | INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x13] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x14] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x15] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x16] = INAT_MODRM | INAT_VEXOK | INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x17] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x18] = INAT_MAKE_GROUP(13), +- [0x1a] = INAT_MODRM | INAT_MODRM | INAT_MODRM | INAT_MODRM, +- [0x1b] = INAT_MODRM | INAT_MODRM | INAT_MODRM | INAT_MODRM, +- [0x1f] = INAT_MODRM, +- [0x20] = INAT_MODRM, +- [0x21] = INAT_MODRM, +- [0x22] = INAT_MODRM, +- [0x23] = INAT_MODRM, +- [0x28] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x29] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x2a] = INAT_MODRM | INAT_VARIANT, +- [0x2b] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x2c] = INAT_MODRM | INAT_VARIANT, +- [0x2d] = INAT_MODRM | INAT_VARIANT, +- [0x2e] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x2f] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x38] = INAT_MAKE_ESCAPE(2), +- [0x3a] = INAT_MAKE_ESCAPE(3), +- [0x40] = INAT_MODRM, +- [0x41] = INAT_MODRM, +- [0x42] = INAT_MODRM, +- [0x43] = INAT_MODRM, +- [0x44] = INAT_MODRM, +- [0x45] = INAT_MODRM, +- [0x46] = INAT_MODRM, +- [0x47] = INAT_MODRM, +- [0x48] = INAT_MODRM, +- [0x49] = INAT_MODRM, +- [0x4a] = INAT_MODRM, +- [0x4b] = INAT_MODRM, +- [0x4c] = INAT_MODRM, +- [0x4d] = INAT_MODRM, +- [0x4e] = INAT_MODRM, +- [0x4f] = INAT_MODRM, +- [0x50] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x51] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x52] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x53] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x54] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x55] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x56] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x57] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x58] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x59] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x5a] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x5b] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x5c] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x5d] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x5e] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x5f] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x60] = INAT_MODRM | INAT_VARIANT, +- [0x61] = INAT_MODRM | INAT_VARIANT, +- [0x62] = INAT_MODRM | INAT_VARIANT, +- [0x63] = INAT_MODRM | INAT_VARIANT, +- [0x64] = INAT_MODRM | INAT_VARIANT, +- [0x65] = INAT_MODRM | INAT_VARIANT, +- [0x66] = INAT_MODRM | INAT_VARIANT, +- [0x67] = INAT_MODRM | INAT_VARIANT, +- [0x68] = INAT_MODRM | INAT_VARIANT, +- [0x69] = INAT_MODRM | INAT_VARIANT, +- [0x6a] = INAT_MODRM | INAT_VARIANT, +- [0x6b] = INAT_MODRM | INAT_VARIANT, +- [0x6c] = INAT_VARIANT, +- [0x6d] = INAT_VARIANT, +- [0x6e] = INAT_MODRM | INAT_VARIANT, +- [0x6f] = INAT_MODRM | INAT_VARIANT, +- [0x70] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, +- [0x71] = INAT_MAKE_GROUP(14), +- [0x72] = INAT_MAKE_GROUP(15), +- [0x73] = INAT_MAKE_GROUP(16), +- [0x74] = INAT_MODRM | INAT_VARIANT, +- [0x75] = INAT_MODRM | INAT_VARIANT, +- [0x76] = INAT_MODRM | INAT_VARIANT, +- [0x77] = INAT_VEXOK | INAT_VEXOK, +- [0x78] = INAT_MODRM, +- [0x79] = INAT_MODRM, +- [0x7c] = INAT_VARIANT, +- [0x7d] = INAT_VARIANT, +- [0x7e] = INAT_MODRM | INAT_VARIANT, +- [0x7f] = INAT_MODRM | INAT_VARIANT, +- [0x80] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x81] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x82] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x83] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x84] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x85] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x86] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x87] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x88] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x89] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x8a] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x8b] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x8c] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x8d] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x8e] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x8f] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, +- [0x90] = INAT_MODRM, +- [0x91] = INAT_MODRM, +- [0x92] = INAT_MODRM, +- [0x93] = INAT_MODRM, +- [0x94] = INAT_MODRM, +- [0x95] = INAT_MODRM, +- [0x96] = INAT_MODRM, +- [0x97] = INAT_MODRM, +- [0x98] = INAT_MODRM, +- [0x99] = INAT_MODRM, +- [0x9a] = INAT_MODRM, +- [0x9b] = INAT_MODRM, +- [0x9c] = INAT_MODRM, +- [0x9d] = INAT_MODRM, +- [0x9e] = INAT_MODRM, +- [0x9f] = INAT_MODRM, +- [0xa0] = INAT_FORCE64, +- [0xa1] = INAT_FORCE64, +- [0xa3] = INAT_MODRM, +- [0xa4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, +- [0xa5] = INAT_MODRM, +- [0xa6] = INAT_MAKE_GROUP(17), +- [0xa7] = INAT_MAKE_GROUP(18), +- [0xa8] = INAT_FORCE64, +- [0xa9] = INAT_FORCE64, +- [0xab] = INAT_MODRM, +- [0xac] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, +- [0xad] = INAT_MODRM, +- [0xae] = INAT_MAKE_GROUP(19), +- [0xaf] = INAT_MODRM, +- [0xb0] = INAT_MODRM, +- [0xb1] = INAT_MODRM, +- [0xb2] = INAT_MODRM, +- [0xb3] = INAT_MODRM, +- [0xb4] = INAT_MODRM, +- [0xb5] = INAT_MODRM, +- [0xb6] = INAT_MODRM, +- [0xb7] = INAT_MODRM, +- [0xb8] = INAT_VARIANT, +- [0xb9] = INAT_MAKE_GROUP(20), +- [0xba] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(21), +- [0xbb] = INAT_MODRM, +- [0xbc] = INAT_MODRM | INAT_VARIANT, +- [0xbd] = INAT_MODRM | INAT_VARIANT, +- [0xbe] = INAT_MODRM, +- [0xbf] = INAT_MODRM, +- [0xc0] = INAT_MODRM, +- [0xc1] = INAT_MODRM, +- [0xc2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0xc3] = INAT_MODRM, +- [0xc4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, +- [0xc5] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, +- [0xc6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0xc7] = INAT_MAKE_GROUP(22), +- [0xd0] = INAT_VARIANT, +- [0xd1] = INAT_MODRM | INAT_VARIANT, +- [0xd2] = INAT_MODRM | INAT_VARIANT, +- [0xd3] = INAT_MODRM | INAT_VARIANT, +- [0xd4] = INAT_MODRM | INAT_VARIANT, +- [0xd5] = INAT_MODRM | INAT_VARIANT, +- [0xd6] = INAT_VARIANT, +- [0xd7] = INAT_MODRM | INAT_VARIANT, +- [0xd8] = INAT_MODRM | INAT_VARIANT, +- [0xd9] = INAT_MODRM | INAT_VARIANT, +- [0xda] = INAT_MODRM | INAT_VARIANT, +- [0xdb] = INAT_MODRM | INAT_VARIANT, +- [0xdc] = INAT_MODRM | INAT_VARIANT, +- [0xdd] = INAT_MODRM | INAT_VARIANT, +- [0xde] = INAT_MODRM | INAT_VARIANT, +- [0xdf] = INAT_MODRM | INAT_VARIANT, +- [0xe0] = INAT_MODRM | INAT_VARIANT, +- [0xe1] = INAT_MODRM | INAT_VARIANT, +- [0xe2] = INAT_MODRM | INAT_VARIANT, +- [0xe3] = INAT_MODRM | INAT_VARIANT, +- [0xe4] = INAT_MODRM | INAT_VARIANT, +- [0xe5] = INAT_MODRM | INAT_VARIANT, +- [0xe6] = INAT_VARIANT, +- [0xe7] = INAT_MODRM | INAT_VARIANT, +- [0xe8] = INAT_MODRM | INAT_VARIANT, +- [0xe9] = INAT_MODRM | INAT_VARIANT, +- [0xea] = INAT_MODRM | INAT_VARIANT, +- [0xeb] = INAT_MODRM | INAT_VARIANT, +- [0xec] = INAT_MODRM | INAT_VARIANT, +- [0xed] = INAT_MODRM | INAT_VARIANT, +- [0xee] = INAT_MODRM | INAT_VARIANT, +- [0xef] = INAT_MODRM | INAT_VARIANT, +- [0xf0] = INAT_VARIANT, +- [0xf1] = INAT_MODRM | INAT_VARIANT, +- [0xf2] = INAT_MODRM | INAT_VARIANT, +- [0xf3] = INAT_MODRM | INAT_VARIANT, +- [0xf4] = INAT_MODRM | INAT_VARIANT, +- [0xf5] = INAT_MODRM | INAT_VARIANT, +- [0xf6] = INAT_MODRM | INAT_VARIANT, +- [0xf7] = INAT_MODRM | INAT_VARIANT, +- [0xf8] = INAT_MODRM | INAT_VARIANT, +- [0xf9] = INAT_MODRM | INAT_VARIANT, +- [0xfa] = INAT_MODRM | INAT_VARIANT, +- [0xfb] = INAT_MODRM | INAT_VARIANT, +- [0xfc] = INAT_MODRM | INAT_VARIANT, +- [0xfd] = INAT_MODRM | INAT_VARIANT, +- [0xfe] = INAT_MODRM | INAT_VARIANT, ++ [0x00] = INAT_MAKE_GROUP(10), ++ [0x01] = INAT_MAKE_GROUP(11), ++ [0x02] = INAT_MODRM, ++ [0x03] = INAT_MODRM, ++ [0x0d] = INAT_MAKE_GROUP(12), ++ [0x0f] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, ++ [0x10] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x11] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x12] = INAT_MODRM | INAT_VEXOK | INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x13] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x14] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x15] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x16] = INAT_MODRM | INAT_VEXOK | INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x17] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x18] = INAT_MAKE_GROUP(13), ++ [0x1a] = INAT_MODRM | INAT_MODRM | INAT_MODRM | INAT_MODRM, ++ [0x1b] = INAT_MODRM | INAT_MODRM | INAT_MODRM | INAT_MODRM, ++ [0x1f] = INAT_MODRM, ++ [0x20] = INAT_MODRM, ++ [0x21] = INAT_MODRM, ++ [0x22] = INAT_MODRM, ++ [0x23] = INAT_MODRM, ++ [0x28] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x29] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x2a] = INAT_MODRM | INAT_VARIANT, ++ [0x2b] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x2c] = INAT_MODRM | INAT_VARIANT, ++ [0x2d] = INAT_MODRM | INAT_VARIANT, ++ [0x2e] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x2f] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x38] = INAT_MAKE_ESCAPE(2), ++ [0x3a] = INAT_MAKE_ESCAPE(3), ++ [0x40] = INAT_MODRM, ++ [0x41] = INAT_MODRM, ++ [0x42] = INAT_MODRM, ++ [0x43] = INAT_MODRM, ++ [0x44] = INAT_MODRM, ++ [0x45] = INAT_MODRM, ++ [0x46] = INAT_MODRM, ++ [0x47] = INAT_MODRM, ++ [0x48] = INAT_MODRM, ++ [0x49] = INAT_MODRM, ++ [0x4a] = INAT_MODRM, ++ [0x4b] = INAT_MODRM, ++ [0x4c] = INAT_MODRM, ++ [0x4d] = INAT_MODRM, ++ [0x4e] = INAT_MODRM, ++ [0x4f] = INAT_MODRM, ++ [0x50] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x51] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x52] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x53] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x54] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x55] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x56] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x57] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x58] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x59] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x5a] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x5b] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x5c] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x5d] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x5e] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x5f] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x60] = INAT_MODRM | INAT_VARIANT, ++ [0x61] = INAT_MODRM | INAT_VARIANT, ++ [0x62] = INAT_MODRM | INAT_VARIANT, ++ [0x63] = INAT_MODRM | INAT_VARIANT, ++ [0x64] = INAT_MODRM | INAT_VARIANT, ++ [0x65] = INAT_MODRM | INAT_VARIANT, ++ [0x66] = INAT_MODRM | INAT_VARIANT, ++ [0x67] = INAT_MODRM | INAT_VARIANT, ++ [0x68] = INAT_MODRM | INAT_VARIANT, ++ [0x69] = INAT_MODRM | INAT_VARIANT, ++ [0x6a] = INAT_MODRM | INAT_VARIANT, ++ [0x6b] = INAT_MODRM | INAT_VARIANT, ++ [0x6c] = INAT_VARIANT, ++ [0x6d] = INAT_VARIANT, ++ [0x6e] = INAT_MODRM | INAT_VARIANT, ++ [0x6f] = INAT_MODRM | INAT_VARIANT, ++ [0x70] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, ++ [0x71] = INAT_MAKE_GROUP(14), ++ [0x72] = INAT_MAKE_GROUP(15), ++ [0x73] = INAT_MAKE_GROUP(16), ++ [0x74] = INAT_MODRM | INAT_VARIANT, ++ [0x75] = INAT_MODRM | INAT_VARIANT, ++ [0x76] = INAT_MODRM | INAT_VARIANT, ++ [0x77] = INAT_VEXOK | INAT_VEXOK, ++ [0x78] = INAT_MODRM, ++ [0x79] = INAT_MODRM, ++ [0x7c] = INAT_VARIANT, ++ [0x7d] = INAT_VARIANT, ++ [0x7e] = INAT_MODRM | INAT_VARIANT, ++ [0x7f] = INAT_MODRM | INAT_VARIANT, ++ [0x80] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x81] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x82] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x83] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x84] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x85] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x86] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x87] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x88] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x89] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x8a] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x8b] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x8c] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x8d] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x8e] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x8f] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, ++ [0x90] = INAT_MODRM, ++ [0x91] = INAT_MODRM, ++ [0x92] = INAT_MODRM, ++ [0x93] = INAT_MODRM, ++ [0x94] = INAT_MODRM, ++ [0x95] = INAT_MODRM, ++ [0x96] = INAT_MODRM, ++ [0x97] = INAT_MODRM, ++ [0x98] = INAT_MODRM, ++ [0x99] = INAT_MODRM, ++ [0x9a] = INAT_MODRM, ++ [0x9b] = INAT_MODRM, ++ [0x9c] = INAT_MODRM, ++ [0x9d] = INAT_MODRM, ++ [0x9e] = INAT_MODRM, ++ [0x9f] = INAT_MODRM, ++ [0xa0] = INAT_FORCE64, ++ [0xa1] = INAT_FORCE64, ++ [0xa3] = INAT_MODRM, ++ [0xa4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, ++ [0xa5] = INAT_MODRM, ++ [0xa6] = INAT_MAKE_GROUP(17), ++ [0xa7] = INAT_MAKE_GROUP(18), ++ [0xa8] = INAT_FORCE64, ++ [0xa9] = INAT_FORCE64, ++ [0xab] = INAT_MODRM, ++ [0xac] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, ++ [0xad] = INAT_MODRM, ++ [0xae] = INAT_MAKE_GROUP(19), ++ [0xaf] = INAT_MODRM, ++ [0xb0] = INAT_MODRM, ++ [0xb1] = INAT_MODRM, ++ [0xb2] = INAT_MODRM, ++ [0xb3] = INAT_MODRM, ++ [0xb4] = INAT_MODRM, ++ [0xb5] = INAT_MODRM, ++ [0xb6] = INAT_MODRM, ++ [0xb7] = INAT_MODRM, ++ [0xb8] = INAT_VARIANT, ++ [0xb9] = INAT_MAKE_GROUP(20), ++ [0xba] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(21), ++ [0xbb] = INAT_MODRM, ++ [0xbc] = INAT_MODRM | INAT_VARIANT, ++ [0xbd] = INAT_MODRM | INAT_VARIANT, ++ [0xbe] = INAT_MODRM, ++ [0xbf] = INAT_MODRM, ++ [0xc0] = INAT_MODRM, ++ [0xc1] = INAT_MODRM, ++ [0xc2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0xc3] = INAT_MODRM, ++ [0xc4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, ++ [0xc5] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, ++ [0xc6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0xc7] = INAT_MAKE_GROUP(22), ++ [0xd0] = INAT_VARIANT, ++ [0xd1] = INAT_MODRM | INAT_VARIANT, ++ [0xd2] = INAT_MODRM | INAT_VARIANT, ++ [0xd3] = INAT_MODRM | INAT_VARIANT, ++ [0xd4] = INAT_MODRM | INAT_VARIANT, ++ [0xd5] = INAT_MODRM | INAT_VARIANT, ++ [0xd6] = INAT_VARIANT, ++ [0xd7] = INAT_MODRM | INAT_VARIANT, ++ [0xd8] = INAT_MODRM | INAT_VARIANT, ++ [0xd9] = INAT_MODRM | INAT_VARIANT, ++ [0xda] = INAT_MODRM | INAT_VARIANT, ++ [0xdb] = INAT_MODRM | INAT_VARIANT, ++ [0xdc] = INAT_MODRM | INAT_VARIANT, ++ [0xdd] = INAT_MODRM | INAT_VARIANT, ++ [0xde] = INAT_MODRM | INAT_VARIANT, ++ [0xdf] = INAT_MODRM | INAT_VARIANT, ++ [0xe0] = INAT_MODRM | INAT_VARIANT, ++ [0xe1] = INAT_MODRM | INAT_VARIANT, ++ [0xe2] = INAT_MODRM | INAT_VARIANT, ++ [0xe3] = INAT_MODRM | INAT_VARIANT, ++ [0xe4] = INAT_MODRM | INAT_VARIANT, ++ [0xe5] = INAT_MODRM | INAT_VARIANT, ++ [0xe6] = INAT_VARIANT, ++ [0xe7] = INAT_MODRM | INAT_VARIANT, ++ [0xe8] = INAT_MODRM | INAT_VARIANT, ++ [0xe9] = INAT_MODRM | INAT_VARIANT, ++ [0xea] = INAT_MODRM | INAT_VARIANT, ++ [0xeb] = INAT_MODRM | INAT_VARIANT, ++ [0xec] = INAT_MODRM | INAT_VARIANT, ++ [0xed] = INAT_MODRM | INAT_VARIANT, ++ [0xee] = INAT_MODRM | INAT_VARIANT, ++ [0xef] = INAT_MODRM | INAT_VARIANT, ++ [0xf0] = INAT_VARIANT, ++ [0xf1] = INAT_MODRM | INAT_VARIANT, ++ [0xf2] = INAT_MODRM | INAT_VARIANT, ++ [0xf3] = INAT_MODRM | INAT_VARIANT, ++ [0xf4] = INAT_MODRM | INAT_VARIANT, ++ [0xf5] = INAT_MODRM | INAT_VARIANT, ++ [0xf6] = INAT_MODRM | INAT_VARIANT, ++ [0xf7] = INAT_MODRM | INAT_VARIANT, ++ [0xf8] = INAT_MODRM | INAT_VARIANT, ++ [0xf9] = INAT_MODRM | INAT_VARIANT, ++ [0xfa] = INAT_MODRM | INAT_VARIANT, ++ [0xfb] = INAT_MODRM | INAT_VARIANT, ++ [0xfc] = INAT_MODRM | INAT_VARIANT, ++ [0xfd] = INAT_MODRM | INAT_VARIANT, ++ [0xfe] = INAT_MODRM | INAT_VARIANT, + }; + const insn_attr_t inat_escape_table_1_1[INAT_OPCODE_TABLE_SIZE] = { +- [0x10] = INAT_MODRM | INAT_VEXOK, +- [0x11] = INAT_MODRM | INAT_VEXOK, +- [0x12] = INAT_MODRM | INAT_VEXOK, +- [0x13] = INAT_MODRM | INAT_VEXOK, +- [0x14] = INAT_MODRM | INAT_VEXOK, +- [0x15] = INAT_MODRM | INAT_VEXOK, +- [0x16] = INAT_MODRM | INAT_VEXOK, +- [0x17] = INAT_MODRM | INAT_VEXOK, +- [0x28] = INAT_MODRM | INAT_VEXOK, +- [0x29] = INAT_MODRM | INAT_VEXOK, +- [0x2a] = INAT_MODRM, +- [0x2b] = INAT_MODRM | INAT_VEXOK, +- [0x2c] = INAT_MODRM, +- [0x2d] = INAT_MODRM, +- [0x2e] = INAT_MODRM | INAT_VEXOK, +- [0x2f] = INAT_MODRM | INAT_VEXOK, +- [0x50] = INAT_MODRM | INAT_VEXOK, +- [0x51] = INAT_MODRM | INAT_VEXOK, +- [0x54] = INAT_MODRM | INAT_VEXOK, +- [0x55] = INAT_MODRM | INAT_VEXOK, +- [0x56] = INAT_MODRM | INAT_VEXOK, +- [0x57] = INAT_MODRM | INAT_VEXOK, +- [0x58] = INAT_MODRM | INAT_VEXOK, +- [0x59] = INAT_MODRM | INAT_VEXOK, +- [0x5a] = INAT_MODRM | INAT_VEXOK, +- [0x5b] = INAT_MODRM | INAT_VEXOK, +- [0x5c] = INAT_MODRM | INAT_VEXOK, +- [0x5d] = INAT_MODRM | INAT_VEXOK, +- [0x5e] = INAT_MODRM | INAT_VEXOK, +- [0x5f] = INAT_MODRM | INAT_VEXOK, +- [0x60] = INAT_MODRM | INAT_VEXOK, +- [0x61] = INAT_MODRM | INAT_VEXOK, +- [0x62] = INAT_MODRM | INAT_VEXOK, +- [0x63] = INAT_MODRM | INAT_VEXOK, +- [0x64] = INAT_MODRM | INAT_VEXOK, +- [0x65] = INAT_MODRM | INAT_VEXOK, +- [0x66] = INAT_MODRM | INAT_VEXOK, +- [0x67] = INAT_MODRM | INAT_VEXOK, +- [0x68] = INAT_MODRM | INAT_VEXOK, +- [0x69] = INAT_MODRM | INAT_VEXOK, +- [0x6a] = INAT_MODRM | INAT_VEXOK, +- [0x6b] = INAT_MODRM | INAT_VEXOK, +- [0x6c] = INAT_MODRM | INAT_VEXOK, +- [0x6d] = INAT_MODRM | INAT_VEXOK, +- [0x6e] = INAT_MODRM | INAT_VEXOK, +- [0x6f] = INAT_MODRM | INAT_VEXOK, +- [0x70] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x74] = INAT_MODRM | INAT_VEXOK, +- [0x75] = INAT_MODRM | INAT_VEXOK, +- [0x76] = INAT_MODRM | INAT_VEXOK, +- [0x7c] = INAT_MODRM | INAT_VEXOK, +- [0x7d] = INAT_MODRM | INAT_VEXOK, +- [0x7e] = INAT_MODRM | INAT_VEXOK, +- [0x7f] = INAT_MODRM | INAT_VEXOK, +- [0xbc] = INAT_MODRM, +- [0xbd] = INAT_MODRM, +- [0xc2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0xc4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0xc5] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0xc6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0xd0] = INAT_MODRM | INAT_VEXOK, +- [0xd1] = INAT_MODRM | INAT_VEXOK, +- [0xd2] = INAT_MODRM | INAT_VEXOK, +- [0xd3] = INAT_MODRM | INAT_VEXOK, +- [0xd4] = INAT_MODRM | INAT_VEXOK, +- [0xd5] = INAT_MODRM | INAT_VEXOK, +- [0xd6] = INAT_MODRM | INAT_VEXOK, +- [0xd7] = INAT_MODRM | INAT_VEXOK, +- [0xd8] = INAT_MODRM | INAT_VEXOK, +- [0xd9] = INAT_MODRM | INAT_VEXOK, +- [0xda] = INAT_MODRM | INAT_VEXOK, +- [0xdb] = INAT_MODRM | INAT_VEXOK, +- [0xdc] = INAT_MODRM | INAT_VEXOK, +- [0xdd] = INAT_MODRM | INAT_VEXOK, +- [0xde] = INAT_MODRM | INAT_VEXOK, +- [0xdf] = INAT_MODRM | INAT_VEXOK, +- [0xe0] = INAT_MODRM | INAT_VEXOK, +- [0xe1] = INAT_MODRM | INAT_VEXOK, +- [0xe2] = INAT_MODRM | INAT_VEXOK, +- [0xe3] = INAT_MODRM | INAT_VEXOK, +- [0xe4] = INAT_MODRM | INAT_VEXOK, +- [0xe5] = INAT_MODRM | INAT_VEXOK, +- [0xe6] = INAT_MODRM | INAT_VEXOK, +- [0xe7] = INAT_MODRM | INAT_VEXOK, +- [0xe8] = INAT_MODRM | INAT_VEXOK, +- [0xe9] = INAT_MODRM | INAT_VEXOK, +- [0xea] = INAT_MODRM | INAT_VEXOK, +- [0xeb] = INAT_MODRM | INAT_VEXOK, +- [0xec] = INAT_MODRM | INAT_VEXOK, +- [0xed] = INAT_MODRM | INAT_VEXOK, +- [0xee] = INAT_MODRM | INAT_VEXOK, +- [0xef] = INAT_MODRM | INAT_VEXOK, +- [0xf1] = INAT_MODRM | INAT_VEXOK, +- [0xf2] = INAT_MODRM | INAT_VEXOK, +- [0xf3] = INAT_MODRM | INAT_VEXOK, +- [0xf4] = INAT_MODRM | INAT_VEXOK, +- [0xf5] = INAT_MODRM | INAT_VEXOK, +- [0xf6] = INAT_MODRM | INAT_VEXOK, +- [0xf7] = INAT_MODRM | INAT_VEXOK, +- [0xf8] = INAT_MODRM | INAT_VEXOK, +- [0xf9] = INAT_MODRM | INAT_VEXOK, +- [0xfa] = INAT_MODRM | INAT_VEXOK, +- [0xfb] = INAT_MODRM | INAT_VEXOK, +- [0xfc] = INAT_MODRM | INAT_VEXOK, +- [0xfd] = INAT_MODRM | INAT_VEXOK, +- [0xfe] = INAT_MODRM | INAT_VEXOK, ++ [0x10] = INAT_MODRM | INAT_VEXOK, ++ [0x11] = INAT_MODRM | INAT_VEXOK, ++ [0x12] = INAT_MODRM | INAT_VEXOK, ++ [0x13] = INAT_MODRM | INAT_VEXOK, ++ [0x14] = INAT_MODRM | INAT_VEXOK, ++ [0x15] = INAT_MODRM | INAT_VEXOK, ++ [0x16] = INAT_MODRM | INAT_VEXOK, ++ [0x17] = INAT_MODRM | INAT_VEXOK, ++ [0x28] = INAT_MODRM | INAT_VEXOK, ++ [0x29] = INAT_MODRM | INAT_VEXOK, ++ [0x2a] = INAT_MODRM, ++ [0x2b] = INAT_MODRM | INAT_VEXOK, ++ [0x2c] = INAT_MODRM, ++ [0x2d] = INAT_MODRM, ++ [0x2e] = INAT_MODRM | INAT_VEXOK, ++ [0x2f] = INAT_MODRM | INAT_VEXOK, ++ [0x50] = INAT_MODRM | INAT_VEXOK, ++ [0x51] = INAT_MODRM | INAT_VEXOK, ++ [0x54] = INAT_MODRM | INAT_VEXOK, ++ [0x55] = INAT_MODRM | INAT_VEXOK, ++ [0x56] = INAT_MODRM | INAT_VEXOK, ++ [0x57] = INAT_MODRM | INAT_VEXOK, ++ [0x58] = INAT_MODRM | INAT_VEXOK, ++ [0x59] = INAT_MODRM | INAT_VEXOK, ++ [0x5a] = INAT_MODRM | INAT_VEXOK, ++ [0x5b] = INAT_MODRM | INAT_VEXOK, ++ [0x5c] = INAT_MODRM | INAT_VEXOK, ++ [0x5d] = INAT_MODRM | INAT_VEXOK, ++ [0x5e] = INAT_MODRM | INAT_VEXOK, ++ [0x5f] = INAT_MODRM | INAT_VEXOK, ++ [0x60] = INAT_MODRM | INAT_VEXOK, ++ [0x61] = INAT_MODRM | INAT_VEXOK, ++ [0x62] = INAT_MODRM | INAT_VEXOK, ++ [0x63] = INAT_MODRM | INAT_VEXOK, ++ [0x64] = INAT_MODRM | INAT_VEXOK, ++ [0x65] = INAT_MODRM | INAT_VEXOK, ++ [0x66] = INAT_MODRM | INAT_VEXOK, ++ [0x67] = INAT_MODRM | INAT_VEXOK, ++ [0x68] = INAT_MODRM | INAT_VEXOK, ++ [0x69] = INAT_MODRM | INAT_VEXOK, ++ [0x6a] = INAT_MODRM | INAT_VEXOK, ++ [0x6b] = INAT_MODRM | INAT_VEXOK, ++ [0x6c] = INAT_MODRM | INAT_VEXOK, ++ [0x6d] = INAT_MODRM | INAT_VEXOK, ++ [0x6e] = INAT_MODRM | INAT_VEXOK, ++ [0x6f] = INAT_MODRM | INAT_VEXOK, ++ [0x70] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x74] = INAT_MODRM | INAT_VEXOK, ++ [0x75] = INAT_MODRM | INAT_VEXOK, ++ [0x76] = INAT_MODRM | INAT_VEXOK, ++ [0x7c] = INAT_MODRM | INAT_VEXOK, ++ [0x7d] = INAT_MODRM | INAT_VEXOK, ++ [0x7e] = INAT_MODRM | INAT_VEXOK, ++ [0x7f] = INAT_MODRM | INAT_VEXOK, ++ [0xbc] = INAT_MODRM, ++ [0xbd] = INAT_MODRM, ++ [0xc2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0xc4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0xc5] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0xc6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0xd0] = INAT_MODRM | INAT_VEXOK, ++ [0xd1] = INAT_MODRM | INAT_VEXOK, ++ [0xd2] = INAT_MODRM | INAT_VEXOK, ++ [0xd3] = INAT_MODRM | INAT_VEXOK, ++ [0xd4] = INAT_MODRM | INAT_VEXOK, ++ [0xd5] = INAT_MODRM | INAT_VEXOK, ++ [0xd6] = INAT_MODRM | INAT_VEXOK, ++ [0xd7] = INAT_MODRM | INAT_VEXOK, ++ [0xd8] = INAT_MODRM | INAT_VEXOK, ++ [0xd9] = INAT_MODRM | INAT_VEXOK, ++ [0xda] = INAT_MODRM | INAT_VEXOK, ++ [0xdb] = INAT_MODRM | INAT_VEXOK, ++ [0xdc] = INAT_MODRM | INAT_VEXOK, ++ [0xdd] = INAT_MODRM | INAT_VEXOK, ++ [0xde] = INAT_MODRM | INAT_VEXOK, ++ [0xdf] = INAT_MODRM | INAT_VEXOK, ++ [0xe0] = INAT_MODRM | INAT_VEXOK, ++ [0xe1] = INAT_MODRM | INAT_VEXOK, ++ [0xe2] = INAT_MODRM | INAT_VEXOK, ++ [0xe3] = INAT_MODRM | INAT_VEXOK, ++ [0xe4] = INAT_MODRM | INAT_VEXOK, ++ [0xe5] = INAT_MODRM | INAT_VEXOK, ++ [0xe6] = INAT_MODRM | INAT_VEXOK, ++ [0xe7] = INAT_MODRM | INAT_VEXOK, ++ [0xe8] = INAT_MODRM | INAT_VEXOK, ++ [0xe9] = INAT_MODRM | INAT_VEXOK, ++ [0xea] = INAT_MODRM | INAT_VEXOK, ++ [0xeb] = INAT_MODRM | INAT_VEXOK, ++ [0xec] = INAT_MODRM | INAT_VEXOK, ++ [0xed] = INAT_MODRM | INAT_VEXOK, ++ [0xee] = INAT_MODRM | INAT_VEXOK, ++ [0xef] = INAT_MODRM | INAT_VEXOK, ++ [0xf1] = INAT_MODRM | INAT_VEXOK, ++ [0xf2] = INAT_MODRM | INAT_VEXOK, ++ [0xf3] = INAT_MODRM | INAT_VEXOK, ++ [0xf4] = INAT_MODRM | INAT_VEXOK, ++ [0xf5] = INAT_MODRM | INAT_VEXOK, ++ [0xf6] = INAT_MODRM | INAT_VEXOK, ++ [0xf7] = INAT_MODRM | INAT_VEXOK, ++ [0xf8] = INAT_MODRM | INAT_VEXOK, ++ [0xf9] = INAT_MODRM | INAT_VEXOK, ++ [0xfa] = INAT_MODRM | INAT_VEXOK, ++ [0xfb] = INAT_MODRM | INAT_VEXOK, ++ [0xfc] = INAT_MODRM | INAT_VEXOK, ++ [0xfd] = INAT_MODRM | INAT_VEXOK, ++ [0xfe] = INAT_MODRM | INAT_VEXOK, + }; + const insn_attr_t inat_escape_table_1_2[INAT_OPCODE_TABLE_SIZE] = { +- [0x10] = INAT_MODRM | INAT_VEXOK, +- [0x11] = INAT_MODRM | INAT_VEXOK, +- [0x12] = INAT_MODRM | INAT_VEXOK, +- [0x16] = INAT_MODRM | INAT_VEXOK, +- [0x2a] = INAT_MODRM | INAT_VEXOK, +- [0x2c] = INAT_MODRM | INAT_VEXOK, +- [0x2d] = INAT_MODRM | INAT_VEXOK, +- [0x51] = INAT_MODRM | INAT_VEXOK, +- [0x52] = INAT_MODRM | INAT_VEXOK, +- [0x53] = INAT_MODRM | INAT_VEXOK, +- [0x58] = INAT_MODRM | INAT_VEXOK, +- [0x59] = INAT_MODRM | INAT_VEXOK, +- [0x5a] = INAT_MODRM | INAT_VEXOK, +- [0x5b] = INAT_MODRM | INAT_VEXOK, +- [0x5c] = INAT_MODRM | INAT_VEXOK, +- [0x5d] = INAT_MODRM | INAT_VEXOK, +- [0x5e] = INAT_MODRM | INAT_VEXOK, +- [0x5f] = INAT_MODRM | INAT_VEXOK, +- [0x6f] = INAT_MODRM | INAT_VEXOK, +- [0x70] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x7e] = INAT_MODRM | INAT_VEXOK, +- [0x7f] = INAT_MODRM | INAT_VEXOK, +- [0xb8] = INAT_MODRM, +- [0xbc] = INAT_MODRM, +- [0xbd] = INAT_MODRM, +- [0xc2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0xd6] = INAT_MODRM, +- [0xe6] = INAT_MODRM | INAT_VEXOK, ++ [0x10] = INAT_MODRM | INAT_VEXOK, ++ [0x11] = INAT_MODRM | INAT_VEXOK, ++ [0x12] = INAT_MODRM | INAT_VEXOK, ++ [0x16] = INAT_MODRM | INAT_VEXOK, ++ [0x2a] = INAT_MODRM | INAT_VEXOK, ++ [0x2c] = INAT_MODRM | INAT_VEXOK, ++ [0x2d] = INAT_MODRM | INAT_VEXOK, ++ [0x51] = INAT_MODRM | INAT_VEXOK, ++ [0x52] = INAT_MODRM | INAT_VEXOK, ++ [0x53] = INAT_MODRM | INAT_VEXOK, ++ [0x58] = INAT_MODRM | INAT_VEXOK, ++ [0x59] = INAT_MODRM | INAT_VEXOK, ++ [0x5a] = INAT_MODRM | INAT_VEXOK, ++ [0x5b] = INAT_MODRM | INAT_VEXOK, ++ [0x5c] = INAT_MODRM | INAT_VEXOK, ++ [0x5d] = INAT_MODRM | INAT_VEXOK, ++ [0x5e] = INAT_MODRM | INAT_VEXOK, ++ [0x5f] = INAT_MODRM | INAT_VEXOK, ++ [0x6f] = INAT_MODRM | INAT_VEXOK, ++ [0x70] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x7e] = INAT_MODRM | INAT_VEXOK, ++ [0x7f] = INAT_MODRM | INAT_VEXOK, ++ [0xb8] = INAT_MODRM, ++ [0xbc] = INAT_MODRM, ++ [0xbd] = INAT_MODRM, ++ [0xc2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0xd6] = INAT_MODRM, ++ [0xe6] = INAT_MODRM | INAT_VEXOK, + }; + const insn_attr_t inat_escape_table_1_3[INAT_OPCODE_TABLE_SIZE] = { +- [0x10] = INAT_MODRM | INAT_VEXOK, +- [0x11] = INAT_MODRM | INAT_VEXOK, +- [0x12] = INAT_MODRM | INAT_VEXOK, +- [0x2a] = INAT_MODRM | INAT_VEXOK, +- [0x2c] = INAT_MODRM | INAT_VEXOK, +- [0x2d] = INAT_MODRM | INAT_VEXOK, +- [0x51] = INAT_MODRM | INAT_VEXOK, +- [0x58] = INAT_MODRM | INAT_VEXOK, +- [0x59] = INAT_MODRM | INAT_VEXOK, +- [0x5a] = INAT_MODRM | INAT_VEXOK, +- [0x5c] = INAT_MODRM | INAT_VEXOK, +- [0x5d] = INAT_MODRM | INAT_VEXOK, +- [0x5e] = INAT_MODRM | INAT_VEXOK, +- [0x5f] = INAT_MODRM | INAT_VEXOK, +- [0x70] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x7c] = INAT_MODRM | INAT_VEXOK, +- [0x7d] = INAT_MODRM | INAT_VEXOK, +- [0xbc] = INAT_MODRM, +- [0xbd] = INAT_MODRM, +- [0xc2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0xd0] = INAT_MODRM | INAT_VEXOK, +- [0xd6] = INAT_MODRM, +- [0xe6] = INAT_MODRM | INAT_VEXOK, +- [0xf0] = INAT_MODRM | INAT_VEXOK, ++ [0x10] = INAT_MODRM | INAT_VEXOK, ++ [0x11] = INAT_MODRM | INAT_VEXOK, ++ [0x12] = INAT_MODRM | INAT_VEXOK, ++ [0x2a] = INAT_MODRM | INAT_VEXOK, ++ [0x2c] = INAT_MODRM | INAT_VEXOK, ++ [0x2d] = INAT_MODRM | INAT_VEXOK, ++ [0x51] = INAT_MODRM | INAT_VEXOK, ++ [0x58] = INAT_MODRM | INAT_VEXOK, ++ [0x59] = INAT_MODRM | INAT_VEXOK, ++ [0x5a] = INAT_MODRM | INAT_VEXOK, ++ [0x5c] = INAT_MODRM | INAT_VEXOK, ++ [0x5d] = INAT_MODRM | INAT_VEXOK, ++ [0x5e] = INAT_MODRM | INAT_VEXOK, ++ [0x5f] = INAT_MODRM | INAT_VEXOK, ++ [0x70] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x7c] = INAT_MODRM | INAT_VEXOK, ++ [0x7d] = INAT_MODRM | INAT_VEXOK, ++ [0xbc] = INAT_MODRM, ++ [0xbd] = INAT_MODRM, ++ [0xc2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0xd0] = INAT_MODRM | INAT_VEXOK, ++ [0xd6] = INAT_MODRM, ++ [0xe6] = INAT_MODRM | INAT_VEXOK, ++ [0xf0] = INAT_MODRM | INAT_VEXOK, + }; + + /* Table: 3-byte opcode 1 (0x0f 0x38) */ + const insn_attr_t inat_escape_table_2[INAT_OPCODE_TABLE_SIZE] = { +- [0x00] = INAT_MODRM | INAT_VARIANT, +- [0x01] = INAT_MODRM | INAT_VARIANT, +- [0x02] = INAT_MODRM | INAT_VARIANT, +- [0x03] = INAT_MODRM | INAT_VARIANT, +- [0x04] = INAT_MODRM | INAT_VARIANT, +- [0x05] = INAT_MODRM | INAT_VARIANT, +- [0x06] = INAT_MODRM | INAT_VARIANT, +- [0x07] = INAT_MODRM | INAT_VARIANT, +- [0x08] = INAT_MODRM | INAT_VARIANT, +- [0x09] = INAT_MODRM | INAT_VARIANT, +- [0x0a] = INAT_MODRM | INAT_VARIANT, +- [0x0b] = INAT_MODRM | INAT_VARIANT, +- [0x0c] = INAT_VARIANT, +- [0x0d] = INAT_VARIANT, +- [0x0e] = INAT_VARIANT, +- [0x0f] = INAT_VARIANT, +- [0x10] = INAT_VARIANT, +- [0x13] = INAT_VARIANT, +- [0x14] = INAT_VARIANT, +- [0x15] = INAT_VARIANT, +- [0x16] = INAT_VARIANT, +- [0x17] = INAT_VARIANT, +- [0x18] = INAT_VARIANT, +- [0x19] = INAT_VARIANT, +- [0x1a] = INAT_VARIANT, +- [0x1c] = INAT_MODRM | INAT_VARIANT, +- [0x1d] = INAT_MODRM | INAT_VARIANT, +- [0x1e] = INAT_MODRM | INAT_VARIANT, +- [0x20] = INAT_VARIANT, +- [0x21] = INAT_VARIANT, +- [0x22] = INAT_VARIANT, +- [0x23] = INAT_VARIANT, +- [0x24] = INAT_VARIANT, +- [0x25] = INAT_VARIANT, +- [0x28] = INAT_VARIANT, +- [0x29] = INAT_VARIANT, +- [0x2a] = INAT_VARIANT, +- [0x2b] = INAT_VARIANT, +- [0x2c] = INAT_VARIANT, +- [0x2d] = INAT_VARIANT, +- [0x2e] = INAT_VARIANT, +- [0x2f] = INAT_VARIANT, +- [0x30] = INAT_VARIANT, +- [0x31] = INAT_VARIANT, +- [0x32] = INAT_VARIANT, +- [0x33] = INAT_VARIANT, +- [0x34] = INAT_VARIANT, +- [0x35] = INAT_VARIANT, +- [0x36] = INAT_VARIANT, +- [0x37] = INAT_VARIANT, +- [0x38] = INAT_VARIANT, +- [0x39] = INAT_VARIANT, +- [0x3a] = INAT_VARIANT, +- [0x3b] = INAT_VARIANT, +- [0x3c] = INAT_VARIANT, +- [0x3d] = INAT_VARIANT, +- [0x3e] = INAT_VARIANT, +- [0x3f] = INAT_VARIANT, +- [0x40] = INAT_VARIANT, +- [0x41] = INAT_VARIANT, +- [0x45] = INAT_VARIANT, +- [0x46] = INAT_VARIANT, +- [0x47] = INAT_VARIANT, +- [0x58] = INAT_VARIANT, +- [0x59] = INAT_VARIANT, +- [0x5a] = INAT_VARIANT, +- [0x78] = INAT_VARIANT, +- [0x79] = INAT_VARIANT, +- [0x80] = INAT_VARIANT, +- [0x81] = INAT_VARIANT, +- [0x82] = INAT_VARIANT, +- [0x8c] = INAT_VARIANT, +- [0x8e] = INAT_VARIANT, +- [0x90] = INAT_VARIANT, +- [0x91] = INAT_VARIANT, +- [0x92] = INAT_VARIANT, +- [0x93] = INAT_VARIANT, +- [0x96] = INAT_VARIANT, +- [0x97] = INAT_VARIANT, +- [0x98] = INAT_VARIANT, +- [0x99] = INAT_VARIANT, +- [0x9a] = INAT_VARIANT, +- [0x9b] = INAT_VARIANT, +- [0x9c] = INAT_VARIANT, +- [0x9d] = INAT_VARIANT, +- [0x9e] = INAT_VARIANT, +- [0x9f] = INAT_VARIANT, +- [0xa6] = INAT_VARIANT, +- [0xa7] = INAT_VARIANT, +- [0xa8] = INAT_VARIANT, +- [0xa9] = INAT_VARIANT, +- [0xaa] = INAT_VARIANT, +- [0xab] = INAT_VARIANT, +- [0xac] = INAT_VARIANT, +- [0xad] = INAT_VARIANT, +- [0xae] = INAT_VARIANT, +- [0xaf] = INAT_VARIANT, +- [0xb6] = INAT_VARIANT, +- [0xb7] = INAT_VARIANT, +- [0xb8] = INAT_VARIANT, +- [0xb9] = INAT_VARIANT, +- [0xba] = INAT_VARIANT, +- [0xbb] = INAT_VARIANT, +- [0xbc] = INAT_VARIANT, +- [0xbd] = INAT_VARIANT, +- [0xbe] = INAT_VARIANT, +- [0xbf] = INAT_VARIANT, +- [0xdb] = INAT_VARIANT, +- [0xdc] = INAT_VARIANT, +- [0xdd] = INAT_VARIANT, +- [0xde] = INAT_VARIANT, +- [0xdf] = INAT_VARIANT, +- [0xf0] = INAT_MODRM | INAT_MODRM | INAT_VARIANT, +- [0xf1] = INAT_MODRM | INAT_MODRM | INAT_VARIANT, +- [0xf2] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xf3] = INAT_MAKE_GROUP(23), +- [0xf5] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY | INAT_VARIANT, +- [0xf6] = INAT_VARIANT, +- [0xf7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY | INAT_VARIANT, ++ [0x00] = INAT_MODRM | INAT_VARIANT, ++ [0x01] = INAT_MODRM | INAT_VARIANT, ++ [0x02] = INAT_MODRM | INAT_VARIANT, ++ [0x03] = INAT_MODRM | INAT_VARIANT, ++ [0x04] = INAT_MODRM | INAT_VARIANT, ++ [0x05] = INAT_MODRM | INAT_VARIANT, ++ [0x06] = INAT_MODRM | INAT_VARIANT, ++ [0x07] = INAT_MODRM | INAT_VARIANT, ++ [0x08] = INAT_MODRM | INAT_VARIANT, ++ [0x09] = INAT_MODRM | INAT_VARIANT, ++ [0x0a] = INAT_MODRM | INAT_VARIANT, ++ [0x0b] = INAT_MODRM | INAT_VARIANT, ++ [0x0c] = INAT_VARIANT, ++ [0x0d] = INAT_VARIANT, ++ [0x0e] = INAT_VARIANT, ++ [0x0f] = INAT_VARIANT, ++ [0x10] = INAT_VARIANT, ++ [0x13] = INAT_VARIANT, ++ [0x14] = INAT_VARIANT, ++ [0x15] = INAT_VARIANT, ++ [0x16] = INAT_VARIANT, ++ [0x17] = INAT_VARIANT, ++ [0x18] = INAT_VARIANT, ++ [0x19] = INAT_VARIANT, ++ [0x1a] = INAT_VARIANT, ++ [0x1c] = INAT_MODRM | INAT_VARIANT, ++ [0x1d] = INAT_MODRM | INAT_VARIANT, ++ [0x1e] = INAT_MODRM | INAT_VARIANT, ++ [0x20] = INAT_VARIANT, ++ [0x21] = INAT_VARIANT, ++ [0x22] = INAT_VARIANT, ++ [0x23] = INAT_VARIANT, ++ [0x24] = INAT_VARIANT, ++ [0x25] = INAT_VARIANT, ++ [0x28] = INAT_VARIANT, ++ [0x29] = INAT_VARIANT, ++ [0x2a] = INAT_VARIANT, ++ [0x2b] = INAT_VARIANT, ++ [0x2c] = INAT_VARIANT, ++ [0x2d] = INAT_VARIANT, ++ [0x2e] = INAT_VARIANT, ++ [0x2f] = INAT_VARIANT, ++ [0x30] = INAT_VARIANT, ++ [0x31] = INAT_VARIANT, ++ [0x32] = INAT_VARIANT, ++ [0x33] = INAT_VARIANT, ++ [0x34] = INAT_VARIANT, ++ [0x35] = INAT_VARIANT, ++ [0x36] = INAT_VARIANT, ++ [0x37] = INAT_VARIANT, ++ [0x38] = INAT_VARIANT, ++ [0x39] = INAT_VARIANT, ++ [0x3a] = INAT_VARIANT, ++ [0x3b] = INAT_VARIANT, ++ [0x3c] = INAT_VARIANT, ++ [0x3d] = INAT_VARIANT, ++ [0x3e] = INAT_VARIANT, ++ [0x3f] = INAT_VARIANT, ++ [0x40] = INAT_VARIANT, ++ [0x41] = INAT_VARIANT, ++ [0x45] = INAT_VARIANT, ++ [0x46] = INAT_VARIANT, ++ [0x47] = INAT_VARIANT, ++ [0x58] = INAT_VARIANT, ++ [0x59] = INAT_VARIANT, ++ [0x5a] = INAT_VARIANT, ++ [0x78] = INAT_VARIANT, ++ [0x79] = INAT_VARIANT, ++ [0x80] = INAT_VARIANT, ++ [0x81] = INAT_VARIANT, ++ [0x82] = INAT_VARIANT, ++ [0x8c] = INAT_VARIANT, ++ [0x8e] = INAT_VARIANT, ++ [0x90] = INAT_VARIANT, ++ [0x91] = INAT_VARIANT, ++ [0x92] = INAT_VARIANT, ++ [0x93] = INAT_VARIANT, ++ [0x96] = INAT_VARIANT, ++ [0x97] = INAT_VARIANT, ++ [0x98] = INAT_VARIANT, ++ [0x99] = INAT_VARIANT, ++ [0x9a] = INAT_VARIANT, ++ [0x9b] = INAT_VARIANT, ++ [0x9c] = INAT_VARIANT, ++ [0x9d] = INAT_VARIANT, ++ [0x9e] = INAT_VARIANT, ++ [0x9f] = INAT_VARIANT, ++ [0xa6] = INAT_VARIANT, ++ [0xa7] = INAT_VARIANT, ++ [0xa8] = INAT_VARIANT, ++ [0xa9] = INAT_VARIANT, ++ [0xaa] = INAT_VARIANT, ++ [0xab] = INAT_VARIANT, ++ [0xac] = INAT_VARIANT, ++ [0xad] = INAT_VARIANT, ++ [0xae] = INAT_VARIANT, ++ [0xaf] = INAT_VARIANT, ++ [0xb6] = INAT_VARIANT, ++ [0xb7] = INAT_VARIANT, ++ [0xb8] = INAT_VARIANT, ++ [0xb9] = INAT_VARIANT, ++ [0xba] = INAT_VARIANT, ++ [0xbb] = INAT_VARIANT, ++ [0xbc] = INAT_VARIANT, ++ [0xbd] = INAT_VARIANT, ++ [0xbe] = INAT_VARIANT, ++ [0xbf] = INAT_VARIANT, ++ [0xdb] = INAT_VARIANT, ++ [0xdc] = INAT_VARIANT, ++ [0xdd] = INAT_VARIANT, ++ [0xde] = INAT_VARIANT, ++ [0xdf] = INAT_VARIANT, ++ [0xf0] = INAT_MODRM | INAT_MODRM | INAT_VARIANT, ++ [0xf1] = INAT_MODRM | INAT_MODRM | INAT_VARIANT, ++ [0xf2] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xf3] = INAT_MAKE_GROUP(23), ++ [0xf5] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY | INAT_VARIANT, ++ [0xf6] = INAT_VARIANT, ++ [0xf7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY | INAT_VARIANT, + }; + const insn_attr_t inat_escape_table_2_1[INAT_OPCODE_TABLE_SIZE] = { +- [0x00] = INAT_MODRM | INAT_VEXOK, +- [0x01] = INAT_MODRM | INAT_VEXOK, +- [0x02] = INAT_MODRM | INAT_VEXOK, +- [0x03] = INAT_MODRM | INAT_VEXOK, +- [0x04] = INAT_MODRM | INAT_VEXOK, +- [0x05] = INAT_MODRM | INAT_VEXOK, +- [0x06] = INAT_MODRM | INAT_VEXOK, +- [0x07] = INAT_MODRM | INAT_VEXOK, +- [0x08] = INAT_MODRM | INAT_VEXOK, +- [0x09] = INAT_MODRM | INAT_VEXOK, +- [0x0a] = INAT_MODRM | INAT_VEXOK, +- [0x0b] = INAT_MODRM | INAT_VEXOK, +- [0x0c] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x0d] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x0e] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x0f] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x10] = INAT_MODRM, +- [0x13] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x14] = INAT_MODRM, +- [0x15] = INAT_MODRM, +- [0x16] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x17] = INAT_MODRM | INAT_VEXOK, +- [0x18] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x19] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x1a] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x1c] = INAT_MODRM | INAT_VEXOK, +- [0x1d] = INAT_MODRM | INAT_VEXOK, +- [0x1e] = INAT_MODRM | INAT_VEXOK, +- [0x20] = INAT_MODRM | INAT_VEXOK, +- [0x21] = INAT_MODRM | INAT_VEXOK, +- [0x22] = INAT_MODRM | INAT_VEXOK, +- [0x23] = INAT_MODRM | INAT_VEXOK, +- [0x24] = INAT_MODRM | INAT_VEXOK, +- [0x25] = INAT_MODRM | INAT_VEXOK, +- [0x28] = INAT_MODRM | INAT_VEXOK, +- [0x29] = INAT_MODRM | INAT_VEXOK, +- [0x2a] = INAT_MODRM | INAT_VEXOK, +- [0x2b] = INAT_MODRM | INAT_VEXOK, +- [0x2c] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x2d] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x2e] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x2f] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x30] = INAT_MODRM | INAT_VEXOK, +- [0x31] = INAT_MODRM | INAT_VEXOK, +- [0x32] = INAT_MODRM | INAT_VEXOK, +- [0x33] = INAT_MODRM | INAT_VEXOK, +- [0x34] = INAT_MODRM | INAT_VEXOK, +- [0x35] = INAT_MODRM | INAT_VEXOK, +- [0x36] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x37] = INAT_MODRM | INAT_VEXOK, +- [0x38] = INAT_MODRM | INAT_VEXOK, +- [0x39] = INAT_MODRM | INAT_VEXOK, +- [0x3a] = INAT_MODRM | INAT_VEXOK, +- [0x3b] = INAT_MODRM | INAT_VEXOK, +- [0x3c] = INAT_MODRM | INAT_VEXOK, +- [0x3d] = INAT_MODRM | INAT_VEXOK, +- [0x3e] = INAT_MODRM | INAT_VEXOK, +- [0x3f] = INAT_MODRM | INAT_VEXOK, +- [0x40] = INAT_MODRM | INAT_VEXOK, +- [0x41] = INAT_MODRM | INAT_VEXOK, +- [0x45] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x46] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x47] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x58] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x59] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x5a] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x78] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x79] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x80] = INAT_MODRM, +- [0x81] = INAT_MODRM, +- [0x82] = INAT_MODRM, +- [0x8c] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x8e] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x90] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x91] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x92] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x93] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x96] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x97] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x98] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x99] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x9a] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x9b] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x9c] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x9d] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x9e] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x9f] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xa6] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xa7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xa8] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xa9] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xaa] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xab] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xac] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xad] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xae] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xaf] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xb6] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xb7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xb8] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xb9] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xba] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xbb] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xbc] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xbd] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xbe] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xbf] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xdb] = INAT_MODRM | INAT_VEXOK, +- [0xdc] = INAT_MODRM | INAT_VEXOK, +- [0xdd] = INAT_MODRM | INAT_VEXOK, +- [0xde] = INAT_MODRM | INAT_VEXOK, +- [0xdf] = INAT_MODRM | INAT_VEXOK, +- [0xf0] = INAT_MODRM, +- [0xf1] = INAT_MODRM, +- [0xf6] = INAT_MODRM, +- [0xf7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x00] = INAT_MODRM | INAT_VEXOK, ++ [0x01] = INAT_MODRM | INAT_VEXOK, ++ [0x02] = INAT_MODRM | INAT_VEXOK, ++ [0x03] = INAT_MODRM | INAT_VEXOK, ++ [0x04] = INAT_MODRM | INAT_VEXOK, ++ [0x05] = INAT_MODRM | INAT_VEXOK, ++ [0x06] = INAT_MODRM | INAT_VEXOK, ++ [0x07] = INAT_MODRM | INAT_VEXOK, ++ [0x08] = INAT_MODRM | INAT_VEXOK, ++ [0x09] = INAT_MODRM | INAT_VEXOK, ++ [0x0a] = INAT_MODRM | INAT_VEXOK, ++ [0x0b] = INAT_MODRM | INAT_VEXOK, ++ [0x0c] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x0d] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x0e] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x0f] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x10] = INAT_MODRM, ++ [0x13] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x14] = INAT_MODRM, ++ [0x15] = INAT_MODRM, ++ [0x16] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x17] = INAT_MODRM | INAT_VEXOK, ++ [0x18] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x19] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x1a] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x1c] = INAT_MODRM | INAT_VEXOK, ++ [0x1d] = INAT_MODRM | INAT_VEXOK, ++ [0x1e] = INAT_MODRM | INAT_VEXOK, ++ [0x20] = INAT_MODRM | INAT_VEXOK, ++ [0x21] = INAT_MODRM | INAT_VEXOK, ++ [0x22] = INAT_MODRM | INAT_VEXOK, ++ [0x23] = INAT_MODRM | INAT_VEXOK, ++ [0x24] = INAT_MODRM | INAT_VEXOK, ++ [0x25] = INAT_MODRM | INAT_VEXOK, ++ [0x28] = INAT_MODRM | INAT_VEXOK, ++ [0x29] = INAT_MODRM | INAT_VEXOK, ++ [0x2a] = INAT_MODRM | INAT_VEXOK, ++ [0x2b] = INAT_MODRM | INAT_VEXOK, ++ [0x2c] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x2d] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x2e] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x2f] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x30] = INAT_MODRM | INAT_VEXOK, ++ [0x31] = INAT_MODRM | INAT_VEXOK, ++ [0x32] = INAT_MODRM | INAT_VEXOK, ++ [0x33] = INAT_MODRM | INAT_VEXOK, ++ [0x34] = INAT_MODRM | INAT_VEXOK, ++ [0x35] = INAT_MODRM | INAT_VEXOK, ++ [0x36] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x37] = INAT_MODRM | INAT_VEXOK, ++ [0x38] = INAT_MODRM | INAT_VEXOK, ++ [0x39] = INAT_MODRM | INAT_VEXOK, ++ [0x3a] = INAT_MODRM | INAT_VEXOK, ++ [0x3b] = INAT_MODRM | INAT_VEXOK, ++ [0x3c] = INAT_MODRM | INAT_VEXOK, ++ [0x3d] = INAT_MODRM | INAT_VEXOK, ++ [0x3e] = INAT_MODRM | INAT_VEXOK, ++ [0x3f] = INAT_MODRM | INAT_VEXOK, ++ [0x40] = INAT_MODRM | INAT_VEXOK, ++ [0x41] = INAT_MODRM | INAT_VEXOK, ++ [0x45] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x46] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x47] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x58] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x59] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x5a] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x78] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x79] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x80] = INAT_MODRM, ++ [0x81] = INAT_MODRM, ++ [0x82] = INAT_MODRM, ++ [0x8c] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x8e] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x90] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x91] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x92] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x93] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x96] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x97] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x98] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x99] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x9a] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x9b] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x9c] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x9d] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x9e] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x9f] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xa6] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xa7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xa8] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xa9] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xaa] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xab] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xac] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xad] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xae] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xaf] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xb6] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xb7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xb8] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xb9] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xba] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xbb] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xbc] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xbd] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xbe] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xbf] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xdb] = INAT_MODRM | INAT_VEXOK, ++ [0xdc] = INAT_MODRM | INAT_VEXOK, ++ [0xdd] = INAT_MODRM | INAT_VEXOK, ++ [0xde] = INAT_MODRM | INAT_VEXOK, ++ [0xdf] = INAT_MODRM | INAT_VEXOK, ++ [0xf0] = INAT_MODRM, ++ [0xf1] = INAT_MODRM, ++ [0xf6] = INAT_MODRM, ++ [0xf7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, + }; + const insn_attr_t inat_escape_table_2_2[INAT_OPCODE_TABLE_SIZE] = { +- [0xf5] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xf6] = INAT_MODRM, +- [0xf7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xf5] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xf6] = INAT_MODRM, ++ [0xf7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, + }; + const insn_attr_t inat_escape_table_2_3[INAT_OPCODE_TABLE_SIZE] = { +- [0xf0] = INAT_MODRM | INAT_MODRM, +- [0xf1] = INAT_MODRM | INAT_MODRM, +- [0xf5] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xf6] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0xf7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xf0] = INAT_MODRM | INAT_MODRM, ++ [0xf1] = INAT_MODRM | INAT_MODRM, ++ [0xf5] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xf6] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xf7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, + }; + + /* Table: 3-byte opcode 2 (0x0f 0x3a) */ + const insn_attr_t inat_escape_table_3[INAT_OPCODE_TABLE_SIZE] = { +- [0x00] = INAT_VARIANT, +- [0x01] = INAT_VARIANT, +- [0x02] = INAT_VARIANT, +- [0x04] = INAT_VARIANT, +- [0x05] = INAT_VARIANT, +- [0x06] = INAT_VARIANT, +- [0x08] = INAT_VARIANT, +- [0x09] = INAT_VARIANT, +- [0x0a] = INAT_VARIANT, +- [0x0b] = INAT_VARIANT, +- [0x0c] = INAT_VARIANT, +- [0x0d] = INAT_VARIANT, +- [0x0e] = INAT_VARIANT, +- [0x0f] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, +- [0x14] = INAT_VARIANT, +- [0x15] = INAT_VARIANT, +- [0x16] = INAT_VARIANT, +- [0x17] = INAT_VARIANT, +- [0x18] = INAT_VARIANT, +- [0x19] = INAT_VARIANT, +- [0x1d] = INAT_VARIANT, +- [0x20] = INAT_VARIANT, +- [0x21] = INAT_VARIANT, +- [0x22] = INAT_VARIANT, +- [0x38] = INAT_VARIANT, +- [0x39] = INAT_VARIANT, +- [0x40] = INAT_VARIANT, +- [0x41] = INAT_VARIANT, +- [0x42] = INAT_VARIANT, +- [0x44] = INAT_VARIANT, +- [0x46] = INAT_VARIANT, +- [0x4a] = INAT_VARIANT, +- [0x4b] = INAT_VARIANT, +- [0x4c] = INAT_VARIANT, +- [0x60] = INAT_VARIANT, +- [0x61] = INAT_VARIANT, +- [0x62] = INAT_VARIANT, +- [0x63] = INAT_VARIANT, +- [0xdf] = INAT_VARIANT, +- [0xf0] = INAT_VARIANT, ++ [0x00] = INAT_VARIANT, ++ [0x01] = INAT_VARIANT, ++ [0x02] = INAT_VARIANT, ++ [0x04] = INAT_VARIANT, ++ [0x05] = INAT_VARIANT, ++ [0x06] = INAT_VARIANT, ++ [0x08] = INAT_VARIANT, ++ [0x09] = INAT_VARIANT, ++ [0x0a] = INAT_VARIANT, ++ [0x0b] = INAT_VARIANT, ++ [0x0c] = INAT_VARIANT, ++ [0x0d] = INAT_VARIANT, ++ [0x0e] = INAT_VARIANT, ++ [0x0f] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, ++ [0x14] = INAT_VARIANT, ++ [0x15] = INAT_VARIANT, ++ [0x16] = INAT_VARIANT, ++ [0x17] = INAT_VARIANT, ++ [0x18] = INAT_VARIANT, ++ [0x19] = INAT_VARIANT, ++ [0x1d] = INAT_VARIANT, ++ [0x20] = INAT_VARIANT, ++ [0x21] = INAT_VARIANT, ++ [0x22] = INAT_VARIANT, ++ [0x38] = INAT_VARIANT, ++ [0x39] = INAT_VARIANT, ++ [0x40] = INAT_VARIANT, ++ [0x41] = INAT_VARIANT, ++ [0x42] = INAT_VARIANT, ++ [0x44] = INAT_VARIANT, ++ [0x46] = INAT_VARIANT, ++ [0x4a] = INAT_VARIANT, ++ [0x4b] = INAT_VARIANT, ++ [0x4c] = INAT_VARIANT, ++ [0x60] = INAT_VARIANT, ++ [0x61] = INAT_VARIANT, ++ [0x62] = INAT_VARIANT, ++ [0x63] = INAT_VARIANT, ++ [0xdf] = INAT_VARIANT, ++ [0xf0] = INAT_VARIANT, + }; + const insn_attr_t inat_escape_table_3_1[INAT_OPCODE_TABLE_SIZE] = { +- [0x00] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x01] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x02] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x04] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x05] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x06] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x08] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x09] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x0a] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x0b] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x0c] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x0d] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x0e] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x0f] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x14] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x15] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x16] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x17] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x18] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x19] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x1d] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x20] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x21] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x22] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x38] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x39] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x40] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x41] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x42] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x44] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x46] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x4a] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x4b] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x4c] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x60] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x61] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x62] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x63] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0xdf] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x00] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x01] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x02] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x04] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x05] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x06] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x08] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x09] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x0a] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x0b] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x0c] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x0d] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x0e] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x0f] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x14] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x15] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x16] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x17] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x18] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x19] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x1d] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x20] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x21] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x22] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x38] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x39] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x40] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x41] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x42] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x44] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x46] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x4a] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x4b] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x4c] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x60] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x61] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x62] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x63] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0xdf] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, + }; + const insn_attr_t inat_escape_table_3_3[INAT_OPCODE_TABLE_SIZE] = { +- [0xf0] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0xf0] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, + }; + + /* GrpTable: Grp1 */ +@@ -937,159 +937,159 @@ const insn_attr_t inat_escape_table_3_3[INAT_OPCODE_TABLE_SIZE] = { + + /* GrpTable: Grp3_1 */ + const insn_attr_t inat_group_table_6[INAT_GROUP_TABLE_SIZE] = { +- [0x0] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, +- [0x2] = INAT_MODRM, +- [0x3] = INAT_MODRM, +- [0x4] = INAT_MODRM, +- [0x5] = INAT_MODRM, +- [0x6] = INAT_MODRM, +- [0x7] = INAT_MODRM, ++ [0x0] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, ++ [0x2] = INAT_MODRM, ++ [0x3] = INAT_MODRM, ++ [0x4] = INAT_MODRM, ++ [0x5] = INAT_MODRM, ++ [0x6] = INAT_MODRM, ++ [0x7] = INAT_MODRM, + }; + + /* GrpTable: Grp3_2 */ + const insn_attr_t inat_group_table_7[INAT_GROUP_TABLE_SIZE] = { +- [0x0] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_MODRM, +- [0x2] = INAT_MODRM, +- [0x3] = INAT_MODRM, +- [0x4] = INAT_MODRM, +- [0x5] = INAT_MODRM, +- [0x6] = INAT_MODRM, +- [0x7] = INAT_MODRM, ++ [0x0] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_MODRM, ++ [0x2] = INAT_MODRM, ++ [0x3] = INAT_MODRM, ++ [0x4] = INAT_MODRM, ++ [0x5] = INAT_MODRM, ++ [0x6] = INAT_MODRM, ++ [0x7] = INAT_MODRM, + }; + + /* GrpTable: Grp4 */ + const insn_attr_t inat_group_table_8[INAT_GROUP_TABLE_SIZE] = { +- [0x0] = INAT_MODRM, +- [0x1] = INAT_MODRM, ++ [0x0] = INAT_MODRM, ++ [0x1] = INAT_MODRM, + }; + + /* GrpTable: Grp5 */ + const insn_attr_t inat_group_table_9[INAT_GROUP_TABLE_SIZE] = { +- [0x0] = INAT_MODRM, +- [0x1] = INAT_MODRM, +- [0x2] = INAT_MODRM | INAT_FORCE64, +- [0x3] = INAT_MODRM, +- [0x4] = INAT_MODRM | INAT_FORCE64, +- [0x5] = INAT_MODRM, +- [0x6] = INAT_MODRM | INAT_FORCE64, ++ [0x0] = INAT_MODRM, ++ [0x1] = INAT_MODRM, ++ [0x2] = INAT_MODRM | INAT_FORCE64, ++ [0x3] = INAT_MODRM, ++ [0x4] = INAT_MODRM | INAT_FORCE64, ++ [0x5] = INAT_MODRM, ++ [0x6] = INAT_MODRM | INAT_FORCE64, + }; + + /* GrpTable: Grp6 */ + const insn_attr_t inat_group_table_10[INAT_GROUP_TABLE_SIZE] = { +- [0x0] = INAT_MODRM, +- [0x1] = INAT_MODRM, +- [0x2] = INAT_MODRM, +- [0x3] = INAT_MODRM, +- [0x4] = INAT_MODRM, +- [0x5] = INAT_MODRM, ++ [0x0] = INAT_MODRM, ++ [0x1] = INAT_MODRM, ++ [0x2] = INAT_MODRM, ++ [0x3] = INAT_MODRM, ++ [0x4] = INAT_MODRM, ++ [0x5] = INAT_MODRM, + }; + + /* GrpTable: Grp7 */ + const insn_attr_t inat_group_table_11[INAT_GROUP_TABLE_SIZE] = { +- [0x0] = INAT_MODRM, +- [0x1] = INAT_MODRM, +- [0x2] = INAT_MODRM, +- [0x3] = INAT_MODRM, +- [0x4] = INAT_MODRM, +- [0x6] = INAT_MODRM, +- [0x7] = INAT_MODRM, ++ [0x0] = INAT_MODRM, ++ [0x1] = INAT_MODRM, ++ [0x2] = INAT_MODRM, ++ [0x3] = INAT_MODRM, ++ [0x4] = INAT_MODRM, ++ [0x6] = INAT_MODRM, ++ [0x7] = INAT_MODRM, + }; + + /* GrpTable: Grp8 */ + + /* GrpTable: Grp9 */ + const insn_attr_t inat_group_table_22[INAT_GROUP_TABLE_SIZE] = { +- [0x1] = INAT_MODRM, +- [0x6] = INAT_MODRM | INAT_MODRM | INAT_VARIANT, +- [0x7] = INAT_MODRM | INAT_MODRM | INAT_VARIANT, ++ [0x1] = INAT_MODRM, ++ [0x6] = INAT_MODRM | INAT_MODRM | INAT_VARIANT, ++ [0x7] = INAT_MODRM | INAT_MODRM | INAT_VARIANT, + }; + const insn_attr_t inat_group_table_22_1[INAT_GROUP_TABLE_SIZE] = { +- [0x6] = INAT_MODRM, ++ [0x6] = INAT_MODRM, + }; + const insn_attr_t inat_group_table_22_2[INAT_GROUP_TABLE_SIZE] = { +- [0x6] = INAT_MODRM, +- [0x7] = INAT_MODRM, ++ [0x6] = INAT_MODRM, ++ [0x7] = INAT_MODRM, + }; + + /* GrpTable: Grp10 */ + + /* GrpTable: Grp11A */ + const insn_attr_t inat_group_table_4[INAT_GROUP_TABLE_SIZE] = { +- [0x0] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, +- [0x7] = INAT_MAKE_IMM(INAT_IMM_BYTE), ++ [0x0] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, ++ [0x7] = INAT_MAKE_IMM(INAT_IMM_BYTE), + }; + + /* GrpTable: Grp11B */ + const insn_attr_t inat_group_table_5[INAT_GROUP_TABLE_SIZE] = { +- [0x0] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_MODRM, +- [0x7] = INAT_MAKE_IMM(INAT_IMM_VWORD32), ++ [0x0] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_MODRM, ++ [0x7] = INAT_MAKE_IMM(INAT_IMM_VWORD32), + }; + + /* GrpTable: Grp12 */ + const insn_attr_t inat_group_table_14[INAT_GROUP_TABLE_SIZE] = { +- [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, +- [0x4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, +- [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, ++ [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, ++ [0x4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, ++ [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, + }; + const insn_attr_t inat_group_table_14_1[INAT_GROUP_TABLE_SIZE] = { +- [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, + }; + + /* GrpTable: Grp13 */ + const insn_attr_t inat_group_table_15[INAT_GROUP_TABLE_SIZE] = { +- [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, +- [0x4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, +- [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, ++ [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, ++ [0x4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, ++ [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, + }; + const insn_attr_t inat_group_table_15_1[INAT_GROUP_TABLE_SIZE] = { +- [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, + }; + + /* GrpTable: Grp14 */ + const insn_attr_t inat_group_table_16[INAT_GROUP_TABLE_SIZE] = { +- [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, +- [0x3] = INAT_VARIANT, +- [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, +- [0x7] = INAT_VARIANT, ++ [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, ++ [0x3] = INAT_VARIANT, ++ [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, ++ [0x7] = INAT_VARIANT, + }; + const insn_attr_t inat_group_table_16_1[INAT_GROUP_TABLE_SIZE] = { +- [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x3] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, +- [0x7] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x3] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, ++ [0x7] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, + }; + + /* GrpTable: Grp15 */ + const insn_attr_t inat_group_table_19[INAT_GROUP_TABLE_SIZE] = { +- [0x0] = INAT_VARIANT, +- [0x1] = INAT_VARIANT, +- [0x2] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, +- [0x3] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x0] = INAT_VARIANT, ++ [0x1] = INAT_VARIANT, ++ [0x2] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, ++ [0x3] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, + }; + const insn_attr_t inat_group_table_19_2[INAT_GROUP_TABLE_SIZE] = { +- [0x0] = INAT_MODRM, +- [0x1] = INAT_MODRM, +- [0x2] = INAT_MODRM, +- [0x3] = INAT_MODRM, ++ [0x0] = INAT_MODRM, ++ [0x1] = INAT_MODRM, ++ [0x2] = INAT_MODRM, ++ [0x3] = INAT_MODRM, + }; + + /* GrpTable: Grp16 */ + const insn_attr_t inat_group_table_13[INAT_GROUP_TABLE_SIZE] = { +- [0x0] = INAT_MODRM, +- [0x1] = INAT_MODRM, +- [0x2] = INAT_MODRM, +- [0x3] = INAT_MODRM, ++ [0x0] = INAT_MODRM, ++ [0x1] = INAT_MODRM, ++ [0x2] = INAT_MODRM, ++ [0x3] = INAT_MODRM, + }; + + /* GrpTable: Grp17 */ + const insn_attr_t inat_group_table_23[INAT_GROUP_TABLE_SIZE] = { +- [0x1] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x2] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, +- [0x3] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x1] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x2] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, ++ [0x3] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, + }; + + /* GrpTable: GrpP */ +@@ -1100,57 +1100,57 @@ const insn_attr_t inat_group_table_23[INAT_GROUP_TABLE_SIZE] = { + + /* Escape opcode map array */ + const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1][INAT_LSTPFX_MAX + 1] = { +- [1][0] = inat_escape_table_1, +- [1][1] = inat_escape_table_1_1, +- [1][2] = inat_escape_table_1_2, +- [1][3] = inat_escape_table_1_3, +- [2][0] = inat_escape_table_2, +- [2][1] = inat_escape_table_2_1, +- [2][2] = inat_escape_table_2_2, +- [2][3] = inat_escape_table_2_3, +- [3][0] = inat_escape_table_3, +- [3][1] = inat_escape_table_3_1, +- [3][3] = inat_escape_table_3_3, ++ [1][0] = inat_escape_table_1, ++ [1][1] = inat_escape_table_1_1, ++ [1][2] = inat_escape_table_1_2, ++ [1][3] = inat_escape_table_1_3, ++ [2][0] = inat_escape_table_2, ++ [2][1] = inat_escape_table_2_1, ++ [2][2] = inat_escape_table_2_2, ++ [2][3] = inat_escape_table_2_3, ++ [3][0] = inat_escape_table_3, ++ [3][1] = inat_escape_table_3_1, ++ [3][3] = inat_escape_table_3_3, + }; + + /* Group opcode map array */ + const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1][INAT_LSTPFX_MAX + 1] = { +- [4][0] = inat_group_table_4, +- [5][0] = inat_group_table_5, +- [6][0] = inat_group_table_6, +- [7][0] = inat_group_table_7, +- [8][0] = inat_group_table_8, +- [9][0] = inat_group_table_9, +- [10][0] = inat_group_table_10, +- [11][0] = inat_group_table_11, +- [13][0] = inat_group_table_13, +- [14][0] = inat_group_table_14, +- [14][1] = inat_group_table_14_1, +- [15][0] = inat_group_table_15, +- [15][1] = inat_group_table_15_1, +- [16][0] = inat_group_table_16, +- [16][1] = inat_group_table_16_1, +- [19][0] = inat_group_table_19, +- [19][2] = inat_group_table_19_2, +- [22][0] = inat_group_table_22, +- [22][1] = inat_group_table_22_1, +- [22][2] = inat_group_table_22_2, +- [23][0] = inat_group_table_23, ++ [4][0] = inat_group_table_4, ++ [5][0] = inat_group_table_5, ++ [6][0] = inat_group_table_6, ++ [7][0] = inat_group_table_7, ++ [8][0] = inat_group_table_8, ++ [9][0] = inat_group_table_9, ++ [10][0] = inat_group_table_10, ++ [11][0] = inat_group_table_11, ++ [13][0] = inat_group_table_13, ++ [14][0] = inat_group_table_14, ++ [14][1] = inat_group_table_14_1, ++ [15][0] = inat_group_table_15, ++ [15][1] = inat_group_table_15_1, ++ [16][0] = inat_group_table_16, ++ [16][1] = inat_group_table_16_1, ++ [19][0] = inat_group_table_19, ++ [19][2] = inat_group_table_19_2, ++ [22][0] = inat_group_table_22, ++ [22][1] = inat_group_table_22_1, ++ [22][2] = inat_group_table_22_2, ++ [23][0] = inat_group_table_23, + }; + + /* AVX opcode map array */ + const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1][INAT_LSTPFX_MAX + 1] = { +- [1][0] = inat_escape_table_1, +- [1][1] = inat_escape_table_1_1, +- [1][2] = inat_escape_table_1_2, +- [1][3] = inat_escape_table_1_3, +- [2][0] = inat_escape_table_2, +- [2][1] = inat_escape_table_2_1, +- [2][2] = inat_escape_table_2_2, +- [2][3] = inat_escape_table_2_3, +- [3][0] = inat_escape_table_3, +- [3][1] = inat_escape_table_3_1, +- [3][3] = inat_escape_table_3_3, ++ [1][0] = inat_escape_table_1, ++ [1][1] = inat_escape_table_1_1, ++ [1][2] = inat_escape_table_1_2, ++ [1][3] = inat_escape_table_1_3, ++ [2][0] = inat_escape_table_2, ++ [2][1] = inat_escape_table_2_1, ++ [2][2] = inat_escape_table_2_2, ++ [2][3] = inat_escape_table_2_3, ++ [3][0] = inat_escape_table_3, ++ [3][1] = inat_escape_table_3_1, ++ [3][3] = inat_escape_table_3_3, + }; + + #endif +diff --git a/upatch-diff/insn/asm/inat.h b/upatch-diff/insn/asm/inat.h +index 4ab84d6..887ddfe 100644 +--- a/upatch-diff/insn/asm/inat.h ++++ b/upatch-diff/insn/asm/inat.h +@@ -33,191 +33,189 @@ + #define INAT_GROUP_TABLE_SIZE 8 + + /* Legacy last prefixes */ +-#define INAT_PFX_OPNDSZ 1 /* 0x66 */ /* LPFX1 */ +-#define INAT_PFX_REPE 2 /* 0xF3 */ /* LPFX2 */ +-#define INAT_PFX_REPNE 3 /* 0xF2 */ /* LPFX3 */ ++#define INAT_PFX_OPNDSZ 1 /* 0x66 */ /* LPFX1 */ ++#define INAT_PFX_REPE 2 /* 0xF3 */ /* LPFX2 */ ++#define INAT_PFX_REPNE 3 /* 0xF2 */ /* LPFX3 */ + /* Other Legacy prefixes */ +-#define INAT_PFX_LOCK 4 /* 0xF0 */ +-#define INAT_PFX_CS 5 /* 0x2E */ +-#define INAT_PFX_DS 6 /* 0x3E */ +-#define INAT_PFX_ES 7 /* 0x26 */ +-#define INAT_PFX_FS 8 /* 0x64 */ +-#define INAT_PFX_GS 9 /* 0x65 */ +-#define INAT_PFX_SS 10 /* 0x36 */ +-#define INAT_PFX_ADDRSZ 11 /* 0x67 */ ++#define INAT_PFX_LOCK 4 /* 0xF0 */ ++#define INAT_PFX_CS 5 /* 0x2E */ ++#define INAT_PFX_DS 6 /* 0x3E */ ++#define INAT_PFX_ES 7 /* 0x26 */ ++#define INAT_PFX_FS 8 /* 0x64 */ ++#define INAT_PFX_GS 9 /* 0x65 */ ++#define INAT_PFX_SS 10 /* 0x36 */ ++#define INAT_PFX_ADDRSZ 11 /* 0x67 */ + /* x86-64 REX prefix */ +-#define INAT_PFX_REX 12 /* 0x4X */ ++#define INAT_PFX_REX 12 /* 0x4X */ + /* AVX VEX prefixes */ +-#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */ +-#define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */ ++#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */ ++#define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */ + +-#define INAT_LSTPFX_MAX 3 +-#define INAT_LGCPFX_MAX 11 ++#define INAT_LSTPFX_MAX 3 ++#define INAT_LGCPFX_MAX 11 + + /* Immediate size */ +-#define INAT_IMM_BYTE 1 +-#define INAT_IMM_WORD 2 +-#define INAT_IMM_DWORD 3 +-#define INAT_IMM_QWORD 4 +-#define INAT_IMM_PTR 5 +-#define INAT_IMM_VWORD32 6 +-#define INAT_IMM_VWORD 7 ++#define INAT_IMM_BYTE 1 ++#define INAT_IMM_WORD 2 ++#define INAT_IMM_DWORD 3 ++#define INAT_IMM_QWORD 4 ++#define INAT_IMM_PTR 5 ++#define INAT_IMM_VWORD32 6 ++#define INAT_IMM_VWORD 7 + + /* Legacy prefix */ +-#define INAT_PFX_OFFS 0 +-#define INAT_PFX_BITS 4 +-#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1) +-#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS) ++#define INAT_PFX_OFFS 0 ++#define INAT_PFX_BITS 4 ++#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1) ++#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS) + /* Escape opcodes */ +-#define INAT_ESC_OFFS (INAT_PFX_OFFS + INAT_PFX_BITS) +-#define INAT_ESC_BITS 2 +-#define INAT_ESC_MAX ((1 << INAT_ESC_BITS) - 1) +-#define INAT_ESC_MASK (INAT_ESC_MAX << INAT_ESC_OFFS) ++#define INAT_ESC_OFFS (INAT_PFX_OFFS + INAT_PFX_BITS) ++#define INAT_ESC_BITS 2 ++#define INAT_ESC_MAX ((1 << INAT_ESC_BITS) - 1) ++#define INAT_ESC_MASK (INAT_ESC_MAX << INAT_ESC_OFFS) + /* Group opcodes (1-16) */ +-#define INAT_GRP_OFFS (INAT_ESC_OFFS + INAT_ESC_BITS) +-#define INAT_GRP_BITS 5 +-#define INAT_GRP_MAX ((1 << INAT_GRP_BITS) - 1) +-#define INAT_GRP_MASK (INAT_GRP_MAX << INAT_GRP_OFFS) ++#define INAT_GRP_OFFS (INAT_ESC_OFFS + INAT_ESC_BITS) ++#define INAT_GRP_BITS 5 ++#define INAT_GRP_MAX ((1 << INAT_GRP_BITS) - 1) ++#define INAT_GRP_MASK (INAT_GRP_MAX << INAT_GRP_OFFS) + /* Immediates */ +-#define INAT_IMM_OFFS (INAT_GRP_OFFS + INAT_GRP_BITS) +-#define INAT_IMM_BITS 3 +-#define INAT_IMM_MASK (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS) ++#define INAT_IMM_OFFS (INAT_GRP_OFFS + INAT_GRP_BITS) ++#define INAT_IMM_BITS 3 ++#define INAT_IMM_MASK (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS) + /* Flags */ +-#define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS) +-#define INAT_MODRM (1 << (INAT_FLAG_OFFS)) +-#define INAT_FORCE64 (1 << (INAT_FLAG_OFFS + 1)) +-#define INAT_SCNDIMM (1 << (INAT_FLAG_OFFS + 2)) +-#define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3)) +-#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) +-#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) +-#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) ++#define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS) ++#define INAT_MODRM (1 << (INAT_FLAG_OFFS)) ++#define INAT_FORCE64 (1 << (INAT_FLAG_OFFS + 1)) ++#define INAT_SCNDIMM (1 << (INAT_FLAG_OFFS + 2)) ++#define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3)) ++#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) ++#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) ++#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) + /* Attribute making macros for attribute tables */ +-#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS) +-#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS) +-#define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM) +-#define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS) ++#define INAT_MAKE_PREFIX(pfx) ((pfx) << INAT_PFX_OFFS) ++#define INAT_MAKE_ESCAPE(esc) ((esc) << INAT_ESC_OFFS) ++#define INAT_MAKE_GROUP(grp) (((grp) << INAT_GRP_OFFS) | INAT_MODRM) ++#define INAT_MAKE_IMM(imm) ((imm) << INAT_IMM_OFFS) + + /* Attribute search APIs */ + extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); + extern int inat_get_last_prefix_id(insn_byte_t last_pfx); + extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, +- int lpfx_id, +- insn_attr_t esc_attr); ++ int lpfx_id, insn_attr_t esc_attr); + extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm, +- int lpfx_id, +- insn_attr_t esc_attr); ++ int lpfx_id, insn_attr_t esc_attr); + extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, +- insn_byte_t vex_m, +- insn_byte_t vex_pp); ++ insn_byte_t vex_m, insn_byte_t vex_pp); + + /* Attribute checking functions */ + static inline int inat_is_legacy_prefix(insn_attr_t attr) + { +- attr &= INAT_PFX_MASK; +- return attr && attr <= INAT_LGCPFX_MAX; ++ attr &= INAT_PFX_MASK; ++ return attr && attr <= INAT_LGCPFX_MAX; + } + + static inline int inat_is_address_size_prefix(insn_attr_t attr) + { +- return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ; ++ return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ; + } + + static inline int inat_is_operand_size_prefix(insn_attr_t attr) + { +- return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ; ++ return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ; + } + + static inline int inat_is_rex_prefix(insn_attr_t attr) + { +- return (attr & INAT_PFX_MASK) == INAT_PFX_REX; ++ return (attr & INAT_PFX_MASK) == INAT_PFX_REX; + } + + static inline int inat_last_prefix_id(insn_attr_t attr) + { +- if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX) +- return 0; +- else +- return attr & INAT_PFX_MASK; ++ if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX) { ++ return 0; ++ } else { ++ return attr & INAT_PFX_MASK; ++ } + } + + static inline int inat_is_vex_prefix(insn_attr_t attr) + { +- attr &= INAT_PFX_MASK; +- return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3; ++ attr &= INAT_PFX_MASK; ++ return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3; + } + + static inline int inat_is_vex3_prefix(insn_attr_t attr) + { +- return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3; ++ return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3; + } + + static inline int inat_is_escape(insn_attr_t attr) + { +- return attr & INAT_ESC_MASK; ++ return attr & INAT_ESC_MASK; + } + + static inline unsigned int inat_escape_id(insn_attr_t attr) + { +- return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS; ++ return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS; + } + + static inline int inat_is_group(insn_attr_t attr) + { +- return attr & INAT_GRP_MASK; ++ return attr & INAT_GRP_MASK; + } + + static inline unsigned int inat_group_id(insn_attr_t attr) + { +- return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS; ++ return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS; + } + + static inline insn_attr_t inat_group_common_attribute(insn_attr_t attr) + { +- return attr & ~(insn_attr_t)INAT_GRP_MASK; ++ return attr & ~(insn_attr_t)INAT_GRP_MASK; + } + + static inline int inat_has_immediate(insn_attr_t attr) + { +- return attr & INAT_IMM_MASK; ++ return attr & INAT_IMM_MASK; + } + + static inline unsigned int inat_immediate_size(insn_attr_t attr) + { +- return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS; ++ return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS; + } + + static inline int inat_has_modrm(insn_attr_t attr) + { +- return attr & INAT_MODRM; ++ return attr & INAT_MODRM; + } + + static inline int inat_is_force64(insn_attr_t attr) + { +- return attr & INAT_FORCE64; ++ return attr & INAT_FORCE64; + } + + static inline int inat_has_second_immediate(insn_attr_t attr) + { +- return attr & INAT_SCNDIMM; ++ return attr & INAT_SCNDIMM; + } + + static inline int inat_has_moffset(insn_attr_t attr) + { +- return attr & INAT_MOFFSET; ++ return attr & INAT_MOFFSET; + } + + static inline int inat_has_variant(insn_attr_t attr) + { +- return attr & INAT_VARIANT; ++ return attr & INAT_VARIANT; + } + + static inline int inat_accept_vex(insn_attr_t attr) + { +- return attr & INAT_VEXOK; ++ return attr & INAT_VEXOK; + } + + static inline int inat_must_vex(insn_attr_t attr) + { +- return attr & INAT_VEXONLY; ++ return attr & INAT_VEXONLY; + } + #endif +diff --git a/upatch-diff/insn/asm/insn.h b/upatch-diff/insn/asm/insn.h +index fc4ae40..09cb33d 100644 +--- a/upatch-diff/insn/asm/insn.h ++++ b/upatch-diff/insn/asm/insn.h +@@ -25,77 +25,77 @@ + #include + + struct insn_field { +- union { +- insn_value_t value; +- insn_byte_t bytes[4]; +- }; +- /* !0 if we've run insn_get_xxx() for this field */ +- unsigned char got; +- unsigned char nbytes; ++ union { ++ insn_value_t value; ++ insn_byte_t bytes[4]; ++ }; ++ /* !0 if we've run insn_get_xxx() for this field */ ++ unsigned char got; ++ unsigned char nbytes; + }; + + struct insn { +- struct insn_field prefixes; /* +- * Prefixes +- * prefixes.bytes[3]: last prefix +- */ +- struct insn_field rex_prefix; /* REX prefix */ +- struct insn_field vex_prefix; /* VEX prefix */ +- struct insn_field opcode; /* +- * opcode.bytes[0]: opcode1 +- * opcode.bytes[1]: opcode2 +- * opcode.bytes[2]: opcode3 +- */ +- struct insn_field modrm; +- struct insn_field sib; +- struct insn_field displacement; +- union { +- struct insn_field immediate; +- struct insn_field moffset1; /* for 64bit MOV */ +- struct insn_field immediate1; /* for 64bit imm or off16/32 */ +- }; +- union { +- struct insn_field moffset2; /* for 64bit MOV */ +- struct insn_field immediate2; /* for 64bit imm or seg16 */ +- }; +- +- insn_attr_t attr; +- unsigned char opnd_bytes; +- unsigned char addr_bytes; +- unsigned char length; +- unsigned char x86_64; +- +- const insn_byte_t *kaddr; /* kernel address of insn to analyze */ +- insn_byte_t *next_byte; ++ struct insn_field prefixes; /* ++ * Prefixes ++ * prefixes.bytes[3]: last prefix ++ */ ++ struct insn_field rex_prefix; /* REX prefix */ ++ struct insn_field vex_prefix; /* VEX prefix */ ++ struct insn_field opcode; /* ++ * opcode.bytes[0]: opcode1 ++ * opcode.bytes[1]: opcode2 ++ * opcode.bytes[2]: opcode3 ++ */ ++ struct insn_field modrm; ++ struct insn_field sib; ++ struct insn_field displacement; ++ union { ++ struct insn_field immediate; ++ struct insn_field moffset1; /* for 64bit MOV */ ++ struct insn_field immediate1; /* for 64bit imm or off16/32 */ ++ }; ++ union { ++ struct insn_field moffset2; /* for 64bit MOV */ ++ struct insn_field immediate2; /* for 64bit imm or seg16 */ ++ }; ++ ++ insn_attr_t attr; ++ unsigned char opnd_bytes; ++ unsigned char addr_bytes; ++ unsigned char length; ++ unsigned char x86_64; ++ ++ const insn_byte_t *kaddr; /* kernel address of insn to analyze */ ++ insn_byte_t *next_byte; + }; + +-#define MAX_INSN_SIZE 16 ++#define MAX_INSN_SIZE 16 + + #define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6) + #define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3) +-#define X86_MODRM_RM(modrm) ((modrm) & 0x07) ++#define X86_MODRM_RM(modrm) ((modrm) & 0x07) + + #define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6) + #define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3) +-#define X86_SIB_BASE(sib) ((sib) & 0x07) ++#define X86_SIB_BASE(sib) ((sib) & 0x07) + +-#define X86_REX_W(rex) ((rex) & 8) +-#define X86_REX_R(rex) ((rex) & 4) +-#define X86_REX_X(rex) ((rex) & 2) +-#define X86_REX_B(rex) ((rex) & 1) ++#define X86_REX_W(rex) ((rex) & 8) ++#define X86_REX_R(rex) ((rex) & 4) ++#define X86_REX_X(rex) ((rex) & 2) ++#define X86_REX_B(rex) ((rex) & 1) + + /* VEX bit flags */ +-#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */ +-#define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */ +-#define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */ +-#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ +-#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ ++#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */ ++#define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */ ++#define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */ ++#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ ++#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ + /* VEX bit fields */ +-#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ +-#define X86_VEX2_M 1 /* VEX2.M always 1 */ +-#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ +-#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ +-#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ ++#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ ++#define X86_VEX2_M 1 /* VEX2.M always 1 */ ++#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ ++#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ ++#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ + + extern void insn_init(struct insn *insn, void *kaddr, int x86_64); + extern void insn_get_prefixes(struct insn *insn); +@@ -109,7 +109,7 @@ extern void insn_get_length(struct insn *insn); + /* Attribute will be determined after getting ModRM (for opcode groups) */ + static inline void insn_get_attribute(struct insn *insn) + { +- insn_get_modrm(insn); ++ insn_get_modrm(insn); + } + + /* Instruction uses RIP-relative addressing */ +@@ -119,82 +119,95 @@ extern int insn_rip_relative(struct insn *insn); + static inline void kernel_insn_init(struct insn *insn, void *kaddr) + { + #ifdef CONFIG_X86_64 +- insn_init(insn, kaddr, 1); ++ insn_init(insn, kaddr, 1); + #else /* CONFIG_X86_32 */ +- insn_init(insn, kaddr, 0); ++ insn_init(insn, kaddr, 0); + #endif + } + + static inline int insn_is_avx(struct insn *insn) + { +- if (!insn->prefixes.got) +- insn_get_prefixes(insn); +- return (insn->vex_prefix.value != 0); ++ if (!insn->prefixes.got) { ++ insn_get_prefixes(insn); ++ } ++ return (insn->vex_prefix.value != 0); + } + + /* Ensure this instruction is decoded completely */ + static inline int insn_complete(struct insn *insn) + { +- return insn->opcode.got && insn->modrm.got && insn->sib.got && +- insn->displacement.got && insn->immediate.got; ++ return insn->opcode.got && insn->modrm.got && insn->sib.got && ++ insn->displacement.got && insn->immediate.got; + } + + static inline insn_byte_t insn_vex_m_bits(struct insn *insn) + { +- if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ +- return X86_VEX2_M; +- else +- return X86_VEX3_M(insn->vex_prefix.bytes[1]); ++ if (insn->vex_prefix.nbytes == 2) { ++ /* 2 bytes VEX */ ++ return X86_VEX2_M; ++ } else { ++ return X86_VEX3_M(insn->vex_prefix.bytes[1]); ++ } + } + + static inline insn_byte_t insn_vex_p_bits(struct insn *insn) + { +- if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ +- return X86_VEX_P(insn->vex_prefix.bytes[1]); +- else +- return X86_VEX_P(insn->vex_prefix.bytes[2]); ++ if (insn->vex_prefix.nbytes == 2) { ++ /* 2 bytes VEX */ ++ return X86_VEX_P(insn->vex_prefix.bytes[1]); ++ } else { ++ return X86_VEX_P(insn->vex_prefix.bytes[2]); ++ } + } + + /* Get the last prefix id from last prefix or VEX prefix */ + static inline int insn_last_prefix_id(struct insn *insn) + { +- if (insn_is_avx(insn)) +- return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ ++ if (insn_is_avx(insn)) { ++ return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ ++ } + +- if (insn->prefixes.bytes[3]) +- return inat_get_last_prefix_id(insn->prefixes.bytes[3]); ++ if (insn->prefixes.bytes[3]) { ++ return inat_get_last_prefix_id(insn->prefixes.bytes[3]); ++ } + +- return 0; ++ return 0; + } + + /* Offset of each field from kaddr */ + static inline int insn_offset_rex_prefix(struct insn *insn) + { +- return insn->prefixes.nbytes; ++ return insn->prefixes.nbytes; + } ++ + static inline int insn_offset_vex_prefix(struct insn *insn) + { +- return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; ++ return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; + } ++ + static inline int insn_offset_opcode(struct insn *insn) + { +- return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes; ++ return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes; + } ++ + static inline int insn_offset_modrm(struct insn *insn) + { +- return insn_offset_opcode(insn) + insn->opcode.nbytes; ++ return insn_offset_opcode(insn) + insn->opcode.nbytes; + } ++ + static inline int insn_offset_sib(struct insn *insn) + { +- return insn_offset_modrm(insn) + insn->modrm.nbytes; ++ return insn_offset_modrm(insn) + insn->modrm.nbytes; + } ++ + static inline int insn_offset_displacement(struct insn *insn) + { +- return insn_offset_sib(insn) + insn->sib.nbytes; ++ return insn_offset_sib(insn) + insn->sib.nbytes; + } ++ + static inline int insn_offset_immediate(struct insn *insn) + { +- return insn_offset_displacement(insn) + insn->displacement.nbytes; ++ return insn_offset_displacement(insn) + insn->displacement.nbytes; + } + +-#endif /* _ASM_X86_INSN_H */ +\ No newline at end of file ++#endif /* _ASM_X86_INSN_H */ +diff --git a/upatch-diff/insn/inat.c b/upatch-diff/insn/inat.c +index cb5aec6..96b0115 100644 +--- a/upatch-diff/insn/inat.c ++++ b/upatch-diff/insn/inat.c +@@ -28,71 +28,78 @@ + /* Attribute search APIs */ + insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode) + { +- return inat_primary_table[opcode]; ++ return inat_primary_table[opcode]; + } + + int inat_get_last_prefix_id(insn_byte_t last_pfx) + { +- insn_attr_t lpfx_attr; ++ insn_attr_t lpfx_attr; + +- lpfx_attr = inat_get_opcode_attribute(last_pfx); +- return inat_last_prefix_id(lpfx_attr); ++ lpfx_attr = inat_get_opcode_attribute(last_pfx); ++ return inat_last_prefix_id(lpfx_attr); + } + + insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, int lpfx_id, +- insn_attr_t esc_attr) ++ insn_attr_t esc_attr) + { +- const insn_attr_t *table; +- unsigned int n; ++ const insn_attr_t *table; ++ unsigned int n; + +- n = inat_escape_id(esc_attr); ++ n = inat_escape_id(esc_attr); + +- table = inat_escape_tables[n][0]; +- if (!table) +- return 0; +- if (inat_has_variant(table[opcode]) && lpfx_id) { +- table = inat_escape_tables[n][lpfx_id]; +- if (!table) +- return 0; +- } +- return table[opcode]; ++ table = inat_escape_tables[n][0]; ++ if (!table) { ++ return 0; ++ } ++ if (inat_has_variant(table[opcode]) && lpfx_id) { ++ table = inat_escape_tables[n][lpfx_id]; ++ if (!table) { ++ return 0; ++ } ++ } ++ return table[opcode]; + } + + insn_attr_t inat_get_group_attribute(insn_byte_t modrm, int lpfx_id, +- insn_attr_t grp_attr) ++ insn_attr_t grp_attr) + { +- const insn_attr_t *table; +- unsigned int n; ++ const insn_attr_t *table; ++ unsigned int n; + +- n = inat_group_id(grp_attr); ++ n = inat_group_id(grp_attr); + +- table = inat_group_tables[n][0]; +- if (!table) +- return inat_group_common_attribute(grp_attr); +- if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) { +- table = inat_group_tables[n][lpfx_id]; +- if (!table) +- return inat_group_common_attribute(grp_attr); +- } +- return table[X86_MODRM_REG(modrm)] | +- inat_group_common_attribute(grp_attr); ++ table = inat_group_tables[n][0]; ++ if (!table) { ++ return inat_group_common_attribute(grp_attr); ++ } ++ if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) { ++ table = inat_group_tables[n][lpfx_id]; ++ if (!table) { ++ return inat_group_common_attribute(grp_attr); ++ } ++ } ++ return table[X86_MODRM_REG(modrm)] | ++ inat_group_common_attribute(grp_attr); + } + + insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, +- insn_byte_t vex_p) ++ insn_byte_t vex_p) + { +- const insn_attr_t *table; +- if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX) +- return 0; +- /* At first, this checks the master table */ +- table = inat_avx_tables[vex_m][0]; +- if (!table) +- return 0; +- if (!inat_is_group(table[opcode]) && vex_p) { +- /* If this is not a group, get attribute directly */ +- table = inat_avx_tables[vex_m][vex_p]; +- if (!table) +- return 0; +- } +- return table[opcode]; ++ const insn_attr_t *table; ++ if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX) { ++ return 0; ++ } ++ /* At first, this checks the master table */ ++ table = inat_avx_tables[vex_m][0]; ++ if (!table) { ++ return 0; ++ } ++ if (!inat_is_group(table[opcode]) && vex_p) { ++ /* If this is not a group, get attribute directly */ ++ table = inat_avx_tables[vex_m][vex_p]; ++ if (!table) { ++ return 0; ++ } ++ } ++ return table[opcode]; + } +diff --git a/upatch-diff/insn/insn.c b/upatch-diff/insn/insn.c +index 7880eed..d38953c 100644 +--- a/upatch-diff/insn/insn.c ++++ b/upatch-diff/insn/insn.c +@@ -26,45 +26,46 @@ + #define unlikely(a) a + + /* Verify next sizeof(t) bytes can be on the same instruction */ +-#define validate_next(t, insn, n) \ +- ((insn)->next_byte + sizeof(t) + n - (insn)->kaddr <= MAX_INSN_SIZE) ++#define validate_next(t, insn, n) \ ++ ((insn)->next_byte + sizeof(t) + (n) - (insn)->kaddr <= MAX_INSN_SIZE) + +-#define __get_next(t, insn) \ +- ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; }) ++#define next_type_of(t, insn) \ ++ ({ t r = *(t*)((insn)->next_byte); (insn)->next_byte += sizeof(t); r; }) + +-#define __peek_nbyte_next(t, insn, n) \ +- ({ t r = *(t*)((insn)->next_byte + n); r; }) ++#define peek_nbytes_of(t, insn, n) \ ++ ({ t r = *(t*)((insn)->next_byte + (n)); r; }) + +-#define get_next(t, insn) \ +- ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); }) ++#define get_next(t, insn) \ ++ ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; next_type_of(t, insn); }) + +-#define peek_nbyte_next(t, insn, n) \ +- ({ if (unlikely(!validate_next(t, insn, n))) goto err_out; __peek_nbyte_next(t, insn, n); }) ++#define peek_nbyte_next(t, insn, n) \ ++ ({ if (unlikely(!validate_next(t, insn, n))) goto err_out; peek_nbytes_of(t, insn, n); }) + +-#define peek_next(t, insn) peek_nbyte_next(t, insn, 0) ++#define peek_next(t, insn) peek_nbyte_next(t, insn, 0) + + /** + * insn_init() - initialize struct insn +- * @insn: &struct insn to be initialized +- * @kaddr: address (in kernel memory) of instruction (or copy thereof) +- * @x86_64: !0 for 64-bit kernel or 64-bit app ++ * @insn: &struct insn to be initialized ++ * @kaddr: address (in kernel memory) of instruction (or copy thereof) ++ * @x86_64: !0 for 64-bit kernel or 64-bit app + */ + void insn_init(struct insn *insn, void *kaddr, int x86_64) + { +- memset(insn, 0, sizeof(*insn)); +- insn->kaddr = kaddr; +- insn->next_byte = kaddr; +- insn->x86_64 = x86_64 ? 1 : 0; +- insn->opnd_bytes = 4; +- if (x86_64) +- insn->addr_bytes = 8; +- else +- insn->addr_bytes = 4; ++ memset(insn, 0, sizeof(*insn)); ++ insn->kaddr = kaddr; ++ insn->next_byte = kaddr; ++ insn->x86_64 = x86_64 ? 1 : 0; ++ insn->opnd_bytes = 4; ++ if (x86_64) { ++ insn->addr_bytes = 8; ++ } else { ++ insn->addr_bytes = 4; ++ } + } + + /** + * insn_get_prefixes - scan x86 instruction prefix bytes +- * @insn: &struct insn containing instruction ++ * @insn: &struct insn containing instruction + * + * Populates the @insn->prefixes bitmap, and updates @insn->next_byte + * to point to the (first) opcode. No effect if @insn->prefixes.got +@@ -72,112 +73,124 @@ void insn_init(struct insn *insn, void *kaddr, int x86_64) + */ + void insn_get_prefixes(struct insn *insn) + { +- struct insn_field *prefixes = &insn->prefixes; +- insn_attr_t attr; +- insn_byte_t b, lb; +- int i, nb; +- +- if (prefixes->got) +- return; +- +- nb = 0; +- lb = 0; +- b = peek_next(insn_byte_t, insn); +- attr = inat_get_opcode_attribute(b); +- while (inat_is_legacy_prefix(attr)) { +- /* Skip if same prefix */ +- for (i = 0; i < nb; i++) +- if (prefixes->bytes[i] == b) +- goto found; +- if (nb == 4) +- /* Invalid instruction */ +- break; +- prefixes->bytes[nb++] = b; +- if (inat_is_address_size_prefix(attr)) { +- /* address size switches 2/4 or 4/8 */ +- if (insn->x86_64) +- insn->addr_bytes ^= 12; +- else +- insn->addr_bytes ^= 6; +- } else if (inat_is_operand_size_prefix(attr)) { +- /* oprand size switches 2/4 */ +- insn->opnd_bytes ^= 6; +- } ++ struct insn_field *prefixes = &insn->prefixes; ++ insn_attr_t attr; ++ insn_byte_t b; ++ insn_byte_t lb; ++ int i; ++ int nb; ++ ++ if (prefixes->got) { ++ return; ++ } ++ ++ nb = 0; ++ lb = 0; ++ b = peek_next(insn_byte_t, insn); ++ attr = inat_get_opcode_attribute(b); ++ while (inat_is_legacy_prefix(attr)) { ++ /* Skip if same prefix */ ++ for (i = 0; i < nb; i++) { ++ if (prefixes->bytes[i] == b) { ++ goto found; ++ } ++ } ++ if (nb == 4) { ++ /* Invalid instruction */ ++ break; ++ } ++ prefixes->bytes[nb++] = b; ++ if (inat_is_address_size_prefix(attr)) { ++ /* address size switches 2/4 or 4/8 */ ++ if (insn->x86_64) { ++ insn->addr_bytes ^= 12; ++ } else { ++ insn->addr_bytes ^= 6; ++ } ++ } else if (inat_is_operand_size_prefix(attr)) { ++ /* oprand size switches 2/4 */ ++ insn->opnd_bytes ^= 6; ++ } + found: +- prefixes->nbytes++; +- insn->next_byte++; +- lb = b; +- b = peek_next(insn_byte_t, insn); +- attr = inat_get_opcode_attribute(b); +- } +- /* Set the last prefix */ +- if (lb && lb != insn->prefixes.bytes[3]) { +- if (unlikely(insn->prefixes.bytes[3])) { +- /* Swap the last prefix */ +- b = insn->prefixes.bytes[3]; +- for (i = 0; i < nb; i++) +- if (prefixes->bytes[i] == lb) +- prefixes->bytes[i] = b; +- } +- insn->prefixes.bytes[3] = lb; +- } +- +- /* Decode REX prefix */ +- if (insn->x86_64) { +- b = peek_next(insn_byte_t, insn); +- attr = inat_get_opcode_attribute(b); +- if (inat_is_rex_prefix(attr)) { +- insn->rex_prefix.value = b; +- insn->rex_prefix.nbytes = 1; +- insn->next_byte++; +- if (X86_REX_W(b)) +- /* REX.W overrides opnd_size */ +- insn->opnd_bytes = 8; +- } +- } +- insn->rex_prefix.got = 1; +- +- /* Decode VEX prefix */ +- b = peek_next(insn_byte_t, insn); +- attr = inat_get_opcode_attribute(b); +- if (inat_is_vex_prefix(attr)) { +- insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); +- if (!insn->x86_64) { +- /* +- * In 32-bits mode, if the [7:6] bits (mod bits of +- * ModRM) on the second byte are not 11b, it is +- * LDS or LES. +- */ +- if (X86_MODRM_MOD(b2) != 3) +- goto vex_end; +- } +- insn->vex_prefix.bytes[0] = b; +- insn->vex_prefix.bytes[1] = b2; +- if (inat_is_vex3_prefix(attr)) { +- b2 = peek_nbyte_next(insn_byte_t, insn, 2); +- insn->vex_prefix.bytes[2] = b2; +- insn->vex_prefix.nbytes = 3; +- insn->next_byte += 3; +- if (insn->x86_64 && X86_VEX_W(b2)) +- /* VEX.W overrides opnd_size */ +- insn->opnd_bytes = 8; +- } else { +- insn->vex_prefix.nbytes = 2; +- insn->next_byte += 2; +- } +- } ++ prefixes->nbytes++; ++ insn->next_byte++; ++ lb = b; ++ b = peek_next(insn_byte_t, insn); ++ attr = inat_get_opcode_attribute(b); ++ } ++ /* Set the last prefix */ ++ if (lb && lb != insn->prefixes.bytes[3]) { ++ if (unlikely(insn->prefixes.bytes[3])) { ++ /* Swap the last prefix */ ++ b = insn->prefixes.bytes[3]; ++ for (i = 0; i < nb; i++) { ++ if (prefixes->bytes[i] == lb) { ++ prefixes->bytes[i] = b; ++ } ++ } ++ } ++ insn->prefixes.bytes[3] = lb; ++ } ++ ++ /* Decode REX prefix */ ++ if (insn->x86_64) { ++ b = peek_next(insn_byte_t, insn); ++ attr = inat_get_opcode_attribute(b); ++ if (inat_is_rex_prefix(attr)) { ++ insn->rex_prefix.value = b; ++ insn->rex_prefix.nbytes = 1; ++ insn->next_byte++; ++ if (X86_REX_W(b)) { ++ /* REX.W overrides opnd_size */ ++ insn->opnd_bytes = 8; ++ } ++ } ++ } ++ insn->rex_prefix.got = 1; ++ ++ /* Decode VEX prefix */ ++ b = peek_next(insn_byte_t, insn); ++ attr = inat_get_opcode_attribute(b); ++ if (inat_is_vex_prefix(attr)) { ++ insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); ++ if (!insn->x86_64) { ++ /* ++ * In 32-bits mode, if the [7:6] bits (mod bits of ++ * ModRM) on the second byte are not 11b, it is ++ * LDS or LES. ++ */ ++ if (X86_MODRM_MOD(b2) != 3) { ++ goto vex_end; ++ } ++ } ++ insn->vex_prefix.bytes[0] = b; ++ insn->vex_prefix.bytes[1] = b2; ++ if (inat_is_vex3_prefix(attr)) { ++ b2 = peek_nbyte_next(insn_byte_t, insn, 2); ++ insn->vex_prefix.bytes[2] = b2; ++ insn->vex_prefix.nbytes = 3; ++ insn->next_byte += 3; ++ if (insn->x86_64 && X86_VEX_W(b2)) { ++ /* VEX.W overrides opnd_size */ ++ insn->opnd_bytes = 8; ++ } ++ } else { ++ insn->vex_prefix.nbytes = 2; ++ insn->next_byte += 2; ++ } ++ } + vex_end: +- insn->vex_prefix.got = 1; ++ insn->vex_prefix.got = 1; + +- prefixes->got = 1; ++ prefixes->got = 1; + + err_out: +- return; ++ return; + } + + /** + * insn_get_opcode - collect opcode(s) +- * @insn: &struct insn containing instruction ++ * @insn: &struct insn containing instruction + * + * Populates @insn->opcode, updates @insn->next_byte to point past the + * opcode byte(s), and set @insn->attr (except for groups). +@@ -187,50 +200,54 @@ err_out: + */ + void insn_get_opcode(struct insn *insn) + { +- struct insn_field *opcode = &insn->opcode; +- insn_byte_t op; +- int pfx_id; +- if (opcode->got) +- return; +- if (!insn->prefixes.got) +- insn_get_prefixes(insn); +- +- /* Get first opcode */ +- op = get_next(insn_byte_t, insn); +- opcode->bytes[0] = op; +- opcode->nbytes = 1; +- +- /* Check if there is VEX prefix or not */ +- if (insn_is_avx(insn)) { +- insn_byte_t m, p; +- m = insn_vex_m_bits(insn); +- p = insn_vex_p_bits(insn); +- insn->attr = inat_get_avx_attribute(op, m, p); +- if (!inat_accept_vex(insn->attr) && !inat_is_group(insn->attr)) +- insn->attr = 0; /* This instruction is bad */ +- goto end; /* VEX has only 1 byte for opcode */ +- } +- +- insn->attr = inat_get_opcode_attribute(op); +- while (inat_is_escape(insn->attr)) { +- /* Get escaped opcode */ +- op = get_next(insn_byte_t, insn); +- opcode->bytes[opcode->nbytes++] = op; +- pfx_id = insn_last_prefix_id(insn); +- insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); +- } +- if (inat_must_vex(insn->attr)) +- insn->attr = 0; /* This instruction is bad */ ++ struct insn_field *opcode = &insn->opcode; ++ insn_byte_t op; ++ int pfx_id; ++ ++ if (opcode->got) { ++ return; ++ } ++ if (!insn->prefixes.got) { ++ insn_get_prefixes(insn); ++ } ++ ++ /* Get first opcode */ ++ op = get_next(insn_byte_t, insn); ++ opcode->bytes[0] = op; ++ opcode->nbytes = 1; ++ ++ /* Check if there is VEX prefix or not */ ++ if (insn_is_avx(insn)) { ++ insn_byte_t m = insn_vex_m_bits(insn); ++ insn_byte_t p = insn_vex_p_bits(insn); ++ insn->attr = inat_get_avx_attribute(op, m, p); ++ if (!inat_accept_vex(insn->attr) && !inat_is_group(insn->attr)) { ++ insn->attr = 0; /* This instruction is bad */ ++ } ++ goto end; /* VEX has only 1 byte for opcode */ ++ } ++ ++ insn->attr = inat_get_opcode_attribute(op); ++ while (inat_is_escape(insn->attr)) { ++ /* Get escaped opcode */ ++ op = get_next(insn_byte_t, insn); ++ opcode->bytes[opcode->nbytes++] = op; ++ pfx_id = insn_last_prefix_id(insn); ++ insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); ++ } ++ if (inat_must_vex(insn->attr)) { ++ insn->attr = 0; /* This instruction is bad */ ++ } + end: +- opcode->got = 1; ++ opcode->got = 1; + + err_out: +- return; ++ return; + } + + /** + * insn_get_modrm - collect ModRM byte, if any +- * @insn: &struct insn containing instruction ++ * @insn: &struct insn containing instruction + * + * Populates @insn->modrm and updates @insn->next_byte to point past the + * ModRM byte, if any. If necessary, first collects the preceding bytes +@@ -238,90 +255,98 @@ err_out: + */ + void insn_get_modrm(struct insn *insn) + { +- struct insn_field *modrm = &insn->modrm; +- insn_byte_t pfx_id, mod; +- if (modrm->got) +- return; +- if (!insn->opcode.got) +- insn_get_opcode(insn); +- +- if (inat_has_modrm(insn->attr)) { +- mod = get_next(insn_byte_t, insn); +- modrm->value = mod; +- modrm->nbytes = 1; +- if (inat_is_group(insn->attr)) { +- pfx_id = (insn_byte_t)insn_last_prefix_id(insn); +- insn->attr = inat_get_group_attribute(mod, pfx_id, +- insn->attr); +- if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) +- insn->attr = 0; /* This is bad */ +- } +- } +- +- if (insn->x86_64 && inat_is_force64(insn->attr)) +- insn->opnd_bytes = 8; +- modrm->got = 1; ++ struct insn_field *modrm = &insn->modrm; ++ insn_byte_t pfx_id; ++ insn_byte_t mod; ++ ++ if (modrm->got) { ++ return; ++ } ++ if (!insn->opcode.got) { ++ insn_get_opcode(insn); ++ } ++ ++ if (inat_has_modrm(insn->attr)) { ++ mod = get_next(insn_byte_t, insn); ++ modrm->value = mod; ++ modrm->nbytes = 1; ++ if (inat_is_group(insn->attr)) { ++ pfx_id = (insn_byte_t)insn_last_prefix_id(insn); ++ insn->attr = inat_get_group_attribute(mod, pfx_id, insn->attr); ++ if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) { ++ insn_get_opcode(insn); ++ } ++ } ++ } ++ ++ if (insn->x86_64 && inat_is_force64(insn->attr)) { ++ insn->opnd_bytes = 8; ++ } ++ modrm->got = 1; + + err_out: +- return; ++ return; + } + + + /** + * insn_rip_relative() - Does instruction use RIP-relative addressing mode? +- * @insn: &struct insn containing instruction ++ * @insn: &struct insn containing instruction + * + * If necessary, first collects the instruction up to and including the + * ModRM byte. No effect if @insn->x86_64 is 0. + */ + int insn_rip_relative(struct insn *insn) + { +- struct insn_field *modrm = &insn->modrm; +- +- if (!insn->x86_64) +- return 0; +- if (!modrm->got) +- insn_get_modrm(insn); +- /* +- * For rip-relative instructions, the mod field (top 2 bits) +- * is zero and the r/m field (bottom 3 bits) is 0x5. +- */ +- return (modrm->nbytes && (modrm->value & 0xc7) == 0x5); ++ struct insn_field *modrm = &insn->modrm; ++ ++ if (!insn->x86_64) { ++ return 0; ++ } ++ if (!modrm->got) { ++ insn_get_modrm(insn); ++ } ++ /* ++ * For rip-relative instructions, the mod field (top 2 bits) ++ * is zero and the r/m field (bottom 3 bits) is 0x5. ++ */ ++ return (modrm->nbytes && (modrm->value & 0xc7) == 0x5); + } + + /** + * insn_get_sib() - Get the SIB byte of instruction +- * @insn: &struct insn containing instruction ++ * @insn: &struct insn containing instruction + * + * If necessary, first collects the instruction up to and including the + * ModRM byte. + */ + void insn_get_sib(struct insn *insn) + { +- insn_byte_t modrm; +- +- if (insn->sib.got) +- return; +- if (!insn->modrm.got) +- insn_get_modrm(insn); +- if (insn->modrm.nbytes) { +- modrm = (insn_byte_t)insn->modrm.value; +- if (insn->addr_bytes != 2 && +- X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { +- insn->sib.value = get_next(insn_byte_t, insn); +- insn->sib.nbytes = 1; +- } +- } +- insn->sib.got = 1; ++ insn_byte_t modrm; ++ ++ if (insn->sib.got) { ++ return; ++ } ++ if (!insn->modrm.got) { ++ insn_get_modrm(insn); ++ } ++ if (insn->modrm.nbytes) { ++ modrm = (insn_byte_t)insn->modrm.value; ++ if (insn->addr_bytes != 2 && ++ X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { ++ insn->sib.value = get_next(insn_byte_t, insn); ++ insn->sib.nbytes = 1; ++ } ++ } ++ insn->sib.got = 1; + + err_out: +- return; ++ return; + } + +- + /** + * insn_get_displacement() - Get the displacement of instruction +- * @insn: &struct insn containing instruction ++ * @insn: &struct insn containing instruction + * + * If necessary, first collects the instruction up to and including the + * SIB byte. +@@ -329,169 +354,176 @@ err_out: + */ + void insn_get_displacement(struct insn *insn) + { +- insn_byte_t mod, rm, base; +- +- if (insn->displacement.got) +- return; +- if (!insn->sib.got) +- insn_get_sib(insn); +- if (insn->modrm.nbytes) { +- /* +- * Interpreting the modrm byte: +- * mod = 00 - no displacement fields (exceptions below) +- * mod = 01 - 1-byte displacement field +- * mod = 10 - displacement field is 4 bytes, or 2 bytes if +- * address size = 2 (0x67 prefix in 32-bit mode) +- * mod = 11 - no memory operand +- * +- * If address size = 2... +- * mod = 00, r/m = 110 - displacement field is 2 bytes +- * +- * If address size != 2... +- * mod != 11, r/m = 100 - SIB byte exists +- * mod = 00, SIB base = 101 - displacement field is 4 bytes +- * mod = 00, r/m = 101 - rip-relative addressing, displacement +- * field is 4 bytes +- */ +- mod = X86_MODRM_MOD(insn->modrm.value); +- rm = X86_MODRM_RM(insn->modrm.value); +- base = X86_SIB_BASE(insn->sib.value); +- if (mod == 3) +- goto out; +- if (mod == 1) { +- insn->displacement.value = get_next(char, insn); +- insn->displacement.nbytes = 1; +- } else if (insn->addr_bytes == 2) { +- if ((mod == 0 && rm == 6) || mod == 2) { +- insn->displacement.value = +- get_next(short, insn); +- insn->displacement.nbytes = 2; +- } +- } else { +- if ((mod == 0 && rm == 5) || mod == 2 || +- (mod == 0 && base == 5)) { +- insn->displacement.value = get_next(int, insn); +- insn->displacement.nbytes = 4; +- } +- } +- } ++ insn_byte_t mod; ++ insn_byte_t rm; ++ insn_byte_t base; ++ ++ if (insn->displacement.got) { ++ return; ++ } ++ if (!insn->sib.got) { ++ insn_get_sib(insn); ++ } ++ if (insn->modrm.nbytes) { ++ /* ++ * Interpreting the modrm byte: ++ * mod = 00 - no displacement fields (exceptions below) ++ * mod = 01 - 1-byte displacement field ++ * mod = 10 - displacement field is 4 bytes, or 2 bytes if ++ * address size = 2 (0x67 prefix in 32-bit mode) ++ * mod = 11 - no memory operand ++ * ++ * If address size = 2... ++ * mod = 00, r/m = 110 - displacement field is 2 bytes ++ * ++ * If address size != 2... ++ * mod != 11, r/m = 100 - SIB byte exists ++ * mod = 00, SIB base = 101 - displacement field is 4 bytes ++ * mod = 00, r/m = 101 - rip-relative addressing, displacement ++ * field is 4 bytes ++ */ ++ mod = X86_MODRM_MOD(insn->modrm.value); ++ rm = X86_MODRM_RM(insn->modrm.value); ++ base = X86_SIB_BASE(insn->sib.value); ++ if (mod == 3) { ++ goto out; ++ } ++ if (mod == 1) { ++ insn->displacement.value = get_next(char, insn); ++ insn->displacement.nbytes = 1; ++ } else if (insn->addr_bytes == 2) { ++ if ((mod == 0 && rm == 6) || mod == 2) { ++ insn->displacement.value = ++ get_next(short, insn); ++ insn->displacement.nbytes = 2; ++ } ++ } else { ++ if ((mod == 0 && rm == 5) || mod == 2 || ++ (mod == 0 && base == 5)) { ++ insn->displacement.value = get_next(int, insn); ++ insn->displacement.nbytes = 4; ++ } ++ } ++ } + out: +- insn->displacement.got = 1; ++ insn->displacement.got = 1; + + err_out: +- return; ++ return; + } + + /* Decode moffset16/32/64. Return 0 if failed */ +-static int __get_moffset(struct insn *insn) ++static int get_moffset(struct insn *insn) + { +- switch (insn->addr_bytes) { +- case 2: +- insn->moffset1.value = get_next(short, insn); +- insn->moffset1.nbytes = 2; +- break; +- case 4: +- insn->moffset1.value = get_next(int, insn); +- insn->moffset1.nbytes = 4; +- break; +- case 8: +- insn->moffset1.value = get_next(int, insn); +- insn->moffset1.nbytes = 4; +- insn->moffset2.value = get_next(int, insn); +- insn->moffset2.nbytes = 4; +- break; +- default: /* opnd_bytes must be modified manually */ +- goto err_out; +- } +- insn->moffset1.got = insn->moffset2.got = 1; +- +- return 1; ++ switch (insn->addr_bytes) { ++ case 2: ++ insn->moffset1.value = get_next(short, insn); ++ insn->moffset1.nbytes = 2; ++ break; ++ case 4: ++ insn->moffset1.value = get_next(int, insn); ++ insn->moffset1.nbytes = 4; ++ break; ++ case 8: ++ insn->moffset1.value = get_next(int, insn); ++ insn->moffset1.nbytes = 4; ++ insn->moffset2.value = get_next(int, insn); ++ insn->moffset2.nbytes = 4; ++ break; ++ default: /* opnd_bytes must be modified manually */ ++ goto err_out; ++ } ++ insn->moffset1.got = insn->moffset2.got = 1; ++ ++ return 1; + + err_out: +- return 0; ++ return 0; + } + + /* Decode imm v32(Iz). Return 0 if failed */ +-static int __get_immv32(struct insn *insn) ++static int get_immv32(struct insn *insn) + { +- switch (insn->opnd_bytes) { +- case 2: +- insn->immediate.value = get_next(short, insn); +- insn->immediate.nbytes = 2; +- break; +- case 4: +- case 8: +- insn->immediate.value = get_next(int, insn); +- insn->immediate.nbytes = 4; +- break; +- default: /* opnd_bytes must be modified manually */ +- goto err_out; +- } +- +- return 1; ++ switch (insn->opnd_bytes) { ++ case 2: ++ insn->immediate.value = get_next(short, insn); ++ insn->immediate.nbytes = 2; ++ break; ++ case 4: ++ case 8: ++ insn->immediate.value = get_next(int, insn); ++ insn->immediate.nbytes = 4; ++ break; ++ default: /* opnd_bytes must be modified manually */ ++ goto err_out; ++ } ++ ++ return 1; + + err_out: +- return 0; ++ return 0; + } + + /* Decode imm v64(Iv/Ov), Return 0 if failed */ +-static int __get_immv(struct insn *insn) ++static int get_immv(struct insn *insn) + { +- switch (insn->opnd_bytes) { +- case 2: +- insn->immediate1.value = get_next(short, insn); +- insn->immediate1.nbytes = 2; +- break; +- case 4: +- insn->immediate1.value = get_next(int, insn); +- insn->immediate1.nbytes = 4; +- break; +- case 8: +- insn->immediate1.value = get_next(int, insn); +- insn->immediate1.nbytes = 4; +- insn->immediate2.value = get_next(int, insn); +- insn->immediate2.nbytes = 4; +- break; +- default: /* opnd_bytes must be modified manually */ +- goto err_out; +- } +- insn->immediate1.got = insn->immediate2.got = 1; +- +- return 1; ++ switch (insn->opnd_bytes) { ++ case 2: ++ insn->immediate1.value = get_next(short, insn); ++ insn->immediate1.nbytes = 2; ++ break; ++ case 4: ++ insn->immediate1.value = get_next(int, insn); ++ insn->immediate1.nbytes = 4; ++ break; ++ case 8: ++ insn->immediate1.value = get_next(int, insn); ++ insn->immediate1.nbytes = 4; ++ insn->immediate2.value = get_next(int, insn); ++ insn->immediate2.nbytes = 4; ++ break; ++ default: /* opnd_bytes must be modified manually */ ++ goto err_out; ++ } ++ insn->immediate1.got = insn->immediate2.got = 1; ++ ++ return 1; ++ + err_out: +- return 0; ++ return 0; + } + + /* Decode ptr16:16/32(Ap) */ +-static int __get_immptr(struct insn *insn) ++static int get_immptr(struct insn *insn) + { +- switch (insn->opnd_bytes) { +- case 2: +- insn->immediate1.value = get_next(short, insn); +- insn->immediate1.nbytes = 2; +- break; +- case 4: +- insn->immediate1.value = get_next(int, insn); +- insn->immediate1.nbytes = 4; +- break; +- case 8: +- /* ptr16:64 is not exist (no segment) */ +- return 0; +- default: /* opnd_bytes must be modified manually */ +- goto err_out; +- } +- insn->immediate2.value = get_next(unsigned short, insn); +- insn->immediate2.nbytes = 2; +- insn->immediate1.got = insn->immediate2.got = 1; +- +- return 1; ++ switch (insn->opnd_bytes) { ++ case 2: ++ insn->immediate1.value = get_next(short, insn); ++ insn->immediate1.nbytes = 2; ++ break; ++ case 4: ++ insn->immediate1.value = get_next(int, insn); ++ insn->immediate1.nbytes = 4; ++ break; ++ case 8: ++ /* ptr16:64 is not exist (no segment) */ ++ return 0; ++ default: /* opnd_bytes must be modified manually */ ++ goto err_out; ++ } ++ insn->immediate2.value = get_next(unsigned short, insn); ++ insn->immediate2.nbytes = 2; ++ insn->immediate1.got = insn->immediate2.got = 1; ++ ++ return 1; ++ + err_out: +- return 0; ++ return 0; + } + + /** + * insn_get_immediate() - Get the immediates of instruction +- * @insn: &struct insn containing instruction ++ * @insn: &struct insn containing instruction + * + * If necessary, first collects the instruction up to and including the + * displacement bytes. +@@ -500,80 +532,89 @@ err_out: + */ + void insn_get_immediate(struct insn *insn) + { +- if (insn->immediate.got) +- return; +- if (!insn->displacement.got) +- insn_get_displacement(insn); +- +- if (inat_has_moffset(insn->attr)) { +- if (!__get_moffset(insn)) +- goto err_out; +- goto done; +- } +- +- if (!inat_has_immediate(insn->attr)) +- /* no immediates */ +- goto done; +- +- switch (inat_immediate_size(insn->attr)) { +- case INAT_IMM_BYTE: +- insn->immediate.value = get_next(char, insn); +- insn->immediate.nbytes = 1; +- break; +- case INAT_IMM_WORD: +- insn->immediate.value = get_next(short, insn); +- insn->immediate.nbytes = 2; +- break; +- case INAT_IMM_DWORD: +- insn->immediate.value = get_next(int, insn); +- insn->immediate.nbytes = 4; +- break; +- case INAT_IMM_QWORD: +- insn->immediate1.value = get_next(int, insn); +- insn->immediate1.nbytes = 4; +- insn->immediate2.value = get_next(int, insn); +- insn->immediate2.nbytes = 4; +- break; +- case INAT_IMM_PTR: +- if (!__get_immptr(insn)) +- goto err_out; +- break; +- case INAT_IMM_VWORD32: +- if (!__get_immv32(insn)) +- goto err_out; +- break; +- case INAT_IMM_VWORD: +- if (!__get_immv(insn)) +- goto err_out; +- break; +- default: +- /* Here, insn must have an immediate, but failed */ +- goto err_out; +- } +- if (inat_has_second_immediate(insn->attr)) { +- insn->immediate2.value = get_next(char, insn); +- insn->immediate2.nbytes = 1; +- } ++ if (insn->immediate.got) { ++ return; ++ } ++ if (!insn->displacement.got) { ++ insn_get_displacement(insn); ++ } ++ ++ if (inat_has_moffset(insn->attr)) { ++ if (!get_moffset(insn)) { ++ goto err_out; ++ } ++ goto done; ++ } ++ ++ if (!inat_has_immediate(insn->attr)) { ++ /* no immediates */ ++ goto done; ++ } ++ ++ switch (inat_immediate_size(insn->attr)) { ++ case INAT_IMM_BYTE: ++ insn->immediate.value = get_next(char, insn); ++ insn->immediate.nbytes = 1; ++ break; ++ case INAT_IMM_WORD: ++ insn->immediate.value = get_next(short, insn); ++ insn->immediate.nbytes = 2; ++ break; ++ case INAT_IMM_DWORD: ++ insn->immediate.value = get_next(int, insn); ++ insn->immediate.nbytes = 4; ++ break; ++ case INAT_IMM_QWORD: ++ insn->immediate1.value = get_next(int, insn); ++ insn->immediate1.nbytes = 4; ++ insn->immediate2.value = get_next(int, insn); ++ insn->immediate2.nbytes = 4; ++ break; ++ case INAT_IMM_PTR: ++ if (!get_immptr(insn)) { ++ goto err_out; ++ } ++ break; ++ case INAT_IMM_VWORD32: ++ if (!get_immv32(insn)) { ++ goto err_out; ++ } ++ break; ++ case INAT_IMM_VWORD: ++ if (!get_immv(insn)) { ++ goto err_out; ++ } ++ break; ++ default: ++ /* Here, insn must have an immediate, but failed */ ++ goto err_out; ++ } ++ if (inat_has_second_immediate(insn->attr)) { ++ insn->immediate2.value = get_next(char, insn); ++ insn->immediate2.nbytes = 1; ++ } + done: +- insn->immediate.got = 1; ++ insn->immediate.got = 1; + + err_out: +- return; ++ return; + } + + /** + * insn_get_length() - Get the length of instruction +- * @insn: &struct insn containing instruction ++ * @insn: &struct insn containing instruction + * + * If necessary, first collects the instruction up to and including the + * immediates bytes. + */ + void insn_get_length(struct insn *insn) + { +- if (insn->length) +- return; +- if (!insn->immediate.got) +- insn_get_immediate(insn); +- insn->length = (unsigned char)((unsigned long)insn->next_byte - +- (unsigned long)insn->kaddr); ++ if (insn->length) { ++ return; ++ } ++ if (!insn->immediate.got) { ++ insn_get_immediate(insn); ++ } ++ insn->length = (unsigned char)((unsigned long)insn->next_byte - ++ (unsigned long)insn->kaddr); + } +diff --git a/upatch-diff/list.h b/upatch-diff/list.h +index b3b28e1..b56a2b0 100644 +--- a/upatch-diff/list.h ++++ b/upatch-diff/list.h +@@ -33,8 +33,8 @@ + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +-#define LIST_POISON1 ((void *) 0x00100100) +-#define LIST_POISON2 ((void *) 0x00200200) ++#define LIST_POISON1 ((void *) 0x00100100) ++#define LIST_POISON2 ((void *) 0x00200200) + + /** + * Get offset of a member +@@ -48,9 +48,10 @@ + * @param member the name of the member within the struct. + * + */ +-#define container_of(ptr, type, member) ({ \ +- typeof( ((type *)0)->member ) *__mptr = (ptr); \ +- (type *)( (char *)__mptr - offsetof(type,member) );}) ++#define container_of(ptr, type, member) ({ \ ++ typeof(((type *)0)->member) *__mptr = (ptr); \ ++ (type *)((char *)__mptr - offsetof(type, member)); \ ++}) + + /** + * Simple doubly linked list implementation. +@@ -62,67 +63,66 @@ + * using the generic single-entry routines. + */ + struct list_head { +- struct list_head *next, *prev; ++ struct list_head *next, *prev; + }; + + #define LIST_HEAD_INIT(name) { &(name), &(name) } + + #define LIST_HEAD(name) \ +- struct list_head name = LIST_HEAD_INIT(name) ++ struct list_head name = LIST_HEAD_INIT(name) + + #define INIT_LIST_HEAD(ptr) do { \ +- (ptr)->next = (ptr); (ptr)->prev = (ptr); \ ++ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ + } while (0) + + #define list_entry(ptr, type, member) \ +- container_of(ptr, type, member) ++ container_of(ptr, type, member) + + /** + * list_next_entry - get the next element in list +- * @pos: the type * to cursor +- * @member: the name of the list_struct within the struct. ++ * @pos: the type * to cursor ++ * @member: the name of the list_struct within the struct. + */ + #define list_next_entry(pos, member) \ +- list_entry((pos)->member.next, typeof(*(pos)), member) ++ list_entry((pos)->member.next, typeof(*(pos)), member) + + /** +- * list_for_each_entry - iterate over list of given type +- * @pos: the type * to use as a loop counter. +- * @head: the head for your list. +- * @member: the name of the list_struct within the struct. ++ * list_for_each_entry - iterate over list of given type ++ * @pos: the type * to use as a loop counter. ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. + */ +-#define list_for_each_entry(pos, head, member) \ +- for (pos = list_entry((head)->next, typeof(*pos), member); \ +- &pos->member != (head); \ +- pos = list_entry(pos->member.next, typeof(*pos), member)) ++#define list_for_each_entry(pos, head, member) \ ++ for ((pos) = list_entry((head)->next, typeof(*(pos)), member); \ ++ &((pos)->member) != (head); \ ++ (pos) = list_entry((pos)->member.next, typeof(*(pos)), member)) + + /** + * list_for_each_entry_continue - continue iteration over list of given type +- * @pos: the type * to use as a loop cursor. +- * @head: the head for your list. +- * @member: the name of the list_struct within the struct. ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +-#define list_for_each_entry_continue(pos, head, member) \ +- for (pos = list_next_entry(pos, member); \ +- &pos->member != (head); \ +- pos = list_next_entry(pos, member)) ++#define list_for_each_entry_continue(pos, head, member) \ ++ for ((pos) = list_next_entry(pos, member); \ ++ &((pos)->member) != (head); \ ++ (pos) = list_next_entry(pos, member)) + + /** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry +- * @pos: the type * to use as a loop counter. +- * @n: another type * to use as temporary storage +- * @head: the head for your list. +- * @member: the name of the list_struct within the struct. ++ * @pos: the type * to use as a loop counter. ++ * @n: another type * to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. + */ +-#define list_for_each_entry_safe(pos, n, head, member) \ +- for (pos = list_entry((head)->next, typeof(*pos), member), \ +- n = list_entry(pos->member.next, typeof(*pos), member); \ +- &pos->member != (head); \ +- pos = n, n = list_entry(n->member.next, typeof(*n), member)) +- ++#define list_for_each_entry_safe(pos, n, head, member) \ ++ for ((pos) = list_entry((head)->next, typeof(*(pos)), member), \ ++ (n) = list_entry((pos)->member.next, typeof(*(pos)), member); \ ++ &((pos)->member) != (head); \ ++ (pos) = (n), (n) = list_entry((n)->member.next, typeof(*(n)), member)) + + /* + * Insert a new entry between two known consecutive entries. +@@ -130,14 +130,12 @@ struct list_head { + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +-static inline void __list_add(struct list_head *new, +- struct list_head *prev, +- struct list_head *next) ++static inline void list_insert(struct list_head *new, struct list_head *prev, struct list_head *next) + { +- next->prev = new; +- new->next = next; +- new->prev = prev; +- prev->next = new; ++ next->prev = new; ++ new->next = next; ++ new->prev = prev; ++ prev->next = new; + } + + /** +@@ -150,7 +148,7 @@ static inline void __list_add(struct list_head *new, + */ + static inline void list_add(struct list_head *new, struct list_head *head) + { +- __list_add(new, head, head->next); ++ list_insert(new, head, head->next); + } + + /** +@@ -163,7 +161,7 @@ static inline void list_add(struct list_head *new, struct list_head *head) + */ + static inline void list_add_tail(struct list_head *new, struct list_head *head) + { +- __list_add(new, head->prev, head); ++ list_insert(new, head->prev, head); + } + + +@@ -174,10 +172,10 @@ static inline void list_add_tail(struct list_head *new, struct list_head *head) + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +-static inline void __list_del(struct list_head * prev, struct list_head * next) ++static inline void list_remove(struct list_head * prev, struct list_head * next) + { +- next->prev = prev; +- prev->next = next; ++ next->prev = prev; ++ prev->next = next; + } + + /** +@@ -188,9 +186,9 @@ static inline void __list_del(struct list_head * prev, struct list_head * next) + */ + static inline void list_del(struct list_head *entry) + { +- __list_del(entry->prev, entry->next); +- entry->next = LIST_POISON1; +- entry->prev = LIST_POISON2; ++ list_remove(entry->prev, entry->next); ++ entry->next = LIST_POISON1; ++ entry->prev = LIST_POISON2; + } + + /** +@@ -200,13 +198,12 @@ static inline void list_del(struct list_head *entry) + * + * If @old was empty, it will be overwritten. + */ +-static inline void list_replace(struct list_head *old, +- struct list_head *new) ++static inline void list_replace(struct list_head *old, struct list_head *new) + { +- new->next = old->next; +- new->next->prev = new; +- new->prev = old->prev; +- new->prev->next = new; ++ new->next = old->next; ++ new->next->prev = new; ++ new->prev = old->prev; ++ new->prev->next = new; + } + +-#endif +\ No newline at end of file ++#endif +diff --git a/upatch-diff/log.h b/upatch-diff/log.h +index 34b58bf..a109958 100644 +--- a/upatch-diff/log.h ++++ b/upatch-diff/log.h +@@ -29,43 +29,45 @@ + #include + + /* Files that include log.h must define g_loglevel and g_logprefix */ +-extern enum LogLevel g_loglevel; ++extern enum log_level g_loglevel; + extern char *g_logprefix; + +-enum exit_status{ +- EXIT_STATUS_SUCCESS = 0, +- EXIT_STATUS_ERROR = 1, +- EXIT_STATUS_DIFF_FATAL = 2, +- EXIT_STATUS_NO_CHANGE = 3, ++enum exit_status { ++ EXIT_STATUS_SUCCESS = 0, ++ EXIT_STATUS_ERROR = 1, + }; + + /* Since upatch-build is an one-shot program, we do not care about failure handler */ + #define ERROR(format, ...) \ +- error(EXIT_STATUS_ERROR, 0, "ERROR: %s: %s: %d: " format, g_logprefix, __FUNCTION__, __LINE__, ##__VA_ARGS__) +- +-#define DIFF_FATAL(format, ...) \ +- error(EXIT_STATUS_DIFF_FATAL, 0, "ERROR: %s: %s: %d: " format, g_logprefix, __FUNCTION__, __LINE__, ##__VA_ARGS__) ++ error(EXIT_STATUS_ERROR, 0, "ERROR: %s: %s: %d: " format, \ ++ g_logprefix, __FUNCTION__, __LINE__, ##__VA_ARGS__) + + /* it is time cost */ + #define log_debug(format, ...) log(DEBUG, format, ##__VA_ARGS__) +-#define log_normal(format, ...) log(NORMAL, "%s: " format, g_logprefix, ##__VA_ARGS__) +-#define log_warn(format, ...) log(WARN, "%s: " format, g_logprefix, ##__VA_ARGS__) ++#define log_normal(format, ...) log(NORMAL, format, ##__VA_ARGS__) ++#define log_warn(format, ...) log(WARN, format, ##__VA_ARGS__) ++#define log_error(format, ...) log(ERR, format, ##__VA_ARGS__) + + #define log(level, format, ...) \ +-({ \ +- if (g_loglevel <= (level)) \ +- printf(format, ##__VA_ARGS__); \ +-}) ++ do { \ ++ if (g_loglevel <= (level)) { \ ++ printf(format, ##__VA_ARGS__); \ ++ } \ ++ } while (0) + + #define REQUIRE(COND, message) \ +- do \ +- if (!(COND)) \ +- ERROR(message); \ +- while (0) ++ do { \ ++ if (!(COND)) { \ ++ ERROR(message); \ ++ } \ ++ } \ ++ while (0) + +-enum LogLevel { +- DEBUG, +- NORMAL, ++enum log_level { ++ DEBUG, ++ NORMAL, + WARN, ++ ERR, + }; +-#endif +\ No newline at end of file ++ ++#endif +diff --git a/upatch-diff/running-elf.c b/upatch-diff/running-elf.c +index c99b395..d9c1d6f 100644 +--- a/upatch-diff/running-elf.c ++++ b/upatch-diff/running-elf.c +@@ -35,7 +35,8 @@ + #include "running-elf.h" + #include "log.h" + +-/* TODO: need to judge whether running_elf is a Position-Independent Executable file ++/* TODO: ++ * need to judge whether running_elf is a Position-Independent Executable file + * https://github.com/bminor/binutils-gdb/blob/master/binutils/readelf.c + */ + static bool is_pie(void) +@@ -47,9 +48,9 @@ static bool is_exec(struct Elf *elf) + { + GElf_Ehdr ehdr; + +- if (!gelf_getehdr(elf, &ehdr)) ++ if (!gelf_getehdr(elf, &ehdr)) { + ERROR("gelf_getehdr running_file failed for %s.", elf_errmsg(0)); +- ++ } + return ehdr.e_type == ET_EXEC || (ehdr.e_type == ET_DYN && is_pie()); + } + +@@ -61,38 +62,46 @@ void relf_init(char *elf_name, struct running_elf *relf) + GElf_Sym sym; + + relf->fd = open(elf_name, O_RDONLY); +- if (relf->fd == -1) ++ if (relf->fd == -1) { + ERROR("open with errno = %d", errno); ++ } + + relf->elf = elf_begin(relf->fd, ELF_C_READ, NULL); +- if (!relf->elf) ++ if (!relf->elf) { + ERROR("elf_begin with error %s", elf_errmsg(0)); ++ } + + relf->is_exec = is_exec(relf->elf); + + while ((scn = elf_nextscn(relf->elf, scn)) != NULL) { +- if (!gelf_getshdr(scn, &shdr)) ++ if (!gelf_getshdr(scn, &shdr)) { + ERROR("gelf_getshdr with error %s", elf_errmsg(0)); +- +- if (shdr.sh_type == SHT_SYMTAB) ++ } ++ if (shdr.sh_type == SHT_SYMTAB) { + break; ++ } + } + + data = elf_getdata(scn, NULL); +- if (!data) ++ if (!data) { + ERROR("elf_getdata with error %s", elf_errmsg(0)); ++ } + + relf->obj_nr = (int)(shdr.sh_size / shdr.sh_entsize); + relf->obj_syms = calloc((size_t)relf->obj_nr, sizeof(struct debug_symbol)); +- if (!relf->obj_syms) ++ if (!relf->obj_syms) { + ERROR("calloc with errno = %d", errno); ++ } + +- for (int i = 0; i < relf->obj_nr; i ++) { +- if (!gelf_getsym(data, i, &sym)) ++ for (int i = 0; i < relf->obj_nr; i++) { ++ if (!gelf_getsym(data, i, &sym)) { + ERROR("gelf_getsym with error %s", elf_errmsg(0)); +- relf->obj_syms[i].name = elf_strptr(relf->elf, shdr.sh_link, sym.st_name); +- if (!relf->obj_syms[i].name) ++ } ++ relf->obj_syms[i].name = elf_strptr(relf->elf, ++ shdr.sh_link, sym.st_name); ++ if (!relf->obj_syms[i].name) { + ERROR("elf_strptr with error %s", elf_errmsg(0)); ++ } + relf->obj_syms[i].type = GELF_ST_TYPE(sym.st_info); + relf->obj_syms[i].bind = GELF_ST_BIND(sym.st_info); + relf->obj_syms[i].shndx = sym.st_shndx; +@@ -112,8 +121,8 @@ int relf_close(struct running_elf *relf) + return 0; + } + +-bool lookup_relf(struct running_elf *relf, +- struct symbol *lookup_sym, struct lookup_result *result) ++bool lookup_relf(struct running_elf *relf, struct symbol *lookup_sym, ++ struct lookup_result *result) + { + struct debug_symbol *symbol = NULL; + unsigned long sympos = 0; +@@ -128,7 +137,6 @@ bool lookup_relf(struct running_elf *relf, + if (result->symbol != NULL && symbol->type == STT_FILE) { + break; + } +- + if (strcmp(symbol->name, lookup_sym->name) != 0 || + symbol->bind != lookup_sym->bind) { + continue; +diff --git a/upatch-diff/running-elf.h b/upatch-diff/running-elf.h +index b02c8e2..cdf61d1 100644 +--- a/upatch-diff/running-elf.h ++++ b/upatch-diff/running-elf.h +@@ -36,8 +36,8 @@ struct symbol; + + struct lookup_result { + struct debug_symbol *symbol; +- unsigned long sympos; +- bool global; ++ unsigned long sympos; ++ bool global; + }; + + struct debug_symbol { +@@ -62,4 +62,4 @@ int relf_close(struct running_elf *); + + bool lookup_relf(struct running_elf *, struct symbol *, struct lookup_result *); + +-#endif +\ No newline at end of file ++#endif +diff --git a/upatch-diff/upatch-dynrela.h b/upatch-diff/upatch-dynrela.h +index 7d10378..d31c9f0 100644 +--- a/upatch-diff/upatch-dynrela.h ++++ b/upatch-diff/upatch-dynrela.h +@@ -37,4 +37,4 @@ struct upatch_relocation { + struct upatch_symbol *sym; + }; + +-#endif /* __UPATCH_DYN_RELA_H_ */ +\ No newline at end of file ++#endif /* __UPATCH_DYN_RELA_H_ */ +diff --git a/upatch-diff/upatch-elf.c b/upatch-diff/upatch-elf.c +index 171e88e..a51f008 100644 +--- a/upatch-diff/upatch-elf.c ++++ b/upatch-diff/upatch-elf.c +@@ -40,36 +40,43 @@ + + static void create_section_list(struct upatch_elf *uelf) + { +- size_t shstrndx, sections_nr; ++ size_t shstrndx; ++ size_t sections_nr; + + struct section *sec; + Elf_Scn *scn = NULL; + +- if (elf_getshdrnum(uelf->elf, §ions_nr)) ++ if (elf_getshdrnum(uelf->elf, §ions_nr)) { + ERROR("elf_getshdrnum with error %s", elf_errmsg(0)); ++ } + +- sections_nr --; ++ sections_nr--; + +- if (elf_getshdrstrndx(uelf->elf, &shstrndx)) ++ if (elf_getshdrstrndx(uelf->elf, &shstrndx)) { + ERROR("elf_getshdrstrndx with error %s", elf_errmsg(0)); ++ } + +- log_debug("=== section list (%zu) === \n", sections_nr); +- while (sections_nr --) { ++ log_debug("=== section list (%zu) ===\n", sections_nr); ++ while (sections_nr--) { + ALLOC_LINK(sec, &uelf->sections); + + scn = elf_nextscn(uelf->elf, scn); +- if (!scn) ++ if (!scn) { + ERROR("elf_nextscn with error %s", elf_errmsg(0)); +- +- if (!gelf_getshdr(scn, &sec->sh)) ++ } ++ if (!gelf_getshdr(scn, &sec->sh)) { + ERROR("gelf_getshdr with error %s", elf_errmsg(0)); ++ } + + sec->name = elf_strptr(uelf->elf, shstrndx, sec->sh.sh_name); +- if (!sec->name) ++ if (!sec->name) { + ERROR("elf_strptr with error %s", elf_errmsg(0)); ++ } ++ + sec->data = elf_getdata(scn, NULL); +- if (!sec->data) ++ if (!sec->data) { + ERROR("elf_getdata with error %s", elf_errmsg(0)); ++ } + + sec->name_source = DATA_SOURCE_ELF; + sec->data_source = DATA_SOURCE_ELF; +@@ -77,46 +84,52 @@ static void create_section_list(struct upatch_elf *uelf) + + sec->index = (unsigned int)elf_ndxscn(scn); + /* found extended section header */ +- if (sec->sh.sh_type == SHT_SYMTAB_SHNDX) ++ if (sec->sh.sh_type == SHT_SYMTAB_SHNDX) { + uelf->symtab_shndx = sec->data; /* correct ? */ ++ } + + log_debug("ndx %02d, data %p, size %zu, name %s\n", + sec->index, sec->data->d_buf, sec->data->d_size, sec->name); + } + +- if (elf_nextscn(uelf->elf, scn)) ++ if (elf_nextscn(uelf->elf, scn)) { + ERROR("elf_nextscn with error %s", elf_errmsg(0)); ++ } + } + + static void create_symbol_list(struct upatch_elf *uelf) + { + struct section *symtab; +- unsigned int symbols_nr; + Elf32_Word shndx; +- struct symbol *sym; ++ ++ unsigned int symbols_nr; + unsigned int index = 0; ++ struct symbol *sym; + + /* consider type first */ + symtab = find_section_by_name(&uelf->sections, ".symtab"); +- if (!symtab) ++ if (!symtab) { + ERROR("can't find symbol table"); ++ } + + symbols_nr = (unsigned int)(symtab->sh.sh_size / symtab->sh.sh_entsize); + + log_debug("\n=== symbol list (%d entries) ===\n", symbols_nr); +- while (symbols_nr --) { ++ while (symbols_nr--) { + ALLOC_LINK(sym, &uelf->symbols); + INIT_LIST_HEAD(&sym->children); + + sym->index = index; +- if (!gelf_getsym(symtab->data, (int)index, &sym->sym)) ++ if (!gelf_getsym(symtab->data, (int)index, &sym->sym)) { + ERROR("gelf_getsym with error %s", elf_errmsg(0)); ++ } + +- index ++; ++ index++; + + sym->name = elf_strptr(uelf->elf, symtab->sh.sh_link, sym->sym.st_name); +- if (!sym->name) ++ if (!sym->name) { + ERROR("elf_strptr with error %s", elf_errmsg(0)); ++ } + + sym->type = GELF_ST_TYPE(sym->sym.st_info); + sym->bind = GELF_ST_BIND(sym->sym.st_info); +@@ -125,70 +138,74 @@ static void create_symbol_list(struct upatch_elf *uelf) + /* releated section located in extended header */ + if (shndx == SHN_XINDEX && + !gelf_getsymshndx(symtab->data, uelf->symtab_shndx, +- (int)sym->index, &sym->sym, &shndx)) ++ (int)sym->index, &sym->sym, &shndx)) { + ERROR("gelf_getsymshndx with error %s", elf_errmsg(0)); +- +- if ((sym->sym.st_shndx > SHN_UNDEF && sym->sym.st_shndx < SHN_LORESERVE) || +- sym->sym.st_shndx == SHN_XINDEX) { +- ++ } ++ if (sym->sym.st_shndx == SHN_XINDEX || ++ (sym->sym.st_shndx > SHN_UNDEF && ++ sym->sym.st_shndx < SHN_LORESERVE)) { + sym->sec = find_section_by_index(&uelf->sections, shndx); +- if (!sym->sec) +- ERROR("no releated section found for symbol %s \n", sym->name); ++ if (!sym->sec) { ++ ERROR("no releated section found for symbol %s\n", sym->name); ++ } + + /* this symbol is releated with a section */ + if (sym->type == STT_SECTION) { + /* secsym must be the bundleable symbol */ + sym->sec->secsym = sym; +- + /* use section name as symbol name */ + sym->name = sym->sec->name; + } + } + log_debug("sym %02d, type %d, bind %d, ndx %02d, name %s", +- sym->index, sym->type, sym->bind, sym->sym.st_shndx, +- sym->name); +- if (sym->sec) ++ sym->index, sym->type, sym->bind, sym->sym.st_shndx, sym->name); ++ if (sym->sec) { + log_debug(" -> %s", sym->sec->name); ++ } + log_debug("\n"); + } + } + + static void create_rela_list(struct upatch_elf *uelf, struct section *relasec) + { ++ struct rela *rela; + unsigned long rela_nr; ++ + unsigned int symndx; +- struct rela *rela; +- int index = 0, skip = 0; ++ int index = 0; ++ int skip = 0; + + INIT_LIST_HEAD(&relasec->relas); + +- /* for relocation sections, sh_info is the index which these informations apply */ ++ /* for relocation sections, sh_info is the index which these info apply */ + relasec->base = find_section_by_index(&uelf->sections, relasec->sh.sh_info); +- if (!relasec->base) ++ if (!relasec->base) { + ERROR("no base section found for relocation section %s", relasec->name); ++ } + + relasec->base->rela = relasec; + rela_nr = relasec->sh.sh_size / relasec->sh.sh_entsize; + +- log_debug("\n=== rela list for %s (%ld entries) === \n", ++ log_debug("\n=== rela list for %s (%ld entries) ===\n", + relasec->base->name, rela_nr); + + if (is_debug_section(relasec)) { +- log_debug("skipping rela listing for .debug_* section \n"); ++ log_debug("skipping rela listing for .debug_* section\n"); + skip = 1; + } + + if (is_note_section(relasec)) { +- log_debug("skipping rela listing for .note_* section \n"); ++ log_debug("skipping rela listing for .note_* section\n"); + skip = 1; + } + +- while (rela_nr --) { ++ while (rela_nr--) { + ALLOC_LINK(rela, &relasec->relas); + + /* use index because we need to keep the order of rela */ +- if (!gelf_getrela(relasec->data, index, &rela->rela)) ++ if (!gelf_getrela(relasec->data, index, &rela->rela)) { + ERROR("gelf_getrela with error %s", elf_errmsg(0)); ++ } + index++; + + rela->type = GELF_R_TYPE(rela->rela.r_info); +@@ -196,33 +213,39 @@ static void create_rela_list(struct upatch_elf *uelf, struct section *relasec) + rela->offset = (unsigned int)rela->rela.r_offset; + symndx = (unsigned int)GELF_R_SYM(rela->rela.r_info); + rela->sym = find_symbol_by_index(&uelf->symbols, symndx); +- if (!rela->sym) +- ERROR("no rela entry symbol found \n"); ++ if (!rela->sym) { ++ ERROR("no rela entry symbol found\n"); ++ } + + if (rela->sym->sec && is_string_section(rela->sym->sec)) { + rela->string = rela->sym->sec->data->d_buf + + rela->sym->sym.st_value + + rela_target_offset(uelf, relasec, rela); +- if (!rela->string) ++ if (!rela->string) { + ERROR("could not lookup rela string for %s+%ld", + rela->sym->name, rela->addend); ++ } + } + +- if (skip) ++ if (skip) { + continue; ++ } + + log_debug("offset %ld, type %d, %s %s %ld", rela->offset, + rela->type, rela->sym->name, + (rela->addend < 0) ? "-" : "+", labs(rela->addend)); +- if (rela->string) // rela->string is not utf8 ++ if (rela->string) { ++ // rela->string is not utf8 + log_debug(" string = %s", rela->string); ++ } + log_debug("\n"); + } + } + + static void destroy_rela_list(struct section *relasec) + { +- struct rela *rela = NULL, *saferela = NULL; ++ struct rela *rela = NULL; ++ struct rela *saferela = NULL; + + list_for_each_entry_safe(rela, saferela, &relasec->relas, list) { + list_del(&rela->list); +@@ -234,7 +257,8 @@ static void destroy_rela_list(struct section *relasec) + + static void destroy_section_list(struct upatch_elf *uelf) + { +- struct section *sec = NULL, *safesec = NULL; ++ struct section *sec = NULL; ++ struct section *safesec = NULL; + + list_for_each_entry_safe(sec, safesec, &uelf->sections, list) { + if (sec->twin) { +@@ -270,7 +294,8 @@ static void destroy_section_list(struct upatch_elf *uelf) + + static void destroy_symbol_list(struct upatch_elf *uelf) + { +- struct symbol *sym = NULL, *safesym = NULL; ++ struct symbol *sym = NULL; ++ struct symbol *safesym = NULL; + + list_for_each_entry_safe(sym, safesym, &uelf->symbols, list) { + if (sym->twin) { +@@ -286,7 +311,8 @@ static void destroy_symbol_list(struct upatch_elf *uelf) + + static void destroy_string_list(struct upatch_elf *uelf) + { +- struct string *str = NULL, *safestr = NULL; ++ struct string *str = NULL; ++ struct string *safestr = NULL; + + list_for_each_entry_safe(str, safestr, &uelf->strings, list) { + list_del(&str->list); +@@ -298,18 +324,22 @@ static void destroy_string_list(struct upatch_elf *uelf) + + void upatch_elf_open(struct upatch_elf *uelf, const char *name) + { ++ int fd = 1; ++ ++ Elf *elf = NULL; ++ + GElf_Ehdr ehdr; + struct section *sec; +- Elf *elf = NULL; +- int fd = 1; + + fd = open(name, O_RDONLY); +- if (fd == -1) +- ERROR("open %s failed with errno %d \n", name, errno); ++ if (fd == -1) { ++ ERROR("open %s failed with errno %d\n", name, errno); ++ } + + elf = elf_begin(fd, ELF_C_RDWR, NULL); +- if (!elf) +- ERROR("open elf %s failed with error %s \n", name, elf_errmsg(0)); ++ if (!elf) { ++ ERROR("open elf %s failed with error %s\n", name, elf_errmsg(0)); ++ } + + memset(uelf, 0, sizeof(*uelf)); + INIT_LIST_HEAD(&uelf->sections); +@@ -319,27 +349,27 @@ void upatch_elf_open(struct upatch_elf *uelf, const char *name) + uelf->elf = elf; + uelf->fd = fd; + +- if (!gelf_getehdr(uelf->elf, &ehdr)) +- ERROR("get file %s elf header failed with error %s \n", +- name, elf_errmsg(0)); +- +- /* TODO: check ELF type here, we only handle object file */ +- if (ehdr.e_type != ET_REL) +- ERROR("only handles relocatable files \n"); ++ if (!gelf_getehdr(uelf->elf, &ehdr)) { ++ ERROR("get file %s elf header failed with error %s\n", name, ++ elf_errmsg(0)); ++ } ++ if (ehdr.e_type != ET_REL) { ++ ERROR("only handles relocatable files\n"); ++ } + + /* + * Main problem here is stack check, for kernel, only x86 is support + * Not sure how to handle userspace, but let us handle x86 first here + */ + switch (ehdr.e_machine) { +- case EM_AARCH64: +- uelf->arch = AARCH64; +- break; +- case EM_X86_64: +- uelf->arch = X86_64; +- break; +- default: +- ERROR("unsupported architecture here"); ++ case EM_AARCH64: ++ uelf->arch = AARCH64; ++ break; ++ case EM_X86_64: ++ uelf->arch = X86_64; ++ break; ++ default: ++ ERROR("unsupported architecture here"); + } + + create_section_list(uelf); +diff --git a/upatch-diff/upatch-elf.h b/upatch-diff/upatch-elf.h +index 6c62c93..030feca 100644 +--- a/upatch-diff/upatch-elf.h ++++ b/upatch-diff/upatch-elf.h +@@ -40,102 +40,102 @@ struct rela; + struct symbol; + + enum data_source { +- DATA_SOURCE_ELF, +- DATA_SOURCE_REF, +- DATA_SOURCE_ALLOC, ++ DATA_SOURCE_ELF, ++ DATA_SOURCE_REF, ++ DATA_SOURCE_ALLOC, + }; + + enum status { +- NEW, +- CHANGED, +- SAME ++ NEW, ++ CHANGED, ++ SAME + }; + + enum symbol_strip { +- SYMBOL_DEFAULT, +- SYMBOL_USED, +- SYMBOL_STRIP, ++ SYMBOL_DEFAULT, ++ SYMBOL_USED, ++ SYMBOL_STRIP, + }; + + struct string { +- struct list_head list; +- char *name; ++ struct list_head list; ++ char *name; + }; + + struct section { +- struct list_head list; +- struct section *twin; +- char *name; +- Elf_Data *data; +- enum data_source name_source; +- enum data_source data_source; +- enum data_source dbuf_source; +- GElf_Shdr sh; +- int ignore; +- int include; +- int grouped; +- unsigned int index; +- enum status status; +- union { ++ struct list_head list; ++ struct section *twin; ++ char *name; ++ Elf_Data *data; ++ enum data_source name_source; ++ enum data_source data_source; ++ enum data_source dbuf_source; ++ GElf_Shdr sh; ++ int ignore; ++ int include; ++ int grouped; ++ unsigned int index; ++ enum status status; ++ union { + // section with relocation information +- struct { +- struct section *base; +- struct list_head relas; +- }; ++ struct { ++ struct section *base; ++ struct list_head relas; ++ }; + // other function or data section +- struct { +- struct section *rela; +- struct symbol *sym; +- struct symbol *secsym; +- }; +- }; ++ struct { ++ struct section *rela; ++ struct symbol *sym; ++ struct symbol *secsym; ++ }; ++ }; + }; + + struct rela { +- struct list_head list; +- GElf_Rela rela; +- struct symbol *sym; +- unsigned int type; +- unsigned long offset; +- long addend; +- char *string; +- bool need_dynrela; ++ struct list_head list; ++ GElf_Rela rela; ++ struct symbol *sym; ++ unsigned int type; ++ unsigned long offset; ++ long addend; ++ char *string; ++ bool need_dynrela; + }; + + struct symbol { +- struct list_head list; +- struct symbol *twin; +- struct symbol *parent; +- struct list_head children; +- struct list_head subfunction_node; +- struct section *sec; +- GElf_Sym sym; +- char *name; +- enum data_source name_source; +- struct debug_symbol *relf_sym; +- unsigned int index; +- unsigned char bind; +- unsigned char type; +- enum status status; +- union { +- int include; /* used in the patched elf */ +- enum symbol_strip strip; /* used in the output elf */ +- }; ++ struct list_head list; ++ struct symbol *twin; ++ struct symbol *parent; ++ struct list_head children; ++ struct list_head subfunction_node; ++ struct section *sec; ++ GElf_Sym sym; ++ char *name; ++ enum data_source name_source; ++ struct debug_symbol *relf_sym; ++ unsigned int index; ++ unsigned char bind; ++ unsigned char type; ++ enum status status; ++ union { ++ int include; /* used in the patched elf */ ++ enum symbol_strip strip; /* used in the output elf */ ++ }; + }; + + enum architecture { +- X86_64 = 0x1 << 0, +- AARCH64 = 0x1 << 1, ++ X86_64 = 0x1 << 0, ++ AARCH64 = 0x1 << 1, + }; + + struct upatch_elf { +- Elf *elf; +- enum architecture arch; +- struct list_head sections; +- struct list_head symbols; +- struct list_head strings; +- Elf_Data *symtab_shndx; +- int fd; ++ Elf *elf; ++ enum architecture arch; ++ struct list_head sections; ++ struct list_head symbols; ++ struct list_head strings; ++ Elf_Data *symtab_shndx; ++ int fd; + }; + + // init a upatch_elf from a path +diff --git a/upatch-diff/upatch-patch.h b/upatch-diff/upatch-patch.h +index 5e2abce..ec0148f 100644 +--- a/upatch-diff/upatch-patch.h ++++ b/upatch-diff/upatch-patch.h +@@ -23,7 +23,7 @@ + #ifndef __UPATCH_PATCH_H_ + #define __UPATCH_PATCH_H_ + +-#define SYM_OTHER 0x40 ++#define SYM_OTHER 0x40 + + struct upatch_patch_func { + unsigned long new_addr; +@@ -34,4 +34,4 @@ struct upatch_patch_func { + char *name; + }; + +-#endif /* __UPATCH_PATCH_H_ */ +\ No newline at end of file ++#endif /* __UPATCH_PATCH_H_ */ +-- +2.34.1 + diff --git a/0013-upatch-manage-format-code.patch b/0013-upatch-manage-format-code.patch new file mode 100644 index 0000000..f915b9c --- /dev/null +++ b/0013-upatch-manage-format-code.patch @@ -0,0 +1,8180 @@ +From 9356dfedc5a242df73febf40eccb428347c3a7ce Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Mon, 17 Feb 2025 15:41:50 +0800 +Subject: [PATCH] upatch-manage: format code + +Signed-off-by: renoseven +--- + upatch-manage/arch/aarch64/insn.c | 203 +-- + upatch-manage/arch/aarch64/insn.h | 34 +- + upatch-manage/arch/aarch64/ptrace.c | 307 ++--- + upatch-manage/arch/aarch64/relocation.c | 562 ++++---- + upatch-manage/arch/aarch64/resolve.c | 201 ++- + upatch-manage/arch/x86_64/ptrace.c | 260 ++-- + upatch-manage/arch/x86_64/relocation.c | 207 +-- + upatch-manage/arch/x86_64/resolve.c | 161 ++- + upatch-manage/list.h | 400 +++--- + upatch-manage/log.h | 61 +- + upatch-manage/upatch-common.c | 4 +- + upatch-manage/upatch-common.h | 47 +- + upatch-manage/upatch-elf.c | 80 +- + upatch-manage/upatch-elf.h | 148 +-- + upatch-manage/upatch-manage.c | 299 ++--- + upatch-manage/upatch-patch.c | 1602 +++++++++++------------ + upatch-manage/upatch-process.c | 1373 +++++++++---------- + upatch-manage/upatch-process.h | 116 +- + upatch-manage/upatch-ptrace.c | 414 +++--- + upatch-manage/upatch-ptrace.h | 41 +- + upatch-manage/upatch-relocation.c | 61 +- + upatch-manage/upatch-relocation.h | 2 +- + upatch-manage/upatch-resolve.c | 78 +- + upatch-manage/upatch-resolve.h | 10 +- + upatch-manage/upatch-stack-check.c | 22 +- + upatch-manage/upatch-stack-check.h | 6 +- + 26 files changed, 3405 insertions(+), 3294 deletions(-) + +diff --git a/upatch-manage/arch/aarch64/insn.c b/upatch-manage/arch/aarch64/insn.c +index bb61f77..63f6227 100644 +--- a/upatch-manage/arch/aarch64/insn.c ++++ b/upatch-manage/arch/aarch64/insn.c +@@ -11,120 +11,121 @@ + #include "insn.h" + + static int aarch64_get_imm_shift_mask(enum aarch64_insn_imm_type type, +- u32 *maskp, int *shiftp) ++ u32 *maskp, int *shiftp) + { +- u32 mask; +- int shift; +- +- switch (type) { +- case AARCH64_INSN_IMM_26: +- mask = BIT(26) - 1; +- shift = 0; +- break; +- case AARCH64_INSN_IMM_19: +- mask = BIT(19) - 1; +- shift = 5; +- break; +- case AARCH64_INSN_IMM_16: +- mask = BIT(16) - 1; +- shift = 5; +- break; +- case AARCH64_INSN_IMM_14: +- mask = BIT(14) - 1; +- shift = 5; +- break; +- case AARCH64_INSN_IMM_12: +- mask = BIT(12) - 1; +- shift = 10; +- break; +- case AARCH64_INSN_IMM_9: +- mask = BIT(9) - 1; +- shift = 12; +- break; +- case AARCH64_INSN_IMM_7: +- mask = BIT(7) - 1; +- shift = 15; +- break; +- case AARCH64_INSN_IMM_6: +- case AARCH64_INSN_IMM_S: +- mask = BIT(6) - 1; +- shift = 10; +- break; +- case AARCH64_INSN_IMM_R: +- mask = BIT(6) - 1; +- shift = 16; +- break; +- case AARCH64_INSN_IMM_N: +- mask = 1; +- shift = 22; +- break; +- default: +- return -EINVAL; +- } +- +- *maskp = mask; +- *shiftp = shift; +- +- return 0; ++ u32 mask; ++ int shift; ++ ++ switch (type) { ++ case AARCH64_INSN_IMM_26: ++ mask = BIT(26) - 1; ++ shift = 0; ++ break; ++ case AARCH64_INSN_IMM_19: ++ mask = BIT(19) - 1; ++ shift = 5; ++ break; ++ case AARCH64_INSN_IMM_16: ++ mask = BIT(16) - 1; ++ shift = 5; ++ break; ++ case AARCH64_INSN_IMM_14: ++ mask = BIT(14) - 1; ++ shift = 5; ++ break; ++ case AARCH64_INSN_IMM_12: ++ mask = BIT(12) - 1; ++ shift = 10; ++ break; ++ case AARCH64_INSN_IMM_9: ++ mask = BIT(9) - 1; ++ shift = 12; ++ break; ++ case AARCH64_INSN_IMM_7: ++ mask = BIT(7) - 1; ++ shift = 15; ++ break; ++ case AARCH64_INSN_IMM_6: ++ case AARCH64_INSN_IMM_S: ++ mask = BIT(6) - 1; ++ shift = 10; ++ break; ++ case AARCH64_INSN_IMM_R: ++ mask = BIT(6) - 1; ++ shift = 16; ++ break; ++ case AARCH64_INSN_IMM_N: ++ mask = 1; ++ shift = 22; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ *maskp = mask; ++ *shiftp = shift; ++ ++ return 0; + } + +-u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, u32 insn, +- u64 imm) ++u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, ++ u32 insn, u64 imm) + { +- u32 immlo, immhi, mask; +- int shift; +- +- if (insn == AARCH64_BREAK_FAULT) +- return AARCH64_BREAK_FAULT; +- +- switch (type) { +- case AARCH64_INSN_IMM_ADR: +- shift = 0; +- immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT; +- imm >>= ADR_IMM_HILOSPLIT; +- immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT; +- imm = immlo | immhi; +- mask = ((ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) | +- (ADR_IMM_HIMASK << ADR_IMM_HISHIFT)); +- break; +- default: +- if (aarch64_get_imm_shift_mask(type, &mask, &shift) < 0) { +- log_error("upatch: unknown immediate encoding %d\n", +- type); +- return AARCH64_BREAK_FAULT; +- } +- } +- +- /* Update the immediate field. */ +- insn &= ~(mask << shift); +- insn |= (u32)(imm & mask) << shift; +- +- return insn; ++ u32 immlo; ++ u32 immhi; ++ u32 mask; ++ ++ int shift; ++ ++ if (insn == AARCH64_BREAK_FAULT) { ++ return AARCH64_BREAK_FAULT; ++ } ++ ++ switch (type) { ++ case AARCH64_INSN_IMM_ADR: ++ shift = 0; ++ immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT; ++ imm >>= ADR_IMM_HILOSPLIT; ++ immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT; ++ imm = immlo | immhi; ++ mask = ((ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) | ++ (ADR_IMM_HIMASK << ADR_IMM_HISHIFT)); ++ break; ++ default: ++ if (aarch64_get_imm_shift_mask(type, &mask, &shift) < 0) { ++ log_error("upatch: unknown immediate encoding %d\n", type); ++ return AARCH64_BREAK_FAULT; ++ } ++ } ++ ++ /* Update the immediate field. */ ++ insn &= ~(mask << shift); ++ insn |= (u32)(imm & mask) << shift; ++ ++ return insn; + } + + s64 extract_insn_imm(s64 sval, int len, int lsb) + { +- s64 imm, imm_mask; ++ s64 imm; ++ s64 imm_mask; + +- imm = sval >> lsb; +- imm_mask = (s64)((BIT(lsb + len) - 1) >> lsb); +- imm = imm & imm_mask; ++ imm = sval >> lsb; ++ imm_mask = (s64)((BIT(lsb + len) - 1) >> lsb); ++ imm = imm & imm_mask; + +- log_debug("upatch: extract imm, X=0x%lx, X[%d:%d]=0x%lx\n", sval, +- (len + lsb - 1), lsb, imm); +- return imm; ++ log_debug("upatch: extract imm, X=0x%lx, X[%d:%d]=0x%lx\n", ++ sval, (len + lsb - 1), lsb, imm); ++ return imm; + } + + s32 insert_insn_imm(enum aarch64_insn_imm_type imm_type, void *place, u64 imm) + { +- u32 insn, new_insn; ++ u32 insn = le32_to_cpu(*(__le32 *)place); ++ u32 new_insn = aarch64_insn_encode_immediate(imm_type, insn, imm); + +- insn = le32_to_cpu(*(__le32 *)place); +- new_insn = aarch64_insn_encode_immediate(imm_type, insn, imm); +- +- log_debug( +- "upatch: insert imm, P=0x%lx, insn=0x%x, imm_type=%d, imm=0x%lx, " +- "new_insn=0x%x\n", +- (u64)place, insn, imm_type, imm, new_insn); +- return (s32)new_insn; ++ log_debug("upatch: inset imm" ++ "P=0x%lx, insn=0x%x, imm_type=%d, imm=0x%lx, new_insn=0x%x\n", ++ (u64)place, insn, imm_type, imm, new_insn); ++ return (s32)new_insn; + } +diff --git a/upatch-manage/arch/aarch64/insn.h b/upatch-manage/arch/aarch64/insn.h +index 76a9689..8efc81b 100644 +--- a/upatch-manage/arch/aarch64/insn.h ++++ b/upatch-manage/arch/aarch64/insn.h +@@ -15,19 +15,19 @@ + #include "upatch-relocation.h" + + enum aarch64_insn_imm_type { +- AARCH64_INSN_IMM_ADR, +- AARCH64_INSN_IMM_26, +- AARCH64_INSN_IMM_19, +- AARCH64_INSN_IMM_16, +- AARCH64_INSN_IMM_14, +- AARCH64_INSN_IMM_12, +- AARCH64_INSN_IMM_9, +- AARCH64_INSN_IMM_7, +- AARCH64_INSN_IMM_6, +- AARCH64_INSN_IMM_S, +- AARCH64_INSN_IMM_R, +- AARCH64_INSN_IMM_N, +- AARCH64_INSN_IMM_MAX ++ AARCH64_INSN_IMM_ADR, ++ AARCH64_INSN_IMM_26, ++ AARCH64_INSN_IMM_19, ++ AARCH64_INSN_IMM_16, ++ AARCH64_INSN_IMM_14, ++ AARCH64_INSN_IMM_12, ++ AARCH64_INSN_IMM_9, ++ AARCH64_INSN_IMM_7, ++ AARCH64_INSN_IMM_6, ++ AARCH64_INSN_IMM_S, ++ AARCH64_INSN_IMM_R, ++ AARCH64_INSN_IMM_N, ++ AARCH64_INSN_IMM_MAX + }; + + #define SZ_2M 0x00200000 +@@ -61,11 +61,11 @@ enum aarch64_insn_imm_type { + #define cpu_to_le32(val) bswap_32(val) + #endif + +-u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, u32 insn, +- u64 imm); ++u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, ++ u32 insn, u64 imm); + +-s64 extract_insn_imm(s64, int, int); ++s64 extract_insn_imm(s64 sval, int len, int lsb); + +-s32 insert_insn_imm(enum aarch64_insn_imm_type, void *, u64); ++s32 insert_insn_imm(enum aarch64_insn_imm_type imm_type, void *place, u64 imm); + + #endif /* _ARCH_AARCH64_INSN_H */ +diff --git a/upatch-manage/arch/aarch64/ptrace.c b/upatch-manage/arch/aarch64/ptrace.c +index 247e544..131e0dd 100644 +--- a/upatch-manage/arch/aarch64/ptrace.c ++++ b/upatch-manage/arch/aarch64/ptrace.c +@@ -28,185 +28,194 @@ + + #define ORIGIN_INSN_LEN 16 + ++#define UPATCH_INSN_LEN 8 ++#define UPATCH_ADDR_LEN 8 ++ + int upatch_arch_reg_init(int pid, unsigned long *sp, unsigned long *pc) + { +- struct iovec regs_iov; +- struct user_regs_struct regs; +- +- regs_iov.iov_base = ®s; +- regs_iov.iov_len = sizeof(regs); +- +- if (ptrace(PTRACE_GETREGSET, pid, +- (void *)NT_PRSTATUS, (void *)®s_iov) < 0) { +- log_error("Cannot get regs from %d\n", pid); +- return -1; +- } +- *sp = (unsigned long)regs.sp; +- *pc = (unsigned long)regs.pc; +- return 0; ++ struct iovec regs_iov; ++ struct user_regs_struct regs; ++ ++ regs_iov.iov_base = ®s; ++ regs_iov.iov_len = sizeof(regs); ++ ++ if (ptrace(PTRACE_GETREGSET, pid, ++ (void *)NT_PRSTATUS, (void *)®s_iov) < 0) { ++ log_error("Cannot get regs from %d\n", pid); ++ return -1; ++ } ++ *sp = (unsigned long)regs.sp; ++ *pc = (unsigned long)regs.pc; ++ ++ return 0; + } + long upatch_arch_syscall_remote(struct upatch_ptrace_ctx *pctx, int nr, +- unsigned long arg1, unsigned long arg2, +- unsigned long arg3, unsigned long arg4, +- unsigned long arg5, unsigned long arg6, +- unsigned long *res) ++ unsigned long arg1, unsigned long arg2, ++ unsigned long arg3, unsigned long arg4, ++ unsigned long arg5, unsigned long arg6, ++ unsigned long *res) + { +- struct user_regs_struct regs; +- unsigned char syscall[] = { +- 0x01, 0x00, 0x00, 0xd4, // 0xd4000001 svc #0 = syscall +- 0xa0, 0x00, 0x20, 0xd4, // 0xd42000a0 brk #5 = int3 +- }; +- long ret; +- +- log_debug("Executing syscall %d (pid %d)...\n", nr, pctx->pid); +- regs.regs[8] = (unsigned long long)nr; +- regs.regs[0] = arg1; +- regs.regs[1] = arg2; +- regs.regs[2] = arg3; +- regs.regs[3] = arg4; +- regs.regs[4] = arg5; +- regs.regs[5] = arg6; +- +- ret = upatch_execute_remote(pctx, syscall, sizeof(syscall), ®s); +- if (ret == 0) +- *res = regs.regs[0]; +- +- return ret; ++ struct user_regs_struct regs; ++ unsigned char syscall[] = { ++ 0x01, 0x00, 0x00, 0xd4, // 0xd4000001 svc #0 = syscall ++ 0xa0, 0x00, 0x20, 0xd4, // 0xd42000a0 brk #5 = int3 ++ }; ++ long ret; ++ ++ log_debug("Executing syscall %d (pid %d)...\n", nr, pctx->pid); ++ regs.regs[8] = (unsigned long long)nr; ++ regs.regs[0] = arg1; ++ regs.regs[1] = arg2; ++ regs.regs[2] = arg3; ++ regs.regs[3] = arg4; ++ regs.regs[4] = arg5; ++ regs.regs[5] = arg6; ++ ++ ret = upatch_execute_remote(pctx, syscall, sizeof(syscall), ®s); ++ if (ret == 0) { ++ *res = regs.regs[0]; ++ } ++ ++ return ret; + } + + long upatch_arch_execute_remote_func(struct upatch_ptrace_ctx *pctx, +- const unsigned char *code, size_t codelen, +- struct user_regs_struct *pregs, +- int (*func)(struct upatch_ptrace_ctx *pctx, +- const void *data), +- const void *data) ++ const unsigned char *code, size_t codelen, ++ struct user_regs_struct *pregs, ++ int (*func)(struct upatch_ptrace_ctx *pctx, const void *data), ++ const void *data) + { +- long ret; +- struct user_regs_struct orig_regs, regs; +- struct iovec orig_regs_iov, regs_iov; +- struct upatch_process *proc = pctx->proc; +- unsigned long libc_base = proc->libc_base; +- unsigned char *orig_code = (unsigned char *)malloc(sizeof(*orig_code) * codelen); +- +- if (orig_code == NULL) { +- log_error("Malloc orig_code failed\n"); +- return -1; +- } +- +- orig_regs_iov.iov_base = &orig_regs; +- orig_regs_iov.iov_len = sizeof(orig_regs); +- regs_iov.iov_base = ®s; +- regs_iov.iov_len = sizeof(regs); +- +- ret = ptrace(PTRACE_GETREGSET, pctx->pid, (void *)NT_PRSTATUS, +- (void *)&orig_regs_iov); +- if (ret < 0) { +- log_error("can't get regs - %d\n", pctx->pid); +- free(orig_code); +- return -1; +- } +- ret = upatch_process_mem_read(proc, libc_base, +- (unsigned long *)orig_code, codelen); +- if (ret < 0) { +- log_error("can't peek original code - %d\n", pctx->pid); +- free(orig_code); +- return -1; +- } +- ret = upatch_process_mem_write(proc, code, libc_base, +- codelen); +- if (ret < 0) { +- log_error("can't poke syscall code - %d\n", pctx->pid); +- goto poke_back; +- } +- +- regs = orig_regs; +- regs.pc = libc_base; +- +- copy_regs(®s, pregs); +- +- ret = ptrace(PTRACE_SETREGSET, pctx->pid, (void *)NT_PRSTATUS, +- (void *)®s_iov); +- if (ret < 0) { +- log_error("can't set regs - %d\n", pctx->pid); +- goto poke_back; +- } +- +- ret = func(pctx, data); +- if (ret < 0) { +- log_error("failed call to func\n"); +- goto poke_back; +- } +- +- ret = ptrace(PTRACE_GETREGSET, pctx->pid, (void *)NT_PRSTATUS, +- (void *)®s_iov); +- if (ret < 0) { +- log_error("can't get updated regs - %d\n", pctx->pid); +- goto poke_back; +- } +- +- ret = ptrace(PTRACE_SETREGSET, pctx->pid, (void *)NT_PRSTATUS, +- (void *)&orig_regs_iov); +- if (ret < 0) { +- log_error("can't restore regs - %d\n", pctx->pid); +- goto poke_back; +- } +- +- *pregs = regs; ++ long ret; ++ ++ struct user_regs_struct orig_regs; ++ struct user_regs_struct regs; ++ ++ struct iovec orig_regs_iov; ++ struct iovec regs_iov; ++ ++ struct upatch_process *proc = pctx->proc; ++ unsigned long libc_base = proc->libc_base; ++ ++ unsigned char *orig_code = (unsigned char *)malloc( ++ sizeof(*orig_code) * codelen); ++ if (orig_code == NULL) { ++ log_error("Malloc orig_code failed\n"); ++ return -1; ++ } ++ ++ orig_regs_iov.iov_base = &orig_regs; ++ orig_regs_iov.iov_len = sizeof(orig_regs); ++ regs_iov.iov_base = ®s; ++ regs_iov.iov_len = sizeof(regs); ++ ++ ret = ptrace(PTRACE_GETREGSET, pctx->pid, (void *)NT_PRSTATUS, ++ (void *)&orig_regs_iov); ++ if (ret < 0) { ++ log_error("can't get regs - %d\n", pctx->pid); ++ free(orig_code); ++ return -1; ++ } ++ ret = upatch_process_mem_read(proc, libc_base, ++ (unsigned long *)orig_code, codelen); ++ if (ret < 0) { ++ log_error("can't peek original code - %d\n", pctx->pid); ++ free(orig_code); ++ return -1; ++ } ++ ret = upatch_process_mem_write(proc, code, ++ libc_base, codelen); ++ if (ret < 0) { ++ log_error("can't poke syscall code - %d\n", pctx->pid); ++ goto poke_back; ++ } ++ ++ regs = orig_regs; ++ regs.pc = libc_base; ++ copy_regs(®s, pregs); ++ ++ ret = ptrace(PTRACE_SETREGSET, pctx->pid, (void *)NT_PRSTATUS, ++ (void *)®s_iov); ++ if (ret < 0) { ++ log_error("can't set regs - %d\n", pctx->pid); ++ goto poke_back; ++ } ++ ++ ret = func(pctx, data); ++ if (ret < 0) { ++ log_error("failed call to func\n"); ++ goto poke_back; ++ } ++ ++ ret = ptrace(PTRACE_GETREGSET, pctx->pid, (void *)NT_PRSTATUS, ++ (void *)®s_iov); ++ if (ret < 0) { ++ log_error("can't get updated regs - %d\n", pctx->pid); ++ goto poke_back; ++ } ++ ++ ret = ptrace(PTRACE_SETREGSET, pctx->pid, (void *)NT_PRSTATUS, ++ (void *)&orig_regs_iov); ++ if (ret < 0) { ++ log_error("can't restore regs - %d\n", pctx->pid); ++ goto poke_back; ++ } ++ ++ *pregs = regs; + + poke_back: +- upatch_process_mem_write(proc, (unsigned long *)orig_code, libc_base, +- codelen); +- free(orig_code); +- return ret; ++ upatch_process_mem_write(proc, (unsigned long *)orig_code, ++ libc_base, codelen); ++ ++ free(orig_code); ++ return ret; + } + + void copy_regs(struct user_regs_struct *dst, struct user_regs_struct *src) + { + #define COPY_REG(x) dst->x = src->x +- COPY_REG(regs[0]); +- COPY_REG(regs[1]); +- COPY_REG(regs[2]); +- COPY_REG(regs[3]); +- COPY_REG(regs[4]); +- COPY_REG(regs[5]); +- COPY_REG(regs[8]); +- COPY_REG(regs[29]); +- +- COPY_REG(regs[9]); +- COPY_REG(regs[10]); +- COPY_REG(regs[11]); +- COPY_REG(regs[12]); +- COPY_REG(regs[13]); +- COPY_REG(regs[14]); +- COPY_REG(regs[15]); +- COPY_REG(regs[16]); +- COPY_REG(regs[17]); +- COPY_REG(regs[18]); +- COPY_REG(regs[19]); +- COPY_REG(regs[20]); ++ COPY_REG(regs[0]); ++ COPY_REG(regs[1]); ++ COPY_REG(regs[2]); ++ COPY_REG(regs[3]); ++ COPY_REG(regs[4]); ++ COPY_REG(regs[5]); ++ COPY_REG(regs[8]); ++ COPY_REG(regs[29]); ++ ++ COPY_REG(regs[9]); ++ COPY_REG(regs[10]); ++ COPY_REG(regs[11]); ++ COPY_REG(regs[12]); ++ COPY_REG(regs[13]); ++ COPY_REG(regs[14]); ++ COPY_REG(regs[15]); ++ COPY_REG(regs[16]); ++ COPY_REG(regs[17]); ++ COPY_REG(regs[18]); ++ COPY_REG(regs[19]); ++ COPY_REG(regs[20]); + #undef COPY_REG + } + + size_t get_origin_insn_len(void) + { +- return ORIGIN_INSN_LEN; ++ return ORIGIN_INSN_LEN; + } +-#define UPATCH_INSN_LEN 8 +-#define UPATCH_ADDR_LEN 8 ++ + size_t get_upatch_insn_len(void) + { +- return UPATCH_INSN_LEN; ++ return UPATCH_INSN_LEN; + } + + size_t get_upatch_addr_len(void) + { +- return UPATCH_ADDR_LEN; ++ return UPATCH_ADDR_LEN; + } + + // for long jumper + unsigned long get_new_insn(void) + { +- unsigned int insn0 = 0x58000051; // ldr x17, #8 +- unsigned int insn4 = 0xd61f0220; // br x17 +- return (unsigned long)(insn0 | ((unsigned long)insn4 << 32)); +-} +\ No newline at end of file ++ unsigned int insn0 = 0x58000051; // ldr x17, #8 ++ unsigned int insn4 = 0xd61f0220; // br x17 ++ return (unsigned long)(insn0 | ((unsigned long)insn4 << 32)); ++} +diff --git a/upatch-manage/arch/aarch64/relocation.c b/upatch-manage/arch/aarch64/relocation.c +index 3951135..57e864c 100644 +--- a/upatch-manage/arch/aarch64/relocation.c ++++ b/upatch-manage/arch/aarch64/relocation.c +@@ -24,300 +24,308 @@ + #include "upatch-relocation.h" + #include "upatch-resolve.h" + +-#define TCB_SIZE 2 * sizeof(void *) ++#define TCB_SIZE (2 * sizeof(void *)) + + enum aarch64_reloc_op { +- RELOC_OP_NONE, +- RELOC_OP_ABS, +- RELOC_OP_PREL, +- RELOC_OP_PAGE, ++ RELOC_OP_NONE, ++ RELOC_OP_ABS, ++ RELOC_OP_PREL, ++ RELOC_OP_PAGE, + }; + + static inline s64 calc_reloc(enum aarch64_reloc_op op, void *place, u64 val) + { +- s64 sval; +- switch (op) { +- case RELOC_OP_ABS: +- // S + A +- sval = (s64)val; +- break; +- case RELOC_OP_PREL: +- // S + A - P +- sval = (s64)(val - (u64)place); +- break; +- case RELOC_OP_PAGE: +- // Page(S + A) - Page(P) +- sval = (s64)((val & ~(u64)0xfff) - ((u64)place & ~(u64)0xfff)); +- break; +- default: +- log_error("upatch: unknown relocation operation %d\n", op); +- break; +- } ++ s64 sval; ++ switch (op) { ++ case RELOC_OP_ABS: ++ // S + A ++ sval = (s64)val; ++ break; ++ case RELOC_OP_PREL: ++ // S + A - P ++ sval = (s64)(val - (u64)place); ++ break; ++ case RELOC_OP_PAGE: ++ // Page(S + A) - Page(P) ++ sval = (s64)((val & ~(u64)0xfff) - ((u64)place & ~(u64)0xfff)); ++ break; ++ default: ++ log_error("upatch: unknown relocation operation %d\n", op); ++ break; ++ } + +- log_debug("upatch: reloc, S+A=0x%lx, P=0x%lx, X=0x%lx\n", val, +- (u64)place, sval); +- return sval; ++ log_debug("upatch: reloc, S+A=0x%lx, P=0x%lx, X=0x%lx\n", ++ val, (u64)place, sval); ++ return sval; + } + + int apply_relocate_add(struct upatch_elf *uelf, unsigned int symindex, +- unsigned int relsec) ++ unsigned int relsec) + { +- unsigned int i; +- GElf_Sym *sym; +- char const *sym_name; +- void *loc; +- void *uloc; +- u64 val; +- s64 result; +- GElf_Shdr *shdrs = (void *)uelf->info.shdrs; +- GElf_Rela *rel = (void *)shdrs[relsec].sh_addr; ++ unsigned int i; ++ GElf_Sym *sym; ++ char const *sym_name; ++ void *loc; ++ void *uloc; ++ u64 val; ++ s64 result; ++ GElf_Shdr *shdrs = (void *)uelf->info.shdrs; ++ GElf_Rela *rel = (void *)shdrs[relsec].sh_addr; + +- for (i = 0; i < shdrs[relsec].sh_size / sizeof(*rel); i++) { +- /* loc corresponds to P in the kernel space */ +- loc = (void *)shdrs[shdrs[relsec].sh_info].sh_addr + +- rel[i].r_offset; ++ for (i = 0; i < shdrs[relsec].sh_size / sizeof(*rel); i++) { ++ /* loc corresponds to P in the kernel space */ ++ loc = (void *)shdrs[shdrs[relsec].sh_info].sh_addr + rel[i].r_offset; + +- // /* uloc corresponds P in user space */ +- uloc = (void *)shdrs[shdrs[relsec].sh_info].sh_addralign + +- rel[i].r_offset; ++ /* uloc corresponds P in user space */ ++ uloc = (void *)shdrs[shdrs[relsec].sh_info].sh_addralign + ++ rel[i].r_offset; + +- /* sym is the ELF symbol we're referring to */ +- sym = (GElf_Sym *)shdrs[symindex].sh_addr + +- GELF_R_SYM(rel[i].r_info); +- if (GELF_ST_TYPE(sym[i].st_info) == STT_SECTION && +- sym->st_shndx < uelf->info.hdr->e_shnum) +- sym_name = uelf->info.shstrtab + +- shdrs[sym->st_shndx].sh_name; +- else +- sym_name = uelf->strtab + sym->st_name; ++ /* sym is the ELF symbol we're referring to */ ++ sym = (GElf_Sym *)shdrs[symindex].sh_addr + GELF_R_SYM(rel[i].r_info); ++ if (GELF_ST_TYPE(sym[i].st_info) == STT_SECTION && ++ sym->st_shndx < uelf->info.hdr->e_shnum) { ++ sym_name = uelf->info.shstrtab + shdrs[sym->st_shndx].sh_name; ++ } else { ++ sym_name = uelf->strtab + sym->st_name; ++ } + +- /* val corresponds to (S + A) */ +- val = (unsigned long)sym->st_value + (unsigned long)rel[i].r_addend; +- log_debug( +- "upatch: reloc symbol, name=%s, k_addr=0x%lx, u_addr=0x%lx, " +- "r_offset=0x%lx, st_value=0x%lx, r_addend=0x%lx \n", +- sym_name, shdrs[shdrs[relsec].sh_info].sh_addr, +- shdrs[shdrs[relsec].sh_info].sh_addralign, +- rel[i].r_offset, sym->st_value, rel[i].r_addend); ++ /* val corresponds to (S + A) */ ++ val = (unsigned long)sym->st_value + (unsigned long)rel[i].r_addend; ++ log_debug( ++ "upatch: reloc symbol, name=%s, k_addr=0x%lx, u_addr=0x%lx, " ++ "r_offset=0x%lx, st_value=0x%lx, r_addend=0x%lx\n", ++ sym_name, shdrs[shdrs[relsec].sh_info].sh_addr, ++ shdrs[shdrs[relsec].sh_info].sh_addralign, ++ rel[i].r_offset, sym->st_value, rel[i].r_addend); + +- /* Perform the static relocation. */ +- switch (GELF_R_TYPE(rel[i].r_info)) { +- case R_AARCH64_NONE: +- break; +- /* Data relocations. */ +- case R_AARCH64_ABS64: +- result = calc_reloc(RELOC_OP_ABS, uloc, val); +- *(s64 *)loc = result; +- break; +- case R_AARCH64_ABS32: +- result = calc_reloc(RELOC_OP_ABS, uloc, val); +- if (result < -(s64)BIT(31) || result >= (s64)BIT(32)) +- goto overflow; +- *(s32 *)loc = (s32)result; +- break; +- case R_AARCH64_ABS16: +- result = calc_reloc(RELOC_OP_ABS, uloc, val); +- if (result < -(s64)BIT(15) || result >= (s64)BIT(16)) +- goto overflow; +- *(s16 *)loc = (s16)result; +- break; +- case R_AARCH64_PREL64: +- result = calc_reloc(RELOC_OP_PREL, uloc, val); +- *(s64 *)loc = result; +- break; +- case R_AARCH64_PREL32: +- result = calc_reloc(RELOC_OP_PREL, uloc, val); +- if (result < -(s64)BIT(31) || result >= (s64)BIT(32)) +- goto overflow; +- *(s32 *)loc = (s32)result; +- break; +- case R_AARCH64_PREL16: +- result = calc_reloc(RELOC_OP_PREL, uloc, val); +- if (result < -(s64)BIT(15) || result >= (s64)BIT(16)) +- goto overflow; +- *(s16 *)loc = (s16)result; +- break; +- /* Immediate instruction relocations. */ +- case R_AARCH64_LD_PREL_LO19: +- result = calc_reloc(RELOC_OP_PREL, uloc, val); +- if (result < -(s64)BIT(20) || result >= (s64)BIT(20)) +- goto overflow; +- result = extract_insn_imm(result, 19, 2); +- result = insert_insn_imm(AARCH64_INSN_IMM_19, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_ADR_PREL_LO21: +- result = calc_reloc(RELOC_OP_PREL, uloc, val); +- if (result < -(s64)BIT(20) || result >= (s64)BIT(20)) +- goto overflow; +- result = extract_insn_imm(result, 21, 0); +- result = insert_insn_imm(AARCH64_INSN_IMM_ADR, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_ADR_PREL_PG_HI21: +- result = calc_reloc(RELOC_OP_PAGE, uloc, val); +- if (result < -(s64)BIT(32) || result >= (s64)BIT(32)) +- goto overflow; +- result = extract_insn_imm(result, 21, 12); +- result = insert_insn_imm(AARCH64_INSN_IMM_ADR, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_ADR_PREL_PG_HI21_NC: +- result = calc_reloc(RELOC_OP_PAGE, uloc, val); +- result = extract_insn_imm(result, 21, 12); +- result = insert_insn_imm(AARCH64_INSN_IMM_ADR, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_ADD_ABS_LO12_NC: +- case R_AARCH64_LDST8_ABS_LO12_NC: +- result = calc_reloc(RELOC_OP_ABS, uloc, val); +- result = extract_insn_imm(result, 12, 0); +- result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_LDST16_ABS_LO12_NC: +- result = calc_reloc(RELOC_OP_ABS, uloc, val); +- result = extract_insn_imm(result, 11, 1); +- result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_LDST32_ABS_LO12_NC: +- result = calc_reloc(RELOC_OP_ABS, uloc, val); +- result = extract_insn_imm(result, 10, 2); +- result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_LDST64_ABS_LO12_NC: +- result = calc_reloc(RELOC_OP_ABS, uloc, val); +- result = extract_insn_imm(result, 9, 3); +- result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_LDST128_ABS_LO12_NC: +- result = calc_reloc(RELOC_OP_ABS, uloc, val); +- result = extract_insn_imm(result, 8, 4); +- result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_TSTBR14: +- result = calc_reloc(RELOC_OP_PREL, uloc, val); +- if (result < -(s64)BIT(15) || result >= (s64)BIT(15)) +- goto overflow; +- result = extract_insn_imm(result, 14, 2); +- result = insert_insn_imm(AARCH64_INSN_IMM_14, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_CONDBR19: +- result = calc_reloc(RELOC_OP_PREL, uloc, val); +- result = extract_insn_imm(result, 19, 2); +- result = insert_insn_imm(AARCH64_INSN_IMM_19, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_JUMP26: +- case R_AARCH64_CALL26: +- result = calc_reloc(RELOC_OP_PREL, uloc, val); +- if (result < -(s64)BIT(27) || result >= (s64)BIT(27)) { +- log_debug( +- "R_AARCH64_CALL26 overflow: result = 0x%lx, uloc = " +- "0x%lx, val = 0x%lx\n", +- result, (unsigned long)uloc, val); +- val = search_insert_plt_table(uelf, val, +- (u64)&val); +- log_debug( +- "R_AARCH64_CALL26 overflow: plt.addr = 0x%lx\n", +- val); +- if (!val) +- goto overflow; +- result = calc_reloc(RELOC_OP_PREL, uloc, val); +- } +- result = extract_insn_imm(result, 26, 2); +- result = insert_insn_imm(AARCH64_INSN_IMM_26, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_ADR_GOT_PAGE: +- result = calc_reloc(RELOC_OP_PAGE, uloc, val); +- if (result < -(s64)BIT(32) || result >= (s64)BIT(32)) +- goto overflow; +- result = extract_insn_imm(result, 21, 12); +- result = insert_insn_imm(AARCH64_INSN_IMM_ADR, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_LD64_GOT_LO12_NC: +- result = calc_reloc(RELOC_OP_ABS, uloc, val); +- // don't check result & 7 == 0. +- // sometimes, result & 7 != 0, it works fine. +- result = extract_insn_imm(result, 9, 3); +- result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_TLSLE_ADD_TPREL_HI12: +- result = (long)(ALIGN(TCB_SIZE, uelf->relf->tls_align) + val); +- if (result < 0 || result >= (s64)BIT(24)) +- goto overflow; +- result = extract_insn_imm(result, 12, 12); +- result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: +- result = (long)(ALIGN(TCB_SIZE, uelf->relf->tls_align) + val); +- result = extract_insn_imm(result, 12, 0); +- result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_TLSDESC_ADR_PAGE21: +- result = calc_reloc(RELOC_OP_PAGE, uloc, val); +- if (result < -(s64)BIT(32) || result >= (s64)BIT(32)) +- goto overflow; +- result = extract_insn_imm(result, 21, 12); +- result = insert_insn_imm(AARCH64_INSN_IMM_ADR, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_TLSDESC_LD64_LO12: +- result = calc_reloc(RELOC_OP_ABS, uloc, val); +- // don't check result & 7 == 0. +- result = extract_insn_imm(result, 9, 3); +- result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_TLSDESC_ADD_LO12: +- result = calc_reloc(RELOC_OP_ABS, uloc, val); +- result = extract_insn_imm(result, 12, 0); +- result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, +- (unsigned long)result); +- *(__le32 *)loc = cpu_to_le32((__le32)result); +- break; +- case R_AARCH64_TLSDESC_CALL: +- // this is a blr instruction, don't need to modify +- break; ++ /* Perform the static relocation. */ ++ switch (GELF_R_TYPE(rel[i].r_info)) { ++ case R_AARCH64_NONE: ++ break; ++ /* Data relocations. */ ++ case R_AARCH64_ABS64: ++ result = calc_reloc(RELOC_OP_ABS, uloc, val); ++ *(s64 *)loc = result; ++ break; ++ case R_AARCH64_ABS32: ++ result = calc_reloc(RELOC_OP_ABS, uloc, val); ++ if (result < -(s64)BIT(31) || result >= (s64)BIT(32)) { ++ goto overflow; ++ } ++ *(s32 *)loc = (s32)result; ++ break; ++ case R_AARCH64_ABS16: ++ result = calc_reloc(RELOC_OP_ABS, uloc, val); ++ if (result < -(s64)BIT(15) || result >= (s64)BIT(16)) { ++ goto overflow; ++ } ++ *(s16 *)loc = (s16)result; ++ break; ++ case R_AARCH64_PREL64: ++ result = calc_reloc(RELOC_OP_PREL, uloc, val); ++ *(s64 *)loc = result; ++ break; ++ case R_AARCH64_PREL32: ++ result = calc_reloc(RELOC_OP_PREL, uloc, val); ++ if (result < -(s64)BIT(31) || result >= (s64)BIT(32)) { ++ goto overflow; ++ } ++ *(s32 *)loc = (s32)result; ++ break; ++ case R_AARCH64_PREL16: ++ result = calc_reloc(RELOC_OP_PREL, uloc, val); ++ if (result < -(s64)BIT(15) || result >= (s64)BIT(16)) { ++ goto overflow; ++ } ++ *(s16 *)loc = (s16)result; ++ break; ++ /* Immediate instruction relocations. */ ++ case R_AARCH64_LD_PREL_LO19: ++ result = calc_reloc(RELOC_OP_PREL, uloc, val); ++ if (result < -(s64)BIT(20) || result >= (s64)BIT(20)) { ++ goto overflow; ++ } ++ result = extract_insn_imm(result, 19, 2); ++ result = insert_insn_imm(AARCH64_INSN_IMM_19, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_ADR_PREL_LO21: ++ result = calc_reloc(RELOC_OP_PREL, uloc, val); ++ if (result < -(s64)BIT(20) || result >= (s64)BIT(20)) { ++ goto overflow; ++ } + +- default: +- log_error("upatch: unsupported RELA relocation: %lu\n", +- GELF_R_TYPE(rel[i].r_info)); +- return -ENOEXEC; +- } +- } +- return 0; ++ result = extract_insn_imm(result, 21, 0); ++ result = insert_insn_imm(AARCH64_INSN_IMM_ADR, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_ADR_PREL_PG_HI21: ++ result = calc_reloc(RELOC_OP_PAGE, uloc, val); ++ if (result < -(s64)BIT(32) || result >= (s64)BIT(32)) { ++ goto overflow; ++ } ++ result = extract_insn_imm(result, 21, 12); ++ result = insert_insn_imm(AARCH64_INSN_IMM_ADR, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_ADR_PREL_PG_HI21_NC: ++ result = calc_reloc(RELOC_OP_PAGE, uloc, val); ++ result = extract_insn_imm(result, 21, 12); ++ result = insert_insn_imm(AARCH64_INSN_IMM_ADR, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_ADD_ABS_LO12_NC: ++ case R_AARCH64_LDST8_ABS_LO12_NC: ++ result = calc_reloc(RELOC_OP_ABS, uloc, val); ++ result = extract_insn_imm(result, 12, 0); ++ result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_LDST16_ABS_LO12_NC: ++ result = calc_reloc(RELOC_OP_ABS, uloc, val); ++ result = extract_insn_imm(result, 11, 1); ++ result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_LDST32_ABS_LO12_NC: ++ result = calc_reloc(RELOC_OP_ABS, uloc, val); ++ result = extract_insn_imm(result, 10, 2); ++ result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_LDST64_ABS_LO12_NC: ++ result = calc_reloc(RELOC_OP_ABS, uloc, val); ++ result = extract_insn_imm(result, 9, 3); ++ result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_LDST128_ABS_LO12_NC: ++ result = calc_reloc(RELOC_OP_ABS, uloc, val); ++ result = extract_insn_imm(result, 8, 4); ++ result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_TSTBR14: ++ result = calc_reloc(RELOC_OP_PREL, uloc, val); ++ if (result < -(s64)BIT(15) || result >= (s64)BIT(15)) { ++ goto overflow; ++ } ++ result = extract_insn_imm(result, 14, 2); ++ result = insert_insn_imm(AARCH64_INSN_IMM_14, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_CONDBR19: ++ result = calc_reloc(RELOC_OP_PREL, uloc, val); ++ result = extract_insn_imm(result, 19, 2); ++ result = insert_insn_imm(AARCH64_INSN_IMM_19, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_JUMP26: ++ case R_AARCH64_CALL26: ++ result = calc_reloc(RELOC_OP_PREL, uloc, val); ++ if (result < -(s64)BIT(27) || result >= (s64)BIT(27)) { ++ log_debug( ++ "R_AARCH64_CALL26 overflow: " ++ "result = 0x%lx, uloc = 0x%lx, val = 0x%lx\n", ++ result, (unsigned long)uloc, val); ++ val = search_insert_plt_table(uelf, val, (u64)&val); ++ log_debug("R_AARCH64_CALL26 overflow: " ++ "plt.addr = 0x%lx\n", val); ++ if (!val) { ++ goto overflow; ++ } ++ result = calc_reloc(RELOC_OP_PREL, uloc, val); ++ } ++ result = extract_insn_imm(result, 26, 2); ++ result = insert_insn_imm(AARCH64_INSN_IMM_26, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_ADR_GOT_PAGE: ++ result = calc_reloc(RELOC_OP_PAGE, uloc, val); ++ if (result < -(s64)BIT(32) || result >= (s64)BIT(32)) { ++ goto overflow; ++ } ++ result = extract_insn_imm(result, 21, 12); ++ result = insert_insn_imm(AARCH64_INSN_IMM_ADR, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_LD64_GOT_LO12_NC: ++ result = calc_reloc(RELOC_OP_ABS, uloc, val); ++ // don't check result & 7 == 0. ++ // sometimes, result & 7 != 0, it works fine. ++ result = extract_insn_imm(result, 9, 3); ++ result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_TLSLE_ADD_TPREL_HI12: ++ result = (long)(ALIGN(TCB_SIZE, uelf->relf->tls_align) + val); ++ if (result < 0 || result >= (s64)BIT(24)) { ++ goto overflow; ++ } ++ result = extract_insn_imm(result, 12, 12); ++ result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: ++ result = (long)(ALIGN(TCB_SIZE, uelf->relf->tls_align) + val); ++ result = extract_insn_imm(result, 12, 0); ++ result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_TLSDESC_ADR_PAGE21: ++ result = calc_reloc(RELOC_OP_PAGE, uloc, val); ++ if (result < -(s64)BIT(32) || result >= (s64)BIT(32)) { ++ goto overflow; ++ } ++ result = extract_insn_imm(result, 21, 12); ++ result = insert_insn_imm(AARCH64_INSN_IMM_ADR, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_TLSDESC_LD64_LO12: ++ result = calc_reloc(RELOC_OP_ABS, uloc, val); ++ // don't check result & 7 == 0. ++ result = extract_insn_imm(result, 9, 3); ++ result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_TLSDESC_ADD_LO12: ++ result = calc_reloc(RELOC_OP_ABS, uloc, val); ++ result = extract_insn_imm(result, 12, 0); ++ result = insert_insn_imm(AARCH64_INSN_IMM_12, loc, ++ (unsigned long)result); ++ *(__le32 *)loc = cpu_to_le32((__le32)result); ++ break; ++ case R_AARCH64_TLSDESC_CALL: ++ // this is a blr instruction, don't need to modify ++ break; ++ default: ++ log_error("upatch: unsupported RELA relocation: %lu\n", ++ GELF_R_TYPE(rel[i].r_info)); ++ return -ENOEXEC; ++ } ++ } ++ return 0; + + overflow: +- log_error("upatch: overflow in relocation type %d val %lx reloc %lx\n", +- (int)GELF_R_TYPE(rel[i].r_info), val, result); +- return -ENOEXEC; ++ log_error("upatch: overflow in relocation type %d val %lx reloc %lx\n", ++ (int)GELF_R_TYPE(rel[i].r_info), val, result); ++ return -ENOEXEC; + } +diff --git a/upatch-manage/arch/aarch64/resolve.c b/upatch-manage/arch/aarch64/resolve.c +index 99fa307..5e0ddea 100644 +--- a/upatch-manage/arch/aarch64/resolve.c ++++ b/upatch-manage/arch/aarch64/resolve.c +@@ -34,133 +34,128 @@ + #define AARCH64_JUMP_TABLE_JMP2 0xffffffffd61f0220 + + struct upatch_jmp_table_entry { +- unsigned long inst[2]; +- unsigned long addr[2]; ++ unsigned long inst[2]; ++ unsigned long addr[2]; + }; + + unsigned int get_jmp_table_entry() + { +- return sizeof(struct upatch_jmp_table_entry); ++ return sizeof(struct upatch_jmp_table_entry); + } + + static unsigned long setup_jmp_table(struct upatch_elf *uelf, +- unsigned long jmp_addr, +- unsigned long origin_addr) ++ unsigned long jmp_addr, unsigned long origin_addr) + { +- struct upatch_jmp_table_entry *table = +- uelf->core_layout.kbase + uelf->jmp_offs; +- unsigned int index = uelf->jmp_cur_entry; +- if (index >= uelf->jmp_max_entry) { +- log_error("jmp table overflow\n"); +- return 0; +- } +- +- table[index].inst[0] = AARCH64_JUMP_TABLE_JMP1; +- table[index].inst[1] = AARCH64_JUMP_TABLE_JMP2; +- table[index].addr[0] = jmp_addr; +- table[index].addr[1] = origin_addr; +- uelf->jmp_cur_entry++; +- return (unsigned long)(uelf->core_layout.base + uelf->jmp_offs + +- index * sizeof(struct upatch_jmp_table_entry)); ++ struct upatch_jmp_table_entry *table = uelf->core_layout.kbase + ++ uelf->jmp_offs; ++ ++ unsigned int index = uelf->jmp_cur_entry; ++ if (index >= uelf->jmp_max_entry) { ++ log_error("jmp table overflow\n"); ++ return 0; ++ } ++ ++ table[index].inst[0] = AARCH64_JUMP_TABLE_JMP1; ++ table[index].inst[1] = AARCH64_JUMP_TABLE_JMP2; ++ table[index].addr[0] = jmp_addr; ++ table[index].addr[1] = origin_addr; ++ uelf->jmp_cur_entry++; ++ ++ return (unsigned long)(uelf->core_layout.base + uelf->jmp_offs + ++ index * sizeof(struct upatch_jmp_table_entry)); + } + + static unsigned long setup_got_table(struct upatch_elf *uelf, +- unsigned long jmp_addr, +- unsigned long tls_addr) ++ unsigned long jmp_addr, unsigned long tls_addr) + { +- struct upatch_jmp_table_entry *table = +- uelf->core_layout.kbase + uelf->jmp_offs; +- unsigned int index = uelf->jmp_cur_entry; +- +- if (index >= uelf->jmp_max_entry) { +- log_error("got table overflow\n"); +- return 0; +- } +- +- table[index].inst[0] = jmp_addr; +- table[index].inst[1] = tls_addr; +- table[index].addr[0] = 0xffffffff; +- table[index].addr[1] = 0xffffffff; +- uelf->jmp_cur_entry++; +- return (unsigned long)(uelf->core_layout.base + uelf->jmp_offs + +- index * sizeof(struct upatch_jmp_table_entry)); ++ struct upatch_jmp_table_entry *table = uelf->core_layout.kbase + ++ uelf->jmp_offs; ++ ++ unsigned int index = uelf->jmp_cur_entry; ++ if (index >= uelf->jmp_max_entry) { ++ log_error("got table overflow\n"); ++ return 0; ++ } ++ ++ table[index].inst[0] = jmp_addr; ++ table[index].inst[1] = tls_addr; ++ table[index].addr[0] = 0xffffffff; ++ table[index].addr[1] = 0xffffffff; ++ uelf->jmp_cur_entry++; ++ ++ return (unsigned long)(uelf->core_layout.base + uelf->jmp_offs + ++ index * sizeof(struct upatch_jmp_table_entry)); + } + + unsigned long insert_plt_table(struct upatch_elf *uelf, struct object_file *obj, +- unsigned long r_type, unsigned long addr) ++ unsigned long r_type, unsigned long addr) + { +- unsigned long jmp_addr = 0xffffffff; +- unsigned long tls_addr = 0xffffffff; +- unsigned long elf_addr = 0; +- +- if (upatch_process_mem_read(obj->proc, addr, &jmp_addr, +- sizeof(jmp_addr))) { +- log_error("copy address failed\n"); +- goto out; +- } +- +- if (r_type == R_AARCH64_TLSDESC && +- upatch_process_mem_read(obj->proc, addr + sizeof(unsigned long), +- &tls_addr, sizeof(tls_addr))) { +- log_error("copy address failed\n"); +- goto out; +- } +- +- if (r_type == R_AARCH64_TLSDESC) +- elf_addr = setup_got_table(uelf, jmp_addr, tls_addr); +- else +- elf_addr = setup_jmp_table(uelf, jmp_addr, (unsigned long)addr); +- +- log_debug("0x%lx: jmp_addr=0x%lx, tls_addr=0x%lx\n", elf_addr, +- jmp_addr, tls_addr); +- ++ unsigned long jmp_addr = 0xffffffff; ++ unsigned long tls_addr = 0xffffffff; ++ unsigned long elf_addr = 0; ++ ++ if (upatch_process_mem_read(obj->proc, addr, &jmp_addr, sizeof(jmp_addr))) { ++ log_error("copy address failed\n"); ++ goto out; ++ } ++ ++ if (r_type == R_AARCH64_TLSDESC && ++ upatch_process_mem_read(obj->proc, addr + sizeof(unsigned long), ++ &tls_addr, sizeof(tls_addr))) { ++ log_error("copy address failed\n"); ++ goto out; ++ } ++ ++ if (r_type == R_AARCH64_TLSDESC) { ++ elf_addr = setup_got_table(uelf, jmp_addr, tls_addr); ++ } else { ++ elf_addr = setup_jmp_table(uelf, jmp_addr, (unsigned long)addr); ++ } ++ log_debug("0x%lx: jmp_addr=0x%lx, tls_addr=0x%lx\n", ++ elf_addr, jmp_addr, tls_addr); + out: +- return elf_addr; ++ return elf_addr; + } + + unsigned long insert_got_table(struct upatch_elf *uelf, struct object_file *obj, +- unsigned long r_type, unsigned long addr) ++ unsigned long r_type, unsigned long addr) + { +- unsigned long jmp_addr = 0xffffffff; +- unsigned long tls_addr = 0xffffffff; +- unsigned long elf_addr = 0; +- +- if (upatch_process_mem_read(obj->proc, addr, &jmp_addr, +- sizeof(jmp_addr))) { +- log_error("copy address failed\n"); +- goto out; +- } +- +- if (r_type == R_AARCH64_TLSDESC && +- upatch_process_mem_read(obj->proc, addr + sizeof(unsigned long), +- &tls_addr, sizeof(tls_addr))) { +- log_error("copy address failed\n"); +- goto out; +- } +- +- elf_addr = setup_got_table(uelf, jmp_addr, tls_addr); +- +- log_debug("0x%lx: jmp_addr=0x%lx, tls_addr=0x%lx\n", elf_addr, +- jmp_addr, tls_addr); ++ unsigned long jmp_addr = 0xffffffff; ++ unsigned long tls_addr = 0xffffffff; ++ unsigned long elf_addr = 0; ++ ++ if (upatch_process_mem_read(obj->proc, addr, &jmp_addr, sizeof(jmp_addr))) { ++ log_error("copy address failed\n"); ++ goto out; ++ } ++ if (r_type == R_AARCH64_TLSDESC && ++ upatch_process_mem_read(obj->proc, addr + sizeof(unsigned long), ++ &tls_addr, sizeof(tls_addr))) { ++ log_error("copy address failed\n"); ++ goto out; ++ } ++ ++ elf_addr = setup_got_table(uelf, jmp_addr, tls_addr); ++ log_debug("0x%lx: jmp_addr=0x%lx, tls_addr=0x%lx\n", elf_addr, ++ jmp_addr, tls_addr); + + out: +- return elf_addr; ++ return elf_addr; + } + + unsigned long search_insert_plt_table(struct upatch_elf *uelf, +- unsigned long jmp_addr, +- unsigned long origin_addr) ++ unsigned long jmp_addr, unsigned long origin_addr) + { +- struct upatch_jmp_table_entry *table = +- uelf->core_layout.kbase + uelf->jmp_offs; +- unsigned int i = 0; +- +- for (i = 0; i < uelf->jmp_cur_entry; ++i) { +- if (table[i].addr[0] != jmp_addr) +- continue; +- return (unsigned long)(uelf->core_layout.base + uelf->jmp_offs + +- i * sizeof(struct upatch_jmp_table_entry)); +- } +- +- return setup_jmp_table(uelf, jmp_addr, origin_addr); +-} +\ No newline at end of file ++ struct upatch_jmp_table_entry *table = uelf->core_layout.kbase + ++ uelf->jmp_offs; ++ ++ for (unsigned int i = 0; i < uelf->jmp_cur_entry; ++i) { ++ if (table[i].addr[0] != jmp_addr) { ++ continue; ++ } ++ return (unsigned long)(uelf->core_layout.base + uelf->jmp_offs + ++ i * sizeof(struct upatch_jmp_table_entry)); ++ } ++ ++ return setup_jmp_table(uelf, jmp_addr, origin_addr); ++} +diff --git a/upatch-manage/arch/x86_64/ptrace.c b/upatch-manage/arch/x86_64/ptrace.c +index 15c7b58..2a84a2f 100644 +--- a/upatch-manage/arch/x86_64/ptrace.c ++++ b/upatch-manage/arch/x86_64/ptrace.c +@@ -27,153 +27,159 @@ + + #include "upatch-ptrace.h" + ++#define UPATCH_INSN_LEN 6 ++#define UPATCH_ADDR_LEN 8 ++#define ORIGIN_INSN_LEN (UPATCH_INSN_LEN + UPATCH_ADDR_LEN) ++ + int upatch_arch_reg_init(int pid, unsigned long *sp, unsigned long *pc) + { +- struct user_regs_struct regs; +- +- if (ptrace(PTRACE_GETREGS, pid, NULL, ®s) < 0) { +- log_error("Cannot get regs from %d\n", pid); +- return -1; +- } +- *sp = (unsigned long)regs.rsp; +- *pc = (unsigned long)regs.rip; +- return 0; ++ struct user_regs_struct regs; ++ ++ if (ptrace(PTRACE_GETREGS, pid, NULL, ®s) < 0) { ++ log_error("Cannot get regs from %d\n", pid); ++ return -1; ++ } ++ *sp = (unsigned long)regs.rsp; ++ *pc = (unsigned long)regs.rip; ++ return 0; + } + + long upatch_arch_syscall_remote(struct upatch_ptrace_ctx *pctx, int nr, +- unsigned long arg1, unsigned long arg2, +- unsigned long arg3, unsigned long arg4, +- unsigned long arg5, unsigned long arg6, +- unsigned long *res) ++ unsigned long arg1, unsigned long arg2, ++ unsigned long arg3, unsigned long arg4, ++ unsigned long arg5, unsigned long arg6, ++ unsigned long *res) + { +- struct user_regs_struct regs; +- +- unsigned char syscall[] = { +- 0x0f, 0x05, /* syscall */ +- 0xcc, /* int3 */ +- }; +- long ret; +- +- memset(®s, 0, sizeof(struct user_regs_struct)); +- log_debug("Executing syscall %d (pid %d)...\n", nr, pctx->pid); +- regs.rax = (unsigned long long)nr; +- regs.rdi = arg1; +- regs.rsi = arg2; +- regs.rdx = arg3; +- regs.r10 = arg4; +- regs.r8 = arg5; +- regs.r9 = arg6; +- +- ret = upatch_execute_remote(pctx, syscall, sizeof(syscall), ®s); +- if (ret == 0) +- *res = regs.rax; +- +- return ret; ++ struct user_regs_struct regs; ++ ++ unsigned char syscall[] = { ++ 0x0f, 0x05, /* syscall */ ++ 0xcc, /* int3 */ ++ }; ++ long ret; ++ ++ memset(®s, 0, sizeof(struct user_regs_struct)); ++ log_debug("Executing syscall %d (pid %d)...\n", nr, pctx->pid); ++ regs.rax = (unsigned long long)nr; ++ regs.rdi = arg1; ++ regs.rsi = arg2; ++ regs.rdx = arg3; ++ regs.r10 = arg4; ++ regs.r8 = arg5; ++ regs.r9 = arg6; ++ ++ ret = upatch_execute_remote(pctx, syscall, sizeof(syscall), ®s); ++ if (ret == 0) { ++ *res = regs.rax; ++ } ++ ++ return ret; + } + + long upatch_arch_execute_remote_func(struct upatch_ptrace_ctx *pctx, +- const unsigned char *code, size_t codelen, +- struct user_regs_struct *pregs, +- int (*func)(struct upatch_ptrace_ctx *pctx, +- const void *data), +- const void *data) ++ const unsigned char *code, size_t codelen, ++ struct user_regs_struct *pregs, ++ int (*func)(struct upatch_ptrace_ctx *pctx, const void *data), ++ const void *data) + { +- struct user_regs_struct orig_regs, regs; +- long ret; +- struct upatch_process *proc = pctx->proc; +- unsigned long libc_base = proc->libc_base; +- +- unsigned char *orig_code = (unsigned char *)malloc(sizeof(*orig_code) * codelen); +- +- if (orig_code == NULL) { +- log_error("Malloc orig_code failed\n"); +- return -1; +- } +- ret = ptrace(PTRACE_GETREGS, pctx->pid, NULL, &orig_regs); +- if (ret < 0) { +- log_error("can't get regs - %d\n", pctx->pid); +- free(orig_code); +- return -1; +- } +- ret = upatch_process_mem_read(proc, libc_base, +- (unsigned long *)orig_code, codelen); +- if (ret < 0) { +- log_error("can't peek original code - %d\n", pctx->pid); +- free(orig_code); +- return -1; +- } +- ret = upatch_process_mem_write(proc, code, libc_base, +- codelen); +- if (ret < 0) { +- log_error("can't poke syscall code - %d\n", pctx->pid); +- goto poke_back; +- } +- +- regs = orig_regs; +- regs.rip = libc_base; +- +- copy_regs(®s, pregs); +- +- ret = ptrace(PTRACE_SETREGS, pctx->pid, NULL, ®s); +- if (ret < 0) { +- log_error("can't set regs - %d\n", pctx->pid); +- goto poke_back; +- } +- +- ret = func(pctx, data); +- if (ret < 0) { +- log_error("failed call to func\n"); +- goto poke_back; +- } +- +- ret = ptrace(PTRACE_GETREGS, pctx->pid, NULL, ®s); +- if (ret < 0) { +- log_error("can't get updated regs - %d\n", pctx->pid); +- goto poke_back; +- } +- +- ret = ptrace(PTRACE_SETREGS, pctx->pid, NULL, &orig_regs); +- if (ret < 0) { +- log_error("can't restore regs - %d\n", pctx->pid); +- goto poke_back; +- } +- +- *pregs = regs; ++ long ret; ++ ++ struct user_regs_struct orig_regs; ++ struct user_regs_struct regs; ++ ++ struct upatch_process *proc = pctx->proc; ++ unsigned long libc_base = proc->libc_base; ++ ++ unsigned char *orig_code = (unsigned char *)malloc( ++ sizeof(*orig_code) * codelen); ++ if (orig_code == NULL) { ++ log_error("Malloc orig_code failed\n"); ++ return -1; ++ } ++ ++ ret = ptrace(PTRACE_GETREGS, pctx->pid, NULL, &orig_regs); ++ if (ret < 0) { ++ log_error("can't get regs - %d\n", pctx->pid); ++ free(orig_code); ++ return -1; ++ } ++ ++ ret = upatch_process_mem_read(proc, libc_base, ++ (unsigned long *)orig_code, codelen); ++ if (ret < 0) { ++ log_error("can't peek original code - %d\n", pctx->pid); ++ free(orig_code); ++ return -1; ++ } ++ ++ ret = upatch_process_mem_write(proc, code, libc_base, codelen); ++ if (ret < 0) { ++ log_error("can't poke syscall code - %d\n", pctx->pid); ++ goto poke_back; ++ } ++ ++ regs = orig_regs; ++ regs.rip = libc_base; ++ copy_regs(®s, pregs); ++ ++ ret = ptrace(PTRACE_SETREGS, pctx->pid, NULL, ®s); ++ if (ret < 0) { ++ log_error("can't set regs - %d\n", pctx->pid); ++ goto poke_back; ++ } ++ ++ ret = func(pctx, data); ++ if (ret < 0) { ++ log_error("failed call to func\n"); ++ goto poke_back; ++ } ++ ++ ret = ptrace(PTRACE_GETREGS, pctx->pid, NULL, ®s); ++ if (ret < 0) { ++ log_error("can't get updated regs - %d\n", pctx->pid); ++ goto poke_back; ++ } ++ ++ ret = ptrace(PTRACE_SETREGS, pctx->pid, NULL, &orig_regs); ++ if (ret < 0) { ++ log_error("can't restore regs - %d\n", pctx->pid); ++ goto poke_back; ++ } ++ ++ *pregs = regs; + + poke_back: +- upatch_process_mem_write(proc, (unsigned long *)orig_code, libc_base, +- codelen); +- free(orig_code); +- return ret; ++ upatch_process_mem_write(proc, (unsigned long *)orig_code, ++ libc_base, codelen); ++ free(orig_code); ++ ++ return ret; + } + + void copy_regs(struct user_regs_struct *dst, struct user_regs_struct *src) + { + #define COPY_REG(x) dst->x = src->x +- COPY_REG(r15); +- COPY_REG(r14); +- COPY_REG(r13); +- COPY_REG(r12); +- COPY_REG(rbp); +- COPY_REG(rbx); +- COPY_REG(r11); +- COPY_REG(r10); +- COPY_REG(r9); +- COPY_REG(r8); +- COPY_REG(rax); +- COPY_REG(rcx); +- COPY_REG(rdx); +- COPY_REG(rsi); +- COPY_REG(rdi); ++ COPY_REG(r15); ++ COPY_REG(r14); ++ COPY_REG(r13); ++ COPY_REG(r12); ++ COPY_REG(rbp); ++ COPY_REG(rbx); ++ COPY_REG(r11); ++ COPY_REG(r10); ++ COPY_REG(r9); ++ COPY_REG(r8); ++ COPY_REG(rax); ++ COPY_REG(rcx); ++ COPY_REG(rdx); ++ COPY_REG(rsi); ++ COPY_REG(rdi); + #undef COPY_REG + } + +-#define UPATCH_INSN_LEN 6 +-#define UPATCH_ADDR_LEN 8 +-#define ORIGIN_INSN_LEN (UPATCH_INSN_LEN + UPATCH_ADDR_LEN) + size_t get_origin_insn_len() + { +- return ORIGIN_INSN_LEN; ++ return ORIGIN_INSN_LEN; + } + + size_t get_upatch_insn_len() +@@ -188,6 +194,6 @@ size_t get_upatch_addr_len() + + unsigned long get_new_insn(void) + { +- // ASM: jmp word ptr [di] (FF25 0000 0000 0000) +- return 0x25FF; ++ // ASM: jmp word ptr [di] (FF25 0000 0000 0000) ++ return 0x25FF; + } +diff --git a/upatch-manage/arch/x86_64/relocation.c b/upatch-manage/arch/x86_64/relocation.c +index 657f014..e492b1e 100644 +--- a/upatch-manage/arch/x86_64/relocation.c ++++ b/upatch-manage/arch/x86_64/relocation.c +@@ -25,116 +25,121 @@ + #include "upatch-relocation.h" + + int apply_relocate_add(struct upatch_elf *uelf, unsigned int symindex, +- unsigned int relsec) ++ unsigned int relsec) + { +- unsigned int i; +- GElf_Sym *sym; +- void *loc, *real_loc; +- u64 val; +- const char *sym_name; +- GElf_Xword tls_size; +- GElf_Shdr *shdrs = (void *)uelf->info.shdrs; +- GElf_Rela *rel = (void *)shdrs[relsec].sh_addr; ++ unsigned int i; ++ GElf_Sym *sym; ++ void *loc; ++ void *real_loc; ++ u64 val; ++ const char *sym_name; ++ GElf_Xword tls_size; ++ GElf_Shdr *shdrs = (void *)uelf->info.shdrs; ++ GElf_Rela *rel = (void *)shdrs[relsec].sh_addr; + +- log_debug("Applying relocate section %u to %u\n", relsec, +- shdrs[relsec].sh_info); ++ log_debug("Applying relocate section %u to %u\n", relsec, ++ shdrs[relsec].sh_info); + +- for (i = 0; i < shdrs[relsec].sh_size / sizeof(*rel); i++) { +- /* This is where to make the change, calculate it from kernel address */ +- loc = (void *)shdrs[shdrs[relsec].sh_info].sh_addr + +- rel[i].r_offset; ++ for (i = 0; i < shdrs[relsec].sh_size / sizeof(*rel); i++) { ++ /* This is where to make the change, calculate it from kernel address */ ++ loc = (void *)shdrs[shdrs[relsec].sh_info].sh_addr + rel[i].r_offset; ++ real_loc = (void *)shdrs[shdrs[relsec].sh_info].sh_addralign + ++ rel[i].r_offset; + +- real_loc = (void *)shdrs[shdrs[relsec].sh_info].sh_addralign + +- rel[i].r_offset; ++ /* This is the symbol it is referring to. Note that all ++ undefined symbols have been resolved. */ ++ sym = (GElf_Sym *)shdrs[symindex].sh_addr + GELF_R_SYM(rel[i].r_info); ++ if (GELF_ST_TYPE(sym[i].st_info) == STT_SECTION && ++ sym->st_shndx < uelf->info.hdr->e_shnum) { ++ sym_name = uelf->info.shstrtab + shdrs[sym->st_shndx].sh_name; ++ } else { ++ sym_name = uelf->strtab + sym->st_name; ++ } + +- /* This is the symbol it is referring to. Note that all +- undefined symbols have been resolved. */ +- sym = (GElf_Sym *)shdrs[symindex].sh_addr + +- GELF_R_SYM(rel[i].r_info); ++ log_debug("type %d st_value %lx r_addend %lx loc %lx\n", ++ (int)GELF_R_TYPE(rel[i].r_info), sym->st_value, ++ rel[i].r_addend, (u64)loc); + +- if (GELF_ST_TYPE(sym[i].st_info) == STT_SECTION && +- sym->st_shndx < uelf->info.hdr->e_shnum) +- sym_name = uelf->info.shstrtab + +- shdrs[sym->st_shndx].sh_name; +- else +- sym_name = uelf->strtab + sym->st_name; +- +- log_debug("type %d st_value %lx r_addend %lx loc %lx\n", +- (int)GELF_R_TYPE(rel[i].r_info), sym->st_value, +- rel[i].r_addend, (u64)loc); +- +- val = sym->st_value + (unsigned long)rel[i].r_addend; +- switch (GELF_R_TYPE(rel[i].r_info)) { +- case R_X86_64_NONE: +- break; +- case R_X86_64_64: +- if (*(u64 *)loc != 0) +- goto invalid_relocation; +- memcpy(loc, &val, 8); +- break; +- case R_X86_64_32: +- if (*(u32 *)loc != 0) +- goto invalid_relocation; +- memcpy(loc, &val, 4); +- if (val != *(u32 *)loc && +- (GELF_ST_TYPE(sym->st_info) != STT_SECTION)) +- goto overflow; +- break; +- case R_X86_64_32S: +- if (*(s32 *)loc != 0) +- goto invalid_relocation; +- memcpy(loc, &val, 4); +- if ((s64)val != *(s32 *)loc && +- (GELF_ST_TYPE(sym->st_info) != STT_SECTION)) +- goto overflow; +- break; +- case R_X86_64_TLSGD: +- case R_X86_64_GOTTPOFF: +- case R_X86_64_GOTPCRELX: +- case R_X86_64_REX_GOTPCRELX: +- if (sym->st_value == 0) +- goto overflow; +- /* G + GOT + A*/ +- val = sym->st_value + (unsigned long)rel[i].r_addend; +- /* fallthrough*/ +- case R_X86_64_PC32: +- case R_X86_64_PLT32: +- if (*(u32 *)loc != 0) +- goto invalid_relocation; +- val -= (u64)real_loc; +- memcpy(loc, &val, 4); +- break; +- case R_X86_64_PC64: +- if (*(u64 *)loc != 0) +- goto invalid_relocation; +- val -= (u64)real_loc; +- memcpy(loc, &val, 8); +- break; +- case R_X86_64_TPOFF32: +- tls_size = ALIGN(uelf->relf->tls_size, +- uelf->relf->tls_align); +- // %fs + val - tls_size +- if (val >= tls_size) +- goto overflow; +- val -= (u64)tls_size; +- memcpy(loc, &val, 4); +- break; +- default: +- log_error("Unknown rela relocation: %lu\n", +- GELF_R_TYPE(rel[i].r_info)); +- return -ENOEXEC; +- } +- } +- return 0; ++ val = sym->st_value + (unsigned long)rel[i].r_addend; ++ switch (GELF_R_TYPE(rel[i].r_info)) { ++ case R_X86_64_NONE: ++ break; ++ case R_X86_64_64: ++ if (*(u64 *)loc != 0) { ++ goto invalid_relocation; ++ } ++ memcpy(loc, &val, 8); ++ break; ++ case R_X86_64_32: ++ if (*(u32 *)loc != 0) { ++ goto invalid_relocation; ++ } ++ memcpy(loc, &val, 4); ++ if (val != *(u32 *)loc && ++ (GELF_ST_TYPE(sym->st_info) != STT_SECTION)) { ++ goto overflow; ++ } ++ break; ++ case R_X86_64_32S: ++ if (*(s32 *)loc != 0) { ++ goto invalid_relocation; ++ } ++ memcpy(loc, &val, 4); ++ if ((s64)val != *(s32 *)loc && ++ (GELF_ST_TYPE(sym->st_info) != STT_SECTION)) { ++ goto overflow; ++ } ++ break; ++ case R_X86_64_TLSGD: ++ case R_X86_64_GOTTPOFF: ++ case R_X86_64_GOTPCRELX: ++ case R_X86_64_REX_GOTPCRELX: ++ if (sym->st_value == 0) { ++ goto overflow; ++ } ++ /* G + GOT + A */ ++ val = sym->st_value + (unsigned long)rel[i].r_addend; ++ /* fall through */ ++ case R_X86_64_PC32: ++ case R_X86_64_PLT32: ++ if (*(u32 *)loc != 0) { ++ goto invalid_relocation; ++ } ++ val -= (u64)real_loc; ++ memcpy(loc, &val, 4); ++ break; ++ case R_X86_64_PC64: ++ if (*(u64 *)loc != 0) { ++ goto invalid_relocation; ++ } ++ val -= (u64)real_loc; ++ memcpy(loc, &val, 8); ++ break; ++ case R_X86_64_TPOFF32: ++ tls_size = ALIGN(uelf->relf->tls_size, uelf->relf->tls_align); ++ // %fs + val - tls_size ++ if (val >= tls_size) { ++ goto overflow; ++ } ++ val -= (u64)tls_size; ++ memcpy(loc, &val, 4); ++ break; ++ default: ++ log_error("Unknown rela relocation: %lu\n", ++ GELF_R_TYPE(rel[i].r_info)); ++ return -ENOEXEC; ++ } ++ } ++ return 0; + + invalid_relocation: +- log_error("upatch: Skipping invalid relocation target, \ ++ log_error("upatch: Skipping invalid relocation target, \ + existing value is nonzero for type %d, loc %p, name %s\n", +- (int)GELF_R_TYPE(rel[i].r_info), loc, sym_name); +- return -ENOEXEC; ++ (int)GELF_R_TYPE(rel[i].r_info), loc, sym_name); ++ return -ENOEXEC; + + overflow: +- log_error("upatch: overflow in relocation type %d name %s\n", +- (int)GELF_R_TYPE(rel[i].r_info), sym_name); +- return -ENOEXEC; ++ log_error("upatch: overflow in relocation type %d name %s\n", ++ (int)GELF_R_TYPE(rel[i].r_info), sym_name); ++ return -ENOEXEC; + } +diff --git a/upatch-manage/arch/x86_64/resolve.c b/upatch-manage/arch/x86_64/resolve.c +index 0f8623d..71b303a 100644 +--- a/upatch-manage/arch/x86_64/resolve.c ++++ b/upatch-manage/arch/x86_64/resolve.c +@@ -26,31 +26,33 @@ + #define X86_64_JUMP_TABLE_JMP 0x90900000000225ff /* jmp [rip+2]; nop; nop */ + + struct upatch_jmp_table_entry { +- unsigned long inst; +- unsigned long addr; ++ unsigned long inst; ++ unsigned long addr; + }; + + unsigned int get_jmp_table_entry(void) + { +- return sizeof(struct upatch_jmp_table_entry); ++ return sizeof(struct upatch_jmp_table_entry); + } + + static unsigned long setup_jmp_table(struct upatch_elf *uelf, +- unsigned long jmp_addr) ++ unsigned long jmp_addr) + { +- struct upatch_jmp_table_entry *table = +- uelf->core_layout.kbase + uelf->jmp_offs; +- unsigned int index = uelf->jmp_cur_entry; +- if (index >= uelf->jmp_max_entry) { +- log_error("jmp table overflow\n"); +- return 0; +- } +- +- table[index].inst = X86_64_JUMP_TABLE_JMP; +- table[index].addr = jmp_addr; +- uelf->jmp_cur_entry++; +- return (unsigned long)(uelf->core_layout.base + uelf->jmp_offs + +- index * sizeof(struct upatch_jmp_table_entry)); ++ struct upatch_jmp_table_entry *table = uelf->core_layout.kbase + ++ uelf->jmp_offs; ++ ++ unsigned int index = uelf->jmp_cur_entry; ++ if (index >= uelf->jmp_max_entry) { ++ log_error("jmp table overflow\n"); ++ return 0; ++ } ++ ++ table[index].inst = X86_64_JUMP_TABLE_JMP; ++ table[index].addr = jmp_addr; ++ uelf->jmp_cur_entry++; ++ ++ return (unsigned long)(uelf->core_layout.base + uelf->jmp_offs + ++ index * sizeof(struct upatch_jmp_table_entry)); + } + + /* +@@ -60,84 +62,79 @@ static unsigned long setup_jmp_table(struct upatch_elf *uelf, + * To simplify design, use same table for both jmp table and GOT. + */ + static unsigned long setup_got_table(struct upatch_elf *uelf, +- unsigned long jmp_addr, +- unsigned long tls_addr) ++ unsigned long jmp_addr, unsigned long tls_addr) + { +- struct upatch_jmp_table_entry *table = +- uelf->core_layout.kbase + uelf->jmp_offs; +- unsigned int index = uelf->jmp_cur_entry; +- if (index >= uelf->jmp_max_entry) { +- log_error("got table overflow\n"); +- return 0; +- } +- +- table[index].inst = jmp_addr; +- table[index].addr = tls_addr; +- uelf->jmp_cur_entry++; +- return (unsigned long)(uelf->core_layout.base + uelf->jmp_offs + +- index * sizeof(struct upatch_jmp_table_entry)); ++ struct upatch_jmp_table_entry *table = uelf->core_layout.kbase + ++ uelf->jmp_offs; ++ ++ unsigned int index = uelf->jmp_cur_entry; ++ if (index >= uelf->jmp_max_entry) { ++ log_error("got table overflow\n"); ++ return 0; ++ } ++ ++ table[index].inst = jmp_addr; ++ table[index].addr = tls_addr; ++ uelf->jmp_cur_entry++; ++ ++ return (unsigned long)(uelf->core_layout.base + uelf->jmp_offs + ++ index * sizeof(struct upatch_jmp_table_entry)); + } + + unsigned long insert_plt_table(struct upatch_elf *uelf, struct object_file *obj, +- unsigned long r_type, unsigned long addr) ++ unsigned long r_type, unsigned long addr) + { +- unsigned long jmp_addr; +- unsigned long elf_addr = 0; ++ unsigned long jmp_addr; ++ unsigned long elf_addr = 0; + +- (void)r_type; +- if (upatch_process_mem_read(obj->proc, addr, &jmp_addr, +- sizeof(jmp_addr))) { +- log_error("copy address failed\n"); +- goto out; +- } ++ (void)r_type; ++ if (upatch_process_mem_read(obj->proc, addr, &jmp_addr, sizeof(jmp_addr))) { ++ log_error("copy address failed\n"); ++ goto out; ++ } + +- elf_addr = setup_jmp_table(uelf, jmp_addr); +- +- log_debug("0x%lx: jmp_addr=0x%lx\n", elf_addr, jmp_addr); ++ elf_addr = setup_jmp_table(uelf, jmp_addr); ++ log_debug("0x%lx: jmp_addr=0x%lx\n", elf_addr, jmp_addr); + + out: +- return elf_addr; ++ return elf_addr; + } + + unsigned long insert_got_table(struct upatch_elf *uelf, struct object_file *obj, +- unsigned long r_type, unsigned long addr) ++ unsigned long r_type, unsigned long addr) + { +- unsigned long jmp_addr; +- unsigned long tls_addr = 0xffffffff; +- unsigned long elf_addr = 0; +- +- if (upatch_process_mem_read(obj->proc, addr, &jmp_addr, +- sizeof(jmp_addr))) { +- log_error("copy address failed\n"); +- goto out; +- } +- +- /* +- * R_X86_64_TLSGD: allocate two contiguous entries in the GOT to hold a +- * tls_index structure tls_index has two unsigned long, the first one is +- * R_X86_64_DTPMOD64. +- */ +- if (r_type == R_X86_64_DTPMOD64 && +- upatch_process_mem_read(obj->proc, addr + sizeof(unsigned long), +- &tls_addr, sizeof(tls_addr))) { +- log_error("copy address failed\n"); +- goto out; +- } +- +- if (uelf->relf->info.is_dyn && !uelf->relf->info.is_pie) { +- elf_addr = setup_got_table(uelf, jmp_addr, tls_addr); +- +- log_debug("0x%lx: jmp_addr=0x%lx\n", elf_addr, jmp_addr); +- +- } else { +- /* +- * For non-dynamic library files, global variables are not placed in the GOT table +- */ +- elf_addr = jmp_addr; +- log_debug("For non-dynamic library: jmp_addr=0x%lx\n", jmp_addr); +- } +- ++ unsigned long jmp_addr; ++ unsigned long tls_addr = 0xffffffff; ++ unsigned long elf_addr = 0; ++ ++ if (upatch_process_mem_read(obj->proc, addr, &jmp_addr, sizeof(jmp_addr))) { ++ log_error("copy address failed\n"); ++ goto out; ++ } ++ ++ /* ++ * R_X86_64_TLSGD: allocate two contiguous entries in the GOT to hold a ++ * tls_index structure tls_index has two unsigned long, the first one is ++ * R_X86_64_DTPMOD64. ++ */ ++ if (r_type == R_X86_64_DTPMOD64 && ++ upatch_process_mem_read(obj->proc, addr + sizeof(unsigned long), ++ &tls_addr, sizeof(tls_addr))) { ++ log_error("copy address failed\n"); ++ goto out; ++ } ++ ++ if (uelf->relf->info.is_dyn && !uelf->relf->info.is_pie) { ++ elf_addr = setup_got_table(uelf, jmp_addr, tls_addr); ++ log_debug("0x%lx: jmp_addr=0x%lx\n", elf_addr, jmp_addr); ++ } else { ++ /* ++ * For non-dynamic library files, global variables are not placed in the GOT table ++ */ ++ elf_addr = jmp_addr; ++ log_debug("For non-dynamic library: jmp_addr=0x%lx\n", jmp_addr); ++ } + + out: +- return elf_addr; ++ return elf_addr; + } +diff --git a/upatch-manage/list.h b/upatch-manage/list.h +index 7e1e16f..f175c29 100644 +--- a/upatch-manage/list.h ++++ b/upatch-manage/list.h +@@ -34,29 +34,29 @@ + */ + + #define container_of(ptr, type, member) \ +- ((type *)(((char *)(ptr)) - offsetof(type, member))) ++ ((type *)(((char *)(ptr)) - offsetof(type, member))) + + struct list_head { +- struct list_head *next, *prev; ++ struct list_head *next, *prev; + }; + +-#define LIST_HEAD_INIT(name) \ +- { \ +- &(name), &(name) \ +- } ++#define LIST_HEAD_INIT(name) \ ++ { \ ++ &(name), &(name) \ ++ } + + #define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name) + +-#define INIT_LIST_HEAD(ptr) \ +- do { \ +- (ptr)->next = (ptr); \ +- (ptr)->prev = (ptr); \ +- } while (0) ++#define INIT_LIST_HEAD(ptr) \ ++ do { \ ++ (ptr)->next = (ptr); \ ++ (ptr)->prev = (ptr); \ ++ } while (0) + + static inline void list_init(struct list_head *list) + { +- list->next = list; +- list->prev = list; ++ list->next = list; ++ list->prev = list; + } + + /* +@@ -66,12 +66,12 @@ static inline void list_init(struct list_head *list) + * the prev/next entries already! + */ + static inline void __list_add(struct list_head *new, struct list_head *prev, +- struct list_head *next) ++ struct list_head *next) + { +- next->prev = new; +- new->next = next; +- new->prev = prev; +- prev->next = new; ++ next->prev = new; ++ new->next = next; ++ new->prev = prev; ++ prev->next = new; + } + + /** +@@ -84,7 +84,7 @@ static inline void __list_add(struct list_head *new, struct list_head *prev, + */ + static inline void list_add_head(struct list_head *new, struct list_head *head) + { +- __list_add(new, head, head->next); ++ __list_add(new, head, head->next); + } + + /** +@@ -97,7 +97,7 @@ static inline void list_add_head(struct list_head *new, struct list_head *head) + */ + static inline void list_add(struct list_head *new, struct list_head *head) + { +- __list_add(new, head->prev, head); ++ __list_add(new, head->prev, head); + } + + /* +@@ -109,8 +109,8 @@ static inline void list_add(struct list_head *new, struct list_head *head) + */ + static inline void __list_del(struct list_head *prev, struct list_head *next) + { +- next->prev = prev; +- prev->next = next; ++ next->prev = prev; ++ prev->next = next; + } + + /** +@@ -121,27 +121,27 @@ static inline void __list_del(struct list_head *prev, struct list_head *next) + */ + static inline void __list_del_entry(struct list_head *entry) + { +- __list_del(entry->prev, entry->next); ++ __list_del(entry->prev, entry->next); + } + + static inline void list_del(struct list_head *entry) + { +- __list_del_entry(entry); ++ __list_del_entry(entry); + } + + /** + * list_replace - replace old entry by new one +- * @old : the element to be replaced +- * @new : the new element to insert ++ * @old: the element to be replaced ++ * @new: the new element to insert + * + * If @old was empty, it will be overwritten. + */ + static inline void list_replace(struct list_head *old, struct list_head *new) + { +- new->next = old->next; +- new->next->prev = new; +- new->prev = old->prev; +- new->prev->next = new; ++ new->next = old->next; ++ new->next->prev = new; ++ new->prev = old->prev; ++ new->prev->next = new; + } + + /** +@@ -151,8 +151,8 @@ static inline void list_replace(struct list_head *old, struct list_head *new) + */ + static inline void list_move(struct list_head *list, struct list_head *head) + { +- __list_del_entry(list); +- list_add(list, head); ++ __list_del_entry(list); ++ list_add(list, head); + } + + /** +@@ -161,10 +161,10 @@ static inline void list_move(struct list_head *list, struct list_head *head) + * @head: the head that will follow our entry + */ + static inline void list_move_tail(struct list_head *list, +- struct list_head *head) ++ struct list_head *head) + { +- __list_del_entry(list); +- list_add(list, head); ++ __list_del_entry(list); ++ list_add(list, head); + } + + /** +@@ -173,9 +173,9 @@ static inline void list_move_tail(struct list_head *list, + * @head: the head of the list + */ + static inline int list_is_last(const struct list_head *list, +- const struct list_head *head) ++ const struct list_head *head) + { +- return list->next == head; ++ return list->next == head; + } + + /** +@@ -184,7 +184,7 @@ static inline int list_is_last(const struct list_head *list, + */ + static inline int list_empty(const struct list_head *head) + { +- return head->next == head; ++ return head->next == head; + } + + /** +@@ -202,8 +202,8 @@ static inline int list_empty(const struct list_head *head) + */ + static inline int list_empty_careful(const struct list_head *head) + { +- struct list_head *next = head->next; +- return (next == head) && (next == head->prev); ++ struct list_head *next = head->next; ++ return (next == head) && (next == head->prev); + } + + /** +@@ -212,12 +212,12 @@ static inline int list_empty_careful(const struct list_head *head) + */ + static inline void list_rotate_left(struct list_head *head) + { +- struct list_head *first; ++ struct list_head *first; + +- if (!list_empty(head)) { +- first = head->next; +- list_move_tail(first, head); +- } ++ if (!list_empty(head)) { ++ first = head->next; ++ list_move_tail(first, head); ++ } + } + + /** +@@ -226,33 +226,33 @@ static inline void list_rotate_left(struct list_head *head) + */ + static inline int list_is_singular(const struct list_head *head) + { +- return !list_empty(head) && (head->next == head->prev); ++ return !list_empty(head) && (head->next == head->prev); + } + + static inline void __list_cut_position(struct list_head *list, +- struct list_head *head, +- struct list_head *entry) ++ struct list_head *head, struct list_head *entry) + { +- struct list_head *new_first = entry->next; +- list->next = head->next; +- list->next->prev = list; +- list->prev = entry; +- entry->next = list; +- head->next = new_first; +- new_first->prev = head; ++ struct list_head *new_first = entry->next; ++ ++ list->next = head->next; ++ list->next->prev = list; ++ list->prev = entry; ++ entry->next = list; ++ head->next = new_first; ++ new_first->prev = head; + } + + static inline void __list_splice(const struct list_head *list, +- struct list_head *prev, struct list_head *next) ++ struct list_head *prev, struct list_head *next) + { +- struct list_head *first = list->next; +- struct list_head *last = list->prev; ++ struct list_head *first = list->next; ++ struct list_head *last = list->prev; + +- first->prev = prev; +- prev->next = first; ++ first->prev = prev; ++ prev->next = first; + +- last->next = next; +- next->prev = last; ++ last->next = next; ++ next->prev = last; + } + + /** +@@ -261,10 +261,11 @@ static inline void __list_splice(const struct list_head *list, + * @head: the place to add it in the first list. + */ + static inline void list_splice(const struct list_head *list, +- struct list_head *head) ++ struct list_head *head) + { +- if (!list_empty(list)) +- __list_splice(list, head, head->next); ++ if (!list_empty(list)) { ++ __list_splice(list, head, head->next); ++ } + } + + /** +@@ -273,36 +274,37 @@ static inline void list_splice(const struct list_head *list, + * @head: the place to add it in the first list. + */ + static inline void list_splice_tail(struct list_head *list, +- struct list_head *head) ++ struct list_head *head) + { +- if (!list_empty(list)) +- __list_splice(list, head->prev, head); ++ if (!list_empty(list)) { ++ __list_splice(list, head->prev, head); ++ } + } + + /** + * list_entry - get the struct for this entry +- * @ptr: the &struct list_head pointer. +- * @type: the type of the struct this is embedded in. +- * @member: the name of the list_head within the struct. ++ * @ptr: the &struct list_head pointer. ++ * @type: the type of the struct this is embedded in. ++ * @member: the name of the list_head within the struct. + */ + #define list_entry(ptr, type, member) container_of(ptr, type, member) + + /** + * list_first_entry - get the first element from a list +- * @ptr: the list head to take the element from. +- * @type: the type of the struct this is embedded in. +- * @member: the name of the list_head within the struct. ++ * @ptr: the list head to take the element from. ++ * @type: the type of the struct this is embedded in. ++ * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ + #define list_first_entry(ptr, type, member) \ +- list_entry((ptr)->next, type, member) ++ list_entry((ptr)->next, type, member) + + /** + * list_last_entry - get the last element from a list +- * @ptr: the list head to take the element from. +- * @type: the type of the struct this is embedded in. +- * @member: the name of the list_head within the struct. ++ * @ptr: the list head to take the element from. ++ * @type: the type of the struct this is embedded in. ++ * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ +@@ -310,220 +312,250 @@ static inline void list_splice_tail(struct list_head *list, + + /** + * list_first_entry_or_null - get the first element from a list +- * @ptr: the list head to take the element from. +- * @type: the type of the struct this is embedded in. +- * @member: the name of the list_head within the struct. ++ * @ptr: the list head to take the element from. ++ * @type: the type of the struct this is embedded in. ++ * @member: the name of the list_head within the struct. + * + * Note that if the list is empty, it returns NULL. + */ +-#define list_first_entry_or_null(ptr, type, member) \ +- ({ \ +- struct list_head *head__ = (ptr); \ +- struct list_head *pos__ = READ_ONCE(head__->next); \ +- pos__ != head__ ? list_entry(pos__, type, member) : NULL; \ +- }) ++#define list_first_entry_or_null(ptr, type, member) \ ++ ({ \ ++ struct list_head *head__ = (ptr); \ ++ struct list_head *pos__ = READ_ONCE(head__->next); \ ++ pos__ != head__ ? list_entry(pos__, type, member) : NULL; \ ++ }) + + /** + * list_next_entry - get the next element in list +- * @pos: the type * to cursor +- * @member: the name of the list_head within the struct. ++ * @pos: the type * to cursor ++ * @member: the name of the list_head within the struct. + */ + #define list_next_entry(pos, member) \ +- list_entry((pos)->member.next, typeof(*(pos)), member) ++ list_entry((pos)->member.next, typeof(*(pos)), member) + + /** + * list_prev_entry - get the prev element in list +- * @pos: the type * to cursor +- * @member: the name of the list_head within the struct. ++ * @pos: the type * to cursor ++ * @member: the name of the list_head within the struct. + */ + #define list_prev_entry(pos, member) \ +- list_entry((pos)->member.prev, typeof(*(pos)), member) ++ list_entry((pos)->member.prev, typeof(*(pos)), member) + + /** +- * list_for_each - iterate over a list +- * @pos: the &struct list_head to use as a loop cursor. +- * @head: the head for your list. ++ * list_for_each - iterate over a list ++ * @pos: the &struct list_head to use as a loop cursor. ++ * @head: the head for your list. + */ + #define list_for_each(pos, head) \ +- for (pos = (head)->next; pos != (head); pos = pos->next) ++ for ((pos) = (head)->next; (pos) != (head); (pos) = (pos)->next) + + /** +- * list_for_each_prev - iterate over a list backwards +- * @pos: the &struct list_head to use as a loop cursor. +- * @head: the head for your list. ++ * list_for_each_prev - iterate over a list backwards ++ * @pos: the &struct list_head to use as a loop cursor. ++ * @head: the head for your list. + */ + #define list_for_each_prev(pos, head) \ +- for (pos = (head)->prev; pos != (head); pos = pos->prev) ++ for ((pos) = (head)->prev; (pos) != (head); (pos) = (pos)->prev) + + /** + * list_for_each_safe - iterate over a list safe against removal of list entry +- * @pos: the &struct list_head to use as a loop cursor. +- * @n: another &struct list_head to use as temporary storage +- * @head: the head for your list. ++ * @pos: the &struct list_head to use as a loop cursor. ++ * @n: another &struct list_head to use as temporary storage ++ * @head: the head for your list. + */ +-#define list_for_each_safe(pos, n, head) \ +- for (pos = (head)->next, n = pos->next; pos != (head); \ +- pos = n, n = pos->next) ++#define list_for_each_safe(pos, n, head) \ ++ for ( \ ++ (pos) = (head)->next, (n) = (pos)->next; \ ++ (pos) != (head); \ ++ (pos) = (n), (n) = (pos)->next \ ++ ) + + /** + * list_for_each_prev_safe - iterate over a list backwards safe against removal + * of list entry +- * @pos: the &struct list_head to use as a loop cursor. +- * @n: another &struct list_head to use as temporary storage +- * @head: the head for your list. ++ * @pos: the &struct list_head to use as a loop cursor. ++ * @n: another &struct list_head to use as temporary storage ++ * @head: the head for your list. + */ +-#define list_for_each_prev_safe(pos, n, head) \ +- for (pos = (head)->prev, n = pos->prev; pos != (head); \ +- pos = n, n = pos->prev) ++#define list_for_each_prev_safe(pos, n, head) \ ++ for ( \ ++ (pos) = (head)->prev, (n) = (pos)->prev; \ ++ (pos) != (head); \ ++ (pos) = (n), (n) = (pos)->prev \ ++ ) + + /** +- * list_for_each_entry - iterate over list of given type +- * @pos: the type * to use as a loop cursor. +- * @head: the head for your list. +- * @member: the name of the list_head within the struct. ++ * list_for_each_entry - iterate over list of given type ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_head within the struct. + */ +-#define list_for_each_entry(pos, head, member) \ +- for (pos = list_first_entry(head, typeof(*pos), member); \ +- &pos->member != (head); pos = list_next_entry(pos, member)) ++#define list_for_each_entry(pos, head, member) \ ++ for ( \ ++ (pos) = list_first_entry(head, typeof(*(pos)), member); \ ++ &((pos)->member) != (head); \ ++ (pos) = list_next_entry(pos, member) \ ++ ) + + /** + * list_for_each_entry_reverse - iterate backwards over list of given type. +- * @pos: the type * to use as a loop cursor. +- * @head: the head for your list. +- * @member: the name of the list_head within the struct. ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_head within the struct. + */ +-#define list_for_each_entry_reverse(pos, head, member) \ +- for (pos = list_last_entry(head, typeof(*pos), member); \ +- &pos->member != (head); pos = list_prev_entry(pos, member)) ++#define list_for_each_entry_reverse(pos, head, member) \ ++ for ( \ ++ (pos) = list_last_entry(head, typeof(*(pos)), member); \ ++ &((pos)->member) != (head); \ ++ (pos) = list_prev_entry(pos, member) \ ++ ) + + /** + * list_prepare_entry - prepare a pos entry for use in + * list_for_each_entry_continue() +- * @pos: the type * to use as a start point +- * @head: the head of the list +- * @member: the name of the list_head within the struct. ++ * @pos: the type * to use as a start point ++ * @head: the head of the list ++ * @member: the name of the list_head within the struct. + * + * Prepares a pos entry for use as a start point in + * list_for_each_entry_continue(). + */ + #define list_prepare_entry(pos, head, member) \ +- ((pos) ?: list_entry(head, typeof(*pos), member)) ++ ((pos) ?: list_entry(head, typeof(*(pos)), member)) + + /** + * list_for_each_entry_continue - continue iteration over list of given type +- * @pos: the type * to use as a loop cursor. +- * @head: the head for your list. +- * @member: the name of the list_head within the struct. ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_head within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +-#define list_for_each_entry_continue(pos, head, member) \ +- for (pos = list_next_entry(pos, member); &pos->member != (head); \ +- pos = list_next_entry(pos, member)) ++#define list_for_each_entry_continue(pos, head, member) \ ++ for ( \ ++ (pos) = list_next_entry(pos, member); \ ++ &((pos)->member) != (head); \ ++ (pos) = list_next_entry(pos, member) \ ++ ) + + /** + * list_for_each_entry_continue_reverse - iterate backwards from the given point +- * @pos: the type * to use as a loop cursor. +- * @head: the head for your list. +- * @member: the name of the list_head within the struct. ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_head within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +-#define list_for_each_entry_continue_reverse(pos, head, member) \ +- for (pos = list_prev_entry(pos, member); &pos->member != (head); \ +- pos = list_prev_entry(pos, member)) ++#define list_for_each_entry_continue_reverse(pos, head, member) \ ++ for ( \ ++ (pos) = list_prev_entry(pos, member); \ ++ &((pos)->member) != (head); \ ++ (pos) = list_prev_entry(pos, member) \ ++ ) + + /** + * list_for_each_entry_from - iterate over list of given type from the current + * point +- * @pos: the type * to use as a loop cursor. +- * @head: the head for your list. +- * @member: the name of the list_head within the struct. ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_head within the struct. + * + * Iterate over list of given type, continuing from current position. + */ + #define list_for_each_entry_from(pos, head, member) \ +- for (; &pos->member != (head); pos = list_next_entry(pos, member)) ++ for (; &((pos)->member) != (head); (pos) = list_next_entry(pos, member)) + + /** + * list_for_each_entry_from_reverse - iterate backwards over list of given type + * from the current point +- * @pos: the type * to use as a loop cursor. +- * @head: the head for your list. +- * @member: the name of the list_head within the struct. ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_head within the struct. + * + * Iterate backwards over list of given type, continuing from current position. + */ + #define list_for_each_entry_from_reverse(pos, head, member) \ +- for (; &pos->member != (head); pos = list_prev_entry(pos, member)) ++ for (; &((pos)->member) != (head); (pos) = list_prev_entry(pos, member)) + + /** + * list_for_each_entry_safe - iterate over list of given type safe against + * removal of list entry +- * @pos: the type * to use as a loop cursor. +- * @n: another type * to use as temporary storage +- * @head: the head for your list. +- * @member: the name of the list_head within the struct. ++ * @pos: the type * to use as a loop cursor. ++ * @n: another type * to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the list_head within the struct. + */ +-#define list_for_each_entry_safe(pos, n, head, member) \ +- for (pos = list_first_entry(head, typeof(*pos), member), \ +- n = list_next_entry(pos, member); \ +- &pos->member != (head); pos = n, n = list_next_entry(n, member)) ++#define list_for_each_entry_safe(pos, n, head, member) \ ++ for ( \ ++ (pos) = list_first_entry(head, typeof(*(pos)), member), \ ++ (n) = list_next_entry(pos, member); \ ++ &((pos)->member) != (head); \ ++ (pos) = (n), (n) = list_next_entry(n, member) \ ++ ) + + /** + * list_for_each_entry_safe_continue - continue list iteration safe against + * removal +- * @pos: the type * to use as a loop cursor. +- * @n: another type * to use as temporary storage +- * @head: the head for your list. +- * @member: the name of the list_head within the struct. ++ * @pos: the type * to use as a loop cursor. ++ * @n: another type * to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the list_head within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ + #define list_for_each_entry_safe_continue(pos, n, head, member) \ +- for (pos = list_next_entry(pos, member), \ +- n = list_next_entry(pos, member); \ +- &pos->member != (head); pos = n, n = list_next_entry(n, member)) ++ for ( \ ++ (pos) = list_next_entry(pos, member), \ ++ (n) = list_next_entry(pos, member); \ ++ &((pos)->member) != (head); \ ++ (pos) = (n), (n) = list_next_entry(n, member) \ ++ ) + + /** + * list_for_each_entry_safe_from - iterate over list from current point safe + * against removal +- * @pos: the type * to use as a loop cursor. +- * @n: another type * to use as temporary storage +- * @head: the head for your list. +- * @member: the name of the list_head within the struct. ++ * @pos: the type * to use as a loop cursor. ++ * @n: another type * to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the list_head within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +-#define list_for_each_entry_safe_from(pos, n, head, member) \ +- for (n = list_next_entry(pos, member); &pos->member != (head); \ +- pos = n, n = list_next_entry(n, member)) ++#define list_for_each_entry_safe_from(pos, n, head, member) \ ++ for ( \ ++ (n) = list_next_entry(pos, member); \ ++ &((pos)->member) != (head); \ ++ (pos) = (n), (n) = list_next_entry(n, member) \ ++ ) + + /** + * list_for_each_entry_safe_reverse - iterate backwards over list safe against + * removal +- * @pos: the type * to use as a loop cursor. +- * @n: another type * to use as temporary storage +- * @head: the head for your list. +- * @member: the name of the list_head within the struct. ++ * @pos: the type * to use as a loop cursor. ++ * @n: another type * to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the list_head within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +-#define list_for_each_entry_safe_reverse(pos, n, head, member) \ +- for (pos = list_last_entry(head, typeof(*pos), member), \ +- n = list_prev_entry(pos, member); \ +- &pos->member != (head); pos = n, n = list_prev_entry(n, member)) ++#define list_for_each_entry_safe_reverse(pos, n, head, member) \ ++ for ( \ ++ (pos) = list_last_entry(head, typeof(*(pos)), member), \ ++ (n) = list_prev_entry(pos, member); \ ++ &((pos)->member) != (head); \ ++ (pos) = (n), (n) = list_prev_entry(n, member) \ ++ ) + + /** + * list_safe_reset_next - reset a stale list_for_each_entry_safe loop +- * @pos: the loop cursor used in the list_for_each_entry_safe loop +- * @n: temporary storage used in list_for_each_entry_safe +- * @member: the name of the list_head within the struct. ++ * @pos: the loop cursor used in the list_for_each_entry_safe loop ++ * @n: temporary storage used in list_for_each_entry_safe ++ * @member: the name of the list_head within the struct. + * + * list_safe_reset_next is not safe to use in general if the list may be + * modified concurrently (eg. the lock is dropped in the loop body). An +@@ -531,6 +563,6 @@ static inline void list_splice_tail(struct list_head *list, + * and list_safe_reset_next is called after re-taking the lock and before + * completing the current iteration of the loop body. + */ +-#define list_safe_reset_next(pos, n, member) n = list_next_entry(pos, member) ++#define list_safe_reset_next(pos, n, member) (n) = list_next_entry(pos, member) + + #endif +diff --git a/upatch-manage/log.h b/upatch-manage/log.h +index 32e9c56..a109958 100644 +--- a/upatch-manage/log.h ++++ b/upatch-manage/log.h +@@ -25,29 +25,22 @@ + #ifndef __UPATCH_LOG_H_ + #define __UPATCH_LOG_H_ + +-#include + #include ++#include + +-/* Files that include log.h must define loglevel and logprefix */ +-extern enum loglevel loglevel; +-extern char *logprefix; ++/* Files that include log.h must define g_loglevel and g_logprefix */ ++extern enum log_level g_loglevel; ++extern char *g_logprefix; + + enum exit_status { +- EXIT_STATUS_SUCCESS = 0, +- EXIT_STATUS_ERROR = 1, +- EXIT_STATUS_DIFF_FATAL = 2, +- EXIT_STATUS_NO_CHANGE = 3, ++ EXIT_STATUS_SUCCESS = 0, ++ EXIT_STATUS_ERROR = 1, + }; + +-/* Since upatch-build is an one-shot program, we do not care about failure +- * handler */ +-#define ERROR(format, ...) \ +- error(EXIT_STATUS_ERROR, 0, "ERROR: %s: %s: %d: " format, logprefix, \ +- __FUNCTION__, __LINE__, ##__VA_ARGS__) +- +-#define DIFF_FATAL(format, ...) \ +- error(EXIT_STATUS_DIFF_FATAL, 0, "ERROR: %s: %s: %d: " format, \ +- logprefix, __FUNCTION__, __LINE__, ##__VA_ARGS__) ++/* Since upatch-build is an one-shot program, we do not care about failure handler */ ++#define ERROR(format, ...) \ ++ error(EXIT_STATUS_ERROR, 0, "ERROR: %s: %s: %d: " format, \ ++ g_logprefix, __FUNCTION__, __LINE__, ##__VA_ARGS__) + + /* it is time cost */ + #define log_debug(format, ...) log(DEBUG, format, ##__VA_ARGS__) +@@ -55,22 +48,26 @@ enum exit_status { + #define log_warn(format, ...) log(WARN, format, ##__VA_ARGS__) + #define log_error(format, ...) log(ERR, format, ##__VA_ARGS__) + +-#define log(level, format, ...) \ +- ({ \ +- if (loglevel <= (level)) \ +- printf(format, ##__VA_ARGS__); \ +- }) ++#define log(level, format, ...) \ ++ do { \ ++ if (g_loglevel <= (level)) { \ ++ printf(format, ##__VA_ARGS__); \ ++ } \ ++ } while (0) + +-#define REQUIRE(COND, message) \ +- do \ +- if (!(COND)) \ +- ERROR(message); \ +- while (0) ++#define REQUIRE(COND, message) \ ++ do { \ ++ if (!(COND)) { \ ++ ERROR(message); \ ++ } \ ++ } \ ++ while (0) + +-enum loglevel { +- DEBUG, +- NORMAL, +- WARN, +- ERR, ++enum log_level { ++ DEBUG, ++ NORMAL, ++ WARN, ++ ERR, + }; ++ + #endif +diff --git a/upatch-manage/upatch-common.c b/upatch-manage/upatch-common.c +index 0161350..f9076ee 100644 +--- a/upatch-manage/upatch-common.c ++++ b/upatch-manage/upatch-common.c +@@ -24,5 +24,5 @@ + + bool streql(const char *a, const char *b) + { +- return strlen(a) == strlen(b) && !strncmp(a, b, strlen(a)); +-} +\ No newline at end of file ++ return strlen(a) == strlen(b) && !strncmp(a, b, strlen(a)); ++} +diff --git a/upatch-manage/upatch-common.h b/upatch-manage/upatch-common.h +index 0c0784d..9b5a0e6 100644 +--- a/upatch-manage/upatch-common.h ++++ b/upatch-manage/upatch-common.h +@@ -24,26 +24,28 @@ + #include + #include + +-#define ALLOC_LINK(_new, _list) \ +- { \ +- (_new) = calloc(1, sizeof(*(_new))); \ +- if (!(_new)) \ +- ERROR("calloc"); \ +- INIT_LIST_HEAD(&(_new)->list); \ +- if (_list) \ +- list_add(&(_new)->list, (_list)); \ +- } ++#define ALLOC_LINK(_new, _list) \ ++ do { \ ++ (_new) = calloc(1, sizeof(*(_new))); \ ++ if (!(_new)) { \ ++ ERROR("calloc"); \ ++ } \ ++ INIT_LIST_HEAD(&(_new)->list); \ ++ if (_list) { \ ++ list_add(&(_new)->list, (_list)); \ ++ } \ ++ } while (0) + + static inline int page_shift(long n) + { +- int res = -1; ++ int res = -1; + +- while (n) { +- res++; +- n >>= 1; +- } ++ while (n) { ++ res++; ++ n >>= 1; ++ } + +- return res; ++ return res; + } + + #ifndef PAGE_SIZE +@@ -51,12 +53,13 @@ static inline int page_shift(long n) + #define PAGE_MASK (~(PAGE_SIZE - 1)) + #define PAGE_SHIFT page_shift(PAGE_SIZE) + #endif ++ + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +-#define ALIGN(x, a) (((x) + (a)-1) & (~((a)-1))) ++#define ALIGN(x, a) (((x) + (a) - 1) & (~((a) - 1))) + #define PAGE_ALIGN(x) ALIGN((x), (unsigned long)PAGE_SIZE) + +-#define ROUND_DOWN(x, m) ((x) & ~((m)-1)) +-#define ROUND_UP(x, m) (((x) + (m)-1) & ~((m)-1)) ++#define ROUND_DOWN(x, m) ((x) & ~((m) - 1)) ++#define ROUND_UP(x, m) (((x) + (m) - 1) & ~((m) - 1)) + + #define BIT(x) (1UL << (x)) + +@@ -64,12 +67,12 @@ static inline int page_shift(long n) + + static inline long get_microseconds(struct timeval *start, struct timeval *end) + { +- long sec = end->tv_sec - start->tv_sec; +- long usec = end->tv_usec - start->tv_usec; ++ long sec = end->tv_sec - start->tv_sec; ++ long usec = end->tv_usec - start->tv_usec; + +- return sec * SEC2MICRO + usec; ++ return sec * SEC2MICRO + usec; + } + + bool streql(const char *, const char *); + +-#endif +\ No newline at end of file ++#endif +diff --git a/upatch-manage/upatch-elf.c b/upatch-manage/upatch-elf.c +index b8fd86b..93cb0b2 100644 +--- a/upatch-manage/upatch-elf.c ++++ b/upatch-manage/upatch-elf.c +@@ -47,7 +47,8 @@ static int read_from_offset(int fd, void **buf, unsigned long len, off_t offset) + + static int open_elf(struct elf_info *einfo, const char *name) + { +- int ret = 0, fd = -1; ++ int ret = 0; ++ int fd = -1; + char *sec_name; + struct stat st; + +@@ -65,7 +66,8 @@ static int open_elf(struct elf_info *einfo, const char *name) + goto out; + } + +- ret = read_from_offset(fd, (void **)&einfo->patch_buff, (unsigned long)st.st_size, 0); ++ ret = read_from_offset(fd, (void **)&einfo->patch_buff, ++ (unsigned long)st.st_size, 0); + if (ret != 0) { + log_error("Failed to read file '%s'\n", name); + goto out; +@@ -76,10 +78,12 @@ static int open_elf(struct elf_info *einfo, const char *name) + einfo->patch_size = (unsigned long)st.st_size; + einfo->hdr = (void *)einfo->patch_buff; + einfo->shdrs = (void *)einfo->hdr + einfo->hdr->e_shoff; +- einfo->shstrtab = (void *)einfo->hdr + einfo->shdrs[einfo->hdr->e_shstrndx].sh_offset; ++ einfo->shstrtab = (void *)einfo->hdr + ++ einfo->shdrs[einfo->hdr->e_shstrndx].sh_offset; + + void *einfo_eof = einfo->hdr + einfo->patch_size; +- if ((void *)einfo->shdrs > einfo_eof || (void *)einfo->shstrtab > einfo_eof) { ++ if ((void *)einfo->shdrs > einfo_eof || ++ (void *)einfo->shstrtab > einfo_eof) { + log_error("File '%s' is not a valid elf\n", name); + ret = -ENOEXEC; + goto out; +@@ -87,7 +91,8 @@ static int open_elf(struct elf_info *einfo, const char *name) + + for (unsigned int i = 0; i < einfo->hdr->e_shnum; ++i) { + sec_name = einfo->shstrtab + einfo->shdrs[i].sh_name; +- if (streql(sec_name, BUILD_ID_NAME) && einfo->shdrs[i].sh_type == SHT_NOTE) { ++ if (streql(sec_name, BUILD_ID_NAME) && ++ einfo->shdrs[i].sh_type == SHT_NOTE) { + einfo->num_build_id = i; + break; + } +@@ -123,7 +128,7 @@ int upatch_init(struct upatch_elf *uelf, const char *name) + uelf->index.sym = i; + uelf->index.str = uelf->info.shdrs[i].sh_link; + uelf->strtab = (char *)uelf->info.hdr + +- uelf->info.shdrs[uelf->info.shdrs[i].sh_link].sh_offset; ++ uelf->info.shdrs[uelf->info.shdrs[i].sh_link].sh_offset; + } else if (streql(sec_name, UPATCH_FUNC_NAME)) { + uelf->index.upatch_funcs = i; + } else if (streql(sec_name, UPATCH_FUNC_STRING)) { +@@ -138,25 +143,27 @@ static bool is_pie_elf(struct running_elf *relf) + { + GElf_Shdr *shdr = &relf->info.shdrs[relf->index.dynamic]; + GElf_Dyn *dyns = (void *)relf->info.hdr + shdr->sh_offset; ++ + if (relf->index.dynamic == 0) { + return false; + } ++ + for (Elf64_Xword i = 0; i < shdr->sh_size / sizeof(GElf_Dyn); i++) { + log_debug("Syminfo %lx, %lx\n", dyns[i].d_tag, dyns[i].d_un.d_val); + if (dyns[i].d_tag == DT_FLAGS_1) { +- if ((dyns[i].d_un.d_val & DF_1_PIE) != 0) ++ if ((dyns[i].d_un.d_val & DF_1_PIE) != 0) { + return true; ++ } + break; + } + } ++ + return false; + } + +-static bool is_dyn_elf(struct running_elf *relf) ++static inline bool is_dyn_elf(struct running_elf *relf) + { +- GElf_Ehdr *ehdr = relf->info.hdr; +- +- return ehdr->e_type == ET_DYN; ++ return relf->info.hdr->e_type == ET_DYN; + } + + int binary_init(struct running_elf *relf, const char *name) +@@ -175,22 +182,22 @@ int binary_init(struct running_elf *relf, const char *name) + relf->index.sym = i; + relf->index.str = relf->info.shdrs[i].sh_link; + relf->strtab = (char *)relf->info.hdr + +- relf->info.shdrs[relf->info.shdrs[i].sh_link].sh_offset; ++ relf->info.shdrs[relf->info.shdrs[i].sh_link].sh_offset; + } else if (relf->info.shdrs[i].sh_type == SHT_DYNSYM) { + log_debug("Found section '%s', idx=%d\n", DYNSYM_NAME, i); + relf->index.dynsym = i; + relf->index.dynstr = relf->info.shdrs[i].sh_link; + relf->dynstrtab = (char *)relf->info.hdr + +- relf->info.shdrs[relf->info.shdrs[i].sh_link].sh_offset; ++ relf->info.shdrs[relf->info.shdrs[i].sh_link].sh_offset; + } else if (relf->info.shdrs[i].sh_type == SHT_DYNAMIC) { +- log_debug("Found section '%s', idx=%d\n", DYNAMIC_NAME, i); ++ log_debug("Found section '%s', idx=%d\n", DYNAMIC_NAME, i); + relf->index.dynamic = i; + } else if (streql(sec_name, PLT_RELA_NAME) && +- relf->info.shdrs[i].sh_type == SHT_RELA) { ++ relf->info.shdrs[i].sh_type == SHT_RELA) { + log_debug("Found section '%s', idx=%d\n", PLT_RELA_NAME, i); + relf->index.rela_plt = i; + } else if (streql(sec_name, GOT_RELA_NAME) && +- relf->info.shdrs[i].sh_type == SHT_RELA) { ++ relf->info.shdrs[i].sh_type == SHT_RELA) { + log_debug("Found section '%s' idx=%d\n", GOT_RELA_NAME, i); + relf->index.rela_dyn = i; + } +@@ -201,50 +208,53 @@ int binary_init(struct running_elf *relf, const char *name) + if (relf->phdrs[i].p_type == PT_TLS) { + relf->tls_size = relf->phdrs[i].p_memsz; + relf->tls_align = relf->phdrs[i].p_align; +- log_debug("Found TLS size = %ld, align = %ld\n", relf->tls_size, relf->tls_align); ++ log_debug("Found TLS size = %ld, align = %ld\n", ++ relf->tls_size, relf->tls_align); + break; + } + } + + relf->info.is_pie = is_pie_elf(relf); + relf->info.is_dyn = is_dyn_elf(relf); ++ + return 0; + } + + bool check_build_id(struct elf_info *uelf, struct elf_info *relf) + { +- if (uelf->shdrs[uelf->num_build_id].sh_size != relf->shdrs[relf->num_build_id].sh_size) { +- return false; +- } +- +- void* uelf_build_id = (void *)uelf->hdr + uelf->shdrs[uelf->num_build_id].sh_offset; +- void* relf_build_id = (void *)relf->hdr + relf->shdrs[relf->num_build_id].sh_offset; +- size_t build_id_len = uelf->shdrs[uelf->num_build_id].sh_size; +- +- if (memcmp(uelf_build_id, relf_build_id, build_id_len) != 0) { +- return false; +- } +- return true; ++ GElf_Shdr *uelf_shdr = &uelf->shdrs[uelf->num_build_id]; ++ GElf_Shdr *relf_shdr = &relf->shdrs[uelf->num_build_id]; ++ ++ if (uelf_shdr->sh_size != relf_shdr->sh_size) { ++ return false; ++ } ++ ++ void* uelf_build_id = (void *)uelf->hdr + uelf_shdr->sh_offset; ++ void* relf_build_id = (void *)relf->hdr + relf_shdr->sh_offset; ++ size_t build_id_len = uelf_shdr->sh_size; ++ ++ if (memcmp(uelf_build_id, relf_build_id, build_id_len) != 0) { ++ return false; ++ } ++ ++ return true; + } + + void binary_close(struct running_elf *relf) + { +- // TODO: free relf + if (relf->info.patch_buff) { + free(relf->info.patch_buff); +- } ++ } + } + + void upatch_close(struct upatch_elf *uelf) + { +- // TODO: free uelf + if (uelf->info.patch_buff) { + free(uelf->info.patch_buff); +- } +- ++ } + if (uelf->core_layout.kbase) { + free(uelf->core_layout.kbase); +- } ++ } + } + + bool is_upatch_section(const char *name) +diff --git a/upatch-manage/upatch-elf.h b/upatch-manage/upatch-elf.h +index 51013b5..18e0d2c 100644 +--- a/upatch-manage/upatch-elf.h ++++ b/upatch-manage/upatch-elf.h +@@ -45,110 +45,110 @@ + #define UPATCH_ID_LEN 40 + + struct upatch_func_addr { +- unsigned long new_addr; +- unsigned long new_size; +- unsigned long old_addr; +- unsigned long old_size; ++ unsigned long new_addr; ++ unsigned long new_size; ++ unsigned long old_addr; ++ unsigned long old_size; + }; + + struct upatch_info_func { +- struct upatch_func_addr addr; +- unsigned long old_insn[2]; +- unsigned long new_insn; +- char *name; ++ struct upatch_func_addr addr; ++ unsigned long old_insn[2]; ++ unsigned long new_insn; ++ char *name; + }; + + struct upatch_info { +- char magic[7]; // upatch magic +- char id[UPATCH_ID_LEN + 1]; // upatch id +- unsigned long size; // upatch_info and upatch_info_func size +- unsigned long start; // upatch vma start +- unsigned long end; // upatch vma end +- unsigned long changed_func_num; +- struct upatch_info_func *funcs; +- char *func_names; +- unsigned long func_names_size; ++ char magic[7]; // upatch magic ++ char id[UPATCH_ID_LEN + 1]; // upatch id ++ unsigned long size; // upatch_info and upatch_info_func size ++ unsigned long start; // upatch vma start ++ unsigned long end; // upatch vma end ++ unsigned long changed_func_num; ++ struct upatch_info_func *funcs; ++ char *func_names; ++ unsigned long func_names_size; + }; + + struct upatch_layout { +- /* The actual code + data. */ +- void *kbase; +- void *base; +- /* Total size. */ +- unsigned long size; +- /* The size of the executable code. */ +- unsigned long text_size; +- /* Size of RO section of the module (text+rodata) */ +- unsigned long ro_size; +- /* Size of RO after init section, not use it now */ +- unsigned long ro_after_init_size; +- /* The size of the info. */ +- unsigned long info_size; ++ /* The actual code + data. */ ++ void *kbase; ++ void *base; ++ /* Total size. */ ++ unsigned long size; ++ /* The size of the executable code. */ ++ unsigned long text_size; ++ /* Size of RO section of the module (text+rodata) */ ++ unsigned long ro_size; ++ /* Size of RO after init section, not use it now */ ++ unsigned long ro_after_init_size; ++ /* The size of the info. */ ++ unsigned long info_size; + }; + + struct upatch_patch_func { +- struct upatch_func_addr addr; +- unsigned long sympos; /* handle local symbols */ +- char *name; ++ struct upatch_func_addr addr; ++ unsigned long sympos; /* handle local symbols */ ++ char *name; + }; + + struct elf_info { +- const char *name; +- ino_t inode; +- void *patch_buff; +- size_t patch_size; +- +- GElf_Ehdr *hdr; +- GElf_Shdr *shdrs; +- char *shstrtab; +- +- unsigned int num_build_id; +- bool is_pie; +- bool is_dyn; ++ const char *name; ++ ino_t inode; ++ void *patch_buff; ++ size_t patch_size; ++ ++ GElf_Ehdr *hdr; ++ GElf_Shdr *shdrs; ++ char *shstrtab; ++ ++ unsigned int num_build_id; ++ bool is_pie; ++ bool is_dyn; + }; + + struct running_elf { +- struct elf_info info; ++ struct elf_info info; + +- unsigned long num_syms; +- char *strtab; +- char *dynstrtab; ++ unsigned long num_syms; ++ char *strtab; ++ char *dynstrtab; + +- GElf_Phdr *phdrs; +- GElf_Xword tls_size; +- GElf_Xword tls_align; ++ GElf_Phdr *phdrs; ++ GElf_Xword tls_size; ++ GElf_Xword tls_align; + +- struct { +- unsigned int sym, str; +- unsigned int rela_dyn, rela_plt; +- unsigned int dynsym, dynstr, dynamic; +- } index; ++ struct { ++ unsigned int sym, str; ++ unsigned int rela_dyn, rela_plt; ++ unsigned int dynsym, dynstr, dynamic; ++ } index; + +- /* load bias, used to handle ASLR */ +- unsigned long load_bias; +- unsigned long load_start; ++ /* load bias, used to handle ASLR */ ++ unsigned long load_bias; ++ unsigned long load_start; + }; + + struct upatch_elf { +- struct elf_info info; ++ struct elf_info info; + +- unsigned long num_syms; +- char *strtab; ++ unsigned long num_syms; ++ char *strtab; + +- struct { +- unsigned int sym, str; +- unsigned int upatch_funcs; +- unsigned int upatch_string; +- } index; ++ struct { ++ unsigned int sym, str; ++ unsigned int upatch_funcs; ++ unsigned int upatch_string; ++ } index; + +- unsigned long symoffs, stroffs, core_typeoffs; +- unsigned long jmp_offs; +- unsigned int jmp_cur_entry, jmp_max_entry; ++ unsigned long symoffs, stroffs, core_typeoffs; ++ unsigned long jmp_offs; ++ unsigned int jmp_cur_entry, jmp_max_entry; + +- /* memory layout for patch */ +- struct upatch_layout core_layout; ++ /* memory layout for patch */ ++ struct upatch_layout core_layout; + +- struct running_elf *relf; ++ struct running_elf *relf; + }; + + int upatch_init(struct upatch_elf *, const char *); +diff --git a/upatch-manage/upatch-manage.c b/upatch-manage/upatch-manage.c +index 8b10a42..98868b7 100644 +--- a/upatch-manage/upatch-manage.c ++++ b/upatch-manage/upatch-manage.c +@@ -34,193 +34,200 @@ + #define PROG_VERSION "upatch-manage "BUILD_VERSION + #define COMMAND_SIZE 4 + +-enum loglevel loglevel = NORMAL; +-char *logprefix; ++enum log_level g_loglevel = NORMAL; ++char *g_logprefix; + + char *command[COMMAND_SIZE] = { "", "patch", "unpatch", "info" }; + enum Command { +- DEFAULT, +- PATCH, +- UNPATCH, +- INFO, ++ DEFAULT, ++ PATCH, ++ UNPATCH, ++ INFO, + }; + + struct arguments { +- int cmd; +- int pid; +- char *upatch; +- char *binary; +- char *uuid; +- bool verbose; ++ int cmd; ++ int pid; ++ char *upatch; ++ char *binary; ++ char *uuid; ++ bool verbose; + }; + + static struct argp_option options[] = { +- { "verbose", 'v', NULL, 0, "Show verbose output", 0 }, +- { "uuid", 'U', "uuid", 0, "the uuid of the upatch", 0 }, +- { "pid", 'p', "pid", 0, "the pid of the user-space process", 0 }, +- { "upatch", 'u', "upatch", 0, "the upatch file", 0 }, +- { "binary", 'b', "binary", 0, "the binary file", 0 }, +- { "cmd", 0, "patch", 0, "Apply a upatch file to a user-space process", 0 }, +- { "cmd", 0, "unpatch", 0, +- "Unapply a upatch file to a user-space process", 0 }, +- { NULL } ++ { "cmd", 0, "patch", 0, "Apply a upatch file to a process", 0 }, ++ { "cmd", 0, "unpatch", 0, "Unapply a upatch file to a process", 0 }, ++ { "pid", 'p', "pid", 0, "the pid of the user-space process", 0 }, ++ { "uuid", 'U', "uuid", 0, "the uuid of the upatch", 0 }, ++ { "upatch", 'u', "upatch", 0, "the upatch file", 0 }, ++ { "binary", 'b', "binary", 0, "the binary file", 0 }, ++ { "verbose", 'v', NULL, 0, "Show verbose output", 0 }, ++ { NULL } + }; + +-static char program_doc[] = "Operate a upatch file on the user-space process"; ++static char program_doc[] = "Operate a upatch file on the process"; + +-static char args_doc[] = +- " --pid --upatch --binary --uuid "; ++static char args_doc[] = " --pid --uuid " ++ "--upatch --binary "; + + const char *argp_program_version = PROG_VERSION; + + static error_t check_opt(struct argp_state *state) + { +- struct arguments *arguments = state->input; +- +- if (arguments->cmd == DEFAULT) { +- argp_usage(state); +- return ARGP_ERR_UNKNOWN; +- } +- switch (arguments->cmd) { +- case PATCH: +- case UNPATCH: +- case INFO: +- if (!arguments->pid || arguments->upatch == NULL || +- arguments->binary == NULL || arguments->uuid == NULL) { +- argp_usage(state); +- return ARGP_ERR_UNKNOWN; +- } +- default: +- break; +- } +- return 0; ++ struct arguments *arguments = state->input; ++ ++ if (arguments->cmd == DEFAULT) { ++ argp_usage(state); ++ return ARGP_ERR_UNKNOWN; ++ } ++ ++ switch (arguments->cmd) { ++ case PATCH: ++ case UNPATCH: ++ case INFO: ++ if (!arguments->pid || arguments->upatch == NULL || ++ arguments->binary == NULL || arguments->uuid == NULL) { ++ argp_usage(state); ++ return ARGP_ERR_UNKNOWN; ++ } ++ default: ++ break; ++ } ++ ++ return 0; + } + + static error_t parse_opt(int key, char *arg, struct argp_state *state) + { +- struct arguments *arguments = state->input; +- +- switch (key) { +- case 'v': +- arguments->verbose = true; +- break; +- case 'p': +- arguments->pid = atoi(arg); +- break; +- case 'u': +- arguments->upatch = arg; +- break; +- case 'b': +- arguments->binary = arg; +- break; +- case 'U': +- arguments->uuid = arg; +- break; +- case ARGP_KEY_ARG: +- if (state->arg_num >= 1) +- argp_usage(state); +- if (arguments->cmd != DEFAULT) +- argp_usage(state); +- for (int i = 1; i < COMMAND_SIZE; ++i) { +- if (!strcmp(arg, command[i])) { +- arguments->cmd = i; +- break; +- } +- } +- break; +- case ARGP_KEY_END: +- return check_opt(state); +- default: +- return ARGP_ERR_UNKNOWN; +- } +- return 0; ++ struct arguments *arguments = state->input; ++ ++ switch (key) { ++ case 'v': ++ arguments->verbose = true; ++ break; ++ case 'p': ++ arguments->pid = atoi(arg); ++ break; ++ case 'u': ++ arguments->upatch = arg; ++ break; ++ case 'b': ++ arguments->binary = arg; ++ break; ++ case 'U': ++ arguments->uuid = arg; ++ break; ++ case ARGP_KEY_ARG: ++ if (state->arg_num >= 1) { ++ argp_usage(state); ++ } ++ if (arguments->cmd != DEFAULT) { ++ argp_usage(state); ++ } ++ for (int i = 1; i < COMMAND_SIZE; ++i) { ++ if (!strcmp(arg, command[i])) { ++ arguments->cmd = i; ++ break; ++ } ++ } ++ break; ++ case ARGP_KEY_END: ++ return check_opt(state); ++ default: ++ return ARGP_ERR_UNKNOWN; ++ } ++ return 0; + } + +-static struct argp argp = { options, parse_opt, args_doc, program_doc, NULL, NULL, NULL }; ++static struct argp argp = { ++ options, parse_opt, args_doc, program_doc, NULL, NULL, NULL ++}; + +-int patch_upatch(const char *uuid, const char *binary_path, const char *upatch_path, int pid) ++int patch_upatch(const char *uuid, const char *binary_path, ++ const char *upatch_path, int pid) + { +- struct upatch_elf uelf; +- struct running_elf relf; +- memset(&uelf, 0, sizeof(struct upatch_elf)); +- memset(&relf, 0, sizeof(struct running_elf)); +- +- int ret = upatch_init(&uelf, upatch_path); +- if (ret) { +- log_error("Failed to initialize patch, pid=%d, ret=%d\n", pid, ret); +- goto out; +- } +- +- ret = process_patch(pid, &uelf, &relf, uuid, binary_path); +- if (ret) { +- log_error("Failed to patch process, pid=%d, ret=%d\n", pid, ret); +- goto out; +- } ++ struct upatch_elf uelf; ++ struct running_elf relf; ++ memset(&uelf, 0, sizeof(struct upatch_elf)); ++ memset(&relf, 0, sizeof(struct running_elf)); ++ ++ int ret = upatch_init(&uelf, upatch_path); ++ if (ret) { ++ log_error("Failed to initialize patch, pid=%d, ret=%d\n", pid, ret); ++ goto out; ++ } ++ ++ ret = process_patch(pid, &uelf, &relf, uuid, binary_path); ++ if (ret) { ++ log_error("Failed to patch process, pid=%d, ret=%d\n", pid, ret); ++ goto out; ++ } + + out: +- upatch_close(&uelf); +- binary_close(&relf); ++ upatch_close(&uelf); ++ binary_close(&relf); + +- return ret; ++ return ret; + } + + int unpatch_upatch(const char *uuid, int pid) + { +- int ret = 0; ++ int ret = 0; + +- ret = process_unpatch(pid, uuid); +- if (ret) { +- log_error("Failed to unpatch process, pid=%d, ret=%d\n", pid, ret); +- return ret; +- } ++ ret = process_unpatch(pid, uuid); ++ if (ret) { ++ log_error("Failed to unpatch process, pid=%d, ret=%d\n", pid, ret); ++ return ret; ++ } + +- return 0; ++ return 0; + } + + int info_upatch(int pid) + { +- int ret = process_info(pid); +- if (ret != 0) { +- log_error("Failed to get patch info, pid=%d, ret=%d\n", pid, ret); +- return ret; +- } ++ int ret = process_info(pid); ++ if (ret != 0) { ++ log_error("Failed to get patch info, pid=%d, ret=%d\n", pid, ret); ++ return ret; ++ } + +- return 0; ++ return 0; + } + + int main(int argc, char *argv[]) + { +- struct arguments args; +- int ret; +- +- memset(&args, 0, sizeof(struct arguments)); +- argp_parse(&argp, argc, argv, 0, NULL, &args); +- if (args.verbose) { +- loglevel = DEBUG; +- } +- +- logprefix = basename(args.upatch); +- log_debug("PID: %d\n", args.pid); +- log_debug("UUID: %s\n", args.uuid); +- log_debug("Patch: %s\n", args.upatch); +- log_debug("Binary: %s\n", args.binary); +- +- args.pid = args.pid & INT32_MAX; +- switch (args.cmd) { +- case PATCH: +- ret = patch_upatch(args.uuid, args.binary, args.upatch, args.pid); +- break; +- case UNPATCH: +- ret = unpatch_upatch(args.uuid, args.pid); +- break; +- case INFO: +- ret = info_upatch(args.pid); +- break; +- default: +- ERROR("Unknown command"); +- ret = EINVAL; +- break; +- } +- +- return abs(ret); ++ int ret; ++ ++ struct arguments args; ++ ++ memset(&args, 0, sizeof(struct arguments)); ++ argp_parse(&argp, argc, argv, 0, NULL, &args); ++ if (args.verbose) { ++ g_loglevel = DEBUG; ++ } ++ ++ g_logprefix = basename(args.upatch); ++ log_debug("PID: %d\n", args.pid); ++ log_debug("UUID: %s\n", args.uuid); ++ log_debug("Patch: %s\n", args.upatch); ++ log_debug("Binary: %s\n", args.binary); ++ ++ args.pid = args.pid & INT32_MAX; ++ switch (args.cmd) { ++ case PATCH: ++ ret = patch_upatch(args.uuid, args.binary, args.upatch, args.pid); ++ break; ++ case UNPATCH: ++ ret = unpatch_upatch(args.uuid, args.pid); ++ break; ++ case INFO: ++ ret = info_upatch(args.pid); ++ break; ++ default: ++ ERROR("Unknown command"); ++ ret = EINVAL; ++ break; ++ } ++ ++ return abs(ret); + } +diff --git a/upatch-manage/upatch-patch.c b/upatch-manage/upatch-patch.c +index 8aaa3b4..819b966 100644 +--- a/upatch-manage/upatch-patch.c ++++ b/upatch-manage/upatch-patch.c +@@ -46,175 +46,169 @@ + #define BITS_PER_LONG sizeof(unsigned long) * 8 + + static GElf_Off calculate_load_address(struct running_elf *relf, +- bool check_code) +-{ +- int i; +- GElf_Off min_addr = (unsigned long)-1; +- +- /* TODO: for ET_DYN, consider check PIE */ +- if (relf->info.hdr->e_type != ET_EXEC && +- relf->info.hdr->e_type != ET_DYN) { +- log_error("invalid elf type, it should be ET_EXEC or ET_DYN\n"); +- goto out; +- } +- +- for (i = 0; i < relf->info.hdr->e_phnum; ++i) { +- if (relf->phdrs[i].p_type != PT_LOAD) +- continue; +- if (!check_code || +- (check_code && (relf->phdrs[i].p_flags & PF_X))) +- min_addr = (min_addr > relf->phdrs[i].p_vaddr) ? +- relf->phdrs[i].p_vaddr : +- min_addr; +- // min_addr = min(min_addr, relf->phdrs[i].p_vaddr); +- } ++ bool check_code) ++{ ++ GElf_Off min_addr = (unsigned long)-1; ++ ++ /* TODO: for ET_DYN, consider check PIE */ ++ if (relf->info.hdr->e_type != ET_EXEC && ++ relf->info.hdr->e_type != ET_DYN) { ++ log_error("invalid elf type, it should be ET_EXEC or ET_DYN\n"); ++ goto out; ++ } ++ ++ for (int i = 0; i < relf->info.hdr->e_phnum; ++i) { ++ if (relf->phdrs[i].p_type != PT_LOAD) { ++ continue; ++ } ++ if (!check_code || ++ (check_code && (relf->phdrs[i].p_flags & PF_X))) { ++ min_addr = (min_addr > relf->phdrs[i].p_vaddr) ? ++ relf->phdrs[i].p_vaddr : min_addr; ++ } ++ } + + out: +- return min_addr; ++ return min_addr; + } + + static unsigned long calculate_mem_load(struct object_file *obj) + { +- struct obj_vm_area *ovma; +- unsigned long load_addr = (unsigned long)-1; +- +- list_for_each_entry(ovma, &obj->vma, list) { +- if (ovma->inmem.prot & PROT_EXEC) { +- load_addr = (load_addr > ovma->inmem.start) ? +- ovma->inmem.start : +- load_addr; +- } +- } ++ struct obj_vm_area *ovma; ++ unsigned long load_addr = (unsigned long)-1; ++ ++ list_for_each_entry(ovma, &obj->vma, list) { ++ if (ovma->inmem.prot & PROT_EXEC) { ++ load_addr = (load_addr > ovma->inmem.start) ? ++ ovma->inmem.start : load_addr; ++ } ++ } + +- return load_addr; ++ return load_addr; + } + + static int rewrite_section_headers(struct upatch_elf *uelf) + { +- unsigned int i; +- +- /* Handle SHF_ALLOC in this part */ +- +- /* This should always be true, but let's be sure. */ +- uelf->info.shdrs[0].sh_addr = 0; +- uelf->info.shdrs[0].sh_addralign = 0; +- +- for (i = 1; i < uelf->info.hdr->e_shnum; i++) { +- GElf_Shdr *shdr = &uelf->info.shdrs[i]; +- if (shdr->sh_type != SHT_NOBITS && +- uelf->info.patch_size < shdr->sh_offset + shdr->sh_size) { +- log_error("upatch len %lu truncated\n", +- uelf->info.patch_size); +- return -ENOEXEC; +- } +- +- /* Mark all sections sh_addr with their address in the +- temporary image. */ +- shdr->sh_addr = (size_t)uelf->info.hdr + shdr->sh_offset; +- log_debug("section %s at 0x%lx\n", +- uelf->info.shstrtab + shdr->sh_name, shdr->sh_addr); +- } ++ unsigned int i; ++ /* Handle SHF_ALLOC in this part */ ++ ++ /* This should always be true, but let's be sure. */ ++ uelf->info.shdrs[0].sh_addr = 0; ++ uelf->info.shdrs[0].sh_addralign = 0; ++ ++ for (i = 1; i < uelf->info.hdr->e_shnum; i++) { ++ GElf_Shdr *shdr = &uelf->info.shdrs[i]; ++ if (shdr->sh_type != SHT_NOBITS && ++ uelf->info.patch_size < shdr->sh_offset + shdr->sh_size) { ++ log_error("upatch len %lu truncated\n", uelf->info.patch_size); ++ return -ENOEXEC; ++ } ++ ++ /* Mark all sections sh_addr with their address in the ++ temporary image. */ ++ shdr->sh_addr = (size_t)uelf->info.hdr + shdr->sh_offset; ++ log_debug("section %s at 0x%lx\n", ++ uelf->info.shstrtab + shdr->sh_name, shdr->sh_addr); ++ } + +- return 0; ++ return 0; + } + +-static unsigned long get_offset(unsigned long *size, +- GElf_Shdr *sechdr) ++static unsigned long get_offset(unsigned long *size, GElf_Shdr *sechdr) + { +- unsigned long ret; ++ unsigned long ret; ++ ++ ret = ALIGN(*size, (unsigned long)(sechdr->sh_addralign ?: 1)); ++ *size = (unsigned long)ret + sechdr->sh_size; + +- ret = ALIGN(*size, (unsigned long)(sechdr->sh_addralign ?: 1)); +- *size = (unsigned long)ret + sechdr->sh_size; +- return ret; ++ return ret; + } + + static void layout_upatch_info(struct upatch_elf *uelf) + { +- GElf_Shdr *upatch_func = uelf->info.shdrs + uelf->index.upatch_funcs; +- unsigned long num = upatch_func->sh_size / sizeof(struct upatch_patch_func); +- GElf_Shdr *upatch_string = uelf->info.shdrs + uelf->index.upatch_string; ++ GElf_Shdr *upatch_func = uelf->info.shdrs + uelf->index.upatch_funcs; ++ unsigned long num = upatch_func->sh_size / sizeof(struct upatch_patch_func); ++ GElf_Shdr *upatch_string = uelf->info.shdrs + uelf->index.upatch_string; + +- uelf->core_layout.info_size = uelf->core_layout.size; +- uelf->core_layout.size += sizeof(struct upatch_info) + +- num * sizeof(struct upatch_info_func) + upatch_string->sh_size; +- uelf->core_layout.size = PAGE_ALIGN(uelf->core_layout.size); ++ uelf->core_layout.info_size = uelf->core_layout.size; ++ uelf->core_layout.size += sizeof(struct upatch_info) + ++ num * sizeof(struct upatch_info_func) + upatch_string->sh_size; ++ uelf->core_layout.size = PAGE_ALIGN(uelf->core_layout.size); + } + + static void layout_jmptable(struct upatch_elf *uelf) + { +- uelf->jmp_cur_entry = 0; +- uelf->jmp_max_entry = JMP_TABLE_MAX_ENTRY; +- uelf->jmp_offs = ALIGN(uelf->core_layout.size, sizeof(unsigned long)); +- uelf->core_layout.size = +- uelf->jmp_offs + uelf->jmp_max_entry * get_jmp_table_entry(); +- uelf->core_layout.text_size = uelf->core_layout.size; ++ uelf->jmp_cur_entry = 0; ++ uelf->jmp_max_entry = JMP_TABLE_MAX_ENTRY; ++ uelf->jmp_offs = ALIGN(uelf->core_layout.size, sizeof(unsigned long)); ++ uelf->core_layout.size = uelf->jmp_offs + ++ uelf->jmp_max_entry * get_jmp_table_entry(); ++ uelf->core_layout.text_size = uelf->core_layout.size; + } + + static void layout_sections(struct upatch_elf *uelf) + { +- static unsigned long const masks[][2] = { +- /* NOTE: all executable code must be the last section +- * in this array; otherwise modify the text_size +- * finder in the two loops below */ +- { SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL }, +- { SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL }, +- { SHF_RO_AFTER_INIT | SHF_ALLOC, ARCH_SHF_SMALL }, +- { SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL }, +- { ARCH_SHF_SMALL | SHF_ALLOC, 0 } +- }; +- unsigned int m, i; +- +- for (i = 0; i < uelf->info.hdr->e_shnum; i++) +- uelf->info.shdrs[i].sh_entsize = ~0UL; +- +- log_debug("upatch section allocation order:\n"); +- for (m = 0; m < ARRAY_SIZE(masks); ++m) { +- for (i = 0; i < uelf->info.hdr->e_shnum; ++i) { +- GElf_Shdr *s = &uelf->info.shdrs[i]; +- const char *sname = uelf->info.shstrtab + s->sh_name; +- +- if ((s->sh_flags & masks[m][0]) != masks[m][0] || +- (s->sh_flags & masks[m][1]) || +- s->sh_entsize != ~0UL) +- continue; +- +- s->sh_entsize = +- get_offset(&uelf->core_layout.size, s); +- log_debug("\tm = %d; %s: sh_entsize: 0x%lx\n", m, sname, +- s->sh_entsize); +- } +- switch (m) { +- case 0: /* executable */ +- uelf->core_layout.size = +- PAGE_ALIGN(uelf->core_layout.size); +- uelf->core_layout.text_size = uelf->core_layout.size; +- break; +- case 1: /* RO: text and ro-data */ +- uelf->core_layout.size = +- PAGE_ALIGN(uelf->core_layout.size); +- uelf->core_layout.ro_size = uelf->core_layout.size; +- break; +- case 2: /* RO after init */ +- uelf->core_layout.size = +- PAGE_ALIGN(uelf->core_layout.size); +- uelf->core_layout.ro_after_init_size = +- uelf->core_layout.size; +- break; +- case 3: /* whole core */ +- uelf->core_layout.size = +- PAGE_ALIGN(uelf->core_layout.size); +- break; +- default: +- break; +- } +- } ++ static unsigned long const masks[][2] = { ++ /* NOTE: all executable code must be the last section ++ * in this array; otherwise modify the text_size ++ * finder in the two loops below */ ++ { SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL }, ++ { SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL }, ++ { SHF_RO_AFTER_INIT | SHF_ALLOC, ARCH_SHF_SMALL }, ++ { SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL }, ++ { ARCH_SHF_SMALL | SHF_ALLOC, 0 } ++ }; ++ unsigned int m; ++ unsigned int i; ++ ++ for (i = 0; i < uelf->info.hdr->e_shnum; i++) { ++ uelf->info.shdrs[i].sh_entsize = ~0UL; ++ } ++ ++ log_debug("upatch section allocation order:\n"); ++ for (m = 0; m < ARRAY_SIZE(masks); ++m) { ++ for (i = 0; i < uelf->info.hdr->e_shnum; ++i) { ++ GElf_Shdr *s = &uelf->info.shdrs[i]; ++ const char *sname = uelf->info.shstrtab + s->sh_name; ++ ++ if ((s->sh_flags & masks[m][0]) != masks[m][0] || ++ (s->sh_flags & masks[m][1]) || s->sh_entsize != ~0UL) { ++ continue; ++ } ++ ++ s->sh_entsize = get_offset(&uelf->core_layout.size, s); ++ log_debug("\tm = %d; %s: sh_entsize: 0x%lx\n", m, sname, ++ s->sh_entsize); ++ } ++ switch (m) { ++ case 0: /* executable */ ++ uelf->core_layout.size = PAGE_ALIGN(uelf->core_layout.size); ++ uelf->core_layout.text_size = uelf->core_layout.size; ++ break; ++ case 1: /* RO: text and ro-data */ ++ uelf->core_layout.size = PAGE_ALIGN(uelf->core_layout.size); ++ uelf->core_layout.ro_size = uelf->core_layout.size; ++ break; ++ case 2: /* RO after init */ ++ uelf->core_layout.size = PAGE_ALIGN(uelf->core_layout.size); ++ uelf->core_layout.ro_after_init_size = ++ uelf->core_layout.size; ++ break; ++ case 3: /* whole core */ ++ uelf->core_layout.size = PAGE_ALIGN(uelf->core_layout.size); ++ break; ++ default: ++ break; ++ } ++ } + } + + /* TODO: only included used symbol */ + static bool is_upatch_symbol(void) + { +- return true; ++ return true; + } ++ + /* + * We only allocate and copy the strings needed by the parts of symtab + * we keep. This is simple, but has the effect of making multiple +@@ -224,798 +218,794 @@ static bool is_upatch_symbol(void) + */ + static void layout_symtab(struct upatch_elf *uelf) + { +- GElf_Shdr *symsect = uelf->info.shdrs + uelf->index.sym; +- GElf_Shdr *strsect = uelf->info.shdrs + uelf->index.str; +- /* TODO: only support same arch as kernel now */ +- const GElf_Sym *src; +- unsigned long i, nsrc, ndst, strtab_size = 0; +- +- /* Put symbol section at end of init part of module. */ +- symsect->sh_flags |= SHF_ALLOC; +- symsect->sh_entsize = get_offset(&uelf->core_layout.size, symsect); +- log_debug("\t%s\n", uelf->info.shstrtab + symsect->sh_name); +- +- src = (void *)uelf->info.hdr + symsect->sh_offset; +- nsrc = symsect->sh_size / sizeof(*src); +- +- /* Compute total space required for the symbols' strtab. */ +- for (ndst = i = 0; i < nsrc; i++) { +- if (i == 0 || is_upatch_symbol()) { +- strtab_size += +- strlen(&uelf->strtab[src[i].st_name]) + 1; +- ndst++; +- } +- } +- +- /* Append room for core symbols at end of core part. */ +- uelf->symoffs = +- ALIGN(uelf->core_layout.size, symsect->sh_addralign ?: 1); +- uelf->stroffs = uelf->core_layout.size = +- uelf->symoffs + ndst * sizeof(GElf_Sym); +- uelf->core_layout.size += strtab_size; +- uelf->core_typeoffs = uelf->core_layout.size; +- uelf->core_layout.size += ndst * sizeof(char); +- uelf->core_layout.size = PAGE_ALIGN(uelf->core_layout.size); +- +- /* Put string table section at end of init part of module. */ +- strsect->sh_flags |= SHF_ALLOC; +- strsect->sh_entsize = get_offset(&uelf->core_layout.size, strsect); +- uelf->core_layout.size = PAGE_ALIGN(uelf->core_layout.size); +- log_debug("\t%s\n", uelf->info.shstrtab + strsect->sh_name); ++ GElf_Shdr *symsect = uelf->info.shdrs + uelf->index.sym; ++ GElf_Shdr *strsect = uelf->info.shdrs + uelf->index.str; ++ /* TODO: only support same arch as kernel now */ ++ const GElf_Sym *src; ++ unsigned long i; ++ unsigned long nsrc; ++ unsigned long ndst; ++ unsigned long strtab_size = 0; ++ ++ /* Put symbol section at end of init part of module. */ ++ symsect->sh_flags |= SHF_ALLOC; ++ symsect->sh_entsize = get_offset(&uelf->core_layout.size, symsect); ++ log_debug("\t%s\n", uelf->info.shstrtab + symsect->sh_name); ++ ++ src = (void *)uelf->info.hdr + symsect->sh_offset; ++ nsrc = symsect->sh_size / sizeof(*src); ++ ++ /* Compute total space required for the symbols' strtab. */ ++ for (ndst = i = 0; i < nsrc; i++) { ++ if (i == 0 || is_upatch_symbol()) { ++ strtab_size += strlen(&uelf->strtab[src[i].st_name]) + 1; ++ ndst++; ++ } ++ } ++ ++ /* Append room for core symbols at end of core part. */ ++ uelf->symoffs = ALIGN(uelf->core_layout.size, symsect->sh_addralign ?: 1); ++ uelf->stroffs = uelf->core_layout.size = ++ uelf->symoffs + ndst * sizeof(GElf_Sym); ++ uelf->core_layout.size += strtab_size; ++ uelf->core_typeoffs = uelf->core_layout.size; ++ uelf->core_layout.size += ndst * sizeof(char); ++ uelf->core_layout.size = PAGE_ALIGN(uelf->core_layout.size); ++ ++ /* Put string table section at end of init part of module. */ ++ strsect->sh_flags |= SHF_ALLOC; ++ strsect->sh_entsize = get_offset(&uelf->core_layout.size, strsect); ++ uelf->core_layout.size = PAGE_ALIGN(uelf->core_layout.size); ++ log_debug("\t%s\n", uelf->info.shstrtab + strsect->sh_name); + } + + static void *upatch_alloc(struct object_file *obj, size_t sz) + { +- int ret; +- unsigned long addr; +- struct vm_hole *hole = NULL; +- +- addr = object_find_patch_region(obj, sz, &hole); +- if (!addr) +- return NULL; ++ struct vm_hole *hole = NULL; + +- addr = upatch_mmap_remote(proc2pctx(obj->proc), addr, sz, +- PROT_READ | PROT_WRITE | PROT_EXEC, +- MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, +- (unsigned long)-1, 0); +- if (addr == 0) { +- return NULL; +- } ++ unsigned long addr = object_find_patch_region(obj, sz, &hole); ++ if (!addr) { ++ return NULL; ++ } + +- log_debug("Allocated 0x%lx bytes at 0x%lx of '%s'\n", sz, addr, obj->name); ++ addr = upatch_mmap_remote(proc2pctx(obj->proc), addr, sz, ++ PROT_READ | PROT_WRITE | PROT_EXEC, ++ MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, ++ (unsigned long)-1, 0); ++ if (addr == 0) { ++ return NULL; ++ } + +- // log_debug("Marking this space as busy\n"); +- ret = vm_hole_split(hole, addr, addr + sz); +- if (ret) { +- // TODO: clear +- log_error("Failed to split vm hole\n"); +- return NULL; +- } ++ log_debug("Allocated 0x%lx bytes at 0x%lx of '%s'\n", sz, addr, obj->name); ++ int ret = vm_hole_split(hole, addr, addr + sz); ++ if (ret) { ++ // TODO: clear ++ log_error("Failed to split vm hole\n"); ++ return NULL; ++ } + +- return (void *)addr; ++ return (void *)addr; + } + +-static void upatch_free(struct object_file *obj, void *base, +- unsigned long size) ++static void upatch_free(struct object_file *obj, void *base, unsigned long size) + { +- log_debug("Free patch memory %p\n", base); +- if (upatch_munmap_remote(proc2pctx(obj->proc), (unsigned long)base, size)) { +- log_error("Failed to free patch memory %p\n", base); +- } ++ log_debug("Free patch memory %p\n", base); ++ if (upatch_munmap_remote(proc2pctx(obj->proc), (unsigned long)base, size)) { ++ log_error("Failed to free patch memory %p\n", base); ++ } + } + + static int __alloc_memory(struct object_file *obj_file, +- struct upatch_layout *layout) ++ struct upatch_layout *layout) + { +- /* Do the allocs. */ +- layout->base = upatch_alloc(obj_file, layout->size); +- if (!layout->base) { +- return -errno; +- } ++ /* Do the allocs. */ ++ layout->base = upatch_alloc(obj_file, layout->size); ++ if (!layout->base) { ++ return -errno; ++ } + +- layout->kbase = malloc(layout->size); +- if (!layout->kbase) { +- upatch_free(obj_file, layout->base, layout->size); +- return -errno; +- } ++ layout->kbase = malloc(layout->size); ++ if (!layout->kbase) { ++ upatch_free(obj_file, layout->base, layout->size); ++ return -errno; ++ } + +- memset(layout->kbase, 0, layout->size); ++ memset(layout->kbase, 0, layout->size); + +- return 0; ++ return 0; + } + + static int alloc_memory(struct upatch_elf *uelf, struct object_file *obj) + { +- int i, ret; +- +- /* Do the allocs. */ +- ret = __alloc_memory(obj, &uelf->core_layout); +- if (ret) { +- return ret; +- } +- +- /* Transfer each section which specifies SHF_ALLOC */ +- log_debug("Final section addresses:\n"); +- for (i = 0; i < uelf->info.hdr->e_shnum; i++) { +- void *kdest; +- void *dest; +- GElf_Shdr *shdr = &uelf->info.shdrs[i]; +- +- if (!(shdr->sh_flags & SHF_ALLOC)) { +- continue; +- } +- +- kdest = uelf->core_layout.kbase + shdr->sh_entsize; +- dest = uelf->core_layout.base + shdr->sh_entsize; +- +- if (shdr->sh_type != SHT_NOBITS) { +- memcpy(kdest, (void *)shdr->sh_addr, shdr->sh_size); +- } ++ int ret = __alloc_memory(obj, &uelf->core_layout); ++ if (ret) { ++ return ret; ++ } + +- shdr->sh_addr = (unsigned long)kdest; +- /* overuse this attr to record user address */ +- shdr->sh_addralign = (unsigned long)dest; +- log_debug("\t0x%lx %s <- 0x%lx\n", (long)kdest, +- uelf->info.shstrtab + shdr->sh_name, (long)dest); +- } ++ /* Transfer each section which specifies SHF_ALLOC */ ++ log_debug("Final section addresses:\n"); ++ for (int i = 0; i < uelf->info.hdr->e_shnum; i++) { ++ GElf_Shdr *shdr = &uelf->info.shdrs[i]; ++ ++ if (!(shdr->sh_flags & SHF_ALLOC)) { ++ continue; ++ } ++ ++ void *kdest = uelf->core_layout.kbase + shdr->sh_entsize; ++ void *dest = uelf->core_layout.base + shdr->sh_entsize; ++ if (shdr->sh_type != SHT_NOBITS) { ++ memcpy(kdest, (void *)shdr->sh_addr, shdr->sh_size); ++ } ++ ++ shdr->sh_addr = (unsigned long)kdest; ++ /* overuse this attr to record user address */ ++ shdr->sh_addralign = (unsigned long)dest; ++ log_debug("\t0x%lx %s <- 0x%lx\n", (long)kdest, ++ uelf->info.shstrtab + shdr->sh_name, (long)dest); ++ } + +- return 0; ++ return 0; + } + + static int post_memory(struct upatch_elf *uelf, struct object_file *obj) + { +- int ret = 0; +- +- log_debug("Post kbase %lx(%lx) to base %lx\n", +- (unsigned long)uelf->core_layout.kbase, +- uelf->core_layout.size, +- (unsigned long)uelf->core_layout.base); +- ret = upatch_process_mem_write(obj->proc, uelf->core_layout.kbase, +- (unsigned long)uelf->core_layout.base, +- uelf->core_layout.size); +- if (ret) { +- log_error("Failed to move kbase to base, ret=%d\n", ret); +- goto out; +- } ++ log_debug("Post kbase %lx(%lx) to base %lx\n", ++ (unsigned long)uelf->core_layout.kbase, ++ uelf->core_layout.size, ++ (unsigned long)uelf->core_layout.base); ++ ++ int ret = upatch_process_mem_write(obj->proc, ++ uelf->core_layout.kbase, (unsigned long)uelf->core_layout.base, ++ uelf->core_layout.size); ++ if (ret) { ++ log_error("Failed to move kbase to base, ret=%d\n", ret); ++ } + +-out: +- return ret; ++ return ret; + } + + static int upatch_info_alloc(struct upatch_elf *uelf, struct upatch_info *uinfo) + { +- GElf_Shdr *upatch_funcs = &uelf->info.shdrs[uelf->index.upatch_funcs]; +- size_t num = upatch_funcs->sh_size / sizeof(struct upatch_patch_func); ++ GElf_Shdr *upatch_funcs = &uelf->info.shdrs[uelf->index.upatch_funcs]; ++ size_t num = upatch_funcs->sh_size / sizeof(struct upatch_patch_func); + +- uinfo->funcs = (void *)malloc(num * sizeof(*uinfo->funcs)); +- if (uinfo->funcs == NULL) { +- log_error("Failed to malloc uinfo->funcs\n"); +- return -ENOMEM; +- } +- return 0; ++ uinfo->funcs = (void *)malloc(num * sizeof(*uinfo->funcs)); ++ if (uinfo->funcs == NULL) { ++ log_error("Failed to malloc uinfo->funcs\n"); ++ return -ENOMEM; ++ } ++ return 0; + } + + static void upatch_info_init(struct upatch_elf *uelf, struct upatch_info *uinfo) + { +- GElf_Shdr *ufuncs = &uelf->info.shdrs[uelf->index.upatch_funcs]; +- GElf_Shdr *ustring = &uelf->info.shdrs[uelf->index.upatch_string]; +- struct upatch_patch_func *funcs = (void *)uelf->info.hdr + ufuncs->sh_offset; +- char *names = (void *)uelf->info.hdr + ustring->sh_offset; +- +- uinfo->changed_func_num = ufuncs->sh_size / sizeof(struct upatch_patch_func); +- uinfo->func_names_size = ustring->sh_size; +- uinfo->func_names = names; +- +- for (unsigned long i = 0; i < uinfo->changed_func_num; i++) { +- uinfo->funcs[i].addr = funcs[i].addr; +- uinfo->funcs[i].addr.old_addr += uelf->relf->load_bias; +- uinfo->funcs[i].name = names; +- names += strlen(names) + 1; +- } ++ GElf_Shdr *ufuncs = &uelf->info.shdrs[uelf->index.upatch_funcs]; ++ GElf_Shdr *ustring = &uelf->info.shdrs[uelf->index.upatch_string]; ++ struct upatch_patch_func *funcs = (void *)uelf->info.hdr + ++ ufuncs->sh_offset; ++ char *names = (void *)uelf->info.hdr + ustring->sh_offset; ++ ++ uinfo->changed_func_num = ufuncs->sh_size / ++ sizeof(struct upatch_patch_func); ++ uinfo->func_names_size = ustring->sh_size; ++ uinfo->func_names = names; ++ ++ for (unsigned long i = 0; i < uinfo->changed_func_num; i++) { ++ uinfo->funcs[i].addr = funcs[i].addr; ++ uinfo->funcs[i].addr.old_addr += uelf->relf->load_bias; ++ uinfo->funcs[i].name = names; ++ names += strlen(names) + 1; ++ } + } + +-static int upatch_active_stack_check(struct upatch_elf *uelf, struct upatch_process *proc) ++static int upatch_active_stack_check(struct upatch_elf *uelf, ++ struct upatch_process *proc) + { +- struct upatch_info uinfo; +- int ret = 0; ++ struct upatch_info uinfo; ++ ++ int ret = upatch_info_alloc(uelf, &uinfo); ++ if (ret < 0) { ++ return ret; ++ } + +- ret = upatch_info_alloc(uelf, &uinfo); +- if (ret < 0) { +- return ret; +- } +- upatch_info_init(uelf, &uinfo); +- ret = upatch_stack_check(&uinfo, proc, ACTIVE); +- free(uinfo.funcs); +- return ret; ++ upatch_info_init(uelf, &uinfo); ++ ret = upatch_stack_check(&uinfo, proc, ACTIVE); ++ ++ free(uinfo.funcs); ++ return ret; + } + + static struct object_file *upatch_find_obj(struct upatch_elf *uelf, +- struct upatch_process *proc) +-{ +- struct object_file *obj = NULL; +- GElf_Off min_addr; +- +- list_for_each_entry(obj, &proc->objs, list) { +- if (obj->inode == uelf->relf->info.inode) { +- min_addr = calculate_load_address(uelf->relf, true); +- uelf->relf->load_start = calculate_mem_load(obj); +- uelf->relf->load_bias = uelf->relf->load_start - min_addr; +- log_debug("load_bias = %lx\n", uelf->relf->load_bias); +- return obj; +- } +- } +- log_error("Cannot find inode %lu in pid %d, file is not loaded\n", +- uelf->relf->info.inode, proc->pid); +- return NULL; +-} +-static int complete_info(struct upatch_elf *uelf, struct object_file *obj, const char *uuid) +-{ +- int ret = 0; +- struct upatch_info *uinfo = +- (void *)uelf->core_layout.kbase + uelf->core_layout.info_size; +- struct upatch_patch_func *upatch_funcs_addr = +- (void *)uelf->info.shdrs[uelf->index.upatch_funcs].sh_addr; +- GElf_Shdr *upatch_string = &uelf->info.shdrs[uelf->index.upatch_string]; +- +- memcpy(uinfo->magic, UPATCH_HEADER, strlen(UPATCH_HEADER)); +- memcpy(uinfo->id, uuid, strlen(uuid)); +- +- uinfo->size = uelf->core_layout.size - uelf->core_layout.info_size; +- uinfo->start = (unsigned long)uelf->core_layout.base; +- uinfo->end = +- (unsigned long)uelf->core_layout.base + uelf->core_layout.size; +- uinfo->changed_func_num = +- uelf->info.shdrs[uelf->index.upatch_funcs].sh_size / +- sizeof(struct upatch_patch_func); +- +- uinfo->func_names = (void *)uinfo + sizeof(*uinfo); +- uinfo->func_names_size = upatch_string->sh_size; +- memcpy(uinfo->func_names, (void *)upatch_string->sh_addr, upatch_string->sh_size); +- +- log_debug("Changed insn:\n"); +- uinfo->funcs = (void *)uinfo->func_names + uinfo->func_names_size; +- for (unsigned int i = 0; i < uinfo->changed_func_num; ++i) { +- struct upatch_info_func *upatch_func = &uinfo->funcs[i]; +- +- upatch_func->addr = upatch_funcs_addr[i].addr; +- upatch_func->addr.old_addr += uelf->relf->load_bias; +- ret = upatch_process_mem_read(obj->proc, upatch_func->addr.old_addr, +- &upatch_func->old_insn, +- get_origin_insn_len()); +- if (ret) { +- log_error("can't read origin insn at 0x%lx - %d\n", +- upatch_func->addr.old_addr, ret); +- goto out; +- } +- +- upatch_func->new_insn = get_new_insn(); +- +- log_debug("\t0x%lx(0x%lx 0x%lx -> 0x%lx 0x%lx)\n", upatch_func->addr.old_addr, +- upatch_func->old_insn[0], upatch_func->old_insn[1], +- upatch_func->new_insn, upatch_func->addr.new_addr); +- } ++ struct upatch_process *proc) ++{ ++ struct object_file *obj = NULL; ++ GElf_Off min_addr; ++ ++ list_for_each_entry(obj, &proc->objs, list) { ++ if (obj->inode == uelf->relf->info.inode) { ++ min_addr = calculate_load_address(uelf->relf, true); ++ uelf->relf->load_start = calculate_mem_load(obj); ++ uelf->relf->load_bias = uelf->relf->load_start - min_addr; ++ ++ log_debug("load_bias = %lx\n", uelf->relf->load_bias); ++ return obj; ++ } ++ } ++ ++ log_error("Cannot find inode %lu in pid %d, file is not loaded\n", ++ uelf->relf->info.inode, proc->pid); ++ return NULL; ++} ++static int complete_info(struct upatch_elf *uelf, ++ struct object_file *obj, const char *uuid) ++{ ++ int ret = 0; ++ ++ struct upatch_info *uinfo = (void *)uelf->core_layout.kbase + ++ uelf->core_layout.info_size; ++ struct upatch_patch_func *upatch_funcs_addr = ++ (void *)uelf->info.shdrs[uelf->index.upatch_funcs].sh_addr; ++ GElf_Shdr *upatch_string = &uelf->info.shdrs[uelf->index.upatch_string]; ++ ++ memcpy(uinfo->magic, UPATCH_HEADER, strlen(UPATCH_HEADER)); ++ memcpy(uinfo->id, uuid, strlen(uuid)); ++ ++ uinfo->size = uelf->core_layout.size - uelf->core_layout.info_size; ++ uinfo->start = (unsigned long)uelf->core_layout.base; ++ uinfo->end = (unsigned long)uelf->core_layout.base + ++ uelf->core_layout.size; ++ uinfo->changed_func_num = ++ uelf->info.shdrs[uelf->index.upatch_funcs].sh_size / ++ sizeof(struct upatch_patch_func); ++ ++ uinfo->func_names = (void *)uinfo + sizeof(*uinfo); ++ uinfo->func_names_size = upatch_string->sh_size; ++ memcpy(uinfo->func_names, (void *)upatch_string->sh_addr, ++ upatch_string->sh_size); ++ ++ log_debug("Changed insn:\n"); ++ uinfo->funcs = (void *)uinfo->func_names + uinfo->func_names_size; ++ for (unsigned int i = 0; i < uinfo->changed_func_num; ++i) { ++ struct upatch_info_func *upatch_func = &uinfo->funcs[i]; ++ ++ upatch_func->addr = upatch_funcs_addr[i].addr; ++ upatch_func->addr.old_addr += uelf->relf->load_bias; ++ ret = upatch_process_mem_read(obj->proc, upatch_func->addr.old_addr, ++ &upatch_func->old_insn, get_origin_insn_len()); ++ if (ret) { ++ log_error("can't read origin insn at 0x%lx - %d\n", ++ upatch_func->addr.old_addr, ret); ++ goto out; ++ } ++ ++ upatch_func->new_insn = get_new_insn(); ++ log_debug("\t0x%lx(0x%lx 0x%lx -> 0x%lx 0x%lx)\n", ++ upatch_func->addr.old_addr, ++ upatch_func->old_insn[0], upatch_func->old_insn[1], ++ upatch_func->new_insn, upatch_func->addr.new_addr); ++ } + + out: +- return ret; ++ return ret; + } + + static int unapply_patch(struct object_file *obj, +- struct upatch_info_func *funcs, +- unsigned long changed_func_num) ++ struct upatch_info_func *funcs, unsigned long changed_func_num) + { +- log_debug("Changed insn:\n"); +- for (unsigned int i = 0; i < changed_func_num; ++i) { +- log_debug("\t0x%lx(0x%lx -> 0x%lx)\n", funcs[i].addr.old_addr, +- funcs[i].new_insn, funcs[i].old_insn[0]); +- +- int ret = upatch_process_mem_write(obj->proc, &funcs[i].old_insn, +- (unsigned long)funcs[i].addr.old_addr, get_origin_insn_len()); +- +- if (ret) { +- log_error("Failed to write old insn at 0x%lx, ret=%d\n", +- funcs[i].addr.old_addr, ret); +- return ret; +- } +- } +- return 0; ++ log_debug("Changed insn:\n"); ++ for (unsigned int i = 0; i < changed_func_num; ++i) { ++ log_debug("\t0x%lx(0x%lx -> 0x%lx)\n", funcs[i].addr.old_addr, ++ funcs[i].new_insn, funcs[i].old_insn[0]); ++ ++ int ret = upatch_process_mem_write(obj->proc, &funcs[i].old_insn, ++ (unsigned long)funcs[i].addr.old_addr, get_origin_insn_len()); ++ if (ret) { ++ log_error("Failed to write old insn at 0x%lx, ret=%d\n", ++ funcs[i].addr.old_addr, ret); ++ return ret; ++ } ++ } ++ return 0; + } + + static int apply_patch(struct upatch_elf *uelf, struct object_file *obj) + { +- int ret = 0; +- unsigned int i; +- struct upatch_info *uinfo = +- (void *)uelf->core_layout.kbase + uelf->core_layout.info_size; +- +- for (i = 0; i < uinfo->changed_func_num; ++i) { +- struct upatch_info_func *upatch_func = &uinfo->funcs[i]; +- +- // write jumper insn to first 8 bytes +- ret = upatch_process_mem_write(obj->proc, &upatch_func->new_insn, +- (unsigned long)upatch_func->addr.old_addr, get_upatch_insn_len()); +- if (ret) { +- log_error( +- "Failed to ptrace upatch func at 0x%lx(0x%lx) - %d\n", +- upatch_func->addr.old_addr, upatch_func->new_insn, +- ret); +- goto out; +- } +- // write 64bit new addr to second 8 bytes +- ret = upatch_process_mem_write(obj->proc, &upatch_func->addr.new_addr, +- (unsigned long)upatch_func->addr.old_addr + get_upatch_insn_len(), +- get_upatch_addr_len()); +- if (ret) { +- log_error( +- "Failed to ptrace upatch func at 0x%lx(0x%lx) - %d\n", +- upatch_func->addr.old_addr + get_upatch_insn_len(), +- upatch_func->addr.new_addr, ret); +- goto out; +- } +- } ++ int ret = 0; ++ unsigned int i; ++ ++ struct upatch_info *uinfo = (void *)uelf->core_layout.kbase + ++ uelf->core_layout.info_size; ++ for (i = 0; i < uinfo->changed_func_num; ++i) { ++ struct upatch_info_func *upatch_func = &uinfo->funcs[i]; ++ ++ // write jumper insn to first 8 bytes ++ ret = upatch_process_mem_write(obj->proc, &upatch_func->new_insn, ++ (unsigned long)upatch_func->addr.old_addr, get_upatch_insn_len()); ++ if (ret) { ++ log_error( ++ "Failed to ptrace upatch func at 0x%lx(0x%lx) - %d\n", ++ upatch_func->addr.old_addr, upatch_func->new_insn, ++ ret); ++ goto out; ++ } ++ // write 64bit new addr to second 8 bytes ++ ret = upatch_process_mem_write(obj->proc, &upatch_func->addr.new_addr, ++ (unsigned long)upatch_func->addr.old_addr + get_upatch_insn_len(), ++ get_upatch_addr_len()); ++ if (ret) { ++ log_error( ++ "Failed to ptrace upatch func at 0x%lx(0x%lx) - %d\n", ++ upatch_func->addr.old_addr + get_upatch_insn_len(), ++ upatch_func->addr.new_addr, ret); ++ goto out; ++ } ++ } + + out: +- if (ret) { +- unapply_patch(obj, uinfo->funcs, uinfo->changed_func_num); +- } +- return ret; ++ if (ret) { ++ unapply_patch(obj, uinfo->funcs, uinfo->changed_func_num); ++ } ++ return ret; + } + + static int upatch_mprotect(struct upatch_elf *uelf, struct object_file *obj) + { +- int ret; +- +- if (uelf->core_layout.text_size > 0) { +- ret = upatch_mprotect_remote( +- proc2pctx(obj->proc), +- (unsigned long)uelf->core_layout.base, +- uelf->core_layout.text_size, PROT_READ | PROT_EXEC); +- if (ret < 0) { +- log_error("Failed to change upatch text protection to r-x"); +- return ret; +- } +- } +- +- if (uelf->core_layout.ro_size > uelf->core_layout.text_size) { +- ret = upatch_mprotect_remote( +- proc2pctx(obj->proc), +- (unsigned long)uelf->core_layout.base + uelf->core_layout.text_size, +- uelf->core_layout.ro_size - uelf->core_layout.text_size, +- PROT_READ); +- if (ret < 0) { +- log_error("Failed to change upatch ro protection to r--"); +- return ret; +- } +- } +- +- if (uelf->core_layout.ro_after_init_size > uelf->core_layout.ro_size) { +- ret = upatch_mprotect_remote( +- proc2pctx(obj->proc), +- (unsigned long)uelf->core_layout.base + uelf->core_layout.ro_size, +- uelf->core_layout.ro_after_init_size - uelf->core_layout.ro_size, +- PROT_READ); +- if (ret < 0) { +- log_error("Failed to change upatch ro init protection to r--"); +- return ret; +- } +- } +- +- if (uelf->core_layout.info_size > +- uelf->core_layout.ro_after_init_size) { +- ret = upatch_mprotect_remote( +- proc2pctx(obj->proc), +- (unsigned long)uelf->core_layout.base + uelf->core_layout.ro_after_init_size, +- uelf->core_layout.info_size - uelf->core_layout.ro_after_init_size, +- PROT_READ | PROT_WRITE); +- if (ret < 0) { +- log_error("Failed to change upatch rw protection to rw-"); +- return ret; +- } +- } +- +- if (uelf->core_layout.size > uelf->core_layout.info_size) { +- ret = upatch_mprotect_remote( +- proc2pctx(obj->proc), +- (unsigned long)uelf->core_layout.base + uelf->core_layout.info_size, +- uelf->core_layout.size - uelf->core_layout.info_size, +- PROT_READ); +- if (ret < 0) { +- log_error("Failed to change upatch info protection to r--"); +- return ret; +- } +- } +- +- return 0; ++ int ret; ++ ++ if (uelf->core_layout.text_size > 0) { ++ ret = upatch_mprotect_remote( ++ proc2pctx(obj->proc), ++ (unsigned long)uelf->core_layout.base, ++ uelf->core_layout.text_size, PROT_READ | PROT_EXEC); ++ if (ret < 0) { ++ log_error("Failed to change upatch text protection to r-x"); ++ return ret; ++ } ++ } ++ ++ if (uelf->core_layout.ro_size > uelf->core_layout.text_size) { ++ ret = upatch_mprotect_remote( ++ proc2pctx(obj->proc), ++ (unsigned long)uelf->core_layout.base + uelf->core_layout.text_size, ++ uelf->core_layout.ro_size - uelf->core_layout.text_size, ++ PROT_READ); ++ if (ret < 0) { ++ log_error("Failed to change upatch ro protection to r--"); ++ return ret; ++ } ++ } ++ ++ if (uelf->core_layout.ro_after_init_size > uelf->core_layout.ro_size) { ++ ret = upatch_mprotect_remote( ++ proc2pctx(obj->proc), ++ (unsigned long)uelf->core_layout.base + uelf->core_layout.ro_size, ++ uelf->core_layout.ro_after_init_size - uelf->core_layout.ro_size, ++ PROT_READ); ++ if (ret < 0) { ++ log_error("Failed to change upatch ro init protection to r--"); ++ return ret; ++ } ++ } ++ ++ if (uelf->core_layout.info_size > ++ uelf->core_layout.ro_after_init_size) { ++ ret = upatch_mprotect_remote( ++ proc2pctx(obj->proc), ++ (unsigned long)uelf->core_layout.base + uelf->core_layout.ro_after_init_size, ++ uelf->core_layout.info_size - uelf->core_layout.ro_after_init_size, ++ PROT_READ | PROT_WRITE); ++ if (ret < 0) { ++ log_error("Failed to change upatch rw protection to rw-"); ++ return ret; ++ } ++ } ++ ++ if (uelf->core_layout.size > uelf->core_layout.info_size) { ++ ret = upatch_mprotect_remote( ++ proc2pctx(obj->proc), ++ (unsigned long)uelf->core_layout.base + uelf->core_layout.info_size, ++ uelf->core_layout.size - uelf->core_layout.info_size, ++ PROT_READ); ++ if (ret < 0) { ++ log_error("Failed to change upatch info protection to r--"); ++ return ret; ++ } ++ } ++ ++ return 0; + } + + static int upatch_apply_patches(struct object_file *obj, +- struct upatch_elf *uelf, const char *uuid) +-{ +- int ret = 0; +- +- ret = rewrite_section_headers(uelf); +- if (ret) { +- return ret; +- } +- +- // Caculate upatch mem size +- layout_jmptable(uelf); +- layout_sections(uelf); +- layout_symtab(uelf); +- layout_upatch_info(uelf); +- +- log_debug("calculate core layout = %lx\n", uelf->core_layout.size); +- log_debug( +- "Core layout: text_size = %lx, ro_size = %lx, ro_after_init_size = " +- "%lx, info = %lx, size = %lx\n", +- uelf->core_layout.text_size, uelf->core_layout.ro_size, +- uelf->core_layout.ro_after_init_size, +- uelf->core_layout.info_size, uelf->core_layout.size); +- +- /* +- * Map patch as close to the original code as possible. +- * Otherwise we can't use 32-bit jumps. +- */ +- ret = alloc_memory(uelf, obj); +- if (ret) { +- log_error("Failed to alloc patch memory\n"); +- goto free; +- } +- +- ret = upatch_mprotect(uelf, obj); +- if (ret) { +- log_error("Failed to set patch memory permission\n"); +- goto free; +- } +- +- /* Fix up syms, so that st_value is a pointer to location. */ +- ret = simplify_symbols(uelf, obj); +- if (ret) { +- goto free; +- } +- +- /* upatch new address will be updated */ +- ret = apply_relocations(uelf); +- if (ret) { +- goto free; +- } +- +- /* upatch upatch info */ +- ret = complete_info(uelf, obj, uuid); +- if (ret) { +- goto free; +- } +- +- ret = post_memory(uelf, obj); +- if (ret) { +- goto free; +- } +- +- ret = apply_patch(uelf, obj); +- if (ret) { +- goto free; +- } +- +- ret = 0; +- goto out; ++ struct upatch_elf *uelf, const char *uuid) ++{ ++ int ret = 0; ++ ++ ret = rewrite_section_headers(uelf); ++ if (ret) { ++ return ret; ++ } ++ ++ // Caculate upatch mem size ++ layout_jmptable(uelf); ++ layout_sections(uelf); ++ layout_symtab(uelf); ++ layout_upatch_info(uelf); ++ ++ log_debug("calculate core layout = %lx\n", uelf->core_layout.size); ++ log_debug( ++ "Core layout: text_size = %lx, ro_size = %lx, ro_after_init_size = " ++ "%lx, info = %lx, size = %lx\n", ++ uelf->core_layout.text_size, uelf->core_layout.ro_size, ++ uelf->core_layout.ro_after_init_size, ++ uelf->core_layout.info_size, uelf->core_layout.size); ++ ++ /* ++ * Map patch as close to the original code as possible. ++ * Otherwise we can't use 32-bit jumps. ++ */ ++ ret = alloc_memory(uelf, obj); ++ if (ret) { ++ log_error("Failed to alloc patch memory\n"); ++ goto free; ++ } ++ ++ ret = upatch_mprotect(uelf, obj); ++ if (ret) { ++ log_error("Failed to set patch memory permission\n"); ++ goto free; ++ } ++ ++ /* Fix up syms, so that st_value is a pointer to location. */ ++ ret = simplify_symbols(uelf, obj); ++ if (ret) { ++ goto free; ++ } ++ ++ /* upatch new address will be updated */ ++ ret = apply_relocations(uelf); ++ if (ret) { ++ goto free; ++ } ++ ++ /* upatch upatch info */ ++ ret = complete_info(uelf, obj, uuid); ++ if (ret) { ++ goto free; ++ } ++ ++ ret = post_memory(uelf, obj); ++ if (ret) { ++ goto free; ++ } ++ ++ ret = apply_patch(uelf, obj); ++ if (ret) { ++ goto free; ++ } ++ ++ ret = 0; ++ goto out; + + // TODO: clear + free: +- upatch_free(obj, uelf->core_layout.base, uelf->core_layout.size); ++ upatch_free(obj, uelf->core_layout.base, uelf->core_layout.size); + out: +- return ret; ++ return ret; + } + +-static void upatch_time_tick(int pid) { +- static struct timeval start_tv; +- static struct timeval end_tv; ++static void upatch_time_tick(int pid) ++{ ++ static struct timeval start_tv; ++ static struct timeval end_tv; + +- if ((end_tv.tv_sec != 0) || (end_tv.tv_usec != 0)) { +- memset(&start_tv, 0, sizeof(struct timeval)); +- memset(&end_tv, 0, sizeof(struct timeval)); +- } ++ if ((end_tv.tv_sec != 0) || (end_tv.tv_usec != 0)) { ++ memset(&start_tv, 0, sizeof(struct timeval)); ++ memset(&end_tv, 0, sizeof(struct timeval)); ++ } + +- if ((start_tv.tv_sec == 0) && (start_tv.tv_usec == 0)) { +- gettimeofday(&start_tv, NULL); +- } else { +- gettimeofday(&end_tv, NULL); +- } ++ if ((start_tv.tv_sec == 0) && (start_tv.tv_usec == 0)) { ++ gettimeofday(&start_tv, NULL); ++ } else { ++ gettimeofday(&end_tv, NULL); ++ } + +- if ((start_tv.tv_sec == 0) || (start_tv.tv_usec == 0) || +- (end_tv.tv_sec == 0) || (end_tv.tv_usec == 0)) { +- return; +- } ++ if ((start_tv.tv_sec == 0) || (start_tv.tv_usec == 0) || ++ (end_tv.tv_sec == 0) || (end_tv.tv_usec == 0)) { ++ return; ++ } + +- long frozen_time = get_microseconds(&start_tv, &end_tv); +- log_debug("Process %d frozen time is %ld microsecond(s)\n", +- pid, frozen_time); ++ long frozen_time = get_microseconds(&start_tv, &end_tv); ++ log_debug("Process %d frozen time is %ld microsecond(s)\n", ++ pid, frozen_time); + } + +-static struct object_patch *upatch_find_patch(struct upatch_process *proc, const char *uuid) ++static struct object_patch *upatch_find_patch(struct upatch_process *proc, ++ const char *uuid) + { +- struct object_file *obj = NULL; +- struct object_patch *patch = NULL; +- +- // Traverse all mapped memory and find all upatch memory +- list_for_each_entry(obj, &proc->objs, list) { +- if (!obj->is_patch) { +- continue; +- } +- list_for_each_entry(patch, &obj->applied_patch, list) { +- if (strncmp(patch->uinfo->id, uuid, UPATCH_ID_LEN) == 0) { +- return patch; +- } +- } +- } +- return NULL; ++ struct object_file *obj = NULL; ++ struct object_patch *patch = NULL; ++ ++ // Traverse all mapped memory and find all upatch memory ++ list_for_each_entry(obj, &proc->objs, list) { ++ if (!obj->is_patch) { ++ continue; ++ } ++ list_for_each_entry(patch, &obj->applied_patch, list) { ++ if (strncmp(patch->uinfo->id, uuid, UPATCH_ID_LEN) == 0) { ++ return patch; ++ } ++ } ++ } ++ return NULL; + } + + static int upatch_apply_prepare(struct upatch_elf *uelf, +- struct upatch_process *proc, struct object_file **obj) +-{ +- int ret = 0; +- +- for (int i = 0; i < STACK_CHECK_RETRY_TIMES; i++) { +- ret = upatch_process_attach(proc); +- if (ret < 0) { +- log_error("Failed to attach process\n"); +- goto detach; +- } +- +- *obj = upatch_find_obj(uelf, proc); +- if (*obj == NULL) { +- ret = -ENODATA; +- goto detach; +- } +- +- ret = upatch_active_stack_check(uelf, proc); +- if (ret != -EBUSY) { +- return ret; +- } +- upatch_process_detach(proc); +- sleep(1); +- } ++ struct upatch_process *proc, struct object_file **obj) ++{ ++ int ret = 0; ++ ++ for (int i = 0; i < STACK_CHECK_RETRY_TIMES; i++) { ++ ret = upatch_process_attach(proc); ++ if (ret < 0) { ++ log_error("Failed to attach process\n"); ++ goto detach; ++ } ++ ++ *obj = upatch_find_obj(uelf, proc); ++ if (*obj == NULL) { ++ ret = -ENODATA; ++ goto detach; ++ } ++ ++ ret = upatch_active_stack_check(uelf, proc); ++ if (ret != -EBUSY) { ++ return ret; ++ } ++ upatch_process_detach(proc); ++ sleep(1); ++ } + detach: +- upatch_process_detach(proc); +- return ret; +-} +- +-int process_patch(int pid, struct upatch_elf *uelf, struct running_elf *relf, const char *uuid, const char *binary_path) +-{ +- struct upatch_process proc; +- struct object_file *obj = NULL; +- +- // 查看process的信息,pid: maps, mem, cmdline, exe +- int ret = upatch_process_init(&proc, pid); +- if (ret < 0) { +- log_error("Failed to init process\n"); +- goto out; +- } +- +- printf("Patch '%s' to ", uuid); +- upatch_process_print_short(&proc); +- +- ret = upatch_process_mem_open(&proc, MEM_READ); +- if (ret < 0) { +- log_error("Failed to open process memory\n"); +- goto out_free; +- } +- +- // use uprobe to interpose function. the program has been executed to the entry +- // point +- +- /* +- * For each object file that we want to patch (either binary itself or +- * shared library) we need its ELF structure to perform relocations. +- * Because we know uniq BuildID of the object the section addresses +- * stored in the patch are valid for the original object. +- */ +- // 解析process的mem-maps,获得各个块的内存映射以及phdr +- ret = upatch_process_map_object_files(&proc); +- if (ret < 0) { +- log_error("Failed to read process memory mapping\n"); +- goto out_free; +- } +- struct object_patch *patch = upatch_find_patch(&proc, uuid); +- if (patch != NULL) { +- log_error("Patch '%s' already exists\n", uuid); +- goto out_free; +- } +- ret = binary_init(relf, binary_path); ++ upatch_process_detach(proc); ++ return ret; ++} ++ ++int process_patch(int pid, struct upatch_elf *uelf, struct running_elf *relf, ++ const char *uuid, const char *binary_path) ++{ ++ struct upatch_process proc; ++ struct object_file *obj = NULL; ++ ++ // 查看process的信息,pid: maps, mem, cmdline, exe ++ int ret = upatch_process_init(&proc, pid); ++ if (ret < 0) { ++ log_error("Failed to init process\n"); ++ goto out; ++ } ++ ++ printf("Patch '%s' to ", uuid); ++ upatch_process_print_short(&proc); ++ ++ ret = upatch_process_mem_open(&proc, MEM_READ); ++ if (ret < 0) { ++ log_error("Failed to open process memory\n"); ++ goto out_free; ++ } ++ ++ // use uprobe to interpose function. the program has been executed to the ++ // entry point ++ ++ /* ++ * For each object file that we want to patch (either binary itself or ++ * shared library) we need its ELF structure to perform relocations. ++ * Because we know uniq BuildID of the object the section addresses ++ * stored in the patch are valid for the original object. ++ */ ++ // 解析process的mem-maps,获得各个块的内存映射以及phdr ++ ret = upatch_process_map_object_files(&proc); ++ if (ret < 0) { ++ log_error("Failed to read process memory mapping\n"); ++ goto out_free; ++ } ++ struct object_patch *patch = upatch_find_patch(&proc, uuid); ++ if (patch != NULL) { ++ log_error("Patch '%s' already exists\n", uuid); ++ goto out_free; ++ } ++ ret = binary_init(relf, binary_path); + if (ret) { + log_error("Failed to load binary\n"); + goto out_free; + } + + uelf->relf = relf; +- upatch_time_tick(pid); +- +- ret = upatch_apply_prepare(uelf, &proc, &obj); +- if (ret < 0) { +- goto out_free; +- } +- // 应用 +- ret = upatch_apply_patches(obj, uelf, uuid); +- if (ret < 0) { +- log_error("Failed to apply patch\n"); +- goto out_free; +- } ++ upatch_time_tick(pid); ++ ++ ret = upatch_apply_prepare(uelf, &proc, &obj); ++ if (ret < 0) { ++ goto out_free; ++ } ++ // 应用 ++ ret = upatch_apply_patches(obj, uelf, uuid); ++ if (ret < 0) { ++ log_error("Failed to apply patch\n"); ++ goto out_free; ++ } + + out_free: +- upatch_process_detach(&proc); +- upatch_time_tick(pid); +- upatch_process_destroy(&proc); ++ upatch_process_detach(&proc); ++ upatch_time_tick(pid); ++ upatch_process_destroy(&proc); + out: +- return ret; ++ return ret; + } + +-static int upatch_unapply_patches(struct object_file *obj, struct upatch_info *uinfo) ++static int upatch_unapply_patches(struct object_file *obj, ++ struct upatch_info *uinfo) + { +- int ret = 0; ++ int ret = 0; + +- ret = unapply_patch(obj, uinfo->funcs, uinfo->changed_func_num); +- if (ret) { +- return ret; +- } ++ ret = unapply_patch(obj, uinfo->funcs, uinfo->changed_func_num); ++ if (ret) { ++ return ret; ++ } + +- log_debug("munmap upatch layout core:\n"); +- upatch_free(obj, (void *)uinfo->start, uinfo->end - uinfo->start); +- return ret; ++ log_debug("munmap upatch layout core:\n"); ++ upatch_free(obj, (void *)uinfo->start, uinfo->end - uinfo->start); ++ return ret; + } + + static int upatch_unapply_prepare(struct upatch_process *proc, +- const char *uuid, struct object_patch **patch) +-{ +- int ret = 0; +- +- for (int i = 0; i < STACK_CHECK_RETRY_TIMES; i++) { +- ret = upatch_process_attach(proc); +- if (ret < 0) { +- log_error("Failed to attach process\n"); +- goto detach; +- } +- *patch = upatch_find_patch(proc, uuid); +- if (*patch == NULL) { +- log_error("Patch '%s' is not found\n", uuid); +- ret = -ENODATA; +- goto detach; +- } +- ret = upatch_stack_check((*patch)->uinfo, proc, DEACTIVE); +- if (ret != -EBUSY) { +- return ret; +- } +- upatch_process_detach(proc); +- sleep(1); +- } ++ const char *uuid, struct object_patch **patch) ++{ ++ int ret = 0; ++ ++ for (int i = 0; i < STACK_CHECK_RETRY_TIMES; i++) { ++ ret = upatch_process_attach(proc); ++ if (ret < 0) { ++ log_error("Failed to attach process\n"); ++ goto detach; ++ } ++ *patch = upatch_find_patch(proc, uuid); ++ if (*patch == NULL) { ++ log_error("Patch '%s' is not found\n", uuid); ++ ret = -ENODATA; ++ goto detach; ++ } ++ ret = upatch_stack_check((*patch)->uinfo, proc, DEACTIVE); ++ if (ret != -EBUSY) { ++ return ret; ++ } ++ upatch_process_detach(proc); ++ sleep(1); ++ } + detach: +- upatch_process_detach(proc); +- return ret; ++ upatch_process_detach(proc); ++ return ret; + } + + int process_unpatch(int pid, const char *uuid) + { +- struct upatch_process proc; +- struct object_patch *patch = NULL; +- +- // 查看process的信息,pid: maps, mem, cmdline, exe +- int ret = upatch_process_init(&proc, pid); +- if (ret < 0) { +- log_error("Failed to init process\n"); +- goto out; +- } +- +- printf("Unpatch '%s' from ", uuid); +- upatch_process_print_short(&proc); +- +- ret = upatch_process_mem_open(&proc, MEM_READ); +- if (ret < 0) { +- log_error("Failed to open process memory\n"); +- goto out_free; +- } +- +- // use uprobe to interpose function. the program has been executed to the entry +- // point +- +- /* +- * For each object file that we want to patch (either binary itself or +- * shared library) we need its ELF structure to perform relocations. +- * Because we know uniq BuildID of the object the section addresses +- * stored in the patch are valid for the original object. +- */ +- // 解析process的mem-maps,获得各个块的内存映射以及phdr +- ret = upatch_process_map_object_files(&proc); +- if (ret < 0) { +- log_error("Failed to read process memory mapping\n"); +- goto out_free; +- } +- +- upatch_time_tick(pid); +- ret = upatch_unapply_prepare(&proc, uuid, &patch); +- if (ret < 0) { +- goto out_free; +- } +- // 应用 +- ret = upatch_unapply_patches(patch->obj, patch->uinfo); +- if (ret < 0) { +- log_error("Failed to remove patch\n"); +- goto out_free; +- } ++ struct upatch_process proc; ++ struct object_patch *patch = NULL; ++ ++ // 查看process的信息,pid: maps, mem, cmdline, exe ++ int ret = upatch_process_init(&proc, pid); ++ if (ret < 0) { ++ log_error("Failed to init process\n"); ++ goto out; ++ } ++ ++ printf("Unpatch '%s' from ", uuid); ++ upatch_process_print_short(&proc); ++ ++ ret = upatch_process_mem_open(&proc, MEM_READ); ++ if (ret < 0) { ++ log_error("Failed to open process memory\n"); ++ goto out_free; ++ } ++ ++ // use uprobe to interpose function. the program has been executed to the ++ // entry point ++ ++ /* ++ * For each object file that we want to patch (either binary itself or ++ * shared library) we need its ELF structure to perform relocations. ++ * Because we know uniq BuildID of the object the section addresses ++ * stored in the patch are valid for the original object. ++ */ ++ // 解析process的mem-maps,获得各个块的内存映射以及phdr ++ ret = upatch_process_map_object_files(&proc); ++ if (ret < 0) { ++ log_error("Failed to read process memory mapping\n"); ++ goto out_free; ++ } ++ ++ upatch_time_tick(pid); ++ ret = upatch_unapply_prepare(&proc, uuid, &patch); ++ if (ret < 0) { ++ goto out_free; ++ } ++ // 应用 ++ ret = upatch_unapply_patches(patch->obj, patch->uinfo); ++ if (ret < 0) { ++ log_error("Failed to remove patch\n"); ++ goto out_free; ++ } + + out_free: +- upatch_process_detach(&proc); +- upatch_time_tick(pid); +- upatch_process_destroy(&proc); ++ upatch_process_detach(&proc); ++ upatch_time_tick(pid); ++ upatch_process_destroy(&proc); + + out: +- return ret; ++ return ret; + } + + static int upatch_info(struct upatch_process *proc) + { +- struct object_file *obj = NULL; +- struct object_patch *patch = NULL; +- bool found = false; +- +- list_for_each_entry(obj, &proc->objs, list) { +- if (obj->is_patch) { +- found = true; +- break; +- } +- } ++ struct object_file *obj = NULL; ++ struct object_patch *patch = NULL; ++ bool found = false; ++ ++ list_for_each_entry(obj, &proc->objs, list) { ++ if (obj->is_patch) { ++ found = true; ++ break; ++ } ++ } + +- if (!found) +- return found; ++ if (!found) { ++ return found; ++ } + +- found = false; +- list_for_each_entry(patch, &obj->applied_patch, list) { +- // TODO: check upatch_info id +- found = true; +- break; +- } ++ found = false; ++ list_for_each_entry(patch, &obj->applied_patch, list) { ++ found = true; ++ break; ++ } + +- return found; ++ return found; + } + + int process_info(int pid) + { +- int ret; +- struct upatch_process proc; +- char *status = "error"; +- +- // TODO: check build id +- // TODO: 栈解析 +- // 查看process的信息,pid: maps, mem, cmdline, exe +- ret = upatch_process_init(&proc, pid); +- if (ret < 0) { +- log_error("Failed to init process\n"); +- goto out; +- } +- +- ret = upatch_process_mem_open(&proc, MEM_READ); +- if (ret < 0) { +- log_error("Failed to open process memory\n"); +- goto out_free; +- } +- +- ret = upatch_process_map_object_files(&proc); +- if (ret < 0) { +- log_error("Failed to read process memory mapping\n"); +- goto out_free; +- } +- +- ret = upatch_info(&proc); +- if (ret) { +- status = "actived"; +- } +- else { +- status = "removed"; +- } +- +- ret = 0; ++ int ret; ++ struct upatch_process proc; ++ char *status = "error"; ++ ++ // TODO: check build id ++ // TODO: 栈解析 ++ // 查看process的信息,pid: maps, mem, cmdline, exe ++ ret = upatch_process_init(&proc, pid); ++ if (ret < 0) { ++ log_error("Failed to init process\n"); ++ goto out; ++ } ++ ++ ret = upatch_process_mem_open(&proc, MEM_READ); ++ if (ret < 0) { ++ log_error("Failed to open process memory\n"); ++ goto out_free; ++ } ++ ++ ret = upatch_process_map_object_files(&proc); ++ if (ret < 0) { ++ log_error("Failed to read process memory mapping\n"); ++ goto out_free; ++ } ++ ++ ret = upatch_info(&proc); ++ if (ret) { ++ status = "actived"; ++ } else { ++ status = "removed"; ++ } ++ ret = 0; + + out_free: +- upatch_process_destroy(&proc); ++ upatch_process_destroy(&proc); + + out: +- log_debug("%s\n", status); +- return ret; ++ log_debug("%s\n", status); ++ return ret; + } +diff --git a/upatch-manage/upatch-process.c b/upatch-manage/upatch-process.c +index a8b1e2b..924a9c4 100644 +--- a/upatch-manage/upatch-process.c ++++ b/upatch-manage/upatch-process.c +@@ -48,788 +48,820 @@ static const int MAX_ATTACH_ATTEMPTS = 3; + */ + static int lock_process(int pid) + { +- int fd; +- char path[128]; ++ int fd; ++ char path[128]; + +- log_debug("Locking PID %d...", pid); +- snprintf(path, sizeof(path), "/proc/%d/maps", pid); ++ log_debug("Locking PID %d...", pid); ++ (void) snprintf(path, sizeof(path), "/proc/%d/maps", pid); + +- fd = open(path, O_RDONLY); +- if (fd < 0) { +- log_error("Failed to open file '%s'\n", path); +- return -1; +- } +- log_debug("OK\n"); ++ fd = open(path, O_RDONLY); ++ if (fd < 0) { ++ log_error("Failed to open file '%s'\n", path); ++ return -1; ++ } ++ log_debug("OK\n"); + +- return fd; ++ return fd; + } + + static void unlock_process(int fdmaps) + { +- int errsv = errno; +- close(fdmaps); +- errno = errsv; ++ int errsv = errno; ++ close(fdmaps); ++ errno = errsv; + } + + // TODO: get addr_space + static int upatch_coroutines_init(struct upatch_process *proc) + { +- INIT_LIST_HEAD(&proc->coro.coros); ++ INIT_LIST_HEAD(&proc->coro.coros); + +- return 0; ++ return 0; + } + + static int process_get_comm(struct upatch_process *proc) + { +- char path[128]; +- char realpath[PATH_MAX]; +- char *bn, *c; +- ssize_t ret; +- +- snprintf(path, sizeof(path), "/proc/%d/exe", proc->pid); +- log_debug("Reading from '%s'...", path); +- +- ret = readlink(path, realpath, sizeof(realpath)); +- if (ret < 0) { +- return -1; +- } +- +- realpath[ret] = '\0'; +- bn = basename(realpath); +- strncpy(path, bn, sizeof(path) - 1); +- if ((c = strstr(path, " (deleted)"))) { +- *c = '\0'; +- } +- +- proc->comm[sizeof(proc->comm) - 1] = '\0'; +- memcpy(proc->comm, path, sizeof(proc->comm) - 1); +- // TODO: the comm is ldxxx +- log_debug("OK\n"); +- +- return 0; ++ char path[128]; ++ char realpath[PATH_MAX]; ++ char *bn; ++ char *c; ++ ssize_t ret; ++ ++ (void) snprintf(path, sizeof(path), "/proc/%d/exe", proc->pid); ++ log_debug("Reading from '%s'...", path); ++ ++ ret = readlink(path, realpath, sizeof(realpath)); ++ if (ret < 0) { ++ return -1; ++ } ++ ++ realpath[ret] = '\0'; ++ bn = basename(realpath); ++ strncpy(path, bn, sizeof(path) - 1); ++ if ((c = strstr(path, " (deleted)"))) { ++ *c = '\0'; ++ } ++ ++ proc->comm[sizeof(proc->comm) - 1] = '\0'; ++ memcpy(proc->comm, path, sizeof(proc->comm) - 1); ++ // TODO: the comm is ldxxx ++ log_debug("OK\n"); ++ ++ return 0; + } + + int upatch_process_init(struct upatch_process *proc, int pid) + { +- int fdmaps; ++ int fdmaps; + +- fdmaps = lock_process(pid); +- if (fdmaps < 0) { +- goto out_err; +- } ++ fdmaps = lock_process(pid); ++ if (fdmaps < 0) { ++ goto out_err; ++ } + +- memset(proc, 0, sizeof(*proc)); ++ memset(proc, 0, sizeof(*proc)); + +- proc->pid = pid; +- proc->fdmaps = fdmaps; +- proc->memfd = -1; ++ proc->pid = pid; ++ proc->fdmaps = fdmaps; ++ proc->memfd = -1; + +- INIT_LIST_HEAD(&proc->ptrace.pctxs); +- INIT_LIST_HEAD(&proc->objs); +- INIT_LIST_HEAD(&proc->vmaholes); +- proc->num_objs = 0; ++ INIT_LIST_HEAD(&proc->ptrace.pctxs); ++ INIT_LIST_HEAD(&proc->objs); ++ INIT_LIST_HEAD(&proc->vmaholes); ++ proc->num_objs = 0; + +- if (upatch_coroutines_init(proc)) { +- goto out_unlock; +- } ++ if (upatch_coroutines_init(proc)) { ++ goto out_unlock; ++ } + +- if (process_get_comm(proc)) { +- goto out_unlock; +- } ++ if (process_get_comm(proc)) { ++ goto out_unlock; ++ } + +- return 0; ++ return 0; + + out_unlock: +- unlock_process(fdmaps); ++ unlock_process(fdmaps); + out_err: +- return -1; ++ return -1; + } + + static void upatch_object_memfree(struct object_file *obj) + { +- struct object_patch *opatch, *opatch_safe; +- struct obj_vm_area *ovma, *ovma_safe; +- +- if (obj->name) { +- free(obj->name); +- } +- +- list_for_each_entry_safe(opatch, opatch_safe, &obj->applied_patch, list) { +- if (opatch->uinfo) { +- if (opatch->uinfo->funcs) { +- free(opatch->uinfo->funcs); +- } +- free(opatch->uinfo); +- } +- free(opatch); +- } +- +- list_for_each_entry_safe(ovma, ovma_safe, &obj->vma, list) { +- free(ovma); +- } ++ struct object_patch *opatch; ++ struct object_patch *opatch_safe; ++ struct obj_vm_area *ovma; ++ struct obj_vm_area *ovma_safe; ++ ++ if (obj->name) { ++ free(obj->name); ++ } ++ ++ list_for_each_entry_safe(opatch, opatch_safe, &obj->applied_patch, list) { ++ if (opatch->uinfo) { ++ if (opatch->uinfo->funcs) { ++ free(opatch->uinfo->funcs); ++ } ++ free(opatch->uinfo); ++ } ++ free(opatch); ++ } ++ ++ list_for_each_entry_safe(ovma, ovma_safe, &obj->vma, list) { ++ free(ovma); ++ } + } + + static void upatch_process_memfree(struct upatch_process *proc) + { +- struct upatch_ptrace_ctx *p, *p_safe; +- struct object_file *obj, *obj_safe; +- struct vm_hole *hole, *hole_safe; +- +- list_for_each_entry_safe(p, p_safe, &proc->ptrace.pctxs, list) { +- free(p); +- } +- +- list_for_each_entry_safe(hole, hole_safe, &proc->vmaholes, list) { +- free(hole); +- } +- +- list_for_each_entry_safe(obj, obj_safe, &proc->objs, list) { +- upatch_object_memfree(obj); +- free(obj); +- } ++ struct upatch_ptrace_ctx *p; ++ struct upatch_ptrace_ctx *p_safe; ++ struct object_file *obj; ++ struct object_file *obj_safe; ++ struct vm_hole *hole; ++ struct vm_hole *hole_safe; ++ ++ list_for_each_entry_safe(p, p_safe, &proc->ptrace.pctxs, list) { ++ free(p); ++ } ++ ++ list_for_each_entry_safe(hole, hole_safe, &proc->vmaholes, list) { ++ free(hole); ++ } ++ ++ list_for_each_entry_safe(obj, obj_safe, &proc->objs, list) { ++ upatch_object_memfree(obj); ++ free(obj); ++ } + } + + void upatch_process_destroy(struct upatch_process *proc) + { +- unlock_process(proc->fdmaps); +- upatch_process_memfree(proc); ++ unlock_process(proc->fdmaps); ++ upatch_process_memfree(proc); + } + + static void process_print_cmdline(struct upatch_process *proc) + { +- char buf[PATH_MAX]; +- ssize_t i, rv; +- +- snprintf(buf, PATH_MAX, "/proc/%d/cmdline", proc->pid); +- int fd = open(buf, O_RDONLY); +- if (fd == -1) { +- log_error("Failed to open file '%s'\n", buf); +- return; +- } +- +- while (1) { +- rv = read(fd, buf, sizeof(buf)); +- +- if (rv == -1) { +- if (errno == EINTR) { +- continue; +- } +- log_error("Failed to read cmdline\n"); +- goto err_close; +- } +- +- if (rv == 0) { +- break; +- } +- +- for (i = 0; i < rv; i++) { +- if (isprint(buf[i])) { +- log_debug("%c", buf[i]); +- } +- else { +- log_debug(" "); +- } +- } +- } ++ char buf[PATH_MAX]; ++ ssize_t i; ++ ssize_t rv; ++ ++ (void) snprintf(buf, PATH_MAX, "/proc/%d/cmdline", proc->pid); ++ ++ int fd = open(buf, O_RDONLY); ++ if (fd == -1) { ++ log_error("Failed to open file '%s'\n", buf); ++ return; ++ } ++ ++ while (1) { ++ rv = read(fd, buf, sizeof(buf)); ++ if (rv == -1) { ++ if (errno == EINTR) { ++ continue; ++ } ++ log_error("Failed to read cmdline\n"); ++ goto err_close; ++ } ++ ++ if (rv == 0) { ++ break; ++ } ++ ++ for (i = 0; i < rv; i++) { ++ if (isprint(buf[i])) { ++ log_debug("%c", buf[i]); ++ } else { ++ log_debug(" "); ++ } ++ } ++ } + + err_close: +- close(fd); ++ close(fd); + } + + void upatch_process_print_short(struct upatch_process *proc) + { +- log_debug("process %d, cmdline: ", proc->pid); +- process_print_cmdline(proc); +- log_debug("\n"); ++ log_debug("process %d, cmdline: ", proc->pid); ++ process_print_cmdline(proc); ++ log_debug("\n"); + } + + int upatch_process_mem_open(struct upatch_process *proc, int mode) + { +- char path[PATH_MAX]; ++ char path[PATH_MAX]; + +- if (proc->memfd >= 0) { +- close(proc->memfd); +- } ++ if (proc->memfd >= 0) { ++ close(proc->memfd); ++ } + +- snprintf(path, sizeof(path), "/proc/%d/mem", proc->pid); +- proc->memfd = open(path, mode == MEM_WRITE ? O_RDWR : O_RDONLY); +- if (proc->memfd < 0) { +- log_error("Failed to open file '%s'\n", path); +- return -1; +- } ++ (void) snprintf(path, sizeof(path), "/proc/%d/mem", proc->pid); ++ proc->memfd = open(path, mode == MEM_WRITE ? O_RDWR : O_RDONLY); ++ if (proc->memfd < 0) { ++ log_error("Failed to open file '%s'\n", path); ++ return -1; ++ } + +- return 0; ++ return 0; + } + + static unsigned int perms2prot(const char *perms) + { +- unsigned int prot = 0; +- +- if (perms[0] == 'r') +- prot |= PROT_READ; +- if (perms[1] == 'w') +- prot |= PROT_WRITE; +- if (perms[2] == 'x') +- prot |= PROT_EXEC; +- /* Ignore 'p'/'s' flag, we don't need it */ +- return prot; ++ unsigned int prot = 0; ++ ++ if (perms[0] == 'r') { ++ prot |= PROT_READ; ++ } ++ if (perms[1] == 'w') { ++ prot |= PROT_WRITE; ++ } ++ if (perms[2] == 'x') { ++ prot |= PROT_EXEC; ++ } ++ /* Ignore 'p'/'s' flag, we don't need it */ ++ return prot; + } + + static struct vm_hole *process_add_vm_hole(struct upatch_process *proc, +- unsigned long hole_start, +- unsigned long hole_end) ++ unsigned long hole_start, unsigned long hole_end) + { +- struct vm_hole *hole; ++ struct vm_hole *hole; + +- hole = malloc(sizeof(*hole)); +- if (hole == NULL) +- return NULL; ++ hole = malloc(sizeof(*hole)); ++ if (hole == NULL) { ++ return NULL; ++ } + +- memset(hole, 0, sizeof(*hole)); +- hole->start = hole_start; +- hole->end = hole_end; ++ memset(hole, 0, sizeof(*hole)); ++ hole->start = hole_start; ++ hole->end = hole_end; + +- list_add(&hole->list, &proc->vmaholes); ++ list_add(&hole->list, &proc->vmaholes); + +- return hole; ++ return hole; + } + + static int process_get_object_type(struct upatch_process *proc, +- struct vm_area *vma, char *name, +- unsigned char *buf, size_t bufsize) ++ struct vm_area *vma, char *name, unsigned char *buf, size_t bufsize) + { +- int ret, type = OBJECT_UNKNOWN; +- +- ret = upatch_process_mem_read(proc, vma->start, buf, bufsize); +- if (ret < 0) +- return -1; +- +- if (vma->prot == PROT_READ && +- !strncmp(name, "[anonymous]", strlen("[anonymous]")) && +- !memcmp(buf, UPATCH_HEADER, UPATCH_HEADER_LEN)) { +- type = OBJECT_UPATCH; +- } else if (!memcmp(buf, ELFMAG, SELFMAG)) { +- type = OBJECT_ELF; +- } else { +- type = OBJECT_UNKNOWN; +- } +- +- return type; ++ int ret; ++ int type = OBJECT_UNKNOWN; ++ ++ ret = upatch_process_mem_read(proc, vma->start, buf, bufsize); ++ if (ret < 0) { ++ return -1; ++ } ++ ++ if (vma->prot == PROT_READ && ++ !strncmp(name, "[anonymous]", strlen("[anonymous]")) && ++ !memcmp(buf, UPATCH_HEADER, UPATCH_HEADER_LEN)) { ++ type = OBJECT_UPATCH; ++ } else if (!memcmp(buf, ELFMAG, SELFMAG)) { ++ type = OBJECT_ELF; ++ } else { ++ type = OBJECT_UNKNOWN; ++ } ++ ++ return type; + } + + static int vm_area_same(struct vm_area *a, struct vm_area *b) + { +- return ((a->start == b->start) && (a->end == b->end) && +- (a->prot == b->prot)); ++ return ((a->start == b->start) && ++ (a->end == b->end) && ++ (a->prot == b->prot)); + } + + static int object_add_vm_area(struct object_file *o, struct vm_area *vma, +- struct vm_hole *hole) ++ struct vm_hole *hole) + { +- struct obj_vm_area *ovma; +- +- if (o->previous_hole == NULL) +- o->previous_hole = hole; +- list_for_each_entry(ovma, &o->vma, list) { +- if (vm_area_same(vma, &ovma->inmem)) +- return 0; +- } +- ovma = malloc(sizeof(*ovma)); +- if (!ovma) +- return -1; +- memset(ovma, 0, sizeof(*ovma)); +- ovma->inmem = *vma; +- list_add(&ovma->list, &o->vma); +- return 0; ++ struct obj_vm_area *ovma; ++ ++ if (o->previous_hole == NULL) { ++ o->previous_hole = hole; ++ } ++ ++ list_for_each_entry(ovma, &o->vma, list) { ++ if (vm_area_same(vma, &ovma->inmem)) { ++ return 0; ++ } ++ } ++ ++ ovma = malloc(sizeof(*ovma)); ++ if (!ovma) { ++ return -1; ++ } ++ ++ memset(ovma, 0, sizeof(*ovma)); ++ ovma->inmem = *vma; ++ ++ list_add(&ovma->list, &o->vma); ++ return 0; + } + +-static struct object_file * +-process_new_object(struct upatch_process *proc, dev_t dev, ino_t inode, +- const char *name, struct vm_area *vma, struct vm_hole *hole) ++static struct object_file *process_new_object(struct upatch_process *proc, ++ dev_t dev, ino_t inode, const char *name, ++ struct vm_area *vma, struct vm_hole *hole) + { +- struct object_file *o; +- +- log_debug("Creating object file '%s' for %lx:%lu...", name, dev, inode); +- +- o = malloc(sizeof(*o)); +- if (!o) { +- log_error("FAILED\n"); +- return NULL; +- } +- memset(o, 0, sizeof(struct object_file)); +- +- INIT_LIST_HEAD(&o->list); +- INIT_LIST_HEAD(&o->vma); +- INIT_LIST_HEAD(&o->applied_patch); +- o->num_applied_patch = 0; +- o->proc = proc; +- o->dev = dev; +- o->inode = inode; +- o->is_patch = 0; +- +- o->previous_hole = hole; +- if (object_add_vm_area(o, vma, hole) < 0) { +- log_error("Cannot add vm area for %s\n", name); +- free(o); +- return NULL; +- } +- +- o->name = strdup(name); +- o->is_elf = 0; +- +- list_add(&o->list, &proc->objs); +- proc->num_objs++; +- +- log_debug("OK\n"); +- return o; ++ struct object_file *o; ++ ++ log_debug("Creating object file '%s' for %lx:%lu...", name, dev, inode); ++ ++ o = malloc(sizeof(*o)); ++ if (!o) { ++ log_error("FAILED\n"); ++ return NULL; ++ } ++ memset(o, 0, sizeof(struct object_file)); ++ ++ INIT_LIST_HEAD(&o->list); ++ INIT_LIST_HEAD(&o->vma); ++ INIT_LIST_HEAD(&o->applied_patch); ++ o->num_applied_patch = 0; ++ o->proc = proc; ++ o->dev = dev; ++ o->inode = inode; ++ o->is_patch = 0; ++ ++ o->previous_hole = hole; ++ if (object_add_vm_area(o, vma, hole) < 0) { ++ log_error("Cannot add vm area for %s\n", name); ++ free(o); ++ return NULL; ++ } ++ ++ o->name = strdup(name); ++ o->is_elf = 0; ++ ++ list_add(&o->list, &proc->objs); ++ proc->num_objs++; ++ ++ log_debug("OK\n"); ++ return o; + } + + static void link_funcs_name(struct upatch_info *uinfo) + { +- unsigned long idx = 0; ++ unsigned long idx = 0; + +- for (unsigned long i = 0; i < uinfo->changed_func_num; i++) { +- char *name = (char *)uinfo->func_names + idx; ++ for (unsigned long i = 0; i < uinfo->changed_func_num; i++) { ++ char *name = (char *)uinfo->func_names + idx; + +- uinfo->funcs[i].name = name; +- idx += strlen(name) + 1; +- } ++ uinfo->funcs[i].name = name; ++ idx += strlen(name) + 1; ++ } + } + + static void free_object_patch(struct object_patch *opatch) + { +- if (opatch == NULL) { +- return; +- } +- if (opatch->uinfo != NULL) { +- if (opatch->uinfo->funcs != NULL) { +- free(opatch->uinfo->funcs); +- } +- if (opatch->uinfo->func_names != NULL) { +- free(opatch->uinfo->func_names); +- } +- free(opatch->uinfo); +- } +- free(opatch); ++ if (opatch == NULL) { ++ return; ++ } ++ ++ if (opatch->uinfo != NULL) { ++ if (opatch->uinfo->funcs != NULL) { ++ free(opatch->uinfo->funcs); ++ } ++ if (opatch->uinfo->func_names != NULL) { ++ free(opatch->uinfo->func_names); ++ } ++ free(opatch->uinfo); ++ } ++ ++ free(opatch); + } + +-static int add_upatch_object(struct upatch_process *proc, +- struct object_file *o, unsigned long src, unsigned char *header_buf) ++static int add_upatch_object(struct upatch_process *proc, struct object_file *o, ++ unsigned long src, unsigned char *header_buf) + { +- struct object_patch *opatch; +- +- opatch = malloc(sizeof(struct object_patch)); +- if (opatch == NULL) { +- log_error("malloc opatch failed\n"); +- return -1; +- } +- +- opatch->obj = o; +- opatch->uinfo = malloc(sizeof(struct upatch_info)); +- if (opatch->uinfo == NULL) { +- log_error("malloc opatch->uinfo failed\n"); +- free(opatch); +- return -1; +- } +- +- memcpy(opatch->uinfo->magic, header_buf, sizeof(struct upatch_info)); +- +- opatch->uinfo->func_names = malloc(opatch->uinfo->func_names_size); +- if (opatch->uinfo->func_names == NULL) { +- log_error("Failed to malloc funcs_names\n"); +- free_object_patch(opatch); +- return -ENOMEM; +- } +- if (upatch_process_mem_read(proc, src, +- opatch->uinfo->func_names, opatch->uinfo->func_names_size)) { +- log_error("Cannot read patch func names at 0x%lx\n", src); +- free_object_patch(opatch); +- return -1; +- } +- +- src += opatch->uinfo->func_names_size; +- opatch->uinfo->funcs = malloc(opatch->uinfo->changed_func_num * +- sizeof(struct upatch_info_func)); +- if (upatch_process_mem_read(proc, src, opatch->uinfo->funcs, +- opatch->uinfo->changed_func_num * sizeof(struct upatch_info_func))) { +- log_error("can't read patch funcs at 0x%lx\n", src); +- free_object_patch(opatch); +- return -1; +- } +- link_funcs_name(opatch->uinfo); +- list_add(&opatch->list, &o->applied_patch); +- o->num_applied_patch++; +- o->is_patch = 1; +- return 0; ++ struct object_patch *opatch; ++ ++ opatch = malloc(sizeof(struct object_patch)); ++ if (opatch == NULL) { ++ log_error("malloc opatch failed\n"); ++ return -1; ++ } ++ ++ opatch->obj = o; ++ opatch->uinfo = malloc(sizeof(struct upatch_info)); ++ if (opatch->uinfo == NULL) { ++ log_error("malloc opatch->uinfo failed\n"); ++ free(opatch); ++ return -1; ++ } ++ ++ memcpy(opatch->uinfo->magic, header_buf, sizeof(struct upatch_info)); ++ ++ opatch->uinfo->func_names = malloc(opatch->uinfo->func_names_size); ++ if (opatch->uinfo->func_names == NULL) { ++ log_error("Failed to malloc funcs_names\n"); ++ free_object_patch(opatch); ++ return -ENOMEM; ++ } ++ ++ if (upatch_process_mem_read(proc, src, ++ opatch->uinfo->func_names, opatch->uinfo->func_names_size)) { ++ log_error("Cannot read patch func names at 0x%lx\n", src); ++ free_object_patch(opatch); ++ return -1; ++ } ++ ++ src += opatch->uinfo->func_names_size; ++ opatch->uinfo->funcs = malloc(opatch->uinfo->changed_func_num * ++ sizeof(struct upatch_info_func)); ++ if (upatch_process_mem_read(proc, src, opatch->uinfo->funcs, ++ opatch->uinfo->changed_func_num * sizeof(struct upatch_info_func))) { ++ log_error("can't read patch funcs at 0x%lx\n", src); ++ free_object_patch(opatch); ++ return -1; ++ } ++ ++ link_funcs_name(opatch->uinfo); ++ list_add(&opatch->list, &o->applied_patch); ++ o->num_applied_patch++; ++ o->is_patch = 1; ++ ++ return 0; + } + /** + * Returns: 0 if everything is ok, -1 on error. + */ +-static int process_add_object_vma(struct upatch_process *proc, dev_t dev, +- ino_t inode, char *name, struct vm_area *vma, +- struct vm_hole *hole) ++static int process_add_object_vma(struct upatch_process *proc, ++ dev_t dev, ino_t inode, char *name, ++ struct vm_area *vma, struct vm_hole *hole) + { +- int object_type; +- unsigned char header_buf[1024]; +- struct object_file *o; +- +- /* Event though process_get_object_type() return -1, +- * we still need continue process. */ +- object_type = process_get_object_type(proc, vma, name, header_buf, +- sizeof(header_buf)); +- +- if (object_type != OBJECT_UPATCH) { +- /* Is not a upatch, look if this is a vm_area of an already +- * enlisted object. +- */ +- list_for_each_entry_reverse(o, &proc->objs, list) { +- if ((dev && inode && o->dev == dev && +- o->inode == (ino_t)inode) || +- (dev == 0 && !strcmp(o->name, name))) { +- return object_add_vm_area(o, vma, hole); +- } +- } +- } +- +- o = process_new_object(proc, dev, inode, name, vma, hole); +- if (o == NULL) { +- return -1; +- } +- +- if (object_type == OBJECT_UPATCH) { +- unsigned long src = vma->start + sizeof(struct upatch_info); +- if (add_upatch_object(proc, o, src, header_buf) != 0) { +- return -1; +- } +- } +- if (object_type == OBJECT_ELF) { +- o->is_elf = 1; +- } +- +- return 0; ++ int object_type; ++ unsigned char header_buf[1024]; ++ struct object_file *o; ++ ++ /* Event though process_get_object_type() return -1, ++ * we still need continue process. */ ++ object_type = process_get_object_type(proc, vma, name, ++ header_buf, sizeof(header_buf)); ++ if (object_type != OBJECT_UPATCH) { ++ /* Is not a upatch, look if this is a vm_area of an already ++ * enlisted object. ++ */ ++ list_for_each_entry_reverse(o, &proc->objs, list) { ++ if ((dev && inode && o->dev == dev && ++ o->inode == (ino_t)inode) || ++ (dev == 0 && !strcmp(o->name, name))) { ++ return object_add_vm_area(o, vma, hole); ++ } ++ } ++ } ++ ++ o = process_new_object(proc, dev, inode, name, vma, hole); ++ if (o == NULL) { ++ return -1; ++ } ++ ++ if (object_type == OBJECT_UPATCH) { ++ unsigned long src = vma->start + sizeof(struct upatch_info); ++ if (add_upatch_object(proc, o, src, header_buf) != 0) { ++ return -1; ++ } ++ } ++ ++ if (object_type == OBJECT_ELF) { ++ o->is_elf = 1; ++ } ++ ++ return 0; + } + + int upatch_process_parse_proc_maps(struct upatch_process *proc) + { +- FILE *f; +- int ret, is_libc_base_set = 0; +- unsigned long hole_start = 0; +- struct vm_hole *hole = NULL; +- +- /* +- * 1. Create the list of all objects in the process +- * 2. Check whether we have patch for any of them +- * 3. If we have at least one patch, create files for all +- * of the object (we might have references to them +- * in the patch). +- */ +- int fd = dup(proc->fdmaps); +- if (fd < 0) { +- log_error("unable to dup fd %d", proc->fdmaps); +- return -1; +- } +- +- lseek(fd, 0, SEEK_SET); +- f = fdopen(fd, "r"); +- if (f == NULL) { +- log_error("unable to fdopen %d", fd); +- close(fd); +- return -1; +- } +- +- do { +- struct vm_area vma; +- char line[1024]; +- unsigned long start, end, offset; +- unsigned int maj, min, inode; +- char perms[5], name_[256], *name = name_; +- int r; +- +- if (!fgets(line, sizeof(line), f)) { +- break; +- } +- +- r = sscanf(line, "%lx-%lx %s %lx %x:%x %d %255s", &start, &end, +- perms, &offset, &maj, &min, &inode, name_); +- if (r == EOF) { +- log_error("Failed to read maps: unexpected EOF"); +- goto error; +- } +- +- if (r != 8) { +- strcpy(name, "[anonymous]"); +- } +- +- vma.start = start; +- vma.end = end; +- vma.offset = offset; +- vma.prot = perms2prot(perms); +- +- /* Hole must be at least 2 pages for guardians */ +- if (start - hole_start > (unsigned long)(2 * PAGE_SIZE)) { +- hole = process_add_vm_hole(proc, hole_start + (unsigned long)PAGE_SIZE, +- start - (unsigned long)PAGE_SIZE); +- if (hole == NULL) { +- log_error("Failed to add vma hole"); +- goto error; +- } +- } +- hole_start = end; +- +- name = name[0] == '/' ? basename(name) : name; +- +- ret = process_add_object_vma(proc, makedev(maj, min), inode, +- name, &vma, hole); +- if (ret < 0) { +- log_error("Failed to add object vma"); +- goto error; +- } +- +- if (!is_libc_base_set && !strncmp(basename(name), "libc", 4) && +- vma.prot & PROT_EXEC) { +- proc->libc_base = start; +- is_libc_base_set = 1; +- } +- +- } while (1); +- fclose(f); +- close(fd); +- +- log_debug("Found %d object file(s)\n", proc->num_objs); +- +- if (!is_libc_base_set) { +- log_error("Can't find libc_base required for manipulations: %d", +- proc->pid); +- return -1; +- } +- +- return 0; ++ FILE *f; ++ int ret; ++ int is_libc_base_set = 0; ++ unsigned long hole_start = 0; ++ struct vm_hole *hole = NULL; ++ ++ /* ++ * 1. Create the list of all objects in the process ++ * 2. Check whether we have patch for any of them ++ * 3. If we have at least one patch, create files for all ++ * of the object (we might have references to them ++ * in the patch). ++ */ ++ int fd = dup(proc->fdmaps); ++ if (fd < 0) { ++ log_error("unable to dup fd %d", proc->fdmaps); ++ return -1; ++ } ++ ++ lseek(fd, 0, SEEK_SET); ++ f = fdopen(fd, "r"); ++ if (f == NULL) { ++ log_error("unable to fdopen %d", fd); ++ close(fd); ++ return -1; ++ } ++ ++ do { ++ struct vm_area vma; ++ char line[1024]; ++ unsigned long start; ++ unsigned long end; ++ unsigned long offset; ++ unsigned int maj; ++ unsigned int min; ++ unsigned int inode; ++ char perms[5]; ++ char name_[256]; ++ char *name = name_; ++ int r; ++ ++ if (!fgets(line, sizeof(line), f)) { ++ break; ++ } ++ ++ r = sscanf(line, "%lx-%lx %s %lx %x:%x %d %255s", ++ &start, &end, perms, &offset, &maj, &min, &inode, name_); ++ if (r == EOF) { ++ log_error("Failed to read maps: unexpected EOF"); ++ goto error; ++ } ++ if (r != 8) { ++ strcpy(name, "[anonymous]"); ++ } ++ ++ vma.start = start; ++ vma.end = end; ++ vma.offset = offset; ++ vma.prot = perms2prot(perms); ++ ++ /* Hole must be at least 2 pages for guardians */ ++ if (start - hole_start > (unsigned long)(2 * PAGE_SIZE)) { ++ hole = process_add_vm_hole(proc, hole_start + (unsigned long)PAGE_SIZE, ++ start - (unsigned long)PAGE_SIZE); ++ if (hole == NULL) { ++ log_error("Failed to add vma hole"); ++ goto error; ++ } ++ } ++ hole_start = end; ++ name = name[0] == '/' ? basename(name) : name; ++ ++ ret = process_add_object_vma(proc, makedev(maj, min), inode, ++ name, &vma, hole); ++ if (ret < 0) { ++ log_error("Failed to add object vma"); ++ goto error; ++ } ++ ++ if (!is_libc_base_set && !strncmp(basename(name), "libc", 4) && ++ (vma.prot & PROT_EXEC)) { ++ proc->libc_base = start; ++ is_libc_base_set = 1; ++ } ++ } while (1); ++ ++ fclose(f); ++ close(fd); ++ log_debug("Found %d object file(s)\n", proc->num_objs); ++ ++ if (!is_libc_base_set) { ++ log_error("Can't find libc_base required for manipulations: %d", ++ proc->pid); ++ return -1; ++ } ++ ++ return 0; + + error: +- fclose(f); +- close(fd); +- return -1; ++ fclose(f); ++ close(fd); ++ return -1; + } + + int upatch_process_map_object_files(struct upatch_process *proc) + { +- // we can get plt/got table from mem's elf_segments +- // Now we read them from the running file +- return upatch_process_parse_proc_maps(proc); ++ // we can get plt/got table from mem's elf_segments ++ // Now we read them from the running file ++ return upatch_process_parse_proc_maps(proc); + } + + static int process_list_threads(struct upatch_process *proc, int **ppids, +- size_t *npids, size_t *alloc) ++ size_t *npids, size_t *alloc) + { +- DIR *dir = NULL; +- struct dirent *de; +- char path[PATH_MAX]; +- int *pids = *ppids; +- +- snprintf(path, sizeof(path), "/proc/%d/task", proc->pid); +- +- dir = opendir(path); +- if (!dir) { +- log_error("Failed to open directory '%s'\n", path); +- goto dealloc; +- } +- +- *npids = 0; +- while ((de = readdir(dir))) { +- int *t; +- if (de->d_name[0] == '.') { +- continue; +- } +- +- if (*npids >= *alloc) { +- *alloc = *alloc ? *alloc * 2 : 1; +- +- t = realloc(pids, *alloc * sizeof(*pids)); +- if (t == NULL) { +- log_error("Failed to (re)allocate memory for pids\n"); +- goto dealloc; +- } +- +- pids = t; +- } +- +- pids[*npids] = atoi(de->d_name); +- (*npids)++; +- } +- closedir(dir); +- +- *ppids = pids; +- +- return (int)*npids; ++ DIR *dir = NULL; ++ struct dirent *de; ++ char path[PATH_MAX]; ++ int *pids = *ppids; ++ ++ (void) snprintf(path, sizeof(path), "/proc/%d/task", proc->pid); ++ dir = opendir(path); ++ if (!dir) { ++ log_error("Failed to open directory '%s'\n", path); ++ goto dealloc; ++ } ++ ++ *npids = 0; ++ while ((de = readdir(dir))) { ++ int *t; ++ if (de->d_name[0] == '.') { ++ continue; ++ } ++ if (*npids >= *alloc) { ++ *alloc = *alloc ? *alloc * 2 : 1; ++ t = realloc(pids, *alloc * sizeof(*pids)); ++ if (t == NULL) { ++ log_error("Failed to (re)allocate memory for pids\n"); ++ goto dealloc; ++ } ++ pids = t; ++ } ++ ++ pids[*npids] = atoi(de->d_name); ++ (*npids)++; ++ } ++ ++ closedir(dir); ++ *ppids = pids; ++ ++ return (int)*npids; + + dealloc: +- if (dir) { +- closedir(dir); +- } +- free(pids); +- *ppids = NULL; +- *alloc = *npids = 0; +- return -1; ++ if (dir) { ++ closedir(dir); ++ } ++ ++ free(pids); ++ *ppids = NULL; ++ *alloc = *npids = 0; ++ return -1; + } + + int upatch_process_attach(struct upatch_process *proc) + { +- int *pids = NULL, ret; +- size_t i, npids = 0, alloc = 0, prevnpids = 0, nattempts; +- +- if (upatch_process_mem_open(proc, MEM_WRITE) < 0) { +- return -1; +- } +- +- for (nattempts = 0; nattempts < MAX_ATTACH_ATTEMPTS; nattempts++) { +- ret = process_list_threads(proc, &pids, &npids, &alloc); +- if (ret == -1) +- goto detach; +- +- if (nattempts == 0) { +- log_debug("Found %lu thread(s), attaching...\n", npids); +- } else { +- /* +- * FIXME(pboldin): This is wrong, amount of threads can +- * be the same because some new spawned and some old +- * died +- */ +- if (prevnpids == npids) +- break; +- +- log_debug("Found %lu new thread(s), attaching...\n", +- prevnpids - npids); +- } +- +- for (i = prevnpids; i < npids; i++) { +- int pid = pids[i]; +- +- // if (process_has_thread_pid(proc, pid)) { +- // log_debug("already have pid %d\n", pid); +- // continue; +- // } +- +- ret = upatch_ptrace_attach_thread(proc, pid); +- if (ret < 0) +- goto detach; +- } +- +- prevnpids = npids; +- } +- +- if (nattempts == MAX_ATTACH_ATTEMPTS) { +- log_error("Unable to catch up with process, bailing\n"); +- goto detach; +- } +- +- log_debug("Attached to %lu thread(s): %d", npids, pids[0]); +- for (i = 1; i < npids; i++) { +- log_debug(", %d", pids[i]); +- } +- log_debug("\n"); +- +- free(pids); +- return 0; ++ int *pids = NULL; ++ int ret; ++ ++ size_t i; ++ size_t npids = 0; ++ size_t alloc = 0; ++ size_t prevnpids = 0; ++ size_t nattempts; ++ ++ if (upatch_process_mem_open(proc, MEM_WRITE) < 0) { ++ return -1; ++ } ++ ++ for (nattempts = 0; nattempts < MAX_ATTACH_ATTEMPTS; nattempts++) { ++ ret = process_list_threads(proc, &pids, &npids, &alloc); ++ if (ret == -1) { ++ goto detach; ++ } ++ ++ if (nattempts == 0) { ++ log_debug("Found %lu thread(s), attaching...\n", npids); ++ } else { ++ /* ++ * FIXME(pboldin): This is wrong, amount of threads can ++ * be the same because some new spawned and some old ++ * died ++ */ ++ if (prevnpids == npids) { ++ break; ++ } ++ log_debug("Found %lu new thread(s), attaching...\n", ++ prevnpids - npids); ++ } ++ ++ for (i = prevnpids; i < npids; i++) { ++ int pid = pids[i]; ++ ++ ret = upatch_ptrace_attach_thread(proc, pid); ++ if (ret < 0) { ++ goto detach; ++ } ++ } ++ ++ prevnpids = npids; ++ } ++ ++ if (nattempts == MAX_ATTACH_ATTEMPTS) { ++ log_error("Unable to catch up with process, bailing\n"); ++ goto detach; ++ } ++ ++ log_debug("Attached to %lu thread(s): %d", npids, pids[0]); ++ for (i = 1; i < npids; i++) { ++ log_debug(", %d", pids[i]); ++ } ++ log_debug("\n"); ++ ++ free(pids); ++ return 0; + + detach: +- upatch_process_detach(proc); +- free(pids); +- return -1; ++ upatch_process_detach(proc); ++ free(pids); ++ return -1; + } + + void upatch_process_detach(struct upatch_process *proc) + { +- struct upatch_ptrace_ctx *p, *ptmp; +- int status; +- pid_t pid; +- +- if (proc->memfd >= 0 && close(proc->memfd) < 0) { +- log_error("Failed to close memfd"); +- } +- proc->memfd = -1; +- +- list_for_each_entry_safe(p, ptmp, &proc->ptrace.pctxs, list) { +- /** +- * If upatch_ptrace_detach(p) return -ESRCH, there are two situations, +- * as described below: +- * 1. the specified thread does not exist, it means the thread dead +- * during the attach processing, so we need to wait for the thread +- * to exit; +- * 2. the specified thread is not currently being traced by us, +- * or is not stopped, so we just ignore it; +- * +- * We using the running variable of the struct upatch_ptrace_ctx to +- * distinguish them: +- * 1. if pctx->running = 0, it means the thread is traced by us, we +- * will wait for the thread to exit; +- * 2. if pctx->running = 1, it means we can not sure about the status of +- * the thread, we just ignore it; +- */ +- if (upatch_ptrace_detach(p) == -ESRCH && !p->running) { +- do { +- pid = waitpid(p->pid, &status, __WALL); +- } while (pid > 0 && !WIFEXITED(status)); +- } +- list_del(&p->list); +- free(p); +- } +- log_debug("Process detached\n"); ++ struct upatch_ptrace_ctx *p; ++ struct upatch_ptrace_ctx *ptmp; ++ int status; ++ pid_t pid; ++ ++ if (proc->memfd >= 0 && close(proc->memfd) < 0) { ++ log_error("Failed to close memfd"); ++ } ++ proc->memfd = -1; ++ ++ list_for_each_entry_safe(p, ptmp, &proc->ptrace.pctxs, list) { ++ /** ++ * If upatch_ptrace_detach(p) return -ESRCH, there are two situations, ++ * as described below: ++ * 1. the specified thread does not exist, it means the thread dead ++ * during the attach processing, so we need to wait for the thread ++ * to exit; ++ * 2. the specified thread is not currently being traced by us, ++ * or is not stopped, so we just ignore it; ++ * ++ * We using the running variable of the struct upatch_ptrace_ctx to ++ * distinguish them: ++ * 1. if pctx->running = 0, it means the thread is traced by us, we ++ * will wait for the thread to exit; ++ * 2. if pctx->running = 1, it means we can not sure about the status of ++ * the thread, we just ignore it; ++ */ ++ if (upatch_ptrace_detach(p) == -ESRCH && !p->running) { ++ do { ++ pid = waitpid(p->pid, &status, __WALL); ++ } while (pid > 0 && !WIFEXITED(status)); ++ } ++ list_del(&p->list); ++ free(p); ++ } ++ log_debug("Process detached\n"); + } + + static inline struct vm_hole *next_hole(struct vm_hole *hole, +- struct list_head *head) ++ struct list_head *head) + { +- if (hole == NULL || hole->list.next == head) +- return NULL; ++ if (hole == NULL || hole->list.next == head) { ++ return NULL; ++ } + +- return list_entry(hole->list.next, struct vm_hole, list); ++ return list_entry(hole->list.next, struct vm_hole, list); + } + + static inline struct vm_hole *prev_hole(struct vm_hole *hole, +- struct list_head *head) ++ struct list_head *head) + { +- if (hole == NULL || hole->list.prev == head) +- return NULL; ++ if (hole == NULL || hole->list.prev == head) { ++ return NULL; ++ } + +- return list_entry(hole->list.prev, struct vm_hole, list); ++ return list_entry(hole->list.prev, struct vm_hole, list); + } + + static inline unsigned long hole_size(struct vm_hole *hole) + { +- if (hole == NULL) +- return 0; +- return hole->end - hole->start; ++ if (hole == NULL) { ++ return 0; ++ } ++ ++ return hole->end - hole->start; + } + +-int vm_hole_split(struct vm_hole *hole, unsigned long alloc_start, +- unsigned long alloc_end) ++int vm_hole_split(struct vm_hole *hole, ++ unsigned long alloc_start, unsigned long alloc_end) + { +- unsigned long page_size = (unsigned long)PAGE_SIZE; ++ unsigned long page_size = (unsigned long)PAGE_SIZE; + +- alloc_start = ROUND_DOWN(alloc_start, page_size) - page_size; +- alloc_end = ROUND_UP(alloc_end, page_size) + page_size; ++ alloc_start = ROUND_DOWN(alloc_start, page_size) - page_size; ++ alloc_end = ROUND_UP(alloc_end, page_size) + page_size; + +- if (alloc_start > hole->start) { +- struct vm_hole *left = NULL; ++ if (alloc_start > hole->start) { ++ struct vm_hole *left = NULL; + +- left = malloc(sizeof(*hole)); +- if (left == NULL) { +- log_error("Failed to malloc for vm hole"); +- return -1; +- } ++ left = malloc(sizeof(*hole)); ++ if (left == NULL) { ++ log_error("Failed to malloc for vm hole"); ++ return -1; ++ } + +- left->start = hole->start; +- left->end = alloc_start; ++ left->start = hole->start; ++ left->end = alloc_start; + +- list_add(&left->list, &hole->list); +- } ++ list_add(&left->list, &hole->list); ++ } + +- /* Reuse hole pointer as the right hole since it is pointed to by +- * the `previous_hole` of some `object_file`. */ +- hole->start = alloc_end; +- hole->end = hole->end > alloc_end ? hole->end : alloc_end; ++ /* Reuse hole pointer as the right hole since it is pointed to by ++ * the `previous_hole` of some `object_file`. */ ++ hole->start = alloc_end; ++ hole->end = hole->end > alloc_end ? hole->end : alloc_end; + +- return 0; ++ return 0; + } + + /* +@@ -841,49 +873,52 @@ int vm_hole_split(struct vm_hole *hole, unsigned long alloc_start, + * from the obj. + * eg: R_AARCH64_ADR_GOT_PAGE + */ +-unsigned long object_find_patch_region(struct object_file *obj, size_t memsize, +- struct vm_hole **hole) ++unsigned long object_find_patch_region(struct object_file *obj, ++ size_t memsize, struct vm_hole **hole) + { +- struct list_head *head = &obj->proc->vmaholes; +- struct vm_hole *left_hole = obj->previous_hole; +- struct vm_hole *right_hole = next_hole(left_hole, head); +- unsigned long region_start = 0; +- struct obj_vm_area *sovma; +- unsigned long obj_start, obj_end; +- +- sovma = list_first_entry(&obj->vma, struct obj_vm_area, list); +- obj_start = sovma->inmem.start; +- sovma = list_entry(obj->vma.prev, struct obj_vm_area, list); +- obj_end = sovma->inmem.end; +- +- log_debug("Looking for patch region for '%s'...\n", obj->name); +- +- while (right_hole != NULL || left_hole != NULL) { +- if (hole_size(right_hole) > memsize) { +- *hole = right_hole; +- region_start = right_hole->start; +- if (region_start + memsize - obj_start > MAX_DISTANCE) { +- continue; +- } +- goto found; +- } +- if (hole_size(left_hole) > memsize) { +- *hole = left_hole; +- region_start = left_hole->end - memsize; +- if (obj_end - region_start > MAX_DISTANCE) { +- continue; +- } +- goto found; +- } +- right_hole = next_hole(right_hole, head); +- left_hole = prev_hole(left_hole, head); +- } +- log_error("Cannot find suitable region for patch '%s'\n", obj->name); +- return -1UL; ++ struct list_head *head = &obj->proc->vmaholes; ++ struct vm_hole *left_hole = obj->previous_hole; ++ struct vm_hole *right_hole = next_hole(left_hole, head); ++ unsigned long region_start = 0; ++ struct obj_vm_area *sovma; ++ unsigned long obj_start; ++ unsigned long obj_end; ++ ++ sovma = list_first_entry(&obj->vma, struct obj_vm_area, list); ++ obj_start = sovma->inmem.start; ++ sovma = list_entry(obj->vma.prev, struct obj_vm_area, list); ++ obj_end = sovma->inmem.end; ++ ++ log_debug("Looking for patch region for '%s'...\n", obj->name); ++ ++ while (right_hole != NULL || left_hole != NULL) { ++ if (hole_size(right_hole) > memsize) { ++ *hole = right_hole; ++ region_start = right_hole->start; ++ if (region_start + memsize - obj_start > MAX_DISTANCE) { ++ continue; ++ } ++ goto found; ++ } ++ if (hole_size(left_hole) > memsize) { ++ *hole = left_hole; ++ region_start = left_hole->end - memsize; ++ if (obj_end - region_start > MAX_DISTANCE) { ++ continue; ++ } ++ goto found; ++ } ++ right_hole = next_hole(right_hole, head); ++ left_hole = prev_hole(left_hole, head); ++ } ++ ++ log_error("Cannot find suitable region for patch '%s'\n", obj->name); ++ return -1UL; ++ + found: +- region_start = (region_start >> PAGE_SHIFT) << PAGE_SHIFT; +- log_debug("Found patch region for '%s' 0xat %lx\n", obj->name, +- region_start); ++ region_start = (region_start >> PAGE_SHIFT) << PAGE_SHIFT; ++ log_debug("Found patch region for '%s' 0xat %lx\n", ++ obj->name, region_start); + +- return region_start; ++ return region_start; + } +diff --git a/upatch-manage/upatch-process.h b/upatch-manage/upatch-process.h +index a98b542..23cbced 100644 +--- a/upatch-manage/upatch-process.h ++++ b/upatch-manage/upatch-process.h +@@ -38,95 +38,95 @@ + #endif + + enum { +- MEM_READ, +- MEM_WRITE, ++ MEM_READ, ++ MEM_WRITE, + }; + + struct object_file { +- struct list_head list; +- struct upatch_process *proc; ++ struct list_head list; ++ struct upatch_process *proc; + +- /* Device the object resides on */ +- dev_t dev; +- ino_t inode; ++ /* Device the object resides on */ ++ dev_t dev; ++ ino_t inode; + +- /* Object name (as seen in /proc//maps) */ +- char *name; ++ /* Object name (as seen in /proc//maps) */ ++ char *name; + +- /* List of object's VM areas */ +- struct list_head vma; ++ /* List of object's VM areas */ ++ struct list_head vma; + +- /* Pointer to the previous hole in the patient's mapping */ +- struct vm_hole *previous_hole; ++ /* Pointer to the previous hole in the patient's mapping */ ++ struct vm_hole *previous_hole; + +- /* Pointer to the applied patch list, if any */ +- struct list_head applied_patch; +- /* The number of applied patch */ +- size_t num_applied_patch; ++ /* Pointer to the applied patch list, if any */ ++ struct list_head applied_patch; ++ /* The number of applied patch */ ++ size_t num_applied_patch; + +- /* Is that a patch for some object? */ +- unsigned int is_patch; ++ /* Is that a patch for some object? */ ++ unsigned int is_patch; + +- /* Is it an ELF or a mmap'ed regular file? */ +- unsigned int is_elf; ++ /* Is it an ELF or a mmap'ed regular file? */ ++ unsigned int is_elf; + }; + + struct vm_area { +- unsigned long start; +- unsigned long end; +- unsigned long offset; +- unsigned int prot; ++ unsigned long start; ++ unsigned long end; ++ unsigned long offset; ++ unsigned int prot; + }; + + struct vm_hole { +- unsigned long start; +- unsigned long end; +- struct list_head list; ++ unsigned long start; ++ unsigned long end; ++ struct list_head list; + }; + + struct obj_vm_area { +- struct list_head list; +- struct vm_area inmem; ++ struct list_head list; ++ struct vm_area inmem; + }; + + struct object_patch { +- struct list_head list; +- struct upatch_info *uinfo; +- struct object_file *obj; ++ struct list_head list; ++ struct upatch_info *uinfo; ++ struct object_file *obj; + }; + + struct upatch_process { +- /* Pid of target process */ +- int pid; ++ /* Pid of target process */ ++ int pid; + +- /* memory fd of /proc//mem */ +- int memfd; ++ /* memory fd of /proc//mem */ ++ int memfd; + +- /* /proc//maps FD, also works as lock */ +- int fdmaps; ++ /* /proc//maps FD, also works as lock */ ++ int fdmaps; + +- /* Process name */ +- char comm[16]; ++ /* Process name */ ++ char comm[16]; + +- /* List of process objects */ +- struct list_head objs; +- int num_objs; ++ /* List of process objects */ ++ struct list_head objs; ++ int num_objs; + +- /* List ptrace contexts (one per each thread) */ +- struct { +- struct list_head pctxs; +- } ptrace; ++ /* List ptrace contexts (one per each thread) */ ++ struct { ++ struct list_head pctxs; ++ } ptrace; + +- struct { +- struct list_head coros; +- } coro; ++ struct { ++ struct list_head coros; ++ } coro; + +- /* List of free VMA areas */ +- struct list_head vmaholes; ++ /* List of free VMA areas */ ++ struct list_head vmaholes; + +- // TODO: other base? +- /* libc's base address to use as a worksheet */ +- unsigned long libc_base; ++ // TODO: other base? ++ /* libc's base address to use as a worksheet */ ++ unsigned long libc_base; + }; + + int upatch_process_init(struct upatch_process *, int); +@@ -145,7 +145,7 @@ void upatch_process_detach(struct upatch_process *proc); + + int vm_hole_split(struct vm_hole *, unsigned long, unsigned long); + +-unsigned long object_find_patch_region(struct object_file *, size_t, +- struct vm_hole **); ++unsigned long object_find_patch_region(struct object_file *, ++ size_t, struct vm_hole **); + + #endif +diff --git a/upatch-manage/upatch-ptrace.c b/upatch-manage/upatch-ptrace.c +index 03296bc..2d0845c 100644 +--- a/upatch-manage/upatch-ptrace.c ++++ b/upatch-manage/upatch-ptrace.c +@@ -33,254 +33,262 @@ + + /* process's memory access */ + int upatch_process_mem_read(struct upatch_process *proc, unsigned long src, +- void *dst, size_t size) ++ void *dst, size_t size) + { +- ssize_t r = pread(proc->memfd, dst, size, (off_t)src); ++ ssize_t r = pread(proc->memfd, dst, size, (off_t)src); + +- return r != (ssize_t)size ? -1 : 0; ++ return r != (ssize_t)size ? -1 : 0; + } + + static int upatch_process_mem_write_ptrace(struct upatch_process *proc, +- const void *src, unsigned long dst, size_t size) ++ const void *src, unsigned long dst, size_t size) + { +- long ret; +- +- while (ROUND_DOWN(size, sizeof(long)) != 0) { +- ret = ptrace(PTRACE_POKEDATA, proc->pid, dst, *(const unsigned long *)src); +- if (ret) { +- return -1; +- } +- dst += sizeof(long); +- src += sizeof(long); +- size -= sizeof(long); +- } +- +- if (size) { +- long tmp; +- +- tmp = ptrace(PTRACE_PEEKDATA, proc->pid, dst, NULL); +- if (tmp == -1 && errno) { +- return -1; +- } +- memcpy(&tmp, src, size); +- +- ret = ptrace(PTRACE_POKEDATA, proc->pid, dst, tmp); +- if (ret) { +- return -1; +- } +- } +- +- return 0; ++ long ret; ++ ++ while (ROUND_DOWN(size, sizeof(long)) != 0) { ++ ret = ptrace(PTRACE_POKEDATA, proc->pid, dst, *(const unsigned long *)src); ++ if (ret) { ++ return -1; ++ } ++ dst += sizeof(long); ++ src += sizeof(long); ++ size -= sizeof(long); ++ } ++ ++ if (size) { ++ long tmp; ++ ++ tmp = ptrace(PTRACE_PEEKDATA, proc->pid, dst, NULL); ++ if (tmp == -1 && errno) { ++ return -1; ++ } ++ memcpy(&tmp, src, size); ++ ++ ret = ptrace(PTRACE_POKEDATA, proc->pid, dst, tmp); ++ if (ret) { ++ return -1; ++ } ++ } ++ ++ return 0; + } + + int upatch_process_mem_write(struct upatch_process *proc, const void *src, +- unsigned long dst, size_t size) ++ unsigned long dst, size_t size) + { +- static int use_pwrite = 1; +- ssize_t w; +- +- if (use_pwrite) { +- w = pwrite(proc->memfd, src, size, (off_t)dst); +- } +- if (!use_pwrite || (w == -1 && errno == EINVAL)) { +- use_pwrite = 0; +- return upatch_process_mem_write_ptrace(proc, src, dst, size); +- } +- +- return w != (ssize_t)size ? -1 : 0; ++ static int use_pwrite = 1; ++ ssize_t w; ++ ++ if (use_pwrite) { ++ w = pwrite(proc->memfd, src, size, (off_t)dst); ++ } ++ if (!use_pwrite || (w == -1 && errno == EINVAL)) { ++ use_pwrite = 0; ++ return upatch_process_mem_write_ptrace(proc, src, dst, size); ++ } ++ ++ return w != (ssize_t)size ? -1 : 0; + } + + static struct upatch_ptrace_ctx* upatch_ptrace_ctx_alloc( +- struct upatch_process *proc) ++ struct upatch_process *proc) + { +- struct upatch_ptrace_ctx *p; ++ struct upatch_ptrace_ctx *p; + +- p = malloc(sizeof(*p)); +- if (!p) { +- return NULL; +- } ++ p = malloc(sizeof(*p)); ++ if (!p) { ++ return NULL; ++ } + +- memset(p, 0, sizeof(*p)); ++ memset(p, 0, sizeof(*p)); + +- p->execute_until = 0UL; +- p->running = 1; +- p->proc = proc; ++ p->execute_until = 0UL; ++ p->running = 1; ++ p->proc = proc; + +- INIT_LIST_HEAD(&p->list); +- list_add(&p->list, &proc->ptrace.pctxs); ++ INIT_LIST_HEAD(&p->list); ++ list_add(&p->list, &proc->ptrace.pctxs); + +- return p; ++ return p; + } + + int upatch_ptrace_attach_thread(struct upatch_process *proc, int tid) + { +- struct upatch_ptrace_ctx *pctx = upatch_ptrace_ctx_alloc(proc); +- if (pctx == NULL) { +- log_error("Failed to alloc ptrace context"); +- return -1; +- } +- +- pctx->pid = tid; +- log_debug("Attaching to %d...", tid); +- +- long ret = ptrace(PTRACE_ATTACH, tid, NULL, NULL); +- if (ret < 0) { +- log_error("Failed to attach thread, pid=%d, ret=%ld\n", tid, ret); +- return -1; +- } +- +- do { +- int status = 0; +- +- ret = waitpid(tid, &status, __WALL); +- if (ret < 0) { +- log_error("Failed to wait thread, tid=%d, ret=%ld\n", tid, ret); +- return -1; +- } +- +- /* We are expecting SIGSTOP */ +- if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP) { +- break; +- } +- +- /* If we got SIGTRAP because we just got out of execve, wait +- * for the SIGSTOP +- */ +- if (WIFSTOPPED(status)) { +- status = (WSTOPSIG(status) == SIGTRAP) ? 0 : WSTOPSIG(status); +- } else if (WIFSIGNALED(status)) { +- /* Resend signal */ +- status = WTERMSIG(status); +- } +- +- ret = ptrace(PTRACE_CONT, tid, NULL, (void *)(uintptr_t)status); +- if (ret < 0) { +- log_error("Failed to continue thread, tid=%d, ret=%ld\n", tid, ret); +- return -1; +- } +- } while (1); +- +- pctx->running = 0; +- +- log_debug("OK\n"); +- return 0; ++ struct upatch_ptrace_ctx *pctx = upatch_ptrace_ctx_alloc(proc); ++ if (pctx == NULL) { ++ log_error("Failed to alloc ptrace context"); ++ return -1; ++ } ++ ++ pctx->pid = tid; ++ log_debug("Attaching to %d...", tid); ++ ++ long ret = ptrace(PTRACE_ATTACH, tid, NULL, NULL); ++ if (ret < 0) { ++ log_error("Failed to attach thread, pid=%d, ret=%ld\n", tid, ret); ++ return -1; ++ } ++ ++ do { ++ int status = 0; ++ ++ ret = waitpid(tid, &status, __WALL); ++ if (ret < 0) { ++ log_error("Failed to wait thread, tid=%d, ret=%ld\n", tid, ret); ++ return -1; ++ } ++ ++ /* We are expecting SIGSTOP */ ++ if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP) { ++ break; ++ } ++ ++ /* If we got SIGTRAP because we just got out of execve, wait ++ * for the SIGSTOP ++ */ ++ if (WIFSTOPPED(status)) { ++ status = (WSTOPSIG(status) == SIGTRAP) ? 0 : WSTOPSIG(status); ++ } else if (WIFSIGNALED(status)) { ++ /* Resend signal */ ++ status = WTERMSIG(status); ++ } ++ ++ ret = ptrace(PTRACE_CONT, tid, NULL, (void *)(uintptr_t)status); ++ if (ret < 0) { ++ log_error("Failed to continue thread, tid=%d, ret=%ld\n", tid, ret); ++ return -1; ++ } ++ } while (1); ++ ++ pctx->running = 0; ++ ++ log_debug("OK\n"); ++ return 0; + } + + int wait_for_stop(struct upatch_ptrace_ctx *pctx, const void *data) + { +- long ret; +- int status = 0, pid = (int)(uintptr_t)data ?: pctx->pid; +- log_debug("wait_for_stop(pctx->pid=%d, pid=%d)\n", pctx->pid, pid); +- +- while (1) { +- ret = ptrace(PTRACE_CONT, pctx->pid, NULL, (void *)(uintptr_t)status); +- if (ret < 0) { +- log_error("Cannot start tracee %d, ret=%ld\n", pctx->pid, ret); +- return -1; +- } +- +- ret = waitpid(pid, &status, __WALL); +- if (ret < 0) { +- log_error("Cannot wait tracee %d, ret=%ld\n", pid, ret); +- return -1; +- } +- +- if (WIFSTOPPED(status)) { +- if (WSTOPSIG(status) == SIGSTOP || WSTOPSIG(status) == SIGTRAP) { +- break; +- } +- status = WSTOPSIG(status); +- continue; +- } +- +- status = WIFSIGNALED(status) ? WTERMSIG(status) : 0; +- } +- +- return 0; ++ long ret; ++ ++ int status = 0; ++ int pid = (int)(uintptr_t)data ?: pctx->pid; ++ log_debug("wait_for_stop(pctx->pid=%d, pid=%d)\n", pctx->pid, pid); ++ ++ while (1) { ++ ret = ptrace(PTRACE_CONT, pctx->pid, NULL, (void *)(uintptr_t)status); ++ if (ret < 0) { ++ log_error("Cannot start tracee %d, ret=%ld\n", pctx->pid, ret); ++ return -1; ++ } ++ ++ ret = waitpid(pid, &status, __WALL); ++ if (ret < 0) { ++ log_error("Cannot wait tracee %d, ret=%ld\n", pid, ret); ++ return -1; ++ } ++ ++ if (WIFSTOPPED(status)) { ++ if (WSTOPSIG(status) == SIGSTOP || WSTOPSIG(status) == SIGTRAP) { ++ break; ++ } ++ status = WSTOPSIG(status); ++ continue; ++ } ++ ++ status = WIFSIGNALED(status) ? WTERMSIG(status) : 0; ++ } ++ ++ return 0; + } + + int upatch_ptrace_detach(struct upatch_ptrace_ctx *pctx) + { +- if (!pctx->pid) { +- return 0; +- } +- +- log_debug("Detaching from %d...", pctx->pid); +- long ret = ptrace(PTRACE_DETACH, pctx->pid, NULL, NULL); +- if (ret < 0) { +- log_error("Failed to detach from process, pid=%d, ret=%ld\n", pctx->pid, ret); +- return -errno; +- } +- log_debug("OK\n"); +- +- pctx->running = 1; +- pctx->pid = 0; +- return 0; ++ if (!pctx->pid) { ++ return 0; ++ } ++ ++ log_debug("Detaching from %d...", pctx->pid); ++ long ret = ptrace(PTRACE_DETACH, pctx->pid, NULL, NULL); ++ if (ret < 0) { ++ log_error("Failed to detach from process, pid=%d, ret=%ld\n", pctx->pid, ret); ++ return -errno; ++ } ++ log_debug("OK\n"); ++ ++ pctx->running = 1; ++ pctx->pid = 0; ++ return 0; + } + + long upatch_execute_remote(struct upatch_ptrace_ctx *pctx, +- const unsigned char *code, size_t codelen, +- struct user_regs_struct *pregs) ++ const unsigned char *code, size_t codelen, ++ struct user_regs_struct *pregs) + { +- return upatch_arch_execute_remote_func( +- pctx, code, codelen, pregs, wait_for_stop, NULL); ++ return upatch_arch_execute_remote_func(pctx, code, codelen, pregs, ++ wait_for_stop, NULL); + } + + unsigned long upatch_mmap_remote(struct upatch_ptrace_ctx *pctx, +- unsigned long addr, size_t length, unsigned long prot, +- unsigned long flags, unsigned long fd, unsigned long offset) ++ unsigned long addr, size_t length, unsigned long prot, ++ unsigned long flags, unsigned long fd, unsigned long offset) + { +- long ret; +- unsigned long res = 0; +- +- log_debug("mmap_remote: 0x%lx+%lx, %lx, %lx, %lu, %lx\n", addr, length, +- prot, flags, fd, offset); +- ret = upatch_arch_syscall_remote(pctx, __NR_mmap, (unsigned long)addr, +- length, prot, flags, fd, offset, &res); +- if (ret < 0) { +- return 0; +- } +- if (ret == 0 && res >= (unsigned long)-MAX_ERRNO) { +- errno = -(int)res; +- return 0; +- } +- return res; ++ long ret; ++ unsigned long res = 0; ++ ++ log_debug("mmap_remote: 0x%lx+%lx, %lx, %lx, %lu, %lx\n", addr, length, ++ prot, flags, fd, offset); ++ ret = upatch_arch_syscall_remote(pctx, __NR_mmap, ++ (unsigned long)addr, length, prot, flags, fd, offset, &res); ++ if (ret < 0) { ++ return 0; ++ } ++ ++ if (ret == 0 && res >= (unsigned long)-MAX_ERRNO) { ++ errno = -(int)res; ++ return 0; ++ } ++ ++ return res; + } + + int upatch_mprotect_remote(struct upatch_ptrace_ctx *pctx, unsigned long addr, +- size_t length, unsigned long prot) ++ size_t length, unsigned long prot) + { +- long ret; +- unsigned long res; +- +- log_debug("mprotect_remote: 0x%lx+%lx\n", addr, length); +- ret = upatch_arch_syscall_remote(pctx, __NR_mprotect, +- (unsigned long)addr, length, prot, 0, +- 0, 0, &res); +- if (ret < 0) +- return -1; +- if (ret == 0 && res >= (unsigned long)-MAX_ERRNO) { +- errno = -(int)res; +- return -1; +- } +- +- return 0; ++ long ret; ++ unsigned long res; ++ ++ log_debug("mprotect_remote: 0x%lx+%lx\n", addr, length); ++ ret = upatch_arch_syscall_remote(pctx, __NR_mprotect, ++ (unsigned long)addr, length, prot, 0, 0, 0, &res); ++ if (ret < 0) { ++ return -1; ++ } ++ ++ if (ret == 0 && res >= (unsigned long)-MAX_ERRNO) { ++ errno = -(int)res; ++ return -1; ++ } ++ ++ return 0; + } + + int upatch_munmap_remote(struct upatch_ptrace_ctx *pctx, unsigned long addr, +- size_t length) ++ size_t length) + { +- long ret; +- unsigned long res; +- +- log_debug("munmap_remote: 0x%lx+%lx\n", addr, length); +- ret = upatch_arch_syscall_remote(pctx, __NR_munmap, (unsigned long)addr, +- length, 0, 0, 0, 0, &res); +- if (ret < 0) +- return -1; +- if (ret == 0 && res >= (unsigned long)-MAX_ERRNO) { +- errno = -(int)res; +- return -1; +- } +- return 0; ++ long ret; ++ unsigned long res; ++ ++ log_debug("munmap_remote: 0x%lx+%lx\n", addr, length); ++ ret = upatch_arch_syscall_remote(pctx, __NR_munmap, ++ (unsigned long)addr, length, 0, 0, 0, 0, &res); ++ if (ret < 0) { ++ return -1; ++ } ++ ++ if (ret == 0 && res >= (unsigned long)-MAX_ERRNO) { ++ errno = -(int)res; ++ return -1; ++ } ++ ++ return 0; + } +diff --git a/upatch-manage/upatch-ptrace.h b/upatch-manage/upatch-ptrace.h +index b88c656..8f36565 100644 +--- a/upatch-manage/upatch-ptrace.h ++++ b/upatch-manage/upatch-ptrace.h +@@ -30,21 +30,21 @@ + #define MAX_ERRNO 4095 + + struct upatch_ptrace_ctx { +- int pid; +- int running; +- unsigned long execute_until; +- struct upatch_process *proc; +- struct list_head list; ++ int pid; ++ int running; ++ unsigned long execute_until; ++ struct upatch_process *proc; ++ struct list_head list; + }; + + #define proc2pctx(proc) \ +- list_first_entry(&(proc)->ptrace.pctxs, struct upatch_ptrace_ctx, list) ++ list_first_entry(&(proc)->ptrace.pctxs, struct upatch_ptrace_ctx, list) + + int upatch_process_mem_read(struct upatch_process *proc, unsigned long src, +- void *dst, size_t size); ++ void *dst, size_t size); + +-int upatch_process_mem_write(struct upatch_process *, const void *, unsigned long, +- size_t); ++int upatch_process_mem_write(struct upatch_process *, const void *, ++ unsigned long, size_t); + + int upatch_ptrace_attach_thread(struct upatch_process *, int); + +@@ -55,27 +55,26 @@ int wait_for_stop(struct upatch_ptrace_ctx *, const void *); + void copy_regs(struct user_regs_struct *, struct user_regs_struct *); + + long upatch_arch_execute_remote_func(struct upatch_ptrace_ctx *pctx, +- const unsigned char *code, size_t codelen, +- struct user_regs_struct *pregs, +- int (*func)(struct upatch_ptrace_ctx *pctx, +- const void *data), +- const void *data); ++ const unsigned char *code, size_t codelen, ++ struct user_regs_struct *pregs, ++ int (*func)(struct upatch_ptrace_ctx *pctx, const void *data), ++ const void *data); + + long upatch_arch_syscall_remote(struct upatch_ptrace_ctx *, int, unsigned long, +- unsigned long, unsigned long, unsigned long, +- unsigned long, unsigned long, unsigned long *); ++ unsigned long, unsigned long, unsigned long, ++ unsigned long, unsigned long, unsigned long *); + + unsigned long upatch_mmap_remote(struct upatch_ptrace_ctx *pctx, +- unsigned long addr, size_t length, unsigned long prot, +- unsigned long flags, unsigned long fd, unsigned long offset); ++ unsigned long addr, size_t length, unsigned long prot, ++ unsigned long flags, unsigned long fd, unsigned long offset); + + int upatch_mprotect_remote(struct upatch_ptrace_ctx *pctx, unsigned long addr, +- size_t length, unsigned long prot); ++ size_t length, unsigned long prot); + + int upatch_munmap_remote(struct upatch_ptrace_ctx *, unsigned long, size_t); + +-long upatch_execute_remote(struct upatch_ptrace_ctx *, const unsigned char *, +- size_t, struct user_regs_struct *); ++long upatch_execute_remote(struct upatch_ptrace_ctx *, ++ const unsigned char *, size_t, struct user_regs_struct *); + + size_t get_origin_insn_len(void); + size_t get_upatch_insn_len(void); +diff --git a/upatch-manage/upatch-relocation.c b/upatch-manage/upatch-relocation.c +index a4200b6..57db9ba 100644 +--- a/upatch-manage/upatch-relocation.c ++++ b/upatch-manage/upatch-relocation.c +@@ -25,32 +25,35 @@ + + int apply_relocations(struct upatch_elf *uelf) + { +- unsigned int i; +- int err = 0; +- +- /* Now do relocations. */ +- for (i = 1; i < uelf->info.hdr->e_shnum; i++) { +- unsigned int infosec = uelf->info.shdrs[i].sh_info; +- const char *name = +- uelf->info.shstrtab + uelf->info.shdrs[i].sh_name; +- +- /* Not a valid relocation section? */ +- if (infosec >= uelf->info.hdr->e_shnum) +- continue; +- +- /* Don't bother with non-allocated sections */ +- if (!(uelf->info.shdrs[infosec].sh_flags & SHF_ALLOC)) +- continue; +- +- log_debug("Relocate '%s'\n", name); +- if (uelf->info.shdrs[i].sh_type == SHT_REL) { +- return -EPERM; +- } else if (uelf->info.shdrs[i].sh_type == SHT_RELA) { +- err = apply_relocate_add(uelf, uelf->index.sym, i); +- } +- +- if (err < 0) +- break; +- } +- return err; +-} +\ No newline at end of file ++ unsigned int i; ++ int err = 0; ++ ++ /* Now do relocations. */ ++ for (i = 1; i < uelf->info.hdr->e_shnum; i++) { ++ unsigned int infosec = uelf->info.shdrs[i].sh_info; ++ const char *name = uelf->info.shstrtab + uelf->info.shdrs[i].sh_name; ++ ++ /* Not a valid relocation section? */ ++ if (infosec >= uelf->info.hdr->e_shnum) { ++ continue; ++ } ++ ++ /* Don't bother with non-allocated sections */ ++ if (!(uelf->info.shdrs[infosec].sh_flags & SHF_ALLOC)) { ++ continue; ++ } ++ ++ log_debug("Relocate '%s'\n", name); ++ if (uelf->info.shdrs[i].sh_type == SHT_REL) { ++ return -EPERM; ++ } else if (uelf->info.shdrs[i].sh_type == SHT_RELA) { ++ err = apply_relocate_add(uelf, uelf->index.sym, i); ++ } ++ ++ if (err < 0) { ++ break; ++ } ++ } ++ ++ return err; ++} +diff --git a/upatch-manage/upatch-relocation.h b/upatch-manage/upatch-relocation.h +index bbb1962..804656e 100644 +--- a/upatch-manage/upatch-relocation.h ++++ b/upatch-manage/upatch-relocation.h +@@ -39,4 +39,4 @@ int apply_relocate_add(struct upatch_elf *, unsigned int, unsigned int); + + int apply_relocations(struct upatch_elf *); + +-#endif +\ No newline at end of file ++#endif +diff --git a/upatch-manage/upatch-resolve.c b/upatch-manage/upatch-resolve.c +index 5f1c2de..b564578 100644 +--- a/upatch-manage/upatch-resolve.c ++++ b/upatch-manage/upatch-resolve.c +@@ -53,8 +53,7 @@ static unsigned long resolve_rela_dyn(struct upatch_elf *uelf, + if (rela_dyn[i].r_addend != (long)patch_sym->st_value) { + continue; + } +- } +- else { ++ } else { + char *sym_name = relf->dynstrtab + dynsym[sym_idx].st_name; + char *sym_splitter = NULL; + +@@ -256,30 +255,26 @@ static unsigned long resolve_symbol(struct upatch_elf *uelf, + + /* resolve from plt */ + elf_addr = resolve_rela_plt(uelf, obj, name, &patch_sym); +- +- /* resolve from got */ ++ /* resolve from got */ + if (!elf_addr) { + elf_addr = resolve_rela_dyn(uelf, obj, name, &patch_sym); + } +- +- /* resolve from dynsym */ ++ /* resolve from dynsym */ + if (!elf_addr) { + elf_addr = resolve_dynsym(uelf, obj, name); + } +- +- /* resolve from sym */ ++ /* resolve from sym */ + if (!elf_addr) { + elf_addr = resolve_sym(uelf, name); + } +- +- /* resolve from patch sym */ ++ /* resolve from patch sym */ + if (!elf_addr) { + elf_addr = resolve_patch_sym(uelf, name, &patch_sym); + } +- + if (!elf_addr) { + log_error("Cannot resolve symbol '%s'\n", name); + } ++ + return elf_addr; + } + +@@ -295,40 +290,41 @@ int simplify_symbols(struct upatch_elf *uelf, struct object_file *obj) + const char *name; + + if (GELF_ST_TYPE(sym[i].st_info) == STT_SECTION && +- sym[i].st_shndx < uelf->info.hdr->e_shnum) +- name = uelf->info.shstrtab + uelf->info.shdrs[sym[i].st_shndx].sh_name; +- else ++ sym[i].st_shndx < uelf->info.hdr->e_shnum) { ++ name = uelf->info.shstrtab + ++ uelf->info.shdrs[sym[i].st_shndx].sh_name; ++ } else { + name = uelf->strtab + sym[i].st_name; +- ++ } + switch (sym[i].st_shndx) { +- case SHN_COMMON: +- log_debug("Unsupported common symbol '%s'\n", name); +- ret = -ENOEXEC; +- break; +- case SHN_ABS: +- break; +- case SHN_UNDEF: +- elf_addr = resolve_symbol(uelf, obj, name, sym[i]); +- if (!elf_addr) { ++ case SHN_COMMON: ++ log_debug("Unsupported common symbol '%s'\n", name); + ret = -ENOEXEC; ++ break; ++ case SHN_ABS: ++ break; ++ case SHN_UNDEF: ++ elf_addr = resolve_symbol(uelf, obj, name, sym[i]); ++ if (!elf_addr) { ++ ret = -ENOEXEC; ++ } ++ sym[i].st_value = elf_addr; ++ log_debug("Resolved symbol '%s' at 0x%lx\n", ++ name, (unsigned long)sym[i].st_value); ++ break; ++ case SHN_LIVEPATCH: ++ sym[i].st_value += uelf->relf->load_bias; ++ log_debug("Resolved livepatch symbol '%s' at 0x%lx\n", ++ name, (unsigned long)sym[i].st_value); ++ break; ++ default: ++ /* use real address to calculate secbase */ ++ secbase = uelf->info.shdrs[sym[i].st_shndx].sh_addralign; ++ sym[i].st_value += secbase; ++ log_debug("Symbol '%s' at 0x%lx\n", ++ name, (unsigned long)sym[i].st_value); ++ break; + } +- sym[i].st_value = elf_addr; +- log_debug("Resolved symbol '%s' at 0x%lx\n", +- name, (unsigned long)sym[i].st_value); +- break; +- case SHN_LIVEPATCH: +- sym[i].st_value += uelf->relf->load_bias; +- log_debug("Resolved livepatch symbol '%s' at 0x%lx\n", +- name, (unsigned long)sym[i].st_value); +- break; +- default: +- /* use real address to calculate secbase */ +- secbase = uelf->info.shdrs[sym[i].st_shndx].sh_addralign; +- sym[i].st_value += secbase; +- log_debug("Symbol '%s' at 0x%lx\n", +- name, (unsigned long)sym[i].st_value); +- break; +- } + } + + return ret; +diff --git a/upatch-manage/upatch-resolve.h b/upatch-manage/upatch-resolve.h +index 9b31dce..863bcc5 100644 +--- a/upatch-manage/upatch-resolve.h ++++ b/upatch-manage/upatch-resolve.h +@@ -32,13 +32,13 @@ struct upatch_jmp_table_entry; + unsigned int get_jmp_table_entry(void); + + unsigned long insert_plt_table(struct upatch_elf *, struct object_file *, +- unsigned long, unsigned long); ++ unsigned long, unsigned long); + unsigned long insert_got_table(struct upatch_elf *, struct object_file *, +- unsigned long, unsigned long); ++ unsigned long, unsigned long); + +-unsigned long search_insert_plt_table(struct upatch_elf *, unsigned long, +- unsigned long); ++unsigned long search_insert_plt_table(struct upatch_elf *, ++ unsigned long, unsigned long); + + int simplify_symbols(struct upatch_elf *, struct object_file *); + +-#endif +\ No newline at end of file ++#endif +diff --git a/upatch-manage/upatch-stack-check.c b/upatch-manage/upatch-stack-check.c +index 84c2b0e..8cc4867 100644 +--- a/upatch-manage/upatch-stack-check.c ++++ b/upatch-manage/upatch-stack-check.c +@@ -13,7 +13,8 @@ + + static int stack_check(struct upatch_info *uinfo, unsigned long pc, upatch_action_t action) + { +- unsigned long start, end; ++ unsigned long start; ++ unsigned long end; + + for (size_t i = 0; i < uinfo->changed_func_num; i++) { + struct upatch_func_addr addr = uinfo->funcs[i].addr; +@@ -31,7 +32,7 @@ static int stack_check(struct upatch_info *uinfo, unsigned long pc, upatch_actio + if (pc >= start && pc <= end) { + log_error("Failed to check stack, running function: %s\n", + uinfo->funcs[i].name); +- return -1; ++ return -1; + } + } + return 0; +@@ -46,11 +47,13 @@ static unsigned long *stack_alloc(size_t *size) + log_error("Failed to get system stack size config\n"); + return 0; + } ++ + *size = rl.rlim_cur; + stack = (unsigned long *)malloc(*size); + if (stack == NULL) { + log_error("Failed to malloc stack\n"); + } ++ + return stack; + } + +@@ -80,13 +83,16 @@ static int stack_check_each_pid(struct upatch_process *proc, + if (stack == NULL) { + return -1; + } ++ + stack_size = read_stack(proc, stack, stack_size, sp); + log_debug("[%d]Stack size %lu, region [0x%lx, 0x%lx]\n", + pid, stack_size, sp, sp + stack_size); ++ + for (size_t i = 0; i < stack_size / sizeof(*stack); i++) { + if (stack[i] == 0 || stack[i] == -1UL) { + continue; + } ++ + ret = stack_check(uinfo, stack[i], action); + if (ret < 0) { + goto free; +@@ -97,8 +103,8 @@ free: + return ret; + } + +-int upatch_stack_check(struct upatch_info *uinfo, +- struct upatch_process *proc, upatch_action_t action) ++int upatch_stack_check(struct upatch_info *uinfo, struct upatch_process *proc, ++ upatch_action_t action) + { + struct upatch_ptrace_ctx *pctx; + struct timeval start, end; +@@ -106,14 +112,18 @@ int upatch_stack_check(struct upatch_info *uinfo, + if (gettimeofday(&start, NULL) < 0) { + log_error("Failed to get stack check start time\n"); + } ++ + list_for_each_entry(pctx, &proc->ptrace.pctxs, list) { + if (stack_check_each_pid(proc, uinfo, pctx->pid, action) < 0) { + return -EBUSY; + } + } ++ + if (gettimeofday(&end, NULL) < 0) { + log_error("Failed to get stack check end time\n"); + } +- log_debug("Stack check time %ld microseconds\n", get_microseconds(&start, &end)); ++ ++ log_debug("Stack check time %ld microseconds\n", ++ get_microseconds(&start, &end)); + return 0; +-} +\ No newline at end of file ++} +diff --git a/upatch-manage/upatch-stack-check.h b/upatch-manage/upatch-stack-check.h +index 96b8a51..49be6e3 100644 +--- a/upatch-manage/upatch-stack-check.h ++++ b/upatch-manage/upatch-stack-check.h +@@ -12,6 +12,6 @@ typedef enum { + } upatch_action_t; + + int upatch_arch_reg_init(int pid, unsigned long *sp, unsigned long *pc); +-int upatch_stack_check(struct upatch_info *uinfo, +- struct upatch_process *proc, upatch_action_t action); +-#endif +\ No newline at end of file ++int upatch_stack_check(struct upatch_info *uinfo, struct upatch_process *proc, ++ upatch_action_t action); ++#endif +-- +2.34.1 + diff --git a/0014-upatch-manage-remove-build-id-check.patch b/0014-upatch-manage-remove-build-id-check.patch new file mode 100644 index 0000000..ce549f7 --- /dev/null +++ b/0014-upatch-manage-remove-build-id-check.patch @@ -0,0 +1,88 @@ +From a54cbc3202a1409c040e988043310d4d09d91bc8 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Tue, 18 Feb 2025 15:48:28 +0800 +Subject: [PATCH] upatch-manage: remove build id check + +Signed-off-by: renoseven +--- + upatch-manage/upatch-elf.c | 36 ------------------------------------ + upatch-manage/upatch-elf.h | 2 -- + 2 files changed, 38 deletions(-) + +diff --git a/upatch-manage/upatch-elf.c b/upatch-manage/upatch-elf.c +index 93cb0b2..f3773f9 100644 +--- a/upatch-manage/upatch-elf.c ++++ b/upatch-manage/upatch-elf.c +@@ -49,7 +49,6 @@ static int open_elf(struct elf_info *einfo, const char *name) + { + int ret = 0; + int fd = -1; +- char *sec_name; + struct stat st; + + fd = open(name, O_RDONLY); +@@ -89,21 +88,6 @@ static int open_elf(struct elf_info *einfo, const char *name) + goto out; + } + +- for (unsigned int i = 0; i < einfo->hdr->e_shnum; ++i) { +- sec_name = einfo->shstrtab + einfo->shdrs[i].sh_name; +- if (streql(sec_name, BUILD_ID_NAME) && +- einfo->shdrs[i].sh_type == SHT_NOTE) { +- einfo->num_build_id = i; +- break; +- } +- } +- +- if (einfo->num_build_id == 0) { +- ret = -EINVAL; +- log_error("Cannot find section '%s'\n", BUILD_ID_NAME); +- goto out; +- } +- + ret = 0; + + out: +@@ -220,26 +204,6 @@ int binary_init(struct running_elf *relf, const char *name) + return 0; + } + +-bool check_build_id(struct elf_info *uelf, struct elf_info *relf) +-{ +- GElf_Shdr *uelf_shdr = &uelf->shdrs[uelf->num_build_id]; +- GElf_Shdr *relf_shdr = &relf->shdrs[uelf->num_build_id]; +- +- if (uelf_shdr->sh_size != relf_shdr->sh_size) { +- return false; +- } +- +- void* uelf_build_id = (void *)uelf->hdr + uelf_shdr->sh_offset; +- void* relf_build_id = (void *)relf->hdr + relf_shdr->sh_offset; +- size_t build_id_len = uelf_shdr->sh_size; +- +- if (memcmp(uelf_build_id, relf_build_id, build_id_len) != 0) { +- return false; +- } +- +- return true; +-} +- + void binary_close(struct running_elf *relf) + { + if (relf->info.patch_buff) { +diff --git a/upatch-manage/upatch-elf.h b/upatch-manage/upatch-elf.h +index 18e0d2c..2193f9a 100644 +--- a/upatch-manage/upatch-elf.h ++++ b/upatch-manage/upatch-elf.h +@@ -156,8 +156,6 @@ int binary_init(struct running_elf *, const char *); + void upatch_close(struct upatch_elf *); + void binary_close(struct running_elf *); + +-bool check_build_id(struct elf_info *, struct elf_info *); +- + bool is_upatch_section(const char *); + + bool is_note_section(GElf_Word); +-- +2.34.1 + diff --git a/0015-upatch-diff-print-detail-changes.patch b/0015-upatch-diff-print-detail-changes.patch new file mode 100644 index 0000000..92e76e4 --- /dev/null +++ b/0015-upatch-diff-print-detail-changes.patch @@ -0,0 +1,96 @@ +From b923bc814e0863fe61456fe6a40bd8b2be2be993 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Tue, 18 Feb 2025 16:03:26 +0800 +Subject: [PATCH] upatch-diff: print detail changes + +Signed-off-by: renoseven +--- + upatch-diff/elf-debug.c | 67 ++++++++++++++++++++++++++++++++++++----- + 1 file changed, 59 insertions(+), 8 deletions(-) + +diff --git a/upatch-diff/elf-debug.c b/upatch-diff/elf-debug.c +index 677b8bc..9d2641a 100644 +--- a/upatch-diff/elf-debug.c ++++ b/upatch-diff/elf-debug.c +@@ -33,19 +33,70 @@ + + void upatch_print_changes(struct upatch_elf *uelf) + { +- struct symbol *sym; ++ struct symbol *sym = NULL; ++ struct section *sec = NULL; + ++ log_normal("------------------------------\n"); ++ log_normal("New symbol\n"); ++ log_normal("------------------------------\n"); + list_for_each_entry(sym, &uelf->symbols, list) { +- if (!sym->include || !sym->sec || +- sym->type != STT_FUNC || sym->parent) { +- continue; +- } + if (sym->status == NEW) { +- log_normal("New function: %s\n", sym->name); +- } else if (sym->status == CHANGED) { +- log_normal("Changed function: %s\n", sym->name); ++ log_normal("idx: %04u, name: '%s'\n", sym->index, sym->name); ++ } ++ } ++ log_normal("------------------------------\n"); ++ log_normal("\n"); ++ log_normal("------------------------------\n"); ++ log_normal("New section\n"); ++ log_normal("------------------------------\n"); ++ list_for_each_entry(sec, &uelf->sections, list) { ++ if (sec->status == NEW) { ++ log_normal("idx: %04u, name: '%s'\n", sec->index, sec->name); ++ } ++ } ++ log_normal("------------------------------\n"); ++ log_normal("\n"); ++ log_normal("------------------------------\n"); ++ log_normal("Changed symbol\n"); ++ log_normal("------------------------------\n"); ++ list_for_each_entry(sym, &uelf->symbols, list) { ++ if (sym->status == CHANGED) { ++ log_normal("idx: %04u, name: '%s'\n", sym->index, sym->name); ++ } ++ } ++ log_normal("------------------------------\n"); ++ log_normal("\n"); ++ log_normal("------------------------------\n"); ++ log_normal("Changed section\n"); ++ log_normal("------------------------------\n"); ++ list_for_each_entry(sec, &uelf->sections, list) { ++ if (sec->status == CHANGED) { ++ log_normal("idx: %04u, name: '%s'\n", sec->index, sec->name); ++ } ++ } ++ log_normal("------------------------------\n"); ++ log_normal("\n"); ++ log_normal("------------------------------\n"); ++ log_normal("Included symbol\n"); ++ log_normal("------------------------------\n"); ++ list_for_each_entry(sym, &uelf->symbols, list) { ++ if (sym->include != 0) { ++ log_normal("idx: %04u, name: '%s', status: %s\n", ++ sym->index, sym->name, status_str(sym->status)); ++ } ++ } ++ log_normal("------------------------------\n"); ++ log_normal("\n"); ++ log_normal("------------------------------\n"); ++ log_normal("Included section\n"); ++ log_normal("------------------------------\n"); ++ list_for_each_entry(sec, &uelf->sections, list) { ++ if (sec->include != 0) { ++ log_normal("idx: %04u, name: '%s', status: %s\n", ++ sec->index, sec->name, status_str(sec->status)); + } + } ++ log_normal("------------------------------\n"); + } + + void upatch_dump_kelf(struct upatch_elf *uelf) +-- +2.34.1 + diff --git a/0016-upatch-diff-ignore-useless-sections.patch b/0016-upatch-diff-ignore-useless-sections.patch new file mode 100644 index 0000000..e46b309 --- /dev/null +++ b/0016-upatch-diff-ignore-useless-sections.patch @@ -0,0 +1,82 @@ +From c3df3930682334433437ee58a4e8dce46d956929 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Tue, 18 Feb 2025 17:04:46 +0800 +Subject: [PATCH] upatch-diff: ignore useless sections + +Signed-off-by: renoseven +--- + upatch-diff/create-diff-object.c | 33 ++++++++++++++++---------------- + upatch-diff/elf-common.h | 2 ++ + 2 files changed, 18 insertions(+), 17 deletions(-) + +diff --git a/upatch-diff/create-diff-object.c b/upatch-diff/create-diff-object.c +index 02d43c2..1c14b7a 100644 +--- a/upatch-diff/create-diff-object.c ++++ b/upatch-diff/create-diff-object.c +@@ -680,24 +680,26 @@ static void replace_section_syms(struct upatch_elf *uelf) + + static void mark_ignored_sections(struct upatch_elf *uelf) + { +- /* Ignore any discarded sections */ +- struct section *sec; ++ static const char *const IGNORED_SECTIONS[] = { ++ ".comment", ++ ".discard", ++ ".rela.discard", ++ ".GCC.command.line", ++ }; + +- list_for_each_entry(sec, &uelf->sections, list) { +- if (!strncmp(sec->name, ".discard", strlen(".discard")) || +- !strncmp(sec->name, ".rela.discard", strlen(".rela.discard"))) { +- log_debug("Found discard section '%s'\n", sec->name); +- sec->ignore = 1; ++ for (size_t i = 0; i < ARRAY_SIZE(IGNORED_SECTIONS); i++) { ++ const char *const ignored_name = IGNORED_SECTIONS[i]; ++ const size_t name_len = strlen(ignored_name); ++ ++ struct section *sec = NULL; ++ list_for_each_entry(sec, &uelf->sections, list) { ++ if (strncmp(sec->name, ignored_name, name_len) == 0) { ++ sec->status = SAME; ++ break; ++ } + } + } +- +- /* TODO: handle ignore information from sections or settings */ + } +- +-/* TODO: we do not handle it now */ +-static void mark_ignored_functions_same(void) {} +-static void mark_ignored_sections_same(void) {} +- + /* + * For a local symbol referenced in the rela list of a changing function, + * if it has no section, it will link error in arm. +@@ -1053,9 +1055,6 @@ int main(int argc, char*argv[]) + mark_file_symbols(&uelf_source); + find_debug_symbol(&uelf_source, &relf); + +- mark_ignored_functions_same(); +- mark_ignored_sections_same(); +- + include_standard_elements(&uelf_patched); + + num_changed = include_changed_functions(&uelf_patched); +diff --git a/upatch-diff/elf-common.h b/upatch-diff/elf-common.h +index f5a48da..bc2c1ac 100644 +--- a/upatch-diff/elf-common.h ++++ b/upatch-diff/elf-common.h +@@ -35,6 +35,8 @@ + #include "list.h" + #include "log.h" + ++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) ++ + #define ALLOC_LINK(_new, _list) \ + do { \ + (_new) = calloc(1, sizeof(*(_new))); \ +-- +2.34.1 + diff --git a/0017-upatch-manage-enrich-log-output.patch b/0017-upatch-manage-enrich-log-output.patch new file mode 100644 index 0000000..4772eba --- /dev/null +++ b/0017-upatch-manage-enrich-log-output.patch @@ -0,0 +1,340 @@ +From 425450509c8903d86b6f0c17acdbd52cb46c99fe Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Tue, 18 Feb 2025 17:50:34 +0800 +Subject: [PATCH] upatch-manage: enrich log output + +Signed-off-by: renoseven +--- + upatch-manage/arch/aarch64/insn.c | 7 +- + upatch-manage/arch/aarch64/relocation.c | 6 +- + upatch-manage/upatch-patch.c | 115 +++++++++++++----------- + upatch-manage/upatch-relocation.c | 3 +- + upatch-manage/upatch-stack-check.c | 2 +- + 5 files changed, 69 insertions(+), 64 deletions(-) + +diff --git a/upatch-manage/arch/aarch64/insn.c b/upatch-manage/arch/aarch64/insn.c +index 63f6227..9a775a5 100644 +--- a/upatch-manage/arch/aarch64/insn.c ++++ b/upatch-manage/arch/aarch64/insn.c +@@ -114,7 +114,7 @@ s64 extract_insn_imm(s64 sval, int len, int lsb) + imm_mask = (s64)((BIT(lsb + len) - 1) >> lsb); + imm = imm & imm_mask; + +- log_debug("upatch: extract imm, X=0x%lx, X[%d:%d]=0x%lx\n", ++ log_debug("imm: insn=0x%lx, insn[%d:%d]=0x%lx\n", + sval, (len + lsb - 1), lsb, imm); + return imm; + } +@@ -124,8 +124,7 @@ s32 insert_insn_imm(enum aarch64_insn_imm_type imm_type, void *place, u64 imm) + u32 insn = le32_to_cpu(*(__le32 *)place); + u32 new_insn = aarch64_insn_encode_immediate(imm_type, insn, imm); + +- log_debug("upatch: inset imm" +- "P=0x%lx, insn=0x%x, imm_type=%d, imm=0x%lx, new_insn=0x%x\n", +- (u64)place, insn, imm_type, imm, new_insn); ++ log_debug("insn: insn=0x%x, imm_type=%d, imm=0x%lx, new_insn=0x%x\n", ++ insn, imm_type, imm, new_insn); + return (s32)new_insn; + } +diff --git a/upatch-manage/arch/aarch64/relocation.c b/upatch-manage/arch/aarch64/relocation.c +index 57e864c..50bfc4b 100644 +--- a/upatch-manage/arch/aarch64/relocation.c ++++ b/upatch-manage/arch/aarch64/relocation.c +@@ -54,8 +54,7 @@ static inline s64 calc_reloc(enum aarch64_reloc_op op, void *place, u64 val) + break; + } + +- log_debug("upatch: reloc, S+A=0x%lx, P=0x%lx, X=0x%lx\n", +- val, (u64)place, sval); ++ log_debug("reloc: S+A=0x%lx, P=0x%lx, X=0x%lx\n", val, (u64)place, sval); + return sval; + } + +@@ -92,7 +91,7 @@ int apply_relocate_add(struct upatch_elf *uelf, unsigned int symindex, + /* val corresponds to (S + A) */ + val = (unsigned long)sym->st_value + (unsigned long)rel[i].r_addend; + log_debug( +- "upatch: reloc symbol, name=%s, k_addr=0x%lx, u_addr=0x%lx, " ++ "\nsymbol='%s', k_addr=0x%lx, u_addr=0x%lx, " + "r_offset=0x%lx, st_value=0x%lx, r_addend=0x%lx\n", + sym_name, shdrs[shdrs[relsec].sh_info].sh_addr, + shdrs[shdrs[relsec].sh_info].sh_addralign, +@@ -155,7 +154,6 @@ int apply_relocate_add(struct upatch_elf *uelf, unsigned int symindex, + if (result < -(s64)BIT(20) || result >= (s64)BIT(20)) { + goto overflow; + } +- + result = extract_insn_imm(result, 21, 0); + result = insert_insn_imm(AARCH64_INSN_IMM_ADR, loc, + (unsigned long)result); +diff --git a/upatch-manage/upatch-patch.c b/upatch-manage/upatch-patch.c +index 819b966..fab65fd 100644 +--- a/upatch-manage/upatch-patch.c ++++ b/upatch-manage/upatch-patch.c +@@ -259,27 +259,35 @@ static void layout_symtab(struct upatch_elf *uelf) + log_debug("\t%s\n", uelf->info.shstrtab + strsect->sh_name); + } + +-static void *upatch_alloc(struct object_file *obj, size_t sz) ++static void *upatch_alloc(struct object_file *obj, size_t size) + { + struct vm_hole *hole = NULL; + +- unsigned long addr = object_find_patch_region(obj, sz, &hole); +- if (!addr) { ++ uintptr_t addr = object_find_patch_region(obj, size, &hole); ++ if (addr == 0) { ++ log_error("Failed to find patch region\n"); ++ return NULL; ++ } ++ ++ struct upatch_ptrace_ctx *pctx = proc2pctx(obj->proc); ++ if (pctx == NULL) { ++ log_error("Failed to find process context\n"); + return NULL; + } + +- addr = upatch_mmap_remote(proc2pctx(obj->proc), addr, sz, ++ addr = upatch_mmap_remote(pctx, addr, size, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, + (unsigned long)-1, 0); + if (addr == 0) { ++ log_error("Mmap failed, pctx=0x%lx, addr=0x%lx, size=0x%lu, ret=%d\n", ++ (uintptr_t)pctx, addr, size, errno); + return NULL; + } ++ log_debug("%s: Mmap addr=0x%lx, size=0x%lx\n", obj->name, addr, size); + +- log_debug("Allocated 0x%lx bytes at 0x%lx of '%s'\n", sz, addr, obj->name); +- int ret = vm_hole_split(hole, addr, addr + sz); +- if (ret) { +- // TODO: clear ++ int ret = vm_hole_split(hole, addr, addr + size); ++ if (ret != 0) { + log_error("Failed to split vm hole\n"); + return NULL; + } +@@ -295,33 +303,23 @@ static void upatch_free(struct object_file *obj, void *base, unsigned long size) + } + } + +-static int __alloc_memory(struct object_file *obj_file, +- struct upatch_layout *layout) ++static int alloc_memory(struct upatch_elf *uelf, struct object_file *obj) + { +- /* Do the allocs. */ +- layout->base = upatch_alloc(obj_file, layout->size); +- if (!layout->base) { +- return -errno; ++ struct upatch_layout *layout = &uelf->core_layout; ++ ++ layout->base = upatch_alloc(obj, layout->size); ++ if (layout->base == NULL) { ++ log_error("Failed to alloc patch memory\n"); ++ return errno; + } + +- layout->kbase = malloc(layout->size); ++ layout->kbase = calloc(1, layout->size); + if (!layout->kbase) { +- upatch_free(obj_file, layout->base, layout->size); ++ log_error("Failed to alloc memory\n"); ++ upatch_free(obj, layout->base, layout->size); + return -errno; + } + +- memset(layout->kbase, 0, layout->size); +- +- return 0; +-} +- +-static int alloc_memory(struct upatch_elf *uelf, struct object_file *obj) +-{ +- int ret = __alloc_memory(obj, &uelf->core_layout); +- if (ret) { +- return ret; +- } +- + /* Transfer each section which specifies SHF_ALLOC */ + log_debug("Final section addresses:\n"); + for (int i = 0; i < uelf->info.hdr->e_shnum; i++) { +@@ -331,17 +329,17 @@ static int alloc_memory(struct upatch_elf *uelf, struct object_file *obj) + continue; + } + +- void *kdest = uelf->core_layout.kbase + shdr->sh_entsize; +- void *dest = uelf->core_layout.base + shdr->sh_entsize; ++ void *dest = layout->base + shdr->sh_entsize; ++ void *kdest = layout->kbase + shdr->sh_entsize; + if (shdr->sh_type != SHT_NOBITS) { + memcpy(kdest, (void *)shdr->sh_addr, shdr->sh_size); + } + +- shdr->sh_addr = (unsigned long)kdest; ++ shdr->sh_addr = (uintptr_t)kdest; + /* overuse this attr to record user address */ +- shdr->sh_addralign = (unsigned long)dest; +- log_debug("\t0x%lx %s <- 0x%lx\n", (long)kdest, +- uelf->info.shstrtab + shdr->sh_name, (long)dest); ++ shdr->sh_addralign = (uintptr_t)dest; ++ log_debug("\t0x%lx %s <- 0x%lx\n", (uintptr_t)kdest, ++ uelf->info.shstrtab + shdr->sh_name, (uintptr_t)dest); + } + + return 0; +@@ -349,16 +347,15 @@ static int alloc_memory(struct upatch_elf *uelf, struct object_file *obj) + + static int post_memory(struct upatch_elf *uelf, struct object_file *obj) + { +- log_debug("Post kbase %lx(%lx) to base %lx\n", +- (unsigned long)uelf->core_layout.kbase, +- uelf->core_layout.size, +- (unsigned long)uelf->core_layout.base); ++ log_debug("Post memory 0x%lx to 0x%lx, len=0x%lx\n", ++ (uintptr_t)uelf->core_layout.kbase, (uintptr_t)uelf->core_layout.base, ++ uelf->core_layout.size); + + int ret = upatch_process_mem_write(obj->proc, + uelf->core_layout.kbase, (unsigned long)uelf->core_layout.base, + uelf->core_layout.size); + if (ret) { +- log_error("Failed to move kbase to base, ret=%d\n", ret); ++ log_error("Failed to write process memory, ret=%d\n", ret); + } + + return ret; +@@ -436,8 +433,8 @@ static struct object_file *upatch_find_obj(struct upatch_elf *uelf, + uelf->relf->info.inode, proc->pid); + return NULL; + } +-static int complete_info(struct upatch_elf *uelf, +- struct object_file *obj, const char *uuid) ++static int complete_info(struct upatch_elf *uelf, struct object_file *obj, ++ const char *uuid) + { + int ret = 0; + +@@ -460,11 +457,20 @@ static int complete_info(struct upatch_elf *uelf, + + uinfo->func_names = (void *)uinfo + sizeof(*uinfo); + uinfo->func_names_size = upatch_string->sh_size; ++ uinfo->funcs = (void *)uinfo->func_names + uinfo->func_names_size; ++ + memcpy(uinfo->func_names, (void *)upatch_string->sh_addr, + upatch_string->sh_size); + +- log_debug("Changed insn:\n"); +- uinfo->funcs = (void *)uinfo->func_names + uinfo->func_names_size; ++ unsigned long offset = 0; ++ for (unsigned long i = 0; i < uinfo->changed_func_num; ++i) { ++ char *name = (char *)uinfo->func_names + offset; ++ ++ uinfo->funcs[i].name = name; ++ offset += strlen(name) + 1; ++ } ++ ++ log_debug("Changed function:\n"); + for (unsigned int i = 0; i < uinfo->changed_func_num; ++i) { + struct upatch_info_func *upatch_func = &uinfo->funcs[i]; + +@@ -479,10 +485,10 @@ static int complete_info(struct upatch_elf *uelf, + } + + upatch_func->new_insn = get_new_insn(); +- log_debug("\t0x%lx(0x%lx 0x%lx -> 0x%lx 0x%lx)\n", +- upatch_func->addr.old_addr, +- upatch_func->old_insn[0], upatch_func->old_insn[1], +- upatch_func->new_insn, upatch_func->addr.new_addr); ++ log_debug("\taddr: 0x%lx -> 0x%lx, insn: 0x%lx -> 0x%lx, name: '%s'\n", ++ upatch_func->addr.old_addr, upatch_func->addr.new_addr, ++ upatch_func->old_insn[0], upatch_func->new_insn, ++ upatch_func->name); + } + + out: +@@ -492,11 +498,14 @@ out: + static int unapply_patch(struct object_file *obj, + struct upatch_info_func *funcs, unsigned long changed_func_num) + { +- log_debug("Changed insn:\n"); ++ log_debug("Changed function:\n"); + for (unsigned int i = 0; i < changed_func_num; ++i) { +- log_debug("\t0x%lx(0x%lx -> 0x%lx)\n", funcs[i].addr.old_addr, +- funcs[i].new_insn, funcs[i].old_insn[0]); ++ struct upatch_info_func *upatch_func = &funcs[i]; + ++ log_debug("\taddr: 0x%lx -> 0x%lx, insn: 0x%lx -> 0x%lx, name: '%s'\n", ++ upatch_func->addr.new_addr, upatch_func->addr.old_addr, ++ upatch_func->new_insn, upatch_func->old_insn[0], ++ upatch_func->name); + int ret = upatch_process_mem_write(obj->proc, &funcs[i].old_insn, + (unsigned long)funcs[i].addr.old_addr, get_origin_insn_len()); + if (ret) { +@@ -645,13 +654,11 @@ static int upatch_apply_patches(struct object_file *obj, + */ + ret = alloc_memory(uelf, obj); + if (ret) { +- log_error("Failed to alloc patch memory\n"); + goto free; + } + + ret = upatch_mprotect(uelf, obj); + if (ret) { +- log_error("Failed to set patch memory permission\n"); + goto free; + } + +@@ -782,7 +789,7 @@ int process_patch(int pid, struct upatch_elf *uelf, struct running_elf *relf, + goto out; + } + +- printf("Patch '%s' to ", uuid); ++ log_debug("Patch '%s' to ", uuid); + upatch_process_print_short(&proc); + + ret = upatch_process_mem_open(&proc, MEM_READ); +@@ -895,7 +902,7 @@ int process_unpatch(int pid, const char *uuid) + goto out; + } + +- printf("Unpatch '%s' from ", uuid); ++ log_debug("Unpatch '%s' from ", uuid); + upatch_process_print_short(&proc); + + ret = upatch_process_mem_open(&proc, MEM_READ); +diff --git a/upatch-manage/upatch-relocation.c b/upatch-manage/upatch-relocation.c +index 57db9ba..e9b79dd 100644 +--- a/upatch-manage/upatch-relocation.c ++++ b/upatch-manage/upatch-relocation.c +@@ -43,12 +43,13 @@ int apply_relocations(struct upatch_elf *uelf) + continue; + } + +- log_debug("Relocate '%s'\n", name); ++ log_debug("Relocate section '%s':\n", name); + if (uelf->info.shdrs[i].sh_type == SHT_REL) { + return -EPERM; + } else if (uelf->info.shdrs[i].sh_type == SHT_RELA) { + err = apply_relocate_add(uelf, uelf->index.sym, i); + } ++ log_debug("\n"); + + if (err < 0) { + break; +diff --git a/upatch-manage/upatch-stack-check.c b/upatch-manage/upatch-stack-check.c +index 8cc4867..474d857 100644 +--- a/upatch-manage/upatch-stack-check.c ++++ b/upatch-manage/upatch-stack-check.c +@@ -85,7 +85,7 @@ static int stack_check_each_pid(struct upatch_process *proc, + } + + stack_size = read_stack(proc, stack, stack_size, sp); +- log_debug("[%d]Stack size %lu, region [0x%lx, 0x%lx]\n", ++ log_debug("[%d] Stack size %lu, region [0x%lx, 0x%lx]\n", + pid, stack_size, sp, sp + stack_size); + + for (size_t i = 0; i < stack_size / sizeof(*stack); i++) { +-- +2.34.1 + diff --git a/0018-project-change-build-options.patch b/0018-project-change-build-options.patch new file mode 100644 index 0000000..f186c2a --- /dev/null +++ b/0018-project-change-build-options.patch @@ -0,0 +1,58 @@ +From 553e54f017d502da712c8d0e04bf8b40d634beac Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Sat, 22 Feb 2025 17:38:12 +0800 +Subject: [PATCH] project: change build options + +Signed-off-by: renoseven +--- + CMakeLists.txt | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index ff219b9..37da26d 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -53,14 +53,14 @@ endif() + + # Build flags + list(APPEND PROJECT_C_BUILD_FLAGS +- -std=gnu99 -g -Wall -O2 -Werror -Wextra ++ -std=gnu99 -Wall -O2 -Werror -Wextra + -DBUILD_VERSION="${PROJECT_BUILD_VERSION}" -D_FORTIFY_SOURCE=2 + -Wtrampolines -Wformat=2 -Wstrict-prototypes -Wdate-time + -Wstack-usage=8192 -Wfloat-equal -Wswitch-default + -Wshadow -Wconversion -Wcast-qual -Wcast-align -Wunused -Wundef + -funsigned-char -fstack-protector-all -fpic -fpie -ftrapv + -fstack-check -freg-struct-return -fno-canonical-system-headers +- -pipe -fdebug-prefix-map=old=new ++ -fno-common -pipe -fdebug-prefix-map=old=new + ) + list(APPEND PROJECT_RUST_FLAGS + --cfg unsound_local_offset +@@ -80,6 +80,13 @@ list(APPEND PROJECT_C_LINK_FLAGS + -Wl,-no-undefined + ) + ++if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") ++ list(APPEND PROJECT_C_BUILD_FLAGS -g) ++endif() ++if(CMAKE_BUILD_TYPE STREQUAL "Release") ++ list(APPEND PROJECT_C_LINK_FLAGS -s) ++endif() ++ + # Install directories + set(SYSCARE_BINARY_DIR "${CMAKE_INSTALL_FULL_BINDIR}") + set(SYSCARE_LIBEXEC_DIR "${CMAKE_INSTALL_FULL_LIBEXECDIR}/syscare") +@@ -94,7 +101,8 @@ message("╚════██║ ╚██╔╝ ╚════██║█ + message("███████║ ██║ ███████║╚██████╗██║ ██║██║ ██║███████╗") + message("╚══════╝ ╚═╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝") + message("---------------------------------------------------------") +-message("-- Verion: ${PROJECT_BUILD_VERSION}") ++message("-- Build type: ${CMAKE_BUILD_TYPE}") ++message("-- Build Verion: ${PROJECT_BUILD_VERSION}") + message("-- Rust flags: ${PROJECT_RUST_FLAGS}") + message("-- Build flags: ${PROJECT_C_BUILD_FLAGS}") + message("-- Link flags: ${PROJECT_C_LINK_FLAGS}") +-- +2.34.1 + diff --git a/0019-upatch-manage-increase-jump-table-size-to-4096.patch b/0019-upatch-manage-increase-jump-table-size-to-4096.patch new file mode 100644 index 0000000..125e684 --- /dev/null +++ b/0019-upatch-manage-increase-jump-table-size-to-4096.patch @@ -0,0 +1,26 @@ +From c9b05a6f5cb8d55c6836a310542e133a0c0d1fb2 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Fri, 21 Feb 2025 14:37:37 +0800 +Subject: [PATCH] upatch-manage: increase jump table size to 4096 + +Signed-off-by: renoseven +--- + upatch-manage/upatch-elf.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/upatch-manage/upatch-elf.h b/upatch-manage/upatch-elf.h +index 2193f9a..6f62c7d 100644 +--- a/upatch-manage/upatch-elf.h ++++ b/upatch-manage/upatch-elf.h +@@ -39,7 +39,7 @@ + #define TDATA_NAME ".tdata" + #define TBSS_NAME ".tbss" + +-#define JMP_TABLE_MAX_ENTRY 100 ++#define JMP_TABLE_MAX_ENTRY 4096 + #define UPATCH_HEADER "UPATCH" + #define UPATCH_HEADER_LEN 6 + #define UPATCH_ID_LEN 40 +-- +2.34.1 + diff --git a/0020-upatch-manage-fix-failed-to-attach-non-exist-process.patch b/0020-upatch-manage-fix-failed-to-attach-non-exist-process.patch new file mode 100644 index 0000000..2af16d8 --- /dev/null +++ b/0020-upatch-manage-fix-failed-to-attach-non-exist-process.patch @@ -0,0 +1,67 @@ +From 18a08f1f324974535bb00c7eed79f36fe5b8a4b7 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Fri, 21 Feb 2025 16:29:44 +0800 +Subject: [PATCH] upatch-manage: fix 'failed to attach non-exist process' issue + +Signed-off-by: renoseven +--- + upatch-manage/upatch-process.c | 2 +- + upatch-manage/upatch-ptrace.c | 8 ++++---- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/upatch-manage/upatch-process.c b/upatch-manage/upatch-process.c +index 924a9c4..118b71d 100644 +--- a/upatch-manage/upatch-process.c ++++ b/upatch-manage/upatch-process.c +@@ -736,7 +736,7 @@ int upatch_process_attach(struct upatch_process *proc) + int pid = pids[i]; + + ret = upatch_ptrace_attach_thread(proc, pid); +- if (ret < 0) { ++ if ((ret != 0) && (ret != ESRCH)) { + goto detach; + } + } +diff --git a/upatch-manage/upatch-ptrace.c b/upatch-manage/upatch-ptrace.c +index 2d0845c..ab21891 100644 +--- a/upatch-manage/upatch-ptrace.c ++++ b/upatch-manage/upatch-ptrace.c +@@ -117,7 +117,7 @@ int upatch_ptrace_attach_thread(struct upatch_process *proc, int tid) + struct upatch_ptrace_ctx *pctx = upatch_ptrace_ctx_alloc(proc); + if (pctx == NULL) { + log_error("Failed to alloc ptrace context"); +- return -1; ++ return ENOMEM; + } + + pctx->pid = tid; +@@ -126,7 +126,7 @@ int upatch_ptrace_attach_thread(struct upatch_process *proc, int tid) + long ret = ptrace(PTRACE_ATTACH, tid, NULL, NULL); + if (ret < 0) { + log_error("Failed to attach thread, pid=%d, ret=%ld\n", tid, ret); +- return -1; ++ return errno; + } + + do { +@@ -135,7 +135,7 @@ int upatch_ptrace_attach_thread(struct upatch_process *proc, int tid) + ret = waitpid(tid, &status, __WALL); + if (ret < 0) { + log_error("Failed to wait thread, tid=%d, ret=%ld\n", tid, ret); +- return -1; ++ return errno; + } + + /* We are expecting SIGSTOP */ +@@ -156,7 +156,7 @@ int upatch_ptrace_attach_thread(struct upatch_process *proc, int tid) + ret = ptrace(PTRACE_CONT, tid, NULL, (void *)(uintptr_t)status); + if (ret < 0) { + log_error("Failed to continue thread, tid=%d, ret=%ld\n", tid, ret); +- return -1; ++ return errno; + } + } while (1); + +-- +2.34.1 + diff --git a/0021-upatch-manage-fix-failed-to-alloc-patch-memory-issue.patch b/0021-upatch-manage-fix-failed-to-alloc-patch-memory-issue.patch new file mode 100644 index 0000000..734871e --- /dev/null +++ b/0021-upatch-manage-fix-failed-to-alloc-patch-memory-issue.patch @@ -0,0 +1,526 @@ +From b41af7298a34f3f53d611f54aa1f93d1a8bc3e99 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Fri, 21 Feb 2025 15:15:31 +0800 +Subject: [PATCH] upatch-manage: fix 'failed to alloc patch memory' issue + +Signed-off-by: renoseven +--- + upatch-manage/upatch-patch.c | 34 ++--- + upatch-manage/upatch-process.c | 245 ++++++++++++++++----------------- + upatch-manage/upatch-process.h | 10 +- + 3 files changed, 137 insertions(+), 152 deletions(-) + +diff --git a/upatch-manage/upatch-patch.c b/upatch-manage/upatch-patch.c +index fab65fd..4a1e568 100644 +--- a/upatch-manage/upatch-patch.c ++++ b/upatch-manage/upatch-patch.c +@@ -259,36 +259,36 @@ static void layout_symtab(struct upatch_elf *uelf) + log_debug("\t%s\n", uelf->info.shstrtab + strsect->sh_name); + } + +-static void *upatch_alloc(struct object_file *obj, size_t size) ++static void *upatch_alloc(struct object_file *obj, size_t len) + { +- struct vm_hole *hole = NULL; +- +- uintptr_t addr = object_find_patch_region(obj, size, &hole); +- if (addr == 0) { +- log_error("Failed to find patch region\n"); +- return NULL; +- } +- + struct upatch_ptrace_ctx *pctx = proc2pctx(obj->proc); + if (pctx == NULL) { + log_error("Failed to find process context\n"); + return NULL; + } + +- addr = upatch_mmap_remote(pctx, addr, size, ++ log_debug("Finding patch region for '%s', len=0x%lx\n", obj->name, len); ++ struct vm_hole *hole = find_patch_region(obj, len); ++ if (hole == NULL) { ++ log_error("Failed to find patch region for '%s'\n", obj->name); ++ return NULL; ++ } ++ ++ uintptr_t addr = PAGE_ALIGN(hole->start); ++ log_debug("Found patch region at 0x%lx, size=0x%lx\n", addr, len); ++ ++ addr = upatch_mmap_remote(pctx, addr, len, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, + (unsigned long)-1, 0); + if (addr == 0) { +- log_error("Mmap failed, pctx=0x%lx, addr=0x%lx, size=0x%lu, ret=%d\n", +- (uintptr_t)pctx, addr, size, errno); ++ log_error("Failed to map patch region, ret=%d\n", errno); + return NULL; + } +- log_debug("%s: Mmap addr=0x%lx, size=0x%lx\n", obj->name, addr, size); + +- int ret = vm_hole_split(hole, addr, addr + size); ++ int ret = vm_hole_split(hole, addr, (addr + len)); + if (ret != 0) { +- log_error("Failed to split vm hole\n"); ++ log_error("Failed to split vm hole, ret=%d\n", ret); + return NULL; + } + +@@ -310,14 +310,14 @@ static int alloc_memory(struct upatch_elf *uelf, struct object_file *obj) + layout->base = upatch_alloc(obj, layout->size); + if (layout->base == NULL) { + log_error("Failed to alloc patch memory\n"); +- return errno; ++ return ENOMEM; + } + + layout->kbase = calloc(1, layout->size); + if (!layout->kbase) { + log_error("Failed to alloc memory\n"); + upatch_free(obj, layout->base, layout->size); +- return -errno; ++ return ENOMEM; + } + + /* Transfer each section which specifies SHF_ALLOC */ +diff --git a/upatch-manage/upatch-process.c b/upatch-manage/upatch-process.c +index 118b71d..123ecfe 100644 +--- a/upatch-manage/upatch-process.c ++++ b/upatch-manage/upatch-process.c +@@ -127,7 +127,7 @@ int upatch_process_init(struct upatch_process *proc, int pid) + + INIT_LIST_HEAD(&proc->ptrace.pctxs); + INIT_LIST_HEAD(&proc->objs); +- INIT_LIST_HEAD(&proc->vmaholes); ++ INIT_LIST_HEAD(&proc->vma_holes); + proc->num_objs = 0; + + if (upatch_coroutines_init(proc)) { +@@ -185,7 +185,7 @@ static void upatch_process_memfree(struct upatch_process *proc) + free(p); + } + +- list_for_each_entry_safe(hole, hole_safe, &proc->vmaholes, list) { ++ list_for_each_entry_safe(hole, hole_safe, &proc->vma_holes, list) { + free(hole); + } + +@@ -285,21 +285,19 @@ static unsigned int perms2prot(const char *perms) + } + + static struct vm_hole *process_add_vm_hole(struct upatch_process *proc, +- unsigned long hole_start, unsigned long hole_end) ++ unsigned long start, unsigned long end) + { +- struct vm_hole *hole; +- +- hole = malloc(sizeof(*hole)); ++ struct vm_hole *hole = malloc(sizeof(*hole)); + if (hole == NULL) { + return NULL; + } + +- memset(hole, 0, sizeof(*hole)); +- hole->start = hole_start; +- hole->end = hole_end; +- +- list_add(&hole->list, &proc->vmaholes); ++ hole->start = start; ++ hole->end = end; ++ hole->len = end - start; ++ list_init(&hole->list); + ++ list_add(&hole->list, &proc->vma_holes); + return hole; + } + +@@ -339,8 +337,8 @@ static int object_add_vm_area(struct object_file *o, struct vm_area *vma, + { + struct obj_vm_area *ovma; + +- if (o->previous_hole == NULL) { +- o->previous_hole = hole; ++ if (o->prev_hole == NULL) { ++ o->prev_hole = hole; + } + + list_for_each_entry(ovma, &o->vma, list) { +@@ -385,7 +383,7 @@ static struct object_file *process_new_object(struct upatch_process *proc, + o->inode = inode; + o->is_patch = 0; + +- o->previous_hole = hole; ++ o->prev_hole = hole; + if (object_add_vm_area(o, vma, hole) < 0) { + log_error("Cannot add vm area for %s\n", name); + free(o); +@@ -488,7 +486,7 @@ static int add_upatch_object(struct upatch_process *proc, struct object_file *o, + /** + * Returns: 0 if everything is ok, -1 on error. + */ +-static int process_add_object_vma(struct upatch_process *proc, ++static int process_add_vma(struct upatch_process *proc, + dev_t dev, ino_t inode, char *name, + struct vm_area *vma, struct vm_hole *hole) + { +@@ -532,13 +530,9 @@ static int process_add_object_vma(struct upatch_process *proc, + return 0; + } + +-int upatch_process_parse_proc_maps(struct upatch_process *proc) ++int upatch_process_map_object_files(struct upatch_process *proc) + { +- FILE *f; +- int ret; +- int is_libc_base_set = 0; +- unsigned long hole_start = 0; +- struct vm_hole *hole = NULL; ++ int ret = 0; + + /* + * 1. Create the list of all objects in the process +@@ -554,78 +548,81 @@ int upatch_process_parse_proc_maps(struct upatch_process *proc) + } + + lseek(fd, 0, SEEK_SET); +- f = fdopen(fd, "r"); +- if (f == NULL) { ++ FILE *file = fdopen(fd, "r"); ++ if (file == NULL) { + log_error("unable to fdopen %d", fd); + close(fd); + return -1; + } + +- do { ++ unsigned long hole_start = 0; ++ ++ char line[1024]; ++ while (fgets(line, sizeof(line), file) != NULL) { + struct vm_area vma; +- char line[1024]; +- unsigned long start; +- unsigned long end; ++ unsigned long vma_start; ++ unsigned long vma_end; + unsigned long offset; + unsigned int maj; + unsigned int min; + unsigned int inode; + char perms[5]; +- char name_[256]; +- char *name = name_; +- int r; +- +- if (!fgets(line, sizeof(line), f)) { +- break; +- } ++ char name_buf[256]; ++ char *name = name_buf; + +- r = sscanf(line, "%lx-%lx %s %lx %x:%x %d %255s", +- &start, &end, perms, &offset, &maj, &min, &inode, name_); +- if (r == EOF) { ++ ret = sscanf(line, "%lx-%lx %s %lx %x:%x %u %255s", ++ &vma_start, &vma_end, perms, &offset, ++ &maj, &min, &inode, name_buf); ++ if (ret == EOF) { + log_error("Failed to read maps: unexpected EOF"); + goto error; + } +- if (r != 8) { +- strcpy(name, "[anonymous]"); ++ if (ret != 8) { ++ name = "[anonymous]"; + } + +- vma.start = start; +- vma.end = end; ++ vma.start = vma_start; ++ vma.end = vma_end; + vma.offset = offset; + vma.prot = perms2prot(perms); + + /* Hole must be at least 2 pages for guardians */ +- if (start - hole_start > (unsigned long)(2 * PAGE_SIZE)) { +- hole = process_add_vm_hole(proc, hole_start + (unsigned long)PAGE_SIZE, +- start - (unsigned long)PAGE_SIZE); ++ struct vm_hole *hole = NULL; ++ if ((hole_start != 0) && ++ (vma_start - hole_start > 2 * (uintptr_t)PAGE_SIZE)) { ++ uintptr_t start = hole_start + (uintptr_t)PAGE_SIZE; ++ uintptr_t end = vma_start - (uintptr_t)PAGE_SIZE; ++ ++ hole = process_add_vm_hole(proc, start, end); + if (hole == NULL) { + log_error("Failed to add vma hole"); + goto error; + } ++ log_debug("vm_hole: start=0x%lx, end=0x%lx, len=0x%lx\n", ++ hole->start, hole->end, hole->len); + } +- hole_start = end; +- name = name[0] == '/' ? basename(name) : name; ++ hole_start = vma_end; + +- ret = process_add_object_vma(proc, makedev(maj, min), inode, +- name, &vma, hole); ++ name = name[0] == '/' ? basename(name) : name; ++ ret = process_add_vma(proc, makedev(maj, min), inode, name, &vma, hole); + if (ret < 0) { + log_error("Failed to add object vma"); + goto error; + } + +- if (!is_libc_base_set && !strncmp(basename(name), "libc", 4) && +- (vma.prot & PROT_EXEC)) { +- proc->libc_base = start; +- is_libc_base_set = 1; ++ if ((proc->libc_base == 0) && ++ (vma.prot & PROT_EXEC) && ++ !strncmp(basename(name), "libc", 4)) { ++ proc->libc_base = vma_start; + } +- } while (1); ++ } + +- fclose(f); +- close(fd); ++ (void)fclose(file); ++ (void)close(fd); + log_debug("Found %d object file(s)\n", proc->num_objs); + +- if (!is_libc_base_set) { +- log_error("Can't find libc_base required for manipulations: %d", ++ if (proc->libc_base == 0) { ++ log_error("Cannot find libc_base, pid=%d", + proc->pid); + return -1; + } +@@ -633,18 +630,11 @@ int upatch_process_parse_proc_maps(struct upatch_process *proc) + return 0; + + error: +- fclose(f); +- close(fd); ++ (void)fclose(file); ++ (void)close(fd); + return -1; + } + +-int upatch_process_map_object_files(struct upatch_process *proc) +-{ +- // we can get plt/got table from mem's elf_segments +- // Now we read them from the running file +- return upatch_process_parse_proc_maps(proc); +-} +- + static int process_list_threads(struct upatch_process *proc, int **ppids, + size_t *npids, size_t *alloc) + { +@@ -824,48 +814,65 @@ static inline struct vm_hole *prev_hole(struct vm_hole *hole, + return list_entry(hole->list.prev, struct vm_hole, list); + } + +-static inline unsigned long hole_size(struct vm_hole *hole) +-{ +- if (hole == NULL) { +- return 0; +- } +- +- return hole->end - hole->start; +-} +- +-int vm_hole_split(struct vm_hole *hole, +- unsigned long alloc_start, unsigned long alloc_end) ++int vm_hole_split(struct vm_hole *hole, uintptr_t start, uintptr_t end) + { +- unsigned long page_size = (unsigned long)PAGE_SIZE; +- +- alloc_start = ROUND_DOWN(alloc_start, page_size) - page_size; +- alloc_end = ROUND_UP(alloc_end, page_size) + page_size; ++ uintptr_t new_start = ROUND_DOWN(start, PAGE_SIZE) - PAGE_SIZE; ++ uintptr_t new_end = ROUND_UP(end, PAGE_SIZE) + PAGE_SIZE; + +- if (alloc_start > hole->start) { ++ if (new_start > hole->start) { + struct vm_hole *left = NULL; + + left = malloc(sizeof(*hole)); + if (left == NULL) { + log_error("Failed to malloc for vm hole"); +- return -1; ++ return ENOMEM; + } + + left->start = hole->start; +- left->end = alloc_start; ++ left->end = new_start; + + list_add(&left->list, &hole->list); + } + + /* Reuse hole pointer as the right hole since it is pointed to by +- * the `previous_hole` of some `object_file`. */ +- hole->start = alloc_end; +- hole->end = hole->end > alloc_end ? hole->end : alloc_end; ++ * the `prev_hole` of some `object_file`. */ ++ hole->start = new_end; ++ hole->end = hole->end > new_end ? hole->end : new_end; + + return 0; + } + ++static bool is_vm_hole_suitable(struct obj_vm_area *vma, ++ struct vm_hole *hole, size_t len) ++{ ++ uintptr_t vma_start = vma->inmem.start; ++ uintptr_t vma_end = vma->inmem.end; ++ uintptr_t hole_start = PAGE_ALIGN(hole->start); ++ uintptr_t hole_end = PAGE_ALIGN(hole->start + len); ++ ++ log_debug("vma_start=0x%lx, vma_end=0x%lx, " ++ "hole_start=0x%lx, hole_end=0x%lx, hole_len=0x%lx\n", ++ vma_start, vma_end, hole->start, hole->end, hole->len); ++ if (hole->len < len) { ++ return false; ++ } ++ ++ if (hole_end < vma_start) { ++ // hole is on the left side of the vma ++ if ((vma_start - hole_start) <= MAX_DISTANCE) { ++ return true; ++ } ++ } else if (hole_start > vma_end) { ++ // hole is on the right side of the vma ++ if ((hole_end - vma_end) <= MAX_DISTANCE) { ++ return true; ++ } ++ } ++ ++ return false; ++} + /* +- * Find region for a patch. Take object's `previous_hole` as a left candidate ++ * Take object's `prev_hole` as a left candidate + * and the next hole as a right candidate. Pace through them until there is + * enough space in the hole for the patch. + * +@@ -873,52 +880,30 @@ int vm_hole_split(struct vm_hole *hole, + * from the obj. + * eg: R_AARCH64_ADR_GOT_PAGE + */ +-unsigned long object_find_patch_region(struct object_file *obj, +- size_t memsize, struct vm_hole **hole) ++struct vm_hole *find_patch_region(struct object_file *obj, size_t len) + { +- struct list_head *head = &obj->proc->vmaholes; +- struct vm_hole *left_hole = obj->previous_hole; +- struct vm_hole *right_hole = next_hole(left_hole, head); +- unsigned long region_start = 0; +- struct obj_vm_area *sovma; +- unsigned long obj_start; +- unsigned long obj_end; +- +- sovma = list_first_entry(&obj->vma, struct obj_vm_area, list); +- obj_start = sovma->inmem.start; +- sovma = list_entry(obj->vma.prev, struct obj_vm_area, list); +- obj_end = sovma->inmem.end; +- +- log_debug("Looking for patch region for '%s'...\n", obj->name); +- +- while (right_hole != NULL || left_hole != NULL) { +- if (hole_size(right_hole) > memsize) { +- *hole = right_hole; +- region_start = right_hole->start; +- if (region_start + memsize - obj_start > MAX_DISTANCE) { +- continue; ++ struct list_head *vma_holes = &obj->proc->vma_holes; ++ ++ struct obj_vm_area *vma = NULL; ++ list_for_each_entry(vma, &obj->vma, list) { ++ struct vm_hole *left_hole = obj->prev_hole; ++ struct vm_hole *right_hole = next_hole(obj->prev_hole, vma_holes); ++ ++ while ((left_hole != NULL) || (right_hole != NULL)) { ++ if (left_hole != NULL) { ++ if (is_vm_hole_suitable(vma, left_hole, len)) { ++ return left_hole; ++ } ++ left_hole = prev_hole(left_hole, vma_holes); + } +- goto found; +- } +- if (hole_size(left_hole) > memsize) { +- *hole = left_hole; +- region_start = left_hole->end - memsize; +- if (obj_end - region_start > MAX_DISTANCE) { +- continue; ++ if (right_hole != NULL) { ++ if (is_vm_hole_suitable(vma, right_hole, len)) { ++ return right_hole; ++ } ++ right_hole = next_hole(right_hole, vma_holes); + } +- goto found; + } +- right_hole = next_hole(right_hole, head); +- left_hole = prev_hole(left_hole, head); + } + +- log_error("Cannot find suitable region for patch '%s'\n", obj->name); +- return -1UL; +- +-found: +- region_start = (region_start >> PAGE_SHIFT) << PAGE_SHIFT; +- log_debug("Found patch region for '%s' 0xat %lx\n", +- obj->name, region_start); +- +- return region_start; ++ return NULL; + } +diff --git a/upatch-manage/upatch-process.h b/upatch-manage/upatch-process.h +index 23cbced..e8d5dee 100644 +--- a/upatch-manage/upatch-process.h ++++ b/upatch-manage/upatch-process.h +@@ -57,7 +57,7 @@ struct object_file { + struct list_head vma; + + /* Pointer to the previous hole in the patient's mapping */ +- struct vm_hole *previous_hole; ++ struct vm_hole *prev_hole; + + /* Pointer to the applied patch list, if any */ + struct list_head applied_patch; +@@ -81,6 +81,7 @@ struct vm_area { + struct vm_hole { + unsigned long start; + unsigned long end; ++ unsigned long len; + struct list_head list; + }; + +@@ -122,7 +123,7 @@ struct upatch_process { + } coro; + + /* List of free VMA areas */ +- struct list_head vmaholes; ++ struct list_head vma_holes; + + // TODO: other base? + /* libc's base address to use as a worksheet */ +@@ -143,9 +144,8 @@ int upatch_process_attach(struct upatch_process *); + + void upatch_process_detach(struct upatch_process *proc); + +-int vm_hole_split(struct vm_hole *, unsigned long, unsigned long); ++int vm_hole_split(struct vm_hole *, uintptr_t, uintptr_t); + +-unsigned long object_find_patch_region(struct object_file *, +- size_t, struct vm_hole **); ++struct vm_hole *find_patch_region(struct object_file *obj, size_t len); + + #endif +-- +2.34.1 + diff --git a/0022-upatch-manage-fix-misresolve-.rela.plt-symbol-issue.patch b/0022-upatch-manage-fix-misresolve-.rela.plt-symbol-issue.patch new file mode 100644 index 0000000..d1037ec --- /dev/null +++ b/0022-upatch-manage-fix-misresolve-.rela.plt-symbol-issue.patch @@ -0,0 +1,29 @@ +From b70bc8123941d7e7cf103c6c6731423297943935 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Fri, 21 Feb 2025 11:13:00 +0800 +Subject: [PATCH] upatch-manage: fix 'misresolve .rela.plt symbol' issue + +Signed-off-by: renoseven +--- + upatch-manage/upatch-resolve.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/upatch-manage/upatch-resolve.c b/upatch-manage/upatch-resolve.c +index b564578..53debe6 100644 +--- a/upatch-manage/upatch-resolve.c ++++ b/upatch-manage/upatch-resolve.c +@@ -99,8 +99,9 @@ static unsigned long resolve_rela_plt(struct upatch_elf *uelf, + for (Elf64_Xword i = 0; i < rela_plt_shdr->sh_size / sizeof(GElf_Rela); i++) { + unsigned long sym_idx = GELF_R_SYM(rela_plt[i].r_info); + unsigned long sym_type = GELF_ST_TYPE(dynsym[sym_idx].st_info); +- +- if (sym_type != STT_FUNC && sym_type != STT_TLS) { ++ if ((sym_type == STT_NOTYPE) && ++ (sym_type != STT_FUNC) && ++ (sym_type != STT_TLS)) { + continue; + } + +-- +2.34.1 + diff --git a/0023-upatch-manage-fix-misresolve-std-cout-symbol-issue.patch b/0023-upatch-manage-fix-misresolve-std-cout-symbol-issue.patch new file mode 100644 index 0000000..d8a6e2d --- /dev/null +++ b/0023-upatch-manage-fix-misresolve-std-cout-symbol-issue.patch @@ -0,0 +1,29 @@ +From 13faaebfb43c8c374c14fdd049881c4558b497f0 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Fri, 21 Feb 2025 15:24:19 +0800 +Subject: [PATCH] upatch-manage: fix 'misresolve std::cout symbol' issue + +Signed-off-by: renoseven +--- + upatch-manage/arch/aarch64/resolve.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/upatch-manage/arch/aarch64/resolve.c b/upatch-manage/arch/aarch64/resolve.c +index 5e0ddea..ed33925 100644 +--- a/upatch-manage/arch/aarch64/resolve.c ++++ b/upatch-manage/arch/aarch64/resolve.c +@@ -135,7 +135,10 @@ unsigned long insert_got_table(struct upatch_elf *uelf, struct object_file *obj, + goto out; + } + +- elf_addr = setup_got_table(uelf, jmp_addr, tls_addr); ++ elf_addr = jmp_addr; ++ if (r_type != R_AARCH64_GLOB_DAT) { ++ elf_addr = setup_got_table(uelf, jmp_addr, tls_addr); ++ } + log_debug("0x%lx: jmp_addr=0x%lx, tls_addr=0x%lx\n", elf_addr, + jmp_addr, tls_addr); + +-- +2.34.1 + diff --git a/0024-upatch-manage-fix-access-global-variable-coredump-is.patch b/0024-upatch-manage-fix-access-global-variable-coredump-is.patch new file mode 100644 index 0000000..f6bdd4d --- /dev/null +++ b/0024-upatch-manage-fix-access-global-variable-coredump-is.patch @@ -0,0 +1,93 @@ +From daef225331b197ad5f047f36989f7eddeac63eec Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Fri, 21 Feb 2025 14:34:09 +0800 +Subject: [PATCH] upatch-manage: fix 'access global variable coredump' issue + +Signed-off-by: renoseven +--- + upatch-manage/arch/aarch64/relocation.c | 13 +++++++++++-- + upatch-manage/arch/aarch64/resolve.c | 2 +- + upatch-manage/arch/x86_64/resolve.c | 2 +- + upatch-manage/upatch-resolve.h | 2 ++ + 4 files changed, 15 insertions(+), 4 deletions(-) + +diff --git a/upatch-manage/arch/aarch64/relocation.c b/upatch-manage/arch/aarch64/relocation.c +index 50bfc4b..80a817d 100644 +--- a/upatch-manage/arch/aarch64/relocation.c ++++ b/upatch-manage/arch/aarch64/relocation.c +@@ -67,6 +67,7 @@ int apply_relocate_add(struct upatch_elf *uelf, unsigned int symindex, + void *loc; + void *uloc; + u64 val; ++ u64 got; + s64 result; + GElf_Shdr *shdrs = (void *)uelf->info.shdrs; + GElf_Rela *rel = (void *)shdrs[relsec].sh_addr; +@@ -251,7 +252,11 @@ int apply_relocate_add(struct upatch_elf *uelf, unsigned int symindex, + *(__le32 *)loc = cpu_to_le32((__le32)result); + break; + case R_AARCH64_ADR_GOT_PAGE: +- result = calc_reloc(RELOC_OP_PAGE, uloc, val); ++ got = (u64)setup_got_table(uelf, val, 0); ++ if (got == 0) { ++ goto overflow; ++ } ++ result = calc_reloc(RELOC_OP_PAGE, uloc, got); + if (result < -(s64)BIT(32) || result >= (s64)BIT(32)) { + goto overflow; + } +@@ -261,7 +266,11 @@ int apply_relocate_add(struct upatch_elf *uelf, unsigned int symindex, + *(__le32 *)loc = cpu_to_le32((__le32)result); + break; + case R_AARCH64_LD64_GOT_LO12_NC: +- result = calc_reloc(RELOC_OP_ABS, uloc, val); ++ got = (u64)setup_got_table(uelf, val, 0); ++ if (got == 0) { ++ goto overflow; ++ } ++ result = calc_reloc(RELOC_OP_ABS, uloc, got); + // don't check result & 7 == 0. + // sometimes, result & 7 != 0, it works fine. + result = extract_insn_imm(result, 9, 3); +diff --git a/upatch-manage/arch/aarch64/resolve.c b/upatch-manage/arch/aarch64/resolve.c +index ed33925..63ebb0f 100644 +--- a/upatch-manage/arch/aarch64/resolve.c ++++ b/upatch-manage/arch/aarch64/resolve.c +@@ -65,7 +65,7 @@ static unsigned long setup_jmp_table(struct upatch_elf *uelf, + index * sizeof(struct upatch_jmp_table_entry)); + } + +-static unsigned long setup_got_table(struct upatch_elf *uelf, ++unsigned long setup_got_table(struct upatch_elf *uelf, + unsigned long jmp_addr, unsigned long tls_addr) + { + struct upatch_jmp_table_entry *table = uelf->core_layout.kbase + +diff --git a/upatch-manage/arch/x86_64/resolve.c b/upatch-manage/arch/x86_64/resolve.c +index 71b303a..405c90c 100644 +--- a/upatch-manage/arch/x86_64/resolve.c ++++ b/upatch-manage/arch/x86_64/resolve.c +@@ -61,7 +61,7 @@ static unsigned long setup_jmp_table(struct upatch_elf *uelf, + * GOT only need record address and resolve it by [got_addr]. + * To simplify design, use same table for both jmp table and GOT. + */ +-static unsigned long setup_got_table(struct upatch_elf *uelf, ++unsigned long setup_got_table(struct upatch_elf *uelf, + unsigned long jmp_addr, unsigned long tls_addr) + { + struct upatch_jmp_table_entry *table = uelf->core_layout.kbase + +diff --git a/upatch-manage/upatch-resolve.h b/upatch-manage/upatch-resolve.h +index 863bcc5..62efc13 100644 +--- a/upatch-manage/upatch-resolve.h ++++ b/upatch-manage/upatch-resolve.h +@@ -36,6 +36,8 @@ unsigned long insert_plt_table(struct upatch_elf *, struct object_file *, + unsigned long insert_got_table(struct upatch_elf *, struct object_file *, + unsigned long, unsigned long); + ++unsigned long setup_got_table(struct upatch_elf *uelf, ++ unsigned long, unsigned long); + unsigned long search_insert_plt_table(struct upatch_elf *, + unsigned long, unsigned long); + +-- +2.34.1 + diff --git a/0025-project-update-CMakeLists.txt.patch b/0025-project-update-CMakeLists.txt.patch new file mode 100644 index 0000000..a81c940 --- /dev/null +++ b/0025-project-update-CMakeLists.txt.patch @@ -0,0 +1,36 @@ +From 63b964867143e5715e597e39a8209dec163e7de0 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Sat, 22 Feb 2025 18:24:36 +0800 +Subject: [PATCH] project: update CMakeLists.txt + +Signed-off-by: renoseven +--- + CMakeLists.txt | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 37da26d..ca9fdfe 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -82,8 +82,7 @@ list(APPEND PROJECT_C_LINK_FLAGS + + if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") + list(APPEND PROJECT_C_BUILD_FLAGS -g) +-endif() +-if(CMAKE_BUILD_TYPE STREQUAL "Release") ++elseif(CMAKE_BUILD_TYPE STREQUAL "Release") + list(APPEND PROJECT_C_LINK_FLAGS -s) + endif() + +@@ -102,7 +101,7 @@ message("███████║ ██║ ███████║╚█ + message("╚══════╝ ╚═╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝") + message("---------------------------------------------------------") + message("-- Build type: ${CMAKE_BUILD_TYPE}") +-message("-- Build Verion: ${PROJECT_BUILD_VERSION}") ++message("-- Build version: ${PROJECT_BUILD_VERSION}") + message("-- Rust flags: ${PROJECT_RUST_FLAGS}") + message("-- Build flags: ${PROJECT_C_BUILD_FLAGS}") + message("-- Link flags: ${PROJECT_C_LINK_FLAGS}") +-- +2.34.1 + diff --git a/0026-upatch-manage-fix-compile-issue.patch b/0026-upatch-manage-fix-compile-issue.patch new file mode 100644 index 0000000..96a9cd1 --- /dev/null +++ b/0026-upatch-manage-fix-compile-issue.patch @@ -0,0 +1,30 @@ +From cd6381cf0634fb68b1f2b387adf3c559e8a923ba Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Mon, 24 Feb 2025 10:07:17 +0800 +Subject: [PATCH] upatch-manage: fix compile issue + +Signed-off-by: renoseven +--- + upatch-manage/upatch-process.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/upatch-manage/upatch-process.c b/upatch-manage/upatch-process.c +index 123ecfe..c3b07ac 100644 +--- a/upatch-manage/upatch-process.c ++++ b/upatch-manage/upatch-process.c +@@ -816,8 +816,10 @@ static inline struct vm_hole *prev_hole(struct vm_hole *hole, + + int vm_hole_split(struct vm_hole *hole, uintptr_t start, uintptr_t end) + { +- uintptr_t new_start = ROUND_DOWN(start, PAGE_SIZE) - PAGE_SIZE; +- uintptr_t new_end = ROUND_UP(end, PAGE_SIZE) + PAGE_SIZE; ++ uintptr_t new_start = ROUND_DOWN(start, (uintptr_t)PAGE_SIZE) - ++ (uintptr_t)PAGE_SIZE; ++ uintptr_t new_end = ROUND_UP(end, (uintptr_t)PAGE_SIZE) + ++ (uintptr_t)PAGE_SIZE; + + if (new_start > hole->start) { + struct vm_hole *left = NULL; +-- +2.34.1 + diff --git a/0027-syscare-build-supress-rpm-signature-warning.patch b/0027-syscare-build-supress-rpm-signature-warning.patch new file mode 100644 index 0000000..d8d7b90 --- /dev/null +++ b/0027-syscare-build-supress-rpm-signature-warning.patch @@ -0,0 +1,33 @@ +From 8a84b063e8e0d8261118cbe51b7dde68ffe0edf8 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Sat, 1 Mar 2025 14:47:37 +0800 +Subject: [PATCH] syscare-build: supress rpm signature warning + +Signed-off-by: renoseven +--- + syscare-build/src/package/rpm/mod.rs | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/syscare-build/src/package/rpm/mod.rs b/syscare-build/src/package/rpm/mod.rs +index 4054f67..ee7f19f 100644 +--- a/syscare-build/src/package/rpm/mod.rs ++++ b/syscare-build/src/package/rpm/mod.rs +@@ -50,6 +50,7 @@ impl RpmPackage { + .arg("--query") + .arg("--queryformat") + .arg(format) ++ .arg("--nosignature") + .arg("--package") + .arg(pkg_path.as_ref().as_os_str()) + .run_with_output()?; +@@ -106,6 +107,7 @@ impl Package for RpmPackage { + let output = Command::new(RPM_BIN) + .arg("--query") + .arg("--list") ++ .arg("--nosignature") + .arg("--package") + .arg(pkg_path) + .run_with_output()?; +-- +2.34.1 + diff --git a/0028-syscare-build-support-custom-kernel-configuration.patch b/0028-syscare-build-support-custom-kernel-configuration.patch new file mode 100644 index 0000000..4570893 --- /dev/null +++ b/0028-syscare-build-support-custom-kernel-configuration.patch @@ -0,0 +1,208 @@ +From 986c8ff3fcc4af577a90569dba5fe1585649c685 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Fri, 28 Feb 2025 11:30:33 +0800 +Subject: [PATCH] syscare-build: support custom kernel configuration + +Signed-off-by: renoseven +--- + syscare-build/src/args.rs | 7 +++- + syscare-build/src/build_params.rs | 8 ++++- + syscare-build/src/main.rs | 1 + + .../src/patch/kernel_patch/kpatch_builder.rs | 34 +++++++++++++++---- + .../src/patch/kernel_patch/kpatch_helper.rs | 28 ++++++--------- + 5 files changed, 52 insertions(+), 26 deletions(-) + +diff --git a/syscare-build/src/args.rs b/syscare-build/src/args.rs +index 5692b4b..a90b77a 100644 +--- a/syscare-build/src/args.rs ++++ b/syscare-build/src/args.rs +@@ -12,7 +12,7 @@ + * See the Mulan PSL v2 for more details. + */ + +-use std::path::PathBuf; ++use std::{ffi::OsString, path::PathBuf}; + + use anyhow::{ensure, Result}; + use clap::{AppSettings, ColorChoice, Parser}; +@@ -25,6 +25,7 @@ use super::{CLI_ABOUT, CLI_NAME, CLI_VERSION}; + const DEFAULT_PATCH_VERSION: &str = "1"; + const DEFAULT_PATCH_RELEASE: &str = "1"; + const DEFAULT_PATCH_DESCRIPTION: &str = "(none)"; ++const DEFAULT_KERNEL_CONFIG: &str = "openeuler_defconfig"; + const DEFAULT_BUILD_ROOT: &str = "."; + const DEFAULT_OUTPUT_DIR: &str = "."; + +@@ -76,6 +77,10 @@ pub struct Arguments { + #[clap(short, long, multiple = true, required = true)] + pub debuginfo: Vec, + ++ /// Kernel config name or path (kernel patch only) ++ #[clap(short, long, default_value = DEFAULT_KERNEL_CONFIG, hide_default_value = true)] ++ pub kconfig: OsString, ++ + /// Patch file(s) + #[clap(short, long, multiple = true, required = true)] + pub patch: Vec, +diff --git a/syscare-build/src/build_params.rs b/syscare-build/src/build_params.rs +index 6acfb49..f0e391c 100644 +--- a/syscare-build/src/build_params.rs ++++ b/syscare-build/src/build_params.rs +@@ -12,7 +12,7 @@ + * See the Mulan PSL v2 for more details. + */ + +-use std::path::PathBuf; ++use std::{ffi::OsString, path::PathBuf}; + + use syscare_abi::{PackageInfo, PatchFile, PatchType}; + +@@ -30,6 +30,7 @@ pub struct BuildParameters { + pub pkg_build_root: PackageBuildRoot, + pub build_entry: BuildEntry, + pub kernel_build_entry: Option, ++ pub kernel_config: OsString, + pub patch_name: String, + pub patch_type: PatchType, + pub patch_version: String, +@@ -61,6 +62,11 @@ impl std::fmt::Display for BuildParameters { + if let Some(k) = &self.kernel_build_entry { + writeln!(f, "kernel_source: {}", k.build_source.display())?; + writeln!(f, "kernel_spec: {}", k.build_spec.display())?; ++ writeln!( ++ f, ++ "kernel_config: {}", ++ self.kernel_config.to_string_lossy() ++ )?; + } + writeln!(f, "jobs: {}", self.jobs)?; + writeln!(f, "skip_compiler_check: {}", self.skip_compiler_check)?; +diff --git a/syscare-build/src/main.rs b/syscare-build/src/main.rs +index 64363bf..dec67b2 100644 +--- a/syscare-build/src/main.rs ++++ b/syscare-build/src/main.rs +@@ -296,6 +296,7 @@ impl SyscareBuild { + pkg_build_root, + build_entry, + kernel_build_entry, ++ kernel_config: self.args.kconfig.to_owned(), + patch_name: self.args.patch_name.to_owned(), + patch_version: self.args.patch_version.to_owned(), + patch_release: self.args.patch_release, +diff --git a/syscare-build/src/patch/kernel_patch/kpatch_builder.rs b/syscare-build/src/patch/kernel_patch/kpatch_builder.rs +index bcae962..accad0a 100644 +--- a/syscare-build/src/patch/kernel_patch/kpatch_builder.rs ++++ b/syscare-build/src/patch/kernel_patch/kpatch_builder.rs +@@ -22,6 +22,7 @@ use syscare_abi::{PackageInfo, PatchEntity, PatchFile, PatchInfo, PatchType}; + use syscare_common::{ + concat_os, + ffi::OsStrExt, ++ fs, + process::{Command, CommandArgs, CommandEnvs}, + util::digest, + }; +@@ -35,6 +36,7 @@ use crate::{ + use super::kpatch_helper::{KernelPatchHelper, KPATCH_SUFFIX, VMLINUX_FILE_NAME}; + + const KPATCH_BUILD_BIN: &str = "kpatch-build"; ++const GENERATED_KCONFIG_NAME: &str = ".config"; + + struct KBuildParameters { + pkg_build_dir: PathBuf, +@@ -98,13 +100,33 @@ impl KernelPatchBuilder { + let kernel_debug_dir = &build_params.build_root.package.debuginfo; + let oot_source_dir = oot_module_entry.map(|build_entry| build_entry.build_source.clone()); + +- info!("- Generating kernel default config"); +- KernelPatchHelper::generate_defconfig(&kernel_source_dir) +- .context("Failed to generate default config")?; ++ /* ++ * Kernel config: ++ * If it's a valid path, use it directly as an exteral file. ++ * Otherwise, we treat it as a kernel config name. ++ */ ++ let config_file = match fs::canonicalize(&build_params.kernel_config).ok() { ++ Some(file_path) => { ++ info!( ++ "- Using kernel config file '{}'", ++ build_params.kernel_config.to_string_lossy() ++ ); ++ file_path ++ } ++ None => { ++ info!( ++ "- Using kernel config '{}'", ++ build_params.kernel_config.to_string_lossy() ++ ); ++ KernelPatchHelper::generate_config_file( ++ &kernel_source_dir, ++ &build_params.kernel_config, ++ ) ++ .context("Failed to generate kernel config")?; + +- info!("- Finding kernel config"); +- let config_file = KernelPatchHelper::find_kernel_config(&kernel_source_dir) +- .context("Cannot find kernel config")?; ++ kernel_source_dir.join(GENERATED_KCONFIG_NAME) ++ } ++ }; + + info!("- Finding vmlinux"); + let vmlinux_file = KernelPatchHelper::find_vmlinux(kernel_debug_dir) +diff --git a/syscare-build/src/patch/kernel_patch/kpatch_helper.rs b/syscare-build/src/patch/kernel_patch/kpatch_helper.rs +index 8cbe9b3..f109b64 100644 +--- a/syscare-build/src/patch/kernel_patch/kpatch_helper.rs ++++ b/syscare-build/src/patch/kernel_patch/kpatch_helper.rs +@@ -12,7 +12,10 @@ + * See the Mulan PSL v2 for more details. + */ + +-use std::path::{Path, PathBuf}; ++use std::{ ++ ffi::OsStr, ++ path::{Path, PathBuf}, ++}; + + use anyhow::Result; + use log::Level; +@@ -26,31 +29,20 @@ const MAKE_BIN: &str = "make"; + pub struct KernelPatchHelper; + + impl KernelPatchHelper { +- pub fn generate_defconfig>(source_dir: P) -> Result<()> { +- const DEFCONFIG_FILE_NAME: &str = "openeuler_defconfig"; +- ++ pub fn generate_config_file(source_dir: P, name: S) -> Result<()> ++ where ++ P: AsRef, ++ S: AsRef, ++ { + Command::new(MAKE_BIN) + .arg("-C") + .arg(source_dir.as_ref()) +- .arg(DEFCONFIG_FILE_NAME) ++ .arg(name) + .stdout(Level::Debug) + .run_with_output()? + .exit_ok() + } + +- pub fn find_kernel_config>(directory: P) -> Result { +- const KERNEL_CONFIG_FILE_NAME: &str = ".config"; +- +- Ok(fs::find_file( +- directory, +- KERNEL_CONFIG_FILE_NAME, +- fs::FindOptions { +- fuzz: false, +- recursive: true, +- }, +- )?) +- } +- + pub fn find_vmlinux>(directory: P) -> std::io::Result { + fs::find_file( + directory, +-- +2.34.1 + diff --git a/0029-common-add-unit-test-for-process.patch b/0029-common-add-unit-test-for-process.patch new file mode 100644 index 0000000..be0217b --- /dev/null +++ b/0029-common-add-unit-test-for-process.patch @@ -0,0 +1,61 @@ +From 32df34f1fe208e9f99e58022f872ba68feeb14b8 Mon Sep 17 00:00:00 2001 +From: xuxiaojuan1 +Date: Tue, 7 May 2024 17:33:38 +0800 +Subject: [PATCH] common: add unit test for process + +--- + syscare-common/src/os/process.rs | 41 ++++++++++++++++++++++++++++++++ + 1 file changed, 41 insertions(+) + +diff --git a/syscare-common/src/os/process.rs b/syscare-common/src/os/process.rs +index d992372..4569587 100644 +--- a/syscare-common/src/os/process.rs ++++ b/syscare-common/src/os/process.rs +@@ -41,3 +41,44 @@ pub fn name() -> &'static OsStr { + } + PROCESS_NAME.as_os_str() + } ++ ++#[cfg(test)] ++mod tests_process { ++ use crate::os::process::{id, name, path}; ++ use std::process::Command; ++ use std::{println, string::ToString}; ++ ++ fn build_commd(s: &str) -> String { ++ let mut cmd = "ps -ef |grep ".to_string(); ++ cmd = cmd + s + "|grep -v grep"; ++ let output = Command::new("bash").arg("-c").arg(cmd).output().unwrap(); ++ String::from_utf8(output.stdout).unwrap() ++ } ++ ++ #[test] ++ fn test_id() { ++ let process_id = id().to_string(); ++ println!("This process id is {}", process_id); ++ ++ let sys_proc = build_commd(&process_id); ++ assert!(!sys_proc.is_empty()); ++ } ++ ++ #[test] ++ fn test_path() { ++ let process_path = path().display().to_string(); ++ println!("This path is {:#?}", process_path); ++ ++ let sys_path = build_commd(&process_path); ++ assert!(!sys_path.is_empty()); ++ } ++ ++ #[test] ++ fn test_name() { ++ let process_name = name().to_string_lossy(); ++ println!("This name is {:#?}", process_name); ++ ++ let sys_name = build_commd(&process_name); ++ assert!(!sys_name.is_empty()); ++ } ++} +-- +2.34.1 + diff --git a/0030-syscare-build-add-unit-test-for-spec-writer.patch b/0030-syscare-build-add-unit-test-for-spec-writer.patch new file mode 100644 index 0000000..4e14b59 --- /dev/null +++ b/0030-syscare-build-add-unit-test-for-spec-writer.patch @@ -0,0 +1,50 @@ +From 001ddc89ebd935a556e0676d2aba244824570f03 Mon Sep 17 00:00:00 2001 +From: xuxiaojuan1 +Date: Wed, 8 May 2024 17:56:03 +0800 +Subject: [PATCH] syscare-build: add unit test for spec writer + +--- + syscare-build/src/package/rpm/spec_writer.rs | 30 ++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/syscare-build/src/package/rpm/spec_writer.rs b/syscare-build/src/package/rpm/spec_writer.rs +index dc33459..97218c2 100644 +--- a/syscare-build/src/package/rpm/spec_writer.rs ++++ b/syscare-build/src/package/rpm/spec_writer.rs +@@ -152,3 +152,33 @@ impl PackageSpecWriter for RpmSpecWriter { + .context("Failed to write rpm spec file") + } + } ++ ++#[test] ++fn tests_spec_writer() { ++ use std::fs::File; ++ use std::io::{Read, Write}; ++ ++ let mut specfile = File::create("/tmp/test.spec").unwrap(); ++ specfile.write_all(b"Source: kerneltest-1.tar.gz").unwrap(); ++ specfile.write_all(b"%description").unwrap(); ++ ++ specfile.sync_all().unwrap(); ++ let filepath = PathBuf::from("/tmp/test.spec"); ++ ++ let test = RpmSpecWriter; ++ test.add_source_files( ++ &filepath, ++ vec![PathBuf::from("test1"), PathBuf::from("test2")], ++ ) ++ .unwrap(); ++ ++ let mut fileread = File::open(&filepath).unwrap(); ++ let mut content = String::new(); ++ fileread.read_to_string(&mut content).unwrap(); ++ assert!(content.contains("Source1: test1")); ++ assert!(content.contains("Source2: test2")); ++ ++ if filepath.exists() { ++ fs::remove_file(filepath).unwrap(); ++ } ++} +-- +2.34.1 + diff --git a/0031-syscare-remove-root-permission-check.patch b/0031-syscare-remove-root-permission-check.patch new file mode 100644 index 0000000..11bb73c --- /dev/null +++ b/0031-syscare-remove-root-permission-check.patch @@ -0,0 +1,57 @@ +From b0d436bf14fc724a7820ebddda32da58114de8ff Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Wed, 12 Feb 2025 11:24:40 +0800 +Subject: [PATCH] syscare: remove root permission check + +Signed-off-by: renoseven +--- + syscare/src/executor/mod.rs | 14 +------------- + syscare/src/executor/patch.rs | 2 -- + 2 files changed, 1 insertion(+), 15 deletions(-) + +diff --git a/syscare/src/executor/mod.rs b/syscare/src/executor/mod.rs +index 882cd0f..8681996 100644 +--- a/syscare/src/executor/mod.rs ++++ b/syscare/src/executor/mod.rs +@@ -12,8 +12,7 @@ + * See the Mulan PSL v2 for more details. + */ + +-use anyhow::{ensure, Result}; +-use syscare_common::os; ++use anyhow::Result; + + use super::args::SubCommand; + +@@ -22,15 +21,4 @@ pub mod patch; + + pub trait CommandExecutor { + fn invoke(&self, command: &SubCommand) -> Result>; +- +- fn check_root_permission(&self) -> Result<()> { +- const ROOT_UID: u32 = 0; +- +- ensure!( +- os::user::id() == ROOT_UID, +- "This command has to be run with superuser privileges (under the root user on most systems)." +- ); +- +- Ok(()) +- } + } +diff --git a/syscare/src/executor/patch.rs b/syscare/src/executor/patch.rs +index 98e719d..b9606f0 100644 +--- a/syscare/src/executor/patch.rs ++++ b/syscare/src/executor/patch.rs +@@ -91,8 +91,6 @@ impl PatchCommandExecutor { + + impl CommandExecutor for PatchCommandExecutor { + fn invoke(&self, command: &SubCommand) -> Result> { +- self.check_root_permission()?; +- + match command { + SubCommand::Info { identifiers } => { + let mut patch_list = vec![]; +-- +2.34.1 + diff --git a/0032-syscared-remove-upatch-failure-process-blacklist.patch b/0032-syscared-remove-upatch-failure-process-blacklist.patch new file mode 100644 index 0000000..28ab928 --- /dev/null +++ b/0032-syscared-remove-upatch-failure-process-blacklist.patch @@ -0,0 +1,107 @@ +From fa19bb309e2cce60eba73a08408d228d9ef45a72 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Wed, 12 Feb 2025 11:31:15 +0800 +Subject: [PATCH] syscared: remove upatch failure process blacklist + +Signed-off-by: renoseven +--- + syscared/src/patch/driver/upatch/entity.rs | 14 -------------- + syscared/src/patch/driver/upatch/mod.rs | 18 +++++------------- + 2 files changed, 5 insertions(+), 27 deletions(-) + +diff --git a/syscared/src/patch/driver/upatch/entity.rs b/syscared/src/patch/driver/upatch/entity.rs +index 80932c4..5d0a9c0 100644 +--- a/syscared/src/patch/driver/upatch/entity.rs ++++ b/syscared/src/patch/driver/upatch/entity.rs +@@ -20,7 +20,6 @@ use indexmap::{indexset, IndexSet}; + pub struct PatchEntity { + pub patch_file: PathBuf, + process_list: IndexSet, +- ignored_list: IndexSet, + } + + impl PatchEntity { +@@ -28,7 +27,6 @@ impl PatchEntity { + Self { + patch_file, + process_list: indexset! {}, +- ignored_list: indexset! {}, + } + } + } +@@ -42,20 +40,8 @@ impl PatchEntity { + self.process_list.remove(&pid); + } + +- pub fn ignore_process(&mut self, pid: i32) { +- self.ignored_list.insert(pid); +- } +- + pub fn clean_dead_process(&mut self, process_list: &IndexSet) { + self.process_list.retain(|pid| process_list.contains(pid)); +- self.ignored_list.retain(|pid| process_list.contains(pid)); +- } +- +- pub fn need_ignored(&self, process_list: &IndexSet) -> IndexSet { +- process_list +- .intersection(&self.ignored_list) +- .copied() +- .collect() + } + + pub fn need_actived(&self, process_list: &IndexSet) -> IndexSet { +diff --git a/syscared/src/patch/driver/upatch/mod.rs b/syscared/src/patch/driver/upatch/mod.rs +index 73ef94e..a1e9002 100644 +--- a/syscared/src/patch/driver/upatch/mod.rs ++++ b/syscared/src/patch/driver/upatch/mod.rs +@@ -237,10 +237,7 @@ impl UserPatchDriver { + patch_entity.clean_dead_process(&process_list); + + // Active patch +- let need_ignored = patch_entity.need_ignored(&process_list); +- +- let mut need_actived = patch_entity.need_actived(&process_list); +- need_actived.retain(|pid| !need_ignored.contains(pid)); ++ let need_actived = patch_entity.need_actived(&process_list); + if !need_actived.is_empty() { + debug!( + "Activating patch '{}' ({}) for process {:?}", +@@ -260,7 +257,6 @@ impl UserPatchDriver { + pid, + e.to_string().to_lowercase(), + ); +- patch_entity.ignore_process(pid) + } + } + } +@@ -333,9 +329,8 @@ impl UserPatchDriver { + let mut results = Vec::new(); + for pid in patch_entity.need_actived(&process_list) { + let result = sys::active_patch(patch_uuid, pid, target_elf, patch_file); +- match result { +- Ok(_) => patch_entity.add_process(pid), +- Err(_) => patch_entity.ignore_process(pid), ++ if result.is_ok() { ++ patch_entity.add_process(pid); + } + results.push((pid, result)); + } +@@ -411,13 +406,10 @@ impl UserPatchDriver { + target_elf.display(), + ); + +- let need_ignored = patch_entity.need_ignored(&process_list); +- +- let mut need_deactived = patch_entity.need_deactived(&process_list); +- need_deactived.retain(|pid| need_ignored.contains(pid)); ++ let need_deactived = patch_entity.need_deactived(&process_list); + + let mut results = Vec::new(); +- for pid in patch_entity.need_deactived(&process_list) { ++ for pid in need_deactived { + let result = sys::deactive_patch(patch_uuid, pid, target_elf, patch_file); + if result.is_ok() { + patch_entity.remove_process(pid) +-- +2.34.1 + diff --git a/0033-syscare-optimize-syscare-info-syscare-target-output.patch b/0033-syscare-optimize-syscare-info-syscare-target-output.patch new file mode 100644 index 0000000..6579b28 --- /dev/null +++ b/0033-syscare-optimize-syscare-info-syscare-target-output.patch @@ -0,0 +1,53 @@ +From 2d71a1c6c368392359869b3b641e2592db5bb859 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Thu, 13 Feb 2025 09:40:23 +0800 +Subject: [PATCH] syscare: optimize 'syscare info' & 'syscare target' output + +Signed-off-by: renoseven +--- + syscare/src/executor/patch.rs | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/syscare/src/executor/patch.rs b/syscare/src/executor/patch.rs +index b9606f0..5ad9cc2 100644 +--- a/syscare/src/executor/patch.rs ++++ b/syscare/src/executor/patch.rs +@@ -53,23 +53,31 @@ impl PatchCommandExecutor { + } + + fn show_patch_info(patch_list: impl IntoIterator) { +- for (identifier, patch) in patch_list { ++ let mut patch_iter = patch_list.into_iter().peekable(); ++ while let Some((identifier, patch)) = patch_iter.next() { + info!("-------------------------------------------"); + info!("Patch: {}", identifier); + info!("-------------------------------------------"); + info!("{}", patch); ++ if patch_iter.peek().is_some() { ++ continue; ++ } ++ info!("-------------------------------------------"); + } +- info!("-------------------------------------------"); + } + + fn show_patch_target(pkg_list: impl IntoIterator) { +- for (identifier, package) in pkg_list { ++ let mut pkg_iter = pkg_list.into_iter().peekable(); ++ while let Some((identifier, package)) = pkg_iter.next() { + info!("-------------------------------------------"); + info!("Patch: {}", identifier); + info!("-------------------------------------------"); + info!("{}", package); ++ if pkg_iter.peek().is_some() { ++ continue; ++ } ++ info!("-------------------------------------------"); + } +- info!("-------------------------------------------"); + } + + fn show_patch_status(status_list: impl IntoIterator) { +-- +2.34.1 + diff --git a/0034-syscared-impl-syscare-rescan-command.patch b/0034-syscared-impl-syscare-rescan-command.patch new file mode 100644 index 0000000..73985ce --- /dev/null +++ b/0034-syscared-impl-syscare-rescan-command.patch @@ -0,0 +1,44 @@ +From b0553998fe9b9947ead6d880d36b61721155bfbb Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Tue, 11 Feb 2025 17:29:13 +0800 +Subject: [PATCH] syscared: impl 'syscare rescan' command + +Signed-off-by: renoseven +--- + syscared/src/rpc/skeleton/patch.rs | 3 +++ + syscared/src/rpc/skeleton_impl/patch.rs | 9 +++++++++ + 2 files changed, 12 insertions(+) + +diff --git a/syscared/src/rpc/skeleton/patch.rs b/syscared/src/rpc/skeleton/patch.rs +index caeb446..99902b5 100644 +--- a/syscared/src/rpc/skeleton/patch.rs ++++ b/syscared/src/rpc/skeleton/patch.rs +@@ -53,4 +53,7 @@ pub trait PatchSkeleton { + + #[rpc(name = "restore_patch_status")] + fn restore_patch_status(&self, accepted_only: bool) -> RpcResult<()>; ++ ++ #[rpc(name = "rescan_patches")] ++ fn rescan_patches(&self) -> RpcResult<()>; + } +diff --git a/syscared/src/rpc/skeleton_impl/patch.rs b/syscared/src/rpc/skeleton_impl/patch.rs +index 8216428..38c9f37 100644 +--- a/syscared/src/rpc/skeleton_impl/patch.rs ++++ b/syscared/src/rpc/skeleton_impl/patch.rs +@@ -234,4 +234,13 @@ impl PatchSkeleton for PatchSkeletonImpl { + .context("Failed to restore patch status") + }) + } ++ ++ fn rescan_patches(&self) -> RpcResult<()> { ++ RpcFunction::call(move || -> Result<()> { ++ self.patch_manager ++ .write() ++ .rescan_patches() ++ .context("Failed to rescan patches") ++ }) ++ } + } +-- +2.34.1 + diff --git a/0035-syscare-impl-syscare-rescan-command.patch b/0035-syscare-impl-syscare-rescan-command.patch new file mode 100644 index 0000000..b09dda4 --- /dev/null +++ b/0035-syscare-impl-syscare-rescan-command.patch @@ -0,0 +1,59 @@ +From 5636956c349b431b3467cfa993caf4469df37f8d Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Tue, 11 Feb 2025 17:38:41 +0800 +Subject: [PATCH] syscare: impl 'syscare rescan' command + +Signed-off-by: renoseven +--- + syscare/src/args.rs | 2 ++ + syscare/src/executor/patch.rs | 6 ++++++ + syscare/src/rpc/proxy.rs | 5 +++++ + 3 files changed, 13 insertions(+) + +diff --git a/syscare/src/args.rs b/syscare/src/args.rs +index 5e7299d..24a4a5e 100644 +--- a/syscare/src/args.rs ++++ b/syscare/src/args.rs +@@ -127,6 +127,8 @@ pub enum SubCommand { + #[clap(long)] + accepted: bool, + }, ++ /// Rescan all patches ++ Rescan, + } + + impl Arguments { +diff --git a/syscare/src/executor/patch.rs b/syscare/src/executor/patch.rs +index 5ad9cc2..346c30a 100644 +--- a/syscare/src/executor/patch.rs ++++ b/syscare/src/executor/patch.rs +@@ -254,6 +254,12 @@ impl CommandExecutor for PatchCommandExecutor { + self.proxy.restore_patch_status(*accepted)?; + return Ok(Some(0)); + } ++ SubCommand::Rescan => { ++ let _file_lock = FileLock::new(&self.lock_file, FileLockType::Exclusive)?; ++ ++ self.proxy.rescan_patches()?; ++ return Ok(Some(0)); ++ } + _ => {} + } + +diff --git a/syscare/src/rpc/proxy.rs b/syscare/src/rpc/proxy.rs +index bb01a67..d328398 100644 +--- a/syscare/src/rpc/proxy.rs ++++ b/syscare/src/rpc/proxy.rs +@@ -103,4 +103,9 @@ impl RpcProxy { + self.remote + .call_with_args(function_name!(), RpcArguments::new().arg(accepted_only)) + } ++ ++ #[named] ++ pub fn rescan_patches(&self) -> Result<()> { ++ self.remote.call(function_name!()) ++ } + } +-- +2.34.1 + diff --git a/0036-syscared-impl-log-config.patch b/0036-syscared-impl-log-config.patch new file mode 100644 index 0000000..6e00043 --- /dev/null +++ b/0036-syscared-impl-log-config.patch @@ -0,0 +1,141 @@ +From 90dfc6929f4e1bd170f034093bef8aea2b92ad89 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Tue, 11 Feb 2025 18:10:38 +0800 +Subject: [PATCH] syscared: impl log config + +Signed-off-by: renoseven +--- + syscared/src/config.rs | 26 ++++++++++++++++++++------ + syscared/src/main.rs | 40 ++++++++++++++++++++-------------------- + 2 files changed, 40 insertions(+), 26 deletions(-) + +diff --git a/syscared/src/config.rs b/syscared/src/config.rs +index af98a51..08a2878 100644 +--- a/syscared/src/config.rs ++++ b/syscared/src/config.rs +@@ -18,9 +18,27 @@ use anyhow::{anyhow, Result}; + use serde::{Deserialize, Serialize}; + use syscare_common::fs; + ++const DEFAULT_MAX_LOG_SIZE: u64 = 2 * 1024 * 1024; ++const DEFAULT_MAX_LOG_NUM: usize = 7; ++ + const DEFAULT_SOCKET_UID: u32 = 0; + const DEFAULT_SOCKET_GID: u32 = 0; + ++#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] ++pub struct LogConfig { ++ pub max_file_size: u64, ++ pub max_file_num: usize, ++} ++ ++impl Default for LogConfig { ++ fn default() -> Self { ++ Self { ++ max_file_size: DEFAULT_MAX_LOG_SIZE, ++ max_file_num: DEFAULT_MAX_LOG_NUM, ++ } ++ } ++} ++ + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] + pub struct SocketConfig { + pub uid: u32, +@@ -36,14 +54,10 @@ impl Default for SocketConfig { + } + } + +-#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +-pub struct DaemonConfig { +- pub socket: SocketConfig, +-} +- + #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] + pub struct Config { +- pub daemon: DaemonConfig, ++ pub log: LogConfig, ++ pub socket: SocketConfig, + } + + impl Config { +diff --git a/syscared/src/main.rs b/syscared/src/main.rs +index 42e9564..9ddfbe8 100644 +--- a/syscared/src/main.rs ++++ b/syscared/src/main.rs +@@ -22,7 +22,7 @@ use flexi_logger::{ + }; + use jsonrpc_core::IoHandler; + use jsonrpc_ipc_server::{Server, ServerBuilder}; +-use log::{debug, error, info, warn, LevelFilter, Record}; ++use log::{error, info, LevelFilter, Record}; + use nix::unistd::{chown, Gid, Uid}; + use parking_lot::RwLock; + use patch::manager::PatchManager; +@@ -127,6 +127,21 @@ impl Daemon { + ) + })?; + ++ // Initialize config ++ println!("Initializing configuation..."); ++ let config_file = args.config_dir.join(CONFIG_FILE_NAME); ++ let config = match Config::parse(&config_file) { ++ Ok(config) => config, ++ Err(e) => { ++ eprintln!("{:?}", e); ++ println!("Using default configuration..."); ++ let config = Config::default(); ++ config.write(&config_file)?; ++ ++ config ++ } ++ }; ++ + // Initialize logger + let max_level = args.log_level; + let stdout_level = if args.daemon { +@@ -143,29 +158,14 @@ impl Daemon { + .format(Self::format_log) + .duplicate_to_stdout(Duplicate::from(stdout_level)) + .rotate( +- Criterion::Age(Age::Day), ++ Criterion::AgeOrSize(Age::Day, config.log.max_file_size), + Naming::Timestamps, +- Cleanup::KeepCompressedFiles(30), ++ Cleanup::KeepCompressedFiles(config.log.max_file_num), + ) + .write_mode(WriteMode::Direct) + .start() + .context("Failed to initialize logger")?; + +- // Initialize config +- debug!("Initializing configuation..."); +- let config_file = args.config_dir.join(CONFIG_FILE_NAME); +- let config = match Config::parse(&config_file) { +- Ok(config) => config, +- Err(e) => { +- warn!("{:?}", e); +- info!("Using default configuration..."); +- let config = Config::default(); +- config.write(&config_file)?; +- +- config +- } +- }; +- + // Print panic to log incase it really happens + panic::set_hook(Box::new(|info| error!("{}", info))); + +@@ -205,8 +205,8 @@ impl Daemon { + .context("Failed to convert socket path to string")?, + )?; + +- let socket_owner = Uid::from_raw(self.config.daemon.socket.uid); +- let socket_group = Gid::from_raw(self.config.daemon.socket.gid); ++ let socket_owner = Uid::from_raw(self.config.socket.uid); ++ let socket_group = Gid::from_raw(self.config.socket.gid); + chown(&socket_file, Some(socket_owner), Some(socket_group))?; + + fs::set_permissions( +-- +2.34.1 + diff --git a/0037-syscared-impl-patch-blacklist.patch b/0037-syscared-impl-patch-blacklist.patch new file mode 100644 index 0000000..e2d79cf --- /dev/null +++ b/0037-syscared-impl-patch-blacklist.patch @@ -0,0 +1,410 @@ +From f2c7cfcda4c6dbd09cbf5419a33d5dc646bc84d6 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Wed, 12 Feb 2025 10:27:50 +0800 +Subject: [PATCH] syscared: impl patch blacklist + +Signed-off-by: renoseven +--- + syscared/src/config.rs | 22 +++++++++- + syscared/src/main.rs | 3 +- + syscared/src/patch/driver/kpatch/mod.rs | 15 ++++++- + syscared/src/patch/driver/mod.rs | 12 +++--- + syscared/src/patch/driver/upatch/mod.rs | 47 ++++++++++++++------- + syscared/src/patch/driver/upatch/monitor.rs | 24 ++++------- + syscared/src/patch/entity/kpatch.rs | 1 + + syscared/src/patch/manager.rs | 6 +-- + syscared/src/patch/resolver/kpatch.rs | 2 + + 9 files changed, 88 insertions(+), 44 deletions(-) + +diff --git a/syscared/src/config.rs b/syscared/src/config.rs +index 08a2878..7103273 100644 +--- a/syscared/src/config.rs ++++ b/syscared/src/config.rs +@@ -12,7 +12,10 @@ + * See the Mulan PSL v2 for more details. + */ + +-use std::path::Path; ++use std::{ ++ ffi::OsString, ++ path::{Path, PathBuf}, ++}; + + use anyhow::{anyhow, Result}; + use serde::{Deserialize, Serialize}; +@@ -54,10 +57,27 @@ impl Default for SocketConfig { + } + } + ++#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] ++pub struct KernelPatchConfig { ++ pub blocked: Vec, ++} ++ ++#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] ++pub struct UserPatchConfig { ++ pub skipped: Vec, ++} ++ ++#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] ++pub struct PatchConfig { ++ pub kpatch: KernelPatchConfig, ++ pub upatch: UserPatchConfig, ++} ++ + #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] + pub struct Config { + pub log: LogConfig, + pub socket: SocketConfig, ++ pub patch: PatchConfig, + } + + impl Config { +diff --git a/syscared/src/main.rs b/syscared/src/main.rs +index 9ddfbe8..f965497 100644 +--- a/syscared/src/main.rs ++++ b/syscared/src/main.rs +@@ -231,7 +231,8 @@ impl Daemon { + info!("Initializing patch manager..."); + let patch_root = &self.args.data_dir; + let patch_manager = Arc::new(RwLock::new( +- PatchManager::new(patch_root).context("Failed to initialize patch manager")?, ++ PatchManager::new(&self.config.patch, patch_root) ++ .context("Failed to initialize patch manager")?, + )); + + info!("Initializing patch monitor..."); +diff --git a/syscared/src/patch/driver/kpatch/mod.rs b/syscared/src/patch/driver/kpatch/mod.rs +index 970da92..349d495 100644 +--- a/syscared/src/patch/driver/kpatch/mod.rs ++++ b/syscared/src/patch/driver/kpatch/mod.rs +@@ -15,6 +15,7 @@ + use std::{ + ffi::{OsStr, OsString}, + fmt::Write, ++ iter::FromIterator, + }; + + use anyhow::{ensure, Result}; +@@ -24,7 +25,10 @@ use log::{debug, info}; + use syscare_abi::PatchStatus; + use syscare_common::{concat_os, os, util::digest}; + +-use crate::patch::entity::{KernelPatch, KernelPatchFunction}; ++use crate::{ ++ config::KernelPatchConfig, ++ patch::entity::{KernelPatch, KernelPatchFunction}, ++}; + + mod sys; + mod target; +@@ -33,12 +37,14 @@ use target::PatchTarget; + + pub struct KernelPatchDriver { + target_map: IndexMap, ++ blocked_targets: IndexSet, + } + + impl KernelPatchDriver { +- pub fn new() -> Result { ++ pub fn new(config: &KernelPatchConfig) -> Result { + Ok(Self { + target_map: IndexMap::new(), ++ blocked_targets: IndexSet::from_iter(config.blocked.iter().cloned()), + }) + } + } +@@ -247,6 +253,11 @@ impl KernelPatchDriver { + patch.patch_file.display() + ); + ++ ensure!( ++ self.blocked_targets.contains(&patch.target_name), ++ "Patch target '{}' is blocked", ++ patch.target_name.to_string_lossy(), ++ ); + sys::selinux_relable_patch(patch)?; + sys::apply_patch(patch)?; + self.add_patch_target(patch); +diff --git a/syscared/src/patch/driver/mod.rs b/syscared/src/patch/driver/mod.rs +index 7a57579..707bf2f 100644 +--- a/syscared/src/patch/driver/mod.rs ++++ b/syscared/src/patch/driver/mod.rs +@@ -29,6 +29,8 @@ pub enum PatchOpFlag { + Force, + } + ++use crate::config::PatchConfig; ++ + use super::entity::Patch; + + pub struct PatchDriver { +@@ -53,14 +55,14 @@ impl PatchDriver { + } + + impl PatchDriver { +- pub fn new() -> Result { ++ pub fn new(config: &PatchConfig) -> Result { + info!("Initializing kernel patch driver..."); +- let kpatch_driver = +- KernelPatchDriver::new().context("Failed to initialize kernel patch driver")?; ++ let kpatch_driver = KernelPatchDriver::new(&config.kpatch) ++ .context("Failed to initialize kernel patch driver")?; + + info!("Initializing user patch driver..."); +- let upatch_driver = +- UserPatchDriver::new().context("Failed to initialize user patch driver")?; ++ let upatch_driver = UserPatchDriver::new(&config.upatch) ++ .context("Failed to initialize user patch driver")?; + + Ok(Self { + kpatch: kpatch_driver, +diff --git a/syscared/src/patch/driver/upatch/mod.rs b/syscared/src/patch/driver/upatch/mod.rs +index a1e9002..c31ef78 100644 +--- a/syscared/src/patch/driver/upatch/mod.rs ++++ b/syscared/src/patch/driver/upatch/mod.rs +@@ -15,6 +15,7 @@ + use std::{ + ffi::OsStr, + fmt::Write, ++ iter::FromIterator, + os::linux::fs::MetadataExt, + path::{Path, PathBuf}, + sync::Arc, +@@ -29,7 +30,10 @@ use uuid::Uuid; + use syscare_abi::PatchStatus; + use syscare_common::{fs, util::digest}; + +-use crate::patch::{driver::upatch::entity::PatchEntity, entity::UserPatch}; ++use crate::{ ++ config::UserPatchConfig, ++ patch::{driver::upatch::entity::PatchEntity, entity::UserPatch}, ++}; + + mod entity; + mod monitor; +@@ -42,21 +46,25 @@ use target::PatchTarget; + pub struct UserPatchDriver { + status_map: IndexMap, + target_map: Arc>>, ++ skipped_files: Arc>, + monitor: UserPatchMonitor, + } + + impl UserPatchDriver { +- pub fn new() -> Result { +- let status_map = IndexMap::new(); ++ pub fn new(config: &UserPatchConfig) -> Result { + let target_map = Arc::new(RwLock::new(IndexMap::new())); +- let monitor = UserPatchMonitor::new(target_map.clone(), Self::patch_new_process)?; +- let instance = Self { +- status_map, +- target_map, +- monitor, +- }; +- +- Ok(instance) ++ let skipped_files = Arc::new(IndexSet::from_iter(config.skipped.iter().cloned())); ++ ++ Ok(Self { ++ status_map: IndexMap::new(), ++ target_map: target_map.clone(), ++ skipped_files: skipped_files.clone(), ++ monitor: UserPatchMonitor::new(move |target_elfs| { ++ for target_elf in target_elfs { ++ Self::patch_new_process(&target_map, &skipped_files, target_elf); ++ } ++ })?, ++ }) + } + } + +@@ -178,7 +186,10 @@ impl UserPatchDriver { + .and_then(Result::ok) + } + +- fn find_target_process>(target_elf: P) -> Result> { ++ fn find_target_process>( ++ skipped_files: &IndexSet, ++ target_elf: P, ++ ) -> Result> { + let mut target_pids = IndexSet::new(); + let target_path = target_elf.as_ref(); + let target_inode = target_path.metadata()?.st_ino(); +@@ -192,6 +203,9 @@ impl UserPatchDriver { + Ok(file_path) => file_path, + Err(_) => continue, + }; ++ if skipped_files.contains(&exec_path) { ++ continue; ++ } + // Try to match binary path + if exec_path == target_path { + target_pids.insert(pid); +@@ -219,10 +233,11 @@ impl UserPatchDriver { + } + + fn patch_new_process( +- target_map: Arc>>, ++ target_map: &RwLock>, ++ skipped_files: &IndexSet, + target_elf: &Path, + ) { +- let process_list = match Self::find_target_process(target_elf) { ++ let process_list = match Self::find_target_process(skipped_files, target_elf) { + Ok(pids) => pids, + Err(_) => return, + }; +@@ -308,7 +323,7 @@ impl UserPatchDriver { + let patch_functions = patch.functions.as_slice(); + let target_elf = patch.target_elf.as_path(); + +- let process_list = Self::find_target_process(target_elf)?; ++ let process_list = Self::find_target_process(&self.skipped_files, target_elf)?; + + let mut target_map = self.target_map.write(); + let patch_target = target_map +@@ -385,7 +400,7 @@ impl UserPatchDriver { + let patch_functions = patch.functions.as_slice(); + let target_elf = patch.target_elf.as_path(); + +- let process_list = Self::find_target_process(target_elf)?; ++ let process_list = Self::find_target_process(&self.skipped_files, target_elf)?; + + let mut target_map = self.target_map.write(); + let patch_target = target_map +diff --git a/syscared/src/patch/driver/upatch/monitor.rs b/syscared/src/patch/driver/upatch/monitor.rs +index 09df2a2..c0c1b3c 100644 +--- a/syscared/src/patch/driver/upatch/monitor.rs ++++ b/syscared/src/patch/driver/upatch/monitor.rs +@@ -21,14 +21,12 @@ use std::{ + }; + + use anyhow::{bail, Context, Result}; +-use indexmap::{IndexMap, IndexSet}; ++use indexmap::IndexMap; + use inotify::{Inotify, WatchDescriptor, WatchMask}; + use log::info; + use parking_lot::{Mutex, RwLock}; + use syscare_common::ffi::OsStrExt; + +-use super::target::PatchTarget; +- + const MONITOR_THREAD_NAME: &str = "upatch_monitor"; + const MONITOR_CHECK_PERIOD: u64 = 100; + const MONITOR_EVENT_BUFFER_CAPACITY: usize = 16 * 64; // inotify event size: 16 +@@ -41,12 +39,9 @@ pub(super) struct UserPatchMonitor { + } + + impl UserPatchMonitor { +- pub fn new( +- patch_target_map: Arc>>, +- callback: F, +- ) -> Result ++ pub fn new(callback: F) -> Result + where +- F: Fn(Arc>>, &Path) + Send + Sync + 'static, ++ F: Fn(Vec<&Path>) + Send + Sync + 'static, + { + let inotify = Arc::new(Mutex::new(Some( + Inotify::init().context("Failed to initialize inotify")?, +@@ -56,7 +51,6 @@ impl UserPatchMonitor { + let monitor_thread = MonitorThread { + inotify: inotify.clone(), + watch_file_map: watch_file_map.clone(), +- patch_target_map, + callback, + } + .run()?; +@@ -119,13 +113,12 @@ impl UserPatchMonitor { + struct MonitorThread { + inotify: Arc>>, + watch_file_map: Arc>>, +- patch_target_map: Arc>>, + callback: F, + } + + impl MonitorThread + where +- F: Fn(Arc>>, &Path) + Send + Sync + 'static, ++ F: Fn(Vec<&Path>) + Send + Sync + 'static, + { + fn run(self) -> Result> { + thread::Builder::new() +@@ -152,13 +145,12 @@ where + + if let Ok(events) = inotify.read_events(&mut buffer) { + let watch_file_map = self.watch_file_map.read(); +- let target_elfs = events ++ let path_list = events + .filter_map(|event| watch_file_map.get(&event.wd)) + .filter(|path| Self::filter_blacklist_path(path)) +- .collect::>(); +- for target_elf in target_elfs { +- (self.callback)(self.patch_target_map.clone(), target_elf); +- } ++ .map(|path| path.as_ref()) ++ .collect::>(); ++ (self.callback)(path_list) + } + + thread::park_timeout(Duration::from_millis(MONITOR_CHECK_PERIOD)) +diff --git a/syscared/src/patch/entity/kpatch.rs b/syscared/src/patch/entity/kpatch.rs +index a6b48c5..4c0be9c 100644 +--- a/syscared/src/patch/entity/kpatch.rs ++++ b/syscared/src/patch/entity/kpatch.rs +@@ -64,6 +64,7 @@ pub struct KernelPatch { + pub info: Arc, + pub pkg_name: String, + pub module_name: OsString, ++ pub target_name: OsString, + pub functions: Vec, + pub patch_file: PathBuf, + pub sys_file: PathBuf, +diff --git a/syscared/src/patch/manager.rs b/syscared/src/patch/manager.rs +index 48c583a..4bf65ac 100644 +--- a/syscared/src/patch/manager.rs ++++ b/syscared/src/patch/manager.rs +@@ -27,7 +27,7 @@ use uuid::Uuid; + use syscare_abi::PatchStatus; + use syscare_common::{concat_os, ffi::OsStrExt, fs, util::serde}; + +-use crate::patch::resolver::PatchResolver; ++use crate::{config::PatchConfig, patch::resolver::PatchResolver}; + + use super::{ + driver::{PatchDriver, PatchOpFlag}, +@@ -75,8 +75,8 @@ pub struct PatchManager { + } + + impl PatchManager { +- pub fn new>(patch_root: P) -> Result { +- let driver = PatchDriver::new()?; ++ pub fn new>(patch_config: &PatchConfig, patch_root: P) -> Result { ++ let driver = PatchDriver::new(patch_config)?; + let patch_install_dir = patch_root.as_ref().join(PATCH_INSTALL_DIR); + let patch_status_file = patch_root.as_ref().join(PATCH_STATUS_FILE_NAME); + let patch_map = Self::scan_patches(&patch_install_dir)?; +diff --git a/syscared/src/patch/resolver/kpatch.rs b/syscared/src/patch/resolver/kpatch.rs +index 863f65b..4ec35f4 100644 +--- a/syscared/src/patch/resolver/kpatch.rs ++++ b/syscared/src/patch/resolver/kpatch.rs +@@ -194,6 +194,7 @@ impl PatchResolverImpl for KpatchResolverImpl { + patch_info: Arc, + patch_entity: &PatchEntity, + ) -> Result { ++ let target_name = patch_entity.patch_name.as_os_str().to_os_string(); + let module_name = patch_entity.patch_name.replace(['-', '.'], "_"); + let patch_file = patch_root.join(concat_os!(&patch_entity.patch_name, KPATCH_SUFFIX)); + let sys_file = PathBuf::from(KPATCH_SYS_DIR) +@@ -211,6 +212,7 @@ impl PatchResolverImpl for KpatchResolverImpl { + ), + info: patch_info.clone(), + pkg_name: patch_info.target.full_name(), ++ target_name, + module_name, + patch_file, + sys_file, +-- +2.34.1 + diff --git a/0038-metadata-viewer-add-component.patch b/0038-metadata-viewer-add-component.patch new file mode 100644 index 0000000..95b92d8 --- /dev/null +++ b/0038-metadata-viewer-add-component.patch @@ -0,0 +1,284 @@ +From d903d529a5d503d688aa41276240408e747c3366 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Wed, 12 Feb 2025 14:40:32 +0800 +Subject: [PATCH] metadata-viewer: add component + +Signed-off-by: renoseven +--- + CMakeLists.txt | 1 + + Cargo.toml | 3 +- + metadata-viewer/Cargo.toml | 17 +++++++ + metadata-viewer/build.rs | 38 ++++++++++++++++ + metadata-viewer/src/args.rs | 66 +++++++++++++++++++++++++++ + metadata-viewer/src/main.rs | 91 +++++++++++++++++++++++++++++++++++++ + 6 files changed, 215 insertions(+), 1 deletion(-) + create mode 100644 metadata-viewer/Cargo.toml + create mode 100644 metadata-viewer/build.rs + create mode 100644 metadata-viewer/src/args.rs + create mode 100644 metadata-viewer/src/main.rs + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index ca9fdfe..573752a 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -171,6 +171,7 @@ install( + ${RUST_OUTPUT_DIR}/upatch-helper + ${RUST_OUTPUT_DIR}/upatch-cc + ${RUST_OUTPUT_DIR}/upatch-c++ ++ ${RUST_OUTPUT_DIR}/metadata-viewer + PERMISSIONS + OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE +diff --git a/Cargo.toml b/Cargo.toml +index 07c796f..52a4255 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -6,7 +6,8 @@ members = [ + "syscare-build", + "syscared", + "upatch-build", +- "upatch-helper" ++ "upatch-helper", ++ "metadata-viewer", + ] + + [profile.release] +diff --git a/metadata-viewer/Cargo.toml b/metadata-viewer/Cargo.toml +new file mode 100644 +index 0000000..5bd367a +--- /dev/null ++++ b/metadata-viewer/Cargo.toml +@@ -0,0 +1,17 @@ ++[package] ++name = "metadata-viewer" ++version = "1.2.2" ++authors = ["renoseven "] ++description = "Syscare patch metadata viewer" ++license = "MulanPSL-2.0" ++edition = "2018" ++rust-version = "1.60" ++build = "build.rs" ++ ++[dependencies] ++syscare-abi = { package = "syscare-abi", path = "../syscare-abi" } ++syscare-common = { package = "syscare-common", path = "../syscare-common" } ++anyhow = { version = "1.0" } ++clap = { version = "3.2", features = ["cargo", "derive"] } ++flexi_logger = { version = "0.24" } ++log = { version = "0.4" } +diff --git a/metadata-viewer/build.rs b/metadata-viewer/build.rs +new file mode 100644 +index 0000000..d048b74 +--- /dev/null ++++ b/metadata-viewer/build.rs +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: Mulan PSL v2 ++/* ++ * Copyright (c) 2024 Huawei Technologies Co., Ltd. ++ * metadata-viewer is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, ++ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, ++ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++use std::{env, ffi::OsStr, os::unix::ffi::OsStrExt, process::Command}; ++ ++fn rewrite_version() { ++ const PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); ++ const ENV_VERSION: Option<&str> = option_env!("BUILD_VERSION"); ++ ++ println!( ++ "cargo:rustc-env=CARGO_PKG_VERSION={}", ++ ENV_VERSION.map(String::from).unwrap_or_else(|| { ++ Command::new("git") ++ .args(["rev-parse", "--short", "HEAD"]) ++ .output() ++ .map(|output| { ++ let git_version = OsStr::from_bytes(&output.stdout).to_string_lossy(); ++ format!("{}-g{}", PKG_VERSION, git_version) ++ }) ++ .unwrap_or_else(|_| PKG_VERSION.to_string()) ++ }) ++ ); ++} ++ ++fn main() { ++ rewrite_version(); ++} +diff --git a/metadata-viewer/src/args.rs b/metadata-viewer/src/args.rs +new file mode 100644 +index 0000000..bea01c0 +--- /dev/null ++++ b/metadata-viewer/src/args.rs +@@ -0,0 +1,66 @@ ++// SPDX-License-Identifier: Mulan PSL v2 ++/* ++ * Copyright (c) 2024 Huawei Technologies Co., Ltd. ++ * metadata-viewer is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, ++ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, ++ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++use std::path::PathBuf; ++ ++use anyhow::{ensure, Result}; ++use clap::{AppSettings, ColorChoice, Parser}; ++ ++use syscare_common::fs; ++ ++use crate::{CLI_ABOUT, CLI_NAME, CLI_VERSION}; ++ ++#[derive(Debug, Parser)] ++#[clap( ++ bin_name = CLI_NAME, ++ version = CLI_VERSION, ++ about = CLI_ABOUT, ++ arg_required_else_help(true), ++ color(ColorChoice::Never), ++ global_setting(AppSettings::DeriveDisplayOrder), ++ term_width(120), ++)] ++pub struct Arguments { ++ /// Metdata file ++ pub files: Vec, ++ /// Provide more detailed info ++ #[clap(short, long)] ++ pub verbose: bool, ++} ++ ++impl Arguments { ++ pub fn new() -> Result { ++ Self::parse().normalize()?.check() ++ } ++ ++ fn normalize(mut self) -> Result { ++ for file in &mut self.files { ++ *file = fs::normalize(&file)?; ++ } ++ Ok(self) ++ } ++ ++ fn check(self) -> Result { ++ for file in &self.files { ++ ensure!(file.is_file(), "Cannot find {}", file.display()) ++ } ++ Ok(self) ++ } ++} ++ ++impl std::fmt::Display for Arguments { ++ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ++ std::fmt::Debug::fmt(&self, f) ++ } ++} +diff --git a/metadata-viewer/src/main.rs b/metadata-viewer/src/main.rs +new file mode 100644 +index 0000000..8097788 +--- /dev/null ++++ b/metadata-viewer/src/main.rs +@@ -0,0 +1,91 @@ ++// SPDX-License-Identifier: Mulan PSL v2 ++/* ++ * Copyright (c) 2024 Huawei Technologies Co., Ltd. ++ * metadata-viewer is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, ++ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, ++ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++use std::env; ++ ++use anyhow::{Context, Result}; ++use flexi_logger::{LevelFilter, LogSpecification, Logger, WriteMode}; ++use log::{debug, info}; ++ ++use syscare_abi::{PatchInfo, PATCH_INFO_MAGIC}; ++use syscare_common::util::serde; ++ ++const CLI_NAME: &str = env!("CARGO_PKG_NAME"); ++const CLI_VERSION: &str = env!("CARGO_PKG_VERSION"); ++const CLI_ABOUT: &str = env!("CARGO_PKG_DESCRIPTION"); ++ ++mod args; ++use args::Arguments; ++ ++fn main() -> Result<()> { ++ let args = Arguments::new()?; ++ ++ let log_level = if args.verbose { ++ LevelFilter::Trace ++ } else { ++ LevelFilter::Info ++ }; ++ let log_spec = LogSpecification::builder().default(log_level).build(); ++ let _ = Logger::with(log_spec) ++ .log_to_stdout() ++ .format(|w, _, record| write!(w, "{}", record.args())) ++ .write_mode(WriteMode::Direct) ++ .start() ++ .context("Failed to initialize logger")?; ++ ++ debug!("==================================="); ++ debug!("{}", CLI_ABOUT); ++ debug!("Version: {}", CLI_VERSION); ++ debug!("==================================="); ++ debug!("{:#?}", args); ++ debug!(""); ++ ++ for file in &args.files { ++ let patch_info = serde::deserialize_with_magic::(file, PATCH_INFO_MAGIC)?; ++ ++ info!("============================================="); ++ info!("Patch: {}", patch_info.uuid); ++ info!("============================================="); ++ info!("{}", patch_info); ++ info!("---------------------------------------------"); ++ info!(""); ++ ++ info!("---------------------------------------------"); ++ info!("Patch target"); ++ info!("---------------------------------------------"); ++ info!("{}", patch_info.target); ++ info!("---------------------------------------------"); ++ info!(""); ++ ++ info!("---------------------------------------------"); ++ info!("Patch entity"); ++ info!("---------------------------------------------"); ++ for entity in &patch_info.entities { ++ info!("{}", entity); ++ info!("---------------------------------------------"); ++ } ++ info!(""); ++ ++ info!("---------------------------------------------"); ++ info!("Patch file"); ++ info!("---------------------------------------------"); ++ for patch in &patch_info.patches { ++ info!("{}", patch); ++ info!("---------------------------------------------"); ++ } ++ info!(""); ++ } ++ ++ Ok(()) ++} +-- +2.34.1 + diff --git a/0039-metadata-generator-add-component.patch b/0039-metadata-generator-add-component.patch new file mode 100644 index 0000000..cdf4b0d --- /dev/null +++ b/0039-metadata-generator-add-component.patch @@ -0,0 +1,533 @@ +From cce391fe5268723a890fdf9de78144ec046bd8d2 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Thu, 13 Feb 2025 11:27:26 +0800 +Subject: [PATCH] metadata-generator: add component + +Signed-off-by: renoseven +--- + CMakeLists.txt | 1 + + Cargo.toml | 1 + + metadata-generator/Cargo.toml | 18 +++ + metadata-generator/build.rs | 38 +++++ + metadata-generator/src/args.rs | 160 +++++++++++++++++++++ + metadata-generator/src/main.rs | 247 +++++++++++++++++++++++++++++++++ + 6 files changed, 465 insertions(+) + create mode 100644 metadata-generator/Cargo.toml + create mode 100644 metadata-generator/build.rs + create mode 100644 metadata-generator/src/args.rs + create mode 100644 metadata-generator/src/main.rs + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 573752a..2f658b9 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -172,6 +172,7 @@ install( + ${RUST_OUTPUT_DIR}/upatch-cc + ${RUST_OUTPUT_DIR}/upatch-c++ + ${RUST_OUTPUT_DIR}/metadata-viewer ++ ${RUST_OUTPUT_DIR}/metadata-generator + PERMISSIONS + OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE +diff --git a/Cargo.toml b/Cargo.toml +index 52a4255..a514352 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -8,6 +8,7 @@ members = [ + "upatch-build", + "upatch-helper", + "metadata-viewer", ++ "metadata-generator", + ] + + [profile.release] +diff --git a/metadata-generator/Cargo.toml b/metadata-generator/Cargo.toml +new file mode 100644 +index 0000000..f8f57c8 +--- /dev/null ++++ b/metadata-generator/Cargo.toml +@@ -0,0 +1,18 @@ ++[package] ++name = "metadata-generator" ++version = "1.2.2" ++authors = ["renoseven "] ++description = "Syscare patch metadata generator" ++license = "MulanPSL-2.0" ++edition = "2018" ++rust-version = "1.60" ++build = "build.rs" ++ ++[dependencies] ++syscare-abi = { package = "syscare-abi", path = "../syscare-abi" } ++syscare-common = { package = "syscare-common", path = "../syscare-common" } ++anyhow = { version = "1.0" } ++clap = { version = "3.2", features = ["cargo", "derive"] } ++flexi_logger = { version = "0.24" } ++lazy_static = { version = "1.0" } ++log = { version = "0.4" } +diff --git a/metadata-generator/build.rs b/metadata-generator/build.rs +new file mode 100644 +index 0000000..d565c2d +--- /dev/null ++++ b/metadata-generator/build.rs +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: Mulan PSL v2 ++/* ++ * Copyright (c) 2024 Huawei Technologies Co., Ltd. ++ * metadata-generator is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, ++ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, ++ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++use std::{env, ffi::OsStr, os::unix::ffi::OsStrExt, process::Command}; ++ ++fn rewrite_version() { ++ const PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); ++ const ENV_VERSION: Option<&str> = option_env!("BUILD_VERSION"); ++ ++ println!( ++ "cargo:rustc-env=CARGO_PKG_VERSION={}", ++ ENV_VERSION.map(String::from).unwrap_or_else(|| { ++ Command::new("git") ++ .args(["rev-parse", "--short", "HEAD"]) ++ .output() ++ .map(|output| { ++ let git_version = OsStr::from_bytes(&output.stdout).to_string_lossy(); ++ format!("{}-g{}", PKG_VERSION, git_version) ++ }) ++ .unwrap_or_else(|_| PKG_VERSION.to_string()) ++ }) ++ ); ++} ++ ++fn main() { ++ rewrite_version(); ++} +diff --git a/metadata-generator/src/args.rs b/metadata-generator/src/args.rs +new file mode 100644 +index 0000000..20e96b7 +--- /dev/null ++++ b/metadata-generator/src/args.rs +@@ -0,0 +1,160 @@ ++// SPDX-License-Identifier: Mulan PSL v2 ++/* ++ * Copyright (c) 2024 Huawei Technologies Co., Ltd. ++ * metadata-generator is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, ++ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, ++ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++use std::path::PathBuf; ++ ++use anyhow::{ensure, Result}; ++use clap::{AppSettings, ColorChoice, Parser}; ++use lazy_static::lazy_static; ++ ++use syscare_abi::Uuid; ++use syscare_common::{fs, os}; ++ ++use crate::{CLI_ABOUT, CLI_NAME, CLI_VERSION}; ++ ++const DEFAULT_PATCH_VERSION: &str = "1"; ++const DEFAULT_PATCH_RELEASE: &str = "1"; ++const DEFAULT_ARG_NONE: &str = "(none)"; ++const DEFAULT_OUTPUT_DIR: &str = "."; ++ ++lazy_static! { ++ static ref DEFAULT_PATCH_ARCH: String = os::cpu::arch().to_string_lossy().to_string(); ++} ++ ++#[derive(Debug, Parser)] ++#[clap( ++ bin_name = CLI_NAME, ++ version = CLI_VERSION, ++ about = CLI_ABOUT, ++ arg_required_else_help(true), ++ color(ColorChoice::Never), ++ global_setting(AppSettings::DeriveDisplayOrder), ++ term_width(120), ++)] ++pub struct Arguments { ++ /// Patch name ++ #[clap(short('n'), long)] ++ pub name: String, ++ ++ /// Patch uuid ++ #[clap(long, multiple = true)] ++ pub uuid: Vec, ++ ++ /// Patch version ++ #[clap(long, default_value = DEFAULT_PATCH_VERSION)] ++ pub version: String, ++ ++ /// Patch release ++ #[clap(long, default_value = DEFAULT_PATCH_RELEASE)] ++ pub release: u32, ++ ++ /// Patch architecture ++ #[clap(long, default_value = &DEFAULT_PATCH_ARCH)] ++ pub arch: String, ++ ++ /// Patch target package ++ #[clap(short('s'), long)] ++ pub target: String, ++ ++ /// Patch entity target(s) ++ #[clap(short('t'), long, multiple = true, required = true)] ++ pub entity_target: Vec, ++ ++ /// Patch entity patch(es) ++ #[clap(short('p'), long, multiple = true, required = true)] ++ pub entity_patch: Vec, ++ ++ /// Patch license ++ #[clap(long, default_value = DEFAULT_ARG_NONE)] ++ pub license: String, ++ ++ /// Patch description ++ #[clap(long, default_value = DEFAULT_ARG_NONE)] ++ pub description: String, ++ ++ /// Patch file(s) ++ #[clap(short('f'), long, multiple = true, required = true)] ++ pub patch_file: Vec, ++ ++ /// Output directory ++ #[clap(short('o'), long, default_value = DEFAULT_OUTPUT_DIR)] ++ pub output_dir: PathBuf, ++ ++ /// Provide more detailed info ++ #[clap(short('v'), long)] ++ pub verbose: bool, ++} ++ ++impl Arguments { ++ pub fn new() -> Result { ++ Self::parse().normalize()?.generate_uuids().check() ++ } ++ ++ fn normalize(mut self) -> Result { ++ for entity_target in &mut self.entity_target { ++ *entity_target = fs::normalize(&entity_target)?; ++ } ++ for entity_patch in &mut self.entity_patch { ++ *entity_patch = fs::normalize(&entity_patch)?; ++ } ++ for patch_file in &mut self.patch_file { ++ *patch_file = fs::normalize(&patch_file)?; ++ } ++ self.output_dir = fs::normalize(&self.output_dir)?; ++ ++ Ok(self) ++ } ++ ++ fn generate_uuids(mut self) -> Self { ++ if self.uuid.is_empty() { ++ // Uuids would contains patch uuid & entity uuids ++ let uuid_num = self.entity_target.len() + 1; ++ let new_uuids = (0..uuid_num).map(|_| Uuid::new_v4()).collect(); ++ ++ self.uuid = new_uuids; ++ } ++ self ++ } ++ ++ fn check(self) -> Result { ++ ensure!( ++ self.uuid.len() == (self.entity_target.len() + 1), ++ "Argument length of '--uuid' and '--entity-target' does not match" ++ ); ++ ensure!( ++ self.entity_target.len() == self.entity_patch.len(), ++ "Argument length of '--entity-target' and '--entity-patch' does not match" ++ ); ++ ++ /* Would not check entity target, since it may be not a valid path */ ++ for entity_patch in &self.entity_patch { ++ ensure!( ++ entity_patch.is_file(), ++ "Cannot find {}", ++ entity_patch.display() ++ ) ++ } ++ for patch_file in &self.patch_file { ++ ensure!(patch_file.is_file(), "Cannot find {}", patch_file.display()) ++ } ++ ++ Ok(self) ++ } ++} ++ ++impl std::fmt::Display for Arguments { ++ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ++ std::fmt::Debug::fmt(&self, f) ++ } ++} +diff --git a/metadata-generator/src/main.rs b/metadata-generator/src/main.rs +new file mode 100644 +index 0000000..b37a5e3 +--- /dev/null ++++ b/metadata-generator/src/main.rs +@@ -0,0 +1,247 @@ ++// SPDX-License-Identifier: Mulan PSL v2 ++/* ++ * Copyright (c) 2024 Huawei Technologies Co., Ltd. ++ * metadata-generator is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, ++ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, ++ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++use std::{ ++ collections::HashSet, ++ env, ++ path::{Component, Path, PathBuf}, ++}; ++ ++use anyhow::{bail, Context, Result}; ++use flexi_logger::{LevelFilter, LogSpecification, Logger, WriteMode}; ++use log::{debug, info}; ++ ++use syscare_abi::{ ++ PackageInfo, PackageType, PatchEntity, PatchFile, PatchInfo, PatchType, PATCH_INFO_MAGIC, ++}; ++use syscare_common::{ ++ fs, os, ++ util::{digest, serde}, ++}; ++ ++const CLI_NAME: &str = env!("CARGO_PKG_NAME"); ++const CLI_VERSION: &str = env!("CARGO_PKG_VERSION"); ++const CLI_ABOUT: &str = env!("CARGO_PKG_DESCRIPTION"); ++const CLI_UMASK: u32 = 0o022; ++ ++const KERNEL_PATCH_EXTENSION: &str = "ko"; ++const METADATA_FILE_NAME: &str = "patch_info"; ++ ++mod args; ++use args::Arguments; ++ ++fn detect_patch_type(args: &Arguments) -> PatchType { ++ for patch in &args.entity_patch { ++ if patch.extension().unwrap_or_default() == KERNEL_PATCH_EXTENSION { ++ return PatchType::KernelPatch; ++ } ++ } ++ PatchType::UserPatch ++} ++ ++fn parse_target_string(target: &str) -> Option<(&str, &str, &str, &str)> { ++ const PKG_INFO_SPLITTER: char = '-'; ++ const PKG_NAME_SPLITTER: char = ':'; ++ const PKG_DEFAULT_TAG: &str = "(none)"; ++ ++ let mut split = target.rsplitn(3, PKG_INFO_SPLITTER); ++ ++ let release = split.next()?; ++ let version = split.next()?; ++ let name_epoch = split.next()?; ++ let (name, epoch) = name_epoch ++ .split_once(PKG_NAME_SPLITTER) ++ .map_or((name_epoch, PKG_DEFAULT_TAG), |(name, epoch)| (name, epoch)); ++ ++ Some((name, epoch, version, release)) ++} ++ ++fn parse_target_package(args: &Arguments) -> Result { ++ let (name, epoch, version, release) = self::parse_target_string(&args.target) ++ .with_context(|| format!("Patch target package '{}' is invalid", args.target))?; ++ let pkg_info = PackageInfo { ++ name: name.to_string(), ++ kind: PackageType::SourcePackage, ++ arch: args.arch.clone(), ++ epoch: epoch.to_string(), ++ version: version.to_string(), ++ release: release.to_string(), ++ license: args.license.clone(), ++ source_pkg: format!("{}-{}-{}.src.rpm", name, version, release), ++ }; ++ ++ debug!("* {:#?}", pkg_info); ++ Ok(pkg_info) ++} ++ ++fn parse_patch_entities(args: &Arguments) -> Result> { ++ let mut entities = vec![]; ++ let mut target_set = HashSet::new(); ++ let mut patch_set = HashSet::new(); ++ ++ let mut uuid_iter = args.uuid[1..].iter(); ++ let mut target_iter = args.entity_target.iter(); ++ let mut patch_iter = args.entity_patch.iter(); ++ while let (Some(uuid), Some(target), Some(patch)) = ++ (uuid_iter.next(), target_iter.next(), patch_iter.next()) ++ { ++ if !target_set.insert(target) { ++ bail!("Found duplicated patch target {}", target.display()); ++ } ++ if !patch_set.insert(patch) { ++ bail!("Found duplicated patch binary {}", patch.display()); ++ } ++ ++ let entity = PatchEntity { ++ uuid: *uuid, ++ patch_name: patch ++ .file_name() ++ .map(|name| { ++ let mut name = PathBuf::from(name); ++ if name.extension().unwrap_or_default() == KERNEL_PATCH_EXTENSION { ++ name.set_extension(""); ++ } ++ name.into_os_string() ++ }) ++ .context("Failed to parse patch binary name")?, ++ patch_target: target.to_path_buf(), ++ checksum: digest::file(patch).context("Failed to calculate patch binary checksum")?, ++ }; ++ ++ debug!("* {:#?}", entity); ++ entities.push(entity); ++ } ++ ++ Ok(entities) ++} ++ ++fn parse_patch_files(args: &Arguments) -> Result> { ++ let mut patches = vec![]; ++ let mut patch_set = HashSet::new(); ++ ++ for patch in &args.patch_file { ++ if !patch_set.insert(patch) { ++ bail!("Found duplicated patch file {}", patch.display()); ++ } ++ let name = patch ++ .file_name() ++ .context("Failed to parse patch file name")?; ++ let file = PatchFile { ++ name: name.to_os_string(), ++ path: Path::new(&Component::CurDir).join(name), ++ digest: digest::file(patch).context("Failed to calculate patch file checksum")?, ++ }; ++ ++ debug!("* {:#?}", file); ++ patches.push(file); ++ } ++ ++ Ok(patches) ++} ++ ++fn generate_patch_metadata(args: &Arguments) -> Result { ++ let patch_info = PatchInfo { ++ uuid: args.uuid[0], ++ name: args.name.clone(), ++ version: args.version.clone(), ++ release: args.release, ++ arch: args.arch.clone(), ++ kind: self::detect_patch_type(args), ++ target: self::parse_target_package(args)?, ++ entities: self::parse_patch_entities(args)?, ++ description: args.description.clone(), ++ patches: self::parse_patch_files(args)?, ++ }; ++ Ok(patch_info) ++} ++ ++fn write_patch_metadata(patch_info: &PatchInfo, output_dir: &Path) -> Result<()> { ++ serde::serialize_with_magic( ++ &patch_info, ++ output_dir.join(METADATA_FILE_NAME), ++ PATCH_INFO_MAGIC, ++ )?; ++ Ok(()) ++} ++ ++fn copy_patch_files(patch_files: &[PathBuf], output_dir: &Path) -> Result<()> { ++ for src_path in patch_files { ++ let dst_path = output_dir.join( ++ src_path ++ .file_name() ++ .context("Failed to parse patch file name")?, ++ ); ++ fs::copy(src_path, &dst_path)?; ++ } ++ Ok(()) ++} ++ ++fn main_process(args: &Arguments, output_dir: &Path) -> Result<()> { ++ debug!("Generating patch metadata..."); ++ let patch_info = ++ self::generate_patch_metadata(args).context("Failed to generate patch metadata")?; ++ ++ debug!("Writing patch metadata..."); ++ self::write_patch_metadata(&patch_info, output_dir) ++ .context("Failed to write patch metadata")?; ++ ++ debug!("Copying patch files..."); ++ self::copy_patch_files(&args.entity_patch, output_dir).context("Failed to copy patch files")?; ++ ++ info!("---------------------------------------------"); ++ info!("Patch: {}", patch_info.uuid); ++ info!("---------------------------------------------"); ++ info!("{}", patch_info); ++ info!("---------------------------------------------"); ++ info!(""); ++ info!("Output: {}", output_dir.display()); ++ ++ Ok(()) ++} ++ ++fn main() -> Result<()> { ++ let args = Arguments::new()?; ++ os::umask::set_umask(CLI_UMASK); ++ ++ let log_level = if args.verbose { ++ LevelFilter::Trace ++ } else { ++ LevelFilter::Info ++ }; ++ let log_spec = LogSpecification::builder().default(log_level).build(); ++ let _ = Logger::with(log_spec) ++ .log_to_stdout() ++ .format(|w, _, record| write!(w, "{}", record.args())) ++ .write_mode(WriteMode::Direct) ++ .start() ++ .context("Failed to initialize logger")?; ++ ++ debug!("==================================="); ++ debug!("{}", CLI_ABOUT); ++ debug!("Version: {}", CLI_VERSION); ++ debug!("==================================="); ++ debug!("{:#?}", args); ++ debug!(""); ++ ++ let output_dir = PathBuf::from(&args.output_dir).join(args.uuid[0].to_string()); ++ fs::create_dir_all(&output_dir).context("Failed to carete output directory")?; ++ ++ if let Err(e) = self::main_process(&args, &output_dir) { ++ fs::remove_dir_all(&output_dir).ok(); ++ return Err(e); ++ } ++ ++ debug!("Done"); ++ Ok(()) ++} +-- +2.34.1 + diff --git a/0040-project-update-Cargo.lock.patch b/0040-project-update-Cargo.lock.patch new file mode 100644 index 0000000..a3ea709 --- /dev/null +++ b/0040-project-update-Cargo.lock.patch @@ -0,0 +1,49 @@ +From be50605c9b97f43af34e5bfdd284927514e9cdd4 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Thu, 13 Feb 2025 11:38:02 +0800 +Subject: [PATCH] project: update Cargo.lock + +Signed-off-by: renoseven +--- + Cargo.lock | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/Cargo.lock b/Cargo.lock +index 6ae9f36..ce0177e 100644 +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -679,6 +679,31 @@ dependencies = [ + "autocfg", + ] + ++[[package]] ++name = "metadata-generator" ++version = "1.2.2" ++dependencies = [ ++ "anyhow", ++ "clap", ++ "flexi_logger", ++ "lazy_static", ++ "log", ++ "syscare-abi", ++ "syscare-common", ++] ++ ++[[package]] ++name = "metadata-viewer" ++version = "1.2.2" ++dependencies = [ ++ "anyhow", ++ "clap", ++ "flexi_logger", ++ "log", ++ "syscare-abi", ++ "syscare-common", ++] ++ + [[package]] + name = "miniz_oxide" + version = "0.5.4" +-- +2.34.1 + diff --git a/0041-syscared-fix-patch-target-is-blocked-issue.patch b/0041-syscared-fix-patch-target-is-blocked-issue.patch new file mode 100644 index 0000000..ea4d93f --- /dev/null +++ b/0041-syscared-fix-patch-target-is-blocked-issue.patch @@ -0,0 +1,26 @@ +From d8d7101dd519bbbd145c0735309bd0c3b5c7f253 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Mon, 3 Mar 2025 17:22:10 +0800 +Subject: [PATCH] syscared: fix 'patch target is blocked' issue + +Signed-off-by: renoseven +--- + syscared/src/patch/driver/kpatch/mod.rs | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/syscared/src/patch/driver/kpatch/mod.rs b/syscared/src/patch/driver/kpatch/mod.rs +index 349d495..bdcdd4c 100644 +--- a/syscared/src/patch/driver/kpatch/mod.rs ++++ b/syscared/src/patch/driver/kpatch/mod.rs +@@ -254,7 +254,7 @@ impl KernelPatchDriver { + ); + + ensure!( +- self.blocked_targets.contains(&patch.target_name), ++ !self.blocked_targets.contains(&patch.target_name), + "Patch target '{}' is blocked", + patch.target_name.to_string_lossy(), + ); +-- +2.34.1 + diff --git a/0042-riscv64-sync-riscv64-support-from-master-to-2503.patch b/0042-riscv64-sync-riscv64-support-from-master-to-2503.patch new file mode 100644 index 0000000..148d896 --- /dev/null +++ b/0042-riscv64-sync-riscv64-support-from-master-to-2503.patch @@ -0,0 +1,1230 @@ +From 0261efdbb718dd4850232940f9f9b7f156b19675 Mon Sep 17 00:00:00 2001 +From: Jvle +Date: Mon, 3 Mar 2025 10:14:04 +0800 +Subject: [PATCH] riscv64: sync riscv64 support from master to 2503 + +sync from 64e3f03f467be4756d546f68ecbfce5ec93e0d42 + +Signed-off-by: Jvle +--- + README.md | 11 ++ + upatch-diff/create-diff-object.c | 28 ++- + upatch-diff/elf-common.c | 41 +++- + upatch-diff/elf-common.h | 2 + + upatch-diff/elf-compare.c | 4 +- + upatch-diff/elf-insn.c | 8 + + upatch-diff/elf-insn.h | 5 + + upatch-diff/running-elf.c | 1 - + upatch-diff/upatch-elf.c | 14 +- + upatch-diff/upatch-elf.h | 1 + + upatch-manage/arch/riscv64/insn.h | 123 ++++++++++++ + upatch-manage/arch/riscv64/process.h | 28 +++ + upatch-manage/arch/riscv64/ptrace.c | 207 ++++++++++++++++++++ + upatch-manage/arch/riscv64/relocation.c | 242 ++++++++++++++++++++++++ + upatch-manage/arch/riscv64/resolve.c | 154 +++++++++++++++ + upatch-manage/upatch-patch.c | 22 +++ + upatch-manage/upatch-ptrace.c | 4 + + upatch-manage/upatch-ptrace.h | 8 + + 18 files changed, 894 insertions(+), 9 deletions(-) + create mode 100644 upatch-manage/arch/riscv64/insn.h + create mode 100644 upatch-manage/arch/riscv64/process.h + create mode 100644 upatch-manage/arch/riscv64/ptrace.c + create mode 100644 upatch-manage/arch/riscv64/relocation.c + create mode 100644 upatch-manage/arch/riscv64/resolve.c + +diff --git a/README.md b/README.md +index 15d4d48..b34a6c1 100644 +--- a/README.md ++++ b/README.md +@@ -33,6 +33,8 @@ + + * 编译并安装 + ++ PS: 直接编译在应用补丁的时候会显示缺少依赖,建议通过rpm包安装 ++ + ```bash + git clone https://gitee.com/openeuler/syscare.git + cd syscare +@@ -41,6 +43,11 @@ + cmake -DCMAKE_INSTALL_PREFIX=/usr -DKERNEL_VERSION=$(uname -r) .. + make + make install ++ ++ mkdir -p /usr/lib/syscare/patches ++ systemctl daemon-reload ++ systemctl enable syscare ++ systemctl start syscare + ``` + + * 离线编译 +@@ -63,7 +70,11 @@ + ```bash + rpm -ivh syscare-*.rpm + ``` ++或者 + ++``` ++dnf install syscare-*.rpm ++``` + + + ## 使用说明 +diff --git a/upatch-diff/create-diff-object.c b/upatch-diff/create-diff-object.c +index 1c14b7a..a06599e 100644 +--- a/upatch-diff/create-diff-object.c ++++ b/upatch-diff/create-diff-object.c +@@ -614,7 +614,8 @@ static void replace_section_syms(struct upatch_elf *uelf) + !is_text_section(sym->sec) && + (rela->type == R_X86_64_32S || + rela->type == R_X86_64_32 || +- rela->type == R_AARCH64_ABS64) && ++ rela->type == R_AARCH64_ABS64 || ++ rela->type == R_RISCV_64) && + rela->addend == (long)sym->sec->sh.sh_size && + end == (long)sym->sec->sh.sh_size) { + ERROR("Relocation refer end of data sections."); +@@ -759,6 +760,12 @@ static void include_symbol(struct symbol *sym) + if (sym->sec && (sym->type == STT_SECTION || sym->status != SAME)) { + include_section(sym->sec); + } ++#ifdef __riscv ++ /* .L symbols not exist in EXE. If they are included, so are their sections. */ ++ else if (sym->sec && !sym->sec->include && !strncmp(sym->name, ".L", 2)) { ++ include_section(sym->sec); ++ } ++#endif + } + + static void include_section(struct section *sec) +@@ -949,6 +956,23 @@ static void verify_patchability(struct upatch_elf *uelf) + } + } + ++/* ++ * These types are for linker optimization and memory layout. ++ * They have no associated symbols and their names are empty ++ * string which would mismatch running-elf symbols in later ++ * lookup_relf(). Drop these useless items now. ++ */ ++static void rv_drop_useless_rela(struct section *relasec) ++{ ++ struct rela *rela, *saferela; ++ list_for_each_entry_safe(rela, saferela, &relasec->relas, list) ++ if (rela->type == R_RISCV_RELAX || rela->type == R_RISCV_ALIGN) { ++ list_del(&rela->list); ++ memset(rela, 0, sizeof(*rela)); ++ free(rela); ++ } ++} ++ + static void migrate_included_elements(struct upatch_elf *uelf_patched, + struct upatch_elf *uelf_out) + { +@@ -975,6 +999,8 @@ static void migrate_included_elements(struct upatch_elf *uelf_patched, + + if (!is_rela_section(sec) && sec->secsym && !sec->secsym->include) { + sec->secsym = NULL; // break link to non-included section symbol ++ } else if (uelf_patched->arch == RISCV64) { ++ rv_drop_useless_rela(sec); + } + } + +diff --git a/upatch-diff/elf-common.c b/upatch-diff/elf-common.c +index 5aa35f1..3b62a5e 100644 +--- a/upatch-diff/elf-common.c ++++ b/upatch-diff/elf-common.c +@@ -26,6 +26,35 @@ + + #include "elf-common.h" + ++#ifdef __riscv ++/* ++ * .L local symbols are named as ".L" + "class prefix" + "number". ++ * The numbers are volatile due to code change. ++ * Compare class prefix(composed of letters) only. ++ */ ++static int mangled_strcmp_dot_L(char *str1, char *str2) ++{ ++ if (!*str2 || strncmp(str2, ".L", 2)) { ++ return 1; ++ } ++ ++ /* RISCV_FAKE_LABEL_NAME matched exactly */ ++ if (!strcmp(str1, ".L0 ") || !strcmp(str2, ".L0 ")) { ++ return strcmp(str1, str2); ++ } ++ ++ char *p = str1 + 2; ++ char *q = str2 + 2; ++ while (*p < '0' || *p > '9') p++; ++ while (*q < '0' || *q > '9') q++; ++ if ((p - str1 != q - str2) || strncmp(str1, str2, p - str1)) { ++ return 1; ++ } ++ ++ return 0; ++} ++#endif ++ + int mangled_strcmp(char *str1, char *str2) + { + /* +@@ -35,6 +64,12 @@ int mangled_strcmp(char *str1, char *str2) + return strcmp(str1, str2); + } + ++#ifdef __riscv ++ if (!strncmp(str1, ".L", 2)) { ++ return mangled_strcmp_dot_L(str1, str2); ++ } ++#endif ++ + while (*str1 == *str2) { + if (!*str2) { + return 0; +@@ -100,7 +135,6 @@ int offset_of_string(struct list_head *list, char *name) + + ALLOC_LINK(string, list); + string->name = name; +- + return index; + } + +@@ -112,16 +146,17 @@ bool is_gcc6_localentry_bundled_sym(struct upatch_elf *uelf) + return false; + case X86_64: + return false; ++ case RISCV64: ++ return false; + default: + ERROR("unsupported arch"); + } +- + return false; + } + + bool is_mapping_symbol(struct upatch_elf *uelf, struct symbol *sym) + { +- if (uelf->arch != AARCH64) { ++ if ((uelf->arch != AARCH64) && (uelf->arch != RISCV64)) { + return false; + } + if (sym->name && sym->name[0] == '$' && +diff --git a/upatch-diff/elf-common.h b/upatch-diff/elf-common.h +index bc2c1ac..0127314 100644 +--- a/upatch-diff/elf-common.h ++++ b/upatch-diff/elf-common.h +@@ -224,6 +224,8 @@ static inline unsigned int absolute_rela_type(struct upatch_elf *uelf) + return R_AARCH64_ABS64; + case X86_64: + return R_X86_64_64; ++ case RISCV64: ++ return R_RISCV_64; + default: + ERROR("unsupported arch"); + } +diff --git a/upatch-diff/elf-compare.c b/upatch-diff/elf-compare.c +index 7ca6845..da31522 100644 +--- a/upatch-diff/elf-compare.c ++++ b/upatch-diff/elf-compare.c +@@ -175,7 +175,6 @@ bool upatch_handle_redis_line(const char *symname) + !strncmp(symname, "RedisModule__Assert", 19)) { + return true; + } +- + return false; + } + +@@ -362,6 +361,9 @@ static bool line_macro_change_only(struct upatch_elf *uelf, struct section *sec) + return line_macro_change_only_aarch64(uelf, sec); + case X86_64: + return line_macro_change_only_x86_64(uelf, sec); ++ case RISCV64: ++ /* TODO: not support */ ++ break; + default: + ERROR("unsupported arch"); + } +diff --git a/upatch-diff/elf-insn.c b/upatch-diff/elf-insn.c +index 8fcfc39..bb913dd 100644 +--- a/upatch-diff/elf-insn.c ++++ b/upatch-diff/elf-insn.c +@@ -66,6 +66,8 @@ long rela_target_offset(struct upatch_elf *uelf, struct section *relasec, struct + long add_off; + + switch (uelf->arch) { ++ case RISCV64: ++ /* fall through */ + case AARCH64: + add_off = 0; + break; +@@ -105,6 +107,12 @@ unsigned int insn_length(struct upatch_elf *uelf, void *addr) + insn_init(&decoded_insn, addr, 1); + insn_get_length(&decoded_insn); + return decoded_insn.length; ++ case RISCV64: ++ /* LSB 2 bits distinguish insn size. Now only RV32, RVC supported. */ ++ if ((*(char *)addr & 0x3) == 0x3) { ++ return RISCV64_INSN_LEN_4; ++ } ++ return RISCV64_INSN_LEN_2; + default: + ERROR("unsupported arch"); + } +diff --git a/upatch-diff/elf-insn.h b/upatch-diff/elf-insn.h +index f64ebe1..96d2225 100644 +--- a/upatch-diff/elf-insn.h ++++ b/upatch-diff/elf-insn.h +@@ -29,8 +29,13 @@ + #include "asm/insn.h" + #include "upatch-elf.h" + ++// arm + #define ARM64_INSTR_LEN 4 + ++// riscv ++#define RISCV64_INSN_LEN_4 4 ++#define RISCV64_INSN_LEN_2 2 ++ + void rela_insn(const struct section *sec, const struct rela *rela, struct insn *insn); + + /* +diff --git a/upatch-diff/running-elf.c b/upatch-diff/running-elf.c +index d9c1d6f..61c5057 100644 +--- a/upatch-diff/running-elf.c ++++ b/upatch-diff/running-elf.c +@@ -86,7 +86,6 @@ void relf_init(char *elf_name, struct running_elf *relf) + if (!data) { + ERROR("elf_getdata with error %s", elf_errmsg(0)); + } +- + relf->obj_nr = (int)(shdr.sh_size / shdr.sh_entsize); + relf->obj_syms = calloc((size_t)relf->obj_nr, sizeof(struct debug_symbol)); + if (!relf->obj_syms) { +diff --git a/upatch-diff/upatch-elf.c b/upatch-diff/upatch-elf.c +index a51f008..06a3123 100644 +--- a/upatch-diff/upatch-elf.c ++++ b/upatch-diff/upatch-elf.c +@@ -89,7 +89,7 @@ static void create_section_list(struct upatch_elf *uelf) + } + + log_debug("ndx %02d, data %p, size %zu, name %s\n", +- sec->index, sec->data->d_buf, sec->data->d_size, sec->name); ++ sec->index, sec->data->d_buf, sec->data->d_size, sec->name); + } + + if (elf_nextscn(uelf->elf, scn)) { +@@ -111,7 +111,6 @@ static void create_symbol_list(struct upatch_elf *uelf) + if (!symtab) { + ERROR("can't find symbol table"); + } +- + symbols_nr = (unsigned int)(symtab->sh.sh_size / symtab->sh.sh_entsize); + + log_debug("\n=== symbol list (%d entries) ===\n", symbols_nr); +@@ -130,7 +129,6 @@ static void create_symbol_list(struct upatch_elf *uelf) + if (!sym->name) { + ERROR("elf_strptr with error %s", elf_errmsg(0)); + } +- + sym->type = GELF_ST_TYPE(sym->sym.st_info); + sym->bind = GELF_ST_BIND(sym->sym.st_info); + +@@ -368,6 +366,16 @@ void upatch_elf_open(struct upatch_elf *uelf, const char *name) + case EM_X86_64: + uelf->arch = X86_64; + break; ++ case EM_RISCV: ++ /* ++ | Val | Macros | Description | ++ | 1 | ELFCLASS32 | riscv32 | ++ | 2 | ELFCLASS64 | riscv64 | ++ */ ++ if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { ++ uelf->arch = RISCV64; ++ } ++ break; + default: + ERROR("unsupported architecture here"); + } +diff --git a/upatch-diff/upatch-elf.h b/upatch-diff/upatch-elf.h +index 030feca..7597e8e 100644 +--- a/upatch-diff/upatch-elf.h ++++ b/upatch-diff/upatch-elf.h +@@ -126,6 +126,7 @@ struct symbol { + enum architecture { + X86_64 = 0x1 << 0, + AARCH64 = 0x1 << 1, ++ RISCV64 = 0x1 << 2, + }; + + struct upatch_elf { +diff --git a/upatch-manage/arch/riscv64/insn.h b/upatch-manage/arch/riscv64/insn.h +new file mode 100644 +index 0000000..8ab4daf +--- /dev/null ++++ b/upatch-manage/arch/riscv64/insn.h +@@ -0,0 +1,123 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2024 laokz ++ */ ++ ++#ifndef _ARCH_RISCV64_INSN_H ++#define _ARCH_RISCV64_INSN_H ++ ++static inline unsigned set_utype_imm(unsigned ins, unsigned long imm) ++{ ++ /* + imm[11] to counteract lo12 sign extension in next instruction */ ++ unsigned long temp_imm = imm; ++ temp_imm += (temp_imm & 0x800) << 1; ++ return (temp_imm & 0xfffff000) | (ins & 0xfff); ++} ++ ++static inline unsigned set_itype_imm(unsigned ins, unsigned long imm) ++{ ++ return ((imm & 0xfff) << 20) | (ins & 0xfffff); ++} ++ ++static inline unsigned set_stype_imm(unsigned ins, unsigned long imm) ++{ ++ /* rs2 rs1 func opcode ++ ins: imm[11-8,7-5] 1,1111, 1111,1 111, imm[4-1,0] 111,1111 ++ ins mask 0 1 f f f 0 7 f ++ ++ imm bit no. 11-----5 4---0 ++ 1111,111 1,1111 ++ imm mask fe0 1f ++ ++ ==>imm bit no. 31----25 11--7 ++ */ ++ return (ins & 0x1fff07f) | ++ ((imm & 0xfe0) << (31 - 11)) | ((imm & 0x1f) << (11 - 4)); ++} ++ ++static inline unsigned set_jtype_imm(unsigned ins, unsigned long imm) ++{ ++ /* ++ imm bit no. 20 19------12 11 10---------1 ++ 1, 1111,1111, 1 111,1111,111 0 ++ mask 100000 ff000 800 7fe ++ ++ ==>imm bit no. 31 19------12 20 30---------21 ++ */ ++ return (ins & 0xfff) | ++ ((imm & 0x100000) << (31 - 20)) | (imm & 0xff000) | ++ ((imm & 0x800) << (20 - 11)) | ((imm & 0x7fe) << (30 - 10)); ++} ++ ++static inline unsigned set_btype_imm(unsigned ins, unsigned long imm) ++{ ++ /* rs2 rs1 func opcode ++ ins: imm[12 10-8,7-5] 1,1111, 1111,1 111, imm[4-1,11] 111,1111 ++ ins mask 0 1 f f f 0 7 f ++ ++ imm bit no. 12 11 10----5 4--1 ++ 1, 1 111,111 1,111 0 ++ imm mask 1000 800 7e0 1e ++ ++ ==>imm bit no. 31 7 30---25 11-8 ++ */ ++ return (ins & 0x01fff07f) | ++ ((imm & 0x1000) << (31 - 12)) | ((imm & 0x800) >> (11 - 7)) | ++ ((imm & 0x7e0) << (30 - 10)) | ((imm & 0x1e) << (11 - 4)); ++} ++ ++static inline unsigned short set_cjtype_imm(unsigned short ins, unsigned long imm) ++{ ++ /* funct3 imm opcode ++ ins: 111 offset[11,4 9 8 10, 6 7 3 2, 1 5] 11 ++ ins mask e 0 0 3 ++ ++ imm bit no. 11 10 9-8 7 6 5 4 3-1 ++ 1 1 11, 1 1 1 1, 111 0 ++ imm mask 800 400 300 80 40 20 10 e ++ ++ ==>imm bit no. 12 8 10-9 6 7 2 11 5-3 ++ */ ++ return (ins & 0xe003) | ++ ((imm & 0x800) << (12 - 11)) | ((imm & 0x400) >> (10 - 8)) | ++ ((imm & 0x300) << (10 - 9)) | ((imm & 0x80) >> (7 - 6)) | ++ ((imm & 0x40) << (7 - 6)) | ((imm & 0x20) >> (5 - 2)) | ++ ((imm & 0x10) << (11 - 4)) | ((imm & 0xe) << (5 - 3)); ++} ++ ++/* only support C.LUI */ ++static inline unsigned short set_citype_imm(unsigned short ins, unsigned long imm) ++{ ++ /* funct3 imm[17] rd imm[16:12] opcode ++ ins: 111 imm[17], 1111,1 imm[16-14,13-12] 11 ++ ins mask e f 8 3 ++ ++ imm bit no. 17 16--12 ++ 1 1,1111 ++ imm mask 20000 1f000 ++ ++ ==>imm bit no. 12 6---2 ++ */ ++ return (ins & 0xef83) | ++ ((imm & 0x20000) >> (17 - 12)) | ((imm & 0x1f000) >> (16 - 6)); ++} ++ ++/* only support C.BEQZ C.BNEZ */ ++static inline unsigned short set_cbtype_imm(unsigned short ins, unsigned long imm) ++{ ++ /* funct3 imm[8 4 3] rs imm[7 6 2 1 5] opcode ++ ins: 111 0,0 0 11,1 0 0 0,0 0 11 ++ ins mask e 3 8 3 ++ ++ imm bit no. 8 , 7 6 5 4,3 2 1 0 ++ imm mask 100 c0 20 18 6 ++ ++ ==>imm bit no. 12 6-5 2 11-10 4-3 ++ */ ++ return (ins & 0xe383) | ++ ((imm & 0x100) << (12 - 8)) | ((imm & 0xc0) >> (7 - 6)) | ++ ((imm & 0x20) >> (5 - 2)) | ((imm & 0x18) << (11 - 4)) | ++ ((imm & 0x6) << (4 - 2)); ++} ++ ++#endif +diff --git a/upatch-manage/arch/riscv64/process.h b/upatch-manage/arch/riscv64/process.h +new file mode 100644 +index 0000000..91926fa +--- /dev/null ++++ b/upatch-manage/arch/riscv64/process.h +@@ -0,0 +1,28 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * upatch-manage ++ * Copyright (C) 2024 ISCAS ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#ifndef __PROCESS__ ++#define __PROCESS__ ++ ++#ifndef MAX_DISTANCE ++#define MAX_DISTANCE 0x80000000 ++#endif ++ ++#endif +diff --git a/upatch-manage/arch/riscv64/ptrace.c b/upatch-manage/arch/riscv64/ptrace.c +new file mode 100644 +index 0000000..c5691c9 +--- /dev/null ++++ b/upatch-manage/arch/riscv64/ptrace.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * upatch-manage ++ * Copyright (C) 2024 ISCAS ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "upatch-ptrace.h" ++ ++int upatch_arch_reg_init(int pid, unsigned long *sp, unsigned long *pc) ++{ ++ struct iovec regs_iov; ++ struct user_regs_struct regs; ++ ++ regs_iov.iov_base = ®s; ++ regs_iov.iov_len = sizeof(regs); ++ ++ if (ptrace(PTRACE_GETREGSET, pid, ++ (void *)NT_PRSTATUS, (void *)®s_iov) < 0) { ++ log_error("Cannot get regs from %d\n", pid); ++ return -1; ++ } ++ *sp = (unsigned long)regs.sp; ++ *pc = (unsigned long)regs.pc; ++ return 0; ++} ++ ++static long read_gregs(int pid, struct user_regs_struct *regs) ++{ ++ struct iovec data = {regs, sizeof(*regs)}; ++ if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &data) == -1) { ++ log_error("ptrace(PTRACE_GETREGSET)"); ++ return -1; ++ } ++ return 0; ++} ++ ++static long write_gregs(int pid, struct user_regs_struct *regs) ++{ ++ struct iovec data = {regs, sizeof(*regs)}; ++ if (ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &data) == -1) { ++ log_error("ptrace(PTRACE_SETREGSET)"); ++ return -1; ++ } ++ return 0; ++} ++ ++long upatch_arch_syscall_remote(struct upatch_ptrace_ctx *pctx, int nr, ++ unsigned long arg1, unsigned long arg2, ++ unsigned long arg3, unsigned long arg4, ++ unsigned long arg5, unsigned long arg6, ++ unsigned long *res) ++{ ++ struct user_regs_struct regs; ++ unsigned char syscall[] = { ++ 0x73, 0x00, 0x00, 0x00, // ecall ++ 0x73, 0x00, 0x10, 0x00, // ebreak ++ }; ++ long ret; ++ ++ log_debug("Executing syscall %d (pid %d)...\n", nr, pctx->pid); ++ regs.a7 = (unsigned long)nr; ++ regs.a0 = arg1; ++ regs.a1 = arg2; ++ regs.a2 = arg3; ++ regs.a3 = arg4; ++ regs.a4 = arg5; ++ regs.a5 = arg6; ++ ++ ret = upatch_execute_remote(pctx, syscall, sizeof(syscall), ®s); ++ if (ret == 0) ++ *res = regs.a0; ++ ++ return ret; ++} ++ ++long upatch_arch_execute_remote_func(struct upatch_ptrace_ctx *pctx, ++ const unsigned char *code, size_t codelen, ++ struct user_regs_struct *pregs, ++ int (*func)(struct upatch_ptrace_ctx *pctx, ++ const void *data), ++ const void *data) ++{ ++ struct user_regs_struct orig_regs, regs; ++ unsigned char orig_code[codelen]; ++ long ret; ++ struct upatch_process *proc = pctx->proc; ++ unsigned long libc_base = proc->libc_base; ++ ++ ret = read_gregs(pctx->pid, &orig_regs); ++ if (ret < 0) { ++ return -1; ++ } ++ ret = upatch_process_mem_read(proc, libc_base, ++ (unsigned long *)orig_code, codelen); ++ if (ret < 0) { ++ log_error("can't peek original code - %d\n", pctx->pid); ++ return -1; ++ } ++ ret = upatch_process_mem_write(proc, (const unsigned long *)code, libc_base, ++ codelen); ++ if (ret < 0) { ++ log_error("can't poke syscall code - %d\n", pctx->pid); ++ goto poke_back; ++ } ++ ++ regs = orig_regs; ++ regs.pc = libc_base; ++ ++ copy_regs(®s, pregs); ++ ++ ret = write_gregs(pctx->pid, ®s); ++ if (ret < 0) { ++ goto poke_back; ++ } ++ ++ ret = func(pctx, data); ++ if (ret < 0) { ++ log_error("failed call to func\n"); ++ goto poke_back; ++ } ++ ++ ret = read_gregs(pctx->pid, ®s); ++ if (ret < 0) { ++ goto poke_back; ++ } ++ ++ ret = write_gregs(pctx->pid, &orig_regs); ++ if (ret < 0) { ++ goto poke_back; ++ } ++ ++ *pregs = regs; ++ ++poke_back: ++ upatch_process_mem_write(proc, (unsigned long *)orig_code, libc_base, ++ codelen); ++ return ret; ++} ++ ++void copy_regs(struct user_regs_struct *dst, struct user_regs_struct *src) ++{ ++#define COPY_REG(x) dst->x = src->x ++ COPY_REG(a0); ++ COPY_REG(a1); ++ COPY_REG(a2); ++ COPY_REG(a3); ++ COPY_REG(a4); ++ COPY_REG(a5); ++ COPY_REG(a6); ++ COPY_REG(a7); ++#undef COPY_REG ++} ++ ++#define UPATCH_INSN_LEN 8 ++#define UPATCH_ADDR_LEN 8 ++#define ORIGIN_INSN_LEN (UPATCH_INSN_LEN + UPATCH_ADDR_LEN) ++ ++size_t get_origin_insn_len() ++{ ++ return ORIGIN_INSN_LEN; ++} ++ ++size_t get_upatch_insn_len() ++{ ++ return UPATCH_INSN_LEN; ++} ++ ++size_t get_upatch_addr_len() ++{ ++ return UPATCH_ADDR_LEN; ++} ++ ++/* ++ * On RISC-V, there must be 3 instructors(12 bytes) to jump to ++ * arbitrary address. The core upatch-manage limit jump instructor ++ * to one long(8 bytes), for us is +-2G range. ++ */ ++unsigned long get_new_insn(unsigned long old_addr, unsigned long new_addr) ++{ ++ unsigned long offset; ++ unsigned int insn0, insn4; ++ ++ offset = new_addr - old_addr; ++ offset += (offset & 0x800) << 1; ++ insn0 = 0xf97 | (offset & 0xfffff000); // auipc t6, off[20] ++ insn4 = 0xf8067 | ((offset & 0xfff) << 20); // jalr zero, off[12](t6) ++ return (unsigned long)(insn0 | ((unsigned long)insn4 << 32)); ++} +diff --git a/upatch-manage/arch/riscv64/relocation.c b/upatch-manage/arch/riscv64/relocation.c +new file mode 100644 +index 0000000..6c28bf8 +--- /dev/null ++++ b/upatch-manage/arch/riscv64/relocation.c +@@ -0,0 +1,242 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * upatch-manage ++ * Copyright (C) 2024 ISCAS ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++ ++#include "insn.h" ++#include "upatch-relocation.h" ++#include "upatch-resolve.h" ++ ++/* ++ * In PCREL_LO12 relocation entity, its corresponding symbol's value ++ * points to the ..._HI20 instruction, where the LO12 part of the ++ * immediate is part of the ..._HI20 symbol value. ++ */ ++static unsigned long find_pcrel_hi_value(GElf_Rela *r, int idx, GElf_Sym *st, unsigned long v) ++{ ++ int i = idx; ++ r--; ++ for (; i > 0; i--, r--) { ++ if ((r->r_offset == v) && ++ ((GELF_R_TYPE(r->r_info) == R_RISCV_PCREL_HI20) || ++ (GELF_R_TYPE(r->r_info) == R_RISCV_TLS_GOT_HI20) || ++ (GELF_R_TYPE(r->r_info) == R_RISCV_TLS_GD_HI20) || ++ (GELF_R_TYPE(r->r_info) == R_RISCV_GOT_HI20))) ++ return st[GELF_R_SYM(r->r_info)].st_value; ++ } ++ ++ /* should never happen */ ++ log_error("Not found no. %d rela's corresponding HI20\n", idx); ++ return 0; ++} ++ ++/* ++ * The patch is a .o file, has only static relocations, all symbols ++ * have been resolved with our jump table act as got/plt. ++ */ ++int apply_relocate_add(struct upatch_elf *uelf, unsigned int symindex, ++ unsigned int relsec) ++{ ++ unsigned int i; ++ GElf_Sym *sym, *symtab; ++ char const *sym_name; ++ unsigned long uloc_sec; ++ void *loc; ++ void *uloc; ++ u64 val; ++ GElf_Shdr *shdrs = (void *)uelf->info.shdrs; ++ GElf_Rela *rel = (void *)shdrs[relsec].sh_addr; ++ ++ symtab = (GElf_Sym *)shdrs[symindex].sh_addr; ++ for (i = 0; i < shdrs[relsec].sh_size / sizeof(*rel); i++) { ++ /* loc corresponds to P in the kernel space */ ++ loc = (void *)shdrs[shdrs[relsec].sh_info].sh_addr + ++ rel[i].r_offset; ++ ++ /* uloc corresponds P in user space */ ++ uloc_sec = shdrs[shdrs[relsec].sh_info].sh_addralign; ++ uloc = (void *)uloc_sec + rel[i].r_offset; ++ ++ /* sym is the ELF symbol we're referring to */ ++ sym = symtab + GELF_R_SYM(rel[i].r_info); ++ if (GELF_ST_TYPE(sym->st_info) == STT_SECTION && ++ sym->st_shndx < uelf->info.hdr->e_shnum) ++ sym_name = uelf->info.shstrtab + ++ shdrs[sym->st_shndx].sh_name; ++ else ++ sym_name = uelf->strtab + sym->st_name; ++ ++ /* val corresponds to (S + A) */ ++ val = (s64)(sym->st_value + rel[i].r_addend); ++ log_debug( ++ "upatch: reloc symbol, name=%s, k_addr=0x%lx, u_addr=0x%lx, " ++ "r_offset=0x%lx, st_value=0x%lx, r_addend=0x%lx \n", ++ sym_name, shdrs[shdrs[relsec].sh_info].sh_addr, ++ uloc_sec, rel[i].r_offset, sym->st_value, rel[i].r_addend); ++ ++ /* Perform the static relocation. */ ++ switch (GELF_R_TYPE(rel[i].r_info)) { ++ case R_RISCV_NONE: ++ case R_RISCV_TPREL_ADD: ++ break; ++ ++ case R_RISCV_64: ++ *(unsigned long *)loc = val; ++ break; ++ ++ /* seems no need to recalculate as it should confined in the same func */ ++ case R_RISCV_BRANCH: ++ val -= (unsigned long)uloc; ++ if ((signed)val >= 4096 || (signed)val < -4096) ++ goto overflow; ++ *(unsigned *)loc = set_btype_imm(*(unsigned *)loc, val); ++ break; ++ ++ case R_RISCV_JAL: ++ val -= (unsigned long)uloc; ++ if ((signed)val >= (1 << 20) || (signed)val < -(1 << 20)) ++ goto overflow; ++ *(unsigned *)loc = set_jtype_imm(*(unsigned *)loc, val); ++ break; ++ ++ case R_RISCV_CALL: ++ case R_RISCV_CALL_PLT: ++ // in our jump table, must not overflow ++ val -= (unsigned long)uloc; ++ *(unsigned *)loc = set_utype_imm(*(unsigned *)loc, val); ++ *(unsigned *)(loc + 4) = set_itype_imm(*(unsigned *)(loc + 4), val); ++ break; ++ ++ case R_RISCV_GOT_HI20: ++ case R_RISCV_TLS_GOT_HI20: ++ case R_RISCV_TLS_GD_HI20: ++ case R_RISCV_PCREL_HI20: ++ val -= (unsigned long)uloc; // fall through ++ case R_RISCV_HI20: ++ case R_RISCV_TPREL_HI20: ++ if ((long)val != (long)(int)val) ++ goto overflow; ++ *(unsigned *)loc = set_utype_imm(*(unsigned *)loc, val); ++ break; ++ ++ case R_RISCV_PCREL_LO12_I: ++ val = find_pcrel_hi_value(rel + i, i, symtab, sym->st_value - uloc_sec); ++ if (val == 0) ++ goto overflow; ++ val -= sym->st_value; // fall through ++ case R_RISCV_LO12_I: ++ case R_RISCV_TPREL_LO12_I: ++ *(unsigned *)loc = set_itype_imm(*(unsigned *)loc, val); ++ break; ++ ++ case R_RISCV_PCREL_LO12_S: ++ val = find_pcrel_hi_value(rel + i, i, symtab, sym->st_value - uloc_sec); ++ if (val == 0) ++ goto overflow; ++ val -= sym->st_value; // fall through ++ case R_RISCV_LO12_S: ++ case R_RISCV_TPREL_LO12_S: ++ *(unsigned *)loc = set_stype_imm(*(unsigned *)loc, val); ++ break; ++ ++ /* inner function label calculation, must not overflow */ ++ case R_RISCV_ADD8: ++ *(char *)loc += val; ++ break; ++ case R_RISCV_ADD16: ++ *(short *)loc += val; ++ break; ++ case R_RISCV_ADD32: ++ *(int *)loc += val; ++ break; ++ case R_RISCV_ADD64: ++ *(long *)loc += val; ++ break; ++ ++ case R_RISCV_SUB8: ++ *(char *)loc -= val; ++ break; ++ case R_RISCV_SUB16: ++ *(short *)loc -= val; ++ break; ++ case R_RISCV_SUB32: ++ *(int *)loc -= val; ++ break; ++ case R_RISCV_SUB64: ++ *(long *)loc -= val; ++ break; ++ ++ case R_RISCV_RVC_BRANCH: ++ val -= (unsigned long)uloc; ++ if ((signed)val >= 256 || (signed)val < -256) ++ goto overflow; ++ *(unsigned short *)loc = set_cbtype_imm(*(unsigned short *)loc, val); ++ break; ++ ++ case R_RISCV_RVC_JUMP: ++ val -= (unsigned long)uloc; ++ if ((signed)val >= 2048 || (signed)val < -2048) ++ goto overflow; ++ *(unsigned short *)loc = set_cjtype_imm(*(unsigned short *)loc, val); ++ break; ++ ++ case R_RISCV_RVC_LUI: ++ if ((signed)val >= (1 << 17) || (signed)val < -(1 << 17) || (val & 0x3f000) == 0) ++ goto overflow; ++ *(unsigned short *)loc = set_citype_imm(*(unsigned short *)loc, val); ++ break; ++ ++ case R_RISCV_SET8: ++ *(char *)loc = val; ++ break; ++ case R_RISCV_SET16: ++ *(short *)loc = val; ++ break; ++ case R_RISCV_32_PCREL: ++ case R_RISCV_PLT32: ++ val -= (unsigned long)uloc; // fall through ++ case R_RISCV_32: ++ case R_RISCV_SET32: ++ if ((long)val != (long)(int)val) ++ goto overflow; ++ *(int *)loc = val; ++ break; ++ ++ case R_RISCV_SUB6: ++ char w6 = (*(char *)loc - (char)val) & 0x3f; ++ *(char *)loc = (*(char *)loc & 0xc0) | w6; ++ break; ++ case R_RISCV_SET6: ++ *(char *)loc = (*(char *)loc & 0xc0) | (val & 0x3f); ++ break; ++ ++ default: ++ log_error("upatch: unsupported RELA relocation: %lu\n", ++ GELF_R_TYPE(rel[i].r_info)); ++ return -ENOEXEC; ++ } ++ } ++ return 0; ++ ++overflow: ++ log_error("upatch: overflow in relocation type %d val %lx\n", ++ (int)GELF_R_TYPE(rel[i].r_info), val); ++ return -ENOEXEC; ++} +diff --git a/upatch-manage/arch/riscv64/resolve.c b/upatch-manage/arch/riscv64/resolve.c +new file mode 100644 +index 0000000..127fcc0 +--- /dev/null ++++ b/upatch-manage/arch/riscv64/resolve.c +@@ -0,0 +1,154 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * upatch-manage ++ * Copyright (C) 2024 ISCAS ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++#include ++ ++#include "log.h" ++#include "upatch-ptrace.h" ++#include "upatch-resolve.h" ++ ++/* ++ * auipc t6,0x0 ++ * ld t6,16(t6) # addr ++ * jr t6 ++ * undefined ++ */ ++#define RISCV64_JMP_TABLE_JUMP0 0x010fbf8300000f97 ++#define RISCV64_JMP_TABLE_JUMP1 0x000f8067 ++ ++struct upatch_jmp_table_entry { ++ unsigned long inst[2]; ++ unsigned long addr[2]; ++}; ++ ++unsigned int get_jmp_table_entry() ++{ ++ return sizeof(struct upatch_jmp_table_entry); ++} ++ ++static unsigned long setup_jmp_table(struct upatch_elf *uelf, ++ unsigned long jmp_addr, ++ unsigned long origin_addr) ++{ ++ struct upatch_jmp_table_entry *table = ++ uelf->core_layout.kbase + uelf->jmp_offs; ++ unsigned int index = uelf->jmp_cur_entry; ++ if (index >= uelf->jmp_max_entry) { ++ log_error("jmp table overflow\n"); ++ return 0; ++ } ++ ++ table[index].inst[0] = RISCV64_JMP_TABLE_JUMP0; ++ table[index].inst[1] = RISCV64_JMP_TABLE_JUMP1; ++ table[index].addr[0] = jmp_addr; ++ table[index].addr[1] = origin_addr; ++ uelf->jmp_cur_entry++; ++ return (unsigned long)(uelf->core_layout.base + uelf->jmp_offs + ++ index * sizeof(struct upatch_jmp_table_entry)); ++} ++ ++static unsigned long setup_got_table(struct upatch_elf *uelf, ++ unsigned long jmp_addr, ++ unsigned long tls_addr) ++{ ++ struct upatch_jmp_table_entry *table = ++ uelf->core_layout.kbase + uelf->jmp_offs; ++ unsigned int index = uelf->jmp_cur_entry; ++ ++ if (index >= uelf->jmp_max_entry) { ++ log_error("got table overflow\n"); ++ return 0; ++ } ++ ++ table[index].inst[0] = jmp_addr; ++ table[index].inst[1] = tls_addr; ++ table[index].addr[0] = 0xffffffff; ++ table[index].addr[1] = 0xffffffff; ++ uelf->jmp_cur_entry++; ++ return (unsigned long)(uelf->core_layout.base + uelf->jmp_offs + ++ index * sizeof(struct upatch_jmp_table_entry)); ++} ++ ++unsigned long insert_plt_table(struct upatch_elf *uelf, struct object_file *obj, ++ unsigned long r_type, unsigned long addr) ++{ ++ unsigned long jmp_addr = 0xffffffff; ++ unsigned long tls_addr = 0xffffffff; ++ unsigned long elf_addr = 0; ++ ++ if (upatch_process_mem_read(obj->proc, addr, &jmp_addr, ++ sizeof(jmp_addr))) { ++ log_error("copy address failed\n"); ++ goto out; ++ } ++ ++ elf_addr = setup_jmp_table(uelf, jmp_addr, (unsigned long)addr); ++ ++ log_debug("0x%lx: jmp_addr=0x%lx, tls_addr=0x%lx\n", elf_addr, ++ jmp_addr, tls_addr); ++ ++out: ++ return elf_addr; ++} ++ ++unsigned long insert_got_table(struct upatch_elf *uelf, struct object_file *obj, ++ unsigned long r_type, unsigned long addr) ++{ ++ unsigned long jmp_addr = 0xffffffff; ++ unsigned long tls_addr = 0xffffffff; ++ unsigned long elf_addr = 0; ++ ++ if (upatch_process_mem_read(obj->proc, addr, &jmp_addr, ++ sizeof(jmp_addr))) { ++ log_error("copy address failed\n"); ++ goto out; ++ } ++ ++ /* ++ * Addr with this type means the symbol is a dynamic TLS variable. ++ * Addr points to a GOT entry(16 bytes) having type ++ * ++ * typedef struct { ++ * unsigned long int ti_module; ++ * unsigned long int ti_offset; ++ * } tls_index; ++ * ++ * We also need copy ti_offset to our jump table. ++ * ++ * The corresponding symbol will associate with TLS_GD_HI20 ++ * relocation type, using this tls_index as argument to call ++ * `void *__tls_get_addr (tls_index *ti)` to resolve the real address. ++ */ ++ if (r_type == R_RISCV_TLS_DTPMOD64 && ++ upatch_process_mem_read(obj->proc, addr + sizeof(unsigned long), ++ &tls_addr, sizeof(tls_addr))) { ++ log_error("copy address failed\n"); ++ goto out; ++ } ++ ++ elf_addr = setup_got_table(uelf, jmp_addr, tls_addr); ++ ++ log_debug("0x%lx: jmp_addr=0x%lx, tls_addr=0x%lx\n", elf_addr, ++ jmp_addr, tls_addr); ++ ++out: ++ return elf_addr; ++} +diff --git a/upatch-manage/upatch-patch.c b/upatch-manage/upatch-patch.c +index 4a1e568..c57ae74 100644 +--- a/upatch-manage/upatch-patch.c ++++ b/upatch-manage/upatch-patch.c +@@ -476,6 +476,23 @@ static int complete_info(struct upatch_elf *uelf, struct object_file *obj, + + upatch_func->addr = upatch_funcs_addr[i].addr; + upatch_func->addr.old_addr += uelf->relf->load_bias; ++ ++#ifdef __riscv ++#define RISCV_MAX_JUMP_RANGE (1L << 31) ++ /* ++ * On RISC-V, to jump to arbitrary address, there must be ++ * at least 12 bytes to hold 3 instructors. Struct upatch_info ++ * new_insn field is only 8 bytes. We can only jump into ++ * +-2G ranges. Here do the check. ++ */ ++ long offset = upatch_func->addr.new_addr - upatch_func->addr.old_addr; ++ if (offset >= RISCV_MAX_JUMP_RANGE || offset < -RISCV_MAX_JUMP_RANGE) { ++ log_error("new_addr=%lx old_addr=%lx exceed +-2G range\n", ++ upatch_func->addr.new_addr, upatch_func->addr.old_addr); ++ goto out; ++ } ++#endif ++ + ret = upatch_process_mem_read(obj->proc, upatch_func->addr.old_addr, + &upatch_func->old_insn, get_origin_insn_len()); + if (ret) { +@@ -484,7 +501,12 @@ static int complete_info(struct upatch_elf *uelf, struct object_file *obj, + goto out; + } + ++#ifdef __riscv ++ upatch_func->new_insn = get_new_insn( ++ upatch_func->addr.old_addr, upatch_func->addr.new_addr); ++#else + upatch_func->new_insn = get_new_insn(); ++#endif + log_debug("\taddr: 0x%lx -> 0x%lx, insn: 0x%lx -> 0x%lx, name: '%s'\n", + upatch_func->addr.old_addr, upatch_func->addr.new_addr, + upatch_func->old_insn[0], upatch_func->new_insn, +diff --git a/upatch-manage/upatch-ptrace.c b/upatch-manage/upatch-ptrace.c +index ab21891..4ebe038 100644 +--- a/upatch-manage/upatch-ptrace.c ++++ b/upatch-manage/upatch-ptrace.c +@@ -25,6 +25,10 @@ + #include + + #include ++#ifdef __riscv ++/* user_regs_struct defined here */ ++#include ++#endif + #include + #include + +diff --git a/upatch-manage/upatch-ptrace.h b/upatch-manage/upatch-ptrace.h +index 8f36565..f2503cf 100644 +--- a/upatch-manage/upatch-ptrace.h ++++ b/upatch-manage/upatch-ptrace.h +@@ -22,6 +22,9 @@ + #define __UPATCH_PTRACE__ + + #include ++#ifdef __riscv ++#include ++#endif + + #include "upatch-process.h" + #include "list.h" +@@ -79,6 +82,11 @@ long upatch_execute_remote(struct upatch_ptrace_ctx *, + size_t get_origin_insn_len(void); + size_t get_upatch_insn_len(void); + size_t get_upatch_addr_len(void); ++ ++#ifdef __riscv ++unsigned long get_new_insn(unsigned long old_addr, unsigned long new_addr); ++#else + unsigned long get_new_insn(void); ++#endif + + #endif +-- +2.34.1 + diff --git a/0043-syscare-build-fix-detect-incorrect-kernel-source-dir.patch b/0043-syscare-build-fix-detect-incorrect-kernel-source-dir.patch new file mode 100644 index 0000000..3d5bb4d --- /dev/null +++ b/0043-syscare-build-fix-detect-incorrect-kernel-source-dir.patch @@ -0,0 +1,44 @@ +From 0d2a4fc0e9748a06c55d1962c5c794988f488338 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Tue, 4 Mar 2025 11:32:31 +0800 +Subject: [PATCH] syscare-build: fix 'detect incorrect kernel source directory' + issue + +Signed-off-by: renoseven +--- + .../src/patch/kernel_patch/kpatch_builder.rs | 19 +++++++++---------- + 1 file changed, 9 insertions(+), 10 deletions(-) + +diff --git a/syscare-build/src/patch/kernel_patch/kpatch_builder.rs b/syscare-build/src/patch/kernel_patch/kpatch_builder.rs +index accad0a..07d4a85 100644 +--- a/syscare-build/src/patch/kernel_patch/kpatch_builder.rs ++++ b/syscare-build/src/patch/kernel_patch/kpatch_builder.rs +@@ -87,16 +87,15 @@ impl KernelPatchBuilder { + let patch_output_dir: PathBuf = build_params.build_root.patch.output.clone(); + + let kernel_pkg = &kernel_entry.target_pkg; +- let kernel_source_dir: PathBuf = self +- .pkg_impl +- .find_source_directory( +- &kernel_entry.build_source, +- &format!( +- "linux-{}-{}.{}", +- kernel_pkg.version, kernel_pkg.release, kernel_pkg.arch +- ), +- ) +- .context("Cannot find kernel source directory")?; ++ let kernel_source_dir: PathBuf = fs::find_dir( ++ &kernel_entry.build_source, ++ format!("linux-{}", kernel_pkg.version), ++ fs::FindOptions { ++ fuzz: true, ++ recursive: true, ++ }, ++ ) ++ .context("Cannot find kernel source directory")?; + let kernel_debug_dir = &build_params.build_root.package.debuginfo; + let oot_source_dir = oot_module_entry.map(|build_entry| build_entry.build_source.clone()); + +-- +2.34.1 + diff --git a/0044-upatch-manage-fix-compile-failure.patch b/0044-upatch-manage-fix-compile-failure.patch new file mode 100644 index 0000000..0ac19b7 --- /dev/null +++ b/0044-upatch-manage-fix-compile-failure.patch @@ -0,0 +1,26 @@ +From c8ee23919b11e0a0d3ed469af4213d692035d2f7 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Wed, 5 Mar 2025 15:22:45 +0800 +Subject: [PATCH] upatch-manage: fix compile failure + +Signed-off-by: renoseven +--- + upatch-manage/arch/aarch64/relocation.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/upatch-manage/arch/aarch64/relocation.c b/upatch-manage/arch/aarch64/relocation.c +index 80a817d..7dd82eb 100644 +--- a/upatch-manage/arch/aarch64/relocation.c ++++ b/upatch-manage/arch/aarch64/relocation.c +@@ -68,7 +68,7 @@ int apply_relocate_add(struct upatch_elf *uelf, unsigned int symindex, + void *uloc; + u64 val; + u64 got; +- s64 result; ++ s64 result = 0; + GElf_Shdr *shdrs = (void *)uelf->info.shdrs; + GElf_Rela *rel = (void *)shdrs[relsec].sh_addr; + +-- +2.34.1 + diff --git a/0045-syscared-fix-kmod-patch-conflicts-with-itself-issue.patch b/0045-syscared-fix-kmod-patch-conflicts-with-itself-issue.patch new file mode 100644 index 0000000..00125ce --- /dev/null +++ b/0045-syscared-fix-kmod-patch-conflicts-with-itself-issue.patch @@ -0,0 +1,78 @@ +From 48fc62552f397d56c87f1d1879f5a88a9fee9835 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Thu, 6 Mar 2025 10:37:17 +0800 +Subject: [PATCH] syscared: fix 'kmod patch conflicts with itself' issue + + We use a collision list to record symbol overriding. Each +patch symbol has it's own collision list, which is saved in +an IndexMap. Key of the IndexMap is 'old_addr' of a symbol. +But for kmod patch, the 'old_addr' would be always 0. Thus, +the first patched symbol in kmod would be treated as overrided +by following patch symbol. To solve this, we changed the key +from 'old_addr' to 'name' of patch symbols. + +Signed-off-by: renoseven +--- + syscared/src/patch/driver/kpatch/target.rs | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/syscared/src/patch/driver/kpatch/target.rs b/syscared/src/patch/driver/kpatch/target.rs +index beab803..49f1185 100644 +--- a/syscared/src/patch/driver/kpatch/target.rs ++++ b/syscared/src/patch/driver/kpatch/target.rs +@@ -43,7 +43,7 @@ impl PatchFunction { + #[derive(Debug)] + pub struct PatchTarget { + name: OsString, +- function_map: IndexMap>, // function addr -> function collision list ++ function_map: IndexMap>, // function addr -> function collision list + } + + impl PatchTarget { +@@ -69,7 +69,7 @@ impl PatchTarget { + continue; + } + self.function_map +- .entry(function.old_addr) ++ .entry(function.name.clone()) + .or_default() + .push(PatchFunction::new(uuid, function)); + } +@@ -83,14 +83,14 @@ impl PatchTarget { + if self.name != function.object { + continue; + } +- if let Some(collision_list) = self.function_map.get_mut(&function.old_addr) { ++ if let Some(collision_list) = self.function_map.get_mut(&function.name) { + if let Some(index) = collision_list + .iter() + .position(|patch_function| patch_function.is_same_function(uuid, function)) + { + collision_list.remove(index); + if collision_list.is_empty() { +- self.function_map.remove(&function.old_addr); ++ self.function_map.remove(&function.name); + } + } + } +@@ -111,7 +111,7 @@ impl PatchTarget { + return None; + } + self.function_map +- .get(&function.old_addr) ++ .get(&function.name) + .and_then(|list| list.last()) + }) + } +@@ -129,7 +129,7 @@ impl PatchTarget { + return None; + } + self.function_map +- .get(&function.old_addr) ++ .get(&function.name) + .and_then(|list| list.last()) + .filter(|patch_function| !patch_function.is_same_function(uuid, function)) + }) +-- +2.34.1 + diff --git a/0046-common-fix-failed-to-acquire-flock-issue.patch b/0046-common-fix-failed-to-acquire-flock-issue.patch new file mode 100644 index 0000000..0e2fccd --- /dev/null +++ b/0046-common-fix-failed-to-acquire-flock-issue.patch @@ -0,0 +1,177 @@ +From fef1fc6d7bc4a9e8805553a202ffde05ed570f23 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Tue, 11 Mar 2025 12:01:48 +0800 +Subject: [PATCH] common: fix 'failed to acquire flock' issue + +Signed-off-by: renoseven +--- + syscare-common/src/fs/flock.rs | 101 ++++++++++++++++++--------------- + 1 file changed, 56 insertions(+), 45 deletions(-) + +diff --git a/syscare-common/src/fs/flock.rs b/syscare-common/src/fs/flock.rs +index bfd39d7..29bff55 100644 +--- a/syscare-common/src/fs/flock.rs ++++ b/syscare-common/src/fs/flock.rs +@@ -15,65 +15,76 @@ + use std::{ + fs::File, + os::unix::io::{AsRawFd, RawFd}, +- path::Path, ++ path::{Path, PathBuf}, + }; + +-use anyhow::{Context, Result}; +-use nix::fcntl::{flock, FlockArg}; ++use anyhow::{anyhow, Context, Result}; ++use nix::fcntl; + + #[derive(Debug)] + pub enum FileLockType { + Shared, + Exclusive, ++ SharedNonBlock, ++ ExclusiveNonBlock, + } + + #[derive(Debug)] + pub struct FileLock { +- inner: File, ++ path: PathBuf, ++ file: File, + kind: FileLockType, + } + + impl FileLock { +- #[inline] +- fn acquire_lock(&self) -> Result<()> { +- let fd = self.inner.as_raw_fd(); +- let arg = match self.kind { +- FileLockType::Shared => FlockArg::LockSharedNonblock, +- FileLockType::Exclusive => FlockArg::LockExclusiveNonblock, +- }; ++ pub fn new>(path: P, kind: FileLockType) -> Result { ++ let file_path = path.as_ref(); + +- flock(fd, arg).with_context(|| format!("Failed to acquire flock for fd {}", fd)) +- } ++ let file = if file_path.is_file() { ++ File::open(file_path) ++ .map_err(|e| anyhow!("Failed to open lock file {}, {}", file_path.display(), e))? ++ } else { ++ File::create(file_path) ++ .map_err(|e| anyhow!("Failed to create lock file {}, {}", file_path.display(), e))? ++ }; + +- #[inline] +- fn release_lock(&self) -> Result<()> { +- let fd = self.inner.as_raw_fd(); +- let arg = FlockArg::Unlock; ++ let flock = Self { ++ path: file_path.to_path_buf(), ++ file, ++ kind, ++ }; ++ flock.acquire_lock()?; + +- flock(fd, arg).with_context(|| format!("Failed to release flock for fd {}", fd)) ++ Ok(flock) + } + } + + impl FileLock { +- pub fn new>(path: P, kind: FileLockType) -> Result { +- let file_path = path.as_ref(); +- let inner = if file_path.exists() { +- File::open(file_path) +- } else { +- File::create(file_path) +- } +- .with_context(|| format!("Failed to create flock on {}", file_path.display()))?; +- +- let instance = Self { inner, kind }; +- instance.acquire_lock()?; ++ #[inline] ++ fn acquire_lock(&self) -> Result<()> { ++ let fd = self.file.as_raw_fd(); ++ let arg = match self.kind { ++ FileLockType::Shared => fcntl::FlockArg::LockShared, ++ FileLockType::Exclusive => fcntl::FlockArg::LockExclusive, ++ FileLockType::SharedNonBlock => fcntl::FlockArg::LockSharedNonblock, ++ FileLockType::ExclusiveNonBlock => fcntl::FlockArg::LockExclusiveNonblock, ++ }; ++ fcntl::flock(fd, arg) ++ .with_context(|| format!("Failed to acquire flock on {}", self.path.display())) ++ } + +- Ok(instance) ++ #[inline] ++ fn release_lock(&self) -> Result<()> { ++ let fd = self.file.as_raw_fd(); ++ let arg = fcntl::FlockArg::Unlock; ++ fcntl::flock(fd, arg) ++ .with_context(|| format!("Failed to release flock on {}", self.path.display())) + } + } + + impl AsRawFd for FileLock { + fn as_raw_fd(&self) -> RawFd { +- self.inner.as_raw_fd() ++ self.file.as_raw_fd() + } + } + +@@ -93,37 +104,37 @@ fn test() { + println!("Testing exclusive flock on {}...", NON_EXIST_FILE); + fs::remove_file(NON_EXIST_FILE).ok(); + +- let exclusive_lock = FileLock::new(NON_EXIST_FILE, FileLockType::Exclusive) ++ let exclusive_lock = FileLock::new(NON_EXIST_FILE, FileLockType::ExclusiveNonBlock) + .expect("Failed to create exclusive flock"); + drop(exclusive_lock); + + println!("Testing shared flock on {}...", NON_EXIST_FILE); + fs::remove_file(NON_EXIST_FILE).ok(); +- let shared_lock = +- FileLock::new(NON_EXIST_FILE, FileLockType::Shared).expect("Failed to create shared flock"); ++ let shared_lock = FileLock::new(NON_EXIST_FILE, FileLockType::SharedNonBlock) ++ .expect("Failed to create shared flock"); + drop(shared_lock); + + fs::remove_file(NON_EXIST_FILE).ok(); + + println!("Testing exclusive flock on {}...", EXIST_FILE); +- let exclusive_lock = FileLock::new(EXIST_FILE, FileLockType::Exclusive) ++ let exclusive_lock = FileLock::new(EXIST_FILE, FileLockType::ExclusiveNonBlock) + .expect("Failed to create exclusive flock"); +- let _exclusive_err = FileLock::new(EXIST_FILE, FileLockType::Exclusive) ++ let _exclusive_err = FileLock::new(EXIST_FILE, FileLockType::ExclusiveNonBlock) + .expect_err("Exclusive flock should be failed"); +- let _shared_err = +- FileLock::new(EXIST_FILE, FileLockType::Shared).expect_err("Shared flock should be failed"); ++ let _shared_err = FileLock::new(EXIST_FILE, FileLockType::SharedNonBlock) ++ .expect_err("Shared flock should be failed"); + + drop(exclusive_lock); + + println!("Testing shared flock on {}...", EXIST_FILE); +- let shared_lock1 = +- FileLock::new(EXIST_FILE, FileLockType::Shared).expect("Failed to create shared flock"); +- let shared_lock2 = +- FileLock::new(EXIST_FILE, FileLockType::Shared).expect("Failed to create shared flock"); +- let _exclusive_err = FileLock::new(EXIST_FILE, FileLockType::Exclusive) ++ let shared_lock1 = FileLock::new(EXIST_FILE, FileLockType::SharedNonBlock) ++ .expect("Failed to create shared flock"); ++ let shared_lock2 = FileLock::new(EXIST_FILE, FileLockType::SharedNonBlock) ++ .expect("Failed to create shared flock"); ++ let _exclusive_err = FileLock::new(EXIST_FILE, FileLockType::ExclusiveNonBlock) + .expect_err("Exclusive flock should be failed"); +- let shared_lock3 = +- FileLock::new(EXIST_FILE, FileLockType::Shared).expect("Failed to create shared flock"); ++ let shared_lock3 = FileLock::new(EXIST_FILE, FileLockType::SharedNonBlock) ++ .expect("Failed to create shared flock"); + + drop(shared_lock1); + drop(shared_lock2); +-- +2.34.1 + diff --git a/0047-syscare-rewrite-syscare-cli.patch b/0047-syscare-rewrite-syscare-cli.patch new file mode 100644 index 0000000..cae0376 --- /dev/null +++ b/0047-syscare-rewrite-syscare-cli.patch @@ -0,0 +1,1352 @@ +From 2cebc4d7a83c1b7837b62ef5f9723a0b93ea18c4 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Thu, 6 Mar 2025 16:48:10 +0800 +Subject: [PATCH] syscare: rewrite syscare cli + +1. remove 'build' subcommand +2. remove Executor trait, execute subcommand directly +3. process unknown subcommand as external command +4. move rpc logic into RpcClient +5. move patch logic into PatchProxy +6. rename 'patch_op.lock' to 'syscare.lock' +7. change umask from 077 to 022 + +Signed-off-by: renoseven +--- + syscare/src/args.rs | 15 +- + syscare/src/executor/build.rs | 43 ----- + syscare/src/executor/mod.rs | 24 --- + syscare/src/executor/patch.rs | 268 ------------------------------ + syscare/src/main.rs | 200 +++++++++++------------ + syscare/src/rpc/args.rs | 42 ----- + syscare/src/rpc/client.rs | 144 +++++++++++++++++ + syscare/src/rpc/mod.rs | 7 +- + syscare/src/rpc/proxy.rs | 297 ++++++++++++++++++++++++++++++---- + syscare/src/rpc/remote.rs | 86 ---------- + 10 files changed, 516 insertions(+), 610 deletions(-) + delete mode 100644 syscare/src/executor/build.rs + delete mode 100644 syscare/src/executor/mod.rs + delete mode 100644 syscare/src/executor/patch.rs + delete mode 100644 syscare/src/rpc/args.rs + create mode 100644 syscare/src/rpc/client.rs + delete mode 100644 syscare/src/rpc/remote.rs + +diff --git a/syscare/src/args.rs b/syscare/src/args.rs +index 24a4a5e..5f19835 100644 +--- a/syscare/src/args.rs ++++ b/syscare/src/args.rs +@@ -12,7 +12,7 @@ + * See the Mulan PSL v2 for more details. + */ + +-use std::path::PathBuf; ++use std::{ffi::OsString, path::PathBuf}; + + use anyhow::Result; + use clap::{AppSettings, ColorChoice, Parser, Subcommand}; +@@ -28,6 +28,7 @@ const DEFAULT_WORK_DIR: &str = "/var/run/syscare"; + bin_name = CLI_NAME, + version = CLI_VERSION, + about = CLI_ABOUT, ++ allow_external_subcommands(true), + arg_required_else_help(true), + color(ColorChoice::Never), + disable_help_subcommand(true), +@@ -37,7 +38,7 @@ const DEFAULT_WORK_DIR: &str = "/var/run/syscare"; + pub struct Arguments { + /// Command name + #[clap(subcommand)] +- pub command: SubCommand, ++ pub subcommand: SubCommand, + + /// Path for working directory + #[clap(short, long, default_value=DEFAULT_WORK_DIR)] +@@ -50,13 +51,6 @@ pub struct Arguments { + + #[derive(Debug, Clone, Subcommand)] + pub enum SubCommand { +- /// Build a patch +- #[clap( +- disable_help_flag(true), +- subcommand_precedence_over_arg(true), +- allow_hyphen_values(true) +- )] +- Build { args: Vec }, + /// Show patch info + Info { + /// Patch identifier +@@ -129,6 +123,9 @@ pub enum SubCommand { + }, + /// Rescan all patches + Rescan, ++ /// External subcommand ++ #[clap(external_subcommand)] ++ External(Vec), + } + + impl Arguments { +diff --git a/syscare/src/executor/build.rs b/syscare/src/executor/build.rs +deleted file mode 100644 +index 6d3866f..0000000 +--- a/syscare/src/executor/build.rs ++++ /dev/null +@@ -1,43 +0,0 @@ +-// SPDX-License-Identifier: Mulan PSL v2 +-/* +- * Copyright (c) 2024 Huawei Technologies Co., Ltd. +- * syscare is licensed under Mulan PSL v2. +- * You can use this software according to the terms and conditions of the Mulan PSL v2. +- * You may obtain a copy of Mulan PSL v2 at: +- * http://license.coscl.org.cn/MulanPSL2 +- * +- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +- * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +- * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +- * See the Mulan PSL v2 for more details. +- */ +- +-use std::{os::unix::process::CommandExt, process::Command}; +- +-use anyhow::{bail, Context, Result}; +- +-use super::CommandExecutor; +-use crate::args::SubCommand; +- +-const SYSCARE_BUILD_BIN: &str = "syscare-build"; +- +-pub struct BuildCommandExecutor; +- +-impl CommandExecutor for BuildCommandExecutor { +- fn invoke(&self, command: &SubCommand) -> Result> { +- if let SubCommand::Build { args } = command { +- let e = Command::new(SYSCARE_BUILD_BIN).args(args).exec(); +- +- match e.kind() { +- std::io::ErrorKind::NotFound => { +- bail!("Package syscare-build is not installed"); +- } +- _ => { +- return Err(e).with_context(|| format!("Failed to start {}", SYSCARE_BUILD_BIN)) +- } +- } +- } +- +- Ok(None) +- } +-} +diff --git a/syscare/src/executor/mod.rs b/syscare/src/executor/mod.rs +deleted file mode 100644 +index 8681996..0000000 +--- a/syscare/src/executor/mod.rs ++++ /dev/null +@@ -1,24 +0,0 @@ +-// SPDX-License-Identifier: Mulan PSL v2 +-/* +- * Copyright (c) 2024 Huawei Technologies Co., Ltd. +- * syscare is licensed under Mulan PSL v2. +- * You can use this software according to the terms and conditions of the Mulan PSL v2. +- * You may obtain a copy of Mulan PSL v2 at: +- * http://license.coscl.org.cn/MulanPSL2 +- * +- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +- * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +- * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +- * See the Mulan PSL v2 for more details. +- */ +- +-use anyhow::Result; +- +-use super::args::SubCommand; +- +-pub mod build; +-pub mod patch; +- +-pub trait CommandExecutor { +- fn invoke(&self, command: &SubCommand) -> Result>; +-} +diff --git a/syscare/src/executor/patch.rs b/syscare/src/executor/patch.rs +deleted file mode 100644 +index 346c30a..0000000 +--- a/syscare/src/executor/patch.rs ++++ /dev/null +@@ -1,268 +0,0 @@ +-// SPDX-License-Identifier: Mulan PSL v2 +-/* +- * Copyright (c) 2024 Huawei Technologies Co., Ltd. +- * syscare is licensed under Mulan PSL v2. +- * You can use this software according to the terms and conditions of the Mulan PSL v2. +- * You may obtain a copy of Mulan PSL v2 at: +- * http://license.coscl.org.cn/MulanPSL2 +- * +- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +- * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +- * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +- * See the Mulan PSL v2 for more details. +- */ +- +-use std::{fmt::Write, path::PathBuf}; +- +-use anyhow::{anyhow, Context, Error, Result}; +-use log::info; +- +-use syscare_abi::{PackageInfo, PatchInfo, PatchListRecord, PatchStateRecord}; +-use syscare_common::fs::{FileLock, FileLockType}; +- +-use crate::{args::SubCommand, rpc::RpcProxy}; +- +-use super::CommandExecutor; +- +-pub struct PatchCommandExecutor { +- proxy: RpcProxy, +- lock_file: PathBuf, +-} +- +-impl PatchCommandExecutor { +- pub fn new(proxy: RpcProxy, lock_file: PathBuf) -> Self { +- Self { proxy, lock_file } +- } +-} +- +-impl PatchCommandExecutor { +- fn check_error(mut error_list: Vec) -> Result<()> { +- match error_list.len() { +- 0 => Ok(()), +- 1 => Err(error_list.pop().context("Invalid error")?), +- _ => { +- let mut err_msg = String::new(); +- for (idx, e) in error_list.into_iter().enumerate() { +- writeln!(err_msg, "{}. {}", idx, e)?; +- } +- err_msg.pop(); +- +- Err(anyhow!(err_msg)) +- } +- } +- } +- +- fn show_patch_info(patch_list: impl IntoIterator) { +- let mut patch_iter = patch_list.into_iter().peekable(); +- while let Some((identifier, patch)) = patch_iter.next() { +- info!("-------------------------------------------"); +- info!("Patch: {}", identifier); +- info!("-------------------------------------------"); +- info!("{}", patch); +- if patch_iter.peek().is_some() { +- continue; +- } +- info!("-------------------------------------------"); +- } +- } +- +- fn show_patch_target(pkg_list: impl IntoIterator) { +- let mut pkg_iter = pkg_list.into_iter().peekable(); +- while let Some((identifier, package)) = pkg_iter.next() { +- info!("-------------------------------------------"); +- info!("Patch: {}", identifier); +- info!("-------------------------------------------"); +- info!("{}", package); +- if pkg_iter.peek().is_some() { +- continue; +- } +- info!("-------------------------------------------"); +- } +- } +- +- fn show_patch_status(status_list: impl IntoIterator) { +- for record in status_list { +- info!("{}: {}", record.name, record.status) +- } +- } +- +- fn show_patch_list(patch_list: impl IntoIterator) { +- info!("{:<40} {:<60} {:<12}", "Uuid", "Name", "Status"); +- for record in patch_list { +- info!( +- "{:<40} {:<60} {:<12}", +- record.uuid, record.name, record.status +- ) +- } +- } +-} +- +-impl CommandExecutor for PatchCommandExecutor { +- fn invoke(&self, command: &SubCommand) -> Result> { +- match command { +- SubCommand::Info { identifiers } => { +- let mut patch_list = vec![]; +- let mut error_list = vec![]; +- +- for identifier in identifiers { +- match self.proxy.get_patch_info(identifier) { +- Ok(patch) => patch_list.push((identifier.to_owned(), patch)), +- Err(e) => error_list.push(e), +- } +- } +- Self::show_patch_info(patch_list); +- Self::check_error(error_list)?; +- +- return Ok(Some(0)); +- } +- SubCommand::Target { identifiers } => { +- let mut pkg_list = vec![]; +- let mut error_list = vec![]; +- +- for identifier in identifiers { +- match self.proxy.get_patch_target(identifier) { +- Ok(pkg) => pkg_list.push((identifier.to_owned(), pkg)), +- Err(e) => error_list.push(e), +- } +- } +- Self::show_patch_target(pkg_list); +- Self::check_error(error_list)?; +- +- return Ok(Some(0)); +- } +- SubCommand::Status { identifiers } => { +- let mut status_list = vec![]; +- let mut error_list = vec![]; +- +- for identifier in identifiers { +- match self.proxy.get_patch_status(identifier) { +- Ok(new_status) => status_list.extend(new_status), +- Err(e) => error_list.push(e), +- } +- } +- Self::show_patch_status(status_list); +- Self::check_error(error_list)?; +- +- return Ok(Some(0)); +- } +- SubCommand::List => { +- Self::show_patch_list(self.proxy.get_patch_list()?); +- return Ok(Some(0)); +- } +- SubCommand::Check { identifiers } => { +- let _file_lock = FileLock::new(&self.lock_file, FileLockType::Exclusive)?; +- +- let mut error_list = vec![]; +- for identifier in identifiers { +- if let Err(e) = self.proxy.check_patch(identifier) { +- error_list.push(e); +- } +- } +- Self::check_error(error_list)?; +- +- return Ok(Some(0)); +- } +- SubCommand::Apply { identifiers, force } => { +- let _file_lock = FileLock::new(&self.lock_file, FileLockType::Exclusive)?; +- +- let mut status_list = vec![]; +- let mut error_list = vec![]; +- for identifier in identifiers { +- match self.proxy.apply_patch(identifier, *force) { +- Ok(new_status) => status_list.extend(new_status), +- Err(e) => error_list.push(e), +- } +- } +- Self::show_patch_status(status_list); +- Self::check_error(error_list)?; +- +- return Ok(Some(0)); +- } +- SubCommand::Remove { identifiers } => { +- let _file_lock = FileLock::new(&self.lock_file, FileLockType::Exclusive)?; +- +- let mut status_list = vec![]; +- let mut error_list = vec![]; +- for identifier in identifiers { +- match self.proxy.remove_patch(identifier) { +- Ok(new_status) => status_list.extend(new_status), +- Err(e) => error_list.push(e), +- } +- } +- Self::show_patch_status(status_list); +- Self::check_error(error_list)?; +- +- return Ok(Some(0)); +- } +- SubCommand::Active { identifiers, force } => { +- let _file_lock = FileLock::new(&self.lock_file, FileLockType::Exclusive)?; +- +- let mut status_list = vec![]; +- let mut error_list = vec![]; +- for identifier in identifiers { +- match self.proxy.active_patch(identifier, *force) { +- Ok(new_status) => status_list.extend(new_status), +- Err(e) => error_list.push(e), +- } +- } +- Self::show_patch_status(status_list); +- Self::check_error(error_list)?; +- +- return Ok(Some(0)); +- } +- SubCommand::Deactive { identifiers } => { +- let _file_lock = FileLock::new(&self.lock_file, FileLockType::Exclusive)?; +- +- let mut status_list = vec![]; +- let mut error_list = vec![]; +- for identifier in identifiers { +- match self.proxy.deactive_patch(identifier) { +- Ok(new_status) => status_list.extend(new_status), +- Err(e) => error_list.push(e), +- } +- } +- Self::show_patch_status(status_list); +- Self::check_error(error_list)?; +- +- return Ok(Some(0)); +- } +- SubCommand::Accept { identifiers } => { +- let _file_lock = FileLock::new(&self.lock_file, FileLockType::Exclusive)?; +- +- let mut status_list = vec![]; +- let mut error_list = vec![]; +- for identifier in identifiers { +- match self.proxy.accept_patch(identifier) { +- Ok(new_status) => status_list.extend(new_status), +- Err(e) => error_list.push(e), +- } +- } +- Self::show_patch_status(status_list); +- Self::check_error(error_list)?; +- +- return Ok(Some(0)); +- } +- SubCommand::Save => { +- let _file_lock = FileLock::new(&self.lock_file, FileLockType::Exclusive)?; +- +- self.proxy.save_patch_status()?; +- return Ok(Some(0)); +- } +- SubCommand::Restore { accepted } => { +- let _file_lock = FileLock::new(&self.lock_file, FileLockType::Exclusive)?; +- +- self.proxy.restore_patch_status(*accepted)?; +- return Ok(Some(0)); +- } +- SubCommand::Rescan => { +- let _file_lock = FileLock::new(&self.lock_file, FileLockType::Exclusive)?; +- +- self.proxy.rescan_patches()?; +- return Ok(Some(0)); +- } +- _ => {} +- } +- +- Ok(None) +- } +-} +diff --git a/syscare/src/main.rs b/syscare/src/main.rs +index 754307f..38416f2 100644 +--- a/syscare/src/main.rs ++++ b/syscare/src/main.rs +@@ -12,129 +12,129 @@ + * See the Mulan PSL v2 for more details. + */ + +-use std::{env, process, rc::Rc}; ++use std::{env, ffi::OsString, os::unix::process::CommandExt, process::Command}; + +-use anyhow::{Context, Result}; +-use flexi_logger::{DeferredNow, LogSpecification, Logger, LoggerHandle, WriteMode}; +-use log::{debug, error, LevelFilter, Record}; ++use anyhow::{bail, Context, Result}; ++use args::SubCommand; ++use flexi_logger::{LogSpecification, Logger, WriteMode}; ++use log::{debug, LevelFilter}; ++ ++use syscare_common::{concat_os, ffi::OsStrExt, os}; + + mod args; +-mod executor; + mod rpc; + +-use args::Arguments; +-use executor::{build::BuildCommandExecutor, patch::PatchCommandExecutor, CommandExecutor}; +-use rpc::{RpcProxy, RpcRemote}; +-use syscare_common::{concat_os, os}; ++use self::{ ++ args::Arguments, ++ rpc::{PatchProxy, RpcClient}, ++}; + + pub const CLI_NAME: &str = env!("CARGO_PKG_NAME"); + pub const CLI_VERSION: &str = env!("CARGO_PKG_VERSION"); + pub const CLI_ABOUT: &str = env!("CARGO_PKG_DESCRIPTION"); +-const CLI_UMASK: u32 = 0o077; ++pub const CLI_UMASK: u32 = 0o022; + + const PATH_ENV_NAME: &str = "PATH"; + const PATH_ENV_VALUE: &str = "/usr/libexec/syscare"; +- +-const SOCKET_FILE_NAME: &str = "syscared.sock"; +-const PATCH_OP_LOCK_NAME: &str = "patch_op.lock"; +- +-struct SyscareCLI { +- args: Arguments, +- logger: LoggerHandle, +-} +- +-impl SyscareCLI { +- fn format_log( +- w: &mut dyn std::io::Write, +- _now: &mut DeferredNow, +- record: &Record, +- ) -> std::io::Result<()> { +- write!(w, "{}", &record.args()) +- } +- +- fn new() -> Result { +- // Initialize arguments & prepare environments +- os::umask::set_umask(CLI_UMASK); +- if let Some(path_env) = env::var_os(PATH_ENV_NAME) { +- env::set_var(PATH_ENV_NAME, concat_os!(PATH_ENV_VALUE, ":", path_env)); ++const EXTERNAL_CMD_PREFIX: &str = "syscare-"; ++ ++fn exec_external_cmd(mut args: Vec) -> Result<()> { ++ let program = concat_os!(EXTERNAL_CMD_PREFIX, args.remove(0).trim()); ++ ++ let error = Command::new(&program).args(&args).exec(); ++ match error.kind() { ++ std::io::ErrorKind::NotFound => { ++ bail!( ++ "External command '{}' is not installed", ++ program.to_string_lossy() ++ ); ++ } ++ _ => { ++ bail!( ++ "Failed to execute '{}', {}", ++ program.to_string_lossy(), ++ error ++ ); + } +- +- let args = Arguments::new()?; +- +- // Initialize logger +- let log_level_max = if args.verbose { +- LevelFilter::Trace +- } else { +- LevelFilter::Info +- }; +- let log_spec = LogSpecification::builder().default(log_level_max).build(); +- let logger = Logger::with(log_spec) +- .log_to_stdout() +- .format(Self::format_log) +- .write_mode(WriteMode::Direct) +- .start() +- .context("Failed to initialize logger")?; +- +- Ok(Self { args, logger }) + } + } + +-impl SyscareCLI { +- fn run(&self) -> Result { +- debug!("Start with {:#?}", self.args); +- +- debug!("Initializing remote procedure call client..."); +- let socket_file = self.args.work_dir.join(SOCKET_FILE_NAME); +- let remote = Rc::new(RpcRemote::new(socket_file)); +- +- debug!("Initializing remote procedure calls..."); +- let patch_proxy = RpcProxy::new(remote); +- +- debug!("Initializing command executors..."); +- let patch_lock_file = self.args.work_dir.join(PATCH_OP_LOCK_NAME); +- let executors: Vec> = vec![ +- Box::new(BuildCommandExecutor), +- Box::new(PatchCommandExecutor::new(patch_proxy, patch_lock_file)), +- ]; +- +- let command = &self.args.command; +- debug!("Invoking command: {:#?}", command); +- for executor in &executors { +- if let Some(exit_code) = executor.invoke(command)? { +- debug!("Done"); +- return Ok(exit_code); +- } +- } ++fn main() -> Result<()> { ++ // Parse arguments ++ let args = Arguments::new()?; + +- Ok(0) ++ // Set up environments ++ os::umask::set_umask(CLI_UMASK); ++ if let Some(path_env) = env::var_os(PATH_ENV_NAME) { ++ env::set_var(PATH_ENV_NAME, concat_os!(PATH_ENV_VALUE, ":", path_env)); + } +-} + +-impl Drop for SyscareCLI { +- fn drop(&mut self) { +- self.logger.flush(); +- self.logger.shutdown(); ++ // Initialize logger ++ let max_log_level = if args.verbose { ++ LevelFilter::Trace ++ } else { ++ LevelFilter::Info ++ }; ++ let log_spec = LogSpecification::builder().default(max_log_level).build(); ++ let _ = Logger::with(log_spec) ++ .log_to_stdout() ++ .format(|w, _, record| write!(w, "{}", record.args())) ++ .write_mode(WriteMode::Direct) ++ .start() ++ .context("Failed to initialize logger")?; ++ ++ debug!("Start with {:#?}", args); ++ if let SubCommand::External(cmd_args) = args.subcommand { ++ self::exec_external_cmd(cmd_args)?; ++ return Ok(()); + } +-} + +-fn main() { +- let cli = match SyscareCLI::new() { +- Ok(instance) => instance, +- Err(e) => { +- eprintln!("Error: {:?}", e); +- process::exit(-1); +- } +- }; ++ debug!("Initializing rpc client..."); ++ let client = RpcClient::new(&args.work_dir).context("Failed to initialize rpc client")?; + +- match cli.run() { +- Ok(exit_code) => { +- process::exit(exit_code); ++ debug!("Invoking rpc call..."); ++ match &args.subcommand { ++ SubCommand::Info { identifiers } => { ++ PatchProxy::new(&client).show_patch_info(identifiers)?; + } +- Err(e) => { +- error!("Error: {:?}", e); +- +- drop(cli); +- process::exit(-1); ++ SubCommand::Target { identifiers } => { ++ PatchProxy::new(&client).show_patch_target(identifiers)?; ++ } ++ SubCommand::Status { identifiers } => { ++ PatchProxy::new(&client).show_patch_status(identifiers)?; ++ } ++ SubCommand::List => { ++ PatchProxy::new(&client).show_patch_list()?; ++ } ++ SubCommand::Check { identifiers } => { ++ PatchProxy::new(&client).check_patches(identifiers)?; ++ } ++ SubCommand::Apply { identifiers, force } => { ++ PatchProxy::new(&client).apply_patches(identifiers, *force)?; ++ } ++ SubCommand::Remove { identifiers } => { ++ PatchProxy::new(&client).remove_patches(identifiers)?; + } ++ SubCommand::Active { identifiers, force } => { ++ PatchProxy::new(&client).active_patches(identifiers, *force)?; ++ } ++ SubCommand::Deactive { identifiers } => { ++ PatchProxy::new(&client).deactive_patches(identifiers)?; ++ } ++ SubCommand::Accept { identifiers } => { ++ PatchProxy::new(&client).accept_patches(identifiers)?; ++ } ++ SubCommand::Save => { ++ PatchProxy::new(&client).save_patches()?; ++ } ++ SubCommand::Restore { accepted } => { ++ PatchProxy::new(&client).restore_patches(*accepted)?; ++ } ++ SubCommand::Rescan => { ++ PatchProxy::new(&client).rescan_all_patches()?; ++ } ++ _ => unreachable!(), + } ++ ++ Ok(()) + } +diff --git a/syscare/src/rpc/args.rs b/syscare/src/rpc/args.rs +deleted file mode 100644 +index a315a21..0000000 +--- a/syscare/src/rpc/args.rs ++++ /dev/null +@@ -1,42 +0,0 @@ +-// SPDX-License-Identifier: Mulan PSL v2 +-/* +- * Copyright (c) 2024 Huawei Technologies Co., Ltd. +- * syscare is licensed under Mulan PSL v2. +- * You can use this software according to the terms and conditions of the Mulan PSL v2. +- * You may obtain a copy of Mulan PSL v2 at: +- * http://license.coscl.org.cn/MulanPSL2 +- * +- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +- * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +- * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +- * See the Mulan PSL v2 for more details. +- */ +- +-use std::ops::Deref; +- +-use jsonrpc::serde_json::value::RawValue; +-use serde::Serialize; +- +-#[derive(Debug, Default)] +-pub struct RpcArguments { +- args: Vec>, +-} +- +-impl RpcArguments { +- pub fn new() -> Self { +- Self::default() +- } +- +- pub fn arg(mut self, arg: T) -> Self { +- self.args.push(jsonrpc::arg(arg)); +- self +- } +-} +- +-impl Deref for RpcArguments { +- type Target = [Box]; +- +- fn deref(&self) -> &Self::Target { +- &self.args +- } +-} +diff --git a/syscare/src/rpc/client.rs b/syscare/src/rpc/client.rs +new file mode 100644 +index 0000000..c609849 +--- /dev/null ++++ b/syscare/src/rpc/client.rs +@@ -0,0 +1,144 @@ ++// SPDX-License-Identifier: Mulan PSL v2 ++/* ++ * Copyright (c) 2024 Huawei Technologies Co., Ltd. ++ * syscare is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, ++ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, ++ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++use std::{ ++ ops::Deref, ++ path::{Path, PathBuf}, ++}; ++ ++use anyhow::{anyhow, ensure, Error, Result}; ++use jsonrpc::{ ++ serde_json::value::RawValue, ++ simple_uds::{self, UdsTransport}, ++ Client, ++}; ++use log::debug; ++use serde::{Deserialize, Serialize}; ++ ++use syscare_common::fs::{FileLock, FileLockType}; ++ ++#[derive(Debug, Default)] ++pub struct RpcArguments { ++ args: Vec>, ++} ++ ++impl RpcArguments { ++ pub fn new() -> Self { ++ Self::default() ++ } ++ ++ pub fn arg(mut self, arg: T) -> Self { ++ self.args.push(jsonrpc::arg(arg)); ++ self ++ } ++} ++ ++impl Deref for RpcArguments { ++ type Target = [Box]; ++ ++ fn deref(&self) -> &Self::Target { ++ &self.args ++ } ++} ++ ++pub struct RpcClient { ++ lock: PathBuf, ++ socket: PathBuf, ++ client: Client, ++} ++ ++impl RpcClient { ++ pub fn new(work_dir: &Path) -> Result { ++ const LOCK_FILE_NAME: &str = "syscare.lock"; ++ const SOCKET_FILE_NAME: &str = "syscared.sock"; ++ ++ ensure!( ++ work_dir.is_dir(), ++ "Working directory '{}' is invalid", ++ work_dir.display() ++ ); ++ let lock = work_dir.join(LOCK_FILE_NAME); ++ let socket = work_dir.join(SOCKET_FILE_NAME); ++ let client = Client::with_transport(UdsTransport::new(&socket)); ++ ++ Ok(Self { ++ lock, ++ socket, ++ client, ++ }) ++ } ++ ++ pub fn lock(&self) -> Result { ++ FileLock::new(&self.lock, FileLockType::Exclusive) ++ } ++ ++ pub fn call(&self, cmd: &str) -> Result ++ where ++ T: for<'a> Deserialize<'a>, ++ { ++ self.call_with_args::(cmd, RpcArguments::default()) ++ } ++ ++ pub fn call_with_args(&self, cmd: &str, args: RpcArguments) -> Result ++ where ++ T: for<'a> Deserialize<'a>, ++ { ++ let request = self.client.build_request(cmd, &args); ++ debug!("{:#?}", request); ++ ++ let response = self ++ .client ++ .send_request(request) ++ .map_err(|e| self.parse_request_error(e))?; ++ debug!("{:#?}", response); ++ ++ response.result().map_err(|e| self.parse_response_error(e)) ++ } ++} ++ ++impl RpcClient { ++ fn parse_transport_error(&self, error: Box) -> Error { ++ anyhow!( ++ "Cannot connect to syscare daemon at unix://{}, {}", ++ self.socket.display(), ++ match error.downcast::() { ++ Ok(err) => match *err { ++ simple_uds::Error::SocketError(e) => e.to_string(), ++ simple_uds::Error::Timeout => String::from("Connection timeout"), ++ simple_uds::Error::Json(_) => String::from("Invalid data format"), ++ }, ++ Err(_) => { ++ String::from("Unknown error") ++ } ++ } ++ ) ++ } ++ ++ fn parse_request_error(&self, error: jsonrpc::Error) -> Error { ++ match error { ++ jsonrpc::Error::Transport(err) => self.parse_transport_error(err), ++ jsonrpc::Error::Json(_) => anyhow!("Request format error"), ++ _ => anyhow!("Unknown request error"), ++ } ++ } ++ ++ fn parse_response_error(&self, error: jsonrpc::Error) -> Error { ++ match error { ++ jsonrpc::Error::Transport(err) => self.parse_transport_error(err), ++ jsonrpc::Error::Json(_) => anyhow!("Response format error"), ++ jsonrpc::Error::Rpc(_) => anyhow!("Request is unrecognized"), ++ _ => anyhow!("Unknown response error"), ++ } ++ } ++} +diff --git a/syscare/src/rpc/mod.rs b/syscare/src/rpc/mod.rs +index 7d4d872..93ba645 100644 +--- a/syscare/src/rpc/mod.rs ++++ b/syscare/src/rpc/mod.rs +@@ -12,9 +12,8 @@ + * See the Mulan PSL v2 for more details. + */ + +-mod args; ++mod client; + mod proxy; +-mod remote; + +-pub use proxy::*; +-pub use remote::*; ++pub use client::RpcClient; ++pub use proxy::PatchProxy; +diff --git a/syscare/src/rpc/proxy.rs b/syscare/src/rpc/proxy.rs +index d328398..4e59664 100644 +--- a/syscare/src/rpc/proxy.rs ++++ b/syscare/src/rpc/proxy.rs +@@ -12,100 +12,329 @@ + * See the Mulan PSL v2 for more details. + */ + +-use std::rc::Rc; ++use std::fmt::Write; + +-use anyhow::Result; ++use anyhow::{anyhow, Error, Result}; + use function_name::named; + ++use log::info; + use syscare_abi::{PackageInfo, PatchInfo, PatchListRecord, PatchStateRecord}; + +-use super::{args::RpcArguments, remote::RpcRemote}; ++use super::client::{RpcArguments, RpcClient}; + +-pub struct RpcProxy { +- remote: Rc, ++pub struct PatchProxy<'a> { ++ client: &'a RpcClient, + } + +-impl RpcProxy { +- pub fn new(remote: Rc) -> Self { +- Self { remote } ++impl<'a> PatchProxy<'a> { ++ pub fn new(client: &'a RpcClient) -> Self { ++ Self { client } + } ++} + ++/* RPC methods */ ++impl PatchProxy<'_> { + #[named] +- pub fn check_patch(&self, identifier: &str) -> Result<()> { +- self.remote ++ fn check_patch(&self, identifier: &str) -> Result<()> { ++ self.client + .call_with_args(function_name!(), RpcArguments::new().arg(identifier)) + } + + #[named] +- pub fn apply_patch(&self, identifier: &str, force: bool) -> Result> { +- self.remote.call_with_args( ++ fn apply_patch(&self, identifier: &str, force: bool) -> Result> { ++ self.client.call_with_args( + function_name!(), + RpcArguments::new().arg(identifier).arg(force), + ) + } + + #[named] +- pub fn remove_patch(&self, identifier: &str) -> Result> { +- self.remote ++ fn remove_patch(&self, identifier: &str) -> Result> { ++ self.client + .call_with_args(function_name!(), RpcArguments::new().arg(identifier)) + } + + #[named] +- pub fn active_patch(&self, identifier: &str, force: bool) -> Result> { +- self.remote.call_with_args( ++ fn active_patch(&self, identifier: &str, force: bool) -> Result> { ++ self.client.call_with_args( + function_name!(), + RpcArguments::new().arg(identifier).arg(force), + ) + } + + #[named] +- pub fn deactive_patch(&self, identifier: &str) -> Result> { +- self.remote ++ fn deactive_patch(&self, identifier: &str) -> Result> { ++ self.client + .call_with_args(function_name!(), RpcArguments::new().arg(identifier)) + } + + #[named] +- pub fn accept_patch(&self, identifier: &str) -> Result> { +- self.remote ++ fn accept_patch(&self, identifier: &str) -> Result> { ++ self.client + .call_with_args(function_name!(), RpcArguments::new().arg(identifier)) + } + + #[named] +- pub fn get_patch_list(&self) -> Result> { +- self.remote.call(function_name!()) ++ fn get_patch_list(&self) -> Result> { ++ self.client.call(function_name!()) + } + + #[named] +- pub fn get_patch_status(&self, identifier: &str) -> Result> { +- self.remote ++ fn get_patch_status(&self, identifier: &str) -> Result> { ++ self.client + .call_with_args(function_name!(), RpcArguments::new().arg(identifier)) + } + + #[named] +- pub fn get_patch_info(&self, identifier: &str) -> Result { +- self.remote ++ fn get_patch_info(&self, identifier: &str) -> Result { ++ self.client + .call_with_args(function_name!(), RpcArguments::new().arg(identifier)) + } + + #[named] +- pub fn get_patch_target(&self, identifier: &str) -> Result { +- self.remote ++ fn get_patch_target(&self, identifier: &str) -> Result { ++ self.client + .call_with_args(function_name!(), RpcArguments::new().arg(identifier)) + } + + #[named] +- pub fn save_patch_status(&self) -> Result<()> { +- self.remote.call(function_name!()) ++ fn save_patch_status(&self) -> Result<()> { ++ self.client.call(function_name!()) + } + + #[named] +- pub fn restore_patch_status(&self, accepted_only: bool) -> Result<()> { +- self.remote ++ fn restore_patch_status(&self, accepted_only: bool) -> Result<()> { ++ self.client + .call_with_args(function_name!(), RpcArguments::new().arg(accepted_only)) + } + + #[named] +- pub fn rescan_patches(&self) -> Result<()> { +- self.remote.call(function_name!()) ++ fn rescan_patches(&self) -> Result<()> { ++ self.client.call(function_name!()) ++ } ++} ++ ++/* Internal methods */ ++impl PatchProxy<'_> { ++ fn check_error(mut errors: Vec) -> Result<()> { ++ match errors.len() { ++ 0 => Ok(()), ++ 1 => Err(errors.remove(0)), ++ _ => { ++ let mut err_msg = String::new(); ++ for (idx, e) in errors.into_iter().enumerate() { ++ writeln!(err_msg, "{}. {}", idx, e)?; ++ } ++ err_msg.pop(); ++ ++ Err(anyhow!(err_msg)) ++ } ++ } ++ } ++} ++ ++/* External methods */ ++impl PatchProxy<'_> { ++ pub fn show_patch_info(&self, identifiers: &[String]) -> Result<()> { ++ let _ = self.client.lock()?; ++ ++ let mut results = vec![]; ++ let mut errors = vec![]; ++ ++ for identifier in identifiers { ++ match self.get_patch_info(identifier) { ++ Ok(patch_info) => results.push((identifier.as_str(), patch_info)), ++ Err(e) => errors.push(e), ++ } ++ } ++ ++ let mut result_iter = results.into_iter().peekable(); ++ while let Some((identifier, patch_info)) = result_iter.next() { ++ info!("-------------------------------------------"); ++ info!("Patch: {}", identifier); ++ info!("-------------------------------------------"); ++ info!("{}", patch_info); ++ if result_iter.peek().is_some() { ++ continue; ++ } ++ info!("-------------------------------------------"); ++ } ++ Self::check_error(errors) ++ } ++ ++ pub fn show_patch_target(&self, identifiers: &[String]) -> Result<()> { ++ let _ = self.client.lock()?; ++ ++ let mut results = vec![]; ++ let mut errors = vec![]; ++ ++ for identifier in identifiers { ++ match self.get_patch_target(identifier) { ++ Ok(pkg_info) => results.push((identifier.as_str(), pkg_info)), ++ Err(e) => errors.push(e), ++ } ++ } ++ ++ let mut result_iter = results.into_iter().peekable(); ++ while let Some((identifier, pkg_info)) = result_iter.next() { ++ info!("-------------------------------------------"); ++ info!("Patch: {}", identifier); ++ info!("-------------------------------------------"); ++ info!("{}", pkg_info); ++ if result_iter.peek().is_some() { ++ continue; ++ } ++ info!("-------------------------------------------"); ++ } ++ Self::check_error(errors) ++ } ++ ++ pub fn show_patch_status(&self, identifiers: &[String]) -> Result<()> { ++ let _ = self.client.lock()?; ++ ++ let mut results = vec![]; ++ let mut errors = vec![]; ++ ++ for identifier in identifiers { ++ match self.get_patch_status(identifier) { ++ Ok(status_list) => results.extend(status_list), ++ Err(e) => errors.push(e), ++ } ++ } ++ ++ for record in results { ++ info!("{}: {}", record.name, record.status) ++ } ++ Self::check_error(errors) ++ } ++ ++ pub fn show_patch_list(&self) -> Result<()> { ++ let _ = self.client.lock()?; ++ ++ let patch_list = self.get_patch_list()?; ++ ++ info!("{:<40} {:<60} {:<12}", "Uuid", "Name", "Status"); ++ for patch in patch_list { ++ info!("{:<40} {:<60} {:<12}", patch.uuid, patch.name, patch.status) ++ } ++ ++ Ok(()) ++ } ++ ++ pub fn check_patches(&self, identifiers: &[String]) -> Result<()> { ++ let _ = self.client.lock()?; ++ ++ let mut errors = vec![]; ++ for identifier in identifiers { ++ if let Err(e) = self.check_patch(identifier) { ++ errors.push(e); ++ } ++ } ++ Self::check_error(errors) ++ } ++ ++ pub fn apply_patches(&self, identifiers: &[String], force: bool) -> Result<()> { ++ let _ = self.client.lock()?; ++ ++ let mut results = vec![]; ++ let mut errors = vec![]; ++ for identifier in identifiers { ++ match self.apply_patch(identifier, force) { ++ Ok(status_list) => results.extend(status_list), ++ Err(e) => errors.push(e), ++ } ++ } ++ ++ for result in results { ++ info!("{}: {}", result.name, result.status); ++ } ++ Self::check_error(errors) ++ } ++ ++ pub fn remove_patches(&self, identifiers: &[String]) -> Result<()> { ++ let _ = self.client.lock()?; ++ ++ let mut results = vec![]; ++ let mut errors = vec![]; ++ for identifier in identifiers { ++ match self.remove_patch(identifier) { ++ Ok(status_list) => results.extend(status_list), ++ Err(e) => errors.push(e), ++ } ++ } ++ ++ for result in results { ++ info!("{}: {}", result.name, result.status); ++ } ++ Self::check_error(errors) ++ } ++ ++ pub fn active_patches(&self, identifiers: &[String], force: bool) -> Result<()> { ++ let _ = self.client.lock()?; ++ ++ let mut results = vec![]; ++ let mut errors = vec![]; ++ for identifier in identifiers { ++ match self.active_patch(identifier, force) { ++ Ok(status_list) => results.extend(status_list), ++ Err(e) => errors.push(e), ++ } ++ } ++ ++ for result in results { ++ info!("{}: {}", result.name, result.status); ++ } ++ Self::check_error(errors) ++ } ++ ++ pub fn deactive_patches(&self, identifiers: &[String]) -> Result<()> { ++ let _ = self.client.lock()?; ++ ++ let mut results = vec![]; ++ let mut errors = vec![]; ++ for identifier in identifiers { ++ match self.deactive_patch(identifier) { ++ Ok(status_list) => results.extend(status_list), ++ Err(e) => errors.push(e), ++ } ++ } ++ ++ for result in results { ++ info!("{}: {}", result.name, result.status); ++ } ++ Self::check_error(errors) ++ } ++ ++ pub fn accept_patches(&self, identifiers: &[String]) -> Result<()> { ++ let _ = self.client.lock()?; ++ ++ let mut results = vec![]; ++ let mut errors = vec![]; ++ for identifier in identifiers { ++ match self.accept_patch(identifier) { ++ Ok(status_list) => results.extend(status_list), ++ Err(e) => errors.push(e), ++ } ++ } ++ ++ for result in results { ++ info!("{}: {}", result.name, result.status); ++ } ++ Self::check_error(errors) ++ } ++ ++ pub fn save_patches(&self) -> Result<()> { ++ let _ = self.client.lock()?; ++ self.save_patch_status() ++ } ++ ++ pub fn restore_patches(&self, accepted_only: bool) -> Result<()> { ++ let _ = self.client.lock()?; ++ self.restore_patch_status(accepted_only) ++ } ++ ++ pub fn rescan_all_patches(&self) -> Result<()> { ++ let _ = self.client.lock()?; ++ self.rescan_patches() + } + } +diff --git a/syscare/src/rpc/remote.rs b/syscare/src/rpc/remote.rs +deleted file mode 100644 +index f2c9244..0000000 +--- a/syscare/src/rpc/remote.rs ++++ /dev/null +@@ -1,86 +0,0 @@ +-// SPDX-License-Identifier: Mulan PSL v2 +-/* +- * Copyright (c) 2024 Huawei Technologies Co., Ltd. +- * syscare is licensed under Mulan PSL v2. +- * You can use this software according to the terms and conditions of the Mulan PSL v2. +- * You may obtain a copy of Mulan PSL v2 at: +- * http://license.coscl.org.cn/MulanPSL2 +- * +- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +- * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +- * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +- * See the Mulan PSL v2 for more details. +- */ +- +-use std::path::{Path, PathBuf}; +- +-use anyhow::{anyhow, Result}; +-use jsonrpc::{simple_uds::UdsTransport, Client, Error}; +-use log::debug; +-use serde::Deserialize; +- +-use super::args::RpcArguments; +- +-pub struct RpcRemote { +- socket: PathBuf, +- client: Client, +-} +- +-impl RpcRemote { +- pub fn new>(file_path: P) -> Self { +- Self { +- socket: file_path.as_ref().to_path_buf(), +- client: Client::with_transport(UdsTransport::new(file_path)), +- } +- } +- +- pub fn call(&self, cmd: &str) -> Result +- where +- T: for<'a> Deserialize<'a>, +- { +- self.call_with_args::(cmd, RpcArguments::default()) +- } +- +- pub fn call_with_args(&self, cmd: &str, args: RpcArguments) -> Result +- where +- T: for<'a> Deserialize<'a>, +- { +- let request = self.client.build_request(cmd, &args); +- debug!("{:#?}", request); +- +- let response = self +- .client +- .send_request(request) +- .map_err(|e| self.parse_error(e))?; +- debug!("{:#?}", response); +- +- response.result().map_err(|e| self.parse_error(e)) +- } +-} +- +-impl RpcRemote { +- fn parse_error(&self, error: Error) -> anyhow::Error { +- match error { +- Error::Transport(err) => { +- anyhow!( +- "Cannot connect to syscare daemon at unix://{}, {}", +- self.socket.display(), +- err.source() +- .map(|e| e.to_string()) +- .unwrap_or_else(|| "Connection timeout".to_string()) +- ) +- } +- Error::Json(err) => { +- debug!("Json parse error: {:?}", err); +- anyhow!("Failed to parse response") +- } +- Error::Rpc(err) => { +- anyhow!("{}", err.message) +- } +- _ => { +- debug!("{:?}", error); +- anyhow!("Response is invalid") +- } +- } +- } +-} +-- +2.34.1 + diff --git a/syscare.spec b/syscare.spec index 91148be..3c5af8e 100644 --- a/syscare.spec +++ b/syscare.spec @@ -5,7 +5,7 @@ ############################################ Name: syscare Version: 1.2.2 -Release: 4 +Release: 5 Summary: System hot-fix service License: MulanPSL-2.0 and GPL-2.0-only URL: https://gitee.com/openeuler/syscare @@ -30,6 +30,42 @@ Patch0008: 0008-all-remove-signal-handler.patch Patch0009: 0009-project-update-Cargo.lock.patch Patch0010: 0010-syscare-remove-working-directory-check.patch Patch0011: 0011-all-fix-cargo-clippy-warnings.patch +Patch0012: 0012-upatch-diff-format-code.patch +Patch0013: 0013-upatch-manage-format-code.patch +Patch0014: 0014-upatch-manage-remove-build-id-check.patch +Patch0015: 0015-upatch-diff-print-detail-changes.patch +Patch0016: 0016-upatch-diff-ignore-useless-sections.patch +Patch0017: 0017-upatch-manage-enrich-log-output.patch +Patch0018: 0018-project-change-build-options.patch +Patch0019: 0019-upatch-manage-increase-jump-table-size-to-4096.patch +Patch0020: 0020-upatch-manage-fix-failed-to-attach-non-exist-process.patch +Patch0021: 0021-upatch-manage-fix-failed-to-alloc-patch-memory-issue.patch +Patch0022: 0022-upatch-manage-fix-misresolve-.rela.plt-symbol-issue.patch +Patch0023: 0023-upatch-manage-fix-misresolve-std-cout-symbol-issue.patch +Patch0024: 0024-upatch-manage-fix-access-global-variable-coredump-is.patch +Patch0025: 0025-project-update-CMakeLists.txt.patch +Patch0026: 0026-upatch-manage-fix-compile-issue.patch +Patch0027: 0027-syscare-build-supress-rpm-signature-warning.patch +Patch0028: 0028-syscare-build-support-custom-kernel-configuration.patch +Patch0029: 0029-common-add-unit-test-for-process.patch +Patch0030: 0030-syscare-build-add-unit-test-for-spec-writer.patch +Patch0031: 0031-syscare-remove-root-permission-check.patch +Patch0032: 0032-syscared-remove-upatch-failure-process-blacklist.patch +Patch0033: 0033-syscare-optimize-syscare-info-syscare-target-output.patch +Patch0034: 0034-syscared-impl-syscare-rescan-command.patch +Patch0035: 0035-syscare-impl-syscare-rescan-command.patch +Patch0036: 0036-syscared-impl-log-config.patch +Patch0037: 0037-syscared-impl-patch-blacklist.patch +Patch0038: 0038-metadata-viewer-add-component.patch +Patch0039: 0039-metadata-generator-add-component.patch +Patch0040: 0040-project-update-Cargo.lock.patch +Patch0041: 0041-syscared-fix-patch-target-is-blocked-issue.patch +Patch0042: 0042-riscv64-sync-riscv64-support-from-master-to-2503.patch +Patch0043: 0043-syscare-build-fix-detect-incorrect-kernel-source-dir.patch +Patch0044: 0044-upatch-manage-fix-compile-failure.patch +Patch0045: 0045-syscared-fix-kmod-patch-conflicts-with-itself-issue.patch +Patch0046: 0046-common-fix-failed-to-acquire-flock-issue.patch +Patch0047: 0047-syscare-rewrite-syscare-cli.patch ############### Description ################ %description @@ -103,6 +139,7 @@ fi %attr(0555,root,root) /usr/bin/syscare %attr(0550,root,root) /usr/bin/syscared %attr(0550,root,root) /usr/libexec/syscare/upatch-manage +%attr(0550,root,root) /usr/libexec/syscare/metadata-viewer %attr(0550,root,root) /usr/lib/systemd/system/syscare.service ############################################ @@ -131,23 +168,41 @@ Syscare patch building toolset. %attr(555,root,root) /usr/libexec/syscare/upatch-helper %attr(555,root,root) /usr/libexec/syscare/upatch-cc %attr(555,root,root) /usr/libexec/syscare/upatch-c++ +%attr(555,root,root) /usr/libexec/syscare/metadata-generator ############################################ ################ Change log ################ ############################################ %changelog +* Thu Mar 13 2025 renoseven - 1.2.2-5 +- feature: support riscv64 +- feature: support 'syscare rescan' command +- feature: support patch blacklist / blocklist +- feature: support custom kernel config +- feature: support log config +- feature: add metadata viewer +- feature: add metadata generator +- bugfix: supress rpm signature warnings +- bugfix: remove build id check +- bugfix: ignore useless sections +- bugfix: fix attach non-exist process failure +- bugfix: fix remote mmap failure +- bugfix: fix some symbol resolving issue +- bugfix: remove upatch failure process list +- bugfix: remove root permission check + * Thu Feb 20 2025 renoseven - 1.2.2-4 -- all: fix rust 1.84 compile failure -- syscare: fix cannot find working directory -- syscare-build: fix set signal handler failure -- syscared: fix active accepted patch failure +- bugfix: fix rust 1.84 compile failure +- bugfix: fix cannot find working directory +- bugfix: fix set signal handler failure +- bugfix: fix active accepted patch failure * Mon Nov 11 2024 renoseven - 1.2.2-3 -- syscared: support saving & restoring patch status by operation order +- feature: support saving & restoring patch status by operation order * Wed Sep 18 2024 renoseven - 1.2.2-2 -- syscared: fix kernel patch apply failure issue -- upatch-helper: fix object upatch id duplicated issue +- bugfix: fix kernel patch apply failure issue +- bugfix: fix object upatch id duplicated issue * Fri Aug 16 2024 renoseven - 1.2.2-1 - Release version 1.2.2-1. -- Gitee