Lines Matching +full:tsan +full:- +full:build
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com>
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()
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()
57 if (!insn->len) in next_insn_same_sec()
76 if (func == func->cfunc) in next_insn_same_func()
80 return find_insn(file, func->cfunc->sec, func->cfunc->offset); in next_insn_same_func()
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()
113 for (insn = find_insn(file, func->sec, func->offset); \
118 for (insn = find_insn(file, sym->sec, sym->offset); \
119 insn && insn->offset < sym->offset + sym->len; \
124 insn && insn->offset >= sym->offset; \
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()
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()
154 struct alt_group *alt_group = insn->alt_group; in is_jump_table_jump()
160 return alt_group && alt_group->orig_group && in is_jump_table_jump()
161 insn_jump_table(alt_group->orig_group->first_insn); in is_jump_table_jump()
167 * Assume only STT_FUNC calls have jump-tables. in is_sibling_call()
171 if (insn->type == INSN_JUMP_DYNAMIC) in is_sibling_call()
204 if (func->bind == STB_GLOBAL || func->bind == STB_WEAK) in __dead_end_function()
206 if (!strcmp(func->name, global_noreturns[i])) in __dead_end_function()
209 if (func->bind == STB_WEAK) in __dead_end_function()
212 if (!func->len) in __dead_end_function()
215 insn = find_insn(file, func->sec, func->offset); in __dead_end_function()
222 if (insn->type == INSN_RETURN) in __dead_end_function()
231 * case, the function's dead-end status depends on whether the target in __dead_end_function()
236 struct instruction *dest = insn->jump_dest; in __dead_end_function()
269 cfi->regs[i].base = CFI_UNDEFINED; in init_cfi_state()
270 cfi->vals[i].base = CFI_UNDEFINED; in init_cfi_state()
272 cfi->cfa.base = CFI_UNDEFINED; in init_cfi_state()
273 cfi->drap_reg = CFI_UNDEFINED; in init_cfi_state()
274 cfi->drap_offset = -1; in init_cfi_state()
281 init_cfi_state(&state->cfi); in init_insn_state()
285 * not correctly determine insn_call_dest(insn)->sec (external symbols in init_insn_state()
289 state->noinstr = sec->noinstr; in init_insn_state()
308 return memcmp((void *)cfi1 + sizeof(cfi1->hash), in cficmp()
309 (void *)cfi2 + sizeof(cfi2->hash), in cficmp()
310 sizeof(struct cfi_state) - sizeof(struct hlist_node)); in cficmp()
315 return jhash((void *)cfi + sizeof(cfi->hash), in cfi_key()
316 sizeof(*cfi) - sizeof(cfi->hash), 0); in cfi_key()
333 hlist_add_head(&obj->hash, head); in cfi_hash_find_or_add()
342 hlist_add_head(&cfi->hash, head); in cfi_hash_add()
350 MAP_PRIVATE|MAP_ANON, -1, 0); in cfi_hash_alloc()
351 if (cfi_hash == (void *)-1L) { in cfi_hash_alloc()
365 * Call the arch-specific instruction decoder for all the instructions and add
381 if (!(sec->sh.sh_flags & SHF_EXECINSTR)) in decode_instructions()
384 if (strcmp(sec->name, ".altinstr_replacement") && in decode_instructions()
385 strcmp(sec->name, ".altinstr_aux") && in decode_instructions()
386 strncmp(sec->name, ".discard.", 9)) in decode_instructions()
387 sec->text = true; in decode_instructions()
389 if (!strcmp(sec->name, ".noinstr.text") || in decode_instructions()
390 !strcmp(sec->name, ".entry.text") || in decode_instructions()
391 !strcmp(sec->name, ".cpuidle.text") || in decode_instructions()
392 !strncmp(sec->name, ".text..__x86.", 13)) in decode_instructions()
393 sec->noinstr = true; in decode_instructions()
401 if (!strcmp(sec->name, ".init.text") && !opts.module) in decode_instructions()
402 sec->init = true; in decode_instructions()
404 for (offset = 0; offset < sec->sh.sh_size; offset += insn->len) { in decode_instructions()
409 return -1; 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()
424 sec->sh.sh_size - offset, in decode_instructions()
429 prev_len = insn->len; in decode_instructions()
434 * divide-by-zero cases. 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()
443 // printf("%s: last chunk used: %d\n", sec->name, (int)idx); in decode_instructions()
446 if (func->type != STT_NOTYPE && func->type != STT_FUNC) in decode_instructions()
449 if (func->offset == sec->sh.sh_size) { in decode_instructions()
451 if (func->type == STT_NOTYPE) in decode_instructions()
454 func->name); in decode_instructions()
455 return -1; in decode_instructions()
458 if (func->embedded_insn || func->alias != func) in decode_instructions()
461 if (!find_insn(file, sec, func->offset)) { in decode_instructions()
463 func->name); in decode_instructions()
464 return -1; in decode_instructions()
468 insn->sym = func; in decode_instructions()
469 if (func->type == STT_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()
474 file->nr_endbr++; in decode_instructions()
476 file->nr_endbr_int++; in decode_instructions()
499 sym = find_symbol_by_name(file->elf, symname); in add_pv_ops()
503 off = sym->offset; in add_pv_ops()
504 end = off + sym->len; in add_pv_ops()
506 reloc = find_reloc_by_dest_range(file->elf, sym->sec, off, end - off); in add_pv_ops()
510 func = reloc->sym; in add_pv_ops()
511 if (func->type == STT_SECTION) in add_pv_ops()
512 func = find_symbol_by_offset(reloc->sym->sec, in add_pv_ops()
515 idx = (reloc_offset(reloc) - sym->offset) / sizeof(unsigned long); in add_pv_ops()
528 * Allocate and initialize file->pv_ops[].
546 file->pv_ops = NULL; in init_pv_ops()
548 sym = find_symbol_by_name(file->elf, "pv_ops"); in init_pv_ops()
552 nr = sym->len / sizeof(unsigned long); in init_pv_ops()
553 file->pv_ops = calloc(sizeof(struct pv_state), nr); in init_pv_ops()
554 if (!file->pv_ops) in init_pv_ops()
555 return -1; in init_pv_ops()
558 INIT_LIST_HEAD(&file->pv_ops[idx].targets); in init_pv_ops()
571 unsigned int end = (sec->sh.sh_size > 10) ? sec->sh.sh_size - 10 : 0; in find_last_insn()
573 for (offset = sec->sh.sh_size - 1; offset >= end && !insn; offset--) in find_last_insn()
592 rsec = find_section_by_name(file->elf, ".rela.discard.unreachable"); in add_dead_ends()
598 if (reloc->sym->type != STT_SECTION) { in add_dead_ends()
599 WARN("unexpected relocation symbol type in %s", rsec->name); in add_dead_ends()
600 return -1; in add_dead_ends()
605 insn = find_insn(file, reloc->sym->sec, addend); in add_dead_ends()
608 else if (addend == reloc->sym->sec->sh.sh_size) { in add_dead_ends()
609 insn = find_last_insn(file, reloc->sym->sec); in add_dead_ends()
612 reloc->sym->sec->name, addend); in add_dead_ends()
613 return -1; in add_dead_ends()
617 reloc->sym->sec->name, addend); in add_dead_ends()
618 return -1; in add_dead_ends()
621 insn->dead_end = true; in add_dead_ends()
631 rsec = find_section_by_name(file->elf, ".rela.discard.reachable"); in add_dead_ends()
637 if (reloc->sym->type != STT_SECTION) { in add_dead_ends()
638 WARN("unexpected relocation symbol type in %s", rsec->name); in add_dead_ends()
639 return -1; in add_dead_ends()
644 insn = find_insn(file, reloc->sym->sec, addend); in add_dead_ends()
647 else if (addend == reloc->sym->sec->sh.sh_size) { in add_dead_ends()
648 insn = find_last_insn(file, reloc->sym->sec); in add_dead_ends()
651 reloc->sym->sec->name, addend); in add_dead_ends()
652 return -1; in add_dead_ends()
656 reloc->sym->sec->name, addend); in add_dead_ends()
657 return -1; in add_dead_ends()
660 insn->dead_end = false; in add_dead_ends()
675 sec = find_section_by_name(file->elf, ".static_call_sites"); in create_static_call_sections()
677 INIT_LIST_HEAD(&file->static_call_list); in create_static_call_sections()
682 if (list_empty(&file->static_call_list)) in create_static_call_sections()
686 list_for_each_entry(insn, &file->static_call_list, call_node) in create_static_call_sections()
689 sec = elf_create_section_pair(file->elf, ".static_call_sites", in create_static_call_sections()
692 return -1; in create_static_call_sections()
695 sec->sh.sh_flags |= SHF_WRITE; in create_static_call_sections()
698 list_for_each_entry(insn, &file->static_call_list, call_node) { in create_static_call_sections()
701 if (!elf_init_reloc_text_sym(file->elf, sec, in create_static_call_sections()
703 insn->sec, insn->offset)) in create_static_call_sections()
704 return -1; in create_static_call_sections()
707 key_name = strdup(insn_call_dest(insn)->name); in create_static_call_sections()
710 return -1; in create_static_call_sections()
716 return -1; in create_static_call_sections()
718 tmp = key_name + STATIC_CALL_TRAMP_PREFIX_LEN - STATIC_CALL_KEY_PREFIX_LEN; in create_static_call_sections()
721 key_sym = find_symbol_by_name(file->elf, tmp); in create_static_call_sections()
726 return -1; in create_static_call_sections()
743 if (!elf_init_reloc_data_sym(file->elf, sec, in create_static_call_sections()
747 return -1; in create_static_call_sections()
761 sec = find_section_by_name(file->elf, ".retpoline_sites"); in create_retpoline_sites_sections()
768 list_for_each_entry(insn, &file->retpoline_call_list, call_node) in create_retpoline_sites_sections()
774 sec = elf_create_section_pair(file->elf, ".retpoline_sites", in create_retpoline_sites_sections()
777 return -1; in create_retpoline_sites_sections()
780 list_for_each_entry(insn, &file->retpoline_call_list, call_node) { in create_retpoline_sites_sections()
782 if (!elf_init_reloc_text_sym(file->elf, sec, in create_retpoline_sites_sections()
784 insn->sec, insn->offset)) in create_retpoline_sites_sections()
785 return -1; in create_retpoline_sites_sections()
799 sec = find_section_by_name(file->elf, ".return_sites"); in create_return_sites_sections()
806 list_for_each_entry(insn, &file->return_thunk_list, call_node) in create_return_sites_sections()
812 sec = elf_create_section_pair(file->elf, ".return_sites", in create_return_sites_sections()
815 return -1; in create_return_sites_sections()
818 list_for_each_entry(insn, &file->return_thunk_list, call_node) { in create_return_sites_sections()
820 if (!elf_init_reloc_text_sym(file->elf, sec, in create_return_sites_sections()
822 insn->sec, insn->offset)) in create_return_sites_sections()
823 return -1; in create_return_sites_sections()
837 sec = find_section_by_name(file->elf, ".ibt_endbr_seal"); in create_ibt_endbr_seal_sections()
844 list_for_each_entry(insn, &file->endbr_list, call_node) in create_ibt_endbr_seal_sections()
848 printf("ibt: ENDBR at function start: %d\n", file->nr_endbr); in create_ibt_endbr_seal_sections()
849 printf("ibt: ENDBR inside functions: %d\n", file->nr_endbr_int); in create_ibt_endbr_seal_sections()
856 sec = elf_create_section_pair(file->elf, ".ibt_endbr_seal", in create_ibt_endbr_seal_sections()
859 return -1; in create_ibt_endbr_seal_sections()
862 list_for_each_entry(insn, &file->endbr_list, call_node) { in create_ibt_endbr_seal_sections()
864 int *site = (int *)sec->data->d_buf + idx; in create_ibt_endbr_seal_sections()
865 struct symbol *sym = insn->sym; in create_ibt_endbr_seal_sections()
868 if (opts.module && sym && sym->type == STT_FUNC && in create_ibt_endbr_seal_sections()
869 insn->offset == sym->offset && in create_ibt_endbr_seal_sections()
870 (!strcmp(sym->name, "init_module") || in create_ibt_endbr_seal_sections()
871 !strcmp(sym->name, "cleanup_module"))) in create_ibt_endbr_seal_sections()
872 WARN("%s(): not an indirect call target", sym->name); in create_ibt_endbr_seal_sections()
874 if (!elf_init_reloc_text_sym(file->elf, sec, in create_ibt_endbr_seal_sections()
876 insn->sec, insn->offset)) in create_ibt_endbr_seal_sections()
877 return -1; in create_ibt_endbr_seal_sections()
891 sec = find_section_by_name(file->elf, ".cfi_sites"); in create_cfi_sections()
893 INIT_LIST_HEAD(&file->call_list); in create_cfi_sections()
900 if (sym->type != STT_FUNC) in create_cfi_sections()
903 if (strncmp(sym->name, "__cfi_", 6)) in create_cfi_sections()
909 sec = elf_create_section_pair(file->elf, ".cfi_sites", in create_cfi_sections()
912 return -1; in create_cfi_sections()
916 if (sym->type != STT_FUNC) in create_cfi_sections()
919 if (strncmp(sym->name, "__cfi_", 6)) in create_cfi_sections()
922 if (!elf_init_reloc_text_sym(file->elf, sec, in create_cfi_sections()
924 sym->sec, sym->offset)) in create_cfi_sections()
925 return -1; in create_cfi_sections()
935 size_t addr_size = elf_addr_size(file->elf); in create_mcount_loc_sections()
940 sec = find_section_by_name(file->elf, "__mcount_loc"); in create_mcount_loc_sections()
942 INIT_LIST_HEAD(&file->mcount_loc_list); in create_mcount_loc_sections()
947 if (list_empty(&file->mcount_loc_list)) in create_mcount_loc_sections()
951 list_for_each_entry(insn, &file->mcount_loc_list, call_node) in create_mcount_loc_sections()
954 sec = elf_create_section_pair(file->elf, "__mcount_loc", addr_size, in create_mcount_loc_sections()
957 return -1; in create_mcount_loc_sections()
959 sec->sh.sh_addralign = addr_size; in create_mcount_loc_sections()
962 list_for_each_entry(insn, &file->mcount_loc_list, call_node) { in create_mcount_loc_sections()
966 reloc = elf_init_reloc_text_sym(file->elf, sec, idx * addr_size, idx, in create_mcount_loc_sections()
967 insn->sec, insn->offset); in create_mcount_loc_sections()
969 return -1; in create_mcount_loc_sections()
971 set_reloc_type(file->elf, reloc, addr_size == 8 ? R_ABS64 : R_ABS32); in create_mcount_loc_sections()
985 sec = find_section_by_name(file->elf, ".call_sites"); in create_direct_call_sections()
987 INIT_LIST_HEAD(&file->call_list); in create_direct_call_sections()
992 if (list_empty(&file->call_list)) in create_direct_call_sections()
996 list_for_each_entry(insn, &file->call_list, call_node) in create_direct_call_sections()
999 sec = elf_create_section_pair(file->elf, ".call_sites", in create_direct_call_sections()
1002 return -1; in create_direct_call_sections()
1005 list_for_each_entry(insn, &file->call_list, call_node) { in create_direct_call_sections()
1007 if (!elf_init_reloc_text_sym(file->elf, sec, in create_direct_call_sections()
1009 insn->sec, insn->offset)) in create_direct_call_sections()
1010 return -1; in create_direct_call_sections()
1028 rsec = find_section_by_name(file->elf, ".rela.discard.func_stack_frame_non_standard"); in add_ignores()
1033 switch (reloc->sym->type) { in add_ignores()
1035 func = reloc->sym; in add_ignores()
1039 func = find_func_by_offset(reloc->sym->sec, reloc_addend(reloc)); in add_ignores()
1046 rsec->name, reloc->sym->type); in add_ignores()
1051 insn->ignore = true; in add_ignores()
1066 /* KASAN out-of-line */
1081 /* KASAN in-line */
1105 /* KCSAN/TSAN */
1249 func = find_symbol_by_name(file->elf, *name); in add_uaccess_safe()
1253 func->uaccess_safe = true; in add_uaccess_safe()
1269 rsec = find_section_by_name(file->elf, ".rela.discard.ignore_alts"); in add_ignore_alternatives()
1274 if (reloc->sym->type != STT_SECTION) { in add_ignore_alternatives()
1275 WARN("unexpected relocation symbol type in %s", rsec->name); in add_ignore_alternatives()
1276 return -1; in add_ignore_alternatives()
1279 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in add_ignore_alternatives()
1282 return -1; in add_ignore_alternatives()
1285 insn->ignore_alts = true; in add_ignore_alternatives()
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()
1342 for (op = insn->stack_ops; op; op = next) { in remove_insn_ops()
1343 next = op->next; in remove_insn_ops()
1346 insn->stack_ops = NULL; in remove_insn_ops()
1356 sym = reloc->sym; in annotate_call_site()
1364 if (!strcmp(insn->sec->name, ".altinstr_replacement")) in annotate_call_site()
1367 if (sym->static_call_tramp) { in annotate_call_site()
1368 list_add_tail(&insn->call_node, &file->static_call_list); in annotate_call_site()
1372 if (sym->retpoline_thunk) { 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()
1384 set_reloc_type(file->elf, reloc, R_NONE); 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()
1395 * We've replaced the tail-call JMP insn by two new in annotate_call_site()
1400 insn->retpoline_safe = true; in annotate_call_site()
1406 if (opts.mcount && sym->fentry) { in annotate_call_site()
1411 set_reloc_type(file->elf, reloc, R_NONE); 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()
1434 insn->_call_dest = dest; in add_call_dest()
1442 * Annotated intra-function calls retain the stack_ops but in add_call_dest()
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()
1476 * Annotated intra-function calls retain the stack_ops but in add_retpoline_call()
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()
1500 if (insn->offset == sym->offset) in is_first_func_insn()
1507 if (prev && prev->type == INSN_ENDBR && in is_first_func_insn()
1508 insn->offset == sym->offset + prev->len) in is_first_func_insn()
1516 * A sibling call is a tail-call to another symbol -- to differentiate from a
1517 * recursive tail-call which is to the same symbol.
1522 struct symbol *fs = from->sym; in jump_is_sibling_call()
1523 struct symbol *ts = to->sym; in jump_is_sibling_call()
1534 if (ts->type == STT_NOTYPE) in jump_is_sibling_call()
1538 return fs->pfunc != ts->pfunc; in jump_is_sibling_call()
1552 if (insn->jump_dest) { in add_jump_destinations()
1564 dest_sec = insn->sec; in add_jump_destinations()
1566 } else if (reloc->sym->type == STT_SECTION) { in add_jump_destinations()
1567 dest_sec = reloc->sym->sec; in add_jump_destinations()
1569 } else if (reloc->sym->retpoline_thunk) { in add_jump_destinations()
1572 } else if (reloc->sym->return_thunk) { in add_jump_destinations()
1580 add_call_dest(file, insn, reloc->sym, true); in add_jump_destinations()
1582 } else if (reloc->sym->sec->idx) { in add_jump_destinations()
1583 dest_sec = reloc->sym->sec; in add_jump_destinations()
1584 dest_off = reloc->sym->sym.st_value + in add_jump_destinations()
1587 /* non-func asm code jumping to another file */ in add_jump_destinations()
1603 if (sym && sym->embedded_insn) { in add_jump_destinations()
1609 dest_sec->name, dest_off); in add_jump_destinations()
1610 return -1; in add_jump_destinations()
1614 * Cross-function jump. in add_jump_destinations()
1634 if (!strstr(insn_func(insn)->name, ".cold") && in add_jump_destinations()
1635 strstr(insn_func(jump_dest)->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()
1650 insn->jump_dest = jump_dest; in add_jump_destinations()
1678 if (insn->type != INSN_CALL) in add_call_destinations()
1684 dest = find_call_destination(insn->sec, dest_off); in add_call_destinations()
1688 if (insn->ignore) in add_call_destinations()
1692 WARN_INSN(insn, "unannotated intra-function call"); in add_call_destinations()
1693 return -1; 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()
1698 return -1; in add_call_destinations()
1701 } else if (reloc->sym->type == STT_SECTION) { in add_call_destinations()
1703 dest = find_call_destination(reloc->sym->sec, dest_off); in add_call_destinations()
1706 reloc->sym->sec->name, dest_off); in add_call_destinations()
1707 return -1; in add_call_destinations()
1712 } else if (reloc->sym->retpoline_thunk) { in add_call_destinations()
1716 add_call_dest(file, insn, reloc->sym, false); in add_call_destinations()
1735 orig_alt_group = orig_insn->alt_group; in handle_group_alt()
1742 return -1; in handle_group_alt()
1744 orig_alt_group->cfi = calloc(special_alt->orig_len, in handle_group_alt()
1746 if (!orig_alt_group->cfi) { in handle_group_alt()
1748 return -1; 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()
1759 orig_alt_group->orig_group = NULL; in handle_group_alt()
1760 orig_alt_group->first_insn = orig_insn; in handle_group_alt()
1761 orig_alt_group->last_insn = last_orig_insn; in handle_group_alt()
1762 orig_alt_group->nop = NULL; in handle_group_alt()
1764 if (orig_alt_group->last_insn->offset + orig_alt_group->last_insn->len - in handle_group_alt()
1765 orig_alt_group->first_insn->offset != special_alt->orig_len) { in handle_group_alt()
1767 orig_alt_group->last_insn->offset + in handle_group_alt()
1768 orig_alt_group->last_insn->len - in handle_group_alt()
1769 orig_alt_group->first_insn->offset, in handle_group_alt()
1770 special_alt->orig_len); in handle_group_alt()
1771 return -1; in handle_group_alt()
1778 return -1; in handle_group_alt()
1781 if (special_alt->new_len < special_alt->orig_len) { in handle_group_alt()
1792 return -1; in handle_group_alt()
1796 nop->sec = special_alt->new_sec; in handle_group_alt()
1797 nop->offset = special_alt->new_off + special_alt->new_len; in handle_group_alt()
1798 nop->len = special_alt->orig_len - special_alt->new_len; in handle_group_alt()
1799 nop->type = INSN_NOP; in handle_group_alt()
1800 nop->sym = orig_insn->sym; in handle_group_alt()
1801 nop->alt_group = new_alt_group; in handle_group_alt()
1802 nop->ignore = orig_insn->ignore_alts; in handle_group_alt()
1805 if (!special_alt->new_len) { in handle_group_alt()
1814 if (insn->offset >= special_alt->new_off + special_alt->new_len) 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()
1826 * have relative-address relocation references to outside the in handle_group_alt()
1836 return -1; in handle_group_alt()
1842 if (!insn->immediate) in handle_group_alt()
1846 if (dest_off == special_alt->new_off + special_alt->new_len) { 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()
1850 return -1; in handle_group_alt()
1857 special_alt->new_sec, special_alt->new_off); in handle_group_alt()
1858 return -1; in handle_group_alt()
1862 new_alt_group->orig_group = orig_alt_group; in handle_group_alt()
1863 new_alt_group->first_insn = *new_insn; in handle_group_alt()
1864 new_alt_group->last_insn = last_new_insn; in handle_group_alt()
1865 new_alt_group->nop = nop; in handle_group_alt()
1866 new_alt_group->cfi = orig_alt_group->cfi; in handle_group_alt()
1880 if (orig_insn->type != INSN_JUMP_UNCONDITIONAL && in handle_jump_alt()
1881 orig_insn->type != INSN_NOP) { in handle_jump_alt()
1884 return -1; in handle_jump_alt()
1887 if (opts.hack_jump_label && special_alt->key_addend & 2) { in handle_jump_alt()
1891 set_reloc_type(file->elf, reloc, R_NONE); in handle_jump_alt()
1892 elf_write_insn(file->elf, orig_insn->sec, in handle_jump_alt()
1893 orig_insn->offset, orig_insn->len, in handle_jump_alt()
1894 arch_nop_insn(orig_insn->len)); in handle_jump_alt()
1895 orig_insn->type = INSN_NOP; in handle_jump_alt()
1898 if (orig_insn->type == INSN_NOP) { in handle_jump_alt()
1899 if (orig_insn->len == 2) in handle_jump_alt()
1900 file->jl_nop_short++; in handle_jump_alt()
1902 file->jl_nop_long++; in handle_jump_alt()
1907 if (orig_insn->len == 2) in handle_jump_alt()
1908 file->jl_short++; in handle_jump_alt()
1910 file->jl_long++; in handle_jump_alt()
1919 * instruction(s) has them added to its insn->alts list, which will be
1930 ret = special_get_alts(file->elf, &special_alts); in add_special_section_alts()
1936 orig_insn = find_insn(file, special_alt->orig_sec, in add_special_section_alts()
1937 special_alt->orig_off); in add_special_section_alts()
1940 special_alt->orig_sec, special_alt->orig_off); in add_special_section_alts()
1941 ret = -1; in add_special_section_alts()
1946 if (!special_alt->group || special_alt->new_len) { in add_special_section_alts()
1947 new_insn = find_insn(file, special_alt->new_sec, in add_special_section_alts()
1948 special_alt->new_off); in add_special_section_alts()
1951 special_alt->new_sec, in add_special_section_alts()
1952 special_alt->new_off); in add_special_section_alts()
1953 ret = -1; in add_special_section_alts()
1958 if (special_alt->group) { in add_special_section_alts()
1959 if (!special_alt->orig_len) { in add_special_section_alts()
1968 } else if (special_alt->jump_or_nop) { in add_special_section_alts()
1978 ret = -1; in add_special_section_alts()
1982 alt->insn = new_insn; in add_special_section_alts()
1983 alt->skip_orig = special_alt->skip_orig; in add_special_section_alts()
1984 orig_insn->ignore_alts |= special_alt->skip_alt; in add_special_section_alts()
1985 alt->next = orig_insn->alts; in add_special_section_alts()
1986 orig_insn->alts = alt; in add_special_section_alts()
1988 list_del(&special_alt->list); in add_special_section_alts()
1994 printf("short:\t%ld\t%ld\n", file->jl_nop_short, file->jl_short); in add_special_section_alts()
1995 printf("long:\t%ld\t%ld\n", file->jl_nop_long, file->jl_long); in add_special_section_alts()
2005 struct symbol *pfunc = insn_func(insn)->pfunc; in add_jump_table()
2016 for_each_reloc_from(table->sec, reloc) { in add_jump_table()
2027 if (reloc->sym->sec == pfunc->sec && in add_jump_table()
2028 reloc_addend(reloc) == pfunc->offset) in add_jump_table()
2031 dest_insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in add_jump_table()
2036 if (!insn_func(dest_insn) || insn_func(dest_insn)->pfunc != pfunc) in add_jump_table()
2042 return -1; 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()
2053 return -1; in add_jump_table()
2060 * find_jump_table() - Given a dynamic jump, find the switch 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()
2092 dest_insn = find_insn(file, table_reloc->sym->sec, reloc_addend(table_reloc)); in find_jump_table()
2093 if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func) in find_jump_table()
2117 * Store back-pointers for unconditional forward jumps such in mark_func_jump_tables()
2118 * that find_jump_table() can back-track using those and 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()
2135 insn->_jump_table = reloc; in mark_func_jump_tables()
2172 * This finds these jump tables and adds them to the insn->alts lists.
2179 if (!file->rodata) in add_jump_table_alts()
2183 if (func->type != STT_FUNC) in add_jump_table_alts()
2197 state->cfa = initial_func_cfi.cfa; in set_func_state()
2198 memcpy(&state->regs, &initial_func_cfi.regs, in set_func_state()
2200 state->stack_size = initial_func_cfi.cfa.offset; in set_func_state()
2201 state->type = UNWIND_HINT_TYPE_CALL; in set_func_state()
2213 sec = find_section_by_name(file->elf, ".discard.unwind_hints"); in read_unwind_hints()
2217 if (!sec->rsec) { in read_unwind_hints()
2219 return -1; in read_unwind_hints()
2222 if (sec->sh.sh_size % sizeof(struct unwind_hint)) { in read_unwind_hints()
2224 return -1; in read_unwind_hints()
2227 file->hints = true; in read_unwind_hints()
2229 for (i = 0; i < sec->sh.sh_size / sizeof(struct unwind_hint); i++) { in read_unwind_hints()
2230 hint = (struct unwind_hint *)sec->data->d_buf + i; in read_unwind_hints()
2232 reloc = find_reloc_by_dest(file->elf, sec, i * sizeof(*hint)); in read_unwind_hints()
2235 return -1; in read_unwind_hints()
2238 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_unwind_hints()
2241 return -1; in read_unwind_hints()
2244 insn->hint = true; in read_unwind_hints()
2246 if (hint->type == UNWIND_HINT_TYPE_UNDEFINED) { in read_unwind_hints()
2247 insn->cfi = &force_undefined_cfi; in read_unwind_hints()
2251 if (hint->type == UNWIND_HINT_TYPE_SAVE) { in read_unwind_hints()
2252 insn->hint = false; in read_unwind_hints()
2253 insn->save = true; in read_unwind_hints()
2257 if (hint->type == UNWIND_HINT_TYPE_RESTORE) { in read_unwind_hints()
2258 insn->restore = true; in read_unwind_hints()
2262 if (hint->type == UNWIND_HINT_TYPE_REGS_PARTIAL) { in read_unwind_hints()
2263 struct symbol *sym = find_symbol_by_offset(insn->sec, insn->offset); in read_unwind_hints()
2265 if (sym && sym->bind == STB_GLOBAL) { in read_unwind_hints()
2266 if (opts.ibt && insn->type != INSN_ENDBR && !insn->noendbr) { in read_unwind_hints()
2272 if (hint->type == UNWIND_HINT_TYPE_FUNC) { 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()
2280 if (arch_decode_hint_reg(hint->sp_reg, &cfi.cfa.base)) { in read_unwind_hints()
2281 WARN_INSN(insn, "unsupported unwind_hint sp base reg %d", hint->sp_reg); in read_unwind_hints()
2282 return -1; in read_unwind_hints()
2285 cfi.cfa.offset = bswap_if_needed(file->elf, hint->sp_offset); in read_unwind_hints()
2286 cfi.type = hint->type; in read_unwind_hints()
2287 cfi.signal = hint->signal; in read_unwind_hints()
2289 insn->cfi = cfi_hash_find_or_add(&cfi); in read_unwind_hints()
2301 rsec = find_section_by_name(file->elf, ".rela.discard.noendbr"); in read_noendbr_hints()
2306 insn = find_insn(file, reloc->sym->sec, in read_noendbr_hints()
2307 reloc->sym->offset + reloc_addend(reloc)); in read_noendbr_hints()
2310 return -1; in read_noendbr_hints()
2313 insn->noendbr = 1; in read_noendbr_hints()
2325 rsec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe"); in read_retpoline_hints()
2330 if (reloc->sym->type != STT_SECTION) { in read_retpoline_hints()
2331 WARN("unexpected relocation symbol type in %s", rsec->name); in read_retpoline_hints()
2332 return -1; in read_retpoline_hints()
2335 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_retpoline_hints()
2338 return -1; 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()
2346 return -1; in read_retpoline_hints()
2349 insn->retpoline_safe = true; in read_retpoline_hints()
2361 rsec = find_section_by_name(file->elf, ".rela.discard.instr_end"); in read_instr_hints()
2366 if (reloc->sym->type != STT_SECTION) { in read_instr_hints()
2367 WARN("unexpected relocation symbol type in %s", rsec->name); in read_instr_hints()
2368 return -1; in read_instr_hints()
2371 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_instr_hints()
2374 return -1; in read_instr_hints()
2377 insn->instr--; in read_instr_hints()
2380 rsec = find_section_by_name(file->elf, ".rela.discard.instr_begin"); in read_instr_hints()
2385 if (reloc->sym->type != STT_SECTION) { in read_instr_hints()
2386 WARN("unexpected relocation symbol type in %s", rsec->name); in read_instr_hints()
2387 return -1; in read_instr_hints()
2390 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_instr_hints()
2393 return -1; in read_instr_hints()
2396 insn->instr++; in read_instr_hints()
2408 rsec = find_section_by_name(file->elf, ".rela.discard.validate_unret"); in read_validate_unret_hints()
2413 if (reloc->sym->type != STT_SECTION) { in read_validate_unret_hints()
2414 WARN("unexpected relocation symbol type in %s", rsec->name); in read_validate_unret_hints()
2415 return -1; in read_validate_unret_hints()
2418 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_validate_unret_hints()
2421 return -1; in read_validate_unret_hints()
2423 insn->unret = 1; in read_validate_unret_hints()
2436 rsec = find_section_by_name(file->elf, ".rela.discard.intra_function_calls"); in read_intra_function_calls()
2443 if (reloc->sym->type != STT_SECTION) { in read_intra_function_calls()
2445 rsec->name); in read_intra_function_calls()
2446 return -1; in read_intra_function_calls()
2449 insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); in read_intra_function_calls()
2452 return -1; in read_intra_function_calls()
2455 if (insn->type != INSN_CALL) { in read_intra_function_calls()
2457 return -1; in read_intra_function_calls()
2461 * Treat intra-function CALLs as JMPs, but with a stack_op. in read_intra_function_calls()
2465 insn->type = INSN_JUMP_UNCONDITIONAL; 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()
2471 insn->sec->name, dest_off); in read_intra_function_calls()
2472 return -1; in read_intra_function_calls()
2509 if (func->bind != STB_GLOBAL) in classify_symbols()
2512 if (!strncmp(func->name, STATIC_CALL_TRAMP_PREFIX_STR, in classify_symbols()
2514 func->static_call_tramp = true; in classify_symbols()
2517 func->retpoline_thunk = true; in classify_symbols()
2520 func->return_thunk = true; in classify_symbols()
2523 func->embedded_insn = true; in classify_symbols()
2525 if (arch_ftrace_match(func->name)) in classify_symbols()
2526 func->fentry = true; in classify_symbols()
2528 if (is_profiling_func(func->name)) in classify_symbols()
2529 func->profiling_func = true; in classify_symbols()
2544 * - .rodata: can contain GCC switch tables in mark_rodata()
2545 * - .rodata.<func>: same, if -fdata-sections is being used in mark_rodata()
2546 * - .rodata..c_jump_table: contains C annotated jump tables in mark_rodata()
2551 if (!strncmp(sec->name, ".rodata", 7) && in mark_rodata()
2552 !strstr(sec->name, ".str1.")) { in mark_rodata()
2553 sec->rodata = true; in mark_rodata()
2558 file->rodata = found; in mark_rodata()
2590 * Must be before read_unwind_hints() since that needs insn->noendbr. in decode_sections()
2655 if (insn->type == INSN_CALL) { in is_special_call()
2661 if (dest->fentry || dest->embedded_insn) in is_special_call()
2670 struct cfi_state *cfi = &state->cfi; in has_modified_stack_frame()
2673 if (cfi->cfa.base != initial_func_cfi.cfa.base || cfi->drap) in has_modified_stack_frame()
2676 if (cfi->cfa.offset != initial_func_cfi.cfa.offset) in has_modified_stack_frame()
2679 if (cfi->stack_size != initial_func_cfi.cfa.offset) in has_modified_stack_frame()
2683 if (cfi->regs[i].base != initial_func_cfi.regs[i].base || in has_modified_stack_frame()
2684 cfi->regs[i].offset != initial_func_cfi.regs[i].offset) in has_modified_stack_frame()
2694 return reg->base == CFI_CFA && in check_reg_frame_pos()
2695 reg->offset == expected_offset; in check_reg_frame_pos()
2700 struct cfi_state *cfi = &state->cfi; in has_valid_stack_frame()
2702 if (cfi->cfa.base == CFI_BP && in has_valid_stack_frame()
2703 check_reg_frame_pos(&cfi->regs[CFI_BP], -cfi->cfa.offset) && in has_valid_stack_frame()
2704 check_reg_frame_pos(&cfi->regs[CFI_RA], -cfi->cfa.offset + 8)) in has_valid_stack_frame()
2707 if (cfi->drap && cfi->regs[CFI_BP].base == CFI_BP) in has_valid_stack_frame()
2717 struct cfi_reg *cfa = &cfi->cfa; in update_cfi_state_regs()
2719 if (cfa->base != CFI_SP && cfa->base != CFI_SP_INDIRECT) in update_cfi_state_regs()
2723 if (op->dest.type == OP_DEST_PUSH || op->dest.type == OP_DEST_PUSHF) in update_cfi_state_regs()
2724 cfa->offset += 8; in update_cfi_state_regs()
2727 if (op->src.type == OP_SRC_POP || op->src.type == OP_SRC_POPF) in update_cfi_state_regs()
2728 cfa->offset -= 8; in update_cfi_state_regs()
2731 if (op->dest.type == OP_DEST_REG && op->src.type == OP_SRC_ADD && in update_cfi_state_regs()
2732 op->dest.reg == CFI_SP && op->src.reg == CFI_SP) in update_cfi_state_regs()
2733 cfa->offset -= op->src.offset; in update_cfi_state_regs()
2741 cfi->regs[reg].base == CFI_UNDEFINED) { in save_reg()
2742 cfi->regs[reg].base = base; in save_reg()
2743 cfi->regs[reg].offset = offset; in save_reg()
2749 cfi->regs[reg].base = initial_func_cfi.regs[reg].base; in restore_reg()
2750 cfi->regs[reg].offset = initial_func_cfi.regs[reg].offset; in restore_reg()
2762 * 41 ff 72 f8 pushq -0x8(%r10)
2771 * 49 8d 62 f8 lea -0x8(%r10),%rsp
2782 * 49 8d 62 f8 lea -0x8(%r10),%rsp
2787 * 4c 8b 55 e8 mov -0x18(%rbp),%r10
2788 * 48 8b 5d e0 mov -0x20(%rbp),%rbx
2789 * 4c 8b 65 f0 mov -0x10(%rbp),%r12
2790 * 4c 8b 6d f8 mov -0x8(%rbp),%r13
2792 * 49 8d 62 f8 lea -0x8(%r10),%rsp
2802 * 49 8d 65 f0 lea -0x10(%r13),%rsp
2810 struct cfi_reg *cfa = &cfi->cfa; in update_cfi_state()
2811 struct cfi_reg *regs = cfi->regs; in update_cfi_state()
2814 if (cfi->force_undefined) in update_cfi_state()
2818 if (cfa->base == CFI_UNDEFINED) { in update_cfi_state()
2821 return -1; in update_cfi_state()
2826 if (cfi->type == UNWIND_HINT_TYPE_REGS || in update_cfi_state()
2827 cfi->type == UNWIND_HINT_TYPE_REGS_PARTIAL) in update_cfi_state()
2830 switch (op->dest.type) { in update_cfi_state()
2833 switch (op->src.type) { in update_cfi_state()
2836 if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP && in update_cfi_state()
2837 cfa->base == CFI_SP && in update_cfi_state()
2838 check_reg_frame_pos(®s[CFI_BP], -cfa->offset)) { in update_cfi_state()
2841 cfa->base = op->dest.reg; in update_cfi_state()
2842 cfi->bp_scratch = false; in update_cfi_state()
2845 else if (op->src.reg == CFI_SP && in update_cfi_state()
2846 op->dest.reg == CFI_BP && cfi->drap) { in update_cfi_state()
2850 regs[CFI_BP].offset = -cfi->stack_size; in update_cfi_state()
2851 cfi->bp_scratch = false; in update_cfi_state()
2854 else if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { in update_cfi_state()
2866 cfi->vals[op->dest.reg].base = CFI_CFA; in update_cfi_state()
2867 cfi->vals[op->dest.reg].offset = -cfi->stack_size; in update_cfi_state()
2870 else if (op->src.reg == CFI_BP && op->dest.reg == CFI_SP && in update_cfi_state()
2871 (cfa->base == CFI_BP || cfa->base == cfi->drap_reg)) { in update_cfi_state()
2878 cfi->stack_size = -cfi->regs[CFI_BP].offset; in update_cfi_state()
2881 else if (op->dest.reg == cfa->base) { in update_cfi_state()
2884 if (cfa->base == CFI_SP && in update_cfi_state()
2885 cfi->vals[op->src.reg].base == CFI_CFA) { in update_cfi_state()
2895 cfa->offset = -cfi->vals[op->src.reg].offset; in update_cfi_state()
2896 cfi->stack_size = cfa->offset; in update_cfi_state()
2898 } else if (cfa->base == CFI_SP && in update_cfi_state()
2899 cfi->vals[op->src.reg].base == CFI_SP_INDIRECT && in update_cfi_state()
2900 cfi->vals[op->src.reg].offset == cfa->offset) { in update_cfi_state()
2912 * 1 - places a pointer to the previous in update_cfi_state()
2913 * stack at the Top-of-Stack of the in update_cfi_state()
2916 * 2 - switches to the new stack. in update_cfi_state()
2918 * 3 - pops the Top-of-Stack to restore in update_cfi_state()
2928 cfa->base = CFI_SP_INDIRECT; in update_cfi_state()
2931 cfa->base = CFI_UNDEFINED; in update_cfi_state()
2932 cfa->offset = 0; in update_cfi_state()
2936 else if (op->dest.reg == CFI_SP && in update_cfi_state()
2937 cfi->vals[op->src.reg].base == CFI_SP_INDIRECT && in update_cfi_state()
2938 cfi->vals[op->src.reg].offset == cfa->offset) { in update_cfi_state()
2942 * because we can't change cfa->base, case 3) in update_cfi_state()
2946 cfi->stack_size += 8; in update_cfi_state()
2953 if (op->dest.reg == CFI_SP && op->src.reg == CFI_SP) { in update_cfi_state()
2956 cfi->stack_size -= op->src.offset; in update_cfi_state()
2957 if (cfa->base == CFI_SP) in update_cfi_state()
2958 cfa->offset -= op->src.offset; in update_cfi_state()
2962 if (op->dest.reg == CFI_SP && op->src.reg == CFI_BP) { in update_cfi_state()
2965 cfi->stack_size = -(op->src.offset + regs[CFI_BP].offset); in update_cfi_state()
2969 if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { in update_cfi_state()
2972 cfi->drap_reg = op->dest.reg; in update_cfi_state()
2984 cfi->vals[op->dest.reg].base = CFI_CFA; in update_cfi_state()
2985 cfi->vals[op->dest.reg].offset = \ in update_cfi_state()
2986 -cfi->stack_size + op->src.offset; in update_cfi_state()
2991 if (cfi->drap && op->dest.reg == CFI_SP && in update_cfi_state()
2992 op->src.reg == cfi->drap_reg) { in update_cfi_state()
2995 cfa->base = CFI_SP; in update_cfi_state()
2996 cfa->offset = cfi->stack_size = -op->src.offset; in update_cfi_state()
2997 cfi->drap_reg = CFI_UNDEFINED; in update_cfi_state()
2998 cfi->drap = false; in update_cfi_state()
3002 if (op->dest.reg == cfi->cfa.base && !(next_insn && next_insn->hint)) { in update_cfi_state()
3004 return -1; in update_cfi_state()
3010 if (op->dest.reg != CFI_SP || in update_cfi_state()
3011 (cfi->drap_reg != CFI_UNDEFINED && cfa->base != CFI_SP) || in update_cfi_state()
3012 (cfi->drap_reg == CFI_UNDEFINED && cfa->base != CFI_BP)) { in update_cfi_state()
3014 return -1; in update_cfi_state()
3017 if (cfi->drap_reg != CFI_UNDEFINED) { in update_cfi_state()
3019 cfa->base = cfi->drap_reg; in update_cfi_state()
3020 cfa->offset = cfi->stack_size = 0; in update_cfi_state()
3021 cfi->drap = true; in update_cfi_state()
3033 if (op->dest.reg == CFI_SP && cfa->base == CFI_SP_INDIRECT) { in update_cfi_state()
3036 cfa->base = CFI_SP; in update_cfi_state()
3040 if (!cfi->drap && op->dest.reg == cfa->base) { in update_cfi_state()
3043 cfa->base = CFI_SP; in update_cfi_state()
3046 if (cfi->drap && cfa->base == CFI_BP_INDIRECT && in update_cfi_state()
3047 op->dest.reg == cfi->drap_reg && in update_cfi_state()
3048 cfi->drap_offset == -cfi->stack_size) { in update_cfi_state()
3051 cfa->base = cfi->drap_reg; in update_cfi_state()
3052 cfa->offset = 0; in update_cfi_state()
3053 cfi->drap_offset = -1; in update_cfi_state()
3055 } else if (cfi->stack_size == -regs[op->dest.reg].offset) { in update_cfi_state()
3058 restore_reg(cfi, op->dest.reg); in update_cfi_state()
3061 cfi->stack_size -= 8; in update_cfi_state()
3062 if (cfa->base == CFI_SP) in update_cfi_state()
3063 cfa->offset -= 8; in update_cfi_state()
3068 if (!cfi->drap && op->dest.reg == cfa->base && in update_cfi_state()
3069 op->dest.reg == CFI_BP) { in update_cfi_state()
3072 cfa->base = CFI_SP; in update_cfi_state()
3073 cfa->offset = cfi->stack_size; in update_cfi_state()
3076 if (cfi->drap && op->src.reg == CFI_BP && in update_cfi_state()
3077 op->src.offset == cfi->drap_offset) { in update_cfi_state()
3080 cfa->base = cfi->drap_reg; in update_cfi_state()
3081 cfa->offset = 0; in update_cfi_state()
3082 cfi->drap_offset = -1; in update_cfi_state()
3085 if (cfi->drap && op->src.reg == CFI_BP && in update_cfi_state()
3086 op->src.offset == regs[op->dest.reg].offset) { in update_cfi_state()
3089 restore_reg(cfi, op->dest.reg); in update_cfi_state()
3091 } else if (op->src.reg == cfa->base && in update_cfi_state()
3092 op->src.offset == regs[op->dest.reg].offset + cfa->offset) { in update_cfi_state()
3096 restore_reg(cfi, op->dest.reg); in update_cfi_state()
3098 } else if (op->src.reg == CFI_SP && in update_cfi_state()
3099 op->src.offset == regs[op->dest.reg].offset + cfi->stack_size) { in update_cfi_state()
3102 restore_reg(cfi, op->dest.reg); in update_cfi_state()
3108 WARN_INSN(insn, "unknown stack-related instruction"); in update_cfi_state()
3109 return -1; in update_cfi_state()
3116 cfi->stack_size += 8; in update_cfi_state()
3117 if (cfa->base == CFI_SP) in update_cfi_state()
3118 cfa->offset += 8; in update_cfi_state()
3120 if (op->src.type != OP_SRC_REG) in update_cfi_state()
3123 if (cfi->drap) { in update_cfi_state()
3124 if (op->src.reg == cfa->base && op->src.reg == cfi->drap_reg) { in update_cfi_state()
3127 cfa->base = CFI_BP_INDIRECT; in update_cfi_state()
3128 cfa->offset = -cfi->stack_size; in update_cfi_state()
3131 cfi->drap_offset = -cfi->stack_size; in update_cfi_state()
3133 } else if (op->src.reg == CFI_BP && cfa->base == cfi->drap_reg) { in update_cfi_state()
3136 cfi->stack_size = 0; in update_cfi_state()
3141 save_reg(cfi, op->src.reg, CFI_BP, -cfi->stack_size); in update_cfi_state()
3147 save_reg(cfi, op->src.reg, CFI_CFA, -cfi->stack_size); in update_cfi_state()
3151 if (opts.stackval && insn_func(insn) && op->src.reg == CFI_BP && in update_cfi_state()
3152 cfa->base != CFI_BP) in update_cfi_state()
3153 cfi->bp_scratch = true; in update_cfi_state()
3158 if (cfi->drap) { in update_cfi_state()
3159 if (op->src.reg == cfa->base && op->src.reg == cfi->drap_reg) { in update_cfi_state()
3162 cfa->base = CFI_BP_INDIRECT; in update_cfi_state()
3163 cfa->offset = op->dest.offset; in update_cfi_state()
3166 cfi->drap_offset = op->dest.offset; in update_cfi_state()
3170 save_reg(cfi, op->src.reg, CFI_BP, op->dest.offset); in update_cfi_state()
3173 } else if (op->dest.reg == cfa->base) { in update_cfi_state()
3177 save_reg(cfi, op->src.reg, CFI_CFA, in update_cfi_state()
3178 op->dest.offset - cfi->cfa.offset); in update_cfi_state()
3180 } else if (op->dest.reg == CFI_SP) { in update_cfi_state()
3183 save_reg(cfi, op->src.reg, CFI_CFA, in update_cfi_state()
3184 op->dest.offset - cfi->stack_size); in update_cfi_state()
3186 } else if (op->src.reg == CFI_SP && op->dest.offset == 0) { in update_cfi_state()
3189 cfi->vals[op->dest.reg].base = CFI_SP_INDIRECT; in update_cfi_state()
3190 cfi->vals[op->dest.reg].offset = cfa->offset; in update_cfi_state()
3196 if (op->src.type != OP_SRC_POP && op->src.type != OP_SRC_POPF) { in update_cfi_state()
3197 WARN_INSN(insn, "unknown stack-related memory operation"); in update_cfi_state()
3198 return -1; in update_cfi_state()
3202 cfi->stack_size -= 8; in update_cfi_state()
3203 if (cfa->base == CFI_SP) in update_cfi_state()
3204 cfa->offset -= 8; in update_cfi_state()
3209 WARN_INSN(insn, "unknown stack-related instruction"); in update_cfi_state()
3210 return -1; in update_cfi_state()
3230 if (!insn->alt_group) in propagate_alt_cfi()
3233 if (!insn->cfi) { in propagate_alt_cfi()
3235 return -1; 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()
3246 struct instruction *orig = orig_group->first_insn; in propagate_alt_cfi()
3247 char *where = offstr(insn->sec, insn->offset); in propagate_alt_cfi()
3250 return -1; in propagate_alt_cfi()
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()
3271 if (op->dest.type == OP_DEST_PUSHF) { in handle_insn_ops()
3272 if (!state->uaccess_stack) { in handle_insn_ops()
3273 state->uaccess_stack = 1; in handle_insn_ops()
3274 } else if (state->uaccess_stack >> 31) { in handle_insn_ops()
3278 state->uaccess_stack <<= 1; in handle_insn_ops()
3279 state->uaccess_stack |= state->uaccess; in handle_insn_ops()
3282 if (op->src.type == OP_SRC_POPF) { in handle_insn_ops()
3283 if (state->uaccess_stack) { in handle_insn_ops()
3284 state->uaccess = state->uaccess_stack & 1; in handle_insn_ops()
3285 state->uaccess_stack >>= 1; in handle_insn_ops()
3286 if (state->uaccess_stack == 1) in handle_insn_ops()
3287 state->uaccess_stack = 0; in handle_insn_ops()
3297 struct cfi_state *cfi1 = insn->cfi; in insn_cfi_match()
3305 if (memcmp(&cfi1->cfa, &cfi2->cfa, sizeof(cfi1->cfa))) { in insn_cfi_match()
3308 cfi1->cfa.base, cfi1->cfa.offset, in insn_cfi_match()
3309 cfi2->cfa.base, cfi2->cfa.offset); in insn_cfi_match()
3311 } else if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) { in insn_cfi_match()
3313 if (!memcmp(&cfi1->regs[i], &cfi2->regs[i], in insn_cfi_match()
3318 i, cfi1->regs[i].base, cfi1->regs[i].offset, in insn_cfi_match()
3319 i, cfi2->regs[i].base, cfi2->regs[i].offset); in insn_cfi_match()
3323 } else if (cfi1->type != cfi2->type) { in insn_cfi_match()
3326 cfi1->type, cfi2->type); in insn_cfi_match()
3328 } else if (cfi1->drap != cfi2->drap || in insn_cfi_match()
3329 (cfi1->drap && cfi1->drap_reg != cfi2->drap_reg) || in insn_cfi_match()
3330 (cfi1->drap && cfi1->drap_offset != cfi2->drap_offset)) { in insn_cfi_match()
3333 cfi1->drap, cfi1->drap_reg, cfi1->drap_offset, in insn_cfi_match()
3334 cfi2->drap, cfi2->drap_reg, cfi2->drap_offset); in insn_cfi_match()
3345 return func->uaccess_safe; in func_uaccess_safe()
3357 return insn_call_dest(insn)->name; in call_dest_name()
3360 if (reloc && !strcmp(reloc->sym->name, "pv_ops")) { in call_dest_name()
3376 if (!reloc || strcmp(reloc->sym->name, "pv_ops")) in pv_call_dest()
3381 if (file->pv_ops[idx].clean) in pv_call_dest()
3384 file->pv_ops[idx].clean = true; in pv_call_dest()
3386 list_for_each_entry(target, &file->pv_ops[idx].targets, pv_target) { in pv_call_dest()
3387 if (!target->sec->noinstr) { in pv_call_dest()
3388 WARN("pv_ops[%d]: %s", idx, target->name); in pv_call_dest()
3389 file->pv_ops[idx].clean = false; in pv_call_dest()
3393 return file->pv_ops[idx].clean; in pv_call_dest()
3405 if (file->pv_ops) in noinstr_call_dest()
3414 if (func->sec->noinstr) in noinstr_call_dest()
3420 if (func->static_call_tramp) in noinstr_call_dest()
3428 if (!strncmp(func->name, "__ubsan_handle_", 15)) in noinstr_call_dest()
3438 if (state->noinstr && state->instr <= 0 && in validate_call()
3444 if (state->uaccess && !func_uaccess_safe(insn_call_dest(insn))) { in validate_call()
3449 if (state->df) { in validate_call()
3471 if (state->noinstr && state->instr > 0) { in validate_return()
3476 if (state->uaccess && !func_uaccess_safe(func)) { in validate_return()
3481 if (!state->uaccess && func_uaccess_safe(func)) { in validate_return()
3482 WARN_INSN(insn, "return with UACCESS disabled from a UACCESS-safe function"); in validate_return()
3486 if (state->df) { in validate_return()
3496 if (state->cfi.bp_scratch) { in validate_return()
3507 struct alt_group *alt_group = insn->alt_group; in next_insn_to_validate()
3510 * Simulate the fact that alternatives are patched in-place. When the in next_insn_to_validate()
3514 * insn->alts->insn -> alt_group->first_insn in next_insn_to_validate()
3516 * alt_group->last_insn in next_insn_to_validate()
3517 * [alt_group->nop] -> next(orig_group->last_insn) in next_insn_to_validate()
3520 if (alt_group->nop) { in next_insn_to_validate()
3521 /* ->nop implies ->orig_group */ in next_insn_to_validate()
3522 if (insn == alt_group->last_insn) in next_insn_to_validate()
3523 return alt_group->nop; 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()
3534 return next_insn_same_sec(file, alt_group->orig_group->last_insn); in next_insn_to_validate()
3552 sec = insn->sec; in validate_branch()
3557 if (func && insn_func(insn) && func != insn_func(insn)->pfunc) { in validate_branch()
3559 if (!strncmp(func->name, "__cfi_", 6) || in validate_branch()
3560 !strncmp(func->name, "__pfx_", 6)) in validate_branch()
3564 func->name, insn_func(insn)->name); in validate_branch()
3568 if (func && insn->ignore) { 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()
3595 if (i->save) { in validate_branch()
3606 if (!save_insn->visited) { in validate_branch()
3614 * straight-line path. in validate_branch()
3623 insn->cfi = save_insn->cfi; in validate_branch()
3627 state.cfi = *insn->cfi; in validate_branch()
3631 if (prev_insn && !cficmp(prev_insn->cfi, &state.cfi)) { in validate_branch()
3632 insn->cfi = prev_insn->cfi; in validate_branch()
3635 insn->cfi = cfi_hash_find_or_add(&state.cfi); in validate_branch()
3639 insn->visited |= visited; in validate_branch()
3644 if (!insn->ignore_alts && insn->alts) { in validate_branch()
3647 for (alt = insn->alts; alt; alt = alt->next) { in validate_branch()
3648 if (alt->skip_orig) in validate_branch()
3651 ret = validate_branch(file, func, alt->insn, state); in validate_branch()
3665 switch (insn->type) { in validate_branch()
3682 if (insn->dead_end) in validate_branch()
3694 } else if (insn->jump_dest) { in validate_branch()
3696 insn->jump_dest, state); in validate_branch()
3703 if (insn->type == INSN_JUMP_UNCONDITIONAL) in validate_branch()
3716 if (insn->type == INSN_JUMP_DYNAMIC) in validate_branch()
3723 if (!next_insn || !next_insn->hint) { in validate_branch()
3747 WARN_INSN(insn, "UACCESS-safe disables UACCESS"); in validate_branch()
3776 if (insn->dead_end) in validate_branch()
3782 WARN("%s: unexpected end of section", sec->name); in validate_branch()
3797 if (insn->hint && !insn->visited && !insn->ignore) { in validate_unwind_hint()
3813 if (!file->hints) in validate_unwind_hints()
3832 * Follow every branch (intra-function) and ensure VALIDATE_UNRET_END comes
3843 if (insn->visited & VISITED_UNRET) in validate_unret()
3846 insn->visited |= VISITED_UNRET; in validate_unret()
3848 if (!insn->ignore_alts && insn->alts) { in validate_unret()
3852 for (alt = insn->alts; alt; alt = alt->next) { in validate_unret()
3853 if (alt->skip_orig) in validate_unret()
3856 ret = validate_unret(file, alt->insn); in validate_unret()
3867 switch (insn->type) { in validate_unret()
3878 if (!insn->jump_dest) { in validate_unret()
3880 return -1; in validate_unret()
3882 ret = validate_unret(file, insn->jump_dest); in validate_unret()
3885 insn->type == INSN_JUMP_CONDITIONAL ? "-cond" : ""); in validate_unret()
3889 if (insn->type == INSN_JUMP_UNCONDITIONAL) in validate_unret()
3897 dest = find_insn(file, insn_call_dest(insn)->sec, in validate_unret()
3898 insn_call_dest(insn)->offset); in validate_unret()
3901 insn_call_dest(insn)->name); in validate_unret()
3902 return -1; in validate_unret()
3912 * Therefore any non-error return is a success. in validate_unret()
3921 if (insn->retpoline_safe) in validate_unret()
3931 return -1; in validate_unret()
3949 if (!insn->unret) in validate_unrets()
3969 if (insn->type != INSN_JUMP_DYNAMIC && in validate_retpoline()
3970 insn->type != INSN_CALL_DYNAMIC && in validate_retpoline()
3971 insn->type != INSN_RETURN) in validate_retpoline()
3974 if (insn->retpoline_safe) in validate_retpoline()
3977 if (insn->sec->init) in validate_retpoline()
3980 if (insn->type == INSN_RETURN) { in validate_retpoline()
3982 WARN_INSN(insn, "'naked' return found in RETHUNK build"); in validate_retpoline()
3986 WARN_INSN(insn, "indirect %s found in RETPOLINE build", in validate_retpoline()
3987 insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); in validate_retpoline()
3998 return (insn->type == INSN_CALL && in is_kasan_insn()
3999 !strcmp(insn_call_dest(insn)->name, "__asan_handle_no_return")); in is_kasan_insn()
4004 return (insn->type == INSN_CALL && in is_ubsan_insn()
4005 !strcmp(insn_call_dest(insn)->name, in is_ubsan_insn()
4014 if (insn->ignore || insn->type == INSN_NOP || insn->type == INSN_TRAP) in ignore_unreachable_insn()
4021 if (!strcmp(insn->sec->name, ".altinstr_replacement") || in ignore_unreachable_insn()
4022 !strcmp(insn->sec->name, ".altinstr_aux")) in ignore_unreachable_insn()
4034 int size = find_symbol_hole_containing(insn->sec, insn->offset); in ignore_unreachable_insn()
4035 unsigned long end = insn->offset + size; in ignore_unreachable_insn()
4048 if (insn->visited) in ignore_unreachable_insn()
4051 if (insn->offset >= end) in ignore_unreachable_insn()
4057 if (insn->jump_dest && insn_func(insn->jump_dest) && in ignore_unreachable_insn()
4058 strstr(insn_func(insn->jump_dest)->name, ".cold")) { in ignore_unreachable_insn()
4059 struct instruction *dest = insn->jump_dest; in ignore_unreachable_insn()
4061 dest->ignore = true; in ignore_unreachable_insn()
4071 if (insn_func(insn)->static_call_tramp) in ignore_unreachable_insn()
4083 if (prev_insn->dead_end && in ignore_unreachable_insn()
4084 (insn->type == INSN_BUG || in ignore_unreachable_insn()
4085 (insn->type == INSN_JUMP_UNCONDITIONAL && in ignore_unreachable_insn()
4086 insn->jump_dest && insn->jump_dest->type == INSN_BUG))) in ignore_unreachable_insn()
4100 if (insn->type == INSN_JUMP_UNCONDITIONAL) { in ignore_unreachable_insn()
4101 if (insn->jump_dest && in ignore_unreachable_insn()
4102 insn_func(insn->jump_dest) == insn_func(insn)) { in ignore_unreachable_insn()
4103 insn = insn->jump_dest; in ignore_unreachable_insn()
4110 if (insn->offset + insn->len >= insn_func(insn)->offset + insn_func(insn)->len) in ignore_unreachable_insn()
4124 insn = find_insn(file, func->sec, func->offset); in add_prefix_symbol()
4126 return -1; in add_prefix_symbol()
4133 if (prev->type != INSN_NOP) in add_prefix_symbol()
4134 return -1; in add_prefix_symbol()
4136 offset = func->offset - prev->offset; in add_prefix_symbol()
4139 return -1; in add_prefix_symbol()
4144 elf_create_prefix_symbol(file->elf, func, opts.prefix); in add_prefix_symbol()
4149 return -1; in add_prefix_symbol()
4151 if (!insn->cfi) { in add_prefix_symbol()
4159 /* Propagate insn->cfi to the prefix code */ in add_prefix_symbol()
4160 cfi = cfi_hash_find_or_add(insn->cfi); in add_prefix_symbol()
4162 prev->cfi = cfi; in add_prefix_symbol()
4173 if (!(sec->sh.sh_flags & SHF_EXECINSTR)) in add_prefix_symbols()
4177 if (func->type != STT_FUNC) in add_prefix_symbols()
4193 if (!sym->len) { in validate_symbol()
4194 WARN("%s() is missing an ELF size annotation", sym->name); in validate_symbol()
4198 if (sym->pfunc != sym || sym->alias != sym) in validate_symbol()
4201 insn = find_insn(file, sec, sym->offset); in validate_symbol()
4202 if (!insn || insn->ignore || insn->visited) in validate_symbol()
4205 state->uaccess = sym->uaccess_safe; in validate_symbol()
4220 if (func->type != STT_FUNC) in validate_section()
4237 sec = find_section_by_name(file->elf, ".noinstr.text"); in validate_noinstr_sections()
4243 sec = find_section_by_name(file->elf, ".entry.text"); in validate_noinstr_sections()
4249 sec = find_section_by_name(file->elf, ".cpuidle.text"); in validate_noinstr_sections()
4264 if (!(sec->sh.sh_flags & SHF_EXECINSTR)) in validate_functions()
4275 if (!list_empty(&insn->call_node)) in mark_endbr_used()
4276 list_del_init(&insn->call_node); in mark_endbr_used()
4281 struct symbol *sym = find_symbol_containing(insn->sec, insn->offset-1); in noendbr_range()
4287 first = find_insn(file, sym->sec, sym->offset); in noendbr_range()
4291 if (first->type != INSN_ENDBR && !first->noendbr) in noendbr_range()
4294 return insn->offset == sym->offset + sym->len; in noendbr_range()
4308 switch (insn->type) { in validate_ibt_insn()
4324 reloc = find_reloc_by_dest_range(file->elf, insn->sec, in validate_ibt_insn()
4326 (insn->offset + insn->len) - (reloc_offset(reloc) + 1))) { in validate_ibt_insn()
4332 if (reloc->sym->static_call_tramp) in validate_ibt_insn()
4335 off = reloc->sym->offset; in validate_ibt_insn()
4342 dest = find_insn(file, reloc->sym->sec, off); in validate_ibt_insn()
4346 if (dest->type == INSN_ENDBR) { in validate_ibt_insn()
4352 insn_func(dest)->pfunc == insn_func(insn)->pfunc) { in validate_ibt_insn()
4354 * Anything from->to self is either _THIS_IP_ or in validate_ibt_insn()
4355 * IRET-to-self. in validate_ibt_insn()
4360 * do, leading to vast amounts of false-positives. in validate_ibt_insn()
4365 * As such, blanket accept self-references without in validate_ibt_insn()
4374 if (dest->noendbr) in validate_ibt_insn()
4379 * that is (no)endbr -- typical code-range usage. in validate_ibt_insn()
4384 WARN_INSN(insn, "relocation to !ENDBR: %s", offstr(dest->sec, dest->offset)); in validate_ibt_insn()
4397 dest = find_insn(file, reloc->sym->sec, in validate_ibt_data_reloc()
4398 reloc->sym->offset + reloc_addend(reloc)); in validate_ibt_data_reloc()
4402 if (dest->type == INSN_ENDBR) { in validate_ibt_data_reloc()
4407 if (dest->noendbr) in validate_ibt_data_reloc()
4411 reloc->sec->base, reloc_offset(reloc), in validate_ibt_data_reloc()
4412 offstr(dest->sec, dest->offset)); in validate_ibt_data_reloc()
4435 if (sec->sh.sh_flags & SHF_EXECINSTR) in validate_ibt()
4438 if (!sec->rsec) in validate_ibt()
4445 if ((!strncmp(sec->name, ".discard", 8) && in validate_ibt()
4446 strcmp(sec->name, ".discard.ibt_endbr_noseal")) || in validate_ibt()
4447 !strncmp(sec->name, ".debug", 6) || in validate_ibt()
4448 !strcmp(sec->name, ".altinstructions") || in validate_ibt()
4449 !strcmp(sec->name, ".ibt_endbr_seal") || in validate_ibt()
4450 !strcmp(sec->name, ".orc_unwind_ip") || in validate_ibt()
4451 !strcmp(sec->name, ".parainstructions") || in validate_ibt()
4452 !strcmp(sec->name, ".retpoline_sites") || in validate_ibt()
4453 !strcmp(sec->name, ".smp_locks") || in validate_ibt()
4454 !strcmp(sec->name, ".static_call_sites") || in validate_ibt()
4455 !strcmp(sec->name, "_error_injection_whitelist") || in validate_ibt()
4456 !strcmp(sec->name, "_kprobe_blacklist") || in validate_ibt()
4457 !strcmp(sec->name, "__bug_table") || in validate_ibt()
4458 !strcmp(sec->name, "__ex_table") || in validate_ibt()
4459 !strcmp(sec->name, "__jump_table") || in validate_ibt()
4460 !strcmp(sec->name, "__mcount_loc") || in validate_ibt()
4461 !strcmp(sec->name, ".kcfi_traps") || in validate_ibt()
4462 strstr(sec->name, "__patchable_function_entries")) in validate_ibt()
4465 for_each_reloc(sec->rsec, reloc) in validate_ibt()
4480 if (insn->retpoline_safe) in validate_sls()
4483 switch (insn->type) { in validate_sls()
4485 if (!next_insn || next_insn->type != INSN_TRAP) { in validate_sls()
4492 if (!next_insn || next_insn->type != INSN_TRAP) { in validate_sls()
4518 * - have compiler communicate __noreturn functions somehow in ignore_noreturn_call()
4519 * - remove CONFIG_X86_ESPFIX64 in ignore_noreturn_call()
4520 * - read the .config file in ignore_noreturn_call()
4521 * - add a cmdline option in ignore_noreturn_call()
4522 * - create a generic objtool annotation format (vs a bunch of custom in ignore_noreturn_call()
4525 if (!strcmp(call_dest->name, "exc_double_fault")) { in ignore_noreturn_call()
4527 insn->sym->warned = 1; in ignore_noreturn_call()
4540 if (file->ignore_unreachables) in validate_reachable_instructions()
4544 if (insn->visited || ignore_unreachable_insn(file, insn)) in validate_reachable_instructions()
4548 if (prev_insn && prev_insn->dead_end) { in validate_reachable_instructions()
4552 call_dest->name); in validate_reachable_instructions()
4565 /* 'funcs' is a space-separated list of function names */
4574 objdump_str = "%sobjdump -wdr %s | gawk -M -v _funcs='%s' '" in disas_funcs()
4590 "printf(\"%%04x \", addr - base);" in disas_funcs()
4599 return -1; in disas_funcs()
4609 return -1; in disas_funcs()
4621 if (sym->warned) { in disas_warned_funcs()
4623 funcs = malloc(strlen(sym->name) + 1); in disas_warned_funcs()
4624 strcpy(funcs, sym->name); in disas_warned_funcs()
4626 tmp = malloc(strlen(funcs) + strlen(sym->name) + 2); in disas_warned_funcs()
4627 sprintf(tmp, "%s %s", funcs, sym->name); in disas_warned_funcs()
4656 if (!insn->idx) { in free_insns()
4658 chunk->addr = insn; in free_insns()
4659 chunk->next = chunks; in free_insns()
4664 for (chunk = chunks; chunk; chunk = chunk->next) in free_insns()
4665 free(chunk->addr); in free_insns()
4679 if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3))) in check()
4729 * further games with insn->visited. in check()
4828 * For now, don't fail the kernel build on fatal warnings. These in check()