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