Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

objtool: Extract code to validate instruction from the validate branch loop

The code to validate a branch loops through all instructions of the
branch and validate each instruction. Move the code to validate an
instruction to a separated function.

Signed-off-by: Alexandre Chartre <alexandre.chartre@oracle.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Josh Poimboeuf <jpoimboe@kernel.org>
Link: https://patch.msgid.link/20251121095340.464045-9-alexandre.chartre@oracle.com

authored by

Alexandre Chartre and committed by
Peter Zijlstra
a0e5bf9f 0bb080ba

+235 -211
+235 -211
tools/objtool/check.c
··· 3654 3654 checksum_update(func, insn, &offset, sizeof(offset)); 3655 3655 } 3656 3656 3657 + static int validate_branch(struct objtool_file *file, struct symbol *func, 3658 + struct instruction *insn, struct insn_state state); 3659 + 3660 + static int validate_insn(struct objtool_file *file, struct symbol *func, 3661 + struct instruction *insn, struct insn_state *statep, 3662 + struct instruction *prev_insn, struct instruction *next_insn, 3663 + bool *dead_end) 3664 + { 3665 + struct alternative *alt; 3666 + u8 visited; 3667 + int ret; 3668 + 3669 + /* 3670 + * Any returns before the end of this function are effectively dead 3671 + * ends, i.e. validate_branch() has reached the end of the branch. 3672 + */ 3673 + *dead_end = true; 3674 + 3675 + visited = VISITED_BRANCH << statep->uaccess; 3676 + if (insn->visited & VISITED_BRANCH_MASK) { 3677 + if (!insn->hint && !insn_cfi_match(insn, &statep->cfi)) 3678 + return 1; 3679 + 3680 + if (insn->visited & visited) 3681 + return 0; 3682 + } else { 3683 + nr_insns_visited++; 3684 + } 3685 + 3686 + if (statep->noinstr) 3687 + statep->instr += insn->instr; 3688 + 3689 + if (insn->hint) { 3690 + if (insn->restore) { 3691 + struct instruction *save_insn, *i; 3692 + 3693 + i = insn; 3694 + save_insn = NULL; 3695 + 3696 + sym_for_each_insn_continue_reverse(file, func, i) { 3697 + if (i->save) { 3698 + save_insn = i; 3699 + break; 3700 + } 3701 + } 3702 + 3703 + if (!save_insn) { 3704 + WARN_INSN(insn, "no corresponding CFI save for CFI restore"); 3705 + return 1; 3706 + } 3707 + 3708 + if (!save_insn->visited) { 3709 + /* 3710 + * If the restore hint insn is at the 3711 + * beginning of a basic block and was 3712 + * branched to from elsewhere, and the 3713 + * save insn hasn't been visited yet, 3714 + * defer following this branch for now. 3715 + * It will be seen later via the 3716 + * straight-line path. 3717 + */ 3718 + if (!prev_insn) 3719 + return 0; 3720 + 3721 + WARN_INSN(insn, "objtool isn't smart enough to handle this CFI save/restore combo"); 3722 + return 1; 3723 + } 3724 + 3725 + insn->cfi = save_insn->cfi; 3726 + nr_cfi_reused++; 3727 + } 3728 + 3729 + statep->cfi = *insn->cfi; 3730 + } else { 3731 + /* XXX track if we actually changed statep->cfi */ 3732 + 3733 + if (prev_insn && !cficmp(prev_insn->cfi, &statep->cfi)) { 3734 + insn->cfi = prev_insn->cfi; 3735 + nr_cfi_reused++; 3736 + } else { 3737 + insn->cfi = cfi_hash_find_or_add(&statep->cfi); 3738 + } 3739 + } 3740 + 3741 + insn->visited |= visited; 3742 + 3743 + if (propagate_alt_cfi(file, insn)) 3744 + return 1; 3745 + 3746 + if (insn->alts) { 3747 + for (alt = insn->alts; alt; alt = alt->next) { 3748 + ret = validate_branch(file, func, alt->insn, *statep); 3749 + if (ret) { 3750 + BT_INSN(insn, "(alt)"); 3751 + return ret; 3752 + } 3753 + } 3754 + } 3755 + 3756 + if (skip_alt_group(insn)) 3757 + return 0; 3758 + 3759 + if (handle_insn_ops(insn, next_insn, statep)) 3760 + return 1; 3761 + 3762 + switch (insn->type) { 3763 + 3764 + case INSN_RETURN: 3765 + return validate_return(func, insn, statep); 3766 + 3767 + case INSN_CALL: 3768 + case INSN_CALL_DYNAMIC: 3769 + ret = validate_call(file, insn, statep); 3770 + if (ret) 3771 + return ret; 3772 + 3773 + if (opts.stackval && func && !is_special_call(insn) && 3774 + !has_valid_stack_frame(statep)) { 3775 + WARN_INSN(insn, "call without frame pointer save/setup"); 3776 + return 1; 3777 + } 3778 + 3779 + break; 3780 + 3781 + case INSN_JUMP_CONDITIONAL: 3782 + case INSN_JUMP_UNCONDITIONAL: 3783 + if (is_sibling_call(insn)) { 3784 + ret = validate_sibling_call(file, insn, statep); 3785 + if (ret) 3786 + return ret; 3787 + 3788 + } else if (insn->jump_dest) { 3789 + ret = validate_branch(file, func, 3790 + insn->jump_dest, *statep); 3791 + if (ret) { 3792 + BT_INSN(insn, "(branch)"); 3793 + return ret; 3794 + } 3795 + } 3796 + 3797 + if (insn->type == INSN_JUMP_UNCONDITIONAL) 3798 + return 0; 3799 + 3800 + break; 3801 + 3802 + case INSN_JUMP_DYNAMIC: 3803 + case INSN_JUMP_DYNAMIC_CONDITIONAL: 3804 + if (is_sibling_call(insn)) { 3805 + ret = validate_sibling_call(file, insn, statep); 3806 + if (ret) 3807 + return ret; 3808 + } 3809 + 3810 + if (insn->type == INSN_JUMP_DYNAMIC) 3811 + return 0; 3812 + 3813 + break; 3814 + 3815 + case INSN_SYSCALL: 3816 + if (func && (!next_insn || !next_insn->hint)) { 3817 + WARN_INSN(insn, "unsupported instruction in callable function"); 3818 + return 1; 3819 + } 3820 + 3821 + break; 3822 + 3823 + case INSN_SYSRET: 3824 + if (func && (!next_insn || !next_insn->hint)) { 3825 + WARN_INSN(insn, "unsupported instruction in callable function"); 3826 + return 1; 3827 + } 3828 + 3829 + return 0; 3830 + 3831 + case INSN_STAC: 3832 + if (!opts.uaccess) 3833 + break; 3834 + 3835 + if (statep->uaccess) { 3836 + WARN_INSN(insn, "recursive UACCESS enable"); 3837 + return 1; 3838 + } 3839 + 3840 + statep->uaccess = true; 3841 + break; 3842 + 3843 + case INSN_CLAC: 3844 + if (!opts.uaccess) 3845 + break; 3846 + 3847 + if (!statep->uaccess && func) { 3848 + WARN_INSN(insn, "redundant UACCESS disable"); 3849 + return 1; 3850 + } 3851 + 3852 + if (func_uaccess_safe(func) && !statep->uaccess_stack) { 3853 + WARN_INSN(insn, "UACCESS-safe disables UACCESS"); 3854 + return 1; 3855 + } 3856 + 3857 + statep->uaccess = false; 3858 + break; 3859 + 3860 + case INSN_STD: 3861 + if (statep->df) { 3862 + WARN_INSN(insn, "recursive STD"); 3863 + return 1; 3864 + } 3865 + 3866 + statep->df = true; 3867 + break; 3868 + 3869 + case INSN_CLD: 3870 + if (!statep->df && func) { 3871 + WARN_INSN(insn, "redundant CLD"); 3872 + return 1; 3873 + } 3874 + 3875 + statep->df = false; 3876 + break; 3877 + 3878 + default: 3879 + break; 3880 + } 3881 + 3882 + *dead_end = insn->dead_end; 3883 + 3884 + return 0; 3885 + } 3886 + 3657 3887 /* 3658 3888 * Follow the branch starting at the given instruction, and recursively follow 3659 3889 * any other branches (jumps). Meanwhile, track the frame pointer state at ··· 3893 3663 static int validate_branch(struct objtool_file *file, struct symbol *func, 3894 3664 struct instruction *insn, struct insn_state state) 3895 3665 { 3896 - struct alternative *alt; 3897 3666 struct instruction *next_insn, *prev_insn = NULL; 3898 - u8 visited; 3667 + bool dead_end; 3899 3668 int ret; 3900 3669 3901 3670 if (func && func->ignore) ··· 3921 3692 return 1; 3922 3693 } 3923 3694 3924 - visited = VISITED_BRANCH << state.uaccess; 3925 - if (insn->visited & VISITED_BRANCH_MASK) { 3926 - if (!insn->hint && !insn_cfi_match(insn, &state.cfi)) 3927 - return 1; 3928 - 3929 - if (insn->visited & visited) 3930 - return 0; 3931 - } else { 3932 - nr_insns_visited++; 3933 - } 3934 - 3935 - if (state.noinstr) 3936 - state.instr += insn->instr; 3937 - 3938 - if (insn->hint) { 3939 - if (insn->restore) { 3940 - struct instruction *save_insn, *i; 3941 - 3942 - i = insn; 3943 - save_insn = NULL; 3944 - 3945 - sym_for_each_insn_continue_reverse(file, func, i) { 3946 - if (i->save) { 3947 - save_insn = i; 3948 - break; 3949 - } 3950 - } 3951 - 3952 - if (!save_insn) { 3953 - WARN_INSN(insn, "no corresponding CFI save for CFI restore"); 3954 - return 1; 3955 - } 3956 - 3957 - if (!save_insn->visited) { 3958 - /* 3959 - * If the restore hint insn is at the 3960 - * beginning of a basic block and was 3961 - * branched to from elsewhere, and the 3962 - * save insn hasn't been visited yet, 3963 - * defer following this branch for now. 3964 - * It will be seen later via the 3965 - * straight-line path. 3966 - */ 3967 - if (!prev_insn) 3968 - return 0; 3969 - 3970 - WARN_INSN(insn, "objtool isn't smart enough to handle this CFI save/restore combo"); 3971 - return 1; 3972 - } 3973 - 3974 - insn->cfi = save_insn->cfi; 3975 - nr_cfi_reused++; 3976 - } 3977 - 3978 - state.cfi = *insn->cfi; 3979 - } else { 3980 - /* XXX track if we actually changed state.cfi */ 3981 - 3982 - if (prev_insn && !cficmp(prev_insn->cfi, &state.cfi)) { 3983 - insn->cfi = prev_insn->cfi; 3984 - nr_cfi_reused++; 3985 - } else { 3986 - insn->cfi = cfi_hash_find_or_add(&state.cfi); 3987 - } 3988 - } 3989 - 3990 - insn->visited |= visited; 3991 - 3992 - if (propagate_alt_cfi(file, insn)) 3993 - return 1; 3994 - 3995 - if (insn->alts) { 3996 - for (alt = insn->alts; alt; alt = alt->next) { 3997 - ret = validate_branch(file, func, alt->insn, state); 3998 - if (ret) { 3999 - BT_INSN(insn, "(alt)"); 4000 - return ret; 4001 - } 4002 - } 4003 - } 4004 - 4005 - if (skip_alt_group(insn)) 4006 - return 0; 4007 - 4008 - if (handle_insn_ops(insn, next_insn, &state)) 4009 - return 1; 4010 - 4011 - switch (insn->type) { 4012 - 4013 - case INSN_RETURN: 4014 - return validate_return(func, insn, &state); 4015 - 4016 - case INSN_CALL: 4017 - case INSN_CALL_DYNAMIC: 4018 - ret = validate_call(file, insn, &state); 4019 - if (ret) 4020 - return ret; 4021 - 4022 - if (opts.stackval && func && !is_special_call(insn) && 4023 - !has_valid_stack_frame(&state)) { 4024 - WARN_INSN(insn, "call without frame pointer save/setup"); 4025 - return 1; 4026 - } 4027 - 3695 + ret = validate_insn(file, func, insn, &state, prev_insn, next_insn, 3696 + &dead_end); 3697 + if (dead_end) 4028 3698 break; 4029 - 4030 - case INSN_JUMP_CONDITIONAL: 4031 - case INSN_JUMP_UNCONDITIONAL: 4032 - if (is_sibling_call(insn)) { 4033 - ret = validate_sibling_call(file, insn, &state); 4034 - if (ret) 4035 - return ret; 4036 - 4037 - } else if (insn->jump_dest) { 4038 - ret = validate_branch(file, func, 4039 - insn->jump_dest, state); 4040 - if (ret) { 4041 - BT_INSN(insn, "(branch)"); 4042 - return ret; 4043 - } 4044 - } 4045 - 4046 - if (insn->type == INSN_JUMP_UNCONDITIONAL) 4047 - return 0; 4048 - 4049 - break; 4050 - 4051 - case INSN_JUMP_DYNAMIC: 4052 - case INSN_JUMP_DYNAMIC_CONDITIONAL: 4053 - if (is_sibling_call(insn)) { 4054 - ret = validate_sibling_call(file, insn, &state); 4055 - if (ret) 4056 - return ret; 4057 - } 4058 - 4059 - if (insn->type == INSN_JUMP_DYNAMIC) 4060 - return 0; 4061 - 4062 - break; 4063 - 4064 - case INSN_SYSCALL: 4065 - if (func && (!next_insn || !next_insn->hint)) { 4066 - WARN_INSN(insn, "unsupported instruction in callable function"); 4067 - return 1; 4068 - } 4069 - 4070 - break; 4071 - 4072 - case INSN_SYSRET: 4073 - if (func && (!next_insn || !next_insn->hint)) { 4074 - WARN_INSN(insn, "unsupported instruction in callable function"); 4075 - return 1; 4076 - } 4077 - 4078 - return 0; 4079 - 4080 - case INSN_STAC: 4081 - if (!opts.uaccess) 4082 - break; 4083 - 4084 - if (state.uaccess) { 4085 - WARN_INSN(insn, "recursive UACCESS enable"); 4086 - return 1; 4087 - } 4088 - 4089 - state.uaccess = true; 4090 - break; 4091 - 4092 - case INSN_CLAC: 4093 - if (!opts.uaccess) 4094 - break; 4095 - 4096 - if (!state.uaccess && func) { 4097 - WARN_INSN(insn, "redundant UACCESS disable"); 4098 - return 1; 4099 - } 4100 - 4101 - if (func_uaccess_safe(func) && !state.uaccess_stack) { 4102 - WARN_INSN(insn, "UACCESS-safe disables UACCESS"); 4103 - return 1; 4104 - } 4105 - 4106 - state.uaccess = false; 4107 - break; 4108 - 4109 - case INSN_STD: 4110 - if (state.df) { 4111 - WARN_INSN(insn, "recursive STD"); 4112 - return 1; 4113 - } 4114 - 4115 - state.df = true; 4116 - break; 4117 - 4118 - case INSN_CLD: 4119 - if (!state.df && func) { 4120 - WARN_INSN(insn, "redundant CLD"); 4121 - return 1; 4122 - } 4123 - 4124 - state.df = false; 4125 - break; 4126 - 4127 - default: 4128 - break; 4129 - } 4130 - 4131 - if (insn->dead_end) 4132 - return 0; 4133 3699 4134 3700 if (!next_insn) { 4135 3701 if (state.cfi.cfa.base == CFI_UNDEFINED) ··· 3942 3918 insn = next_insn; 3943 3919 } 3944 3920 3945 - return 0; 3921 + return ret; 3946 3922 } 3947 3923 3948 3924 static int validate_unwind_hint(struct objtool_file *file,