aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
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 */