In preparation for porting the checksum code to other arches, make its functionality independent from the CFG reverse engineering code. Move it into a standalone calculate_checksums() function which iterates all functions and instructions directly, rather than being called inline from do_validate_branch(). Since checksum_update_insn() is no longer called during CFG traversal, it needs to manually iterate the alternatives.
Showing the changes to tools/objtool (2 of 2 files). Show all
Unified · Split
| @@ -1350,10 +1350,7 @@ static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *i · 1349 unmodified lines | |||
| 1350 | { | 1350 | { |
| 1351 | struct reloc *reloc; | 1351 | struct reloc *reloc; |
| 1352 | 1352 | ||
| 1353 | if (insn->no_reloc) | 1353 | if (!file || insn->no_reloc || insn->fake) |
| 1354 | return NULL; | ||
| 1355 | |||
| 1356 | if (!file) | ||
| 1357 | return NULL; | 1354 | return NULL; |
| 1358 | 1355 | ||
| 1359 | reloc = find_reloc_by_dest_range(file->elf, insn->sec, | 1356 | reloc = find_reloc_by_dest_range(file->elf, insn->sec, |
| @@ -2622,9 +2619,17 @@ static void mark_holes(struct objtool_file *file) · 1262 unmodified lines | |||
| 2622 | 2619 | ||
| 2623 | static bool validate_branch_enabled(void) | 2620 | static bool validate_branch_enabled(void) |
| 2624 | { | 2621 | { |
| 2625 | return opts.stackval || | 2622 | return opts.stackval || |
| 2626 | opts.orc || | 2623 | opts.orc || |
| 2627 | opts.uaccess || | 2624 | opts.uaccess; |
| 2625 | } | ||
| 2626 | |||
| 2627 | static bool alts_needed(void) | ||
| 2628 | { | ||
| 2629 | return validate_branch_enabled() || | ||
| 2630 | opts.noinstr || | ||
| 2631 | opts.hack_jump_label || | ||
| 2632 | opts.disas || | ||
| 2628 | opts.checksum; | 2633 | opts.checksum; |
| 2629 | } | 2634 | } |
| 2630 | 2635 | ||
| @@ -2658,7 +2663,7 @@ static int decode_sections(struct objtool_file *file) · 27 unmodified lines | |||
| 2658 | * Must be before add_jump_destinations(), which depends on 'func' | 2663 | * Must be before add_jump_destinations(), which depends on 'func' |
| 2659 | * being set for alternatives, to enable proper sibling call detection. | 2664 | * being set for alternatives, to enable proper sibling call detection. |
| 2660 | */ | 2665 | */ |
| 2661 | if (validate_branch_enabled() || opts.noinstr || opts.hack_jump_label || opts.disas) { | 2666 | if (alts_needed()) { |
| 2662 | if (add_special_section_alts(file)) | 2667 | if (add_special_section_alts(file)) |
| 2663 | return -1; | 2668 | return -1; |
| 2664 | } | 2669 | } |
| @@ -3654,6 +3659,7 @@ static bool skip_alt_group(struct instruction *insn) · 989 unmodified lines | |||
| 3654 | return alt_insn->type == INSN_CLAC || alt_insn->type == INSN_STAC; | 3659 | return alt_insn->type == INSN_CLAC || alt_insn->type == INSN_STAC; |
| 3655 | } | 3660 | } |
| 3656 | 3661 | ||
| 3662 | #ifdef BUILD_KLP | ||
| 3657 | static int checksum_debug_init(struct objtool_file *file) | 3663 | static int checksum_debug_init(struct objtool_file *file) |
| 3658 | { | 3664 | { |
| 3659 | char *dup, *s; | 3665 | char *dup, *s; |
| @@ -3701,8 +3707,10 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func, · 41 unmodified lines | |||
| 3701 | struct instruction *insn) | 3707 | struct instruction *insn) |
| 3702 | { | 3708 | { |
| 3703 | struct reloc *reloc = insn_reloc(file, insn); | 3709 | struct reloc *reloc = insn_reloc(file, insn); |
| 3710 | struct alternative *alt; | ||
| 3704 | unsigned long offset; | 3711 | unsigned long offset; |
| 3705 | struct symbol *sym; | 3712 | struct symbol *sym; |
| 3713 | static bool in_alt; | ||
| 3706 | 3714 | ||
| 3707 | if (insn->fake) | 3715 | if (insn->fake) |
| 3708 | return; | 3716 | return; |
| @@ -3715,7 +3723,7 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func, · 6 unmodified lines | |||
| 3715 | if (call_dest) | 3723 | if (call_dest) |
| 3716 | checksum_update(func, insn, call_dest->demangled_name, | 3724 | checksum_update(func, insn, call_dest->demangled_name, |
| 3717 | strlen(call_dest->demangled_name)); | 3725 | strlen(call_dest->demangled_name)); |
| 3718 | return; | 3726 | goto alts; |
| 3719 | } | 3727 | } |
| 3720 | 3728 | ||
| 3721 | sym = reloc->sym; | 3729 | sym = reloc->sym; |
| @@ -3726,21 +3734,78 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func, · 4 unmodified lines | |||
| 3726 | 3734 | ||
| 3727 | str = sym->sec->data->d_buf + sym->offset + offset; | 3735 | str = sym->sec->data->d_buf + sym->offset + offset; |
| 3728 | checksum_update(func, insn, str, strlen(str)); | 3736 | checksum_update(func, insn, str, strlen(str)); |
| 3729 | return; | 3737 | goto alts; |
| 3730 | } | 3738 | } |
| 3731 | 3739 | ||
| 3732 | if (is_sec_sym(sym)) { | 3740 | if (is_sec_sym(sym)) { |
| 3733 | sym = find_symbol_containing(reloc->sym->sec, offset); | 3741 | sym = find_symbol_containing(reloc->sym->sec, offset); |
| 3734 | if (!sym) | 3742 | if (!sym) |
| 3735 | return; | 3743 | goto alts; |
| 3736 | 3744 | ||
| 3737 | offset -= sym->offset; | 3745 | offset -= sym->offset; |
| 3738 | } | 3746 | } |
| 3739 | 3747 | ||
| 3740 | checksum_update(func, insn, sym->demangled_name, strlen(sym->demangled_name)); | 3748 | checksum_update(func, insn, sym->demangled_name, strlen(sym->demangled_name)); |
| 3741 | checksum_update(func, insn, &offset, sizeof(offset)); | 3749 | checksum_update(func, insn, &offset, sizeof(offset)); |
| 3750 | |||
| 3751 | alts: | ||
| 3752 | for (alt = insn->alts; alt; alt = alt->next) { | ||
| 3753 | struct alt_group *alt_group = alt->insn->alt_group; | ||
| 3754 | |||
| 3755 | /* Prevent __ex_table recursion, e.g. LOAD_SEGMENT() */ | ||
| 3756 | if (in_alt) | ||
| 3757 | break; | ||
| 3758 | in_alt = true; | ||
| 3759 | |||
| 3760 | checksum_update(func, insn, &alt->type, sizeof(alt->type)); | ||
| 3761 | |||
| 3762 | if (alt_group && alt_group->orig_group) { | ||
| 3763 | struct instruction *alt_insn; | ||
| 3764 | |||
| 3765 | checksum_update(func, insn, &alt_group->feature, sizeof(alt_group->feature)); | ||
| 3766 | |||
| 3767 | for (alt_insn = alt->insn; alt_insn; alt_insn = next_insn_same_sec(file, alt_insn)) { | ||
| 3768 | checksum_update_insn(file, func, alt_insn); | ||
| 3769 | if (!alt_group->last_insn || alt_insn == alt_group->last_insn) | ||
| 3770 | break; | ||
| 3771 | } | ||
| 3772 | } else { | ||
| 3773 | checksum_update_insn(file, func, alt->insn); | ||
| 3774 | } | ||
| 3775 | |||
| 3776 | in_alt = false; | ||
| 3777 | } | ||
| 3742 | } | 3778 | } |
| 3743 | 3779 | ||
| 3780 | static int calculate_checksums(struct objtool_file *file) | ||
| 3781 | { | ||
| 3782 | struct instruction *insn; | ||
| 3783 | struct symbol *func; | ||
| 3784 | |||
| 3785 | if (checksum_debug_init(file)) | ||
| 3786 | return -1; | ||
| 3787 | |||
| 3788 | for_each_sym(file->elf, func) { | ||
| 3789 | /* | ||
| 3790 | * Skip cold subfunctions and aliases: they share the | ||
| 3791 | * parent's checksum via func_for_each_insn() which | ||
| 3792 | * follows func->cfunc into the cold subfunction. | ||
| 3793 | */ | ||
| 3794 | if (!is_func_sym(func) || is_cold_func(func) || | ||
| 3795 | is_alias_sym(func) || !func->len) | ||
| 3796 | continue; | ||
| 3797 | |||
| 3798 | checksum_init(func); | ||
| 3799 | |||
| 3800 | func_for_each_insn(file, func, insn) | ||
| 3801 | checksum_update_insn(file, func, insn); | ||
| 3802 | |||
| 3803 | checksum_finish(func); | ||
| 3804 | } | ||
| 3805 | return 0; | ||
| 3806 | } | ||
| 3807 | #endif /* BUILD_KLP */ | ||
| 3808 | |||
| 3744 | static int validate_branch(struct objtool_file *file, struct symbol *func, | 3809 | static int validate_branch(struct objtool_file *file, struct symbol *func, |
| 3745 | struct instruction *insn, struct insn_state state); | 3810 | struct instruction *insn, struct insn_state state); |
| 3746 | static int do_validate_branch(struct objtool_file *file, struct symbol *func, | 3811 | static int do_validate_branch(struct objtool_file *file, struct symbol *func, |
| @@ -4022,9 +4087,6 @@ static int do_validate_branch(struct objtool_file *file, struct symbol *func, · 275 unmodified lines | |||
| 4022 | insn->trace = 0; | 4087 | insn->trace = 0; |
| 4023 | next_insn = next_insn_to_validate(file, insn); | 4088 | next_insn = next_insn_to_validate(file, insn); |
| 4024 | 4089 | ||
| 4025 | if (opts.checksum && func && insn->sec) | ||
| 4026 | checksum_update_insn(file, func, insn); | ||
| 4027 | |||
| 4028 | if (func && insn_func(insn) && func != insn_func(insn)->pfunc) { | 4090 | if (func && insn_func(insn) && func != insn_func(insn)->pfunc) { |
| 4029 | /* Ignore KCFI type preambles, which always fall through */ | 4091 | /* Ignore KCFI type preambles, which always fall through */ |
| 4030 | if (is_prefix_func(func)) | 4092 | if (is_prefix_func(func)) |
| @@ -4090,9 +4152,6 @@ static int validate_unwind_hint(struct objtool_file *file, · 59 unmodified lines | |||
| 4090 | struct symbol *func = insn_func(insn); | 4152 | struct symbol *func = insn_func(insn); |
| 4091 | int ret; | 4153 | int ret; |
| 4092 | 4154 | ||
| 4093 | if (opts.checksum) | ||
| 4094 | checksum_init(func); | ||
| 4095 | |||
| 4096 | ret = validate_branch(file, func, insn, *state); | 4155 | ret = validate_branch(file, func, insn, *state); |
| 4097 | if (ret) | 4156 | if (ret) |
| 4098 | BT_INSN(insn, "<=== (hint)"); | 4157 | BT_INSN(insn, "<=== (hint)"); |
| @@ -4535,9 +4594,6 @@ static int validate_symbol(struct objtool_file *file, struct section *sec, · 436 unmodified lines | |||
| 4535 | 4594 | ||
| 4536 | func = insn_func(insn); | 4595 | func = insn_func(insn); |
| 4537 | 4596 | ||
| 4538 | if (opts.checksum) | ||
| 4539 | checksum_init(func); | ||
| 4540 | |||
| 4541 | if (opts.trace && !fnmatch(opts.trace, sym->name, 0)) { | 4597 | if (opts.trace && !fnmatch(opts.trace, sym->name, 0)) { |
| 4542 | trace_enable(); | 4598 | trace_enable(); |
| 4543 | TRACE("%s: validation begin\n", sym->name); | 4599 | TRACE("%s: validation begin\n", sym->name); |
| @@ -4550,9 +4606,6 @@ static int validate_symbol(struct objtool_file *file, struct section *sec, · 6 unmodified lines | |||
| 4550 | TRACE("%s: validation %s\n\n", sym->name, ret ? "failed" : "end"); | 4606 | TRACE("%s: validation %s\n\n", sym->name, ret ? "failed" : "end"); |
| 4551 | trace_disable(); | 4607 | trace_disable(); |
| 4552 | 4608 | ||
| 4553 | if (opts.checksum) | ||
| 4554 | checksum_finish(func); | ||
| 4555 | |||
| 4556 | return ret; | 4609 | return ret; |
| 4557 | } | 4610 | } |
| 4558 | 4611 | ||
| @@ -5007,10 +5060,6 @@ int check(struct objtool_file *file) · 448 unmodified lines | |||
| 5007 | cfi_hash_add(&init_cfi); | 5060 | cfi_hash_add(&init_cfi); |
| 5008 | cfi_hash_add(&func_cfi); | 5061 | cfi_hash_add(&func_cfi); |
| 5009 | 5062 | ||
| 5010 | ret = checksum_debug_init(file); | ||
| 5011 | if (ret) | ||
| 5012 | goto out; | ||
| 5013 | |||
| 5014 | ret = decode_sections(file); | 5063 | ret = decode_sections(file); |
| 5015 | if (ret) | 5064 | if (ret) |
| 5016 | goto out; | 5065 | goto out; |
| @@ -5101,6 +5150,9 @@ int check(struct objtool_file *file) · 84 unmodified lines | |||
| 5101 | warnings += check_abs_references(file); | 5150 | warnings += check_abs_references(file); |
| 5102 | 5151 | ||
| 5103 | if (opts.checksum) { | 5152 | if (opts.checksum) { |
| 5153 | ret = calculate_checksums(file); | ||
| 5154 | if (ret) | ||
| 5155 | goto out; | ||
| 5104 | ret = create_sym_checksum_section(file); | 5156 | ret = create_sym_checksum_section(file); |
| 5105 | if (ret) | 5157 | if (ret) |
| 5106 | goto out; | 5158 | goto out; |
| @@ -33,11 +33,7 @@ static inline void checksum_finish(struct symbol *func) · 32 unmodified lines | |||
| 33 | 33 | ||
| 34 | #else /* !BUILD_KLP */ | 34 | #else /* !BUILD_KLP */ |
| 35 | 35 | ||
| 36 | static inline void checksum_init(struct symbol *func) {} | 36 | static inline int calculate_checksums(struct objtool_file *file) { return -ENOSYS; } |
| 37 | static inline void checksum_update(struct symbol *func, | ||
| 38 | struct instruction *insn, | ||
| 39 | const void *data, size_t size) {} | ||
| 40 | static inline void checksum_finish(struct symbol *func) {} | ||
| 41 | 37 | ||
| 42 | #endif /* !BUILD_KLP */ | 38 | #endif /* !BUILD_KLP */ |
| 43 | 39 | ||