^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include "builtin.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "cfi.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "arch.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "check.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "special.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "warn.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "arch_elf.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/objtool.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/hashtable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/static_call_types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define FAKE_JUMP_OFFSET -1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct alternative {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) bool skip_orig;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct cfi_init_state initial_func_cfi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct instruction *find_insn(struct objtool_file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct section *sec, unsigned long offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) hash_for_each_possible(file->insn_hash, insn, hash, sec_offset_hash(sec, offset)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (insn->sec == sec && insn->offset == offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static struct instruction *next_insn_same_sec(struct objtool_file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct instruction *insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct instruction *next = list_next_entry(insn, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (!next || &next->list == &file->insn_list || next->sec != insn->sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static struct instruction *next_insn_same_func(struct objtool_file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct instruction *insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct instruction *next = list_next_entry(insn, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct symbol *func = insn->func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (!func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (&next->list != &file->insn_list && next->func == func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /* Check if we're already in the subfunction: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (func == func->cfunc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /* Move to the subfunction: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return find_insn(file, func->cfunc->sec, func->cfunc->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) static struct instruction *prev_insn_same_sym(struct objtool_file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct instruction *insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct instruction *prev = list_prev_entry(insn, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (&prev->list != &file->insn_list && prev->func == insn->func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return prev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define func_for_each_insn(file, func, insn) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) for (insn = find_insn(file, func->sec, func->offset); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) insn; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) insn = next_insn_same_func(file, insn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) #define sym_for_each_insn(file, sym, insn) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) for (insn = find_insn(file, sym->sec, sym->offset); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) insn && &insn->list != &file->insn_list && \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) insn->sec == sym->sec && \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) insn->offset < sym->offset + sym->len; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) insn = list_next_entry(insn, list))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) #define sym_for_each_insn_continue_reverse(file, sym, insn) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) for (insn = list_prev_entry(insn, list); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) &insn->list != &file->insn_list && \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) insn->sec == sym->sec && insn->offset >= sym->offset; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) insn = list_prev_entry(insn, list))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) #define sec_for_each_insn_from(file, insn) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) for (; insn; insn = next_insn_same_sec(file, insn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) #define sec_for_each_insn_continue(file, insn) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) for (insn = next_insn_same_sec(file, insn); insn; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) insn = next_insn_same_sec(file, insn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static bool is_sibling_call(struct instruction *insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /* An indirect jump is either a sibling call or a jump to a table. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (insn->type == INSN_JUMP_DYNAMIC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return list_empty(&insn->alts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (!is_static_jump(insn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /* add_jump_destinations() sets insn->call_dest for sibling calls. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return !!insn->call_dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * This checks to see if the given function is a "noreturn" function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * For global functions which are outside the scope of this object file, we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * have to keep a manual list of them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * For local functions, we have to detect them manually by simply looking for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * the lack of a return instruction.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) int recursion)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) bool empty = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * Unfortunately these have to be hard coded because the noreturn
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * attribute isn't provided in ELF data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static const char * const global_noreturns[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) "__stack_chk_fail",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) "panic",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) "do_exit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) "do_task_dead",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) "__module_put_and_exit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) "complete_and_exit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) "__reiserfs_panic",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) "lbug_with_loc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) "fortify_panic",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) "usercopy_abort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) "machine_real_restart",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) "rewind_stack_do_exit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) "kunit_try_catch_throw",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) "xen_start_kernel",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) "cpu_bringup_and_idle",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (!func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (func->bind == STB_WEAK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (func->bind == STB_GLOBAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) for (i = 0; i < ARRAY_SIZE(global_noreturns); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (!strcmp(func->name, global_noreturns[i]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (!func->len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) insn = find_insn(file, func->sec, func->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (!insn->func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) func_for_each_insn(file, func, insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) empty = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (insn->type == INSN_RETURN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (empty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * A function can have a sibling call instead of a return. In that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) * case, the function's dead-end status depends on whether the target
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * of the sibling call returns.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) func_for_each_insn(file, func, insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (is_sibling_call(insn)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) struct instruction *dest = insn->jump_dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (!dest)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) /* sibling call to another file */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) /* local sibling call */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) if (recursion == 5) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * Infinite recursion: two functions have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) * sibling calls to each other. This is a very
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * rare case. It means they aren't dead ends.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return __dead_end_function(file, dest->func, recursion+1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static bool dead_end_function(struct objtool_file *file, struct symbol *func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return __dead_end_function(file, func, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) static void init_cfi_state(struct cfi_state *cfi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) for (i = 0; i < CFI_NUM_REGS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) cfi->regs[i].base = CFI_UNDEFINED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) cfi->vals[i].base = CFI_UNDEFINED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) cfi->cfa.base = CFI_UNDEFINED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) cfi->drap_reg = CFI_UNDEFINED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) cfi->drap_offset = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) static void init_insn_state(struct insn_state *state, struct section *sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) memset(state, 0, sizeof(*state));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) init_cfi_state(&state->cfi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * We need the full vmlinux for noinstr validation, otherwise we can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) * not correctly determine insn->call_dest->sec (external symbols do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) * not have a section).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) if (vmlinux && noinstr && sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) state->noinstr = sec->noinstr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * Call the arch-specific instruction decoder for all the instructions and add
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * them to the global instruction list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) static int decode_instructions(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) struct section *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) struct symbol *func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) unsigned long offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) unsigned long nr_insns = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) for_each_sec(file, sec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) if (!(sec->sh.sh_flags & SHF_EXECINSTR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (strcmp(sec->name, ".altinstr_replacement") &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) strcmp(sec->name, ".altinstr_aux") &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) strncmp(sec->name, ".discard.", 9))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) sec->text = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if (!strcmp(sec->name, ".noinstr.text") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) !strcmp(sec->name, ".entry.text"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) sec->noinstr = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) for (offset = 0; offset < sec->len; offset += insn->len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) insn = malloc(sizeof(*insn));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (!insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) WARN("malloc failed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) memset(insn, 0, sizeof(*insn));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) INIT_LIST_HEAD(&insn->alts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) INIT_LIST_HEAD(&insn->stack_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) init_cfi_state(&insn->cfi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) insn->sec = sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) insn->offset = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) ret = arch_decode_instruction(file->elf, sec, offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) sec->len - offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) &insn->len, &insn->type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) &insn->immediate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) &insn->stack_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) hash_add(file->insn_hash, &insn->hash, sec_offset_hash(sec, insn->offset));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) list_add_tail(&insn->list, &file->insn_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) nr_insns++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) list_for_each_entry(func, &sec->symbol_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (func->type != STT_FUNC || func->alias != func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (!find_insn(file, sec, func->offset)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) WARN("%s(): can't find starting instruction",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) func->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) sym_for_each_insn(file, func, insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) insn->func = func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) if (stats)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) printf("nr_insns: %lu\n", nr_insns);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) free(insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) static struct instruction *find_last_insn(struct objtool_file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) struct section *sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) struct instruction *insn = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) unsigned int offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) unsigned int end = (sec->len > 10) ? sec->len - 10 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) for (offset = sec->len - 1; offset >= end && !insn; offset--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) insn = find_insn(file, sec, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) * Mark "ud2" instructions and manually annotated dead ends.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) static int add_dead_ends(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) struct section *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) struct reloc *reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) * By default, "ud2" is a dead end unless otherwise annotated, because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) * GCC 7 inserts it for certain divide-by-zero cases.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) for_each_insn(file, insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) if (insn->type == INSN_BUG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) insn->dead_end = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) * Check for manually annotated dead ends.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) sec = find_section_by_name(file->elf, ".rela.discard.unreachable");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) if (!sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) goto reachable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) list_for_each_entry(reloc, &sec->reloc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (reloc->sym->type != STT_SECTION) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) WARN("unexpected relocation symbol type in %s", sec->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) insn = find_insn(file, reloc->sym->sec, reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) if (insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) insn = list_prev_entry(insn, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) else if (reloc->addend == reloc->sym->sec->len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) insn = find_last_insn(file, reloc->sym->sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) if (!insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) WARN("can't find unreachable insn at %s+0x%x",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) reloc->sym->sec->name, reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) WARN("can't find unreachable insn at %s+0x%x",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) reloc->sym->sec->name, reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) insn->dead_end = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) reachable:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * These manually annotated reachable checks are needed for GCC 4.4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) * where the Linux unreachable() macro isn't supported. In that case
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) * GCC doesn't know the "ud2" is fatal, so it generates code as if it's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) * not a dead end.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) sec = find_section_by_name(file->elf, ".rela.discard.reachable");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (!sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) list_for_each_entry(reloc, &sec->reloc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (reloc->sym->type != STT_SECTION) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) WARN("unexpected relocation symbol type in %s", sec->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) insn = find_insn(file, reloc->sym->sec, reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) insn = list_prev_entry(insn, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) else if (reloc->addend == reloc->sym->sec->len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) insn = find_last_insn(file, reloc->sym->sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) if (!insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) WARN("can't find reachable insn at %s+0x%x",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) reloc->sym->sec->name, reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) WARN("can't find reachable insn at %s+0x%x",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) reloc->sym->sec->name, reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) insn->dead_end = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) static int create_static_call_sections(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) struct section *sec, *reloc_sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) struct reloc *reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) struct static_call_site *site;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) struct symbol *key_sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) char *key_name, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) int idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) sec = find_section_by_name(file->elf, ".static_call_sites");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) if (sec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) INIT_LIST_HEAD(&file->static_call_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) WARN("file already has .static_call_sites section, skipping");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) if (list_empty(&file->static_call_list))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) idx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) list_for_each_entry(insn, &file->static_call_list, static_call_node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) sec = elf_create_section(file->elf, ".static_call_sites", SHF_WRITE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) sizeof(struct static_call_site), idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (!sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) reloc_sec = elf_create_reloc_section(file->elf, sec, SHT_RELA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) if (!reloc_sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) idx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) list_for_each_entry(insn, &file->static_call_list, static_call_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) site = (struct static_call_site *)sec->data->d_buf + idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) memset(site, 0, sizeof(struct static_call_site));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) /* populate reloc for 'addr' */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) reloc = malloc(sizeof(*reloc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) if (!reloc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) perror("malloc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) memset(reloc, 0, sizeof(*reloc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) insn_to_reloc_sym_addend(insn->sec, insn->offset, reloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if (!reloc->sym) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) WARN_FUNC("static call tramp: missing containing symbol",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) reloc->type = R_X86_64_PC32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) reloc->offset = idx * sizeof(struct static_call_site);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) reloc->sec = reloc_sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) elf_add_reloc(file->elf, reloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) /* find key symbol */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) key_name = strdup(insn->call_dest->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (!key_name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) perror("strdup");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) if (strncmp(key_name, STATIC_CALL_TRAMP_PREFIX_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) STATIC_CALL_TRAMP_PREFIX_LEN)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) WARN("static_call: trampoline name malformed: %s", key_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) tmp = key_name + STATIC_CALL_TRAMP_PREFIX_LEN - STATIC_CALL_KEY_PREFIX_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) memcpy(tmp, STATIC_CALL_KEY_PREFIX_STR, STATIC_CALL_KEY_PREFIX_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) key_sym = find_symbol_by_name(file->elf, tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) if (!key_sym) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) if (!module) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) WARN("static_call: can't find static_call_key symbol: %s", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) * For modules(), the key might not be exported, which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) * means the module can make static calls but isn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) * allowed to change them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) * In that case we temporarily set the key to be the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) * trampoline address. This is fixed up in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) * static_call_add_module().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) key_sym = insn->call_dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) free(key_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) /* populate reloc for 'key' */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) reloc = malloc(sizeof(*reloc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) if (!reloc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) perror("malloc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) memset(reloc, 0, sizeof(*reloc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) reloc->sym = key_sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) reloc->addend = is_sibling_call(insn) ? STATIC_CALL_SITE_TAIL : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) reloc->type = R_X86_64_PC32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) reloc->offset = idx * sizeof(struct static_call_site) + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) reloc->sec = reloc_sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) elf_add_reloc(file->elf, reloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) if (elf_rebuild_reloc_section(file->elf, reloc_sec))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) static int create_mcount_loc_sections(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) struct section *sec, *reloc_sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) struct reloc *reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) unsigned long *loc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) int idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) sec = find_section_by_name(file->elf, "__mcount_loc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) if (sec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) INIT_LIST_HEAD(&file->mcount_loc_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) WARN("file already has __mcount_loc section, skipping");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) if (list_empty(&file->mcount_loc_list))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) idx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) list_for_each_entry(insn, &file->mcount_loc_list, mcount_loc_node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) sec = elf_create_section(file->elf, "__mcount_loc", 0, sizeof(unsigned long), idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) if (!sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) reloc_sec = elf_create_reloc_section(file->elf, sec, SHT_RELA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) if (!reloc_sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) idx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) list_for_each_entry(insn, &file->mcount_loc_list, mcount_loc_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) loc = (unsigned long *)sec->data->d_buf + idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) memset(loc, 0, sizeof(unsigned long));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) reloc = malloc(sizeof(*reloc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) if (!reloc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) perror("malloc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) memset(reloc, 0, sizeof(*reloc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) if (insn->sec->sym) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) reloc->sym = insn->sec->sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) reloc->addend = insn->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) reloc->sym = find_symbol_containing(insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) if (!reloc->sym) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) WARN("missing symbol for insn at offset 0x%lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) reloc->addend = insn->offset - reloc->sym->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) reloc->type = R_X86_64_64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) reloc->offset = idx * sizeof(unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) reloc->sec = reloc_sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) elf_add_reloc(file->elf, reloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) if (elf_rebuild_reloc_section(file->elf, reloc_sec))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) * Warnings shouldn't be reported for ignored functions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) static void add_ignores(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) struct section *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) struct symbol *func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) struct reloc *reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) sec = find_section_by_name(file->elf, ".rela.discard.func_stack_frame_non_standard");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) if (!sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) list_for_each_entry(reloc, &sec->reloc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) switch (reloc->sym->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) case STT_FUNC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) func = reloc->sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) case STT_SECTION:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) func = find_func_by_offset(reloc->sym->sec, reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) if (!func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) WARN("unexpected relocation symbol type in %s: %d", sec->name, reloc->sym->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) func_for_each_insn(file, func, insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) insn->ignore = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) * This is a whitelist of functions that is allowed to be called with AC set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) * The list is meant to be minimal and only contains compiler instrumentation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) * ABI and a few functions used to implement *_{to,from}_user() functions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) * These functions must not directly change AC, but may PUSHF/POPF.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) static const char *uaccess_safe_builtin[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) /* KASAN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) "kasan_report",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) "kasan_check_range",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) /* KASAN out-of-line */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) "__asan_loadN_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) "__asan_load1_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) "__asan_load2_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) "__asan_load4_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) "__asan_load8_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) "__asan_load16_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) "__asan_storeN_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) "__asan_store1_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) "__asan_store2_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) "__asan_store4_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) "__asan_store8_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) "__asan_store16_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) "__kasan_check_read",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) "__kasan_check_write",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) /* KASAN in-line */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) "__asan_report_load_n_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) "__asan_report_load1_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) "__asan_report_load2_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) "__asan_report_load4_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) "__asan_report_load8_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) "__asan_report_load16_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) "__asan_report_store_n_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) "__asan_report_store1_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) "__asan_report_store2_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) "__asan_report_store4_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) "__asan_report_store8_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) "__asan_report_store16_noabort",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) /* KCSAN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) "__kcsan_check_access",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) "kcsan_found_watchpoint",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) "kcsan_setup_watchpoint",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) "kcsan_check_scoped_accesses",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) "kcsan_disable_current",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) "kcsan_enable_current_nowarn",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) /* KCSAN/TSAN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) "__tsan_func_entry",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) "__tsan_func_exit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) "__tsan_read_range",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) "__tsan_write_range",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) "__tsan_read1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) "__tsan_read2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) "__tsan_read4",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) "__tsan_read8",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) "__tsan_read16",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) "__tsan_write1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) "__tsan_write2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) "__tsan_write4",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) "__tsan_write8",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) "__tsan_write16",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) "__tsan_read_write1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) "__tsan_read_write2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) "__tsan_read_write4",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) "__tsan_read_write8",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) "__tsan_read_write16",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) "__tsan_atomic8_load",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) "__tsan_atomic16_load",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) "__tsan_atomic32_load",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) "__tsan_atomic64_load",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) "__tsan_atomic8_store",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) "__tsan_atomic16_store",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) "__tsan_atomic32_store",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) "__tsan_atomic64_store",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) "__tsan_atomic8_exchange",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) "__tsan_atomic16_exchange",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) "__tsan_atomic32_exchange",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) "__tsan_atomic64_exchange",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) "__tsan_atomic8_fetch_add",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) "__tsan_atomic16_fetch_add",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) "__tsan_atomic32_fetch_add",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) "__tsan_atomic64_fetch_add",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) "__tsan_atomic8_fetch_sub",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) "__tsan_atomic16_fetch_sub",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) "__tsan_atomic32_fetch_sub",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) "__tsan_atomic64_fetch_sub",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) "__tsan_atomic8_fetch_and",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) "__tsan_atomic16_fetch_and",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) "__tsan_atomic32_fetch_and",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) "__tsan_atomic64_fetch_and",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) "__tsan_atomic8_fetch_or",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) "__tsan_atomic16_fetch_or",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) "__tsan_atomic32_fetch_or",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) "__tsan_atomic64_fetch_or",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) "__tsan_atomic8_fetch_xor",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) "__tsan_atomic16_fetch_xor",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) "__tsan_atomic32_fetch_xor",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) "__tsan_atomic64_fetch_xor",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) "__tsan_atomic8_fetch_nand",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) "__tsan_atomic16_fetch_nand",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) "__tsan_atomic32_fetch_nand",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) "__tsan_atomic64_fetch_nand",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) "__tsan_atomic8_compare_exchange_strong",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) "__tsan_atomic16_compare_exchange_strong",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) "__tsan_atomic32_compare_exchange_strong",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) "__tsan_atomic64_compare_exchange_strong",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) "__tsan_atomic8_compare_exchange_weak",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) "__tsan_atomic16_compare_exchange_weak",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) "__tsan_atomic32_compare_exchange_weak",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) "__tsan_atomic64_compare_exchange_weak",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) "__tsan_atomic8_compare_exchange_val",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) "__tsan_atomic16_compare_exchange_val",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) "__tsan_atomic32_compare_exchange_val",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) "__tsan_atomic64_compare_exchange_val",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) "__tsan_atomic_thread_fence",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) "__tsan_atomic_signal_fence",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) /* KCOV */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) "write_comp_data",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) "check_kcov_mode",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) "__sanitizer_cov_trace_pc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) "__sanitizer_cov_trace_const_cmp1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) "__sanitizer_cov_trace_const_cmp2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) "__sanitizer_cov_trace_const_cmp4",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) "__sanitizer_cov_trace_const_cmp8",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) "__sanitizer_cov_trace_cmp1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) "__sanitizer_cov_trace_cmp2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) "__sanitizer_cov_trace_cmp4",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) "__sanitizer_cov_trace_cmp8",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) "__sanitizer_cov_trace_switch",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) /* UBSAN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) "ubsan_type_mismatch_common",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) "__ubsan_handle_type_mismatch",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) "__ubsan_handle_type_mismatch_v1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) "__ubsan_handle_shift_out_of_bounds",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) /* misc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) "csum_partial_copy_generic",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) "copy_mc_fragile",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) "copy_mc_fragile_handle_tail",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) "copy_mc_enhanced_fast_string",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) "ftrace_likely_update", /* CONFIG_TRACE_BRANCH_PROFILING */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) static void add_uaccess_safe(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) struct symbol *func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) const char **name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) if (!uaccess)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) for (name = uaccess_safe_builtin; *name; name++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) func = find_symbol_by_name(file->elf, *name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) if (!func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) func->uaccess_safe = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) * FIXME: For now, just ignore any alternatives which add retpolines. This is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) * a temporary hack, as it doesn't allow ORC to unwind from inside a retpoline.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) * But it at least allows objtool to understand the control flow *around* the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) * retpoline.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) static int add_ignore_alternatives(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) struct section *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) struct reloc *reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) sec = find_section_by_name(file->elf, ".rela.discard.ignore_alts");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) if (!sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) list_for_each_entry(reloc, &sec->reloc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) if (reloc->sym->type != STT_SECTION) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) WARN("unexpected relocation symbol type in %s", sec->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) insn = find_insn(file, reloc->sym->sec, reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) if (!insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) WARN("bad .discard.ignore_alts entry");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) insn->ignore_alts = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) * CONFIG_CFI_CLANG: Check if the section is a CFI jump table or a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) * compiler-generated CFI handler.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) static bool is_cfi_section(struct section *sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) return (sec->name &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) (!strncmp(sec->name, ".text..L.cfi.jumptable", 22) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) !strcmp(sec->name, ".text.__cfi_check")));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) * CONFIG_CFI_CLANG: Ignore CFI jump tables.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) static void add_cfi_jumptables(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) struct section *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) struct symbol *func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) for_each_sec(file, sec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) if (!is_cfi_section(sec))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) list_for_each_entry(func, &sec->symbol_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) sym_for_each_insn(file, func, insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) insn->ignore = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) * Find the destination instructions for all jumps.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) static int add_jump_destinations(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) struct reloc *reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) struct section *dest_sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) unsigned long dest_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) for_each_insn(file, insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) if (!is_static_jump(insn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) if (insn->offset == FAKE_JUMP_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) reloc = find_reloc_by_dest_range(file->elf, insn->sec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) insn->offset, insn->len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) if (!reloc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) dest_sec = insn->sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) dest_off = arch_jump_destination(insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) } else if (reloc->sym->type == STT_SECTION) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) dest_sec = reloc->sym->sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) dest_off = arch_dest_reloc_offset(reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) } else if (reloc->sym->sec->idx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) dest_sec = reloc->sym->sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) dest_off = reloc->sym->sym.st_value +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) arch_dest_reloc_offset(reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) } else if (!strncmp(reloc->sym->name, "__x86_indirect_thunk_", 21) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) !strncmp(reloc->sym->name, "__x86_retpoline_", 16)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) * Retpoline jumps are really dynamic jumps in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) * disguise, so convert them accordingly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) if (insn->type == INSN_JUMP_UNCONDITIONAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) insn->type = INSN_JUMP_DYNAMIC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) insn->retpoline_safe = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) /* external sibling call */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) insn->call_dest = reloc->sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) if (insn->call_dest->static_call_tramp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) list_add_tail(&insn->static_call_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) &file->static_call_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) insn->jump_dest = find_insn(file, dest_sec, dest_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) if (!insn->jump_dest && dest_sec->len == dest_off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) insn->jump_dest = find_last_insn(file, dest_sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) if (!insn->jump_dest) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) * This is a special case where an alt instruction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) * jumps past the end of the section. These are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) * handled later in handle_group_alt().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) if (!strcmp(insn->sec->name, ".altinstr_replacement"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) if (is_cfi_section(insn->sec))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) WARN_FUNC("can't find jump dest instruction at %s+0x%lx",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) insn->sec, insn->offset, dest_sec->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) dest_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) * Cross-function jump.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) if (insn->func && insn->jump_dest->func &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) insn->func != insn->jump_dest->func) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) * For GCC 8+, create parent/child links for any cold
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) * subfunctions. This is _mostly_ redundant with a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) * similar initialization in read_symbols().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) * If a function has aliases, we want the *first* such
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) * function in the symbol table to be the subfunction's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) * parent. In that case we overwrite the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) * initialization done in read_symbols().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) * However this code can't completely replace the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) * read_symbols() code because this doesn't detect the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) * case where the parent function's only reference to a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) * subfunction is through a jump table.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) if (!strstr(insn->func->name, ".cold") &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) strstr(insn->jump_dest->func->name, ".cold")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) insn->func->cfunc = insn->jump_dest->func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) insn->jump_dest->func->pfunc = insn->func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) } else if (insn->jump_dest->func->pfunc != insn->func->pfunc &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) insn->jump_dest->offset == insn->jump_dest->func->offset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) /* internal sibling call */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) insn->call_dest = insn->jump_dest->func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) if (insn->call_dest->static_call_tramp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) list_add_tail(&insn->static_call_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) &file->static_call_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) static void remove_insn_ops(struct instruction *insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) struct stack_op *op, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) list_for_each_entry_safe(op, tmp, &insn->stack_ops, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) list_del(&op->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) free(op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) static struct symbol *find_call_destination(struct section *sec, unsigned long offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) struct symbol *call_dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) call_dest = find_func_by_offset(sec, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) if (!call_dest)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) call_dest = find_symbol_by_offset(sec, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) return call_dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) * Find the destination instructions for all calls.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) static int add_call_destinations(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) unsigned long dest_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) struct reloc *reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) for_each_insn(file, insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) if (insn->type != INSN_CALL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) reloc = find_reloc_by_dest_range(file->elf, insn->sec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) insn->offset, insn->len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) if (!reloc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) dest_off = arch_jump_destination(insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) insn->call_dest = find_call_destination(insn->sec, dest_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) if (insn->ignore)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) if (!insn->call_dest) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) WARN_FUNC("unannotated intra-function call", insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) if (insn->func && insn->call_dest->type != STT_FUNC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) WARN_FUNC("unsupported call to non-function",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) } else if (reloc->sym->type == STT_SECTION) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) dest_off = arch_dest_reloc_offset(reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) insn->call_dest = find_call_destination(reloc->sym->sec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) dest_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) if (!insn->call_dest) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) if (is_cfi_section(reloc->sym->sec))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) WARN_FUNC("can't find call dest symbol at %s+0x%lx",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) insn->sec, insn->offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) reloc->sym->sec->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) dest_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) insn->call_dest = reloc->sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) if (insn->call_dest && insn->call_dest->static_call_tramp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) list_add_tail(&insn->static_call_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) &file->static_call_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) * Many compilers cannot disable KCOV with a function attribute
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) * so they need a little help, NOP out any KCOV calls from noinstr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) * text.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) if (insn->sec->noinstr &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) !strncmp(insn->call_dest->name, "__sanitizer_cov_", 16)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) if (reloc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) reloc->type = R_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) elf_write_reloc(file->elf, reloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) elf_write_insn(file->elf, insn->sec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) insn->offset, insn->len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) arch_nop_insn(insn->len));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) insn->type = INSN_NOP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) if (mcount && !strcmp(insn->call_dest->name, "__fentry__")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) if (reloc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) reloc->type = R_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) elf_write_reloc(file->elf, reloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) elf_write_insn(file->elf, insn->sec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) insn->offset, insn->len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) arch_nop_insn(insn->len));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) insn->type = INSN_NOP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) list_add_tail(&insn->mcount_loc_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) &file->mcount_loc_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) * Whatever stack impact regular CALLs have, should be undone
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) * by the RETURN of the called function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) * Annotated intra-function calls retain the stack_ops but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) * are converted to JUMP, see read_intra_function_calls().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) remove_insn_ops(insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) * The .alternatives section requires some extra special care, over and above
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) * what other special sections require:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) * 1. Because alternatives are patched in-place, we need to insert a fake jump
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) * instruction at the end so that validate_branch() skips all the original
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) * replaced instructions when validating the new instruction path.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) * 2. An added wrinkle is that the new instruction length might be zero. In
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) * that case the old instructions are replaced with noops. We simulate that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) * by creating a fake jump as the only new instruction.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) * 3. In some cases, the alternative section includes an instruction which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) * conditionally jumps to the _end_ of the entry. We have to modify these
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) * jumps' destinations to point back to .text rather than the end of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) * entry in .altinstr_replacement.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) static int handle_group_alt(struct objtool_file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) struct special_alt *special_alt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) struct instruction *orig_insn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) struct instruction **new_insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) static unsigned int alt_group_next_index = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) unsigned int alt_group = alt_group_next_index++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) unsigned long dest_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) last_orig_insn = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) insn = orig_insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) sec_for_each_insn_from(file, insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) if (insn->offset >= special_alt->orig_off + special_alt->orig_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) insn->alt_group = alt_group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) last_orig_insn = insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) if (next_insn_same_sec(file, last_orig_insn)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) fake_jump = malloc(sizeof(*fake_jump));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) if (!fake_jump) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) WARN("malloc failed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) memset(fake_jump, 0, sizeof(*fake_jump));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) INIT_LIST_HEAD(&fake_jump->alts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) INIT_LIST_HEAD(&fake_jump->stack_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) init_cfi_state(&fake_jump->cfi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) fake_jump->sec = special_alt->new_sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) fake_jump->offset = FAKE_JUMP_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) fake_jump->type = INSN_JUMP_UNCONDITIONAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) fake_jump->jump_dest = list_next_entry(last_orig_insn, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) fake_jump->func = orig_insn->func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) if (!special_alt->new_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) if (!fake_jump) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) WARN("%s: empty alternative at end of section",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) special_alt->orig_sec->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) *new_insn = fake_jump;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) last_new_insn = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) alt_group = alt_group_next_index++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) insn = *new_insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) sec_for_each_insn_from(file, insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) struct reloc *alt_reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) if (insn->offset >= special_alt->new_off + special_alt->new_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) last_new_insn = insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) insn->ignore = orig_insn->ignore_alts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) insn->func = orig_insn->func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) insn->alt_group = alt_group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) * Since alternative replacement code is copy/pasted by the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) * kernel after applying relocations, generally such code can't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) * have relative-address relocation references to outside the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) * .altinstr_replacement section, unless the arch's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) * alternatives code can adjust the relative offsets
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) * accordingly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) alt_reloc = find_reloc_by_dest_range(file->elf, insn->sec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) insn->offset, insn->len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) if (alt_reloc &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) !arch_support_alt_relocation(special_alt, insn, alt_reloc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) WARN_FUNC("unsupported relocation in alternatives section",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) if (!is_static_jump(insn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) if (!insn->immediate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) dest_off = arch_jump_destination(insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) if (dest_off == special_alt->new_off + special_alt->new_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) if (!fake_jump) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) WARN("%s: alternative jump to end of section",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) special_alt->orig_sec->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) insn->jump_dest = fake_jump;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) if (!insn->jump_dest) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) WARN_FUNC("can't find alternative jump destination",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) if (!last_new_insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) WARN_FUNC("can't find last new alternative instruction",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) special_alt->new_sec, special_alt->new_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) if (fake_jump)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) list_add(&fake_jump->list, &last_new_insn->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) * A jump table entry can either convert a nop to a jump or a jump to a nop.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) * If the original instruction is a jump, make the alt entry an effective nop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) * by just skipping the original instruction.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) static int handle_jump_alt(struct objtool_file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) struct special_alt *special_alt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) struct instruction *orig_insn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) struct instruction **new_insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) if (orig_insn->type == INSN_NOP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) WARN_FUNC("unsupported instruction at jump label",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) orig_insn->sec, orig_insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) *new_insn = list_next_entry(orig_insn, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) * Read all the special sections which have alternate instructions which can be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) * patched in or redirected to at runtime. Each instruction having alternate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) * instruction(s) has them added to its insn->alts list, which will be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) * traversed in validate_branch().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) static int add_special_section_alts(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) struct list_head special_alts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) struct instruction *orig_insn, *new_insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) struct special_alt *special_alt, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) struct alternative *alt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) ret = special_get_alts(file->elf, &special_alts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) list_for_each_entry_safe(special_alt, tmp, &special_alts, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) orig_insn = find_insn(file, special_alt->orig_sec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) special_alt->orig_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) if (!orig_insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) WARN_FUNC("special: can't find orig instruction",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) special_alt->orig_sec, special_alt->orig_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) ret = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) new_insn = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) if (!special_alt->group || special_alt->new_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) new_insn = find_insn(file, special_alt->new_sec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) special_alt->new_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) if (!new_insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) WARN_FUNC("special: can't find new instruction",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) special_alt->new_sec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) special_alt->new_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) ret = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) if (special_alt->group) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) if (!special_alt->orig_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) WARN_FUNC("empty alternative entry",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) orig_insn->sec, orig_insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) ret = handle_group_alt(file, special_alt, orig_insn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) &new_insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) } else if (special_alt->jump_or_nop) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) ret = handle_jump_alt(file, special_alt, orig_insn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) &new_insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) alt = malloc(sizeof(*alt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) if (!alt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) WARN("malloc failed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) ret = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) alt->insn = new_insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) alt->skip_orig = special_alt->skip_orig;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) orig_insn->ignore_alts |= special_alt->skip_alt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) list_add_tail(&alt->list, &orig_insn->alts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) list_del(&special_alt->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) free(special_alt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) static int add_jump_table(struct objtool_file *file, struct instruction *insn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) struct reloc *table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) struct reloc *reloc = table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) struct instruction *dest_insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) struct alternative *alt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) struct symbol *pfunc = insn->func->pfunc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) unsigned int prev_offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) * Each @reloc is a switch table relocation which points to the target
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) * instruction.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) list_for_each_entry_from(reloc, &table->sec->reloc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) /* Check for the end of the table: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) if (reloc != table && reloc->jump_table_start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) /* Make sure the table entries are consecutive: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) if (prev_offset && reloc->offset != prev_offset + 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) /* Detect function pointers from contiguous objects: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) if (reloc->sym->sec == pfunc->sec &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) reloc->addend == pfunc->offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) dest_insn = find_insn(file, reloc->sym->sec, reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) if (!dest_insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) /* Make sure the destination is in the same function: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) if (!dest_insn->func || dest_insn->func->pfunc != pfunc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) alt = malloc(sizeof(*alt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) if (!alt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) WARN("malloc failed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) alt->insn = dest_insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) list_add_tail(&alt->list, &insn->alts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) prev_offset = reloc->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) if (!prev_offset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) WARN_FUNC("can't find switch jump table",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) * find_jump_table() - Given a dynamic jump, find the switch jump table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) * associated with it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) static struct reloc *find_jump_table(struct objtool_file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) struct symbol *func,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) struct instruction *insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) struct reloc *table_reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) struct instruction *dest_insn, *orig_insn = insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) * Backward search using the @first_jump_src links, these help avoid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) * much of the 'in between' code. Which avoids us getting confused by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) * it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) for (;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) insn && insn->func && insn->func->pfunc == func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) insn = insn->first_jump_src ?: prev_insn_same_sym(file, insn)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) /* allow small jumps within the range */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) if (insn->type == INSN_JUMP_UNCONDITIONAL &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) insn->jump_dest &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) (insn->jump_dest->offset <= insn->offset ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) insn->jump_dest->offset > orig_insn->offset))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) table_reloc = arch_find_switch_table(file, insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) if (!table_reloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) dest_insn = find_insn(file, table_reloc->sym->sec, table_reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) if (!dest_insn || !dest_insn->func || dest_insn->func->pfunc != func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) return table_reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) * First pass: Mark the head of each jump table so that in the next pass,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) * we know when a given jump table ends and the next one starts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) static void mark_func_jump_tables(struct objtool_file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) struct symbol *func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) struct instruction *insn, *last = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) struct reloc *reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) func_for_each_insn(file, func, insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) if (!last)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) last = insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) * Store back-pointers for unconditional forward jumps such
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) * that find_jump_table() can back-track using those and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) * avoid some potentially confusing code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) insn->offset > last->offset &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) insn->jump_dest->offset > insn->offset &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) !insn->jump_dest->first_jump_src) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) insn->jump_dest->first_jump_src = insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) last = insn->jump_dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) if (insn->type != INSN_JUMP_DYNAMIC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) reloc = find_jump_table(file, func, insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) if (reloc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) reloc->jump_table_start = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) insn->jump_table = reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) static int add_func_jump_tables(struct objtool_file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) struct symbol *func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) func_for_each_insn(file, func, insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) if (!insn->jump_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) ret = add_jump_table(file, insn, insn->jump_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) * For some switch statements, gcc generates a jump table in the .rodata
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) * section which contains a list of addresses within the function to jump to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) * This finds these jump tables and adds them to the insn->alts lists.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) static int add_jump_table_alts(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) struct section *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) struct symbol *func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) if (!file->rodata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) for_each_sec(file, sec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) list_for_each_entry(func, &sec->symbol_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) if (func->type != STT_FUNC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) mark_func_jump_tables(file, func);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) ret = add_func_jump_tables(file, func);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) static int read_unwind_hints(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) struct section *sec, *relocsec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) struct reloc *reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) struct unwind_hint *hint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) struct cfi_reg *cfa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) sec = find_section_by_name(file->elf, ".discard.unwind_hints");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) if (!sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) relocsec = sec->reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) if (!relocsec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) WARN("missing .rela.discard.unwind_hints section");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) if (sec->len % sizeof(struct unwind_hint)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) WARN("struct unwind_hint size mismatch");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) file->hints = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) for (i = 0; i < sec->len / sizeof(struct unwind_hint); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) hint = (struct unwind_hint *)sec->data->d_buf + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) reloc = find_reloc_by_dest(file->elf, sec, i * sizeof(*hint));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) if (!reloc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) WARN("can't find reloc for unwind_hints[%d]", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) insn = find_insn(file, reloc->sym->sec, reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) if (!insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) WARN("can't find insn for unwind_hints[%d]", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) cfa = &insn->cfi.cfa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) if (hint->type == UNWIND_HINT_TYPE_RET_OFFSET) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) insn->ret_offset = hint->sp_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) insn->hint = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) if (arch_decode_hint_reg(insn, hint->sp_reg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) WARN_FUNC("unsupported unwind_hint sp base reg %d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) insn->sec, insn->offset, hint->sp_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) cfa->offset = hint->sp_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) insn->cfi.type = hint->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) insn->cfi.end = hint->end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) static int read_retpoline_hints(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) struct section *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) struct reloc *reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) sec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) if (!sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) list_for_each_entry(reloc, &sec->reloc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) if (reloc->sym->type != STT_SECTION) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) WARN("unexpected relocation symbol type in %s", sec->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) insn = find_insn(file, reloc->sym->sec, reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) if (!insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) WARN("bad .discard.retpoline_safe entry");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) if (insn->type != INSN_JUMP_DYNAMIC &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) insn->type != INSN_CALL_DYNAMIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) WARN_FUNC("retpoline_safe hint not an indirect jump/call",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) insn->retpoline_safe = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) static int read_instr_hints(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) struct section *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) struct reloc *reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) sec = find_section_by_name(file->elf, ".rela.discard.instr_end");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) if (!sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) list_for_each_entry(reloc, &sec->reloc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) if (reloc->sym->type != STT_SECTION) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) WARN("unexpected relocation symbol type in %s", sec->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) insn = find_insn(file, reloc->sym->sec, reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) if (!insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) WARN("bad .discard.instr_end entry");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) insn->instr--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) sec = find_section_by_name(file->elf, ".rela.discard.instr_begin");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) if (!sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) list_for_each_entry(reloc, &sec->reloc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) if (reloc->sym->type != STT_SECTION) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) WARN("unexpected relocation symbol type in %s", sec->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) insn = find_insn(file, reloc->sym->sec, reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) if (!insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) WARN("bad .discard.instr_begin entry");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) insn->instr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) static int read_intra_function_calls(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) struct section *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) struct reloc *reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) sec = find_section_by_name(file->elf, ".rela.discard.intra_function_calls");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) if (!sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) list_for_each_entry(reloc, &sec->reloc_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701) unsigned long dest_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) if (reloc->sym->type != STT_SECTION) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) WARN("unexpected relocation symbol type in %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) sec->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709) insn = find_insn(file, reloc->sym->sec, reloc->addend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710) if (!insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711) WARN("bad .discard.intra_function_call entry");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) if (insn->type != INSN_CALL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) WARN_FUNC("intra_function_call not a direct call",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) * Treat intra-function CALLs as JMPs, but with a stack_op.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) * See add_call_destinations(), which strips stack_ops from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724) * normal CALLs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) insn->type = INSN_JUMP_UNCONDITIONAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) dest_off = insn->offset + insn->len + insn->immediate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) insn->jump_dest = find_insn(file, insn->sec, dest_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) if (!insn->jump_dest) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731) WARN_FUNC("can't find call dest at %s+0x%lx",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732) insn->sec, insn->offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) insn->sec->name, dest_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) static int read_static_call_tramps(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) struct section *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744) struct symbol *func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) for_each_sec(file, sec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) list_for_each_entry(func, &sec->symbol_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748) if (func->bind == STB_GLOBAL &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749) !strncmp(func->name, STATIC_CALL_TRAMP_PREFIX_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) strlen(STATIC_CALL_TRAMP_PREFIX_STR)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) func->static_call_tramp = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) static void mark_rodata(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760) struct section *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) bool found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) * Search for the following rodata sections, each of which can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) * potentially contain jump tables:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) * - .rodata: can contain GCC switch tables
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) * - .rodata.<func>: same, if -fdata-sections is being used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) * - .rodata..c_jump_table: contains C annotated jump tables
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) * .rodata.str1.* sections are ignored; they don't contain jump tables.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) for_each_sec(file, sec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774) if (!strncmp(sec->name, ".rodata", 7) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) !strstr(sec->name, ".str1.")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) sec->rodata = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777) found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) file->rodata = found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784) static int decode_sections(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788) mark_rodata(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790) ret = decode_instructions(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794) ret = add_dead_ends(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798) add_ignores(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) add_uaccess_safe(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800) add_cfi_jumptables(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) ret = add_ignore_alternatives(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807) * Must be before add_{jump_call}_destination.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) ret = read_static_call_tramps(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813) ret = add_jump_destinations(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817) ret = add_special_section_alts(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) * Must be before add_call_destination(); it changes INSN_CALL to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823) * INSN_JUMP.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825) ret = read_intra_function_calls(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829) ret = add_call_destinations(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) ret = add_jump_table_alts(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) ret = read_unwind_hints(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841) ret = read_retpoline_hints(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845) ret = read_instr_hints(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852) static bool is_fentry_call(struct instruction *insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854) if (insn->type == INSN_CALL && insn->call_dest &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855) insn->call_dest->type == STT_NOTYPE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856) !strcmp(insn->call_dest->name, "__fentry__"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862) static bool has_modified_stack_frame(struct instruction *insn, struct insn_state *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864) u8 ret_offset = insn->ret_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) struct cfi_state *cfi = &state->cfi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868) if (cfi->cfa.base != initial_func_cfi.cfa.base || cfi->drap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871) if (cfi->cfa.offset != initial_func_cfi.cfa.offset + ret_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874) if (cfi->stack_size != initial_func_cfi.cfa.offset + ret_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878) * If there is a ret offset hint then don't check registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879) * because a callee-saved register might have been pushed on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880) * the stack.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882) if (ret_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885) for (i = 0; i < CFI_NUM_REGS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) if (cfi->regs[i].base != initial_func_cfi.regs[i].base ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887) cfi->regs[i].offset != initial_func_cfi.regs[i].offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894) static bool has_valid_stack_frame(struct insn_state *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) struct cfi_state *cfi = &state->cfi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1898) if (cfi->cfa.base == CFI_BP && cfi->regs[CFI_BP].base == CFI_CFA &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1899) cfi->regs[CFI_BP].offset == -16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1900) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1902) if (cfi->drap && cfi->regs[CFI_BP].base == CFI_BP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1903) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1905) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1906) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1908) static int update_cfi_state_regs(struct instruction *insn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1909) struct cfi_state *cfi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1910) struct stack_op *op)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1911) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1912) struct cfi_reg *cfa = &cfi->cfa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1913)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1914) if (cfa->base != CFI_SP && cfa->base != CFI_SP_INDIRECT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1915) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1916)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1917) /* push */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1918) if (op->dest.type == OP_DEST_PUSH || op->dest.type == OP_DEST_PUSHF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1919) cfa->offset += 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1920)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1921) /* pop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1922) if (op->src.type == OP_SRC_POP || op->src.type == OP_SRC_POPF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1923) cfa->offset -= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1925) /* add immediate to sp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1926) if (op->dest.type == OP_DEST_REG && op->src.type == OP_SRC_ADD &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1927) op->dest.reg == CFI_SP && op->src.reg == CFI_SP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1928) cfa->offset -= op->src.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1929)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1930) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1931) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1933) static void save_reg(struct cfi_state *cfi, unsigned char reg, int base, int offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1934) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1935) if (arch_callee_saved_reg(reg) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1936) cfi->regs[reg].base == CFI_UNDEFINED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1937) cfi->regs[reg].base = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1938) cfi->regs[reg].offset = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1939) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1940) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1942) static void restore_reg(struct cfi_state *cfi, unsigned char reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1943) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1944) cfi->regs[reg].base = initial_func_cfi.regs[reg].base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1945) cfi->regs[reg].offset = initial_func_cfi.regs[reg].offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1946) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1948) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1949) * A note about DRAP stack alignment:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1950) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1951) * GCC has the concept of a DRAP register, which is used to help keep track of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1952) * the stack pointer when aligning the stack. r10 or r13 is used as the DRAP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1953) * register. The typical DRAP pattern is:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1954) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1955) * 4c 8d 54 24 08 lea 0x8(%rsp),%r10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1956) * 48 83 e4 c0 and $0xffffffffffffffc0,%rsp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1957) * 41 ff 72 f8 pushq -0x8(%r10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1958) * 55 push %rbp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1959) * 48 89 e5 mov %rsp,%rbp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1960) * (more pushes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1961) * 41 52 push %r10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1962) * ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1963) * 41 5a pop %r10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1964) * (more pops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1965) * 5d pop %rbp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1966) * 49 8d 62 f8 lea -0x8(%r10),%rsp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1967) * c3 retq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1968) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1969) * There are some variations in the epilogues, like:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1970) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1971) * 5b pop %rbx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1972) * 41 5a pop %r10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1973) * 41 5c pop %r12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1974) * 41 5d pop %r13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1975) * 41 5e pop %r14
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1976) * c9 leaveq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1977) * 49 8d 62 f8 lea -0x8(%r10),%rsp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1978) * c3 retq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1979) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1980) * and:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1981) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1982) * 4c 8b 55 e8 mov -0x18(%rbp),%r10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1983) * 48 8b 5d e0 mov -0x20(%rbp),%rbx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1984) * 4c 8b 65 f0 mov -0x10(%rbp),%r12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1985) * 4c 8b 6d f8 mov -0x8(%rbp),%r13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1986) * c9 leaveq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1987) * 49 8d 62 f8 lea -0x8(%r10),%rsp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1988) * c3 retq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1989) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1990) * Sometimes r13 is used as the DRAP register, in which case it's saved and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1991) * restored beforehand:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1992) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1993) * 41 55 push %r13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1994) * 4c 8d 6c 24 10 lea 0x10(%rsp),%r13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1995) * 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1996) * ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1997) * 49 8d 65 f0 lea -0x10(%r13),%rsp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1998) * 41 5d pop %r13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1999) * c3 retq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2000) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2001) static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2002) struct stack_op *op)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2003) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2004) struct cfi_reg *cfa = &cfi->cfa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2005) struct cfi_reg *regs = cfi->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2007) /* stack operations don't make sense with an undefined CFA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2008) if (cfa->base == CFI_UNDEFINED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2009) if (insn->func) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2010) WARN_FUNC("undefined stack state", insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2011) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2012) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2013) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2014) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2015)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2016) if (cfi->type == UNWIND_HINT_TYPE_REGS ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2017) cfi->type == UNWIND_HINT_TYPE_REGS_PARTIAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2018) return update_cfi_state_regs(insn, cfi, op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2020) switch (op->dest.type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2021)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2022) case OP_DEST_REG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2023) switch (op->src.type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2025) case OP_SRC_REG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2026) if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2027) cfa->base == CFI_SP &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2028) regs[CFI_BP].base == CFI_CFA &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2029) regs[CFI_BP].offset == -cfa->offset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2030)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2031) /* mov %rsp, %rbp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2032) cfa->base = op->dest.reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2033) cfi->bp_scratch = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2034) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2035)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2036) else if (op->src.reg == CFI_SP &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2037) op->dest.reg == CFI_BP && cfi->drap) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2039) /* drap: mov %rsp, %rbp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2040) regs[CFI_BP].base = CFI_BP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2041) regs[CFI_BP].offset = -cfi->stack_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2042) cfi->bp_scratch = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2043) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2044)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2045) else if (op->src.reg == CFI_SP && cfa->base == CFI_SP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2046)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2047) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2048) * mov %rsp, %reg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2049) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2050) * This is needed for the rare case where GCC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2051) * does:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2052) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2053) * mov %rsp, %rax
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2054) * ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2055) * mov %rax, %rsp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2056) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2057) cfi->vals[op->dest.reg].base = CFI_CFA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2058) cfi->vals[op->dest.reg].offset = -cfi->stack_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2059) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2060)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2061) else if (op->src.reg == CFI_BP && op->dest.reg == CFI_SP &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2062) cfa->base == CFI_BP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2063)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2064) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2065) * mov %rbp, %rsp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2066) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2067) * Restore the original stack pointer (Clang).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2068) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2069) cfi->stack_size = -cfi->regs[CFI_BP].offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2070) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2071)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2072) else if (op->dest.reg == cfa->base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2073)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2074) /* mov %reg, %rsp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2075) if (cfa->base == CFI_SP &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2076) cfi->vals[op->src.reg].base == CFI_CFA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2077)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2078) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2079) * This is needed for the rare case
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2080) * where GCC does something dumb like:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2081) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2082) * lea 0x8(%rsp), %rcx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2083) * ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2084) * mov %rcx, %rsp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2085) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2086) cfa->offset = -cfi->vals[op->src.reg].offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2087) cfi->stack_size = cfa->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2089) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2090) cfa->base = CFI_UNDEFINED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2091) cfa->offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2092) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2093) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2094)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2095) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2097) case OP_SRC_ADD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2098) if (op->dest.reg == CFI_SP && op->src.reg == CFI_SP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2099)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2100) /* add imm, %rsp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2101) cfi->stack_size -= op->src.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2102) if (cfa->base == CFI_SP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2103) cfa->offset -= op->src.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2104) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2107) if (op->dest.reg == CFI_SP && op->src.reg == CFI_BP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2109) /* lea disp(%rbp), %rsp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2110) cfi->stack_size = -(op->src.offset + regs[CFI_BP].offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2111) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2114) if (op->src.reg == CFI_SP && cfa->base == CFI_SP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2116) /* drap: lea disp(%rsp), %drap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2117) cfi->drap_reg = op->dest.reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2119) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2120) * lea disp(%rsp), %reg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2121) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2122) * This is needed for the rare case where GCC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2123) * does something dumb like:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2124) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2125) * lea 0x8(%rsp), %rcx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2126) * ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2127) * mov %rcx, %rsp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2128) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2129) cfi->vals[op->dest.reg].base = CFI_CFA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2130) cfi->vals[op->dest.reg].offset = \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2131) -cfi->stack_size + op->src.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2133) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2136) if (cfi->drap && op->dest.reg == CFI_SP &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2137) op->src.reg == cfi->drap_reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2139) /* drap: lea disp(%drap), %rsp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2140) cfa->base = CFI_SP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2141) cfa->offset = cfi->stack_size = -op->src.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2142) cfi->drap_reg = CFI_UNDEFINED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2143) cfi->drap = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2144) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2147) if (op->dest.reg == cfi->cfa.base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2148) WARN_FUNC("unsupported stack register modification",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2149) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2150) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2153) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2155) case OP_SRC_AND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2156) if (op->dest.reg != CFI_SP ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2157) (cfi->drap_reg != CFI_UNDEFINED && cfa->base != CFI_SP) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2158) (cfi->drap_reg == CFI_UNDEFINED && cfa->base != CFI_BP)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2159) WARN_FUNC("unsupported stack pointer realignment",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2160) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2161) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2164) if (cfi->drap_reg != CFI_UNDEFINED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2165) /* drap: and imm, %rsp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2166) cfa->base = cfi->drap_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2167) cfa->offset = cfi->stack_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2168) cfi->drap = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2171) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2172) * Older versions of GCC (4.8ish) realign the stack
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2173) * without DRAP, with a frame pointer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2174) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2176) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2178) case OP_SRC_POP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2179) case OP_SRC_POPF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2180) if (!cfi->drap && op->dest.reg == cfa->base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2182) /* pop %rbp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2183) cfa->base = CFI_SP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2186) if (cfi->drap && cfa->base == CFI_BP_INDIRECT &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2187) op->dest.reg == cfi->drap_reg &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2188) cfi->drap_offset == -cfi->stack_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2190) /* drap: pop %drap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2191) cfa->base = cfi->drap_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2192) cfa->offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2193) cfi->drap_offset = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2195) } else if (regs[op->dest.reg].offset == -cfi->stack_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2197) /* pop %reg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2198) restore_reg(cfi, op->dest.reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2201) cfi->stack_size -= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2202) if (cfa->base == CFI_SP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2203) cfa->offset -= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2205) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2207) case OP_SRC_REG_INDIRECT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2208) if (cfi->drap && op->src.reg == CFI_BP &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2209) op->src.offset == cfi->drap_offset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2211) /* drap: mov disp(%rbp), %drap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2212) cfa->base = cfi->drap_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2213) cfa->offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2214) cfi->drap_offset = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2217) if (cfi->drap && op->src.reg == CFI_BP &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2218) op->src.offset == regs[op->dest.reg].offset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2220) /* drap: mov disp(%rbp), %reg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2221) restore_reg(cfi, op->dest.reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2223) } else if (op->src.reg == cfa->base &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2224) op->src.offset == regs[op->dest.reg].offset + cfa->offset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2226) /* mov disp(%rbp), %reg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2227) /* mov disp(%rsp), %reg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2228) restore_reg(cfi, op->dest.reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2231) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2233) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2234) WARN_FUNC("unknown stack-related instruction",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2235) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2236) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2239) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2241) case OP_DEST_PUSH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2242) case OP_DEST_PUSHF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2243) cfi->stack_size += 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2244) if (cfa->base == CFI_SP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2245) cfa->offset += 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2247) if (op->src.type != OP_SRC_REG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2248) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2250) if (cfi->drap) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2251) if (op->src.reg == cfa->base && op->src.reg == cfi->drap_reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2253) /* drap: push %drap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2254) cfa->base = CFI_BP_INDIRECT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2255) cfa->offset = -cfi->stack_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2257) /* save drap so we know when to restore it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2258) cfi->drap_offset = -cfi->stack_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2260) } else if (op->src.reg == CFI_BP && cfa->base == cfi->drap_reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2262) /* drap: push %rbp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2263) cfi->stack_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2265) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2267) /* drap: push %reg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2268) save_reg(cfi, op->src.reg, CFI_BP, -cfi->stack_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2271) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2273) /* push %reg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2274) save_reg(cfi, op->src.reg, CFI_CFA, -cfi->stack_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2277) /* detect when asm code uses rbp as a scratch register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2278) if (!no_fp && insn->func && op->src.reg == CFI_BP &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2279) cfa->base != CFI_BP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2280) cfi->bp_scratch = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2281) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2283) case OP_DEST_REG_INDIRECT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2285) if (cfi->drap) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2286) if (op->src.reg == cfa->base && op->src.reg == cfi->drap_reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2288) /* drap: mov %drap, disp(%rbp) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2289) cfa->base = CFI_BP_INDIRECT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2290) cfa->offset = op->dest.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2292) /* save drap offset so we know when to restore it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2293) cfi->drap_offset = op->dest.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2294) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2296) /* drap: mov reg, disp(%rbp) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2297) save_reg(cfi, op->src.reg, CFI_BP, op->dest.offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2300) } else if (op->dest.reg == cfa->base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2302) /* mov reg, disp(%rbp) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2303) /* mov reg, disp(%rsp) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2304) save_reg(cfi, op->src.reg, CFI_CFA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2305) op->dest.offset - cfi->cfa.offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2308) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2310) case OP_DEST_LEAVE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2311) if ((!cfi->drap && cfa->base != CFI_BP) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2312) (cfi->drap && cfa->base != cfi->drap_reg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2313) WARN_FUNC("leave instruction with modified stack frame",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2314) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2315) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2318) /* leave (mov %rbp, %rsp; pop %rbp) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2320) cfi->stack_size = -cfi->regs[CFI_BP].offset - 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2321) restore_reg(cfi, CFI_BP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2323) if (!cfi->drap) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2324) cfa->base = CFI_SP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2325) cfa->offset -= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2328) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2330) case OP_DEST_MEM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2331) if (op->src.type != OP_SRC_POP && op->src.type != OP_SRC_POPF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2332) WARN_FUNC("unknown stack-related memory operation",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2333) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2334) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2337) /* pop mem */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2338) cfi->stack_size -= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2339) if (cfa->base == CFI_SP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2340) cfa->offset -= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2342) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2344) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2345) WARN_FUNC("unknown stack-related instruction",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2346) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2347) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2350) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2353) static int handle_insn_ops(struct instruction *insn, struct insn_state *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2354) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2355) struct stack_op *op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2357) list_for_each_entry(op, &insn->stack_ops, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2358) struct cfi_state old_cfi = state->cfi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2359) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2361) res = update_cfi_state(insn, &state->cfi, op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2362) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2363) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2365) if (insn->alt_group && memcmp(&state->cfi, &old_cfi, sizeof(struct cfi_state))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2366) WARN_FUNC("alternative modifies stack", insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2367) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2370) if (op->dest.type == OP_DEST_PUSHF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2371) if (!state->uaccess_stack) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2372) state->uaccess_stack = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2373) } else if (state->uaccess_stack >> 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2374) WARN_FUNC("PUSHF stack exhausted",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2375) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2376) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2378) state->uaccess_stack <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2379) state->uaccess_stack |= state->uaccess;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2380) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2382) if (op->src.type == OP_SRC_POPF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2383) if (state->uaccess_stack) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2384) state->uaccess = state->uaccess_stack & 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2385) state->uaccess_stack >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2386) if (state->uaccess_stack == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2387) state->uaccess_stack = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2388) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2392) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2395) static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2396) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2397) struct cfi_state *cfi1 = &insn->cfi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2398) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2400) if (memcmp(&cfi1->cfa, &cfi2->cfa, sizeof(cfi1->cfa))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2402) WARN_FUNC("stack state mismatch: cfa1=%d%+d cfa2=%d%+d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2403) insn->sec, insn->offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2404) cfi1->cfa.base, cfi1->cfa.offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2405) cfi2->cfa.base, cfi2->cfa.offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2407) } else if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2408) for (i = 0; i < CFI_NUM_REGS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2409) if (!memcmp(&cfi1->regs[i], &cfi2->regs[i],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2410) sizeof(struct cfi_reg)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2411) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2413) WARN_FUNC("stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2414) insn->sec, insn->offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2415) i, cfi1->regs[i].base, cfi1->regs[i].offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2416) i, cfi2->regs[i].base, cfi2->regs[i].offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2417) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2418) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2420) } else if (cfi1->type != cfi2->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2422) WARN_FUNC("stack state mismatch: type1=%d type2=%d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2423) insn->sec, insn->offset, cfi1->type, cfi2->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2425) } else if (cfi1->drap != cfi2->drap ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2426) (cfi1->drap && cfi1->drap_reg != cfi2->drap_reg) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2427) (cfi1->drap && cfi1->drap_offset != cfi2->drap_offset)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2429) WARN_FUNC("stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2430) insn->sec, insn->offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2431) cfi1->drap, cfi1->drap_reg, cfi1->drap_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2432) cfi2->drap, cfi2->drap_reg, cfi2->drap_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2434) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2435) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2437) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2438) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2440) static inline bool func_uaccess_safe(struct symbol *func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2441) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2442) if (func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2443) return func->uaccess_safe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2445) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2448) static inline const char *call_dest_name(struct instruction *insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2449) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2450) if (insn->call_dest)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2451) return insn->call_dest->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2453) return "{dynamic}";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2454) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2456) static inline bool noinstr_call_dest(struct symbol *func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2457) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2458) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2459) * We can't deal with indirect function calls at present;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2460) * assume they're instrumented.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2461) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2462) if (!func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2463) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2465) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2466) * If the symbol is from a noinstr section; we good.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2467) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2468) if (func->sec->noinstr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2469) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2471) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2472) * The __ubsan_handle_*() calls are like WARN(), they only happen when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2473) * something 'BAD' happened. At the risk of taking the machine down,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2474) * let them proceed to get the message out.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2475) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2476) if (!strncmp(func->name, "__ubsan_handle_", 15))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2477) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2479) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2480) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2482) static int validate_call(struct instruction *insn, struct insn_state *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2483) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2484) if (state->noinstr && state->instr <= 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2485) !noinstr_call_dest(insn->call_dest)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2486) WARN_FUNC("call to %s() leaves .noinstr.text section",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2487) insn->sec, insn->offset, call_dest_name(insn));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2488) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2489) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2491) if (state->uaccess && !func_uaccess_safe(insn->call_dest)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2492) WARN_FUNC("call to %s() with UACCESS enabled",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2493) insn->sec, insn->offset, call_dest_name(insn));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2494) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2495) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2497) if (state->df) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2498) WARN_FUNC("call to %s() with DF set",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2499) insn->sec, insn->offset, call_dest_name(insn));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2500) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2501) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2503) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2506) static int validate_sibling_call(struct instruction *insn, struct insn_state *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2507) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2508) if (has_modified_stack_frame(insn, state)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2509) WARN_FUNC("sibling call from callable instruction with modified stack frame",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2510) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2511) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2512) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2514) return validate_call(insn, state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2517) static int validate_return(struct symbol *func, struct instruction *insn, struct insn_state *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2518) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2519) if (state->noinstr && state->instr > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2520) WARN_FUNC("return with instrumentation enabled",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2521) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2522) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2525) if (state->uaccess && !func_uaccess_safe(func)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2526) WARN_FUNC("return with UACCESS enabled",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2527) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2528) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2529) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2531) if (!state->uaccess && func_uaccess_safe(func)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2532) WARN_FUNC("return with UACCESS disabled from a UACCESS-safe function",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2533) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2534) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2535) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2537) if (state->df) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2538) WARN_FUNC("return with DF set",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2539) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2540) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2541) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2543) if (func && has_modified_stack_frame(insn, state)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2544) WARN_FUNC("return with modified stack frame",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2545) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2546) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2547) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2549) if (state->cfi.bp_scratch) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2550) WARN_FUNC("BP used as a scratch register",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2551) insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2552) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2553) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2555) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2556) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2558) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2559) * Alternatives should not contain any ORC entries, this in turn means they
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2560) * should not contain any CFI ops, which implies all instructions should have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2561) * the same same CFI state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2562) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2563) * It is possible to constuct alternatives that have unreachable holes that go
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2564) * unreported (because they're NOPs), such holes would result in CFI_UNDEFINED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2565) * states which then results in ORC entries, which we just said we didn't want.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2566) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2567) * Avoid them by copying the CFI entry of the first instruction into the whole
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2568) * alternative.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2569) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2570) static void fill_alternative_cfi(struct objtool_file *file, struct instruction *insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2571) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2572) struct instruction *first_insn = insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2573) int alt_group = insn->alt_group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2575) sec_for_each_insn_continue(file, insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2576) if (insn->alt_group != alt_group)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2577) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2578) insn->cfi = first_insn->cfi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2582) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2583) * Follow the branch starting at the given instruction, and recursively follow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2584) * any other branches (jumps). Meanwhile, track the frame pointer state at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2585) * each instruction and validate all the rules described in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2586) * tools/objtool/Documentation/stack-validation.txt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2587) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2588) static int validate_branch(struct objtool_file *file, struct symbol *func,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2589) struct instruction *insn, struct insn_state state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2590) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2591) struct alternative *alt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2592) struct instruction *next_insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2593) struct section *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2594) u8 visited;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2595) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2597) sec = insn->sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2599) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2600) next_insn = next_insn_same_sec(file, insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2602) if (file->c_file && func && insn->func && func != insn->func->pfunc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2603) WARN("%s() falls through to next function %s()",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2604) func->name, insn->func->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2605) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2608) if (func && insn->ignore) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2609) WARN_FUNC("BUG: why am I validating an ignored function?",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2610) sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2611) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2612) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2614) visited = 1 << state.uaccess;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2615) if (insn->visited) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2616) if (!insn->hint && !insn_cfi_match(insn, &state.cfi))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2617) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2619) if (insn->visited & visited)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2620) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2621) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2623) if (state.noinstr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2624) state.instr += insn->instr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2626) if (insn->hint)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2627) state.cfi = insn->cfi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2628) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2629) insn->cfi = state.cfi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2631) insn->visited |= visited;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2633) if (!insn->ignore_alts && !list_empty(&insn->alts)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2634) bool skip_orig = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2636) list_for_each_entry(alt, &insn->alts, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2637) if (alt->skip_orig)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2638) skip_orig = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2640) ret = validate_branch(file, func, alt->insn, state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2641) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2642) if (backtrace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2643) BT_FUNC("(alt)", insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2644) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2645) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2646) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2648) if (insn->alt_group)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2649) fill_alternative_cfi(file, insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2651) if (skip_orig)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2652) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2653) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2655) if (handle_insn_ops(insn, &state))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2656) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2658) switch (insn->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2660) case INSN_RETURN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2661) return validate_return(func, insn, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2663) case INSN_CALL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2664) case INSN_CALL_DYNAMIC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2665) ret = validate_call(insn, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2666) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2667) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2669) if (!no_fp && func && !is_fentry_call(insn) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2670) !has_valid_stack_frame(&state)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2671) WARN_FUNC("call without frame pointer save/setup",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2672) sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2673) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2674) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2676) if (dead_end_function(file, insn->call_dest))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2677) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2679) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2681) case INSN_JUMP_CONDITIONAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2682) case INSN_JUMP_UNCONDITIONAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2683) if (func && is_sibling_call(insn)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2684) ret = validate_sibling_call(insn, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2685) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2686) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2688) } else if (insn->jump_dest) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2689) ret = validate_branch(file, func,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2690) insn->jump_dest, state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2691) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2692) if (backtrace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2693) BT_FUNC("(branch)", insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2694) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2695) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2696) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2697)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2698) if (insn->type == INSN_JUMP_UNCONDITIONAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2699) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2701) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2703) case INSN_JUMP_DYNAMIC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2704) case INSN_JUMP_DYNAMIC_CONDITIONAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2705) if (func && is_sibling_call(insn)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2706) ret = validate_sibling_call(insn, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2707) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2708) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2709) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2711) if (insn->type == INSN_JUMP_DYNAMIC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2712) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2714) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2716) case INSN_CONTEXT_SWITCH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2717) if (func && (!next_insn || !next_insn->hint)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2718) WARN_FUNC("unsupported instruction in callable function",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2719) sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2720) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2721) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2722) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2724) case INSN_STAC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2725) if (state.uaccess) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2726) WARN_FUNC("recursive UACCESS enable", sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2727) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2728) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2730) state.uaccess = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2731) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2733) case INSN_CLAC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2734) if (!state.uaccess && func) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2735) WARN_FUNC("redundant UACCESS disable", sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2736) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2737) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2739) if (func_uaccess_safe(func) && !state.uaccess_stack) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2740) WARN_FUNC("UACCESS-safe disables UACCESS", sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2741) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2742) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2744) state.uaccess = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2745) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2747) case INSN_STD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2748) if (state.df) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2749) WARN_FUNC("recursive STD", sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2750) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2751) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2752)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2753) state.df = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2754) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2756) case INSN_CLD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2757) if (!state.df && func) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2758) WARN_FUNC("redundant CLD", sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2759) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2760) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2762) state.df = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2763) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2765) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2766) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2767) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2769) if (insn->dead_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2770) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2771)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2772) if (!next_insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2773) if (state.cfi.cfa.base == CFI_UNDEFINED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2774) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2775) WARN("%s: unexpected end of section", sec->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2776) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2777) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2778)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2779) insn = next_insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2780) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2782) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2783) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2785) static int validate_unwind_hints(struct objtool_file *file, struct section *sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2786) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2787) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2788) struct insn_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2789) int ret, warnings = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2791) if (!file->hints)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2792) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2794) init_insn_state(&state, sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2796) if (sec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2797) insn = find_insn(file, sec, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2798) if (!insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2799) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2800) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2801) insn = list_first_entry(&file->insn_list, typeof(*insn), list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2802) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2804) while (&insn->list != &file->insn_list && (!sec || insn->sec == sec)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2805) if (insn->hint && !insn->visited) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2806) ret = validate_branch(file, insn->func, insn, state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2807) if (ret && backtrace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2808) BT_FUNC("<=== (hint)", insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2809) warnings += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2810) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2812) insn = list_next_entry(insn, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2813) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2814)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2815) return warnings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2816) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2818) static int validate_retpoline(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2819) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2820) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2821) int warnings = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2823) for_each_insn(file, insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2824) if (insn->type != INSN_JUMP_DYNAMIC &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2825) insn->type != INSN_CALL_DYNAMIC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2826) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2827)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2828) if (insn->retpoline_safe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2829) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2831) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2832) * .init.text code is ran before userspace and thus doesn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2833) * strictly need retpolines, except for modules which are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2834) * loaded late, they very much do need retpoline in their
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2835) * .init.text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2836) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2837) if (!strcmp(insn->sec->name, ".init.text") && !module)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2838) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2840) WARN_FUNC("indirect %s found in RETPOLINE build",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2841) insn->sec, insn->offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2842) insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2844) warnings++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2845) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2847) return warnings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2848) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2850) static bool is_kasan_insn(struct instruction *insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2851) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2852) return (insn->type == INSN_CALL &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2853) !strcmp(insn->call_dest->name, "__asan_handle_no_return"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2854) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2855)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2856) static bool is_ubsan_insn(struct instruction *insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2857) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2858) return (insn->type == INSN_CALL &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2859) !strcmp(insn->call_dest->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2860) "__ubsan_handle_builtin_unreachable"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2861) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2862)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2863) static bool ignore_unreachable_insn(struct objtool_file *file, struct instruction *insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2864) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2865) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2866) struct instruction *prev_insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2867)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2868) if (insn->ignore || insn->type == INSN_NOP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2869) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2871) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2872) * Ignore any unused exceptions. This can happen when a whitelisted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2873) * function has an exception table entry.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2874) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2875) * Also ignore alternative replacement instructions. This can happen
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2876) * when a whitelisted function uses one of the ALTERNATIVE macros.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2877) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2878) if (!strcmp(insn->sec->name, ".fixup") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2879) !strcmp(insn->sec->name, ".altinstr_replacement") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2880) !strcmp(insn->sec->name, ".altinstr_aux"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2881) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2882)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2883) if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->offset == FAKE_JUMP_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2884) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2885)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2886) if (!insn->func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2887) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2889) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2890) * CONFIG_UBSAN_TRAP inserts a UD2 when it sees
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2891) * __builtin_unreachable(). The BUG() macro has an unreachable() after
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2892) * the UD2, which causes GCC's undefined trap logic to emit another UD2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2893) * (or occasionally a JMP to UD2).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2894) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2895) * It may also insert a UD2 after calling a __noreturn function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2896) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2897) prev_insn = list_prev_entry(insn, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2898) if ((prev_insn->dead_end || dead_end_function(file, prev_insn->call_dest)) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2899) (insn->type == INSN_BUG ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2900) (insn->type == INSN_JUMP_UNCONDITIONAL &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2901) insn->jump_dest && insn->jump_dest->type == INSN_BUG)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2902) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2904) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2905) * Check if this (or a subsequent) instruction is related to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2906) * CONFIG_UBSAN or CONFIG_KASAN.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2907) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2908) * End the search at 5 instructions to avoid going into the weeds.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2909) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2910) for (i = 0; i < 5; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2912) if (is_kasan_insn(insn) || is_ubsan_insn(insn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2913) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2914)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2915) if (insn->type == INSN_JUMP_UNCONDITIONAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2916) if (insn->jump_dest &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2917) insn->jump_dest->func == insn->func) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2918) insn = insn->jump_dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2919) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2920) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2921)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2922) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2923) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2925) if (insn->offset + insn->len >= insn->func->offset + insn->func->len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2926) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2928) insn = list_next_entry(insn, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2929) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2931) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2932) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2934) static int validate_symbol(struct objtool_file *file, struct section *sec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2935) struct symbol *sym, struct insn_state *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2936) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2937) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2938) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2940) if (!sym->len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2941) WARN("%s() is missing an ELF size annotation", sym->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2942) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2943) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2944)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2945) if (sym->pfunc != sym || sym->alias != sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2946) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2948) insn = find_insn(file, sec, sym->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2949) if (!insn || insn->ignore || insn->visited)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2950) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2951)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2952) state->uaccess = sym->uaccess_safe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2954) ret = validate_branch(file, insn->func, insn, *state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2955) if (ret && backtrace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2956) BT_FUNC("<=== (sym)", insn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2957) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2958) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2960) static int validate_section(struct objtool_file *file, struct section *sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2961) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2962) struct insn_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2963) struct symbol *func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2964) int warnings = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2966) list_for_each_entry(func, &sec->symbol_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2967) if (func->type != STT_FUNC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2968) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2970) init_insn_state(&state, sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2971) state.cfi.cfa = initial_func_cfi.cfa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2972) memcpy(&state.cfi.regs, &initial_func_cfi.regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2973) CFI_NUM_REGS * sizeof(struct cfi_reg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2974) state.cfi.stack_size = initial_func_cfi.cfa.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2976) warnings += validate_symbol(file, sec, func, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2977) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2979) return warnings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2980) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2981)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2982) static int validate_vmlinux_functions(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2983) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2984) struct section *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2985) int warnings = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2987) sec = find_section_by_name(file->elf, ".noinstr.text");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2988) if (sec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2989) warnings += validate_section(file, sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2990) warnings += validate_unwind_hints(file, sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2991) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2992)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2993) sec = find_section_by_name(file->elf, ".entry.text");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2994) if (sec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2995) warnings += validate_section(file, sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2996) warnings += validate_unwind_hints(file, sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2997) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2998)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2999) return warnings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3000) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3002) static int validate_functions(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3003) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3004) struct section *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3005) int warnings = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3007) for_each_sec(file, sec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3008) if (!(sec->sh.sh_flags & SHF_EXECINSTR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3009) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3011) warnings += validate_section(file, sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3012) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3013)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3014) return warnings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3015) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3016)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3017) static int validate_reachable_instructions(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3018) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3019) struct instruction *insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3020)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3021) if (file->ignore_unreachables)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3022) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3023)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3024) for_each_insn(file, insn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3025) if (insn->visited || ignore_unreachable_insn(file, insn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3026) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3027)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3028) WARN_FUNC("unreachable instruction", insn->sec, insn->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3029) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3030) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3032) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3033) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3034)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3035) int check(struct objtool_file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3036) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3037) int ret, warnings = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3039) arch_initial_func_cfi_state(&initial_func_cfi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3040)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3041) ret = decode_sections(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3042) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3043) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3044) warnings += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3045)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3046) if (list_empty(&file->insn_list))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3047) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3049) if (vmlinux && !validate_dup) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3050) ret = validate_vmlinux_functions(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3051) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3052) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3053)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3054) warnings += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3055) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3056) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3058) if (retpoline) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3059) ret = validate_retpoline(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3060) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3061) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3062) warnings += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3063) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3064)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3065) ret = validate_functions(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3066) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3067) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3068) warnings += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3069)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3070) ret = validate_unwind_hints(file, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3071) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3072) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3073) warnings += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3074)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3075) if (!warnings) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3076) ret = validate_reachable_instructions(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3077) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3078) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3079) warnings += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3080) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3081)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3082) ret = create_static_call_sections(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3083) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3084) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3085) warnings += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3086)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3087) if (mcount) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3088) ret = create_mcount_loc_sections(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3089) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3090) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3091) warnings += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3092) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3093)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3094) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3095) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3096) * For now, don't fail the kernel build on fatal warnings. These
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3097) * errors are still fairly common due to the growing matrix of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3098) * supported toolchains and their recent pace of change.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3099) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3100) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3101) }