Merge tag 'perf-core-for-mingo-20160607' of git://git.kernel.org/pub/scm/linux/kernel...
[cascardo/linux.git] / tools / perf / util / unwind-libunwind.c
1 #include "unwind.h"
2 #include "thread.h"
3 #include "session.h"
4 #include "debug.h"
5 #include "arch/common.h"
6
7 struct unwind_libunwind_ops __weak *local_unwind_libunwind_ops;
8 struct unwind_libunwind_ops __weak *x86_32_unwind_libunwind_ops;
9 struct unwind_libunwind_ops __weak *arm64_unwind_libunwind_ops;
10
11 static void unwind__register_ops(struct thread *thread,
12                           struct unwind_libunwind_ops *ops)
13 {
14         thread->unwind_libunwind_ops = ops;
15 }
16
17 int unwind__prepare_access(struct thread *thread, struct map *map)
18 {
19         const char *arch;
20         enum dso_type dso_type;
21         struct unwind_libunwind_ops *ops = local_unwind_libunwind_ops;
22
23         if (thread->addr_space) {
24                 pr_debug("unwind: thread map already set, dso=%s\n",
25                          map->dso->name);
26                 return 0;
27         }
28
29         /* env->arch is NULL for live-mode (i.e. perf top) */
30         if (!thread->mg->machine->env || !thread->mg->machine->env->arch)
31                 goto out_register;
32
33         dso_type = dso__type(map->dso, thread->mg->machine);
34         if (dso_type == DSO__TYPE_UNKNOWN)
35                 return 0;
36
37         arch = normalize_arch(thread->mg->machine->env->arch);
38
39         if (!strcmp(arch, "x86")) {
40                 if (dso_type != DSO__TYPE_64BIT)
41                         ops = x86_32_unwind_libunwind_ops;
42         } else if (!strcmp(arch, "arm64") || !strcmp(arch, "arm")) {
43                 if (dso_type == DSO__TYPE_64BIT)
44                         ops = arm64_unwind_libunwind_ops;
45         }
46
47         if (!ops) {
48                 pr_err("unwind: target platform=%s is not supported\n", arch);
49                 return -1;
50         }
51 out_register:
52         unwind__register_ops(thread, ops);
53
54         return thread->unwind_libunwind_ops->prepare_access(thread);
55 }
56
57 void unwind__flush_access(struct thread *thread)
58 {
59         if (thread->unwind_libunwind_ops)
60                 thread->unwind_libunwind_ops->flush_access(thread);
61 }
62
63 void unwind__finish_access(struct thread *thread)
64 {
65         if (thread->unwind_libunwind_ops)
66                 thread->unwind_libunwind_ops->finish_access(thread);
67 }
68
69 int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
70                          struct thread *thread,
71                          struct perf_sample *data, int max_stack)
72 {
73         if (thread->unwind_libunwind_ops)
74                 return thread->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack);
75         return 0;
76 }