Lines Matching refs:insn

27 	struct instruction *insn;  member
40 struct instruction *insn; in find_insn() local
42 hash_for_each_possible(file->insn_hash, insn, hash, sec_offset_hash(sec, offset)) { in find_insn()
43 if (insn->sec == sec && insn->offset == offset) in find_insn()
44 return insn; in find_insn()
51 struct instruction *insn) in next_insn_same_sec() argument
53 if (insn->idx == INSN_CHUNK_MAX) in next_insn_same_sec()
54 return find_insn(file, insn->sec, insn->offset + insn->len); in next_insn_same_sec()
56 insn++; in next_insn_same_sec()
57 if (!insn->len) in next_insn_same_sec()
60 return insn; in next_insn_same_sec()
64 struct instruction *insn) in next_insn_same_func() argument
66 struct instruction *next = next_insn_same_sec(file, insn); in next_insn_same_func()
67 struct symbol *func = insn_func(insn); in next_insn_same_func()
84 struct instruction *insn) in prev_insn_same_sec() argument
86 if (insn->idx == 0) { in prev_insn_same_sec()
87 if (insn->prev_len) in prev_insn_same_sec()
88 return find_insn(file, insn->sec, insn->offset - insn->prev_len); in prev_insn_same_sec()
92 return insn - 1; in prev_insn_same_sec()
96 struct instruction *insn) in prev_insn_same_sym() argument
98 struct instruction *prev = prev_insn_same_sec(file, insn); in prev_insn_same_sym()
100 if (prev && insn_func(prev) == insn_func(insn)) in prev_insn_same_sym()
106 #define for_each_insn(file, insn) \ argument
110 sec_for_each_insn(file, __sec, insn)
112 #define func_for_each_insn(file, func, insn) \ argument
113 for (insn = find_insn(file, func->sec, func->offset); \
114 insn; \
115 insn = next_insn_same_func(file, insn))
117 #define sym_for_each_insn(file, sym, insn) \ argument
118 for (insn = find_insn(file, sym->sec, sym->offset); \
119 insn && insn->offset < sym->offset + sym->len; \
120 insn = next_insn_same_sec(file, insn))
122 #define sym_for_each_insn_continue_reverse(file, sym, insn) \ argument
123 for (insn = prev_insn_same_sec(file, insn); \
124 insn && insn->offset >= sym->offset; \
125 insn = prev_insn_same_sec(file, insn))
127 #define sec_for_each_insn_from(file, insn) \ argument
128 for (; insn; insn = next_insn_same_sec(file, insn))
130 #define sec_for_each_insn_continue(file, insn) \ argument
131 for (insn = next_insn_same_sec(file, insn); insn; \
132 insn = next_insn_same_sec(file, insn))
134 static inline struct symbol *insn_call_dest(struct instruction *insn) in insn_call_dest() argument
136 if (insn->type == INSN_JUMP_DYNAMIC || in insn_call_dest()
137 insn->type == INSN_CALL_DYNAMIC) in insn_call_dest()
140 return insn->_call_dest; in insn_call_dest()
143 static inline struct reloc *insn_jump_table(struct instruction *insn) in insn_jump_table() argument
145 if (insn->type == INSN_JUMP_DYNAMIC || in insn_jump_table()
146 insn->type == INSN_CALL_DYNAMIC) in insn_jump_table()
147 return insn->_jump_table; in insn_jump_table()
152 static inline unsigned long insn_jump_table_size(struct instruction *insn) in insn_jump_table_size() argument
154 if (insn->type == INSN_JUMP_DYNAMIC || in insn_jump_table_size()
155 insn->type == INSN_CALL_DYNAMIC) in insn_jump_table_size()
156 return insn->_jump_table_size; in insn_jump_table_size()
161 static bool is_jump_table_jump(struct instruction *insn) in is_jump_table_jump() argument
163 struct alt_group *alt_group = insn->alt_group; in is_jump_table_jump()
165 if (insn_jump_table(insn)) in is_jump_table_jump()
173 static bool is_sibling_call(struct instruction *insn) in is_sibling_call() argument
178 if (insn_func(insn)) { in is_sibling_call()
180 if (insn->type == INSN_JUMP_DYNAMIC) in is_sibling_call()
181 return !is_jump_table_jump(insn); in is_sibling_call()
185 return (is_static_jump(insn) && insn_call_dest(insn)); in is_sibling_call()
250 struct instruction *insn; in __dead_end_function() local
277 insn = find_insn(file, func->sec, func->offset); in __dead_end_function()
278 if (!insn || !insn_func(insn)) in __dead_end_function()
281 func_for_each_insn(file, func, insn) { in __dead_end_function()
284 if (insn->type == INSN_RETURN) in __dead_end_function()
296 func_for_each_insn(file, func, insn) { in __dead_end_function()
297 if (is_sibling_call(insn)) { in __dead_end_function()
298 struct instruction *dest = insn->jump_dest; in __dead_end_function()
430 struct instruction *insn; in decode_instructions() local
461 for (offset = 0; offset < sec->sh.sh_size; offset += insn->len) { in decode_instructions()
463 insns = calloc(sizeof(*insn), INSN_CHUNK_SIZE); in decode_instructions()
472 insn = &insns[idx]; in decode_instructions()
473 insn->idx = idx; in decode_instructions()
475 INIT_LIST_HEAD(&insn->call_node); in decode_instructions()
476 insn->sec = sec; in decode_instructions()
477 insn->offset = offset; in decode_instructions()
478 insn->prev_len = prev_len; in decode_instructions()
482 insn); in decode_instructions()
486 prev_len = insn->len; in decode_instructions()
493 if (insn->type == INSN_BUG) in decode_instructions()
494 insn->dead_end = true; in decode_instructions()
496 hash_add(file->insn_hash, &insn->hash, sec_offset_hash(sec, insn->offset)); in decode_instructions()
520 sym_for_each_insn(file, func, insn) { in decode_instructions()
521 insn->sym = func; in decode_instructions()
523 insn->type == INSN_ENDBR && in decode_instructions()
524 list_empty(&insn->call_node)) { in decode_instructions()
525 if (insn->offset == func->offset) { in decode_instructions()
526 list_add_tail(&insn->call_node, &file->endbr_list); in decode_instructions()
634 struct instruction *insn; in create_static_call_sections() local
650 list_for_each_entry(insn, &file->static_call_list, call_node) in create_static_call_sections()
662 list_for_each_entry(insn, &file->static_call_list, call_node) { in create_static_call_sections()
667 insn->sec, insn->offset)) in create_static_call_sections()
671 key_name = strdup(insn_call_dest(insn)->name); in create_static_call_sections()
700 key_sym = insn_call_dest(insn); in create_static_call_sections()
707 is_sibling_call(insn) * STATIC_CALL_SITE_TAIL)) in create_static_call_sections()
718 struct instruction *insn; in create_retpoline_sites_sections() local
729 list_for_each_entry(insn, &file->retpoline_call_list, call_node) in create_retpoline_sites_sections()
741 list_for_each_entry(insn, &file->retpoline_call_list, call_node) { in create_retpoline_sites_sections()
745 insn->sec, insn->offset)) in create_retpoline_sites_sections()
756 struct instruction *insn; in create_return_sites_sections() local
767 list_for_each_entry(insn, &file->return_thunk_list, call_node) in create_return_sites_sections()
779 list_for_each_entry(insn, &file->return_thunk_list, call_node) { in create_return_sites_sections()
783 insn->sec, insn->offset)) in create_return_sites_sections()
794 struct instruction *insn; in create_ibt_endbr_seal_sections() local
805 list_for_each_entry(insn, &file->endbr_list, call_node) in create_ibt_endbr_seal_sections()
823 list_for_each_entry(insn, &file->endbr_list, call_node) { in create_ibt_endbr_seal_sections()
826 struct symbol *sym = insn->sym; in create_ibt_endbr_seal_sections()
830 insn->offset == sym->offset && in create_ibt_endbr_seal_sections()
840 insn->sec, insn->offset)) in create_ibt_endbr_seal_sections()
900 struct instruction *insn; in create_mcount_loc_sections() local
915 list_for_each_entry(insn, &file->mcount_loc_list, call_node) in create_mcount_loc_sections()
926 list_for_each_entry(insn, &file->mcount_loc_list, call_node) { in create_mcount_loc_sections()
931 insn->sec, insn->offset); in create_mcount_loc_sections()
945 struct instruction *insn; in create_direct_call_sections() local
960 list_for_each_entry(insn, &file->call_list, call_node) in create_direct_call_sections()
969 list_for_each_entry(insn, &file->call_list, call_node) { in create_direct_call_sections()
973 insn->sec, insn->offset)) in create_direct_call_sections()
1255 static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn) in insn_reloc() argument
1259 if (insn->no_reloc) in insn_reloc()
1265 reloc = find_reloc_by_dest_range(file->elf, insn->sec, in insn_reloc()
1266 insn->offset, insn->len); in insn_reloc()
1268 insn->no_reloc = 1; in insn_reloc()
1275 static void remove_insn_ops(struct instruction *insn) in remove_insn_ops() argument
1279 for (op = insn->stack_ops; op; op = next) { in remove_insn_ops()
1283 insn->stack_ops = NULL; in remove_insn_ops()
1287 struct instruction *insn, bool sibling) in annotate_call_site() argument
1289 struct reloc *reloc = insn_reloc(file, insn); in annotate_call_site()
1290 struct symbol *sym = insn_call_dest(insn); in annotate_call_site()
1296 list_add_tail(&insn->call_node, &file->static_call_list); in annotate_call_site()
1301 list_add_tail(&insn->call_node, &file->retpoline_call_list); in annotate_call_site()
1310 if (opts.hack_noinstr && insn->sec->noinstr && sym->profiling_func) { in annotate_call_site()
1314 if (elf_write_insn(file->elf, insn->sec, in annotate_call_site()
1315 insn->offset, insn->len, in annotate_call_site()
1316 sibling ? arch_ret_insn(insn->len) in annotate_call_site()
1317 : arch_nop_insn(insn->len))) { in annotate_call_site()
1321 insn->type = sibling ? INSN_RETURN : INSN_NOP; in annotate_call_site()
1330 insn->retpoline_safe = true; in annotate_call_site()
1338 WARN_INSN(insn, "tail call to __fentry__ !?!?"); in annotate_call_site()
1343 if (elf_write_insn(file->elf, insn->sec, in annotate_call_site()
1344 insn->offset, insn->len, in annotate_call_site()
1345 arch_nop_insn(insn->len))) { in annotate_call_site()
1349 insn->type = INSN_NOP; in annotate_call_site()
1352 list_add_tail(&insn->call_node, &file->mcount_loc_list); in annotate_call_site()
1356 if (insn->type == INSN_CALL && !insn->sec->init && in annotate_call_site()
1357 !insn->_call_dest->embedded_insn) in annotate_call_site()
1358 list_add_tail(&insn->call_node, &file->call_list); in annotate_call_site()
1361 insn->dead_end = true; in annotate_call_site()
1366 static int add_call_dest(struct objtool_file *file, struct instruction *insn, in add_call_dest() argument
1369 insn->_call_dest = dest; in add_call_dest()
1380 remove_insn_ops(insn); in add_call_dest()
1382 return annotate_call_site(file, insn, sibling); in add_call_dest()
1385 static int add_retpoline_call(struct objtool_file *file, struct instruction *insn) in add_retpoline_call() argument
1391 switch (insn->type) { in add_retpoline_call()
1393 insn->type = INSN_CALL_DYNAMIC; in add_retpoline_call()
1396 insn->type = INSN_JUMP_DYNAMIC; in add_retpoline_call()
1399 insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL; in add_retpoline_call()
1405 insn->retpoline_safe = true; in add_retpoline_call()
1414 remove_insn_ops(insn); in add_retpoline_call()
1416 return annotate_call_site(file, insn, false); in add_retpoline_call()
1419 static void add_return_call(struct objtool_file *file, struct instruction *insn, bool add) in add_return_call() argument
1425 insn->type = INSN_RETURN; in add_return_call()
1426 insn->retpoline_safe = true; in add_return_call()
1429 list_add_tail(&insn->call_node, &file->return_thunk_list); in add_return_call()
1433 struct instruction *insn, struct symbol *sym) in is_first_func_insn() argument
1435 if (insn->offset == sym->offset) in is_first_func_insn()
1440 struct instruction *prev = prev_insn_same_sym(file, insn); in is_first_func_insn()
1443 insn->offset == sym->offset + prev->len) in is_first_func_insn()
1481 struct instruction *insn, *jump_dest; in add_jump_destinations() local
1487 for_each_insn(file, insn) { in add_jump_destinations()
1488 struct symbol *func = insn_func(insn); in add_jump_destinations()
1490 if (insn->jump_dest) { in add_jump_destinations()
1497 if (!is_static_jump(insn)) in add_jump_destinations()
1500 reloc = insn_reloc(file, insn); in add_jump_destinations()
1502 dest_sec = insn->sec; in add_jump_destinations()
1503 dest_off = arch_jump_destination(insn); in add_jump_destinations()
1508 ret = add_retpoline_call(file, insn); in add_jump_destinations()
1513 add_return_call(file, insn, true); in add_jump_destinations()
1520 ret = add_call_dest(file, insn, reloc->sym, true); in add_jump_destinations()
1546 add_return_call(file, insn, false); in add_jump_destinations()
1555 dest_sec == insn->sec && in add_jump_destinations()
1559 ERROR_INSN(insn, "can't find jump dest instruction at %s+0x%lx", in add_jump_destinations()
1571 ret = add_retpoline_call(file, insn); in add_jump_destinations()
1577 add_return_call(file, insn, true); in add_jump_destinations()
1609 if (jump_is_sibling_call(file, insn, jump_dest)) { in add_jump_destinations()
1614 ret = add_call_dest(file, insn, insn_func(jump_dest), true); in add_jump_destinations()
1620 insn->jump_dest = jump_dest; in add_jump_destinations()
1642 struct instruction *insn; in add_call_destinations() local
1648 for_each_insn(file, insn) { in add_call_destinations()
1649 struct symbol *func = insn_func(insn); in add_call_destinations()
1650 if (insn->type != INSN_CALL) in add_call_destinations()
1653 reloc = insn_reloc(file, insn); in add_call_destinations()
1655 dest_off = arch_jump_destination(insn); in add_call_destinations()
1656 dest = find_call_destination(insn->sec, dest_off); in add_call_destinations()
1658 ret = add_call_dest(file, insn, dest, false); in add_call_destinations()
1665 if (!insn_call_dest(insn)) { in add_call_destinations()
1666 ERROR_INSN(insn, "unannotated intra-function call"); in add_call_destinations()
1670 if (func && insn_call_dest(insn)->type != STT_FUNC) { in add_call_destinations()
1671 ERROR_INSN(insn, "unsupported call to non-function"); in add_call_destinations()
1679 ERROR_INSN(insn, "can't find call dest symbol at %s+0x%lx", in add_call_destinations()
1684 ret = add_call_dest(file, insn, dest, false); in add_call_destinations()
1689 ret = add_retpoline_call(file, insn); in add_call_destinations()
1694 ret = add_call_dest(file, insn, reloc->sym, false); in add_call_destinations()
1712 struct instruction *last_new_insn = NULL, *insn, *nop = NULL; in handle_group_alt() local
1732 insn = orig_insn; in handle_group_alt()
1733 sec_for_each_insn_from(file, insn) { in handle_group_alt()
1734 if (insn->offset >= special_alt->orig_off + special_alt->orig_len) in handle_group_alt()
1737 insn->alt_group = orig_alt_group; in handle_group_alt()
1738 last_orig_insn = insn; in handle_group_alt()
1791 insn = *new_insn; in handle_group_alt()
1792 sec_for_each_insn_from(file, insn) { in handle_group_alt()
1795 if (insn->offset >= special_alt->new_off + special_alt->new_len) in handle_group_alt()
1798 last_new_insn = insn; in handle_group_alt()
1800 insn->sym = orig_insn->sym; in handle_group_alt()
1801 insn->alt_group = new_alt_group; in handle_group_alt()
1811 alt_reloc = insn_reloc(file, insn); in handle_group_alt()
1813 !arch_support_alt_relocation(special_alt, insn, alt_reloc)) { in handle_group_alt()
1815 ERROR_INSN(insn, "unsupported relocation in alternatives section"); in handle_group_alt()
1819 if (!is_static_jump(insn)) in handle_group_alt()
1822 if (!insn->immediate) in handle_group_alt()
1825 dest_off = arch_jump_destination(insn); in handle_group_alt()
1827 insn->jump_dest = next_insn_same_sec(file, orig_alt_group->last_insn); in handle_group_alt()
1828 if (!insn->jump_dest) { in handle_group_alt()
1829 ERROR_INSN(insn, "can't find alternative jump destination"); in handle_group_alt()
1963 alt->insn = new_insn; in add_special_section_alts()
1985 static int add_jump_table(struct objtool_file *file, struct instruction *insn) in add_jump_table() argument
1987 unsigned long table_size = insn_jump_table_size(insn); in add_jump_table()
1988 struct symbol *pfunc = insn_func(insn)->pfunc; in add_jump_table()
1989 struct reloc *table = insn_jump_table(insn); in add_jump_table()
2040 alt->insn = dest_insn; in add_jump_table()
2041 alt->next = insn->alts; in add_jump_table()
2042 insn->alts = alt; in add_jump_table()
2048 ERROR_INSN(insn, "can't find switch jump table"); in add_jump_table()
2060 struct instruction *insn) in find_jump_table() argument
2063 struct instruction *dest_insn, *orig_insn = insn; in find_jump_table()
2073 insn && insn_func(insn) && insn_func(insn)->pfunc == func; in find_jump_table()
2074 insn = insn->first_jump_src ?: prev_insn_same_sym(file, insn)) { in find_jump_table()
2076 if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC) in find_jump_table()
2080 if (insn->type == INSN_JUMP_UNCONDITIONAL && in find_jump_table()
2081 insn->jump_dest && in find_jump_table()
2082 (insn->jump_dest->offset <= insn->offset || in find_jump_table()
2083 insn->jump_dest->offset > orig_insn->offset)) in find_jump_table()
2086 table_reloc = arch_find_switch_table(file, insn, &table_size); in find_jump_table()
2111 struct instruction *insn, *last = NULL; in mark_func_jump_tables() local
2113 func_for_each_insn(file, func, insn) { in mark_func_jump_tables()
2115 last = insn; in mark_func_jump_tables()
2122 if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest && in mark_func_jump_tables()
2123 insn->offset > last->offset && in mark_func_jump_tables()
2124 insn->jump_dest->offset > insn->offset && in mark_func_jump_tables()
2125 !insn->jump_dest->first_jump_src) { in mark_func_jump_tables()
2127 insn->jump_dest->first_jump_src = insn; in mark_func_jump_tables()
2128 last = insn->jump_dest; in mark_func_jump_tables()
2131 if (insn->type != INSN_JUMP_DYNAMIC) in mark_func_jump_tables()
2134 find_jump_table(file, func, insn); in mark_func_jump_tables()
2141 struct instruction *insn; in add_func_jump_tables() local
2144 func_for_each_insn(file, func, insn) { in add_func_jump_tables()
2145 if (!insn_jump_table(insn)) in add_func_jump_tables()
2148 ret = add_jump_table(file, insn); in add_func_jump_tables()
2196 struct instruction *insn; in read_unwind_hints() local
2235 insn = find_insn(file, reloc->sym->sec, offset); in read_unwind_hints()
2236 if (!insn) { in read_unwind_hints()
2241 insn->hint = true; in read_unwind_hints()
2244 insn->cfi = &force_undefined_cfi; in read_unwind_hints()
2249 insn->hint = false; in read_unwind_hints()
2250 insn->save = true; in read_unwind_hints()
2255 insn->restore = true; in read_unwind_hints()
2260 struct symbol *sym = find_symbol_by_offset(insn->sec, insn->offset); in read_unwind_hints()
2263 if (opts.ibt && insn->type != INSN_ENDBR && !insn->noendbr) { in read_unwind_hints()
2264 ERROR_INSN(insn, "UNWIND_HINT_IRET_REGS without ENDBR"); in read_unwind_hints()
2271 insn->cfi = &func_cfi; in read_unwind_hints()
2275 if (insn->cfi) in read_unwind_hints()
2276 cfi = *(insn->cfi); in read_unwind_hints()
2279 ERROR_INSN(insn, "unsupported unwind_hint sp base reg %d", hint->sp_reg); in read_unwind_hints()
2287 insn->cfi = cfi_hash_find_or_add(&cfi); in read_unwind_hints()
2294 int (*func)(struct objtool_file *file, int type, struct instruction *insn)) in read_annotate() argument
2297 struct instruction *insn; in read_annotate() local
2322 insn = find_insn(file, reloc->sym->sec, offset); in read_annotate()
2324 if (!insn) { in read_annotate()
2329 ret = func(file, type, insn); in read_annotate()
2337 static int __annotate_early(struct objtool_file *file, int type, struct instruction *insn) in __annotate_early() argument
2343 insn->ignore_alts = true; in __annotate_early()
2350 insn->noendbr = 1; in __annotate_early()
2360 static int __annotate_ifc(struct objtool_file *file, int type, struct instruction *insn) in __annotate_ifc() argument
2367 if (insn->type != INSN_CALL) { in __annotate_ifc()
2368 ERROR_INSN(insn, "intra_function_call not a direct call"); in __annotate_ifc()
2377 insn->type = INSN_JUMP_UNCONDITIONAL; in __annotate_ifc()
2379 dest_off = arch_jump_destination(insn); in __annotate_ifc()
2380 insn->jump_dest = find_insn(file, insn->sec, dest_off); in __annotate_ifc()
2381 if (!insn->jump_dest) { in __annotate_ifc()
2382 ERROR_INSN(insn, "can't find call dest at %s+0x%lx", in __annotate_ifc()
2383 insn->sec->name, dest_off); in __annotate_ifc()
2390 static int __annotate_late(struct objtool_file *file, int type, struct instruction *insn) in __annotate_late() argument
2398 if (insn->type != INSN_JUMP_DYNAMIC && in __annotate_late()
2399 insn->type != INSN_CALL_DYNAMIC && in __annotate_late()
2400 insn->type != INSN_RETURN && in __annotate_late()
2401 insn->type != INSN_NOP) { in __annotate_late()
2402 ERROR_INSN(insn, "retpoline_safe hint not an indirect jump/call/ret/nop"); in __annotate_late()
2406 insn->retpoline_safe = true; in __annotate_late()
2410 insn->instr++; in __annotate_late()
2414 insn->instr--; in __annotate_late()
2418 insn->unret = 1; in __annotate_late()
2430 insn->dead_end = false; in __annotate_late()
2434 ERROR_INSN(insn, "Unknown annotation type: %d", type); in __annotate_late()
2603 static bool is_special_call(struct instruction *insn) in is_special_call() argument
2605 if (insn->type == INSN_CALL) { in is_special_call()
2606 struct symbol *dest = insn_call_dest(insn); in is_special_call()
2618 static bool has_modified_stack_frame(struct instruction *insn, struct insn_state *state) in has_modified_stack_frame() argument
2663 static int update_cfi_state_regs(struct instruction *insn, in update_cfi_state_regs() argument
2756 static int update_cfi_state(struct instruction *insn, in update_cfi_state() argument
2769 if (insn_func(insn)) { in update_cfi_state()
2770 WARN_INSN(insn, "undefined stack state"); in update_cfi_state()
2778 return update_cfi_state_regs(insn, cfi, op); in update_cfi_state()
2913 insn->sym->frame_pointer) { in update_cfi_state()
2925 if (insn->sym->frame_pointer) { in update_cfi_state()
2970 WARN_INSN(insn, "unsupported stack register modification"); in update_cfi_state()
2980 WARN_INSN(insn, "unsupported stack pointer realignment"); in update_cfi_state()
3075 WARN_INSN(insn, "unknown stack-related instruction"); in update_cfi_state()
3118 if (opts.stackval && insn_func(insn) && op->src.reg == CFI_BP && in update_cfi_state()
3164 WARN_INSN(insn, "unknown stack-related memory operation"); in update_cfi_state()
3176 WARN_INSN(insn, "unknown stack-related instruction"); in update_cfi_state()
3192 static int propagate_alt_cfi(struct objtool_file *file, struct instruction *insn) in propagate_alt_cfi() argument
3197 if (!insn->alt_group) in propagate_alt_cfi()
3200 if (!insn->cfi) { in propagate_alt_cfi()
3205 alt_cfi = insn->alt_group->cfi; in propagate_alt_cfi()
3206 group_off = insn->offset - insn->alt_group->first_insn->offset; in propagate_alt_cfi()
3209 alt_cfi[group_off] = insn->cfi; in propagate_alt_cfi()
3211 if (cficmp(alt_cfi[group_off], insn->cfi)) { in propagate_alt_cfi()
3212 struct alt_group *orig_group = insn->alt_group->orig_group ?: insn->alt_group; in propagate_alt_cfi()
3215 offstr(insn->sec, insn->offset)); in propagate_alt_cfi()
3223 static int handle_insn_ops(struct instruction *insn, in handle_insn_ops() argument
3230 for (op = insn->stack_ops; op; op = op->next) { in handle_insn_ops()
3232 ret = update_cfi_state(insn, next_insn, &state->cfi, op); in handle_insn_ops()
3236 if (!opts.uaccess || !insn->alt_group) in handle_insn_ops()
3243 WARN_INSN(insn, "PUSHF stack exhausted"); in handle_insn_ops()
3263 static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2) in insn_cfi_match() argument
3265 struct cfi_state *cfi1 = insn->cfi; in insn_cfi_match()
3275 WARN_INSN(insn, "stack state mismatch: cfa1=%d%+d cfa2=%d%+d", in insn_cfi_match()
3288 WARN_INSN(insn, "stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d", in insn_cfi_match()
3297 WARN_INSN(insn, "stack state mismatch: type1=%d type2=%d", in insn_cfi_match()
3306 WARN_INSN(insn, "stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)", in insn_cfi_match()
3323 static inline const char *call_dest_name(struct instruction *insn) in call_dest_name() argument
3329 if (insn_call_dest(insn)) in call_dest_name()
3330 return insn_call_dest(insn)->name; in call_dest_name()
3332 reloc = insn_reloc(NULL, insn); in call_dest_name()
3342 static bool pv_call_dest(struct objtool_file *file, struct instruction *insn) in pv_call_dest() argument
3348 reloc = insn_reloc(file, insn); in pv_call_dest()
3370 struct instruction *insn, in noinstr_call_dest() argument
3379 return pv_call_dest(file, insn); in noinstr_call_dest()
3408 struct instruction *insn, in validate_call() argument
3412 !noinstr_call_dest(file, insn, insn_call_dest(insn))) { in validate_call()
3413 WARN_INSN(insn, "call to %s() leaves .noinstr.text section", call_dest_name(insn)); in validate_call()
3417 if (state->uaccess && !func_uaccess_safe(insn_call_dest(insn))) { in validate_call()
3418 WARN_INSN(insn, "call to %s() with UACCESS enabled", call_dest_name(insn)); in validate_call()
3423 WARN_INSN(insn, "call to %s() with DF set", call_dest_name(insn)); in validate_call()
3431 struct instruction *insn, in validate_sibling_call() argument
3434 if (insn_func(insn) && has_modified_stack_frame(insn, state)) { in validate_sibling_call()
3435 WARN_INSN(insn, "sibling call from callable instruction with modified stack frame"); in validate_sibling_call()
3439 return validate_call(file, insn, state); in validate_sibling_call()
3442 static int validate_return(struct symbol *func, struct instruction *insn, struct insn_state *state) in validate_return() argument
3445 WARN_INSN(insn, "return with instrumentation enabled"); in validate_return()
3450 WARN_INSN(insn, "return with UACCESS enabled"); in validate_return()
3455 WARN_INSN(insn, "return with UACCESS disabled from a UACCESS-safe function"); in validate_return()
3460 WARN_INSN(insn, "return with DF set"); in validate_return()
3464 if (func && has_modified_stack_frame(insn, state)) { in validate_return()
3465 WARN_INSN(insn, "return with modified stack frame"); in validate_return()
3470 WARN_INSN(insn, "BP used as a scratch register"); in validate_return()
3478 struct instruction *insn) in next_insn_to_validate() argument
3480 struct alt_group *alt_group = insn->alt_group; in next_insn_to_validate()
3495 if (insn == alt_group->last_insn) in next_insn_to_validate()
3497 if (insn == alt_group->nop) in next_insn_to_validate()
3500 if (insn == alt_group->last_insn && alt_group->orig_group) in next_insn_to_validate()
3504 return next_insn_same_sec(file, insn); in next_insn_to_validate()
3510 static bool skip_alt_group(struct instruction *insn) in skip_alt_group() argument
3512 struct instruction *alt_insn = insn->alts ? insn->alts->insn : NULL; in skip_alt_group()
3515 if (insn->alt_group && insn->alt_group->ignore) in skip_alt_group()
3545 struct instruction *insn, struct insn_state state) in validate_branch() argument
3556 sec = insn->sec; in validate_branch()
3559 next_insn = next_insn_to_validate(file, insn); in validate_branch()
3561 if (func && insn_func(insn) && func != insn_func(insn)->pfunc) { in validate_branch()
3571 func->name, insn_func(insn)->name); in validate_branch()
3578 if (insn->visited & VISITED_BRANCH_MASK) { in validate_branch()
3579 if (!insn->hint && !insn_cfi_match(insn, &state.cfi)) in validate_branch()
3582 if (insn->visited & visited) in validate_branch()
3589 state.instr += insn->instr; in validate_branch()
3591 if (insn->hint) { in validate_branch()
3592 if (insn->restore) { in validate_branch()
3595 i = insn; in validate_branch()
3606 WARN_INSN(insn, "no corresponding CFI save for CFI restore"); in validate_branch()
3623 WARN_INSN(insn, "objtool isn't smart enough to handle this CFI save/restore combo"); in validate_branch()
3627 insn->cfi = save_insn->cfi; in validate_branch()
3631 state.cfi = *insn->cfi; in validate_branch()
3636 insn->cfi = prev_insn->cfi; in validate_branch()
3639 insn->cfi = cfi_hash_find_or_add(&state.cfi); in validate_branch()
3643 insn->visited |= visited; in validate_branch()
3645 if (propagate_alt_cfi(file, insn)) in validate_branch()
3648 if (insn->alts) { in validate_branch()
3649 for (alt = insn->alts; alt; alt = alt->next) { in validate_branch()
3650 ret = validate_branch(file, func, alt->insn, state); in validate_branch()
3652 BT_INSN(insn, "(alt)"); in validate_branch()
3658 if (skip_alt_group(insn)) in validate_branch()
3661 if (handle_insn_ops(insn, next_insn, &state)) in validate_branch()
3664 switch (insn->type) { in validate_branch()
3667 return validate_return(func, insn, &state); in validate_branch()
3671 ret = validate_call(file, insn, &state); in validate_branch()
3675 if (opts.stackval && func && !is_special_call(insn) && in validate_branch()
3677 WARN_INSN(insn, "call without frame pointer save/setup"); in validate_branch()
3685 if (is_sibling_call(insn)) { in validate_branch()
3686 ret = validate_sibling_call(file, insn, &state); in validate_branch()
3690 } else if (insn->jump_dest) { in validate_branch()
3692 insn->jump_dest, state); in validate_branch()
3694 BT_INSN(insn, "(branch)"); in validate_branch()
3699 if (insn->type == INSN_JUMP_UNCONDITIONAL) in validate_branch()
3706 if (is_sibling_call(insn)) { in validate_branch()
3707 ret = validate_sibling_call(file, insn, &state); in validate_branch()
3712 if (insn->type == INSN_JUMP_DYNAMIC) in validate_branch()
3719 WARN_INSN(insn, "unsupported instruction in callable function"); in validate_branch()
3727 WARN_INSN(insn, "unsupported instruction in callable function"); in validate_branch()
3738 WARN_INSN(insn, "recursive UACCESS enable"); in validate_branch()
3750 WARN_INSN(insn, "redundant UACCESS disable"); in validate_branch()
3755 WARN_INSN(insn, "UACCESS-safe disables UACCESS"); in validate_branch()
3764 WARN_INSN(insn, "recursive STD"); in validate_branch()
3773 WARN_INSN(insn, "redundant CLD"); in validate_branch()
3784 if (insn->dead_end) in validate_branch()
3799 prev_insn = insn; in validate_branch()
3800 insn = next_insn; in validate_branch()
3807 struct instruction *insn, in validate_unwind_hint() argument
3810 if (insn->hint && !insn->visited) { in validate_unwind_hint()
3811 int ret = validate_branch(file, insn_func(insn), insn, *state); in validate_unwind_hint()
3813 BT_INSN(insn, "<=== (hint)"); in validate_unwind_hint()
3822 struct instruction *insn; in validate_unwind_hints() local
3832 sec_for_each_insn(file, sec, insn) in validate_unwind_hints()
3833 warnings += validate_unwind_hint(file, insn, &state); in validate_unwind_hints()
3835 for_each_insn(file, insn) in validate_unwind_hints()
3836 warnings += validate_unwind_hint(file, insn, &state); in validate_unwind_hints()
3848 static int validate_unret(struct objtool_file *file, struct instruction *insn) in validate_unret() argument
3854 next = next_insn_to_validate(file, insn); in validate_unret()
3856 if (insn->visited & VISITED_UNRET) in validate_unret()
3859 insn->visited |= VISITED_UNRET; in validate_unret()
3861 if (insn->alts) { in validate_unret()
3863 for (alt = insn->alts; alt; alt = alt->next) { in validate_unret()
3864 ret = validate_unret(file, alt->insn); in validate_unret()
3866 BT_INSN(insn, "(alt)"); in validate_unret()
3872 switch (insn->type) { in validate_unret()
3877 WARN_INSN(insn, "early indirect call"); in validate_unret()
3882 if (!is_sibling_call(insn)) { in validate_unret()
3883 if (!insn->jump_dest) { in validate_unret()
3884 WARN_INSN(insn, "unresolved jump target after linking?!?"); in validate_unret()
3887 ret = validate_unret(file, insn->jump_dest); in validate_unret()
3889 BT_INSN(insn, "(branch%s)", in validate_unret()
3890 insn->type == INSN_JUMP_CONDITIONAL ? "-cond" : ""); in validate_unret()
3894 if (insn->type == INSN_JUMP_UNCONDITIONAL) in validate_unret()
3902 dest = find_insn(file, insn_call_dest(insn)->sec, in validate_unret()
3903 insn_call_dest(insn)->offset); in validate_unret()
3906 insn_call_dest(insn)->name); in validate_unret()
3912 BT_INSN(insn, "(call)"); in validate_unret()
3922 WARN_INSN(insn, "RET before UNTRAIN"); in validate_unret()
3932 if (insn->retpoline_safe) in validate_unret()
3940 if (insn->dead_end) in validate_unret()
3944 WARN_INSN(insn, "teh end!"); in validate_unret()
3947 insn = next; in validate_unret()
3959 struct instruction *insn; in validate_unrets() local
3962 for_each_insn(file, insn) { in validate_unrets()
3963 if (!insn->unret) in validate_unrets()
3966 warnings += validate_unret(file, insn); in validate_unrets()
3974 struct instruction *insn; in validate_retpoline() local
3977 for_each_insn(file, insn) { in validate_retpoline()
3978 if (insn->type != INSN_JUMP_DYNAMIC && in validate_retpoline()
3979 insn->type != INSN_CALL_DYNAMIC && in validate_retpoline()
3980 insn->type != INSN_RETURN) in validate_retpoline()
3983 if (insn->retpoline_safe) in validate_retpoline()
3986 if (insn->sec->init) in validate_retpoline()
3989 if (insn->type == INSN_RETURN) { in validate_retpoline()
3991 WARN_INSN(insn, "'naked' return found in MITIGATION_RETHUNK build"); in validate_retpoline()
3997 WARN_INSN(insn, "indirect %s found in MITIGATION_RETPOLINE build", in validate_retpoline()
3998 insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); in validate_retpoline()
4005 static bool is_kasan_insn(struct instruction *insn) in is_kasan_insn() argument
4007 return (insn->type == INSN_CALL && in is_kasan_insn()
4008 !strcmp(insn_call_dest(insn)->name, "__asan_handle_no_return")); in is_kasan_insn()
4011 static bool is_ubsan_insn(struct instruction *insn) in is_ubsan_insn() argument
4013 return (insn->type == INSN_CALL && in is_ubsan_insn()
4014 !strcmp(insn_call_dest(insn)->name, in is_ubsan_insn()
4018 static bool ignore_unreachable_insn(struct objtool_file *file, struct instruction *insn) in ignore_unreachable_insn() argument
4020 struct symbol *func = insn_func(insn); in ignore_unreachable_insn()
4024 if (insn->type == INSN_NOP || insn->type == INSN_TRAP || (func && func->ignore)) in ignore_unreachable_insn()
4031 if (!strcmp(insn->sec->name, ".altinstr_replacement") || in ignore_unreachable_insn()
4032 !strcmp(insn->sec->name, ".altinstr_aux")) in ignore_unreachable_insn()
4044 int size = find_symbol_hole_containing(insn->sec, insn->offset); in ignore_unreachable_insn()
4045 unsigned long end = insn->offset + size; in ignore_unreachable_insn()
4053 sec_for_each_insn_continue(file, insn) { in ignore_unreachable_insn()
4058 if (insn->visited) in ignore_unreachable_insn()
4061 if (insn->offset >= end) in ignore_unreachable_insn()
4067 if (insn->jump_dest && insn_func(insn->jump_dest) && in ignore_unreachable_insn()
4068 strstr(insn_func(insn->jump_dest)->name, ".cold")) { in ignore_unreachable_insn()
4069 insn_func(insn->jump_dest)->ignore = true; in ignore_unreachable_insn()
4090 prev_insn = prev_insn_same_sec(file, insn); in ignore_unreachable_insn()
4092 (insn->type == INSN_BUG || in ignore_unreachable_insn()
4093 (insn->type == INSN_JUMP_UNCONDITIONAL && in ignore_unreachable_insn()
4094 insn->jump_dest && insn->jump_dest->type == INSN_BUG))) in ignore_unreachable_insn()
4105 if (is_kasan_insn(insn) || is_ubsan_insn(insn)) in ignore_unreachable_insn()
4108 if (insn->type == INSN_JUMP_UNCONDITIONAL) { in ignore_unreachable_insn()
4109 if (insn->jump_dest && in ignore_unreachable_insn()
4110 insn_func(insn->jump_dest) == func) { in ignore_unreachable_insn()
4111 insn = insn->jump_dest; in ignore_unreachable_insn()
4118 if (insn->offset + insn->len >= func->offset + func->len) in ignore_unreachable_insn()
4121 insn = next_insn_same_sec(file, insn); in ignore_unreachable_insn()
4129 struct instruction *insn, *prev; in add_prefix_symbol() local
4132 insn = find_insn(file, func->sec, func->offset); in add_prefix_symbol()
4133 if (!insn) in add_prefix_symbol()
4136 for (prev = prev_insn_same_sec(file, insn); in add_prefix_symbol()
4159 if (!insn->cfi) { in add_prefix_symbol()
4168 cfi = cfi_hash_find_or_add(insn->cfi); in add_prefix_symbol()
4169 for (; prev != insn; prev = next_insn_same_sec(file, prev)) in add_prefix_symbol()
4198 struct instruction *insn; in validate_symbol() local
4209 insn = find_insn(file, sec, sym->offset); in validate_symbol()
4210 if (!insn || insn->visited) in validate_symbol()
4216 ret = validate_branch(file, insn_func(insn), insn, *state); in validate_symbol()
4218 BT_INSN(insn, "<=== (sym)"); in validate_symbol()
4282 static void mark_endbr_used(struct instruction *insn) in mark_endbr_used() argument
4284 if (!list_empty(&insn->call_node)) in mark_endbr_used()
4285 list_del_init(&insn->call_node); in mark_endbr_used()
4288 static bool noendbr_range(struct objtool_file *file, struct instruction *insn) in noendbr_range() argument
4290 struct symbol *sym = find_symbol_containing(insn->sec, insn->offset-1); in noendbr_range()
4303 return insn->offset == sym->offset + sym->len; in noendbr_range()
4306 static int __validate_ibt_insn(struct objtool_file *file, struct instruction *insn, in __validate_ibt_insn() argument
4314 if (insn_func(dest) && insn_func(insn) && in __validate_ibt_insn()
4315 insn_func(dest)->pfunc == insn_func(insn)->pfunc) { in __validate_ibt_insn()
4347 WARN_INSN(insn, "relocation to !ENDBR: %s", offstr(dest->sec, dest->offset)); in __validate_ibt_insn()
4351 static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn) in validate_ibt_insn() argument
4362 switch (insn->type) { in validate_ibt_insn()
4375 if (!insn_reloc(file, insn)) { in validate_ibt_insn()
4378 off = arch_jump_destination(insn); in validate_ibt_insn()
4380 dest = find_insn(file, insn->sec, off); in validate_ibt_insn()
4382 WARN_INSN(insn, "corrupt function pointer reference"); in validate_ibt_insn()
4386 return __validate_ibt_insn(file, insn, dest); in validate_ibt_insn()
4394 for (reloc = insn_reloc(file, insn); in validate_ibt_insn()
4396 reloc = find_reloc_by_dest_range(file->elf, insn->sec, in validate_ibt_insn()
4398 (insn->offset + insn->len) - (reloc_offset(reloc) + 1))) { in validate_ibt_insn()
4411 warnings += __validate_ibt_insn(file, insn, dest); in validate_ibt_insn()
4450 struct instruction *insn; in validate_ibt() local
4453 for_each_insn(file, insn) in validate_ibt()
4454 warnings += validate_ibt_insn(file, insn); in validate_ibt()
4501 struct instruction *insn, *next_insn; in validate_sls() local
4504 for_each_insn(file, insn) { in validate_sls()
4505 next_insn = next_insn_same_sec(file, insn); in validate_sls()
4507 if (insn->retpoline_safe) in validate_sls()
4510 switch (insn->type) { in validate_sls()
4513 WARN_INSN(insn, "missing int3 after ret"); in validate_sls()
4520 WARN_INSN(insn, "missing int3 after indirect jump"); in validate_sls()
4534 struct instruction *insn, *prev_insn; in validate_reachable_instructions() local
4541 for_each_insn(file, insn) { in validate_reachable_instructions()
4542 if (insn->visited || ignore_unreachable_insn(file, insn)) in validate_reachable_instructions()
4545 prev_insn = prev_insn_same_sec(file, insn); in validate_reachable_instructions()
4549 WARN_INSN(insn, "%s() missing __noreturn in .c/.h or NORETURN() in noreturns.h", in validate_reachable_instructions()
4556 WARN_INSN(insn, "unreachable instruction"); in validate_reachable_instructions()
4656 struct instruction *insn; in free_insns() local
4659 for_each_insn(file, insn) { in free_insns()
4660 if (!insn->idx) { in free_insns()
4662 chunk->addr = insn; in free_insns()