diff options
Diffstat (limited to 'tools/objtool/objtool.c')
-rw-r--r-- | tools/objtool/objtool.c | 176 |
1 files changed, 101 insertions, 75 deletions
diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c index 58fdda510653..f40febdd6e36 100644 --- a/tools/objtool/objtool.c +++ b/tools/objtool/objtool.c @@ -3,104 +3,139 @@ * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> */ -/* - * objtool: - * - * The 'check' subcmd analyzes every .o file and ensures the validity of its - * stack trace metadata. It enforces a set of rules on asm code and C inline - * assembly code so that stack traces can be reliable. - * - * For more information, see tools/objtool/Documentation/stack-validation.txt. - */ - #include <stdio.h> #include <stdbool.h> #include <string.h> #include <stdlib.h> +#include <unistd.h> #include <subcmd/exec-cmd.h> #include <subcmd/pager.h> #include <linux/kernel.h> -#include "builtin.h" +#include <objtool/builtin.h> +#include <objtool/objtool.h> +#include <objtool/warn.h> -struct cmd_struct { - const char *name; - int (*fn)(int, const char **); - const char *help; -}; +bool help; -static const char objtool_usage_string[] = - "objtool COMMAND [ARGS]"; +const char *objname; +static struct objtool_file file; -static struct cmd_struct objtool_cmds[] = { - {"check", cmd_check, "Perform stack metadata validation on an object file" }, - {"orc", cmd_orc, "Generate in-place ORC unwind tables for an object file" }, -}; +static bool objtool_create_backup(const char *_objname) +{ + int len = strlen(_objname); + char *buf, *base, *name = malloc(len+6); + int s, d, l, t; -bool help; + if (!name) { + perror("failed backup name malloc"); + return false; + } -static void cmd_usage(void) -{ - unsigned int i, longest = 0; + strcpy(name, _objname); + strcpy(name + len, ".orig"); + + d = open(name, O_CREAT|O_WRONLY|O_TRUNC, 0644); + if (d < 0) { + perror("failed to create backup file"); + return false; + } + + s = open(_objname, O_RDONLY); + if (s < 0) { + perror("failed to open orig file"); + return false; + } - printf("\n usage: %s\n\n", objtool_usage_string); + buf = malloc(4096); + if (!buf) { + perror("failed backup data malloc"); + return false; + } - for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { - if (longest < strlen(objtool_cmds[i].name)) - longest = strlen(objtool_cmds[i].name); + while ((l = read(s, buf, 4096)) > 0) { + base = buf; + do { + t = write(d, base, l); + if (t < 0) { + perror("failed backup write"); + return false; + } + base += t; + l -= t; + } while (l); } - puts(" Commands:"); - for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { - printf(" %-*s ", longest, objtool_cmds[i].name); - puts(objtool_cmds[i].help); + if (l < 0) { + perror("failed backup read"); + return false; } - printf("\n"); + free(name); + free(buf); + close(d); + close(s); - if (!help) - exit(129); - exit(0); + return true; } -static void handle_options(int *argc, const char ***argv) +struct objtool_file *objtool_open_read(const char *_objname) { - while (*argc > 0) { - const char *cmd = (*argv)[0]; - - if (cmd[0] != '-') - break; - - if (!strcmp(cmd, "--help") || !strcmp(cmd, "-h")) { - help = true; - break; - } else { - fprintf(stderr, "Unknown option: %s\n", cmd); - cmd_usage(); + if (objname) { + if (strcmp(objname, _objname)) { + WARN("won't handle more than one file at a time"); + return NULL; } + return &file; + } + objname = _objname; - (*argv)++; - (*argc)--; + file.elf = elf_open_read(objname, O_RDWR); + if (!file.elf) + return NULL; + + if (opts.backup && !objtool_create_backup(objname)) { + WARN("can't create backup file"); + return NULL; } + + hash_init(file.insn_hash); + INIT_LIST_HEAD(&file.retpoline_call_list); + INIT_LIST_HEAD(&file.return_thunk_list); + INIT_LIST_HEAD(&file.static_call_list); + INIT_LIST_HEAD(&file.mcount_loc_list); + INIT_LIST_HEAD(&file.endbr_list); + INIT_LIST_HEAD(&file.call_list); + file.ignore_unreachables = opts.no_unreachable; + file.hints = false; + + return &file; } -static void handle_internal_command(int argc, const char **argv) +void objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func) { - const char *cmd = argv[0]; - unsigned int i, ret; - - for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { - struct cmd_struct *p = objtool_cmds+i; + if (!opts.noinstr) + return; - if (strcmp(p->name, cmd)) - continue; + if (!f->pv_ops) { + WARN("paravirt confusion"); + return; + } - ret = p->fn(argc, argv); + /* + * These functions will be patched into native code, + * see paravirt_patch(). + */ + if (!strcmp(func->name, "_paravirt_nop") || + !strcmp(func->name, "_paravirt_ident_64")) + return; - exit(ret); - } + /* already added this function */ + if (!list_empty(&func->pv_target)) + return; - cmd_usage(); + list_add(&func->pv_target, &f->pv_ops[idx].targets); + f->pv_ops[idx].clean = false; } int main(int argc, const char **argv) @@ -111,14 +146,5 @@ int main(int argc, const char **argv) exec_cmd_init("objtool", UNUSED, UNUSED, UNUSED); pager_init(UNUSED); - argv++; - argc--; - handle_options(&argc, &argv); - - if (!argc || help) - cmd_usage(); - - handle_internal_command(argc, argv); - - return 0; + return objtool_run(argc, argv); } |