Lines Matching refs:insn

25 	struct instruction *insn;  member
35 struct instruction *insn; in find_insn() local
37 hash_for_each_possible(file->insn_hash, insn, hash, offset) in find_insn()
38 if (insn->sec == sec && insn->offset == offset) in find_insn()
39 return insn; in find_insn()
45 struct instruction *insn) in next_insn_same_sec() argument
47 struct instruction *next = list_next_entry(insn, list); in next_insn_same_sec()
49 if (!next || &next->list == &file->insn_list || next->sec != insn->sec) in next_insn_same_sec()
56 struct instruction *insn) in next_insn_same_func() argument
58 struct instruction *next = list_next_entry(insn, list); in next_insn_same_func()
59 struct symbol *func = insn->func; in next_insn_same_func()
75 #define func_for_each_insn_all(file, func, insn) \ argument
76 for (insn = find_insn(file, func->sec, func->offset); \
77 insn; \
78 insn = next_insn_same_func(file, insn))
80 #define func_for_each_insn(file, func, insn) \ argument
81 for (insn = find_insn(file, func->sec, func->offset); \
82 insn && &insn->list != &file->insn_list && \
83 insn->sec == func->sec && \
84 insn->offset < func->offset + func->len; \
85 insn = list_next_entry(insn, list))
87 #define func_for_each_insn_continue_reverse(file, func, insn) \ argument
88 for (insn = list_prev_entry(insn, list); \
89 &insn->list != &file->insn_list && \
90 insn->sec == func->sec && insn->offset >= func->offset; \
91 insn = list_prev_entry(insn, list))
93 #define sec_for_each_insn_from(file, insn) \ argument
94 for (; insn; insn = next_insn_same_sec(file, insn))
96 #define sec_for_each_insn_continue(file, insn) \ argument
97 for (insn = next_insn_same_sec(file, insn); insn; \
98 insn = next_insn_same_sec(file, insn))
100 static bool is_sibling_call(struct instruction *insn) in is_sibling_call() argument
103 if (insn->type == INSN_JUMP_DYNAMIC) in is_sibling_call()
104 return list_empty(&insn->alts); in is_sibling_call()
106 if (insn->type != INSN_JUMP_CONDITIONAL && in is_sibling_call()
107 insn->type != INSN_JUMP_UNCONDITIONAL) in is_sibling_call()
111 return !!insn->call_dest; in is_sibling_call()
127 struct instruction *insn; in __dead_end_function() local
163 insn = find_insn(file, func->sec, func->offset); in __dead_end_function()
164 if (!insn->func) in __dead_end_function()
167 func_for_each_insn_all(file, func, insn) { in __dead_end_function()
170 if (insn->type == INSN_RETURN) in __dead_end_function()
182 func_for_each_insn_all(file, func, insn) { in __dead_end_function()
183 if (is_sibling_call(insn)) { in __dead_end_function()
184 struct instruction *dest = insn->jump_dest; in __dead_end_function()
235 struct instruction *insn; in decode_instructions() local
248 for (offset = 0; offset < sec->len; offset += insn->len) { in decode_instructions()
249 insn = malloc(sizeof(*insn)); in decode_instructions()
250 if (!insn) { in decode_instructions()
254 memset(insn, 0, sizeof(*insn)); in decode_instructions()
255 INIT_LIST_HEAD(&insn->alts); in decode_instructions()
256 clear_insn_state(&insn->state); in decode_instructions()
258 insn->sec = sec; in decode_instructions()
259 insn->offset = offset; in decode_instructions()
263 &insn->len, &insn->type, in decode_instructions()
264 &insn->immediate, in decode_instructions()
265 &insn->stack_op); in decode_instructions()
269 hash_add(file->insn_hash, &insn->hash, insn->offset); in decode_instructions()
270 list_add_tail(&insn->list, &file->insn_list); in decode_instructions()
283 func_for_each_insn(file, func, insn) in decode_instructions()
284 insn->func = func; in decode_instructions()
291 free(insn); in decode_instructions()
302 struct instruction *insn; in add_dead_ends() local
309 for_each_insn(file, insn) in add_dead_ends()
310 if (insn->type == INSN_BUG) in add_dead_ends()
311 insn->dead_end = true; in add_dead_ends()
325 insn = find_insn(file, rela->sym->sec, rela->addend); in add_dead_ends()
326 if (insn) in add_dead_ends()
327 insn = list_prev_entry(insn, list); in add_dead_ends()
330 list_for_each_entry_reverse(insn, &file->insn_list, list) { in add_dead_ends()
331 if (insn->sec == rela->sym->sec) { in add_dead_ends()
348 insn->dead_end = true; in add_dead_ends()
367 insn = find_insn(file, rela->sym->sec, rela->addend); in add_dead_ends()
368 if (insn) in add_dead_ends()
369 insn = list_prev_entry(insn, list); in add_dead_ends()
372 list_for_each_entry_reverse(insn, &file->insn_list, list) { in add_dead_ends()
373 if (insn->sec == rela->sym->sec) { in add_dead_ends()
390 insn->dead_end = false; in add_dead_ends()
401 struct instruction *insn; in add_ignores() local
427 func_for_each_insn_all(file, func, insn) in add_ignores()
428 insn->ignore = true; in add_ignores()
519 struct instruction *insn; in add_ignore_alternatives() local
531 insn = find_insn(file, rela->sym->sec, rela->addend); in add_ignore_alternatives()
532 if (!insn) { in add_ignore_alternatives()
537 insn->ignore_alts = true; in add_ignore_alternatives()
548 struct instruction *insn; in add_jump_destinations() local
553 for_each_insn(file, insn) { in add_jump_destinations()
554 if (insn->type != INSN_JUMP_CONDITIONAL && in add_jump_destinations()
555 insn->type != INSN_JUMP_UNCONDITIONAL) in add_jump_destinations()
558 if (insn->ignore || insn->offset == FAKE_JUMP_OFFSET) in add_jump_destinations()
561 rela = find_rela_by_dest_range(insn->sec, insn->offset, in add_jump_destinations()
562 insn->len); in add_jump_destinations()
564 dest_sec = insn->sec; in add_jump_destinations()
565 dest_off = insn->offset + insn->len + insn->immediate; in add_jump_destinations()
577 if (insn->type == INSN_JUMP_UNCONDITIONAL) in add_jump_destinations()
578 insn->type = INSN_JUMP_DYNAMIC; in add_jump_destinations()
580 insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL; in add_jump_destinations()
582 insn->retpoline_safe = true; in add_jump_destinations()
586 insn->call_dest = rela->sym; in add_jump_destinations()
590 insn->jump_dest = find_insn(file, dest_sec, dest_off); in add_jump_destinations()
591 if (!insn->jump_dest) { in add_jump_destinations()
598 if (!strcmp(insn->sec->name, ".altinstr_replacement")) in add_jump_destinations()
602 insn->sec, insn->offset, dest_sec->name, in add_jump_destinations()
610 if (insn->func && insn->jump_dest->func && in add_jump_destinations()
611 insn->func != insn->jump_dest->func) { in add_jump_destinations()
628 if (!strstr(insn->func->name, ".cold.") && in add_jump_destinations()
629 strstr(insn->jump_dest->func->name, ".cold.")) { in add_jump_destinations()
630 insn->func->cfunc = insn->jump_dest->func; in add_jump_destinations()
631 insn->jump_dest->func->pfunc = insn->func; in add_jump_destinations()
633 } else if (insn->jump_dest->func->pfunc != insn->func->pfunc && in add_jump_destinations()
634 insn->jump_dest->offset == insn->jump_dest->func->offset) { in add_jump_destinations()
637 insn->call_dest = insn->jump_dest->func; in add_jump_destinations()
650 struct instruction *insn; in add_call_destinations() local
654 for_each_insn(file, insn) { in add_call_destinations()
655 if (insn->type != INSN_CALL) in add_call_destinations()
658 rela = find_rela_by_dest_range(insn->sec, insn->offset, in add_call_destinations()
659 insn->len); in add_call_destinations()
661 dest_off = insn->offset + insn->len + insn->immediate; in add_call_destinations()
662 insn->call_dest = find_symbol_by_offset(insn->sec, in add_call_destinations()
665 if (!insn->call_dest && !insn->ignore) { in add_call_destinations()
667 insn->sec, insn->offset); in add_call_destinations()
674 insn->call_dest = find_symbol_by_offset(rela->sym->sec, in add_call_destinations()
676 if (!insn->call_dest || in add_call_destinations()
677 insn->call_dest->type != STT_FUNC) { in add_call_destinations()
679 insn->sec, insn->offset, in add_call_destinations()
685 insn->call_dest = rela->sym; in add_call_destinations()
713 struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump = NULL; in handle_group_alt() local
717 insn = orig_insn; in handle_group_alt()
718 sec_for_each_insn_from(file, insn) { in handle_group_alt()
719 if (insn->offset >= special_alt->orig_off + special_alt->orig_len) in handle_group_alt()
722 insn->alt_group = true; in handle_group_alt()
723 last_orig_insn = insn; in handle_group_alt()
755 insn = *new_insn; in handle_group_alt()
756 sec_for_each_insn_from(file, insn) { in handle_group_alt()
757 if (insn->offset >= special_alt->new_off + special_alt->new_len) in handle_group_alt()
760 last_new_insn = insn; in handle_group_alt()
762 insn->ignore = orig_insn->ignore_alts; in handle_group_alt()
763 insn->func = orig_insn->func; in handle_group_alt()
765 if (insn->type != INSN_JUMP_CONDITIONAL && in handle_group_alt()
766 insn->type != INSN_JUMP_UNCONDITIONAL) in handle_group_alt()
769 if (!insn->immediate) in handle_group_alt()
772 dest_off = insn->offset + insn->len + insn->immediate; in handle_group_alt()
779 insn->jump_dest = fake_jump; in handle_group_alt()
782 if (!insn->jump_dest) { in handle_group_alt()
784 insn->sec, insn->offset); in handle_group_alt()
885 alt->insn = new_insn; in add_special_section_alts()
898 static int add_jump_table(struct objtool_file *file, struct instruction *insn, in add_jump_table() argument
904 struct symbol *pfunc = insn->func->pfunc; in add_jump_table()
940 alt->insn = dest_insn; in add_jump_table()
941 list_add_tail(&alt->list, &insn->alts); in add_jump_table()
947 insn->sec, insn->offset); in add_jump_table()
999 struct instruction *insn) in find_jump_table() argument
1002 struct instruction *orig_insn = insn; in find_jump_table()
1012 &insn->list != &file->insn_list && in find_jump_table()
1013 insn->sec == func->sec && in find_jump_table()
1014 insn->offset >= func->offset; in find_jump_table()
1016 insn = insn->first_jump_src ?: list_prev_entry(insn, list)) { in find_jump_table()
1018 if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC) in find_jump_table()
1022 if (insn->type == INSN_JUMP_UNCONDITIONAL && in find_jump_table()
1023 insn->jump_dest && in find_jump_table()
1024 (insn->jump_dest->offset <= insn->offset || in find_jump_table()
1025 insn->jump_dest->offset > orig_insn->offset)) in find_jump_table()
1029 text_rela = find_rela_by_dest_range(insn->sec, insn->offset, in find_jump_table()
1030 insn->len); in find_jump_table()
1080 struct instruction *insn, *last = NULL; in mark_func_jump_tables() local
1083 func_for_each_insn_all(file, func, insn) { in mark_func_jump_tables()
1085 last = insn; in mark_func_jump_tables()
1092 if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest && in mark_func_jump_tables()
1093 insn->offset > last->offset && in mark_func_jump_tables()
1094 insn->jump_dest->offset > insn->offset && in mark_func_jump_tables()
1095 !insn->jump_dest->first_jump_src) { in mark_func_jump_tables()
1097 insn->jump_dest->first_jump_src = insn; in mark_func_jump_tables()
1098 last = insn->jump_dest; in mark_func_jump_tables()
1101 if (insn->type != INSN_JUMP_DYNAMIC) in mark_func_jump_tables()
1104 rela = find_jump_table(file, func, insn); in mark_func_jump_tables()
1107 insn->jump_table = rela; in mark_func_jump_tables()
1115 struct instruction *insn; in add_func_jump_tables() local
1118 func_for_each_insn_all(file, func, insn) { in add_func_jump_tables()
1119 if (!insn->jump_table) in add_func_jump_tables()
1122 ret = add_jump_table(file, insn, insn->jump_table); in add_func_jump_tables()
1164 struct instruction *insn; in read_unwind_hints() local
1194 insn = find_insn(file, rela->sym->sec, rela->addend); in read_unwind_hints()
1195 if (!insn) { in read_unwind_hints()
1200 cfa = &insn->state.cfa; in read_unwind_hints()
1203 insn->save = true; in read_unwind_hints()
1207 insn->restore = true; in read_unwind_hints()
1208 insn->hint = true; in read_unwind_hints()
1212 insn->hint = true; in read_unwind_hints()
1241 insn->sec, insn->offset, hint->sp_reg); in read_unwind_hints()
1246 insn->state.type = hint->type; in read_unwind_hints()
1247 insn->state.end = hint->end; in read_unwind_hints()
1256 struct instruction *insn; in read_retpoline_hints() local
1269 insn = find_insn(file, rela->sym->sec, rela->addend); in read_retpoline_hints()
1270 if (!insn) { in read_retpoline_hints()
1275 if (insn->type != INSN_JUMP_DYNAMIC && in read_retpoline_hints()
1276 insn->type != INSN_CALL_DYNAMIC) { in read_retpoline_hints()
1278 insn->sec, insn->offset); in read_retpoline_hints()
1282 insn->retpoline_safe = true; in read_retpoline_hints()
1362 static bool is_fentry_call(struct instruction *insn) in is_fentry_call() argument
1364 if (insn->type == INSN_CALL && in is_fentry_call()
1365 insn->call_dest->type == STT_NOTYPE && in is_fentry_call()
1366 !strcmp(insn->call_dest->name, "__fentry__")) in is_fentry_call()
1402 static int update_insn_state_regs(struct instruction *insn, struct insn_state *state) in update_insn_state_regs() argument
1405 struct stack_op *op = &insn->stack_op; in update_insn_state_regs()
1495 static int update_insn_state(struct instruction *insn, struct insn_state *state) in update_insn_state() argument
1497 struct stack_op *op = &insn->stack_op; in update_insn_state()
1503 if (insn->func) { in update_insn_state()
1504 WARN_FUNC("undefined stack state", insn->sec, insn->offset); in update_insn_state()
1511 return update_insn_state_regs(insn, state); in update_insn_state()
1642 insn->sec, insn->offset); in update_insn_state()
1653 insn->sec, insn->offset); in update_insn_state()
1730 insn->sec, insn->offset); in update_insn_state()
1773 if (!no_fp && insn->func && op->src.reg == CFI_BP && in update_insn_state()
1811 insn->sec, insn->offset); in update_insn_state()
1830 insn->sec, insn->offset); in update_insn_state()
1843 insn->sec, insn->offset); in update_insn_state()
1850 static bool insn_state_match(struct instruction *insn, struct insn_state *state) in insn_state_match() argument
1852 struct insn_state *state1 = &insn->state, *state2 = state; in insn_state_match()
1857 insn->sec, insn->offset, in insn_state_match()
1868 insn->sec, insn->offset, in insn_state_match()
1876 insn->sec, insn->offset, state1->type, state2->type); in insn_state_match()
1882 insn->sec, insn->offset, in insn_state_match()
1900 static inline const char *call_dest_name(struct instruction *insn) in call_dest_name() argument
1902 if (insn->call_dest) in call_dest_name()
1903 return insn->call_dest->name; in call_dest_name()
1908 static int validate_call(struct instruction *insn, struct insn_state *state) in validate_call() argument
1910 if (state->uaccess && !func_uaccess_safe(insn->call_dest)) { in validate_call()
1912 insn->sec, insn->offset, call_dest_name(insn)); in validate_call()
1918 insn->sec, insn->offset, call_dest_name(insn)); in validate_call()
1925 static int validate_sibling_call(struct instruction *insn, struct insn_state *state) in validate_sibling_call() argument
1929 insn->sec, insn->offset); in validate_sibling_call()
1933 return validate_call(insn, state); in validate_sibling_call()
1946 struct instruction *insn, *next_insn; in validate_branch() local
1951 insn = first; in validate_branch()
1952 sec = insn->sec; in validate_branch()
1954 if (insn->alt_group && list_empty(&insn->alts)) { in validate_branch()
1956 sec, insn->offset); in validate_branch()
1961 next_insn = next_insn_same_sec(file, insn); in validate_branch()
1963 if (file->c_file && func && insn->func && func != insn->func->pfunc) { in validate_branch()
1965 func->name, insn->func->name); in validate_branch()
1969 if (func && insn->ignore) { in validate_branch()
1971 sec, insn->offset); in validate_branch()
1976 if (insn->visited) { in validate_branch()
1977 if (!insn->hint && !insn_state_match(insn, &state)) in validate_branch()
1980 if (insn->visited & visited) in validate_branch()
1984 if (insn->hint) { in validate_branch()
1985 if (insn->restore) { in validate_branch()
1988 i = insn; in validate_branch()
1999 sec, insn->offset); in validate_branch()
2011 if (insn == first) in validate_branch()
2015 sec, insn->offset); in validate_branch()
2019 insn->state = save_insn->state; in validate_branch()
2022 state = insn->state; in validate_branch()
2025 insn->state = state; in validate_branch()
2027 insn->visited |= visited; in validate_branch()
2029 if (!insn->ignore_alts) { in validate_branch()
2032 list_for_each_entry(alt, &insn->alts, list) { in validate_branch()
2036 ret = validate_branch(file, func, alt->insn, state); in validate_branch()
2039 BT_FUNC("(alt)", insn); in validate_branch()
2048 switch (insn->type) { in validate_branch()
2052 WARN_FUNC("return with UACCESS enabled", sec, insn->offset); in validate_branch()
2057 WARN_FUNC("return with UACCESS disabled from a UACCESS-safe function", sec, insn->offset); in validate_branch()
2062 WARN_FUNC("return with DF set", sec, insn->offset); in validate_branch()
2068 sec, insn->offset); in validate_branch()
2082 ret = validate_call(insn, &state); in validate_branch()
2086 if (!no_fp && func && !is_fentry_call(insn) && in validate_branch()
2089 sec, insn->offset); in validate_branch()
2093 if (dead_end_function(file, insn->call_dest)) in validate_branch()
2100 if (func && is_sibling_call(insn)) { in validate_branch()
2101 ret = validate_sibling_call(insn, &state); in validate_branch()
2105 } else if (insn->jump_dest) { in validate_branch()
2107 insn->jump_dest, state); in validate_branch()
2110 BT_FUNC("(branch)", insn); in validate_branch()
2115 if (insn->type == INSN_JUMP_UNCONDITIONAL) in validate_branch()
2122 if (func && is_sibling_call(insn)) { in validate_branch()
2123 ret = validate_sibling_call(insn, &state); in validate_branch()
2128 if (insn->type == INSN_JUMP_DYNAMIC) in validate_branch()
2136 sec, insn->offset); in validate_branch()
2142 if (update_insn_state(insn, &state)) in validate_branch()
2145 if (insn->stack_op.dest.type == OP_DEST_PUSHF) { in validate_branch()
2149 WARN_FUNC("PUSHF stack exhausted", sec, insn->offset); in validate_branch()
2156 if (insn->stack_op.src.type == OP_SRC_POPF) { in validate_branch()
2169 WARN_FUNC("recursive UACCESS enable", sec, insn->offset); in validate_branch()
2178 WARN_FUNC("redundant UACCESS disable", sec, insn->offset); in validate_branch()
2183 WARN_FUNC("UACCESS-safe disables UACCESS", sec, insn->offset); in validate_branch()
2192 WARN_FUNC("recursive STD", sec, insn->offset); in validate_branch()
2199 WARN_FUNC("redundant CLD", sec, insn->offset); in validate_branch()
2208 if (insn->dead_end) in validate_branch()
2218 insn = next_insn; in validate_branch()
2226 struct instruction *insn; in validate_unwind_hints() local
2235 for_each_insn(file, insn) { in validate_unwind_hints()
2236 if (insn->hint && !insn->visited) { in validate_unwind_hints()
2237 ret = validate_branch(file, insn->func, insn, state); in validate_unwind_hints()
2239 BT_FUNC("<=== (hint)", insn); in validate_unwind_hints()
2249 struct instruction *insn; in validate_retpoline() local
2252 for_each_insn(file, insn) { in validate_retpoline()
2253 if (insn->type != INSN_JUMP_DYNAMIC && in validate_retpoline()
2254 insn->type != INSN_CALL_DYNAMIC) in validate_retpoline()
2257 if (insn->retpoline_safe) in validate_retpoline()
2266 if (!strcmp(insn->sec->name, ".init.text") && !module) in validate_retpoline()
2270 insn->sec, insn->offset, in validate_retpoline()
2271 insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); in validate_retpoline()
2279 static bool is_kasan_insn(struct instruction *insn) in is_kasan_insn() argument
2281 return (insn->type == INSN_CALL && in is_kasan_insn()
2282 !strcmp(insn->call_dest->name, "__asan_handle_no_return")); in is_kasan_insn()
2285 static bool is_ubsan_insn(struct instruction *insn) in is_ubsan_insn() argument
2287 return (insn->type == INSN_CALL && in is_ubsan_insn()
2288 !strcmp(insn->call_dest->name, in is_ubsan_insn()
2292 static bool ignore_unreachable_insn(struct instruction *insn) in ignore_unreachable_insn() argument
2296 if (insn->ignore || insn->type == INSN_NOP) in ignore_unreachable_insn()
2306 if (!strcmp(insn->sec->name, ".fixup") || in ignore_unreachable_insn()
2307 !strcmp(insn->sec->name, ".altinstr_replacement") || in ignore_unreachable_insn()
2308 !strcmp(insn->sec->name, ".altinstr_aux")) in ignore_unreachable_insn()
2317 if (!insn->func) in ignore_unreachable_insn()
2321 if (is_kasan_insn(insn) || is_ubsan_insn(insn)) in ignore_unreachable_insn()
2324 if (insn->type == INSN_JUMP_UNCONDITIONAL) { in ignore_unreachable_insn()
2325 if (insn->jump_dest && in ignore_unreachable_insn()
2326 insn->jump_dest->func == insn->func) { in ignore_unreachable_insn()
2327 insn = insn->jump_dest; in ignore_unreachable_insn()
2334 if (insn->offset + insn->len >= insn->func->offset + insn->func->len) in ignore_unreachable_insn()
2337 insn = list_next_entry(insn, list); in ignore_unreachable_insn()
2347 struct instruction *insn; in validate_functions() local
2372 insn = find_insn(file, sec, func->offset); in validate_functions()
2373 if (!insn || insn->ignore || insn->visited) in validate_functions()
2378 ret = validate_branch(file, func, insn, state); in validate_functions()
2380 BT_FUNC("<=== (func)", insn); in validate_functions()
2390 struct instruction *insn; in validate_reachable_instructions() local
2395 for_each_insn(file, insn) { in validate_reachable_instructions()
2396 if (insn->visited || ignore_unreachable_insn(insn)) in validate_reachable_instructions()
2399 WARN_FUNC("unreachable instruction", insn->sec, insn->offset); in validate_reachable_instructions()
2408 struct instruction *insn, *tmpinsn; in cleanup() local
2411 list_for_each_entry_safe(insn, tmpinsn, &file->insn_list, list) { in cleanup()
2412 list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) { in cleanup()
2416 list_del(&insn->list); in cleanup()
2417 hash_del(&insn->hash); in cleanup()
2418 free(insn); in cleanup()