builtin-check.c 28.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
 * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

/*
 * objtool check:
 *
 * This command analyzes every .o file and ensures the validity of its stack
 * trace metadata.  It enforces a set of rules on asm code and C inline
 * assembly code so that stack traces can be reliable.
 *
 * For more information, see tools/objtool/Documentation/stack-validation.txt.
 */

#include <string.h>
29
#include <stdlib.h>
30 31 32 33 34 35 36 37
#include <subcmd/parse-options.h>

#include "builtin.h"
#include "elf.h"
#include "special.h"
#include "arch.h"
#include "warn.h"

38 39
#include <linux/hashtable.h>

40 41 42 43 44 45 46 47
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

#define STATE_FP_SAVED		0x1
#define STATE_FP_SETUP		0x2
#define STATE_FENTRY		0x4

struct instruction {
	struct list_head list;
48
	struct hlist_node hash;
49 50 51 52 53 54 55 56 57
	struct section *sec;
	unsigned long offset;
	unsigned int len, state;
	unsigned char type;
	unsigned long immediate;
	bool alt_group, visited;
	struct symbol *call_dest;
	struct instruction *jump_dest;
	struct list_head alts;
58
	struct symbol *func;
59 60 61 62 63 64 65 66 67
};

struct alternative {
	struct list_head list;
	struct instruction *insn;
};

struct objtool_file {
	struct elf *elf;
68
	struct list_head insn_list;
69 70
	DECLARE_HASHTABLE(insn_hash, 16);
	struct section *rodata, *whitelist;
71
	bool ignore_unreachables, c_file;
72 73 74 75 76
};

const char *objname;
static bool nofp;

77 78
static struct instruction *find_insn(struct objtool_file *file,
				     struct section *sec, unsigned long offset)
79 80 81
{
	struct instruction *insn;

82
	hash_for_each_possible(file->insn_hash, insn, hash, offset)
83 84 85 86 87 88
		if (insn->sec == sec && insn->offset == offset)
			return insn;

	return NULL;
}

89 90 91 92 93
static struct instruction *next_insn_same_sec(struct objtool_file *file,
					      struct instruction *insn)
{
	struct instruction *next = list_next_entry(insn, list);

94
	if (&next->list == &file->insn_list || next->sec != insn->sec)
95 96 97 98 99 100
		return NULL;

	return next;
}

#define for_each_insn(file, insn)					\
101
	list_for_each_entry(insn, &file->insn_list, list)
102 103 104

#define func_for_each_insn(file, func, insn)				\
	for (insn = find_insn(file, func->sec, func->offset);		\
105
	     insn && &insn->list != &file->insn_list &&			\
106 107 108 109 110 111 112 113
		insn->sec == func->sec &&				\
		insn->offset < func->offset + func->len;		\
	     insn = list_next_entry(insn, list))

#define sec_for_each_insn_from(file, insn)				\
	for (; insn; insn = next_insn_same_sec(file, insn))


114 115 116 117 118 119 120 121 122 123 124
/*
 * Check if the function has been manually whitelisted with the
 * STACK_FRAME_NON_STANDARD macro, or if it should be automatically whitelisted
 * due to its use of a context switching instruction.
 */
static bool ignore_func(struct objtool_file *file, struct symbol *func)
{
	struct rela *rela;
	struct instruction *insn;

	/* check for STACK_FRAME_NON_STANDARD */
125 126
	if (file->whitelist && file->whitelist->rela)
		list_for_each_entry(rela, &file->whitelist->rela->rela_list, list)
127 128 129 130 131
			if (rela->sym->sec == func->sec &&
			    rela->addend == func->offset)
				return true;

	/* check if it has a context switching instruction */
132
	func_for_each_insn(file, func, insn)
133 134 135 136 137 138 139 140 141 142 143 144 145 146
		if (insn->type == INSN_CONTEXT_SWITCH)
			return true;

	return false;
}

/*
 * This checks to see if the given function is a "noreturn" function.
 *
 * For global functions which are outside the scope of this object file, we
 * have to keep a manual list of them.
 *
 * For local functions, we have to detect them manually by simply looking for
 * the lack of a return instruction.
147 148 149 150 151
 *
 * Returns:
 *  -1: error
 *   0: no dead end
 *   1: dead end
152
 */
153 154
static int __dead_end_function(struct objtool_file *file, struct symbol *func,
			       int recursion)
