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

objtool: Reorganize cmdline options

Split the existing options into two groups: actions, which actually do
something; and options, which modify the actions in some way.

Also there's no need to have short flags for all the non-action options.
Reserve short flags for the more important actions.

While at it:

- change a few of the short flags to be more intuitive

- make option descriptions more consistently descriptive

- sort options in the source like they are when printed

- move options to a global struct

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/9dcaa752f83aca24b1b21f0b0eeb28a0c181c0b0.1650300597.git.jpoimboe@redhat.com

authored by

Josh Poimboeuf and committed by
Peter Zijlstra
2daf7fab aa3d60e0

+110 -80
+6 -6
scripts/Makefile.build
··· 228 228 229 229 objtool_args = \ 230 230 $(if $(CONFIG_UNWINDER_ORC),orc generate,check) \ 231 - $(if $(part-of-module), --module) \ 232 231 $(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \ 233 - $(if $(CONFIG_FRAME_POINTER),, --no-fp) \ 234 - $(if $(CONFIG_GCOV_KERNEL), --no-unreachable) \ 235 - $(if $(CONFIG_RETPOLINE), --retpoline) \ 236 - $(if $(CONFIG_X86_SMAP), --uaccess) \ 237 232 $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \ 238 - $(if $(CONFIG_SLS), --sls) 233 + $(if $(CONFIG_RETPOLINE), --retpoline) \ 234 + $(if $(CONFIG_SLS), --sls) \ 235 + $(if $(CONFIG_X86_SMAP), --uaccess) \ 236 + $(if $(part-of-module), --module) \ 237 + $(if $(CONFIG_FRAME_POINTER),, --no-fp) \ 238 + $(if $(CONFIG_GCOV_KERNEL), --no-unreachable) 239 239 240 240 cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool_args) $@) 241 241 cmd_gen_objtooldep = $(if $(objtool-enabled), { echo ; echo '$@: $$(wildcard $(objtool))' ; } >> $(dot-target).cmd)
+1 -1
tools/objtool/arch/x86/decode.c
··· 581 581 break; 582 582 583 583 case 0xc7: /* mov imm, r/m */ 584 - if (!noinstr) 584 + if (!opts.noinstr) 585 585 break; 586 586 587 587 if (insn.length == 3+4+4 && !strncmp(sec->name, ".init.text", 10)) {
+1 -1
tools/objtool/arch/x86/special.c
··· 20 20 * find paths that see the STAC but take the NOP instead of 21 21 * CLAC and the other way around. 22 22 */ 23 - if (uaccess) 23 + if (opts.uaccess) 24 24 alt->skip_orig = true; 25 25 else 26 26 alt->skip_alt = true;
+21 -19
tools/objtool/builtin-check.c
··· 19 19 #include <objtool/builtin.h> 20 20 #include <objtool/objtool.h> 21 21 22 - bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, 23 - lto, vmlinux, mcount, noinstr, backup, sls, dryrun, 24 - ibt; 22 + struct opts opts; 25 23 26 24 static const char * const check_usage[] = { 27 - "objtool check [<options>] file.o", 25 + "objtool check <actions> [<options>] file.o", 28 26 NULL, 29 27 }; 30 28 ··· 32 34 }; 33 35 34 36 const struct option check_options[] = { 35 - OPT_BOOLEAN('f', "no-fp", &no_fp, "Skip frame pointer validation"), 36 - OPT_BOOLEAN('u', "no-unreachable", &no_unreachable, "Skip 'unreachable instruction' warnings"), 37 - OPT_BOOLEAN('r', "retpoline", &retpoline, "Validate retpoline assumptions"), 38 - OPT_BOOLEAN('m', "module", &module, "Indicates the object will be part of a kernel module"), 39 - OPT_BOOLEAN('b', "backtrace", &backtrace, "unwind on error"), 40 - OPT_BOOLEAN('a', "uaccess", &uaccess, "enable uaccess checking"), 41 - OPT_BOOLEAN('s', "stats", &stats, "print statistics"), 42 - OPT_BOOLEAN(0, "lto", &lto, "whole-archive like runs"), 43 - OPT_BOOLEAN('n', "noinstr", &noinstr, "noinstr validation for vmlinux.o"), 44 - OPT_BOOLEAN('l', "vmlinux", &vmlinux, "vmlinux.o validation"), 45 - OPT_BOOLEAN('M', "mcount", &mcount, "generate __mcount_loc"), 46 - OPT_BOOLEAN('B', "backup", &backup, "create .orig files before modification"), 47 - OPT_BOOLEAN('S', "sls", &sls, "validate straight-line-speculation"), 48 - OPT_BOOLEAN(0, "dry-run", &dryrun, "don't write the modifications"), 49 - OPT_BOOLEAN(0, "ibt", &ibt, "validate ENDBR placement"), 37 + OPT_GROUP("Actions:"), 38 + OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"), 39 + OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"), 40 + OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"), 41 + OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"), 42 + OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mitigations"), 43 + OPT_BOOLEAN('u', "uaccess", &opts.uaccess, "validate uaccess rules for SMAP"), 44 + 45 + OPT_GROUP("Options:"), 46 + OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"), 47 + OPT_BOOLEAN(0, "backup", &opts.backup, "create .orig files before modification"), 48 + OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"), 49 + OPT_BOOLEAN(0, "lto", &opts.lto, "whole-archive like runs"), 50 + OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"), 51 + OPT_BOOLEAN(0, "no-fp", &opts.no_fp, "skip frame pointer validation"), 52 + OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"), 53 + OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"), 54 + OPT_BOOLEAN(0, "vmlinux", &opts.vmlinux, "vmlinux.o validation"), 55 + 50 56 OPT_END(), 51 57 }; 52 58
+31 -31
tools/objtool/check.c
··· 273 273 * not correctly determine insn->call_dest->sec (external symbols do 274 274 * not have a section). 275 275 */ 276 - if (vmlinux && noinstr && sec) 276 + if (opts.vmlinux && opts.noinstr && sec) 277 277 state->noinstr = sec->noinstr; 278 278 } 279 279 ··· 339 339 if (cfi_hash == (void *)-1L) { 340 340 WARN("mmap fail cfi_hash"); 341 341 cfi_hash = NULL; 342 - } else if (stats) { 342 + } else if (opts.stats) { 343 343 printf("cfi_bits: %d\n", cfi_bits); 344 344 } 345 345 ··· 434 434 } 435 435 } 436 436 437 - if (stats) 437 + if (opts.stats) 438 438 printf("nr_insns: %lu\n", nr_insns); 439 439 440 440 return 0; ··· 497 497 struct symbol *sym; 498 498 int idx, nr; 499 499 500 - if (!noinstr) 500 + if (!opts.noinstr) 501 501 return 0; 502 502 503 503 file->pv_ops = NULL; ··· 668 668 669 669 key_sym = find_symbol_by_name(file->elf, tmp); 670 670 if (!key_sym) { 671 - if (!module) { 671 + if (!opts.module) { 672 672 WARN("static_call: can't find static_call_key symbol: %s", tmp); 673 673 return -1; 674 674 } ··· 761 761 list_for_each_entry(insn, &file->endbr_list, call_node) 762 762 idx++; 763 763 764 - if (stats) { 764 + if (opts.stats) { 765 765 printf("ibt: ENDBR at function start: %d\n", file->nr_endbr); 766 766 printf("ibt: ENDBR inside functions: %d\n", file->nr_endbr_int); 767 767 printf("ibt: superfluous ENDBR: %d\n", idx); ··· 1028 1028 struct symbol *func; 1029 1029 const char **name; 1030 1030 1031 - if (!uaccess) 1031 + if (!opts.uaccess) 1032 1032 return; 1033 1033 1034 1034 for (name = uaccess_safe_builtin; *name; name++) { ··· 1170 1170 return; 1171 1171 } 1172 1172 1173 - if (mcount && sym->fentry) { 1173 + if (opts.mcount && sym->fentry) { 1174 1174 if (sibling) 1175 1175 WARN_FUNC("Tail call to __fentry__ !?!?", insn->sec, insn->offset); 1176 1176 ··· 1256 1256 if (insn->offset == insn->func->offset) 1257 1257 return true; 1258 1258 1259 - if (ibt) { 1259 + if (opts.ibt) { 1260 1260 struct instruction *prev = prev_insn_same_sym(file, insn); 1261 1261 1262 1262 if (prev && prev->type == INSN_ENDBR && ··· 1699 1699 free(special_alt); 1700 1700 } 1701 1701 1702 - if (stats) { 1702 + if (opts.stats) { 1703 1703 printf("jl\\\tNOP\tJMP\n"); 1704 1704 printf("short:\t%ld\t%ld\n", file->jl_nop_short, file->jl_short); 1705 1705 printf("long:\t%ld\t%ld\n", file->jl_nop_long, file->jl_long); ··· 1945 1945 1946 1946 insn->hint = true; 1947 1947 1948 - if (ibt && hint->type == UNWIND_HINT_TYPE_REGS_PARTIAL) { 1948 + if (opts.ibt && hint->type == UNWIND_HINT_TYPE_REGS_PARTIAL) { 1949 1949 struct symbol *sym = find_symbol_by_offset(insn->sec, insn->offset); 1950 1950 1951 1951 if (sym && sym->bind == STB_GLOBAL && ··· 2806 2806 } 2807 2807 2808 2808 /* detect when asm code uses rbp as a scratch register */ 2809 - if (!no_fp && insn->func && op->src.reg == CFI_BP && 2809 + if (!opts.no_fp && insn->func && op->src.reg == CFI_BP && 2810 2810 cfa->base != CFI_BP) 2811 2811 cfi->bp_scratch = true; 2812 2812 break; ··· 3363 3363 3364 3364 ret = validate_branch(file, func, alt->insn, state); 3365 3365 if (ret) { 3366 - if (backtrace) 3366 + if (opts.backtrace) 3367 3367 BT_FUNC("(alt)", insn); 3368 3368 return ret; 3369 3369 } ··· 3379 3379 switch (insn->type) { 3380 3380 3381 3381 case INSN_RETURN: 3382 - if (sls && !insn->retpoline_safe && 3382 + if (opts.sls && !insn->retpoline_safe && 3383 3383 next_insn && next_insn->type != INSN_TRAP) { 3384 3384 WARN_FUNC("missing int3 after ret", 3385 3385 insn->sec, insn->offset); ··· 3392 3392 if (ret) 3393 3393 return ret; 3394 3394 3395 - if (!no_fp && func && !is_fentry_call(insn) && 3395 + if (!opts.no_fp && func && !is_fentry_call(insn) && 3396 3396 !has_valid_stack_frame(&state)) { 3397 3397 WARN_FUNC("call without frame pointer save/setup", 3398 3398 sec, insn->offset); ··· 3415 3415 ret = validate_branch(file, func, 3416 3416 insn->jump_dest, state); 3417 3417 if (ret) { 3418 - if (backtrace) 3418 + if (opts.backtrace) 3419 3419 BT_FUNC("(branch)", insn); 3420 3420 return ret; 3421 3421 } ··· 3427 3427 break; 3428 3428 3429 3429 case INSN_JUMP_DYNAMIC: 3430 - if (sls && !insn->retpoline_safe && 3430 + if (opts.sls && !insn->retpoline_safe && 3431 3431 next_insn && next_insn->type != INSN_TRAP) { 3432 3432 WARN_FUNC("missing int3 after indirect jump", 3433 3433 insn->sec, insn->offset); ··· 3499 3499 break; 3500 3500 } 3501 3501 3502 - if (ibt) 3502 + if (opts.ibt) 3503 3503 validate_ibt_insn(file, insn); 3504 3504 3505 3505 if (insn->dead_end) ··· 3541 3541 while (&insn->list != &file->insn_list && (!sec || insn->sec == sec)) { 3542 3542 if (insn->hint && !insn->visited && !insn->ignore) { 3543 3543 ret = validate_branch(file, insn->func, insn, state); 3544 - if (ret && backtrace) 3544 + if (ret && opts.backtrace) 3545 3545 BT_FUNC("<=== (hint)", insn); 3546 3546 warnings += ret; 3547 3547 } ··· 3571 3571 * loaded late, they very much do need retpoline in their 3572 3572 * .init.text 3573 3573 */ 3574 - if (!strcmp(insn->sec->name, ".init.text") && !module) 3574 + if (!strcmp(insn->sec->name, ".init.text") && !opts.module) 3575 3575 continue; 3576 3576 3577 3577 WARN_FUNC("indirect %s found in RETPOLINE build", ··· 3621 3621 * In this case we'll find a piece of code (whole function) that is not 3622 3622 * covered by a !section symbol. Ignore them. 3623 3623 */ 3624 - if (!insn->func && lto) { 3624 + if (!insn->func && opts.lto) { 3625 3625 int size = find_symbol_hole_containing(insn->sec, insn->offset); 3626 3626 unsigned long end = insn->offset + size; 3627 3627 ··· 3728 3728 state->uaccess = sym->uaccess_safe; 3729 3729 3730 3730 ret = validate_branch(file, insn->func, insn, *state); 3731 - if (ret && backtrace) 3731 + if (ret && opts.backtrace) 3732 3732 BT_FUNC("<=== (sym)", insn); 3733 3733 return ret; 3734 3734 } ··· 3853 3853 { 3854 3854 int ret, warnings = 0; 3855 3855 3856 - if (lto && !(vmlinux || module)) { 3856 + if (opts.lto && !(opts.vmlinux || opts.module)) { 3857 3857 fprintf(stderr, "--lto requires: --vmlinux or --module\n"); 3858 3858 return 1; 3859 3859 } 3860 3860 3861 - if (ibt && !lto) { 3861 + if (opts.ibt && !opts.lto) { 3862 3862 fprintf(stderr, "--ibt requires: --lto\n"); 3863 3863 return 1; 3864 3864 } ··· 3883 3883 if (list_empty(&file->insn_list)) 3884 3884 goto out; 3885 3885 3886 - if (vmlinux && !lto) { 3886 + if (opts.vmlinux && !opts.lto) { 3887 3887 ret = validate_vmlinux_functions(file); 3888 3888 if (ret < 0) 3889 3889 goto out; ··· 3892 3892 goto out; 3893 3893 } 3894 3894 3895 - if (retpoline) { 3895 + if (opts.retpoline) { 3896 3896 ret = validate_retpoline(file); 3897 3897 if (ret < 0) 3898 3898 return ret; ··· 3909 3909 goto out; 3910 3910 warnings += ret; 3911 3911 3912 - if (ibt) { 3912 + if (opts.ibt) { 3913 3913 ret = validate_ibt(file); 3914 3914 if (ret < 0) 3915 3915 goto out; ··· 3928 3928 goto out; 3929 3929 warnings += ret; 3930 3930 3931 - if (retpoline) { 3931 + if (opts.retpoline) { 3932 3932 ret = create_retpoline_sites_sections(file); 3933 3933 if (ret < 0) 3934 3934 goto out; 3935 3935 warnings += ret; 3936 3936 } 3937 3937 3938 - if (mcount) { 3938 + if (opts.mcount) { 3939 3939 ret = create_mcount_loc_sections(file); 3940 3940 if (ret < 0) 3941 3941 goto out; 3942 3942 warnings += ret; 3943 3943 } 3944 3944 3945 - if (ibt) { 3945 + if (opts.ibt) { 3946 3946 ret = create_ibt_endbr_seal_sections(file); 3947 3947 if (ret < 0) 3948 3948 goto out; 3949 3949 warnings += ret; 3950 3950 } 3951 3951 3952 - if (stats) { 3952 + if (opts.stats) { 3953 3953 printf("nr_insns_visited: %ld\n", nr_insns_visited); 3954 3954 printf("nr_cfi: %ld\n", nr_cfi); 3955 3955 printf("nr_cfi_reused: %ld\n", nr_cfi_reused);
+4 -4
tools/objtool/elf.c
··· 355 355 elf_hash_add(section_name, &sec->name_hash, str_hash(sec->name)); 356 356 } 357 357 358 - if (stats) { 358 + if (opts.stats) { 359 359 printf("nr_sections: %lu\n", (unsigned long)sections_nr); 360 360 printf("section_bits: %d\n", elf->section_bits); 361 361 } ··· 475 475 elf_add_symbol(elf, sym); 476 476 } 477 477 478 - if (stats) { 478 + if (opts.stats) { 479 479 printf("nr_symbols: %lu\n", (unsigned long)symbols_nr); 480 480 printf("symbol_bits: %d\n", elf->symbol_bits); 481 481 } ··· 843 843 tot_reloc += nr_reloc; 844 844 } 845 845 846 - if (stats) { 846 + if (opts.stats) { 847 847 printf("max_reloc: %lu\n", max_reloc); 848 848 printf("tot_reloc: %lu\n", tot_reloc); 849 849 printf("reloc_bits: %d\n", elf->reloc_bits); ··· 1222 1222 struct section *sec; 1223 1223 Elf_Scn *s; 1224 1224 1225 - if (dryrun) 1225 + if (opts.dryrun) 1226 1226 return 0; 1227 1227 1228 1228 /* Update changed relocation sections and section headers: */
+23 -3
tools/objtool/include/objtool/builtin.h
··· 8 8 #include <subcmd/parse-options.h> 9 9 10 10 extern const struct option check_options[]; 11 - extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, 12 - lto, vmlinux, mcount, noinstr, backup, sls, dryrun, 13 - ibt; 11 + 12 + struct opts { 13 + /* actions: */ 14 + bool ibt; 15 + bool mcount; 16 + bool noinstr; 17 + bool retpoline; 18 + bool sls; 19 + bool uaccess; 20 + 21 + /* options: */ 22 + bool backtrace; 23 + bool backup; 24 + bool dryrun; 25 + bool lto; 26 + bool module; 27 + bool no_fp; 28 + bool no_unreachable; 29 + bool stats; 30 + bool vmlinux; 31 + }; 32 + 33 + extern struct opts opts; 14 34 15 35 extern int cmd_parse_options(int argc, const char **argv, const char * const usage[]); 16 36
+3 -3
tools/objtool/objtool.c
··· 118 118 if (!file.elf) 119 119 return NULL; 120 120 121 - if (backup && !objtool_create_backup(objname)) { 121 + if (opts.backup && !objtool_create_backup(objname)) { 122 122 WARN("can't create backup file"); 123 123 return NULL; 124 124 } ··· 129 129 INIT_LIST_HEAD(&file.static_call_list); 130 130 INIT_LIST_HEAD(&file.mcount_loc_list); 131 131 INIT_LIST_HEAD(&file.endbr_list); 132 - file.ignore_unreachables = no_unreachable; 132 + file.ignore_unreachables = opts.no_unreachable; 133 133 file.hints = false; 134 134 135 135 return &file; ··· 137 137 138 138 void objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func) 139 139 { 140 - if (!noinstr) 140 + if (!opts.noinstr) 141 141 return; 142 142 143 143 if (!f->pv_ops) {