xref: /linux/tools/perf/util/debug.c (revision b228ab57e51b62663a80ca820c87ba2650583f08)
1 // SPDX-License-Identifier: GPL-2.0
2 /* For general debugging purposes */
3 
4 #include <inttypes.h>
5 #include <string.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/wait.h>
10 #include <api/debug.h>
11 #include <linux/kernel.h>
12 #include <linux/time64.h>
13 #include <sys/time.h>
14 #ifdef HAVE_BACKTRACE_SUPPORT
15 #include <execinfo.h>
16 #endif
17 #include "color.h"
18 #include "event.h"
19 #include "debug.h"
20 #include "print_binary.h"
21 #include "target.h"
22 #include "trace-event.h"
23 #include "ui/helpline.h"
24 #include "ui/ui.h"
25 #include "util/parse-sublevel-options.h"
26 
27 #include <linux/ctype.h>
28 
29 #ifdef HAVE_LIBTRACEEVENT
30 #include <traceevent/event-parse.h>
31 #else
32 #define LIBTRACEEVENT_VERSION 0
33 #endif
34 
35 int verbose;
36 int debug_kmaps;
37 int debug_peo_args;
38 bool dump_trace = false, quiet = false;
39 int debug_ordered_events;
40 static int redirect_to_stderr;
41 int debug_data_convert;
42 static FILE *_debug_file;
43 bool debug_display_time;
44 
45 FILE *debug_file(void)
46 {
47 	if (!_debug_file) {
48 		pr_warning_once("debug_file not set");
49 		debug_set_file(stderr);
50 	}
51 	return _debug_file;
52 }
53 
54 void debug_set_file(FILE *file)
55 {
56 	_debug_file = file;
57 }
58 
59 void debug_set_display_time(bool set)
60 {
61 	debug_display_time = set;
62 }
63 
64 static int fprintf_time(FILE *file)
65 {
66 	struct timeval tod;
67 	struct tm ltime;
68 	char date[64];
69 
70 	if (!debug_display_time)
71 		return 0;
72 
73 	if (gettimeofday(&tod, NULL) != 0)
74 		return 0;
75 
76 	if (localtime_r(&tod.tv_sec, &ltime) == NULL)
77 		return 0;
78 
79 	strftime(date, sizeof(date),  "%F %H:%M:%S", &ltime);
80 	return fprintf(file, "[%s.%06lu] ", date, (long)tod.tv_usec);
81 }
82 
83 int veprintf(int level, int var, const char *fmt, va_list args)
84 {
85 	int ret = 0;
86 
87 	if (var >= level) {
88 		if (use_browser >= 1 && !redirect_to_stderr) {
89 			ui_helpline__vshow(fmt, args);
90 		} else {
91 			ret = fprintf_time(debug_file());
92 			ret += vfprintf(debug_file(), fmt, args);
93 		}
94 	}
95 
96 	return ret;
97 }
98 
99 int eprintf(int level, int var, const char *fmt, ...)
100 {
101 	va_list args;
102 	int ret;
103 
104 	va_start(args, fmt);
105 	ret = veprintf(level, var, fmt, args);
106 	va_end(args);
107 
108 	return ret;
109 }
110 
111 static int veprintf_time(u64 t, const char *fmt, va_list args)
112 {
113 	int ret = 0;
114 	u64 secs, usecs, nsecs = t;
115 
116 	secs   = nsecs / NSEC_PER_SEC;
117 	nsecs -= secs  * NSEC_PER_SEC;
118 	usecs  = nsecs / NSEC_PER_USEC;
119 
120 	ret = fprintf(debug_file(), "[%13" PRIu64 ".%06" PRIu64 "] ", secs, usecs);
121 	ret += vfprintf(debug_file(), fmt, args);
122 	return ret;
123 }
124 
125 int eprintf_time(int level, int var, u64 t, const char *fmt, ...)
126 {
127 	int ret = 0;
128 	va_list args;
129 
130 	if (var >= level) {
131 		va_start(args, fmt);
132 		ret = veprintf_time(t, fmt, args);
133 		va_end(args);
134 	}
135 
136 	return ret;
137 }
138 
139 /*
140  * Overloading libtraceevent standard info print
141  * function, display with -v in perf.
142  */
143 void pr_stat(const char *fmt, ...)
144 {
145 	va_list args;
146 
147 	va_start(args, fmt);
148 	veprintf(1, verbose, fmt, args);
149 	va_end(args);
150 	eprintf(1, verbose, "\n");
151 }
152 
153 int dump_printf(const char *fmt, ...)
154 {
155 	va_list args;
156 	int ret = 0;
157 
158 	if (dump_trace) {
159 		va_start(args, fmt);
160 		ret = vprintf(fmt, args);
161 		va_end(args);
162 	}
163 
164 	return ret;
165 }
166 
167 static int trace_event_printer(enum binary_printer_ops op,
168 			       unsigned int val, void *extra, FILE *fp)
169 {
170 	const char *color = PERF_COLOR_BLUE;
171 	union perf_event *event = (union perf_event *)extra;
172 	unsigned char ch = (unsigned char)val;
173 	int printed = 0;
174 
175 	switch (op) {
176 	case BINARY_PRINT_DATA_BEGIN:
177 		printed += fprintf(fp, ".");
178 		printed += color_fprintf(fp, color, "\n. ... raw event: size %d bytes\n",
179 					 event->header.size);
180 		break;
181 	case BINARY_PRINT_LINE_BEGIN:
182 		printed += fprintf(fp, ".");
183 		break;
184 	case BINARY_PRINT_ADDR:
185 		printed += color_fprintf(fp, color, "  %04x: ", val);
186 		break;
187 	case BINARY_PRINT_NUM_DATA:
188 		printed += color_fprintf(fp, color, " %02x", val);
189 		break;
190 	case BINARY_PRINT_NUM_PAD:
191 		printed += color_fprintf(fp, color, "   ");
192 		break;
193 	case BINARY_PRINT_SEP:
194 		printed += color_fprintf(fp, color, "  ");
195 		break;
196 	case BINARY_PRINT_CHAR_DATA:
197 		printed += color_fprintf(fp, color, "%c",
198 			      isprint(ch) && isascii(ch) ? ch : '.');
199 		break;
200 	case BINARY_PRINT_CHAR_PAD:
201 		printed += color_fprintf(fp, color, " ");
202 		break;
203 	case BINARY_PRINT_LINE_END:
204 		printed += color_fprintf(fp, color, "\n");
205 		break;
206 	case BINARY_PRINT_DATA_END:
207 		printed += fprintf(fp, "\n");
208 		break;
209 	default:
210 		break;
211 	}
212 
213 	return printed;
214 }
215 
216 void trace_event(union perf_event *event)
217 {
218 	unsigned char *raw_event = (void *)event;
219 
220 	if (!dump_trace)
221 		return;
222 
223 	print_binary(raw_event, event->header.size, 16,
224 		     trace_event_printer, event);
225 }
226 
227 static struct sublevel_option debug_opts[] = {
228 	{ .name = "verbose",		.value_ptr = &verbose },
229 	{ .name = "ordered-events",	.value_ptr = &debug_ordered_events},
230 	{ .name = "stderr",		.value_ptr = &redirect_to_stderr},
231 	{ .name = "data-convert",	.value_ptr = &debug_data_convert },
232 	{ .name = "perf-event-open",	.value_ptr = &debug_peo_args },
233 	{ .name = "kmaps",		.value_ptr = &debug_kmaps },
234 	{ .name = NULL, }
235 };
236 
237 int perf_debug_option(const char *str)
238 {
239 	int ret;
240 
241 	ret = perf_parse_sublevel_options(str, debug_opts);
242 	if (ret)
243 		return ret;
244 
245 	/* Allow only verbose value in range (0, 10), otherwise set 0. */
246 	verbose = (verbose < 0) || (verbose > 10) ? 0 : verbose;
247 
248 #if LIBTRACEEVENT_VERSION >= MAKE_LIBTRACEEVENT_VERSION(1, 3, 0)
249 	if (verbose == 1)
250 		tep_set_loglevel(TEP_LOG_INFO);
251 	else if (verbose == 2)
252 		tep_set_loglevel(TEP_LOG_DEBUG);
253 	else if (verbose >= 3)
254 		tep_set_loglevel(TEP_LOG_ALL);
255 #endif
256 	return 0;
257 }
258 
259 int perf_quiet_option(void)
260 {
261 	struct sublevel_option *opt = &debug_opts[0];
262 
263 	/* disable all debug messages */
264 	while (opt->name) {
265 		*opt->value_ptr = -1;
266 		opt++;
267 	}
268 
269 	/* For debug variables that are used as bool types, set to 0. */
270 	redirect_to_stderr = 0;
271 	debug_peo_args = 0;
272 	debug_kmaps = 0;
273 
274 	return 0;
275 }
276 
277 #define DEBUG_WRAPPER(__n, __l)				\
278 static int pr_ ## __n ## _wrapper(const char *fmt, ...)	\
279 {							\
280 	va_list args;					\
281 	int ret;					\
282 							\
283 	va_start(args, fmt);				\
284 	ret = veprintf(__l, verbose, fmt, args);	\
285 	va_end(args);					\
286 	return ret;					\
287 }
288 
289 DEBUG_WRAPPER(warning, 0);
290 DEBUG_WRAPPER(debug, 1);
291 
292 void perf_debug_setup(void)
293 {
294 	debug_set_file(stderr);
295 	libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);
296 }
297 
298 /* Obtain a backtrace and print it to stdout. */
299 #ifdef HAVE_BACKTRACE_SUPPORT
300 void dump_stack(void)
301 {
302 	void *array[16];
303 	size_t size = backtrace(array, ARRAY_SIZE(array));
304 	char **strings = backtrace_symbols(array, size);
305 	size_t i;
306 
307 	printf("Obtained %zd stack frames.\n", size);
308 
309 	for (i = 0; i < size; i++)
310 		printf("%s\n", strings[i]);
311 
312 	free(strings);
313 }
314 #else
315 void dump_stack(void) {}
316 #endif
317 
318 void sighandler_dump_stack(int sig)
319 {
320 	psignal(sig, "perf");
321 	dump_stack();
322 	signal(sig, SIG_DFL);
323 	raise(sig);
324 }
325