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.
Unified · Split
| @@ -1350,10 +1350,7 @@ static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *i · 1349 unmodified lines | ||
| 1350 | 1350 | { |
| 1351 | 1351 | struct reloc *reloc; |
| 1352 | 1352 | |
| 1353 | − if (insn->no_reloc) | |
| 1354 | − return NULL; | |
| 1355 | − | |
| 1356 | − if (!file) | |
| 1353 | + if (!file || insn->no_reloc || insn->fake) | |
| 1357 | 1354 | return NULL; |
| 1358 | 1355 | |
| 1359 | 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 | 2620 | static bool validate_branch_enabled(void) |
| 2624 | 2621 | { |
| 2625 | − return opts.stackval || | |
| 2626 | − opts.orc || | |
| 2627 | − opts.uaccess || | |
| 2622 | + return opts.stackval || | |
| 2623 | + opts.orc || | |
| 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 | 2633 | opts.checksum; |
| 2629 | 2634 | } |
| 2630 | 2635 | |
| @@ -2658,7 +2663,7 @@ static int decode_sections(struct objtool_file *file) · 27 unmodified lines | ||
| 2658 | 2663 | * Must be before add_jump_destinations(), which depends on 'func' |
| 2659 | 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 | 2667 | if (add_special_section_alts(file)) |
| 2663 | 2668 | return -1; |
| 2664 | 2669 | } |
| @@ -3654,6 +3659,7 @@ static bool skip_alt_group(struct instruction *insn) · 989 unmodified lines | ||
| 3654 | 3659 | return alt_insn->type == INSN_CLAC || alt_insn->type == INSN_STAC; |
| 3655 | 3660 | } |
| 3656 | 3661 | |
| 3662 | +#ifdef BUILD_KLP | |
| 3657 | 3663 | static int checksum_debug_init(struct objtool_file *file) |
| 3658 | 3664 | { |
| 3659 | 3665 | char *dup, *s; |
| @@ -3701,8 +3707,10 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func, · 41 unmodified lines | ||
| 3701 | 3707 | struct instruction *insn) |
| 3702 | 3708 | { |
| 3703 | 3709 | struct reloc *reloc = insn_reloc(file, insn); |
| 3710 | + struct alternative *alt; | |
| 3704 | 3711 | unsigned long offset; |
| 3705 | 3712 | struct symbol *sym; |
| 3713 | + static bool in_alt; | |
| 3706 | 3714 | |
| 3707 | 3715 | if (insn->fake) |
| 3708 | 3716 | return; |
| @@ -3715,7 +3723,7 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func, · 6 unmodified lines | ||
| 3715 | 3723 | if (call_dest) |
| 3716 | 3724 | checksum_update(func, insn, call_dest->demangled_name, |
| 3717 | 3725 | strlen(call_dest->demangled_name)); |
| 3718 | − return; | |
| 3726 | + goto alts; | |
| 3719 | 3727 | } |
| 3720 | 3728 | |
| 3721 | 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 | 3735 | str = sym->sec->data->d_buf + sym->offset + offset; |
| 3728 | 3736 | checksum_update(func, insn, str, strlen(str)); |
| 3729 | − return; | |
| 3737 | + goto alts; | |
| 3730 | 3738 | } |
| 3731 | 3739 | |
| 3732 | 3740 | if (is_sec_sym(sym)) { |
| 3733 | 3741 | sym = find_symbol_containing(reloc->sym->sec, offset); |
| 3734 | 3742 | if (!sym) |
| 3735 | − return; | |
| 3743 | + goto alts; | |
| 3736 | 3744 | |
| 3737 | 3745 | offset -= sym->offset; |
| 3738 | 3746 | } |
| 3739 | 3747 | |
| 3740 | 3748 | checksum_update(func, insn, sym->demangled_name, strlen(sym->demangled_name)); |
| 3741 | 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 | 3809 | static int validate_branch(struct objtool_file *file, struct symbol *func, |
| 3745 | 3810 | struct instruction *insn, struct insn_state state); |
| 3746 | 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 | 4087 | insn->trace = 0; |
| 4023 | 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 | 4090 | if (func && insn_func(insn) && func != insn_func(insn)->pfunc) { |
| 4029 | 4091 | /* Ignore KCFI type preambles, which always fall through */ |
| 4030 | 4092 | if (is_prefix_func(func)) |
| @@ -4090,9 +4152,6 @@ static int validate_unwind_hint(struct objtool_file *file, · 59 unmodified lines | ||
| 4090 | 4152 | struct symbol *func = insn_func(insn); |
| 4091 | 4153 | int ret; |
| 4092 | 4154 | |
| 4093 | − if (opts.checksum) | |
| 4094 | − checksum_init(func); | |
| 4095 | − | |
| 4096 | 4155 | ret = validate_branch(file, func, insn, *state); |
| 4097 | 4156 | if (ret) |
| 4098 | 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 | 4595 | func = insn_func(insn); |
| 4537 | 4596 | |
| 4538 | − if (opts.checksum) | |
| 4539 | − checksum_init(func); | |
| 4540 | − | |
| 4541 | 4597 | if (opts.trace && !fnmatch(opts.trace, sym->name, 0)) { |
| 4542 | 4598 | trace_enable(); |
| 4543 | 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 | 4606 | TRACE("%s: validation %s\n\n", sym->name, ret ? "failed" : "end"); |
| 4551 | 4607 | trace_disable(); |
| 4552 | 4608 | |
| 4553 | − if (opts.checksum) | |
| 4554 | − checksum_finish(func); | |
| 4555 | − | |
| 4556 | 4609 | return ret; |
| 4557 | 4610 | } |
| 4558 | 4611 | |
| @@ -5007,10 +5060,6 @@ int check(struct objtool_file *file) · 448 unmodified lines | ||
| 5007 | 5060 | cfi_hash_add(&init_cfi); |
| 5008 | 5061 | cfi_hash_add(&func_cfi); |
| 5009 | 5062 | |
| 5010 | − ret = checksum_debug_init(file); | |
| 5011 | − if (ret) | |
| 5012 | − goto out; | |
| 5013 | − | |
| 5014 | 5063 | ret = decode_sections(file); |
| 5015 | 5064 | if (ret) |
| 5016 | 5065 | goto out; |
| @@ -5101,6 +5150,9 @@ int check(struct objtool_file *file) · 84 unmodified lines | ||
| 5101 | 5150 | warnings += check_abs_references(file); |
| 5102 | 5151 | |
| 5103 | 5152 | if (opts.checksum) { |
| 5153 | + ret = calculate_checksums(file); | |
| 5154 | + if (ret) | |
| 5155 | + goto out; | |
| 5104 | 5156 | ret = create_sym_checksum_section(file); |
| 5105 | 5157 | if (ret) |
| 5106 | 5158 | goto out; |
| @@ -33,11 +33,7 @@ static inline void checksum_finish(struct symbol *func) · 32 unmodified lines | ||
| 33 | 33 | |
| 34 | 34 | #else /* !BUILD_KLP */ |
| 35 | 35 | |
| 36 | −static inline void checksum_init(struct symbol *func) {} | |
| 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) {} | |
| 36 | +static inline int calculate_checksums(struct objtool_file *file) { return -ENOSYS; } | |
| 41 | 37 | |
| 42 | 38 | #endif /* !BUILD_KLP */ |
| 43 | 39 | |