155 156
{
	int i;
157
	struct instruction *insn;
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
	bool empty = true;

	/*
	 * Unfortunately these have to be hard coded because the noreturn
	 * attribute isn't provided in ELF data.
	 */
	static const char * const global_noreturns[] = {
		"__stack_chk_fail",
		"panic",
		"do_exit",
		"__module_put_and_exit",
		"complete_and_exit",
		"kvm_spurious_fault",
		"__reiserfs_panic",
		"lbug_with_loc"
	};

	if (func->bind == STB_WEAK)
176
		return 0;
177 178 179 180

	if (func->bind == STB_GLOBAL)
		for (i = 0; i < ARRAY_SIZE(global_noreturns); i++)
			if (!strcmp(func->name, global_noreturns[i]))
181
				return 1;
182 183

	if (!func->sec)
184
		return 0;
185

186
	func_for_each_insn(file, func, insn) {
187 188 189
		empty = false;

		if (insn->type == INSN_RETURN)
190
			return 0;
191 192 193
	}

	if (empty)
194
		return 0;
195 196 197 198 199 200

	/*
	 * A function can have a sibling call instead of a return.  In that
	 * case, the function's dead-end status depends on whether the target
	 * of the sibling call returns.
	 */
201
	func_for_each_insn(file, func, insn) {
202 203 204
		if (insn->sec != func->sec ||
		    insn->offset >= func->offset + func->len)
			break;
205 206 207 208 209 210 211

		if (insn->type == INSN_JUMP_UNCONDITIONAL) {
			struct instruction *dest = insn->jump_dest;
			struct symbol *dest_func;

			if (!dest)
				/* sibling call to another file */
212
				return 0;
213 214 215 216 217 218 219 220 221 222

			if (dest->sec != func->sec ||
			    dest->offset < func->offset ||
			    dest->offset >= func->offset + func->len) {
				/* local sibling call */
				dest_func = find_symbol_by_offset(dest->sec,
								  dest->offset);
				if (!dest_func)
					continue;

223 224 225 226 227 228 229 230
				if (recursion == 5) {
					WARN_FUNC("infinite recursion (objtool bug!)",
						  dest->sec, dest->offset);
					return -1;
				}

				return __dead_end_function(file, dest_func,
							   recursion + 1);
231 232 233
			}
		}

234
		if (insn->type == INSN_JUMP_DYNAMIC && list_empty(&insn->alts))
235
			/* sibling call */
236
			return 0;
237 238
	}

239 240 241 242 243 244
	return 1;
}

static int dead_end_function(struct objtool_file *file, struct symbol *func)
{
	return __dead_end_function(file, func, 0);
245 246 247 248
}

/*
 * Call the arch-specific instruction decoder for all the instructions and add
249
 * them to the global instruction list.
250 251 252 253
 */
static int decode_instructions(struct objtool_file *file)
{
	struct section *sec;
254
	struct symbol *func;
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
	unsigned long offset;
	struct instruction *insn;
	int ret;

	list_for_each_entry(sec, &file->elf->sections, list) {

		if (!(sec->sh.sh_flags & SHF_EXECINSTR))
			continue;

		for (offset = 0; offset < sec->len; offset += insn->len) {
			insn = malloc(sizeof(*insn));
			memset(insn, 0, sizeof(*insn));

			INIT_LIST_HEAD(&insn->alts);
			insn->sec = sec;
			insn->offset = offset;

			ret = arch_decode_instruction(file->elf, sec, offset,
						      sec->len - offset,
						      &insn->len, &insn->type,
						      &insn->immediate);
			if (ret)
				return ret;

			if (!insn->type || insn->type > INSN_LAST) {
				WARN_FUNC("invalid instruction type %d",
					  insn->sec, insn->offset, insn->type);
				return -1;
			}

285
			hash_add(file->insn_hash, &insn->hash, insn->offset);
286
			list_add_tail(&insn->list, &file->insn_list);
287
		}
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302

		list_for_each_entry(func, &sec->symbol_list, list) {
			if (func->type != STT_FUNC)
				continue;

			if (!find_insn(file, sec, func->offset)) {
				WARN("%s(): can't find starting instruction",
				     func->name);
				return -1;
			}

			func_for_each_insn(file, func, insn)
				if (!insn->func)
					insn->func = func;
		}
303 304 305 306 307 308 309 310
	}

	return 0;
}

