brintos

brintos / linux-shallow public Read only

0
0
Text · 5.6 KiB · 387d56a Raw
239 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com>4 */5 6#include <subcmd/parse-options.h>7#include <string.h>8#include <stdlib.h>9#include <objtool/builtin.h>10#include <objtool/objtool.h>11 12#define ERROR(format, ...)				\13	fprintf(stderr,					\14		"error: objtool: " format "\n",		\15		##__VA_ARGS__)16 17struct opts opts;18 19static const char * const check_usage[] = {20	"objtool <actions> [<options>] file.o",21	NULL,22};23 24static const char * const env_usage[] = {25	"OBJTOOL_ARGS=\"<options>\"",26	NULL,27};28 29static int parse_dump(const struct option *opt, const char *str, int unset)30{31	if (!str || !strcmp(str, "orc")) {32		opts.dump_orc = true;33		return 0;34	}35 36	return -1;37}38 39static int parse_hacks(const struct option *opt, const char *str, int unset)40{41	bool found = false;42 43	/*44	 * Use strstr() as a lazy method of checking for comma-separated45	 * options.46	 *47	 * No string provided == enable all options.48	 */49 50	if (!str || strstr(str, "jump_label")) {51		opts.hack_jump_label = true;52		found = true;53	}54 55	if (!str || strstr(str, "noinstr")) {56		opts.hack_noinstr = true;57		found = true;58	}59 60	if (!str || strstr(str, "skylake")) {61		opts.hack_skylake = true;62		found = true;63	}64 65	return found ? 0 : -1;66}67 68static const struct option check_options[] = {69	OPT_GROUP("Actions:"),70	OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label,noinstr,skylake", "patch toolchain bugs/limitations", parse_hacks),71	OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"),72	OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"),73	OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"),74	OPT_BOOLEAN('o', "orc", &opts.orc, "generate ORC metadata"),75	OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),76	OPT_BOOLEAN(0,   "rethunk", &opts.rethunk, "validate and annotate rethunk usage"),77	OPT_BOOLEAN(0,   "unret", &opts.unret, "validate entry unret placement"),78	OPT_INTEGER(0,   "prefix", &opts.prefix, "generate prefix symbols"),79	OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mitigations"),80	OPT_BOOLEAN('s', "stackval", &opts.stackval, "validate frame pointer rules"),81	OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static calls"),82	OPT_BOOLEAN('u', "uaccess", &opts.uaccess, "validate uaccess rules for SMAP"),83	OPT_BOOLEAN(0  , "cfi", &opts.cfi, "annotate kernel control flow integrity (kCFI) function preambles"),84	OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse_dump),85 86	OPT_GROUP("Options:"),87	OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"),88	OPT_BOOLEAN(0, "backup", &opts.backup, "create .orig files before modification"),89	OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"),90	OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"),91	OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"),92	OPT_BOOLEAN(0, "mnop", &opts.mnop, "nop out mcount call sites"),93	OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"),94	OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses in warnings"),95	OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"),96	OPT_BOOLEAN('v', "verbose", &opts.verbose, "verbose warnings"),97 98	OPT_END(),99};100 101int cmd_parse_options(int argc, const char **argv, const char * const usage[])102{103	const char *envv[16] = { };104	char *env;105	int envc;106 107	env = getenv("OBJTOOL_ARGS");108	if (env) {109		envv[0] = "OBJTOOL_ARGS";110		for (envc = 1; envc < ARRAY_SIZE(envv); ) {111			envv[envc++] = env;112			env = strchr(env, ' ');113			if (!env)114				break;115			*env = '\0';116			env++;117		}118 119		parse_options(envc, envv, check_options, env_usage, 0);120	}121 122	env = getenv("OBJTOOL_VERBOSE");123	if (env && !strcmp(env, "1"))124		opts.verbose = true;125 126	argc = parse_options(argc, argv, check_options, usage, 0);127	if (argc != 1)128		usage_with_options(usage, check_options);129	return argc;130}131 132static bool opts_valid(void)133{134	if (opts.hack_jump_label	||135	    opts.hack_noinstr		||136	    opts.ibt			||137	    opts.mcount			||138	    opts.noinstr		||139	    opts.orc			||140	    opts.retpoline		||141	    opts.rethunk		||142	    opts.sls			||143	    opts.stackval		||144	    opts.static_call		||145	    opts.uaccess) {146		if (opts.dump_orc) {147			ERROR("--dump can't be combined with other actions");148			return false;149		}150 151		return true;152	}153 154	if (opts.unret && !opts.rethunk) {155		ERROR("--unret requires --rethunk");156		return false;157	}158 159	if (opts.dump_orc)160		return true;161 162	ERROR("At least one action required");163	return false;164}165 166static bool mnop_opts_valid(void)167{168	if (opts.mnop && !opts.mcount) {169		ERROR("--mnop requires --mcount");170		return false;171	}172 173	return true;174}175 176static bool link_opts_valid(struct objtool_file *file)177{178	if (opts.link)179		return true;180 181	if (has_multiple_files(file->elf)) {182		ERROR("Linked object detected, forcing --link");183		opts.link = true;184		return true;185	}186 187	if (opts.noinstr) {188		ERROR("--noinstr requires --link");189		return false;190	}191 192	if (opts.ibt) {193		ERROR("--ibt requires --link");194		return false;195	}196 197	if (opts.unret) {198		ERROR("--unret requires --link");199		return false;200	}201 202	return true;203}204 205int objtool_run(int argc, const char **argv)206{207	const char *objname;208	struct objtool_file *file;209	int ret;210 211	argc = cmd_parse_options(argc, argv, check_usage);212	objname = argv[0];213 214	if (!opts_valid())215		return 1;216 217	if (opts.dump_orc)218		return orc_dump(objname);219 220	file = objtool_open_read(objname);221	if (!file)222		return 1;223 224	if (!mnop_opts_valid())225		return 1;226 227	if (!link_opts_valid(file))228		return 1;229 230	ret = check(file);231	if (ret)232		return ret;233 234	if (file->elf->changed)235		return elf_write(file->elf);236 237	return 0;238}239