1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2015 Josh Poimboeuf <[email protected]> 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.static_call_list); 129 INIT_LIST_HEAD(&file.mcount_loc_list); 130 file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment"); 131 file.ignore_unreachables = no_unreachable; 132 file.hints = false; 133 134 return &file; 135 } 136 137 static void cmd_usage(void) 138 { 139 unsigned int i, longest = 0; 140 141 printf("\n usage: %s\n\n", objtool_usage_string); 142 143 for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 144 if (longest < strlen(objtool_cmds[i].name)) 145 longest = strlen(objtool_cmds[i].name); 146 } 147 148 puts(" Commands:"); 149 for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 150 printf(" %-*s ", longest, objtool_cmds[i].name); 151 puts(objtool_cmds[i].help); 152 } 153 154 printf("\n"); 155 156 if (!help) 157 exit(129); 158 exit(0); 159 } 160 161 static void handle_options(int *argc, const char ***argv) 162 { 163 while (*argc > 0) { 164 const char *cmd = (*argv)[0]; 165 166 if (cmd[0] != '-') 167 break; 168 169 if (!strcmp(cmd, "--help") || !strcmp(cmd, "-h")) { 170 help = true; 171 break; 172 } else { 173 fprintf(stderr, "Unknown option: %s\n", cmd); 174 cmd_usage(); 175 } 176 177 (*argv)++; 178 (*argc)--; 179 } 180 } 181 182 static void handle_internal_command(int argc, const char **argv) 183 { 184 const char *cmd = argv[0]; 185 unsigned int i, ret; 186 187 for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 188 struct cmd_struct *p = objtool_cmds+i; 189 190 if (strcmp(p->name, cmd)) 191 continue; 192 193 ret = p->fn(argc, argv); 194 195 exit(ret); 196 } 197 198 cmd_usage(); 199 } 200 201 int main(int argc, const char **argv) 202 { 203 static const char *UNUSED = "OBJTOOL_NOT_IMPLEMENTED"; 204 205 /* libsubcmd init */ 206 exec_cmd_init("objtool", UNUSED, UNUSED, UNUSED); 207 pager_init(UNUSED); 208 209 argv++; 210 argc--; 211 handle_options(&argc, &argv); 212 213 if (!argc || help) 214 cmd_usage(); 215 216 handle_internal_command(argc, argv); 217 218 return 0; 219 } 220