xref: /linux/tools/perf/util/unwind.c (revision 3d5e48944e824bddc20d7b874e784f7b279636fe)
1 // SPDX-License-Identifier: GPL-2.0
2 #include "debug.h"
3 #include "symbol_conf.h"
4 #include "unwind.h"
5 #include <linux/string.h>
6 #include <string.h>
7 #include <stdlib.h>
8 
9 int unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, void *arg __maybe_unused,
10 			struct thread *thread __maybe_unused,
11 			struct perf_sample *data __maybe_unused,
12 			int max_stack __maybe_unused,
13 			bool best_effort __maybe_unused)
14 {
15 	int ret = 0;
16 
17 #if defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT)
18 	if (symbol_conf.unwind_style[0] == UNWIND_STYLE_UNKNOWN) {
19 		int i = 0;
20 #ifdef HAVE_LIBDW_SUPPORT
21 		symbol_conf.unwind_style[i++] = UNWIND_STYLE_LIBDW;
22 #endif
23 #ifdef HAVE_LIBUNWIND_SUPPORT
24 		symbol_conf.unwind_style[i++] = UNWIND_STYLE_LIBUNWIND;
25 #endif
26 	}
27 #endif //defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT)
28 
29 	for (size_t i = 0; i < ARRAY_SIZE(symbol_conf.unwind_style); i++) {
30 		switch (symbol_conf.unwind_style[i]) {
31 		case UNWIND_STYLE_LIBDW:
32 			ret = libdw__get_entries(cb, arg, thread, data, max_stack, best_effort);
33 			break;
34 		case UNWIND_STYLE_LIBUNWIND:
35 			ret = libunwind__get_entries(cb, arg, thread, data, max_stack, best_effort);
36 			break;
37 		case UNWIND_STYLE_UNKNOWN:
38 		default:
39 #if !defined(HAVE_LIBDW_SUPPORT) && !defined(HAVE_LIBUNWIND_SUPPORT)
40 			pr_warning_once(
41 				"Error: dwarf unwinding not supported, build perf with libdw or libunwind.\n");
42 #endif
43 			ret = 0;
44 			break;
45 		}
46 		if (ret > 0) {
47 			ret = 0;
48 			break;
49 		}
50 		if (ret < 0)
51 			break;
52 	}
53 	return ret;
54 }
55 
56 int unwind__configure(const char *var, const char *value, void *cb __maybe_unused)
57 {
58 	static const char * const unwind_style_names[] = {
59 		[UNWIND_STYLE_LIBDW] = "libdw",
60 		[UNWIND_STYLE_LIBUNWIND] = "libunwind",
61 		NULL
62 	};
63 	char *s, *p, *saveptr;
64 	size_t i = 0;
65 
66 	if (strcmp(var, "unwind.style"))
67 		return 0;
68 
69 	if (!value)
70 		return -1;
71 
72 	s = strdup(value);
73 	if (!s)
74 		return -1;
75 
76 	memset(symbol_conf.unwind_style, 0, sizeof(symbol_conf.unwind_style));
77 
78 	p = strtok_r(s, ",", &saveptr);
79 	while (p && i < ARRAY_SIZE(symbol_conf.unwind_style)) {
80 		bool found = false;
81 		char *q = strim(p);
82 
83 		for (size_t j = UNWIND_STYLE_LIBDW; j < MAX_UNWIND_STYLE; j++) {
84 			if (!strcasecmp(q, unwind_style_names[j])) {
85 				symbol_conf.unwind_style[i++] = j;
86 				found = true;
87 				break;
88 			}
89 		}
90 		if (!found)
91 			pr_warning("Unknown unwind style: %s\n", q);
92 		p = strtok_r(NULL, ",", &saveptr);
93 	}
94 
95 	free(s);
96 	return 0;
97 }
98 
99 int unwind__option(const struct option *opt __maybe_unused,
100 		   const char *arg,
101 		   int unset __maybe_unused)
102 {
103 	return unwind__configure("unwind.style", arg, NULL);
104 }
105