1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> 4 * 5 * Parts came from builtin-annotate.c, see those files for further 6 * copyright notes. 7 */ 8 9 #include <errno.h> 10 #include <inttypes.h> 11 #include <libgen.h> 12 #include <stdlib.h> 13 #include "util.h" // hex_width() 14 #include "ui/ui.h" 15 #include "sort.h" 16 #include "build-id.h" 17 #include "color.h" 18 #include "config.h" 19 #include "disasm.h" 20 #include "dso.h" 21 #include "env.h" 22 #include "map.h" 23 #include "maps.h" 24 #include "symbol.h" 25 #include "srcline.h" 26 #include "units.h" 27 #include "debug.h" 28 #include "debuginfo.h" 29 #include "annotate.h" 30 #include "annotate-data.h" 31 #include "evsel.h" 32 #include "evlist.h" 33 #include "bpf-event.h" 34 #include "bpf-utils.h" 35 #include "block-range.h" 36 #include "string2.h" 37 #include "dwarf-regs.h" 38 #include "util/event.h" 39 #include "util/sharded_mutex.h" 40 #include "arch/common.h" 41 #include "namespaces.h" 42 #include "thread.h" 43 #include "hashmap.h" 44 #include "strbuf.h" 45 #include <regex.h> 46 #include <linux/bitops.h> 47 #include <linux/kernel.h> 48 #include <linux/string.h> 49 #include <linux/zalloc.h> 50 #include <subcmd/parse-options.h> 51 #include <subcmd/run-command.h> 52 #include <math.h> 53 54 /* FIXME: For the HE_COLORSET */ 55 #include "ui/browser.h" 56 57 /* 58 * FIXME: Using the same values as slang.h, 59 * but that header may not be available everywhere 60 */ 61 #define LARROW_CHAR ((unsigned char)',') 62 #define RARROW_CHAR ((unsigned char)'+') 63 #define DARROW_CHAR ((unsigned char)'.') 64 #define UARROW_CHAR ((unsigned char)'-') 65 66 #include <linux/ctype.h> 67 68 /* global annotation options */ 69 struct annotation_options annotate_opts; 70 71 /* Data type collection debug statistics */ 72 struct annotated_data_stat ann_data_stat; 73 LIST_HEAD(ann_insn_stat); 74 75 /* Pseudo data types */ 76 struct annotated_data_type stackop_type = { 77 .self = { 78 .type_name = (char *)"(stack operation)", 79 .children = LIST_HEAD_INIT(stackop_type.self.children), 80 }, 81 }; 82 83 struct annotated_data_type canary_type = { 84 .self = { 85 .type_name = (char *)"(stack canary)", 86 .children = LIST_HEAD_INIT(canary_type.self.children), 87 }, 88 }; 89 90 /* symbol histogram: key = offset << 16 | evsel->core.idx */ 91 static size_t sym_hist_hash(long key, void *ctx __maybe_unused) 92 { 93 return (key >> 16) + (key & 0xffff); 94 } 95 96 static bool sym_hist_equal(long key1, long key2, void *ctx __maybe_unused) 97 { 98 return key1 == key2; 99 } 100 101 static struct annotated_source *annotated_source__new(void) 102 { 103 struct annotated_source *src = zalloc(sizeof(*src)); 104 105 if (src != NULL) 106 INIT_LIST_HEAD(&src->source); 107 108 return src; 109 } 110 111 static __maybe_unused void annotated_source__delete(struct annotated_source *src) 112 { 113 struct hashmap_entry *cur; 114 size_t bkt; 115 116 if (src == NULL) 117 return; 118 119 if (src->samples) { 120 hashmap__for_each_entry(src->samples, cur, bkt) 121 zfree(&cur->pvalue); 122 hashmap__free(src->samples); 123 } 124 zfree(&src->histograms); 125 free(src); 126 } 127 128 static int annotated_source__alloc_histograms(struct annotated_source *src, 129 int nr_hists) 130 { 131 src->nr_histograms = nr_hists; 132 src->histograms = calloc(nr_hists, sizeof(*src->histograms)); 133 134 if (src->histograms == NULL) 135 return -1; 136 137 src->samples = hashmap__new(sym_hist_hash, sym_hist_equal, NULL); 138 if (src->samples == NULL) 139 zfree(&src->histograms); 140 141 return src->histograms ? 0 : -1; 142 } 143 144 void symbol__annotate_zero_histograms(struct symbol *sym) 145 { 146 struct annotation *notes = symbol__annotation(sym); 147 148 annotation__lock(notes); 149 if (notes->src != NULL) { 150 memset(notes->src->histograms, 0, 151 notes->src->nr_histograms * sizeof(*notes->src->histograms)); 152 hashmap__clear(notes->src->samples); 153 } 154 if (notes->branch && notes->branch->cycles_hist) { 155 memset(notes->branch->cycles_hist, 0, 156 symbol__size(sym) * sizeof(struct cyc_hist)); 157 } 158 annotation__unlock(notes); 159 } 160 161 static int __symbol__account_cycles(struct cyc_hist *ch, 162 u64 start, 163 unsigned offset, unsigned cycles, 164 unsigned have_start) 165 { 166 /* 167 * For now we can only account one basic block per 168 * final jump. But multiple could be overlapping. 169 * Always account the longest one. So when 170 * a shorter one has been already seen throw it away. 171 * 172 * We separately always account the full cycles. 173 */ 174 ch[offset].num_aggr++; 175 ch[offset].cycles_aggr += cycles; 176 177 if (cycles > ch[offset].cycles_max) 178 ch[offset].cycles_max = cycles; 179 180 if (ch[offset].cycles_min) { 181 if (cycles && cycles < ch[offset].cycles_min) 182 ch[offset].cycles_min = cycles; 183 } else 184 ch[offset].cycles_min = cycles; 185 186 if (!have_start && ch[offset].have_start) 187 return 0; 188 if (ch[offset].num) { 189 if (have_start && (!ch[offset].have_start || 190 ch[offset].start > start)) { 191 ch[offset].have_start = 0; 192 ch[offset].cycles = 0; 193 ch[offset].num = 0; 194 if (ch[offset].reset < 0xffff) 195 ch[offset].reset++; 196 } else if (have_start && 197 ch[offset].start < start) 198 return 0; 199 } 200 201 if (ch[offset].num < NUM_SPARKS) 202 ch[offset].cycles_spark[ch[offset].num] = cycles; 203 204 ch[offset].have_start = have_start; 205 ch[offset].start = start; 206 ch[offset].cycles += cycles; 207 ch[offset].num++; 208 return 0; 209 } 210 211 static int __symbol__inc_addr_samples(struct map_symbol *ms, 212 struct annotated_source *src, int evidx, u64 addr, 213 struct perf_sample *sample) 214 { 215 struct symbol *sym = ms->sym; 216 long hash_key; 217 u64 offset; 218 struct sym_hist *h; 219 struct sym_hist_entry *entry; 220 221 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map__unmap_ip(ms->map, addr)); 222 223 if ((addr < sym->start || addr >= sym->end) && 224 (addr != sym->end || sym->start != sym->end)) { 225 pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n", 226 __func__, __LINE__, sym->name, sym->start, addr, sym->end); 227 return -ERANGE; 228 } 229 230 offset = addr - sym->start; 231 h = annotated_source__histogram(src, evidx); 232 if (h == NULL) { 233 pr_debug("%s(%d): ENOMEM! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 ", func: %d\n", 234 __func__, __LINE__, sym->name, sym->start, addr, sym->end, sym->type == STT_FUNC); 235 return -ENOMEM; 236 } 237 238 hash_key = offset << 16 | evidx; 239 if (!hashmap__find(src->samples, hash_key, &entry)) { 240 entry = zalloc(sizeof(*entry)); 241 if (entry == NULL) 242 return -ENOMEM; 243 244 if (hashmap__add(src->samples, hash_key, entry) < 0) 245 return -ENOMEM; 246 } 247 248 h->nr_samples++; 249 h->period += sample->period; 250 entry->nr_samples++; 251 entry->period += sample->period; 252 253 pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64 254 ", evidx=%d] => nr_samples: %" PRIu64 ", period: %" PRIu64 "\n", 255 sym->start, sym->name, addr, addr - sym->start, evidx, 256 entry->nr_samples, entry->period); 257 return 0; 258 } 259 260 struct annotated_branch *annotation__get_branch(struct annotation *notes) 261 { 262 if (notes == NULL) 263 return NULL; 264 265 if (notes->branch == NULL) 266 notes->branch = zalloc(sizeof(*notes->branch)); 267 268 return notes->branch; 269 } 270 271 static struct annotated_branch *symbol__find_branch_hist(struct symbol *sym, 272 unsigned int br_cntr_nr) 273 { 274 struct annotation *notes = symbol__annotation(sym); 275 struct annotated_branch *branch; 276 const size_t size = symbol__size(sym); 277 278 branch = annotation__get_branch(notes); 279 if (branch == NULL) 280 return NULL; 281 282 if (branch->cycles_hist == NULL) { 283 branch->cycles_hist = calloc(size, sizeof(struct cyc_hist)); 284 if (!branch->cycles_hist) 285 return NULL; 286 } 287 288 if (br_cntr_nr && branch->br_cntr == NULL) { 289 branch->br_cntr = calloc(br_cntr_nr * size, sizeof(u64)); 290 if (!branch->br_cntr) 291 return NULL; 292 } 293 294 return branch; 295 } 296 297 struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists) 298 { 299 struct annotation *notes = symbol__annotation(sym); 300 301 if (notes->src == NULL) { 302 notes->src = annotated_source__new(); 303 if (notes->src == NULL) 304 return NULL; 305 goto alloc_histograms; 306 } 307 308 if (notes->src->histograms == NULL) { 309 alloc_histograms: 310 annotated_source__alloc_histograms(notes->src, nr_hists); 311 } 312 313 return notes->src; 314 } 315 316 static int symbol__inc_addr_samples(struct map_symbol *ms, 317 struct evsel *evsel, u64 addr, 318 struct perf_sample *sample) 319 { 320 struct symbol *sym = ms->sym; 321 struct annotated_source *src; 322 323 if (sym == NULL) 324 return 0; 325 src = symbol__hists(sym, evsel->evlist->core.nr_entries); 326 return src ? __symbol__inc_addr_samples(ms, src, evsel->core.idx, addr, sample) : 0; 327 } 328 329 static int symbol__account_br_cntr(struct annotated_branch *branch, 330 struct evsel *evsel, 331 unsigned offset, 332 u64 br_cntr) 333 { 334 unsigned int br_cntr_nr = evsel__leader(evsel)->br_cntr_nr; 335 unsigned int base = evsel__leader(evsel)->br_cntr_idx; 336 unsigned int width = evsel__env(evsel)->br_cntr_width; 337 unsigned int off = offset * evsel->evlist->nr_br_cntr; 338 unsigned int i, mask = (1L << width) - 1; 339 u64 *branch_br_cntr = branch->br_cntr; 340 341 if (!br_cntr || !branch_br_cntr) 342 return 0; 343 344 for (i = 0; i < br_cntr_nr; i++) { 345 u64 cntr = (br_cntr >> i * width) & mask; 346 347 branch_br_cntr[off + i + base] += cntr; 348 if (cntr == mask) 349 branch_br_cntr[off + i + base] |= ANNOTATION__BR_CNTR_SATURATED_FLAG; 350 } 351 352 return 0; 353 } 354 355 static int symbol__account_cycles(u64 addr, u64 start, struct symbol *sym, 356 unsigned cycles, struct evsel *evsel, 357 u64 br_cntr) 358 { 359 struct annotated_branch *branch; 360 unsigned offset; 361 int ret; 362 363 if (sym == NULL) 364 return 0; 365 branch = symbol__find_branch_hist(sym, evsel->evlist->nr_br_cntr); 366 if (!branch) 367 return -ENOMEM; 368 if (addr < sym->start || addr >= sym->end) 369 return -ERANGE; 370 371 if (start) { 372 if (start < sym->start || start >= sym->end) 373 return -ERANGE; 374 if (start >= addr) 375 start = 0; 376 } 377 offset = addr - sym->start; 378 ret = __symbol__account_cycles(branch->cycles_hist, 379 start ? start - sym->start : 0, 380 offset, cycles, 381 !!start); 382 383 if (ret) 384 return ret; 385 386 return symbol__account_br_cntr(branch, evsel, offset, br_cntr); 387 } 388 389 int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, 390 struct addr_map_symbol *start, 391 unsigned cycles, 392 struct evsel *evsel, 393 u64 br_cntr) 394 { 395 u64 saddr = 0; 396 int err; 397 398 if (!cycles) 399 return 0; 400 401 /* 402 * Only set start when IPC can be computed. We can only 403 * compute it when the basic block is completely in a single 404 * function. 405 * Special case the case when the jump is elsewhere, but 406 * it starts on the function start. 407 */ 408 if (start && 409 (start->ms.sym == ams->ms.sym || 410 (ams->ms.sym && 411 start->addr == ams->ms.sym->start + map__start(ams->ms.map)))) 412 saddr = start->al_addr; 413 if (saddr == 0) 414 pr_debug2("BB with bad start: addr %"PRIx64" start %"PRIx64" sym %"PRIx64" saddr %"PRIx64"\n", 415 ams->addr, 416 start ? start->addr : 0, 417 ams->ms.sym ? ams->ms.sym->start + map__start(ams->ms.map) : 0, 418 saddr); 419 err = symbol__account_cycles(ams->al_addr, saddr, ams->ms.sym, cycles, evsel, br_cntr); 420 if (err) 421 pr_debug2("account_cycles failed %d\n", err); 422 return err; 423 } 424 425 struct annotation_line *annotated_source__get_line(struct annotated_source *src, 426 s64 offset) 427 { 428 struct annotation_line *al; 429 430 list_for_each_entry(al, &src->source, node) { 431 if (al->offset == offset) 432 return al; 433 } 434 return NULL; 435 } 436 437 static unsigned annotation__count_insn(struct annotation *notes, u64 start, u64 end) 438 { 439 struct annotation_line *al; 440 unsigned n_insn = 0; 441 442 al = annotated_source__get_line(notes->src, start); 443 if (al == NULL) 444 return 0; 445 446 list_for_each_entry_from(al, ¬es->src->source, node) { 447 if (al->offset == -1) 448 continue; 449 if ((u64)al->offset > end) 450 break; 451 n_insn++; 452 } 453 return n_insn; 454 } 455 456 static void annotated_branch__delete(struct annotated_branch *branch) 457 { 458 if (branch) { 459 zfree(&branch->cycles_hist); 460 free(branch->br_cntr); 461 free(branch); 462 } 463 } 464 465 static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 end, struct cyc_hist *ch) 466 { 467 unsigned n_insn; 468 unsigned int cover_insn = 0; 469 470 n_insn = annotation__count_insn(notes, start, end); 471 if (n_insn && ch->num && ch->cycles) { 472 struct annotation_line *al; 473 struct annotated_branch *branch; 474 float ipc = n_insn / ((double)ch->cycles / (double)ch->num); 475 476 /* Hide data when there are too many overlaps. */ 477 if (ch->reset >= 0x7fff) 478 return; 479 480 al = annotated_source__get_line(notes->src, start); 481 if (al == NULL) 482 return; 483 484 list_for_each_entry_from(al, ¬es->src->source, node) { 485 if (al->offset == -1) 486 continue; 487 if ((u64)al->offset > end) 488 break; 489 if (al->cycles && al->cycles->ipc == 0.0) { 490 al->cycles->ipc = ipc; 491 cover_insn++; 492 } 493 } 494 495 branch = annotation__get_branch(notes); 496 if (cover_insn && branch) { 497 branch->hit_cycles += ch->cycles; 498 branch->hit_insn += n_insn * ch->num; 499 branch->cover_insn += cover_insn; 500 } 501 } 502 } 503 504 static int annotation__compute_ipc(struct annotation *notes, size_t size, 505 struct evsel *evsel) 506 { 507 unsigned int br_cntr_nr = evsel->evlist->nr_br_cntr; 508 int err = 0; 509 s64 offset; 510 511 if (!notes->branch || !notes->branch->cycles_hist) 512 return 0; 513 514 notes->branch->total_insn = annotation__count_insn(notes, 0, size - 1); 515 notes->branch->hit_cycles = 0; 516 notes->branch->hit_insn = 0; 517 notes->branch->cover_insn = 0; 518 519 annotation__lock(notes); 520 for (offset = size - 1; offset >= 0; --offset) { 521 struct cyc_hist *ch; 522 523 ch = ¬es->branch->cycles_hist[offset]; 524 if (ch && ch->cycles) { 525 struct annotation_line *al; 526 527 al = annotated_source__get_line(notes->src, offset); 528 if (al && al->cycles == NULL) { 529 al->cycles = zalloc(sizeof(*al->cycles)); 530 if (al->cycles == NULL) { 531 err = ENOMEM; 532 break; 533 } 534 } 535 if (ch->have_start) 536 annotation__count_and_fill(notes, ch->start, offset, ch); 537 if (al && ch->num_aggr) { 538 al->cycles->avg = ch->cycles_aggr / ch->num_aggr; 539 al->cycles->max = ch->cycles_max; 540 al->cycles->min = ch->cycles_min; 541 } 542 if (al && notes->branch->br_cntr) { 543 if (!al->br_cntr) { 544 al->br_cntr = calloc(br_cntr_nr, sizeof(u64)); 545 if (!al->br_cntr) { 546 err = ENOMEM; 547 break; 548 } 549 } 550 al->num_aggr = ch->num_aggr; 551 al->br_cntr_nr = br_cntr_nr; 552 al->evsel = evsel; 553 memcpy(al->br_cntr, ¬es->branch->br_cntr[offset * br_cntr_nr], 554 br_cntr_nr * sizeof(u64)); 555 } 556 } 557 } 558 559 if (err) { 560 while (++offset < (s64)size) { 561 struct cyc_hist *ch = ¬es->branch->cycles_hist[offset]; 562 563 if (ch && ch->cycles) { 564 struct annotation_line *al; 565 566 al = annotated_source__get_line(notes->src, offset); 567 if (al) { 568 zfree(&al->cycles); 569 zfree(&al->br_cntr); 570 } 571 } 572 } 573 } 574 575 annotation__unlock(notes); 576 return 0; 577 } 578 579 int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, 580 struct evsel *evsel) 581 { 582 return symbol__inc_addr_samples(&ams->ms, evsel, ams->al_addr, sample); 583 } 584 585 int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, 586 struct evsel *evsel, u64 ip) 587 { 588 return symbol__inc_addr_samples(&he->ms, evsel, ip, sample); 589 } 590 591 592 void annotation__exit(struct annotation *notes) 593 { 594 annotated_source__delete(notes->src); 595 annotated_branch__delete(notes->branch); 596 } 597 598 static struct sharded_mutex *sharded_mutex; 599 600 static void annotation__init_sharded_mutex(void) 601 { 602 /* As many mutexes as there are CPUs. */ 603 sharded_mutex = sharded_mutex__new(cpu__max_present_cpu().cpu); 604 } 605 606 static size_t annotation__hash(const struct annotation *notes) 607 { 608 return (size_t)notes; 609 } 610 611 static struct mutex *annotation__get_mutex(const struct annotation *notes) 612 { 613 static pthread_once_t once = PTHREAD_ONCE_INIT; 614 615 pthread_once(&once, annotation__init_sharded_mutex); 616 if (!sharded_mutex) 617 return NULL; 618 619 return sharded_mutex__get_mutex(sharded_mutex, annotation__hash(notes)); 620 } 621 622 void annotation__lock(struct annotation *notes) 623 NO_THREAD_SAFETY_ANALYSIS 624 { 625 struct mutex *mutex = annotation__get_mutex(notes); 626 627 if (mutex) 628 mutex_lock(mutex); 629 } 630 631 void annotation__unlock(struct annotation *notes) 632 NO_THREAD_SAFETY_ANALYSIS 633 { 634 struct mutex *mutex = annotation__get_mutex(notes); 635 636 if (mutex) 637 mutex_unlock(mutex); 638 } 639 640 bool annotation__trylock(struct annotation *notes) 641 { 642 struct mutex *mutex = annotation__get_mutex(notes); 643 644 if (!mutex) 645 return false; 646 647 return mutex_trylock(mutex); 648 } 649 650 void annotation_line__add(struct annotation_line *al, struct list_head *head) 651 { 652 list_add_tail(&al->node, head); 653 } 654 655 struct annotation_line * 656 annotation_line__next(struct annotation_line *pos, struct list_head *head) 657 { 658 list_for_each_entry_continue(pos, head, node) 659 if (pos->offset >= 0) 660 return pos; 661 662 return NULL; 663 } 664 665 static const char *annotate__address_color(struct block_range *br) 666 { 667 double cov = block_range__coverage(br); 668 669 if (cov >= 0) { 670 /* mark red for >75% coverage */ 671 if (cov > 0.75) 672 return PERF_COLOR_RED; 673 674 /* mark dull for <1% coverage */ 675 if (cov < 0.01) 676 return PERF_COLOR_NORMAL; 677 } 678 679 return PERF_COLOR_MAGENTA; 680 } 681 682 static const char *annotate__asm_color(struct block_range *br) 683 { 684 double cov = block_range__coverage(br); 685 686 if (cov >= 0) { 687 /* mark dull for <1% coverage */ 688 if (cov < 0.01) 689 return PERF_COLOR_NORMAL; 690 } 691 692 return PERF_COLOR_BLUE; 693 } 694 695 static void annotate__branch_printf(struct block_range *br, u64 addr) 696 { 697 bool emit_comment = true; 698 699 if (!br) 700 return; 701 702 #if 1 703 if (br->is_target && br->start == addr) { 704 struct block_range *branch = br; 705 double p; 706 707 /* 708 * Find matching branch to our target. 709 */ 710 while (!branch->is_branch) 711 branch = block_range__next(branch); 712 713 p = 100 *(double)br->entry / branch->coverage; 714 715 if (p > 0.1) { 716 if (emit_comment) { 717 emit_comment = false; 718 printf("\t#"); 719 } 720 721 /* 722 * The percentage of coverage joined at this target in relation 723 * to the next branch. 724 */ 725 printf(" +%.2f%%", p); 726 } 727 } 728 #endif 729 if (br->is_branch && br->end == addr) { 730 double p = 100*(double)br->taken / br->coverage; 731 732 if (p > 0.1) { 733 if (emit_comment) { 734 emit_comment = false; 735 printf("\t#"); 736 } 737 738 /* 739 * The percentage of coverage leaving at this branch, and 740 * its prediction ratio. 741 */ 742 printf(" -%.2f%% (p:%.2f%%)", p, 100*(double)br->pred / br->taken); 743 } 744 } 745 } 746 747 static int disasm_line__print(struct disasm_line *dl, u64 start, int addr_fmt_width) 748 { 749 s64 offset = dl->al.offset; 750 const u64 addr = start + offset; 751 struct block_range *br; 752 753 br = block_range__find(addr); 754 color_fprintf(stdout, annotate__address_color(br), " %*" PRIx64 ":", addr_fmt_width, addr); 755 color_fprintf(stdout, annotate__asm_color(br), "%s", dl->al.line); 756 annotate__branch_printf(br, addr); 757 return 0; 758 } 759 760 static int 761 annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, 762 struct evsel *evsel, u64 len, int min_pcnt, int printed, 763 int max_lines, struct annotation_line *queue, int addr_fmt_width, 764 int percent_type) 765 { 766 struct disasm_line *dl = container_of(al, struct disasm_line, al); 767 struct annotation *notes = symbol__annotation(sym); 768 static const char *prev_line; 769 770 if (al->offset != -1) { 771 double max_percent = 0.0; 772 int i, nr_percent = 1; 773 const char *color; 774 775 for (i = 0; i < al->data_nr; i++) { 776 double percent; 777 778 percent = annotation_data__percent(&al->data[i], 779 percent_type); 780 781 if (percent > max_percent) 782 max_percent = percent; 783 } 784 785 if (al->data_nr > nr_percent) 786 nr_percent = al->data_nr; 787 788 if (max_percent < min_pcnt) 789 return -1; 790 791 if (max_lines && printed >= max_lines) 792 return 1; 793 794 if (queue != NULL) { 795 list_for_each_entry_from(queue, ¬es->src->source, node) { 796 if (queue == al) 797 break; 798 annotation_line__print(queue, sym, start, evsel, len, 799 0, 0, 1, NULL, addr_fmt_width, 800 percent_type); 801 } 802 } 803 804 color = get_percent_color(max_percent); 805 806 for (i = 0; i < nr_percent; i++) { 807 struct annotation_data *data = &al->data[i]; 808 double percent; 809 810 percent = annotation_data__percent(data, percent_type); 811 color = get_percent_color(percent); 812 813 if (symbol_conf.show_total_period) 814 color_fprintf(stdout, color, " %11" PRIu64, 815 data->he.period); 816 else if (symbol_conf.show_nr_samples) 817 color_fprintf(stdout, color, " %7" PRIu64, 818 data->he.nr_samples); 819 else 820 color_fprintf(stdout, color, " %7.2f", percent); 821 } 822 823 printf(" : "); 824 825 disasm_line__print(dl, start, addr_fmt_width); 826 827 /* 828 * Also color the filename and line if needed, with 829 * the same color than the percentage. Don't print it 830 * twice for close colored addr with the same filename:line 831 */ 832 if (al->path) { 833 if (!prev_line || strcmp(prev_line, al->path)) { 834 color_fprintf(stdout, color, " // %s", al->path); 835 prev_line = al->path; 836 } 837 } 838 839 printf("\n"); 840 } else if (max_lines && printed >= max_lines) 841 return 1; 842 else { 843 int width = annotation__pcnt_width(notes); 844 845 if (queue) 846 return -1; 847 848 if (!*al->line) 849 printf(" %*s:\n", width, " "); 850 else 851 printf(" %*s: %-*d %s\n", width, " ", addr_fmt_width, al->line_nr, al->line); 852 } 853 854 return 0; 855 } 856 857 static void calc_percent(struct annotation *notes, 858 struct evsel *evsel, 859 struct annotation_data *data, 860 s64 offset, s64 end) 861 { 862 struct hists *hists = evsel__hists(evsel); 863 int evidx = evsel->core.idx; 864 struct sym_hist *sym_hist = annotation__histogram(notes, evidx); 865 unsigned int hits = 0; 866 u64 period = 0; 867 868 while (offset < end) { 869 struct sym_hist_entry *entry; 870 871 entry = annotated_source__hist_entry(notes->src, evidx, offset); 872 if (entry) { 873 hits += entry->nr_samples; 874 period += entry->period; 875 } 876 ++offset; 877 } 878 879 if (sym_hist->nr_samples) { 880 data->he.period = period; 881 data->he.nr_samples = hits; 882 data->percent[PERCENT_HITS_LOCAL] = 100.0 * hits / sym_hist->nr_samples; 883 } 884 885 if (hists->stats.nr_non_filtered_samples) 886 data->percent[PERCENT_HITS_GLOBAL] = 100.0 * hits / hists->stats.nr_non_filtered_samples; 887 888 if (sym_hist->period) 889 data->percent[PERCENT_PERIOD_LOCAL] = 100.0 * period / sym_hist->period; 890 891 if (hists->stats.total_period) 892 data->percent[PERCENT_PERIOD_GLOBAL] = 100.0 * period / hists->stats.total_period; 893 } 894 895 static void annotation__calc_percent(struct annotation *notes, 896 struct evsel *leader, s64 len) 897 { 898 struct annotation_line *al, *next; 899 struct evsel *evsel; 900 901 list_for_each_entry(al, ¬es->src->source, node) { 902 s64 end; 903 int i = 0; 904 905 if (al->offset == -1) 906 continue; 907 908 next = annotation_line__next(al, ¬es->src->source); 909 end = next ? next->offset : len; 910 911 for_each_group_evsel(evsel, leader) { 912 struct annotation_data *data; 913 914 BUG_ON(i >= al->data_nr); 915 916 if (symbol_conf.skip_empty && 917 evsel__hists(evsel)->stats.nr_samples == 0) 918 continue; 919 920 data = &al->data[i++]; 921 922 calc_percent(notes, evsel, data, al->offset, end); 923 } 924 } 925 } 926 927 void symbol__calc_percent(struct symbol *sym, struct evsel *evsel) 928 { 929 struct annotation *notes = symbol__annotation(sym); 930 931 annotation__calc_percent(notes, evsel, symbol__size(sym)); 932 } 933 934 static int evsel__get_arch(struct evsel *evsel, struct arch **parch) 935 { 936 struct perf_env *env = evsel__env(evsel); 937 const char *arch_name = perf_env__arch(env); 938 struct arch *arch; 939 int err; 940 941 if (!arch_name) { 942 *parch = NULL; 943 return errno; 944 } 945 946 *parch = arch = arch__find(arch_name); 947 if (arch == NULL) { 948 pr_err("%s: unsupported arch %s\n", __func__, arch_name); 949 return ENOTSUP; 950 } 951 952 if (arch->init) { 953 err = arch->init(arch, env ? env->cpuid : NULL); 954 if (err) { 955 pr_err("%s: failed to initialize %s arch priv area\n", 956 __func__, arch->name); 957 return err; 958 } 959 } 960 return 0; 961 } 962 963 int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, 964 struct arch **parch) 965 { 966 struct symbol *sym = ms->sym; 967 struct annotation *notes = symbol__annotation(sym); 968 struct annotate_args args = { 969 .evsel = evsel, 970 .options = &annotate_opts, 971 }; 972 struct arch *arch = NULL; 973 int err, nr; 974 975 err = evsel__get_arch(evsel, &arch); 976 if (err < 0) 977 return err; 978 979 if (parch) 980 *parch = arch; 981 982 if (notes->src && !list_empty(¬es->src->source)) 983 return 0; 984 985 args.arch = arch; 986 args.ms = *ms; 987 988 if (notes->src == NULL) { 989 notes->src = annotated_source__new(); 990 if (notes->src == NULL) 991 return -1; 992 } 993 994 nr = 0; 995 if (evsel__is_group_event(evsel)) { 996 struct evsel *pos; 997 998 for_each_group_evsel(pos, evsel) { 999 if (symbol_conf.skip_empty && 1000 evsel__hists(pos)->stats.nr_samples == 0) 1001 continue; 1002 nr++; 1003 } 1004 } 1005 notes->src->nr_events = nr ? nr : 1; 1006 1007 if (annotate_opts.full_addr) 1008 notes->src->start = map__objdump_2mem(ms->map, ms->sym->start); 1009 else 1010 notes->src->start = map__rip_2objdump(ms->map, ms->sym->start); 1011 1012 return symbol__disassemble(sym, &args); 1013 } 1014 1015 static void insert_source_line(struct rb_root *root, struct annotation_line *al) 1016 { 1017 struct annotation_line *iter; 1018 struct rb_node **p = &root->rb_node; 1019 struct rb_node *parent = NULL; 1020 unsigned int percent_type = annotate_opts.percent_type; 1021 int i, ret; 1022 1023 while (*p != NULL) { 1024 parent = *p; 1025 iter = rb_entry(parent, struct annotation_line, rb_node); 1026 1027 ret = strcmp(iter->path, al->path); 1028 if (ret == 0) { 1029 for (i = 0; i < al->data_nr; i++) { 1030 iter->data[i].percent_sum += annotation_data__percent(&al->data[i], 1031 percent_type); 1032 } 1033 return; 1034 } 1035 1036 if (ret < 0) 1037 p = &(*p)->rb_left; 1038 else 1039 p = &(*p)->rb_right; 1040 } 1041 1042 for (i = 0; i < al->data_nr; i++) { 1043 al->data[i].percent_sum = annotation_data__percent(&al->data[i], 1044 percent_type); 1045 } 1046 1047 rb_link_node(&al->rb_node, parent, p); 1048 rb_insert_color(&al->rb_node, root); 1049 } 1050 1051 static int cmp_source_line(struct annotation_line *a, struct annotation_line *b) 1052 { 1053 int i; 1054 1055 for (i = 0; i < a->data_nr; i++) { 1056 if (a->data[i].percent_sum == b->data[i].percent_sum) 1057 continue; 1058 return a->data[i].percent_sum > b->data[i].percent_sum; 1059 } 1060 1061 return 0; 1062 } 1063 1064 static void __resort_source_line(struct rb_root *root, struct annotation_line *al) 1065 { 1066 struct annotation_line *iter; 1067 struct rb_node **p = &root->rb_node; 1068 struct rb_node *parent = NULL; 1069 1070 while (*p != NULL) { 1071 parent = *p; 1072 iter = rb_entry(parent, struct annotation_line, rb_node); 1073 1074 if (cmp_source_line(al, iter)) 1075 p = &(*p)->rb_left; 1076 else 1077 p = &(*p)->rb_right; 1078 } 1079 1080 rb_link_node(&al->rb_node, parent, p); 1081 rb_insert_color(&al->rb_node, root); 1082 } 1083 1084 static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root) 1085 { 1086 struct annotation_line *al; 1087 struct rb_node *node; 1088 1089 node = rb_first(src_root); 1090 while (node) { 1091 struct rb_node *next; 1092 1093 al = rb_entry(node, struct annotation_line, rb_node); 1094 next = rb_next(node); 1095 rb_erase(node, src_root); 1096 1097 __resort_source_line(dest_root, al); 1098 node = next; 1099 } 1100 } 1101 1102 static void print_summary(struct rb_root *root, const char *filename) 1103 { 1104 struct annotation_line *al; 1105 struct rb_node *node; 1106 1107 printf("\nSorted summary for file %s\n", filename); 1108 printf("----------------------------------------------\n\n"); 1109 1110 if (RB_EMPTY_ROOT(root)) { 1111 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN); 1112 return; 1113 } 1114 1115 node = rb_first(root); 1116 while (node) { 1117 double percent, percent_max = 0.0; 1118 const char *color; 1119 char *path; 1120 int i; 1121 1122 al = rb_entry(node, struct annotation_line, rb_node); 1123 for (i = 0; i < al->data_nr; i++) { 1124 percent = al->data[i].percent_sum; 1125 color = get_percent_color(percent); 1126 color_fprintf(stdout, color, " %7.2f", percent); 1127 1128 if (percent > percent_max) 1129 percent_max = percent; 1130 } 1131 1132 path = al->path; 1133 color = get_percent_color(percent_max); 1134 color_fprintf(stdout, color, " %s\n", path); 1135 1136 node = rb_next(node); 1137 } 1138 } 1139 1140 static void symbol__annotate_hits(struct symbol *sym, struct evsel *evsel) 1141 { 1142 int evidx = evsel->core.idx; 1143 struct annotation *notes = symbol__annotation(sym); 1144 struct sym_hist *h = annotation__histogram(notes, evidx); 1145 u64 len = symbol__size(sym), offset; 1146 1147 for (offset = 0; offset < len; ++offset) { 1148 struct sym_hist_entry *entry; 1149 1150 entry = annotated_source__hist_entry(notes->src, evidx, offset); 1151 if (entry && entry->nr_samples != 0) 1152 printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2, 1153 sym->start + offset, entry->nr_samples); 1154 } 1155 printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->nr_samples", h->nr_samples); 1156 } 1157 1158 static int annotated_source__addr_fmt_width(struct list_head *lines, u64 start) 1159 { 1160 char bf[32]; 1161 struct annotation_line *line; 1162 1163 list_for_each_entry_reverse(line, lines, node) { 1164 if (line->offset != -1) 1165 return scnprintf(bf, sizeof(bf), "%" PRIx64, start + line->offset); 1166 } 1167 1168 return 0; 1169 } 1170 1171 int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel) 1172 { 1173 struct map *map = ms->map; 1174 struct symbol *sym = ms->sym; 1175 struct dso *dso = map__dso(map); 1176 char *filename; 1177 const char *d_filename; 1178 const char *evsel_name = evsel__name(evsel); 1179 struct annotation *notes = symbol__annotation(sym); 1180 struct sym_hist *h = annotation__histogram(notes, evsel->core.idx); 1181 struct annotation_line *pos, *queue = NULL; 1182 struct annotation_options *opts = &annotate_opts; 1183 u64 start = map__rip_2objdump(map, sym->start); 1184 int printed = 2, queue_len = 0, addr_fmt_width; 1185 int more = 0; 1186 bool context = opts->context; 1187 u64 len; 1188 int width = annotation__pcnt_width(notes); 1189 int graph_dotted_len; 1190 char buf[512]; 1191 1192 filename = strdup(dso__long_name(dso)); 1193 if (!filename) 1194 return -ENOMEM; 1195 1196 if (opts->full_path) 1197 d_filename = filename; 1198 else 1199 d_filename = basename(filename); 1200 1201 len = symbol__size(sym); 1202 1203 if (evsel__is_group_event(evsel)) { 1204 evsel__group_desc(evsel, buf, sizeof(buf)); 1205 evsel_name = buf; 1206 } 1207 1208 graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples, " 1209 "percent: %s)\n", 1210 width, width, symbol_conf.show_total_period ? "Period" : 1211 symbol_conf.show_nr_samples ? "Samples" : "Percent", 1212 d_filename, evsel_name, h->nr_samples, 1213 percent_type_str(opts->percent_type)); 1214 1215 printf("%-*.*s----\n", 1216 graph_dotted_len, graph_dotted_len, graph_dotted_line); 1217 1218 if (verbose > 0) 1219 symbol__annotate_hits(sym, evsel); 1220 1221 addr_fmt_width = annotated_source__addr_fmt_width(¬es->src->source, start); 1222 1223 list_for_each_entry(pos, ¬es->src->source, node) { 1224 int err; 1225 1226 if (context && queue == NULL) { 1227 queue = pos; 1228 queue_len = 0; 1229 } 1230 1231 err = annotation_line__print(pos, sym, start, evsel, len, 1232 opts->min_pcnt, printed, opts->max_lines, 1233 queue, addr_fmt_width, opts->percent_type); 1234 1235 switch (err) { 1236 case 0: 1237 ++printed; 1238 if (context) { 1239 printed += queue_len; 1240 queue = NULL; 1241 queue_len = 0; 1242 } 1243 break; 1244 case 1: 1245 /* filtered by max_lines */ 1246 ++more; 1247 break; 1248 case -1: 1249 default: 1250 /* 1251 * Filtered by min_pcnt or non IP lines when 1252 * context != 0 1253 */ 1254 if (!context) 1255 break; 1256 if (queue_len == context) 1257 queue = list_entry(queue->node.next, typeof(*queue), node); 1258 else 1259 ++queue_len; 1260 break; 1261 } 1262 } 1263 1264 free(filename); 1265 1266 return more; 1267 } 1268 1269 static void FILE__set_percent_color(void *fp __maybe_unused, 1270 double percent __maybe_unused, 1271 bool current __maybe_unused) 1272 { 1273 } 1274 1275 static int FILE__set_jumps_percent_color(void *fp __maybe_unused, 1276 int nr __maybe_unused, bool current __maybe_unused) 1277 { 1278 return 0; 1279 } 1280 1281 static int FILE__set_color(void *fp __maybe_unused, int color __maybe_unused) 1282 { 1283 return 0; 1284 } 1285 1286 static void FILE__printf(void *fp, const char *fmt, ...) 1287 { 1288 va_list args; 1289 1290 va_start(args, fmt); 1291 vfprintf(fp, fmt, args); 1292 va_end(args); 1293 } 1294 1295 static void FILE__write_graph(void *fp, int graph) 1296 { 1297 const char *s; 1298 switch (graph) { 1299 1300 case DARROW_CHAR: s = "↓"; break; 1301 case UARROW_CHAR: s = "↑"; break; 1302 case LARROW_CHAR: s = "←"; break; 1303 case RARROW_CHAR: s = "→"; break; 1304 default: s = "?"; break; 1305 } 1306 1307 fputs(s, fp); 1308 } 1309 1310 static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) 1311 { 1312 struct annotation *notes = symbol__annotation(sym); 1313 struct annotation_write_ops wops = { 1314 .first_line = true, 1315 .obj = fp, 1316 .set_color = FILE__set_color, 1317 .set_percent_color = FILE__set_percent_color, 1318 .set_jumps_percent_color = FILE__set_jumps_percent_color, 1319 .printf = FILE__printf, 1320 .write_graph = FILE__write_graph, 1321 }; 1322 struct annotation_line *al; 1323 1324 list_for_each_entry(al, ¬es->src->source, node) { 1325 if (annotation_line__filter(al)) 1326 continue; 1327 annotation_line__write(al, notes, &wops); 1328 fputc('\n', fp); 1329 wops.first_line = false; 1330 } 1331 1332 return 0; 1333 } 1334 1335 int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel) 1336 { 1337 const char *ev_name = evsel__name(evsel); 1338 char buf[1024]; 1339 char *filename; 1340 int err = -1; 1341 FILE *fp; 1342 1343 if (asprintf(&filename, "%s.annotation", ms->sym->name) < 0) 1344 return -1; 1345 1346 fp = fopen(filename, "w"); 1347 if (fp == NULL) 1348 goto out_free_filename; 1349 1350 if (evsel__is_group_event(evsel)) { 1351 evsel__group_desc(evsel, buf, sizeof(buf)); 1352 ev_name = buf; 1353 } 1354 1355 fprintf(fp, "%s() %s\nEvent: %s\n\n", 1356 ms->sym->name, dso__long_name(map__dso(ms->map)), ev_name); 1357 symbol__annotate_fprintf2(ms->sym, fp); 1358 1359 fclose(fp); 1360 err = 0; 1361 out_free_filename: 1362 free(filename); 1363 return err; 1364 } 1365 1366 void symbol__annotate_zero_histogram(struct symbol *sym, int evidx) 1367 { 1368 struct annotation *notes = symbol__annotation(sym); 1369 struct sym_hist *h = annotation__histogram(notes, evidx); 1370 1371 memset(h, 0, sizeof(*notes->src->histograms) * notes->src->nr_histograms); 1372 } 1373 1374 void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) 1375 { 1376 struct annotation *notes = symbol__annotation(sym); 1377 struct sym_hist *h = annotation__histogram(notes, evidx); 1378 struct annotation_line *al; 1379 1380 h->nr_samples = 0; 1381 list_for_each_entry(al, ¬es->src->source, node) { 1382 struct sym_hist_entry *entry; 1383 1384 if (al->offset == -1) 1385 continue; 1386 1387 entry = annotated_source__hist_entry(notes->src, evidx, al->offset); 1388 if (entry == NULL) 1389 continue; 1390 1391 entry->nr_samples = entry->nr_samples * 7 / 8; 1392 h->nr_samples += entry->nr_samples; 1393 } 1394 } 1395 1396 void annotated_source__purge(struct annotated_source *as) 1397 { 1398 struct annotation_line *al, *n; 1399 1400 list_for_each_entry_safe(al, n, &as->source, node) { 1401 list_del_init(&al->node); 1402 disasm_line__free(disasm_line(al)); 1403 } 1404 } 1405 1406 static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp) 1407 { 1408 size_t printed; 1409 1410 if (dl->al.offset == -1) 1411 return fprintf(fp, "%s\n", dl->al.line); 1412 1413 printed = fprintf(fp, "%#" PRIx64 " %s", dl->al.offset, dl->ins.name); 1414 1415 if (dl->ops.raw[0] != '\0') { 1416 printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ", 1417 dl->ops.raw); 1418 } 1419 1420 return printed + fprintf(fp, "\n"); 1421 } 1422 1423 size_t disasm__fprintf(struct list_head *head, FILE *fp) 1424 { 1425 struct disasm_line *pos; 1426 size_t printed = 0; 1427 1428 list_for_each_entry(pos, head, al.node) 1429 printed += disasm_line__fprintf(pos, fp); 1430 1431 return printed; 1432 } 1433 1434 bool disasm_line__is_valid_local_jump(struct disasm_line *dl, struct symbol *sym) 1435 { 1436 if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins) || 1437 !disasm_line__has_local_offset(dl) || dl->ops.target.offset < 0 || 1438 dl->ops.target.offset >= (s64)symbol__size(sym)) 1439 return false; 1440 1441 return true; 1442 } 1443 1444 static void 1445 annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) 1446 { 1447 struct annotation_line *al; 1448 1449 /* PLT symbols contain external offsets */ 1450 if (strstr(sym->name, "@plt")) 1451 return; 1452 1453 list_for_each_entry(al, ¬es->src->source, node) { 1454 struct disasm_line *dl; 1455 struct annotation_line *target; 1456 1457 dl = disasm_line(al); 1458 1459 if (!disasm_line__is_valid_local_jump(dl, sym)) 1460 continue; 1461 1462 target = annotated_source__get_line(notes->src, 1463 dl->ops.target.offset); 1464 /* 1465 * FIXME: Oops, no jump target? Buggy disassembler? Or do we 1466 * have to adjust to the previous offset? 1467 */ 1468 if (target == NULL) 1469 continue; 1470 1471 if (++target->jump_sources > notes->src->max_jump_sources) 1472 notes->src->max_jump_sources = target->jump_sources; 1473 } 1474 } 1475 1476 static void annotation__set_index(struct annotation *notes) 1477 { 1478 struct annotation_line *al; 1479 struct annotated_source *src = notes->src; 1480 1481 src->widths.max_line_len = 0; 1482 src->nr_entries = 0; 1483 src->nr_asm_entries = 0; 1484 1485 list_for_each_entry(al, &src->source, node) { 1486 size_t line_len = strlen(al->line); 1487 1488 if (src->widths.max_line_len < line_len) 1489 src->widths.max_line_len = line_len; 1490 al->idx = src->nr_entries++; 1491 if (al->offset != -1) 1492 al->idx_asm = src->nr_asm_entries++; 1493 else 1494 al->idx_asm = -1; 1495 } 1496 } 1497 1498 static inline int width_jumps(int n) 1499 { 1500 if (n >= 100) 1501 return 5; 1502 if (n / 10) 1503 return 2; 1504 return 1; 1505 } 1506 1507 static int annotation__max_ins_name(struct annotation *notes) 1508 { 1509 int max_name = 0, len; 1510 struct annotation_line *al; 1511 1512 list_for_each_entry(al, ¬es->src->source, node) { 1513 if (al->offset == -1) 1514 continue; 1515 1516 len = strlen(disasm_line(al)->ins.name); 1517 if (max_name < len) 1518 max_name = len; 1519 } 1520 1521 return max_name; 1522 } 1523 1524 static void 1525 annotation__init_column_widths(struct annotation *notes, struct symbol *sym) 1526 { 1527 notes->src->widths.addr = notes->src->widths.target = 1528 notes->src->widths.min_addr = hex_width(symbol__size(sym)); 1529 notes->src->widths.max_addr = hex_width(sym->end); 1530 notes->src->widths.jumps = width_jumps(notes->src->max_jump_sources); 1531 notes->src->widths.max_ins_name = annotation__max_ins_name(notes); 1532 } 1533 1534 void annotation__update_column_widths(struct annotation *notes) 1535 { 1536 if (annotate_opts.use_offset) 1537 notes->src->widths.target = notes->src->widths.min_addr; 1538 else if (annotate_opts.full_addr) 1539 notes->src->widths.target = BITS_PER_LONG / 4; 1540 else 1541 notes->src->widths.target = notes->src->widths.max_addr; 1542 1543 notes->src->widths.addr = notes->src->widths.target; 1544 1545 if (annotate_opts.show_nr_jumps) 1546 notes->src->widths.addr += notes->src->widths.jumps + 1; 1547 } 1548 1549 void annotation__toggle_full_addr(struct annotation *notes, struct map_symbol *ms) 1550 { 1551 annotate_opts.full_addr = !annotate_opts.full_addr; 1552 1553 if (annotate_opts.full_addr) 1554 notes->src->start = map__objdump_2mem(ms->map, ms->sym->start); 1555 else 1556 notes->src->start = map__rip_2objdump(ms->map, ms->sym->start); 1557 1558 annotation__update_column_widths(notes); 1559 } 1560 1561 static void annotation__calc_lines(struct annotation *notes, struct map_symbol *ms, 1562 struct rb_root *root) 1563 { 1564 struct annotation_line *al; 1565 struct rb_root tmp_root = RB_ROOT; 1566 1567 list_for_each_entry(al, ¬es->src->source, node) { 1568 double percent_max = 0.0; 1569 u64 addr; 1570 int i; 1571 1572 for (i = 0; i < al->data_nr; i++) { 1573 double percent; 1574 1575 percent = annotation_data__percent(&al->data[i], 1576 annotate_opts.percent_type); 1577 1578 if (percent > percent_max) 1579 percent_max = percent; 1580 } 1581 1582 if (percent_max <= 0.5) 1583 continue; 1584 1585 addr = map__rip_2objdump(ms->map, ms->sym->start); 1586 al->path = get_srcline(map__dso(ms->map), addr + al->offset, NULL, 1587 false, true, ms->sym->start + al->offset); 1588 insert_source_line(&tmp_root, al); 1589 } 1590 1591 resort_source_line(root, &tmp_root); 1592 } 1593 1594 static void symbol__calc_lines(struct map_symbol *ms, struct rb_root *root) 1595 { 1596 struct annotation *notes = symbol__annotation(ms->sym); 1597 1598 annotation__calc_lines(notes, ms, root); 1599 } 1600 1601 int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel) 1602 { 1603 struct dso *dso = map__dso(ms->map); 1604 struct symbol *sym = ms->sym; 1605 struct rb_root source_line = RB_ROOT; 1606 struct hists *hists = evsel__hists(evsel); 1607 char buf[1024]; 1608 int err; 1609 1610 err = symbol__annotate2(ms, evsel, NULL); 1611 if (err) { 1612 char msg[BUFSIZ]; 1613 1614 dso__set_annotate_warned(dso); 1615 symbol__strerror_disassemble(ms, err, msg, sizeof(msg)); 1616 ui__error("Couldn't annotate %s:\n%s", sym->name, msg); 1617 return -1; 1618 } 1619 1620 if (annotate_opts.print_lines) { 1621 srcline_full_filename = annotate_opts.full_path; 1622 symbol__calc_lines(ms, &source_line); 1623 print_summary(&source_line, dso__long_name(dso)); 1624 } 1625 1626 hists__scnprintf_title(hists, buf, sizeof(buf)); 1627 fprintf(stdout, "%s, [percent: %s]\n%s() %s\n", 1628 buf, percent_type_str(annotate_opts.percent_type), sym->name, dso__long_name(dso)); 1629 symbol__annotate_fprintf2(sym, stdout); 1630 1631 annotated_source__purge(symbol__annotation(sym)->src); 1632 1633 return 0; 1634 } 1635 1636 int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel) 1637 { 1638 struct dso *dso = map__dso(ms->map); 1639 struct symbol *sym = ms->sym; 1640 struct rb_root source_line = RB_ROOT; 1641 int err; 1642 1643 err = symbol__annotate(ms, evsel, NULL); 1644 if (err) { 1645 char msg[BUFSIZ]; 1646 1647 dso__set_annotate_warned(dso); 1648 symbol__strerror_disassemble(ms, err, msg, sizeof(msg)); 1649 ui__error("Couldn't annotate %s:\n%s", sym->name, msg); 1650 return -1; 1651 } 1652 1653 symbol__calc_percent(sym, evsel); 1654 1655 if (annotate_opts.print_lines) { 1656 srcline_full_filename = annotate_opts.full_path; 1657 symbol__calc_lines(ms, &source_line); 1658 print_summary(&source_line, dso__long_name(dso)); 1659 } 1660 1661 symbol__annotate_printf(ms, evsel); 1662 1663 annotated_source__purge(symbol__annotation(sym)->src); 1664 1665 return 0; 1666 } 1667 1668 bool ui__has_annotation(void) 1669 { 1670 return use_browser == 1 && perf_hpp_list.sym; 1671 } 1672 1673 1674 static double annotation_line__max_percent(struct annotation_line *al, 1675 unsigned int percent_type) 1676 { 1677 double percent_max = 0.0; 1678 int i; 1679 1680 for (i = 0; i < al->data_nr; i++) { 1681 double percent; 1682 1683 percent = annotation_data__percent(&al->data[i], 1684 percent_type); 1685 1686 if (percent > percent_max) 1687 percent_max = percent; 1688 } 1689 1690 return percent_max; 1691 } 1692 1693 static void disasm_line__write(struct disasm_line *dl, struct annotation *notes, 1694 void *obj, char *bf, size_t size, 1695 void (*obj__printf)(void *obj, const char *fmt, ...), 1696 void (*obj__write_graph)(void *obj, int graph)) 1697 { 1698 if (dl->ins.ops && dl->ins.ops->scnprintf) { 1699 if (ins__is_jump(&dl->ins)) { 1700 bool fwd; 1701 1702 if (dl->ops.target.outside) 1703 goto call_like; 1704 fwd = dl->ops.target.offset > dl->al.offset; 1705 obj__write_graph(obj, fwd ? DARROW_CHAR : UARROW_CHAR); 1706 obj__printf(obj, " "); 1707 } else if (ins__is_call(&dl->ins)) { 1708 call_like: 1709 obj__write_graph(obj, RARROW_CHAR); 1710 obj__printf(obj, " "); 1711 } else if (ins__is_ret(&dl->ins)) { 1712 obj__write_graph(obj, LARROW_CHAR); 1713 obj__printf(obj, " "); 1714 } else { 1715 obj__printf(obj, " "); 1716 } 1717 } else { 1718 obj__printf(obj, " "); 1719 } 1720 1721 disasm_line__scnprintf(dl, bf, size, !annotate_opts.use_offset, 1722 notes->src->widths.max_ins_name); 1723 } 1724 1725 static void ipc_coverage_string(char *bf, int size, struct annotation *notes) 1726 { 1727 double ipc = 0.0, coverage = 0.0; 1728 struct annotated_branch *branch = annotation__get_branch(notes); 1729 1730 if (branch && branch->hit_cycles) 1731 ipc = branch->hit_insn / ((double)branch->hit_cycles); 1732 1733 if (branch && branch->total_insn) { 1734 coverage = branch->cover_insn * 100.0 / 1735 ((double)branch->total_insn); 1736 } 1737 1738 scnprintf(bf, size, "(Average IPC: %.2f, IPC Coverage: %.1f%%)", 1739 ipc, coverage); 1740 } 1741 1742 int annotation_br_cntr_abbr_list(char **str, struct evsel *evsel, bool header) 1743 { 1744 struct evsel *pos; 1745 struct strbuf sb; 1746 1747 if (evsel->evlist->nr_br_cntr <= 0) 1748 return -ENOTSUP; 1749 1750 strbuf_init(&sb, /*hint=*/ 0); 1751 1752 if (header && strbuf_addf(&sb, "# Branch counter abbr list:\n")) 1753 goto err; 1754 1755 evlist__for_each_entry(evsel->evlist, pos) { 1756 if (!(pos->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS)) 1757 continue; 1758 if (header && strbuf_addf(&sb, "#")) 1759 goto err; 1760 1761 if (strbuf_addf(&sb, " %s = %s\n", pos->name, pos->abbr_name)) 1762 goto err; 1763 } 1764 1765 if (header && strbuf_addf(&sb, "#")) 1766 goto err; 1767 if (strbuf_addf(&sb, " '-' No event occurs\n")) 1768 goto err; 1769 1770 if (header && strbuf_addf(&sb, "#")) 1771 goto err; 1772 if (strbuf_addf(&sb, " '+' Event occurrences may be lost due to branch counter saturated\n")) 1773 goto err; 1774 1775 *str = strbuf_detach(&sb, NULL); 1776 1777 return 0; 1778 err: 1779 strbuf_release(&sb); 1780 return -ENOMEM; 1781 } 1782 1783 /* Assume the branch counter saturated at 3 */ 1784 #define ANNOTATION_BR_CNTR_SATURATION 3 1785 1786 int annotation_br_cntr_entry(char **str, int br_cntr_nr, 1787 u64 *br_cntr, int num_aggr, 1788 struct evsel *evsel) 1789 { 1790 struct evsel *pos = evsel ? evlist__first(evsel->evlist) : NULL; 1791 bool saturated = false; 1792 int i, j, avg, used; 1793 struct strbuf sb; 1794 1795 strbuf_init(&sb, /*hint=*/ 0); 1796 for (i = 0; i < br_cntr_nr; i++) { 1797 used = 0; 1798 avg = ceil((double)(br_cntr[i] & ~ANNOTATION__BR_CNTR_SATURATED_FLAG) / 1799 (double)num_aggr); 1800 1801 /* 1802 * A histogram with the abbr name is displayed by default. 1803 * With -v, the exact number of branch counter is displayed. 1804 */ 1805 if (verbose) { 1806 evlist__for_each_entry_from(evsel->evlist, pos) { 1807 if ((pos->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS) && 1808 (pos->br_cntr_idx == i)) 1809 break; 1810 } 1811 if (strbuf_addstr(&sb, pos->abbr_name)) 1812 goto err; 1813 1814 if (!br_cntr[i]) { 1815 if (strbuf_addstr(&sb, "=-")) 1816 goto err; 1817 } else { 1818 if (strbuf_addf(&sb, "=%d", avg)) 1819 goto err; 1820 } 1821 if (br_cntr[i] & ANNOTATION__BR_CNTR_SATURATED_FLAG) { 1822 if (strbuf_addch(&sb, '+')) 1823 goto err; 1824 } else { 1825 if (strbuf_addch(&sb, ' ')) 1826 goto err; 1827 } 1828 1829 if ((i < br_cntr_nr - 1) && strbuf_addch(&sb, ',')) 1830 goto err; 1831 continue; 1832 } 1833 1834 if (strbuf_addch(&sb, '|')) 1835 goto err; 1836 1837 if (!br_cntr[i]) { 1838 if (strbuf_addch(&sb, '-')) 1839 goto err; 1840 used++; 1841 } else { 1842 evlist__for_each_entry_from(evsel->evlist, pos) { 1843 if ((pos->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS) && 1844 (pos->br_cntr_idx == i)) 1845 break; 1846 } 1847 if (br_cntr[i] & ANNOTATION__BR_CNTR_SATURATED_FLAG) 1848 saturated = true; 1849 1850 for (j = 0; j < avg; j++, used++) { 1851 /* Print + if the number of logged events > 3 */ 1852 if (j >= ANNOTATION_BR_CNTR_SATURATION) { 1853 saturated = true; 1854 break; 1855 } 1856 if (strbuf_addstr(&sb, pos->abbr_name)) 1857 goto err; 1858 } 1859 1860 if (saturated) { 1861 if (strbuf_addch(&sb, '+')) 1862 goto err; 1863 used++; 1864 } 1865 pos = list_next_entry(pos, core.node); 1866 } 1867 1868 for (j = used; j < ANNOTATION_BR_CNTR_SATURATION + 1; j++) { 1869 if (strbuf_addch(&sb, ' ')) 1870 goto err; 1871 } 1872 } 1873 1874 if (!verbose && strbuf_addch(&sb, br_cntr_nr ? '|' : ' ')) 1875 goto err; 1876 1877 *str = strbuf_detach(&sb, NULL); 1878 1879 return 0; 1880 err: 1881 strbuf_release(&sb); 1882 return -ENOMEM; 1883 } 1884 1885 static void __annotation_line__write(struct annotation_line *al, struct annotation *notes, 1886 bool first_line, bool current_entry, bool change_color, int width, 1887 void *obj, unsigned int percent_type, 1888 int (*obj__set_color)(void *obj, int color), 1889 void (*obj__set_percent_color)(void *obj, double percent, bool current), 1890 int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), 1891 void (*obj__printf)(void *obj, const char *fmt, ...), 1892 void (*obj__write_graph)(void *obj, int graph)) 1893 1894 { 1895 double percent_max = annotation_line__max_percent(al, percent_type); 1896 int pcnt_width = annotation__pcnt_width(notes), 1897 cycles_width = annotation__cycles_width(notes); 1898 bool show_title = false; 1899 char bf[256]; 1900 int printed; 1901 1902 if (first_line && (al->offset == -1 || percent_max == 0.0)) { 1903 if (notes->branch && al->cycles) { 1904 if (al->cycles->ipc == 0.0 && al->cycles->avg == 0) 1905 show_title = true; 1906 } else 1907 show_title = true; 1908 } 1909 1910 if (al->offset != -1 && percent_max != 0.0) { 1911 int i; 1912 1913 for (i = 0; i < al->data_nr; i++) { 1914 double percent; 1915 1916 percent = annotation_data__percent(&al->data[i], percent_type); 1917 1918 obj__set_percent_color(obj, percent, current_entry); 1919 if (symbol_conf.show_total_period) { 1920 obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period); 1921 } else if (symbol_conf.show_nr_samples) { 1922 obj__printf(obj, "%7" PRIu64 " ", 1923 al->data[i].he.nr_samples); 1924 } else { 1925 obj__printf(obj, "%7.2f ", percent); 1926 } 1927 } 1928 } else { 1929 obj__set_percent_color(obj, 0, current_entry); 1930 1931 if (!show_title) 1932 obj__printf(obj, "%-*s", pcnt_width, " "); 1933 else { 1934 obj__printf(obj, "%-*s", pcnt_width, 1935 symbol_conf.show_total_period ? "Period" : 1936 symbol_conf.show_nr_samples ? "Samples" : "Percent"); 1937 } 1938 } 1939 1940 if (notes->branch) { 1941 if (al->cycles && al->cycles->ipc) 1942 obj__printf(obj, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->cycles->ipc); 1943 else if (!show_title) 1944 obj__printf(obj, "%*s", ANNOTATION__IPC_WIDTH, " "); 1945 else 1946 obj__printf(obj, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC"); 1947 1948 if (!annotate_opts.show_minmax_cycle) { 1949 if (al->cycles && al->cycles->avg) 1950 obj__printf(obj, "%*" PRIu64 " ", 1951 ANNOTATION__CYCLES_WIDTH - 1, al->cycles->avg); 1952 else if (!show_title) 1953 obj__printf(obj, "%*s", 1954 ANNOTATION__CYCLES_WIDTH, " "); 1955 else 1956 obj__printf(obj, "%*s ", 1957 ANNOTATION__CYCLES_WIDTH - 1, 1958 "Cycle"); 1959 } else { 1960 if (al->cycles) { 1961 char str[32]; 1962 1963 scnprintf(str, sizeof(str), 1964 "%" PRIu64 "(%" PRIu64 "/%" PRIu64 ")", 1965 al->cycles->avg, al->cycles->min, 1966 al->cycles->max); 1967 1968 obj__printf(obj, "%*s ", 1969 ANNOTATION__MINMAX_CYCLES_WIDTH - 1, 1970 str); 1971 } else if (!show_title) 1972 obj__printf(obj, "%*s", 1973 ANNOTATION__MINMAX_CYCLES_WIDTH, 1974 " "); 1975 else 1976 obj__printf(obj, "%*s ", 1977 ANNOTATION__MINMAX_CYCLES_WIDTH - 1, 1978 "Cycle(min/max)"); 1979 } 1980 1981 if (annotate_opts.show_br_cntr) { 1982 if (show_title) { 1983 obj__printf(obj, "%*s ", 1984 ANNOTATION__BR_CNTR_WIDTH, 1985 "Branch Counter"); 1986 } else { 1987 char *buf; 1988 1989 if (!annotation_br_cntr_entry(&buf, al->br_cntr_nr, al->br_cntr, 1990 al->num_aggr, al->evsel)) { 1991 obj__printf(obj, "%*s ", ANNOTATION__BR_CNTR_WIDTH, buf); 1992 free(buf); 1993 } 1994 } 1995 } 1996 1997 if (show_title && !*al->line) { 1998 ipc_coverage_string(bf, sizeof(bf), notes); 1999 obj__printf(obj, "%*s", ANNOTATION__AVG_IPC_WIDTH, bf); 2000 } 2001 } 2002 2003 obj__printf(obj, " "); 2004 2005 if (!*al->line) 2006 obj__printf(obj, "%-*s", width - pcnt_width - cycles_width, " "); 2007 else if (al->offset == -1) { 2008 if (al->line_nr && annotate_opts.show_linenr) 2009 printed = scnprintf(bf, sizeof(bf), "%-*d ", 2010 notes->src->widths.addr + 1, al->line_nr); 2011 else 2012 printed = scnprintf(bf, sizeof(bf), "%-*s ", 2013 notes->src->widths.addr, " "); 2014 obj__printf(obj, bf); 2015 obj__printf(obj, "%-*s", width - printed - pcnt_width - cycles_width + 1, al->line); 2016 } else { 2017 u64 addr = al->offset; 2018 int color = -1; 2019 2020 if (!annotate_opts.use_offset) 2021 addr += notes->src->start; 2022 2023 if (!annotate_opts.use_offset) { 2024 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); 2025 } else { 2026 if (al->jump_sources && 2027 annotate_opts.offset_level >= ANNOTATION__OFFSET_JUMP_TARGETS) { 2028 if (annotate_opts.show_nr_jumps) { 2029 int prev; 2030 printed = scnprintf(bf, sizeof(bf), "%*d ", 2031 notes->src->widths.jumps, 2032 al->jump_sources); 2033 prev = obj__set_jumps_percent_color(obj, al->jump_sources, 2034 current_entry); 2035 obj__printf(obj, bf); 2036 obj__set_color(obj, prev); 2037 } 2038 print_addr: 2039 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ", 2040 notes->src->widths.target, addr); 2041 } else if (ins__is_call(&disasm_line(al)->ins) && 2042 annotate_opts.offset_level >= ANNOTATION__OFFSET_CALL) { 2043 goto print_addr; 2044 } else if (annotate_opts.offset_level == ANNOTATION__MAX_OFFSET_LEVEL) { 2045 goto print_addr; 2046 } else { 2047 printed = scnprintf(bf, sizeof(bf), "%-*s ", 2048 notes->src->widths.addr, " "); 2049 } 2050 } 2051 2052 if (change_color) 2053 color = obj__set_color(obj, HE_COLORSET_ADDR); 2054 obj__printf(obj, bf); 2055 if (change_color) 2056 obj__set_color(obj, color); 2057 2058 disasm_line__write(disasm_line(al), notes, obj, bf, sizeof(bf), obj__printf, obj__write_graph); 2059 2060 obj__printf(obj, "%-*s", width - pcnt_width - cycles_width - 3 - printed, bf); 2061 } 2062 2063 } 2064 2065 void annotation_line__write(struct annotation_line *al, struct annotation *notes, 2066 struct annotation_write_ops *wops) 2067 { 2068 __annotation_line__write(al, notes, wops->first_line, wops->current_entry, 2069 wops->change_color, wops->width, wops->obj, 2070 annotate_opts.percent_type, 2071 wops->set_color, wops->set_percent_color, 2072 wops->set_jumps_percent_color, wops->printf, 2073 wops->write_graph); 2074 } 2075 2076 int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel, 2077 struct arch **parch) 2078 { 2079 struct symbol *sym = ms->sym; 2080 struct annotation *notes = symbol__annotation(sym); 2081 size_t size = symbol__size(sym); 2082 int err; 2083 2084 err = symbol__annotate(ms, evsel, parch); 2085 if (err) 2086 return err; 2087 2088 symbol__calc_percent(sym, evsel); 2089 2090 annotation__set_index(notes); 2091 annotation__mark_jump_targets(notes, sym); 2092 2093 err = annotation__compute_ipc(notes, size, evsel); 2094 if (err) 2095 return err; 2096 2097 annotation__init_column_widths(notes, sym); 2098 annotation__update_column_widths(notes); 2099 sym->annotate2 = 1; 2100 2101 return 0; 2102 } 2103 2104 static int annotation__config(const char *var, const char *value, void *data) 2105 { 2106 struct annotation_options *opt = data; 2107 2108 if (!strstarts(var, "annotate.")) 2109 return 0; 2110 2111 if (!strcmp(var, "annotate.offset_level")) { 2112 perf_config_u8(&opt->offset_level, "offset_level", value); 2113 2114 if (opt->offset_level > ANNOTATION__MAX_OFFSET_LEVEL) 2115 opt->offset_level = ANNOTATION__MAX_OFFSET_LEVEL; 2116 else if (opt->offset_level < ANNOTATION__MIN_OFFSET_LEVEL) 2117 opt->offset_level = ANNOTATION__MIN_OFFSET_LEVEL; 2118 } else if (!strcmp(var, "annotate.hide_src_code")) { 2119 opt->hide_src_code = perf_config_bool("hide_src_code", value); 2120 } else if (!strcmp(var, "annotate.jump_arrows")) { 2121 opt->jump_arrows = perf_config_bool("jump_arrows", value); 2122 } else if (!strcmp(var, "annotate.show_linenr")) { 2123 opt->show_linenr = perf_config_bool("show_linenr", value); 2124 } else if (!strcmp(var, "annotate.show_nr_jumps")) { 2125 opt->show_nr_jumps = perf_config_bool("show_nr_jumps", value); 2126 } else if (!strcmp(var, "annotate.show_nr_samples")) { 2127 symbol_conf.show_nr_samples = perf_config_bool("show_nr_samples", 2128 value); 2129 } else if (!strcmp(var, "annotate.show_total_period")) { 2130 symbol_conf.show_total_period = perf_config_bool("show_total_period", 2131 value); 2132 } else if (!strcmp(var, "annotate.use_offset")) { 2133 opt->use_offset = perf_config_bool("use_offset", value); 2134 } else if (!strcmp(var, "annotate.disassembler_style")) { 2135 opt->disassembler_style = strdup(value); 2136 if (!opt->disassembler_style) { 2137 pr_err("Not enough memory for annotate.disassembler_style\n"); 2138 return -1; 2139 } 2140 } else if (!strcmp(var, "annotate.objdump")) { 2141 opt->objdump_path = strdup(value); 2142 if (!opt->objdump_path) { 2143 pr_err("Not enough memory for annotate.objdump\n"); 2144 return -1; 2145 } 2146 } else if (!strcmp(var, "annotate.addr2line")) { 2147 symbol_conf.addr2line_path = strdup(value); 2148 if (!symbol_conf.addr2line_path) { 2149 pr_err("Not enough memory for annotate.addr2line\n"); 2150 return -1; 2151 } 2152 } else if (!strcmp(var, "annotate.demangle")) { 2153 symbol_conf.demangle = perf_config_bool("demangle", value); 2154 } else if (!strcmp(var, "annotate.demangle_kernel")) { 2155 symbol_conf.demangle_kernel = perf_config_bool("demangle_kernel", value); 2156 } else { 2157 pr_debug("%s variable unknown, ignoring...", var); 2158 } 2159 2160 return 0; 2161 } 2162 2163 void annotation_options__init(void) 2164 { 2165 struct annotation_options *opt = &annotate_opts; 2166 2167 memset(opt, 0, sizeof(*opt)); 2168 2169 /* Default values. */ 2170 opt->use_offset = true; 2171 opt->jump_arrows = true; 2172 opt->annotate_src = true; 2173 opt->offset_level = ANNOTATION__OFFSET_JUMP_TARGETS; 2174 opt->percent_type = PERCENT_PERIOD_LOCAL; 2175 } 2176 2177 void annotation_options__exit(void) 2178 { 2179 zfree(&annotate_opts.disassembler_style); 2180 zfree(&annotate_opts.objdump_path); 2181 } 2182 2183 void annotation_config__init(void) 2184 { 2185 perf_config(annotation__config, &annotate_opts); 2186 } 2187 2188 static unsigned int parse_percent_type(char *str1, char *str2) 2189 { 2190 unsigned int type = (unsigned int) -1; 2191 2192 if (!strcmp("period", str1)) { 2193 if (!strcmp("local", str2)) 2194 type = PERCENT_PERIOD_LOCAL; 2195 else if (!strcmp("global", str2)) 2196 type = PERCENT_PERIOD_GLOBAL; 2197 } 2198 2199 if (!strcmp("hits", str1)) { 2200 if (!strcmp("local", str2)) 2201 type = PERCENT_HITS_LOCAL; 2202 else if (!strcmp("global", str2)) 2203 type = PERCENT_HITS_GLOBAL; 2204 } 2205 2206 return type; 2207 } 2208 2209 int annotate_parse_percent_type(const struct option *opt __maybe_unused, const char *_str, 2210 int unset __maybe_unused) 2211 { 2212 unsigned int type; 2213 char *str1, *str2; 2214 int err = -1; 2215 2216 str1 = strdup(_str); 2217 if (!str1) 2218 return -ENOMEM; 2219 2220 str2 = strchr(str1, '-'); 2221 if (!str2) 2222 goto out; 2223 2224 *str2++ = 0; 2225 2226 type = parse_percent_type(str1, str2); 2227 if (type == (unsigned int) -1) 2228 type = parse_percent_type(str2, str1); 2229 if (type != (unsigned int) -1) { 2230 annotate_opts.percent_type = type; 2231 err = 0; 2232 } 2233 2234 out: 2235 free(str1); 2236 return err; 2237 } 2238 2239 int annotate_check_args(void) 2240 { 2241 struct annotation_options *args = &annotate_opts; 2242 2243 if (args->prefix_strip && !args->prefix) { 2244 pr_err("--prefix-strip requires --prefix\n"); 2245 return -1; 2246 } 2247 return 0; 2248 } 2249 2250 /* 2251 * Get register number and access offset from the given instruction. 2252 * It assumes AT&T x86 asm format like OFFSET(REG). Maybe it needs 2253 * to revisit the format when it handles different architecture. 2254 * Fills @reg and @offset when return 0. 2255 */ 2256 static int extract_reg_offset(struct arch *arch, const char *str, 2257 struct annotated_op_loc *op_loc) 2258 { 2259 char *p; 2260 char *regname; 2261 2262 if (arch->objdump.register_char == 0) 2263 return -1; 2264 2265 /* 2266 * It should start from offset, but it's possible to skip 0 2267 * in the asm. So 0(%rax) should be same as (%rax). 2268 * 2269 * However, it also start with a segment select register like 2270 * %gs:0x18(%rbx). In that case it should skip the part. 2271 */ 2272 if (*str == arch->objdump.register_char) { 2273 if (arch__is(arch, "x86")) { 2274 /* FIXME: Handle other segment registers */ 2275 if (!strncmp(str, "%gs:", 4)) 2276 op_loc->segment = INSN_SEG_X86_GS; 2277 } 2278 2279 while (*str && !isdigit(*str) && 2280 *str != arch->objdump.memory_ref_char) 2281 str++; 2282 } 2283 2284 op_loc->offset = strtol(str, &p, 0); 2285 2286 p = strchr(p, arch->objdump.register_char); 2287 if (p == NULL) 2288 return -1; 2289 2290 regname = strdup(p); 2291 if (regname == NULL) 2292 return -1; 2293 2294 op_loc->reg1 = get_dwarf_regnum(regname, 0); 2295 free(regname); 2296 2297 /* Get the second register */ 2298 if (op_loc->multi_regs) { 2299 p = strchr(p + 1, arch->objdump.register_char); 2300 if (p == NULL) 2301 return -1; 2302 2303 regname = strdup(p); 2304 if (regname == NULL) 2305 return -1; 2306 2307 op_loc->reg2 = get_dwarf_regnum(regname, 0); 2308 free(regname); 2309 } 2310 return 0; 2311 } 2312 2313 /** 2314 * annotate_get_insn_location - Get location of instruction 2315 * @arch: the architecture info 2316 * @dl: the target instruction 2317 * @loc: a buffer to save the data 2318 * 2319 * Get detailed location info (register and offset) in the instruction. 2320 * It needs both source and target operand and whether it accesses a 2321 * memory location. The offset field is meaningful only when the 2322 * corresponding mem flag is set. The reg2 field is meaningful only 2323 * when multi_regs flag is set. 2324 * 2325 * Some examples on x86: 2326 * 2327 * mov (%rax), %rcx # src_reg1 = rax, src_mem = 1, src_offset = 0 2328 * # dst_reg1 = rcx, dst_mem = 0 2329 * 2330 * mov 0x18, %r8 # src_reg1 = -1, src_mem = 0 2331 * # dst_reg1 = r8, dst_mem = 0 2332 * 2333 * mov %rsi, 8(%rbx,%rcx,4) # src_reg1 = rsi, src_mem = 0, src_multi_regs = 0 2334 * # dst_reg1 = rbx, dst_reg2 = rcx, dst_mem = 1 2335 * # dst_multi_regs = 1, dst_offset = 8 2336 */ 2337 int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl, 2338 struct annotated_insn_loc *loc) 2339 { 2340 struct ins_operands *ops; 2341 struct annotated_op_loc *op_loc; 2342 int i; 2343 2344 if (ins__is_lock(&dl->ins)) 2345 ops = dl->ops.locked.ops; 2346 else 2347 ops = &dl->ops; 2348 2349 if (ops == NULL) 2350 return -1; 2351 2352 memset(loc, 0, sizeof(*loc)); 2353 2354 for_each_insn_op_loc(loc, i, op_loc) { 2355 const char *insn_str = ops->source.raw; 2356 bool multi_regs = ops->source.multi_regs; 2357 bool mem_ref = ops->source.mem_ref; 2358 2359 if (i == INSN_OP_TARGET) { 2360 insn_str = ops->target.raw; 2361 multi_regs = ops->target.multi_regs; 2362 mem_ref = ops->target.mem_ref; 2363 } 2364 2365 /* Invalidate the register by default */ 2366 op_loc->reg1 = -1; 2367 op_loc->reg2 = -1; 2368 2369 if (insn_str == NULL) { 2370 if (!arch__is(arch, "powerpc")) 2371 continue; 2372 } 2373 2374 /* 2375 * For powerpc, call get_powerpc_regs function which extracts the 2376 * required fields for op_loc, ie reg1, reg2, offset from the 2377 * raw instruction. 2378 */ 2379 if (arch__is(arch, "powerpc")) { 2380 op_loc->mem_ref = mem_ref; 2381 op_loc->multi_regs = multi_regs; 2382 get_powerpc_regs(dl->raw.raw_insn, !i, op_loc); 2383 } else if (strchr(insn_str, arch->objdump.memory_ref_char)) { 2384 op_loc->mem_ref = true; 2385 op_loc->multi_regs = multi_regs; 2386 extract_reg_offset(arch, insn_str, op_loc); 2387 } else { 2388 char *s, *p = NULL; 2389 2390 if (arch__is(arch, "x86")) { 2391 /* FIXME: Handle other segment registers */ 2392 if (!strncmp(insn_str, "%gs:", 4)) { 2393 op_loc->segment = INSN_SEG_X86_GS; 2394 op_loc->offset = strtol(insn_str + 4, 2395 &p, 0); 2396 if (p && p != insn_str + 4) 2397 op_loc->imm = true; 2398 continue; 2399 } 2400 } 2401 2402 s = strdup(insn_str); 2403 if (s == NULL) 2404 return -1; 2405 2406 if (*s == arch->objdump.register_char) 2407 op_loc->reg1 = get_dwarf_regnum(s, 0); 2408 else if (*s == arch->objdump.imm_char) { 2409 op_loc->offset = strtol(s + 1, &p, 0); 2410 if (p && p != s + 1) 2411 op_loc->imm = true; 2412 } 2413 free(s); 2414 } 2415 } 2416 2417 return 0; 2418 } 2419 2420 static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip, 2421 bool allow_update) 2422 { 2423 struct disasm_line *dl; 2424 struct annotation *notes; 2425 2426 notes = symbol__annotation(sym); 2427 2428 list_for_each_entry(dl, ¬es->src->source, al.node) { 2429 if (dl->al.offset == -1) 2430 continue; 2431 2432 if (sym->start + dl->al.offset == ip) { 2433 /* 2434 * llvm-objdump places "lock" in a separate line and 2435 * in that case, we want to get the next line. 2436 */ 2437 if (ins__is_lock(&dl->ins) && 2438 *dl->ops.raw == '\0' && allow_update) { 2439 ip++; 2440 continue; 2441 } 2442 return dl; 2443 } 2444 } 2445 return NULL; 2446 } 2447 2448 static struct annotated_item_stat *annotate_data_stat(struct list_head *head, 2449 const char *name) 2450 { 2451 struct annotated_item_stat *istat; 2452 2453 list_for_each_entry(istat, head, list) { 2454 if (!strcmp(istat->name, name)) 2455 return istat; 2456 } 2457 2458 istat = zalloc(sizeof(*istat)); 2459 if (istat == NULL) 2460 return NULL; 2461 2462 istat->name = strdup(name); 2463 if ((istat->name == NULL) || (!strlen(istat->name))) { 2464 free(istat); 2465 return NULL; 2466 } 2467 2468 list_add_tail(&istat->list, head); 2469 return istat; 2470 } 2471 2472 static bool is_stack_operation(struct arch *arch, struct disasm_line *dl) 2473 { 2474 if (arch__is(arch, "x86")) { 2475 if (!strncmp(dl->ins.name, "push", 4) || 2476 !strncmp(dl->ins.name, "pop", 3) || 2477 !strncmp(dl->ins.name, "ret", 3)) 2478 return true; 2479 } 2480 2481 return false; 2482 } 2483 2484 static bool is_stack_canary(struct arch *arch, struct annotated_op_loc *loc) 2485 { 2486 /* On x86_64, %gs:40 is used for stack canary */ 2487 if (arch__is(arch, "x86")) { 2488 if (loc->segment == INSN_SEG_X86_GS && loc->imm && 2489 loc->offset == 40) 2490 return true; 2491 } 2492 2493 return false; 2494 } 2495 2496 static struct disasm_line * 2497 annotation__prev_asm_line(struct annotation *notes, struct disasm_line *curr) 2498 { 2499 struct list_head *sources = ¬es->src->source; 2500 struct disasm_line *prev; 2501 2502 if (curr == list_first_entry(sources, struct disasm_line, al.node)) 2503 return NULL; 2504 2505 prev = list_prev_entry(curr, al.node); 2506 while (prev->al.offset == -1 && 2507 prev != list_first_entry(sources, struct disasm_line, al.node)) 2508 prev = list_prev_entry(prev, al.node); 2509 2510 if (prev->al.offset == -1) 2511 return NULL; 2512 2513 return prev; 2514 } 2515 2516 static struct disasm_line * 2517 annotation__next_asm_line(struct annotation *notes, struct disasm_line *curr) 2518 { 2519 struct list_head *sources = ¬es->src->source; 2520 struct disasm_line *next; 2521 2522 if (curr == list_last_entry(sources, struct disasm_line, al.node)) 2523 return NULL; 2524 2525 next = list_next_entry(curr, al.node); 2526 while (next->al.offset == -1 && 2527 next != list_last_entry(sources, struct disasm_line, al.node)) 2528 next = list_next_entry(next, al.node); 2529 2530 if (next->al.offset == -1) 2531 return NULL; 2532 2533 return next; 2534 } 2535 2536 u64 annotate_calc_pcrel(struct map_symbol *ms, u64 ip, int offset, 2537 struct disasm_line *dl) 2538 { 2539 struct annotation *notes; 2540 struct disasm_line *next; 2541 u64 addr; 2542 2543 notes = symbol__annotation(ms->sym); 2544 /* 2545 * PC-relative addressing starts from the next instruction address 2546 * But the IP is for the current instruction. Since disasm_line 2547 * doesn't have the instruction size, calculate it using the next 2548 * disasm_line. If it's the last one, we can use symbol's end 2549 * address directly. 2550 */ 2551 next = annotation__next_asm_line(notes, dl); 2552 if (next == NULL) 2553 addr = ms->sym->end + offset; 2554 else 2555 addr = ip + (next->al.offset - dl->al.offset) + offset; 2556 2557 return map__rip_2objdump(ms->map, addr); 2558 } 2559 2560 static struct debuginfo_cache { 2561 struct dso *dso; 2562 struct debuginfo *dbg; 2563 } di_cache; 2564 2565 void debuginfo_cache__delete(void) 2566 { 2567 dso__put(di_cache.dso); 2568 di_cache.dso = NULL; 2569 2570 debuginfo__delete(di_cache.dbg); 2571 di_cache.dbg = NULL; 2572 } 2573 2574 /** 2575 * hist_entry__get_data_type - find data type for given hist entry 2576 * @he: hist entry 2577 * 2578 * This function first annotates the instruction at @he->ip and extracts 2579 * register and offset info from it. Then it searches the DWARF debug 2580 * info to get a variable and type information using the address, register, 2581 * and offset. 2582 */ 2583 struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) 2584 { 2585 struct map_symbol *ms = &he->ms; 2586 struct evsel *evsel = hists_to_evsel(he->hists); 2587 struct arch *arch; 2588 struct disasm_line *dl; 2589 struct annotated_insn_loc loc; 2590 struct annotated_op_loc *op_loc; 2591 struct annotated_data_type *mem_type; 2592 struct annotated_item_stat *istat; 2593 u64 ip = he->ip; 2594 int i; 2595 2596 ann_data_stat.total++; 2597 2598 if (ms->map == NULL || ms->sym == NULL) { 2599 ann_data_stat.no_sym++; 2600 return NULL; 2601 } 2602 2603 if (!symbol_conf.init_annotation) { 2604 ann_data_stat.no_sym++; 2605 return NULL; 2606 } 2607 2608 /* 2609 * di_cache holds a pair of values, but code below assumes 2610 * di_cache.dso can be compared/updated and di_cache.dbg can be 2611 * read/updated independently from each other. That assumption only 2612 * holds in single threaded code. 2613 */ 2614 assert(perf_singlethreaded); 2615 2616 if (map__dso(ms->map) != di_cache.dso) { 2617 dso__put(di_cache.dso); 2618 di_cache.dso = dso__get(map__dso(ms->map)); 2619 2620 debuginfo__delete(di_cache.dbg); 2621 di_cache.dbg = debuginfo__new(dso__long_name(di_cache.dso)); 2622 } 2623 2624 if (di_cache.dbg == NULL) { 2625 ann_data_stat.no_dbginfo++; 2626 return NULL; 2627 } 2628 2629 /* Make sure it has the disasm of the function */ 2630 if (symbol__annotate(ms, evsel, &arch) < 0) { 2631 ann_data_stat.no_insn++; 2632 return NULL; 2633 } 2634 2635 /* 2636 * Get a disasm to extract the location from the insn. 2637 * This is too slow... 2638 */ 2639 dl = find_disasm_line(ms->sym, ip, /*allow_update=*/true); 2640 if (dl == NULL) { 2641 ann_data_stat.no_insn++; 2642 return NULL; 2643 } 2644 2645 retry: 2646 istat = annotate_data_stat(&ann_insn_stat, dl->ins.name); 2647 if (istat == NULL) { 2648 ann_data_stat.no_insn++; 2649 return NULL; 2650 } 2651 2652 if (annotate_get_insn_location(arch, dl, &loc) < 0) { 2653 ann_data_stat.no_insn_ops++; 2654 istat->bad++; 2655 return NULL; 2656 } 2657 2658 if (is_stack_operation(arch, dl)) { 2659 istat->good++; 2660 he->mem_type_off = 0; 2661 return &stackop_type; 2662 } 2663 2664 for_each_insn_op_loc(&loc, i, op_loc) { 2665 struct data_loc_info dloc = { 2666 .arch = arch, 2667 .thread = he->thread, 2668 .ms = ms, 2669 /* Recalculate IP for LOCK prefix or insn fusion */ 2670 .ip = ms->sym->start + dl->al.offset, 2671 .cpumode = he->cpumode, 2672 .op = op_loc, 2673 .di = di_cache.dbg, 2674 }; 2675 2676 if (!op_loc->mem_ref && op_loc->segment == INSN_SEG_NONE) 2677 continue; 2678 2679 /* Recalculate IP because of LOCK prefix or insn fusion */ 2680 ip = ms->sym->start + dl->al.offset; 2681 2682 /* PC-relative addressing */ 2683 if (op_loc->reg1 == DWARF_REG_PC) { 2684 dloc.var_addr = annotate_calc_pcrel(ms, dloc.ip, 2685 op_loc->offset, dl); 2686 } 2687 2688 /* This CPU access in kernel - pretend PC-relative addressing */ 2689 if (dso__kernel(map__dso(ms->map)) && arch__is(arch, "x86") && 2690 op_loc->segment == INSN_SEG_X86_GS && op_loc->imm) { 2691 dloc.var_addr = op_loc->offset; 2692 op_loc->reg1 = DWARF_REG_PC; 2693 } 2694 2695 mem_type = find_data_type(&dloc); 2696 2697 if (mem_type == NULL && is_stack_canary(arch, op_loc)) { 2698 istat->good++; 2699 he->mem_type_off = 0; 2700 return &canary_type; 2701 } 2702 2703 if (mem_type) 2704 istat->good++; 2705 else 2706 istat->bad++; 2707 2708 if (symbol_conf.annotate_data_sample) { 2709 annotated_data_type__update_samples(mem_type, evsel, 2710 dloc.type_offset, 2711 he->stat.nr_events, 2712 he->stat.period); 2713 } 2714 he->mem_type_off = dloc.type_offset; 2715 return mem_type; 2716 } 2717 2718 /* 2719 * Some instructions can be fused and the actual memory access came 2720 * from the previous instruction. 2721 */ 2722 if (dl->al.offset > 0) { 2723 struct annotation *notes; 2724 struct disasm_line *prev_dl; 2725 2726 notes = symbol__annotation(ms->sym); 2727 prev_dl = annotation__prev_asm_line(notes, dl); 2728 2729 if (prev_dl && ins__is_fused(arch, prev_dl->ins.name, dl->ins.name)) { 2730 dl = prev_dl; 2731 goto retry; 2732 } 2733 } 2734 2735 ann_data_stat.no_mem_ops++; 2736 istat->bad++; 2737 return NULL; 2738 } 2739 2740 /* Basic block traversal (BFS) data structure */ 2741 struct basic_block_data { 2742 struct list_head queue; 2743 struct list_head visited; 2744 }; 2745 2746 /* 2747 * During the traversal, it needs to know the parent block where the current 2748 * block block started from. Note that single basic block can be parent of 2749 * two child basic blocks (in case of condition jump). 2750 */ 2751 struct basic_block_link { 2752 struct list_head node; 2753 struct basic_block_link *parent; 2754 struct annotated_basic_block *bb; 2755 }; 2756 2757 /* Check any of basic block in the list already has the offset */ 2758 static bool basic_block_has_offset(struct list_head *head, s64 offset) 2759 { 2760 struct basic_block_link *link; 2761 2762 list_for_each_entry(link, head, node) { 2763 s64 begin_offset = link->bb->begin->al.offset; 2764 s64 end_offset = link->bb->end->al.offset; 2765 2766 if (begin_offset <= offset && offset <= end_offset) 2767 return true; 2768 } 2769 return false; 2770 } 2771 2772 static bool is_new_basic_block(struct basic_block_data *bb_data, 2773 struct disasm_line *dl) 2774 { 2775 s64 offset = dl->al.offset; 2776 2777 if (basic_block_has_offset(&bb_data->visited, offset)) 2778 return false; 2779 if (basic_block_has_offset(&bb_data->queue, offset)) 2780 return false; 2781 return true; 2782 } 2783 2784 /* Add a basic block starting from dl and link it to the parent */ 2785 static int add_basic_block(struct basic_block_data *bb_data, 2786 struct basic_block_link *parent, 2787 struct disasm_line *dl) 2788 { 2789 struct annotated_basic_block *bb; 2790 struct basic_block_link *link; 2791 2792 if (dl == NULL) 2793 return -1; 2794 2795 if (!is_new_basic_block(bb_data, dl)) 2796 return 0; 2797 2798 bb = zalloc(sizeof(*bb)); 2799 if (bb == NULL) 2800 return -1; 2801 2802 bb->begin = dl; 2803 bb->end = dl; 2804 INIT_LIST_HEAD(&bb->list); 2805 2806 link = malloc(sizeof(*link)); 2807 if (link == NULL) { 2808 free(bb); 2809 return -1; 2810 } 2811 2812 link->bb = bb; 2813 link->parent = parent; 2814 list_add_tail(&link->node, &bb_data->queue); 2815 return 0; 2816 } 2817 2818 /* Returns true when it finds the target in the current basic block */ 2819 static bool process_basic_block(struct basic_block_data *bb_data, 2820 struct basic_block_link *link, 2821 struct symbol *sym, u64 target) 2822 { 2823 struct disasm_line *dl, *next_dl, *last_dl; 2824 struct annotation *notes = symbol__annotation(sym); 2825 bool found = false; 2826 2827 dl = link->bb->begin; 2828 /* Check if it's already visited */ 2829 if (basic_block_has_offset(&bb_data->visited, dl->al.offset)) 2830 return false; 2831 2832 last_dl = list_last_entry(¬es->src->source, 2833 struct disasm_line, al.node); 2834 if (last_dl->al.offset == -1) 2835 last_dl = annotation__prev_asm_line(notes, last_dl); 2836 2837 if (last_dl == NULL) 2838 return false; 2839 2840 list_for_each_entry_from(dl, ¬es->src->source, al.node) { 2841 /* Skip comment or debug info line */ 2842 if (dl->al.offset == -1) 2843 continue; 2844 /* Found the target instruction */ 2845 if (sym->start + dl->al.offset == target) { 2846 found = true; 2847 break; 2848 } 2849 /* End of the function, finish the block */ 2850 if (dl == last_dl) 2851 break; 2852 /* 'return' instruction finishes the block */ 2853 if (ins__is_ret(&dl->ins)) 2854 break; 2855 /* normal instructions are part of the basic block */ 2856 if (!ins__is_jump(&dl->ins)) 2857 continue; 2858 /* jump to a different function, tail call or return */ 2859 if (dl->ops.target.outside) 2860 break; 2861 /* jump instruction creates new basic block(s) */ 2862 next_dl = find_disasm_line(sym, sym->start + dl->ops.target.offset, 2863 /*allow_update=*/false); 2864 if (next_dl) 2865 add_basic_block(bb_data, link, next_dl); 2866 2867 /* 2868 * FIXME: determine conditional jumps properly. 2869 * Conditional jumps create another basic block with the 2870 * next disasm line. 2871 */ 2872 if (!strstr(dl->ins.name, "jmp")) { 2873 next_dl = annotation__next_asm_line(notes, dl); 2874 if (next_dl) 2875 add_basic_block(bb_data, link, next_dl); 2876 } 2877 break; 2878 2879 } 2880 link->bb->end = dl; 2881 return found; 2882 } 2883 2884 /* 2885 * It founds a target basic block, build a proper linked list of basic blocks 2886 * by following the link recursively. 2887 */ 2888 static void link_found_basic_blocks(struct basic_block_link *link, 2889 struct list_head *head) 2890 { 2891 while (link) { 2892 struct basic_block_link *parent = link->parent; 2893 2894 list_move(&link->bb->list, head); 2895 list_del(&link->node); 2896 free(link); 2897 2898 link = parent; 2899 } 2900 } 2901 2902 static void delete_basic_blocks(struct basic_block_data *bb_data) 2903 { 2904 struct basic_block_link *link, *tmp; 2905 2906 list_for_each_entry_safe(link, tmp, &bb_data->queue, node) { 2907 list_del(&link->node); 2908 zfree(&link->bb); 2909 free(link); 2910 } 2911 2912 list_for_each_entry_safe(link, tmp, &bb_data->visited, node) { 2913 list_del(&link->node); 2914 zfree(&link->bb); 2915 free(link); 2916 } 2917 } 2918 2919 /** 2920 * annotate_get_basic_blocks - Get basic blocks for given address range 2921 * @sym: symbol to annotate 2922 * @src: source address 2923 * @dst: destination address 2924 * @head: list head to save basic blocks 2925 * 2926 * This function traverses disasm_lines from @src to @dst and save them in a 2927 * list of annotated_basic_block to @head. It uses BFS to find the shortest 2928 * path between two. The basic_block_link is to maintain parent links so 2929 * that it can build a list of blocks from the start. 2930 */ 2931 int annotate_get_basic_blocks(struct symbol *sym, s64 src, s64 dst, 2932 struct list_head *head) 2933 { 2934 struct basic_block_data bb_data = { 2935 .queue = LIST_HEAD_INIT(bb_data.queue), 2936 .visited = LIST_HEAD_INIT(bb_data.visited), 2937 }; 2938 struct basic_block_link *link; 2939 struct disasm_line *dl; 2940 int ret = -1; 2941 2942 dl = find_disasm_line(sym, src, /*allow_update=*/false); 2943 if (dl == NULL) 2944 return -1; 2945 2946 if (add_basic_block(&bb_data, /*parent=*/NULL, dl) < 0) 2947 return -1; 2948 2949 /* Find shortest path from src to dst using BFS */ 2950 while (!list_empty(&bb_data.queue)) { 2951 link = list_first_entry(&bb_data.queue, struct basic_block_link, node); 2952 2953 if (process_basic_block(&bb_data, link, sym, dst)) { 2954 link_found_basic_blocks(link, head); 2955 ret = 0; 2956 break; 2957 } 2958 list_move(&link->node, &bb_data.visited); 2959 } 2960 delete_basic_blocks(&bb_data); 2961 return ret; 2962 } 2963