]> Git Repo - linux.git/blobdiff - tools/perf/util/annotate.c
perf annotate: Pass a 'map_symbol' in places receiving a pair of 'map' and 'symbol...
[linux.git] / tools / perf / util / annotate.c
index e42bf572358c7edd584ad43309f0e02a336dfebd..78ef3cc2eb6680510bb481228555365dda9b0fc3 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/string.h>
 #include <bpf/libbpf.h>
 #include <subcmd/parse-options.h>
+#include <subcmd/run-command.h>
 
 /* FIXME: For the HE_COLORSET */
 #include "ui/browser.h"
@@ -270,7 +271,7 @@ static int call__parse(struct arch *arch, struct ins_operands *ops, struct map_s
 find_target:
        target.addr = map__objdump_2mem(map, ops->target.addr);
 
-       if (map_groups__find_ams(&target) == 0 &&
+       if (map_groups__find_ams(map->groups, &target) == 0 &&
            map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr)
                ops->target.sym = target.sym;
 
@@ -390,7 +391,7 @@ static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_s
         * Actual navigation will come next, with further understanding of how
         * the symbol searching and disassembly should be done.
         */
-       if (map_groups__find_ams(&target) == 0 &&
+       if (map_groups__find_ams(map->groups, &target) == 0 &&
            map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr)
                ops->target.sym = target.sym;
 
@@ -853,6 +854,10 @@ static int __symbol__account_cycles(struct cyc_hist *ch,
                           ch[offset].start < start)
                        return 0;
        }
+
+       if (ch[offset].num < NUM_SPARKS)
+               ch[offset].cycles_spark[ch[offset].num] = cycles;
+
        ch[offset].have_start = have_start;
        ch[offset].start = start;
        ch[offset].cycles += cycles;
@@ -1485,44 +1490,26 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start
  * means that it's not a disassembly line so should be treated differently.
  * The ops.raw part will be parsed further according to type of the instruction.
  */
-static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
+static int symbol__parse_objdump_line(struct symbol *sym,
                                      struct annotate_args *args,
-                                     int *line_nr)
+                                     char *parsed_line, int *line_nr)
 {
        struct map *map = args->ms.map;
        struct annotation *notes = symbol__annotation(sym);
        struct disasm_line *dl;
-       char *line = NULL, *parsed_line, *tmp, *tmp2;
-       size_t line_len;
+       char *tmp;
        s64 line_ip, offset = -1;
        regmatch_t match[2];
 
-       if (getline(&line, &line_len, file) < 0)
-               return -1;
-
-       if (!line)
-               return -1;
-
-       line_ip = -1;
-       parsed_line = strim(line);
-
        /* /filename:linenr ? Save line number and ignore. */
        if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) {
                *line_nr = atoi(parsed_line + match[1].rm_so);
                return 0;
        }
 
-       tmp = skip_spaces(parsed_line);
-       if (*tmp) {
-               /*
-                * Parse hexa addresses followed by ':'
-                */
-               line_ip = strtoull(tmp, &tmp2, 16);
-               if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
-                       line_ip = -1;
-       }
-
-       if (line_ip != -1) {
+       /* Process hex address followed by ':'. */
+       line_ip = strtoull(parsed_line, &tmp, 16);
+       if (parsed_line != tmp && tmp[0] == ':' && tmp[1] != '\0') {
                u64 start = map__rip_2objdump(map, sym->start),
                    end = map__rip_2objdump(map, sym->end);
 
@@ -1530,7 +1517,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
                if ((u64)line_ip < start || (u64)line_ip >= end)
                        offset = -1;
                else
-                       parsed_line = tmp2 + 1;
+                       parsed_line = tmp + 1;
        }
 
        args->offset  = offset;
@@ -1539,7 +1526,6 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
        args->ms.sym  = sym;
 
        dl = disasm_line__new(args);
-       free(line);
        (*line_nr)++;
 
        if (dl == NULL)
@@ -1558,7 +1544,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
                        .addr = dl->ops.target.addr,
                };
 
-               if (!map_groups__find_ams(&target) &&
+               if (!map_groups__find_ams(map->groups, &target) &&
                    target.sym->start == target.al_addr)
                        dl->ops.target.sym = target.sym;
        }
@@ -1597,10 +1583,9 @@ static void delete_last_nop(struct symbol *sym)
        }
 }
 
