1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2015 Josh Poimboeuf <[email protected]> 4 */ 5 6 #include <stdio.h> 7 #include <stdbool.h> 8 #include <string.h> 9 #include <stdlib.h> 10 #include <unistd.h> 11 #include <subcmd/exec-cmd.h> 12 #include <subcmd/pager.h> 13 #include <linux/kernel.h> 14 15 #include <objtool/builtin.h> 16 #include <objtool/objtool.h> 17 #include <objtool/warn.h> 18 19 bool help; 20 21 static struct objtool_file file; 22 23 static bool objtool_create_backup(const char *_objname) 24 { 25 int len = strlen(_objname); 26 char *buf, *base, *name = malloc(len+6); 27 int s, d, l, t; 28 29 if (!name) { 30 perror("failed backup name malloc"); 31 return false; 32 } 33 34 strcpy(name, _objname); 35 strcpy(name + len, ".orig"); 36 37 d = open(name, O_CREAT|O_WRONLY|O_TRUNC, 0644); 38 if (d < 0) { 39 perror("failed to create backup file"); 40 return false; 41 } 42 43 s = open(_objname, O_RDONLY); 44 if (s < 0) { 45 perror("failed to open orig file"); 46 return false; 47 } 48 49 buf = malloc(4096); 50 if (!buf) { 51 perror("failed backup data malloc"); 52 return false; 53 } 54 55 while ((l = read(s, buf, 4096)) > 0) { 56 base = buf; 57 do { 58 t = write(d, base, l); 59 if (t < 0) { 60 perror("failed backup write"); 61 return false; 62 } 63 base += t; 64 l -= t; 65 } while (l); 66 } 67 68 if (l < 0) { 69 perror("failed backup read"); 70 return false; 71 } 72 73 free(name); 74 free(buf); 75 close(d); 76 close(s); 77 78 return true; 79 } 80 81 struct objtool_file *objtool_open_read(const char *filename) 82 { 83 if (file.elf) { 84 WARN("won't handle more than one file at a time"); 85 return NULL; 86 } 87 88 file.elf = elf_open_read(filename, O_RDWR); 89 if (!file.elf) 90 return NULL; 91 92 if (opts.backup && !objtool_create_backup(objname)) { 93 WARN("can't create backup file"); 94 return NULL; 95 } 96 97 hash_init(file.insn_hash); 98 INIT_LIST_HEAD(&file.retpoline_call_list); 99 INIT_LIST_HEAD(&file.return_thunk_list); 100 INIT_LIST_HEAD(&file.static_call_list); 101 INIT_LIST_HEAD(&file.mcount_loc_list); 102 INIT_LIST_HEAD(&file.endbr_list); 103 INIT_LIST_HEAD(&file.call_list); 104 file.ignore_unreachables = opts.no_unreachable; 105 file.hints = false; 106 107 return &file; 108 } 109 110 void objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func) 111 { 112 if (!opts.noinstr) 113 return; 114 115 if (!f->pv_ops) { 116 WARN("paravirt confusion"); 117 return; 118 } 119 120 /* 121 * These functions will be patched into native code, 122 * see paravirt_patch(). 123 */ 124 if (!strcmp(func->name, "_paravirt_nop") || 125 !strcmp(func->name, "_paravirt_ident_64")) 126 return; 127 128 /* already added this function */ 129 if (!list_empty(&func->pv_target)) 130 return; 131 132 list_add(&func->pv_target, &f->pv_ops[idx].targets); 133 f->pv_ops[idx].clean = false; 134 } 135 136 int main(int argc, const char **argv) 137 { 138 static const char *UNUSED = "OBJTOOL_NOT_IMPLEMENTED"; 139 140 /* libsubcmd init */ 141 exec_cmd_init("objtool", UNUSED, UNUSED, UNUSED); 142 pager_init(UNUSED); 143 144 return objtool_run(argc, argv); 145 } 146