/*
 * Warnings shouldn't be reported for ignored functions.
 */
311
static void add_ignores(struct objtool_file *file)
312 313 314 315 316 317
{
	struct instruction *insn;
	struct section *sec;
	struct symbol *func;

	list_for_each_entry(sec, &file->elf->sections, list) {
318
		list_for_each_entry(func, &sec->symbol_list, list) {
319 320 321 322 323 324
			if (func->type != STT_FUNC)
				continue;

			if (!ignore_func(file, func))
				continue;

325
			func_for_each_insn(file, func, insn)
326 327 328 329 330 331 332 333
				insn->visited = true;
		}
	}
}

/*
 * Find the destination instructions for all jumps.
 */
334
static int add_jump_destinations(struct objtool_file *file)
335 336 337 338 339 340
{
	struct instruction *insn;
	struct rela *rela;
	struct section *dest_sec;
	unsigned long dest_off;

341
	for_each_insn(file, insn) {
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
		if (insn->type != INSN_JUMP_CONDITIONAL &&
		    insn->type != INSN_JUMP_UNCONDITIONAL)
			continue;

		/* skip ignores */
		if (insn->visited)
			continue;

		rela = find_rela_by_dest_range(insn->sec, insn->offset,
					       insn->len);
		if (!rela) {
			dest_sec = insn->sec;
			dest_off = insn->offset + insn->len + insn->immediate;
		} else if (rela->sym->type == STT_SECTION) {
			dest_sec = rela->sym->sec;
			dest_off = rela->addend + 4;
		} else if (rela->sym->sec->idx) {
			dest_sec = rela->sym->sec;
			dest_off = rela->sym->sym.st_value + rela->addend + 4;
		} else {
			/* sibling call */
			insn->jump_dest = 0;
			continue;
		}

367
		insn->jump_dest = find_insn(file, dest_sec, dest_off);
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
		if (!insn->jump_dest) {

			/*
			 * This is a special case where an alt instruction
			 * jumps past the end of the section.  These are
			 * handled later in handle_group_alt().
			 */
			if (!strcmp(insn->sec->name, ".altinstr_replacement"))
				continue;

			WARN_FUNC("can't find jump dest instruction at %s+0x%lx",
				  insn->sec, insn->offset, dest_sec->name,
				  dest_off);
			return -1;
		}
	}

	return 0;
}

/*
 * Find the destination instructions for all calls.
 */
391
static int add_call_destinations(struct objtool_file *file)
392 393 394 395 396
{
	struct instruction *insn;
	unsigned long dest_off;
	struct rela *rela;

397
	for_each_insn(file, insn) {
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
		if (insn->type != INSN_CALL)
			continue;

		rela = find_rela_by_dest_range(insn->sec, insn->offset,
					       insn->len);
		if (!rela) {
			dest_off = insn->offset + insn->len + insn->immediate;
			insn->call_dest = find_symbol_by_offset(insn->sec,
								dest_off);
			if (!insn->call_dest) {
				WARN_FUNC("can't find call dest symbol at offset 0x%lx",
					  insn->sec, insn->offset, dest_off);
				return -1;
			}
		} else if (rela->sym->type == STT_SECTION) {
			insn->call_dest = find_symbol_by_offset(rela->sym->sec,
								rela->addend+4);
			if (!insn->call_dest ||
			    insn->call_dest->type != STT_FUNC) {
				WARN_FUNC("can't find call dest symbol at %s+0x%x",
					  insn->sec, insn->offset,
					  rela->sym->sec->name,
					  rela->addend + 4);
				return -1;
			}
		} else
			insn->call_dest = rela->sym;
	}

	return 0;
}

/*
 * The .alternatives section requires some extra special care, over and above
 * what other special sections require:
 *
 * 1. Because alternatives are patched in-place, we need to insert a fake jump
 *    instruction at the end so that validate_branch() skips all the original
 *    replaced instructions when validating the new instruction path.
 *
 * 2. An added wrinkle is that the new instruction length might be zero.  In
 *    that case the old instructions are replaced with noops.  We simulate that
 *    by creating a fake jump as the only new instruction.
 *
 * 3. In some cases, the alternative section includes an instruction which
 *    conditionally jumps to the _end_ of the entry.  We have to modify these
 *    jumps' destinations to point back to .text rather than the end of the
 *    entry in .altinstr_replacement.
 *
 * 4. It has been requested that we don't validate the !POPCNT feature path
 *    which is a "very very small percentage of machines".
 */
