xref: /linux/tools/objtool/builtin-check.c (revision 442f04c34a1a467759d024a1d2c1df0f744dcb06)
1 /*
2  * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  * objtool check:
20  *
21  * This command analyzes every .o file and ensures the validity of its stack
22  * trace metadata.  It enforces a set of rules on asm code and C inline
23  * assembly code so that stack traces can be reliable.
24  *
25  * For more information, see tools/objtool/Documentation/stack-validation.txt.
26  */
27 
28 #include <string.h>
29 #include <subcmd/parse-options.h>
30 
31 #include "builtin.h"
32 #include "elf.h"
33 #include "special.h"
34 #include "arch.h"
35 #include "warn.h"
36 
37 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
38 
39 #define STATE_FP_SAVED		0x1
40 #define STATE_FP_SETUP		0x2
41 #define STATE_FENTRY		0x4
42 
43 struct instruction {
44 	struct list_head list;
45 	struct section *sec;
46 	unsigned long offset;
47 	unsigned int len, state;
48 	unsigned char type;
49 	unsigned long immediate;
50 	bool alt_group, visited;
51 	struct symbol *call_dest;
52 	struct instruction *jump_dest;
53 	struct list_head alts;
54 };
55 
56 struct alternative {
57 	struct list_head list;
58 	struct instruction *insn;
59 };
60 
61 struct objtool_file {
62 	struct elf *elf;
63 	struct list_head insns;
64 };
65 
66 const char *objname;
67 static bool nofp;
68 
69 static struct instruction *find_instruction(struct objtool_file *file,
70 					    struct section *sec,
71 					    unsigned long offset)
72 {
73 	struct instruction *insn;
74 
75 	list_for_each_entry(insn, &file->insns, list)
76 		if (insn->sec == sec && insn->offset == offset)
77 			return insn;
78 
79 	return NULL;
80 }
81 
82 /*
83  * Check if the function has been manually whitelisted with the
84  * STACK_FRAME_NON_STANDARD macro, or if it should be automatically whitelisted
85  * due to its use of a context switching instruction.
86  */
87 static bool ignore_func(struct objtool_file *file, struct symbol *func)
88 {
89 	struct section *macro_sec;
90 	struct rela *rela;
91 	struct instruction *insn;
92 
93 	/* check for STACK_FRAME_NON_STANDARD */
94 	macro_sec = find_section_by_name(file->elf, "__func_stack_frame_non_standard");
95 	if (macro_sec && macro_sec->rela)
96 		list_for_each_entry(rela, &macro_sec->rela->relas, list)
97 			if (rela->sym->sec == func->sec &&
98 			    rela->addend == func->offset)
99 				return true;
100 
101 	/* check if it has a context switching instruction */
102 	insn = find_instruction(file, func->sec, func->offset);
103 	if (!insn)
104 		return false;
105 	list_for_each_entry_from(insn, &file->insns, list) {
106 		if (insn->sec != func->sec ||
107 		    insn->offset >= func->offset + func->len)
108 			break;
109 		if (insn->type == INSN_CONTEXT_SWITCH)
110 			return true;
111 	}
112 
113 	return false;
114 }
115 
116 /*
117  * This checks to see if the given function is a "noreturn" function.
118  *
119  * For global functions which are outside the scope of this object file, we
120  * have to keep a manual list of them.
121  *
122  * For local functions, we have to detect them manually by simply looking for
123  * the lack of a return instruction.
124  */
125 static bool dead_end_function(struct objtool_file *file, struct symbol *func)
126 {
127 	int i;
128 	struct instruction *insn;
129 	bool empty = true;
130 
131 	/*
132 	 * Unfortunately these have to be hard coded because the noreturn
133 	 * attribute isn't provided in ELF data.
134 	 */
135 	static const char * const global_noreturns[] = {
136 		"__stack_chk_fail",
137 		"panic",
138 		"do_exit",
139 		"__module_put_and_exit",
140 		"complete_and_exit",
141 		"kvm_spurious_fault",
142 		"__reiserfs_panic",
143 		"lbug_with_loc"
144 	};
145 
146 	if (func->bind == STB_WEAK)
147 		return false;
148 
149 	if (func->bind == STB_GLOBAL)
150 		for (i = 0; i < ARRAY_SIZE(global_noreturns); i++)
151 			if (!strcmp(func->name, global_noreturns[i]))
152 				return true;
153 
154 	if (!func->sec)
155 		return false;
156 
157 	insn = find_instruction(file, func->sec, func->offset);
158 	if (!insn)
159 		return false;
160 
161 	list_for_each_entry_from(insn, &file->insns, list) {
162 		if (insn->sec != func->sec ||
163 		    insn->offset >= func->offset + func->len)
164 			break;
165 
166 		empty = false;
167 
168 		if (insn->type == INSN_RETURN)
169 			return false;
170 
171 		if (insn->type == INSN_JUMP_UNCONDITIONAL) {
172 			struct instruction *dest = insn->jump_dest;
173 			struct symbol *dest_func;
174 
175 			if (!dest)
176 				/* sibling call to another file */
177 				return false;
178 
179 			if (dest->sec != func->sec ||
180 			    dest->offset < func->offset ||
181 			    dest->offset >= func->offset + func->len) {
182 				/* local sibling call */
183 				dest_func = find_symbol_by_offset(dest->sec,
184 								  dest->offset);
185 				if (!dest_func)
186 					continue;
187 
188 				return dead_end_function(file, dest_func);
189 			}
190 		}
191 
192 		if (insn->type == INSN_JUMP_DYNAMIC)
193 			/* sibling call */
194 			return false;
195 	}
196 
197 	return !empty;
198 }
199 
200 /*
201  * Call the arch-specific instruction decoder for all the instructions and add
202  * them to the global insns list.
203  */
204 static int decode_instructions(struct objtool_file *file)
205 {
206 	struct section *sec;
207 	unsigned long offset;
208 	struct instruction *insn;
209 	int ret;
210 
211 	INIT_LIST_HEAD(&file->insns);
212 
213 	list_for_each_entry(sec, &file->elf->sections, list) {
214 
215 		if (!(sec->sh.sh_flags & SHF_EXECINSTR))
216 			continue;
217 
218 		for (offset = 0; offset < sec->len; offset += insn->len) {
219 			insn = malloc(sizeof(*insn));
220 			memset(insn, 0, sizeof(*insn));
221 
222 			INIT_LIST_HEAD(&insn->alts);
223 			insn->sec = sec;
224 			insn->offset = offset;
225 
226 			ret = arch_decode_instruction(file->elf, sec, offset,
227 						      sec->len - offset,
228 						      &insn->len, &insn->type,
229 						      &insn->immediate);
230 			if (ret)
231 				return ret;
232 
233 			if (!insn->type || insn->type > INSN_LAST) {
234 				WARN_FUNC("invalid instruction type %d",
235 					  insn->sec, insn->offset, insn->type);
236 				return -1;
237 			}
238 
239 			list_add_tail(&insn->list, &file->insns);
240 		}
241 	}
242 
243 	return 0;
244 }
245 
246 /*
247  * Warnings shouldn't be reported for ignored functions.
248  */
249 static void get_ignores(struct objtool_file *file)
250 {
251 	struct instruction *insn;
252 	struct section *sec;
253 	struct symbol *func;
254 
255 	list_for_each_entry(sec, &file->elf->sections, list) {
256 		list_for_each_entry(func, &sec->symbols, list) {
257 			if (func->type != STT_FUNC)
258 				continue;
259 
260 			if (!ignore_func(file, func))
261 				continue;
262 
263 			insn = find_instruction(file, sec, func->offset);
264 			if (!insn)
265 				continue;
266 
267 			list_for_each_entry_from(insn, &file->insns, list) {
268 				if (insn->sec != func->sec ||
269 				    insn->offset >= func->offset + func->len)
270 					break;
271 
272 				insn->visited = true;
273 			}
274 		}
275 	}
276 }
277 
278 /*
279  * Find the destination instructions for all jumps.
280  */
281 static int get_jump_destinations(struct objtool_file *file)
282 {
283 	struct instruction *insn;
284 	struct rela *rela;
285 	struct section *dest_sec;
286 	unsigned long dest_off;
287 
288 	list_for_each_entry(insn, &file->insns, list) {
289 		if (insn->type != INSN_JUMP_CONDITIONAL &&
290 		    insn->type != INSN_JUMP_UNCONDITIONAL)
291 			continue;
292 
293 		/* skip ignores */
294 		if (insn->visited)
295 			continue;
296 
297 		rela = find_rela_by_dest_range(insn->sec, insn->offset,
298 					       insn->len);
299 		if (!rela) {
300 			dest_sec = insn->sec;
301 			dest_off = insn->offset + insn->len + insn->immediate;
302 		} else if (rela->sym->type == STT_SECTION) {
303 			dest_sec = rela->sym->sec;
304 			dest_off = rela->addend + 4;
305 		} else if (rela->sym->sec->idx) {
306 			dest_sec = rela->sym->sec;
307 			dest_off = rela->sym->sym.st_value + rela->addend + 4;
308 		} else {
309 			/* sibling call */
310 			insn->jump_dest = 0;
311 			continue;
312 		}
313 
314 		insn->jump_dest = find_instruction(file, dest_sec, dest_off);
315 		if (!insn->jump_dest) {
316 
317 			/*
318 			 * This is a special case where an alt instruction
319 			 * jumps past the end of the section.  These are
320 			 * handled later in handle_group_alt().
321 			 */
322 			if (!strcmp(insn->sec->name, ".altinstr_replacement"))
323 				continue;
324 
325 			WARN_FUNC("can't find jump dest instruction at %s+0x%lx",
326 				  insn->sec, insn->offset, dest_sec->name,
327 				  dest_off);
328 			return -1;
329 		}
330 	}
331 
332 	return 0;
333 }
334 
335 /*
336  * Find the destination instructions for all calls.
337  */
338 static int get_call_destinations(struct objtool_file *file)
339 {
340 	struct instruction *insn;
341 	unsigned long dest_off;
342 	struct rela *rela;
343 
344 	list_for_each_entry(insn, &file->insns, list) {
345 		if (insn->type != INSN_CALL)
346 			continue;
347 
348 		rela = find_rela_by_dest_range(insn->sec, insn->offset,
349 					       insn->len);
350 		if (!rela) {
351 			dest_off = insn->offset + insn->len + insn->immediate;
352 			insn->call_dest = find_symbol_by_offset(insn->sec,
353 								dest_off);
354 			if (!insn->call_dest) {
355 				WARN_FUNC("can't find call dest symbol at offset 0x%lx",
356 					  insn->sec, insn->offset, dest_off);
357 				return -1;
358 			}
359 		} else if (rela->sym->type == STT_SECTION) {
360 			insn->call_dest = find_symbol_by_offset(rela->sym->sec,
361 								rela->addend+4);
362 			if (!insn->call_dest ||
363 			    insn->call_dest->type != STT_FUNC) {
364 				WARN_FUNC("can't find call dest symbol at %s+0x%x",
365 					  insn->sec, insn->offset,
366 					  rela->sym->sec->name,
367 					  rela->addend + 4);
368 				return -1;
369 			}
370 		} else
371 			insn->call_dest = rela->sym;
372 	}
373 
374 	return 0;
375 }
376 
377 /*
378  * The .alternatives section requires some extra special care, over and above
379  * what other special sections require:
380  *
381  * 1. Because alternatives are patched in-place, we need to insert a fake jump
382  *    instruction at the end so that validate_branch() skips all the original
383  *    replaced instructions when validating the new instruction path.
384  *
385  * 2. An added wrinkle is that the new instruction length might be zero.  In
386  *    that case the old instructions are replaced with noops.  We simulate that
387  *    by creating a fake jump as the only new instruction.
388  *
389  * 3. In some cases, the alternative section includes an instruction which
390  *    conditionally jumps to the _end_ of the entry.  We have to modify these
391  *    jumps' destinations to point back to .text rather than the end of the
392  *    entry in .altinstr_replacement.
393  *
394  * 4. It has been requested that we don't validate the !POPCNT feature path
395  *    which is a "very very small percentage of machines".
396  */
397 static int handle_group_alt(struct objtool_file *file,
398 			    struct special_alt *special_alt,
399 			    struct instruction *orig_insn,
400 			    struct instruction **new_insn)
401 {
402 	struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump;
403 	unsigned long dest_off;
404 
405 	last_orig_insn = NULL;
406 	insn = orig_insn;
407 	list_for_each_entry_from(insn, &file->insns, list) {
408 		if (insn->sec != special_alt->orig_sec ||
409 		    insn->offset >= special_alt->orig_off + special_alt->orig_len)
410 			break;
411 
412 		if (special_alt->skip_orig)
413 			insn->type = INSN_NOP;
414 
415 		insn->alt_group = true;
416 		last_orig_insn = insn;
417 	}
418 
419 	if (list_is_last(&last_orig_insn->list, &file->insns) ||
420 	    list_next_entry(last_orig_insn, list)->sec != special_alt->orig_sec) {
421 		WARN("%s: don't know how to handle alternatives at end of section",
422 		     special_alt->orig_sec->name);
423 		return -1;
424 	}
425 
426 	fake_jump = malloc(sizeof(*fake_jump));
427 	if (!fake_jump) {
428 		WARN("malloc failed");
429 		return -1;
430 	}
431 	memset(fake_jump, 0, sizeof(*fake_jump));
432 	INIT_LIST_HEAD(&fake_jump->alts);
433 	fake_jump->sec = special_alt->new_sec;
434 	fake_jump->offset = -1;
435 	fake_jump->type = INSN_JUMP_UNCONDITIONAL;
436 	fake_jump->jump_dest = list_next_entry(last_orig_insn, list);
437 
438 	if (!special_alt->new_len) {
439 		*new_insn = fake_jump;
440 		return 0;
441 	}
442 
443 	last_new_insn = NULL;
444 	insn = *new_insn;
445 	list_for_each_entry_from(insn, &file->insns, list) {
446 		if (insn->sec != special_alt->new_sec ||
447 		    insn->offset >= special_alt->new_off + special_alt->new_len)
448 			break;
449 
450 		last_new_insn = insn;
451 
452 		if (insn->type != INSN_JUMP_CONDITIONAL &&
453 		    insn->type != INSN_JUMP_UNCONDITIONAL)
454 			continue;
455 
456 		if (!insn->immediate)
457 			continue;
458 
459 		dest_off = insn->offset + insn->len + insn->immediate;
460 		if (dest_off == special_alt->new_off + special_alt->new_len)
461 			insn->jump_dest = fake_jump;
462 
463 		if (!insn->jump_dest) {
464 			WARN_FUNC("can't find alternative jump destination",
465 				  insn->sec, insn->offset);
466 			return -1;
467 		}
468 	}
469 
470 	if (!last_new_insn) {
471 		WARN_FUNC("can't find last new alternative instruction",
472 			  special_alt->new_sec, special_alt->new_off);
473 		return -1;
474 	}
475 
476 	list_add(&fake_jump->list, &last_new_insn->list);
477 
478 	return 0;
479 }
480 
481 /*
482  * A jump table entry can either convert a nop to a jump or a jump to a nop.
483  * If the original instruction is a jump, make the alt entry an effective nop
484  * by just skipping the original instruction.
485  */
486 static int handle_jump_alt(struct objtool_file *file,
487 			   struct special_alt *special_alt,
488 			   struct instruction *orig_insn,
489 			   struct instruction **new_insn)
490 {
491 	if (orig_insn->type == INSN_NOP)
492 		return 0;
493 
494 	if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) {
495 		WARN_FUNC("unsupported instruction at jump label",
496 			  orig_insn->sec, orig_insn->offset);
497 		return -1;
498 	}
499 
500 	*new_insn = list_next_entry(orig_insn, list);
501 	return 0;
502 }
503 
504 /*
505  * Read all the special sections which have alternate instructions which can be
506  * patched in or redirected to at runtime.  Each instruction having alternate
507  * instruction(s) has them added to its insn->alts list, which will be
508  * traversed in validate_branch().
509  */
510 static int get_special_section_alts(struct objtool_file *file)
511 {
512 	struct list_head special_alts;
513 	struct instruction *orig_insn, *new_insn;
514 	struct special_alt *special_alt, *tmp;
515 	struct alternative *alt;
516 	int ret;
517 
518 	ret = special_get_alts(file->elf, &special_alts);
519 	if (ret)
520 		return ret;
521 
522 	list_for_each_entry_safe(special_alt, tmp, &special_alts, list) {
523 		alt = malloc(sizeof(*alt));
524 		if (!alt) {
525 			WARN("malloc failed");
526 			ret = -1;
527 			goto out;
528 		}
529 
530 		orig_insn = find_instruction(file, special_alt->orig_sec,
531 					     special_alt->orig_off);
532 		if (!orig_insn) {
533 			WARN_FUNC("special: can't find orig instruction",
534 				  special_alt->orig_sec, special_alt->orig_off);
535 			ret = -1;
536 			goto out;
537 		}
538 
539 		new_insn = NULL;
540 		if (!special_alt->group || special_alt->new_len) {
541 			new_insn = find_instruction(file, special_alt->new_sec,
542 						    special_alt->new_off);
543 			if (!new_insn) {
544 				WARN_FUNC("special: can't find new instruction",
545 					  special_alt->new_sec,
546 					  special_alt->new_off);
547 				ret = -1;
548 				goto out;
549 			}
550 		}
551 
552 		if (special_alt->group) {
553 			ret = handle_group_alt(file, special_alt, orig_insn,
554 					       &new_insn);
555 			if (ret)
556 				goto out;
557 		} else if (special_alt->jump_or_nop) {
558 			ret = handle_jump_alt(file, special_alt, orig_insn,
559 					      &new_insn);
560 			if (ret)
561 				goto out;
562 		}
563 
564 		alt->insn = new_insn;
565 		list_add_tail(&alt->list, &orig_insn->alts);
566 
567 		list_del(&special_alt->list);
568 		free(special_alt);
569 	}
570 
571 out:
572 	return ret;
573 }
574 
575 /*
576  * For some switch statements, gcc generates a jump table in the .rodata
577  * section which contains a list of addresses within the function to jump to.
578  * This finds these jump tables and adds them to the insn->alts lists.
579  */
580 static int get_switch_alts(struct objtool_file *file)
581 {
582 	struct instruction *insn, *alt_insn;
583 	struct rela *rodata_rela, *rela;
584 	struct section *rodata;
585 	struct symbol *func;
586 	struct alternative *alt;
587 
588 	list_for_each_entry(insn, &file->insns, list) {
589 		if (insn->type != INSN_JUMP_DYNAMIC)
590 			continue;
591 
592 		rodata_rela = find_rela_by_dest_range(insn->sec, insn->offset,
593 						      insn->len);
594 		if (!rodata_rela || strcmp(rodata_rela->sym->name, ".rodata"))
595 			continue;
596 
597 		rodata = find_section_by_name(file->elf, ".rodata");
598 		if (!rodata || !rodata->rela)
599 			continue;
600 
601 		/* common case: jmpq *[addr](,%rax,8) */
602 		rela = find_rela_by_dest(rodata, rodata_rela->addend);
603 
604 		/* rare case:   jmpq *[addr](%rip) */
605 		if (!rela)
606 			rela = find_rela_by_dest(rodata,
607 						 rodata_rela->addend + 4);
608 		if (!rela)
609 			continue;
610 
611 		func = find_containing_func(insn->sec, insn->offset);
612 		if (!func) {
613 			WARN_FUNC("can't find containing func",
614 				  insn->sec, insn->offset);
615 			return -1;
616 		}
617 
618 		list_for_each_entry_from(rela, &rodata->rela->relas, list) {
619 			if (rela->sym->sec != insn->sec ||
620 			    rela->addend <= func->offset ||
621 			    rela->addend >= func->offset + func->len)
622 				break;
623 
624 			alt_insn = find_instruction(file, insn->sec,
625 						    rela->addend);
626 			if (!alt_insn) {
627 				WARN("%s: can't find instruction at %s+0x%x",
628 				     rodata->rela->name, insn->sec->name,
629 				     rela->addend);
630 				return -1;
631 			}
632 
633 			alt = malloc(sizeof(*alt));
634 			if (!alt) {
635 				WARN("malloc failed");
636 				return -1;
637 			}
638 
639 			alt->insn = alt_insn;
640 			list_add_tail(&alt->list, &insn->alts);
641 		}
642 	}
643 
644 	return 0;
645 }
646 
647 static int decode_sections(struct objtool_file *file)
648 {
649 	int ret;
650 
651 	ret = decode_instructions(file);
652 	if (ret)
653 		return ret;
654 
655 	get_ignores(file);
656 
657 	ret = get_jump_destinations(file);
658 	if (ret)
659 		return ret;
660 
661 	ret = get_call_destinations(file);
662 	if (ret)
663 		return ret;
664 
665 	ret = get_special_section_alts(file);
666 	if (ret)
667 		return ret;
668 
669 	ret = get_switch_alts(file);
670 	if (ret)
671 		return ret;
672 
673 	return 0;
674 }
675 
676 static bool is_fentry_call(struct instruction *insn)
677 {
678 	if (insn->type == INSN_CALL &&
679 	    insn->call_dest->type == STT_NOTYPE &&
680 	    !strcmp(insn->call_dest->name, "__fentry__"))
681 		return true;
682 
683 	return false;
684 }
685 
686 static bool has_modified_stack_frame(struct instruction *insn)
687 {
688 	return (insn->state & STATE_FP_SAVED) ||
689 	       (insn->state & STATE_FP_SETUP);
690 }
691 
692 static bool has_valid_stack_frame(struct instruction *insn)
693 {
694 	return (insn->state & STATE_FP_SAVED) &&
695 	       (insn->state & STATE_FP_SETUP);
696 }
697 
698 /*
699  * Follow the branch starting at the given instruction, and recursively follow
700  * any other branches (jumps).  Meanwhile, track the frame pointer state at
701  * each instruction and validate all the rules described in
702  * tools/objtool/Documentation/stack-validation.txt.
703  */
704 static int validate_branch(struct objtool_file *file,
705 			   struct instruction *first, unsigned char first_state)
706 {
707 	struct alternative *alt;
708 	struct instruction *insn;
709 	struct section *sec;
710 	unsigned char state;
711 	int ret, warnings = 0;
712 
713 	insn = first;
714 	sec = insn->sec;
715 	state = first_state;
716 
717 	if (insn->alt_group && list_empty(&insn->alts)) {
718 		WARN_FUNC("don't know how to handle branch to middle of alternative instruction group",
719 			  sec, insn->offset);
720 		warnings++;
721 	}
722 
723 	while (1) {
724 		if (insn->visited) {
725 			if (insn->state != state) {
726 				WARN_FUNC("frame pointer state mismatch",
727 					  sec, insn->offset);
728 				warnings++;
729 			}
730 
731 			return warnings;
732 		}
733 
734 		/*
735 		 * Catch a rare case where a noreturn function falls through to
736 		 * the next function.
737 		 */
738 		if (is_fentry_call(insn) && (state & STATE_FENTRY))
739 			return warnings;
740 
741 		insn->visited = true;
742 		insn->state = state;
743 
744 		list_for_each_entry(alt, &insn->alts, list) {
745 			ret = validate_branch(file, alt->insn, state);
746 			warnings += ret;
747 		}
748 
749 		switch (insn->type) {
750 
751 		case INSN_FP_SAVE:
752 			if (!nofp) {
753 				if (state & STATE_FP_SAVED) {
754 					WARN_FUNC("duplicate frame pointer save",
755 						  sec, insn->offset);
756 					warnings++;
757 				}
758 				state |= STATE_FP_SAVED;
759 			}
760 			break;
761 
762 		case INSN_FP_SETUP:
763 			if (!nofp) {
764 				if (state & STATE_FP_SETUP) {
765 					WARN_FUNC("duplicate frame pointer setup",
766 						  sec, insn->offset);
767 					warnings++;
768 				}
769 				state |= STATE_FP_SETUP;
770 			}
771 			break;
772 
773 		case INSN_FP_RESTORE:
774 			if (!nofp) {
775 				if (has_valid_stack_frame(insn))
776 					state &= ~STATE_FP_SETUP;
777 
778 				state &= ~STATE_FP_SAVED;
779 			}
780 			break;
781 
782 		case INSN_RETURN:
783 			if (!nofp && has_modified_stack_frame(insn)) {
784 				WARN_FUNC("return without frame pointer restore",
785 					  sec, insn->offset);
786 				warnings++;
787 			}
788 			return warnings;
789 
790 		case INSN_CALL:
791 			if (is_fentry_call(insn)) {
792 				state |= STATE_FENTRY;
793 				break;
794 			}
795 
796 			if (dead_end_function(file, insn->call_dest))
797 				return warnings;
798 
799 			/* fallthrough */
800 		case INSN_CALL_DYNAMIC:
801 			if (!nofp && !has_valid_stack_frame(insn)) {
802 				WARN_FUNC("call without frame pointer save/setup",
803 					  sec, insn->offset);
804 				warnings++;
805 			}
806 			break;
807 
808 		case INSN_JUMP_CONDITIONAL:
809 		case INSN_JUMP_UNCONDITIONAL:
810 			if (insn->jump_dest) {
811 				ret = validate_branch(file, insn->jump_dest,
812 						      state);
813 				warnings += ret;
814 			} else if (has_modified_stack_frame(insn)) {
815 				WARN_FUNC("sibling call from callable instruction with changed frame pointer",
816 					  sec, insn->offset);
817 				warnings++;
818 			} /* else it's a sibling call */
819 
820 			if (insn->type == INSN_JUMP_UNCONDITIONAL)
821 				return warnings;
822 
823 			break;
824 
825 		case INSN_JUMP_DYNAMIC:
826 			if (list_empty(&insn->alts) &&
827 			    has_modified_stack_frame(insn)) {
828 				WARN_FUNC("sibling call from callable instruction with changed frame pointer",
829 					  sec, insn->offset);
830 				warnings++;
831 			}
832 
833 			return warnings;
834 
835 		case INSN_BUG:
836 			return warnings;
837 
838 		default:
839 			break;
840 		}
841 
842 		insn = list_next_entry(insn, list);
843 
844 		if (&insn->list == &file->insns || insn->sec != sec) {
845 			WARN("%s: unexpected end of section", sec->name);
846 			warnings++;
847 			return warnings;
848 		}
849 	}
850 
851 	return warnings;
852 }
853 
854 static bool is_gcov_insn(struct instruction *insn)
855 {
856 	struct rela *rela;
857 	struct section *sec;
858 	struct symbol *sym;
859 	unsigned long offset;
860 
861 	rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
862 	if (!rela)
863 		return false;
864 
865 	if (rela->sym->type != STT_SECTION)
866 		return false;
867 
868 	sec = rela->sym->sec;
869 	offset = rela->addend + insn->offset + insn->len - rela->offset;
870 
871 	list_for_each_entry(sym, &sec->symbols, list) {
872 		if (sym->type != STT_OBJECT)
873 			continue;
874 
875 		if (offset >= sym->offset && offset < sym->offset + sym->len)
876 			return (!memcmp(sym->name, "__gcov0.", 8));
877 	}
878 
879 	return false;
880 }
881 
882 static bool is_kasan_insn(struct instruction *insn)
883 {
884 	return (insn->type == INSN_CALL &&
885 		!strcmp(insn->call_dest->name, "__asan_handle_no_return"));
886 }
887 
888 static bool is_ubsan_insn(struct instruction *insn)
889 {
890 	return (insn->type == INSN_CALL &&
891 		!strcmp(insn->call_dest->name,
892 			"__ubsan_handle_builtin_unreachable"));
893 }
894 
895 static bool ignore_unreachable_insn(struct instruction *insn,
896 				    unsigned long func_end)
897 {
898 	int i;
899 
900 	if (insn->type == INSN_NOP)
901 		return true;
902 
903 	if (is_gcov_insn(insn))
904 		return true;
905 
906 	/*
907 	 * Check if this (or a subsequent) instruction is related to
908 	 * CONFIG_UBSAN or CONFIG_KASAN.
909 	 *
910 	 * End the search at 5 instructions to avoid going into the weeds.
911 	 */
912 	for (i = 0; i < 5; i++) {
913 
914 		if (is_kasan_insn(insn) || is_ubsan_insn(insn))
915 			return true;
916 
917 		if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest) {
918 			insn = insn->jump_dest;
919 			continue;
920 		}
921 
922 		if (insn->offset + insn->len >= func_end)
923 			break;
924 		insn = list_next_entry(insn, list);
925 	}
926 
927 	return false;
928 }
929 
930 static int validate_functions(struct objtool_file *file)
931 {
932 	struct section *sec;
933 	struct symbol *func;
934 	struct instruction *insn;
935 	unsigned long func_end;
936 	int ret, warnings = 0;
937 
938 	list_for_each_entry(sec, &file->elf->sections, list) {
939 		list_for_each_entry(func, &sec->symbols, list) {
940 			if (func->type != STT_FUNC)
941 				continue;
942 
943 			insn = find_instruction(file, sec, func->offset);
944 			if (!insn) {
945 				WARN("%s(): can't find starting instruction",
946 				     func->name);
947 				warnings++;
948 				continue;
949 			}
950 
951 			ret = validate_branch(file, insn, 0);
952 			warnings += ret;
953 		}
954 	}
955 
956 	list_for_each_entry(sec, &file->elf->sections, list) {
957 		list_for_each_entry(func, &sec->symbols, list) {
958 			if (func->type != STT_FUNC)
959 				continue;
960 
961 			insn = find_instruction(file, sec, func->offset);
962 			if (!insn)
963 				continue;
964 
965 			func_end = func->offset + func->len;
966 
967 			list_for_each_entry_from(insn, &file->insns, list) {
968 				if (insn->sec != func->sec ||
969 				    insn->offset >= func_end)
970 					break;
971 
972 				if (insn->visited)
973 					continue;
974 
975 				if (!ignore_unreachable_insn(insn, func_end)) {
976 					WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset);
977 					warnings++;
978 				}
979 
980 				insn->visited = true;
981 			}
982 		}
983 	}
984 
985 	return warnings;
986 }
987 
988 static int validate_uncallable_instructions(struct objtool_file *file)
989 {
990 	struct instruction *insn;
991 	int warnings = 0;
992 
993 	list_for_each_entry(insn, &file->insns, list) {
994 		if (!insn->visited && insn->type == INSN_RETURN) {
995 			WARN_FUNC("return instruction outside of a callable function",
996 				  insn->sec, insn->offset);
997 			warnings++;
998 		}
999 	}
1000 
1001 	return warnings;
1002 }
1003 
1004 static void cleanup(struct objtool_file *file)
1005 {
1006 	struct instruction *insn, *tmpinsn;
1007 	struct alternative *alt, *tmpalt;
1008 
1009 	list_for_each_entry_safe(insn, tmpinsn, &file->insns, list) {
1010 		list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) {
1011 			list_del(&alt->list);
1012 			free(alt);
1013 		}
1014 		list_del(&insn->list);
1015 		free(insn);
1016 	}
1017 	elf_close(file->elf);
1018 }
1019 
1020 const char * const check_usage[] = {
1021 	"objtool check [<options>] file.o",
1022 	NULL,
1023 };
1024 
1025 int cmd_check(int argc, const char **argv)
1026 {
1027 	struct objtool_file file;
1028 	int ret, warnings = 0;
1029 
1030 	const struct option options[] = {
1031 		OPT_BOOLEAN('f', "no-fp", &nofp, "Skip frame pointer validation"),
1032 		OPT_END(),
1033 	};
1034 
1035 	argc = parse_options(argc, argv, options, check_usage, 0);
1036 
1037 	if (argc != 1)
1038 		usage_with_options(check_usage, options);
1039 
1040 	objname = argv[0];
1041 
1042 	file.elf = elf_open(objname);
1043 	if (!file.elf) {
1044 		fprintf(stderr, "error reading elf file %s\n", objname);
1045 		return 1;
1046 	}
1047 
1048 	INIT_LIST_HEAD(&file.insns);
1049 
1050 	ret = decode_sections(&file);
1051 	if (ret < 0)
1052 		goto out;
1053 	warnings += ret;
1054 
1055 	ret = validate_functions(&file);
1056 	if (ret < 0)
1057 		goto out;
1058 	warnings += ret;
1059 
1060 	ret = validate_uncallable_instructions(&file);
1061 	if (ret < 0)
1062 		goto out;
1063 	warnings += ret;
1064 
1065 out:
1066 	cleanup(&file);
1067 
1068 	/* ignore warnings for now until we get all the code cleaned up */
1069 	if (ret || warnings)
1070 		return 0;
1071 	return 0;
1072 }
1073