Lines Matching refs:insn

26 	struct instruction *insn;  member
40 struct instruction *insn; in find_insn() local
42 hash_for_each_possible(file->insn_hash, insn, hash, sec_offset_hash(sec, offset)) { in find_insn()
43 if (insn->sec == sec && insn->offset == offset) in find_insn()
44 return insn; in find_insn()
51 struct instruction *insn) in next_insn_same_sec() argument
53 if (insn->idx == INSN_CHUNK_MAX) in next_insn_same_sec()
54 return find_insn(file, insn->sec, insn->offset + insn->len); in next_insn_same_sec()
56 insn++; in next_insn_same_sec()
57 if (!insn->len) in next_insn_same_sec()
60 return insn; in next_insn_same_sec()
64 struct instruction *insn) in next_insn_same_func() argument
66 struct instruction *next = next_insn_same_sec(file, insn); in next_insn_same_func()
67 struct symbol *func = insn_func(insn); in next_insn_same_func()
84 struct instruction *insn) in prev_insn_same_sec() argument
86 if (insn->idx == 0) { in prev_insn_same_sec()
87 if (insn->prev_len) in prev_insn_same_sec()
88 return find_insn(file, insn->sec, insn->offset - insn->prev_len); in prev_insn_same_sec()
92 return insn - 1; in prev_insn_same_sec()
96 struct instruction *insn) in prev_insn_same_sym() argument
98 struct instruction *prev = prev_insn_same_sec(file, insn); in prev_insn_same_sym()
100 if (prev && insn_func(prev) == insn_func(insn)) in prev_insn_same_sym()
106 #define for_each_insn(file, insn) \ argument
110 sec_for_each_insn(file, __sec, insn)
112 #define func_for_each_insn(file, func, insn) \ argument
113 for (insn = find_insn(file, func->sec, func->offset); \
114 insn; \
115 insn = next_insn_same_func(file, insn))
117 #define sym_for_each_insn(file, sym, insn) \ argument
118 for (insn = find_insn(file, sym->sec, sym->offset); \
119 insn && insn->offset < sym->offset + sym->len; \
120 insn = next_insn_same_sec(file, insn))
122 #define sym_for_each_insn_continue_reverse(file, sym, insn) \ argument
123 for (insn = prev_insn_same_sec(file, insn); \
124 insn && insn->offset >= sym->offset; \
125 insn = prev_insn_same_sec(file, insn))
127 #define sec_for_each_insn_from(file, insn) \ argument
128 for (; insn; insn = next_insn_same_sec(file, insn))
130 #define sec_for_each_insn_continue(file, insn) \ argument
131 for (insn = next_insn_same_sec(file, insn); insn; \
132 insn = next_insn_same_sec(file, insn))
134 static inline struct symbol *insn_call_dest(struct instruction *insn) in insn_call_dest() argument
136 if (insn->type == INSN_JUMP_DYNAMIC || in insn_call_dest()
137 insn->type == INSN_CALL_DYNAMIC) in insn_call_dest()
140 return insn->_call_dest; in insn_call_dest()
143 static inline struct reloc *insn_jump_table(struct instruction *insn) in insn_jump_table() argument
145 if (insn->type == INSN_JUMP_DYNAMIC || in insn_jump_table()
146 insn->type == INSN_CALL_DYNAMIC) in insn_jump_table()
147 return insn->_jump_table; in insn_jump_table()
152 static bool is_jump_table_jump(struct instruction *insn) in is_jump_table_jump() argument
154 struct alt_group *alt_group = insn->alt_group; in is_jump_table_jump()
156 if (insn_jump_table(insn)) in is_jump_table_jump()
164 static bool is_sibling_call(struct instruction *insn) in is_sibling_call() argument
169 if (insn_func(insn)) { in is_sibling_call()
171 if (insn->type == INSN_JUMP_DYNAMIC) in is_sibling_call()
172 return !is_jump_table_jump(insn); in is_sibling_call()
176 return (is_static_jump(insn) && insn_call_dest(insn)); in is_sibling_call()
192 struct instruction *insn; in __dead_end_function() local
215 insn = find_insn(file, func->sec, func->offset); in __dead_end_function()
216 if (!insn || !insn_func(insn)) in __dead_end_function()
219 func_for_each_insn(file, func, insn) { in __dead_end_function()
222 if (insn->type == INSN_RETURN) in __dead_end_function()
234 func_for_each_insn(file, func, insn) { in __dead_end_function()
235 if (is_sibling_call(insn)) { in __dead_end_function()
236 struct instruction *dest = insn->jump_dest; in __dead_end_function()
373 struct instruction *insn; in decode_instructions() local
404 for (offset = 0; offset < sec->sh.sh_size; offset += insn->len) { in decode_instructions()
406 insns = calloc(sizeof(*insn), INSN_CHUNK_SIZE); in decode_instructions()
415 insn = &insns[idx]; in decode_instructions()
416 insn->idx = idx; in decode_instructions()
418 INIT_LIST_HEAD(&insn->call_node); in decode_instructions()
419 insn->sec = sec; in decode_instructions()
420 insn->offset = offset; in decode_instructions()
421 insn->prev_len = prev_len; in decode_instructions()
425 insn); in decode_instructions()
429 prev_len = insn->len; in decode_instructions()
436 if (insn->type == INSN_BUG) in decode_instructions()
437 insn->dead_end = true; in decode_instructions()
439 hash_add(file->insn_hash, &insn->hash, sec_offset_hash(sec, insn->offset)); in decode_instructions()
467 sym_for_each_insn(file, func, insn) { in decode_instructions()
468 insn->sym = func; in decode_instructions()
470 insn->type == INSN_ENDBR && in decode_instructions()
471 list_empty(&insn->call_node)) { in decode_instructions()
472 if (insn->offset == func->offset) { in decode_instructions()
473 list_add_tail(&insn->call_node, &file->endbr_list); in decode_instructions()
569 struct instruction *insn = NULL; in find_last_insn() local
573 for (offset = sec->sh.sh_size - 1; offset >= end && !insn; offset--) in find_last_insn()
574 insn = find_insn(file, sec, offset); in find_last_insn()
576 return insn; in find_last_insn()
586 struct instruction *insn; in add_dead_ends() local
605 insn = find_insn(file, reloc->sym->sec, addend); in add_dead_ends()
606 if (insn) in add_dead_ends()
607 insn = prev_insn_same_sec(file, insn); in add_dead_ends()
609 insn = find_last_insn(file, reloc->sym->sec); in add_dead_ends()
610 if (!insn) { in add_dead_ends()
621 insn->dead_end = true; in add_dead_ends()
644 insn = find_insn(file, reloc->sym->sec, addend); in add_dead_ends()
645 if (insn) in add_dead_ends()
646 insn = prev_insn_same_sec(file, insn); in add_dead_ends()
648 insn = find_last_insn(file, reloc->sym->sec); in add_dead_ends()
649 if (!insn) { in add_dead_ends()
660 insn->dead_end = false; in add_dead_ends()
670 struct instruction *insn; in create_static_call_sections() local
686 list_for_each_entry(insn, &file->static_call_list, call_node) in create_static_call_sections()
698 list_for_each_entry(insn, &file->static_call_list, call_node) { in create_static_call_sections()
703 insn->sec, insn->offset)) in create_static_call_sections()
707 key_name = strdup(insn_call_dest(insn)->name); in create_static_call_sections()
738 key_sym = insn_call_dest(insn); in create_static_call_sections()
746 is_sibling_call(insn) * STATIC_CALL_SITE_TAIL)) in create_static_call_sections()
757 struct instruction *insn; in create_retpoline_sites_sections() local
768 list_for_each_entry(insn, &file->retpoline_call_list, call_node) in create_retpoline_sites_sections()
780 list_for_each_entry(insn, &file->retpoline_call_list, call_node) { in create_retpoline_sites_sections()
784 insn->sec, insn->offset)) in create_retpoline_sites_sections()
795 struct instruction *insn; in create_return_sites_sections() local
806 list_for_each_entry(insn, &file->return_thunk_list, call_node) in create_return_sites_sections()
818 list_for_each_entry(insn, &file->return_thunk_list, call_node) { in create_return_sites_sections()
822 insn->sec, insn->offset)) in create_return_sites_sections()
833 struct instruction *insn; in create_ibt_endbr_seal_sections() local
844 list_for_each_entry(insn, &file->endbr_list, call_node) in create_ibt_endbr_seal_sections()
862 list_for_each_entry(insn, &file->endbr_list, call_node) { in create_ibt_endbr_seal_sections()
865 struct symbol *sym = insn->sym; in create_ibt_endbr_seal_sections()
869 insn->offset == sym->offset && in create_ibt_endbr_seal_sections()
876 insn->sec, insn->offset)) in create_ibt_endbr_seal_sections()
936 struct instruction *insn; in create_mcount_loc_sections() local
951 list_for_each_entry(insn, &file->mcount_loc_list, call_node) in create_mcount_loc_sections()
962 list_for_each_entry(insn, &file->mcount_loc_list, call_node) { in create_mcount_loc_sections()
967 insn->sec, insn->offset); in create_mcount_loc_sections()
981 struct instruction *insn; in create_direct_call_sections() local
996 list_for_each_entry(insn, &file->call_list, call_node) in create_direct_call_sections()
1005 list_for_each_entry(insn, &file->call_list, call_node) { in create_direct_call_sections()
1009 insn->sec, insn->offset)) in create_direct_call_sections()
1023 struct instruction *insn; in add_ignores() local
1050 func_for_each_insn(file, func, insn) in add_ignores()
1051 insn->ignore = true; in add_ignores()
1267 struct instruction *insn; in add_ignore_alternatives() local
1279 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in add_ignore_alternatives()
1280 if (!insn) { in add_ignore_alternatives()
1285 insn->ignore_alts = true; in add_ignore_alternatives()
1318 static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn) in insn_reloc() argument
1322 if (insn->no_reloc) in insn_reloc()
1328 reloc = find_reloc_by_dest_range(file->elf, insn->sec, in insn_reloc()
1329 insn->offset, insn->len); in insn_reloc()
1331 insn->no_reloc = 1; in insn_reloc()
1338 static void remove_insn_ops(struct instruction *insn) in remove_insn_ops() argument
1342 for (op = insn->stack_ops; op; op = next) { in remove_insn_ops()
1346 insn->stack_ops = NULL; in remove_insn_ops()
1350 struct instruction *insn, bool sibling) in annotate_call_site() argument
1352 struct reloc *reloc = insn_reloc(file, insn); in annotate_call_site()
1353 struct symbol *sym = insn_call_dest(insn); in annotate_call_site()
1364 if (!strcmp(insn->sec->name, ".altinstr_replacement")) in annotate_call_site()
1368 list_add_tail(&insn->call_node, &file->static_call_list); in annotate_call_site()
1373 list_add_tail(&insn->call_node, &file->retpoline_call_list); in annotate_call_site()
1382 if (opts.hack_noinstr && insn->sec->noinstr && sym->profiling_func) { in annotate_call_site()
1386 elf_write_insn(file->elf, insn->sec, in annotate_call_site()
1387 insn->offset, insn->len, in annotate_call_site()
1388 sibling ? arch_ret_insn(insn->len) in annotate_call_site()
1389 : arch_nop_insn(insn->len)); in annotate_call_site()
1391 insn->type = sibling ? INSN_RETURN : INSN_NOP; in annotate_call_site()
1400 insn->retpoline_safe = true; in annotate_call_site()
1408 WARN_INSN(insn, "tail call to __fentry__ !?!?"); in annotate_call_site()
1413 elf_write_insn(file->elf, insn->sec, in annotate_call_site()
1414 insn->offset, insn->len, in annotate_call_site()
1415 arch_nop_insn(insn->len)); in annotate_call_site()
1417 insn->type = INSN_NOP; in annotate_call_site()
1420 list_add_tail(&insn->call_node, &file->mcount_loc_list); in annotate_call_site()
1424 if (insn->type == INSN_CALL && !insn->sec->init) in annotate_call_site()
1425 list_add_tail(&insn->call_node, &file->call_list); in annotate_call_site()
1428 insn->dead_end = true; in annotate_call_site()
1431 static void add_call_dest(struct objtool_file *file, struct instruction *insn, in add_call_dest() argument
1434 insn->_call_dest = dest; in add_call_dest()
1445 remove_insn_ops(insn); in add_call_dest()
1447 annotate_call_site(file, insn, sibling); in add_call_dest()
1450 static void add_retpoline_call(struct objtool_file *file, struct instruction *insn) in add_retpoline_call() argument
1456 switch (insn->type) { in add_retpoline_call()
1458 insn->type = INSN_CALL_DYNAMIC; in add_retpoline_call()
1461 insn->type = INSN_JUMP_DYNAMIC; in add_retpoline_call()
1464 insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL; in add_retpoline_call()
1470 insn->retpoline_safe = true; in add_retpoline_call()
1479 remove_insn_ops(insn); in add_retpoline_call()
1481 annotate_call_site(file, insn, false); in add_retpoline_call()
1484 static void add_return_call(struct objtool_file *file, struct instruction *insn, bool add) in add_return_call() argument
1490 insn->type = INSN_RETURN; in add_return_call()
1491 insn->retpoline_safe = true; in add_return_call()
1494 list_add_tail(&insn->call_node, &file->return_thunk_list); in add_return_call()
1498 struct instruction *insn, struct symbol *sym) in is_first_func_insn() argument
1500 if (insn->offset == sym->offset) in is_first_func_insn()
1505 struct instruction *prev = prev_insn_same_sym(file, insn); in is_first_func_insn()
1508 insn->offset == sym->offset + prev->len) in is_first_func_insn()
1546 struct instruction *insn, *jump_dest; in add_jump_destinations() local
1551 for_each_insn(file, insn) { in add_jump_destinations()
1552 if (insn->jump_dest) { in add_jump_destinations()
1559 if (!is_static_jump(insn)) in add_jump_destinations()
1562 reloc = insn_reloc(file, insn); in add_jump_destinations()
1564 dest_sec = insn->sec; in add_jump_destinations()
1565 dest_off = arch_jump_destination(insn); in add_jump_destinations()
1570 add_retpoline_call(file, insn); in add_jump_destinations()
1573 add_return_call(file, insn, true); in add_jump_destinations()
1575 } else if (insn_func(insn)) { in add_jump_destinations()
1580 add_call_dest(file, insn, reloc->sym, true); in add_jump_destinations()
1604 add_return_call(file, insn, false); in add_jump_destinations()
1608 WARN_INSN(insn, "can't find jump dest instruction at %s+0x%lx", in add_jump_destinations()
1616 if (insn_func(insn) && insn_func(jump_dest) && in add_jump_destinations()
1617 insn_func(insn) != insn_func(jump_dest)) { in add_jump_destinations()
1634 if (!strstr(insn_func(insn)->name, ".cold") && in add_jump_destinations()
1636 insn_func(insn)->cfunc = insn_func(jump_dest); in add_jump_destinations()
1637 insn_func(jump_dest)->pfunc = insn_func(insn); in add_jump_destinations()
1641 if (jump_is_sibling_call(file, insn, jump_dest)) { in add_jump_destinations()
1646 add_call_dest(file, insn, insn_func(jump_dest), true); in add_jump_destinations()
1650 insn->jump_dest = jump_dest; in add_jump_destinations()
1672 struct instruction *insn; in add_call_destinations() local
1677 for_each_insn(file, insn) { in add_call_destinations()
1678 if (insn->type != INSN_CALL) in add_call_destinations()
1681 reloc = insn_reloc(file, insn); in add_call_destinations()
1683 dest_off = arch_jump_destination(insn); in add_call_destinations()
1684 dest = find_call_destination(insn->sec, dest_off); in add_call_destinations()
1686 add_call_dest(file, insn, dest, false); in add_call_destinations()
1688 if (insn->ignore) in add_call_destinations()
1691 if (!insn_call_dest(insn)) { in add_call_destinations()
1692 WARN_INSN(insn, "unannotated intra-function call"); in add_call_destinations()
1696 if (insn_func(insn) && insn_call_dest(insn)->type != STT_FUNC) { in add_call_destinations()
1697 WARN_INSN(insn, "unsupported call to non-function"); in add_call_destinations()
1705 WARN_INSN(insn, "can't find call dest symbol at %s+0x%lx", in add_call_destinations()
1710 add_call_dest(file, insn, dest, false); in add_call_destinations()
1713 add_retpoline_call(file, insn); in add_call_destinations()
1716 add_call_dest(file, insn, reloc->sym, false); in add_call_destinations()
1731 struct instruction *last_new_insn = NULL, *insn, *nop = NULL; in handle_group_alt() local
1751 insn = orig_insn; in handle_group_alt()
1752 sec_for_each_insn_from(file, insn) { in handle_group_alt()
1753 if (insn->offset >= special_alt->orig_off + special_alt->orig_len) in handle_group_alt()
1756 insn->alt_group = orig_alt_group; in handle_group_alt()
1757 last_orig_insn = insn; in handle_group_alt()
1810 insn = *new_insn; in handle_group_alt()
1811 sec_for_each_insn_from(file, insn) { in handle_group_alt()
1814 if (insn->offset >= special_alt->new_off + special_alt->new_len) in handle_group_alt()
1817 last_new_insn = insn; in handle_group_alt()
1819 insn->ignore = orig_insn->ignore_alts; in handle_group_alt()
1820 insn->sym = orig_insn->sym; in handle_group_alt()
1821 insn->alt_group = new_alt_group; in handle_group_alt()
1831 alt_reloc = insn_reloc(file, insn); in handle_group_alt()
1833 !arch_support_alt_relocation(special_alt, insn, alt_reloc)) { in handle_group_alt()
1835 WARN_INSN(insn, "unsupported relocation in alternatives section"); in handle_group_alt()
1839 if (!is_static_jump(insn)) in handle_group_alt()
1842 if (!insn->immediate) in handle_group_alt()
1845 dest_off = arch_jump_destination(insn); in handle_group_alt()
1847 insn->jump_dest = next_insn_same_sec(file, orig_alt_group->last_insn); in handle_group_alt()
1848 if (!insn->jump_dest) { in handle_group_alt()
1849 WARN_INSN(insn, "can't find alternative jump destination"); in handle_group_alt()
1982 alt->insn = new_insn; in add_special_section_alts()
2002 static int add_jump_table(struct objtool_file *file, struct instruction *insn, in add_jump_table() argument
2005 struct symbol *pfunc = insn_func(insn)->pfunc; in add_jump_table()
2006 struct reloc *table = insn_jump_table(insn); in add_jump_table()
2045 alt->insn = dest_insn; in add_jump_table()
2046 alt->next = insn->alts; in add_jump_table()
2047 insn->alts = alt; in add_jump_table()
2052 WARN_INSN(insn, "can't find switch jump table"); in add_jump_table()
2065 struct instruction *insn) in find_jump_table() argument
2068 struct instruction *dest_insn, *orig_insn = insn; in find_jump_table()
2076 insn && insn_func(insn) && insn_func(insn)->pfunc == func; in find_jump_table()
2077 insn = insn->first_jump_src ?: prev_insn_same_sym(file, insn)) { in find_jump_table()
2079 if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC) in find_jump_table()
2083 if (insn->type == INSN_JUMP_UNCONDITIONAL && in find_jump_table()
2084 insn->jump_dest && in find_jump_table()
2085 (insn->jump_dest->offset <= insn->offset || in find_jump_table()
2086 insn->jump_dest->offset > orig_insn->offset)) in find_jump_table()
2089 table_reloc = arch_find_switch_table(file, insn); in find_jump_table()
2109 struct instruction *insn, *last = NULL; in mark_func_jump_tables() local
2112 func_for_each_insn(file, func, insn) { in mark_func_jump_tables()
2114 last = insn; in mark_func_jump_tables()
2121 if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest && in mark_func_jump_tables()
2122 insn->offset > last->offset && in mark_func_jump_tables()
2123 insn->jump_dest->offset > insn->offset && in mark_func_jump_tables()
2124 !insn->jump_dest->first_jump_src) { in mark_func_jump_tables()
2126 insn->jump_dest->first_jump_src = insn; in mark_func_jump_tables()
2127 last = insn->jump_dest; in mark_func_jump_tables()
2130 if (insn->type != INSN_JUMP_DYNAMIC) in mark_func_jump_tables()
2133 reloc = find_jump_table(file, func, insn); in mark_func_jump_tables()
2135 insn->_jump_table = reloc; in mark_func_jump_tables()
2142 struct instruction *insn, *insn_t1 = NULL, *insn_t2; in add_func_jump_tables() local
2145 func_for_each_insn(file, func, insn) { in add_func_jump_tables()
2146 if (!insn_jump_table(insn)) in add_func_jump_tables()
2150 insn_t1 = insn; in add_func_jump_tables()
2154 insn_t2 = insn; in add_func_jump_tables()
2209 struct instruction *insn; in read_unwind_hints() local
2238 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_unwind_hints()
2239 if (!insn) { in read_unwind_hints()
2244 insn->hint = true; in read_unwind_hints()
2247 insn->cfi = &force_undefined_cfi; in read_unwind_hints()
2252 insn->hint = false; in read_unwind_hints()
2253 insn->save = true; in read_unwind_hints()
2258 insn->restore = true; in read_unwind_hints()
2263 struct symbol *sym = find_symbol_by_offset(insn->sec, insn->offset); in read_unwind_hints()
2266 if (opts.ibt && insn->type != INSN_ENDBR && !insn->noendbr) { in read_unwind_hints()
2267 WARN_INSN(insn, "UNWIND_HINT_IRET_REGS without ENDBR"); in read_unwind_hints()
2273 insn->cfi = &func_cfi; in read_unwind_hints()
2277 if (insn->cfi) in read_unwind_hints()
2278 cfi = *(insn->cfi); in read_unwind_hints()
2281 WARN_INSN(insn, "unsupported unwind_hint sp base reg %d", hint->sp_reg); in read_unwind_hints()
2289 insn->cfi = cfi_hash_find_or_add(&cfi); in read_unwind_hints()
2297 struct instruction *insn; in read_noendbr_hints() local
2306 insn = find_insn(file, reloc->sym->sec, in read_noendbr_hints()
2308 if (!insn) { in read_noendbr_hints()
2313 insn->noendbr = 1; in read_noendbr_hints()
2322 struct instruction *insn; in read_retpoline_hints() local
2335 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_retpoline_hints()
2336 if (!insn) { in read_retpoline_hints()
2341 if (insn->type != INSN_JUMP_DYNAMIC && in read_retpoline_hints()
2342 insn->type != INSN_CALL_DYNAMIC && in read_retpoline_hints()
2343 insn->type != INSN_RETURN && in read_retpoline_hints()
2344 insn->type != INSN_NOP) { in read_retpoline_hints()
2345 WARN_INSN(insn, "retpoline_safe hint not an indirect jump/call/ret/nop"); in read_retpoline_hints()
2349 insn->retpoline_safe = true; in read_retpoline_hints()
2358 struct instruction *insn; in read_instr_hints() local
2371 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_instr_hints()
2372 if (!insn) { in read_instr_hints()
2377 insn->instr--; in read_instr_hints()
2390 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_instr_hints()
2391 if (!insn) { in read_instr_hints()
2396 insn->instr++; in read_instr_hints()
2405 struct instruction *insn; in read_validate_unret_hints() local
2418 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_validate_unret_hints()
2419 if (!insn) { in read_validate_unret_hints()
2423 insn->unret = 1; in read_validate_unret_hints()
2432 struct instruction *insn; in read_intra_function_calls() local
2449 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_intra_function_calls()
2450 if (!insn) { in read_intra_function_calls()
2455 if (insn->type != INSN_CALL) { in read_intra_function_calls()
2456 WARN_INSN(insn, "intra_function_call not a direct call"); in read_intra_function_calls()
2465 insn->type = INSN_JUMP_UNCONDITIONAL; in read_intra_function_calls()
2467 dest_off = arch_jump_destination(insn); in read_intra_function_calls()
2468 insn->jump_dest = find_insn(file, insn->sec, dest_off); in read_intra_function_calls()
2469 if (!insn->jump_dest) { in read_intra_function_calls()
2470 WARN_INSN(insn, "can't find call dest at %s+0x%lx", in read_intra_function_calls()
2471 insn->sec->name, dest_off); in read_intra_function_calls()
2653 static bool is_special_call(struct instruction *insn) in is_special_call() argument
2655 if (insn->type == INSN_CALL) { in is_special_call()
2656 struct symbol *dest = insn_call_dest(insn); in is_special_call()
2668 static bool has_modified_stack_frame(struct instruction *insn, struct insn_state *state) in has_modified_stack_frame() argument
2713 static int update_cfi_state_regs(struct instruction *insn, in update_cfi_state_regs() argument
2806 static int update_cfi_state(struct instruction *insn, in update_cfi_state() argument
2819 if (insn_func(insn)) { in update_cfi_state()
2820 WARN_INSN(insn, "undefined stack state"); in update_cfi_state()
2828 return update_cfi_state_regs(insn, cfi, op); in update_cfi_state()
3003 WARN_INSN(insn, "unsupported stack register modification"); in update_cfi_state()
3013 WARN_INSN(insn, "unsupported stack pointer realignment"); in update_cfi_state()
3108 WARN_INSN(insn, "unknown stack-related instruction"); in update_cfi_state()
3151 if (opts.stackval && insn_func(insn) && op->src.reg == CFI_BP && in update_cfi_state()
3197 WARN_INSN(insn, "unknown stack-related memory operation"); in update_cfi_state()
3209 WARN_INSN(insn, "unknown stack-related instruction"); in update_cfi_state()
3225 static int propagate_alt_cfi(struct objtool_file *file, struct instruction *insn) in propagate_alt_cfi() argument
3230 if (!insn->alt_group) in propagate_alt_cfi()
3233 if (!insn->cfi) { in propagate_alt_cfi()
3238 alt_cfi = insn->alt_group->cfi; in propagate_alt_cfi()
3239 group_off = insn->offset - insn->alt_group->first_insn->offset; in propagate_alt_cfi()
3242 alt_cfi[group_off] = insn->cfi; in propagate_alt_cfi()
3244 if (cficmp(alt_cfi[group_off], insn->cfi)) { in propagate_alt_cfi()
3245 struct alt_group *orig_group = insn->alt_group->orig_group ?: insn->alt_group; in propagate_alt_cfi()
3247 char *where = offstr(insn->sec, insn->offset); in propagate_alt_cfi()
3257 static int handle_insn_ops(struct instruction *insn, in handle_insn_ops() argument
3263 for (op = insn->stack_ops; op; op = op->next) { in handle_insn_ops()
3265 if (update_cfi_state(insn, next_insn, &state->cfi, op)) in handle_insn_ops()
3268 if (!insn->alt_group) in handle_insn_ops()
3275 WARN_INSN(insn, "PUSHF stack exhausted"); in handle_insn_ops()
3295 static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2) in insn_cfi_match() argument
3297 struct cfi_state *cfi1 = insn->cfi; in insn_cfi_match()
3307 WARN_INSN(insn, "stack state mismatch: cfa1=%d%+d cfa2=%d%+d", in insn_cfi_match()
3317 WARN_INSN(insn, "stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d", in insn_cfi_match()
3325 WARN_INSN(insn, "stack state mismatch: type1=%d type2=%d", in insn_cfi_match()
3332 WARN_INSN(insn, "stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)", in insn_cfi_match()
3350 static inline const char *call_dest_name(struct instruction *insn) in call_dest_name() argument
3356 if (insn_call_dest(insn)) in call_dest_name()
3357 return insn_call_dest(insn)->name; in call_dest_name()
3359 reloc = insn_reloc(NULL, insn); in call_dest_name()
3369 static bool pv_call_dest(struct objtool_file *file, struct instruction *insn) in pv_call_dest() argument
3375 reloc = insn_reloc(file, insn); in pv_call_dest()
3397 struct instruction *insn, in noinstr_call_dest() argument
3406 return pv_call_dest(file, insn); in noinstr_call_dest()
3435 struct instruction *insn, in validate_call() argument
3439 !noinstr_call_dest(file, insn, insn_call_dest(insn))) { in validate_call()
3440 WARN_INSN(insn, "call to %s() leaves .noinstr.text section", call_dest_name(insn)); in validate_call()
3444 if (state->uaccess && !func_uaccess_safe(insn_call_dest(insn))) { in validate_call()
3445 WARN_INSN(insn, "call to %s() with UACCESS enabled", call_dest_name(insn)); in validate_call()
3450 WARN_INSN(insn, "call to %s() with DF set", call_dest_name(insn)); in validate_call()
3458 struct instruction *insn, in validate_sibling_call() argument
3461 if (insn_func(insn) && has_modified_stack_frame(insn, state)) { in validate_sibling_call()
3462 WARN_INSN(insn, "sibling call from callable instruction with modified stack frame"); in validate_sibling_call()
3466 return validate_call(file, insn, state); in validate_sibling_call()
3469 static int validate_return(struct symbol *func, struct instruction *insn, struct insn_state *state) in validate_return() argument
3472 WARN_INSN(insn, "return with instrumentation enabled"); in validate_return()
3477 WARN_INSN(insn, "return with UACCESS enabled"); in validate_return()
3482 WARN_INSN(insn, "return with UACCESS disabled from a UACCESS-safe function"); in validate_return()
3487 WARN_INSN(insn, "return with DF set"); in validate_return()
3491 if (func && has_modified_stack_frame(insn, state)) { in validate_return()
3492 WARN_INSN(insn, "return with modified stack frame"); in validate_return()
3497 WARN_INSN(insn, "BP used as a scratch register"); in validate_return()
3505 struct instruction *insn) in next_insn_to_validate() argument
3507 struct alt_group *alt_group = insn->alt_group; in next_insn_to_validate()
3522 if (insn == alt_group->last_insn) in next_insn_to_validate()
3524 if (insn == alt_group->nop) in next_insn_to_validate()
3527 if (insn == alt_group->last_insn && alt_group->orig_group) in next_insn_to_validate()
3531 return next_insn_same_sec(file, insn); in next_insn_to_validate()
3544 struct instruction *insn, struct insn_state state) in validate_branch() argument
3552 sec = insn->sec; in validate_branch()
3555 next_insn = next_insn_to_validate(file, insn); in validate_branch()
3557 if (func && insn_func(insn) && func != insn_func(insn)->pfunc) { in validate_branch()
3564 func->name, insn_func(insn)->name); in validate_branch()
3568 if (func && insn->ignore) { in validate_branch()
3569 WARN_INSN(insn, "BUG: why am I validating an ignored function?"); in validate_branch()
3574 if (insn->visited & VISITED_BRANCH_MASK) { in validate_branch()
3575 if (!insn->hint && !insn_cfi_match(insn, &state.cfi)) in validate_branch()
3578 if (insn->visited & visited) in validate_branch()
3585 state.instr += insn->instr; in validate_branch()
3587 if (insn->hint) { in validate_branch()
3588 if (insn->restore) { in validate_branch()
3591 i = insn; in validate_branch()
3602 WARN_INSN(insn, "no corresponding CFI save for CFI restore"); in validate_branch()
3607 WARN_INSN(insn, "objtool isn't smart enough to handle this CFI save/restore combo"); in validate_branch()
3611 insn->cfi = save_insn->cfi; in validate_branch()
3615 state.cfi = *insn->cfi; in validate_branch()
3620 insn->cfi = prev_insn->cfi; in validate_branch()
3623 insn->cfi = cfi_hash_find_or_add(&state.cfi); in validate_branch()
3627 insn->visited |= visited; in validate_branch()
3629 if (propagate_alt_cfi(file, insn)) in validate_branch()
3632 if (!insn->ignore_alts && insn->alts) { in validate_branch()
3635 for (alt = insn->alts; alt; alt = alt->next) { in validate_branch()
3639 ret = validate_branch(file, func, alt->insn, state); in validate_branch()
3641 BT_INSN(insn, "(alt)"); in validate_branch()
3650 if (handle_insn_ops(insn, next_insn, &state)) in validate_branch()
3653 switch (insn->type) { in validate_branch()
3656 return validate_return(func, insn, &state); in validate_branch()
3660 ret = validate_call(file, insn, &state); in validate_branch()
3664 if (opts.stackval && func && !is_special_call(insn) && in validate_branch()
3666 WARN_INSN(insn, "call without frame pointer save/setup"); in validate_branch()
3670 if (insn->dead_end) in validate_branch()
3677 if (is_sibling_call(insn)) { in validate_branch()
3678 ret = validate_sibling_call(file, insn, &state); in validate_branch()
3682 } else if (insn->jump_dest) { in validate_branch()
3684 insn->jump_dest, state); in validate_branch()
3686 BT_INSN(insn, "(branch)"); in validate_branch()
3691 if (insn->type == INSN_JUMP_UNCONDITIONAL) in validate_branch()
3698 if (is_sibling_call(insn)) { in validate_branch()
3699 ret = validate_sibling_call(file, insn, &state); in validate_branch()
3704 if (insn->type == INSN_JUMP_DYNAMIC) in validate_branch()
3711 WARN_INSN(insn, "unsupported instruction in callable function"); in validate_branch()
3718 WARN_INSN(insn, "recursive UACCESS enable"); in validate_branch()
3727 WARN_INSN(insn, "redundant UACCESS disable"); in validate_branch()
3732 WARN_INSN(insn, "UACCESS-safe disables UACCESS"); in validate_branch()
3741 WARN_INSN(insn, "recursive STD"); in validate_branch()
3750 WARN_INSN(insn, "redundant CLD"); in validate_branch()
3761 if (insn->dead_end) in validate_branch()
3771 prev_insn = insn; in validate_branch()
3772 insn = next_insn; in validate_branch()
3779 struct instruction *insn, in validate_unwind_hint() argument
3782 if (insn->hint && !insn->visited && !insn->ignore) { in validate_unwind_hint()
3783 int ret = validate_branch(file, insn_func(insn), insn, *state); in validate_unwind_hint()
3785 BT_INSN(insn, "<=== (hint)"); in validate_unwind_hint()
3794 struct instruction *insn; in validate_unwind_hints() local
3804 sec_for_each_insn(file, sec, insn) in validate_unwind_hints()
3805 warnings += validate_unwind_hint(file, insn, &state); in validate_unwind_hints()
3807 for_each_insn(file, insn) in validate_unwind_hints()
3808 warnings += validate_unwind_hint(file, insn, &state); in validate_unwind_hints()
3820 static int validate_unret(struct objtool_file *file, struct instruction *insn) in validate_unret() argument
3826 next = next_insn_to_validate(file, insn); in validate_unret()
3828 if (insn->visited & VISITED_UNRET) in validate_unret()
3831 insn->visited |= VISITED_UNRET; in validate_unret()
3833 if (!insn->ignore_alts && insn->alts) { in validate_unret()
3837 for (alt = insn->alts; alt; alt = alt->next) { in validate_unret()
3841 ret = validate_unret(file, alt->insn); in validate_unret()
3843 BT_INSN(insn, "(alt)"); in validate_unret()
3852 switch (insn->type) { in validate_unret()
3857 WARN_INSN(insn, "early indirect call"); in validate_unret()
3862 if (!is_sibling_call(insn)) { in validate_unret()
3863 if (!insn->jump_dest) { in validate_unret()
3864 WARN_INSN(insn, "unresolved jump target after linking?!?"); in validate_unret()
3867 ret = validate_unret(file, insn->jump_dest); in validate_unret()
3869 BT_INSN(insn, "(branch%s)", in validate_unret()
3870 insn->type == INSN_JUMP_CONDITIONAL ? "-cond" : ""); in validate_unret()
3874 if (insn->type == INSN_JUMP_UNCONDITIONAL) in validate_unret()
3882 dest = find_insn(file, insn_call_dest(insn)->sec, in validate_unret()
3883 insn_call_dest(insn)->offset); in validate_unret()
3886 insn_call_dest(insn)->name); in validate_unret()
3892 BT_INSN(insn, "(call)"); in validate_unret()
3902 WARN_INSN(insn, "RET before UNTRAIN"); in validate_unret()
3906 if (insn->retpoline_safe) in validate_unret()
3915 WARN_INSN(insn, "teh end!"); in validate_unret()
3918 insn = next; in validate_unret()
3930 struct instruction *insn; in validate_unrets() local
3933 for_each_insn(file, insn) { in validate_unrets()
3934 if (!insn->unret) in validate_unrets()
3937 ret = validate_unret(file, insn); in validate_unrets()
3939 WARN_INSN(insn, "Failed UNRET validation"); in validate_unrets()
3950 struct instruction *insn; in validate_retpoline() local
3953 for_each_insn(file, insn) { in validate_retpoline()
3954 if (insn->type != INSN_JUMP_DYNAMIC && in validate_retpoline()
3955 insn->type != INSN_CALL_DYNAMIC && in validate_retpoline()
3956 insn->type != INSN_RETURN) in validate_retpoline()
3959 if (insn->retpoline_safe) in validate_retpoline()
3962 if (insn->sec->init) in validate_retpoline()
3965 if (insn->type == INSN_RETURN) { in validate_retpoline()
3967 WARN_INSN(insn, "'naked' return found in RETHUNK build"); in validate_retpoline()
3971 WARN_INSN(insn, "indirect %s found in RETPOLINE build", in validate_retpoline()
3972 insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); in validate_retpoline()
3981 static bool is_kasan_insn(struct instruction *insn) in is_kasan_insn() argument
3983 return (insn->type == INSN_CALL && in is_kasan_insn()
3984 !strcmp(insn_call_dest(insn)->name, "__asan_handle_no_return")); in is_kasan_insn()
3987 static bool is_ubsan_insn(struct instruction *insn) in is_ubsan_insn() argument
3989 return (insn->type == INSN_CALL && in is_ubsan_insn()
3990 !strcmp(insn_call_dest(insn)->name, in is_ubsan_insn()
3994 static bool ignore_unreachable_insn(struct objtool_file *file, struct instruction *insn) in ignore_unreachable_insn() argument
3999 if (insn->ignore || insn->type == INSN_NOP || insn->type == INSN_TRAP) in ignore_unreachable_insn()
4006 if (!strcmp(insn->sec->name, ".altinstr_replacement") || in ignore_unreachable_insn()
4007 !strcmp(insn->sec->name, ".altinstr_aux")) in ignore_unreachable_insn()
4018 if (opts.link && !insn_func(insn)) { in ignore_unreachable_insn()
4019 int size = find_symbol_hole_containing(insn->sec, insn->offset); in ignore_unreachable_insn()
4020 unsigned long end = insn->offset + size; in ignore_unreachable_insn()
4028 sec_for_each_insn_continue(file, insn) { in ignore_unreachable_insn()
4033 if (insn->visited) in ignore_unreachable_insn()
4036 if (insn->offset >= end) in ignore_unreachable_insn()
4042 if (insn->jump_dest && insn_func(insn->jump_dest) && in ignore_unreachable_insn()
4043 strstr(insn_func(insn->jump_dest)->name, ".cold")) { in ignore_unreachable_insn()
4044 struct instruction *dest = insn->jump_dest; in ignore_unreachable_insn()
4053 if (!insn_func(insn)) in ignore_unreachable_insn()
4056 if (insn_func(insn)->static_call_tramp) in ignore_unreachable_insn()
4067 prev_insn = prev_insn_same_sec(file, insn); in ignore_unreachable_insn()
4069 (insn->type == INSN_BUG || in ignore_unreachable_insn()
4070 (insn->type == INSN_JUMP_UNCONDITIONAL && in ignore_unreachable_insn()
4071 insn->jump_dest && insn->jump_dest->type == INSN_BUG))) in ignore_unreachable_insn()
4082 if (is_kasan_insn(insn) || is_ubsan_insn(insn)) in ignore_unreachable_insn()
4085 if (insn->type == INSN_JUMP_UNCONDITIONAL) { in ignore_unreachable_insn()
4086 if (insn->jump_dest && in ignore_unreachable_insn()
4087 insn_func(insn->jump_dest) == insn_func(insn)) { in ignore_unreachable_insn()
4088 insn = insn->jump_dest; in ignore_unreachable_insn()
4095 if (insn->offset + insn->len >= insn_func(insn)->offset + insn_func(insn)->len) in ignore_unreachable_insn()
4098 insn = next_insn_same_sec(file, insn); in ignore_unreachable_insn()
4106 struct instruction *insn, *prev; in add_prefix_symbol() local
4109 insn = find_insn(file, func->sec, func->offset); in add_prefix_symbol()
4110 if (!insn) in add_prefix_symbol()
4113 for (prev = prev_insn_same_sec(file, insn); in add_prefix_symbol()
4136 if (!insn->cfi) { in add_prefix_symbol()
4145 cfi = cfi_hash_find_or_add(insn->cfi); in add_prefix_symbol()
4146 for (; prev != insn; prev = next_insn_same_sec(file, prev)) in add_prefix_symbol()
4175 struct instruction *insn; in validate_symbol() local
4186 insn = find_insn(file, sec, sym->offset); in validate_symbol()
4187 if (!insn || insn->ignore || insn->visited) in validate_symbol()
4192 ret = validate_branch(file, insn_func(insn), insn, *state); in validate_symbol()
4194 BT_INSN(insn, "<=== (sym)"); in validate_symbol()
4258 static void mark_endbr_used(struct instruction *insn) in mark_endbr_used() argument
4260 if (!list_empty(&insn->call_node)) in mark_endbr_used()
4261 list_del_init(&insn->call_node); in mark_endbr_used()
4264 static bool noendbr_range(struct objtool_file *file, struct instruction *insn) in noendbr_range() argument
4266 struct symbol *sym = find_symbol_containing(insn->sec, insn->offset-1); in noendbr_range()
4279 return insn->offset == sym->offset + sym->len; in noendbr_range()
4282 static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn) in validate_ibt_insn() argument
4293 switch (insn->type) { in validate_ibt_insn()
4307 for (reloc = insn_reloc(file, insn); in validate_ibt_insn()
4309 reloc = find_reloc_by_dest_range(file->elf, insn->sec, in validate_ibt_insn()
4311 (insn->offset + insn->len) - (reloc_offset(reloc) + 1))) { in validate_ibt_insn()
4336 if (insn_func(dest) && insn_func(insn) && in validate_ibt_insn()
4337 insn_func(dest)->pfunc == insn_func(insn)->pfunc) { in validate_ibt_insn()
4369 WARN_INSN(insn, "relocation to !ENDBR: %s", offstr(dest->sec, dest->offset)); in validate_ibt_insn()
4411 struct instruction *insn; in validate_ibt() local
4414 for_each_insn(file, insn) in validate_ibt()
4415 warnings += validate_ibt_insn(file, insn); in validate_ibt()
4459 struct instruction *insn, *next_insn; in validate_sls() local
4462 for_each_insn(file, insn) { in validate_sls()
4463 next_insn = next_insn_same_sec(file, insn); in validate_sls()
4465 if (insn->retpoline_safe) in validate_sls()
4468 switch (insn->type) { in validate_sls()
4471 WARN_INSN(insn, "missing int3 after ret"); in validate_sls()
4478 WARN_INSN(insn, "missing int3 after indirect jump"); in validate_sls()
4490 static bool ignore_noreturn_call(struct instruction *insn) in ignore_noreturn_call() argument
4492 struct symbol *call_dest = insn_call_dest(insn); in ignore_noreturn_call()
4512 insn->sym->warned = 1; in ignore_noreturn_call()
4521 struct instruction *insn, *prev_insn; in validate_reachable_instructions() local
4528 for_each_insn(file, insn) { in validate_reachable_instructions()
4529 if (insn->visited || ignore_unreachable_insn(file, insn)) in validate_reachable_instructions()
4532 prev_insn = prev_insn_same_sec(file, insn); in validate_reachable_instructions()
4536 WARN_INSN(insn, "%s() is missing a __noreturn annotation", in validate_reachable_instructions()
4543 WARN_INSN(insn, "unreachable instruction"); in validate_reachable_instructions()
4637 struct instruction *insn; in free_insns() local
4640 for_each_insn(file, insn) { in free_insns()
4641 if (!insn->idx) { in free_insns()
4643 chunk->addr = insn; in free_insns()