Merge tag 'perf-core-for-mingo-20160803' of git://git.kernel.org/pub/scm/linux/kernel...
[cascardo/linux.git] / tools / perf / util / annotate.c
index 7e5a1e8..4024d30 100644 (file)
@@ -354,6 +354,15 @@ static struct ins_ops nop_ops = {
        .scnprintf = nop__scnprintf,
 };
 
+static struct ins_ops ret_ops = {
+       .scnprintf = ins__raw_scnprintf,
+};
+
+bool ins__is_ret(const struct ins *ins)
+{
+       return ins->ops == &ret_ops;
+}
+
 static struct ins instructions[] = {
        { .name = "add",   .ops  = &mov_ops, },
        { .name = "addl",  .ops  = &mov_ops, },
@@ -444,6 +453,7 @@ static struct ins instructions[] = {
        { .name = "xadd",  .ops  = &mov_ops, },
        { .name = "xbeginl", .ops  = &jump_ops, },
        { .name = "xbeginq", .ops  = &jump_ops, },
+       { .name = "retq",  .ops  = &ret_ops, },
 };
 
 static int ins__key_cmp(const void *name, const void *insp)
@@ -1113,7 +1123,46 @@ static void delete_last_nop(struct symbol *sym)
        }
 }
 
-int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
+int symbol__strerror_disassemble(struct symbol *sym __maybe_unused, struct map *map,
+                             int errnum, char *buf, size_t buflen)
+{
+       struct dso *dso = map->dso;
+
+       BUG_ON(buflen == 0);
+
+       if (errnum >= 0) {
+               str_error_r(errnum, buf, buflen);
+               return 0;
+       }
+
+       switch (errnum) {
+       case SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX: {
+               char bf[SBUILD_ID_SIZE + 15] = " with build id ";
+               char *build_id_msg = NULL;
+
+               if (dso->has_build_id) {
+                       build_id__sprintf(dso->build_id,
+                                         sizeof(dso->build_id), bf + 15);
+                       build_id_msg = bf;
+               }
+               scnprintf(buf, buflen,
+                         "No vmlinux file%s\nwas found in the path.\n\n"
+                         "Note that annotation using /proc/kcore requires CAP_SYS_RAWIO capability.\n\n"
+                         "Please use:\n\n"
+                         "  perf buildid-cache -vu vmlinux\n\n"
+                         "or:\n\n"
+                         "  --vmlinux vmlinux\n", build_id_msg ?: "");
+       }
+               break;
+       default:
+               scnprintf(buf, buflen, "Internal error: Invalid %d error code\n", errnum);
+               break;
+       }
+
+       return 0;
+}
+
+int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize)
 {
        struct dso *dso = map->dso;
        char *filename = dso__build_id_filename(dso, NULL, 0);
@@ -1124,22 +1173,20 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
        char symfs_filename[PATH_MAX];
        struct kcore_extract kce;
        bool delete_extract = false;
+       int stdout_fd[2];
        int lineno = 0;
        int nline;
+       pid_t pid;
 
        if (filename)
                symbol__join_symfs(symfs_filename, filename);
 
        if (filename == NULL) {
-               if (dso->has_build_id) {
-                       pr_err("Can't annotate %s: not enough memory\n",
-                              sym->name);
-                       return -ENOMEM;
-               }
-               goto fallback;
-       } else if (dso__is_kcore(dso)) {
+               if (dso->has_build_id)
+                       return ENOMEM;
                goto fallback;
-       } else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
+       } else if (dso__is_kcore(dso) ||
+                  readlink(symfs_filename, command, sizeof(command)) < 0 ||
                   strstr(command, DSO__NAME_KALLSYMS) ||
                   access(symfs_filename, R_OK)) {
                free(filename);
@@ -1156,27 +1203,7 @@ fallback:
 
        if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
            !dso__is_kcore(dso)) {
-               char bf[SBUILD_ID_SIZE + 15] = " with build id ";
-               char *build_id_msg = NULL;
-
-               if (dso->annotate_warned)
-                       goto out_free_filename;
-
-               if (dso->has_build_id) {
-                       build_id__sprintf(dso->build_id,
-                                         sizeof(dso->build_id), bf + 15);
-                       build_id_msg = bf;
-               }
-               err = -ENOENT;
-               dso->annotate_warned = 1;
-               pr_err("Can't annotate %s:\n\n"
-                      "No vmlinux file%s\nwas found in the path.\n\n"
-                      "Note that annotation using /proc/kcore requires CAP_SYS_RAWIO capability.\n\n"
-                      "Please use:\n\n"
-                      "  perf buildid-cache -vu vmlinux\n\n"
-                      "or:\n\n"
-                      "  --vmlinux vmlinux\n",
-                      sym->name, build_id_msg ?: "");
+               err = SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX;
                goto out_free_filename;
        }
 
