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 13struct 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 22struct 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 43struct 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 reloc *_jump_table; 75 }; 76 struct alternative *alts; 77 struct symbol *sym; 78 struct stack_op *stack_ops; 79 struct cfi_state *cfi; 80}; 81 82static inline struct symbol *insn_func(struct instruction *insn) 83{ 84 struct symbol *sym = insn->sym; 85 86 if (sym && sym->type != STT_FUNC) 87 sym = NULL; 88 89 return sym; 90} 91 92#define VISITED_BRANCH 0x01 93#define VISITED_BRANCH_UACCESS 0x02 94#define VISITED_BRANCH_MASK 0x03 95#define VISITED_UNRET 0x04 96 97static inline bool is_static_jump(struct instruction *insn) 98{ 99 return insn->type == INSN_JUMP_CONDITIONAL || 100 insn->type == INSN_JUMP_UNCONDITIONAL; 101} 102 103static inline bool is_dynamic_jump(struct instruction *insn) 104{ 105 return insn->type == INSN_JUMP_DYNAMIC || 106 insn->type == INSN_JUMP_DYNAMIC_CONDITIONAL; 107} 108 109static inline bool is_jump(struct instruction *insn) 110{ 111 return is_static_jump(insn) || is_dynamic_jump(insn); 112} 113 114struct instruction *find_insn(struct objtool_file *file, 115 struct section *sec, unsigned long offset); 116 117struct instruction *next_insn_same_sec(struct objtool_file *file, struct instruction *insn); 118 119#define sec_for_each_insn(file, _sec, insn) \ 120 for (insn = find_insn(file, _sec, 0); \ 121 insn && insn->sec == _sec; \ 122 insn = next_insn_same_sec(file, insn)) 123 124#endif /* _CHECK_H */ 125