static int handle_group_alt(struct objtool_file *file,
			    struct special_alt *special_alt,
			    struct instruction *orig_insn,
			    struct instruction **new_insn)
{
	struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump;
	unsigned long dest_off;

	last_orig_insn = NULL;
	insn = orig_insn;
460 461
	sec_for_each_insn_from(file, insn) {
		if (insn->offset >= special_alt->orig_off + special_alt->orig_len)
462 463 464 465 466 467 468 469 470
			break;

		if (special_alt->skip_orig)
			insn->type = INSN_NOP;

		insn->alt_group = true;
		last_orig_insn = insn;
	}

471
	if (!next_insn_same_sec(file, last_orig_insn)) {
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
		WARN("%s: don't know how to handle alternatives at end of section",
		     special_alt->orig_sec->name);
		return -1;
	}

	fake_jump = malloc(sizeof(*fake_jump));
	if (!fake_jump) {
		WARN("malloc failed");
		return -1;
	}
	memset(fake_jump, 0, sizeof(*fake_jump));
	INIT_LIST_HEAD(&fake_jump->alts);
	fake_jump->sec = special_alt->new_sec;
	fake_jump->offset = -1;
	fake_jump->type = INSN_JUMP_UNCONDITIONAL;
	fake_jump->jump_dest = list_next_entry(last_orig_insn, list);

	if (!special_alt->new_len) {
		*new_insn = fake_jump;
		return 0;
	}

	last_new_insn = NULL;
	insn = *new_insn;
496 497
	sec_for_each_insn_from(file, insn) {
		if (insn->offset >= special_alt->new_off + special_alt->new_len)
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
			break;

		last_new_insn = insn;

		if (insn->type != INSN_JUMP_CONDITIONAL &&
		    insn->type != INSN_JUMP_UNCONDITIONAL)
			continue;

		if (!insn->immediate)
			continue;

		dest_off = insn->offset + insn->len + insn->immediate;
		if (dest_off == special_alt->new_off + special_alt->new_len)
			insn->jump_dest = fake_jump;

		if (!insn->jump_dest) {
			WARN_FUNC("can't find alternative jump destination",
				  insn->sec, insn->offset);
			return -1;
		}
	}

	if (!last_new_insn) {
		WARN_FUNC("can't find last new alternative instruction",
			  special_alt->new_sec, special_alt->new_off);
		return -1;
	}

	list_add(&fake_jump->list, &last_new_insn->list);

	return 0;
}

/*
 * A jump table entry can either convert a nop to a jump or a jump to a nop.
 * If the original instruction is a jump, make the alt entry an effective nop
 * by just skipping the original instruction.
 */
static int handle_jump_alt(struct objtool_file *file,
			   struct special_alt *special_alt,
			   struct instruction *orig_insn,
			   struct instruction **new_insn)
{
	if (orig_insn->type == INSN_NOP)
		return 0;

	if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) {
		WARN_FUNC("unsupported instruction at jump label",
			  orig_insn->sec, orig_insn->offset);
		return -1;
	}

	*new_insn = list_next_entry(orig_insn, list);
	return 0;
}

/*
 * Read all the special sections which have alternate instructions which can be
 * patched in or redirected to at runtime.  Each instruction having alternate
 * instruction(s) has them added to its insn->alts list, which will be
 * traversed in validate_branch().
 */
