Lines Matching refs:insn
27 struct instruction *insn; member
41 struct instruction *insn; in find_insn() local
43 hash_for_each_possible(file->insn_hash, insn, hash, sec_offset_hash(sec, offset)) { in find_insn()
44 if (insn->sec == sec && insn->offset == offset) in find_insn()
45 return insn; in find_insn()
52 struct instruction *insn) in next_insn_same_sec() argument
54 if (insn->idx == INSN_CHUNK_MAX) in next_insn_same_sec()
55 return find_insn(file, insn->sec, insn->offset + insn->len); in next_insn_same_sec()
57 insn++; in next_insn_same_sec()
58 if (!insn->len) in next_insn_same_sec()
61 return insn; in next_insn_same_sec()
65 struct instruction *insn) in next_insn_same_func() argument
67 struct instruction *next = next_insn_same_sec(file, insn); in next_insn_same_func()
68 struct symbol *func = insn_func(insn); in next_insn_same_func()
85 struct instruction *insn) in prev_insn_same_sec() argument
87 if (insn->idx == 0) { in prev_insn_same_sec()
88 if (insn->prev_len) in prev_insn_same_sec()
89 return find_insn(file, insn->sec, insn->offset - insn->prev_len); in prev_insn_same_sec()
93 return insn - 1; in prev_insn_same_sec()
97 struct instruction *insn) in prev_insn_same_sym() argument
99 struct instruction *prev = prev_insn_same_sec(file, insn); in prev_insn_same_sym()
101 if (prev && insn_func(prev) == insn_func(insn)) in prev_insn_same_sym()
107 #define for_each_insn(file, insn) \ argument
111 sec_for_each_insn(file, __sec, insn)
113 #define func_for_each_insn(file, func, insn) \ argument
114 for (insn = find_insn(file, func->sec, func->offset); \
115 insn; \
116 insn = next_insn_same_func(file, insn))
118 #define sym_for_each_insn(file, sym, insn) \ argument
119 for (insn = find_insn(file, sym->sec, sym->offset); \
120 insn && insn->offset < sym->offset + sym->len; \
121 insn = next_insn_same_sec(file, insn))
123 #define sym_for_each_insn_continue_reverse(file, sym, insn) \ argument
124 for (insn = prev_insn_same_sec(file, insn); \
125 insn && insn->offset >= sym->offset; \
126 insn = prev_insn_same_sec(file, insn))
128 #define sec_for_each_insn_from(file, insn) \ argument
129 for (; insn; insn = next_insn_same_sec(file, insn))
131 #define sec_for_each_insn_continue(file, insn) \ argument
132 for (insn = next_insn_same_sec(file, insn); insn; \
133 insn = next_insn_same_sec(file, insn))
135 static inline struct symbol *insn_call_dest(struct instruction *insn) in insn_call_dest() argument
137 if (insn->type == INSN_JUMP_DYNAMIC || in insn_call_dest()
138 insn->type == INSN_CALL_DYNAMIC) in insn_call_dest()
141 return insn->_call_dest; in insn_call_dest()
144 static inline struct reloc *insn_jump_table(struct instruction *insn) in insn_jump_table() argument
146 if (insn->type == INSN_JUMP_DYNAMIC || in insn_jump_table()
147 insn->type == INSN_CALL_DYNAMIC) in insn_jump_table()
148 return insn->_jump_table; in insn_jump_table()
153 static bool is_jump_table_jump(struct instruction *insn) in is_jump_table_jump() argument
155 struct alt_group *alt_group = insn->alt_group; in is_jump_table_jump()
157 if (insn_jump_table(insn)) in is_jump_table_jump()
165 static bool is_sibling_call(struct instruction *insn) in is_sibling_call() argument
170 if (insn_func(insn)) { in is_sibling_call()
172 if (insn->type == INSN_JUMP_DYNAMIC) in is_sibling_call()
173 return !is_jump_table_jump(insn); in is_sibling_call()
177 return (is_static_jump(insn) && insn_call_dest(insn)); in is_sibling_call()
239 struct instruction *insn; in __dead_end_function() local
266 insn = find_insn(file, func->sec, func->offset); in __dead_end_function()
267 if (!insn || !insn_func(insn)) in __dead_end_function()
270 func_for_each_insn(file, func, insn) { in __dead_end_function()
273 if (insn->type == INSN_RETURN) in __dead_end_function()
285 func_for_each_insn(file, func, insn) { in __dead_end_function()
286 if (is_sibling_call(insn)) { in __dead_end_function()
287 struct instruction *dest = insn->jump_dest; in __dead_end_function()
424 struct instruction *insn; in decode_instructions() local
455 for (offset = 0; offset < sec->sh.sh_size; offset += insn->len) { in decode_instructions()
457 insns = calloc(sizeof(*insn), INSN_CHUNK_SIZE); in decode_instructions()
466 insn = &insns[idx]; in decode_instructions()
467 insn->idx = idx; in decode_instructions()
469 INIT_LIST_HEAD(&insn->call_node); in decode_instructions()
470 insn->sec = sec; in decode_instructions()
471 insn->offset = offset; in decode_instructions()
472 insn->prev_len = prev_len; in decode_instructions()
476 insn); in decode_instructions()
480 prev_len = insn->len; in decode_instructions()
487 if (insn->type == INSN_BUG) in decode_instructions()
488 insn->dead_end = true; in decode_instructions()
490 hash_add(file->insn_hash, &insn->hash, sec_offset_hash(sec, insn->offset)); in decode_instructions()
518 sym_for_each_insn(file, func, insn) { in decode_instructions()
519 insn->sym = func; in decode_instructions()
521 insn->type == INSN_ENDBR && in decode_instructions()
522 list_empty(&insn->call_node)) { in decode_instructions()
523 if (insn->offset == func->offset) { in decode_instructions()
524 list_add_tail(&insn->call_node, &file->endbr_list); in decode_instructions()
620 struct instruction *insn = NULL; in find_last_insn() local
624 for (offset = sec->sh.sh_size - 1; offset >= end && !insn; offset--) in find_last_insn()
625 insn = find_insn(file, sec, offset); in find_last_insn()
627 return insn; in find_last_insn()
637 struct instruction *insn; in add_dead_ends() local
657 insn = find_insn(file, reloc->sym->sec, offset); in add_dead_ends()
658 if (insn) in add_dead_ends()
659 insn = prev_insn_same_sec(file, insn); in add_dead_ends()
661 insn = find_last_insn(file, reloc->sym->sec); in add_dead_ends()
662 if (!insn) { in add_dead_ends()
673 insn->dead_end = true; in add_dead_ends()
697 insn = find_insn(file, reloc->sym->sec, offset); in add_dead_ends()
698 if (insn) in add_dead_ends()
699 insn = prev_insn_same_sec(file, insn); in add_dead_ends()
701 insn = find_last_insn(file, reloc->sym->sec); in add_dead_ends()
702 if (!insn) { in add_dead_ends()
713 insn->dead_end = false; in add_dead_ends()
723 struct instruction *insn; in create_static_call_sections() local
739 list_for_each_entry(insn, &file->static_call_list, call_node) in create_static_call_sections()
751 list_for_each_entry(insn, &file->static_call_list, call_node) { in create_static_call_sections()
756 insn->sec, insn->offset)) in create_static_call_sections()
760 key_name = strdup(insn_call_dest(insn)->name); in create_static_call_sections()
791 key_sym = insn_call_dest(insn); in create_static_call_sections()
799 is_sibling_call(insn) * STATIC_CALL_SITE_TAIL)) in create_static_call_sections()
810 struct instruction *insn; in create_retpoline_sites_sections() local
821 list_for_each_entry(insn, &file->retpoline_call_list, call_node) in create_retpoline_sites_sections()
833 list_for_each_entry(insn, &file->retpoline_call_list, call_node) { in create_retpoline_sites_sections()
837 insn->sec, insn->offset)) in create_retpoline_sites_sections()
848 struct instruction *insn; in create_return_sites_sections() local
859 list_for_each_entry(insn, &file->return_thunk_list, call_node) in create_return_sites_sections()
871 list_for_each_entry(insn, &file->return_thunk_list, call_node) { in create_return_sites_sections()
875 insn->sec, insn->offset)) in create_return_sites_sections()
886 struct instruction *insn; in create_ibt_endbr_seal_sections() local
897 list_for_each_entry(insn, &file->endbr_list, call_node) in create_ibt_endbr_seal_sections()
915 list_for_each_entry(insn, &file->endbr_list, call_node) { in create_ibt_endbr_seal_sections()
918 struct symbol *sym = insn->sym; in create_ibt_endbr_seal_sections()
922 insn->offset == sym->offset && in create_ibt_endbr_seal_sections()
929 insn->sec, insn->offset)) in create_ibt_endbr_seal_sections()
989 struct instruction *insn; in create_mcount_loc_sections() local
1004 list_for_each_entry(insn, &file->mcount_loc_list, call_node) in create_mcount_loc_sections()
1015 list_for_each_entry(insn, &file->mcount_loc_list, call_node) { in create_mcount_loc_sections()
1020 insn->sec, insn->offset); in create_mcount_loc_sections()
1034 struct instruction *insn; in create_direct_call_sections() local
1049 list_for_each_entry(insn, &file->call_list, call_node) in create_direct_call_sections()
1058 list_for_each_entry(insn, &file->call_list, call_node) { in create_direct_call_sections()
1062 insn->sec, insn->offset)) in create_direct_call_sections()
1076 struct instruction *insn; in add_ignores() local
1103 func_for_each_insn(file, func, insn) in add_ignores()
1104 insn->ignore = true; in add_ignores()
1322 struct instruction *insn; in add_ignore_alternatives() local
1334 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in add_ignore_alternatives()
1335 if (!insn) { in add_ignore_alternatives()
1340 insn->ignore_alts = true; in add_ignore_alternatives()
1373 static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn) in insn_reloc() argument
1377 if (insn->no_reloc) in insn_reloc()
1383 reloc = find_reloc_by_dest_range(file->elf, insn->sec, in insn_reloc()
1384 insn->offset, insn->len); in insn_reloc()
1386 insn->no_reloc = 1; in insn_reloc()
1393 static void remove_insn_ops(struct instruction *insn) in remove_insn_ops() argument
1397 for (op = insn->stack_ops; op; op = next) { in remove_insn_ops()
1401 insn->stack_ops = NULL; in remove_insn_ops()
1405 struct instruction *insn, bool sibling) in annotate_call_site() argument
1407 struct reloc *reloc = insn_reloc(file, insn); in annotate_call_site()
1408 struct symbol *sym = insn_call_dest(insn); in annotate_call_site()
1419 if (!strcmp(insn->sec->name, ".altinstr_replacement")) in annotate_call_site()
1423 list_add_tail(&insn->call_node, &file->static_call_list); in annotate_call_site()
1428 list_add_tail(&insn->call_node, &file->retpoline_call_list); in annotate_call_site()
1437 if (opts.hack_noinstr && insn->sec->noinstr && sym->profiling_func) { in annotate_call_site()
1441 elf_write_insn(file->elf, insn->sec, in annotate_call_site()
1442 insn->offset, insn->len, in annotate_call_site()
1443 sibling ? arch_ret_insn(insn->len) in annotate_call_site()
1444 : arch_nop_insn(insn->len)); in annotate_call_site()
1446 insn->type = sibling ? INSN_RETURN : INSN_NOP; in annotate_call_site()
1455 insn->retpoline_safe = true; in annotate_call_site()
1463 WARN_INSN(insn, "tail call to __fentry__ !?!?"); in annotate_call_site()
1468 elf_write_insn(file->elf, insn->sec, in annotate_call_site()
1469 insn->offset, insn->len, in annotate_call_site()
1470 arch_nop_insn(insn->len)); in annotate_call_site()
1472 insn->type = INSN_NOP; in annotate_call_site()
1475 list_add_tail(&insn->call_node, &file->mcount_loc_list); in annotate_call_site()
1479 if (insn->type == INSN_CALL && !insn->sec->init) in annotate_call_site()
1480 list_add_tail(&insn->call_node, &file->call_list); in annotate_call_site()
1483 insn->dead_end = true; in annotate_call_site()
1486 static void add_call_dest(struct objtool_file *file, struct instruction *insn, in add_call_dest() argument
1489 insn->_call_dest = dest; in add_call_dest()
1500 remove_insn_ops(insn); in add_call_dest()
1502 annotate_call_site(file, insn, sibling); in add_call_dest()
1505 static void add_retpoline_call(struct objtool_file *file, struct instruction *insn) in add_retpoline_call() argument
1511 switch (insn->type) { in add_retpoline_call()
1513 insn->type = INSN_CALL_DYNAMIC; in add_retpoline_call()
1516 insn->type = INSN_JUMP_DYNAMIC; in add_retpoline_call()
1519 insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL; in add_retpoline_call()
1525 insn->retpoline_safe = true; in add_retpoline_call()
1534 remove_insn_ops(insn); in add_retpoline_call()
1536 annotate_call_site(file, insn, false); in add_retpoline_call()
1539 static void add_return_call(struct objtool_file *file, struct instruction *insn, bool add) in add_return_call() argument
1545 insn->type = INSN_RETURN; in add_return_call()
1546 insn->retpoline_safe = true; in add_return_call()
1549 list_add_tail(&insn->call_node, &file->return_thunk_list); in add_return_call()
1553 struct instruction *insn, struct symbol *sym) in is_first_func_insn() argument
1555 if (insn->offset == sym->offset) in is_first_func_insn()
1560 struct instruction *prev = prev_insn_same_sym(file, insn); in is_first_func_insn()
1563 insn->offset == sym->offset + prev->len) in is_first_func_insn()
1601 struct instruction *insn, *jump_dest; in add_jump_destinations() local
1606 for_each_insn(file, insn) { in add_jump_destinations()
1607 if (insn->jump_dest) { in add_jump_destinations()
1614 if (!is_static_jump(insn)) in add_jump_destinations()
1617 reloc = insn_reloc(file, insn); in add_jump_destinations()
1619 dest_sec = insn->sec; in add_jump_destinations()
1620 dest_off = arch_jump_destination(insn); in add_jump_destinations()
1625 add_retpoline_call(file, insn); in add_jump_destinations()
1628 add_return_call(file, insn, true); in add_jump_destinations()
1630 } else if (insn_func(insn)) { in add_jump_destinations()
1635 add_call_dest(file, insn, reloc->sym, true); in add_jump_destinations()
1659 add_return_call(file, insn, false); in add_jump_destinations()
1663 WARN_INSN(insn, "can't find jump dest instruction at %s+0x%lx", in add_jump_destinations()
1675 add_retpoline_call(file, insn); in add_jump_destinations()
1679 add_return_call(file, insn, true); in add_jump_destinations()
1687 if (insn_func(insn) && insn_func(jump_dest) && in add_jump_destinations()
1688 insn_func(insn) != insn_func(jump_dest)) { in add_jump_destinations()
1705 if (!strstr(insn_func(insn)->name, ".cold") && in add_jump_destinations()
1707 insn_func(insn)->cfunc = insn_func(jump_dest); in add_jump_destinations()
1708 insn_func(jump_dest)->pfunc = insn_func(insn); in add_jump_destinations()
1712 if (jump_is_sibling_call(file, insn, jump_dest)) { in add_jump_destinations()
1717 add_call_dest(file, insn, insn_func(jump_dest), true); in add_jump_destinations()
1721 insn->jump_dest = jump_dest; in add_jump_destinations()
1743 struct instruction *insn; in add_call_destinations() local
1748 for_each_insn(file, insn) { in add_call_destinations()
1749 if (insn->type != INSN_CALL) in add_call_destinations()
1752 reloc = insn_reloc(file, insn); in add_call_destinations()
1754 dest_off = arch_jump_destination(insn); in add_call_destinations()
1755 dest = find_call_destination(insn->sec, dest_off); in add_call_destinations()
1757 add_call_dest(file, insn, dest, false); in add_call_destinations()
1759 if (insn->ignore) in add_call_destinations()
1762 if (!insn_call_dest(insn)) { in add_call_destinations()
1763 WARN_INSN(insn, "unannotated intra-function call"); in add_call_destinations()
1767 if (insn_func(insn) && insn_call_dest(insn)->type != STT_FUNC) { in add_call_destinations()
1768 WARN_INSN(insn, "unsupported call to non-function"); in add_call_destinations()
1776 WARN_INSN(insn, "can't find call dest symbol at %s+0x%lx", in add_call_destinations()
1781 add_call_dest(file, insn, dest, false); in add_call_destinations()
1784 add_retpoline_call(file, insn); in add_call_destinations()
1787 add_call_dest(file, insn, reloc->sym, false); in add_call_destinations()
1802 struct instruction *last_new_insn = NULL, *insn, *nop = NULL; in handle_group_alt() local
1822 insn = orig_insn; in handle_group_alt()
1823 sec_for_each_insn_from(file, insn) { in handle_group_alt()
1824 if (insn->offset >= special_alt->orig_off + special_alt->orig_len) in handle_group_alt()
1827 insn->alt_group = orig_alt_group; in handle_group_alt()
1828 last_orig_insn = insn; in handle_group_alt()
1881 insn = *new_insn; in handle_group_alt()
1882 sec_for_each_insn_from(file, insn) { in handle_group_alt()
1885 if (insn->offset >= special_alt->new_off + special_alt->new_len) in handle_group_alt()
1888 last_new_insn = insn; in handle_group_alt()
1890 insn->ignore = orig_insn->ignore_alts; in handle_group_alt()
1891 insn->sym = orig_insn->sym; in handle_group_alt()
1892 insn->alt_group = new_alt_group; in handle_group_alt()
1902 alt_reloc = insn_reloc(file, insn); in handle_group_alt()
1904 !arch_support_alt_relocation(special_alt, insn, alt_reloc)) { in handle_group_alt()
1906 WARN_INSN(insn, "unsupported relocation in alternatives section"); in handle_group_alt()
1910 if (!is_static_jump(insn)) in handle_group_alt()
1913 if (!insn->immediate) in handle_group_alt()
1916 dest_off = arch_jump_destination(insn); in handle_group_alt()
1918 insn->jump_dest = next_insn_same_sec(file, orig_alt_group->last_insn); in handle_group_alt()
1919 if (!insn->jump_dest) { in handle_group_alt()
1920 WARN_INSN(insn, "can't find alternative jump destination"); in handle_group_alt()
2053 alt->insn = new_insn; in add_special_section_alts()
2073 static int add_jump_table(struct objtool_file *file, struct instruction *insn, in add_jump_table() argument
2076 struct symbol *pfunc = insn_func(insn)->pfunc; in add_jump_table()
2077 struct reloc *table = insn_jump_table(insn); in add_jump_table()
2116 alt->insn = dest_insn; in add_jump_table()
2117 alt->next = insn->alts; in add_jump_table()
2118 insn->alts = alt; in add_jump_table()
2123 WARN_INSN(insn, "can't find switch jump table"); in add_jump_table()
2136 struct instruction *insn) in find_jump_table() argument
2139 struct instruction *dest_insn, *orig_insn = insn; in find_jump_table()
2147 insn && insn_func(insn) && insn_func(insn)->pfunc == func; in find_jump_table()
2148 insn = insn->first_jump_src ?: prev_insn_same_sym(file, insn)) { in find_jump_table()
2150 if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC) in find_jump_table()
2154 if (insn->type == INSN_JUMP_UNCONDITIONAL && in find_jump_table()
2155 insn->jump_dest && in find_jump_table()
2156 (insn->jump_dest->offset <= insn->offset || in find_jump_table()
2157 insn->jump_dest->offset > orig_insn->offset)) in find_jump_table()
2160 table_reloc = arch_find_switch_table(file, insn); in find_jump_table()
2180 struct instruction *insn, *last = NULL; in mark_func_jump_tables() local
2183 func_for_each_insn(file, func, insn) { in mark_func_jump_tables()
2185 last = insn; in mark_func_jump_tables()
2192 if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest && in mark_func_jump_tables()
2193 insn->offset > last->offset && in mark_func_jump_tables()
2194 insn->jump_dest->offset > insn->offset && in mark_func_jump_tables()
2195 !insn->jump_dest->first_jump_src) { in mark_func_jump_tables()
2197 insn->jump_dest->first_jump_src = insn; in mark_func_jump_tables()
2198 last = insn->jump_dest; in mark_func_jump_tables()
2201 if (insn->type != INSN_JUMP_DYNAMIC) in mark_func_jump_tables()
2204 reloc = find_jump_table(file, func, insn); in mark_func_jump_tables()
2206 insn->_jump_table = reloc; in mark_func_jump_tables()
2213 struct instruction *insn, *insn_t1 = NULL, *insn_t2; in add_func_jump_tables() local
2216 func_for_each_insn(file, func, insn) { in add_func_jump_tables()
2217 if (!insn_jump_table(insn)) in add_func_jump_tables()
2221 insn_t1 = insn; in add_func_jump_tables()
2225 insn_t2 = insn; in add_func_jump_tables()
2280 struct instruction *insn; in read_unwind_hints() local
2319 insn = find_insn(file, reloc->sym->sec, offset); in read_unwind_hints()
2320 if (!insn) { in read_unwind_hints()
2325 insn->hint = true; in read_unwind_hints()
2328 insn->cfi = &force_undefined_cfi; in read_unwind_hints()
2333 insn->hint = false; in read_unwind_hints()
2334 insn->save = true; in read_unwind_hints()
2339 insn->restore = true; in read_unwind_hints()
2344 struct symbol *sym = find_symbol_by_offset(insn->sec, insn->offset); in read_unwind_hints()
2347 if (opts.ibt && insn->type != INSN_ENDBR && !insn->noendbr) { in read_unwind_hints()
2348 WARN_INSN(insn, "UNWIND_HINT_IRET_REGS without ENDBR"); in read_unwind_hints()
2354 insn->cfi = &func_cfi; in read_unwind_hints()
2358 if (insn->cfi) in read_unwind_hints()
2359 cfi = *(insn->cfi); in read_unwind_hints()
2362 WARN_INSN(insn, "unsupported unwind_hint sp base reg %d", hint->sp_reg); in read_unwind_hints()
2370 insn->cfi = cfi_hash_find_or_add(&cfi); in read_unwind_hints()
2378 struct instruction *insn; in read_noendbr_hints() local
2387 insn = find_insn(file, reloc->sym->sec, in read_noendbr_hints()
2389 if (!insn) { in read_noendbr_hints()
2394 insn->noendbr = 1; in read_noendbr_hints()
2403 struct instruction *insn; in read_retpoline_hints() local
2416 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_retpoline_hints()
2417 if (!insn) { in read_retpoline_hints()
2422 if (insn->type != INSN_JUMP_DYNAMIC && in read_retpoline_hints()
2423 insn->type != INSN_CALL_DYNAMIC && in read_retpoline_hints()
2424 insn->type != INSN_RETURN && in read_retpoline_hints()
2425 insn->type != INSN_NOP) { in read_retpoline_hints()
2426 WARN_INSN(insn, "retpoline_safe hint not an indirect jump/call/ret/nop"); in read_retpoline_hints()
2430 insn->retpoline_safe = true; in read_retpoline_hints()
2439 struct instruction *insn; in read_instr_hints() local
2452 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_instr_hints()
2453 if (!insn) { in read_instr_hints()
2458 insn->instr--; in read_instr_hints()
2471 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_instr_hints()
2472 if (!insn) { in read_instr_hints()
2477 insn->instr++; in read_instr_hints()
2486 struct instruction *insn; in read_validate_unret_hints() local
2499 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_validate_unret_hints()
2500 if (!insn) { in read_validate_unret_hints()
2504 insn->unret = 1; in read_validate_unret_hints()
2513 struct instruction *insn; in read_intra_function_calls() local
2530 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_intra_function_calls()
2531 if (!insn) { in read_intra_function_calls()
2536 if (insn->type != INSN_CALL) { in read_intra_function_calls()
2537 WARN_INSN(insn, "intra_function_call not a direct call"); in read_intra_function_calls()
2546 insn->type = INSN_JUMP_UNCONDITIONAL; in read_intra_function_calls()
2548 dest_off = arch_jump_destination(insn); in read_intra_function_calls()
2549 insn->jump_dest = find_insn(file, insn->sec, dest_off); in read_intra_function_calls()
2550 if (!insn->jump_dest) { in read_intra_function_calls()
2551 WARN_INSN(insn, "can't find call dest at %s+0x%lx", in read_intra_function_calls()
2552 insn->sec->name, dest_off); in read_intra_function_calls()
2737 static bool is_special_call(struct instruction *insn) in is_special_call() argument
2739 if (insn->type == INSN_CALL) { in is_special_call()
2740 struct symbol *dest = insn_call_dest(insn); in is_special_call()
2752 static bool has_modified_stack_frame(struct instruction *insn, struct insn_state *state) in has_modified_stack_frame() argument
2797 static int update_cfi_state_regs(struct instruction *insn, in update_cfi_state_regs() argument
2890 static int update_cfi_state(struct instruction *insn, in update_cfi_state() argument
2903 if (insn_func(insn)) { in update_cfi_state()
2904 WARN_INSN(insn, "undefined stack state"); in update_cfi_state()
2912 return update_cfi_state_regs(insn, cfi, op); in update_cfi_state()
3047 insn->sym->frame_pointer) { in update_cfi_state()
3059 if (insn->sym->frame_pointer) { in update_cfi_state()
3104 WARN_INSN(insn, "unsupported stack register modification"); in update_cfi_state()
3114 WARN_INSN(insn, "unsupported stack pointer realignment"); in update_cfi_state()
3209 WARN_INSN(insn, "unknown stack-related instruction"); in update_cfi_state()
3252 if (opts.stackval && insn_func(insn) && op->src.reg == CFI_BP && in update_cfi_state()
3298 WARN_INSN(insn, "unknown stack-related memory operation"); in update_cfi_state()
3310 WARN_INSN(insn, "unknown stack-related instruction"); in update_cfi_state()
3326 static int propagate_alt_cfi(struct objtool_file *file, struct instruction *insn) in propagate_alt_cfi() argument
3331 if (!insn->alt_group) in propagate_alt_cfi()
3334 if (!insn->cfi) { in propagate_alt_cfi()
3339 alt_cfi = insn->alt_group->cfi; in propagate_alt_cfi()
3340 group_off = insn->offset - insn->alt_group->first_insn->offset; in propagate_alt_cfi()
3343 alt_cfi[group_off] = insn->cfi; in propagate_alt_cfi()
3345 if (cficmp(alt_cfi[group_off], insn->cfi)) { in propagate_alt_cfi()
3346 struct alt_group *orig_group = insn->alt_group->orig_group ?: insn->alt_group; in propagate_alt_cfi()
3348 char *where = offstr(insn->sec, insn->offset); in propagate_alt_cfi()
3358 static int handle_insn_ops(struct instruction *insn, in handle_insn_ops() argument
3364 for (op = insn->stack_ops; op; op = op->next) { in handle_insn_ops()
3366 if (update_cfi_state(insn, next_insn, &state->cfi, op)) in handle_insn_ops()
3369 if (!insn->alt_group) in handle_insn_ops()
3376 WARN_INSN(insn, "PUSHF stack exhausted"); in handle_insn_ops()
3396 static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2) in insn_cfi_match() argument
3398 struct cfi_state *cfi1 = insn->cfi; in insn_cfi_match()
3408 WARN_INSN(insn, "stack state mismatch: cfa1=%d%+d cfa2=%d%+d", in insn_cfi_match()
3418 WARN_INSN(insn, "stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d", in insn_cfi_match()
3426 WARN_INSN(insn, "stack state mismatch: type1=%d type2=%d", in insn_cfi_match()
3433 WARN_INSN(insn, "stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)", in insn_cfi_match()
3451 static inline const char *call_dest_name(struct instruction *insn) in call_dest_name() argument
3457 if (insn_call_dest(insn)) in call_dest_name()
3458 return insn_call_dest(insn)->name; in call_dest_name()
3460 reloc = insn_reloc(NULL, insn); in call_dest_name()
3470 static bool pv_call_dest(struct objtool_file *file, struct instruction *insn) in pv_call_dest() argument
3476 reloc = insn_reloc(file, insn); in pv_call_dest()
3498 struct instruction *insn, in noinstr_call_dest() argument
3507 return pv_call_dest(file, insn); in noinstr_call_dest()
3536 struct instruction *insn, in validate_call() argument
3540 !noinstr_call_dest(file, insn, insn_call_dest(insn))) { in validate_call()
3541 WARN_INSN(insn, "call to %s() leaves .noinstr.text section", call_dest_name(insn)); in validate_call()
3545 if (state->uaccess && !func_uaccess_safe(insn_call_dest(insn))) { in validate_call()
3546 WARN_INSN(insn, "call to %s() with UACCESS enabled", call_dest_name(insn)); in validate_call()
3551 WARN_INSN(insn, "call to %s() with DF set", call_dest_name(insn)); in validate_call()
3559 struct instruction *insn, in validate_sibling_call() argument
3562 if (insn_func(insn) && has_modified_stack_frame(insn, state)) { in validate_sibling_call()
3563 WARN_INSN(insn, "sibling call from callable instruction with modified stack frame"); in validate_sibling_call()
3567 return validate_call(file, insn, state); in validate_sibling_call()
3570 static int validate_return(struct symbol *func, struct instruction *insn, struct insn_state *state) in validate_return() argument
3573 WARN_INSN(insn, "return with instrumentation enabled"); in validate_return()
3578 WARN_INSN(insn, "return with UACCESS enabled"); in validate_return()
3583 WARN_INSN(insn, "return with UACCESS disabled from a UACCESS-safe function"); in validate_return()
3588 WARN_INSN(insn, "return with DF set"); in validate_return()
3592 if (func && has_modified_stack_frame(insn, state)) { in validate_return()
3593 WARN_INSN(insn, "return with modified stack frame"); in validate_return()
3598 WARN_INSN(insn, "BP used as a scratch register"); in validate_return()
3606 struct instruction *insn) in next_insn_to_validate() argument
3608 struct alt_group *alt_group = insn->alt_group; in next_insn_to_validate()
3623 if (insn == alt_group->last_insn) in next_insn_to_validate()
3625 if (insn == alt_group->nop) in next_insn_to_validate()
3628 if (insn == alt_group->last_insn && alt_group->orig_group) in next_insn_to_validate()
3632 return next_insn_same_sec(file, insn); in next_insn_to_validate()
3645 struct instruction *insn, struct insn_state state) in validate_branch() argument
3653 sec = insn->sec; in validate_branch()
3656 next_insn = next_insn_to_validate(file, insn); in validate_branch()
3658 if (func && insn_func(insn) && func != insn_func(insn)->pfunc) { in validate_branch()
3665 func->name, insn_func(insn)->name); in validate_branch()
3669 if (func && insn->ignore) { in validate_branch()
3670 WARN_INSN(insn, "BUG: why am I validating an ignored function?"); in validate_branch()
3675 if (insn->visited & VISITED_BRANCH_MASK) { in validate_branch()
3676 if (!insn->hint && !insn_cfi_match(insn, &state.cfi)) in validate_branch()
3679 if (insn->visited & visited) in validate_branch()
3686 state.instr += insn->instr; in validate_branch()
3688 if (insn->hint) { in validate_branch()
3689 if (insn->restore) { in validate_branch()
3692 i = insn; in validate_branch()
3703 WARN_INSN(insn, "no corresponding CFI save for CFI restore"); in validate_branch()
3720 WARN_INSN(insn, "objtool isn't smart enough to handle this CFI save/restore combo"); in validate_branch()
3724 insn->cfi = save_insn->cfi; in validate_branch()
3728 state.cfi = *insn->cfi; in validate_branch()
3733 insn->cfi = prev_insn->cfi; in validate_branch()
3736 insn->cfi = cfi_hash_find_or_add(&state.cfi); in validate_branch()
3740 insn->visited |= visited; in validate_branch()
3742 if (propagate_alt_cfi(file, insn)) in validate_branch()
3745 if (!insn->ignore_alts && insn->alts) { in validate_branch()
3748 for (alt = insn->alts; alt; alt = alt->next) { in validate_branch()
3752 ret = validate_branch(file, func, alt->insn, state); in validate_branch()
3754 BT_INSN(insn, "(alt)"); in validate_branch()
3763 if (handle_insn_ops(insn, next_insn, &state)) in validate_branch()
3766 switch (insn->type) { in validate_branch()
3769 return validate_return(func, insn, &state); in validate_branch()
3773 ret = validate_call(file, insn, &state); in validate_branch()
3777 if (opts.stackval && func && !is_special_call(insn) && in validate_branch()
3779 WARN_INSN(insn, "call without frame pointer save/setup"); in validate_branch()
3783 if (insn->dead_end) in validate_branch()
3790 if (is_sibling_call(insn)) { in validate_branch()
3791 ret = validate_sibling_call(file, insn, &state); in validate_branch()
3795 } else if (insn->jump_dest) { in validate_branch()
3797 insn->jump_dest, state); in validate_branch()
3799 BT_INSN(insn, "(branch)"); in validate_branch()
3804 if (insn->type == INSN_JUMP_UNCONDITIONAL) in validate_branch()
3811 if (is_sibling_call(insn)) { in validate_branch()
3812 ret = validate_sibling_call(file, insn, &state); in validate_branch()
3817 if (insn->type == INSN_JUMP_DYNAMIC) in validate_branch()
3824 WARN_INSN(insn, "unsupported instruction in callable function"); in validate_branch()
3831 WARN_INSN(insn, "recursive UACCESS enable"); in validate_branch()
3840 WARN_INSN(insn, "redundant UACCESS disable"); in validate_branch()
3845 WARN_INSN(insn, "UACCESS-safe disables UACCESS"); in validate_branch()
3854 WARN_INSN(insn, "recursive STD"); in validate_branch()
3863 WARN_INSN(insn, "redundant CLD"); in validate_branch()
3874 if (insn->dead_end) in validate_branch()
3884 prev_insn = insn; in validate_branch()
3885 insn = next_insn; in validate_branch()
3892 struct instruction *insn, in validate_unwind_hint() argument
3895 if (insn->hint && !insn->visited && !insn->ignore) { in validate_unwind_hint()
3896 int ret = validate_branch(file, insn_func(insn), insn, *state); in validate_unwind_hint()
3898 BT_INSN(insn, "<=== (hint)"); in validate_unwind_hint()
3907 struct instruction *insn; in validate_unwind_hints() local
3917 sec_for_each_insn(file, sec, insn) in validate_unwind_hints()
3918 warnings += validate_unwind_hint(file, insn, &state); in validate_unwind_hints()
3920 for_each_insn(file, insn) in validate_unwind_hints()
3921 warnings += validate_unwind_hint(file, insn, &state); in validate_unwind_hints()
3933 static int validate_unret(struct objtool_file *file, struct instruction *insn) in validate_unret() argument
3939 next = next_insn_to_validate(file, insn); in validate_unret()
3941 if (insn->visited & VISITED_UNRET) in validate_unret()
3944 insn->visited |= VISITED_UNRET; in validate_unret()
3946 if (!insn->ignore_alts && insn->alts) { in validate_unret()
3950 for (alt = insn->alts; alt; alt = alt->next) { in validate_unret()
3954 ret = validate_unret(file, alt->insn); in validate_unret()
3956 BT_INSN(insn, "(alt)"); in validate_unret()
3965 switch (insn->type) { in validate_unret()
3970 WARN_INSN(insn, "early indirect call"); in validate_unret()
3975 if (!is_sibling_call(insn)) { in validate_unret()
3976 if (!insn->jump_dest) { in validate_unret()
3977 WARN_INSN(insn, "unresolved jump target after linking?!?"); in validate_unret()
3980 ret = validate_unret(file, insn->jump_dest); in validate_unret()
3982 BT_INSN(insn, "(branch%s)", in validate_unret()
3983 insn->type == INSN_JUMP_CONDITIONAL ? "-cond" : ""); in validate_unret()
3987 if (insn->type == INSN_JUMP_UNCONDITIONAL) in validate_unret()
3995 dest = find_insn(file, insn_call_dest(insn)->sec, in validate_unret()
3996 insn_call_dest(insn)->offset); in validate_unret()
3999 insn_call_dest(insn)->name); in validate_unret()
4005 BT_INSN(insn, "(call)"); in validate_unret()
4015 WARN_INSN(insn, "RET before UNTRAIN"); in validate_unret()
4019 if (insn->retpoline_safe) in validate_unret()
4028 WARN_INSN(insn, "teh end!"); in validate_unret()
4031 insn = next; in validate_unret()
4043 struct instruction *insn; in validate_unrets() local
4046 for_each_insn(file, insn) { in validate_unrets()
4047 if (!insn->unret) in validate_unrets()
4050 ret = validate_unret(file, insn); in validate_unrets()
4052 WARN_INSN(insn, "Failed UNRET validation"); in validate_unrets()
4063 struct instruction *insn; in validate_retpoline() local
4066 for_each_insn(file, insn) { in validate_retpoline()
4067 if (insn->type != INSN_JUMP_DYNAMIC && in validate_retpoline()
4068 insn->type != INSN_CALL_DYNAMIC && in validate_retpoline()
4069 insn->type != INSN_RETURN) in validate_retpoline()
4072 if (insn->retpoline_safe) in validate_retpoline()
4075 if (insn->sec->init) in validate_retpoline()
4078 if (insn->type == INSN_RETURN) { in validate_retpoline()
4080 WARN_INSN(insn, "'naked' return found in MITIGATION_RETHUNK build"); in validate_retpoline()
4084 WARN_INSN(insn, "indirect %s found in MITIGATION_RETPOLINE build", in validate_retpoline()
4085 insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); in validate_retpoline()
4094 static bool is_kasan_insn(struct instruction *insn) in is_kasan_insn() argument
4096 return (insn->type == INSN_CALL && in is_kasan_insn()
4097 !strcmp(insn_call_dest(insn)->name, "__asan_handle_no_return")); in is_kasan_insn()
4100 static bool is_ubsan_insn(struct instruction *insn) in is_ubsan_insn() argument
4102 return (insn->type == INSN_CALL && in is_ubsan_insn()
4103 !strcmp(insn_call_dest(insn)->name, in is_ubsan_insn()
4107 static bool ignore_unreachable_insn(struct objtool_file *file, struct instruction *insn) in ignore_unreachable_insn() argument
4112 if (insn->ignore || insn->type == INSN_NOP || insn->type == INSN_TRAP) in ignore_unreachable_insn()
4119 if (!strcmp(insn->sec->name, ".altinstr_replacement") || in ignore_unreachable_insn()
4120 !strcmp(insn->sec->name, ".altinstr_aux")) in ignore_unreachable_insn()
4131 if (opts.link && !insn_func(insn)) { in ignore_unreachable_insn()
4132 int size = find_symbol_hole_containing(insn->sec, insn->offset); in ignore_unreachable_insn()
4133 unsigned long end = insn->offset + size; in ignore_unreachable_insn()
4141 sec_for_each_insn_continue(file, insn) { in ignore_unreachable_insn()
4146 if (insn->visited) in ignore_unreachable_insn()
4149 if (insn->offset >= end) in ignore_unreachable_insn()
4155 if (insn->jump_dest && insn_func(insn->jump_dest) && in ignore_unreachable_insn()
4156 strstr(insn_func(insn->jump_dest)->name, ".cold")) { in ignore_unreachable_insn()
4157 struct instruction *dest = insn->jump_dest; in ignore_unreachable_insn()
4166 if (!insn_func(insn)) in ignore_unreachable_insn()
4169 if (insn_func(insn)->static_call_tramp) in ignore_unreachable_insn()
4180 prev_insn = prev_insn_same_sec(file, insn); in ignore_unreachable_insn()
4182 (insn->type == INSN_BUG || in ignore_unreachable_insn()
4183 (insn->type == INSN_JUMP_UNCONDITIONAL && in ignore_unreachable_insn()
4184 insn->jump_dest && insn->jump_dest->type == INSN_BUG))) in ignore_unreachable_insn()
4195 if (is_kasan_insn(insn) || is_ubsan_insn(insn)) in ignore_unreachable_insn()
4198 if (insn->type == INSN_JUMP_UNCONDITIONAL) { in ignore_unreachable_insn()
4199 if (insn->jump_dest && in ignore_unreachable_insn()
4200 insn_func(insn->jump_dest) == insn_func(insn)) { in ignore_unreachable_insn()
4201 insn = insn->jump_dest; in ignore_unreachable_insn()
4208 if (insn->offset + insn->len >= insn_func(insn)->offset + insn_func(insn)->len) in ignore_unreachable_insn()
4211 insn = next_insn_same_sec(file, insn); in ignore_unreachable_insn()
4219 struct instruction *insn, *prev; in add_prefix_symbol() local
4222 insn = find_insn(file, func->sec, func->offset); in add_prefix_symbol()
4223 if (!insn) in add_prefix_symbol()
4226 for (prev = prev_insn_same_sec(file, insn); in add_prefix_symbol()
4249 if (!insn->cfi) { in add_prefix_symbol()
4258 cfi = cfi_hash_find_or_add(insn->cfi); in add_prefix_symbol()
4259 for (; prev != insn; prev = next_insn_same_sec(file, prev)) in add_prefix_symbol()
4288 struct instruction *insn; in validate_symbol() local
4299 insn = find_insn(file, sec, sym->offset); in validate_symbol()
4300 if (!insn || insn->ignore || insn->visited) in validate_symbol()
4305 ret = validate_branch(file, insn_func(insn), insn, *state); in validate_symbol()
4307 BT_INSN(insn, "<=== (sym)"); in validate_symbol()
4371 static void mark_endbr_used(struct instruction *insn) in mark_endbr_used() argument
4373 if (!list_empty(&insn->call_node)) in mark_endbr_used()
4374 list_del_init(&insn->call_node); in mark_endbr_used()
4377 static bool noendbr_range(struct objtool_file *file, struct instruction *insn) in noendbr_range() argument
4379 struct symbol *sym = find_symbol_containing(insn->sec, insn->offset-1); in noendbr_range()
4392 return insn->offset == sym->offset + sym->len; in noendbr_range()
4395 static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn) in validate_ibt_insn() argument
4406 switch (insn->type) { in validate_ibt_insn()
4420 for (reloc = insn_reloc(file, insn); in validate_ibt_insn()
4422 reloc = find_reloc_by_dest_range(file->elf, insn->sec, in validate_ibt_insn()
4424 (insn->offset + insn->len) - (reloc_offset(reloc) + 1))) { in validate_ibt_insn()
4449 if (insn_func(dest) && insn_func(insn) && in validate_ibt_insn()
4450 insn_func(dest)->pfunc == insn_func(insn)->pfunc) { in validate_ibt_insn()
4482 WARN_INSN(insn, "relocation to !ENDBR: %s", offstr(dest->sec, dest->offset)); in validate_ibt_insn()
4524 struct instruction *insn; in validate_ibt() local
4527 for_each_insn(file, insn) in validate_ibt()
4528 warnings += validate_ibt_insn(file, insn); in validate_ibt()
4572 struct instruction *insn, *next_insn; in validate_sls() local
4575 for_each_insn(file, insn) { in validate_sls()
4576 next_insn = next_insn_same_sec(file, insn); in validate_sls()
4578 if (insn->retpoline_safe) in validate_sls()
4581 switch (insn->type) { in validate_sls()
4584 WARN_INSN(insn, "missing int3 after ret"); in validate_sls()
4591 WARN_INSN(insn, "missing int3 after indirect jump"); in validate_sls()
4603 static bool ignore_noreturn_call(struct instruction *insn) in ignore_noreturn_call() argument
4605 struct symbol *call_dest = insn_call_dest(insn); in ignore_noreturn_call()
4625 insn->sym->warned = 1; in ignore_noreturn_call()
4634 struct instruction *insn, *prev_insn; in validate_reachable_instructions() local
4641 for_each_insn(file, insn) { in validate_reachable_instructions()
4642 if (insn->visited || ignore_unreachable_insn(file, insn)) in validate_reachable_instructions()
4645 prev_insn = prev_insn_same_sec(file, insn); in validate_reachable_instructions()
4649 WARN_INSN(insn, "%s() is missing a __noreturn annotation", in validate_reachable_instructions()
4656 WARN_INSN(insn, "unreachable instruction"); in validate_reachable_instructions()
4750 struct instruction *insn; in free_insns() local
4753 for_each_insn(file, insn) { in free_insns()
4754 if (!insn->idx) { in free_insns()
4756 chunk->addr = insn; in free_insns()