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 bool *initialized) 19 { 20 const char *arch; 21 enum dso_type dso_type; 22 struct unwind_libunwind_ops *ops = local_unwind_libunwind_ops; 23 int err; 24 25 if (thread->addr_space) { 26 pr_debug("unwind: thread map already set, dso=%s\n", 27 map->dso->name); 28 if (initialized) 29 *initialized = true; 30 return 0; 31 } 32 33 /* env->arch is NULL for live-mode (i.e. perf top) */ 34 if (!thread->mg->machine->env || !thread->mg->machine->env->arch) 35 goto out_register; 36 37 dso_type = dso__type(map->dso, thread->mg->machine); 38 if (dso_type == DSO__TYPE_UNKNOWN) 39 return 0; 40 41 arch = normalize_arch(thread->mg->machine->env->arch); 42 43 if (!strcmp(arch, "x86")) { 44 if (dso_type != DSO__TYPE_64BIT) 45 ops = x86_32_unwind_libunwind_ops; 46 } else if (!strcmp(arch, "arm64") || !strcmp(arch, "arm")) { 47 if (dso_type == DSO__TYPE_64BIT) 48 ops = arm64_unwind_libunwind_ops; 49 } 50 51 if (!ops) { 52 pr_err("unwind: target platform=%s is not supported\n", arch); 53 return -1; 54 } 55 out_register: 56 unwind__register_ops(thread, ops); 57 58 err = thread->unwind_libunwind_ops->prepare_access(thread); 59 if (initialized) 60 *initialized = err ? false : true; 61 return err; 62 } 63 64 void unwind__flush_access(struct thread *thread) 65 { 66 if (thread->unwind_libunwind_ops) 67 thread->unwind_libunwind_ops->flush_access(thread); 68 } 69 70 void unwind__finish_access(struct thread *thread) 71 { 72 if (thread->unwind_libunwind_ops) 73 thread->unwind_libunwind_ops->finish_access(thread); 74 } 75 76 int unwind__get_entries(unwind_entry_cb_t cb, void *arg, 77 struct thread *thread, 78 struct perf_sample *data, int max_stack) 79 { 80 if (thread->unwind_libunwind_ops) 81 return thread->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack); 82 return 0; 83 } 84