1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <string.h>
19#include <stdlib.h>
20
21#include "builtin.h"
22#include "check.h"
23#include "elf.h"
24#include "special.h"
25#include "arch.h"
26#include "warn.h"
27
28#include <linux/hashtable.h>
29#include <linux/kernel.h>
30
31struct alternative {
32 struct list_head list;
33 struct instruction *insn;
34};
35
36const char *objname;
37struct cfi_state initial_func_cfi;
38
39struct instruction *find_insn(struct objtool_file *file,
40 struct section *sec, unsigned long offset)
41{
42 struct instruction *insn;
43
44 hash_for_each_possible(file->insn_hash, insn, hash, offset)
45 if (insn->sec == sec && insn->offset == offset)
46 return insn;
47
48 return NULL;
49}
50
51static struct instruction *next_insn_same_sec(struct objtool_file *file,
52 struct instruction *insn)
53{
54 struct instruction *next = list_next_entry(insn, list);
55
56 if (!next || &next->list == &file->insn_list || next->sec != insn->sec)
57 return NULL;
58
59 return next;
60}
61
62static struct instruction *next_insn_same_func(struct objtool_file *file,
63 struct instruction *insn)
64{
65 struct instruction *next = list_next_entry(insn, list);
66 struct symbol *func = insn->func;
67
68 if (!func)
69 return NULL;
70
71 if (&next->list != &file->insn_list && next->func == func)
72 return next;
73
74
75 if (func == func->cfunc)
76 return NULL;
77
78
79 return find_insn(file, func->cfunc->sec, func->cfunc->offset);
80}
81
82#define func_for_each_insn_all(file, func, insn) \
83 for (insn = find_insn(file, func->sec, func->offset); \
84 insn; \
85 insn = next_insn_same_func(file, insn))
86
87#define func_for_each_insn(file, func, insn) \
88 for (insn = find_insn(file, func->sec, func->offset); \
89 insn && &insn->list != &file->insn_list && \
90 insn->sec == func->sec && \
91 insn->offset < func->offset + func->len; \
92 insn = list_next_entry(insn, list))
93
94#define func_for_each_insn_continue_reverse(file, func, insn) \
95 for (insn = list_prev_entry(insn, list); \
96 &insn->list != &file->insn_list && \
97 insn->sec == func->sec && insn->offset >= func->offset; \
98 insn = list_prev_entry(insn, list))
99
100#define sec_for_each_insn_from(file, insn) \
101 for (; insn; insn = next_insn_same_sec(file, insn))
102
103#define sec_for_each_insn_continue(file, insn) \
104 for (insn = next_insn_same_sec(file, insn); insn; \
105 insn = next_insn_same_sec(file, insn))
106
107
108
109
110
111
112static bool ignore_func(struct objtool_file *file, struct symbol *func)
113{
114 struct rela *rela;
115
116
117 if (file->whitelist && file->whitelist->rela)
118 list_for_each_entry(rela, &file->whitelist->rela->rela_list, list) {
119 if (rela->sym->type == STT_SECTION &&
120 rela->sym->sec == func->sec &&
121 rela->addend == func->offset)
122 return true;
123 if (rela->sym->type == STT_FUNC && rela->sym == func)
124 return true;
125 }
126
127 return false;
128}
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144static int __dead_end_function(struct objtool_file *file, struct symbol *func,
145 int recursion)
146{
147 int i;
148 struct instruction *insn;
149 bool empty = true;
150
151
152
153
154
155 static const char * const global_noreturns[] = {
156 "__stack_chk_fail",
157 "panic",
158 "do_exit",
159 "do_task_dead",
160 "__module_put_and_exit",
161 "complete_and_exit",
162 "kvm_spurious_fault",
163 "__reiserfs_panic",
164 "lbug_with_loc",
165 "fortify_panic",
166 "usercopy_abort",
167 };
168
169 if (func->bind == STB_WEAK)
170 return 0;
171
172 if (func->bind == STB_GLOBAL)
173 for (i = 0; i < ARRAY_SIZE(global_noreturns); i++)
174 if (!strcmp(func->name, global_noreturns[i]))
175 return 1;
176
177 if (!func->len)
178 return 0;
179
180 insn = find_insn(file, func->sec, func->offset);
181 if (!insn->func)
182 return 0;
183
184 func_for_each_insn_all(file, func, insn) {
185 empty = false;
186
187 if (insn->type == INSN_RETURN)
188 return 0;
189 }
190
191 if (empty)
192 return 0;
193
194
195
196
197
198
199 func_for_each_insn_all(file, func, insn) {
200 if (insn->type == INSN_JUMP_UNCONDITIONAL) {
201 struct instruction *dest = insn->jump_dest;
202
203 if (!dest)
204
205 return 0;
206
207 if (dest->func && dest->func->pfunc != insn->func->pfunc) {
208
209
210 if (recursion == 5) {
211
212
213
214
215
216
217 return 0;
218 }
219
220 return __dead_end_function(file, dest->func,
221 recursion + 1);
222 }
223 }
224
225 if (insn->type == INSN_JUMP_DYNAMIC && list_empty(&insn->alts))
226
227 return 0;
228 }
229
230 return 1;
231}
232
233static int dead_end_function(struct objtool_file *file, struct symbol *func)
234{
235 return __dead_end_function(file, func, 0);
236}
237
238static void clear_insn_state(struct insn_state *state)
239{
240 int i;
241
242 memset(state, 0, sizeof(*state));
243 state->cfa.base = CFI_UNDEFINED;
244 for (i = 0; i < CFI_NUM_REGS; i++) {
245 state->regs[i].base = CFI_UNDEFINED;
246 state->vals[i].base = CFI_UNDEFINED;
247 }
248 state->drap_reg = CFI_UNDEFINED;
249 state->drap_offset = -1;
250}
251
252
253
254
255
256static int decode_instructions(struct objtool_file *file)
257{
258 struct section *sec;
259 struct symbol *func;
260 unsigned long offset;
261 struct instruction *insn;
262 int ret;
263
264 for_each_sec(file, sec) {
265
266 if (!(sec->sh.sh_flags & SHF_EXECINSTR))
267 continue;
268
269 if (strcmp(sec->name, ".altinstr_replacement") &&
270 strcmp(sec->name, ".altinstr_aux") &&
271 strncmp(sec->name, ".discard.", 9))
272 sec->text = true;
273
274 for (offset = 0; offset < sec->len; offset += insn->len) {
275 insn = malloc(sizeof(*insn));
276 if (!insn) {
277 WARN("malloc failed");
278 return -1;
279 }
280 memset(insn, 0, sizeof(*insn));
281 INIT_LIST_HEAD(&insn->alts);
282 clear_insn_state(&insn->state);
283
284 insn->sec = sec;
285 insn->offset = offset;
286
287 ret = arch_decode_instruction(file->elf, sec, offset,
288 sec->len - offset,
289 &insn->len, &insn->type,
290 &insn->immediate,
291 &insn->stack_op);
292 if (ret)
293 goto err;
294
295 if (!insn->type || insn->type > INSN_LAST) {
296 WARN_FUNC("invalid instruction type %d",
297 insn->sec, insn->offset, insn->type);
298 ret = -1;
299 goto err;
300 }
301
302 hash_add(file->insn_hash, &insn->hash, insn->offset);
303 list_add_tail(&insn->list, &file->insn_list);
304 }
305
306 list_for_each_entry(func, &sec->symbol_list, list) {
307 if (func->type != STT_FUNC)
308 continue;
309
310 if (!find_insn(file, sec, func->offset)) {
311 WARN("%s(): can't find starting instruction",
312 func->name);
313 return -1;
314 }
315
316 func_for_each_insn(file, func, insn)
317 if (!insn->func)
318 insn->func = func;
319 }
320 }
321
322 return 0;
323
324err:
325 free(insn);
326 return ret;
327}
328
329
330
331
332static int add_dead_ends(struct objtool_file *file)
333{
334 struct section *sec;
335 struct rela *rela;
336 struct instruction *insn;
337 bool found;
338
339
340
341
342
343 for_each_insn(file, insn)
344 if (insn->type == INSN_BUG)
345 insn->dead_end = true;
346
347
348
349
350 sec = find_section_by_name(file->elf, ".rela.discard.unreachable");
351 if (!sec)
352 goto reachable;
353
354 list_for_each_entry(rela, &sec->rela_list, list) {
355 if (rela->sym->type != STT_SECTION) {
356 WARN("unexpected relocation symbol type in %s", sec->name);
357 return -1;
358 }
359 insn = find_insn(file, rela->sym->sec, rela->addend);
360 if (insn)
361 insn = list_prev_entry(insn, list);
362 else if (rela->addend == rela->sym->sec->len) {
363 found = false;
364 list_for_each_entry_reverse(insn, &file->insn_list, list) {
365 if (insn->sec == rela->sym->sec) {
366 found = true;
367 break;
368 }
369 }
370
371 if (!found) {
372 WARN("can't find unreachable insn at %s+0x%x",
373 rela->sym->sec->name, rela->addend);
374 return -1;
375 }
376 } else {
377 WARN("can't find unreachable insn at %s+0x%x",
378 rela->sym->sec->name, rela->addend);
379 return -1;
380 }
381
382 insn->dead_end = true;
383 }
384
385reachable:
386
387
388
389
390
391
392 sec = find_section_by_name(file->elf, ".rela.discard.reachable");
393 if (!sec)
394 return 0;
395
396 list_for_each_entry(rela, &sec->rela_list, list) {
397 if (rela->sym->type != STT_SECTION) {
398 WARN("unexpected relocation symbol type in %s", sec->name);
399 return -1;
400 }
401 insn = find_insn(file, rela->sym->sec, rela->addend);
402 if (insn)
403 insn = list_prev_entry(insn, list);
404 else if (rela->addend == rela->sym->sec->len) {
405 found = false;
406 list_for_each_entry_reverse(insn, &file->insn_list, list) {
407 if (insn->sec == rela->sym->sec) {
408 found = true;
409 break;
410 }
411 }
412
413 if (!found) {
414 WARN("can't find reachable insn at %s+0x%x",
415 rela->sym->sec->name, rela->addend);
416 return -1;
417 }
418 } else {
419 WARN("can't find reachable insn at %s+0x%x",
420 rela->sym->sec->name, rela->addend);
421 return -1;
422 }
423
424 insn->dead_end = false;
425 }
426
427 return 0;
428}
429
430
431
432
433static void add_ignores(struct objtool_file *file)
434{
435 struct instruction *insn;
436 struct section *sec;
437 struct symbol *func;
438
439 for_each_sec(file, sec) {
440 list_for_each_entry(func, &sec->symbol_list, list) {
441 if (func->type != STT_FUNC)
442 continue;
443
444 if (!ignore_func(file, func))
445 continue;
446
447 func_for_each_insn_all(file, func, insn)
448 insn->ignore = true;
449 }
450 }
451}
452
453
454
455
456
457
458
459static int add_nospec_ignores(struct objtool_file *file)
460{
461 struct section *sec;
462 struct rela *rela;
463 struct instruction *insn;
464
465 sec = find_section_by_name(file->elf, ".rela.discard.nospec");
466 if (!sec)
467 return 0;
468
469 list_for_each_entry(rela, &sec->rela_list, list) {
470 if (rela->sym->type != STT_SECTION) {
471 WARN("unexpected relocation symbol type in %s", sec->name);
472 return -1;
473 }
474
475 insn = find_insn(file, rela->sym->sec, rela->addend);
476 if (!insn) {
477 WARN("bad .discard.nospec entry");
478 return -1;
479 }
480
481 insn->ignore_alts = true;
482 }
483
484 return 0;
485}
486
487
488
489
490static int add_jump_destinations(struct objtool_file *file)
491{
492 struct instruction *insn;
493 struct rela *rela;
494 struct section *dest_sec;
495 unsigned long dest_off;
496
497 for_each_insn(file, insn) {
498 if (insn->type != INSN_JUMP_CONDITIONAL &&
499 insn->type != INSN_JUMP_UNCONDITIONAL)
500 continue;
501
502 if (insn->ignore)
503 continue;
504
505 rela = find_rela_by_dest_range(insn->sec, insn->offset,
506 insn->len);
507 if (!rela) {
508 dest_sec = insn->sec;
509 dest_off = insn->offset + insn->len + insn->immediate;
510 } else if (rela->sym->type == STT_SECTION) {
511 dest_sec = rela->sym->sec;
512 dest_off = rela->addend + 4;
513 } else if (rela->sym->sec->idx) {
514 dest_sec = rela->sym->sec;
515 dest_off = rela->sym->sym.st_value + rela->addend + 4;
516 } else if (strstr(rela->sym->name, "_indirect_thunk_")) {
517
518
519
520
521 insn->type = INSN_JUMP_DYNAMIC;
522 insn->retpoline_safe = true;
523 continue;
524 } else {
525
526 insn->jump_dest = 0;
527 continue;
528 }
529
530 insn->jump_dest = find_insn(file, dest_sec, dest_off);
531 if (!insn->jump_dest) {
532
533
534
535
536
537
538 if (!strcmp(insn->sec->name, ".altinstr_replacement"))
539 continue;
540
541 WARN_FUNC("can't find jump dest instruction at %s+0x%lx",
542 insn->sec, insn->offset, dest_sec->name,
543 dest_off);
544 return -1;
545 }
546 }
547
548 return 0;
549}
550
551
552
553
554static int add_call_destinations(struct objtool_file *file)
555{
556 struct instruction *insn;
557 unsigned long dest_off;
558 struct rela *rela;
559
560 for_each_insn(file, insn) {
561 if (insn->type != INSN_CALL)
562 continue;
563
564 rela = find_rela_by_dest_range(insn->sec, insn->offset,
565 insn->len);
566 if (!rela) {
567 dest_off = insn->offset + insn->len + insn->immediate;
568 insn->call_dest = find_symbol_by_offset(insn->sec,
569 dest_off);
570
571 if (!insn->call_dest && !insn->ignore) {
572 WARN_FUNC("unsupported intra-function call",
573 insn->sec, insn->offset);
574 if (retpoline)
575 WARN("If this is a retpoline, please patch it in with alternatives and annotate it with ANNOTATE_NOSPEC_ALTERNATIVE.");
576 return -1;
577 }
578
579 } else if (rela->sym->type == STT_SECTION) {
580 insn->call_dest = find_symbol_by_offset(rela->sym->sec,
581 rela->addend+4);
582 if (!insn->call_dest ||
583 insn->call_dest->type != STT_FUNC) {
584 WARN_FUNC("can't find call dest symbol at %s+0x%x",
585 insn->sec, insn->offset,
586 rela->sym->sec->name,
587 rela->addend + 4);
588 return -1;
589 }
590 } else
591 insn->call_dest = rela->sym;
592 }
593
594 return 0;
595}
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617static int handle_group_alt(struct objtool_file *file,
618 struct special_alt *special_alt,
619 struct instruction *orig_insn,
620 struct instruction **new_insn)
621{
622 struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump = NULL;
623 unsigned long dest_off;
624
625 last_orig_insn = NULL;
626 insn = orig_insn;
627 sec_for_each_insn_from(file, insn) {
628 if (insn->offset >= special_alt->orig_off + special_alt->orig_len)
629 break;
630
631 if (special_alt->skip_orig)
632 insn->type = INSN_NOP;
633
634 insn->alt_group = true;
635 last_orig_insn = insn;
636 }
637
638 if (next_insn_same_sec(file, last_orig_insn)) {
639 fake_jump = malloc(sizeof(*fake_jump));
640 if (!fake_jump) {
641 WARN("malloc failed");
642 return -1;
643 }
644 memset(fake_jump, 0, sizeof(*fake_jump));
645 INIT_LIST_HEAD(&fake_jump->alts);
646 clear_insn_state(&fake_jump->state);
647
648 fake_jump->sec = special_alt->new_sec;
649 fake_jump->offset = -1;
650 fake_jump->type = INSN_JUMP_UNCONDITIONAL;
651 fake_jump->jump_dest = list_next_entry(last_orig_insn, list);
652 fake_jump->ignore = true;
653 }
654
655 if (!special_alt->new_len) {
656 if (!fake_jump) {
657 WARN("%s: empty alternative at end of section",
658 special_alt->orig_sec->name);
659 return -1;
660 }
661
662 *new_insn = fake_jump;
663 return 0;
664 }
665
666 last_new_insn = NULL;
667 insn = *new_insn;
668 sec_for_each_insn_from(file, insn) {
669 if (insn->offset >= special_alt->new_off + special_alt->new_len)
670 break;
671
672 last_new_insn = insn;
673
674 insn->ignore = orig_insn->ignore_alts;
675
676 if (insn->type != INSN_JUMP_CONDITIONAL &&
677 insn->type != INSN_JUMP_UNCONDITIONAL)
678 continue;
679
680 if (!insn->immediate)
681 continue;
682
683 dest_off = insn->offset + insn->len + insn->immediate;
684 if (dest_off == special_alt->new_off + special_alt->new_len) {
685 if (!fake_jump) {
686 WARN("%s: alternative jump to end of section",
687 special_alt->orig_sec->name);
688 return -1;
689 }
690 insn->jump_dest = fake_jump;
691 }
692
693 if (!insn->jump_dest) {
694 WARN_FUNC("can't find alternative jump destination",
695 insn->sec, insn->offset);
696 return -1;
697 }
698 }
699
700 if (!last_new_insn) {
701 WARN_FUNC("can't find last new alternative instruction",
702 special_alt->new_sec, special_alt->new_off);
703 return -1;
704 }
705
706 if (fake_jump)
707 list_add(&fake_jump->list, &last_new_insn->list);
708
709 return 0;
710}
711
712
713
714
715
716
717static int handle_jump_alt(struct objtool_file *file,
718 struct special_alt *special_alt,
719 struct instruction *orig_insn,
720 struct instruction **new_insn)
721{
722 if (orig_insn->type == INSN_NOP)
723 return 0;
724
725 if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) {
726 WARN_FUNC("unsupported instruction at jump label",
727 orig_insn->sec, orig_insn->offset);
728 return -1;
729 }
730
731 *new_insn = list_next_entry(orig_insn, list);
732 return 0;
733}
734
735
736
737
738
739
740
741static int add_special_section_alts(struct objtool_file *file)
742{
743 struct list_head special_alts;
744 struct instruction *orig_insn, *new_insn;
745 struct special_alt *special_alt, *tmp;
746 struct alternative *alt;
747 int ret;
748
749 ret = special_get_alts(file->elf, &special_alts);
750 if (ret)
751 return ret;
752
753 list_for_each_entry_safe(special_alt, tmp, &special_alts, list) {
754
755 orig_insn = find_insn(file, special_alt->orig_sec,
756 special_alt->orig_off);
757 if (!orig_insn) {
758 WARN_FUNC("special: can't find orig instruction",
759 special_alt->orig_sec, special_alt->orig_off);
760 ret = -1;
761 goto out;
762 }
763
764 new_insn = NULL;
765 if (!special_alt->group || special_alt->new_len) {
766 new_insn = find_insn(file, special_alt->new_sec,
767 special_alt->new_off);
768 if (!new_insn) {
769 WARN_FUNC("special: can't find new instruction",
770 special_alt->new_sec,
771 special_alt->new_off);
772 ret = -1;
773 goto out;
774 }
775 }
776
777 if (special_alt->group) {
778 ret = handle_group_alt(file, special_alt, orig_insn,
779 &new_insn);
780 if (ret)
781 goto out;
782 } else if (special_alt->jump_or_nop) {
783 ret = handle_jump_alt(file, special_alt, orig_insn,
784 &new_insn);
785 if (ret)
786 goto out;
787 }
788
789 alt = malloc(sizeof(*alt));
790 if (!alt) {
791 WARN("malloc failed");
792 ret = -1;
793 goto out;
794 }
795
796 alt->insn = new_insn;
797 list_add_tail(&alt->list, &orig_insn->alts);
798
799 list_del(&special_alt->list);
800 free(special_alt);
801 }
802
803out:
804 return ret;
805}
806
807static int add_switch_table(struct objtool_file *file, struct instruction *insn,
808 struct rela *table, struct rela *next_table)
809{
810 struct rela *rela = table;
811 struct instruction *alt_insn;
812 struct alternative *alt;
813 struct symbol *pfunc = insn->func->pfunc;
814 unsigned int prev_offset = 0;
815
816 list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) {
817 if (rela == next_table)
818 break;
819
820
821 if (prev_offset && rela->offset != prev_offset + 8)
822 break;
823
824
825 if (rela->sym->sec == pfunc->sec &&
826 rela->addend == pfunc->offset)
827 break;
828
829 alt_insn = find_insn(file, rela->sym->sec, rela->addend);
830 if (!alt_insn)
831 break;
832
833
834 if (alt_insn->func->pfunc != pfunc)
835 break;
836
837 alt = malloc(sizeof(*alt));
838 if (!alt) {
839 WARN("malloc failed");
840 return -1;
841 }
842
843 alt->insn = alt_insn;
844 list_add_tail(&alt->list, &insn->alts);
845 prev_offset = rela->offset;
846 }
847
848 if (!prev_offset) {
849 WARN_FUNC("can't find switch jump table",
850 insn->sec, insn->offset);
851 return -1;
852 }
853
854 return 0;
855}
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900static struct rela *find_switch_table(struct objtool_file *file,
901 struct symbol *func,
902 struct instruction *insn)
903{
904 struct rela *text_rela, *rodata_rela;
905 struct instruction *orig_insn = insn;
906 unsigned long table_offset;
907
908
909
910
911
912
913 for (;
914 &insn->list != &file->insn_list &&
915 insn->sec == func->sec &&
916 insn->offset >= func->offset;
917
918 insn = insn->first_jump_src ?: list_prev_entry(insn, list)) {
919
920 if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC)
921 break;
922
923
924 if (insn->type == INSN_JUMP_UNCONDITIONAL &&
925 insn->jump_dest &&
926 (insn->jump_dest->offset <= insn->offset ||
927 insn->jump_dest->offset > orig_insn->offset))
928 break;
929
930
931 text_rela = find_rela_by_dest_range(insn->sec, insn->offset,
932 insn->len);
933 if (!text_rela || text_rela->sym != file->rodata->sym)
934 continue;
935
936 table_offset = text_rela->addend;
937 if (text_rela->type == R_X86_64_PC32)
938 table_offset += 4;
939
940
941
942
943
944 if (find_symbol_containing(file->rodata, table_offset))
945 continue;
946
947 rodata_rela = find_rela_by_dest(file->rodata, table_offset);
948 if (rodata_rela) {
949
950
951
952
953
954 if (text_rela->type == R_X86_64_PC32)
955 file->ignore_unreachables = true;
956
957 return rodata_rela;
958 }
959 }
960
961 return NULL;
962}
963
964
965static int add_func_switch_tables(struct objtool_file *file,
966 struct symbol *func)
967{
968 struct instruction *insn, *last = NULL, *prev_jump = NULL;
969 struct rela *rela, *prev_rela = NULL;
970 int ret;
971
972 func_for_each_insn_all(file, func, insn) {
973 if (!last)
974 last = insn;
975
976
977
978
979
980
981 if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
982 insn->offset > last->offset &&
983 insn->jump_dest->offset > insn->offset &&
984 !insn->jump_dest->first_jump_src) {
985
986 insn->jump_dest->first_jump_src = insn;
987 last = insn->jump_dest;
988 }
989
990 if (insn->type != INSN_JUMP_DYNAMIC)
991 continue;
992
993 rela = find_switch_table(file, func, insn);
994 if (!rela)
995 continue;
996
997
998
999
1000
1001
1002 if (prev_jump) {
1003 ret = add_switch_table(file, prev_jump, prev_rela, rela);
1004 if (ret)
1005 return ret;
1006 }
1007
1008 prev_jump = insn;
1009 prev_rela = rela;
1010 }
1011
1012 if (prev_jump) {
1013 ret = add_switch_table(file, prev_jump, prev_rela, NULL);
1014 if (ret)
1015 return ret;
1016 }
1017
1018 return 0;
1019}
1020
1021
1022
1023
1024
1025
1026static int add_switch_table_alts(struct objtool_file *file)
1027{
1028 struct section *sec;
1029 struct symbol *func;
1030 int ret;
1031
1032 if (!file->rodata || !file->rodata->rela)
1033 return 0;
1034
1035 for_each_sec(file, sec) {
1036 list_for_each_entry(func, &sec->symbol_list, list) {
1037 if (func->type != STT_FUNC)
1038 continue;
1039
1040 ret = add_func_switch_tables(file, func);
1041 if (ret)
1042 return ret;
1043 }
1044 }
1045
1046 return 0;
1047}
1048
1049static int read_unwind_hints(struct objtool_file *file)
1050{
1051 struct section *sec, *relasec;
1052 struct rela *rela;
1053 struct unwind_hint *hint;
1054 struct instruction *insn;
1055 struct cfi_reg *cfa;
1056 int i;
1057
1058 sec = find_section_by_name(file->elf, ".discard.unwind_hints");
1059 if (!sec)
1060 return 0;
1061
1062 relasec = sec->rela;
1063 if (!relasec) {
1064 WARN("missing .rela.discard.unwind_hints section");
1065 return -1;
1066 }
1067
1068 if (sec->len % sizeof(struct unwind_hint)) {
1069 WARN("struct unwind_hint size mismatch");
1070 return -1;
1071 }
1072
1073 file->hints = true;
1074
1075 for (i = 0; i < sec->len / sizeof(struct unwind_hint); i++) {
1076 hint = (struct unwind_hint *)sec->data->d_buf + i;
1077
1078 rela = find_rela_by_dest(sec, i * sizeof(*hint));
1079 if (!rela) {
1080 WARN("can't find rela for unwind_hints[%d]", i);
1081 return -1;
1082 }
1083
1084 insn = find_insn(file, rela->sym->sec, rela->addend);
1085 if (!insn) {
1086 WARN("can't find insn for unwind_hints[%d]", i);
1087 return -1;
1088 }
1089
1090 cfa = &insn->state.cfa;
1091
1092 if (hint->type == UNWIND_HINT_TYPE_SAVE) {
1093 insn->save = true;
1094 continue;
1095
1096 } else if (hint->type == UNWIND_HINT_TYPE_RESTORE) {
1097 insn->restore = true;
1098 insn->hint = true;
1099 continue;
1100 }
1101
1102 insn->hint = true;
1103
1104 switch (hint->sp_reg) {
1105 case ORC_REG_UNDEFINED:
1106 cfa->base = CFI_UNDEFINED;
1107 break;
1108 case ORC_REG_SP:
1109 cfa->base = CFI_SP;
1110 break;
1111 case ORC_REG_BP:
1112 cfa->base = CFI_BP;
1113 break;
1114 case ORC_REG_SP_INDIRECT:
1115 cfa->base = CFI_SP_INDIRECT;
1116 break;
1117 case ORC_REG_R10:
1118 cfa->base = CFI_R10;
1119 break;
1120 case ORC_REG_R13:
1121 cfa->base = CFI_R13;
1122 break;
1123 case ORC_REG_DI:
1124 cfa->base = CFI_DI;
1125 break;
1126 case ORC_REG_DX:
1127 cfa->base = CFI_DX;
1128 break;
1129 default:
1130 WARN_FUNC("unsupported unwind_hint sp base reg %d",
1131 insn->sec, insn->offset, hint->sp_reg);
1132 return -1;
1133 }
1134
1135 cfa->offset = hint->sp_offset;
1136 insn->state.type = hint->type;
1137 }
1138
1139 return 0;
1140}
1141
1142static int read_retpoline_hints(struct objtool_file *file)
1143{
1144 struct section *sec;
1145 struct instruction *insn;
1146 struct rela *rela;
1147
1148 sec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe");
1149 if (!sec)
1150 return 0;
1151
1152 list_for_each_entry(rela, &sec->rela_list, list) {
1153 if (rela->sym->type != STT_SECTION) {
1154 WARN("unexpected relocation symbol type in %s", sec->name);
1155 return -1;
1156 }
1157
1158 insn = find_insn(file, rela->sym->sec, rela->addend);
1159 if (!insn) {
1160 WARN("bad .discard.retpoline_safe entry");
1161 return -1;
1162 }
1163
1164 if (insn->type != INSN_JUMP_DYNAMIC &&
1165 insn->type != INSN_CALL_DYNAMIC) {
1166 WARN_FUNC("retpoline_safe hint not an indirect jump/call",
1167 insn->sec, insn->offset);
1168 return -1;
1169 }
1170
1171 insn->retpoline_safe = true;
1172 }
1173
1174 return 0;
1175}
1176
1177static int decode_sections(struct objtool_file *file)
1178{
1179 int ret;
1180
1181 ret = decode_instructions(file);
1182 if (ret)
1183 return ret;
1184
1185 ret = add_dead_ends(file);
1186 if (ret)
1187 return ret;
1188
1189 add_ignores(file);
1190
1191 ret = add_nospec_ignores(file);
1192 if (ret)
1193 return ret;
1194
1195 ret = add_jump_destinations(file);
1196 if (ret)
1197 return ret;
1198
1199 ret = add_special_section_alts(file);
1200 if (ret)
1201 return ret;
1202
1203 ret = add_call_destinations(file);
1204 if (ret)
1205 return ret;
1206
1207 ret = add_switch_table_alts(file);
1208 if (ret)
1209 return ret;
1210
1211 ret = read_unwind_hints(file);
1212 if (ret)
1213 return ret;
1214
1215 ret = read_retpoline_hints(file);
1216 if (ret)
1217 return ret;
1218
1219 return 0;
1220}
1221
1222static bool is_fentry_call(struct instruction *insn)
1223{
1224 if (insn->type == INSN_CALL &&
1225 insn->call_dest->type == STT_NOTYPE &&
1226 !strcmp(insn->call_dest->name, "__fentry__"))
1227 return true;
1228
1229 return false;
1230}
1231
1232static bool has_modified_stack_frame(struct insn_state *state)
1233{
1234 int i;
1235
1236 if (state->cfa.base != initial_func_cfi.cfa.base ||
1237 state->cfa.offset != initial_func_cfi.cfa.offset ||
1238 state->stack_size != initial_func_cfi.cfa.offset ||
1239 state->drap)
1240 return true;
1241
1242 for (i = 0; i < CFI_NUM_REGS; i++)
1243 if (state->regs[i].base != initial_func_cfi.regs[i].base ||
1244 state->regs[i].offset != initial_func_cfi.regs[i].offset)
1245 return true;
1246
1247 return false;
1248}
1249
1250static bool has_valid_stack_frame(struct insn_state *state)
1251{
1252 if (state->cfa.base == CFI_BP && state->regs[CFI_BP].base == CFI_CFA &&
1253 state->regs[CFI_BP].offset == -16)
1254 return true;
1255
1256 if (state->drap && state->regs[CFI_BP].base == CFI_BP)
1257 return true;
1258
1259 return false;
1260}
1261
1262static int update_insn_state_regs(struct instruction *insn, struct insn_state *state)
1263{
1264 struct cfi_reg *cfa = &state->cfa;
1265 struct stack_op *op = &insn->stack_op;
1266
1267 if (cfa->base != CFI_SP)
1268 return 0;
1269
1270
1271 if (op->dest.type == OP_DEST_PUSH)
1272 cfa->offset += 8;
1273
1274
1275 if (op->src.type == OP_SRC_POP)
1276 cfa->offset -= 8;
1277
1278
1279 if (op->dest.type == OP_DEST_REG && op->src.type == OP_SRC_ADD &&
1280 op->dest.reg == CFI_SP && op->src.reg == CFI_SP)
1281 cfa->offset -= op->src.offset;
1282
1283 return 0;
1284}
1285
1286static void save_reg(struct insn_state *state, unsigned char reg, int base,
1287 int offset)
1288{
1289 if (arch_callee_saved_reg(reg) &&
1290 state->regs[reg].base == CFI_UNDEFINED) {
1291 state->regs[reg].base = base;
1292 state->regs[reg].offset = offset;
1293 }
1294}
1295
1296static void restore_reg(struct insn_state *state, unsigned char reg)
1297{
1298 state->regs[reg].base = CFI_UNDEFINED;
1299 state->regs[reg].offset = 0;
1300}
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355static int update_insn_state(struct instruction *insn, struct insn_state *state)
1356{
1357 struct stack_op *op = &insn->stack_op;
1358 struct cfi_reg *cfa = &state->cfa;
1359 struct cfi_reg *regs = state->regs;
1360
1361
1362 if (cfa->base == CFI_UNDEFINED) {
1363 if (insn->func) {
1364 WARN_FUNC("undefined stack state", insn->sec, insn->offset);
1365 return -1;
1366 }
1367 return 0;
1368 }
1369
1370 if (state->type == ORC_TYPE_REGS || state->type == ORC_TYPE_REGS_IRET)
1371 return update_insn_state_regs(insn, state);
1372
1373 switch (op->dest.type) {
1374
1375 case OP_DEST_REG:
1376 switch (op->src.type) {
1377
1378 case OP_SRC_REG:
1379 if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP &&
1380 cfa->base == CFI_SP &&
1381 regs[CFI_BP].base == CFI_CFA &&
1382 regs[CFI_BP].offset == -cfa->offset) {
1383
1384
1385 cfa->base = op->dest.reg;
1386 state->bp_scratch = false;
1387 }
1388
1389 else if (op->src.reg == CFI_SP &&
1390 op->dest.reg == CFI_BP && state->drap) {
1391
1392
1393 regs[CFI_BP].base = CFI_BP;
1394 regs[CFI_BP].offset = -state->stack_size;
1395 state->bp_scratch = false;
1396 }
1397
1398 else if (op->src.reg == CFI_SP && cfa->base == CFI_SP) {
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410 state->vals[op->dest.reg].base = CFI_CFA;
1411 state->vals[op->dest.reg].offset = -state->stack_size;
1412 }
1413
1414 else if (op->src.reg == CFI_BP && op->dest.reg == CFI_SP &&
1415 cfa->base == CFI_BP) {
1416
1417
1418
1419
1420
1421
1422 state->stack_size = -state->regs[CFI_BP].offset;
1423 }
1424
1425 else if (op->dest.reg == cfa->base) {
1426
1427
1428 if (cfa->base == CFI_SP &&
1429 state->vals[op->src.reg].base == CFI_CFA) {
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439 cfa->offset = -state->vals[op->src.reg].offset;
1440 state->stack_size = cfa->offset;
1441
1442 } else {
1443 cfa->base = CFI_UNDEFINED;
1444 cfa->offset = 0;
1445 }
1446 }
1447
1448 break;
1449
1450 case OP_SRC_ADD:
1451 if (op->dest.reg == CFI_SP && op->src.reg == CFI_SP) {
1452
1453
1454 state->stack_size -= op->src.offset;
1455 if (cfa->base == CFI_SP)
1456 cfa->offset -= op->src.offset;
1457 break;
1458 }
1459
1460 if (op->dest.reg == CFI_SP && op->src.reg == CFI_BP) {
1461
1462
1463 state->stack_size = -(op->src.offset + regs[CFI_BP].offset);
1464 break;
1465 }
1466
1467 if (op->src.reg == CFI_SP && cfa->base == CFI_SP) {
1468
1469
1470 state->drap_reg = op->dest.reg;
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482 state->vals[op->dest.reg].base = CFI_CFA;
1483 state->vals[op->dest.reg].offset = \
1484 -state->stack_size + op->src.offset;
1485
1486 break;
1487 }
1488
1489 if (state->drap && op->dest.reg == CFI_SP &&
1490 op->src.reg == state->drap_reg) {
1491
1492
1493 cfa->base = CFI_SP;
1494 cfa->offset = state->stack_size = -op->src.offset;
1495 state->drap_reg = CFI_UNDEFINED;
1496 state->drap = false;
1497 break;
1498 }
1499
1500 if (op->dest.reg == state->cfa.base) {
1501 WARN_FUNC("unsupported stack register modification",
1502 insn->sec, insn->offset);
1503 return -1;
1504 }
1505
1506 break;
1507
1508 case OP_SRC_AND:
1509 if (op->dest.reg != CFI_SP ||
1510 (state->drap_reg != CFI_UNDEFINED && cfa->base != CFI_SP) ||
1511 (state->drap_reg == CFI_UNDEFINED && cfa->base != CFI_BP)) {
1512 WARN_FUNC("unsupported stack pointer realignment",
1513 insn->sec, insn->offset);
1514 return -1;
1515 }
1516
1517 if (state->drap_reg != CFI_UNDEFINED) {
1518
1519 cfa->base = state->drap_reg;
1520 cfa->offset = state->stack_size = 0;
1521 state->drap = true;
1522 }
1523
1524
1525
1526
1527
1528
1529 break;
1530
1531 case OP_SRC_POP:
1532 if (!state->drap && op->dest.type == OP_DEST_REG &&
1533 op->dest.reg == cfa->base) {
1534
1535
1536 cfa->base = CFI_SP;
1537 }
1538
1539 if (state->drap && cfa->base == CFI_BP_INDIRECT &&
1540 op->dest.type == OP_DEST_REG &&
1541 op->dest.reg == state->drap_reg &&
1542 state->drap_offset == -state->stack_size) {
1543
1544
1545 cfa->base = state->drap_reg;
1546 cfa->offset = 0;
1547 state->drap_offset = -1;
1548
1549 } else if (regs[op->dest.reg].offset == -state->stack_size) {
1550
1551
1552 restore_reg(state, op->dest.reg);
1553 }
1554
1555 state->stack_size -= 8;
1556 if (cfa->base == CFI_SP)
1557 cfa->offset -= 8;
1558
1559 break;
1560
1561 case OP_SRC_REG_INDIRECT:
1562 if (state->drap && op->src.reg == CFI_BP &&
1563 op->src.offset == state->drap_offset) {
1564
1565
1566 cfa->base = state->drap_reg;
1567 cfa->offset = 0;
1568 state->drap_offset = -1;
1569 }
1570
1571 if (state->drap && op->src.reg == CFI_BP &&
1572 op->src.offset == regs[op->dest.reg].offset) {
1573
1574
1575 restore_reg(state, op->dest.reg);
1576
1577 } else if (op->src.reg == cfa->base &&
1578 op->src.offset == regs[op->dest.reg].offset + cfa->offset) {
1579
1580
1581
1582 restore_reg(state, op->dest.reg);
1583 }
1584
1585 break;
1586
1587 default:
1588 WARN_FUNC("unknown stack-related instruction",
1589 insn->sec, insn->offset);
1590 return -1;
1591 }
1592
1593 break;
1594
1595 case OP_DEST_PUSH:
1596 state->stack_size += 8;
1597 if (cfa->base == CFI_SP)
1598 cfa->offset += 8;
1599
1600 if (op->src.type != OP_SRC_REG)
1601 break;
1602
1603 if (state->drap) {
1604 if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) {
1605
1606
1607 cfa->base = CFI_BP_INDIRECT;
1608 cfa->offset = -state->stack_size;
1609
1610
1611 state->drap_offset = -state->stack_size;
1612
1613 } else if (op->src.reg == CFI_BP && cfa->base == state->drap_reg) {
1614
1615
1616 state->stack_size = 0;
1617
1618 } else if (regs[op->src.reg].base == CFI_UNDEFINED) {
1619
1620
1621 save_reg(state, op->src.reg, CFI_BP, -state->stack_size);
1622 }
1623
1624 } else {
1625
1626
1627 save_reg(state, op->src.reg, CFI_CFA, -state->stack_size);
1628 }
1629
1630
1631 if (!no_fp && insn->func && op->src.reg == CFI_BP &&
1632 cfa->base != CFI_BP)
1633 state->bp_scratch = true;
1634 break;
1635
1636 case OP_DEST_REG_INDIRECT:
1637
1638 if (state->drap) {
1639 if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) {
1640
1641
1642 cfa->base = CFI_BP_INDIRECT;
1643 cfa->offset = op->dest.offset;
1644
1645
1646 state->drap_offset = op->dest.offset;
1647 }
1648
1649 else if (regs[op->src.reg].base == CFI_UNDEFINED) {
1650
1651
1652 save_reg(state, op->src.reg, CFI_BP, op->dest.offset);
1653 }
1654
1655 } else if (op->dest.reg == cfa->base) {
1656
1657
1658
1659 save_reg(state, op->src.reg, CFI_CFA,
1660 op->dest.offset - state->cfa.offset);
1661 }
1662
1663 break;
1664
1665 case OP_DEST_LEAVE:
1666 if ((!state->drap && cfa->base != CFI_BP) ||
1667 (state->drap && cfa->base != state->drap_reg)) {
1668 WARN_FUNC("leave instruction with modified stack frame",
1669 insn->sec, insn->offset);
1670 return -1;
1671 }
1672
1673
1674
1675 state->stack_size = -state->regs[CFI_BP].offset - 8;
1676 restore_reg(state, CFI_BP);
1677
1678 if (!state->drap) {
1679 cfa->base = CFI_SP;
1680 cfa->offset -= 8;
1681 }
1682
1683 break;
1684
1685 case OP_DEST_MEM:
1686 if (op->src.type != OP_SRC_POP) {
1687 WARN_FUNC("unknown stack-related memory operation",
1688 insn->sec, insn->offset);
1689 return -1;
1690 }
1691
1692
1693 state->stack_size -= 8;
1694 if (cfa->base == CFI_SP)
1695 cfa->offset -= 8;
1696
1697 break;
1698
1699 default:
1700 WARN_FUNC("unknown stack-related instruction",
1701 insn->sec, insn->offset);
1702 return -1;
1703 }
1704
1705 return 0;
1706}
1707
1708static bool insn_state_match(struct instruction *insn, struct insn_state *state)
1709{
1710 struct insn_state *state1 = &insn->state, *state2 = state;
1711 int i;
1712
1713 if (memcmp(&state1->cfa, &state2->cfa, sizeof(state1->cfa))) {
1714 WARN_FUNC("stack state mismatch: cfa1=%d%+d cfa2=%d%+d",
1715 insn->sec, insn->offset,
1716 state1->cfa.base, state1->cfa.offset,
1717 state2->cfa.base, state2->cfa.offset);
1718
1719 } else if (memcmp(&state1->regs, &state2->regs, sizeof(state1->regs))) {
1720 for (i = 0; i < CFI_NUM_REGS; i++) {
1721 if (!memcmp(&state1->regs[i], &state2->regs[i],
1722 sizeof(struct cfi_reg)))
1723 continue;
1724
1725 WARN_FUNC("stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d",
1726 insn->sec, insn->offset,
1727 i, state1->regs[i].base, state1->regs[i].offset,
1728 i, state2->regs[i].base, state2->regs[i].offset);
1729 break;
1730 }
1731
1732 } else if (state1->type != state2->type) {
1733 WARN_FUNC("stack state mismatch: type1=%d type2=%d",
1734 insn->sec, insn->offset, state1->type, state2->type);
1735
1736 } else if (state1->drap != state2->drap ||
1737 (state1->drap && state1->drap_reg != state2->drap_reg) ||
1738 (state1->drap && state1->drap_offset != state2->drap_offset)) {
1739 WARN_FUNC("stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)",
1740 insn->sec, insn->offset,
1741 state1->drap, state1->drap_reg, state1->drap_offset,
1742 state2->drap, state2->drap_reg, state2->drap_offset);
1743
1744 } else
1745 return true;
1746
1747 return false;
1748}
1749
1750
1751
1752
1753
1754
1755
1756static int validate_branch(struct objtool_file *file, struct instruction *first,
1757 struct insn_state state)
1758{
1759 struct alternative *alt;
1760 struct instruction *insn, *next_insn;
1761 struct section *sec;
1762 struct symbol *func = NULL;
1763 int ret;
1764
1765 insn = first;
1766 sec = insn->sec;
1767
1768 if (insn->alt_group && list_empty(&insn->alts)) {
1769 WARN_FUNC("don't know how to handle branch to middle of alternative instruction group",
1770 sec, insn->offset);
1771 return 1;
1772 }
1773
1774 while (1) {
1775 next_insn = next_insn_same_sec(file, insn);
1776
1777 if (file->c_file && func && insn->func && func != insn->func->pfunc) {
1778 WARN("%s() falls through to next function %s()",
1779 func->name, insn->func->name);
1780 return 1;
1781 }
1782
1783 func = insn->func ? insn->func->pfunc : NULL;
1784
1785 if (func && insn->ignore) {
1786 WARN_FUNC("BUG: why am I validating an ignored function?",
1787 sec, insn->offset);
1788 return 1;
1789 }
1790
1791 if (insn->visited) {
1792 if (!insn->hint && !insn_state_match(insn, &state))
1793 return 1;
1794
1795 return 0;
1796 }
1797
1798 if (insn->hint) {
1799 if (insn->restore) {
1800 struct instruction *save_insn, *i;
1801
1802 i = insn;
1803 save_insn = NULL;
1804 func_for_each_insn_continue_reverse(file, insn->func, i) {
1805 if (i->save) {
1806 save_insn = i;
1807 break;
1808 }
1809 }
1810
1811 if (!save_insn) {
1812 WARN_FUNC("no corresponding CFI save for CFI restore",
1813 sec, insn->offset);
1814 return 1;
1815 }
1816
1817 if (!save_insn->visited) {
1818
1819
1820
1821
1822
1823
1824
1825 if (insn == first)
1826 return 0;
1827
1828 WARN_FUNC("objtool isn't smart enough to handle this CFI save/restore combo",
1829 sec, insn->offset);
1830 return 1;
1831 }
1832
1833 insn->state = save_insn->state;
1834 }
1835
1836 state = insn->state;
1837
1838 } else
1839 insn->state = state;
1840
1841 insn->visited = true;
1842
1843 if (!insn->ignore_alts) {
1844 list_for_each_entry(alt, &insn->alts, list) {
1845 ret = validate_branch(file, alt->insn, state);
1846 if (ret)
1847 return 1;
1848 }
1849 }
1850
1851 switch (insn->type) {
1852
1853 case INSN_RETURN:
1854 if (func && has_modified_stack_frame(&state)) {
1855 WARN_FUNC("return with modified stack frame",
1856 sec, insn->offset);
1857 return 1;
1858 }
1859
1860 if (state.bp_scratch) {
1861 WARN("%s uses BP as a scratch register",
1862 insn->func->name);
1863 return 1;
1864 }
1865
1866 return 0;
1867
1868 case INSN_CALL:
1869 if (is_fentry_call(insn))
1870 break;
1871
1872 ret = dead_end_function(file, insn->call_dest);
1873 if (ret == 1)
1874 return 0;
1875 if (ret == -1)
1876 return 1;
1877
1878
1879 case INSN_CALL_DYNAMIC:
1880 if (!no_fp && func && !has_valid_stack_frame(&state)) {
1881 WARN_FUNC("call without frame pointer save/setup",
1882 sec, insn->offset);
1883 return 1;
1884 }
1885 break;
1886
1887 case INSN_JUMP_CONDITIONAL:
1888 case INSN_JUMP_UNCONDITIONAL:
1889 if (insn->jump_dest &&
1890 (!func || !insn->jump_dest->func ||
1891 insn->jump_dest->func->pfunc == func)) {
1892 ret = validate_branch(file, insn->jump_dest,
1893 state);
1894 if (ret)
1895 return 1;
1896
1897 } else if (func && has_modified_stack_frame(&state)) {
1898 WARN_FUNC("sibling call from callable instruction with modified stack frame",
1899 sec, insn->offset);
1900 return 1;
1901 }
1902
1903 if (insn->type == INSN_JUMP_UNCONDITIONAL)
1904 return 0;
1905
1906 break;
1907
1908 case INSN_JUMP_DYNAMIC:
1909 if (func && list_empty(&insn->alts) &&
1910 has_modified_stack_frame(&state)) {
1911 WARN_FUNC("sibling call from callable instruction with modified stack frame",
1912 sec, insn->offset);
1913 return 1;
1914 }
1915
1916 return 0;
1917
1918 case INSN_CONTEXT_SWITCH:
1919 if (func && (!next_insn || !next_insn->hint)) {
1920 WARN_FUNC("unsupported instruction in callable function",
1921 sec, insn->offset);
1922 return 1;
1923 }
1924 return 0;
1925
1926 case INSN_STACK:
1927 if (update_insn_state(insn, &state))
1928 return 1;
1929
1930 break;
1931
1932 default:
1933 break;
1934 }
1935
1936 if (insn->dead_end)
1937 return 0;
1938
1939 if (!next_insn) {
1940 if (state.cfa.base == CFI_UNDEFINED)
1941 return 0;
1942 WARN("%s: unexpected end of section", sec->name);
1943 return 1;
1944 }
1945
1946 insn = next_insn;
1947 }
1948
1949 return 0;
1950}
1951
1952static int validate_unwind_hints(struct objtool_file *file)
1953{
1954 struct instruction *insn;
1955 int ret, warnings = 0;
1956 struct insn_state state;
1957
1958 if (!file->hints)
1959 return 0;
1960
1961 clear_insn_state(&state);
1962
1963 for_each_insn(file, insn) {
1964 if (insn->hint && !insn->visited) {
1965 ret = validate_branch(file, insn, state);
1966 warnings += ret;
1967 }
1968 }
1969
1970 return warnings;
1971}
1972
1973static int validate_retpoline(struct objtool_file *file)
1974{
1975 struct instruction *insn;
1976 int warnings = 0;
1977
1978 for_each_insn(file, insn) {
1979 if (insn->type != INSN_JUMP_DYNAMIC &&
1980 insn->type != INSN_CALL_DYNAMIC)
1981 continue;
1982
1983 if (insn->retpoline_safe)
1984 continue;
1985
1986
1987
1988
1989
1990
1991
1992 if (!strcmp(insn->sec->name, ".init.text") && !module)
1993 continue;
1994
1995 WARN_FUNC("indirect %s found in RETPOLINE build",
1996 insn->sec, insn->offset,
1997 insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call");
1998
1999 warnings++;
2000 }
2001
2002 return warnings;
2003}
2004
2005static bool is_kasan_insn(struct instruction *insn)
2006{
2007 return (insn->type == INSN_CALL &&
2008 !strcmp(insn->call_dest->name, "__asan_handle_no_return"));
2009}
2010
2011static bool is_ubsan_insn(struct instruction *insn)
2012{
2013 return (insn->type == INSN_CALL &&
2014 !strcmp(insn->call_dest->name,
2015 "__ubsan_handle_builtin_unreachable"));
2016}
2017
2018static bool ignore_unreachable_insn(struct instruction *insn)
2019{
2020 int i;
2021
2022 if (insn->ignore || insn->type == INSN_NOP)
2023 return true;
2024
2025
2026
2027
2028
2029
2030
2031
2032 if (!strcmp(insn->sec->name, ".fixup") ||
2033 !strcmp(insn->sec->name, ".altinstr_replacement") ||
2034 !strcmp(insn->sec->name, ".altinstr_aux"))
2035 return true;
2036
2037
2038
2039
2040
2041
2042
2043 if (!insn->func)
2044 return false;
2045 for (i = 0; i < 5; i++) {
2046
2047 if (is_kasan_insn(insn) || is_ubsan_insn(insn))
2048 return true;
2049
2050 if (insn->type == INSN_JUMP_UNCONDITIONAL) {
2051 if (insn->jump_dest &&
2052 insn->jump_dest->func == insn->func) {
2053 insn = insn->jump_dest;
2054 continue;
2055 }
2056
2057 break;
2058 }
2059
2060 if (insn->offset + insn->len >= insn->func->offset + insn->func->len)
2061 break;
2062
2063 insn = list_next_entry(insn, list);
2064 }
2065
2066 return false;
2067}
2068
2069static int validate_functions(struct objtool_file *file)
2070{
2071 struct section *sec;
2072 struct symbol *func;
2073 struct instruction *insn;
2074 struct insn_state state;
2075 int ret, warnings = 0;
2076
2077 clear_insn_state(&state);
2078
2079 state.cfa = initial_func_cfi.cfa;
2080 memcpy(&state.regs, &initial_func_cfi.regs,
2081 CFI_NUM_REGS * sizeof(struct cfi_reg));
2082 state.stack_size = initial_func_cfi.cfa.offset;
2083
2084 for_each_sec(file, sec) {
2085 list_for_each_entry(func, &sec->symbol_list, list) {
2086 if (func->type != STT_FUNC || func->pfunc != func)
2087 continue;
2088
2089 insn = find_insn(file, sec, func->offset);
2090 if (!insn || insn->ignore)
2091 continue;
2092
2093 ret = validate_branch(file, insn, state);
2094 warnings += ret;
2095 }
2096 }
2097
2098 return warnings;
2099}
2100
2101static int validate_reachable_instructions(struct objtool_file *file)
2102{
2103 struct instruction *insn;
2104
2105 if (file->ignore_unreachables)
2106 return 0;
2107
2108 for_each_insn(file, insn) {
2109 if (insn->visited || ignore_unreachable_insn(insn))
2110 continue;
2111
2112 WARN_FUNC("unreachable instruction", insn->sec, insn->offset);
2113 return 1;
2114 }
2115
2116 return 0;
2117}
2118
2119static void cleanup(struct objtool_file *file)
2120{
2121 struct instruction *insn, *tmpinsn;
2122 struct alternative *alt, *tmpalt;
2123
2124 list_for_each_entry_safe(insn, tmpinsn, &file->insn_list, list) {
2125 list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) {
2126 list_del(&alt->list);
2127 free(alt);
2128 }
2129 list_del(&insn->list);
2130 hash_del(&insn->hash);
2131 free(insn);
2132 }
2133 elf_close(file->elf);
2134}
2135
2136int check(const char *_objname, bool orc)
2137{
2138 struct objtool_file file;
2139 int ret, warnings = 0;
2140
2141 objname = _objname;
2142
2143 file.elf = elf_open(objname, orc ? O_RDWR : O_RDONLY);
2144 if (!file.elf)
2145 return 1;
2146
2147 INIT_LIST_HEAD(&file.insn_list);
2148 hash_init(file.insn_hash);
2149 file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard");
2150 file.rodata = find_section_by_name(file.elf, ".rodata");
2151 file.c_file = find_section_by_name(file.elf, ".comment");
2152 file.ignore_unreachables = no_unreachable;
2153 file.hints = false;
2154
2155 arch_initial_func_cfi_state(&initial_func_cfi);
2156
2157 ret = decode_sections(&file);
2158 if (ret < 0)
2159 goto out;
2160 warnings += ret;
2161
2162 if (list_empty(&file.insn_list))
2163 goto out;
2164
2165 if (retpoline) {
2166 ret = validate_retpoline(&file);
2167 if (ret < 0)
2168 return ret;
2169 warnings += ret;
2170 }
2171
2172 ret = validate_functions(&file);
2173 if (ret < 0)
2174 goto out;
2175 warnings += ret;
2176
2177 ret = validate_unwind_hints(&file);
2178 if (ret < 0)
2179 goto out;
2180 warnings += ret;
2181
2182 if (!warnings) {
2183 ret = validate_reachable_instructions(&file);
2184 if (ret < 0)
2185 goto out;
2186 warnings += ret;
2187 }
2188
2189 if (orc) {
2190 ret = create_orc(&file);
2191 if (ret < 0)
2192 goto out;
2193
2194 ret = create_orc_sections(&file);
2195 if (ret < 0)
2196 goto out;
2197
2198 ret = elf_write(file.elf);
2199 if (ret < 0)
2200 goto out;
2201 }
2202
2203out:
2204 cleanup(&file);
2205
2206
2207 if (ret || warnings)
2208 return 0;
2209 return 0;
2210}
2211