560
static int add_special_section_alts(struct objtool_file *file)
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
{
	struct list_head special_alts;
	struct instruction *orig_insn, *new_insn;
	struct special_alt *special_alt, *tmp;
	struct alternative *alt;
	int ret;

	ret = special_get_alts(file->elf, &special_alts);
	if (ret)
		return ret;

	list_for_each_entry_safe(special_alt, tmp, &special_alts, list) {
		alt = malloc(sizeof(*alt));
		if (!alt) {
			WARN("malloc failed");
			ret = -1;
			goto out;
		}

580 581
		orig_insn = find_insn(file, special_alt->orig_sec,
				      special_alt->orig_off);
582 583 584 585 586 587 588 589 590
		if (!orig_insn) {
			WARN_FUNC("special: can't find orig instruction",
				  special_alt->orig_sec, special_alt->orig_off);
			ret = -1;
			goto out;
		}

		new_insn = NULL;
		if (!special_alt->group || special_alt->new_len) {
591 592
			new_insn = find_insn(file, special_alt->new_sec,
					     special_alt->new_off);
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
			if (!new_insn) {
				WARN_FUNC("special: can't find new instruction",
					  special_alt->new_sec,
					  special_alt->new_off);
				ret = -1;
				goto out;
			}
		}

		if (special_alt->group) {
			ret = handle_group_alt(file, special_alt, orig_insn,
					       &new_insn);
			if (ret)
				goto out;
		} else if (special_alt->jump_or_nop) {
			ret = handle_jump_alt(file, special_alt, orig_insn,
					      &new_insn);
			if (ret)
				goto out;
		}

		alt->insn = new_insn;
		list_add_tail(&alt->list, &orig_insn->alts);

		list_del(&special_alt->list);
		free(special_alt);
	}

out:
	return ret;
}

625 626 627
static int add_switch_table(struct objtool_file *file, struct symbol *func,
			    struct instruction *insn, struct rela *table,
			    struct rela *next_table)
628
{
629 630
	struct rela *rela = table;
	struct instruction *alt_insn;
631 632
	struct alternative *alt;

633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
	list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) {
		if (rela == next_table)
			break;

		if (rela->sym->sec != insn->sec ||
		    rela->addend <= func->offset ||
		    rela->addend >= func->offset + func->len)
			break;

		alt_insn = find_insn(file, insn->sec, rela->addend);
		if (!alt_insn) {
			WARN("%s: can't find instruction at %s+0x%x",
			     file->rodata->rela->name, insn->sec->name,
			     rela->addend);
			return -1;
		}

		alt = malloc(sizeof(*alt));
		if (!alt) {
			WARN("malloc failed");
			return -1;
		}

		alt->insn = alt_insn;
		list_add_tail(&alt->list, &insn->alts);
	}

	return 0;
}

static int add_func_switch_tables(struct objtool_file *file,
				  struct symbol *func)
{
	struct instruction *insn, *prev_jump;
667
	struct rela *text_rela, *rodata_rela, *prev_rela = NULL;
668 669 670 671 672
	int ret;

	prev_jump = NULL;

	func_for_each_insn(file, func, insn) {
673 674 675
		if (insn->type != INSN_JUMP_DYNAMIC)
			continue;

676 677
		text_rela = find_rela_by_dest_range(insn->sec, insn->offset,
						    insn->len);
678
		if (!text_rela || text_rela->sym != file->rodata->sym)
679 680 681
			continue;

		/* common case: jmpq *[addr](,%rax,8) */
682 683 684 685 686
		rodata_rela = find_rela_by_dest(file->rodata,
						text_rela->addend);

		/*
		 * rare case:   jmpq *[addr](%rip)
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
		 *
		 * This check is for a rare gcc quirk, currently only seen in
		 * three driver functions in the kernel, only with certain
		 * obscure non-distro configs.
		 *
		 * As part of an optimization, gcc makes a copy of an existing
		 * switch jump table, modifies it, and then hard-codes the jump
		 * (albeit with an indirect jump) to use a single entry in the
		 * table.  The rest of the jump table and some of its jump
		 * targets remain as dead code.
		 *
		 * In such a case we can just crudely ignore all unreachable
		 * instruction warnings for the entire object file.  Ideally we
		 * would just ignore them for the function, but that would
		 * require redesigning the code quite a bit.  And honestly
		 * that's just not worth doing: unreachable instruction
		 * warnings are of questionable value anyway, and this is such
		 * a rare issue.
		 *
		 * kbuild reports:
		 * - https://lkml.kernel.org/r/201603231906.LWcVUpxm%25fengguang.wu@intel.com
		 * - https://lkml.kernel.org/r/201603271114.K9i45biy%25fengguang.wu@intel.com
		 * - https://lkml.kernel.org/r/201603291058.zuJ6ben1%25fengguang.wu@intel.com
		 *
		 * gcc bug:
		 * - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70604
713
		 */
714
		if (!rodata_rela) {
715
			rodata_rela = find_rela_by_dest(file->rodata,
716
							text_rela->addend + 4);
717 718 719
			if (rodata_rela)
				file->ignore_unreachables = true;
		}
720

721
		if (!rodata_rela)
722 723
			continue;

724 725 726 727 728 729 730 731 732 733
		/*
		 * We found a switch table, but we don't know yet how big it
		 * is.  Don't add it until we reach the end of the function or
		 * the beginning of another switch table in the same function.
		 */
		if (prev_jump) {
			ret = add_switch_table(file, func, prev_jump, prev_rela,
					       rodata_rela);
			if (ret)
				return ret;
734 735
		}

736 737 738
		prev_jump = insn;
		prev_rela = rodata_rela;
	}
739

740 741 742 743 744 745 746 747
	if (prev_jump) {
		ret = add_switch_table(file, func, prev_jump, prev_rela, NULL);
		if (ret)
			return ret;
	}

