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 struct instruction *next = list_next_entry(insn, list); in next_insn_same_sec()
55 if (!next || &next->list == &file->insn_list || next->sec != insn->sec) in next_insn_same_sec()
62 struct instruction *insn) in next_insn_same_func() argument
64 struct instruction *next = list_next_entry(insn, list); in next_insn_same_func()
65 struct symbol *func = insn->func; in next_insn_same_func()
82 struct instruction *insn) in prev_insn_same_sym() argument
84 struct instruction *prev = list_prev_entry(insn, list); in prev_insn_same_sym()
86 if (&prev->list != &file->insn_list && prev->func == insn->func) in prev_insn_same_sym()
92 #define func_for_each_insn(file, func, insn) \ argument
93 for (insn = find_insn(file, func->sec, func->offset); \
94 insn; \
95 insn = next_insn_same_func(file, insn))
97 #define sym_for_each_insn(file, sym, insn) \ argument
98 for (insn = find_insn(file, sym->sec, sym->offset); \
99 insn && &insn->list != &file->insn_list && \
100 insn->sec == sym->sec && \
101 insn->offset < sym->offset + sym->len; \
102 insn = list_next_entry(insn, list))
104 #define sym_for_each_insn_continue_reverse(file, sym, insn) \ argument
105 for (insn = list_prev_entry(insn, list); \
106 &insn->list != &file->insn_list && \
107 insn->sec == sym->sec && insn->offset >= sym->offset; \
108 insn = list_prev_entry(insn, list))
110 #define sec_for_each_insn_from(file, insn) \ argument
111 for (; insn; insn = next_insn_same_sec(file, insn))
113 #define sec_for_each_insn_continue(file, insn) \ argument
114 for (insn = next_insn_same_sec(file, insn); insn; \
115 insn = next_insn_same_sec(file, insn))
117 static bool is_jump_table_jump(struct instruction *insn) in is_jump_table_jump() argument
119 struct alt_group *alt_group = insn->alt_group; in is_jump_table_jump()
121 if (insn->jump_table) in is_jump_table_jump()
129 static bool is_sibling_call(struct instruction *insn) in is_sibling_call() argument
136 if (!insn->func) in is_sibling_call()
140 if (insn->type == INSN_JUMP_DYNAMIC) in is_sibling_call()
141 return !is_jump_table_jump(insn); in is_sibling_call()
144 return (is_static_jump(insn) && insn->call_dest); in is_sibling_call()
160 struct instruction *insn; in __dead_end_function() local
209 insn = find_insn(file, func->sec, func->offset); in __dead_end_function()
210 if (!insn->func) in __dead_end_function()
213 func_for_each_insn(file, func, insn) { in __dead_end_function()
216 if (insn->type == INSN_RETURN) in __dead_end_function()
228 func_for_each_insn(file, func, insn) { in __dead_end_function()
229 if (is_sibling_call(insn)) { in __dead_end_function()
230 struct instruction *dest = insn->jump_dest; in __dead_end_function()
367 struct instruction *insn; in decode_instructions() local
385 for (offset = 0; offset < sec->sh.sh_size; offset += insn->len) { in decode_instructions()
386 insn = malloc(sizeof(*insn)); in decode_instructions()
387 if (!insn) { in decode_instructions()
391 memset(insn, 0, sizeof(*insn)); in decode_instructions()
392 INIT_LIST_HEAD(&insn->alts); in decode_instructions()
393 INIT_LIST_HEAD(&insn->stack_ops); in decode_instructions()
394 INIT_LIST_HEAD(&insn->call_node); in decode_instructions()
396 insn->sec = sec; in decode_instructions()
397 insn->offset = offset; in decode_instructions()
401 &insn->len, &insn->type, in decode_instructions()
402 &insn->immediate, in decode_instructions()
403 &insn->stack_ops); in decode_instructions()
412 if (insn->type == INSN_BUG) in decode_instructions()
413 insn->dead_end = true; in decode_instructions()
415 hash_add(file->insn_hash, &insn->hash, sec_offset_hash(sec, insn->offset)); in decode_instructions()
416 list_add_tail(&insn->list, &file->insn_list); in decode_instructions()
430 sym_for_each_insn(file, func, insn) { in decode_instructions()
431 insn->func = func; in decode_instructions()
432 if (insn->type == INSN_ENDBR && list_empty(&insn->call_node)) { in decode_instructions()
433 if (insn->offset == insn->func->offset) { in decode_instructions()
434 list_add_tail(&insn->call_node, &file->endbr_list); in decode_instructions()
450 free(insn); in decode_instructions()
533 struct instruction *insn = NULL; in find_last_insn() local
537 for (offset = sec->sh.sh_size - 1; offset >= end && !insn; offset--) in find_last_insn()
538 insn = find_insn(file, sec, offset); in find_last_insn()
540 return insn; in find_last_insn()
550 struct instruction *insn; in add_dead_ends() local
564 insn = find_insn(file, reloc->sym->sec, reloc->addend); in add_dead_ends()
565 if (insn) in add_dead_ends()
566 insn = list_prev_entry(insn, list); in add_dead_ends()
568 insn = find_last_insn(file, reloc->sym->sec); in add_dead_ends()
569 if (!insn) { in add_dead_ends()
580 insn->dead_end = true; in add_dead_ends()
599 insn = find_insn(file, reloc->sym->sec, reloc->addend); in add_dead_ends()
600 if (insn) in add_dead_ends()
601 insn = list_prev_entry(insn, list); in add_dead_ends()
603 insn = find_last_insn(file, reloc->sym->sec); in add_dead_ends()
604 if (!insn) { in add_dead_ends()
615 insn->dead_end = false; in add_dead_ends()
625 struct instruction *insn; in create_static_call_sections() local
641 list_for_each_entry(insn, &file->static_call_list, call_node) in create_static_call_sections()
650 list_for_each_entry(insn, &file->static_call_list, call_node) { in create_static_call_sections()
659 insn->sec, insn->offset)) in create_static_call_sections()
663 key_name = strdup(insn->call_dest->name); in create_static_call_sections()
692 key_sym = insn->call_dest; in create_static_call_sections()
700 is_sibling_call(insn) * STATIC_CALL_SITE_TAIL)) in create_static_call_sections()
711 struct instruction *insn; in create_retpoline_sites_sections() local
722 list_for_each_entry(insn, &file->retpoline_call_list, call_node) in create_retpoline_sites_sections()
736 list_for_each_entry(insn, &file->retpoline_call_list, call_node) { in create_retpoline_sites_sections()
744 insn->sec, insn->offset)) { in create_retpoline_sites_sections()
757 struct instruction *insn; in create_return_sites_sections() local
768 list_for_each_entry(insn, &file->return_thunk_list, call_node) in create_return_sites_sections()
782 list_for_each_entry(insn, &file->return_thunk_list, call_node) { in create_return_sites_sections()
790 insn->sec, insn->offset)) { in create_return_sites_sections()
803 struct instruction *insn; in create_ibt_endbr_seal_sections() local
814 list_for_each_entry(insn, &file->endbr_list, call_node) in create_ibt_endbr_seal_sections()
834 list_for_each_entry(insn, &file->endbr_list, call_node) { in create_ibt_endbr_seal_sections()
842 insn->sec, insn->offset)) { in create_ibt_endbr_seal_sections()
857 struct instruction *insn; in create_mcount_loc_sections() local
871 list_for_each_entry(insn, &file->mcount_loc_list, call_node) in create_mcount_loc_sections()
879 list_for_each_entry(insn, &file->mcount_loc_list, call_node) { in create_mcount_loc_sections()
887 insn->sec, insn->offset)) in create_mcount_loc_sections()
901 struct instruction *insn; in add_ignores() local
927 func_for_each_insn(file, func, insn) in add_ignores()
928 insn->ignore = true; in add_ignores()
1129 struct instruction *insn; in add_ignore_alternatives() local
1141 insn = find_insn(file, reloc->sym->sec, reloc->addend); in add_ignore_alternatives()
1142 if (!insn) { in add_ignore_alternatives()
1147 insn->ignore_alts = true; in add_ignore_alternatives()
1165 static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn) in insn_reloc() argument
1167 if (insn->reloc == NEGATIVE_RELOC) in insn_reloc()
1170 if (!insn->reloc) { in insn_reloc()
1174 insn->reloc = find_reloc_by_dest_range(file->elf, insn->sec, in insn_reloc()
1175 insn->offset, insn->len); in insn_reloc()
1176 if (!insn->reloc) { in insn_reloc()
1177 insn->reloc = NEGATIVE_RELOC; in insn_reloc()
1182 return insn->reloc; in insn_reloc()
1185 static void remove_insn_ops(struct instruction *insn) in remove_insn_ops() argument
1189 list_for_each_entry_safe(op, tmp, &insn->stack_ops, list) { in remove_insn_ops()
1196 struct instruction *insn, bool sibling) in annotate_call_site() argument
1198 struct reloc *reloc = insn_reloc(file, insn); in annotate_call_site()
1199 struct symbol *sym = insn->call_dest; in annotate_call_site()
1210 if (!strcmp(insn->sec->name, ".altinstr_replacement")) in annotate_call_site()
1214 list_add_tail(&insn->call_node, &file->static_call_list); in annotate_call_site()
1219 list_add_tail(&insn->call_node, &file->retpoline_call_list); in annotate_call_site()
1228 if (opts.hack_noinstr && insn->sec->noinstr && sym->profiling_func) { in annotate_call_site()
1234 elf_write_insn(file->elf, insn->sec, in annotate_call_site()
1235 insn->offset, insn->len, in annotate_call_site()
1236 sibling ? arch_ret_insn(insn->len) in annotate_call_site()
1237 : arch_nop_insn(insn->len)); in annotate_call_site()
1239 insn->type = sibling ? INSN_RETURN : INSN_NOP; in annotate_call_site()
1248 insn->retpoline_safe = true; in annotate_call_site()
1256 WARN_FUNC("Tail call to __fentry__ !?!?", insn->sec, insn->offset); in annotate_call_site()
1263 elf_write_insn(file->elf, insn->sec, in annotate_call_site()
1264 insn->offset, insn->len, in annotate_call_site()
1265 arch_nop_insn(insn->len)); in annotate_call_site()
1267 insn->type = INSN_NOP; in annotate_call_site()
1269 list_add_tail(&insn->call_node, &file->mcount_loc_list); in annotate_call_site()
1274 insn->dead_end = true; in annotate_call_site()
1277 static void add_call_dest(struct objtool_file *file, struct instruction *insn, in add_call_dest() argument
1280 insn->call_dest = dest; in add_call_dest()
1291 remove_insn_ops(insn); in add_call_dest()
1293 annotate_call_site(file, insn, sibling); in add_call_dest()
1296 static void add_retpoline_call(struct objtool_file *file, struct instruction *insn) in add_retpoline_call() argument
1302 switch (insn->type) { in add_retpoline_call()
1304 insn->type = INSN_CALL_DYNAMIC; in add_retpoline_call()
1307 insn->type = INSN_JUMP_DYNAMIC; in add_retpoline_call()
1310 insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL; in add_retpoline_call()
1316 insn->retpoline_safe = true; in add_retpoline_call()
1325 remove_insn_ops(insn); in add_retpoline_call()
1327 annotate_call_site(file, insn, false); in add_retpoline_call()
1330 static void add_return_call(struct objtool_file *file, struct instruction *insn, bool add) in add_return_call() argument
1336 insn->type = INSN_RETURN; in add_return_call()
1337 insn->retpoline_safe = true; in add_return_call()
1340 list_add_tail(&insn->call_node, &file->return_thunk_list); in add_return_call()
1348 static bool is_first_func_insn(struct objtool_file *file, struct instruction *insn) in is_first_func_insn() argument
1350 if (insn->offset == insn->func->offset) in is_first_func_insn()
1354 struct instruction *prev = prev_insn_same_sym(file, insn); in is_first_func_insn()
1357 insn->offset == insn->func->offset + prev->len) in is_first_func_insn()
1369 struct instruction *insn, *jump_dest; in add_jump_destinations() local
1374 for_each_insn(file, insn) { in add_jump_destinations()
1375 if (insn->jump_dest) { in add_jump_destinations()
1382 if (!is_static_jump(insn)) in add_jump_destinations()
1385 reloc = insn_reloc(file, insn); in add_jump_destinations()
1387 dest_sec = insn->sec; in add_jump_destinations()
1388 dest_off = arch_jump_destination(insn); in add_jump_destinations()
1393 add_retpoline_call(file, insn); in add_jump_destinations()
1396 add_return_call(file, insn, true); in add_jump_destinations()
1398 } else if (insn->func) { in add_jump_destinations()
1403 add_call_dest(file, insn, reloc->sym, true); in add_jump_destinations()
1427 add_return_call(file, insn, false); in add_jump_destinations()
1432 insn->sec, insn->offset, dest_sec->name, in add_jump_destinations()
1440 if (insn->func && jump_dest->func && in add_jump_destinations()
1441 insn->func != jump_dest->func) { in add_jump_destinations()
1458 if (!strstr(insn->func->name, ".cold") && in add_jump_destinations()
1460 insn->func->cfunc = jump_dest->func; in add_jump_destinations()
1461 jump_dest->func->pfunc = insn->func; in add_jump_destinations()
1463 } else if (!same_function(insn, jump_dest) && in add_jump_destinations()
1469 add_call_dest(file, insn, jump_dest->func, true); in add_jump_destinations()
1474 insn->jump_dest = jump_dest; in add_jump_destinations()
1496 struct instruction *insn; in add_call_destinations() local
1501 for_each_insn(file, insn) { in add_call_destinations()
1502 if (insn->type != INSN_CALL) in add_call_destinations()
1505 reloc = insn_reloc(file, insn); in add_call_destinations()
1507 dest_off = arch_jump_destination(insn); in add_call_destinations()
1508 dest = find_call_destination(insn->sec, dest_off); in add_call_destinations()
1510 add_call_dest(file, insn, dest, false); in add_call_destinations()
1512 if (insn->ignore) in add_call_destinations()
1515 if (!insn->call_dest) { in add_call_destinations()
1516 WARN_FUNC("unannotated intra-function call", insn->sec, insn->offset); in add_call_destinations()
1520 if (insn->func && insn->call_dest->type != STT_FUNC) { in add_call_destinations()
1522 insn->sec, insn->offset); in add_call_destinations()
1531 insn->sec, insn->offset, in add_call_destinations()
1537 add_call_dest(file, insn, dest, false); in add_call_destinations()
1540 add_retpoline_call(file, insn); in add_call_destinations()
1543 add_call_dest(file, insn, reloc->sym, false); in add_call_destinations()
1558 struct instruction *last_orig_insn, *last_new_insn = NULL, *insn, *nop = NULL; in handle_group_alt() local
1576 insn = orig_insn; in handle_group_alt()
1577 sec_for_each_insn_from(file, insn) { in handle_group_alt()
1578 if (insn->offset >= special_alt->orig_off + special_alt->orig_len) in handle_group_alt()
1581 insn->alt_group = orig_alt_group; in handle_group_alt()
1582 last_orig_insn = insn; in handle_group_alt()
1626 insn = *new_insn; in handle_group_alt()
1627 sec_for_each_insn_from(file, insn) { in handle_group_alt()
1630 if (insn->offset >= special_alt->new_off + special_alt->new_len) in handle_group_alt()
1633 last_new_insn = insn; in handle_group_alt()
1635 insn->ignore = orig_insn->ignore_alts; in handle_group_alt()
1636 insn->func = orig_insn->func; in handle_group_alt()
1637 insn->alt_group = new_alt_group; in handle_group_alt()
1647 alt_reloc = insn_reloc(file, insn); in handle_group_alt()
1649 !arch_support_alt_relocation(special_alt, insn, alt_reloc)) { in handle_group_alt()
1652 insn->sec, insn->offset); in handle_group_alt()
1656 if (!is_static_jump(insn)) in handle_group_alt()
1659 if (!insn->immediate) in handle_group_alt()
1662 dest_off = arch_jump_destination(insn); in handle_group_alt()
1664 insn->jump_dest = next_insn_same_sec(file, last_orig_insn); in handle_group_alt()
1665 if (!insn->jump_dest) { in handle_group_alt()
1667 insn->sec, insn->offset); in handle_group_alt()
1805 alt->insn = new_insn; in add_special_section_alts()
1824 static int add_jump_table(struct objtool_file *file, struct instruction *insn, in add_jump_table() argument
1830 struct symbol *pfunc = insn->func->pfunc; in add_jump_table()
1866 alt->insn = dest_insn; in add_jump_table()
1867 list_add_tail(&alt->list, &insn->alts); in add_jump_table()
1873 insn->sec, insn->offset); in add_jump_table()
1886 struct instruction *insn) in find_jump_table() argument
1889 struct instruction *dest_insn, *orig_insn = insn; in find_jump_table()
1897 insn && insn->func && insn->func->pfunc == func; in find_jump_table()
1898 insn = insn->first_jump_src ?: prev_insn_same_sym(file, insn)) { in find_jump_table()
1900 if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC) in find_jump_table()
1904 if (insn->type == INSN_JUMP_UNCONDITIONAL && in find_jump_table()
1905 insn->jump_dest && in find_jump_table()
1906 (insn->jump_dest->offset <= insn->offset || in find_jump_table()
1907 insn->jump_dest->offset > orig_insn->offset)) in find_jump_table()
1910 table_reloc = arch_find_switch_table(file, insn); in find_jump_table()
1930 struct instruction *insn, *last = NULL; in mark_func_jump_tables() local
1933 func_for_each_insn(file, func, insn) { in mark_func_jump_tables()
1935 last = insn; in mark_func_jump_tables()
1942 if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest && in mark_func_jump_tables()
1943 insn->offset > last->offset && in mark_func_jump_tables()
1944 insn->jump_dest->offset > insn->offset && in mark_func_jump_tables()
1945 !insn->jump_dest->first_jump_src) { in mark_func_jump_tables()
1947 insn->jump_dest->first_jump_src = insn; in mark_func_jump_tables()
1948 last = insn->jump_dest; in mark_func_jump_tables()
1951 if (insn->type != INSN_JUMP_DYNAMIC) in mark_func_jump_tables()
1954 reloc = find_jump_table(file, func, insn); in mark_func_jump_tables()
1957 insn->jump_table = reloc; in mark_func_jump_tables()
1965 struct instruction *insn; in add_func_jump_tables() local
1968 func_for_each_insn(file, func, insn) { in add_func_jump_tables()
1969 if (!insn->jump_table) in add_func_jump_tables()
1972 ret = add_jump_table(file, insn, insn->jump_table); in add_func_jump_tables()
2022 struct instruction *insn; in read_unwind_hints() local
2052 insn = find_insn(file, reloc->sym->sec, reloc->addend); in read_unwind_hints()
2053 if (!insn) { in read_unwind_hints()
2058 insn->hint = true; in read_unwind_hints()
2061 insn->hint = false; in read_unwind_hints()
2062 insn->save = true; in read_unwind_hints()
2067 insn->restore = true; in read_unwind_hints()
2072 struct symbol *sym = find_symbol_by_offset(insn->sec, insn->offset); in read_unwind_hints()
2075 if (opts.ibt && insn->type != INSN_ENDBR && !insn->noendbr) { in read_unwind_hints()
2077 insn->sec, insn->offset); in read_unwind_hints()
2080 insn->entry = 1; in read_unwind_hints()
2086 insn->entry = 1; in read_unwind_hints()
2090 insn->cfi = &func_cfi; in read_unwind_hints()
2094 if (insn->cfi) in read_unwind_hints()
2095 cfi = *(insn->cfi); in read_unwind_hints()
2099 insn->sec, insn->offset, hint->sp_reg); in read_unwind_hints()
2107 insn->cfi = cfi_hash_find_or_add(&cfi); in read_unwind_hints()
2116 struct instruction *insn; in read_noendbr_hints() local
2124 insn = find_insn(file, reloc->sym->sec, reloc->sym->offset + reloc->addend); in read_noendbr_hints()
2125 if (!insn) { in read_noendbr_hints()
2130 insn->noendbr = 1; in read_noendbr_hints()
2139 struct instruction *insn; in read_retpoline_hints() local
2152 insn = find_insn(file, reloc->sym->sec, reloc->addend); in read_retpoline_hints()
2153 if (!insn) { in read_retpoline_hints()
2158 if (insn->type != INSN_JUMP_DYNAMIC && in read_retpoline_hints()
2159 insn->type != INSN_CALL_DYNAMIC && in read_retpoline_hints()
2160 insn->type != INSN_RETURN && in read_retpoline_hints()
2161 insn->type != INSN_NOP) { in read_retpoline_hints()
2163 insn->sec, insn->offset); in read_retpoline_hints()
2167 insn->retpoline_safe = true; in read_retpoline_hints()
2176 struct instruction *insn; in read_instr_hints() local
2189 insn = find_insn(file, reloc->sym->sec, reloc->addend); in read_instr_hints()
2190 if (!insn) { in read_instr_hints()
2195 insn->instr--; in read_instr_hints()
2208 insn = find_insn(file, reloc->sym->sec, reloc->addend); in read_instr_hints()
2209 if (!insn) { in read_instr_hints()
2214 insn->instr++; in read_instr_hints()
2222 struct instruction *insn; in read_intra_function_calls() local
2239 insn = find_insn(file, reloc->sym->sec, reloc->addend); in read_intra_function_calls()
2240 if (!insn) { in read_intra_function_calls()
2245 if (insn->type != INSN_CALL) { in read_intra_function_calls()
2247 insn->sec, insn->offset); in read_intra_function_calls()
2256 insn->type = INSN_JUMP_UNCONDITIONAL; in read_intra_function_calls()
2258 dest_off = arch_jump_destination(insn); in read_intra_function_calls()
2259 insn->jump_dest = find_insn(file, insn->sec, dest_off); in read_intra_function_calls()
2260 if (!insn->jump_dest) { in read_intra_function_calls()
2262 insn->sec, insn->offset, in read_intra_function_calls()
2263 insn->sec->name, dest_off); in read_intra_function_calls()
2439 static bool is_fentry_call(struct instruction *insn) in is_fentry_call() argument
2441 if (insn->type == INSN_CALL && in is_fentry_call()
2442 insn->call_dest && in is_fentry_call()
2443 insn->call_dest->fentry) in is_fentry_call()
2449 static bool has_modified_stack_frame(struct instruction *insn, struct insn_state *state) in has_modified_stack_frame() argument
2494 static int update_cfi_state_regs(struct instruction *insn, in update_cfi_state_regs() argument
2587 static int update_cfi_state(struct instruction *insn, in update_cfi_state() argument
2596 if (insn->func) { in update_cfi_state()
2597 WARN_FUNC("undefined stack state", insn->sec, insn->offset); in update_cfi_state()
2605 return update_cfi_state_regs(insn, cfi, op); in update_cfi_state()
2792 insn->sec, insn->offset); in update_cfi_state()
2803 insn->sec, insn->offset); in update_cfi_state()
2899 insn->sec, insn->offset); in update_cfi_state()
2942 if (opts.stackval && insn->func && op->src.reg == CFI_BP && in update_cfi_state()
2989 insn->sec, insn->offset); in update_cfi_state()
3002 insn->sec, insn->offset); in update_cfi_state()
3018 static int propagate_alt_cfi(struct objtool_file *file, struct instruction *insn) in propagate_alt_cfi() argument
3023 if (!insn->alt_group) in propagate_alt_cfi()
3026 if (!insn->cfi) { in propagate_alt_cfi()
3031 alt_cfi = insn->alt_group->cfi; in propagate_alt_cfi()
3032 group_off = insn->offset - insn->alt_group->first_insn->offset; in propagate_alt_cfi()
3035 alt_cfi[group_off] = insn->cfi; in propagate_alt_cfi()
3037 if (cficmp(alt_cfi[group_off], insn->cfi)) { in propagate_alt_cfi()
3039 insn->sec, insn->offset); in propagate_alt_cfi()
3047 static int handle_insn_ops(struct instruction *insn, in handle_insn_ops() argument
3053 list_for_each_entry(op, &insn->stack_ops, list) { in handle_insn_ops()
3055 if (update_cfi_state(insn, next_insn, &state->cfi, op)) in handle_insn_ops()
3058 if (!insn->alt_group) in handle_insn_ops()
3066 insn->sec, insn->offset); in handle_insn_ops()
3086 static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2) in insn_cfi_match() argument
3088 struct cfi_state *cfi1 = insn->cfi; in insn_cfi_match()
3099 insn->sec, insn->offset, in insn_cfi_match()
3110 insn->sec, insn->offset, in insn_cfi_match()
3119 insn->sec, insn->offset, cfi1->type, cfi2->type); in insn_cfi_match()
3126 insn->sec, insn->offset, in insn_cfi_match()
3144 static inline const char *call_dest_name(struct instruction *insn) in call_dest_name() argument
3150 if (insn->call_dest) in call_dest_name()
3151 return insn->call_dest->name; in call_dest_name()
3153 rel = insn_reloc(NULL, insn); in call_dest_name()
3163 static bool pv_call_dest(struct objtool_file *file, struct instruction *insn) in pv_call_dest() argument
3169 rel = insn_reloc(file, insn); in pv_call_dest()
3191 struct instruction *insn, in noinstr_call_dest() argument
3200 return pv_call_dest(file, insn); in noinstr_call_dest()
3223 struct instruction *insn, in validate_call() argument
3227 !noinstr_call_dest(file, insn, insn->call_dest)) { in validate_call()
3229 insn->sec, insn->offset, call_dest_name(insn)); in validate_call()
3233 if (state->uaccess && !func_uaccess_safe(insn->call_dest)) { in validate_call()
3235 insn->sec, insn->offset, call_dest_name(insn)); in validate_call()
3241 insn->sec, insn->offset, call_dest_name(insn)); in validate_call()
3249 struct instruction *insn, in validate_sibling_call() argument
3252 if (has_modified_stack_frame(insn, state)) { in validate_sibling_call()
3254 insn->sec, insn->offset); in validate_sibling_call()
3258 return validate_call(file, insn, state); in validate_sibling_call()
3261 static int validate_return(struct symbol *func, struct instruction *insn, struct insn_state *state) in validate_return() argument
3265 insn->sec, insn->offset); in validate_return()
3271 insn->sec, insn->offset); in validate_return()
3277 insn->sec, insn->offset); in validate_return()
3283 insn->sec, insn->offset); in validate_return()
3287 if (func && has_modified_stack_frame(insn, state)) { in validate_return()
3289 insn->sec, insn->offset); in validate_return()
3295 insn->sec, insn->offset); in validate_return()
3303 struct instruction *insn) in next_insn_to_validate() argument
3305 struct alt_group *alt_group = insn->alt_group; in next_insn_to_validate()
3312 if (alt_group && insn == alt_group->last_insn && alt_group->orig_group) in next_insn_to_validate()
3315 return next_insn_same_sec(file, insn); in next_insn_to_validate()
3325 struct instruction *insn, struct insn_state state) in validate_branch() argument
3333 sec = insn->sec; in validate_branch()
3336 next_insn = next_insn_to_validate(file, insn); in validate_branch()
3338 if (func && insn->func && func != insn->func->pfunc) { in validate_branch()
3344 func->name, insn->func->name); in validate_branch()
3348 if (func && insn->ignore) { in validate_branch()
3350 sec, insn->offset); in validate_branch()
3355 if (insn->visited & VISITED_BRANCH_MASK) { in validate_branch()
3356 if (!insn->hint && !insn_cfi_match(insn, &state.cfi)) in validate_branch()
3359 if (insn->visited & visited) in validate_branch()
3366 state.instr += insn->instr; in validate_branch()
3368 if (insn->hint) { in validate_branch()
3369 if (insn->restore) { in validate_branch()
3372 i = insn; in validate_branch()
3384 sec, insn->offset); in validate_branch()
3390 sec, insn->offset); in validate_branch()
3394 insn->cfi = save_insn->cfi; in validate_branch()
3398 state.cfi = *insn->cfi; in validate_branch()
3403 insn->cfi = prev_insn->cfi; in validate_branch()
3406 insn->cfi = cfi_hash_find_or_add(&state.cfi); in validate_branch()
3410 insn->visited |= visited; in validate_branch()
3412 if (propagate_alt_cfi(file, insn)) in validate_branch()
3415 if (!insn->ignore_alts && !list_empty(&insn->alts)) { in validate_branch()
3418 list_for_each_entry(alt, &insn->alts, list) { in validate_branch()
3422 ret = validate_branch(file, func, alt->insn, state); in validate_branch()
3425 BT_FUNC("(alt)", insn); in validate_branch()
3434 if (handle_insn_ops(insn, next_insn, &state)) in validate_branch()
3437 switch (insn->type) { in validate_branch()
3440 return validate_return(func, insn, &state); in validate_branch()
3444 ret = validate_call(file, insn, &state); in validate_branch()
3448 if (opts.stackval && func && !is_fentry_call(insn) && in validate_branch()
3451 sec, insn->offset); in validate_branch()
3455 if (insn->dead_end) in validate_branch()
3462 if (is_sibling_call(insn)) { in validate_branch()
3463 ret = validate_sibling_call(file, insn, &state); in validate_branch()
3467 } else if (insn->jump_dest) { in validate_branch()
3469 insn->jump_dest, state); in validate_branch()
3472 BT_FUNC("(branch)", insn); in validate_branch()
3477 if (insn->type == INSN_JUMP_UNCONDITIONAL) in validate_branch()
3484 if (is_sibling_call(insn)) { in validate_branch()
3485 ret = validate_sibling_call(file, insn, &state); in validate_branch()
3490 if (insn->type == INSN_JUMP_DYNAMIC) in validate_branch()
3498 sec, insn->offset); in validate_branch()
3505 WARN_FUNC("recursive UACCESS enable", sec, insn->offset); in validate_branch()
3514 WARN_FUNC("redundant UACCESS disable", sec, insn->offset); in validate_branch()
3519 WARN_FUNC("UACCESS-safe disables UACCESS", sec, insn->offset); in validate_branch()
3528 WARN_FUNC("recursive STD", sec, insn->offset); in validate_branch()
3537 WARN_FUNC("redundant CLD", sec, insn->offset); in validate_branch()
3548 if (insn->dead_end) in validate_branch()
3558 prev_insn = insn; in validate_branch()
3559 insn = next_insn; in validate_branch()
3567 struct instruction *insn; in validate_unwind_hints() local
3577 insn = find_insn(file, sec, 0); in validate_unwind_hints()
3578 if (!insn) in validate_unwind_hints()
3581 insn = list_first_entry(&file->insn_list, typeof(*insn), list); in validate_unwind_hints()
3584 while (&insn->list != &file->insn_list && (!sec || insn->sec == sec)) { in validate_unwind_hints()
3585 if (insn->hint && !insn->visited && !insn->ignore) { in validate_unwind_hints()
3586 ret = validate_branch(file, insn->func, insn, state); in validate_unwind_hints()
3588 BT_FUNC("<=== (hint)", insn); in validate_unwind_hints()
3592 insn = list_next_entry(insn, list); in validate_unwind_hints()
3604 static int validate_entry(struct objtool_file *file, struct instruction *insn) in validate_entry() argument
3610 next = next_insn_to_validate(file, insn); in validate_entry()
3612 if (insn->visited & VISITED_ENTRY) in validate_entry()
3615 insn->visited |= VISITED_ENTRY; in validate_entry()
3617 if (!insn->ignore_alts && !list_empty(&insn->alts)) { in validate_entry()
3621 list_for_each_entry(alt, &insn->alts, list) { in validate_entry()
3625 ret = validate_entry(file, alt->insn); in validate_entry()
3628 BT_FUNC("(alt)", insn); in validate_entry()
3637 switch (insn->type) { in validate_entry()
3642 WARN_FUNC("early indirect call", insn->sec, insn->offset); in validate_entry()
3647 if (!is_sibling_call(insn)) { in validate_entry()
3648 if (!insn->jump_dest) { in validate_entry()
3650 insn->sec, insn->offset); in validate_entry()
3653 ret = validate_entry(file, insn->jump_dest); in validate_entry()
3656 BT_FUNC("(branch%s)", insn, in validate_entry()
3657 insn->type == INSN_JUMP_CONDITIONAL ? "-cond" : ""); in validate_entry()
3662 if (insn->type == INSN_JUMP_UNCONDITIONAL) in validate_entry()
3670 dest = find_insn(file, insn->call_dest->sec, in validate_entry()
3671 insn->call_dest->offset); in validate_entry()
3674 insn->call_dest->name); in validate_entry()
3681 BT_FUNC("(call)", insn); in validate_entry()
3691 WARN_FUNC("RET before UNTRAIN", insn->sec, insn->offset); in validate_entry()
3695 if (insn->retpoline_safe) in validate_entry()
3704 WARN_FUNC("teh end!", insn->sec, insn->offset); in validate_entry()
3707 insn = next; in validate_entry()
3719 struct instruction *insn; in validate_unret() local
3722 for_each_insn(file, insn) { in validate_unret()
3723 if (!insn->entry) in validate_unret()
3726 ret = validate_entry(file, insn); in validate_unret()
3728 WARN_FUNC("Failed UNRET validation", insn->sec, insn->offset); in validate_unret()
3739 struct instruction *insn; in validate_retpoline() local
3742 for_each_insn(file, insn) { in validate_retpoline()
3743 if (insn->type != INSN_JUMP_DYNAMIC && in validate_retpoline()
3744 insn->type != INSN_CALL_DYNAMIC && in validate_retpoline()
3745 insn->type != INSN_RETURN) in validate_retpoline()
3748 if (insn->retpoline_safe) in validate_retpoline()
3757 if (!strcmp(insn->sec->name, ".init.text") && !opts.module) in validate_retpoline()
3760 if (insn->type == INSN_RETURN) { in validate_retpoline()
3763 insn->sec, insn->offset); in validate_retpoline()
3768 insn->sec, insn->offset, in validate_retpoline()
3769 insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); in validate_retpoline()
3778 static bool is_kasan_insn(struct instruction *insn) in is_kasan_insn() argument
3780 return (insn->type == INSN_CALL && in is_kasan_insn()
3781 !strcmp(insn->call_dest->name, "__asan_handle_no_return")); in is_kasan_insn()
3784 static bool is_ubsan_insn(struct instruction *insn) in is_ubsan_insn() argument
3786 return (insn->type == INSN_CALL && in is_ubsan_insn()
3787 !strcmp(insn->call_dest->name, in is_ubsan_insn()
3791 static bool ignore_unreachable_insn(struct objtool_file *file, struct instruction *insn) in ignore_unreachable_insn() argument
3796 if (insn->ignore || insn->type == INSN_NOP || insn->type == INSN_TRAP) in ignore_unreachable_insn()
3803 if (!strcmp(insn->sec->name, ".altinstr_replacement") || in ignore_unreachable_insn()
3804 !strcmp(insn->sec->name, ".altinstr_aux")) in ignore_unreachable_insn()
3815 if (opts.link && !insn->func) { in ignore_unreachable_insn()
3816 int size = find_symbol_hole_containing(insn->sec, insn->offset); in ignore_unreachable_insn()
3817 unsigned long end = insn->offset + size; in ignore_unreachable_insn()
3825 sec_for_each_insn_continue(file, insn) { in ignore_unreachable_insn()
3830 if (insn->visited) in ignore_unreachable_insn()
3833 if (insn->offset >= end) in ignore_unreachable_insn()
3839 if (insn->jump_dest && insn->jump_dest->func && in ignore_unreachable_insn()
3840 strstr(insn->jump_dest->func->name, ".cold")) { in ignore_unreachable_insn()
3841 struct instruction *dest = insn->jump_dest; in ignore_unreachable_insn()
3850 if (!insn->func) in ignore_unreachable_insn()
3853 if (insn->func->static_call_tramp) in ignore_unreachable_insn()
3864 prev_insn = list_prev_entry(insn, list); in ignore_unreachable_insn()
3866 (insn->type == INSN_BUG || in ignore_unreachable_insn()
3867 (insn->type == INSN_JUMP_UNCONDITIONAL && in ignore_unreachable_insn()
3868 insn->jump_dest && insn->jump_dest->type == INSN_BUG))) in ignore_unreachable_insn()
3879 if (is_kasan_insn(insn) || is_ubsan_insn(insn)) in ignore_unreachable_insn()
3882 if (insn->type == INSN_JUMP_UNCONDITIONAL) { in ignore_unreachable_insn()
3883 if (insn->jump_dest && in ignore_unreachable_insn()
3884 insn->jump_dest->func == insn->func) { in ignore_unreachable_insn()
3885 insn = insn->jump_dest; in ignore_unreachable_insn()
3892 if (insn->offset + insn->len >= insn->func->offset + insn->func->len) in ignore_unreachable_insn()
3895 insn = list_next_entry(insn, list); in ignore_unreachable_insn()
3904 struct instruction *insn; in validate_symbol() local
3915 insn = find_insn(file, sec, sym->offset); in validate_symbol()
3916 if (!insn || insn->ignore || insn->visited) in validate_symbol()
3921 ret = validate_branch(file, insn->func, insn, *state); in validate_symbol()
3923 BT_FUNC("<=== (sym)", insn); in validate_symbol()
3981 static void mark_endbr_used(struct instruction *insn) in mark_endbr_used() argument
3983 if (!list_empty(&insn->call_node)) in mark_endbr_used()
3984 list_del_init(&insn->call_node); in mark_endbr_used()
3987 static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn) in validate_ibt_insn() argument
3998 switch (insn->type) { in validate_ibt_insn()
4012 for (reloc = insn_reloc(file, insn); in validate_ibt_insn()
4014 reloc = find_reloc_by_dest_range(file->elf, insn->sec, in validate_ibt_insn()
4016 (insn->offset + insn->len) - (reloc->offset + 1))) { in validate_ibt_insn()
4040 if (dest->func && dest->func == insn->func) { in validate_ibt_insn()
4063 insn->sec, insn->offset, in validate_ibt_insn()
4106 struct instruction *insn; in validate_ibt() local
4109 for_each_insn(file, insn) in validate_ibt()
4110 warnings += validate_ibt_insn(file, insn); in validate_ibt()
4154 struct instruction *insn, *next_insn; in validate_sls() local
4157 for_each_insn(file, insn) { in validate_sls()
4158 next_insn = next_insn_same_sec(file, insn); in validate_sls()
4160 if (insn->retpoline_safe) in validate_sls()
4163 switch (insn->type) { in validate_sls()
4167 insn->sec, insn->offset); in validate_sls()
4175 insn->sec, insn->offset); in validate_sls()
4189 struct instruction *insn; in validate_reachable_instructions() local
4194 for_each_insn(file, insn) { in validate_reachable_instructions()
4195 if (insn->visited || ignore_unreachable_insn(file, insn)) in validate_reachable_instructions()
4198 WARN_FUNC("unreachable instruction", insn->sec, insn->offset); in validate_reachable_instructions()