1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> 4 */ 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 #include <stdio.h> 17 #include <stdbool.h> 18 #include <string.h> 19 #include <stdlib.h> 20 #include <subcmd/exec-cmd.h> 21 #include <subcmd/pager.h> 22 #include <linux/kernel.h> 23 24 #include <objtool/builtin.h> 25 #include <objtool/objtool.h> 26 #include <objtool/warn.h> 27 28 struct cmd_struct { 29 const char *name; 30 int (*fn)(int, const char **); 31 const char *help; 32 }; 33 34 static const char objtool_usage_string[] = 35 "objtool COMMAND [ARGS]"; 36 37 static struct cmd_struct objtool_cmds[] = { 38 {"check", cmd_check, "Perform stack metadata validation on an object file" }, 39 {"orc", cmd_orc, "Generate in-place ORC unwind tables for an object file" }, 40 }; 41 42 bool help; 43 44 const char *objname; 45 static struct objtool_file file; 46 47 struct objtool_file *objtool_open_read(const char *_objname) 48 { 49 if (objname) { 50 if (strcmp(objname, _objname)) { 51 WARN("won't handle more than one file at a time"); 52 return NULL; 53 } 54 return &file; 55 } 56 objname = _objname; 57 58 file.elf = elf_open_read(objname, O_RDWR); 59 if (!file.elf) 60 return NULL; 61 62 INIT_LIST_HEAD(&file.insn_list); 63 hash_init(file.insn_hash); 64 INIT_LIST_HEAD(&file.static_call_list); 65 file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment"); 66 file.ignore_unreachables = no_unreachable; 67 file.hints = false; 68 69 return &file; 70 } 71 72 static void cmd_usage(void) 73 { 74 unsigned int i, longest = 0; 75 76 printf("\n usage: %s\n\n", objtool_usage_string); 77 78 for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 79 if (longest < strlen(objtool_cmds[i].name)) 80 longest = strlen(objtool_cmds[i].name); 81 } 82 83 puts(" Commands:"); 84 for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 85 printf(" %-*s ", longest, objtool_cmds[i].name); 86 puts(objtool_cmds[i].help); 87 } 88 89 printf("\n"); 90 91 if (!help) 92 exit(129); 93 exit(0); 94 } 95 96 static void handle_options(int *argc, const char ***argv) 97 { 98 while (*argc > 0) { 99 const char *cmd = (*argv)[0]; 100 101 if (cmd[0] != '-') 102 break; 103 104 if (!strcmp(cmd, "--help") || !strcmp(cmd, "-h")) { 105 help = true; 106 break; 107 } else { 108 fprintf(stderr, "Unknown option: %s\n", cmd); 109 cmd_usage(); 110 } 111 112 (*argv)++; 113 (*argc)--; 114 } 115 } 116 117 static void handle_internal_command(int argc, const char **argv) 118 { 119 const char *cmd = argv[0]; 120 unsigned int i, ret; 121 122 for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 123 struct cmd_struct *p = objtool_cmds+i; 124 125 if (strcmp(p->name, cmd)) 126 continue; 127 128 ret = p->fn(argc, argv); 129 130 exit(ret); 131 } 132 133 cmd_usage(); 134 } 135 136 int main(int argc, const char **argv) 137 { 138 static const char *UNUSED = "OBJTOOL_NOT_IMPLEMENTED"; 139 140 /* libsubcmd init */ 141 exec_cmd_init("objtool", UNUSED, UNUSED, UNUSED); 142 pager_init(UNUSED); 143 144 argv++; 145 argc--; 146 handle_options(&argc, &argv); 147 148 if (!argc || help) 149 cmd_usage(); 150 151 handle_internal_command(argc, argv); 152 153 return 0; 154 } 155