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 19 const char *disassembler_style; 20 21 int symbol__annotate_init(struct map *map __used, struct symbol *sym) 22 { 23 struct annotation *notes = symbol__annotation(sym); 24 pthread_mutex_init(¬es->lock, NULL); 25 return 0; 26 } 27 28 int symbol__alloc_hist(struct symbol *sym, int nevents) 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) + nevents * 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 = nevents; 39 INIT_LIST_HEAD(¬es->src->source); 40 return 0; 41 } 42 43 void symbol__annotate_zero_histograms(struct symbol *sym) 44 { 45 struct annotation *notes = symbol__annotation(sym); 46 47 pthread_mutex_lock(¬es->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(¬es->lock); 52 } 53 54 int 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 81 static 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 93 void objdump_line__free(struct objdump_line *self) 94 { 95 free(self->line); 96 free(self); 97 } 98 99 static void objdump__add_line(struct list_head *head, struct objdump_line *line) 100 { 101 list_add_tail(&line->node, head); 102 } 103 104 struct 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 114 static 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(¬es->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, ¬es->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 199 static 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(¬es->src->source, objdump_line); 257 258 return 0; 259 } 260 261 int 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); 287 fallback: 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: No vmlinux file%s was found in the " 314 "path.\nPlease use 'perf buildid-cache -av vmlinux' or " 315 "--vmlinux vmlinux.\n", 316 sym->name, build_id_msg ?: ""); 317 goto out_free_filename; 318 } 319 320 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, 321 filename, sym->name, map->unmap_ip(map, sym->start), 322 map->unmap_ip(map, sym->end)); 323 324 pr_debug("annotating [%p] %30s : [%p] %30s\n", 325 dso, dso->long_name, sym, sym->name); 326 327 snprintf(command, sizeof(command), 328 "objdump %s%s --start-address=0x%016" PRIx64 329 " --stop-address=0x%016" PRIx64 330 " -d %s %s -C %s|grep -v %s|expand", 331 disassembler_style ? "-M " : "", 332 disassembler_style ? disassembler_style : "", 333 map__rip_2objdump(map, sym->start), 334 map__rip_2objdump(map, sym->end), 335 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw", 336 symbol_conf.annotate_src ? "-S" : "", 337 symfs_filename, filename); 338 339 pr_debug("Executing: %s\n", command); 340 341 file = popen(command, "r"); 342 if (!file) 343 goto out_free_filename; 344 345 while (!feof(file)) 346 if (symbol__parse_objdump_line(sym, map, file, privsize) < 0) 347 break; 348 349 pclose(file); 350 out_free_filename: 351 if (free_filename) 352 free(filename); 353 return err; 354 } 355 356 static void insert_source_line(struct rb_root *root, struct source_line *src_line) 357 { 358 struct source_line *iter; 359 struct rb_node **p = &root->rb_node; 360 struct rb_node *parent = NULL; 361 362 while (*p != NULL) { 363 parent = *p; 364 iter = rb_entry(parent, struct source_line, node); 365 366 if (src_line->percent > iter->percent) 367 p = &(*p)->rb_left; 368 else 369 p = &(*p)->rb_right; 370 } 371 372 rb_link_node(&src_line->node, parent, p); 373 rb_insert_color(&src_line->node, root); 374 } 375 376 static void symbol__free_source_line(struct symbol *sym, int len) 377 { 378 struct annotation *notes = symbol__annotation(sym); 379 struct source_line *src_line = notes->src->lines; 380 int i; 381 382 for (i = 0; i < len; i++) 383 free(src_line[i].path); 384 385 free(src_line); 386 notes->src->lines = NULL; 387 } 388 389 /* Get the filename:line for the colored entries */ 390 static int symbol__get_source_line(struct symbol *sym, struct map *map, 391 int evidx, struct rb_root *root, int len, 392 const char *filename) 393 { 394 u64 start; 395 int i; 396 char cmd[PATH_MAX * 2]; 397 struct source_line *src_line; 398 struct annotation *notes = symbol__annotation(sym); 399 struct sym_hist *h = annotation__histogram(notes, evidx); 400 401 if (!h->sum) 402 return 0; 403 404 src_line = notes->src->lines = calloc(len, sizeof(struct source_line)); 405 if (!notes->src->lines) 406 return -1; 407 408 start = map->unmap_ip(map, sym->start); 409 410 for (i = 0; i < len; i++) { 411 char *path = NULL; 412 size_t line_len; 413 u64 offset; 414 FILE *fp; 415 416 src_line[i].percent = 100.0 * h->addr[i] / h->sum; 417 if (src_line[i].percent <= 0.5) 418 continue; 419 420 offset = start + i; 421 sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); 422 fp = popen(cmd, "r"); 423 if (!fp) 424 continue; 425 426 if (getline(&path, &line_len, fp) < 0 || !line_len) 427 goto next; 428 429 src_line[i].path = malloc(sizeof(char) * line_len + 1); 430 if (!src_line[i].path) 431 goto next; 432 433 strcpy(src_line[i].path, path); 434 insert_source_line(root, &src_line[i]); 435 436 next: 437 pclose(fp); 438 } 439 440 return 0; 441 } 442 443 static void print_summary(struct rb_root *root, const char *filename) 444 { 445 struct source_line *src_line; 446 struct rb_node *node; 447 448 printf("\nSorted summary for file %s\n", filename); 449 printf("----------------------------------------------\n\n"); 450 451 if (RB_EMPTY_ROOT(root)) { 452 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN); 453 return; 454 } 455 456 node = rb_first(root); 457 while (node) { 458 double percent; 459 const char *color; 460 char *path; 461 462 src_line = rb_entry(node, struct source_line, node); 463 percent = src_line->percent; 464 color = get_percent_color(percent); 465 path = src_line->path; 466 467 color_fprintf(stdout, color, " %7.2f %s", percent, path); 468 node = rb_next(node); 469 } 470 } 471 472 static void symbol__annotate_hits(struct symbol *sym, int evidx) 473 { 474 struct annotation *notes = symbol__annotation(sym); 475 struct sym_hist *h = annotation__histogram(notes, evidx); 476 u64 len = sym->end - sym->start, offset; 477 478 for (offset = 0; offset < len; ++offset) 479 if (h->addr[offset] != 0) 480 printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2, 481 sym->start + offset, h->addr[offset]); 482 printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); 483 } 484 485 int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, 486 bool full_paths, int min_pcnt, int max_lines, 487 int context) 488 { 489 struct dso *dso = map->dso; 490 const char *filename = dso->long_name, *d_filename; 491 struct annotation *notes = symbol__annotation(sym); 492 struct objdump_line *pos, *queue = NULL; 493 int printed = 2, queue_len = 0; 494 int more = 0; 495 u64 len; 496 497 if (full_paths) 498 d_filename = filename; 499 else 500 d_filename = basename(filename); 501 502 len = sym->end - sym->start; 503 504 printf(" Percent | Source code & Disassembly of %s\n", d_filename); 505 printf("------------------------------------------------\n"); 506 507 if (verbose) 508 symbol__annotate_hits(sym, evidx); 509 510 list_for_each_entry(pos, ¬es->src->source, node) { 511 if (context && queue == NULL) { 512 queue = pos; 513 queue_len = 0; 514 } 515 516 switch (objdump_line__print(pos, sym, evidx, len, min_pcnt, 517 printed, max_lines, queue)) { 518 case 0: 519 ++printed; 520 if (context) { 521 printed += queue_len; 522 queue = NULL; 523 queue_len = 0; 524 } 525 break; 526 case 1: 527 /* filtered by max_lines */ 528 ++more; 529 break; 530 case -1: 531 default: 532 /* 533 * Filtered by min_pcnt or non IP lines when 534 * context != 0 535 */ 536 if (!context) 537 break; 538 if (queue_len == context) 539 queue = list_entry(queue->node.next, typeof(*queue), node); 540 else 541 ++queue_len; 542 break; 543 } 544 } 545 546 return more; 547 } 548 549 void symbol__annotate_zero_histogram(struct symbol *sym, int evidx) 550 { 551 struct annotation *notes = symbol__annotation(sym); 552 struct sym_hist *h = annotation__histogram(notes, evidx); 553 554 memset(h, 0, notes->src->sizeof_sym_hist); 555 } 556 557 void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) 558 { 559 struct annotation *notes = symbol__annotation(sym); 560 struct sym_hist *h = annotation__histogram(notes, evidx); 561 struct objdump_line *pos; 562 int len = sym->end - sym->start; 563 564 h->sum = 0; 565 566 list_for_each_entry(pos, ¬es->src->source, node) { 567 if (pos->offset != -1 && pos->offset < len) { 568 h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8; 569 h->sum += h->addr[pos->offset]; 570 } 571 } 572 } 573 574 void objdump_line_list__purge(struct list_head *head) 575 { 576 struct objdump_line *pos, *n; 577 578 list_for_each_entry_safe(pos, n, head, node) { 579 list_del(&pos->node); 580 objdump_line__free(pos); 581 } 582 } 583 584 int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 585 bool print_lines, bool full_paths, int min_pcnt, 586 int max_lines) 587 { 588 struct dso *dso = map->dso; 589 const char *filename = dso->long_name; 590 struct rb_root source_line = RB_ROOT; 591 u64 len; 592 593 if (symbol__annotate(sym, map, 0) < 0) 594 return -1; 595 596 len = sym->end - sym->start; 597 598 if (print_lines) { 599 symbol__get_source_line(sym, map, evidx, &source_line, 600 len, filename); 601 print_summary(&source_line, filename); 602 } 603 604 symbol__annotate_printf(sym, map, evidx, full_paths, 605 min_pcnt, max_lines, 0); 606 if (print_lines) 607 symbol__free_source_line(sym, len); 608 609 objdump_line_list__purge(&symbol__annotation(sym)->src->source); 610 611 return 0; 612 } 613