diff options
| -rw-r--r-- | tools/perf/builtin-report.c | 31 | ||||
| -rw-r--r-- | tools/perf/builtin-timechart.c | 4 | ||||
| -rw-r--r-- | tools/perf/builtin-trace.c | 19 | ||||
| -rw-r--r-- | tools/perf/util/hist.c | 3 | ||||
| -rw-r--r-- | tools/perf/util/newt.c | 242 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.c | 1 | ||||
| -rw-r--r-- | tools/perf/util/sort.c | 6 | ||||
| -rw-r--r-- | tools/perf/util/symbol.c | 30 | ||||
| -rw-r--r-- | tools/perf/util/symbol.h | 1 |
9 files changed, 297 insertions, 40 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 2f4b92925b26..55fc1f46892a 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -348,7 +348,18 @@ static int __cmd_report(void) | |||
| 348 | hists__tty_browse_tree(&session->hists_tree, help); | 348 | hists__tty_browse_tree(&session->hists_tree, help); |
| 349 | 349 | ||
| 350 | out_delete: | 350 | out_delete: |
| 351 | perf_session__delete(session); | 351 | /* |
| 352 | * Speed up the exit process, for large files this can | ||
| 353 | * take quite a while. | ||
| 354 | * | ||
| 355 | * XXX Enable this when using valgrind or if we ever | ||
| 356 | * librarize this command. | ||
| 357 | * | ||
| 358 | * Also experiment with obstacks to see how much speed | ||
| 359 | * up we'll get here. | ||
| 360 | * | ||
| 361 | * perf_session__delete(session); | ||
| 362 | */ | ||
| 352 | return ret; | 363 | return ret; |
| 353 | } | 364 | } |
| 354 | 365 | ||
| @@ -478,8 +489,24 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) | |||
| 478 | * so don't allocate extra space that won't be used in the stdio | 489 | * so don't allocate extra space that won't be used in the stdio |
| 479 | * implementation. | 490 | * implementation. |
| 480 | */ | 491 | */ |
| 481 | if (use_browser > 0) | 492 | if (use_browser > 0) { |
| 482 | symbol_conf.priv_size = sizeof(struct sym_priv); | 493 | symbol_conf.priv_size = sizeof(struct sym_priv); |
| 494 | /* | ||
| 495 | * For searching by name on the "Browse map details". | ||
| 496 | * providing it only in verbose mode not to bloat too | ||
| 497 | * much struct symbol. | ||
| 498 | */ | ||
| 499 | if (verbose) { | ||
| 500 | /* | ||
| 501 | * XXX: Need to provide a less kludgy way to ask for | ||
| 502 | * more space per symbol, the u32 is for the index on | ||
| 503 | * the ui browser. | ||
| 504 | * See symbol__browser_index. | ||
| 505 | */ | ||
| 506 | symbol_conf.priv_size += sizeof(u32); | ||
| 507 | symbol_conf.sort_by_name = true; | ||
| 508 | } | ||
| 509 | } | ||
| 483 | 510 | ||
| 484 | if (symbol__init() < 0) | 511 | if (symbol__init() < 0) |
| 485 | return -1; | 512 | return -1; |
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 5161619d4714..9bcc38f0b706 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
| @@ -455,8 +455,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) | |||
| 455 | if (p->current->state != TYPE_NONE) | 455 | if (p->current->state != TYPE_NONE) |
| 456 | pid_put_sample(sw->next_pid, p->current->state, cpu, p->current->state_since, timestamp); | 456 | pid_put_sample(sw->next_pid, p->current->state, cpu, p->current->state_since, timestamp); |
| 457 | 457 | ||
| 458 | p->current->state_since = timestamp; | 458 | p->current->state_since = timestamp; |
| 459 | p->current->state = TYPE_RUNNING; | 459 | p->current->state = TYPE_RUNNING; |
| 460 | } | 460 | } |
| 461 | 461 | ||
| 462 | if (prev_p->current) { | 462 | if (prev_p->current) { |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 294da725a57d..40a6a2992d15 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
| @@ -1,13 +1,16 @@ | |||
| 1 | #include "builtin.h" | 1 | #include "builtin.h" |
| 2 | 2 | ||
| 3 | #include "util/util.h" | 3 | #include "perf.h" |
| 4 | #include "util/cache.h" | 4 | #include "util/cache.h" |
| 5 | #include "util/debug.h" | ||
| 6 | #include "util/exec_cmd.h" | ||
| 7 | #include "util/header.h" | ||
| 8 | #include "util/parse-options.h" | ||
| 9 | #include "util/session.h" | ||
| 5 | #include "util/symbol.h" | 10 | #include "util/symbol.h" |
| 6 | #include "util/thread.h" | 11 | #include "util/thread.h" |
| 7 | #include "util/header.h" | ||
| 8 | #include "util/exec_cmd.h" | ||
| 9 | #include "util/trace-event.h" | 12 | #include "util/trace-event.h" |
| 10 | #include "util/session.h" | 13 | #include "util/util.h" |
| 11 | 14 | ||
| 12 | static char const *script_name; | 15 | static char const *script_name; |
| 13 | static char const *generate_script_lang; | 16 | static char const *generate_script_lang; |
| @@ -59,14 +62,6 @@ static int cleanup_scripting(void) | |||
| 59 | return scripting_ops->stop_script(); | 62 | return scripting_ops->stop_script(); |
| 60 | } | 63 | } |
| 61 | 64 | ||
| 62 | #include "util/parse-options.h" | ||
| 63 | |||
| 64 | #include "perf.h" | ||
| 65 | #include "util/debug.h" | ||
| 66 | |||
| 67 | #include "util/trace-event.h" | ||
| 68 | #include "util/exec_cmd.h" | ||
| 69 | |||
| 70 | static char const *input_name = "perf.data"; | 65 | static char const *input_name = "perf.data"; |
| 71 | 66 | ||
| 72 | static int process_sample_event(event_t *event, struct perf_session *session) | 67 | static int process_sample_event(event_t *event, struct perf_session *session) |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index e7263d49bcf0..62ec9b0e4b9a 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -876,6 +876,9 @@ unsigned int hists__sort_list_width(struct hists *self) | |||
| 876 | if (!se->elide) | 876 | if (!se->elide) |
| 877 | ret += 2 + hists__col_len(self, se->se_width_idx); | 877 | ret += 2 + hists__col_len(self, se->se_width_idx); |
| 878 | 878 | ||
| 879 | if (verbose) /* Addr + origin */ | ||
| 880 | ret += 3 + BITS_PER_LONG / 4; | ||
| 881 | |||
| 879 | return ret; | 882 | return ret; |
| 880 | } | 883 | } |
| 881 | 884 | ||
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index 91de99b58445..e2deae0704d7 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <slang.h> | 13 | #include <slang.h> |
| 14 | #include <signal.h> | 14 | #include <signal.h> |
| 15 | #include <stdlib.h> | 15 | #include <stdlib.h> |
| 16 | #include <elf.h> | ||
| 16 | #include <newt.h> | 17 | #include <newt.h> |
| 17 | #include <sys/ttydefaults.h> | 18 | #include <sys/ttydefaults.h> |
| 18 | 19 | ||
| @@ -127,6 +128,39 @@ static void ui_helpline__puts(const char *msg) | |||
| 127 | ui_helpline__push(msg); | 128 | ui_helpline__push(msg); |
| 128 | } | 129 | } |
| 129 | 130 | ||
| 131 | static int ui_entry__read(const char *title, char *bf, size_t size, int width) | ||
| 132 | { | ||
| 133 | struct newtExitStruct es; | ||
| 134 | newtComponent form, entry; | ||
| 135 | const char *result; | ||
| 136 | int err = -1; | ||
| 137 | |||
| 138 | newtCenteredWindow(width, 1, title); | ||
| 139 | form = newtForm(NULL, NULL, 0); | ||
| 140 | if (form == NULL) | ||
| 141 | return -1; | ||
| 142 | |||
| 143 | entry = newtEntry(0, 0, "0x", width, &result, NEWT_FLAG_SCROLL); | ||
| 144 | if (entry == NULL) | ||
| 145 | goto out_free_form; | ||
| 146 | |||
| 147 | newtFormAddComponent(form, entry); | ||
| 148 | newtFormAddHotKey(form, NEWT_KEY_ENTER); | ||
| 149 | newtFormAddHotKey(form, NEWT_KEY_ESCAPE); | ||
| 150 | newtFormAddHotKey(form, NEWT_KEY_LEFT); | ||
| 151 | newtFormAddHotKey(form, CTRL('c')); | ||
| 152 | newtFormRun(form, &es); | ||
| 153 | |||
| 154 | if (result != NULL) { | ||
| 155 | strncpy(bf, result, size); | ||
| 156 | err = 0; | ||
| 157 | } | ||
| 158 | out_free_form: | ||
| 159 | newtPopWindow(); | ||
| 160 | newtFormDestroy(form); | ||
| 161 | return 0; | ||
| 162 | } | ||
| 163 | |||
| 130 | static char browser__last_msg[1024]; | 164 | static char browser__last_msg[1024]; |
| 131 | 165 | ||
| 132 | int browser__show_help(const char *format, va_list ap) | 166 | int browser__show_help(const char *format, va_list ap) |
| @@ -279,7 +313,8 @@ struct ui_browser { | |||
| 279 | void *first_visible_entry, *entries; | 313 | void *first_visible_entry, *entries; |
| 280 | u16 top, left, width, height; | 314 | u16 top, left, width, height; |
| 281 | void *priv; | 315 | void *priv; |
| 282 | unsigned int (*refresh_entries)(struct ui_browser *self); | 316 | unsigned int (*refresh)(struct ui_browser *self); |
| 317 | void (*write)(struct ui_browser *self, void *entry, int row); | ||
| 283 | void (*seek)(struct ui_browser *self, | 318 | void (*seek)(struct ui_browser *self, |
| 284 | off_t offset, int whence); | 319 | off_t offset, int whence); |
| 285 | u32 nr_entries; | 320 | u32 nr_entries; |
| @@ -316,6 +351,58 @@ static void ui_browser__list_head_seek(struct ui_browser *self, | |||
| 316 | self->first_visible_entry = pos; | 351 | self->first_visible_entry = pos; |
| 317 | } | 352 | } |
| 318 | 353 | ||
| 354 | static void ui_browser__rb_tree_seek(struct ui_browser *self, | ||
| 355 | off_t offset, int whence) | ||
| 356 | { | ||
| 357 | struct rb_root *root = self->entries; | ||
| 358 | struct rb_node *nd; | ||
| 359 | |||
| 360 | switch (whence) { | ||
| 361 | case SEEK_SET: | ||
| 362 | nd = rb_first(root); | ||
| 363 | break; | ||
| 364 | case SEEK_CUR: | ||
| 365 | nd = self->first_visible_entry; | ||
| 366 | break; | ||
| 367 | case SEEK_END: | ||
| 368 | nd = rb_last(root); | ||
| 369 | break; | ||
| 370 | default: | ||
| 371 | return; | ||
| 372 | } | ||
| 373 | |||
| 374 | if (offset > 0) { | ||
| 375 | while (offset-- != 0) | ||
| 376 | nd = rb_next(nd); | ||
| 377 | } else { | ||
| 378 | while (offset++ != 0) | ||
| 379 | nd = rb_prev(nd); | ||
| 380 | } | ||
| 381 | |||
| 382 | self->first_visible_entry = nd; | ||
| 383 | } | ||
| 384 | |||
| 385 | static unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self) | ||
| 386 | { | ||
| 387 | struct rb_node *nd; | ||
| 388 | int row = 0; | ||
| 389 | |||
| 390 | if (self->first_visible_entry == NULL) | ||
| 391 | self->first_visible_entry = rb_first(self->entries); | ||
| 392 | |||
| 393 | nd = self->first_visible_entry; | ||
| 394 | |||
| 395 | while (nd != NULL) { | ||
| 396 | SLsmg_gotorc(self->top + row, self->left); | ||
| 397 | self->write(self, nd, row); | ||
| 398 | if (++row == self->height) | ||
| 399 | break; | ||
| 400 | nd = rb_next(nd); | ||
| 401 | } | ||
| 402 | |||
| 403 | return row; | ||
| 404 | } | ||
| 405 | |||
| 319 | static bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row) | 406 | static bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row) |
| 320 | { | 407 | { |
| 321 | return (self->first_visible_entry_idx + row) == self->index; | 408 | return (self->first_visible_entry_idx + row) == self->index; |
| @@ -418,12 +505,12 @@ static int objdump_line__show(struct objdump_line *self, struct list_head *head, | |||
| 418 | return 0; | 505 | return 0; |
| 419 | } | 506 | } |
| 420 | 507 | ||
| 421 | static int ui_browser__refresh_entries(struct ui_browser *self) | 508 | static int ui_browser__refresh(struct ui_browser *self) |
| 422 | { | 509 | { |
| 423 | int row; | 510 | int row; |
| 424 | 511 | ||
| 425 | newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); | 512 | newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); |
| 426 | row = self->refresh_entries(self); | 513 | row = self->refresh(self); |
| 427 | SLsmg_set_color(HE_COLORSET_NORMAL); | 514 | SLsmg_set_color(HE_COLORSET_NORMAL); |
| 428 | SLsmg_fill_region(self->top + row, self->left, | 515 | SLsmg_fill_region(self->top + row, self->left, |
| 429 | self->height - row, self->width, ' '); | 516 | self->height - row, self->width, ' '); |
| @@ -433,7 +520,7 @@ static int ui_browser__refresh_entries(struct ui_browser *self) | |||
| 433 | 520 | ||
| 434 | static int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es) | 521 | static int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es) |
| 435 | { | 522 | { |
| 436 | if (ui_browser__refresh_entries(self) < 0) | 523 | if (ui_browser__refresh(self) < 0) |
| 437 | return -1; | 524 | return -1; |
| 438 | 525 | ||
| 439 | while (1) { | 526 | while (1) { |
| @@ -504,7 +591,7 @@ static int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es) | |||
| 504 | default: | 591 | default: |
| 505 | return es->u.key; | 592 | return es->u.key; |
| 506 | } | 593 | } |
| 507 | if (ui_browser__refresh_entries(self) < 0) | 594 | if (ui_browser__refresh(self) < 0) |
| 508 | return -1; | 595 | return -1; |
| 509 | } | 596 | } |
| 510 | return 0; | 597 | return 0; |
| @@ -567,9 +654,9 @@ int hist_entry__tui_annotate(struct hist_entry *self) | |||
| 567 | ui_helpline__push("Press <- or ESC to exit"); | 654 | ui_helpline__push("Press <- or ESC to exit"); |
| 568 | 655 | ||
| 569 | memset(&browser, 0, sizeof(browser)); | 656 | memset(&browser, 0, sizeof(browser)); |
| 570 | browser.entries = &head; | 657 | browser.entries = &head; |
| 571 | browser.refresh_entries = hist_entry__annotate_browser_refresh; | 658 | browser.refresh = hist_entry__annotate_browser_refresh; |
| 572 | browser.seek = ui_browser__list_head_seek; | 659 | browser.seek = ui_browser__list_head_seek; |
| 573 | browser.priv = self; | 660 | browser.priv = self; |
| 574 | list_for_each_entry(pos, &head, node) { | 661 | list_for_each_entry(pos, &head, node) { |
| 575 | size_t line_len = strlen(pos->line); | 662 | size_t line_len = strlen(pos->line); |
| @@ -592,6 +679,128 @@ int hist_entry__tui_annotate(struct hist_entry *self) | |||
| 592 | return ret; | 679 | return ret; |
| 593 | } | 680 | } |
| 594 | 681 | ||
| 682 | /* -------------------------------------------------------------------- */ | ||
| 683 | |||
| 684 | struct map_browser { | ||
| 685 | struct ui_browser b; | ||
| 686 | struct map *map; | ||
| 687 | u16 namelen; | ||
| 688 | u8 addrlen; | ||
| 689 | }; | ||
| 690 | |||
| 691 | static void map_browser__write(struct ui_browser *self, void *nd, int row) | ||
| 692 | { | ||
| 693 | struct symbol *sym = rb_entry(nd, struct symbol, rb_node); | ||
| 694 | struct map_browser *mb = container_of(self, struct map_browser, b); | ||
| 695 | bool current_entry = ui_browser__is_current_entry(self, row); | ||
| 696 | int color = ui_browser__percent_color(0, current_entry); | ||
| 697 | |||
| 698 | SLsmg_set_color(color); | ||
| 699 | slsmg_printf("%*llx %*llx %c ", | ||
| 700 | mb->addrlen, sym->start, mb->addrlen, sym->end, | ||
| 701 | sym->binding == STB_GLOBAL ? 'g' : | ||
| 702 | sym->binding == STB_LOCAL ? 'l' : 'w'); | ||
| 703 | slsmg_write_nstring(sym->name, mb->namelen); | ||
| 704 | } | ||
| 705 | |||
| 706 | /* FIXME uber-kludgy, see comment on cmd_report... */ | ||
| 707 | static u32 *symbol__browser_index(struct symbol *self) | ||
| 708 | { | ||
| 709 | return ((void *)self) - sizeof(struct rb_node) - sizeof(u32); | ||
| 710 | } | ||
| 711 | |||
| 712 | static int map_browser__search(struct map_browser *self) | ||
| 713 | { | ||
| 714 | char target[512]; | ||
| 715 | struct symbol *sym; | ||
| 716 | int err = ui_entry__read("Search by name/addr", target, sizeof(target), 40); | ||
| 717 | |||
| 718 | if (err) | ||
| 719 | return err; | ||
| 720 | |||
| 721 | if (target[0] == '0' && tolower(target[1]) == 'x') { | ||
| 722 | u64 addr = strtoull(target, NULL, 16); | ||
| 723 | sym = map__find_symbol(self->map, addr, NULL); | ||
| 724 | } else | ||
| 725 | sym = map__find_symbol_by_name(self->map, target, NULL); | ||
| 726 | |||
| 727 | if (sym != NULL) { | ||
| 728 | u32 *idx = symbol__browser_index(sym); | ||
| 729 | |||
| 730 | self->b.first_visible_entry = &sym->rb_node; | ||
| 731 | self->b.index = self->b.first_visible_entry_idx = *idx; | ||
| 732 | } else | ||
| 733 | ui_helpline__fpush("%s not found!", target); | ||
| 734 | |||
| 735 | return 0; | ||
| 736 | } | ||
| 737 | |||
| 738 | static int map_browser__run(struct map_browser *self, struct newtExitStruct *es) | ||
| 739 | { | ||
| 740 | if (ui_browser__show(&self->b, self->map->dso->long_name) < 0) | ||
| 741 | return -1; | ||
| 742 | |||
| 743 | ui_helpline__fpush("Press <- or ESC to exit, %s / to search", | ||
| 744 | verbose ? "" : "restart with -v to use"); | ||
| 745 | newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT); | ||
| 746 | newtFormAddHotKey(self->b.form, NEWT_KEY_ENTER); | ||
| 747 | if (verbose) | ||
| 748 | newtFormAddHotKey(self->b.form, '/'); | ||
| 749 | |||
| 750 | while (1) { | ||
| 751 | ui_browser__run(&self->b, es); | ||
| 752 | |||
| 753 | if (es->reason != NEWT_EXIT_HOTKEY) | ||
| 754 | break; | ||
| 755 | if (verbose && es->u.key == '/') | ||
| 756 | map_browser__search(self); | ||
| 757 | else | ||
| 758 | break; | ||
| 759 | } | ||
| 760 | |||
| 761 | newtFormDestroy(self->b.form); | ||
| 762 | newtPopWindow(); | ||
| 763 | ui_helpline__pop(); | ||
| 764 | return 0; | ||
| 765 | } | ||
| 766 | |||
| 767 | static int map__browse(struct map *self) | ||
| 768 | { | ||
| 769 | struct map_browser mb = { | ||
| 770 | .b = { | ||
| 771 | .entries = &self->dso->symbols[self->type], | ||
| 772 | .refresh = ui_browser__rb_tree_refresh, | ||
| 773 | .seek = ui_browser__rb_tree_seek, | ||
| 774 | .write = map_browser__write, | ||
| 775 | }, | ||
| 776 | .map = self, | ||
| 777 | }; | ||
| 778 | struct newtExitStruct es; | ||
| 779 | struct rb_node *nd; | ||
| 780 | char tmp[BITS_PER_LONG / 4]; | ||
| 781 | u64 maxaddr = 0; | ||
| 782 | |||
| 783 | for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) { | ||
| 784 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); | ||
| 785 | |||
| 786 | if (mb.namelen < pos->namelen) | ||
| 787 | mb.namelen = pos->namelen; | ||
| 788 | if (maxaddr < pos->end) | ||
| 789 | maxaddr = pos->end; | ||
| 790 | if (verbose) { | ||
| 791 | u32 *idx = symbol__browser_index(pos); | ||
| 792 | *idx = mb.b.nr_entries; | ||
| 793 | } | ||
| 794 | ++mb.b.nr_entries; | ||
| 795 | } | ||
| 796 | |||
| 797 | mb.addrlen = snprintf(tmp, sizeof(tmp), "%llx", maxaddr); | ||
| 798 | mb.b.width += mb.addrlen * 2 + 4 + mb.namelen; | ||
| 799 | return map_browser__run(&mb, &es); | ||
| 800 | } | ||
| 801 | |||
| 802 | /* -------------------------------------------------------------------- */ | ||
| 803 | |||
| 595 | struct hist_browser { | 804 | struct hist_browser { |
| 596 | struct ui_browser b; | 805 | struct ui_browser b; |
| 597 | struct hists *hists; | 806 | struct hists *hists; |
| @@ -602,7 +811,7 @@ struct hist_browser { | |||
| 602 | static void hist_browser__reset(struct hist_browser *self); | 811 | static void hist_browser__reset(struct hist_browser *self); |
| 603 | static int hist_browser__run(struct hist_browser *self, const char *title, | 812 | static int hist_browser__run(struct hist_browser *self, const char *title, |
| 604 | struct newtExitStruct *es); | 813 | struct newtExitStruct *es); |
| 605 | static unsigned int hist_browser__refresh_entries(struct ui_browser *self); | 814 | static unsigned int hist_browser__refresh(struct ui_browser *self); |
| 606 | static void ui_browser__hists_seek(struct ui_browser *self, | 815 | static void ui_browser__hists_seek(struct ui_browser *self, |
| 607 | off_t offset, int whence); | 816 | off_t offset, int whence); |
| 608 | 817 | ||
| @@ -612,7 +821,7 @@ static struct hist_browser *hist_browser__new(struct hists *hists) | |||
| 612 | 821 | ||
| 613 | if (self) { | 822 | if (self) { |
| 614 | self->hists = hists; | 823 | self->hists = hists; |
| 615 | self->b.refresh_entries = hist_browser__refresh_entries; | 824 | self->b.refresh = hist_browser__refresh; |
| 616 | self->b.seek = ui_browser__hists_seek; | 825 | self->b.seek = ui_browser__hists_seek; |
| 617 | } | 826 | } |
| 618 | 827 | ||
| @@ -680,7 +889,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) | |||
| 680 | const struct dso *dso; | 889 | const struct dso *dso; |
| 681 | char *options[16]; | 890 | char *options[16]; |
| 682 | int nr_options = 0, choice = 0, i, | 891 | int nr_options = 0, choice = 0, i, |
| 683 | annotate = -2, zoom_dso = -2, zoom_thread = -2; | 892 | annotate = -2, zoom_dso = -2, zoom_thread = -2, |
| 893 | browse_map = -2; | ||
| 684 | 894 | ||
| 685 | if (hist_browser__run(browser, msg, &es)) | 895 | if (hist_browser__run(browser, msg, &es)) |
| 686 | break; | 896 | break; |
| @@ -771,6 +981,10 @@ do_help: | |||
| 771 | (dso->kernel ? "the Kernel" : dso->short_name)) > 0) | 981 | (dso->kernel ? "the Kernel" : dso->short_name)) > 0) |
| 772 | zoom_dso = nr_options++; | 982 | zoom_dso = nr_options++; |
| 773 | 983 | ||
| 984 | if (browser->selection->map != NULL && | ||
| 985 | asprintf(&options[nr_options], "Browse map details") > 0) | ||
| 986 | browse_map = nr_options++; | ||
| 987 | |||
| 774 | options[nr_options++] = (char *)"Exit"; | 988 | options[nr_options++] = (char *)"Exit"; |
| 775 | 989 | ||
| 776 | choice = popup_menu(nr_options, options); | 990 | choice = popup_menu(nr_options, options); |
| @@ -800,7 +1014,9 @@ do_annotate: | |||
| 800 | continue; | 1014 | continue; |
| 801 | 1015 | ||
| 802 | hist_entry__tui_annotate(he); | 1016 | hist_entry__tui_annotate(he); |
| 803 | } else if (choice == zoom_dso) { | 1017 | } else if (choice == browse_map) |
| 1018 | map__browse(browser->selection->map); | ||
| 1019 | else if (choice == zoom_dso) { | ||
| 804 | zoom_dso: | 1020 | zoom_dso: |
| 805 | if (dso_filter) { | 1021 | if (dso_filter) { |
| 806 | pstack__remove(fstack, &dso_filter); | 1022 | pstack__remove(fstack, &dso_filter); |
| @@ -1213,7 +1429,7 @@ static int hist_browser__show_entry(struct hist_browser *self, | |||
| 1213 | return printed; | 1429 | return printed; |
| 1214 | } | 1430 | } |
| 1215 | 1431 | ||
| 1216 | static unsigned int hist_browser__refresh_entries(struct ui_browser *self) | 1432 | static unsigned int hist_browser__refresh(struct ui_browser *self) |
| 1217 | { | 1433 | { |
| 1218 | unsigned row = 0; | 1434 | unsigned row = 0; |
| 1219 | struct rb_node *nd; | 1435 | struct rb_node *nd; |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 840f1aabbb74..6c7750da43d7 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
| @@ -33,7 +33,6 @@ | |||
| 33 | #include <ctype.h> | 33 | #include <ctype.h> |
| 34 | #include <dwarf-regs.h> | 34 | #include <dwarf-regs.h> |
| 35 | 35 | ||
| 36 | #include "string.h" | ||
| 37 | #include "event.h" | 36 | #include "event.h" |
| 38 | #include "debug.h" | 37 | #include "debug.h" |
| 39 | #include "util.h" | 38 | #include "util.h" |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 1c61a4f4aa8a..b62a553cc67d 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
| @@ -196,7 +196,8 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, | |||
| 196 | 196 | ||
| 197 | if (verbose) { | 197 | if (verbose) { |
| 198 | char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!'; | 198 | char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!'; |
| 199 | ret += repsep_snprintf(bf, size, "%#018llx %c ", self->ip, o); | 199 | ret += repsep_snprintf(bf, size, "%*Lx %c ", |
| 200 | BITS_PER_LONG / 4, self->ip, o); | ||
| 200 | } | 201 | } |
| 201 | 202 | ||
| 202 | ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level); | 203 | ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level); |
| @@ -204,7 +205,8 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, | |||
| 204 | ret += repsep_snprintf(bf + ret, size - ret, "%s", | 205 | ret += repsep_snprintf(bf + ret, size - ret, "%s", |
| 205 | self->ms.sym->name); | 206 | self->ms.sym->name); |
| 206 | else | 207 | else |
| 207 | ret += repsep_snprintf(bf + ret, size - ret, "%#016llx", self->ip); | 208 | ret += repsep_snprintf(bf + ret, size - ret, "%*Lx", |
| 209 | BITS_PER_LONG / 4, self->ip); | ||
| 208 | 210 | ||
| 209 | return ret; | 211 | return ret; |
| 210 | } | 212 | } |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 6f0dd90c36ce..b6f5970f9106 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -131,7 +131,8 @@ static void map_groups__fixup_end(struct map_groups *self) | |||
| 131 | __map_groups__fixup_end(self, i); | 131 | __map_groups__fixup_end(self, i); |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | static struct symbol *symbol__new(u64 start, u64 len, const char *name) | 134 | static struct symbol *symbol__new(u64 start, u64 len, u8 binding, |
| 135 | const char *name) | ||
| 135 | { | 136 | { |
| 136 | size_t namelen = strlen(name) + 1; | 137 | size_t namelen = strlen(name) + 1; |
| 137 | struct symbol *self = calloc(1, (symbol_conf.priv_size + | 138 | struct symbol *self = calloc(1, (symbol_conf.priv_size + |
| @@ -144,6 +145,7 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name) | |||
| 144 | 145 | ||
| 145 | self->start = start; | 146 | self->start = start; |
| 146 | self->end = len ? start + len - 1 : start; | 147 | self->end = len ? start + len - 1 : start; |
| 148 | self->binding = binding; | ||
| 147 | self->namelen = namelen - 1; | 149 | self->namelen = namelen - 1; |
| 148 | 150 | ||
| 149 | pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); | 151 | pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); |
| @@ -160,8 +162,11 @@ void symbol__delete(struct symbol *self) | |||
| 160 | 162 | ||
| 161 | static size_t symbol__fprintf(struct symbol *self, FILE *fp) | 163 | static size_t symbol__fprintf(struct symbol *self, FILE *fp) |
| 162 | { | 164 | { |
| 163 | return fprintf(fp, " %llx-%llx %s\n", | 165 | return fprintf(fp, " %llx-%llx %c %s\n", |
| 164 | self->start, self->end, self->name); | 166 | self->start, self->end, |
| 167 | self->binding == STB_GLOBAL ? 'g' : | ||
| 168 | self->binding == STB_LOCAL ? 'l' : 'w', | ||
| 169 | self->name); | ||
| 165 | } | 170 | } |
| 166 | 171 | ||
| 167 | void dso__set_long_name(struct dso *self, char *name) | 172 | void dso__set_long_name(struct dso *self, char *name) |
| @@ -453,6 +458,14 @@ struct process_kallsyms_args { | |||
| 453 | struct dso *dso; | 458 | struct dso *dso; |
| 454 | }; | 459 | }; |
| 455 | 460 | ||
| 461 | static u8 kallsyms2elf_type(char type) | ||
| 462 | { | ||
| 463 | if (type == 'W') | ||
| 464 | return STB_WEAK; | ||
| 465 | |||
| 466 | return isupper(type) ? STB_GLOBAL : STB_LOCAL; | ||
| 467 | } | ||
| 468 | |||
| 456 | static int map__process_kallsym_symbol(void *arg, const char *name, | 469 | static int map__process_kallsym_symbol(void *arg, const char *name, |
| 457 | char type, u64 start) | 470 | char type, u64 start) |
| 458 | { | 471 | { |
| @@ -466,7 +479,7 @@ static int map__process_kallsym_symbol(void *arg, const char *name, | |||
| 466 | /* | 479 | /* |
| 467 | * Will fix up the end later, when we have all symbols sorted. | 480 | * Will fix up the end later, when we have all symbols sorted. |
| 468 | */ | 481 | */ |
| 469 | sym = symbol__new(start, 0, name); | 482 | sym = symbol__new(start, 0, kallsyms2elf_type(type), name); |
| 470 | 483 | ||
| 471 | if (sym == NULL) | 484 | if (sym == NULL) |
| 472 | return -ENOMEM; | 485 | return -ENOMEM; |
| @@ -661,7 +674,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map, | |||
| 661 | if (len + 2 >= line_len) | 674 | if (len + 2 >= line_len) |
| 662 | continue; | 675 | continue; |
| 663 | 676 | ||
| 664 | sym = symbol__new(start, size, line + len); | 677 | sym = symbol__new(start, size, STB_GLOBAL, line + len); |
| 665 | 678 | ||
| 666 | if (sym == NULL) | 679 | if (sym == NULL) |
| 667 | goto out_delete_line; | 680 | goto out_delete_line; |
| @@ -873,7 +886,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, | |||
| 873 | "%s@plt", elf_sym__name(&sym, symstrs)); | 886 | "%s@plt", elf_sym__name(&sym, symstrs)); |
| 874 | 887 | ||
| 875 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | 888 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, |
| 876 | sympltname); | 889 | STB_GLOBAL, sympltname); |
| 877 | if (!f) | 890 | if (!f) |
| 878 | goto out_elf_end; | 891 | goto out_elf_end; |
| 879 | 892 | ||
| @@ -895,7 +908,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, | |||
| 895 | "%s@plt", elf_sym__name(&sym, symstrs)); | 908 | "%s@plt", elf_sym__name(&sym, symstrs)); |
| 896 | 909 | ||
| 897 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | 910 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, |
| 898 | sympltname); | 911 | STB_GLOBAL, sympltname); |
| 899 | if (!f) | 912 | if (!f) |
| 900 | goto out_elf_end; | 913 | goto out_elf_end; |
| 901 | 914 | ||
| @@ -1146,7 +1159,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
| 1146 | if (demangled != NULL) | 1159 | if (demangled != NULL) |
| 1147 | elf_name = demangled; | 1160 | elf_name = demangled; |
| 1148 | new_symbol: | 1161 | new_symbol: |
| 1149 | f = symbol__new(sym.st_value, sym.st_size, elf_name); | 1162 | f = symbol__new(sym.st_value, sym.st_size, |
| 1163 | GELF_ST_BIND(sym.st_info), elf_name); | ||
| 1150 | free(demangled); | 1164 | free(demangled); |
| 1151 | if (!f) | 1165 | if (!f) |
| 1152 | goto out_elf_end; | 1166 | goto out_elf_end; |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 906be20011d9..b7a8da4af5a0 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -53,6 +53,7 @@ struct symbol { | |||
| 53 | u64 start; | 53 | u64 start; |
| 54 | u64 end; | 54 | u64 end; |
| 55 | u16 namelen; | 55 | u16 namelen; |
| 56 | u8 binding; | ||
| 56 | char name[0]; | 57 | char name[0]; |
| 57 | }; | 58 | }; |
| 58 | 59 | ||
