Lines Matching refs:insn
25 struct instruction *insn; member
38 struct instruction *insn; in find_insn() local
40 hash_for_each_possible(file->insn_hash, insn, hash, sec_offset_hash(sec, offset)) { in find_insn()
41 if (insn->sec == sec && insn->offset == offset) in find_insn()
42 return insn; in find_insn()
49 struct instruction *insn) in next_insn_same_sec() argument
51 struct instruction *next = list_next_entry(insn, list); in next_insn_same_sec()
53 if (!next || &next->list == &file->insn_list || next->sec != insn->sec) in next_insn_same_sec()
60 struct instruction *insn) in next_insn_same_func() argument
62 struct instruction *next = list_next_entry(insn, list); in next_insn_same_func()
63 struct symbol *func = insn->func; in next_insn_same_func()
80 struct instruction *insn) in prev_insn_same_sym() argument
82 struct instruction *prev = list_prev_entry(insn, list); in prev_insn_same_sym()
84 if (&prev->list != &file->insn_list && prev->func == insn->func) in prev_insn_same_sym()
90 #define func_for_each_insn(file, func, insn) \ argument
91 for (insn = find_insn(file, func->sec, func->offset); \
92 insn; \
93 insn = next_insn_same_func(file, insn))
95 #define sym_for_each_insn(file, sym, insn) \ argument
96 for (insn = find_insn(file, sym->sec, sym->offset); \
97 insn && &insn->list != &file->insn_list && \
98 insn->sec == sym->sec && \
99 insn->offset < sym->offset + sym->len; \
100 insn = list_next_entry(insn, list))
102 #define sym_for_each_insn_continue_reverse(file, sym, insn) \ argument
103 for (insn = list_prev_entry(insn, list); \
104 &insn->list != &file->insn_list && \
105 insn->sec == sym->sec && insn->offset >= sym->offset; \
106 insn = list_prev_entry(insn, list))
108 #define sec_for_each_insn_from(file, insn) \ argument
109 for (; insn; insn = next_insn_same_sec(file, insn))
111 #define sec_for_each_insn_continue(file, insn) \ argument
112 for (insn = next_insn_same_sec(file, insn); insn; \
113 insn = next_insn_same_sec(file, insn))
115 static bool is_jump_table_jump(struct instruction *insn) in is_jump_table_jump() argument
117 struct alt_group *alt_group = insn->alt_group; in is_jump_table_jump()
119 if (insn->jump_table) in is_jump_table_jump()
127 static bool is_sibling_call(struct instruction *insn) in is_sibling_call() argument
134 if (!insn->func) in is_sibling_call()
138 if (insn->type == INSN_JUMP_DYNAMIC) in is_sibling_call()
139 return !is_jump_table_jump(insn); in is_sibling_call()
142 return (is_static_jump(insn) && insn->call_dest); in is_sibling_call()
158 struct instruction *insn; in __dead_end_function() local
197 insn = find_insn(file, func->sec, func->offset); in __dead_end_function()
198 if (!insn->func) in __dead_end_function()
201 func_for_each_insn(file, func, insn) { in __dead_end_function()
204 if (insn->type == INSN_RETURN) in __dead_end_function()
216 func_for_each_insn(file, func, insn) { in __dead_end_function()
217 if (is_sibling_call(insn)) { in __dead_end_function()
218 struct instruction *dest = insn->jump_dest; in __dead_end_function()
354 struct instruction *insn; in decode_instructions() local
372 for (offset = 0; offset < sec->len; offset += insn->len) { in decode_instructions()
373 insn = malloc(sizeof(*insn)); in decode_instructions()
374 if (!insn) { in decode_instructions()
378 memset(insn, 0, sizeof(*insn)); in decode_instructions()
379 INIT_LIST_HEAD(&insn->alts); in decode_instructions()
380 INIT_LIST_HEAD(&insn->stack_ops); in decode_instructions()
382 insn->sec = sec; in decode_instructions()
383 insn->offset = offset; in decode_instructions()
387 &insn->len, &insn->type, in decode_instructions()
388 &insn->immediate, in decode_instructions()
389 &insn->stack_ops); in decode_instructions()
393 hash_add(file->insn_hash, &insn->hash, sec_offset_hash(sec, insn->offset)); in decode_instructions()
394 list_add_tail(&insn->list, &file->insn_list); in decode_instructions()
408 sym_for_each_insn(file, func, insn) in decode_instructions()
409 insn->func = func; in decode_instructions()
419 free(insn); in decode_instructions()
426 struct instruction *insn = NULL; in find_last_insn() local
430 for (offset = sec->len - 1; offset >= end && !insn; offset--) in find_last_insn()
431 insn = find_insn(file, sec, offset); in find_last_insn()
433 return insn; in find_last_insn()
443 struct instruction *insn; in add_dead_ends() local
449 for_each_insn(file, insn) in add_dead_ends()
450 if (insn->type == INSN_BUG) in add_dead_ends()
451 insn->dead_end = true; in add_dead_ends()
465 insn = find_insn(file, reloc->sym->sec, reloc->addend); in add_dead_ends()
466 if (insn) in add_dead_ends()
467 insn = list_prev_entry(insn, list); in add_dead_ends()
469 insn = find_last_insn(file, reloc->sym->sec); in add_dead_ends()
470 if (!insn) { in add_dead_ends()
481 insn->dead_end = true; in add_dead_ends()
500 insn = find_insn(file, reloc->sym->sec, reloc->addend); in add_dead_ends()
501 if (insn) in add_dead_ends()
502 insn = list_prev_entry(insn, list); in add_dead_ends()
504 insn = find_last_insn(file, reloc->sym->sec); in add_dead_ends()
505 if (!insn) { in add_dead_ends()
516 insn->dead_end = false; in add_dead_ends()
526 struct instruction *insn; in create_static_call_sections() local
542 list_for_each_entry(insn, &file->static_call_list, call_node) in create_static_call_sections()
551 list_for_each_entry(insn, &file->static_call_list, call_node) { in create_static_call_sections()
560 insn->sec, insn->offset)) in create_static_call_sections()
564 key_name = strdup(insn->call_dest->name); in create_static_call_sections()
593 key_sym = insn->call_dest; in create_static_call_sections()
601 is_sibling_call(insn) * STATIC_CALL_SITE_TAIL)) in create_static_call_sections()
612 struct instruction *insn; in create_retpoline_sites_sections() local
623 list_for_each_entry(insn, &file->retpoline_call_list, call_node) in create_retpoline_sites_sections()
637 list_for_each_entry(insn, &file->retpoline_call_list, call_node) { in create_retpoline_sites_sections()
645 insn->sec, insn->offset)) { in create_retpoline_sites_sections()
658 struct instruction *insn; in create_return_sites_sections() local
669 list_for_each_entry(insn, &file->return_thunk_list, call_node) in create_return_sites_sections()
683 list_for_each_entry(insn, &file->return_thunk_list, call_node) { in create_return_sites_sections()
691 insn->sec, insn->offset)) { in create_return_sites_sections()
707 struct instruction *insn; in add_ignores() local
733 func_for_each_insn(file, func, insn) in add_ignores()
734 insn->ignore = true; in add_ignores()
908 struct instruction *insn; in add_ignore_alternatives() local
920 insn = find_insn(file, reloc->sym->sec, reloc->addend); in add_ignore_alternatives()
921 if (!insn) { in add_ignore_alternatives()
926 insn->ignore_alts = true; in add_ignore_alternatives()
944 static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn) in insn_reloc() argument
946 if (insn->reloc == NEGATIVE_RELOC) in insn_reloc()
949 if (!insn->reloc) { in insn_reloc()
950 insn->reloc = find_reloc_by_dest_range(file->elf, insn->sec, in insn_reloc()
951 insn->offset, insn->len); in insn_reloc()
952 if (!insn->reloc) { in insn_reloc()
953 insn->reloc = NEGATIVE_RELOC; in insn_reloc()
958 return insn->reloc; in insn_reloc()
961 static void remove_insn_ops(struct instruction *insn) in remove_insn_ops() argument
965 list_for_each_entry_safe(op, tmp, &insn->stack_ops, list) { in remove_insn_ops()
972 struct instruction *insn, bool sibling) in annotate_call_site() argument
974 struct reloc *reloc = insn_reloc(file, insn); in annotate_call_site()
975 struct symbol *sym = insn->call_dest; in annotate_call_site()
986 if (!strcmp(insn->sec->name, ".altinstr_replacement")) in annotate_call_site()
990 list_add_tail(&insn->call_node, &file->static_call_list); in annotate_call_site()
995 list_add_tail(&insn->call_node, &file->retpoline_call_list); in annotate_call_site()
1004 if (insn->sec->noinstr && sym->kcov) { in annotate_call_site()
1010 elf_write_insn(file->elf, insn->sec, in annotate_call_site()
1011 insn->offset, insn->len, in annotate_call_site()
1012 sibling ? arch_ret_insn(insn->len) in annotate_call_site()
1013 : arch_nop_insn(insn->len)); in annotate_call_site()
1015 insn->type = sibling ? INSN_RETURN : INSN_NOP; in annotate_call_site()
1024 insn->retpoline_safe = true; in annotate_call_site()
1031 static void add_call_dest(struct objtool_file *file, struct instruction *insn, in add_call_dest() argument
1034 insn->call_dest = dest; in add_call_dest()
1045 remove_insn_ops(insn); in add_call_dest()
1047 annotate_call_site(file, insn, sibling); in add_call_dest()
1050 static void add_retpoline_call(struct objtool_file *file, struct instruction *insn) in add_retpoline_call() argument
1056 switch (insn->type) { in add_retpoline_call()
1058 insn->type = INSN_CALL_DYNAMIC; in add_retpoline_call()
1061 insn->type = INSN_JUMP_DYNAMIC; in add_retpoline_call()
1064 insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL; in add_retpoline_call()
1070 insn->retpoline_safe = true; in add_retpoline_call()
1079 remove_insn_ops(insn); in add_retpoline_call()
1081 annotate_call_site(file, insn, false); in add_retpoline_call()
1084 static void add_return_call(struct objtool_file *file, struct instruction *insn, bool add) in add_return_call() argument
1090 insn->type = INSN_RETURN; in add_return_call()
1091 insn->retpoline_safe = true; in add_return_call()
1094 if (add && insn->sec->text) in add_return_call()
1095 list_add_tail(&insn->call_node, &file->return_thunk_list); in add_return_call()
1103 struct instruction *insn; in add_jump_destinations() local
1108 for_each_insn(file, insn) { in add_jump_destinations()
1109 if (!is_static_jump(insn)) in add_jump_destinations()
1112 reloc = insn_reloc(file, insn); in add_jump_destinations()
1114 dest_sec = insn->sec; in add_jump_destinations()
1115 dest_off = arch_jump_destination(insn); in add_jump_destinations()
1120 add_retpoline_call(file, insn); in add_jump_destinations()
1123 add_return_call(file, insn, true); in add_jump_destinations()
1125 } else if (insn->func) { in add_jump_destinations()
1127 add_call_dest(file, insn, reloc->sym, true); in add_jump_destinations()
1138 insn->jump_dest = find_insn(file, dest_sec, dest_off); in add_jump_destinations()
1139 if (!insn->jump_dest) { in add_jump_destinations()
1147 if (!strcmp(insn->sec->name, ".altinstr_replacement")) in add_jump_destinations()
1159 add_return_call(file, insn, false); in add_jump_destinations()
1164 insn->sec, insn->offset, dest_sec->name, in add_jump_destinations()
1172 if (insn->func && insn->jump_dest->func && in add_jump_destinations()
1173 insn->func != insn->jump_dest->func) { in add_jump_destinations()
1190 if (!strstr(insn->func->name, ".cold") && in add_jump_destinations()
1191 strstr(insn->jump_dest->func->name, ".cold")) { in add_jump_destinations()
1192 insn->func->cfunc = insn->jump_dest->func; in add_jump_destinations()
1193 insn->jump_dest->func->pfunc = insn->func; in add_jump_destinations()
1195 } else if (insn->jump_dest->func->pfunc != insn->func->pfunc && in add_jump_destinations()
1196 insn->jump_dest->offset == insn->jump_dest->func->offset) { in add_jump_destinations()
1198 add_call_dest(file, insn, insn->jump_dest->func, true); in add_jump_destinations()
1222 struct instruction *insn; in add_call_destinations() local
1227 for_each_insn(file, insn) { in add_call_destinations()
1228 if (insn->type != INSN_CALL) in add_call_destinations()
1231 reloc = insn_reloc(file, insn); in add_call_destinations()
1233 dest_off = arch_jump_destination(insn); in add_call_destinations()
1234 dest = find_call_destination(insn->sec, dest_off); in add_call_destinations()
1236 add_call_dest(file, insn, dest, false); in add_call_destinations()
1238 if (insn->ignore) in add_call_destinations()
1241 if (!insn->call_dest) { in add_call_destinations()
1242 WARN_FUNC("unannotated intra-function call", insn->sec, insn->offset); in add_call_destinations()
1246 if (insn->func && insn->call_dest->type != STT_FUNC) { in add_call_destinations()
1248 insn->sec, insn->offset); in add_call_destinations()
1257 insn->sec, insn->offset, in add_call_destinations()
1263 add_call_dest(file, insn, dest, false); in add_call_destinations()
1266 add_retpoline_call(file, insn); in add_call_destinations()
1269 add_call_dest(file, insn, reloc->sym, false); in add_call_destinations()
1284 struct instruction *last_orig_insn, *last_new_insn = NULL, *insn, *nop = NULL; in handle_group_alt() local
1302 insn = orig_insn; in handle_group_alt()
1303 sec_for_each_insn_from(file, insn) { in handle_group_alt()
1304 if (insn->offset >= special_alt->orig_off + special_alt->orig_len) in handle_group_alt()
1307 insn->alt_group = orig_alt_group; in handle_group_alt()
1308 last_orig_insn = insn; in handle_group_alt()
1352 insn = *new_insn; in handle_group_alt()
1353 sec_for_each_insn_from(file, insn) { in handle_group_alt()
1356 if (insn->offset >= special_alt->new_off + special_alt->new_len) in handle_group_alt()
1359 last_new_insn = insn; in handle_group_alt()
1361 insn->ignore = orig_insn->ignore_alts; in handle_group_alt()
1362 insn->func = orig_insn->func; in handle_group_alt()
1363 insn->alt_group = new_alt_group; in handle_group_alt()
1373 alt_reloc = insn_reloc(file, insn); in handle_group_alt()
1375 !arch_support_alt_relocation(special_alt, insn, alt_reloc)) { in handle_group_alt()
1378 insn->sec, insn->offset); in handle_group_alt()
1382 if (!is_static_jump(insn)) in handle_group_alt()
1385 if (!insn->immediate) in handle_group_alt()
1388 dest_off = arch_jump_destination(insn); in handle_group_alt()
1390 insn->jump_dest = next_insn_same_sec(file, last_orig_insn); in handle_group_alt()
1392 if (!insn->jump_dest) { in handle_group_alt()
1394 insn->sec, insn->offset); in handle_group_alt()
1505 alt->insn = new_insn; in add_special_section_alts()
1518 static int add_jump_table(struct objtool_file *file, struct instruction *insn, in add_jump_table() argument
1524 struct symbol *pfunc = insn->func->pfunc; in add_jump_table()
1560 alt->insn = dest_insn; in add_jump_table()
1561 list_add_tail(&alt->list, &insn->alts); in add_jump_table()
1567 insn->sec, insn->offset); in add_jump_table()
1580 struct instruction *insn) in find_jump_table() argument
1583 struct instruction *dest_insn, *orig_insn = insn; in find_jump_table()
1591 insn && insn->func && insn->func->pfunc == func; in find_jump_table()
1592 insn = insn->first_jump_src ?: prev_insn_same_sym(file, insn)) { in find_jump_table()
1594 if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC) in find_jump_table()
1598 if (insn->type == INSN_JUMP_UNCONDITIONAL && in find_jump_table()
1599 insn->jump_dest && in find_jump_table()
1600 (insn->jump_dest->offset <= insn->offset || in find_jump_table()
1601 insn->jump_dest->offset > orig_insn->offset)) in find_jump_table()
1604 table_reloc = arch_find_switch_table(file, insn); in find_jump_table()
1624 struct instruction *insn, *last = NULL; in mark_func_jump_tables() local
1627 func_for_each_insn(file, func, insn) { in mark_func_jump_tables()
1629 last = insn; in mark_func_jump_tables()
1636 if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest && in mark_func_jump_tables()
1637 insn->offset > last->offset && in mark_func_jump_tables()
1638 insn->jump_dest->offset > insn->offset && in mark_func_jump_tables()
1639 !insn->jump_dest->first_jump_src) { in mark_func_jump_tables()
1641 insn->jump_dest->first_jump_src = insn; in mark_func_jump_tables()
1642 last = insn->jump_dest; in mark_func_jump_tables()
1645 if (insn->type != INSN_JUMP_DYNAMIC) in mark_func_jump_tables()
1648 reloc = find_jump_table(file, func, insn); in mark_func_jump_tables()
1651 insn->jump_table = reloc; in mark_func_jump_tables()
1659 struct instruction *insn; in add_func_jump_tables() local
1662 func_for_each_insn(file, func, insn) { in add_func_jump_tables()
1663 if (!insn->jump_table) in add_func_jump_tables()
1666 ret = add_jump_table(file, insn, insn->jump_table); in add_func_jump_tables()
1716 struct instruction *insn; in read_unwind_hints() local
1746 insn = find_insn(file, reloc->sym->sec, reloc->addend); in read_unwind_hints()
1747 if (!insn) { in read_unwind_hints()
1752 insn->hint = true; in read_unwind_hints()
1755 insn->hint = false; in read_unwind_hints()
1756 insn->save = true; in read_unwind_hints()
1761 insn->restore = true; in read_unwind_hints()
1766 struct symbol *sym = find_symbol_by_offset(insn->sec, insn->offset); in read_unwind_hints()
1769 insn->entry = 1; in read_unwind_hints()
1775 insn->entry = 1; in read_unwind_hints()
1779 insn->cfi = &func_cfi; in read_unwind_hints()
1783 if (insn->cfi) in read_unwind_hints()
1784 cfi = *(insn->cfi); in read_unwind_hints()
1788 insn->sec, insn->offset, hint->sp_reg); in read_unwind_hints()
1796 insn->cfi = cfi_hash_find_or_add(&cfi); in read_unwind_hints()
1805 struct instruction *insn; in read_retpoline_hints() local
1818 insn = find_insn(file, reloc->sym->sec, reloc->addend); in read_retpoline_hints()
1819 if (!insn) { in read_retpoline_hints()
1824 if (insn->type != INSN_JUMP_DYNAMIC && in read_retpoline_hints()
1825 insn->type != INSN_CALL_DYNAMIC && in read_retpoline_hints()
1826 insn->type != INSN_RETURN && in read_retpoline_hints()
1827 insn->type != INSN_NOP) { in read_retpoline_hints()
1829 insn->sec, insn->offset); in read_retpoline_hints()
1833 insn->retpoline_safe = true; in read_retpoline_hints()
1842 struct instruction *insn; in read_instr_hints() local
1855 insn = find_insn(file, reloc->sym->sec, reloc->addend); in read_instr_hints()
1856 if (!insn) { in read_instr_hints()
1861 insn->instr--; in read_instr_hints()
1874 insn = find_insn(file, reloc->sym->sec, reloc->addend); in read_instr_hints()
1875 if (!insn) { in read_instr_hints()
1880 insn->instr++; in read_instr_hints()
1888 struct instruction *insn; in read_intra_function_calls() local
1905 insn = find_insn(file, reloc->sym->sec, reloc->addend); in read_intra_function_calls()
1906 if (!insn) { in read_intra_function_calls()
1911 if (insn->type != INSN_CALL) { in read_intra_function_calls()
1913 insn->sec, insn->offset); in read_intra_function_calls()
1922 insn->type = INSN_JUMP_UNCONDITIONAL; in read_intra_function_calls()
1924 dest_off = insn->offset + insn->len + insn->immediate; in read_intra_function_calls()
1925 insn->jump_dest = find_insn(file, insn->sec, dest_off); in read_intra_function_calls()
1926 if (!insn->jump_dest) { in read_intra_function_calls()
1928 insn->sec, insn->offset, in read_intra_function_calls()
1929 insn->sec->name, dest_off); in read_intra_function_calls()
2065 static bool is_fentry_call(struct instruction *insn) in is_fentry_call() argument
2067 if (insn->type == INSN_CALL && in is_fentry_call()
2068 insn->call_dest && in is_fentry_call()
2069 insn->call_dest->fentry) in is_fentry_call()
2075 static bool has_modified_stack_frame(struct instruction *insn, struct insn_state *state) in has_modified_stack_frame() argument
2112 static int update_cfi_state_regs(struct instruction *insn, in update_cfi_state_regs() argument
2205 static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi, in update_cfi_state() argument
2213 if (insn->func) { in update_cfi_state()
2214 WARN_FUNC("undefined stack state", insn->sec, insn->offset); in update_cfi_state()
2222 return update_cfi_state_regs(insn, cfi, op); in update_cfi_state()
2353 insn->sec, insn->offset); in update_cfi_state()
2364 insn->sec, insn->offset); in update_cfi_state()
2439 insn->sec, insn->offset); in update_cfi_state()
2482 if (!no_fp && insn->func && op->src.reg == CFI_BP && in update_cfi_state()
2518 insn->sec, insn->offset); in update_cfi_state()
2537 insn->sec, insn->offset); in update_cfi_state()
2550 insn->sec, insn->offset); in update_cfi_state()
2566 static int propagate_alt_cfi(struct objtool_file *file, struct instruction *insn) in propagate_alt_cfi() argument
2571 if (!insn->alt_group) in propagate_alt_cfi()
2574 if (!insn->cfi) { in propagate_alt_cfi()
2579 alt_cfi = insn->alt_group->cfi; in propagate_alt_cfi()
2580 group_off = insn->offset - insn->alt_group->first_insn->offset; in propagate_alt_cfi()
2583 alt_cfi[group_off] = insn->cfi; in propagate_alt_cfi()
2585 if (cficmp(alt_cfi[group_off], insn->cfi)) { in propagate_alt_cfi()
2587 insn->sec, insn->offset); in propagate_alt_cfi()
2595 static int handle_insn_ops(struct instruction *insn, struct insn_state *state) in handle_insn_ops() argument
2599 list_for_each_entry(op, &insn->stack_ops, list) { in handle_insn_ops()
2601 if (update_cfi_state(insn, &state->cfi, op)) in handle_insn_ops()
2609 insn->sec, insn->offset); in handle_insn_ops()
2629 static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2) in insn_cfi_match() argument
2631 struct cfi_state *cfi1 = insn->cfi; in insn_cfi_match()
2642 insn->sec, insn->offset, in insn_cfi_match()
2653 insn->sec, insn->offset, in insn_cfi_match()
2662 insn->sec, insn->offset, cfi1->type, cfi2->type); in insn_cfi_match()
2669 insn->sec, insn->offset, in insn_cfi_match()
2687 static inline const char *call_dest_name(struct instruction *insn) in call_dest_name() argument
2689 if (insn->call_dest) in call_dest_name()
2690 return insn->call_dest->name; in call_dest_name()
2721 static int validate_call(struct instruction *insn, struct insn_state *state) in validate_call() argument
2724 !noinstr_call_dest(insn->call_dest)) { in validate_call()
2726 insn->sec, insn->offset, call_dest_name(insn)); in validate_call()
2730 if (state->uaccess && !func_uaccess_safe(insn->call_dest)) { in validate_call()
2732 insn->sec, insn->offset, call_dest_name(insn)); in validate_call()
2738 insn->sec, insn->offset, call_dest_name(insn)); in validate_call()
2745 static int validate_sibling_call(struct instruction *insn, struct insn_state *state) in validate_sibling_call() argument
2747 if (has_modified_stack_frame(insn, state)) { in validate_sibling_call()
2749 insn->sec, insn->offset); in validate_sibling_call()
2753 return validate_call(insn, state); in validate_sibling_call()
2756 static int validate_return(struct symbol *func, struct instruction *insn, struct insn_state *state) in validate_return() argument
2760 insn->sec, insn->offset); in validate_return()
2766 insn->sec, insn->offset); in validate_return()
2772 insn->sec, insn->offset); in validate_return()
2778 insn->sec, insn->offset); in validate_return()
2782 if (func && has_modified_stack_frame(insn, state)) { in validate_return()
2784 insn->sec, insn->offset); in validate_return()
2790 insn->sec, insn->offset); in validate_return()
2798 struct instruction *insn) in next_insn_to_validate() argument
2800 struct alt_group *alt_group = insn->alt_group; in next_insn_to_validate()
2807 if (alt_group && insn == alt_group->last_insn && alt_group->orig_group) in next_insn_to_validate()
2810 return next_insn_same_sec(file, insn); in next_insn_to_validate()
2820 struct instruction *insn, struct insn_state state) in validate_branch() argument
2828 sec = insn->sec; in validate_branch()
2831 next_insn = next_insn_to_validate(file, insn); in validate_branch()
2833 if (file->c_file && func && insn->func && func != insn->func->pfunc) { in validate_branch()
2835 func->name, insn->func->name); in validate_branch()
2839 if (func && insn->ignore) { in validate_branch()
2841 sec, insn->offset); in validate_branch()
2846 if (insn->visited & VISITED_BRANCH_MASK) { in validate_branch()
2847 if (!insn->hint && !insn_cfi_match(insn, &state.cfi)) in validate_branch()
2850 if (insn->visited & visited) in validate_branch()
2857 state.instr += insn->instr; in validate_branch()
2859 if (insn->hint) { in validate_branch()
2860 if (insn->restore) { in validate_branch()
2863 i = insn; in validate_branch()
2875 sec, insn->offset); in validate_branch()
2881 sec, insn->offset); in validate_branch()
2885 insn->cfi = save_insn->cfi; in validate_branch()
2889 state.cfi = *insn->cfi; in validate_branch()
2894 insn->cfi = prev_insn->cfi; in validate_branch()
2897 insn->cfi = cfi_hash_find_or_add(&state.cfi); in validate_branch()
2901 insn->visited |= visited; in validate_branch()
2903 if (propagate_alt_cfi(file, insn)) in validate_branch()
2906 if (!insn->ignore_alts && !list_empty(&insn->alts)) { in validate_branch()
2909 list_for_each_entry(alt, &insn->alts, list) { in validate_branch()
2913 ret = validate_branch(file, func, alt->insn, state); in validate_branch()
2916 BT_FUNC("(alt)", insn); in validate_branch()
2925 if (handle_insn_ops(insn, &state)) in validate_branch()
2928 switch (insn->type) { in validate_branch()
2931 if (sls && !insn->retpoline_safe && in validate_branch()
2934 insn->sec, insn->offset); in validate_branch()
2936 return validate_return(func, insn, &state); in validate_branch()
2940 ret = validate_call(insn, &state); in validate_branch()
2944 if (!no_fp && func && !is_fentry_call(insn) && in validate_branch()
2947 sec, insn->offset); in validate_branch()
2951 if (dead_end_function(file, insn->call_dest)) in validate_branch()
2958 if (is_sibling_call(insn)) { in validate_branch()
2959 ret = validate_sibling_call(insn, &state); in validate_branch()
2963 } else if (insn->jump_dest) { in validate_branch()
2965 insn->jump_dest, state); in validate_branch()
2968 BT_FUNC("(branch)", insn); in validate_branch()
2973 if (insn->type == INSN_JUMP_UNCONDITIONAL) in validate_branch()
2979 if (sls && !insn->retpoline_safe && in validate_branch()
2982 insn->sec, insn->offset); in validate_branch()
2987 if (is_sibling_call(insn)) { in validate_branch()
2988 ret = validate_sibling_call(insn, &state); in validate_branch()
2993 if (insn->type == INSN_JUMP_DYNAMIC) in validate_branch()
3001 sec, insn->offset); in validate_branch()
3008 WARN_FUNC("recursive UACCESS enable", sec, insn->offset); in validate_branch()
3017 WARN_FUNC("redundant UACCESS disable", sec, insn->offset); in validate_branch()
3022 WARN_FUNC("UACCESS-safe disables UACCESS", sec, insn->offset); in validate_branch()
3031 WARN_FUNC("recursive STD", sec, insn->offset); in validate_branch()
3040 WARN_FUNC("redundant CLD", sec, insn->offset); in validate_branch()
3051 if (insn->dead_end) in validate_branch()
3061 prev_insn = insn; in validate_branch()
3062 insn = next_insn; in validate_branch()
3070 struct instruction *insn; in validate_unwind_hints() local
3080 insn = find_insn(file, sec, 0); in validate_unwind_hints()
3081 if (!insn) in validate_unwind_hints()
3084 insn = list_first_entry(&file->insn_list, typeof(*insn), list); in validate_unwind_hints()
3087 while (&insn->list != &file->insn_list && (!sec || insn->sec == sec)) { in validate_unwind_hints()
3088 if (insn->hint && !insn->visited) { in validate_unwind_hints()
3089 ret = validate_branch(file, insn->func, insn, state); in validate_unwind_hints()
3091 BT_FUNC("<=== (hint)", insn); in validate_unwind_hints()
3095 insn = list_next_entry(insn, list); in validate_unwind_hints()
3107 static int validate_entry(struct objtool_file *file, struct instruction *insn) in validate_entry() argument
3113 next = next_insn_to_validate(file, insn); in validate_entry()
3115 if (insn->visited & VISITED_ENTRY) in validate_entry()
3118 insn->visited |= VISITED_ENTRY; in validate_entry()
3120 if (!insn->ignore_alts && !list_empty(&insn->alts)) { in validate_entry()
3124 list_for_each_entry(alt, &insn->alts, list) { in validate_entry()
3128 ret = validate_entry(file, alt->insn); in validate_entry()
3131 BT_FUNC("(alt)", insn); in validate_entry()
3140 switch (insn->type) { in validate_entry()
3145 WARN_FUNC("early indirect call", insn->sec, insn->offset); in validate_entry()
3150 if (!is_sibling_call(insn)) { in validate_entry()
3151 if (!insn->jump_dest) { in validate_entry()
3153 insn->sec, insn->offset); in validate_entry()
3156 ret = validate_entry(file, insn->jump_dest); in validate_entry()
3159 BT_FUNC("(branch%s)", insn, in validate_entry()
3160 insn->type == INSN_JUMP_CONDITIONAL ? "-cond" : ""); in validate_entry()
3165 if (insn->type == INSN_JUMP_UNCONDITIONAL) in validate_entry()
3173 dest = find_insn(file, insn->call_dest->sec, in validate_entry()
3174 insn->call_dest->offset); in validate_entry()
3177 insn->call_dest->name); in validate_entry()
3184 BT_FUNC("(call)", insn); in validate_entry()
3194 WARN_FUNC("RET before UNTRAIN", insn->sec, insn->offset); in validate_entry()
3198 if (insn->retpoline_safe) in validate_entry()
3207 WARN_FUNC("teh end!", insn->sec, insn->offset); in validate_entry()
3210 insn = next; in validate_entry()
3222 struct instruction *insn; in validate_unret() local
3225 for_each_insn(file, insn) { in validate_unret()
3226 if (!insn->entry) in validate_unret()
3229 ret = validate_entry(file, insn); in validate_unret()
3231 WARN_FUNC("Failed UNRET validation", insn->sec, insn->offset); in validate_unret()
3242 struct instruction *insn; in validate_retpoline() local
3245 for_each_insn(file, insn) { in validate_retpoline()
3246 if (insn->type != INSN_JUMP_DYNAMIC && in validate_retpoline()
3247 insn->type != INSN_CALL_DYNAMIC && in validate_retpoline()
3248 insn->type != INSN_RETURN) in validate_retpoline()
3251 if (insn->retpoline_safe) in validate_retpoline()
3260 if (!strcmp(insn->sec->name, ".init.text") && !module) in validate_retpoline()
3263 if (insn->type == INSN_RETURN) { in validate_retpoline()
3266 insn->sec, insn->offset); in validate_retpoline()
3271 insn->sec, insn->offset, in validate_retpoline()
3272 insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); in validate_retpoline()
3281 static bool is_kasan_insn(struct instruction *insn) in is_kasan_insn() argument
3283 return (insn->type == INSN_CALL && in is_kasan_insn()
3284 !strcmp(insn->call_dest->name, "__asan_handle_no_return")); in is_kasan_insn()
3287 static bool is_ubsan_insn(struct instruction *insn) in is_ubsan_insn() argument
3289 return (insn->type == INSN_CALL && in is_ubsan_insn()
3290 !strcmp(insn->call_dest->name, in is_ubsan_insn()
3294 static bool ignore_unreachable_insn(struct objtool_file *file, struct instruction *insn) in ignore_unreachable_insn() argument
3299 if (insn->ignore || insn->type == INSN_NOP || insn->type == INSN_TRAP) in ignore_unreachable_insn()
3309 if (!strcmp(insn->sec->name, ".fixup") || in ignore_unreachable_insn()
3310 !strcmp(insn->sec->name, ".altinstr_replacement") || in ignore_unreachable_insn()
3311 !strcmp(insn->sec->name, ".altinstr_aux")) in ignore_unreachable_insn()
3314 if (!insn->func) in ignore_unreachable_insn()
3325 prev_insn = list_prev_entry(insn, list); in ignore_unreachable_insn()
3327 (insn->type == INSN_BUG || in ignore_unreachable_insn()
3328 (insn->type == INSN_JUMP_UNCONDITIONAL && in ignore_unreachable_insn()
3329 insn->jump_dest && insn->jump_dest->type == INSN_BUG))) in ignore_unreachable_insn()
3340 if (is_kasan_insn(insn) || is_ubsan_insn(insn)) in ignore_unreachable_insn()
3343 if (insn->type == INSN_JUMP_UNCONDITIONAL) { in ignore_unreachable_insn()
3344 if (insn->jump_dest && in ignore_unreachable_insn()
3345 insn->jump_dest->func == insn->func) { in ignore_unreachable_insn()
3346 insn = insn->jump_dest; in ignore_unreachable_insn()
3353 if (insn->offset + insn->len >= insn->func->offset + insn->func->len) in ignore_unreachable_insn()
3356 insn = list_next_entry(insn, list); in ignore_unreachable_insn()
3365 struct instruction *insn; in validate_symbol() local
3376 insn = find_insn(file, sec, sym->offset); in validate_symbol()
3377 if (!insn || insn->ignore || insn->visited) in validate_symbol()
3382 ret = validate_branch(file, insn->func, insn, *state); in validate_symbol()
3384 BT_FUNC("<=== (sym)", insn); in validate_symbol()
3444 struct instruction *insn; in validate_reachable_instructions() local
3449 for_each_insn(file, insn) { in validate_reachable_instructions()
3450 if (insn->visited || ignore_unreachable_insn(file, insn)) in validate_reachable_instructions()
3453 WARN_FUNC("unreachable instruction", insn->sec, insn->offset); in validate_reachable_instructions()