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 INIT_LIST_HEAD(&file.mcount_loc_list); 66 file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment"); 67 file.ignore_unreachables = no_unreachable; 68 file.hints = false; 69 70 return &file; 71 } 72 73 static void cmd_usage(void) 74 { 75 unsigned int i, longest = 0; 76 77 printf("\n usage: %s\n\n", objtool_usage_string); 78 79 for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 80 if (longest < strlen(objtool_cmds[i].name)) 81 longest = strlen(objtool_cmds[i].name); 82 } 83 84 puts(" Commands:"); 85 for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 86 printf(" %-*s ", longest, objtool_cmds[i].name); 87 puts(objtool_cmds[i].help); 88 } 89 90 printf("\n"); 91 92 if (!help) 93 exit(129); 94 exit(0); 95 } 96 97 static void handle_options(int *argc, const char ***argv) 98 { 99 while (*argc > 0) { 100 const char *cmd = (*argv)[0]; 101 102 if (cmd[0] != '-') 103 break; 104 105 if (!strcmp(cmd, "--help") || !strcmp(cmd, "-h")) { 106 help = true; 107 break; 108 } else { 109 fprintf(stderr, "Unknown option: %s\n", cmd); 110 cmd_usage(); 111 } 112 113 (*argv)++; 114 (*argc)--; 115 } 116 } 117 118 static void handle_internal_command(int argc, const char **argv) 119 { 120 const char *cmd = argv[0]; 121 unsigned int i, ret; 122 123 for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 124 struct cmd_struct *p = objtool_cmds+i; 125 126 if (strcmp(p->name, cmd)) 127 continue; 128 129 ret = p->fn(argc, argv); 130 131 exit(ret); 132 } 133 134 cmd_usage(); 135 } 136 137 int main(int argc, const char **argv) 138 { 139 static const char *UNUSED = "OBJTOOL_NOT_IMPLEMENTED"; 140 141 /* libsubcmd init */ 142 exec_cmd_init("objtool", UNUSED, UNUSED, UNUSED); 143 pager_init(UNUSED); 144 145 argv++; 146 argc--; 147 handle_options(&argc, &argv); 148 149 if (!argc || help) 150 cmd_usage(); 151 152 handle_internal_command(argc, argv); 153 154 return 0; 155 } 156