-int symbol__strerror_disassemble(struct symbol *sym __maybe_unused, struct map *map,
-                             int errnum, char *buf, size_t buflen)
+int symbol__strerror_disassemble(struct map_symbol *ms, int errnum, char *buf, size_t buflen)
 {
-       struct dso *dso = map->dso;
+       struct dso *dso = ms->map->dso;
 
        BUG_ON(buflen == 0);
 
@@ -1857,6 +1842,67 @@ static int symbol__disassemble_bpf(struct symbol *sym __maybe_unused,
 }
 #endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
 
+/*
+ * Possibly create a new version of line with tabs expanded. Returns the
+ * existing or new line, storage is updated if a new line is allocated. If
+ * allocation fails then NULL is returned.
+ */
+static char *expand_tabs(char *line, char **storage, size_t *storage_len)
+{
+       size_t i, src, dst, len, new_storage_len, num_tabs;
+       char *new_line;
+       size_t line_len = strlen(line);
+
+       for (num_tabs = 0, i = 0; i < line_len; i++)
+               if (line[i] == '\t')
+                       num_tabs++;
+
+       if (num_tabs == 0)
+               return line;
+
+       /*
+        * Space for the line and '\0', less the leading and trailing
+        * spaces. Each tab may introduce 7 additional spaces.
+        */
+       new_storage_len = line_len + 1 + (num_tabs * 7);
+
+       new_line = malloc(new_storage_len);
+       if (new_line == NULL) {
+               pr_err("Failure allocating memory for tab expansion\n");
+               return NULL;
+       }
+
+       /*
+        * Copy regions starting at src and expand tabs. If there are two
+        * adjacent tabs then 'src == i', the memcpy is of size 0 and the spaces
+        * are inserted.
+        */
+       for (i = 0, src = 0, dst = 0; i < line_len && num_tabs; i++) {
+               if (line[i] == '\t') {
+                       len = i - src;
+                       memcpy(&new_line[dst], &line[src], len);
+                       dst += len;
+                       new_line[dst++] = ' ';
+                       while (dst % 8 != 0)
+                               new_line[dst++] = ' ';
+                       src = i + 1;
+                       num_tabs--;
+               }
+       }
+
+       /* Expand the last region. */
+       len = line_len - src;
+       memcpy(&new_line[dst], &line[src], len);
+       dst += len;
+       new_line[dst] = '\0';
+
+       free(*storage);
+       *storage = new_line;
+       *storage_len = new_storage_len;
+       return new_line;
+
+}
+
 static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
 {
        struct annotation_options *opts = args->options;
@@ -1868,10 +1914,19 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
        struct kcore_extract kce;
        bool delete_extract = false;
        bool decomp = false;
-       int stdout_fd[2];
        int lineno = 0;
        int nline;
-       pid_t pid;
+       char *line;
+       size_t line_len;
+       const char *objdump_argv[] = {
+               "/bin/sh",
+               "-c",
+               NULL, /* Will be the objdump command to run. */
+               "--",
+               NULL, /* Will be the symfs path. */
+               NULL,
+       };
+       struct child_process objdump_process;
        int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename));
 
        if (err)
@@ -1901,7 +1956,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
 
                if (dso__decompress_kmodule_path(dso, symfs_filename,
                                                 tmp, sizeof(tmp)) < 0)
-                       goto out;
+                       return -1;
 
                decomp = true;
                strcpy(symfs_filename, tmp);
