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