1 /* 2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme (at) 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 /* ANDROID_CHANGE_BEGIN */ 260 #if 0 261 int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) 262 #else 263 int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize, 264 bool print_lines) 265 #endif 266 /* ANDROID_CHANGE_END */ 267 { 268 struct dso *dso = map->dso; 269 char *filename = dso__build_id_filename(dso, NULL, 0); 270 bool free_filename = true; 271 char command[PATH_MAX * 2]; 272 FILE *file; 273 int err = 0; 274 char symfs_filename[PATH_MAX]; 275 276 if (filename) { 277 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", 278 symbol_conf.symfs, filename); 279 } 280 281 if (filename == NULL) { 282 if (dso->has_build_id) { 283 pr_err("Can't annotate %s: not enough memory\n", 284 sym->name); 285 return -ENOMEM; 286 } 287 goto fallback; 288 } else if (readlink(symfs_filename, command, sizeof(command)) < 0 || 289 strstr(command, "[kernel.kallsyms]") || 290 access(symfs_filename, R_OK)) { 291 free(filename); 292 fallback: 293 /* 294 * If we don't have build-ids or the build-id file isn't in the 295 * cache, or is just a kallsyms file, well, lets hope that this 296 * DSO is the same as when 'perf record' ran. 297 */ 298 filename = dso->long_name; 299 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", 300 symbol_conf.symfs, filename); 301 free_filename = false; 302 } 303 304 if (dso->symtab_type == SYMTAB__KALLSYMS) { 305 char bf[BUILD_ID_SIZE * 2 + 16] = " with build id "; 306 char *build_id_msg = NULL; 307 308 if (dso->annotate_warned) 309 goto out_free_filename; 310 311 if (dso->has_build_id) { 312 build_id__sprintf(dso->build_id, 313 sizeof(dso->build_id), bf + 15); 314 build_id_msg = bf; 315 } 316 err = -ENOENT; 317 dso->annotate_warned = 1; 318 pr_err("Can't annotate %s: No vmlinux file%s was found in the " 319 "path.\nPlease use 'perf buildid-cache -av vmlinux' or " 320 "--vmlinux vmlinux.\n", 321 sym->name, build_id_msg ?: ""); 322 goto out_free_filename; 323 } 324 325 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, 326 filename, sym->name, map->unmap_ip(map, sym->start), 327 map->unmap_ip(map, sym->end)); 328 329 pr_debug("annotating [%p] %30s : [%p] %30s\n", 330 dso, dso->long_name, sym, sym->name); 331 332 /* ANDROID_CHANGE_BEGIN */ 333 #if 0 334 snprintf(command, sizeof(command), 335 "objdump --start-address=0x%016" PRIx64 336 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand", 337 map__rip_2objdump(map, sym->start), 338 map__rip_2objdump(map, sym->end), 339 symfs_filename, filename); 340 #else 341 snprintf(command, sizeof(command), 342 "arm-linux-androideabi-objdump --start-address=0x%016" PRIx64 343 " --stop-address=0x%016" PRIx64 " -d%c -C %s|grep -v %s|expand", 344 map__rip_2objdump(map, sym->start), 345 map__rip_2objdump(map, sym->end), 346 print_lines ? 'S' : ' ', 347 symfs_filename, filename); 348 #endif 349 /* ANDROID_CHANGE_END */ 350 351 pr_debug("Executing: %s\n", command); 352 353 file = popen(command, "r"); 354 if (!file) 355 goto out_free_filename; 356 357 while (!feof(file)) 358 if (symbol__parse_objdump_line(sym, map, file, privsize) < 0) 359 break; 360 361 pclose(file); 362 out_free_filename: 363 if (free_filename) 364 free(filename); 365 return err; 366 } 367 368 static void insert_source_line(struct rb_root *root, struct source_line *src_line) 369 { 370 struct source_line *iter; 371 struct rb_node **p = &root->rb_node; 372 struct rb_node *parent = NULL; 373 374 while (*p != NULL) { 375 parent = *p; 376 iter = rb_entry(parent, struct source_line, node); 377 378 if (src_line->percent > iter->percent) 379 p = &(*p)->rb_left; 380 else 381 p = &(*p)->rb_right; 382 } 383 384 rb_link_node(&src_line->node, parent, p); 385 rb_insert_color(&src_line->node, root); 386 } 387 388 static void symbol__free_source_line(struct symbol *sym, int len) 389 { 390 struct annotation *notes = symbol__annotation(sym); 391 struct source_line *src_line = notes->src->lines; 392 int i; 393 394 for (i = 0; i < len; i++) 395 free(src_line[i].path); 396 397 free(src_line); 398 notes->src->lines = NULL; 399 } 400 401 /* Get the filename:line for the colored entries */ 402 static int symbol__get_source_line(struct symbol *sym, struct map *map, 403 int evidx, struct rb_root *root, int len, 404 const char *filename) 405 { 406 u64 start; 407 int i; 408 char cmd[PATH_MAX * 2]; 409 struct source_line *src_line; 410 struct annotation *notes = symbol__annotation(sym); 411 struct sym_hist *h = annotation__histogram(notes, evidx); 412 413 if (!h->sum) 414 return 0; 415 416 src_line = notes->src->lines = calloc(len, sizeof(struct source_line)); 417 if (!notes->src->lines) 418 return -1; 419 420 /* ANDORID_CHANGE_BEGIN */ 421 #if 0 422 start = map->unmap_ip(map, sym->start); 423 #else 424 /* Use relative start address */ 425 start = sym->start; 426 #endif 427 /* ANDORID_CHANGE_END */ 428 429 for (i = 0; i < len; i++) { 430 char *path = NULL; 431 size_t line_len; 432 u64 offset; 433 FILE *fp; 434 435 src_line[i].percent = 100.0 * h->addr[i] / h->sum; 436 if (src_line[i].percent <= 0.5) 437 continue; 438 439 offset = start + i; 440 sprintf(cmd, "arm-linux-androideabi-addr2line -e %s%s %016" PRIx64, symbol_conf.symfs, 441 filename, offset); 442 fp = popen(cmd, "r"); 443 if (!fp) 444 continue; 445 446 if (getline(&path, &line_len, fp) < 0 || !line_len) 447 goto next; 448 449 src_line[i].path = malloc(sizeof(char) * line_len + 1); 450 if (!src_line[i].path) 451 goto next; 452 453 strcpy(src_line[i].path, path); 454 insert_source_line(root, &src_line[i]); 455 456 next: 457 pclose(fp); 458 } 459 460 return 0; 461 } 462 463 static void print_summary(struct rb_root *root, const char *filename) 464 { 465 struct source_line *src_line; 466 struct rb_node *node; 467 468 printf("\nSorted summary for file %s\n", filename); 469 printf("----------------------------------------------\n\n"); 470 471 if (RB_EMPTY_ROOT(root)) { 472 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN); 473 return; 474 } 475 476 node = rb_first(root); 477 while (node) { 478 double percent; 479 const char *color; 480 char *path; 481 482 src_line = rb_entry(node, struct source_line, node); 483 percent = src_line->percent; 484 color = get_percent_color(percent); 485 path = src_line->path; 486 487 color_fprintf(stdout, color, " %7.2f %s", percent, path); 488 node = rb_next(node); 489 } 490 } 491 492 static void symbol__annotate_hits(struct symbol *sym, int evidx) 493 { 494 struct annotation *notes = symbol__annotation(sym); 495 struct sym_hist *h = annotation__histogram(notes, evidx); 496 u64 len = sym->end - sym->start, offset; 497 498 for (offset = 0; offset < len; ++offset) 499 if (h->addr[offset] != 0) 500 printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2, 501 sym->start + offset, h->addr[offset]); 502 printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); 503 } 504 505 int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, 506 bool full_paths, int min_pcnt, int max_lines, 507 int context) 508 { 509 struct dso *dso = map->dso; 510 const char *filename = dso->long_name, *d_filename; 511 struct annotation *notes = symbol__annotation(sym); 512 struct objdump_line *pos, *queue = NULL; 513 int printed = 2, queue_len = 0; 514 int more = 0; 515 u64 len; 516 517 if (full_paths) 518 d_filename = filename; 519 else 520 d_filename = basename(filename); 521 522 len = sym->end - sym->start; 523 524 printf(" Percent | Source code & Disassembly of %s\n", d_filename); 525 printf("------------------------------------------------\n"); 526 527 if (verbose) 528 symbol__annotate_hits(sym, evidx); 529 530 list_for_each_entry(pos, ¬es->src->source, node) { 531 if (context && queue == NULL) { 532 queue = pos; 533 queue_len = 0; 534 } 535 536 switch (objdump_line__print(pos, sym, evidx, len, min_pcnt, 537 printed, max_lines, queue)) { 538 case 0: 539 ++printed; 540 if (context) { 541 printed += queue_len; 542 queue = NULL; 543 queue_len = 0; 544 } 545 break; 546 case 1: 547 /* filtered by max_lines */ 548 ++more; 549 break; 550 case -1: 551 default: 552 /* 553 * Filtered by min_pcnt or non IP lines when 554 * context != 0 555 */ 556 if (!context) 557 break; 558 if (queue_len == context) 559 queue = list_entry(queue->node.next, typeof(*queue), node); 560 else 561 ++queue_len; 562 break; 563 } 564 } 565 566 return more; 567 } 568 569 void symbol__annotate_zero_histogram(struct symbol *sym, int evidx) 570 { 571 struct annotation *notes = symbol__annotation(sym); 572 struct sym_hist *h = annotation__histogram(notes, evidx); 573 574 memset(h, 0, notes->src->sizeof_sym_hist); 575 } 576 577 void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) 578 { 579 struct annotation *notes = symbol__annotation(sym); 580 struct sym_hist *h = annotation__histogram(notes, evidx); 581 struct objdump_line *pos; 582 int len = sym->end - sym->start; 583 584 h->sum = 0; 585 586 list_for_each_entry(pos, ¬es->src->source, node) { 587 if (pos->offset != -1 && pos->offset < len) { 588 h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8; 589 h->sum += h->addr[pos->offset]; 590 } 591 } 592 } 593 594 void objdump_line_list__purge(struct list_head *head) 595 { 596 struct objdump_line *pos, *n; 597 598 list_for_each_entry_safe(pos, n, head, node) { 599 list_del(&pos->node); 600 objdump_line__free(pos); 601 } 602 } 603 604 int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 605 bool print_lines, bool full_paths, int min_pcnt, 606 int max_lines) 607 { 608 struct dso *dso = map->dso; 609 const char *filename = dso->long_name; 610 struct rb_root source_line = RB_ROOT; 611 u64 len; 612 613 /* ANDROID_CHANGE_BEGIN */ 614 #if 0 615 if (symbol__annotate(sym, map, 0) < 0) 616 return -1; 617 #else 618 if (symbol__annotate(sym, map, 0, print_lines) < 0) 619 return -1; 620 #endif 621 /* ANDROID_CHANGE_END */ 622 623 len = sym->end - sym->start; 624 625 if (print_lines) { 626 symbol__get_source_line(sym, map, evidx, &source_line, 627 len, filename); 628 print_summary(&source_line, filename); 629 } 630 631 symbol__annotate_printf(sym, map, evidx, full_paths, 632 min_pcnt, max_lines, 0); 633 if (print_lines) 634 symbol__free_source_line(sym, len); 635 636 objdump_line_list__purge(&symbol__annotation(sym)->src->source); 637 638 return 0; 639 } 640