Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

objtool: Ditch subcommands

Objtool has a fairly singular focus. It runs on object files and does
validations and transformations which can be combined in various ways.
The subcommand model has never been a good fit, making it awkward to
combine and remove options.

Remove the "check" and "orc" subcommands in favor of a more traditional
cmdline option model. This makes it much more flexible to use, and
easier to port individual features to other arches.

Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Link: https://lkml.kernel.org/r/5c61ebf805e90aefc5fa62bc63468ffae53b9df6.1650300597.git.jpoimboe@redhat.com

authored by

Josh Poimboeuf and committed by
Peter Zijlstra
b51277eb 2daf7fab

+72 -211
+1 -1
scripts/Makefile.build
··· 227 227 objtool := $(objtree)/tools/objtool/objtool 228 228 229 229 objtool_args = \ 230 - $(if $(CONFIG_UNWINDER_ORC),orc generate,check) \ 231 230 $(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \ 232 231 $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \ 232 + $(if $(CONFIG_UNWINDER_ORC), --orc) \ 233 233 $(if $(CONFIG_RETPOLINE), --retpoline) \ 234 234 $(if $(CONFIG_SLS), --sls) \ 235 235 $(if $(CONFIG_X86_SMAP), --uaccess) \
+5 -7
tools/objtool/Build
··· 2 2 3 3 objtool-y += weak.o 4 4 5 - objtool-$(SUBCMD_CHECK) += check.o 6 - objtool-$(SUBCMD_CHECK) += special.o 7 - objtool-$(SUBCMD_ORC) += check.o 8 - objtool-$(SUBCMD_ORC) += orc_gen.o 9 - objtool-$(SUBCMD_ORC) += orc_dump.o 10 - 5 + objtool-y += check.o 6 + objtool-y += special.o 11 7 objtool-y += builtin-check.o 12 - objtool-y += builtin-orc.o 13 8 objtool-y += elf.o 14 9 objtool-y += objtool.o 10 + 11 + objtool-$(BUILD_ORC) += orc_gen.o 12 + objtool-$(BUILD_ORC) += orc_dump.o 15 13 16 14 objtool-y += libstring.o 17 15 objtool-y += libctype.o
+3 -5
tools/objtool/Makefile
··· 39 39 40 40 AWK = awk 41 41 42 - SUBCMD_CHECK := n 43 - SUBCMD_ORC := n 42 + BUILD_ORC := n 44 43 45 44 ifeq ($(SRCARCH),x86) 46 - SUBCMD_CHECK := y 47 - SUBCMD_ORC := y 45 + BUILD_ORC := y 48 46 endif 49 47 50 - export SUBCMD_CHECK SUBCMD_ORC 48 + export BUILD_ORC 51 49 export srctree OUTPUT CFLAGS SRCARCH AWK 52 50 include $(srctree)/tools/build/Makefile.include 53 51
+44 -12
tools/objtool/builtin-check.c
··· 3 3 * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com> 4 4 */ 5 5 6 - /* 7 - * objtool check: 8 - * 9 - * This command analyzes every .o file and ensures the validity of its stack 10 - * trace metadata. It enforces a set of rules on asm code and C inline 11 - * assembly code so that stack traces can be reliable. 12 - * 13 - * For more information, see tools/objtool/Documentation/stack-validation.txt. 14 - */ 15 - 16 6 #include <subcmd/parse-options.h> 17 7 #include <string.h> 18 8 #include <stdlib.h> ··· 12 22 struct opts opts; 13 23 14 24 static const char * const check_usage[] = { 15 - "objtool check <actions> [<options>] file.o", 25 + "objtool <actions> [<options>] file.o", 16 26 NULL, 17 27 }; 18 28 ··· 21 31 NULL, 22 32 }; 23 33 34 + static int parse_dump(const struct option *opt, const char *str, int unset) 35 + { 36 + if (!str || !strcmp(str, "orc")) { 37 + opts.dump_orc = true; 38 + return 0; 39 + } 40 + 41 + return -1; 42 + } 43 + 24 44 const struct option check_options[] = { 25 45 OPT_GROUP("Actions:"), 26 46 OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"), 27 47 OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"), 28 48 OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"), 49 + OPT_BOOLEAN('o', "orc", &opts.orc, "generate ORC metadata"), 29 50 OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"), 30 51 OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mitigations"), 31 52 OPT_BOOLEAN('u', "uaccess", &opts.uaccess, "validate uaccess rules for SMAP"), 53 + OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse_dump), 32 54 33 55 OPT_GROUP("Options:"), 34 56 OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"), ··· 83 81 return argc; 84 82 } 85 83 86 - int cmd_check(int argc, const char **argv) 84 + static bool opts_valid(void) 85 + { 86 + if (opts.ibt || 87 + opts.mcount || 88 + opts.noinstr || 89 + opts.orc || 90 + opts.retpoline || 91 + opts.sls || 92 + opts.uaccess) { 93 + if (opts.dump_orc) { 94 + fprintf(stderr, "--dump can't be combined with other options\n"); 95 + return false; 96 + } 97 + 98 + return true; 99 + } 100 + 101 + if (opts.dump_orc) 102 + return true; 103 + 104 + fprintf(stderr, "At least one command required\n"); 105 + return false; 106 + } 107 + 108 + int objtool_run(int argc, const char **argv) 87 109 { 88 110 const char *objname; 89 111 struct objtool_file *file; ··· 115 89 116 90 argc = cmd_parse_options(argc, argv, check_usage); 117 91 objname = argv[0]; 92 + 93 + if (!opts_valid()) 94 + return 1; 95 + 96 + if (opts.dump_orc) 97 + return orc_dump(objname); 118 98 119 99 file = objtool_open_read(objname); 120 100 if (!file)
-73
tools/objtool/builtin-orc.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-or-later 2 - /* 3 - * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> 4 - */ 5 - 6 - /* 7 - * objtool orc: 8 - * 9 - * This command analyzes a .o file and adds .orc_unwind and .orc_unwind_ip 10 - * sections to it, which is used by the in-kernel ORC unwinder. 11 - * 12 - * This command is a superset of "objtool check". 13 - */ 14 - 15 - #include <string.h> 16 - #include <objtool/builtin.h> 17 - #include <objtool/objtool.h> 18 - 19 - static const char *orc_usage[] = { 20 - "objtool orc generate [<options>] file.o", 21 - "objtool orc dump file.o", 22 - NULL, 23 - }; 24 - 25 - int cmd_orc(int argc, const char **argv) 26 - { 27 - const char *objname; 28 - 29 - argc--; argv++; 30 - if (argc <= 0) 31 - usage_with_options(orc_usage, check_options); 32 - 33 - if (!strncmp(argv[0], "gen", 3)) { 34 - struct objtool_file *file; 35 - int ret; 36 - 37 - argc = cmd_parse_options(argc, argv, orc_usage); 38 - objname = argv[0]; 39 - 40 - file = objtool_open_read(objname); 41 - if (!file) 42 - return 1; 43 - 44 - ret = check(file); 45 - if (ret) 46 - return ret; 47 - 48 - if (list_empty(&file->insn_list)) 49 - return 0; 50 - 51 - ret = orc_create(file); 52 - if (ret) 53 - return ret; 54 - 55 - if (!file->elf->changed) 56 - return 0; 57 - 58 - return elf_write(file->elf); 59 - } 60 - 61 - if (!strcmp(argv[0], "dump")) { 62 - if (argc != 2) 63 - usage_with_options(orc_usage, check_options); 64 - 65 - objname = argv[1]; 66 - 67 - return orc_dump(objname); 68 - } 69 - 70 - usage_with_options(orc_usage, check_options); 71 - 72 - return 0; 73 - }
+8
tools/objtool/check.c
··· 3949 3949 warnings += ret; 3950 3950 } 3951 3951 3952 + if (opts.orc && !list_empty(&file->insn_list)) { 3953 + ret = orc_create(file); 3954 + if (ret < 0) 3955 + goto out; 3956 + warnings += ret; 3957 + } 3958 + 3959 + 3952 3960 if (opts.stats) { 3953 3961 printf("nr_insns_visited: %ld\n", nr_insns_visited); 3954 3962 printf("nr_cfi: %ld\n", nr_cfi);
+3 -2
tools/objtool/include/objtool/builtin.h
··· 11 11 12 12 struct opts { 13 13 /* actions: */ 14 + bool dump_orc; 14 15 bool ibt; 15 16 bool mcount; 16 17 bool noinstr; 18 + bool orc; 17 19 bool retpoline; 18 20 bool sls; 19 21 bool uaccess; ··· 36 34 37 35 extern int cmd_parse_options(int argc, const char **argv, const char * const usage[]); 38 36 39 - extern int cmd_check(int argc, const char **argv); 40 - extern int cmd_orc(int argc, const char **argv); 37 + extern int objtool_run(int argc, const char **argv); 41 38 42 39 #endif /* _BUILTIN_H */
+1 -96
tools/objtool/objtool.c
··· 3 3 * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> 4 4 */ 5 5 6 - /* 7 - * objtool: 8 - * 9 - * The 'check' subcmd analyzes every .o file and ensures the validity of its 10 - * stack trace metadata. It enforces a set of rules on asm code and C inline 11 - * assembly code so that stack traces can be reliable. 12 - * 13 - * For more information, see tools/objtool/Documentation/stack-validation.txt. 14 - */ 15 - 16 6 #include <stdio.h> 17 7 #include <stdbool.h> 18 8 #include <string.h> ··· 15 25 #include <objtool/builtin.h> 16 26 #include <objtool/objtool.h> 17 27 #include <objtool/warn.h> 18 - 19 - struct cmd_struct { 20 - const char *name; 21 - int (*fn)(int, const char **); 22 - const char *help; 23 - }; 24 - 25 - static const char objtool_usage_string[] = 26 - "objtool COMMAND [ARGS]"; 27 - 28 - static struct cmd_struct objtool_cmds[] = { 29 - {"check", cmd_check, "Perform stack metadata validation on an object file" }, 30 - {"orc", cmd_orc, "Generate in-place ORC unwind tables for an object file" }, 31 - }; 32 28 33 29 bool help; 34 30 ··· 137 161 f->pv_ops[idx].clean = false; 138 162 } 139 163 140 - static void cmd_usage(void) 141 - { 142 - unsigned int i, longest = 0; 143 - 144 - printf("\n usage: %s\n\n", objtool_usage_string); 145 - 146 - for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 147 - if (longest < strlen(objtool_cmds[i].name)) 148 - longest = strlen(objtool_cmds[i].name); 149 - } 150 - 151 - puts(" Commands:"); 152 - for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 153 - printf(" %-*s ", longest, objtool_cmds[i].name); 154 - puts(objtool_cmds[i].help); 155 - } 156 - 157 - printf("\n"); 158 - 159 - if (!help) 160 - exit(129); 161 - exit(0); 162 - } 163 - 164 - static void handle_options(int *argc, const char ***argv) 165 - { 166 - while (*argc > 0) { 167 - const char *cmd = (*argv)[0]; 168 - 169 - if (cmd[0] != '-') 170 - break; 171 - 172 - if (!strcmp(cmd, "--help") || !strcmp(cmd, "-h")) { 173 - help = true; 174 - break; 175 - } else { 176 - fprintf(stderr, "Unknown option: %s\n", cmd); 177 - cmd_usage(); 178 - } 179 - 180 - (*argv)++; 181 - (*argc)--; 182 - } 183 - } 184 - 185 - static void handle_internal_command(int argc, const char **argv) 186 - { 187 - const char *cmd = argv[0]; 188 - unsigned int i, ret; 189 - 190 - for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 191 - struct cmd_struct *p = objtool_cmds+i; 192 - 193 - if (strcmp(p->name, cmd)) 194 - continue; 195 - 196 - ret = p->fn(argc, argv); 197 - 198 - exit(ret); 199 - } 200 - 201 - cmd_usage(); 202 - } 203 - 204 164 int main(int argc, const char **argv) 205 165 { 206 166 static const char *UNUSED = "OBJTOOL_NOT_IMPLEMENTED"; ··· 145 233 exec_cmd_init("objtool", UNUSED, UNUSED, UNUSED); 146 234 pager_init(UNUSED); 147 235 148 - argv++; 149 - argc--; 150 - handle_options(&argc, &argv); 151 - 152 - if (!argc || help) 153 - cmd_usage(); 154 - 155 - handle_internal_command(argc, argv); 236 + objtool_run(argc, argv); 156 237 157 238 return 0; 158 239 }
+2 -7
tools/objtool/weak.c
··· 15 15 return ENOSYS; \ 16 16 }) 17 17 18 - int __weak check(struct objtool_file *file) 19 - { 20 - UNSUPPORTED("check subcommand"); 21 - } 22 - 23 18 int __weak orc_dump(const char *_objname) 24 19 { 25 - UNSUPPORTED("orc"); 20 + UNSUPPORTED("ORC"); 26 21 } 27 22 28 23 int __weak orc_create(struct objtool_file *file) 29 24 { 30 - UNSUPPORTED("orc"); 25 + UNSUPPORTED("ORC"); 31 26 }