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