@@ -1910,13 +1965,13 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
        err = asprintf(&command,
                 "%s %s%s --start-address=0x%016" PRIx64
                 " --stop-address=0x%016" PRIx64
-                " -l -d %s %s -C \"$1\" 2>/dev/null|grep -v \"$1:\"|expand",
+                " -l -d %s %s -C \"$1\"",
                 opts->objdump_path ?: "objdump",
                 opts->disassembler_style ? "-M " : "",
                 opts->disassembler_style ?: "",
                 map__rip_2objdump(map, sym->start),
                 map__rip_2objdump(map, sym->end),
-                opts->show_asm_raw ? "" : "--no-show-raw",
+                opts->show_asm_raw ? "" : "--no-show-raw-insn",
                 opts->annotate_src ? "-S" : "");
 
        if (err < 0) {
@@ -1926,55 +1981,73 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
 
        pr_debug("Executing: %s\n", command);
 
-       err = -1;
-       if (pipe(stdout_fd) < 0) {
-               pr_err("Failure creating the pipe to run %s\n", command);
-               goto out_free_command;
-       }
-
-       pid = fork();
-       if (pid < 0) {
-               pr_err("Failure forking to run %s\n", command);
-               goto out_close_stdout;
-       }
+       objdump_argv[2] = command;
+       objdump_argv[4] = symfs_filename;
 
-       if (pid == 0) {
-               close(stdout_fd[0]);
-               dup2(stdout_fd[1], 1);
-               close(stdout_fd[1]);
-               execl("/bin/sh", "sh", "-c", command, "--", symfs_filename,
-                     NULL);
-               perror(command);
-               exit(-1);
+       /* Create a pipe to read from for stdout */
+       memset(&objdump_process, 0, sizeof(objdump_process));
+       objdump_process.argv = objdump_argv;
+       objdump_process.out = -1;
+       if (start_command(&objdump_process)) {
+               pr_err("Failure starting to run %s\n", command);
+               err = -1;
+               goto out_free_command;
        }
 
-       close(stdout_fd[1]);
-
-       file = fdopen(stdout_fd[0], "r");
+       file = fdopen(objdump_process.out, "r");
        if (!file) {
                pr_err("Failure creating FILE stream for %s\n", command);
                /*
                 * If we were using debug info should retry with
                 * original binary.
                 */
-               goto out_free_command;
+               err = -1;
+               goto out_close_stdout;
        }
 
+       /* Storage for getline. */
+       line = NULL;
+       line_len = 0;
+
        nline = 0;
        while (!feof(file)) {
+               const char *match;
+               char *expanded_line;
+
+               if (getline(&line, &line_len, file) < 0 || !line)
+                       break;
+
+               /* Skip lines containing "filename:" */
+               match = strstr(line, symfs_filename);
+               if (match && match[strlen(symfs_filename)] == ':')
+                       continue;
+
+               expanded_line = strim(line);
+               expanded_line = expand_tabs(expanded_line, &line, &line_len);
+               if (!expanded_line)
+                       break;
+
                /*
                 * The source code line number (lineno) needs to be kept in
                 * across calls to symbol__parse_objdump_line(), so that it
                 * can associate it with the instructions till the next one.
                 * See disasm_line__new() and struct disasm_line::line_nr.
                 */
-               if (symbol__parse_objdump_line(sym, file, args, &lineno) < 0)
+               if (symbol__parse_objdump_line(sym, args, expanded_line,
+                                              &lineno) < 0)
                        break;
                nline++;
        }
+       free(line);
 
-       if (nline == 0)
+       err = finish_command(&objdump_process);
+       if (err)
+               pr_err("Error running %s\n", command);
+
+       if (nline == 0) {
+               err = -1;
                pr_err("No output from %s\n", command);
+       }
 
        /*
         * kallsyms does not have symbol sizes so there may a nop at the end.
@@ -1984,23 +2057,21 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
                delete_last_nop(sym);
 
        fclose(file);
-       err = 0;
+
+out_close_stdout:
+       close(objdump_process.out);
+
 out_free_command:
        free(command);
-out_remove_tmp:
-       close(stdout_fd[0]);
 
+out_remove_tmp:
        if (decomp)
                unlink(symfs_filename);
 
        if (delete_extract)
                kcore_extract__delete(&kce);
-out:
-       return err;
 
-out_close_stdout:
-       close(stdout_fd[1]);
-       goto out_free_command;
+       return err;
 }
 
 static void calc_percent(struct sym_hist *sym_hist,
@@ -2071,11 +2142,10 @@ void symbol__calc_percent(struct symbol *sym, struct evsel *evsel)
        annotation__calc_percent(notes, evsel, symbol__size(sym));
 }
 
-int symbol__annotate(struct symbol *sym, struct map *map,
-                    struct evsel *evsel, size_t privsize,
-                    struct annotation_options *options,
-                    struct arch **parch)
+int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, size_t privsize,
+                    struct annotation_options *options, struct arch **parch)
 {
+       struct symbol *sym = ms->sym;
        struct annotation *notes = symbol__annotation(sym);
        struct annotate_args args = {
                .privsize       = privsize,
@@ -2105,9 +2175,8 @@ int symbol__annotate(struct symbol *sym, struct map *map,
                }
        }
 
-       args.ms.map = map;
-       args.ms.sym = sym;
-       notes->start = map__rip_2objdump(map, sym->start);
+       args.ms = *ms;
+       notes->start = map__rip_2objdump(ms->map, sym->start);
 
        return symbol__disassemble(sym, &args);
 }
@@ -2263,10 +2332,11 @@ static int annotated_source__addr_fmt_width(struct list_head *lines, u64 start)
        return 0;
 }
 
-int symbol__annotate_printf(struct symbol *sym, struct map *map,
-                           struct evsel *evsel,
+int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel,
                            struct annotation_options *opts)
 {
+       struct map *map = ms->map;
+       struct symbol *sym = ms->sym;
        struct dso *dso = map->dso;
        char *filename;
        const char *d_filename;
@@ -2670,30 +2740,29 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map,
        resort_source_line(root, &tmp_root);
 }
 
-static void symbol__calc_lines(struct symbol *sym, struct map *map,
-                              struct rb_root *root,
+static void symbol__calc_lines(struct map_symbol *ms, struct rb_root *root,
                               struct annotation_options *opts)
 {
-       struct annotation *notes = symbol__annotation(sym);
+       struct annotation *notes = symbol__annotation(ms->sym);
 
-       annotation__calc_lines(notes, map, root, opts);
+       annotation__calc_lines(notes, ms->map, root, opts);
 }
 
-int symbol__tty_annotate2(struct symbol *sym, struct map *map,
-                         struct evsel *evsel,
+int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel,
                          struct annotation_options *opts)
 {
-       struct dso *dso = map->dso;
+       struct dso *dso = ms->map->dso;
+       struct symbol *sym = ms->sym;
        struct rb_root source_line = RB_ROOT;
        struct hists *hists = evsel__hists(evsel);
        char buf[1024];
 
-       if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0)
+       if (symbol__annotate2(ms, evsel, opts, NULL) < 0)
                return -1;
 
        if (opts->print_lines) {
                srcline_full_filename = opts->full_path;
-               symbol__calc_lines(sym, map, &source_line, opts);
+               symbol__calc_lines(ms, &source_line, opts);
                print_summary(&source_line, dso->long_name);
        }
 
@@ -2707,25 +2776,25 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map,
        return 0;
 }
 
-int symbol__tty_annotate(struct symbol *sym, struct map *map,
-                        struct evsel *evsel,
+int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel,
                         struct annotation_options *opts)
 {
-       struct dso *dso = map->dso;
+       struct dso *dso = ms->map->dso;
+       struct symbol *sym = ms->sym;
        struct rb_root source_line = RB_ROOT;
 
-       if (symbol__annotate(sym, map, evsel, 0, opts, NULL) < 0)
+       if (symbol__annotate(ms, evsel, 0, opts, NULL) < 0)
                return -1;
 
        symbol__calc_percent(sym, evsel);
 
        if (opts->print_lines) {
                srcline_full_filename = opts->full_path;
-               symbol__calc_lines(sym, map, &source_line, opts);
+               symbol__calc_lines(ms, &source_line, opts);
                print_summary(&source_line, dso->long_name);
        }
 
-       symbol__annotate_printf(sym, map, evsel, opts);
+       symbol__annotate_printf(ms, evsel, opts);
 
        annotated_source__purge(symbol__annotation(sym)->src);
 
@@ -2979,9 +3048,10 @@ void annotation_line__write(struct annotation_line *al, struct annotation *notes
                                 wops->write_graph);
 }
 
-int symbol__annotate2(struct symbol *sym, struct map *map, struct evsel *evsel,
+int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel,
                      struct annotation_options *options, struct arch **parch)
 {
+       struct symbol *sym = ms->sym;
        struct annotation *notes = symbol__annotation(sym);
        size_t size = symbol__size(sym);
        int nr_pcnt = 1, err;
@@ -2993,7 +3063,7 @@ int symbol__annotate2(struct symbol *sym, struct map *map, struct evsel *evsel,
        if (perf_evsel__is_group_event(evsel))
                nr_pcnt = evsel->core.nr_members;
 
-       err = symbol__annotate(sym, map, evsel, 0, options, parch);
+       err = symbol__annotate(ms, evsel, 0, options, parch);
        if (err)
                goto out_free_offsets;
 
This page took 0.048237 seconds and 4 git commands to generate.