1
2
3
4
5
6#include <string.h>
7#include <stdlib.h>
8
9#include "builtin.h"
10#include "cfi.h"
11#include "arch.h"
12#include "check.h"
13#include "special.h"
14#include "warn.h"
15#include "arch_elf.h"
16
17#include <linux/hashtable.h>
18#include <linux/kernel.h>
19
20#define FAKE_JUMP_OFFSET -1
21
22#define C_JUMP_TABLE_SECTION ".rodata..c_jump_table"
23
24struct alternative {
25 struct list_head list;
26 struct instruction *insn;
27 bool skip_orig;
28};
29
30const char *objname;
31struct cfi_init_state initial_func_cfi;
32
33struct instruction *find_insn(struct objtool_file *file,
34 struct section *sec, unsigned long offset)
35{
36 struct instruction *insn;
37
38 hash_for_each_possible(file->insn_hash, insn, hash, sec_offset_hash(sec, offset)) {
39 if (insn->sec == sec && insn->offset == offset)
40 return insn;
41 }
42
43 return NULL;
44}
45
46static struct instruction *next_insn_same_sec(struct objtool_file *file,
47 struct instruction *insn)
48{
49 struct instruction *next = list_next_entry(insn, list);
50
51 if (!next || &next->list == &file->insn_list || next->sec != insn->sec)
52 return NULL;
53
54 return next;
55}
56
57static struct instruction *next_insn_same_func(struct objtool_file *file,
58 struct instruction *insn)
59{
60 struct instruction *next = list_next_entry(insn, list);
61 struct symbol *func = insn->func;
62
63 if (!func)
64 return NULL;
65
66 if (&next->list != &file->insn_list && next->func == func)
67 return next;
68
69
70 if (func == func->cfunc)
71 return NULL;
72
73
74 return find_insn(file, func->cfunc->sec, func->cfunc->offset);
75}
76
77static struct instruction *prev_insn_same_sym(struct objtool_file *file,
78 struct instruction *insn)
79{
80 struct instruction *prev = list_prev_entry(insn, list);
81
82 if (&prev->list != &file->insn_list && prev->func == insn->func)
83 return prev;
84
85 return NULL;
86}
87
88#define func_for_each_insn(file, func, insn) \
89 for (insn = find_insn(file, func->sec, func->offset); \
90 insn; \
91 insn = next_insn_same_func(file, insn))
92
93#define sym_for_each_insn(file, sym, insn) \
94 for (insn = find_insn(file, sym->sec, sym->offset); \
95 insn && &insn->list != &file->insn_list && \
96 insn->sec == sym->sec && \
97 insn->offset < sym->offset + sym->len; \
98 insn = list_next_entry(insn, list))
99
100#define sym_for_each_insn_continue_reverse(file, sym, insn) \
101 for (insn = list_prev_entry(insn, list); \
102 &insn->list != &file->insn_list && \
103 insn->sec == sym->sec && insn->offset >= sym->offset; \
104 insn = list_prev_entry(insn, list))
105
106#define sec_for_each_insn_from(file, insn) \
107 for (; insn; insn = next_insn_same_sec(file, insn))
108
109#define sec_for_each_insn_continue(file, insn) \
110 for (insn = next_insn_same_sec(file, insn); insn; \
111 insn = next_insn_same_sec(file, insn))
112
113static bool is_static_jump(struct instruction *insn)
114{
115 return insn->type == INSN_JUMP_CONDITIONAL ||
116 insn->type == INSN_JUMP_UNCONDITIONAL;
117}
118
119static bool is_sibling_call(struct instruction *insn)
120{
121
122 if (insn->type == INSN_JUMP_DYNAMIC)
123 return list_empty(&insn->alts);
124
125 if (!is_static_jump(insn))
126 return false;
127
128
129 return !!insn->call_dest;
130}
131
132
133
134
135
136
137
138
139
140
141static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
142 int recursion)
143{
144 int i;
145 struct instruction *insn;
146 bool empty = true;
147
148
149
150
151
152 static const char * const global_noreturns[] = {
153 "__stack_chk_fail",
154 "panic",
155 "do_exit",
156 "do_task_dead",
157 "__module_put_and_exit",
158 "complete_and_exit",
159 "__reiserfs_panic",
160 "lbug_with_loc",
161 "fortify_panic",
162 "usercopy_abort",
163 "machine_real_restart",
164 "rewind_stack_do_exit",
165 "kunit_try_catch_throw",
166 };
167
168 if (!func)
169 return false;
170
171 if (func->bind == STB_WEAK)
172 return false;
173
174 if (func->bind == STB_GLOBAL)
175 for (i = 0; i < ARRAY_SIZE(global_noreturns); i++)
176 if (!strcmp(func->name, global_noreturns[i]))
177 return true;
178
179 if (!func->len)
180 return false;
181
182 insn = find_insn(file, func->sec, func->offset);
183 if (!insn->func)
184 return false;
185
186 func_for_each_insn(file, func, insn) {
187 empty = false;
188
189 if (insn->type == INSN_RETURN)
190 return false;
191 }
192
193 if (empty)
194 return false;
195
196
197
198
199
200
201 func_for_each_insn(file, func, insn) {
202 if (is_sibling_call(insn)) {
203 struct instruction *dest = insn->jump_dest;
204
205 if (!dest)
206
207 return false;
208
209
210 if (recursion == 5) {
211
212
213
214
215
216 return false;
217 }
218
219 return __dead_end_function(file, dest->func, recursion+1);
220 }
221 }
222
223 return true;
224}
225
226static bool dead_end_function(struct objtool_file *file, struct symbol *func)
227{
228 return __dead_end_function(file, func, 0);
229}
230
231static void init_cfi_state(struct cfi_state *cfi)
232{
233 int i;
234
235 for (i = 0; i < CFI_NUM_REGS; i++) {
236 cfi->regs[i].base = CFI_UNDEFINED;
237 cfi->vals[i].base = CFI_UNDEFINED;
238 }
239 cfi->cfa.base = CFI_UNDEFINED;
240 cfi->drap_reg = CFI_UNDEFINED;
241 cfi->drap_offset = -1;
242}
243
244static void init_insn_state(struct insn_state *state, struct section *sec)
245{
246 memset(state, 0, sizeof(*state));
247 init_cfi_state(&state->cfi);
248
249
250
251
252
253
254 if (vmlinux && sec)
255 state->noinstr = sec->noinstr;
256}
257
258
259
260
261
262static int decode_instructions(struct objtool_file *file)
263{
264 struct section *sec;
265 struct symbol *func;
266 unsigned long offset;
267 struct instruction *insn;
268 unsigned long nr_insns = 0;
269 int ret;
270
271 for_each_sec(file, sec) {
272
273 if (!(sec->sh.sh_flags & SHF_EXECINSTR))
274 continue;
275
276 if (strcmp(sec->name, ".altinstr_replacement") &&
277 strcmp(sec->name, ".altinstr_aux") &&
278 strncmp(sec->name, ".discard.", 9))
279 sec->text = true;
280
281 if (!strcmp(sec->name, ".noinstr.text") ||
282 !strcmp(sec->name, ".entry.text"))
283 sec->noinstr = true;
284
285 for (offset = 0; offset < sec->len; offset += insn->len) {
286 insn = malloc(sizeof(*insn));
287 if (!insn) {
288 WARN("malloc failed");
289 return -1;
290 }
291 memset(insn, 0, sizeof(*insn));
292 INIT_LIST_HEAD(&insn->alts);
293 INIT_LIST_HEAD(&insn->stack_ops);
294 init_cfi_state(&insn->cfi);
295
296 insn->sec = sec;
297 insn->offset = offset;
298
299 ret = arch_decode_instruction(file->elf, sec, offset,
300 sec->len - offset,
301 &insn->len, &insn->type,
302 &insn->immediate,
303 &insn->stack_ops);
304 if (ret)
305 goto err;
306
307 hash_add(file->insn_hash, &insn->hash, sec_offset_hash(sec, insn->offset));
308 list_add_tail(&insn->list, &file->insn_list);
309 nr_insns++;
310 }
311
312 list_for_each_entry(func, &sec->symbol_list, list) {
313 if (func->type != STT_FUNC || func->alias != func)
314 continue;
315
316 if (!find_insn(file, sec, func->offset)) {
317 WARN("%s(): can't find starting instruction",
318 func->name);
319 return -1;
320 }
321
322 sym_for_each_insn(file, func, insn)
323 insn->func = func;
324 }
325 }
326
327 if (stats)
328 printf("nr_insns: %lu\n", nr_insns);
329
330 return 0;
331
332err:
333 free(insn);
334 return ret;
335}
336
337static struct instruction *find_last_insn(struct objtool_file *file,
338 struct section *sec)
339{
340 struct instruction *insn = NULL;
341 unsigned int offset;
342 unsigned int end = (sec->len > 10) ? sec->len - 10 : 0;
343
344 for (offset = sec->len - 1; offset >= end && !insn; offset--)
345 insn = find_insn(file, sec, offset);
346
347 return insn;
348}
349
350
351
352
353static int add_dead_ends(struct objtool_file *file)
354{
355 struct section *sec;
356 struct reloc *reloc;
357 struct instruction *insn;
358
359
360
361
362
363 for_each_insn(file, insn)
364 if (insn->type == INSN_BUG)
365 insn->dead_end = true;
366
367
368
369
370 sec = find_section_by_name(file->elf, ".rela.discard.unreachable");
371 if (!sec)
372 goto reachable;
373
374 list_for_each_entry(reloc, &sec->reloc_list, list) {
375 if (reloc->sym->type != STT_SECTION) {
376 WARN("unexpected relocation symbol type in %s", sec->name);
377 return -1;
378 }
379 insn = find_insn(file, reloc->sym->sec, reloc->addend);
380 if (insn)
381 insn = list_prev_entry(insn, list);
382 else if (reloc->addend == reloc->sym->sec->len) {
383 insn = find_last_insn(file, reloc->sym->sec);
384 if (!insn) {
385 WARN("can't find unreachable insn at %s+0x%x",
386 reloc->sym->sec->name, reloc->addend);
387 return -1;
388 }
389 } else {
390 WARN("can't find unreachable insn at %s+0x%x",
391 reloc->sym->sec->name, reloc->addend);
392 return -1;
393 }
394
395 insn->dead_end = true;
396 }
397
398reachable:
399
400
401
402
403
404
405 sec = find_section_by_name(file->elf, ".rela.discard.reachable");
406 if (!sec)
407 return 0;
408
409 list_for_each_entry(reloc, &sec->reloc_list, list) {
410 if (reloc->sym->type != STT_SECTION) {
411 WARN("unexpected relocation symbol type in %s", sec->name);
412 return -1;
413 }
414 insn = find_insn(file, reloc->sym->sec, reloc->addend);
415 if (insn)
416 insn = list_prev_entry(insn, list);
417 else if (reloc->addend == reloc->sym->sec->len) {
418 insn = find_last_insn(file, reloc->sym->sec);
419 if (!insn) {
420 WARN("can't find reachable insn at %s+0x%x",
421 reloc->sym->sec->name, reloc->addend);
422 return -1;
423 }
424 } else {
425 WARN("can't find reachable insn at %s+0x%x",
426 reloc->sym->sec->name, reloc->addend);
427 return -1;
428 }
429
430 insn->dead_end = false;
431 }
432
433 return 0;
434}
435
436
437
438
439static void add_ignores(struct objtool_file *file)
440{
441 struct instruction *insn;
442 struct section *sec;
443 struct symbol *func;
444 struct reloc *reloc;
445
446 sec = find_section_by_name(file->elf, ".rela.discard.func_stack_frame_non_standard");
447 if (!sec)
448 return;
449
450 list_for_each_entry(reloc, &sec->reloc_list, list) {
451 switch (reloc->sym->type) {
452 case STT_FUNC:
453 func = reloc->sym;
454 break;
455
456 case STT_SECTION:
457 func = find_func_by_offset(reloc->sym->sec, reloc->addend);
458 if (!func)
459 continue;
460 break;
461
462 default:
463 WARN("unexpected relocation symbol type in %s: %d", sec->name, reloc->sym->type);
464 continue;
465 }
466
467 func_for_each_insn(file, func, insn)
468 insn->ignore = true;
469 }
470}
471
472
473
474
475
476
477
478
479static const char *uaccess_safe_builtin[] = {
480
481 "kasan_report",
482 "check_memory_region",
483
484 "__asan_loadN_noabort",
485 "__asan_load1_noabort",
486 "__asan_load2_noabort",
487 "__asan_load4_noabort",
488 "__asan_load8_noabort",
489 "__asan_load16_noabort",
490 "__asan_storeN_noabort",
491 "__asan_store1_noabort",
492 "__asan_store2_noabort",
493 "__asan_store4_noabort",
494 "__asan_store8_noabort",
495 "__asan_store16_noabort",
496
497 "__asan_report_load_n_noabort",
498 "__asan_report_load1_noabort",
499 "__asan_report_load2_noabort",
500 "__asan_report_load4_noabort",
501 "__asan_report_load8_noabort",
502 "__asan_report_load16_noabort",
503 "__asan_report_store_n_noabort",
504 "__asan_report_store1_noabort",
505 "__asan_report_store2_noabort",
506 "__asan_report_store4_noabort",
507 "__asan_report_store8_noabort",
508 "__asan_report_store16_noabort",
509
510 "__kcsan_check_access",
511 "kcsan_found_watchpoint",
512 "kcsan_setup_watchpoint",
513 "kcsan_check_scoped_accesses",
514 "kcsan_disable_current",
515 "kcsan_enable_current_nowarn",
516
517 "__tsan_func_entry",
518 "__tsan_func_exit",
519 "__tsan_read_range",
520 "__tsan_write_range",
521 "__tsan_read1",
522 "__tsan_read2",
523 "__tsan_read4",
524 "__tsan_read8",
525 "__tsan_read16",
526 "__tsan_write1",
527 "__tsan_write2",
528 "__tsan_write4",
529 "__tsan_write8",
530 "__tsan_write16",
531
532 "write_comp_data",
533 "check_kcov_mode",
534 "__sanitizer_cov_trace_pc",
535 "__sanitizer_cov_trace_const_cmp1",
536 "__sanitizer_cov_trace_const_cmp2",
537 "__sanitizer_cov_trace_const_cmp4",
538 "__sanitizer_cov_trace_const_cmp8",
539 "__sanitizer_cov_trace_cmp1",
540 "__sanitizer_cov_trace_cmp2",
541 "__sanitizer_cov_trace_cmp4",
542 "__sanitizer_cov_trace_cmp8",
543 "__sanitizer_cov_trace_switch",
544
545 "ubsan_type_mismatch_common",
546 "__ubsan_handle_type_mismatch",
547 "__ubsan_handle_type_mismatch_v1",
548 "__ubsan_handle_shift_out_of_bounds",
549
550 "csum_partial_copy_generic",
551 "__memcpy_mcsafe",
552 "mcsafe_handle_tail",
553 "ftrace_likely_update",
554 NULL
555};
556
557static void add_uaccess_safe(struct objtool_file *file)
558{
559 struct symbol *func;
560 const char **name;
561
562 if (!uaccess)
563 return;
564
565 for (name = uaccess_safe_builtin; *name; name++) {
566 func = find_symbol_by_name(file->elf, *name);
567 if (!func)
568 continue;
569
570 func->uaccess_safe = true;
571 }
572}
573
574
575
576
577
578
579
580static int add_ignore_alternatives(struct objtool_file *file)
581{
582 struct section *sec;
583 struct reloc *reloc;
584 struct instruction *insn;
585
586 sec = find_section_by_name(file->elf, ".rela.discard.ignore_alts");
587 if (!sec)
588 return 0;
589
590 list_for_each_entry(reloc, &sec->reloc_list, list) {
591 if (reloc->sym->type != STT_SECTION) {
592 WARN("unexpected relocation symbol type in %s", sec->name);
593 return -1;
594 }
595
596 insn = find_insn(file, reloc->sym->sec, reloc->addend);
597 if (!insn) {
598 WARN("bad .discard.ignore_alts entry");
599 return -1;
600 }
601
602 insn->ignore_alts = true;
603 }
604
605 return 0;
606}
607
608
609
610
611static int add_jump_destinations(struct objtool_file *file)
612{
613 struct instruction *insn;
614 struct reloc *reloc;
615 struct section *dest_sec;
616 unsigned long dest_off;
617
618 for_each_insn(file, insn) {
619 if (!is_static_jump(insn))
620 continue;
621
622 if (insn->offset == FAKE_JUMP_OFFSET)
623 continue;
624
625 reloc = find_reloc_by_dest_range(file->elf, insn->sec,
626 insn->offset, insn->len);
627 if (!reloc) {
628 dest_sec = insn->sec;
629 dest_off = arch_jump_destination(insn);
630 } else if (reloc->sym->type == STT_SECTION) {
631 dest_sec = reloc->sym->sec;
632 dest_off = arch_dest_reloc_offset(reloc->addend);
633 } else if (reloc->sym->sec->idx) {
634 dest_sec = reloc->sym->sec;
635 dest_off = reloc->sym->sym.st_value +
636 arch_dest_reloc_offset(reloc->addend);
637 } else if (strstr(reloc->sym->name, "_indirect_thunk_")) {
638
639
640
641
642 if (insn->type == INSN_JUMP_UNCONDITIONAL)
643 insn->type = INSN_JUMP_DYNAMIC;
644 else
645 insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL;
646
647 insn->retpoline_safe = true;
648 continue;
649 } else {
650
651 insn->call_dest = reloc->sym;
652 continue;
653 }
654
655 insn->jump_dest = find_insn(file, dest_sec, dest_off);
656 if (!insn->jump_dest) {
657
658
659
660
661
662
663 if (!strcmp(insn->sec->name, ".altinstr_replacement"))
664 continue;
665
666 WARN_FUNC("can't find jump dest instruction at %s+0x%lx",
667 insn->sec, insn->offset, dest_sec->name,
668 dest_off);
669 return -1;
670 }
671
672
673
674
675 if (insn->func && insn->jump_dest->func &&
676 insn->func != insn->jump_dest->func) {
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693 if (!strstr(insn->func->name, ".cold.") &&
694 strstr(insn->jump_dest->func->name, ".cold.")) {
695 insn->func->cfunc = insn->jump_dest->func;
696 insn->jump_dest->func->pfunc = insn->func;
697
698 } else if (insn->jump_dest->func->pfunc != insn->func->pfunc &&
699 insn->jump_dest->offset == insn->jump_dest->func->offset) {
700
701
702 insn->call_dest = insn->jump_dest->func;
703 }
704 }
705 }
706
707 return 0;
708}
709
710static void remove_insn_ops(struct instruction *insn)
711{
712 struct stack_op *op, *tmp;
713
714 list_for_each_entry_safe(op, tmp, &insn->stack_ops, list) {
715 list_del(&op->list);
716 free(op);
717 }
718}
719
720
721
722
723static int add_call_destinations(struct objtool_file *file)
724{
725 struct instruction *insn;
726 unsigned long dest_off;
727 struct reloc *reloc;
728
729 for_each_insn(file, insn) {
730 if (insn->type != INSN_CALL)
731 continue;
732
733 reloc = find_reloc_by_dest_range(file->elf, insn->sec,
734 insn->offset, insn->len);
735 if (!reloc) {
736 dest_off = arch_jump_destination(insn);
737 insn->call_dest = find_func_by_offset(insn->sec, dest_off);
738 if (!insn->call_dest)
739 insn->call_dest = find_symbol_by_offset(insn->sec, dest_off);
740
741 if (insn->ignore)
742 continue;
743
744 if (!insn->call_dest) {
745 WARN_FUNC("unannotated intra-function call", insn->sec, insn->offset);
746 return -1;
747 }
748
749 if (insn->func && insn->call_dest->type != STT_FUNC) {
750 WARN_FUNC("unsupported call to non-function",
751 insn->sec, insn->offset);
752 return -1;
753 }
754
755 } else if (reloc->sym->type == STT_SECTION) {
756 dest_off = arch_dest_reloc_offset(reloc->addend);
757 insn->call_dest = find_func_by_offset(reloc->sym->sec,
758 dest_off);
759 if (!insn->call_dest) {
760 WARN_FUNC("can't find call dest symbol at %s+0x%lx",
761 insn->sec, insn->offset,
762 reloc->sym->sec->name,
763 dest_off);
764 return -1;
765 }
766 } else
767 insn->call_dest = reloc->sym;
768
769
770
771
772
773
774 if (insn->sec->noinstr &&
775 !strncmp(insn->call_dest->name, "__sanitizer_cov_", 16)) {
776 if (reloc) {
777 reloc->type = R_NONE;
778 elf_write_reloc(file->elf, reloc);
779 }
780
781 elf_write_insn(file->elf, insn->sec,
782 insn->offset, insn->len,
783 arch_nop_insn(insn->len));
784 insn->type = INSN_NOP;
785 }
786
787
788
789
790
791
792
793
794 remove_insn_ops(insn);
795 }
796
797 return 0;
798}
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817static int handle_group_alt(struct objtool_file *file,
818 struct special_alt *special_alt,
819 struct instruction *orig_insn,
820 struct instruction **new_insn)
821{
822 static unsigned int alt_group_next_index = 1;
823 struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump = NULL;
824 unsigned int alt_group = alt_group_next_index++;
825 unsigned long dest_off;
826
827 last_orig_insn = NULL;
828 insn = orig_insn;
829 sec_for_each_insn_from(file, insn) {
830 if (insn->offset >= special_alt->orig_off + special_alt->orig_len)
831 break;
832
833 insn->alt_group = alt_group;
834 last_orig_insn = insn;
835 }
836
837 if (next_insn_same_sec(file, last_orig_insn)) {
838 fake_jump = malloc(sizeof(*fake_jump));
839 if (!fake_jump) {
840 WARN("malloc failed");
841 return -1;
842 }
843 memset(fake_jump, 0, sizeof(*fake_jump));
844 INIT_LIST_HEAD(&fake_jump->alts);
845 INIT_LIST_HEAD(&fake_jump->stack_ops);
846 init_cfi_state(&fake_jump->cfi);
847
848 fake_jump->sec = special_alt->new_sec;
849 fake_jump->offset = FAKE_JUMP_OFFSET;
850 fake_jump->type = INSN_JUMP_UNCONDITIONAL;
851 fake_jump->jump_dest = list_next_entry(last_orig_insn, list);
852 fake_jump->func = orig_insn->func;
853 }
854
855 if (!special_alt->new_len) {
856 if (!fake_jump) {
857 WARN("%s: empty alternative at end of section",
858 special_alt->orig_sec->name);
859 return -1;
860 }
861
862 *new_insn = fake_jump;
863 return 0;
864 }
865
866 last_new_insn = NULL;
867 alt_group = alt_group_next_index++;
868 insn = *new_insn;
869 sec_for_each_insn_from(file, insn) {
870 if (insn->offset >= special_alt->new_off + special_alt->new_len)
871 break;
872
873 last_new_insn = insn;
874
875 insn->ignore = orig_insn->ignore_alts;
876 insn->func = orig_insn->func;
877 insn->alt_group = alt_group;
878
879
880
881
882
883
884
885
886
887
888
889
890
891 if ((insn->offset != special_alt->new_off ||
892 (insn->type != INSN_CALL && !is_static_jump(insn))) &&
893 find_reloc_by_dest_range(file->elf, insn->sec, insn->offset, insn->len)) {
894
895 WARN_FUNC("unsupported relocation in alternatives section",
896 insn->sec, insn->offset);
897 return -1;
898 }
899
900 if (!is_static_jump(insn))
901 continue;
902
903 if (!insn->immediate)
904 continue;
905
906 dest_off = arch_jump_destination(insn);
907 if (dest_off == special_alt->new_off + special_alt->new_len) {
908 if (!fake_jump) {
909 WARN("%s: alternative jump to end of section",
910 special_alt->orig_sec->name);
911 return -1;
912 }
913 insn->jump_dest = fake_jump;
914 }
915
916 if (!insn->jump_dest) {
917 WARN_FUNC("can't find alternative jump destination",
918 insn->sec, insn->offset);
919 return -1;
920 }
921 }
922
923 if (!last_new_insn) {
924 WARN_FUNC("can't find last new alternative instruction",
925 special_alt->new_sec, special_alt->new_off);
926 return -1;
927 }
928
929 if (fake_jump)
930 list_add(&fake_jump->list, &last_new_insn->list);
931
932 return 0;
933}
934
935
936
937
938
939
940static int handle_jump_alt(struct objtool_file *file,
941 struct special_alt *special_alt,
942 struct instruction *orig_insn,
943 struct instruction **new_insn)
944{
945 if (orig_insn->type == INSN_NOP)
946 return 0;
947
948 if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) {
949 WARN_FUNC("unsupported instruction at jump label",
950 orig_insn->sec, orig_insn->offset);
951 return -1;
952 }
953
954 *new_insn = list_next_entry(orig_insn, list);
955 return 0;
956}
957
958
959
960
961
962
963
964static int add_special_section_alts(struct objtool_file *file)
965{
966 struct list_head special_alts;
967 struct instruction *orig_insn, *new_insn;
968 struct special_alt *special_alt, *tmp;
969 struct alternative *alt;
970 int ret;
971
972 ret = special_get_alts(file->elf, &special_alts);
973 if (ret)
974 return ret;
975
976 list_for_each_entry_safe(special_alt, tmp, &special_alts, list) {
977
978 orig_insn = find_insn(file, special_alt->orig_sec,
979 special_alt->orig_off);
980 if (!orig_insn) {
981 WARN_FUNC("special: can't find orig instruction",
982 special_alt->orig_sec, special_alt->orig_off);
983 ret = -1;
984 goto out;
985 }
986
987 new_insn = NULL;
988 if (!special_alt->group || special_alt->new_len) {
989 new_insn = find_insn(file, special_alt->new_sec,
990 special_alt->new_off);
991 if (!new_insn) {
992 WARN_FUNC("special: can't find new instruction",
993 special_alt->new_sec,
994 special_alt->new_off);
995 ret = -1;
996 goto out;
997 }
998 }
999
1000 if (special_alt->group) {
1001 if (!special_alt->orig_len) {
1002 WARN_FUNC("empty alternative entry",
1003 orig_insn->sec, orig_insn->offset);
1004 continue;
1005 }
1006
1007 ret = handle_group_alt(file, special_alt, orig_insn,
1008 &new_insn);
1009 if (ret)
1010 goto out;
1011 } else if (special_alt->jump_or_nop) {
1012 ret = handle_jump_alt(file, special_alt, orig_insn,
1013 &new_insn);
1014 if (ret)
1015 goto out;
1016 }
1017
1018 alt = malloc(sizeof(*alt));
1019 if (!alt) {
1020 WARN("malloc failed");
1021 ret = -1;
1022 goto out;
1023 }
1024
1025 alt->insn = new_insn;
1026 alt->skip_orig = special_alt->skip_orig;
1027 orig_insn->ignore_alts |= special_alt->skip_alt;
1028 list_add_tail(&alt->list, &orig_insn->alts);
1029
1030 list_del(&special_alt->list);
1031 free(special_alt);
1032 }
1033
1034out:
1035 return ret;
1036}
1037
1038static int add_jump_table(struct objtool_file *file, struct instruction *insn,
1039 struct reloc *table)
1040{
1041 struct reloc *reloc = table;
1042 struct instruction *dest_insn;
1043 struct alternative *alt;
1044 struct symbol *pfunc = insn->func->pfunc;
1045 unsigned int prev_offset = 0;
1046
1047
1048
1049
1050
1051 list_for_each_entry_from(reloc, &table->sec->reloc_list, list) {
1052
1053
1054 if (reloc != table && reloc->jump_table_start)
1055 break;
1056
1057
1058 if (prev_offset && reloc->offset != prev_offset + 8)
1059 break;
1060
1061
1062 if (reloc->sym->sec == pfunc->sec &&
1063 reloc->addend == pfunc->offset)
1064 break;
1065
1066 dest_insn = find_insn(file, reloc->sym->sec, reloc->addend);
1067 if (!dest_insn)
1068 break;
1069
1070
1071 if (!dest_insn->func || dest_insn->func->pfunc != pfunc)
1072 break;
1073
1074 alt = malloc(sizeof(*alt));
1075 if (!alt) {
1076 WARN("malloc failed");
1077 return -1;
1078 }
1079
1080 alt->insn = dest_insn;
1081 list_add_tail(&alt->list, &insn->alts);
1082 prev_offset = reloc->offset;
1083 }
1084
1085 if (!prev_offset) {
1086 WARN_FUNC("can't find switch jump table",
1087 insn->sec, insn->offset);
1088 return -1;
1089 }
1090
1091 return 0;
1092}
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137static struct reloc *find_jump_table(struct objtool_file *file,
1138 struct symbol *func,
1139 struct instruction *insn)
1140{
1141 struct reloc *text_reloc, *table_reloc;
1142 struct instruction *dest_insn, *orig_insn = insn;
1143 struct section *table_sec;
1144 unsigned long table_offset;
1145
1146
1147
1148
1149
1150
1151 for (;
1152 insn && insn->func && insn->func->pfunc == func;
1153 insn = insn->first_jump_src ?: prev_insn_same_sym(file, insn)) {
1154
1155 if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC)
1156 break;
1157
1158
1159 if (insn->type == INSN_JUMP_UNCONDITIONAL &&
1160 insn->jump_dest &&
1161 (insn->jump_dest->offset <= insn->offset ||
1162 insn->jump_dest->offset > orig_insn->offset))
1163 break;
1164
1165
1166 text_reloc = find_reloc_by_dest_range(file->elf, insn->sec,
1167 insn->offset, insn->len);
1168 if (!text_reloc || text_reloc->sym->type != STT_SECTION ||
1169 !text_reloc->sym->sec->rodata)
1170 continue;
1171
1172 table_offset = text_reloc->addend;
1173 table_sec = text_reloc->sym->sec;
1174
1175 if (text_reloc->type == R_X86_64_PC32)
1176 table_offset += 4;
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187 if (find_symbol_containing(table_sec, table_offset) &&
1188 strcmp(table_sec->name, C_JUMP_TABLE_SECTION))
1189 continue;
1190
1191
1192
1193
1194
1195
1196 table_reloc = find_reloc_by_dest(file->elf, table_sec, table_offset);
1197 if (!table_reloc)
1198 continue;
1199 dest_insn = find_insn(file, table_reloc->sym->sec, table_reloc->addend);
1200 if (!dest_insn || !dest_insn->func || dest_insn->func->pfunc != func)
1201 continue;
1202
1203
1204
1205
1206
1207
1208 if (text_reloc->type == R_X86_64_PC32)
1209 file->ignore_unreachables = true;
1210
1211 return table_reloc;
1212 }
1213
1214 return NULL;
1215}
1216
1217
1218
1219
1220
1221static void mark_func_jump_tables(struct objtool_file *file,
1222 struct symbol *func)
1223{
1224 struct instruction *insn, *last = NULL;
1225 struct reloc *reloc;
1226
1227 func_for_each_insn(file, func, insn) {
1228 if (!last)
1229 last = insn;
1230
1231
1232
1233
1234
1235
1236 if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
1237 insn->offset > last->offset &&
1238 insn->jump_dest->offset > insn->offset &&
1239 !insn->jump_dest->first_jump_src) {
1240
1241 insn->jump_dest->first_jump_src = insn;
1242 last = insn->jump_dest;
1243 }
1244
1245 if (insn->type != INSN_JUMP_DYNAMIC)
1246 continue;
1247
1248 reloc = find_jump_table(file, func, insn);
1249 if (reloc) {
1250 reloc->jump_table_start = true;
1251 insn->jump_table = reloc;
1252 }
1253 }
1254}
1255
1256static int add_func_jump_tables(struct objtool_file *file,
1257 struct symbol *func)
1258{
1259 struct instruction *insn;
1260 int ret;
1261
1262 func_for_each_insn(file, func, insn) {
1263 if (!insn->jump_table)
1264 continue;
1265
1266 ret = add_jump_table(file, insn, insn->jump_table);
1267 if (ret)
1268 return ret;
1269 }
1270
1271 return 0;
1272}
1273
1274
1275
1276
1277
1278
1279static int add_jump_table_alts(struct objtool_file *file)
1280{
1281 struct section *sec;
1282 struct symbol *func;
1283 int ret;
1284
1285 if (!file->rodata)
1286 return 0;
1287
1288 for_each_sec(file, sec) {
1289 list_for_each_entry(func, &sec->symbol_list, list) {
1290 if (func->type != STT_FUNC)
1291 continue;
1292
1293 mark_func_jump_tables(file, func);
1294 ret = add_func_jump_tables(file, func);
1295 if (ret)
1296 return ret;
1297 }
1298 }
1299
1300 return 0;
1301}
1302
1303static int read_unwind_hints(struct objtool_file *file)
1304{
1305 struct section *sec, *relocsec;
1306 struct reloc *reloc;
1307 struct unwind_hint *hint;
1308 struct instruction *insn;
1309 struct cfi_reg *cfa;
1310 int i;
1311
1312 sec = find_section_by_name(file->elf, ".discard.unwind_hints");
1313 if (!sec)
1314 return 0;
1315
1316 relocsec = sec->reloc;
1317 if (!relocsec) {
1318 WARN("missing .rela.discard.unwind_hints section");
1319 return -1;
1320 }
1321
1322 if (sec->len % sizeof(struct unwind_hint)) {
1323 WARN("struct unwind_hint size mismatch");
1324 return -1;
1325 }
1326
1327 file->hints = true;
1328
1329 for (i = 0; i < sec->len / sizeof(struct unwind_hint); i++) {
1330 hint = (struct unwind_hint *)sec->data->d_buf + i;
1331
1332 reloc = find_reloc_by_dest(file->elf, sec, i * sizeof(*hint));
1333 if (!reloc) {
1334 WARN("can't find reloc for unwind_hints[%d]", i);
1335 return -1;
1336 }
1337
1338 insn = find_insn(file, reloc->sym->sec, reloc->addend);
1339 if (!insn) {
1340 WARN("can't find insn for unwind_hints[%d]", i);
1341 return -1;
1342 }
1343
1344 cfa = &insn->cfi.cfa;
1345
1346 if (hint->type == UNWIND_HINT_TYPE_RET_OFFSET) {
1347 insn->ret_offset = hint->sp_offset;
1348 continue;
1349 }
1350
1351 insn->hint = true;
1352
1353 switch (hint->sp_reg) {
1354 case ORC_REG_UNDEFINED:
1355 cfa->base = CFI_UNDEFINED;
1356 break;
1357 case ORC_REG_SP:
1358 cfa->base = CFI_SP;
1359 break;
1360 case ORC_REG_BP:
1361 cfa->base = CFI_BP;
1362 break;
1363 case ORC_REG_SP_INDIRECT:
1364 cfa->base = CFI_SP_INDIRECT;
1365 break;
1366 case ORC_REG_R10:
1367 cfa->base = CFI_R10;
1368 break;
1369 case ORC_REG_R13:
1370 cfa->base = CFI_R13;
1371 break;
1372 case ORC_REG_DI:
1373 cfa->base = CFI_DI;
1374 break;
1375 case ORC_REG_DX:
1376 cfa->base = CFI_DX;
1377 break;
1378 default:
1379 WARN_FUNC("unsupported unwind_hint sp base reg %d",
1380 insn->sec, insn->offset, hint->sp_reg);
1381 return -1;
1382 }
1383
1384 cfa->offset = hint->sp_offset;
1385 insn->cfi.type = hint->type;
1386 insn->cfi.end = hint->end;
1387 }
1388
1389 return 0;
1390}
1391
1392static int read_retpoline_hints(struct objtool_file *file)
1393{
1394 struct section *sec;
1395 struct instruction *insn;
1396 struct reloc *reloc;
1397
1398 sec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe");
1399 if (!sec)
1400 return 0;
1401
1402 list_for_each_entry(reloc, &sec->reloc_list, list) {
1403 if (reloc->sym->type != STT_SECTION) {
1404 WARN("unexpected relocation symbol type in %s", sec->name);
1405 return -1;
1406 }
1407
1408 insn = find_insn(file, reloc->sym->sec, reloc->addend);
1409 if (!insn) {
1410 WARN("bad .discard.retpoline_safe entry");
1411 return -1;
1412 }
1413
1414 if (insn->type != INSN_JUMP_DYNAMIC &&
1415 insn->type != INSN_CALL_DYNAMIC) {
1416 WARN_FUNC("retpoline_safe hint not an indirect jump/call",
1417 insn->sec, insn->offset);
1418 return -1;
1419 }
1420
1421 insn->retpoline_safe = true;
1422 }
1423
1424 return 0;
1425}
1426
1427static int read_instr_hints(struct objtool_file *file)
1428{
1429 struct section *sec;
1430 struct instruction *insn;
1431 struct reloc *reloc;
1432
1433 sec = find_section_by_name(file->elf, ".rela.discard.instr_end");
1434 if (!sec)
1435 return 0;
1436
1437 list_for_each_entry(reloc, &sec->reloc_list, list) {
1438 if (reloc->sym->type != STT_SECTION) {
1439 WARN("unexpected relocation symbol type in %s", sec->name);
1440 return -1;
1441 }
1442
1443 insn = find_insn(file, reloc->sym->sec, reloc->addend);
1444 if (!insn) {
1445 WARN("bad .discard.instr_end entry");
1446 return -1;
1447 }
1448
1449 insn->instr--;
1450 }
1451
1452 sec = find_section_by_name(file->elf, ".rela.discard.instr_begin");
1453 if (!sec)
1454 return 0;
1455
1456 list_for_each_entry(reloc, &sec->reloc_list, list) {
1457 if (reloc->sym->type != STT_SECTION) {
1458 WARN("unexpected relocation symbol type in %s", sec->name);
1459 return -1;
1460 }
1461
1462 insn = find_insn(file, reloc->sym->sec, reloc->addend);
1463 if (!insn) {
1464 WARN("bad .discard.instr_begin entry");
1465 return -1;
1466 }
1467
1468 insn->instr++;
1469 }
1470
1471 return 0;
1472}
1473
1474static int read_intra_function_calls(struct objtool_file *file)
1475{
1476 struct instruction *insn;
1477 struct section *sec;
1478 struct reloc *reloc;
1479
1480 sec = find_section_by_name(file->elf, ".rela.discard.intra_function_calls");
1481 if (!sec)
1482 return 0;
1483
1484 list_for_each_entry(reloc, &sec->reloc_list, list) {
1485 unsigned long dest_off;
1486
1487 if (reloc->sym->type != STT_SECTION) {
1488 WARN("unexpected relocation symbol type in %s",
1489 sec->name);
1490 return -1;
1491 }
1492
1493 insn = find_insn(file, reloc->sym->sec, reloc->addend);
1494 if (!insn) {
1495 WARN("bad .discard.intra_function_call entry");
1496 return -1;
1497 }
1498
1499 if (insn->type != INSN_CALL) {
1500 WARN_FUNC("intra_function_call not a direct call",
1501 insn->sec, insn->offset);
1502 return -1;
1503 }
1504
1505
1506
1507
1508
1509
1510 insn->type = INSN_JUMP_UNCONDITIONAL;
1511
1512 dest_off = insn->offset + insn->len + insn->immediate;
1513 insn->jump_dest = find_insn(file, insn->sec, dest_off);
1514 if (!insn->jump_dest) {
1515 WARN_FUNC("can't find call dest at %s+0x%lx",
1516 insn->sec, insn->offset,
1517 insn->sec->name, dest_off);
1518 return -1;
1519 }
1520 }
1521
1522 return 0;
1523}
1524
1525static void mark_rodata(struct objtool_file *file)
1526{
1527 struct section *sec;
1528 bool found = false;
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540 for_each_sec(file, sec) {
1541 if (!strncmp(sec->name, ".rodata", 7) &&
1542 !strstr(sec->name, ".str1.")) {
1543 sec->rodata = true;
1544 found = true;
1545 }
1546 }
1547
1548 file->rodata = found;
1549}
1550
1551static int decode_sections(struct objtool_file *file)
1552{
1553 int ret;
1554
1555 mark_rodata(file);
1556
1557 ret = decode_instructions(file);
1558 if (ret)
1559 return ret;
1560
1561 ret = add_dead_ends(file);
1562 if (ret)
1563 return ret;
1564
1565 add_ignores(file);
1566 add_uaccess_safe(file);
1567
1568 ret = add_ignore_alternatives(file);
1569 if (ret)
1570 return ret;
1571
1572 ret = add_jump_destinations(file);
1573 if (ret)
1574 return ret;
1575
1576 ret = add_special_section_alts(file);
1577 if (ret)
1578 return ret;
1579
1580 ret = read_intra_function_calls(file);
1581 if (ret)
1582 return ret;
1583
1584 ret = add_call_destinations(file);
1585 if (ret)
1586 return ret;
1587
1588 ret = add_jump_table_alts(file);
1589 if (ret)
1590 return ret;
1591
1592 ret = read_unwind_hints(file);
1593 if (ret)
1594 return ret;
1595
1596 ret = read_retpoline_hints(file);
1597 if (ret)
1598 return ret;
1599
1600 ret = read_instr_hints(file);
1601 if (ret)
1602 return ret;
1603
1604 return 0;
1605}
1606
1607static bool is_fentry_call(struct instruction *insn)
1608{
1609 if (insn->type == INSN_CALL && insn->call_dest &&
1610 insn->call_dest->type == STT_NOTYPE &&
1611 !strcmp(insn->call_dest->name, "__fentry__"))
1612 return true;
1613
1614 return false;
1615}
1616
1617static bool has_modified_stack_frame(struct instruction *insn, struct insn_state *state)
1618{
1619 u8 ret_offset = insn->ret_offset;
1620 struct cfi_state *cfi = &state->cfi;
1621 int i;
1622
1623 if (cfi->cfa.base != initial_func_cfi.cfa.base || cfi->drap)
1624 return true;
1625
1626 if (cfi->cfa.offset != initial_func_cfi.cfa.offset + ret_offset)
1627 return true;
1628
1629 if (cfi->stack_size != initial_func_cfi.cfa.offset + ret_offset)
1630 return true;
1631
1632
1633
1634
1635
1636
1637 if (ret_offset)
1638 return false;
1639
1640 for (i = 0; i < CFI_NUM_REGS; i++) {
1641 if (cfi->regs[i].base != initial_func_cfi.regs[i].base ||
1642 cfi->regs[i].offset != initial_func_cfi.regs[i].offset)
1643 return true;
1644 }
1645
1646 return false;
1647}
1648
1649static bool has_valid_stack_frame(struct insn_state *state)
1650{
1651 struct cfi_state *cfi = &state->cfi;
1652
1653 if (cfi->cfa.base == CFI_BP && cfi->regs[CFI_BP].base == CFI_CFA &&
1654 cfi->regs[CFI_BP].offset == -16)
1655 return true;
1656
1657 if (cfi->drap && cfi->regs[CFI_BP].base == CFI_BP)
1658 return true;
1659
1660 return false;
1661}
1662
1663static int update_cfi_state_regs(struct instruction *insn,
1664 struct cfi_state *cfi,
1665 struct stack_op *op)
1666{
1667 struct cfi_reg *cfa = &cfi->cfa;
1668
1669 if (cfa->base != CFI_SP && cfa->base != CFI_SP_INDIRECT)
1670 return 0;
1671
1672
1673 if (op->dest.type == OP_DEST_PUSH || op->dest.type == OP_DEST_PUSHF)
1674 cfa->offset += 8;
1675
1676
1677 if (op->src.type == OP_SRC_POP || op->src.type == OP_SRC_POPF)
1678 cfa->offset -= 8;
1679
1680
1681 if (op->dest.type == OP_DEST_REG && op->src.type == OP_SRC_ADD &&
1682 op->dest.reg == CFI_SP && op->src.reg == CFI_SP)
1683 cfa->offset -= op->src.offset;
1684
1685 return 0;
1686}
1687
1688static void save_reg(struct cfi_state *cfi, unsigned char reg, int base, int offset)
1689{
1690 if (arch_callee_saved_reg(reg) &&
1691 cfi->regs[reg].base == CFI_UNDEFINED) {
1692 cfi->regs[reg].base = base;
1693 cfi->regs[reg].offset = offset;
1694 }
1695}
1696
1697static void restore_reg(struct cfi_state *cfi, unsigned char reg)
1698{
1699 cfi->regs[reg].base = initial_func_cfi.regs[reg].base;
1700 cfi->regs[reg].offset = initial_func_cfi.regs[reg].offset;
1701}
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
1757 struct stack_op *op)
1758{
1759 struct cfi_reg *cfa = &cfi->cfa;
1760 struct cfi_reg *regs = cfi->regs;
1761
1762
1763 if (cfa->base == CFI_UNDEFINED) {
1764 if (insn->func) {
1765 WARN_FUNC("undefined stack state", insn->sec, insn->offset);
1766 return -1;
1767 }
1768 return 0;
1769 }
1770
1771 if (cfi->type == ORC_TYPE_REGS || cfi->type == ORC_TYPE_REGS_IRET)
1772 return update_cfi_state_regs(insn, cfi, op);
1773
1774 switch (op->dest.type) {
1775
1776 case OP_DEST_REG:
1777 switch (op->src.type) {
1778
1779 case OP_SRC_REG:
1780 if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP &&
1781 cfa->base == CFI_SP &&
1782 regs[CFI_BP].base == CFI_CFA &&
1783 regs[CFI_BP].offset == -cfa->offset) {
1784
1785
1786 cfa->base = op->dest.reg;
1787 cfi->bp_scratch = false;
1788 }
1789
1790 else if (op->src.reg == CFI_SP &&
1791 op->dest.reg == CFI_BP && cfi->drap) {
1792
1793
1794 regs[CFI_BP].base = CFI_BP;
1795 regs[CFI_BP].offset = -cfi->stack_size;
1796 cfi->bp_scratch = false;
1797 }
1798
1799 else if (op->src.reg == CFI_SP && cfa->base == CFI_SP) {
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811 cfi->vals[op->dest.reg].base = CFI_CFA;
1812 cfi->vals[op->dest.reg].offset = -cfi->stack_size;
1813 }
1814
1815 else if (op->src.reg == CFI_BP && op->dest.reg == CFI_SP &&
1816 cfa->base == CFI_BP) {
1817
1818
1819
1820
1821
1822
1823 cfi->stack_size = -cfi->regs[CFI_BP].offset;
1824 }
1825
1826 else if (op->dest.reg == cfa->base) {
1827
1828
1829 if (cfa->base == CFI_SP &&
1830 cfi->vals[op->src.reg].base == CFI_CFA) {
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840 cfa->offset = -cfi->vals[op->src.reg].offset;
1841 cfi->stack_size = cfa->offset;
1842
1843 } else {
1844 cfa->base = CFI_UNDEFINED;
1845 cfa->offset = 0;
1846 }
1847 }
1848
1849 break;
1850
1851 case OP_SRC_ADD:
1852 if (op->dest.reg == CFI_SP && op->src.reg == CFI_SP) {
1853
1854
1855 cfi->stack_size -= op->src.offset;
1856 if (cfa->base == CFI_SP)
1857 cfa->offset -= op->src.offset;
1858 break;
1859 }
1860
1861 if (op->dest.reg == CFI_SP && op->src.reg == CFI_BP) {
1862
1863
1864 cfi->stack_size = -(op->src.offset + regs[CFI_BP].offset);
1865 break;
1866 }
1867
1868 if (op->src.reg == CFI_SP && cfa->base == CFI_SP) {
1869
1870
1871 cfi->drap_reg = op->dest.reg;
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883 cfi->vals[op->dest.reg].base = CFI_CFA;
1884 cfi->vals[op->dest.reg].offset = \
1885 -cfi->stack_size + op->src.offset;
1886
1887 break;
1888 }
1889
1890 if (cfi->drap && op->dest.reg == CFI_SP &&
1891 op->src.reg == cfi->drap_reg) {
1892
1893
1894 cfa->base = CFI_SP;
1895 cfa->offset = cfi->stack_size = -op->src.offset;
1896 cfi->drap_reg = CFI_UNDEFINED;
1897 cfi->drap = false;
1898 break;
1899 }
1900
1901 if (op->dest.reg == cfi->cfa.base) {
1902 WARN_FUNC("unsupported stack register modification",
1903 insn->sec, insn->offset);
1904 return -1;
1905 }
1906
1907 break;
1908
1909 case OP_SRC_AND:
1910 if (op->dest.reg != CFI_SP ||
1911 (cfi->drap_reg != CFI_UNDEFINED && cfa->base != CFI_SP) ||
1912 (cfi->drap_reg == CFI_UNDEFINED && cfa->base != CFI_BP)) {
1913 WARN_FUNC("unsupported stack pointer realignment",
1914 insn->sec, insn->offset);
1915 return -1;
1916 }
1917
1918 if (cfi->drap_reg != CFI_UNDEFINED) {
1919
1920 cfa->base = cfi->drap_reg;
1921 cfa->offset = cfi->stack_size = 0;
1922 cfi->drap = true;
1923 }
1924
1925
1926
1927
1928
1929
1930 break;
1931
1932 case OP_SRC_POP:
1933 case OP_SRC_POPF:
1934 if (!cfi->drap && op->dest.reg == cfa->base) {
1935
1936
1937 cfa->base = CFI_SP;
1938 }
1939
1940 if (cfi->drap && cfa->base == CFI_BP_INDIRECT &&
1941 op->dest.reg == cfi->drap_reg &&
1942 cfi->drap_offset == -cfi->stack_size) {
1943
1944
1945 cfa->base = cfi->drap_reg;
1946 cfa->offset = 0;
1947 cfi->drap_offset = -1;
1948
1949 } else if (regs[op->dest.reg].offset == -cfi->stack_size) {
1950
1951
1952 restore_reg(cfi, op->dest.reg);
1953 }
1954
1955 cfi->stack_size -= 8;
1956 if (cfa->base == CFI_SP)
1957 cfa->offset -= 8;
1958
1959 break;
1960
1961 case OP_SRC_REG_INDIRECT:
1962 if (cfi->drap && op->src.reg == CFI_BP &&
1963 op->src.offset == cfi->drap_offset) {
1964
1965
1966 cfa->base = cfi->drap_reg;
1967 cfa->offset = 0;
1968 cfi->drap_offset = -1;
1969 }
1970
1971 if (cfi->drap && op->src.reg == CFI_BP &&
1972 op->src.offset == regs[op->dest.reg].offset) {
1973
1974
1975 restore_reg(cfi, op->dest.reg);
1976
1977 } else if (op->src.reg == cfa->base &&
1978 op->src.offset == regs[op->dest.reg].offset + cfa->offset) {
1979
1980
1981
1982 restore_reg(cfi, op->dest.reg);
1983 }
1984
1985 break;
1986
1987 default:
1988 WARN_FUNC("unknown stack-related instruction",
1989 insn->sec, insn->offset);
1990 return -1;
1991 }
1992
1993 break;
1994
1995 case OP_DEST_PUSH:
1996 case OP_DEST_PUSHF:
1997 cfi->stack_size += 8;
1998 if (cfa->base == CFI_SP)
1999 cfa->offset += 8;
2000
2001 if (op->src.type != OP_SRC_REG)
2002 break;
2003
2004 if (cfi->drap) {
2005 if (op->src.reg == cfa->base && op->src.reg == cfi->drap_reg) {
2006
2007
2008 cfa->base = CFI_BP_INDIRECT;
2009 cfa->offset = -cfi->stack_size;
2010
2011
2012 cfi->drap_offset = -cfi->stack_size;
2013
2014 } else if (op->src.reg == CFI_BP && cfa->base == cfi->drap_reg) {
2015
2016
2017 cfi->stack_size = 0;
2018
2019 } else if (regs[op->src.reg].base == CFI_UNDEFINED) {
2020
2021
2022 save_reg(cfi, op->src.reg, CFI_BP, -cfi->stack_size);
2023 }
2024
2025 } else {
2026
2027
2028 save_reg(cfi, op->src.reg, CFI_CFA, -cfi->stack_size);
2029 }
2030
2031
2032 if (!no_fp && insn->func && op->src.reg == CFI_BP &&
2033 cfa->base != CFI_BP)
2034 cfi->bp_scratch = true;
2035 break;
2036
2037 case OP_DEST_REG_INDIRECT:
2038
2039 if (cfi->drap) {
2040 if (op->src.reg == cfa->base && op->src.reg == cfi->drap_reg) {
2041
2042
2043 cfa->base = CFI_BP_INDIRECT;
2044 cfa->offset = op->dest.offset;
2045
2046
2047 cfi->drap_offset = op->dest.offset;
2048 }
2049
2050 else if (regs[op->src.reg].base == CFI_UNDEFINED) {
2051
2052
2053 save_reg(cfi, op->src.reg, CFI_BP, op->dest.offset);
2054 }
2055
2056 } else if (op->dest.reg == cfa->base) {
2057
2058
2059
2060 save_reg(cfi, op->src.reg, CFI_CFA,
2061 op->dest.offset - cfi->cfa.offset);
2062 }
2063
2064 break;
2065
2066 case OP_DEST_LEAVE:
2067 if ((!cfi->drap && cfa->base != CFI_BP) ||
2068 (cfi->drap && cfa->base != cfi->drap_reg)) {
2069 WARN_FUNC("leave instruction with modified stack frame",
2070 insn->sec, insn->offset);
2071 return -1;
2072 }
2073
2074
2075
2076 cfi->stack_size = -cfi->regs[CFI_BP].offset - 8;
2077 restore_reg(cfi, CFI_BP);
2078
2079 if (!cfi->drap) {
2080 cfa->base = CFI_SP;
2081 cfa->offset -= 8;
2082 }
2083
2084 break;
2085
2086 case OP_DEST_MEM:
2087 if (op->src.type != OP_SRC_POP && op->src.type != OP_SRC_POPF) {
2088 WARN_FUNC("unknown stack-related memory operation",
2089 insn->sec, insn->offset);
2090 return -1;
2091 }
2092
2093
2094 cfi->stack_size -= 8;
2095 if (cfa->base == CFI_SP)
2096 cfa->offset -= 8;
2097
2098 break;
2099
2100 default:
2101 WARN_FUNC("unknown stack-related instruction",
2102 insn->sec, insn->offset);
2103 return -1;
2104 }
2105
2106 return 0;
2107}
2108
2109static int handle_insn_ops(struct instruction *insn, struct insn_state *state)
2110{
2111 struct stack_op *op;
2112
2113 list_for_each_entry(op, &insn->stack_ops, list) {
2114 struct cfi_state old_cfi = state->cfi;
2115 int res;
2116
2117 res = update_cfi_state(insn, &state->cfi, op);
2118 if (res)
2119 return res;
2120
2121 if (insn->alt_group && memcmp(&state->cfi, &old_cfi, sizeof(struct cfi_state))) {
2122 WARN_FUNC("alternative modifies stack", insn->sec, insn->offset);
2123 return -1;
2124 }
2125
2126 if (op->dest.type == OP_DEST_PUSHF) {
2127 if (!state->uaccess_stack) {
2128 state->uaccess_stack = 1;
2129 } else if (state->uaccess_stack >> 31) {
2130 WARN_FUNC("PUSHF stack exhausted",
2131 insn->sec, insn->offset);
2132 return 1;
2133 }
2134 state->uaccess_stack <<= 1;
2135 state->uaccess_stack |= state->uaccess;
2136 }
2137
2138 if (op->src.type == OP_SRC_POPF) {
2139 if (state->uaccess_stack) {
2140 state->uaccess = state->uaccess_stack & 1;
2141 state->uaccess_stack >>= 1;
2142 if (state->uaccess_stack == 1)
2143 state->uaccess_stack = 0;
2144 }
2145 }
2146 }
2147
2148 return 0;
2149}
2150
2151static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2)
2152{
2153 struct cfi_state *cfi1 = &insn->cfi;
2154 int i;
2155
2156 if (memcmp(&cfi1->cfa, &cfi2->cfa, sizeof(cfi1->cfa))) {
2157
2158 WARN_FUNC("stack state mismatch: cfa1=%d%+d cfa2=%d%+d",
2159 insn->sec, insn->offset,
2160 cfi1->cfa.base, cfi1->cfa.offset,
2161 cfi2->cfa.base, cfi2->cfa.offset);
2162
2163 } else if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) {
2164 for (i = 0; i < CFI_NUM_REGS; i++) {
2165 if (!memcmp(&cfi1->regs[i], &cfi2->regs[i],
2166 sizeof(struct cfi_reg)))
2167 continue;
2168
2169 WARN_FUNC("stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d",
2170 insn->sec, insn->offset,
2171 i, cfi1->regs[i].base, cfi1->regs[i].offset,
2172 i, cfi2->regs[i].base, cfi2->regs[i].offset);
2173 break;
2174 }
2175
2176 } else if (cfi1->type != cfi2->type) {
2177
2178 WARN_FUNC("stack state mismatch: type1=%d type2=%d",
2179 insn->sec, insn->offset, cfi1->type, cfi2->type);
2180
2181 } else if (cfi1->drap != cfi2->drap ||
2182 (cfi1->drap && cfi1->drap_reg != cfi2->drap_reg) ||
2183 (cfi1->drap && cfi1->drap_offset != cfi2->drap_offset)) {
2184
2185 WARN_FUNC("stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)",
2186 insn->sec, insn->offset,
2187 cfi1->drap, cfi1->drap_reg, cfi1->drap_offset,
2188 cfi2->drap, cfi2->drap_reg, cfi2->drap_offset);
2189
2190 } else
2191 return true;
2192
2193 return false;
2194}
2195
2196static inline bool func_uaccess_safe(struct symbol *func)
2197{
2198 if (func)
2199 return func->uaccess_safe;
2200
2201 return false;
2202}
2203
2204static inline const char *call_dest_name(struct instruction *insn)
2205{
2206 if (insn->call_dest)
2207 return insn->call_dest->name;
2208
2209 return "{dynamic}";
2210}
2211
2212static inline bool noinstr_call_dest(struct symbol *func)
2213{
2214
2215
2216
2217
2218 if (!func)
2219 return false;
2220
2221
2222
2223
2224 if (func->sec->noinstr)
2225 return true;
2226
2227
2228
2229
2230
2231
2232 if (!strncmp(func->name, "__ubsan_handle_", 15))
2233 return true;
2234
2235 return false;
2236}
2237
2238static int validate_call(struct instruction *insn, struct insn_state *state)
2239{
2240 if (state->noinstr && state->instr <= 0 &&
2241 !noinstr_call_dest(insn->call_dest)) {
2242 WARN_FUNC("call to %s() leaves .noinstr.text section",
2243 insn->sec, insn->offset, call_dest_name(insn));
2244 return 1;
2245 }
2246
2247 if (state->uaccess && !func_uaccess_safe(insn->call_dest)) {
2248 WARN_FUNC("call to %s() with UACCESS enabled",
2249 insn->sec, insn->offset, call_dest_name(insn));
2250 return 1;
2251 }
2252
2253 if (state->df) {
2254 WARN_FUNC("call to %s() with DF set",
2255 insn->sec, insn->offset, call_dest_name(insn));
2256 return 1;
2257 }
2258
2259 return 0;
2260}
2261
2262static int validate_sibling_call(struct instruction *insn, struct insn_state *state)
2263{
2264 if (has_modified_stack_frame(insn, state)) {
2265 WARN_FUNC("sibling call from callable instruction with modified stack frame",
2266 insn->sec, insn->offset);
2267 return 1;
2268 }
2269
2270 return validate_call(insn, state);
2271}
2272
2273static int validate_return(struct symbol *func, struct instruction *insn, struct insn_state *state)
2274{
2275 if (state->noinstr && state->instr > 0) {
2276 WARN_FUNC("return with instrumentation enabled",
2277 insn->sec, insn->offset);
2278 return 1;
2279 }
2280
2281 if (state->uaccess && !func_uaccess_safe(func)) {
2282 WARN_FUNC("return with UACCESS enabled",
2283 insn->sec, insn->offset);
2284 return 1;
2285 }
2286
2287 if (!state->uaccess && func_uaccess_safe(func)) {
2288 WARN_FUNC("return with UACCESS disabled from a UACCESS-safe function",
2289 insn->sec, insn->offset);
2290 return 1;
2291 }
2292
2293 if (state->df) {
2294 WARN_FUNC("return with DF set",
2295 insn->sec, insn->offset);
2296 return 1;
2297 }
2298
2299 if (func && has_modified_stack_frame(insn, state)) {
2300 WARN_FUNC("return with modified stack frame",
2301 insn->sec, insn->offset);
2302 return 1;
2303 }
2304
2305 if (state->cfi.bp_scratch) {
2306 WARN_FUNC("BP used as a scratch register",
2307 insn->sec, insn->offset);
2308 return 1;
2309 }
2310
2311 return 0;
2312}
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326static void fill_alternative_cfi(struct objtool_file *file, struct instruction *insn)
2327{
2328 struct instruction *first_insn = insn;
2329 int alt_group = insn->alt_group;
2330
2331 sec_for_each_insn_continue(file, insn) {
2332 if (insn->alt_group != alt_group)
2333 break;
2334 insn->cfi = first_insn->cfi;
2335 }
2336}
2337
2338
2339
2340
2341
2342
2343
2344static int validate_branch(struct objtool_file *file, struct symbol *func,
2345 struct instruction *insn, struct insn_state state)
2346{
2347 struct alternative *alt;
2348 struct instruction *next_insn;
2349 struct section *sec;
2350 u8 visited;
2351 int ret;
2352
2353 sec = insn->sec;
2354
2355 while (1) {
2356 next_insn = next_insn_same_sec(file, insn);
2357
2358 if (file->c_file && func && insn->func && func != insn->func->pfunc) {
2359 WARN("%s() falls through to next function %s()",
2360 func->name, insn->func->name);
2361 return 1;
2362 }
2363
2364 if (func && insn->ignore) {
2365 WARN_FUNC("BUG: why am I validating an ignored function?",
2366 sec, insn->offset);
2367 return 1;
2368 }
2369
2370 visited = 1 << state.uaccess;
2371 if (insn->visited) {
2372 if (!insn->hint && !insn_cfi_match(insn, &state.cfi))
2373 return 1;
2374
2375 if (insn->visited & visited)
2376 return 0;
2377 }
2378
2379 if (state.noinstr)
2380 state.instr += insn->instr;
2381
2382 if (insn->hint)
2383 state.cfi = insn->cfi;
2384 else
2385 insn->cfi = state.cfi;
2386
2387 insn->visited |= visited;
2388
2389 if (!insn->ignore_alts && !list_empty(&insn->alts)) {
2390 bool skip_orig = false;
2391
2392 list_for_each_entry(alt, &insn->alts, list) {
2393 if (alt->skip_orig)
2394 skip_orig = true;
2395
2396 ret = validate_branch(file, func, alt->insn, state);
2397 if (ret) {
2398 if (backtrace)
2399 BT_FUNC("(alt)", insn);
2400 return ret;
2401 }
2402 }
2403
2404 if (insn->alt_group)
2405 fill_alternative_cfi(file, insn);
2406
2407 if (skip_orig)
2408 return 0;
2409 }
2410
2411 if (handle_insn_ops(insn, &state))
2412 return 1;
2413
2414 switch (insn->type) {
2415
2416 case INSN_RETURN:
2417 return validate_return(func, insn, &state);
2418
2419 case INSN_CALL:
2420 case INSN_CALL_DYNAMIC:
2421 ret = validate_call(insn, &state);
2422 if (ret)
2423 return ret;
2424
2425 if (!no_fp && func && !is_fentry_call(insn) &&
2426 !has_valid_stack_frame(&state)) {
2427 WARN_FUNC("call without frame pointer save/setup",
2428 sec, insn->offset);
2429 return 1;
2430 }
2431
2432 if (dead_end_function(file, insn->call_dest))
2433 return 0;
2434
2435 break;
2436
2437 case INSN_JUMP_CONDITIONAL:
2438 case INSN_JUMP_UNCONDITIONAL:
2439 if (func && is_sibling_call(insn)) {
2440 ret = validate_sibling_call(insn, &state);
2441 if (ret)
2442 return ret;
2443
2444 } else if (insn->jump_dest) {
2445 ret = validate_branch(file, func,
2446 insn->jump_dest, state);
2447 if (ret) {
2448 if (backtrace)
2449 BT_FUNC("(branch)", insn);
2450 return ret;
2451 }
2452 }
2453
2454 if (insn->type == INSN_JUMP_UNCONDITIONAL)
2455 return 0;
2456
2457 break;
2458
2459 case INSN_JUMP_DYNAMIC:
2460 case INSN_JUMP_DYNAMIC_CONDITIONAL:
2461 if (func && is_sibling_call(insn)) {
2462 ret = validate_sibling_call(insn, &state);
2463 if (ret)
2464 return ret;
2465 }
2466
2467 if (insn->type == INSN_JUMP_DYNAMIC)
2468 return 0;
2469
2470 break;
2471
2472 case INSN_CONTEXT_SWITCH:
2473 if (func && (!next_insn || !next_insn->hint)) {
2474 WARN_FUNC("unsupported instruction in callable function",
2475 sec, insn->offset);
2476 return 1;
2477 }
2478 return 0;
2479
2480 case INSN_STAC:
2481 if (state.uaccess) {
2482 WARN_FUNC("recursive UACCESS enable", sec, insn->offset);
2483 return 1;
2484 }
2485
2486 state.uaccess = true;
2487 break;
2488
2489 case INSN_CLAC:
2490 if (!state.uaccess && func) {
2491 WARN_FUNC("redundant UACCESS disable", sec, insn->offset);
2492 return 1;
2493 }
2494
2495 if (func_uaccess_safe(func) && !state.uaccess_stack) {
2496 WARN_FUNC("UACCESS-safe disables UACCESS", sec, insn->offset);
2497 return 1;
2498 }
2499
2500 state.uaccess = false;
2501 break;
2502
2503 case INSN_STD:
2504 if (state.df)
2505 WARN_FUNC("recursive STD", sec, insn->offset);
2506
2507 state.df = true;
2508 break;
2509
2510 case INSN_CLD:
2511 if (!state.df && func)
2512 WARN_FUNC("redundant CLD", sec, insn->offset);
2513
2514 state.df = false;
2515 break;
2516
2517 default:
2518 break;
2519 }
2520
2521 if (insn->dead_end)
2522 return 0;
2523
2524 if (!next_insn) {
2525 if (state.cfi.cfa.base == CFI_UNDEFINED)
2526 return 0;
2527 WARN("%s: unexpected end of section", sec->name);
2528 return 1;
2529 }
2530
2531 insn = next_insn;
2532 }
2533
2534 return 0;
2535}
2536
2537static int validate_unwind_hints(struct objtool_file *file, struct section *sec)
2538{
2539 struct instruction *insn;
2540 struct insn_state state;
2541 int ret, warnings = 0;
2542
2543 if (!file->hints)
2544 return 0;
2545
2546 init_insn_state(&state, sec);
2547
2548 if (sec) {
2549 insn = find_insn(file, sec, 0);
2550 if (!insn)
2551 return 0;
2552 } else {
2553 insn = list_first_entry(&file->insn_list, typeof(*insn), list);
2554 }
2555
2556 while (&insn->list != &file->insn_list && (!sec || insn->sec == sec)) {
2557 if (insn->hint && !insn->visited) {
2558 ret = validate_branch(file, insn->func, insn, state);
2559 if (ret && backtrace)
2560 BT_FUNC("<=== (hint)", insn);
2561 warnings += ret;
2562 }
2563
2564 insn = list_next_entry(insn, list);
2565 }
2566
2567 return warnings;
2568}
2569
2570static int validate_retpoline(struct objtool_file *file)
2571{
2572 struct instruction *insn;
2573 int warnings = 0;
2574
2575 for_each_insn(file, insn) {
2576 if (insn->type != INSN_JUMP_DYNAMIC &&
2577 insn->type != INSN_CALL_DYNAMIC)
2578 continue;
2579
2580 if (insn->retpoline_safe)
2581 continue;
2582
2583
2584
2585
2586
2587
2588
2589 if (!strcmp(insn->sec->name, ".init.text") && !module)
2590 continue;
2591
2592 WARN_FUNC("indirect %s found in RETPOLINE build",
2593 insn->sec, insn->offset,
2594 insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call");
2595
2596 warnings++;
2597 }
2598
2599 return warnings;
2600}
2601
2602static bool is_kasan_insn(struct instruction *insn)
2603{
2604 return (insn->type == INSN_CALL &&
2605 !strcmp(insn->call_dest->name, "__asan_handle_no_return"));
2606}
2607
2608static bool is_ubsan_insn(struct instruction *insn)
2609{
2610 return (insn->type == INSN_CALL &&
2611 !strcmp(insn->call_dest->name,
2612 "__ubsan_handle_builtin_unreachable"));
2613}
2614
2615static bool ignore_unreachable_insn(struct instruction *insn)
2616{
2617 int i;
2618
2619 if (insn->ignore || insn->type == INSN_NOP)
2620 return true;
2621
2622
2623
2624
2625
2626
2627
2628
2629 if (!strcmp(insn->sec->name, ".fixup") ||
2630 !strcmp(insn->sec->name, ".altinstr_replacement") ||
2631 !strcmp(insn->sec->name, ".altinstr_aux"))
2632 return true;
2633
2634 if (!insn->func)
2635 return false;
2636
2637
2638
2639
2640
2641
2642
2643 if (list_prev_entry(insn, list)->dead_end &&
2644 (insn->type == INSN_BUG ||
2645 (insn->type == INSN_JUMP_UNCONDITIONAL &&
2646 insn->jump_dest && insn->jump_dest->type == INSN_BUG)))
2647 return true;
2648
2649
2650
2651
2652
2653
2654
2655 for (i = 0; i < 5; i++) {
2656
2657 if (is_kasan_insn(insn) || is_ubsan_insn(insn))
2658 return true;
2659
2660 if (insn->type == INSN_JUMP_UNCONDITIONAL) {
2661 if (insn->jump_dest &&
2662 insn->jump_dest->func == insn->func) {
2663 insn = insn->jump_dest;
2664 continue;
2665 }
2666
2667 break;
2668 }
2669
2670 if (insn->offset + insn->len >= insn->func->offset + insn->func->len)
2671 break;
2672
2673 insn = list_next_entry(insn, list);
2674 }
2675
2676 return false;
2677}
2678
2679static int validate_symbol(struct objtool_file *file, struct section *sec,
2680 struct symbol *sym, struct insn_state *state)
2681{
2682 struct instruction *insn;
2683 int ret;
2684
2685 if (!sym->len) {
2686 WARN("%s() is missing an ELF size annotation", sym->name);
2687 return 1;
2688 }
2689
2690 if (sym->pfunc != sym || sym->alias != sym)
2691 return 0;
2692
2693 insn = find_insn(file, sec, sym->offset);
2694 if (!insn || insn->ignore || insn->visited)
2695 return 0;
2696
2697 state->uaccess = sym->uaccess_safe;
2698
2699 ret = validate_branch(file, insn->func, insn, *state);
2700 if (ret && backtrace)
2701 BT_FUNC("<=== (sym)", insn);
2702 return ret;
2703}
2704
2705static int validate_section(struct objtool_file *file, struct section *sec)
2706{
2707 struct insn_state state;
2708 struct symbol *func;
2709 int warnings = 0;
2710
2711 list_for_each_entry(func, &sec->symbol_list, list) {
2712 if (func->type != STT_FUNC)
2713 continue;
2714
2715 init_insn_state(&state, sec);
2716 state.cfi.cfa = initial_func_cfi.cfa;
2717 memcpy(&state.cfi.regs, &initial_func_cfi.regs,
2718 CFI_NUM_REGS * sizeof(struct cfi_reg));
2719 state.cfi.stack_size = initial_func_cfi.cfa.offset;
2720
2721 warnings += validate_symbol(file, sec, func, &state);
2722 }
2723
2724 return warnings;
2725}
2726
2727static int validate_vmlinux_functions(struct objtool_file *file)
2728{
2729 struct section *sec;
2730 int warnings = 0;
2731
2732 sec = find_section_by_name(file->elf, ".noinstr.text");
2733 if (sec) {
2734 warnings += validate_section(file, sec);
2735 warnings += validate_unwind_hints(file, sec);
2736 }
2737
2738 sec = find_section_by_name(file->elf, ".entry.text");
2739 if (sec) {
2740 warnings += validate_section(file, sec);
2741 warnings += validate_unwind_hints(file, sec);
2742 }
2743
2744 return warnings;
2745}
2746
2747static int validate_functions(struct objtool_file *file)
2748{
2749 struct section *sec;
2750 int warnings = 0;
2751
2752 for_each_sec(file, sec) {
2753 if (!(sec->sh.sh_flags & SHF_EXECINSTR))
2754 continue;
2755
2756 warnings += validate_section(file, sec);
2757 }
2758
2759 return warnings;
2760}
2761
2762static int validate_reachable_instructions(struct objtool_file *file)
2763{
2764 struct instruction *insn;
2765
2766 if (file->ignore_unreachables)
2767 return 0;
2768
2769 for_each_insn(file, insn) {
2770 if (insn->visited || ignore_unreachable_insn(insn))
2771 continue;
2772
2773 WARN_FUNC("unreachable instruction", insn->sec, insn->offset);
2774 return 1;
2775 }
2776
2777 return 0;
2778}
2779
2780static struct objtool_file file;
2781
2782int check(const char *_objname, bool orc)
2783{
2784 int ret, warnings = 0;
2785
2786 objname = _objname;
2787
2788 file.elf = elf_open_read(objname, O_RDWR);
2789 if (!file.elf)
2790 return 1;
2791
2792 INIT_LIST_HEAD(&file.insn_list);
2793 hash_init(file.insn_hash);
2794 file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment");
2795 file.ignore_unreachables = no_unreachable;
2796 file.hints = false;
2797
2798 arch_initial_func_cfi_state(&initial_func_cfi);
2799
2800 ret = decode_sections(&file);
2801 if (ret < 0)
2802 goto out;
2803 warnings += ret;
2804
2805 if (list_empty(&file.insn_list))
2806 goto out;
2807
2808 if (vmlinux && !validate_dup) {
2809 ret = validate_vmlinux_functions(&file);
2810 if (ret < 0)
2811 goto out;
2812
2813 warnings += ret;
2814 goto out;
2815 }
2816
2817 if (retpoline) {
2818 ret = validate_retpoline(&file);
2819 if (ret < 0)
2820 return ret;
2821 warnings += ret;
2822 }
2823
2824 ret = validate_functions(&file);
2825 if (ret < 0)
2826 goto out;
2827 warnings += ret;
2828
2829 ret = validate_unwind_hints(&file, NULL);
2830 if (ret < 0)
2831 goto out;
2832 warnings += ret;
2833
2834 if (!warnings) {
2835 ret = validate_reachable_instructions(&file);
2836 if (ret < 0)
2837 goto out;
2838 warnings += ret;
2839 }
2840
2841 if (orc) {
2842 ret = create_orc(&file);
2843 if (ret < 0)
2844 goto out;
2845
2846 ret = create_orc_sections(&file);
2847 if (ret < 0)
2848 goto out;
2849 }
2850
2851 if (file.elf->changed) {
2852 ret = elf_write(file.elf);
2853 if (ret < 0)
2854 goto out;
2855 }
2856
2857out:
2858 if (ret < 0) {
2859
2860
2861
2862
2863
2864 return ret;
2865 }
2866
2867 return 0;
2868}
2869