cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

builtin-check.c (4711B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      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-separated
     45	 * 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	return found ? 0 : -1;
     61}
     62
     63const struct option check_options[] = {
     64	OPT_GROUP("Actions:"),
     65	OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label,noinstr", "patch toolchain bugs/limitations", parse_hacks),
     66	OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"),
     67	OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"),
     68	OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"),
     69	OPT_BOOLEAN('o', "orc", &opts.orc, "generate ORC metadata"),
     70	OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
     71	OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mitigations"),
     72	OPT_BOOLEAN('s', "stackval", &opts.stackval, "validate frame pointer rules"),
     73	OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static calls"),
     74	OPT_BOOLEAN('u', "uaccess", &opts.uaccess, "validate uaccess rules for SMAP"),
     75	OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse_dump),
     76
     77	OPT_GROUP("Options:"),
     78	OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"),
     79	OPT_BOOLEAN(0, "backup", &opts.backup, "create .orig files before modification"),
     80	OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"),
     81	OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"),
     82	OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"),
     83	OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"),
     84	OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses in warnings"),
     85	OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"),
     86
     87	OPT_END(),
     88};
     89
     90int cmd_parse_options(int argc, const char **argv, const char * const usage[])
     91{
     92	const char *envv[16] = { };
     93	char *env;
     94	int envc;
     95
     96	env = getenv("OBJTOOL_ARGS");
     97	if (env) {
     98		envv[0] = "OBJTOOL_ARGS";
     99		for (envc = 1; envc < ARRAY_SIZE(envv); ) {
    100			envv[envc++] = env;
    101			env = strchr(env, ' ');
    102			if (!env)
    103				break;
    104			*env = '\0';
    105			env++;
    106		}
    107
    108		parse_options(envc, envv, check_options, env_usage, 0);
    109	}
    110
    111	argc = parse_options(argc, argv, check_options, usage, 0);
    112	if (argc != 1)
    113		usage_with_options(usage, check_options);
    114	return argc;
    115}
    116
    117static bool opts_valid(void)
    118{
    119	if (opts.hack_jump_label	||
    120	    opts.hack_noinstr		||
    121	    opts.ibt			||
    122	    opts.mcount			||
    123	    opts.noinstr		||
    124	    opts.orc			||
    125	    opts.retpoline		||
    126	    opts.sls			||
    127	    opts.stackval		||
    128	    opts.static_call		||
    129	    opts.uaccess) {
    130		if (opts.dump_orc) {
    131			ERROR("--dump can't be combined with other options");
    132			return false;
    133		}
    134
    135		return true;
    136	}
    137
    138	if (opts.dump_orc)
    139		return true;
    140
    141	ERROR("At least one command required");
    142	return false;
    143}
    144
    145static bool link_opts_valid(struct objtool_file *file)
    146{
    147	if (opts.link)
    148		return true;
    149
    150	if (has_multiple_files(file->elf)) {
    151		ERROR("Linked object detected, forcing --link");
    152		opts.link = true;
    153		return true;
    154	}
    155
    156	if (opts.noinstr) {
    157		ERROR("--noinstr requires --link");
    158		return false;
    159	}
    160
    161	if (opts.ibt) {
    162		ERROR("--ibt requires --link");
    163		return false;
    164	}
    165
    166	return true;
    167}
    168
    169int objtool_run(int argc, const char **argv)
    170{
    171	const char *objname;
    172	struct objtool_file *file;
    173	int ret;
    174
    175	argc = cmd_parse_options(argc, argv, check_usage);
    176	objname = argv[0];
    177
    178	if (!opts_valid())
    179		return 1;
    180
    181	if (opts.dump_orc)
    182		return orc_dump(objname);
    183
    184	file = objtool_open_read(objname);
    185	if (!file)
    186		return 1;
    187
    188	if (!link_opts_valid(file))
    189		return 1;
    190
    191	ret = check(file);
    192	if (ret)
    193		return ret;
    194
    195	if (file->elf->changed)
    196		return elf_write(file->elf);
    197
    198	return 0;
    199}