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