linux/tools/perf/util/annotate.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
   3 *
   4 * Parts came from builtin-annotate.c, see those files for further
   5 * copyright notes.
   6 *
   7 * Released under the GPL v2. (and only v2, not any later version)
   8 */
   9
  10#include "util.h"
  11#include "build-id.h"
  12#include "color.h"
  13#include "cache.h"
  14#include "symbol.h"
  15#include "debug.h"
  16#include "annotate.h"
  17#include <pthread.h>
  18
  19const char      *disassembler_style;
  20
  21int symbol__annotate_init(struct map *map __used, struct symbol *sym)
  22{
  23        struct annotation *notes = symbol__annotation(sym);
  24        pthread_mutex_init(&notes->lock, NULL);
  25        return 0;
  26}
  27
  28int symbol__alloc_hist(struct symbol *sym)
  29{
  30        struct annotation *notes = symbol__annotation(sym);
  31        size_t sizeof_sym_hist = (sizeof(struct sym_hist) +
  32                                  (sym->end - sym->start) * sizeof(u64));
  33
  34        notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
  35        if (notes->src == NULL)
  36                return -1;
  37        notes->src->sizeof_sym_hist = sizeof_sym_hist;
  38        notes->src->nr_histograms   = symbol_conf.nr_events;
  39        INIT_LIST_HEAD(&notes->src->source);
  40        return 0;
  41}
  42
  43void symbol__annotate_zero_histograms(struct symbol *sym)
  44{
  45        struct annotation *notes = symbol__annotation(sym);
  46
  47        pthread_mutex_lock(&notes->lock);
  48        if (notes->src != NULL)
  49                memset(notes->src->histograms, 0,
  50                       notes->src->nr_histograms * notes->src->sizeof_sym_hist);
  51        pthread_mutex_unlock(&notes->lock);
  52}
  53
  54int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
  55                             int evidx, u64 addr)
  56{
  57        unsigned offset;
  58        struct annotation *notes;
  59        struct sym_hist *h;
  60
  61        notes = symbol__annotation(sym);
  62        if (notes->src == NULL)
  63                return -ENOMEM;
  64
  65        pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
  66
  67        if (addr >= sym->end)
  68                return 0;
  69
  70        offset = addr - sym->start;
  71        h = annotation__histogram(notes, evidx);
  72        h->sum++;
  73        h->addr[offset]++;
  74
  75        pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
  76                  ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name,
  77                  addr, addr - sym->start, evidx, h->addr[offset]);
  78        return 0;
  79}
  80
  81static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
  82{
  83        struct objdump_line *self = malloc(sizeof(*self) + privsize);
  84
  85        if (self != NULL) {
  86                self->offset = offset;
  87                self->line = line;
  88        }
  89
  90        return self;
  91}
  92
  93void objdump_line__free(struct objdump_line *self)
  94{
  95        free(self->line);
  96        free(self);
  97}
  98
  99static void objdump__add_line(struct list_head *head, struct objdump_line *line)
 100{
 101        list_add_tail(&line->node, head);
 102}
 103
 104struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
 105                                               struct objdump_line *pos)
 106{
 107        list_for_each_entry_continue(pos, head, node)
 108                if (pos->offset >= 0)
 109                        return pos;
 110
 111        return NULL;
 112}
 113
 114static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
 115                               int evidx, u64 len, int min_pcnt,
 116                               int printed, int max_lines,
 117                               struct objdump_line *queue)
 118{
 119        static const char *prev_line;
 120        static const char *prev_color;
 121
 122        if (oline->offset != -1) {
 123                const char *path = NULL;
 124                unsigned int hits = 0;
 125                double percent = 0.0;
 126                const char *color;
 127                struct annotation *notes = symbol__annotation(sym);
 128                struct source_line *src_line = notes->src->lines;
 129                struct sym_hist *h = annotation__histogram(notes, evidx);
 130                s64 offset = oline->offset;
 131                struct objdump_line *next;
 132
 133                next = objdump__get_next_ip_line(&notes->src->source, oline);
 134
 135                while (offset < (s64)len &&
 136                       (next == NULL || offset < next->offset)) {
 137                        if (src_line) {
 138                                if (path == NULL)
 139                                        path = src_line[offset].path;
 140                                percent += src_line[offset].percent;
 141                        } else
 142                                hits += h->addr[offset];
 143
 144                        ++offset;
 145                }
 146
 147                if (src_line == NULL && h->sum)
 148                        percent = 100.0 * hits / h->sum;
 149
 150                if (percent < min_pcnt)
 151                        return -1;
 152
 153                if (max_lines && printed >= max_lines)
 154                        return 1;
 155
 156                if (queue != NULL) {
 157                        list_for_each_entry_from(queue, &notes->src->source, node) {
 158                                if (queue == oline)
 159                                        break;
 160                                objdump_line__print(queue, sym, evidx, len,
 161                                                    0, 0, 1, NULL);
 162                        }
 163                }
 164
 165                color = get_percent_color(percent);
 166
 167                /*
 168                 * Also color the filename and line if needed, with
 169                 * the same color than the percentage. Don't print it
 170                 * twice for close colored addr with the same filename:line
 171                 */
 172                if (path) {
 173                        if (!prev_line || strcmp(prev_line, path)
 174                                       || color != prev_color) {
 175                                color_fprintf(stdout, color, " %s", path);
 176                                prev_line = path;
 177                                prev_color = color;
 178                        }
 179                }
 180
 181                color_fprintf(stdout, color, " %7.2f", percent);
 182                printf(" :      ");
 183                color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line);
 184        } else if (max_lines && printed >= max_lines)
 185                return 1;
 186        else {
 187                if (queue)
 188                        return -1;
 189
 190                if (!*oline->line)
 191                        printf("         :\n");
 192                else
 193                        printf("         :      %s\n", oline->line);
 194        }
 195
 196        return 0;
 197}
 198
 199static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
 200                                      FILE *file, size_t privsize)
 201{
 202        struct annotation *notes = symbol__annotation(sym);
 203        struct objdump_line *objdump_line;
 204        char *line = NULL, *tmp, *tmp2, *c;
 205        size_t line_len;
 206        s64 line_ip, offset = -1;
 207
 208        if (getline(&line, &line_len, file) < 0)
 209                return -1;
 210
 211        if (!line)
 212                return -1;
 213
 214        while (line_len != 0 && isspace(line[line_len - 1]))
 215                line[--line_len] = '\0';
 216
 217        c = strchr(line, '\n');
 218        if (c)
 219                *c = 0;
 220
 221        line_ip = -1;
 222
 223        /*
 224         * Strip leading spaces:
 225         */
 226        tmp = line;
 227        while (*tmp) {
 228                if (*tmp != ' ')
 229                        break;
 230                tmp++;
 231        }
 232
 233        if (*tmp) {
 234                /*
 235                 * Parse hexa addresses followed by ':'
 236                 */
 237                line_ip = strtoull(tmp, &tmp2, 16);
 238                if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
 239                        line_ip = -1;
 240        }
 241
 242        if (line_ip != -1) {
 243                u64 start = map__rip_2objdump(map, sym->start),
 244                    end = map__rip_2objdump(map, sym->end);
 245
 246                offset = line_ip - start;
 247                if (offset < 0 || (u64)line_ip > end)
 248                        offset = -1;
 249        }
 250
 251        objdump_line = objdump_line__new(offset, line, privsize);
 252        if (objdump_line == NULL) {
 253                free(line);
 254                return -1;
 255        }
 256        objdump__add_line(&notes->src->source, objdump_line);
 257
 258        return 0;
 259}
 260
 261int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
 262{
 263        struct dso *dso = map->dso;
 264        char *filename = dso__build_id_filename(dso, NULL, 0);
 265        bool free_filename = true;
 266        char command[PATH_MAX * 2];
 267        FILE *file;
 268        int err = 0;
 269        char symfs_filename[PATH_MAX];
 270
 271        if (filename) {
 272                snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
 273                         symbol_conf.symfs, filename);
 274        }
 275
 276        if (filename == NULL) {
 277                if (dso->has_build_id) {
 278                        pr_err("Can't annotate %s: not enough memory\n",
 279                               sym->name);
 280                        return -ENOMEM;
 281                }
 282                goto fallback;
 283        } else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
 284                   strstr(command, "[kernel.kallsyms]") ||
 285                   access(symfs_filename, R_OK)) {
 286                free(filename);
 287fallback:
 288                /*
 289                 * If we don't have build-ids or the build-id file isn't in the
 290                 * cache, or is just a kallsyms file, well, lets hope that this
 291                 * DSO is the same as when 'perf record' ran.
 292                 */
 293                filename = dso->long_name;
 294                snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
 295                         symbol_conf.symfs, filename);
 296                free_filename = false;
 297        }
 298
 299        if (dso->symtab_type == SYMTAB__KALLSYMS) {
 300                char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
 301                char *build_id_msg = NULL;
 302
 303                if (dso->annotate_warned)
 304                        goto out_free_filename;
 305
 306                if (dso->has_build_id) {
 307                        build_id__sprintf(dso->build_id,
 308                                          sizeof(dso->build_id), bf + 15);
 309                        build_id_msg = bf;
 310                }
 311                err = -ENOENT;
 312                dso->annotate_warned = 1;
 313                pr_err("Can't annotate %s:\n\n"
 314                       "No vmlinux file%s\nwas found in the path.\n\n"
 315                       "Please use:\n\n"
 316                       "  perf buildid-cache -av vmlinux\n\n"
 317                       "or:\n\n"
 318                       "  --vmlinux vmlinux",
 319                       sym->name, build_id_msg ?: "");
 320                goto out_free_filename;
 321        }
 322
 323        pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
 324                 filename, sym->name, map->unmap_ip(map, sym->start),
 325                 map->unmap_ip(map, sym->end));
 326
 327        pr_debug("annotating [%p] %30s : [%p] %30s\n",
 328                 dso, dso->long_name, sym, sym->name);
 329
 330        snprintf(command, sizeof(command),
 331                 "objdump %s%s --start-address=0x%016" PRIx64
 332                 " --stop-address=0x%016" PRIx64
 333                 " -d %s %s -C %s|grep -v %s|expand",
 334                 disassembler_style ? "-M " : "",
 335                 disassembler_style ? disassembler_style : "",
 336                 map__rip_2objdump(map, sym->start),
 337                 map__rip_2objdump(map, sym->end+1),
 338                 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
 339                 symbol_conf.annotate_src ? "-S" : "",
 340                 symfs_filename, filename);
 341
 342        pr_debug("Executing: %s\n", command);
 343
 344        file = popen(command, "r");
 345        if (!file)
 346                goto out_free_filename;
 347
 348        while (!feof(file))
 349                if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
 350                        break;
 351
 352        pclose(file);
 353out_free_filename:
 354        if (free_filename)
 355                free(filename);
 356        return err;
 357}
 358
 359static void insert_source_line(struct rb_root *root, struct source_line *src_line)
 360{
 361        struct source_line *iter;
 362        struct rb_node **p = &root->rb_node;
 363        struct rb_node *parent = NULL;
 364
 365        while (*p != NULL) {
 366                parent = *p;
 367                iter = rb_entry(parent, struct source_line, node);
 368
 369                if (src_line->percent > iter->percent)
 370                        p = &(*p)->rb_left;
 371                else
 372                        p = &(*p)->rb_right;
 373        }
 374
 375        rb_link_node(&src_line->node, parent, p);
 376        rb_insert_color(&src_line->node, root);
 377}
 378
 379static void symbol__free_source_line(struct symbol *sym, int len)
 380{
 381        struct annotation *notes = symbol__annotation(sym);
 382        struct source_line *src_line = notes->src->lines;
 383        int i;
 384
 385        for (i = 0; i < len; i++)
 386                free(src_line[i].path);
 387
 388        free(src_line);
 389        notes->src->lines = NULL;
 390}
 391
 392/* Get the filename:line for the colored entries */
 393static int symbol__get_source_line(struct symbol *sym, struct map *map,
 394                                   int evidx, struct rb_root *root, int len,
 395                                   const char *filename)
 396{
 397        u64 start;
 398        int i;
 399        char cmd[PATH_MAX * 2];
 400        struct source_line *src_line;
 401        struct annotation *notes = symbol__annotation(sym);
 402        struct sym_hist *h = annotation__histogram(notes, evidx);
 403
 404        if (!h->sum)
 405                return 0;
 406
 407        src_line = notes->src->lines = calloc(len, sizeof(struct source_line));
 408        if (!notes->src->lines)
 409                return -1;
 410
 411        start = map->unmap_ip(map, sym->start);
 412
 413        for (i = 0; i < len; i++) {
 414                char *path = NULL;
 415                size_t line_len;
 416                u64 offset;
 417                FILE *fp;
 418
 419                src_line[i].percent = 100.0 * h->addr[i] / h->sum;
 420                if (src_line[i].percent <= 0.5)
 421                        continue;
 422
 423                offset = start + i;
 424                sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
 425                fp = popen(cmd, "r");
 426                if (!fp)
 427                        continue;
 428
 429                if (getline(&path, &line_len, fp) < 0 || !line_len)
 430                        goto next;
 431
 432                src_line[i].path = malloc(sizeof(char) * line_len + 1);
 433                if (!src_line[i].path)
 434                        goto next;
 435
 436                strcpy(src_line[i].path, path);
 437                insert_source_line(root, &src_line[i]);
 438
 439        next:
 440                pclose(fp);
 441        }
 442
 443        return 0;
 444}
 445
 446static void print_summary(struct rb_root *root, const char *filename)
 447{
 448        struct source_line *src_line;
 449        struct rb_node *node;
 450
 451        printf("\nSorted summary for file %s\n", filename);
 452        printf("----------------------------------------------\n\n");
 453
 454        if (RB_EMPTY_ROOT(root)) {
 455                printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
 456                return;
 457        }
 458
 459        node = rb_first(root);
 460        while (node) {
 461                double percent;
 462                const char *color;
 463                char *path;
 464
 465                src_line = rb_entry(node, struct source_line, node);
 466                percent = src_line->percent;
 467                color = get_percent_color(percent);
 468                path = src_line->path;
 469
 470                color_fprintf(stdout, color, " %7.2f %s", percent, path);
 471                node = rb_next(node);
 472        }
 473}
 474
 475static void symbol__annotate_hits(struct symbol *sym, int evidx)
 476{
 477        struct annotation *notes = symbol__annotation(sym);
 478        struct sym_hist *h = annotation__histogram(notes, evidx);
 479        u64 len = sym->end - sym->start, offset;
 480
 481        for (offset = 0; offset < len; ++offset)
 482                if (h->addr[offset] != 0)
 483                        printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
 484                               sym->start + offset, h->addr[offset]);
 485        printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
 486}
 487
 488int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
 489                            bool full_paths, int min_pcnt, int max_lines,
 490                            int context)
 491{
 492        struct dso *dso = map->dso;
 493        const char *filename = dso->long_name, *d_filename;
 494        struct annotation *notes = symbol__annotation(sym);
 495        struct objdump_line *pos, *queue = NULL;
 496        int printed = 2, queue_len = 0;
 497        int more = 0;
 498        u64 len;
 499
 500        if (full_paths)
 501                d_filename = filename;
 502        else
 503                d_filename = basename(filename);
 504
 505        len = sym->end - sym->start;
 506
 507        printf(" Percent |      Source code & Disassembly of %s\n", d_filename);
 508        printf("------------------------------------------------\n");
 509
 510        if (verbose)
 511                symbol__annotate_hits(sym, evidx);
 512
 513        list_for_each_entry(pos, &notes->src->source, node) {
 514                if (context && queue == NULL) {
 515                        queue = pos;
 516                        queue_len = 0;
 517                }
 518
 519                switch (objdump_line__print(pos, sym, evidx, len, min_pcnt,
 520                                            printed, max_lines, queue)) {
 521                case 0:
 522                        ++printed;
 523                        if (context) {
 524                                printed += queue_len;
 525                                queue = NULL;
 526                                queue_len = 0;
 527                        }
 528                        break;
 529                case 1:
 530                        /* filtered by max_lines */
 531                        ++more;
 532                        break;
 533                case -1:
 534                default:
 535                        /*
 536                         * Filtered by min_pcnt or non IP lines when
 537                         * context != 0
 538                         */
 539                        if (!context)
 540                                break;
 541                        if (queue_len == context)
 542                                queue = list_entry(queue->node.next, typeof(*queue), node);
 543                        else
 544                                ++queue_len;
 545                        break;
 546                }
 547        }
 548
 549        return more;
 550}
 551
 552void symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
 553{
 554        struct annotation *notes = symbol__annotation(sym);
 555        struct sym_hist *h = annotation__histogram(notes, evidx);
 556
 557        memset(h, 0, notes->src->sizeof_sym_hist);
 558}
 559
 560void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
 561{
 562        struct annotation *notes = symbol__annotation(sym);
 563        struct sym_hist *h = annotation__histogram(notes, evidx);
 564        struct objdump_line *pos;
 565        int len = sym->end - sym->start;
 566
 567        h->sum = 0;
 568
 569        list_for_each_entry(pos, &notes->src->source, node) {
 570                if (pos->offset != -1 && pos->offset < len) {
 571                        h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8;
 572                        h->sum += h->addr[pos->offset];
 573                }
 574        }
 575}
 576
 577void objdump_line_list__purge(struct list_head *head)
 578{
 579        struct objdump_line *pos, *n;
 580
 581        list_for_each_entry_safe(pos, n, head, node) {
 582                list_del(&pos->node);
 583                objdump_line__free(pos);
 584        }
 585}
 586
 587int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
 588                         bool print_lines, bool full_paths, int min_pcnt,
 589                         int max_lines)
 590{
 591        struct dso *dso = map->dso;
 592        const char *filename = dso->long_name;
 593        struct rb_root source_line = RB_ROOT;
 594        u64 len;
 595
 596        if (symbol__annotate(sym, map, 0) < 0)
 597                return -1;
 598
 599        len = sym->end - sym->start;
 600
 601        if (print_lines) {
 602                symbol__get_source_line(sym, map, evidx, &source_line,
 603                                        len, filename);
 604                print_summary(&source_line, filename);
 605        }
 606
 607        symbol__annotate_printf(sym, map, evidx, full_paths,
 608                                min_pcnt, max_lines, 0);
 609        if (print_lines)
 610                symbol__free_source_line(sym, len);
 611
 612        objdump_line_list__purge(&symbol__annotation(sym)->src->source);
 613
 614        return 0;
 615}
 616