aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2009-11-27 13:29:23 -0500
committerIngo Molnar <mingo@elte.hu>2009-11-27 14:22:02 -0500
commit1ed091c45ae33b2179d387573c3fe3f3b4adf60a (patch)
treed2b689de158e5a11673b5f0d08b491d243768138 /tools/perf
parent62daacb51a2bf8480e6f6b3696b03f102fc15eb0 (diff)
perf tools: Consolidate symbol resolving across all tools
Now we have a very high level routine for simple tools to process IP sample events: int event__preprocess_sample(const event_t *self, struct addr_location *al, symbol_filter_t filter) It receives the event itself and will insert new threads in the global threads list and resolve the map and symbol, filling all this info into the new addr_location struct, so that tools like annotate and report can further process the event by creating hist_entries in their specific way (with or without callgraphs, etc). It in turn uses the new next layer function: void thread__find_addr_location(struct thread *self, u8 cpumode, enum map_type type, u64 addr, struct addr_location *al, symbol_filter_t filter) This one will, given a thread (userspace or the kernel kthread one), will find the given type (MAP__FUNCTION now, MAP__VARIABLE too in the near future) at the given cpumode, taking vdsos into account (userspace hit, but kernel symbol) and will fill all these details in the addr_location given. Tools that need a more compact API for plain function resolution, like 'kmem', can use this other one: struct symbol *thread__find_function(struct thread *self, u64 addr, symbol_filter_t filter) So, to resolve a kernel symbol, that is all the 'kmem' tool needs, its just a matter of calling: sym = thread__find_function(kthread, addr, NULL); The 'filter' parameter is needed because we do lazy parsing/loading of ELF symtabs or /proc/kallsyms. With this we remove more code duplication all around, which is always good, huh? :-) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: John Kacur <jkacur@redhat.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> LKML-Reference: <1259346563-12568-12-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/builtin-annotate.c55
-rw-r--r--tools/perf/builtin-kmem.c2
-rw-r--r--tools/perf/builtin-report.c135
-rw-r--r--tools/perf/builtin-top.c44
-rw-r--r--tools/perf/util/event.c62
-rw-r--r--tools/perf/util/event.h4
-rw-r--r--tools/perf/util/hist.c15
-rw-r--r--tools/perf/util/hist.h6
-rw-r--r--tools/perf/util/symbol.c26
-rw-r--r--tools/perf/util/symbol.h10
-rw-r--r--tools/perf/util/thread.c12
-rw-r--r--tools/perf/util/thread.h23
12 files changed, 172 insertions, 222 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 7d39bd2b19b8..7f85c6e159a4 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -124,71 +124,30 @@ static void hist_hit(struct hist_entry *he, u64 ip)
124 h->ip[offset]); 124 h->ip[offset]);
125} 125}
126 126
127static int hist_entry__add(struct thread *thread, struct map *map, 127static int hist_entry__add(struct addr_location *al, u64 count)
128 struct symbol *sym, u64 ip, u64 count, char level)
129{ 128{
130 bool hit; 129 bool hit;
131 struct hist_entry *he = __hist_entry__add(thread, map, sym, NULL, ip, 130 struct hist_entry *he = __hist_entry__add(al, NULL, count, &hit);
132 count, level, &hit);
133 if (he == NULL) 131 if (he == NULL)
134 return -ENOMEM; 132 return -ENOMEM;
135 hist_hit(he, ip); 133 hist_hit(he, al->addr);
136 return 0; 134 return 0;
137} 135}
138 136
139static int process_sample_event(event_t *event) 137static int process_sample_event(event_t *event)
140{ 138{
141 char level; 139 struct addr_location al;
142 u64 ip = event->ip.ip;
143 struct map *map = NULL;
144 struct symbol *sym = NULL;
145 struct thread *thread = threads__findnew(event->ip.pid);
146 140
147 dump_printf("(IP, %d): %d: %p\n", event->header.misc, 141 dump_printf("(IP, %d): %d: %p\n", event->header.misc,
148 event->ip.pid, (void *)(long)ip); 142 event->ip.pid, (void *)(long)event->ip.ip);
149 143
150 if (thread == NULL) { 144 if (event__preprocess_sample(event, &al, symbol_filter) < 0) {
151 fprintf(stderr, "problem processing %d event, skipping it.\n", 145 fprintf(stderr, "problem processing %d event, skipping it.\n",
152 event->header.type); 146 event->header.type);
153 return -1; 147 return -1;
154 } 148 }
155 149
156 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 150 if (hist_entry__add(&al, 1)) {
157
158 if (event->header.misc & PERF_RECORD_MISC_KERNEL) {
159 level = 'k';
160 sym = kernel_maps__find_function(ip, &map, symbol_filter);
161 dump_printf(" ...... dso: %s\n",
162 map ? map->dso->long_name : "<not found>");
163 } else if (event->header.misc & PERF_RECORD_MISC_USER) {
164 level = '.';
165 map = thread__find_map(thread, MAP__FUNCTION, ip);
166 if (map != NULL) {
167 ip = map->map_ip(map, ip);
168 sym = map__find_symbol(map, ip, symbol_filter);
169 } else {
170 /*
171 * If this is outside of all known maps,
172 * and is a negative address, try to look it
173 * up in the kernel dso, as it might be a
174 * vsyscall or vdso (which executes in user-mode).
175 *
176 * XXX This is nasty, we should have a symbol list in
177 * the "[vdso]" dso, but for now lets use the old
178 * trick of looking in the whole kernel symbol list.
179 */
180 if ((long long)ip < 0)
181 sym = kernel_maps__find_function(ip, &map,
182 symbol_filter);
183 }
184 dump_printf(" ...... dso: %s\n",
185 map ? map->dso->long_name : "<not found>");
186 } else {
187 level = 'H';
188 dump_printf(" ...... dso: [hypervisor]\n");
189 }
190
191 if (hist_entry__add(thread, map, sym, ip, 1, level)) {
192 fprintf(stderr, "problem incrementing symbol count, " 151 fprintf(stderr, "problem incrementing symbol count, "
193 "skipping event\n"); 152 "skipping event\n");
194 return -1; 153 return -1;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index e7294c8fc620..047fef74bd52 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -420,7 +420,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller)
420 if (is_caller) { 420 if (is_caller) {
421 addr = data->call_site; 421 addr = data->call_site;
422 if (!raw_ip) 422 if (!raw_ip)
423 sym = kernel_maps__find_function(addr, NULL, NULL); 423 sym = thread__find_function(kthread, addr, NULL);
424 } else 424 } else
425 addr = data->ptr; 425 addr = data->ptr;
426 426
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 01ef35cac5f9..383c4ab4f9af 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -408,55 +408,6 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
408 return 0; 408 return 0;
409} 409}
410 410
411
412static struct symbol *
413resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
414{
415 struct map *map = mapp ? *mapp : NULL;
416 u64 ip = *ipp;
417
418 if (map)
419 goto got_map;
420
421 if (!thread)
422 return NULL;
423
424 map = thread__find_map(thread, MAP__FUNCTION, ip);
425 if (map != NULL) {
426 /*
427 * We have to do this here as we may have a dso
428 * with no symbol hit that has a name longer than
429 * the ones with symbols sampled.
430 */
431 if (!sort_dso.elide && !map->dso->slen_calculated)
432 dso__calc_col_width(map->dso);
433
434 if (mapp)
435 *mapp = map;
436got_map:
437 ip = map->map_ip(map, ip);
438 } else {
439 /*
440 * If this is outside of all known maps,
441 * and is a negative address, try to look it
442 * up in the kernel dso, as it might be a
443 * vsyscall or vdso (which executes in user-mode).
444 *
445 * XXX This is nasty, we should have a symbol list in
446 * the "[vdso]" dso, but for now lets use the old
447 * trick of looking in the whole kernel symbol list.
448 */
449 if ((long long)ip < 0)
450 return kernel_maps__find_function(ip, mapp, NULL);
451 }
452 dump_printf(" ...... dso: %s\n",
453 map ? map->dso->long_name : "<not found>");
454 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
455 *ipp = ip;
456
457 return map ? map__find_symbol(map, ip, NULL) : NULL;
458}
459
460static int call__match(struct symbol *sym) 411static int call__match(struct symbol *sym)
461{ 412{
462 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) 413 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
@@ -469,7 +420,7 @@ static struct symbol **resolve_callchain(struct thread *thread,
469 struct ip_callchain *chain, 420 struct ip_callchain *chain,
470 struct symbol **parent) 421 struct symbol **parent)
471{ 422{
472 u64 context = PERF_CONTEXT_MAX; 423 u8 cpumode = PERF_RECORD_MISC_USER;
473 struct symbol **syms = NULL; 424 struct symbol **syms = NULL;
474 unsigned int i; 425 unsigned int i;
475 426
@@ -483,30 +434,31 @@ static struct symbol **resolve_callchain(struct thread *thread,
483 434
484 for (i = 0; i < chain->nr; i++) { 435 for (i = 0; i < chain->nr; i++) {
485 u64 ip = chain->ips[i]; 436 u64 ip = chain->ips[i];
486 struct symbol *sym = NULL; 437 struct addr_location al;
487 438
488 if (ip >= PERF_CONTEXT_MAX) { 439 if (ip >= PERF_CONTEXT_MAX) {
489 context = ip; 440 switch (ip) {
441 case PERF_CONTEXT_HV:
442 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
443 case PERF_CONTEXT_KERNEL:
444 cpumode = PERF_RECORD_MISC_KERNEL; break;
445 case PERF_CONTEXT_USER:
446 cpumode = PERF_RECORD_MISC_USER; break;
447 default:
448 break;
449 }
490 continue; 450 continue;
491 } 451 }
492 452
493 switch (context) { 453 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
494 case PERF_CONTEXT_HV: 454 ip, &al, NULL);
495 break; 455 if (al.sym != NULL) {
496 case PERF_CONTEXT_KERNEL: 456 if (sort__has_parent && !*parent &&
497 sym = kernel_maps__find_function(ip, NULL, NULL); 457 call__match(al.sym))
498 break; 458 *parent = al.sym;
499 default:
500 sym = resolve_symbol(thread, NULL, &ip);
501 break;
502 }
503
504 if (sym) {
505 if (sort__has_parent && !*parent && call__match(sym))
506 *parent = sym;
507 if (!callchain) 459 if (!callchain)
508 break; 460 break;
509 syms[i] = sym; 461 syms[i] = al.sym;
510 } 462 }
511 } 463 }
512 464
@@ -517,20 +469,17 @@ static struct symbol **resolve_callchain(struct thread *thread,
517 * collect histogram counts 469 * collect histogram counts
518 */ 470 */
519 471
520static int 472static int hist_entry__add(struct addr_location *al,
521hist_entry__add(struct thread *thread, struct map *map, 473 struct ip_callchain *chain, u64 count)
522 struct symbol *sym, u64 ip, struct ip_callchain *chain,
523 char level, u64 count)
524{ 474{
525 struct symbol **syms = NULL, *parent = NULL; 475 struct symbol **syms = NULL, *parent = NULL;
526 bool hit; 476 bool hit;
527 struct hist_entry *he; 477 struct hist_entry *he;
528 478
529 if ((sort__has_parent || callchain) && chain) 479 if ((sort__has_parent || callchain) && chain)
530 syms = resolve_callchain(thread, chain, &parent); 480 syms = resolve_callchain(al->thread, chain, &parent);
531 481
532 he = __hist_entry__add(thread, map, sym, parent, 482 he = __hist_entry__add(al, parent, count, &hit);
533 ip, count, level, &hit);
534 if (he == NULL) 483 if (he == NULL)
535 return -ENOMEM; 484 return -ENOMEM;
536 485
@@ -656,14 +605,12 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
656 605
657static int process_sample_event(event_t *event) 606static int process_sample_event(event_t *event)
658{ 607{
659 char level;
660 struct symbol *sym = NULL;
661 u64 ip = event->ip.ip; 608 u64 ip = event->ip.ip;
662 u64 period = 1; 609 u64 period = 1;
663 struct map *map = NULL;
664 void *more_data = event->ip.__more_data; 610 void *more_data = event->ip.__more_data;
665 struct ip_callchain *chain = NULL; 611 struct ip_callchain *chain = NULL;
666 int cpumode; 612 int cpumode;
613 struct addr_location al;
667 struct thread *thread = threads__findnew(event->ip.pid); 614 struct thread *thread = threads__findnew(event->ip.pid);
668 615
669 if (sample_type & PERF_SAMPLE_PERIOD) { 616 if (sample_type & PERF_SAMPLE_PERIOD) {
@@ -709,32 +656,26 @@ static int process_sample_event(event_t *event)
709 656
710 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 657 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
711 658
712 if (cpumode == PERF_RECORD_MISC_KERNEL) { 659 thread__find_addr_location(thread, cpumode,
713 level = 'k'; 660 MAP__FUNCTION, ip, &al, NULL);
714 sym = kernel_maps__find_function(ip, &map, NULL); 661 /*
715 dump_printf(" ...... dso: %s\n", 662 * We have to do this here as we may have a dso with no symbol hit that
716 map ? map->dso->long_name : "<not found>"); 663 * has a name longer than the ones with symbols sampled.
717 } else if (cpumode == PERF_RECORD_MISC_USER) { 664 */
718 level = '.'; 665 if (al.map && !sort_dso.elide && !al.map->dso->slen_calculated)
719 sym = resolve_symbol(thread, &map, &ip); 666 dso__calc_col_width(al.map->dso);
720
721 } else {
722 level = 'H';
723 dump_printf(" ...... dso: [hypervisor]\n");
724 }
725 667
726 if (dso_list && 668 if (dso_list &&
727 (!map || !map->dso || 669 (!al.map || !al.map->dso ||
728 !(strlist__has_entry(dso_list, map->dso->short_name) || 670 !(strlist__has_entry(dso_list, al.map->dso->short_name) ||
729 (map->dso->short_name != map->dso->long_name && 671 (al.map->dso->short_name != al.map->dso->long_name &&
730 strlist__has_entry(dso_list, map->dso->long_name))))) 672 strlist__has_entry(dso_list, al.map->dso->long_name)))))
731 return 0; 673 return 0;
732 674
733 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name)) 675 if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name))
734 return 0; 676 return 0;
735 677
736 if (hist_entry__add(thread, map, sym, ip, 678 if (hist_entry__add(&al, chain, period)) {
737 chain, level, period)) {
738 pr_debug("problem incrementing symbol count, skipping event\n"); 679 pr_debug("problem incrementing symbol count, skipping event\n");
739 return -1; 680 return -1;
740 } 681 }
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 7a3c0c7aad3d..e0a374d0e43a 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -929,55 +929,28 @@ static int symbol_filter(struct map *map, struct symbol *sym)
929static void event__process_sample(const event_t *self, int counter) 929static void event__process_sample(const event_t *self, int counter)
930{ 930{
931 u64 ip = self->ip.ip; 931 u64 ip = self->ip.ip;
932 struct map *map;
933 struct sym_entry *syme; 932 struct sym_entry *syme;
934 struct symbol *sym; 933 struct addr_location al;
935 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 934 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
936 935
937 switch (origin) { 936 switch (origin) {
938 case PERF_RECORD_MISC_USER: { 937 case PERF_RECORD_MISC_USER:
939 struct thread *thread;
940
941 if (hide_user_symbols) 938 if (hide_user_symbols)
942 return; 939 return;
943 940 break;
944 thread = threads__findnew(self->ip.pid);
945 if (thread == NULL)
946 return;
947
948 map = thread__find_map(thread, MAP__FUNCTION, ip);
949 if (map != NULL) {
950 ip = map->map_ip(map, ip);
951 sym = map__find_symbol(map, ip, symbol_filter);
952 if (sym == NULL)
953 return;
954 userspace_samples++;
955 break;
956 }
957 }
958 /*
959 * If this is outside of all known maps,
960 * and is a negative address, try to look it
961 * up in the kernel dso, as it might be a
962 * vsyscall or vdso (which executes in user-mode).
963 */
964 if ((long long)ip >= 0)
965 return;
966 /* Fall thru */
967 case PERF_RECORD_MISC_KERNEL: 941 case PERF_RECORD_MISC_KERNEL:
968 if (hide_kernel_symbols) 942 if (hide_kernel_symbols)
969 return; 943 return;
970
971 sym = kernel_maps__find_function(ip, &map, symbol_filter);
972 if (sym == NULL)
973 return;
974 break; 944 break;
975 default: 945 default:
976 return; 946 return;
977 } 947 }
978 948
979 syme = symbol__priv(sym); 949 if (event__preprocess_sample(self, &al, symbol_filter) < 0 ||
950 al.sym == NULL)
951 return;
980 952
953 syme = symbol__priv(al.sym);
981 if (!syme->skip) { 954 if (!syme->skip) {
982 syme->count[counter]++; 955 syme->count[counter]++;
983 syme->origin = origin; 956 syme->origin = origin;
@@ -986,8 +959,9 @@ static void event__process_sample(const event_t *self, int counter)
986 if (list_empty(&syme->node) || !syme->node.next) 959 if (list_empty(&syme->node) || !syme->node.next)
987 __list_insert_active_sym(syme); 960 __list_insert_active_sym(syme);
988 pthread_mutex_unlock(&active_symbols_lock); 961 pthread_mutex_unlock(&active_symbols_lock);
962 if (origin == PERF_RECORD_MISC_USER)
963 ++userspace_samples;
989 ++samples; 964 ++samples;
990 return;
991 } 965 }
992} 966}
993 967
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 70b4aa03b472..233d7ad9bd7f 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -249,3 +249,65 @@ int event__process_task(event_t *self)
249 249
250 return 0; 250 return 0;
251} 251}
252
253void thread__find_addr_location(struct thread *self, u8 cpumode,
254 enum map_type type, u64 addr,
255 struct addr_location *al,
256 symbol_filter_t filter)
257{
258 struct thread *thread = al->thread = self;
259
260 al->addr = addr;
261
262 if (cpumode & PERF_RECORD_MISC_KERNEL) {
263 al->level = 'k';
264 thread = kthread;
265 } else if (cpumode & PERF_RECORD_MISC_USER)
266 al->level = '.';
267 else {
268 al->level = 'H';
269 al->map = NULL;
270 al->sym = NULL;
271 return;
272 }
273try_again:
274 al->map = thread__find_map(thread, type, al->addr);
275 if (al->map == NULL) {
276 /*
277 * If this is outside of all known maps, and is a negative
278 * address, try to look it up in the kernel dso, as it might be
279 * a vsyscall or vdso (which executes in user-mode).
280 *
281 * XXX This is nasty, we should have a symbol list in the
282 * "[vdso]" dso, but for now lets use the old trick of looking
283 * in the whole kernel symbol list.
284 */
285 if ((long long)al->addr < 0 && thread != kthread) {
286 thread = kthread;
287 goto try_again;
288 }
289 al->sym = NULL;
290 } else {
291 al->addr = al->map->map_ip(al->map, al->addr);
292 al->sym = map__find_symbol(al->map, al->addr, filter);
293 }
294}
295
296int event__preprocess_sample(const event_t *self, struct addr_location *al,
297 symbol_filter_t filter)
298{
299 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
300 struct thread *thread = threads__findnew(self->ip.pid);
301
302 if (thread == NULL)
303 return -1;
304
305 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
306
307 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
308 self->ip.ip, al, filter);
309 dump_printf(" ...... dso: %s\n",
310 al->map ? al->map->dso->long_name :
311 al->level == 'H' ? "[hypervisor]" : "<not found>");
312 return 0;
313}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 13c12c75f970..a4cc8105cf67 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -152,4 +152,8 @@ int event__process_lost(event_t *self);
152int event__process_mmap(event_t *self); 152int event__process_mmap(event_t *self);
153int event__process_task(event_t *self); 153int event__process_task(event_t *self);
154 154
155struct addr_location;
156int event__preprocess_sample(const event_t *self, struct addr_location *al,
157 symbol_filter_t filter);
158
155#endif /* __PERF_RECORD_H */ 159#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index f26cd9ba00fd..0ebf6ee16caa 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -14,20 +14,19 @@ struct callchain_param callchain_param = {
14 * histogram, sorted on item, collects counts 14 * histogram, sorted on item, collects counts
15 */ 15 */
16 16
17struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map, 17struct hist_entry *__hist_entry__add(struct addr_location *al,
18 struct symbol *sym,
19 struct symbol *sym_parent, 18 struct symbol *sym_parent,
20 u64 ip, u64 count, char level, bool *hit) 19 u64 count, bool *hit)
21{ 20{
22 struct rb_node **p = &hist.rb_node; 21 struct rb_node **p = &hist.rb_node;
23 struct rb_node *parent = NULL; 22 struct rb_node *parent = NULL;
24 struct hist_entry *he; 23 struct hist_entry *he;
25 struct hist_entry entry = { 24 struct hist_entry entry = {
26 .thread = thread, 25 .thread = al->thread,
27 .map = map, 26 .map = al->map,
28 .sym = sym, 27 .sym = al->sym,
29 .ip = ip, 28 .ip = al->addr,
30 .level = level, 29 .level = al->level,
31 .count = count, 30 .count = count,
32 .parent = sym_parent, 31 .parent = sym_parent,
33 }; 32 };
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index ac2149c559b0..3020db0c9292 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -36,9 +36,9 @@ extern unsigned long total_fork;
36extern unsigned long total_unknown; 36extern unsigned long total_unknown;
37extern unsigned long total_lost; 37extern unsigned long total_lost;
38 38
39struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map, 39struct hist_entry *__hist_entry__add(struct addr_location *al,
40 struct symbol *sym, struct symbol *parent, 40 struct symbol *parent,
41 u64 ip, u64 count, char level, bool *hit); 41 u64 count, bool *hit);
42extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 42extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
43extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 43extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
44extern void hist_entry__free(struct hist_entry *); 44extern void hist_entry__free(struct hist_entry *);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index b788c2f5d672..fffcb937cdcb 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -43,7 +43,8 @@ static struct symbol_conf symbol_conf__defaults = {
43 .try_vmlinux_path = true, 43 .try_vmlinux_path = true,
44}; 44};
45 45
46static struct thread kthread_mem, *kthread = &kthread_mem; 46static struct thread kthread_mem;
47struct thread *kthread = &kthread_mem;
47 48
48bool dso__loaded(const struct dso *self, enum map_type type) 49bool dso__loaded(const struct dso *self, enum map_type type)
49{ 50{
@@ -1178,29 +1179,6 @@ out:
1178 return ret; 1179 return ret;
1179} 1180}
1180 1181
1181static struct symbol *thread__find_symbol(struct thread *self, u64 ip,
1182 enum map_type type, struct map **mapp,
1183 symbol_filter_t filter)
1184{
1185 struct map *map = thread__find_map(self, type, ip);
1186
1187 if (mapp)
1188 *mapp = map;
1189
1190 if (map) {
1191 ip = map->map_ip(map, ip);
1192 return map__find_symbol(map, ip, filter);
1193 }
1194
1195 return NULL;
1196}
1197
1198struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp,
1199 symbol_filter_t filter)
1200{
1201 return thread__find_symbol(kthread, ip, MAP__FUNCTION, mapp, filter);
1202}
1203
1204static struct map *thread__find_map_by_name(struct thread *self, char *name) 1182static struct map *thread__find_map_by_name(struct thread *self, char *name)
1205{ 1183{
1206 struct rb_node *nd; 1184 struct rb_node *nd;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 3f9e4a4d83dd..17003efa0b39 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -63,6 +63,14 @@ static inline void *symbol__priv(struct symbol *self)
63 return ((void *)self) - symbol__priv_size; 63 return ((void *)self) - symbol__priv_size;
64} 64}
65 65
66struct addr_location {
67 struct thread *thread;
68 struct map *map;
69 struct symbol *sym;
70 u64 addr;
71 char level;
72};
73
66struct dso { 74struct dso {
67 struct list_head node; 75 struct list_head node;
68 struct rb_root symbols[MAP__NR_TYPES]; 76 struct rb_root symbols[MAP__NR_TYPES];
@@ -105,6 +113,8 @@ size_t kernel_maps__fprintf(FILE *fp);
105 113
106int symbol__init(struct symbol_conf *conf); 114int symbol__init(struct symbol_conf *conf);
107 115
116struct thread;
117struct thread *kthread;
108extern struct list_head dsos__user, dsos__kernel; 118extern struct list_head dsos__user, dsos__kernel;
109extern struct dso *vdso; 119extern struct dso *vdso;
110#endif /* __PERF_SYMBOL */ 120#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 2229f82cd630..603f5610861b 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -285,3 +285,15 @@ size_t threads__fprintf(FILE *fp)
285 285
286 return ret; 286 return ret;
287} 287}
288
289struct symbol *thread__find_symbol(struct thread *self,
290 enum map_type type, u64 addr,
291 symbol_filter_t filter)
292{
293 struct map *map = thread__find_map(self, type, addr);
294
295 if (map != NULL)
296 return map__find_symbol(map, map->map_ip(map, addr), filter);
297
298 return NULL;
299}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 59b0d9b577d6..686d6e914d9e 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -27,19 +27,30 @@ size_t thread__fprintf_maps(struct thread *self, FILE *fp);
27size_t threads__fprintf(FILE *fp); 27size_t threads__fprintf(FILE *fp);
28 28
29void maps__insert(struct rb_root *maps, struct map *map); 29void maps__insert(struct rb_root *maps, struct map *map);
30struct map *maps__find(struct rb_root *maps, u64 ip); 30struct map *maps__find(struct rb_root *maps, u64 addr);
31
32struct symbol *kernel_maps__find_function(const u64 ip, struct map **mapp,
33 symbol_filter_t filter);
34 31
35static inline struct map *thread__find_map(struct thread *self, 32static inline struct map *thread__find_map(struct thread *self,
36 enum map_type type, u64 ip) 33 enum map_type type, u64 addr)
37{ 34{
38 return self ? maps__find(&self->maps[type], ip) : NULL; 35 return self ? maps__find(&self->maps[type], addr) : NULL;
39} 36}
40 37
41static inline void __thread__insert_map(struct thread *self, struct map *map) 38static inline void __thread__insert_map(struct thread *self, struct map *map)
42{ 39{
43 maps__insert(&self->maps[map->type], map); 40 maps__insert(&self->maps[map->type], map);
44} 41}
42
43void thread__find_addr_location(struct thread *self, u8 cpumode,
44 enum map_type type, u64 addr,
45 struct addr_location *al,
46 symbol_filter_t filter);
47struct symbol *thread__find_symbol(struct thread *self,
48 enum map_type type, u64 addr,
49 symbol_filter_t filter);
50
51static inline struct symbol *
52thread__find_function(struct thread *self, u64 addr, symbol_filter_t filter)
53{
54 return thread__find_symbol(self, MAP__FUNCTION, addr, filter);
55}
45#endif /* __PERF_THREAD_H */ 56#endif /* __PERF_THREAD_H */