@@ -1248,9 +1275,32 @@ fallback:
 
        pr_debug("Executing: %s\n", command);
 
-       file = popen(command, "r");
+       err = -1;
+       if (pipe(stdout_fd) < 0) {
+               pr_err("Failure creating the pipe to run %s\n", command);
+               goto out_remove_tmp;
+       }
+
+       pid = fork();
+       if (pid < 0) {
+               pr_err("Failure forking to run %s\n", command);
+               goto out_close_stdout;
+       }
+
+       if (pid == 0) {
+               close(stdout_fd[0]);
+               dup2(stdout_fd[1], 1);
+               close(stdout_fd[1]);
+               execl("/bin/sh", "sh", "-c", command, NULL);
+               perror(command);
+               exit(-1);
+       }
+
+       close(stdout_fd[1]);
+
+       file = fdopen(stdout_fd[0], "r");
        if (!file) {
-               pr_err("Failure running %s\n", command);
+               pr_err("Failure creating FILE stream for %s\n", command);
                /*
                 * If we were using debug info should retry with
                 * original binary.
@@ -1276,9 +1326,11 @@ fallback:
        if (dso__is_kcore(dso))
                delete_last_nop(sym);
 
-       pclose(file);
-
+       fclose(file);
+       err = 0;
 out_remove_tmp:
+       close(stdout_fd[0]);
+
        if (dso__needs_decompress(dso))
                unlink(symfs_filename);
 out_free_filename:
@@ -1287,6 +1339,10 @@ out_free_filename:
        if (free_filename)
                free(filename);
        return err;
+
+out_close_stdout:
+       close(stdout_fd[1]);
+       goto out_remove_tmp;
 }
 
 static void insert_source_line(struct rb_root *root, struct source_line *src_line)
@@ -1512,13 +1568,14 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
        const char *d_filename;
        const char *evsel_name = perf_evsel__name(evsel);
        struct annotation *notes = symbol__annotation(sym);
+       struct sym_hist *h = annotation__histogram(notes, evsel->idx);
        struct disasm_line *pos, *queue = NULL;
        u64 start = map__rip_2objdump(map, sym->start);
        int printed = 2, queue_len = 0;
        int more = 0;
        u64 len;
        int width = 8;
-       int namelen, evsel_name_len, graph_dotted_len;
+       int graph_dotted_len;
 
        filename = strdup(dso->long_name);
        if (!filename)
@@ -1530,17 +1587,14 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
                d_filename = basename(filename);
 
        len = symbol__size(sym);
-       namelen = strlen(d_filename);
-       evsel_name_len = strlen(evsel_name);
 
        if (perf_evsel__is_group_event(evsel))
                width *= evsel->nr_members;
 
-       printf(" %-*.*s|        Source code & Disassembly of %s for %s\n",
-              width, width, "Percent", d_filename, evsel_name);
+       graph_dotted_len = printf(" %-*.*s|     Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n",
+              width, width, "Percent", d_filename, evsel_name, h->sum);
 
-       graph_dotted_len = width + namelen + evsel_name_len;
-       printf("-%-*.*s-----------------------------------------\n",
+       printf("%-*.*s----\n",
               graph_dotted_len, graph_dotted_len, graph_dotted_line);
 
        if (verbose)
@@ -1655,7 +1709,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
        struct rb_root source_line = RB_ROOT;
        u64 len;
 
-       if (symbol__annotate(sym, map, 0) < 0)
+       if (symbol__disassemble(sym, map, 0) < 0)
                return -1;
 
        len = symbol__size(sym);
@@ -1676,11 +1730,6 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
        return 0;
 }
 
-int hist_entry__annotate(struct hist_entry *he, size_t privsize)
-{
-       return symbol__annotate(he->ms.sym, he->ms.map, privsize);
-}
-
 bool ui__has_annotation(void)
 {
        return use_browser == 1 && perf_hpp_list.sym;