	return 0;
}
748

749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
/*
 * For some switch statements, gcc generates a jump table in the .rodata
 * section which contains a list of addresses within the function to jump to.
 * This finds these jump tables and adds them to the insn->alts lists.
 */
static int add_switch_table_alts(struct objtool_file *file)
{
	struct section *sec;
	struct symbol *func;
	int ret;

	if (!file->rodata || !file->rodata->rela)
		return 0;

	list_for_each_entry(sec, &file->elf->sections, list) {
		list_for_each_entry(func, &sec->symbol_list, list) {
			if (func->type != STT_FUNC)
				continue;

			ret = add_func_switch_tables(file, func);
			if (ret)
				return ret;
771 772 773 774 775 776 777 778 779 780 781 782 783 784
		}
	}

	return 0;
}

static int decode_sections(struct objtool_file *file)
{
	int ret;

	ret = decode_instructions(file);
	if (ret)
		return ret;

785
	add_ignores(file);
786

787
	ret = add_jump_destinations(file);
788 789 790
	if (ret)
		return ret;

791
	ret = add_call_destinations(file);
792 793 794
	if (ret)
		return ret;

795
	ret = add_special_section_alts(file);
796 797 798
	if (ret)
		return ret;

799
	ret = add_switch_table_alts(file);
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
	if (ret)
		return ret;

	return 0;
}

static bool is_fentry_call(struct instruction *insn)
{
	if (insn->type == INSN_CALL &&
	    insn->call_dest->type == STT_NOTYPE &&
	    !strcmp(insn->call_dest->name, "__fentry__"))
		return true;

	return false;
}

static bool has_modified_stack_frame(struct instruction *insn)
{
	return (insn->state & STATE_FP_SAVED) ||
	       (insn->state & STATE_FP_SETUP);
}

static bool has_valid_stack_frame(struct instruction *insn)
{
	return (insn->state & STATE_FP_SAVED) &&
	       (insn->state & STATE_FP_SETUP);
}

828 829 830 831 832
static unsigned int frame_state(unsigned long state)
{
	return (state & (STATE_FP_SAVED | STATE_FP_SETUP));
}

833 834 835 836 837 838 839 840 841 842 843 844
/*
 * Follow the branch starting at the given instruction, and recursively follow
 * any other branches (jumps).  Meanwhile, track the frame pointer state at
 * each instruction and validate all the rules described in
 * tools/objtool/Documentation/stack-validation.txt.
 */
static int validate_branch(struct objtool_file *file,
			   struct instruction *first, unsigned char first_state)
{
	struct alternative *alt;
	struct instruction *insn;
	struct section *sec;
845
	struct symbol *func = NULL;
846
	unsigned char state;
847
	int ret;
848 849 850 851 852 853 854 855

	insn = first;
	sec = insn->sec;
	state = first_state;

	if (insn->alt_group && list_empty(&insn->alts)) {
		WARN_FUNC("don't know how to handle branch to middle of alternative instruction group",
			  sec, insn->offset);
856
		return 1;
857 858 859
	}

