Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com>
0004  */
0005 
0006 #include <subcmd/parse-options.h>
0007 #include <string.h>
0008 #include <stdlib.h>
0009 #include <objtool/builtin.h>
0010 #include <objtool/objtool.h>
0011 
0012 #define ERROR(format, ...)              \
0013     fprintf(stderr,                 \
0014         "error: objtool: " format "\n",     \
0015         ##__VA_ARGS__)
0016 
0017 struct opts opts;
0018 
0019 static const char * const check_usage[] = {
0020     "objtool <actions> [<options>] file.o",
0021     NULL,
0022 };
0023 
0024 static const char * const env_usage[] = {
0025     "OBJTOOL_ARGS=\"<options>\"",
0026     NULL,
0027 };
0028 
0029 static int parse_dump(const struct option *opt, const char *str, int unset)
0030 {
0031     if (!str || !strcmp(str, "orc")) {
0032         opts.dump_orc = true;
0033         return 0;
0034     }
0035 
0036     return -1;
0037 }
0038 
0039 static int parse_hacks(const struct option *opt, const char *str, int unset)
0040 {
0041     bool found = false;
0042 
0043     /*
0044      * Use strstr() as a lazy method of checking for comma-separated
0045      * options.
0046      *
0047      * No string provided == enable all options.
0048      */
0049 
0050     if (!str || strstr(str, "jump_label")) {
0051         opts.hack_jump_label = true;
0052         found = true;
0053     }
0054 
0055     if (!str || strstr(str, "noinstr")) {
0056         opts.hack_noinstr = true;
0057         found = true;
0058     }
0059 
0060     return found ? 0 : -1;
0061 }
0062 
0063 const struct option check_options[] = {
0064     OPT_GROUP("Actions:"),
0065     OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label,noinstr", "patch toolchain bugs/limitations", parse_hacks),
0066     OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"),
0067     OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"),
0068     OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"),
0069     OPT_BOOLEAN('o', "orc", &opts.orc, "generate ORC metadata"),
0070     OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
0071     OPT_BOOLEAN(0,   "rethunk", &opts.rethunk, "validate and annotate rethunk usage"),
0072     OPT_BOOLEAN(0,   "unret", &opts.unret, "validate entry unret placement"),
0073     OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mitigations"),
0074     OPT_BOOLEAN('s', "stackval", &opts.stackval, "validate frame pointer rules"),
0075     OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static calls"),
0076     OPT_BOOLEAN('u', "uaccess", &opts.uaccess, "validate uaccess rules for SMAP"),
0077     OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse_dump),
0078 
0079     OPT_GROUP("Options:"),
0080     OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"),
0081     OPT_BOOLEAN(0, "backup", &opts.backup, "create .orig files before modification"),
0082     OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"),
0083     OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"),
0084     OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"),
0085     OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"),
0086     OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses in warnings"),
0087     OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"),
0088 
0089     OPT_END(),
0090 };
0091 
0092 int cmd_parse_options(int argc, const char **argv, const char * const usage[])
0093 {
0094     const char *envv[16] = { };
0095     char *env;
0096     int envc;
0097 
0098     env = getenv("OBJTOOL_ARGS");
0099     if (env) {
0100         envv[0] = "OBJTOOL_ARGS";
0101         for (envc = 1; envc < ARRAY_SIZE(envv); ) {
0102             envv[envc++] = env;
0103             env = strchr(env, ' ');
0104             if (!env)
0105                 break;
0106             *env = '\0';
0107             env++;
0108         }
0109 
0110         parse_options(envc, envv, check_options, env_usage, 0);
0111     }
0112 
0113     argc = parse_options(argc, argv, check_options, usage, 0);
0114     if (argc != 1)
0115         usage_with_options(usage, check_options);
0116     return argc;
0117 }
0118 
0119 static bool opts_valid(void)
0120 {
0121     if (opts.hack_jump_label    ||
0122         opts.hack_noinstr       ||
0123         opts.ibt            ||
0124         opts.mcount         ||
0125         opts.noinstr        ||
0126         opts.orc            ||
0127         opts.retpoline      ||
0128         opts.rethunk        ||
0129         opts.sls            ||
0130         opts.stackval       ||
0131         opts.static_call        ||
0132         opts.uaccess) {
0133         if (opts.dump_orc) {
0134             ERROR("--dump can't be combined with other options");
0135             return false;
0136         }
0137 
0138         return true;
0139     }
0140 
0141     if (opts.unret && !opts.rethunk) {
0142         ERROR("--unret requires --rethunk");
0143         return false;
0144     }
0145 
0146     if (opts.dump_orc)
0147         return true;
0148 
0149     ERROR("At least one command required");
0150     return false;
0151 }
0152 
0153 static bool link_opts_valid(struct objtool_file *file)
0154 {
0155     if (opts.link)
0156         return true;
0157 
0158     if (has_multiple_files(file->elf)) {
0159         ERROR("Linked object detected, forcing --link");
0160         opts.link = true;
0161         return true;
0162     }
0163 
0164     if (opts.noinstr) {
0165         ERROR("--noinstr requires --link");
0166         return false;
0167     }
0168 
0169     if (opts.ibt) {
0170         ERROR("--ibt requires --link");
0171         return false;
0172     }
0173 
0174     if (opts.unret) {
0175         ERROR("--unret requires --link");
0176         return false;
0177     }
0178 
0179     return true;
0180 }
0181 
0182 int objtool_run(int argc, const char **argv)
0183 {
0184     const char *objname;
0185     struct objtool_file *file;
0186     int ret;
0187 
0188     argc = cmd_parse_options(argc, argv, check_usage);
0189     objname = argv[0];
0190 
0191     if (!opts_valid())
0192         return 1;
0193 
0194     if (opts.dump_orc)
0195         return orc_dump(objname);
0196 
0197     file = objtool_open_read(objname);
0198     if (!file)
0199         return 1;
0200 
0201     if (!link_opts_valid(file))
0202         return 1;
0203 
0204     ret = check(file);
0205     if (ret)
0206         return ret;
0207 
0208     if (file->elf->changed)
0209         return elf_write(file->elf);
0210 
0211     return 0;
0212 }