xref: /openbmc/linux/tools/perf/util/debug.c (revision efe4a1ac)
1 /* For general debugging purposes */
2 
3 #include "../perf.h"
4 
5 #include <inttypes.h>
6 #include <string.h>
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <sys/wait.h>
10 #include <api/debug.h>
11 #include <linux/time64.h>
12 #ifdef HAVE_BACKTRACE_SUPPORT
13 #include <execinfo.h>
14 #endif
15 #include "cache.h"
16 #include "color.h"
17 #include "event.h"
18 #include "debug.h"
19 #include "print_binary.h"
20 #include "util.h"
21 #include "target.h"
22 
23 #include "sane_ctype.h"
24 
25 int verbose;
26 bool dump_trace = false, quiet = false;
27 int debug_ordered_events;
28 static int redirect_to_stderr;
29 int debug_data_convert;
30 
31 int veprintf(int level, int var, const char *fmt, va_list args)
32 {
33 	int ret = 0;
34 
35 	if (var >= level) {
36 		if (use_browser >= 1 && !redirect_to_stderr)
37 			ui_helpline__vshow(fmt, args);
38 		else
39 			ret = vfprintf(stderr, fmt, args);
40 	}
41 
42 	return ret;
43 }
44 
45 int eprintf(int level, int var, const char *fmt, ...)
46 {
47 	va_list args;
48 	int ret;
49 
50 	va_start(args, fmt);
51 	ret = veprintf(level, var, fmt, args);
52 	va_end(args);
53 
54 	return ret;
55 }
56 
57 static int veprintf_time(u64 t, const char *fmt, va_list args)
58 {
59 	int ret = 0;
60 	u64 secs, usecs, nsecs = t;
61 
62 	secs   = nsecs / NSEC_PER_SEC;
63 	nsecs -= secs  * NSEC_PER_SEC;
64 	usecs  = nsecs / NSEC_PER_USEC;
65 
66 	ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",
67 		      secs, usecs);
68 	ret += vfprintf(stderr, fmt, args);
69 	return ret;
70 }
71 
72 int eprintf_time(int level, int var, u64 t, const char *fmt, ...)
73 {
74 	int ret = 0;
75 	va_list args;
76 
77 	if (var >= level) {
78 		va_start(args, fmt);
79 		ret = veprintf_time(t, fmt, args);
80 		va_end(args);
81 	}
82 
83 	return ret;
84 }
85 
86 /*
87  * Overloading libtraceevent standard info print
88  * function, display with -v in perf.
89  */
90 void pr_stat(const char *fmt, ...)
91 {
92 	va_list args;
93 
94 	va_start(args, fmt);
95 	veprintf(1, verbose, fmt, args);
96 	va_end(args);
97 	eprintf(1, verbose, "\n");
98 }
99 
100 int dump_printf(const char *fmt, ...)
101 {
102 	va_list args;
103 	int ret = 0;
104 
105 	if (dump_trace) {
106 		va_start(args, fmt);
107 		ret = vprintf(fmt, args);
108 		va_end(args);
109 	}
110 
111 	return ret;
112 }
113 
114 static void trace_event_printer(enum binary_printer_ops op,
115 				unsigned int val, void *extra)
116 {
117 	const char *color = PERF_COLOR_BLUE;
118 	union perf_event *event = (union perf_event *)extra;
119 	unsigned char ch = (unsigned char)val;
120 
121 	switch (op) {
122 	case BINARY_PRINT_DATA_BEGIN:
123 		printf(".");
124 		color_fprintf(stdout, color, "\n. ... raw event: size %d bytes\n",
125 				event->header.size);
126 		break;
127 	case BINARY_PRINT_LINE_BEGIN:
128 		printf(".");
129 		break;
130 	case BINARY_PRINT_ADDR:
131 		color_fprintf(stdout, color, "  %04x: ", val);
132 		break;
133 	case BINARY_PRINT_NUM_DATA:
134 		color_fprintf(stdout, color, " %02x", val);
135 		break;
136 	case BINARY_PRINT_NUM_PAD:
137 		color_fprintf(stdout, color, "   ");
138 		break;
139 	case BINARY_PRINT_SEP:
140 		color_fprintf(stdout, color, "  ");
141 		break;
142 	case BINARY_PRINT_CHAR_DATA:
143 		color_fprintf(stdout, color, "%c",
144 			      isprint(ch) ? ch : '.');
145 		break;
146 	case BINARY_PRINT_CHAR_PAD:
147 		color_fprintf(stdout, color, " ");
148 		break;
149 	case BINARY_PRINT_LINE_END:
150 		color_fprintf(stdout, color, "\n");
151 		break;
152 	case BINARY_PRINT_DATA_END:
153 		printf("\n");
154 		break;
155 	default:
156 		break;
157 	}
158 }
159 
160 void trace_event(union perf_event *event)
161 {
162 	unsigned char *raw_event = (void *)event;
163 
164 	if (!dump_trace)
165 		return;
166 
167 	print_binary(raw_event, event->header.size, 16,
168 		     trace_event_printer, event);
169 }
170 
171 static struct debug_variable {
172 	const char *name;
173 	int *ptr;
174 } debug_variables[] = {
175 	{ .name = "verbose",		.ptr = &verbose },
176 	{ .name = "ordered-events",	.ptr = &debug_ordered_events},
177 	{ .name = "stderr",		.ptr = &redirect_to_stderr},
178 	{ .name = "data-convert",	.ptr = &debug_data_convert },
179 	{ .name = NULL, }
180 };
181 
182 int perf_debug_option(const char *str)
183 {
184 	struct debug_variable *var = &debug_variables[0];
185 	char *vstr, *s = strdup(str);
186 	int v = 1;
187 
188 	vstr = strchr(s, '=');
189 	if (vstr)
190 		*vstr++ = 0;
191 
192 	while (var->name) {
193 		if (!strcmp(s, var->name))
194 			break;
195 		var++;
196 	}
197 
198 	if (!var->name) {
199 		pr_err("Unknown debug variable name '%s'\n", s);
200 		free(s);
201 		return -1;
202 	}
203 
204 	if (vstr) {
205 		v = atoi(vstr);
206 		/*
207 		 * Allow only values in range (0, 10),
208 		 * otherwise set 0.
209 		 */
210 		v = (v < 0) || (v > 10) ? 0 : v;
211 	}
212 
213 	if (quiet)
214 		v = -1;
215 
216 	*var->ptr = v;
217 	free(s);
218 	return 0;
219 }
220 
221 int perf_quiet_option(void)
222 {
223 	struct debug_variable *var = &debug_variables[0];
224 
225 	/* disable all debug messages */
226 	while (var->name) {
227 		*var->ptr = -1;
228 		var++;
229 	}
230 
231 	quiet = true;
232 	return 0;
233 }
234 
235 #define DEBUG_WRAPPER(__n, __l)				\
236 static int pr_ ## __n ## _wrapper(const char *fmt, ...)	\
237 {							\
238 	va_list args;					\
239 	int ret;					\
240 							\
241 	va_start(args, fmt);				\
242 	ret = veprintf(__l, verbose, fmt, args);	\
243 	va_end(args);					\
244 	return ret;					\
245 }
246 
247 DEBUG_WRAPPER(warning, 0);
248 DEBUG_WRAPPER(debug, 1);
249 
250 void perf_debug_setup(void)
251 {
252 	libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);
253 }
254 
255 /* Obtain a backtrace and print it to stdout. */
256 #ifdef HAVE_BACKTRACE_SUPPORT
257 void dump_stack(void)
258 {
259 	void *array[16];
260 	size_t size = backtrace(array, ARRAY_SIZE(array));
261 	char **strings = backtrace_symbols(array, size);
262 	size_t i;
263 
264 	printf("Obtained %zd stack frames.\n", size);
265 
266 	for (i = 0; i < size; i++)
267 		printf("%s\n", strings[i]);
268 
269 	free(strings);
270 }
271 #else
272 void dump_stack(void) {}
273 #endif
274 
275 void sighandler_dump_stack(int sig)
276 {
277 	psignal(sig, "perf");
278 	dump_stack();
279 	signal(sig, SIG_DFL);
280 	raise(sig);
281 }
282