1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> 4 */ 5 6 #ifndef _CHECK_H 7 #define _CHECK_H 8 9 #include <stdbool.h> 10 #include <objtool/cfi.h> 11 #include <objtool/arch.h> 12 13 struct insn_state { 14 struct cfi_state cfi; 15 unsigned int uaccess_stack; 16 bool uaccess; 17 bool df; 18 bool noinstr; 19 s8 instr; 20 }; 21 22 struct alt_group { 23 /* 24 * Pointer from a replacement group to the original group. NULL if it 25 * *is* the original group. 26 */ 27 struct alt_group *orig_group; 28 29 /* First and last instructions in the group */ 30 struct instruction *first_insn, *last_insn, *nop; 31 32 /* 33 * Byte-offset-addressed len-sized array of pointers to CFI structs. 34 * This is shared with the other alt_groups in the same alternative. 35 */ 36 struct cfi_state **cfi; 37 }; 38 39 #define INSN_CHUNK_BITS 8 40 #define INSN_CHUNK_SIZE (1 << INSN_CHUNK_BITS) 41 #define INSN_CHUNK_MAX (INSN_CHUNK_SIZE - 1) 42 43 struct instruction { 44 struct hlist_node hash; 45 struct list_head call_node; 46 struct section *sec; 47 unsigned long offset; 48 unsigned long immediate; 49 50 u8 len; 51 u8 prev_len; 52 u8 type; 53 s8 instr; 54 55 u32 idx : INSN_CHUNK_BITS, 56 dead_end : 1, 57 ignore : 1, 58 ignore_alts : 1, 59 hint : 1, 60 save : 1, 61 restore : 1, 62 retpoline_safe : 1, 63 noendbr : 1, 64 unret : 1, 65 visited : 4, 66 no_reloc : 1; 67 /* 10 bit hole */ 68 69 struct alt_group *alt_group; 70 struct instruction *jump_dest; 71 struct instruction *first_jump_src; 72 union { 73 struct symbol *_call_dest; 74 struct { 75 struct reloc *_jump_table; 76 unsigned long _jump_table_size; 77 }; 78 }; 79 struct alternative *alts; 80 struct symbol *sym; 81 struct stack_op *stack_ops; 82 struct cfi_state *cfi; 83 }; 84 85 static inline struct symbol *insn_func(struct instruction *insn) 86 { 87 struct symbol *sym = insn->sym; 88 89 if (sym && sym->type != STT_FUNC) 90 sym = NULL; 91 92 return sym; 93 } 94 95 #define VISITED_BRANCH 0x01 96 #define VISITED_BRANCH_UACCESS 0x02 97 #define VISITED_BRANCH_MASK 0x03 98 #define VISITED_UNRET 0x04 99 100 static inline bool is_static_jump(struct instruction *insn) 101 { 102 return insn->type == INSN_JUMP_CONDITIONAL || 103 insn->type == INSN_JUMP_UNCONDITIONAL; 104 } 105 106 static inline bool is_dynamic_jump(struct instruction *insn) 107 { 108 return insn->type == INSN_JUMP_DYNAMIC || 109 insn->type == INSN_JUMP_DYNAMIC_CONDITIONAL; 110 } 111 112 static inline bool is_jump(struct instruction *insn) 113 { 114 return is_static_jump(insn) || is_dynamic_jump(insn); 115 } 116 117 struct instruction *find_insn(struct objtool_file *file, 118 struct section *sec, unsigned long offset); 119 120 struct instruction *next_insn_same_sec(struct objtool_file *file, struct instruction *insn); 121 122 #define sec_for_each_insn(file, _sec, insn) \ 123 for (insn = find_insn(file, _sec, 0); \ 124 insn && insn->sec == _sec; \ 125 insn = next_insn_same_sec(file, insn)) 126 127 #endif /* _CHECK_H */ 128