	while (1) {
860 861 862 863 864 865 866 867 868 869
		if (file->c_file && insn->func) {
			if (func && func != insn->func) {
				WARN("%s() falls through to next function %s()",
				     func->name, insn->func->name);
				return 1;
			}

			func = insn->func;
		}

870
		if (insn->visited) {
871
			if (frame_state(insn->state) != frame_state(state)) {
872 873
				WARN_FUNC("frame pointer state mismatch",
					  sec, insn->offset);
874
				return 1;
875 876
			}

877
			return 0;
878 879 880 881 882 883 884
		}

		insn->visited = true;
		insn->state = state;

		list_for_each_entry(alt, &insn->alts, list) {
			ret = validate_branch(file, alt->insn, state);
885 886
			if (ret)
				return 1;
887 888 889 890 891 892 893 894 895
		}

		switch (insn->type) {

		case INSN_FP_SAVE:
			if (!nofp) {
				if (state & STATE_FP_SAVED) {
					WARN_FUNC("duplicate frame pointer save",
						  sec, insn->offset);
896
					return 1;
897 898 899 900 901 902 903 904 905 906
				}
				state |= STATE_FP_SAVED;
			}
			break;

		case INSN_FP_SETUP:
			if (!nofp) {
				if (state & STATE_FP_SETUP) {
					WARN_FUNC("duplicate frame pointer setup",
						  sec, insn->offset);
907
					return 1;
908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
				}
				state |= STATE_FP_SETUP;
			}
			break;

		case INSN_FP_RESTORE:
			if (!nofp) {
				if (has_valid_stack_frame(insn))
					state &= ~STATE_FP_SETUP;

				state &= ~STATE_FP_SAVED;
			}
			break;

		case INSN_RETURN:
			if (!nofp && has_modified_stack_frame(insn)) {
				WARN_FUNC("return without frame pointer restore",
					  sec, insn->offset);
926
				return 1;
927
			}
928
			return 0;
929 930 931 932 933 934 935

		case INSN_CALL:
			if (is_fentry_call(insn)) {
				state |= STATE_FENTRY;
				break;
			}

936 937
			ret = dead_end_function(file, insn->call_dest);
			if (ret == 1)
938
				return 0;
939
			if (ret == -1)
940
				return 1;
941 942 943 944 945 946

			/* fallthrough */
		case INSN_CALL_DYNAMIC:
			if (!nofp && !has_valid_stack_frame(insn)) {
				WARN_FUNC("call without frame pointer save/setup",
					  sec, insn->offset);
947
				return 1;
948 949 950 951 952 953 954 955
			}
			break;

		case INSN_JUMP_CONDITIONAL:
		case INSN_JUMP_UNCONDITIONAL:
			if (insn->jump_dest) {
				ret = validate_branch(file, insn->jump_dest,
						      state);
956 957
				if (ret)
					return 1;
958 959 960
			} else if (has_modified_stack_frame(insn)) {
				WARN_FUNC("sibling call from callable instruction with changed frame pointer",
					  sec, insn->offset);
961
				return 1;
962 963 964
			} /* else it's a sibling call */

			if (insn->type == INSN_JUMP_UNCONDITIONAL)
965
				return 0;
966 967 968 969 970 971 972 973

			break;

		case INSN_JUMP_DYNAMIC:
			if (list_empty(&insn->alts) &&
			    has_modified_stack_frame(insn)) {
				WARN_FUNC("sibling call from callable instruction with changed frame pointer",
					  sec, insn->offset);
974
				return 1;
975 976
			}

977
			return 0;
978 979

		case INSN_BUG:
980
			return 0;
981 982 983 984 985

		default:
			break;
		}

986 987
		insn = next_insn_same_sec(file, insn);
		if (!insn) {
988
			WARN("%s: unexpected end of section", sec->name);
989
			return 1;
990 991 992
		}
	}

993
	return 0;
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
}

static bool is_gcov_insn(struct instruction *insn)
{
	struct rela *rela;
	struct section *sec;
	struct symbol *sym;
	unsigned long offset;

	rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
	if (!rela)
		return false;

	if (rela->sym->type != STT_SECTION)
		return false;

	sec = rela->sym->sec;
	offset = rela->addend + insn->offset + insn->len - rela->offset;

1013
	list_for_each_entry(sym, &sec->symbol_list, list) {
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
		if (sym->type != STT_OBJECT)
			continue;

		if (offset >= sym->offset && offset < sym->offset + sym->len)
			return (!memcmp(sym->name, "__gcov0.", 8));
	}

	return false;
}

static bool is_kasan_insn(struct instruction *insn)
{
	return (insn->type == INSN_CALL &&
		!strcmp(insn->call_dest->name, "__asan_handle_no_return"));
}

static bool is_ubsan_insn(struct instruction *insn)
{
	return (insn->type == INSN_CALL &&
		!strcmp(insn->call_dest->name,
			"__ubsan_handle_builtin_unreachable"));
}

