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 <unistd.h> 21 #include <subcmd/exec-cmd.h> 22 #include <subcmd/pager.h> 23 #include <linux/kernel.h> 24 25 #include <objtool/builtin.h> 26 #include <objtool/objtool.h> 27 #include <objtool/warn.h> 28 29 struct cmd_struct { 30 const char *name; 31 int (*fn)(int, const char **); 32 const char *help; 33 }; 34 35 static const char objtool_usage_string[] = 36 "objtool COMMAND [ARGS]"; 37 38 static struct cmd_struct objtool_cmds[] = { 39 {"check", cmd_check, "Perform stack metadata validation on an object file" }, 40 {"orc", cmd_orc, "Generate in-place ORC unwind tables for an object file" }, 41 }; 42 43 bool help; 44 45 const char *objname; 46 static struct objtool_file file; 47 48 static bool objtool_create_backup(const char *_objname) 49 { 50 int len = strlen(_objname); 51 char *buf, *base, *name = malloc(len+6); 52 int s, d, l, t; 53 54 if (!name) { 55 perror("failed backup name malloc"); 56 return false; 57 } 58 59 strcpy(name, _objname); 60 strcpy(name + len, ".orig"); 61 62 d = open(name, O_CREAT|O_WRONLY|O_TRUNC, 0644); 63 if (d < 0) { 64 perror("failed to create backup file"); 65 return false; 66 } 67 68 s = open(_objname, O_RDONLY); 69 if (s < 0) { 70 perror("failed to open orig file"); 71 return false; 72 } 73 74 buf = malloc(4096); 75 if (!buf) { 76 perror("failed backup data malloc"); 77 return false; 78 } 79 80 while ((l = read(s, buf, 4096)) > 0) { 81 base = buf; 82 do { 83 t = write(d, base, l); 84 if (t < 0) { 85 perror("failed backup write"); 86 return false; 87 } 88 base += t; 89 l -= t; 90 } while (l); 91 } 92 93 if (l < 0) { 94 perror("failed backup read"); 95 return false; 96 } 97 98 free(name); 99 free(buf); 100 close(d); 101 close(s); 102 103 return true; 104 } 105 106 struct objtool_file *objtool_open_read(const char *_objname) 107 { 108 if (objname) { 109 if (strcmp(objname, _objname)) { 110 WARN("won't handle more than one file at a time"); 111 return NULL; 112 } 113 return &file; 114 } 115 objname = _objname; 116 117 file.elf = elf_open_read(objname, O_RDWR); 118 if (!file.elf) 119 return NULL; 120 121 if (backup && !objtool_create_backup(objname)) { 122 WARN("can't create backup file"); 123 return NULL; 124 } 125 126 INIT_LIST_HEAD(&file.insn_list); 127 hash_init(file.insn_hash); 128 INIT_LIST_HEAD(&file.retpoline_call_list); 129 INIT_LIST_HEAD(&file.static_call_list); 130 INIT_LIST_HEAD(&file.mcount_loc_list); 131 file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment"); 132 file.ignore_unreachables = no_unreachable; 133 file.hints = false; 134 135 return &file; 136 } 137 138 static void cmd_usage(void) 139 { 140 unsigned int i, longest = 0; 141 142 printf("\n usage: %s\n\n", objtool_usage_string); 143 144 for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 145 if (longest < strlen(objtool_cmds[i].name)) 146 longest = strlen(objtool_cmds[i].name); 147 } 148 149 puts(" Commands:"); 150 for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 151 printf(" %-*s ", longest, objtool_cmds[i].name); 152 puts(objtool_cmds[i].help); 153 } 154 155 printf("\n"); 156 157 if (!help) 158 exit(129); 159 exit(0); 160 } 161 162 static void handle_options(int *argc, const char ***argv) 163 { 164 while (*argc > 0) { 165 const char *cmd = (*argv)[0]; 166 167 if (cmd[0] != '-') 168 break; 169 170 if (!strcmp(cmd, "--help") || !strcmp(cmd, "-h")) { 171 help = true; 172 break; 173 } else { 174 fprintf(stderr, "Unknown option: %s\n", cmd); 175 cmd_usage(); 176 } 177 178 (*argv)++; 179 (*argc)--; 180 } 181 } 182 183 static void handle_internal_command(int argc, const char **argv) 184 { 185 const char *cmd = argv[0]; 186 unsigned int i, ret; 187 188 for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 189 struct cmd_struct *p = objtool_cmds+i; 190 191 if (strcmp(p->name, cmd)) 192 continue; 193 194 ret = p->fn(argc, argv); 195 196 exit(ret); 197 } 198 199 cmd_usage(); 200 } 201 202 int main(int argc, const char **argv) 203 { 204 static const char *UNUSED = "OBJTOOL_NOT_IMPLEMENTED"; 205 206 /* libsubcmd init */ 207 exec_cmd_init("objtool", UNUSED, UNUSED, UNUSED); 208 pager_init(UNUSED); 209 210 argv++; 211 argc--; 212 handle_options(&argc, &argv); 213 214 if (!argc || help) 215 cmd_usage(); 216 217 handle_internal_command(argc, argv); 218 219 return 0; 220 } 221