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 28struct cmd_struct { 29 const char *name; 30 int (*fn)(int, const char **); 31 const char *help; 32}; 33 34static const char objtool_usage_string[] = 35 "objtool COMMAND [ARGS]"; 36 37static 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 42bool help; 43 44const char *objname; 45static struct objtool_file file; 46 47struct 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 74static 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 98static 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 119static 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 138int 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