1037 1038
static bool ignore_unreachable_insn(struct symbol *func,
				    struct instruction *insn)
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
{
	int i;

	if (insn->type == INSN_NOP)
		return true;

	if (is_gcov_insn(insn))
		return true;

	/*
	 * Check if this (or a subsequent) instruction is related to
	 * CONFIG_UBSAN or CONFIG_KASAN.
	 *
	 * End the search at 5 instructions to avoid going into the weeds.
	 */
	for (i = 0; i < 5; i++) {

		if (is_kasan_insn(insn) || is_ubsan_insn(insn))
			return true;

		if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest) {
			insn = insn->jump_dest;
			continue;
		}

1064
		if (insn->offset + insn->len >= func->offset + func->len)
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
			break;
		insn = list_next_entry(insn, list);
	}

	return false;
}

static int validate_functions(struct objtool_file *file)
{
	struct section *sec;
	struct symbol *func;
	struct instruction *insn;
	int ret, warnings = 0;

	list_for_each_entry(sec, &file->elf->sections, list) {
1080
		list_for_each_entry(func, &sec->symbol_list, list) {
1081 1082 1083
			if (func->type != STT_FUNC)
				continue;

1084
			insn = find_insn(file, sec, func->offset);
1085
			if (!insn)
1086 1087 1088 1089 1090 1091 1092 1093
				continue;

			ret = validate_branch(file, insn, 0);
			warnings += ret;
		}
	}

	list_for_each_entry(sec, &file->elf->sections, list) {
1094
		list_for_each_entry(func, &sec->symbol_list, list) {
1095 1096 1097
			if (func->type != STT_FUNC)
				continue;

1098
			func_for_each_insn(file, func, insn) {
1099 1100 1101 1102
				if (insn->visited)
					continue;

				insn->visited = true;
1103 1104 1105 1106 1107 1108 1109

				if (file->ignore_unreachables || warnings ||
				    ignore_unreachable_insn(func, insn))
					continue;

				WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset);
				warnings++;
1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
			}
		}
	}

	return warnings;
}

static int validate_uncallable_instructions(struct objtool_file *file)
{
	struct instruction *insn;
	int warnings = 0;

1122
	for_each_insn(file, insn) {
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
		if (!insn->visited && insn->type == INSN_RETURN) {
			WARN_FUNC("return instruction outside of a callable function",
				  insn->sec, insn->offset);
			warnings++;
		}
	}

	return warnings;
}

static void cleanup(struct objtool_file *file)
{
	struct instruction *insn, *tmpinsn;
	struct alternative *alt, *tmpalt;

1138
	list_for_each_entry_safe(insn, tmpinsn, &file->insn_list, list) {
1139 1140 1141 1142 1143
		list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) {
			list_del(&alt->list);
			free(alt);
		}
		list_del(&insn->list);
1144
		hash_del(&insn->hash);
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
		free(insn);
	}
	elf_close(file->elf);
}

const char * const check_usage[] = {
	"objtool check [<options>] file.o",
	NULL,
};

int cmd_check(int argc, const char **argv)
{
	struct objtool_file file;
	int ret, warnings = 0;

	const struct option options[] = {
		OPT_BOOLEAN('f', "no-fp", &nofp, "Skip frame pointer validation"),
		OPT_END(),
	};

	argc = parse_options(argc, argv, options, check_usage, 0);

	if (argc != 1)
		usage_with_options(check_usage, options);

	objname = argv[0];

	file.elf = elf_open(objname);
	if (!file.elf) {
		fprintf(stderr, "error reading elf file %s\n", objname);
		return 1;
	}

1178
	INIT_LIST_HEAD(&file.insn_list);
1179
	hash_init(file.insn_hash);
1180 1181 1182
	file.whitelist = find_section_by_name(file.elf, "__func_stack_frame_non_standard");
	file.rodata = find_section_by_name(file.elf, ".rodata");
	file.ignore_unreachables = false;
1183
	file.c_file = find_section_by_name(file.elf, ".comment");
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207

	ret = decode_sections(&file);
	if (ret < 0)
		goto out;
	warnings += ret;

	ret = validate_functions(&file);
	if (ret < 0)
		goto out;
	warnings += ret;

	ret = validate_uncallable_instructions(&file);
	if (ret < 0)
		goto out;
	warnings += ret;

out:
	cleanup(&file);

	/* ignore warnings for now until we get all the code cleaned up */
	if (ret || warnings)
		return 0;
	return 0;
}